~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/pci/ca0106/ca0106_mixer.c

Version: ~ [ linux-5.6-rc1 ] ~ [ linux-5.5.2 ] ~ [ linux-5.4.17 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.102 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.170 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.213 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.213 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.81 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
  3  *  Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
  4  *  Version: 0.0.18
  5  *
  6  *  FEATURES currently supported:
  7  *    See ca0106_main.c for features.
  8  * 
  9  *  Changelog:
 10  *    Support interrupts per period.
 11  *    Removed noise from Center/LFE channel when in Analog mode.
 12  *    Rename and remove mixer controls.
 13  *  0.0.6
 14  *    Use separate card based DMA buffer for periods table list.
 15  *  0.0.7
 16  *    Change remove and rename ctrls into lists.
 17  *  0.0.8
 18  *    Try to fix capture sources.
 19  *  0.0.9
 20  *    Fix AC3 output.
 21  *    Enable S32_LE format support.
 22  *  0.0.10
 23  *    Enable playback 48000 and 96000 rates. (Rates other that these do not work, even with "plug:front".)
 24  *  0.0.11
 25  *    Add Model name recognition.
 26  *  0.0.12
 27  *    Correct interrupt timing. interrupt at end of period, instead of in the middle of a playback period.
 28  *    Remove redundent "voice" handling.
 29  *  0.0.13
 30  *    Single trigger call for multi channels.
 31  *  0.0.14
 32  *    Set limits based on what the sound card hardware can do.
 33  *    playback periods_min=2, periods_max=8
 34  *    capture hw constraints require period_size = n * 64 bytes.
 35  *    playback hw constraints require period_size = n * 64 bytes.
 36  *  0.0.15
 37  *    Separated ca0106.c into separate functional .c files.
 38  *  0.0.16
 39  *    Modified Copyright message.
 40  *  0.0.17
 41  *    Implement Mic and Line in Capture.
 42  *  0.0.18
 43  *    Add support for mute control on SB Live 24bit (cards w/ SPI DAC)
 44  *
 45  *  This code was initially based on code from ALSA's emu10k1x.c which is:
 46  *  Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
 47  *
 48  *   This program is free software; you can redistribute it and/or modify
 49  *   it under the terms of the GNU General Public License as published by
 50  *   the Free Software Foundation; either version 2 of the License, or
 51  *   (at your option) any later version.
 52  *
 53  *   This program is distributed in the hope that it will be useful,
 54  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 55  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 56  *   GNU General Public License for more details.
 57  *
 58  *   You should have received a copy of the GNU General Public License
 59  *   along with this program; if not, write to the Free Software
 60  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 61  *
 62  */
 63 #include <linux/delay.h>
 64 #include <linux/init.h>
 65 #include <linux/interrupt.h>
 66 #include <linux/moduleparam.h>
 67 #include <sound/core.h>
 68 #include <sound/initval.h>
 69 #include <sound/pcm.h>
 70 #include <sound/ac97_codec.h>
 71 #include <sound/info.h>
 72 #include <sound/tlv.h>
 73 #include <linux/io.h>
 74 
 75 #include "ca0106.h"
 76 
 77 static void ca0106_spdif_enable(struct snd_ca0106 *emu)
 78 {
 79         unsigned int val;
 80 
 81         if (emu->spdif_enable) {
 82                 /* Digital */
 83                 snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
 84                 snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000);
 85                 val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000;
 86                 snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val);
 87                 val = inl(emu->port + GPIO) & ~0x101;
 88                 outl(val, emu->port + GPIO);
 89 
 90         } else {
 91                 /* Analog */
 92                 snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
 93                 snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000);
 94                 val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000;
 95                 snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val);
 96                 val = inl(emu->port + GPIO) | 0x101;
 97                 outl(val, emu->port + GPIO);
 98         }
 99 }
