2 * sound/arm/omap/omap-alsa-tsc2101-mixer.c
4 * Alsa Driver for TSC2101 codec for OMAP platform boards.
6 * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and
7 * Everett Coleman II <gcc80x86@fuzzyneural.net>
9 * Board initialization code is based on the code in TSC2101 OSS driver.
10 * Copyright (C) 2004 Texas Instruments, Inc.
11 * Written by Nishanth Menon and Sriram Kannan
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 * 2006-03-01 Mika Laitio - Mixer for the tsc2101 driver used in omap boards.
36 * Can switch between headset and loudspeaker playback,
37 * mute and unmute dgc, set dgc volume. Record source switch,
38 * keyclick, buzzer and headset volume and handset volume control
43 #include "omap-alsa-tsc2101.h"
44 #include "omap-alsa-tsc2101-mixer.h"
46 #include <linux/types.h>
47 #include <sound/initval.h>
48 #include <sound/control.h>
50 //#define M_DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
51 #define M_DPRINTK(ARGS...) /* nop */
53 #define DGC_DALVL_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
54 #define DGC_DARVL_EXTRACT(ARG) ((ARG & 0x007f))
55 #define GET_DGC_DALMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(15)) >> 15)
56 #define GET_DGC_DARMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(7)) >> 7)
57 #define IS_DGC_DALMU_UNMUTED(ARG) (((GET_DGC_DALMU_BIT_VALUE(ARG)) == 0))
58 #define IS_DGC_DARMU_UNMUTED(ARG) (((GET_DGC_DARMU_BIT_VALUE(ARG)) == 0))
60 #define HGC_ADPGA_HED_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
61 #define GET_DGC_HGCMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(15)) >> 15)
62 #define IS_DGC_HGCMU_UNMUTED(ARG) (((GET_DGC_HGCMU_BIT_VALUE(ARG)) == 0))
64 #define HNGC_ADPGA_HND_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
65 #define GET_DGC_HNGCMU_BIT_VALUE(ARG) (((ARG) & TSC2101_BIT(15)) >> 15)
66 #define IS_DGC_HNGCMU_UNMUTED(ARG) (((GET_DGC_HNGCMU_BIT_VALUE(ARG)) == 0))
68 static int current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
69 static int current_rec_src = REC_SRC_SINGLE_ENDED_MICIN_HED;
72 * Used for switching between TSC2101 recourd sources.
73 * Logic is adjusted from the TSC2101 OSS code.
75 static int set_record_source(int val)
81 maskedVal = 0xe0 & val;
83 data = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
84 TSC2101_MIXER_PGA_CTRL);
85 data &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
87 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
88 TSC2101_MIXER_PGA_CTRL,
90 current_rec_src = val;
97 * Converts the Alsa mixer volume (0 - 100) to real
98 * Digital Gain Control (DGC) value that can be written
99 * or read from the TSC2101 registry.
101 * Note that the number "OUTPUT_VOLUME_MAX" is smaller than OUTPUT_VOLUME_MIN
102 * because DGC works as a volume decreaser. (The more bigger value is put
103 * to DGC, the more the volume of controlled channel is decreased)
105 * In addition the TCS2101 chip would allow the maximum volume reduction be 63.5 DB
106 * but according to some tests user can not hear anything with this chip
107 * when the volume is set to be less than 25 db.
108 * Therefore this function will return a value that means 38.5 db (63.5 db - 25 db)
109 * reduction in the channel volume, when mixer is set to 0.
110 * For mixer value 100, this will return a value that means 0 db volume reduction.
111 * ([mute_left_bit]0000000[mute_right_bit]0000000)
113 int get_mixer_volume_as_dac_gain_control_volume(int vol)
117 /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
118 retVal = ((vol * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
119 /* invert the value for getting the proper range 0 min and 100 max */
120 retVal = OUTPUT_VOLUME_MIN - retVal;
126 * Converts the Alsa mixer volume (0 - 100) to TSC2101
127 * Digital Gain Control (DGC) volume. Alsa mixer volume 0
128 * is converted to value meaning the volume reduction of -38.5 db
129 * and Alsa mixer volume 100 is converted to value meaning the
132 int set_mixer_volume_as_dac_gain_control_volume(int mixerVolL, int mixerVolR)
139 if ((mixerVolL < 0) ||
143 printk(KERN_ERR "Trying a bad mixer volume as dac gain control volume value, left (%d), right (%d)!\n", mixerVolL, mixerVolR);
146 M_DPRINTK("mixer volume left = %d, right = %d\n", mixerVolL, mixerVolR);
147 volL = get_mixer_volume_as_dac_gain_control_volume(mixerVolL);
148 volR = get_mixer_volume_as_dac_gain_control_volume(mixerVolR);
150 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL);
151 /* keep the old mute bit settings */
152 val &= ~(DGC_DALVL(OUTPUT_VOLUME_MIN) | DGC_DARVL(OUTPUT_VOLUME_MIN));
153 val |= DGC_DALVL(volL) | DGC_DARVL(volR);
156 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
157 TSC2101_DAC_GAIN_CTRL,
160 M_DPRINTK("to registry: left = %d, right = %d, total = %d\n", DGC_DALVL_EXTRACT(val), DGC_DARVL_EXTRACT(val), val);
164 int dac_gain_control_unmute_control(int muteLeft, int muteRight)
170 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL);
171 /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on
172 * so if values are same, it's time to change the registry value.
174 if (muteLeft == GET_DGC_DALMU_BIT_VALUE(val)) {
176 /* mute --> turn bit on */
177 val = val | DGC_DALMU;
180 /* unmute --> turn bit off */
181 val = val & ~DGC_DALMU;
185 if (muteRight == GET_DGC_DARMU_BIT_VALUE(val)) {
186 if (muteRight == 0) {
187 /* mute --> turn bit on */
188 val = val | DGC_DARMU;
191 /* unmute --> turn bit off */
192 val = val & ~DGC_DARMU;
197 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL, val);
198 M_DPRINTK("changed value, is_unmuted left = %d, right = %d\n",
199 IS_DGC_DALMU_UNMUTED(val),
200 IS_DGC_DARMU_UNMUTED(val));
206 * Converts the DGC registry value read from the TSC2101 registry to
207 * Alsa mixer volume format (0 - 100).
209 int get_dac_gain_control_volume_as_mixer_volume(u16 vol)
213 retVal = OUTPUT_VOLUME_MIN - vol;
214 retVal = ((retVal - OUTPUT_VOLUME_MAX) * 100) / OUTPUT_VOLUME_RANGE;
215 /* fix scaling error */
216 if ((retVal > 0) && (retVal < 100)) {
223 * Converts the headset gain control volume (0 - 63.5 db)
224 * to Alsa mixer volume (0 - 100)
226 int get_headset_gain_control_volume_as_mixer_volume(u16 registerVal)
230 retVal = ((registerVal * 100) / INPUT_VOLUME_RANGE);
235 * Converts the handset gain control volume (0 - 63.5 db)
236 * to Alsa mixer volume (0 - 100)
238 int get_handset_gain_control_volume_as_mixer_volume(u16 registerVal)
240 return get_headset_gain_control_volume_as_mixer_volume(registerVal);
244 * Converts the Alsa mixer volume (0 - 100) to
245 * headset gain control volume (0 - 63.5 db)
247 int get_mixer_volume_as_headset_gain_control_volume(u16 mixerVal)
251 retVal = ((mixerVal * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
256 * Writes Alsa mixer volume (0 - 100) to TSC2101 headset volume registry in
257 * a TSC2101 format. (0 - 63.5 db)
258 * In TSC2101 OSS driver this functionality was controlled with "SET_LINE" parameter.
260 int set_mixer_volume_as_headset_gain_control_volume(int mixerVol)
266 if (mixerVol < 0 || mixerVol > 100) {
267 M_DPRINTK("Trying a bad headset mixer volume value(%d)!\n", mixerVol);
270 M_DPRINTK("mixer volume = %d\n", mixerVol);
271 /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
272 /* NOTE: 0 is minimum volume and not mute */
273 volume = get_mixer_volume_as_headset_gain_control_volume(mixerVol);
274 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
275 TSC2101_HEADSET_GAIN_CTRL);
276 /* preserve the old mute settings */
277 val &= ~(HGC_ADPGA_HED(INPUT_VOLUME_MAX));
278 val |= HGC_ADPGA_HED(volume);
279 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
280 TSC2101_HEADSET_GAIN_CTRL,
284 M_DPRINTK("to registry = %d\n", val);
289 * Writes Alsa mixer volume (0 - 100) to TSC2101 handset volume registry in
290 * a TSC2101 format. (0 - 63.5 db)
291 * In TSC2101 OSS driver this functionality was controlled with "SET_MIC" parameter.
293 int set_mixer_volume_as_handset_gain_control_volume(int mixerVol)
299 if (mixerVol < 0 || mixerVol > 100) {
300 M_DPRINTK("Trying a bad mic mixer volume value(%d)!\n", mixerVol);
303 M_DPRINTK("mixer volume = %d\n", mixerVol);
304 /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range
305 * NOTE: 0 is minimum volume and not mute
307 volume = get_mixer_volume_as_headset_gain_control_volume(mixerVol);
308 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HANDSET_GAIN_CTRL);
309 /* preserve the old mute settigns */
310 val &= ~(HNGC_ADPGA_HND(INPUT_VOLUME_MAX));
311 val |= HNGC_ADPGA_HND(volume);
312 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
313 TSC2101_HANDSET_GAIN_CTRL,
317 M_DPRINTK("to registry = %d\n", val);
321 void init_record_sources(void)
323 /* Mute Analog Sidetone
324 * analog sidetone gain db?
325 * Cell Phone In not connected to ADC
326 * Input selected by MICSEL connected to ADC
328 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
329 TSC2101_MIXER_PGA_CTRL,
330 MPC_ASTMU | MPC_ASTG(0x40) | ~MPC_CPADC | MPC_MICADC);
331 /* Set record source, Select MIC_INHED input for headset */
332 set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
335 void set_loudspeaker_to_playback_target(void)
339 /* power down sp1, sp2 and loudspeaker */
340 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
341 TSC2101_CODEC_POWER_CTRL,
342 CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF);
343 /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
347 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
348 TSC2101_AUDIO_CTRL_4,
351 /* DAC left and right routed to SPK1/SPK2
353 * keyclicks routed to SPK1/SPK2
356 AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
357 AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
359 val = val & ~AC5_HDSCPTC;
360 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
361 TSC2101_AUDIO_CTRL_5,
364 /* powerdown spk1/out32n and spk2 */
365 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
366 TSC2101_POWERDOWN_STS);
367 val = val & ~(~PS_SPK1FL | ~PS_HNDFL | PS_LSPKFL);
368 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
369 TSC2101_POWERDOWN_STS,
372 /* routing selected to SPK1 goes to OUT8P/OUT84 alsa. (loudspeaker)
373 * analog sidetone routed to loudspeaker
374 * buzzer pga routed to loudspeaker
375 * keyclick routing to loudspeaker
376 * cellphone input routed to loudspeaker
377 * mic selection (control register 04h/page2) routed to cell phone output (CP_OUT)
378 * routing selected for SPK1 goes also to cellphone output (CP_OUT)
379 * OUT8P/OUT8N (loudspeakers) unmuted (0 = unmuted)
380 * Cellphone output is not muted (0 = unmuted)
381 * Enable loudspeaker short protection control (0 = enable protection)
382 * VGND short protection control (0 = enable protection)
384 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
385 TSC2101_AUDIO_CTRL_6,
386 AC6_SPL2LSK | AC6_AST2LSK | AC6_BUZ2LSK | AC6_KCL2LSK |
387 AC6_CPI2LSK | AC6_MIC2CPO | AC6_SPL2CPO |
388 ~AC6_MUTLSPK | ~AC6_MUTSPK2 | ~AC6_LDSCPTC | ~AC6_VGNDSCPTC);
389 current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
392 void set_headphone_to_playback_target(void)
394 /* power down sp1, sp2 and loudspeaker */
395 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
396 TSC2101_CODEC_POWER_CTRL,
397 CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF);
398 /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
399 /* 1dB AGC hysteresis */
401 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
402 TSC2101_AUDIO_CTRL_4,
405 /* DAC left and right routed to SPK2 */
407 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
408 TSC2101_AUDIO_CTRL_5,
409 AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
410 AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
413 /* OUT8P/N muted, CPOUT muted */
414 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
415 TSC2101_AUDIO_CTRL_6,
416 AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
418 current_playback_target = PLAYBACK_TARGET_HEADPHONE;
422 * Checks whether the headset is detected.
423 * If headset is detected, the type is returned. Type can be
424 * 0x01 = stereo headset detected
425 * 0x02 = cellurar headset detected
426 * 0x03 = stereo + cellurar headset detected
427 * If headset is not detected 0 is returned.
429 u16 get_headset_detected(void)
435 curType = 0; /* not detected */
436 curVal = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
437 TSC2101_AUDIO_CTRL_7);
438 curDetected = curVal & AC7_HDDETFL;
440 printk("headset detected, checking type from %d \n", curVal);
441 curType = ((curVal & 0x6000) >> 13);
442 printk("headset type detected = %d \n", curType);
445 printk("headset not detected\n");
450 void init_playback_targets(void)
454 set_loudspeaker_to_playback_target();
455 /* Left line input volume control
456 * = SET_LINE in the OSS driver
458 set_mixer_volume_as_headset_gain_control_volume(DEFAULT_INPUT_VOLUME);
460 /* Set headset to be controllable by handset mixer
461 * AGC enable for handset input
462 * Handset input not muted
464 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
465 TSC2101_HANDSET_GAIN_CTRL);
466 val = val | HNGC_AGCEN_HND;
467 val = val & ~HNGC_ADMUT_HND;
468 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
469 TSC2101_HANDSET_GAIN_CTRL,
472 /* mic input volume control
473 * SET_MIC in the OSS driver
475 set_mixer_volume_as_handset_gain_control_volume(DEFAULT_INPUT_VOLUME);
477 /* Left/Right headphone channel volume control
478 * Zero-cross detect on
480 set_mixer_volume_as_dac_gain_control_volume(DEFAULT_OUTPUT_VOLUME, DEFAULT_OUTPUT_VOLUME);
482 dac_gain_control_unmute_control(1, 1);
486 * Initializes tsc2101 recourd source (to line) and playback target (to loudspeaker)
488 void snd_omap_init_mixer(void)
492 /* Headset/Hook switch detect enabled */
493 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
494 TSC2101_AUDIO_CTRL_7,
497 init_record_sources();
498 init_playback_targets();
503 static int __pcm_playback_target_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
505 static char *texts[PLAYBACK_TARGET_COUNT] = {
506 "Loudspeaker", "Headphone"
509 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
511 uinfo->value.enumerated.items = PLAYBACK_TARGET_COUNT;
512 if (uinfo->value.enumerated.item > PLAYBACK_TARGET_COUNT - 1) {
513 uinfo->value.enumerated.item = PLAYBACK_TARGET_COUNT - 1;
515 strcpy(uinfo->value.enumerated.name,
516 texts[uinfo->value.enumerated.item]);
520 static int __pcm_playback_target_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
522 ucontrol->value.integer.value[0] = current_playback_target;
526 static int __pcm_playback_target_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
532 curVal = ucontrol->value.integer.value[0];
534 (curVal < PLAYBACK_TARGET_COUNT) &&
535 (curVal != current_playback_target)) {
537 set_loudspeaker_to_playback_target();
540 set_headphone_to_playback_target();
547 static int __pcm_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
549 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
551 uinfo->value.integer.min = 0;
552 uinfo->value.integer.max = 100;
557 * Alsa mixer interface function for getting the volume read from the DGC in a
558 * 0 -100 alsa mixer format.
560 static int __pcm_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
566 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL);
567 M_DPRINTK("registry value = %d!\n", val);
568 volL = DGC_DALVL_EXTRACT(val);
569 volR = DGC_DARVL_EXTRACT(val);
570 /* make sure that other bits are not on */
571 volL = volL & ~DGC_DALMU;
572 volR = volR & ~DGC_DARMU;
574 volL = get_dac_gain_control_volume_as_mixer_volume(volL);
575 volR = get_dac_gain_control_volume_as_mixer_volume(volR);
577 ucontrol->value.integer.value[0] = volL; /* L */
578 ucontrol->value.integer.value[1] = volR; /* R */
580 M_DPRINTK("mixer volume left = %ld, right = %ld\n", ucontrol->value.integer.value[0], ucontrol->value.integer.value[1]);
584 static int __pcm_playback_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
586 return set_mixer_volume_as_dac_gain_control_volume(ucontrol->value.integer.value[0],
587 ucontrol->value.integer.value[1]);
590 static int __pcm_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
592 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
594 uinfo->value.integer.min = 0;
595 uinfo->value.integer.max = 1;
600 * When DGC_DALMU (bit 15) is 1, the left channel is muted.
601 * When DGC_DALMU is 0, left channel is not muted.
602 * Same logic apply also for the right channel.
604 static int __pcm_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
606 u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_DAC_GAIN_CTRL);
608 ucontrol->value.integer.value[0] = IS_DGC_DALMU_UNMUTED(val);
609 ucontrol->value.integer.value[1] = IS_DGC_DARMU_UNMUTED(val);
613 static int __pcm_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
615 return dac_gain_control_unmute_control(ucontrol->value.integer.value[0],
616 ucontrol->value.integer.value[1]);
619 static int __headset_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
621 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
623 uinfo->value.integer.min = 0;
624 uinfo->value.integer.max = 100;
628 static int __headset_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
633 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
634 TSC2101_HEADSET_GAIN_CTRL);
635 M_DPRINTK("registry value = %d\n", val);
636 vol = HGC_ADPGA_HED_EXTRACT(val);
637 vol = vol & ~HGC_ADMUT_HED;
639 vol = get_headset_gain_control_volume_as_mixer_volume(vol);
640 ucontrol->value.integer.value[0] = vol;
642 M_DPRINTK("mixer volume returned = %ld\n", ucontrol->value.integer.value[0]);
646 static int __headset_playback_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
648 return set_mixer_volume_as_headset_gain_control_volume(ucontrol->value.integer.value[0]);
651 static int __headset_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
653 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
655 uinfo->value.integer.min = 0;
656 uinfo->value.integer.max = 1;
660 /* When HGC_ADMUT_HED (bit 15) is 1, the headset is muted.
661 * When HGC_ADMUT_HED is 0, headset is not muted.
663 static int __headset_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
665 u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
666 TSC2101_HEADSET_GAIN_CTRL);
667 ucontrol->value.integer.value[0] = IS_DGC_HGCMU_UNMUTED(val);
671 static int __headset_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
674 u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
675 TSC2101_HEADSET_GAIN_CTRL);
676 /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on
677 * so if values are same, it's time to change the registry value...
679 if (ucontrol->value.integer.value[0] == GET_DGC_HGCMU_BIT_VALUE(val)) {
680 if (ucontrol->value.integer.value[0] == 0) {
681 /* mute --> turn bit on */
682 val = val | HGC_ADMUT_HED;
685 /* unmute --> turn bit off */
686 val = val & ~HGC_ADMUT_HED;
689 M_DPRINTK("changed value, is_unmuted = %d\n", IS_DGC_HGCMU_UNMUTED(val));
692 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
693 TSC2101_HEADSET_GAIN_CTRL,
699 static int __handset_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
701 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
703 uinfo->value.integer.min = 0;
704 uinfo->value.integer.max = 100;
708 static int __handset_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
713 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HANDSET_GAIN_CTRL);
714 M_DPRINTK("registry value = %d\n", val);
715 vol = HNGC_ADPGA_HND_EXTRACT(val);
716 vol = vol & ~HNGC_ADMUT_HND;
717 vol = get_handset_gain_control_volume_as_mixer_volume(vol);
718 ucontrol->value.integer.value[0] = vol;
720 M_DPRINTK("mixer volume returned = %ld\n", ucontrol->value.integer.value[0]);
724 static int __handset_playback_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
726 return set_mixer_volume_as_handset_gain_control_volume(ucontrol->value.integer.value[0]);
729 static int __handset_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
731 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
733 uinfo->value.integer.min = 0;
734 uinfo->value.integer.max = 1;
738 /* When HNGC_ADMUT_HND (bit 15) is 1, the handset is muted.
739 * When HNGC_ADMUT_HND is 0, handset is not muted.
741 static int __handset_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
743 u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HANDSET_GAIN_CTRL);
744 ucontrol->value.integer.value[0] = IS_DGC_HNGCMU_UNMUTED(val);
748 static int __handset_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
751 u16 val = omap_tsc2101_read(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2, TSC2101_HANDSET_GAIN_CTRL);
753 /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on
754 * so if values are same, it's time to change the registry value...
756 if (ucontrol->value.integer.value[0] == GET_DGC_HNGCMU_BIT_VALUE(val)) {
757 if (ucontrol->value.integer.value[0] == 0) {
758 /* mute --> turn bit on */
759 val = val | HNGC_ADMUT_HND;
762 /* unmute --> turn bit off */
763 val = val & ~HNGC_ADMUT_HND;
765 M_DPRINTK("changed value, is_unmuted = %d\n", IS_DGC_HNGCMU_UNMUTED(val));
769 omap_tsc2101_write(TSC2101_AUDIO_CODEC_REGISTERS_PAGE2,
770 TSC2101_HANDSET_GAIN_CTRL,
776 static snd_kcontrol_new_t tsc2101_control[] __devinitdata = {
778 .name = "Playback Playback Route",
779 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
781 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
782 .info = __pcm_playback_target_info,
783 .get = __pcm_playback_target_get,
784 .put = __pcm_playback_target_put,
786 .name = "Master Playback Volume",
787 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
789 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
790 .info = __pcm_playback_volume_info,
791 .get = __pcm_playback_volume_get,
792 .put = __pcm_playback_volume_put,
794 .name = "Master Playback Switch",
795 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
797 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
798 .info = __pcm_playback_switch_info,
799 .get = __pcm_playback_switch_get,
800 .put = __pcm_playback_switch_put,
802 .name = "Headset Playback Volume",
803 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
805 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
806 .info = __headset_playback_volume_info,
807 .get = __headset_playback_volume_get,
808 .put = __headset_playback_volume_put,
810 .name = "Headset Playback Switch",
811 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
813 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
814 .info = __headset_playback_switch_info,
815 .get = __headset_playback_switch_get,
816 .put = __headset_playback_switch_put,
818 .name = "Handset Playback Volume",
819 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
821 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
822 .info = __handset_playback_volume_info,
823 .get = __handset_playback_volume_get,
824 .put = __handset_playback_volume_put,
826 .name = "Handset Playback Switch",
827 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
829 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
830 .info = __handset_playback_switch_info,
831 .get = __handset_playback_switch_get,
832 .put = __handset_playback_switch_put,
838 void snd_omap_suspend_mixer(void)
842 void snd_omap_resume_mixer(void)
844 snd_omap_init_mixer();
848 int snd_omap_mixer(struct snd_card_omap_codec *tsc2101)
856 for (i=0; i < ARRAY_SIZE(tsc2101_control); i++) {
857 if ((err = snd_ctl_add(tsc2101->card,
858 snd_ctl_new1(&tsc2101_control[i],
859 tsc2101->card))) < 0) {