2 * sound/arm/omap/omap-alsa-aic23-mixer.c
4 * Alsa Driver Mixer for generic codecs for omap boards
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
10 * Based on es1688_lib.c,
11 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
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.
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.
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.
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
40 #include <linux/kernel.h>
42 #include <mach/aic23.h>
44 #include <mach/omap-alsa.h>
45 #include "omap-alsa-aic23.h"
46 #include <sound/initval.h>
47 #include <sound/control.h>
49 MODULE_AUTHOR("David Cohen");
50 MODULE_AUTHOR("Daniel Petrini");
52 MODULE_LICENSE("GPL");
53 MODULE_DESCRIPTION("OMAP Alsa mixer driver for ALSA");
56 * Codec dependent region
60 #if defined(CONFIG_SENSORS_TLV320AIC23) || \
61 defined(CONFIG_SENSORS_TLV320AIC23_MODULE)
63 #define MIXER_NAME "Mixer AIC23"
64 #define SND_OMAP_WRITE(reg, val) audio_aic23_write(reg, val)
68 /* Callback Functions */
69 #define OMAP_BOOL(xname, xindex, reg, reg_index, mask, invert) \
71 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
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) | \
81 #define OMAP_MUX(xname, reg, reg_index, mask) \
83 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
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) \
91 #define OMAP_SINGLE(xname, xindex, reg, reg_index, reg_val, mask) \
93 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
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) |\
103 #define OMAP_DOUBLE(xname, xindex, left_reg, right_reg, reg_index, mask) \
105 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
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) | \
115 /* Local Registers */
116 enum snd_device_index {
119 AAC_INDEX, /* Analog Audio Control: reg = l_reg */
136 u16 snd_sidetone[6] = {
145 /* Begin Bool Functions */
147 static int snd_omap_info_bool(struct snd_kcontrol *kcontrol,
148 struct snd_ctl_elem_info *uinfo)
150 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
152 uinfo->value.integer.min = 0;
153 uinfo->value.integer.max = 1;
158 static int snd_omap_get_bool(struct snd_kcontrol *kcontrol,
159 struct snd_ctl_elem_value *ucontrol)
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;
166 ucontrol->value.integer.value[0] =
167 (omap_regs[mic_index].l_reg & mask) ? 0 : 1;
169 ucontrol->value.integer.value[0] =
170 (omap_regs[mic_index].l_reg & mask) ? 1 : 0;
175 static int snd_omap_put_bool(struct snd_kcontrol *kcontrol,
176 struct snd_ctl_elem_value *ucontrol)
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;
185 if (ucontrol->value.integer.value[0]) /* XOR */
187 omap_regs[mic_index].l_reg &= ~mask;
189 omap_regs[mic_index].l_reg |= mask;
192 omap_regs[mic_index].l_reg |= mask;
194 omap_regs[mic_index].l_reg &= ~mask;
196 SND_OMAP_WRITE(reg, omap_regs[mic_index].l_reg);
201 /* End Bool Functions */
203 /* Begin Mux Functions */
205 static int snd_omap_info_mux(struct snd_kcontrol *kcontrol,
206 struct snd_ctl_elem_info *uinfo)
210 static char *texts[2] = { "Mic", "Line" };
212 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
214 uinfo->value.enumerated.items = 2;
216 if (uinfo->value.enumerated.item > 1)
217 uinfo->value.enumerated.item = 1;
219 strcpy(uinfo->value.enumerated.name,
220 texts[uinfo->value.enumerated.item]);
225 static int snd_omap_get_mux(struct snd_kcontrol *kcontrol,
226 struct snd_ctl_elem_value *ucontrol)
228 u16 mask = (kcontrol->private_value >> 10) & 0xff;
229 int mux_idx = (kcontrol->private_value >> 8) & 0x03;
231 ucontrol->value.enumerated.item[0] =
232 (omap_regs[mux_idx].l_reg & mask) ? 0 /* Mic */ : 1 /* Line */;
237 static int snd_omap_put_mux(struct snd_kcontrol *kcontrol,
238 struct snd_ctl_elem_value *ucontrol)
240 u16 reg = kcontrol->private_value & 0xff;
241 u16 mask = (kcontrol->private_value >> 10) & 0xff;
242 int mux_index = (kcontrol->private_value >> 8) & 0x03;
246 if (!ucontrol->value.integer.value[0])
247 omap_regs[mux_index].l_reg |= mask; /* AIC23: Mic */
249 omap_regs[mux_index].l_reg &= ~mask; /* AIC23: Line */
251 SND_OMAP_WRITE(reg, omap_regs[mux_index].l_reg);
256 /* End Mux Functions */
258 /* Begin Single Functions */
260 static int snd_omap_info_single(struct snd_kcontrol *kcontrol,
261 struct snd_ctl_elem_info *uinfo)
263 int mask = (kcontrol->private_value >> 18) & 0xff;
264 int reg_val = (kcontrol->private_value >> 8) & 0xff;
266 uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER :
267 SNDRV_CTL_ELEM_TYPE_BOOLEAN;
269 uinfo->value.integer.min = 0;
270 uinfo->value.integer.max = reg_val-1;
275 static int snd_omap_get_single(struct snd_kcontrol *kcontrol,
276 struct snd_ctl_elem_value *ucontrol)
278 u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
280 ucontrol->value.integer.value[0] = snd_sidetone[reg_val];
285 static int snd_omap_put_single(struct snd_kcontrol *kcontrol,
286 struct snd_ctl_elem_value *ucontrol)
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;
296 if ((omap_regs[reg_index].l_reg !=
297 (ucontrol->value.integer.value[0] & mask))) {
300 omap_regs[reg_index].l_reg &= ~mask;
301 omap_regs[reg_index].l_reg |=
302 snd_sidetone[ucontrol->value.integer.value[0]];
304 snd_sidetone[reg_val] = ucontrol->value.integer.value[0];
305 SND_OMAP_WRITE(reg, omap_regs[reg_index].l_reg);
313 /* End Single Functions */
315 /* Begin Double Functions */
317 static int snd_omap_info_double(struct snd_kcontrol *kcontrol,
318 struct snd_ctl_elem_info *uinfo)
324 int mask = (kcontrol->private_value >> 18) & 0xff;
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;
335 static int snd_omap_get_double(struct snd_kcontrol *kcontrol,
336 struct snd_ctl_elem_value *ucontrol)
342 int mask = (kcontrol->private_value >> 18) & 0xff;
343 int vol_index = (kcontrol->private_value >> 16) & 0x03;
347 ucontrol->value.integer.value[0] = omap_regs[vol_index].sw;
350 ucontrol->value.integer.value[0] = omap_regs[vol_index].l_reg;
351 ucontrol->value.integer.value[1] = omap_regs[vol_index].r_reg;
357 static int snd_omap_put_double(struct snd_kcontrol *kcontrol,
358 struct snd_ctl_elem_value *ucontrol)
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;
371 if (!ucontrol->value.integer.value[0]) {
372 SND_OMAP_WRITE(left_reg, 0x00);
373 SND_OMAP_WRITE(right_reg, 0x00);
375 SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
376 SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
379 omap_regs[vol_index].sw = ucontrol->value.integer.value[0];
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))) {
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);
409 /* End Double Functions */
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,
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,
437 void snd_omap_suspend_mixer(void)
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;
444 omap_pm_regs[AAC_INDEX].l_reg = omap_regs[AAC_INDEX].l_reg;
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;
451 void snd_omap_resume_mixer(void)
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);
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);
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);
475 void snd_omap_init_mixer(void)
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);
488 /* Analog Audio Control's default values */
489 omap_regs[AAC_INDEX].l_reg = DEFAULT_ANALOG_AUDIO_CONTROL;
491 /* Headphone's default values */
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);
502 int snd_omap_mixer(struct snd_card_omap_codec *chip)
504 struct snd_card *card;
508 snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
512 strcpy(card->mixername, MIXER_NAME);
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));