]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/pci/ca0106/ca0106_mixer.c
a135b9c4c3c87ec2de0751cdac68310847fdc881
[linux-2.6-omap-h63xx.git] / sound / pci / ca0106 / ca0106_mixer.c
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.17
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  *
43  *  This code was initally based on code from ALSA's emu10k1x.c which is:
44  *  Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
45  *
46  *   This program is free software; you can redistribute it and/or modify
47  *   it under the terms of the GNU General Public License as published by
48  *   the Free Software Foundation; either version 2 of the License, or
49  *   (at your option) any later version.
50  *
51  *   This program is distributed in the hope that it will be useful,
52  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
53  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
54  *   GNU General Public License for more details.
55  *
56  *   You should have received a copy of the GNU General Public License
57  *   along with this program; if not, write to the Free Software
58  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
59  *
60  */
61 #include <sound/driver.h>
62 #include <linux/delay.h>
63 #include <linux/init.h>
64 #include <linux/interrupt.h>
65 #include <linux/slab.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 <asm/io.h>
74
75 #include "ca0106.h"
76
77 static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
78 static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
79
80 #define snd_ca0106_shared_spdif_info    snd_ctl_boolean_mono_info
81
82 static int snd_ca0106_shared_spdif_get(struct snd_kcontrol *kcontrol,
83                                         struct snd_ctl_elem_value *ucontrol)
84 {
85         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
86
87         ucontrol->value.enumerated.item[0] = emu->spdif_enable;
88         return 0;
89 }
90
91 static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol,
92                                         struct snd_ctl_elem_value *ucontrol)
93 {
94         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
95         unsigned int val;
96         int change = 0;
97         u32 mask;
98
99         val = ucontrol->value.enumerated.item[0] ;
100         change = (emu->spdif_enable != val);
101         if (change) {
102                 emu->spdif_enable = val;
103                 if (val == 1) {
104                         /* Digital */
105                         snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
106                         snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000);
107                         snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0,
108                                 snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000);
109                         mask = inl(emu->port + GPIO) & ~0x101;
110                         outl(mask, emu->port + GPIO);
111
112                 } else {
113                         /* Analog */
114                         snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
115                         snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000);
116                         snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0,
117                                 snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000);
118                         mask = inl(emu->port + GPIO) | 0x101;
119                         outl(mask, emu->port + GPIO);
120                 }
121         }
122         return change;
123 }
124
125 static int snd_ca0106_capture_source_info(struct snd_kcontrol *kcontrol,
126                                           struct snd_ctl_elem_info *uinfo)
127 {
128         static char *texts[6] = {
129                 "IEC958 out", "i2s mixer out", "IEC958 in", "i2s in", "AC97 in", "SRC out"
130         };
131
132         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
133         uinfo->count = 1;
134         uinfo->value.enumerated.items = 6;
135         if (uinfo->value.enumerated.item > 5)
136                 uinfo->value.enumerated.item = 5;
137         strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
138         return 0;
139 }
140
141 static int snd_ca0106_capture_source_get(struct snd_kcontrol *kcontrol,
142                                         struct snd_ctl_elem_value *ucontrol)
143 {
144         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
145
146         ucontrol->value.enumerated.item[0] = emu->capture_source;
147         return 0;
148 }
149
150 static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol,
151                                         struct snd_ctl_elem_value *ucontrol)
152 {
153         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
154         unsigned int val;
155         int change = 0;
156         u32 mask;
157         u32 source;
158
159         val = ucontrol->value.enumerated.item[0] ;
160         change = (emu->capture_source != val);
161         if (change) {
162                 emu->capture_source = val;
163                 source = (val << 28) | (val << 24) | (val << 20) | (val << 16);
164                 mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff;
165                 snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask);
166         }
167         return change;
168 }
169
170 static int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
171                                           struct snd_ctl_elem_info *uinfo)
172 {
173         static char *texts[6] = {
174                 "Phone", "Mic", "Line in", "Aux"
175         };
176
177         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
178         uinfo->count = 1;
179         uinfo->value.enumerated.items = 4;
180         if (uinfo->value.enumerated.item > 3)
181                 uinfo->value.enumerated.item = 3;
182         strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
183         return 0;
184 }
185
186 static int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
187                                         struct snd_ctl_elem_value *ucontrol)
188 {
189         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
190
191         ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
192         return 0;
193 }
194
195 static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
196                                         struct snd_ctl_elem_value *ucontrol)
197 {
198         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
199         unsigned int source_id;
200         unsigned int ngain, ogain;
201         int change = 0;
202         u32 source;
203         /* If the capture source has changed,
204          * update the capture volume from the cached value
205          * for the particular source.
206          */
207         source_id = ucontrol->value.enumerated.item[0] ;
208         change = (emu->i2c_capture_source != source_id);
209         if (change) {
210                 snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
211                 ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
212                 ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
213                 if (ngain != ogain)
214                         snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
215                 ngain = emu->i2c_capture_volume[source_id][1]; /* Left */
216                 ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */
217                 if (ngain != ogain)
218                         snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
219                 source = 1 << source_id;
220                 snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */
221                 emu->i2c_capture_source = source_id;
222         }
223         return change;
224 }
225
226 static int snd_ca0106_capture_line_in_side_out_info(struct snd_kcontrol *kcontrol,
227                                                struct snd_ctl_elem_info *uinfo)
228 {
229         static char *texts[2] = { "Side out", "Line in" };
230
231         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
232         uinfo->count = 1;
233         uinfo->value.enumerated.items = 2;
234         if (uinfo->value.enumerated.item > 1)
235                 uinfo->value.enumerated.item = 1;
236         strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
237         return 0;
238 }
239
240 static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol,
241                                                struct snd_ctl_elem_info *uinfo)
242 {
243         static char *texts[2] = { "Line in", "Mic in" };
244
245         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
246         uinfo->count = 1;
247         uinfo->value.enumerated.items = 2;
248         if (uinfo->value.enumerated.item > 1)
249                 uinfo->value.enumerated.item = 1;
250         strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
251         return 0;
252 }
253
254 static int snd_ca0106_capture_mic_line_in_get(struct snd_kcontrol *kcontrol,
255                                         struct snd_ctl_elem_value *ucontrol)
256 {
257         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
258
259         ucontrol->value.enumerated.item[0] = emu->capture_mic_line_in;
260         return 0;
261 }
262
263 static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol,
264                                         struct snd_ctl_elem_value *ucontrol)
265 {
266         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
267         unsigned int val;
268         int change = 0;
269         u32 tmp;
270
271         val = ucontrol->value.enumerated.item[0] ;
272         change = (emu->capture_mic_line_in != val);
273         if (change) {
274                 emu->capture_mic_line_in = val;
275                 if (val) {
276                         //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
277                         tmp = inl(emu->port+GPIO) & ~0x400;
278                         tmp = tmp | 0x400;
279                         outl(tmp, emu->port+GPIO);
280                         //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC);
281                 } else {
282                         //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
283                         tmp = inl(emu->port+GPIO) & ~0x400;
284                         outl(tmp, emu->port+GPIO);
285                         //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN);
286                 }
287         }
288         return change;
289 }
290
291 static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in __devinitdata =
292 {
293         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
294         .name =         "Shared Mic/Line in Capture Switch",
295         .info =         snd_ca0106_capture_mic_line_in_info,
296         .get =          snd_ca0106_capture_mic_line_in_get,
297         .put =          snd_ca0106_capture_mic_line_in_put
298 };
299
300 static struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out __devinitdata =
301 {
302         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
303         .name =         "Shared Line in/Side out Capture Switch",
304         .info =         snd_ca0106_capture_line_in_side_out_info,
305         .get =          snd_ca0106_capture_mic_line_in_get,
306         .put =          snd_ca0106_capture_mic_line_in_put
307 };
308
309
310 static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol,
311                                  struct snd_ctl_elem_info *uinfo)
312 {
313         uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
314         uinfo->count = 1;
315         return 0;
316 }
317
318 static int snd_ca0106_spdif_get(struct snd_kcontrol *kcontrol,
319                                  struct snd_ctl_elem_value *ucontrol)
320 {
321         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
322         unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
323
324         ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
325         ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
326         ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
327         ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
328         return 0;
329 }
330
331 static int snd_ca0106_spdif_get_mask(struct snd_kcontrol *kcontrol,
332                                       struct snd_ctl_elem_value *ucontrol)
333 {
334         ucontrol->value.iec958.status[0] = 0xff;
335         ucontrol->value.iec958.status[1] = 0xff;
336         ucontrol->value.iec958.status[2] = 0xff;
337         ucontrol->value.iec958.status[3] = 0xff;
338         return 0;
339 }
340
341 static int snd_ca0106_spdif_put(struct snd_kcontrol *kcontrol,
342                                  struct snd_ctl_elem_value *ucontrol)
343 {
344         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
345         unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
346         int change;
347         unsigned int val;
348
349         val = (ucontrol->value.iec958.status[0] << 0) |
350               (ucontrol->value.iec958.status[1] << 8) |
351               (ucontrol->value.iec958.status[2] << 16) |
352               (ucontrol->value.iec958.status[3] << 24);
353         change = val != emu->spdif_bits[idx];
354         if (change) {
355                 snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, val);
356                 emu->spdif_bits[idx] = val;
357         }
358         return change;
359 }
360
361 static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol,
362                                   struct snd_ctl_elem_info *uinfo)
363 {
364         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
365         uinfo->count = 2;
366         uinfo->value.integer.min = 0;
367         uinfo->value.integer.max = 255;
368         return 0;
369 }
370
371 static int snd_ca0106_volume_get(struct snd_kcontrol *kcontrol,
372                                  struct snd_ctl_elem_value *ucontrol)
373 {
374         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
375         unsigned int value;
376         int channel_id, reg;
377
378         channel_id = (kcontrol->private_value >> 8) & 0xff;
379         reg = kcontrol->private_value & 0xff;
380
381         value = snd_ca0106_ptr_read(emu, reg, channel_id);
382         ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */
383         ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */
384         return 0;
385 }
386
387 static int snd_ca0106_volume_put(struct snd_kcontrol *kcontrol,
388                                  struct snd_ctl_elem_value *ucontrol)
389 {
390         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
391         unsigned int oval, nval;
392         int channel_id, reg;
393
394         channel_id = (kcontrol->private_value >> 8) & 0xff;
395         reg = kcontrol->private_value & 0xff;
396
397         oval = snd_ca0106_ptr_read(emu, reg, channel_id);
398         nval = ((0xff - ucontrol->value.integer.value[0]) << 24) |
399                 ((0xff - ucontrol->value.integer.value[1]) << 16);
400         nval |= ((0xff - ucontrol->value.integer.value[0]) << 8) |
401                 ((0xff - ucontrol->value.integer.value[1]) );
402         if (oval == nval)
403                 return 0;
404         snd_ca0106_ptr_write(emu, reg, channel_id, nval);
405         return 1;
406 }
407
408 static int snd_ca0106_i2c_volume_info(struct snd_kcontrol *kcontrol,
409                                   struct snd_ctl_elem_info *uinfo)
410 {
411         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
412         uinfo->count = 2;
413         uinfo->value.integer.min = 0;
414         uinfo->value.integer.max = 255;
415         return 0;
416 }
417
418 static int snd_ca0106_i2c_volume_get(struct snd_kcontrol *kcontrol,
419                                  struct snd_ctl_elem_value *ucontrol)
420 {
421         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
422         int source_id;
423
424         source_id = kcontrol->private_value;
425
426         ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
427         ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
428         return 0;
429 }
430
431 static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
432                                  struct snd_ctl_elem_value *ucontrol)
433 {
434         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
435         unsigned int ogain;
436         unsigned int ngain;
437         int source_id;
438         int change = 0;
439
440         source_id = kcontrol->private_value;
441         ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
442         ngain = ucontrol->value.integer.value[0];
443         if (ngain > 0xff)
444                 return 0;
445         if (ogain != ngain) {
446                 if (emu->i2c_capture_source == source_id)
447                         snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
448                 emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0];
449                 change = 1;
450         }
451         ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
452         ngain = ucontrol->value.integer.value[1];
453         if (ngain > 0xff)
454                 return 0;
455         if (ogain != ngain) {
456                 if (emu->i2c_capture_source == source_id)
457                         snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
458                 emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1];
459                 change = 1;
460         }
461
462         return change;
463 }
464
465 #define CA_VOLUME(xname,chid,reg) \
466 {                                                               \
467         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,     \
468         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |             \
469                   SNDRV_CTL_ELEM_ACCESS_TLV_READ,               \
470         .info =  snd_ca0106_volume_info,                        \
471         .get =   snd_ca0106_volume_get,                         \
472         .put =   snd_ca0106_volume_put,                         \
473         .tlv = { .p = snd_ca0106_db_scale1 },                   \
474         .private_value = ((chid) << 8) | (reg)                  \
475 }
476
477 static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
478         CA_VOLUME("Analog Front Playback Volume",
479                   CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2),
480         CA_VOLUME("Analog Rear Playback Volume",
481                   CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2),
482         CA_VOLUME("Analog Center/LFE Playback Volume",
483                   CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2),
484         CA_VOLUME("Analog Side Playback Volume",
485                   CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2),
486
487         CA_VOLUME("IEC958 Front Playback Volume",
488                   CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1),
489         CA_VOLUME("IEC958 Rear Playback Volume",
490                   CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1),
491         CA_VOLUME("IEC958 Center/LFE Playback Volume",
492                   CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1),
493         CA_VOLUME("IEC958 Unknown Playback Volume",
494                   CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1),
495
496         CA_VOLUME("CAPTURE feedback Playback Volume",
497                   1, CAPTURE_CONTROL),
498
499         {
500                 .access =       SNDRV_CTL_ELEM_ACCESS_READ,
501                 .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
502                 .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
503                 .count =        4,
504                 .info =         snd_ca0106_spdif_info,
505                 .get =          snd_ca0106_spdif_get_mask
506         },
507         {
508                 .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
509                 .name =         "IEC958 Playback Switch",
510                 .info =         snd_ca0106_shared_spdif_info,
511                 .get =          snd_ca0106_shared_spdif_get,
512                 .put =          snd_ca0106_shared_spdif_put
513         },
514         {
515                 .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
516                 .name =         "Digital Source Capture Enum",
517                 .info =         snd_ca0106_capture_source_info,
518                 .get =          snd_ca0106_capture_source_get,
519                 .put =          snd_ca0106_capture_source_put
520         },
521         {
522                 .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
523                 .name =         "Analog Source Capture Enum",
524                 .info =         snd_ca0106_i2c_capture_source_info,
525                 .get =          snd_ca0106_i2c_capture_source_get,
526                 .put =          snd_ca0106_i2c_capture_source_put
527         },
528         {
529                 .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
530                 .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
531                 .count =        4,
532                 .info =         snd_ca0106_spdif_info,
533                 .get =          snd_ca0106_spdif_get,
534                 .put =          snd_ca0106_spdif_put
535         },
536 };
537
538 #define I2C_VOLUME(xname,chid) \
539 {                                                               \
540         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,     \
541         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |             \
542                   SNDRV_CTL_ELEM_ACCESS_TLV_READ,               \
543         .info =  snd_ca0106_i2c_volume_info,                    \
544         .get =   snd_ca0106_i2c_volume_get,                     \
545         .put =   snd_ca0106_i2c_volume_put,                     \
546         .tlv = { .p = snd_ca0106_db_scale2 },                   \
547         .private_value = chid                                   \
548 }
549
550 static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = {
551         I2C_VOLUME("Phone Capture Volume", 0),
552         I2C_VOLUME("Mic Capture Volume", 1),
553         I2C_VOLUME("Line in Capture Volume", 2),
554         I2C_VOLUME("Aux Capture Volume", 3),
555 };
556
557 static int __devinit remove_ctl(struct snd_card *card, const char *name)
558 {
559         struct snd_ctl_elem_id id;
560         memset(&id, 0, sizeof(id));
561         strcpy(id.name, name);
562         id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
563         return snd_ctl_remove_id(card, &id);
564 }
565
566 static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, const char *name)
567 {
568         struct snd_ctl_elem_id sid;
569         memset(&sid, 0, sizeof(sid));
570         /* FIXME: strcpy is bad. */
571         strcpy(sid.name, name);
572         sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
573         return snd_ctl_find_id(card, &sid);
574 }
575
576 static int __devinit rename_ctl(struct snd_card *card, const char *src, const char *dst)
577 {
578         struct snd_kcontrol *kctl = ctl_find(card, src);
579         if (kctl) {
580                 strcpy(kctl->id.name, dst);
581                 return 0;
582         }
583         return -ENOENT;
584 }
585
586 int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
587 {
588         int i, err;
589         struct snd_card *card = emu->card;
590         char **c;
591         static char *ca0106_remove_ctls[] = {
592                 "Master Mono Playback Switch",
593                 "Master Mono Playback Volume",
594                 "3D Control - Switch",
595                 "3D Control Sigmatel - Depth",
596                 "PCM Playback Switch",
597                 "PCM Playback Volume",
598                 "CD Playback Switch",
599                 "CD Playback Volume",
600                 "Phone Playback Switch",
601                 "Phone Playback Volume",
602                 "Video Playback Switch",
603                 "Video Playback Volume",
604                 "PC Speaker Playback Switch",
605                 "PC Speaker Playback Volume",
606                 "Mono Output Select",
607                 "Capture Source",
608                 "Capture Switch",
609                 "Capture Volume",
610                 "External Amplifier",
611                 "Sigmatel 4-Speaker Stereo Playback Switch",
612                 "Sigmatel Surround Phase Inversion Playback ",
613                 NULL
614         };
615         static char *ca0106_rename_ctls[] = {
616                 "Master Playback Switch", "Capture Switch",
617                 "Master Playback Volume", "Capture Volume",
618                 "Line Playback Switch", "AC97 Line Capture Switch",
619                 "Line Playback Volume", "AC97 Line Capture Volume",
620                 "Aux Playback Switch", "AC97 Aux Capture Switch",
621                 "Aux Playback Volume", "AC97 Aux Capture Volume",
622                 "Mic Playback Switch", "AC97 Mic Capture Switch",
623                 "Mic Playback Volume", "AC97 Mic Capture Volume",
624                 "Mic Select", "AC97 Mic Select",
625                 "Mic Boost (+20dB)", "AC97 Mic Boost (+20dB)",
626                 NULL
627         };
628 #if 1
629         for (c = ca0106_remove_ctls; *c; c++)
630                 remove_ctl(card, *c);
631         for (c = ca0106_rename_ctls; *c; c += 2)
632                 rename_ctl(card, c[0], c[1]);
633 #endif
634
635         for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_ctls); i++) {
636                 err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_ctls[i], emu));
637                 if (err < 0)
638                         return err;
639         }
640         if (emu->details->i2c_adc == 1) {
641                 for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_i2c_adc_ctls); i++) {
642                         err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_i2c_adc_ctls[i], emu));
643                         if (err < 0)
644                                 return err;
645                 }
646                 if (emu->details->gpio_type == 1)
647                         err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
648                 else  /* gpio_type == 2 */
649                         err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_line_in_side_out, emu));
650                 if (err < 0)
651                         return err;
652         }
653         return 0;
654 }
655