ALSA: Add the driver for Digigram Lola PCI-e boards
[pandora-kernel.git] / sound / pci / lola / lola_clock.c
1 /*
2  *  Support for Digigram Lola PCI-e boards
3  *
4  *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
5  *
6  *  This program is free software; you can redistribute it and/or modify it
7  *  under the terms of the GNU General Public License as published by the Free
8  *  Software Foundation; either version 2 of the License, or (at your option)
9  *  any later version.
10  *
11  *  This program is distributed in the hope that it will be useful, but WITHOUT
12  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  *  more details.
15  *
16  *  You should have received a copy of the GNU General Public License along with
17  *  this program; if not, write to the Free Software Foundation, Inc., 59
18  *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  */
20
21 #include <linux/kernel.h>
22 #include <linux/init.h>
23 #include <sound/core.h>
24 #include <sound/pcm.h>
25 #include "lola.h"
26
27 static unsigned int sample_rate_convert(unsigned int coded)
28 {
29         unsigned int freq;
30
31         /* base frequency */
32         switch (coded & 0x3) {
33         case 0:     freq = 48000; break;
34         case 1:     freq = 44100; break;
35         case 2:     freq = 32000; break;
36         default:    return 0;   /* error */
37         }
38
39         /* multiplier / devisor */
40         switch (coded & 0x1c) {
41         case (0 << 2):    break;
42         case (4 << 2):    break;
43         case (1 << 2):    freq *= 2; break;
44         case (2 << 2):    freq *= 4; break;
45         case (5 << 2):    freq /= 2; break;
46         case (6 << 2):    freq /= 4; break;
47         default:        return 0;   /* error */
48         }
49
50         /* ajustement */
51         switch (coded & 0x60) {
52         case (0 << 5):    break;
53         case (1 << 5):    freq = (freq * 999) / 1000; break;
54         case (2 << 5):    freq = (freq * 1001) / 1000; break;
55         default:        return 0;   /* error */
56         }
57         return freq;
58 }
59
60 /*
61  * Granualrity
62  */
63
64 #define LOLA_MAXFREQ_AT_GRANULARITY_MIN         48000
65 #define LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX   96000
66
67 static bool check_gran_clock_compatibility(struct lola *chip,
68                                            unsigned int val,
69                                            unsigned int freq)
70 {
71         if (!chip->granularity)
72                 return true;
73
74         if (val < LOLA_GRANULARITY_MIN || val > LOLA_GRANULARITY_MAX ||
75             (val % LOLA_GRANULARITY_STEP) != 0)
76                 return false;
77
78         if (val == LOLA_GRANULARITY_MIN) {
79                 if (freq > LOLA_MAXFREQ_AT_GRANULARITY_MIN)
80                         return false;
81         } else if (val < LOLA_GRANULARITY_MAX) {
82                 if (freq > LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX)
83                         return false;
84         }
85         return true;
86 }
87
88 int lola_set_granularity(struct lola *chip, unsigned int val, bool force)
89 {
90         int err;
91
92         if (!force) {
93                 if (val == chip->granularity)
94                         return 0;
95 #if 0
96                 /* change Gran only if there are no streams allocated ! */
97                 if (chip->audio_in_alloc_mask || chip->audio_out_alloc_mask)
98                         return -EBUSY;
99 #endif
100                 if (!check_gran_clock_compatibility(chip, val,
101                                                     chip->clock.cur_freq))
102                         return -EINVAL;
103         }
104
105         chip->granularity = val;
106         val /= LOLA_GRANULARITY_STEP;
107
108         /* audio function group */
109         err = lola_codec_write(chip, 1, LOLA_VERB_SET_GRANULARITY_STEPS,
110                                val, 0);
111         if (err < 0)
112                 return err;
113         /* this can be a very slow function !!! */
114         usleep_range(400 * val, 20000);
115         return lola_codec_flush(chip);
116 }
117
118 /*
119  * Clock widget handling
120  */
121
122 int __devinit lola_init_clock_widget(struct lola *chip, int nid)
123 {
124         unsigned int val;
125         int i, j, nitems, nb_verbs, idx, idx_list;
126         int err;
127
128         err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
129         if (err < 0) {
130                 printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
131                 return err;
132         }
133
134         if ((val & 0xfff00000) != 0x01f00000) { /* test SubType and Type */
135                 snd_printdd("No valid clock widget\n");
136                 return 0;
137         }
138
139         chip->clock.nid = nid;
140         chip->clock.items = val & 0xff;
141         snd_printdd("clock_list nid=%x, entries=%d\n", nid,
142                     chip->clock.items);
143         if (chip->clock.items > MAX_SAMPLE_CLOCK_COUNT) {
144                 printk(KERN_ERR SFX "CLOCK_LIST too big: %d\n",
145                        chip->clock.items);
146                 return -EINVAL;
147         }
148
149         nitems = chip->clock.items;
150         nb_verbs = (nitems + 3) / 4;
151         idx = 0;
152         idx_list = 0;
153         for (i = 0; i < nb_verbs; i++) {
154                 unsigned int res_ex;
155                 unsigned short items[4];
156
157                 err = lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST,
158                                       idx, 0, &val, &res_ex);
159                 if (err < 0) {
160                         printk(KERN_ERR SFX "Can't read CLOCK_LIST\n");
161                         return -EINVAL;
162                 }
163
164                 items[0] = val & 0xfff;
165                 items[1] = (val >> 16) & 0xfff;
166                 items[2] = res_ex & 0xfff;
167                 items[3] = (res_ex >> 16) & 0xfff;
168
169                 for (j = 0; j < 4; j++) {
170                         unsigned char type = items[j] >> 8;
171                         unsigned int freq = items[j] & 0xff;
172                         int format = LOLA_CLOCK_FORMAT_NONE;
173                         bool add_clock = true;
174                         if (type == LOLA_CLOCK_TYPE_INTERNAL) {
175                                 freq = sample_rate_convert(freq);
176                                 if (freq < chip->sample_rate_min)
177                                         add_clock = false;
178                                 else if (freq == 48000) {
179                                         chip->clock.cur_index = idx_list;
180                                         chip->clock.cur_freq = 48000;
181                                         chip->clock.cur_valid = true;
182                                 }
183                         } else if (type == LOLA_CLOCK_TYPE_VIDEO) {
184                                 freq = sample_rate_convert(freq);
185                                 if (freq < chip->sample_rate_min)
186                                         add_clock = false;
187                                 /* video clock has a format (0:NTSC, 1:PAL)*/
188                                 if (items[j] & 0x80)
189                                         format = LOLA_CLOCK_FORMAT_NTSC;
190                                 else
191                                         format = LOLA_CLOCK_FORMAT_PAL;
192                         }
193                         if (add_clock) {
194                                 struct lola_sample_clock *sc;
195                                 sc = &chip->clock.sample_clock[idx_list];
196                                 sc->type = type;
197                                 sc->format = format;
198                                 sc->freq = freq;
199                                 /* keep the index used with the board */
200                                 chip->clock.idx_lookup[idx_list] = idx;
201                                 idx_list++;
202                         } else {
203                                 chip->clock.items--;
204                         }
205                         if (++idx >= nitems)
206                                 break;
207                 }
208         }
209         return 0;
210 }
211
212 /* enable unsolicited events of the clock widget */
213 int lola_enable_clock_events(struct lola *chip)
214 {
215         unsigned int res;
216         int err;
217
218         err = lola_codec_read(chip, chip->clock.nid,
219                               LOLA_VERB_SET_UNSOLICITED_ENABLE,
220                               LOLA_UNSOLICITED_ENABLE | LOLA_UNSOLICITED_TAG,
221                               0, &res, NULL);
222         if (err < 0)
223                 return err;
224         if (res) {
225                 printk(KERN_WARNING SFX "error in enable_clock_events %d\n",
226                        res);
227                 return -EINVAL;
228         }
229         return 0;
230 }
231
232 int lola_set_clock_index(struct lola *chip, unsigned int idx)
233 {
234         unsigned int res;
235         int err;
236
237         err = lola_codec_read(chip, chip->clock.nid,
238                               LOLA_VERB_SET_CLOCK_SELECT,
239                               chip->clock.idx_lookup[idx],
240                               0, &res, NULL);
241         if (err < 0)
242                 return err;
243         if (res) {
244                 printk(KERN_WARNING SFX "error in set_clock %d\n", res);
245                 return -EINVAL;
246         }
247         return 0;
248 }
249
250 bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val)
251 {
252         unsigned int tag;
253
254         /* the current EXTERNAL clock information gets updated by interrupt
255          * with an unsolicited response
256          */
257         if (!val)
258                 return false;
259         tag = (val >> LOLA_UNSOL_RESP_TAG_OFFSET) & LOLA_UNSOLICITED_TAG_MASK;
260         if (tag != LOLA_UNSOLICITED_TAG)
261                 return false;
262
263         /* only for current = external clocks */
264         if (chip->clock.sample_clock[chip->clock.cur_index].type !=
265             LOLA_CLOCK_TYPE_INTERNAL) {
266                 chip->clock.cur_freq = sample_rate_convert(val & 0x7f);
267                 chip->clock.cur_valid = (val & 0x100) != 0;
268         }
269         return true;
270 }
271
272 int lola_set_clock(struct lola *chip, int idx)
273 {
274         int freq = 0;
275         bool valid = false;
276
277         if (idx == chip->clock.cur_index) {
278                 /* current clock is allowed */
279                 freq = chip->clock.cur_freq;
280                 valid = chip->clock.cur_valid;
281         } else if (chip->clock.sample_clock[idx].type ==
282                    LOLA_CLOCK_TYPE_INTERNAL) {
283                 /* internal clocks allowed */
284                 freq = chip->clock.sample_clock[idx].freq;
285                 valid = true;
286         }
287
288         if (!freq || !valid)
289                 return -EINVAL;
290
291         if (!check_gran_clock_compatibility(chip, chip->granularity, freq))
292                 return -EINVAL;
293
294         if (idx != chip->clock.cur_index) {
295                 int err = lola_set_clock_index(chip, idx);
296                 if (err < 0)
297                         return err;
298                 /* update new settings */
299                 chip->clock.cur_index = idx;
300                 chip->clock.cur_freq = freq;
301                 chip->clock.cur_valid = true;
302         }
303         return 0;
304 }
305
306 int lola_set_sample_rate(struct lola *chip, int rate)
307 {
308         int i;
309
310         if (chip->clock.cur_freq == rate && chip->clock.cur_valid)
311                 return 0;
312         /* search for new dwClockIndex */
313         for (i = 0; i < chip->clock.items; i++) {
314                 if (chip->clock.sample_clock[i].type == LOLA_CLOCK_TYPE_INTERNAL &&
315                     chip->clock.sample_clock[i].freq == rate)
316                         break;
317         }
318         if (i >= chip->clock.items)
319                 return -EINVAL;
320         return lola_set_clock(chip, i);
321 }
322