Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lola_clock.c
Go to the documentation of this file.
1 /*
2  * Support for Digigram Lola PCI-e boards
3  *
4  * Copyright (c) 2011 Takashi Iwai <[email protected]>
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 <linux/delay.h>
24 #include <sound/core.h>
25 #include <sound/pcm.h>
26 #include "lola.h"
27 
28 unsigned int lola_sample_rate_convert(unsigned int coded)
29 {
30  unsigned int freq;
31 
32  /* base frequency */
33  switch (coded & 0x3) {
34  case 0: freq = 48000; break;
35  case 1: freq = 44100; break;
36  case 2: freq = 32000; break;
37  default: return 0; /* error */
38  }
39 
40  /* multiplier / devisor */
41  switch (coded & 0x1c) {
42  case (0 << 2): break;
43  case (4 << 2): break;
44  case (1 << 2): freq *= 2; break;
45  case (2 << 2): freq *= 4; break;
46  case (5 << 2): freq /= 2; break;
47  case (6 << 2): freq /= 4; break;
48  default: return 0; /* error */
49  }
50 
51  /* ajustement */
52  switch (coded & 0x60) {
53  case (0 << 5): break;
54  case (1 << 5): freq = (freq * 999) / 1000; break;
55  case (2 << 5): freq = (freq * 1001) / 1000; break;
56  default: return 0; /* error */
57  }
58  return freq;
59 }
60 
61 /*
62  * Granualrity
63  */
64 
65 #define LOLA_MAXFREQ_AT_GRANULARITY_MIN 48000
66 #define LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX 96000
67 
68 static bool check_gran_clock_compatibility(struct lola *chip,
69  unsigned int val,
70  unsigned int freq)
71 {
72  if (!chip->granularity)
73  return true;
74 
75  if (val < LOLA_GRANULARITY_MIN || val > LOLA_GRANULARITY_MAX ||
76  (val % LOLA_GRANULARITY_STEP) != 0)
77  return false;
78 
79  if (val == LOLA_GRANULARITY_MIN) {
81  return false;
82  } else if (val < LOLA_GRANULARITY_MAX) {
84  return false;
85  }
86  return true;
87 }
88 
89 int lola_set_granularity(struct lola *chip, unsigned int val, bool force)
90 {
91  int err;
92 
93  if (!force) {
94  if (val == chip->granularity)
95  return 0;
96 #if 0
97  /* change Gran only if there are no streams allocated ! */
98  if (chip->audio_in_alloc_mask || chip->audio_out_alloc_mask)
99  return -EBUSY;
100 #endif
101  if (!check_gran_clock_compatibility(chip, val,
102  chip->clock.cur_freq))
103  return -EINVAL;
104  }
105 
106  chip->granularity = val;
107  val /= LOLA_GRANULARITY_STEP;
108 
109  /* audio function group */
111  val, 0);
112  if (err < 0)
113  return err;
114  /* this can be a very slow function !!! */
115  usleep_range(400 * val, 20000);
116  return lola_codec_flush(chip);
117 }
118 
119 /*
120  * Clock widget handling
121  */
122 
124 {
125  unsigned int val;
126  int i, j, nitems, nb_verbs, idx, idx_list;
127  int err;
128 
129  err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
130  if (err < 0) {
131  printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
132  return err;
133  }
134 
135  if ((val & 0xfff00000) != 0x01f00000) { /* test SubType and Type */
136  snd_printdd("No valid clock widget\n");
137  return 0;
138  }
139 
140  chip->clock.nid = nid;
141  chip->clock.items = val & 0xff;
142  snd_printdd("clock_list nid=%x, entries=%d\n", nid,
143  chip->clock.items);
144  if (chip->clock.items > MAX_SAMPLE_CLOCK_COUNT) {
145  printk(KERN_ERR SFX "CLOCK_LIST too big: %d\n",
146  chip->clock.items);
147  return -EINVAL;
148  }
149 
150  nitems = chip->clock.items;
151  nb_verbs = (nitems + 3) / 4;
152  idx = 0;
153  idx_list = 0;
154  for (i = 0; i < nb_verbs; i++) {
155  unsigned int res_ex;
156  unsigned short items[4];
157 
158  err = lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST,
159  idx, 0, &val, &res_ex);
160  if (err < 0) {
161  printk(KERN_ERR SFX "Can't read CLOCK_LIST\n");
162  return -EINVAL;
163  }
164 
165  items[0] = val & 0xfff;
166  items[1] = (val >> 16) & 0xfff;
167  items[2] = res_ex & 0xfff;
168  items[3] = (res_ex >> 16) & 0xfff;
169 
170  for (j = 0; j < 4; j++) {
171  unsigned char type = items[j] >> 8;
172  unsigned int freq = items[j] & 0xff;
174  bool add_clock = true;
175  if (type == LOLA_CLOCK_TYPE_INTERNAL) {
176  freq = lola_sample_rate_convert(freq);
177  if (freq < chip->sample_rate_min)
178  add_clock = false;
179  else if (freq == 48000) {
180  chip->clock.cur_index = idx_list;
181  chip->clock.cur_freq = 48000;
182  chip->clock.cur_valid = true;
183  }
184  } else if (type == LOLA_CLOCK_TYPE_VIDEO) {
185  freq = lola_sample_rate_convert(freq);
186  if (freq < chip->sample_rate_min)
187  add_clock = false;
188  /* video clock has a format (0:NTSC, 1:PAL)*/
189  if (items[j] & 0x80)
190  format = LOLA_CLOCK_FORMAT_NTSC;
191  else
192  format = LOLA_CLOCK_FORMAT_PAL;
193  }
194  if (add_clock) {
195  struct lola_sample_clock *sc;
196  sc = &chip->clock.sample_clock[idx_list];
197  sc->type = type;
198  sc->format = format;
199  sc->freq = freq;
200  /* keep the index used with the board */
201  chip->clock.idx_lookup[idx_list] = idx;
202  idx_list++;
203  } else {
204  chip->clock.items--;
205  }
206  if (++idx >= nitems)
207  break;
208  }
209  }
210  return 0;
211 }
212 
213 /* enable unsolicited events of the clock widget */
215 {
216  unsigned int res;
217  int err;
218 
219  err = lola_codec_read(chip, chip->clock.nid,
222  0, &res, NULL);
223  if (err < 0)
224  return err;
225  if (res) {
226  printk(KERN_WARNING SFX "error in enable_clock_events %d\n",
227  res);
228  return -EINVAL;
229  }
230  return 0;
231 }
232 
233 int lola_set_clock_index(struct lola *chip, unsigned int idx)
234 {
235  unsigned int res;
236  int err;
237 
238  err = lola_codec_read(chip, chip->clock.nid,
240  chip->clock.idx_lookup[idx],
241  0, &res, NULL);
242  if (err < 0)
243  return err;
244  if (res) {
245  printk(KERN_WARNING SFX "error in set_clock %d\n", res);
246  return -EINVAL;
247  }
248  return 0;
249 }
250 
251 bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val)
252 {
253  unsigned int tag;
254 
255  /* the current EXTERNAL clock information gets updated by interrupt
256  * with an unsolicited response
257  */
258  if (!val)
259  return false;
261  if (tag != LOLA_UNSOLICITED_TAG)
262  return false;
263 
264  /* only for current = external clocks */
265  if (chip->clock.sample_clock[chip->clock.cur_index].type !=
267  chip->clock.cur_freq = lola_sample_rate_convert(val & 0x7f);
268  chip->clock.cur_valid = (val & 0x100) != 0;
269  }
270  return true;
271 }
272 
273 int lola_set_clock(struct lola *chip, int idx)
274 {
275  int freq = 0;
276  bool valid = false;
277 
278  if (idx == chip->clock.cur_index) {
279  /* current clock is allowed */
280  freq = chip->clock.cur_freq;
281  valid = chip->clock.cur_valid;
282  } else if (chip->clock.sample_clock[idx].type ==
284  /* internal clocks allowed */
285  freq = chip->clock.sample_clock[idx].freq;
286  valid = true;
287  }
288 
289  if (!freq || !valid)
290  return -EINVAL;
291 
292  if (!check_gran_clock_compatibility(chip, chip->granularity, freq))
293  return -EINVAL;
294 
295  if (idx != chip->clock.cur_index) {
296  int err = lola_set_clock_index(chip, idx);
297  if (err < 0)
298  return err;
299  /* update new settings */
300  chip->clock.cur_index = idx;
301  chip->clock.cur_freq = freq;
302  chip->clock.cur_valid = true;
303  }
304  return 0;
305 }
306 
308 {
309  int i;
310 
311  if (chip->clock.cur_freq == rate && chip->clock.cur_valid)
312  return 0;
313  /* search for new dwClockIndex */
314  for (i = 0; i < chip->clock.items; i++) {
315  if (chip->clock.sample_clock[i].type == LOLA_CLOCK_TYPE_INTERNAL &&
316  chip->clock.sample_clock[i].freq == rate)
317  break;
318  }
319  if (i >= chip->clock.items)
320  return -EINVAL;
321  return lola_set_clock(chip, i);
322 }
323