]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/arm/omap/omap-alsa-aic23-mixer.c
Merge current mainline tree into linux-omap tree
[linux-2.6-omap-h63xx.git] / sound / arm / omap / omap-alsa-aic23-mixer.c
1 /*
2  * sound/arm/omap/omap-alsa-aic23-mixer.c
3  *
4  * Alsa Driver Mixer for generic codecs for omap boards
5  *
6  * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
7  * Written by David Cohen, Daniel Petrini
8  *            {david.cohen, daniel.petrini}@indt.org.br
9  *
10  * Based on es1688_lib.c,
11  * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
12  *
13  * This program is free software; you can redistribute it and/or modify it
14  * under the terms of the GNU General Public License as published by the
15  * Free Software Foundation; either version 2 of the License, or (at your
16  * option) any later version.
17  *
18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
21  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * You should have received a copy of the  GNU General Public License along
30  * with this program; if not, write  to the Free Software Foundation, Inc.,
31  * 675 Mass Ave, Cambridge, MA 02139, USA.
32  *
33  * History:
34  *
35  * 2005-08-02   INdT Kernel Team - Alsa mixer driver for omap osk.
36  *                              Creation of new file omap-alsa-mixer.c.
37  *                              Initial version with aic23 codec for osk5912
38  */
39
40 #include <linux/kernel.h>
41
42 #include <mach/aic23.h>
43
44 #include <mach/omap-alsa.h>
45 #include "omap-alsa-aic23.h"
46 #include <sound/initval.h>
47 #include <sound/control.h>
48
49 MODULE_AUTHOR("David Cohen");
50 MODULE_AUTHOR("Daniel Petrini");
51
52 MODULE_LICENSE("GPL");
53 MODULE_DESCRIPTION("OMAP Alsa mixer driver for ALSA");
54
55 /*
56  * Codec dependent region
57  */
58
59 /* Codec AIC23 */
60 #if defined(CONFIG_SENSORS_TLV320AIC23) || \
61         defined(CONFIG_SENSORS_TLV320AIC23_MODULE)
62
63 #define MIXER_NAME                   "Mixer AIC23"
64 #define SND_OMAP_WRITE(reg, val)     audio_aic23_write(reg, val)
65
66 #endif
67
68 /* Callback Functions */
69 #define OMAP_BOOL(xname, xindex, reg, reg_index, mask, invert) \
70 { \
71         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
72         .name = xname, \
73         .index = xindex, \
74         .info = snd_omap_info_bool, \
75         .get = snd_omap_get_bool, \
76         .put = snd_omap_put_bool, \
77         .private_value = reg | (reg_index << 8) | (invert << 10) | \
78                                 (mask << 12) \
79 }
80
81 #define OMAP_MUX(xname, reg, reg_index, mask) \
82 { \
83         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
84         .name = xname, \
85         .info = snd_omap_info_mux, \
86         .get = snd_omap_get_mux, \
87         .put = snd_omap_put_mux, \
88         .private_value = reg | (reg_index << 8) | (mask << 10) \
89 }
90
91 #define OMAP_SINGLE(xname, xindex, reg, reg_index, reg_val, mask) \
92 {\
93         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
94         .name = xname, \
95         .index = xindex, \
96         .info = snd_omap_info_single, \
97         .get = snd_omap_get_single, \
98         .put = snd_omap_put_single, \
99         .private_value = reg | (reg_val << 8) | (reg_index << 16) |\
100                                 (mask << 18) \
101 }
102
103 #define OMAP_DOUBLE(xname, xindex, left_reg, right_reg, reg_index, mask) \
104 {\
105         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
106         .name = xname, \
107         .index = xindex, \
108         .info = snd_omap_info_double, \
109         .get = snd_omap_get_double, \
110         .put = snd_omap_put_double, \
111         .private_value = left_reg | (right_reg << 8) | (reg_index << 16) | \
112                                 (mask << 18) \
113 }
114
115 /* Local Registers */
116 enum snd_device_index {
117         PCM_INDEX = 0,
118         LINE_INDEX,
119         AAC_INDEX, /* Analog Audio Control: reg = l_reg */
120 };
121
122 struct {
123         u16 l_reg;
124         u16 r_reg;
125         u8 sw;
126 } omap_regs[3];
127
128 #ifdef CONFIG_PM
129 struct {
130         u16 l_reg;
131         u16 r_reg;
132         u8 sw;
133 } omap_pm_regs[3];
134 #endif
135
136 u16 snd_sidetone[6] = {
137         SIDETONE_18,
138         SIDETONE_12,
139         SIDETONE_9,
140         SIDETONE_6,
141         SIDETONE_0,
142         0
143 };
144
145 /* Begin Bool Functions */
146
147 static int snd_omap_info_bool(struct snd_kcontrol *kcontrol,
148                                 struct snd_ctl_elem_info *uinfo)
149 {
150         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
151         uinfo->count = 1;
152         uinfo->value.integer.min = 0;
153         uinfo->value.integer.max = 1;
154
155         return 0;
156 }
157
158 static int snd_omap_get_bool(struct snd_kcontrol *kcontrol,
159                                 struct snd_ctl_elem_value *ucontrol)
160 {
161         int mic_index = (kcontrol->private_value >> 8) & 0x03;
162         u16 mask = (kcontrol->private_value >> 12) & 0xff;
163         int invert = (kcontrol->private_value >> 10) & 0x03;
164
165         if (invert)
166                 ucontrol->value.integer.value[0] =
167                         (omap_regs[mic_index].l_reg & mask) ? 0 : 1;
168         else
169                 ucontrol->value.integer.value[0] =
170                         (omap_regs[mic_index].l_reg & mask) ? 1 : 0;
171
172         return 0;
173 }
174
175 static int snd_omap_put_bool(struct snd_kcontrol *kcontrol,
176                                 struct snd_ctl_elem_value *ucontrol)
177 {
178         int mic_index = (kcontrol->private_value >> 8) & 0x03;
179         u16 mask = (kcontrol->private_value >> 12) & 0xff;
180         u16 reg = kcontrol->private_value & 0xff;
181         int invert = (kcontrol->private_value >> 10) & 0x03;
182
183         int changed = 1;
184
185         if (ucontrol->value.integer.value[0]) /* XOR */
186                 if (invert)
187                         omap_regs[mic_index].l_reg &= ~mask;
188                 else
189                         omap_regs[mic_index].l_reg |= mask;
190         else
191                 if (invert)
192                         omap_regs[mic_index].l_reg |= mask;
193                 else
194                         omap_regs[mic_index].l_reg &= ~mask;
195
196         SND_OMAP_WRITE(reg, omap_regs[mic_index].l_reg);
197
198         return changed;
199 }
200
201 /* End Bool Functions */
202
203 /* Begin Mux Functions */
204
205 static int snd_omap_info_mux(struct snd_kcontrol *kcontrol,
206                                 struct snd_ctl_elem_info *uinfo)
207 {
208         /* Mic = 0
209          * Line = 1 */
210         static char *texts[2] = { "Mic", "Line" };
211
212         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
213         uinfo->count = 1;
214         uinfo->value.enumerated.items = 2;
215
216         if (uinfo->value.enumerated.item > 1)
217                 uinfo->value.enumerated.item = 1;
218
219         strcpy(uinfo->value.enumerated.name,
220                         texts[uinfo->value.enumerated.item]);
221
222         return 0;
223 }
224
225 static int snd_omap_get_mux(struct snd_kcontrol *kcontrol,
226                                 struct snd_ctl_elem_value *ucontrol)
227 {
228         u16 mask = (kcontrol->private_value >> 10) & 0xff;
229         int mux_idx = (kcontrol->private_value >> 8) & 0x03;
230
231         ucontrol->value.enumerated.item[0] =
232                 (omap_regs[mux_idx].l_reg & mask) ? 0 /* Mic */ : 1 /* Line */;
233
234         return 0;
235 }
236
237 static int snd_omap_put_mux(struct snd_kcontrol *kcontrol,
238                                 struct snd_ctl_elem_value *ucontrol)
239 {
240         u16 reg = kcontrol->private_value & 0xff;
241         u16 mask = (kcontrol->private_value >> 10) & 0xff;
242         int mux_index = (kcontrol->private_value >> 8) & 0x03;
243
244         int changed = 1;
245
246         if (!ucontrol->value.integer.value[0])
247                 omap_regs[mux_index].l_reg |= mask; /* AIC23: Mic */
248         else
249                 omap_regs[mux_index].l_reg &= ~mask; /* AIC23: Line */
250
251         SND_OMAP_WRITE(reg, omap_regs[mux_index].l_reg);
252
253         return changed;
254 }
255
256 /* End Mux Functions */
257
258 /* Begin Single Functions */
259
260 static int snd_omap_info_single(struct snd_kcontrol *kcontrol,
261                                 struct snd_ctl_elem_info *uinfo)
262 {
263         int mask = (kcontrol->private_value >> 18) & 0xff;
264         int reg_val = (kcontrol->private_value >> 8) & 0xff;
265
266         uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER :
267                         SNDRV_CTL_ELEM_TYPE_BOOLEAN;
268         uinfo->count = 1;
269         uinfo->value.integer.min = 0;
270         uinfo->value.integer.max = reg_val-1;
271
272         return 0;
273 }
274
275 static int snd_omap_get_single(struct snd_kcontrol *kcontrol,
276                                 struct snd_ctl_elem_value *ucontrol)
277 {
278         u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
279
280         ucontrol->value.integer.value[0] = snd_sidetone[reg_val];
281
282         return 0;
283 }
284
285 static int snd_omap_put_single(struct snd_kcontrol *kcontrol,
286                                 struct snd_ctl_elem_value *ucontrol)
287 {
288         u16 reg_index = (kcontrol->private_value >> 16) & 0x03;
289         u16 mask = (kcontrol->private_value >> 18) & 0x1ff;
290         u16 reg = kcontrol->private_value & 0xff;
291         u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
292
293         int changed = 0;
294
295         /* Volume */
296         if ((omap_regs[reg_index].l_reg !=
297                  (ucontrol->value.integer.value[0] & mask))) {
298                 changed = 1;
299
300                 omap_regs[reg_index].l_reg &= ~mask;
301                 omap_regs[reg_index].l_reg |=
302                         snd_sidetone[ucontrol->value.integer.value[0]];
303
304                 snd_sidetone[reg_val] = ucontrol->value.integer.value[0];
305                 SND_OMAP_WRITE(reg, omap_regs[reg_index].l_reg);
306         } else {
307                 changed = 0;
308         }
309
310         return changed;
311 }
312
313 /* End Single Functions */
314
315 /* Begin Double Functions */
316
317 static int snd_omap_info_double(struct snd_kcontrol *kcontrol,
318                                 struct snd_ctl_elem_info *uinfo)
319 {
320         /*
321          * mask == 0 : Switch
322          * mask != 0 : Volume
323          */
324         int mask = (kcontrol->private_value >> 18) & 0xff;
325
326         uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER :
327                         SNDRV_CTL_ELEM_TYPE_BOOLEAN;
328         uinfo->count = mask ? 2 : 1;
329         uinfo->value.integer.min = 0;
330         uinfo->value.integer.max = mask ? mask : 1;
331
332         return 0;
333 }
334
335 static int snd_omap_get_double(struct snd_kcontrol *kcontrol,
336                                 struct snd_ctl_elem_value *ucontrol)
337 {
338         /*
339          * mask == 0 : Switch
340          * mask != 0 : Volume
341          */
342         int mask = (kcontrol->private_value >> 18) & 0xff;
343         int vol_index = (kcontrol->private_value >> 16) & 0x03;
344
345         if (!mask) {
346                 /* Switch */
347                 ucontrol->value.integer.value[0] = omap_regs[vol_index].sw;
348         } else {
349                 /* Volume */
350                 ucontrol->value.integer.value[0] = omap_regs[vol_index].l_reg;
351                 ucontrol->value.integer.value[1] = omap_regs[vol_index].r_reg;
352         }
353
354         return 0;
355 }
356
357 static int snd_omap_put_double(struct snd_kcontrol *kcontrol,
358                                 struct snd_ctl_elem_value *ucontrol)
359 {
360         /* mask == 0 : Switch
361          * mask != 0 : Volume */
362         int vol_index = (kcontrol->private_value >> 16) & 0x03;
363         int mask = (kcontrol->private_value >> 18) & 0xff;
364         int left_reg = kcontrol->private_value & 0xff;
365         int right_reg = (kcontrol->private_value >> 8) & 0xff;
366
367         int changed = 0;
368
369         if (!mask) {
370                 /* Switch */
371                 if (!ucontrol->value.integer.value[0]) {
372                         SND_OMAP_WRITE(left_reg, 0x00);
373                         SND_OMAP_WRITE(right_reg, 0x00);
374                 } else {
375                         SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
376                         SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
377                 }
378                 changed = 1;
379                 omap_regs[vol_index].sw = ucontrol->value.integer.value[0];
380         } else {
381                 /* Volume */
382                 if ((omap_regs[vol_index].l_reg !=
383                                 (ucontrol->value.integer.value[0] & mask)) ||
384                         (omap_regs[vol_index].r_reg !=
385                                 (ucontrol->value.integer.value[1] & mask))) {
386                         changed = 1;
387
388                         omap_regs[vol_index].l_reg &= ~mask;
389                         omap_regs[vol_index].r_reg &= ~mask;
390                         omap_regs[vol_index].l_reg |=
391                                 (ucontrol->value.integer.value[0] & mask);
392                         omap_regs[vol_index].r_reg |=
393                                 (ucontrol->value.integer.value[1] & mask);
394                         if (omap_regs[vol_index].sw) {
395                                 /* write to registers only if sw is actived */
396                                 SND_OMAP_WRITE(left_reg,
397                                                 omap_regs[vol_index].l_reg);
398                                 SND_OMAP_WRITE(right_reg,
399                                                 omap_regs[vol_index].r_reg);
400                         }
401                 } else {
402                         changed = 0;
403                 }
404         }
405
406         return changed;
407 }
408
409 /* End Double Functions */
410
411 static struct snd_kcontrol_new snd_omap_controls[] = {
412         OMAP_DOUBLE("PCM Playback Switch", 0, LEFT_CHANNEL_VOLUME_ADDR,
413                         RIGHT_CHANNEL_VOLUME_ADDR, PCM_INDEX, 0x00),
414         OMAP_DOUBLE("PCM Playback Volume", 0, LEFT_CHANNEL_VOLUME_ADDR,
415                         RIGHT_CHANNEL_VOLUME_ADDR, PCM_INDEX,
416                         OUTPUT_VOLUME_MASK),
417         OMAP_BOOL("Line Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
418                         AAC_INDEX, BYPASS_ON, 0),
419         OMAP_DOUBLE("Line Capture Switch", 0, LEFT_LINE_VOLUME_ADDR,
420                         RIGHT_LINE_VOLUME_ADDR, LINE_INDEX, 0x00),
421         OMAP_DOUBLE("Line Capture Volume", 0, LEFT_LINE_VOLUME_ADDR,
422                         RIGHT_LINE_VOLUME_ADDR, LINE_INDEX, INPUT_VOLUME_MASK),
423         OMAP_BOOL("Mic Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
424                         AAC_INDEX, STE_ENABLED, 0),
425         OMAP_SINGLE("Mic Playback Volume", 0, ANALOG_AUDIO_CONTROL_ADDR,
426                         AAC_INDEX, 5, SIDETONE_MASK),
427         OMAP_BOOL("Mic Capture Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
428                         AAC_INDEX, MICM_MUTED, 1),
429         OMAP_BOOL("Mic Booster Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
430                         AAC_INDEX, MICB_20DB, 0),
431         OMAP_MUX("Capture Source", ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX,
432                         INSEL_MIC),
433 };
434
435 #ifdef CONFIG_PM
436
437 void snd_omap_suspend_mixer(void)
438 {
439         /* Saves current values to wake-up correctly */
440         omap_pm_regs[LINE_INDEX].l_reg = omap_regs[LINE_INDEX].l_reg;
441         omap_pm_regs[LINE_INDEX].r_reg = omap_regs[LINE_INDEX].l_reg;
442         omap_pm_regs[LINE_INDEX].sw = omap_regs[LINE_INDEX].sw;
443
444         omap_pm_regs[AAC_INDEX].l_reg = omap_regs[AAC_INDEX].l_reg;
445
446         omap_pm_regs[PCM_INDEX].l_reg = omap_regs[PCM_INDEX].l_reg;
447         omap_pm_regs[PCM_INDEX].r_reg = omap_regs[PCM_INDEX].r_reg;
448         omap_pm_regs[PCM_INDEX].sw = omap_regs[PCM_INDEX].sw;
449 }
450
451 void snd_omap_resume_mixer(void)
452 {
453         /* Line's saved values */
454         omap_regs[LINE_INDEX].l_reg = omap_pm_regs[LINE_INDEX].l_reg;
455         omap_regs[LINE_INDEX].r_reg = omap_pm_regs[LINE_INDEX].l_reg;
456         omap_regs[LINE_INDEX].sw = omap_pm_regs[LINE_INDEX].sw;
457         SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
458         SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
459
460         /* Analog Audio Control's saved values */
461         omap_regs[AAC_INDEX].l_reg = omap_pm_regs[AAC_INDEX].l_reg;
462         SND_OMAP_WRITE(ANALOG_AUDIO_CONTROL_ADDR, omap_regs[AAC_INDEX].l_reg);
463
464         /* Headphone's saved values */
465         omap_regs[PCM_INDEX].l_reg = omap_pm_regs[PCM_INDEX].l_reg;
466         omap_regs[PCM_INDEX].r_reg = omap_pm_regs[PCM_INDEX].r_reg;
467         omap_regs[PCM_INDEX].sw = omap_pm_regs[PCM_INDEX].sw;
468         SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR,
469                         omap_pm_regs[PCM_INDEX].l_reg);
470         SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR,
471                         omap_pm_regs[PCM_INDEX].r_reg);
472 }
473 #endif
474
475 void snd_omap_init_mixer(void)
476 {
477         u16 vol_reg;
478
479         /* Line's default values */
480         omap_regs[LINE_INDEX].l_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
481         omap_regs[LINE_INDEX].r_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
482         omap_regs[LINE_INDEX].sw = 0;
483         SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR,
484                         DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
485         SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR,
486                         DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
487
488         /* Analog Audio Control's default values */
489         omap_regs[AAC_INDEX].l_reg = DEFAULT_ANALOG_AUDIO_CONTROL;
490
491         /* Headphone's default values */
492         vol_reg = LZC_ON;
493         vol_reg &= ~OUTPUT_VOLUME_MASK;
494         vol_reg |= DEFAULT_OUTPUT_VOLUME;
495         omap_regs[PCM_INDEX].l_reg = DEFAULT_OUTPUT_VOLUME;
496         omap_regs[PCM_INDEX].r_reg = DEFAULT_OUTPUT_VOLUME;
497         omap_regs[PCM_INDEX].sw = 1;
498         SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR, vol_reg);
499         SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR, vol_reg);
500 }
501
502 int snd_omap_mixer(struct snd_card_omap_codec *chip)
503 {
504         struct snd_card *card;
505         unsigned int idx;
506         int err;
507
508         snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
509
510         card = chip->card;
511
512         strcpy(card->mixername, MIXER_NAME);
513
514         /* Registering alsa mixer controls */
515         for (idx = 0; idx < ARRAY_SIZE(snd_omap_controls); idx++) {
516                 err = snd_ctl_add(card,
517                         snd_ctl_new1(&snd_omap_controls[idx], chip));
518                 if (err < 0)
519                         return err;
520         }
521
522         return 0;
523 }