]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/arm/omap/omap-alsa-aic23-mixer.c
[PATCH] ARM: OMAP: Alsa modularisations and support for tsc2101 2/3 (round 2)
[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. Creation of new 
36  *                                 file omap-alsa-mixer.c. Initial version
37  *                                 with aic23 codec for osk5912
38  */
39
40 #include <linux/config.h>
41 #include <sound/driver.h>
42 #include <asm/arch/aic23.h>
43
44 #include <asm/arch/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, Daniel Petrini - INdT");
50 MODULE_LICENSE("GPL");
51 MODULE_DESCRIPTION("OMAP Alsa mixer driver for ALSA");
52
53 /*
54  * Codec dependent region
55  */
56
57 /* Codec AIC23 */
58 #if defined(CONFIG_SENSORS_TLV320AIC23) || defined (CONFIG_SENSORS_TLV320AIC23_MODULE)
59
60 extern void audio_aic23_write(u8, u16);
61
62 #define MIXER_NAME                   "Mixer AIC23"
63 #define SND_OMAP_WRITE(reg, val)     audio_aic23_write(reg, val)
64
65 #endif
66
67 /* Callback Functions */
68 #define OMAP_BOOL(xname, xindex, reg, reg_index, mask, invert) \
69 { \
70         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
71         .name = xname, \
72         .index = xindex, \
73         .info = snd_omap_info_bool, \
74         .get = snd_omap_get_bool, \
75         .put = snd_omap_put_bool, \
76         .private_value = reg | (reg_index << 8) | (invert << 10) | (mask << 12) \
77 }
78
79 #define OMAP_MUX(xname, reg, reg_index, mask) \
80 { \
81         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
82         .name = xname, \
83         .info = snd_omap_info_mux, \
84         .get = snd_omap_get_mux, \
85         .put = snd_omap_put_mux, \
86         .private_value = reg | (reg_index << 8) | (mask << 10) \
87 }
88
89 #define OMAP_SINGLE(xname, xindex, reg, reg_index, reg_val, mask) \
90 {\
91         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
92         .name = xname, \
93         .index = xindex, \
94         .info = snd_omap_info_single, \
95         .get = snd_omap_get_single, \
96         .put = snd_omap_put_single, \
97         .private_value = reg | (reg_val << 8) | (reg_index << 16) | (mask << 18) \
98 }
99
100 #define OMAP_DOUBLE(xname, xindex, left_reg, right_reg, reg_index, mask) \
101 {\
102         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
103         .name = xname, \
104         .index = xindex, \
105         .info = snd_omap_info_double, \
106         .get = snd_omap_get_double, \
107         .put = snd_omap_put_double, \
108         .private_value = left_reg | (right_reg << 8) | (reg_index << 16) | (mask << 18) \
109 }
110
111 /* Local Registers */
112 enum snd_device_index {
113         PCM_INDEX = 0,
114         LINE_INDEX,
115         AAC_INDEX, /* Analog Audio Control: reg = l_reg */
116 };
117
118 struct {
119         u16 l_reg;
120         u16 r_reg;
121         u8 sw;
122 } omap_regs[3];
123
124 #ifdef CONFIG_PM
125 struct {
126         u16 l_reg;
127         u16 r_reg;
128         u8 sw;
129 } omap_pm_regs[3];
130 #endif
131
132 u16 snd_sidetone[6] = {
133         SIDETONE_18,
134         SIDETONE_12,
135         SIDETONE_9,
136         SIDETONE_6,
137         SIDETONE_0,
138         0
139 };
140
141 /* Begin Bool Functions */
142
143 static int snd_omap_info_bool(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
144 {
145         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
146         uinfo->count = 1;
147         uinfo->value.integer.min = 0;
148         uinfo->value.integer.max = 1;
149         
150         return 0;
151 }
152
153 static int snd_omap_get_bool(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
154 {
155         int mic_index = (kcontrol->private_value >> 8) & 0x03;
156         u16 mask = (kcontrol->private_value >> 12) & 0xff;
157         int invert = (kcontrol->private_value >> 10) & 0x03;
158         
159         if (invert)
160                 ucontrol->value.integer.value[0] = (omap_regs[mic_index].l_reg & mask) ? 0 : 1;
161         else
162                 ucontrol->value.integer.value[0] = (omap_regs[mic_index].l_reg & mask) ? 1 : 0;
163         
164         return 0;
165 }
166
167 static int snd_omap_put_bool(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
168 {
169         int mic_index = (kcontrol->private_value >> 8) & 0x03;
170         u16 mask = (kcontrol->private_value >> 12) & 0xff;
171         u16 reg = kcontrol->private_value & 0xff;
172         int invert = (kcontrol->private_value >> 10) & 0x03;
173         
174         int changed = 1;
175
176         if (ucontrol->value.integer.value[0]) /* XOR */
177                 if (invert)
178                         omap_regs[mic_index].l_reg &= ~mask;
179                 else
180                         omap_regs[mic_index].l_reg |= mask;
181         else
182                 if (invert)
183                         omap_regs[mic_index].l_reg |= mask;
184                 else
185                         omap_regs[mic_index].l_reg &= ~mask;
186                 
187         SND_OMAP_WRITE(reg, omap_regs[mic_index].l_reg);
188         
189         return changed;
190 }
191
192 /* End Bool Functions */
193
194 /* Begin Mux Functions */
195
196 static int snd_omap_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
197 {
198         /* Mic = 0
199          * Line = 1 */
200         static char *texts[2] = { "Mic", "Line" };
201
202         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
203         uinfo->count = 1;
204         uinfo->value.enumerated.items = 2;
205         
206         if (uinfo->value.enumerated.item > 1)
207                 uinfo->value.enumerated.item = 1;
208         
209         strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
210         
211         return 0;
212 }
213
214 static int snd_omap_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
215 {
216         u16 mask = (kcontrol->private_value >> 10) & 0xff;
217         int mux_index = (kcontrol->private_value >> 8) & 0x03;
218
219         ucontrol->value.enumerated.item[0] = (omap_regs[mux_index].l_reg & mask) ? 0 /* Mic */ : 1 /* Line */;
220         
221         return 0;
222 }
223
224 static int snd_omap_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
225 {
226         u16 reg = kcontrol->private_value & 0xff;
227         u16 mask = (kcontrol->private_value >> 10) & 0xff;
228         int mux_index = (kcontrol->private_value >> 8) & 0x03;
229         
230         int changed = 1;
231
232         if (!ucontrol->value.integer.value[0])
233                 omap_regs[mux_index].l_reg |= mask; /* AIC23: Mic */
234         else
235                 omap_regs[mux_index].l_reg &= ~mask; /* AIC23: Line */
236         
237         SND_OMAP_WRITE(reg, omap_regs[mux_index].l_reg);
238         
239         return changed;
240 }
241
242 /* End Mux Functions */
243
244 /* Begin Single Functions */
245
246 static int snd_omap_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
247 {
248         int mask = (kcontrol->private_value >> 18) & 0xff;
249         int reg_val = (kcontrol->private_value >> 8) & 0xff;
250         
251         uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER : SNDRV_CTL_ELEM_TYPE_BOOLEAN;
252         uinfo->count = 1;
253         uinfo->value.integer.min = 0;
254         uinfo->value.integer.max = reg_val-1;
255         
256         return 0;
257 }
258
259 static int snd_omap_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
260 {
261         u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
262
263         ucontrol->value.integer.value[0] = snd_sidetone[reg_val];
264         
265         return 0;
266 }
267
268 static int snd_omap_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
269 {
270         u16 reg_index = (kcontrol->private_value >> 16) & 0x03;
271         u16 mask = (kcontrol->private_value >> 18) & 0x1ff;
272         u16 reg = kcontrol->private_value & 0xff;
273         u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
274
275         int changed = 0;
276
277         /* Volume */
278         if ((omap_regs[reg_index].l_reg != (ucontrol->value.integer.value[0] & mask)))
279         {
280                 changed = 1;
281         
282                 omap_regs[reg_index].l_reg &= ~mask;
283                 omap_regs[reg_index].l_reg |= snd_sidetone[ucontrol->value.integer.value[0]];
284
285                 snd_sidetone[reg_val] = ucontrol->value.integer.value[0];
286                 SND_OMAP_WRITE(reg, omap_regs[reg_index].l_reg);
287         }
288         else
289                 changed = 0;
290         
291         return changed;
292 }
293
294 /* End Single Functions */
295
296 /* Begin Double Functions */
297
298 static int snd_omap_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
299 {
300         /* mask == 0 : Switch
301          * mask != 0 : Volume */
302         int mask = (kcontrol->private_value >> 18) & 0xff;
303
304         uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER : SNDRV_CTL_ELEM_TYPE_BOOLEAN;
305         uinfo->count = mask ? 2 : 1;
306         uinfo->value.integer.min = 0;
307         uinfo->value.integer.max = mask ? mask : 1;
308         
309         return 0;
310 }
311
312 static int snd_omap_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
313 {
314         /* mask == 0 : Switch
315          * mask != 0 : Volume */
316         int mask = (kcontrol->private_value >> 18) & 0xff;
317         int vol_index = (kcontrol->private_value >> 16) & 0x03;
318         
319         if (!mask)
320                 /* Switch */
321                 ucontrol->value.integer.value[0] = omap_regs[vol_index].sw;
322         else
323         {
324                 /* Volume */
325                 ucontrol->value.integer.value[0] = omap_regs[vol_index].l_reg;
326                 ucontrol->value.integer.value[1] = omap_regs[vol_index].r_reg;
327         }
328
329         return 0;
330 }
331
332 static int snd_omap_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
333 {
334         /* mask == 0 : Switch
335          * mask != 0 : Volume */
336         int vol_index = (kcontrol->private_value >> 16) & 0x03;
337         int mask = (kcontrol->private_value >> 18) & 0xff;
338         int left_reg = kcontrol->private_value & 0xff;
339         int right_reg = (kcontrol->private_value >> 8) & 0xff;
340
341         int changed = 0;
342
343         if (!mask)
344         {
345                 /* Switch */
346                 if (!ucontrol->value.integer.value[0])
347                 {
348                         SND_OMAP_WRITE(left_reg, 0x00);
349                         SND_OMAP_WRITE(right_reg, 0x00);
350                 }
351                 else
352                 {
353                         SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
354                         SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
355                 }
356                 changed = 1;
357                 omap_regs[vol_index].sw = ucontrol->value.integer.value[0]; 
358         }
359         else
360         {
361                 /* Volume */
362                 if ((omap_regs[vol_index].l_reg != (ucontrol->value.integer.value[0] & mask)) ||
363                     (omap_regs[vol_index].r_reg != (ucontrol->value.integer.value[1] & mask)))
364                 {
365                         changed = 1;
366                 
367                         omap_regs[vol_index].l_reg &= ~mask;
368                         omap_regs[vol_index].r_reg &= ~mask;
369                         omap_regs[vol_index].l_reg |= (ucontrol->value.integer.value[0] & mask);
370                         omap_regs[vol_index].r_reg |= (ucontrol->value.integer.value[1] & mask);
371                         if (omap_regs[vol_index].sw)
372                         {
373                                 /* write to registers only if sw is actived */
374                                 SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
375                                 SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
376                         }
377                 }
378                 else
379                         changed = 0;
380         }
381         
382         return changed;
383 }
384
385 /* End Double Functions */
386
387 static snd_kcontrol_new_t snd_omap_controls[] = {
388         OMAP_DOUBLE("PCM Playback Switch", 0, LEFT_CHANNEL_VOLUME_ADDR, RIGHT_CHANNEL_VOLUME_ADDR,
389                      PCM_INDEX, 0x00),
390         OMAP_DOUBLE("PCM Playback Volume", 0, LEFT_CHANNEL_VOLUME_ADDR, RIGHT_CHANNEL_VOLUME_ADDR,
391                      PCM_INDEX, OUTPUT_VOLUME_MASK),
392         OMAP_BOOL("Line Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, BYPASS_ON, 0),
393         OMAP_DOUBLE("Line Capture Switch", 0, LEFT_LINE_VOLUME_ADDR, RIGHT_LINE_VOLUME_ADDR,
394                      LINE_INDEX, 0x00),
395         OMAP_DOUBLE("Line Capture Volume", 0, LEFT_LINE_VOLUME_ADDR, RIGHT_LINE_VOLUME_ADDR,
396                      LINE_INDEX, INPUT_VOLUME_MASK),    
397         OMAP_BOOL("Mic Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, STE_ENABLED, 0),      
398         OMAP_SINGLE("Mic Playback Volume", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, 5, SIDETONE_MASK),
399         OMAP_BOOL("Mic Capture Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICM_MUTED, 1),
400         OMAP_BOOL("Mic Booster Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, MICB_20DB, 0),
401         OMAP_MUX("Capture Source", ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX, INSEL_MIC),
402 };
403
404 #ifdef CONFIG_PM
405
406 void snd_omap_suspend_mixer(void)
407 {
408         /* Saves current values to wake-up correctly */
409         omap_pm_regs[LINE_INDEX].l_reg = omap_regs[LINE_INDEX].l_reg;
410         omap_pm_regs[LINE_INDEX].r_reg = omap_regs[LINE_INDEX].l_reg;
411         omap_pm_regs[LINE_INDEX].sw = omap_regs[LINE_INDEX].sw;
412         
413         omap_pm_regs[AAC_INDEX].l_reg = omap_regs[AAC_INDEX].l_reg;
414         
415         omap_pm_regs[PCM_INDEX].l_reg = omap_regs[PCM_INDEX].l_reg;
416         omap_pm_regs[PCM_INDEX].r_reg = omap_regs[PCM_INDEX].r_reg;
417         omap_pm_regs[PCM_INDEX].sw = omap_regs[PCM_INDEX].sw;
418 }
419
420 void snd_omap_resume_mixer(void)
421 {
422         /* Line's saved values */
423         omap_regs[LINE_INDEX].l_reg = omap_pm_regs[LINE_INDEX].l_reg;
424         omap_regs[LINE_INDEX].r_reg = omap_pm_regs[LINE_INDEX].l_reg;
425         omap_regs[LINE_INDEX].sw = omap_pm_regs[LINE_INDEX].sw;
426         SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
427         SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
428         
429         /* Analog Audio Control's saved values */
430         omap_regs[AAC_INDEX].l_reg = omap_pm_regs[AAC_INDEX].l_reg;
431         SND_OMAP_WRITE(ANALOG_AUDIO_CONTROL_ADDR, omap_regs[AAC_INDEX].l_reg);
432         
433         /* Headphone's saved values */
434         omap_regs[PCM_INDEX].l_reg = omap_pm_regs[PCM_INDEX].l_reg;
435         omap_regs[PCM_INDEX].r_reg = omap_pm_regs[PCM_INDEX].r_reg;
436         omap_regs[PCM_INDEX].sw = omap_pm_regs[PCM_INDEX].sw;
437         SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR, omap_pm_regs[PCM_INDEX].l_reg);
438         SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR, omap_pm_regs[PCM_INDEX].r_reg);
439 }
440 #endif
441
442 void snd_omap_init_mixer(void)
443 {
444         u16 vol_reg;
445
446         /* Line's default values */
447         omap_regs[LINE_INDEX].l_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
448         omap_regs[LINE_INDEX].r_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
449         omap_regs[LINE_INDEX].sw = 0;
450         SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR, DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
451         SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR, DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
452         
453         /* Analog Audio Control's default values */
454         omap_regs[AAC_INDEX].l_reg = DEFAULT_ANALOG_AUDIO_CONTROL;
455         
456         /* Headphone's default values */
457         vol_reg = LZC_ON;
458         vol_reg &= ~OUTPUT_VOLUME_MASK;
459         vol_reg |= DEFAULT_OUTPUT_VOLUME;
460         omap_regs[PCM_INDEX].l_reg = DEFAULT_OUTPUT_VOLUME;
461         omap_regs[PCM_INDEX].r_reg = DEFAULT_OUTPUT_VOLUME;
462         omap_regs[PCM_INDEX].sw = 1;
463         SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR, vol_reg);
464         SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR, vol_reg);
465 }
466
467 int snd_omap_mixer(struct snd_card_omap_codec *chip)
468 {
469         snd_card_t *card;
470         unsigned int idx;
471         int err;
472
473         snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
474
475         card = chip->card;
476
477         strcpy(card->mixername, MIXER_NAME);
478
479         /* Registering alsa mixer controls */
480         for (idx = 0; idx < ARRAY_SIZE(snd_omap_controls); idx++) 
481                 if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_omap_controls[idx], chip))) < 0)
482                         return err;
483
484         return 0;
485 }