100 
101 static void ca0106_set_capture_source(struct snd_ca0106 *emu)
102 {
103         unsigned int val = emu->capture_source;
104         unsigned int source, mask;
105         source = (val << 28) | (val << 24) | (val << 20) | (val << 16);
106         mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff;
107         snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask);
108 }
109 
110 static void ca0106_set_i2c_capture_source(struct snd_ca0106 *emu,
111                                           unsigned int val, int force)
112 {
113         unsigned int ngain, ogain;
114         u32 source;
115 
116         snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
117         ngain = emu->i2c_capture_volume[val][0]; /* Left */
118         ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
119         if (force || ngain != ogain)
120                 snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ngain & 0xff);
121         ngain = emu->i2c_capture_volume[val][1]; /* Right */
122         ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
123         if (force || ngain != ogain)
124                 snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ngain & 0xff);
125         source = 1 << val;
126         snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */
127         emu->i2c_capture_source = val;
128 }
129 
130 static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu)
131 {
132         u32 tmp;
133 
134         if (emu->capture_mic_line_in) {
135                 /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */
136                 tmp = inl(emu->port+GPIO) & ~0x400;
137                 tmp = tmp | 0x400;
138                 outl(tmp, emu->port+GPIO);
139                 /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); */
140         } else {
141                 /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */
142                 tmp = inl(emu->port+GPIO) & ~0x400;
143                 outl(tmp, emu->port+GPIO);
144                 /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); */
145         }
146 }
147 
148 static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx)
149 {
150         snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_str_bits[idx]);
151 }
152 
153 /*
154  */
155 static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
156 static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
157 
158 #define snd_ca0106_shared_spdif_info    snd_ctl_boolean_mono_info
159 
160 static int snd_ca0106_shared_spdif_get(struct snd_kcontrol *kcontrol,
161                                         struct snd_ctl_elem_value *ucontrol)
162 {
163         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
164 
165         ucontrol->value.integer.value[0] = emu->spdif_enable;
166         return 0;
167 }
168 
169 static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol,
170                                         struct snd_ctl_elem_value *ucontrol)
171 {
172         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
173         unsigned int val;
174         int change = 0;
175 
176         val = !!ucontrol->value.integer.value[0];
177         change = (emu->spdif_enable != val);
178         if (change) {
179                 emu->spdif_enable = val;
180                 ca0106_spdif_enable(emu);
181         }
182         return change;
183 }
184 
185 static int snd_ca0106_capture_source_info(struct snd_kcontrol *kcontrol,
186                                           struct snd_ctl_elem_info *uinfo)
187 {
188         static const char * const texts[6] = {
189                 "IEC958 out", "i2s mixer out", "IEC958 in", "i2s in", "AC97 in", "SRC out"
190         };
191 
192         return snd_ctl_enum_info(uinfo, 1, 6, texts);
193 }
194 
195 static int snd_ca0106_capture_source_get(struct snd_kcontrol *kcontrol,
196                                         struct snd_ctl_elem_value *ucontrol)
197 {
198         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
199 
200         ucontrol->value.enumerated.item[0] = emu->capture_source;
201         return 0;
202 }
203 
204 static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol,
205                                         struct snd_ctl_elem_value *ucontrol)
206 {
207         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
208         unsigned int val;
209         int change = 0;
210 
211         val = ucontrol->value.enumerated.item[0] ;
212         if (val >= 6)
213                 return -EINVAL;
214         change = (emu->capture_source != val);
215         if (change) {
216                 emu->capture_source = val;
217                 ca0106_set_capture_source(emu);
218         }
219         return change;
220 }
221 
222 static int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
223                                           struct snd_ctl_elem_info *uinfo)
224 {
225         static const char * const texts[4] = {
226                 "Phone", "Mic", "Line in", "Aux"
227         };
228 
229         return snd_ctl_enum_info(uinfo, 1, 4, texts);
230 }
231 
232 static int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
233                                         struct snd_ctl_elem_value *ucontrol)
234 {
235         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
236 
237         ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
238         return 0;
239 }
240 
241 static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
242                                         struct snd_ctl_elem_value *ucontrol)
243 {
244         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
245         unsigned int source_id;
246         int change = 0;
247         /* If the capture source has changed,
248          * update the capture volume from the cached value
249          * for the particular source.
250          */
251         source_id = ucontrol->value.enumerated.item[0] ;
252         if (source_id >= 4)
253                 return -EINVAL;
254         change = (emu->i2c_capture_source != source_id);
255         if (change) {
256                 ca0106_set_i2c_capture_source(emu, source_id, 0);
257         }
258         return change;
259 }
260 
261 static int snd_ca0106_capture_line_in_side_out_info(struct snd_kcontrol *kcontrol,
262                                                struct snd_ctl_elem_info *uinfo)
263 {
264         static const char * const texts[2] = { "Side out", "Line in" };
265 
266         return snd_ctl_enum_info(uinfo, 1, 2, texts);
267 }
268 
269 static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol,
270                                                struct snd_ctl_elem_info *uinfo)
271 {
272         static const char * const texts[2] = { "Line in", "Mic in" };
273 
274         return snd_ctl_enum_info(uinfo, 1, 2, texts);
275 }
276 
277 static int snd_ca0106_capture_mic_line_in_get(struct snd_kcontrol *kcontrol,
278                                         struct snd_ctl_elem_value *ucontrol)
279 {
280         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
281 
282         ucontrol->value.enumerated.item[0] = emu->capture_mic_line_in;
283         return 0;
284 }
285 
286 static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol,
287                                         struct snd_ctl_elem_value *ucontrol)
288 {
289         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
290         unsigned int val;
291         int change = 0;
292 
293         val = ucontrol->value.enumerated.item[0] ;
294         if (val > 1)
295                 return -EINVAL;
296         change = (emu->capture_mic_line_in != val);
297         if (change) {
298                 emu->capture_mic_line_in = val;
299                 ca0106_set_capture_mic_line_in(emu);
300         }
301         return change;
302 }
303 
304 static const struct snd_kcontrol_new snd_ca0106_capture_mic_line_in =
305 {
306         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
307         .name =         "Shared Mic/Line in Capture Switch",
308         .info =         snd_ca0106_capture_mic_line_in_info,
309         .get =          snd_ca0106_capture_mic_line_in_get,
310         .put =          snd_ca0106_capture_mic_line_in_put
311 };
312 
313 static const struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out =
314 {
315         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
316         .name =         "Shared Line in/Side out Capture Switch",
317         .info =         snd_ca0106_capture_line_in_side_out_info,
318         .get =          snd_ca0106_capture_mic_line_in_get,
319         .put =          snd_ca0106_capture_mic_line_in_put
320 };
321 
322 
323 static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol,
324                                  struct snd_ctl_elem_info *uinfo)
325 {
326         uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
327         uinfo->count = 1;
328         return 0;
329 }
330 
331 static void decode_spdif_bits(unsigned char *status, unsigned int bits)
332 {
333         status[0] = (bits >> 0) & 0xff;
334         status[1] = (bits >> 8) & 0xff;
335         status[2] = (bits >> 16) & 0xff;
336         status[3] = (bits >> 24) & 0xff;
337 }
338 
339 static int snd_ca0106_spdif_get_default(struct snd_kcontrol *kcontrol,
340                                  struct snd_ctl_elem_value *ucontrol)
341 {
342         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
343         unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
344 
345         decode_spdif_bits(ucontrol->value.iec958.status,
346                           emu->spdif_bits[idx]);
347         return 0;
348 }
349 
350 static int snd_ca0106_spdif_get_stream(struct snd_kcontrol *kcontrol,
351                                  struct snd_ctl_elem_value *ucontrol)
352 {
353         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
354         unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
355 
356         decode_spdif_bits(ucontrol->value.iec958.status,
357                           emu->spdif_str_bits[idx]);
358         return 0;
359 }
360 
361 static int snd_ca0106_spdif_get_mask(struct snd_kcontrol *kcontrol,
362                                       struct snd_ctl_elem_value *ucontrol)
363 {
364         ucontrol->value.iec958.status[0] = 0xff;
365         ucontrol->value.iec958.status[1] = 0xff;
366         ucontrol->value.iec958.status[2] = 0xff;
367         ucontrol->value.iec958.status[3] = 0xff;
368         return 0;
369 }
370 
371 static unsigned int encode_spdif_bits(unsigned char *status)
372 {
373         return ((unsigned int)status[0] << 0) |
374                 ((unsigned int)status[1] << 8) |
375                 ((unsigned int)status[2] << 16) |
376                 ((unsigned int)status[3] << 24);
377 }
378 
379 static int snd_ca0106_spdif_put_default(struct snd_kcontrol *kcontrol,
380                                  struct snd_ctl_elem_value *ucontrol)
381 {
382         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
383         unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
384         unsigned int val;
385 
386         val = encode_spdif_bits(ucontrol->value.iec958.status);
387         if (val != emu->spdif_bits[idx]) {
388                 emu->spdif_bits[idx] = val;
389                 /* FIXME: this isn't safe, but needed to keep the compatibility
390                  * with older alsa-lib config
391                  */
392                 emu->spdif_str_bits[idx] = val;
393                 ca0106_set_spdif_bits(emu, idx);
394                 return 1;
395         }
396         return 0;
397 }
398 
399 static int snd_ca0106_spdif_put_stream(struct snd_kcontrol *kcontrol,
400                                  struct snd_ctl_elem_value *ucontrol)
401 {
402         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
403         unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
404         unsigned int val;
405 
406         val = encode_spdif_bits(ucontrol->value.iec958.status);
407         if (val != emu->spdif_str_bits[idx]) {
408                 emu->spdif_str_bits[idx] = val;
409                 ca0106_set_spdif_bits(emu, idx);
410                 return 1;
411         }
412         return 0;
413 }
414 
415 static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol,
416                                   struct snd_ctl_elem_info *uinfo)
417 {
418         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
419         uinfo->count = 2;
420         uinfo->value.integer.min = 0;
421         uinfo->value.integer.max = 255;
422         return 0;
423 }
424 
425 static int snd_ca0106_volume_get(struct snd_kcontrol *kcontrol,
426                                  struct snd_ctl_elem_value *ucontrol)
427 {
428         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
429         unsigned int value;
430         int channel_id, reg;
431 
432         channel_id = (kcontrol->private_value >> 8) & 0xff;
433         reg = kcontrol->private_value & 0xff;
434 
435         value = snd_ca0106_ptr_read(emu, reg, channel_id);
436         ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */
437         ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */
438         return 0;
439 }
440 
441 static int snd_ca0106_volume_put(struct snd_kcontrol *kcontrol,
442                                  struct snd_ctl_elem_value *ucontrol)
443 {
444         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
445         unsigned int oval, nval;
446         int channel_id, reg;
447 
448         channel_id = (kcontrol->private_value >> 8) & 0xff;
449         reg = kcontrol->private_value & 0xff;
450 
451         oval = snd_ca0106_ptr_read(emu, reg, channel_id);
452         nval = ((0xff - ucontrol->value.integer.value[0]) << 24) |
453                 ((0xff - ucontrol->value.integer.value[1]) << 16);
454         nval |= ((0xff - ucontrol->value.integer.value[0]) << 8) |
455                 ((0xff - ucontrol->value.integer.value[1]) );
456         if (oval == nval)
457                 return 0;
458         snd_ca0106_ptr_write(emu, reg, channel_id, nval);
459         return 1;
460 }
461 
462 static int snd_ca0106_i2c_volume_info(struct snd_kcontrol *kcontrol,
463                                   struct snd_ctl_elem_info *uinfo)
464 {
465         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
466         uinfo->count = 2;
467         uinfo->value.integer.min = 0;
468         uinfo->value.integer.max = 255;
469         return 0;
470 }
471 
472 static int snd_ca0106_i2c_volume_get(struct snd_kcontrol *kcontrol,
473                                  struct snd_ctl_elem_value *ucontrol)
474 {
475         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
476         int source_id;
477 
478         source_id = kcontrol->private_value;
479 
480         ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
481         ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
482         return 0;
483 }
484 
485 static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
486                                  struct snd_ctl_elem_value *ucontrol)
487 {
488         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
489         unsigned int ogain;
490         unsigned int ngain;
491         int source_id;
492         int change = 0;
493 
494         source_id = kcontrol->private_value;
495         ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
496         ngain = ucontrol->value.integer.value[0];
497         if (ngain > 0xff)
498                 return -EINVAL;
499         if (ogain != ngain) {
500                 if (emu->i2c_capture_source == source_id)
501                         snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
502                 emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0];
503                 change = 1;
504         }
505         ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
506         ngain = ucontrol->value.integer.value[1];
507         if (ngain > 0xff)
508                 return -EINVAL;
509         if (ogain != ngain) {
510                 if (emu->i2c_capture_source == source_id)
511                         snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
512                 emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1];
513                 change = 1;
514         }
515 
516         return change;
517 }
518 
519 #define spi_mute_info   snd_ctl_boolean_mono_info
520 
521 static int spi_mute_get(struct snd_kcontrol *kcontrol,
522                         struct snd_ctl_elem_value *ucontrol)
523 {
524         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
525         unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT;
526         unsigned int bit = kcontrol->private_value & SPI_REG_MASK;
527 
528         ucontrol->value.integer.value[0] = !(emu->spi_dac_reg[reg] & bit);
529         return 0;
530 }
531 
532 static int spi_mute_put(struct snd_kcontrol *kcontrol,
533                         struct snd_ctl_elem_value *ucontrol)
534 {
535         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
536         unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT;
537         unsigned int bit = kcontrol->private_value & SPI_REG_MASK;
538         int ret;
539 
540         ret = emu->spi_dac_reg[reg] & bit;
541         if (ucontrol->value.integer.value[0]) {
542                 if (!ret)       /* bit already cleared, do nothing */
543                         return 0;
544                 emu->spi_dac_reg[reg] &= ~bit;
545         } else {
546                 if (ret)        /* bit already set, do nothing */
547                         return 0;
548                 emu->spi_dac_reg[reg] |= bit;
549         }
550 
551         ret = snd_ca0106_spi_write(emu, emu->spi_dac_reg[reg]);
552         return ret ? -EINVAL : 1;
553 }
554 
555 #define CA_VOLUME(xname,chid,reg) \
556 {                                                               \
557         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,     \
558         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |             \
559                   SNDRV_CTL_ELEM_ACCESS_TLV_READ,               \
560         .info =  snd_ca0106_volume_info,                        \
561         .get =   snd_ca0106_volume_get,                         \
562         .put =   snd_ca0106_volume_put,                         \
563         .tlv = { .p = snd_ca0106_db_scale1 },                   \
564         .private_value = ((chid) << 8) | (reg)                  \
565 }
566 
567 static struct snd_kcontrol_new snd_ca0106_volume_ctls[] = {
568         CA_VOLUME("Analog Front Playback Volume",
569                   CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2),
570         CA_VOLUME("Analog Rear Playback Volume",
571                   CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2),
572         CA_VOLUME("Analog Center/LFE Playback Volume",
573                   CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2),
574         CA_VOLUME("Analog Side Playback Volume",
575                   CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2),
576 
577         CA_VOLUME("IEC958 Front Playback Volume",
578                   CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1),
579         CA_VOLUME("IEC958 Rear Playback Volume",
580                   CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1),
581         CA_VOLUME("IEC958 Center/LFE Playback Volume",
582                   CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1),
583         CA_VOLUME("IEC958 Unknown Playback Volume",
584                   CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1),
585 
586         CA_VOLUME("CAPTURE feedback Playback Volume",
587                   1, CAPTURE_CONTROL),
588 
589         {
590                 .access =       SNDRV_CTL_ELEM_ACCESS_READ,
591                 .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
592                 .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
593                 .count =        4,
594                 .info =         snd_ca0106_spdif_info,
595                 .get =          snd_ca0106_spdif_get_mask
596         },
597         {
598                 .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
599                 .name =         "IEC958 Playback Switch",
600                 .info =         snd_ca0106_shared_spdif_info,
601                 .get =          snd_ca0106_shared_spdif_get,
602                 .put =          snd_ca0106_shared_spdif_put
603         },
604         {
605                 .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
606                 .name =         "Digital Source Capture Enum",
607                 .info =         snd_ca0106_capture_source_info,
608                 .get =          snd_ca0106_capture_source_get,
609                 .put =          snd_ca0106_capture_source_put
610         },
611         {
612                 .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
613                 .name =         "Analog Source Capture Enum",
614                 .info =         snd_ca0106_i2c_capture_source_info,
615                 .get =          snd_ca0106_i2c_capture_source_get,
616                 .put =          snd_ca0106_i2c_capture_source_put
617         },
618         {
619                 .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
620                 .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
621                 .count =        4,
622                 .info =         snd_ca0106_spdif_info,
623                 .get =          snd_ca0106_spdif_get_default,
624                 .put =          snd_ca0106_spdif_put_default
625         },
626         {
627                 .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
628                 .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
629                 .count =        4,
630                 .info =         snd_ca0106_spdif_info,
631                 .get =          snd_ca0106_spdif_get_stream,
632                 .put =          snd_ca0106_spdif_put_stream
633         },
634 };
635 
636 #define I2C_VOLUME(xname,chid) \
637 {                                                               \
638         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,     \
639         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |             \
640                   SNDRV_CTL_ELEM_ACCESS_TLV_READ,               \
641         .info =  snd_ca0106_i2c_volume_info,                    \
642         .get =   snd_ca0106_i2c_volume_get,                     \
643         .put =   snd_ca0106_i2c_volume_put,                     \
644         .tlv = { .p = snd_ca0106_db_scale2 },                   \
645         .private_value = chid                                   \
646 }
647 
648 static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] = {
649         I2C_VOLUME("Phone Capture Volume", 0),
650         I2C_VOLUME("Mic Capture Volume", 1),
651         I2C_VOLUME("Line in Capture Volume", 2),
652         I2C_VOLUME("Aux Capture Volume", 3),
653 };
654 
655 static const int spi_dmute_reg[] = {
656         SPI_DMUTE0_REG,
657         SPI_DMUTE1_REG,
658         SPI_DMUTE2_REG,
659         0,
660         SPI_DMUTE4_REG,
661 };
662 static const int spi_dmute_bit[] = {
663         SPI_DMUTE0_BIT,
664         SPI_DMUTE1_BIT,
665         SPI_DMUTE2_BIT,
666         0,
667         SPI_DMUTE4_BIT,
668 };
669 
670 static struct snd_kcontrol_new
671 snd_ca0106_volume_spi_dac_ctl(struct snd_ca0106_details *details,
672                               int channel_id)
673 {
674         struct snd_kcontrol_new spi_switch = {0};
675         int reg, bit;
676         int dac_id;
677 
678         spi_switch.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
679         spi_switch.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
680         spi_switch.info = spi_mute_info;
681         spi_switch.get = spi_mute_get;
682         spi_switch.put = spi_mute_put;
683 
684         switch (channel_id) {
685         case PCM_FRONT_CHANNEL:
686                 spi_switch.name = "Analog Front Playback Switch";
687                 dac_id = (details->spi_dac & 0xf000) >> (4 * 3);
688                 break;
689         case PCM_REAR_CHANNEL:
690                 spi_switch.name = "Analog Rear Playback Switch";
691                 dac_id = (details->spi_dac & 0x0f00) >> (4 * 2);
692                 break;
693         case PCM_CENTER_LFE_CHANNEL:
694                 spi_switch.name = "Analog Center/LFE Playback Switch";
695                 dac_id = (details->spi_dac & 0x00f0) >> (4 * 1);
696                 break;
697         case PCM_UNKNOWN_CHANNEL:
698                 spi_switch.name = "Analog Side Playback Switch";
699                 dac_id = (details->spi_dac & 0x000f) >> (4 * 0);
700                 break;
701         default:
702                 /* Unused channel */
703                 spi_switch.name = NULL;
704                 dac_id = 0;
705         }
706         reg = spi_dmute_reg[dac_id];
707         bit = spi_dmute_bit[dac_id];
708 
709         spi_switch.private_value = (reg << SPI_REG_SHIFT) | bit;
710 
711         return spi_switch;
712 }
713 
714 static int remove_ctl(struct snd_card *card, const char *name)
715 {
716         struct snd_ctl_elem_id id;
717         memset(&id, 0, sizeof(id));
718         strcpy(id.name, name);
719         id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
720         return snd_ctl_remove_id(card, &id);
721 }
722 
723 static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
724 {
725         struct snd_ctl_elem_id sid;
726         memset(&sid, 0, sizeof(sid));
727         /* FIXME: strcpy is bad. */
728         strcpy(sid.name, name);
729         sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
730         return snd_ctl_find_id(card, &sid);
731 }
732 
733 static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
734 {
735         struct snd_kcontrol *kctl = ctl_find(card, src);
736         if (kctl) {
737                 strcpy(kctl->id.name, dst);
738                 return 0;
739         }
740         return -ENOENT;
741 }
742 
743 #define ADD_CTLS(emu, ctls)                                             \
744         do {                                                            \
745                 int i, _err;                                            \
746                 for (i = 0; i < ARRAY_SIZE(ctls); i++) {                \
747                         _err = snd_ctl_add(card, snd_ctl_new1(&ctls[i], emu)); \
748                         if (_err < 0)                                   \
749                                 return _err;                            \
750                 }                                                       \
751         } while (0)
752 
753 static
754 DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 25, 1);
755 
756 static char *slave_vols[] = {
757         "Analog Front Playback Volume",
758         "Analog Rear Playback Volume",
759         "Analog Center/LFE Playback Volume",
760         "Analog Side Playback Volume",
761         "IEC958 Front Playback Volume",
762         "IEC958 Rear Playback Volume",
763         "IEC958 Center/LFE Playback Volume",
764         "IEC958 Unknown Playback Volume",
765         "CAPTURE feedback Playback Volume",
766         NULL
767 };
768 
769 static char *slave_sws[] = {
770         "Analog Front Playback Switch",
771         "Analog Rear Playback Switch",
772         "Analog Center/LFE Playback Switch",
773         "Analog Side Playback Switch",
774         "IEC958 Playback Switch",
775         NULL
776 };
777 
778 static void add_slaves(struct snd_card *card,
779                                  struct snd_kcontrol *master, char **list)
780 {
781         for (; *list; list++) {
782                 struct snd_kcontrol *slave = ctl_find(card, *list);
783                 if (slave)
784                         snd_ctl_add_slave(master, slave);
785         }
786 }
787 
788 int snd_ca0106_mixer(struct snd_ca0106 *emu)
789 {
790         int err;
791         struct snd_card *card = emu->card;
792         char **c;
793         struct snd_kcontrol *vmaster;
794         static char *ca0106_remove_ctls[] = {
795                 "Master Mono Playback Switch",
796                 "Master Mono Playback Volume",
797                 "3D Control - Switch",
798                 "3D Control Sigmatel - Depth",
799                 "PCM Playback Switch",
800                 "PCM Playback Volume",
801                 "CD Playback Switch",
802                 "CD Playback Volume",
803                 "Phone Playback Switch",
804                 "Phone Playback Volume",
805                 "Video Playback Switch",
806                 "Video Playback Volume",
807                 "Beep Playback Switch",
808                 "Beep Playback Volume",
809                 "Mono Output Select",
810                 "Capture Source",
811                 "Capture Switch",
812                 "Capture Volume",
813                 "External Amplifier",
814                 "Sigmatel 4-Speaker Stereo Playback Switch",
815                 "Surround Phase Inversion Playback Switch",
816                 NULL
817         };
818         static char *ca0106_rename_ctls[] = {
819                 "Master Playback Switch", "Capture Switch",
820                 "Master Playback Volume", "Capture Volume",
821                 "Line Playback Switch", "AC97 Line Capture Switch",
822                 "Line Playback Volume", "AC97 Line Capture Volume",
823                 "Aux Playback Switch", "AC97 Aux Capture Switch",
824                 "Aux Playback Volume", "AC97 Aux Capture Volume",
825                 "Mic Playback Switch", "AC97 Mic Capture Switch",
826                 "Mic Playback Volume", "AC97 Mic Capture Volume",
827                 "Mic Select", "AC97 Mic Select",
828                 "Mic Boost (+20dB)", "AC97 Mic Boost (+20dB)",
829                 NULL
830         };
831 #if 1
832         for (c = ca0106_remove_ctls; *c; c++)
833                 remove_ctl(card, *c);
834         for (c = ca0106_rename_ctls; *c; c += 2)
835                 rename_ctl(card, c[0], c[1]);
836 #endif
837 
838         ADD_CTLS(emu, snd_ca0106_volume_ctls);
839         if (emu->details->i2c_adc == 1) {
840                 ADD_CTLS(emu, snd_ca0106_volume_i2c_adc_ctls);
841                 if (emu->details->gpio_type == 1)
842                         err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
843                 else  /* gpio_type == 2 */
844                         err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_line_in_side_out, emu));
845                 if (err < 0)
846                         return err;
847         }
848         if (emu->details->spi_dac) {
849                 int i;
850                 for (i = 0;; i++) {
851                         struct snd_kcontrol_new ctl;
852                         ctl = snd_ca0106_volume_spi_dac_ctl(emu->details, i);
853                         if (!ctl.name)
854                                 break;
855                         err = snd_ctl_add(card, snd_ctl_new1(&ctl, emu));
856                         if (err < 0)
857                                 return err;
858                 }
859         }
860 
861         /* Create virtual master controls */
862         vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
863                                               snd_ca0106_master_db_scale);
864         if (!vmaster)
865                 return -ENOMEM;
866         err = snd_ctl_add(card, vmaster);
867         if (err < 0)
868                 return err;
869         add_slaves(card, vmaster, slave_vols);
870 
871         if (emu->details->spi_dac) {
872                 vmaster = snd_ctl_make_virtual_master("Master Playback Switch",
873                                                       NULL);
874                 if (!vmaster)
875                         return -ENOMEM;
876                 err = snd_ctl_add(card, vmaster);
877                 if (err < 0)
878                         return err;
879                 add_slaves(card, vmaster, slave_sws);
880         }
881 
882         strcpy(card->mixername, "CA0106");
883         return 0;
884 }
885 
886 #ifdef CONFIG_PM_SLEEP
887 struct ca0106_vol_tbl {
888         unsigned int channel_id;
889         unsigned int reg;
890 };
891 
892 static struct ca0106_vol_tbl saved_volumes[NUM_SAVED_VOLUMES] = {
893         { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2 },
894         { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2 },
895         { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2 },
896         { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2 },
897         { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1 },
898         { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1 },
899         { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1 },
900         { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1 },
901         { 1, CAPTURE_CONTROL },
902 };
903 
904 void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip)
905 {
906         int i;
907 
908         /* save volumes */
909         for (i = 0; i < NUM_SAVED_VOLUMES; i++)
910                 chip->saved_vol[i] =
911                         snd_ca0106_ptr_read(chip, saved_volumes[i].reg,
912                                             saved_volumes[i].channel_id);
913 }
914 
915 void snd_ca0106_mixer_resume(struct snd_ca0106  *chip)
916 {
917         int i;
918 
919         for (i = 0; i < NUM_SAVED_VOLUMES; i++)
920                 snd_ca0106_ptr_write(chip, saved_volumes[i].reg,
921                                      saved_volumes[i].channel_id,
922                                      chip->saved_vol[i]);
923 
924         ca0106_spdif_enable(chip);
925         ca0106_set_capture_source(chip);
926         ca0106_set_i2c_capture_source(chip, chip->i2c_capture_source, 1);
927         for (i = 0; i < 4; i++)
928                 ca0106_set_spdif_bits(chip, i);
929         if (chip->details->i2c_adc)
930                 ca0106_set_capture_mic_line_in(chip);
931 }
932 #endif /* CONFIG_PM_SLEEP */
933 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp