15765e78eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2*fe372850SPierre-Louis Bossart /*
38cc72361SWai Yew CHAY * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
48cc72361SWai Yew CHAY *
58cc72361SWai Yew CHAY * @File ctmixer.c
68cc72361SWai Yew CHAY *
78cc72361SWai Yew CHAY * @Brief
88cc72361SWai Yew CHAY * This file contains the implementation of alsa mixer device functions.
98cc72361SWai Yew CHAY *
108cc72361SWai Yew CHAY * @Author Liu Chun
118cc72361SWai Yew CHAY * @Date May 28 2008
128cc72361SWai Yew CHAY */
138cc72361SWai Yew CHAY
148cc72361SWai Yew CHAY
158cc72361SWai Yew CHAY #include "ctmixer.h"
168cc72361SWai Yew CHAY #include "ctamixer.h"
17d436dd06STakashi Iwai #include <linux/slab.h>
188cc72361SWai Yew CHAY #include <sound/core.h>
198cc72361SWai Yew CHAY #include <sound/control.h>
208cc72361SWai Yew CHAY #include <sound/asoundef.h>
218cc72361SWai Yew CHAY #include <sound/pcm.h>
22d436dd06STakashi Iwai #include <sound/tlv.h>
238cc72361SWai Yew CHAY
248cc72361SWai Yew CHAY enum CT_SUM_CTL {
258cc72361SWai Yew CHAY SUM_IN_F,
268cc72361SWai Yew CHAY SUM_IN_R,
278cc72361SWai Yew CHAY SUM_IN_C,
288cc72361SWai Yew CHAY SUM_IN_S,
298cc72361SWai Yew CHAY SUM_IN_F_C,
308cc72361SWai Yew CHAY
318cc72361SWai Yew CHAY NUM_CT_SUMS
328cc72361SWai Yew CHAY };
338cc72361SWai Yew CHAY
348cc72361SWai Yew CHAY enum CT_AMIXER_CTL {
358cc72361SWai Yew CHAY /* volume control mixers */
368cc72361SWai Yew CHAY AMIXER_MASTER_F,
378cc72361SWai Yew CHAY AMIXER_MASTER_R,
388cc72361SWai Yew CHAY AMIXER_MASTER_C,
398cc72361SWai Yew CHAY AMIXER_MASTER_S,
408cc72361SWai Yew CHAY AMIXER_PCM_F,
418cc72361SWai Yew CHAY AMIXER_PCM_R,
428cc72361SWai Yew CHAY AMIXER_PCM_C,
438cc72361SWai Yew CHAY AMIXER_PCM_S,
448cc72361SWai Yew CHAY AMIXER_SPDIFI,
458cc72361SWai Yew CHAY AMIXER_LINEIN,
468cc72361SWai Yew CHAY AMIXER_MIC,
478cc72361SWai Yew CHAY AMIXER_SPDIFO,
488cc72361SWai Yew CHAY AMIXER_WAVE_F,
498cc72361SWai Yew CHAY AMIXER_WAVE_R,
508cc72361SWai Yew CHAY AMIXER_WAVE_C,
518cc72361SWai Yew CHAY AMIXER_WAVE_S,
528cc72361SWai Yew CHAY AMIXER_MASTER_F_C,
538cc72361SWai Yew CHAY AMIXER_PCM_F_C,
548cc72361SWai Yew CHAY AMIXER_SPDIFI_C,
558cc72361SWai Yew CHAY AMIXER_LINEIN_C,
568cc72361SWai Yew CHAY AMIXER_MIC_C,
578cc72361SWai Yew CHAY
588cc72361SWai Yew CHAY /* this should always be the last one */
598cc72361SWai Yew CHAY NUM_CT_AMIXERS
608cc72361SWai Yew CHAY };
618cc72361SWai Yew CHAY
628cc72361SWai Yew CHAY enum CTALSA_MIXER_CTL {
638cc72361SWai Yew CHAY /* volume control mixers */
648cc72361SWai Yew CHAY MIXER_MASTER_P,
658cc72361SWai Yew CHAY MIXER_PCM_P,
668cc72361SWai Yew CHAY MIXER_LINEIN_P,
678cc72361SWai Yew CHAY MIXER_MIC_P,
688cc72361SWai Yew CHAY MIXER_SPDIFI_P,
698cc72361SWai Yew CHAY MIXER_SPDIFO_P,
708cc72361SWai Yew CHAY MIXER_WAVEF_P,
718cc72361SWai Yew CHAY MIXER_WAVER_P,
728cc72361SWai Yew CHAY MIXER_WAVEC_P,
738cc72361SWai Yew CHAY MIXER_WAVES_P,
748cc72361SWai Yew CHAY MIXER_MASTER_C,
758cc72361SWai Yew CHAY MIXER_PCM_C,
768cc72361SWai Yew CHAY MIXER_LINEIN_C,
778cc72361SWai Yew CHAY MIXER_MIC_C,
788cc72361SWai Yew CHAY MIXER_SPDIFI_C,
798cc72361SWai Yew CHAY
808cc72361SWai Yew CHAY /* switch control mixers */
818cc72361SWai Yew CHAY MIXER_PCM_C_S,
828cc72361SWai Yew CHAY MIXER_LINEIN_C_S,
838cc72361SWai Yew CHAY MIXER_MIC_C_S,
848cc72361SWai Yew CHAY MIXER_SPDIFI_C_S,
858cc72361SWai Yew CHAY MIXER_SPDIFO_P_S,
868cc72361SWai Yew CHAY MIXER_WAVEF_P_S,
878cc72361SWai Yew CHAY MIXER_WAVER_P_S,
888cc72361SWai Yew CHAY MIXER_WAVEC_P_S,
898cc72361SWai Yew CHAY MIXER_WAVES_P_S,
908cc72361SWai Yew CHAY MIXER_DIGITAL_IO_S,
918cc72361SWai Yew CHAY MIXER_IEC958_MASK,
928cc72361SWai Yew CHAY MIXER_IEC958_DEFAULT,
938cc72361SWai Yew CHAY MIXER_IEC958_STREAM,
948cc72361SWai Yew CHAY
958cc72361SWai Yew CHAY /* this should always be the last one */
968cc72361SWai Yew CHAY NUM_CTALSA_MIXERS
978cc72361SWai Yew CHAY };
988cc72361SWai Yew CHAY
998cc72361SWai Yew CHAY #define VOL_MIXER_START MIXER_MASTER_P
1008cc72361SWai Yew CHAY #define VOL_MIXER_END MIXER_SPDIFI_C
1018cc72361SWai Yew CHAY #define VOL_MIXER_NUM (VOL_MIXER_END - VOL_MIXER_START + 1)
1028cc72361SWai Yew CHAY #define SWH_MIXER_START MIXER_PCM_C_S
1038cc72361SWai Yew CHAY #define SWH_MIXER_END MIXER_DIGITAL_IO_S
1048cc72361SWai Yew CHAY #define SWH_CAPTURE_START MIXER_PCM_C_S
1058cc72361SWai Yew CHAY #define SWH_CAPTURE_END MIXER_SPDIFI_C_S
1068cc72361SWai Yew CHAY
1078cc72361SWai Yew CHAY #define CHN_NUM 2
1088cc72361SWai Yew CHAY
1098cc72361SWai Yew CHAY struct ct_kcontrol_init {
1108cc72361SWai Yew CHAY unsigned char ctl;
1118cc72361SWai Yew CHAY char *name;
1128cc72361SWai Yew CHAY };
1138cc72361SWai Yew CHAY
1148cc72361SWai Yew CHAY static struct ct_kcontrol_init
1158cc72361SWai Yew CHAY ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
1168cc72361SWai Yew CHAY [MIXER_MASTER_P] = {
1178cc72361SWai Yew CHAY .ctl = 1,
1188cc72361SWai Yew CHAY .name = "Master Playback Volume",
1198cc72361SWai Yew CHAY },
1208cc72361SWai Yew CHAY [MIXER_MASTER_C] = {
1218cc72361SWai Yew CHAY .ctl = 1,
1228cc72361SWai Yew CHAY .name = "Master Capture Volume",
1238cc72361SWai Yew CHAY },
1248cc72361SWai Yew CHAY [MIXER_PCM_P] = {
1258cc72361SWai Yew CHAY .ctl = 1,
1268cc72361SWai Yew CHAY .name = "PCM Playback Volume",
1278cc72361SWai Yew CHAY },
1288cc72361SWai Yew CHAY [MIXER_PCM_C] = {
1298cc72361SWai Yew CHAY .ctl = 1,
1308cc72361SWai Yew CHAY .name = "PCM Capture Volume",
1318cc72361SWai Yew CHAY },
1328cc72361SWai Yew CHAY [MIXER_LINEIN_P] = {
1338cc72361SWai Yew CHAY .ctl = 1,
13455309216SHarry Butterworth .name = "Line Playback Volume",
1358cc72361SWai Yew CHAY },
1368cc72361SWai Yew CHAY [MIXER_LINEIN_C] = {
1378cc72361SWai Yew CHAY .ctl = 1,
13855309216SHarry Butterworth .name = "Line Capture Volume",
1398cc72361SWai Yew CHAY },
1408cc72361SWai Yew CHAY [MIXER_MIC_P] = {
1418cc72361SWai Yew CHAY .ctl = 1,
1428cc72361SWai Yew CHAY .name = "Mic Playback Volume",
1438cc72361SWai Yew CHAY },
1448cc72361SWai Yew CHAY [MIXER_MIC_C] = {
1458cc72361SWai Yew CHAY .ctl = 1,
1468cc72361SWai Yew CHAY .name = "Mic Capture Volume",
1478cc72361SWai Yew CHAY },
1488cc72361SWai Yew CHAY [MIXER_SPDIFI_P] = {
1498cc72361SWai Yew CHAY .ctl = 1,
15055309216SHarry Butterworth .name = "IEC958 Playback Volume",
1518cc72361SWai Yew CHAY },
1528cc72361SWai Yew CHAY [MIXER_SPDIFI_C] = {
1538cc72361SWai Yew CHAY .ctl = 1,
15455309216SHarry Butterworth .name = "IEC958 Capture Volume",
1558cc72361SWai Yew CHAY },
1568cc72361SWai Yew CHAY [MIXER_SPDIFO_P] = {
1578cc72361SWai Yew CHAY .ctl = 1,
15855309216SHarry Butterworth .name = "Digital Playback Volume",
1598cc72361SWai Yew CHAY },
1608cc72361SWai Yew CHAY [MIXER_WAVEF_P] = {
1618cc72361SWai Yew CHAY .ctl = 1,
1628cc72361SWai Yew CHAY .name = "Front Playback Volume",
1638cc72361SWai Yew CHAY },
1648cc72361SWai Yew CHAY [MIXER_WAVES_P] = {
1658cc72361SWai Yew CHAY .ctl = 1,
1666585db94STakashi Iwai .name = "Side Playback Volume",
1678cc72361SWai Yew CHAY },
1688cc72361SWai Yew CHAY [MIXER_WAVEC_P] = {
1698cc72361SWai Yew CHAY .ctl = 1,
1708cc72361SWai Yew CHAY .name = "Center/LFE Playback Volume",
1718cc72361SWai Yew CHAY },
1728cc72361SWai Yew CHAY [MIXER_WAVER_P] = {
1738cc72361SWai Yew CHAY .ctl = 1,
1746585db94STakashi Iwai .name = "Surround Playback Volume",
1758cc72361SWai Yew CHAY },
1768cc72361SWai Yew CHAY [MIXER_PCM_C_S] = {
1778cc72361SWai Yew CHAY .ctl = 1,
1788cc72361SWai Yew CHAY .name = "PCM Capture Switch",
1798cc72361SWai Yew CHAY },
1808cc72361SWai Yew CHAY [MIXER_LINEIN_C_S] = {
1818cc72361SWai Yew CHAY .ctl = 1,
18255309216SHarry Butterworth .name = "Line Capture Switch",
1838cc72361SWai Yew CHAY },
1848cc72361SWai Yew CHAY [MIXER_MIC_C_S] = {
1858cc72361SWai Yew CHAY .ctl = 1,
1868cc72361SWai Yew CHAY .name = "Mic Capture Switch",
1878cc72361SWai Yew CHAY },
1888cc72361SWai Yew CHAY [MIXER_SPDIFI_C_S] = {
1898cc72361SWai Yew CHAY .ctl = 1,
19055309216SHarry Butterworth .name = "IEC958 Capture Switch",
1918cc72361SWai Yew CHAY },
1928cc72361SWai Yew CHAY [MIXER_SPDIFO_P_S] = {
1938cc72361SWai Yew CHAY .ctl = 1,
19455309216SHarry Butterworth .name = "Digital Playback Switch",
1958cc72361SWai Yew CHAY },
1968cc72361SWai Yew CHAY [MIXER_WAVEF_P_S] = {
1978cc72361SWai Yew CHAY .ctl = 1,
1988cc72361SWai Yew CHAY .name = "Front Playback Switch",
1998cc72361SWai Yew CHAY },
2008cc72361SWai Yew CHAY [MIXER_WAVES_P_S] = {
2018cc72361SWai Yew CHAY .ctl = 1,
2026585db94STakashi Iwai .name = "Side Playback Switch",
2038cc72361SWai Yew CHAY },
2048cc72361SWai Yew CHAY [MIXER_WAVEC_P_S] = {
2058cc72361SWai Yew CHAY .ctl = 1,
2068cc72361SWai Yew CHAY .name = "Center/LFE Playback Switch",
2078cc72361SWai Yew CHAY },
2088cc72361SWai Yew CHAY [MIXER_WAVER_P_S] = {
2098cc72361SWai Yew CHAY .ctl = 1,
2106585db94STakashi Iwai .name = "Surround Playback Switch",
2118cc72361SWai Yew CHAY },
2128cc72361SWai Yew CHAY [MIXER_DIGITAL_IO_S] = {
2138cc72361SWai Yew CHAY .ctl = 0,
2148cc72361SWai Yew CHAY .name = "Digit-IO Playback Switch",
2158cc72361SWai Yew CHAY },
2168cc72361SWai Yew CHAY };
2178cc72361SWai Yew CHAY
2188cc72361SWai Yew CHAY static void
2198cc72361SWai Yew CHAY ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
2208cc72361SWai Yew CHAY
2218cc72361SWai Yew CHAY static void
2228cc72361SWai Yew CHAY ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
2238cc72361SWai Yew CHAY
22455309216SHarry Butterworth /* FIXME: this static looks like it would fail if more than one card was */
22555309216SHarry Butterworth /* installed. */
2268cc72361SWai Yew CHAY static struct snd_kcontrol *kctls[2] = {NULL};
2278cc72361SWai Yew CHAY
get_amixer_index(enum CTALSA_MIXER_CTL alsa_index)2288cc72361SWai Yew CHAY static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index)
2298cc72361SWai Yew CHAY {
2308cc72361SWai Yew CHAY switch (alsa_index) {
2318cc72361SWai Yew CHAY case MIXER_MASTER_P: return AMIXER_MASTER_F;
2328cc72361SWai Yew CHAY case MIXER_MASTER_C: return AMIXER_MASTER_F_C;
2338cc72361SWai Yew CHAY case MIXER_PCM_P: return AMIXER_PCM_F;
2348cc72361SWai Yew CHAY case MIXER_PCM_C:
2358cc72361SWai Yew CHAY case MIXER_PCM_C_S: return AMIXER_PCM_F_C;
2368cc72361SWai Yew CHAY case MIXER_LINEIN_P: return AMIXER_LINEIN;
2378cc72361SWai Yew CHAY case MIXER_LINEIN_C:
2388cc72361SWai Yew CHAY case MIXER_LINEIN_C_S: return AMIXER_LINEIN_C;
2398cc72361SWai Yew CHAY case MIXER_MIC_P: return AMIXER_MIC;
2408cc72361SWai Yew CHAY case MIXER_MIC_C:
2418cc72361SWai Yew CHAY case MIXER_MIC_C_S: return AMIXER_MIC_C;
2428cc72361SWai Yew CHAY case MIXER_SPDIFI_P: return AMIXER_SPDIFI;
2438cc72361SWai Yew CHAY case MIXER_SPDIFI_C:
2448cc72361SWai Yew CHAY case MIXER_SPDIFI_C_S: return AMIXER_SPDIFI_C;
2458cc72361SWai Yew CHAY case MIXER_SPDIFO_P: return AMIXER_SPDIFO;
2468cc72361SWai Yew CHAY case MIXER_WAVEF_P: return AMIXER_WAVE_F;
2478cc72361SWai Yew CHAY case MIXER_WAVES_P: return AMIXER_WAVE_S;
2488cc72361SWai Yew CHAY case MIXER_WAVEC_P: return AMIXER_WAVE_C;
2498cc72361SWai Yew CHAY case MIXER_WAVER_P: return AMIXER_WAVE_R;
2508cc72361SWai Yew CHAY default: return NUM_CT_AMIXERS;
2518cc72361SWai Yew CHAY }
2528cc72361SWai Yew CHAY }
2538cc72361SWai Yew CHAY
get_recording_amixer(enum CT_AMIXER_CTL index)2548cc72361SWai Yew CHAY static enum CT_AMIXER_CTL get_recording_amixer(enum CT_AMIXER_CTL index)
2558cc72361SWai Yew CHAY {
2568cc72361SWai Yew CHAY switch (index) {
2578cc72361SWai Yew CHAY case AMIXER_MASTER_F: return AMIXER_MASTER_F_C;
2588cc72361SWai Yew CHAY case AMIXER_PCM_F: return AMIXER_PCM_F_C;
2598cc72361SWai Yew CHAY case AMIXER_SPDIFI: return AMIXER_SPDIFI_C;
2608cc72361SWai Yew CHAY case AMIXER_LINEIN: return AMIXER_LINEIN_C;
2618cc72361SWai Yew CHAY case AMIXER_MIC: return AMIXER_MIC_C;
2628cc72361SWai Yew CHAY default: return NUM_CT_AMIXERS;
2638cc72361SWai Yew CHAY }
2648cc72361SWai Yew CHAY }
2658cc72361SWai Yew CHAY
2668cc72361SWai Yew CHAY static unsigned char
get_switch_state(struct ct_mixer * mixer,enum CTALSA_MIXER_CTL type)2678cc72361SWai Yew CHAY get_switch_state(struct ct_mixer *mixer, enum CTALSA_MIXER_CTL type)
2688cc72361SWai Yew CHAY {
2698cc72361SWai Yew CHAY return (mixer->switch_state & (0x1 << (type - SWH_MIXER_START)))
2708cc72361SWai Yew CHAY ? 1 : 0;
2718cc72361SWai Yew CHAY }
2728cc72361SWai Yew CHAY
2738cc72361SWai Yew CHAY static void
set_switch_state(struct ct_mixer * mixer,enum CTALSA_MIXER_CTL type,unsigned char state)2748cc72361SWai Yew CHAY set_switch_state(struct ct_mixer *mixer,
2758cc72361SWai Yew CHAY enum CTALSA_MIXER_CTL type, unsigned char state)
2768cc72361SWai Yew CHAY {
2778cc72361SWai Yew CHAY if (state)
2788cc72361SWai Yew CHAY mixer->switch_state |= (0x1 << (type - SWH_MIXER_START));
2798cc72361SWai Yew CHAY else
2808cc72361SWai Yew CHAY mixer->switch_state &= ~(0x1 << (type - SWH_MIXER_START));
2818cc72361SWai Yew CHAY }
2828cc72361SWai Yew CHAY
283d436dd06STakashi Iwai #if 0 /* not used */
2848cc72361SWai Yew CHAY /* Map integer value ranging from 0 to 65535 to 14-bit float value ranging
2858cc72361SWai Yew CHAY * from 2^-6 to (1+1023/1024) */
2868cc72361SWai Yew CHAY static unsigned int uint16_to_float14(unsigned int x)
2878cc72361SWai Yew CHAY {
288514eef9cSTakashi Iwai unsigned int i;
2898cc72361SWai Yew CHAY
2908cc72361SWai Yew CHAY if (x < 17)
2918cc72361SWai Yew CHAY return 0;
2928cc72361SWai Yew CHAY
2938cc72361SWai Yew CHAY x *= 2031;
2948cc72361SWai Yew CHAY x /= 65535;
2958cc72361SWai Yew CHAY x += 16;
2968cc72361SWai Yew CHAY
2978cc72361SWai Yew CHAY /* i <= 6 */
2988cc72361SWai Yew CHAY for (i = 0; !(x & 0x400); i++)
2998cc72361SWai Yew CHAY x <<= 1;
3008cc72361SWai Yew CHAY
3018cc72361SWai Yew CHAY x = (((7 - i) & 0x7) << 10) | (x & 0x3ff);
3028cc72361SWai Yew CHAY
3038cc72361SWai Yew CHAY return x;
3048cc72361SWai Yew CHAY }
3058cc72361SWai Yew CHAY
3068cc72361SWai Yew CHAY static unsigned int float14_to_uint16(unsigned int x)
3078cc72361SWai Yew CHAY {
308514eef9cSTakashi Iwai unsigned int e;
3098cc72361SWai Yew CHAY
3108cc72361SWai Yew CHAY if (!x)
3118cc72361SWai Yew CHAY return x;
3128cc72361SWai Yew CHAY
3138cc72361SWai Yew CHAY e = (x >> 10) & 0x7;
3148cc72361SWai Yew CHAY x &= 0x3ff;
3158cc72361SWai Yew CHAY x += 1024;
3168cc72361SWai Yew CHAY x >>= (7 - e);
3178cc72361SWai Yew CHAY x -= 16;
3188cc72361SWai Yew CHAY x *= 65535;
3198cc72361SWai Yew CHAY x /= 2031;
3208cc72361SWai Yew CHAY
3218cc72361SWai Yew CHAY return x;
3228cc72361SWai Yew CHAY }
323d436dd06STakashi Iwai #endif /* not used */
324d436dd06STakashi Iwai
325d436dd06STakashi Iwai #define VOL_SCALE 0x1c
326d436dd06STakashi Iwai #define VOL_MAX 0x100
327d436dd06STakashi Iwai
328d436dd06STakashi Iwai static const DECLARE_TLV_DB_SCALE(ct_vol_db_scale, -6400, 25, 1);
3298cc72361SWai Yew CHAY
ct_alsa_mix_volume_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3308cc72361SWai Yew CHAY static int ct_alsa_mix_volume_info(struct snd_kcontrol *kcontrol,
3318cc72361SWai Yew CHAY struct snd_ctl_elem_info *uinfo)
3328cc72361SWai Yew CHAY {
3338cc72361SWai Yew CHAY uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
3348cc72361SWai Yew CHAY uinfo->count = 2;
3358cc72361SWai Yew CHAY uinfo->value.integer.min = 0;
336d436dd06STakashi Iwai uinfo->value.integer.max = VOL_MAX;
3378cc72361SWai Yew CHAY
3388cc72361SWai Yew CHAY return 0;
3398cc72361SWai Yew CHAY }
3408cc72361SWai Yew CHAY
ct_alsa_mix_volume_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3418cc72361SWai Yew CHAY static int ct_alsa_mix_volume_get(struct snd_kcontrol *kcontrol,
3428cc72361SWai Yew CHAY struct snd_ctl_elem_value *ucontrol)
3438cc72361SWai Yew CHAY {
3448cc72361SWai Yew CHAY struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
3458cc72361SWai Yew CHAY enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);
346d436dd06STakashi Iwai struct amixer *amixer;
347d436dd06STakashi Iwai int i, val;
3488cc72361SWai Yew CHAY
3498cc72361SWai Yew CHAY for (i = 0; i < 2; i++) {
3508cc72361SWai Yew CHAY amixer = ((struct ct_mixer *)atc->mixer)->
3518cc72361SWai Yew CHAY amixers[type*CHN_NUM+i];
352d436dd06STakashi Iwai val = amixer->ops->get_scale(amixer) / VOL_SCALE;
353d436dd06STakashi Iwai if (val < 0)
354d436dd06STakashi Iwai val = 0;
355d436dd06STakashi Iwai else if (val > VOL_MAX)
356d436dd06STakashi Iwai val = VOL_MAX;
357d436dd06STakashi Iwai ucontrol->value.integer.value[i] = val;
3588cc72361SWai Yew CHAY }
3598cc72361SWai Yew CHAY
3608cc72361SWai Yew CHAY return 0;
3618cc72361SWai Yew CHAY }
3628cc72361SWai Yew CHAY
ct_alsa_mix_volume_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3638cc72361SWai Yew CHAY static int ct_alsa_mix_volume_put(struct snd_kcontrol *kcontrol,
3648cc72361SWai Yew CHAY struct snd_ctl_elem_value *ucontrol)
3658cc72361SWai Yew CHAY {
3668cc72361SWai Yew CHAY struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
3678cc72361SWai Yew CHAY struct ct_mixer *mixer = atc->mixer;
3688cc72361SWai Yew CHAY enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);
369d436dd06STakashi Iwai struct amixer *amixer;
370d436dd06STakashi Iwai int i, j, val, oval, change = 0;
3718cc72361SWai Yew CHAY
3728cc72361SWai Yew CHAY for (i = 0; i < 2; i++) {
373d436dd06STakashi Iwai val = ucontrol->value.integer.value[i];
374d436dd06STakashi Iwai if (val < 0)
375d436dd06STakashi Iwai val = 0;
376d436dd06STakashi Iwai else if (val > VOL_MAX)
377d436dd06STakashi Iwai val = VOL_MAX;
378d436dd06STakashi Iwai val *= VOL_SCALE;
3798cc72361SWai Yew CHAY amixer = mixer->amixers[type*CHN_NUM+i];
380d436dd06STakashi Iwai oval = amixer->ops->get_scale(amixer);
381d436dd06STakashi Iwai if (val != oval) {
3828cc72361SWai Yew CHAY amixer->ops->set_scale(amixer, val);
3838cc72361SWai Yew CHAY amixer->ops->commit_write(amixer);
3848cc72361SWai Yew CHAY change = 1;
3858cc72361SWai Yew CHAY /* Synchronize Master/PCM playback AMIXERs. */
3868cc72361SWai Yew CHAY if (AMIXER_MASTER_F == type || AMIXER_PCM_F == type) {
3878cc72361SWai Yew CHAY for (j = 1; j < 4; j++) {
3888cc72361SWai Yew CHAY amixer = mixer->
3898cc72361SWai Yew CHAY amixers[(type+j)*CHN_NUM+i];
3908cc72361SWai Yew CHAY amixer->ops->set_scale(amixer, val);
3918cc72361SWai Yew CHAY amixer->ops->commit_write(amixer);
3928cc72361SWai Yew CHAY }
3938cc72361SWai Yew CHAY }
3948cc72361SWai Yew CHAY }
3958cc72361SWai Yew CHAY }
3968cc72361SWai Yew CHAY
3978cc72361SWai Yew CHAY return change;
3988cc72361SWai Yew CHAY }
3998cc72361SWai Yew CHAY
4008cc72361SWai Yew CHAY static struct snd_kcontrol_new vol_ctl = {
401d436dd06STakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
402d436dd06STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ,
4038cc72361SWai Yew CHAY .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4048cc72361SWai Yew CHAY .info = ct_alsa_mix_volume_info,
4058cc72361SWai Yew CHAY .get = ct_alsa_mix_volume_get,
406d436dd06STakashi Iwai .put = ct_alsa_mix_volume_put,
407d436dd06STakashi Iwai .tlv = { .p = ct_vol_db_scale },
4088cc72361SWai Yew CHAY };
4098cc72361SWai Yew CHAY
output_switch_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * info)41055309216SHarry Butterworth static int output_switch_info(struct snd_kcontrol *kcontrol,
41155309216SHarry Butterworth struct snd_ctl_elem_info *info)
41255309216SHarry Butterworth {
41355309216SHarry Butterworth static const char *const names[3] = {
41455309216SHarry Butterworth "FP Headphones", "Headphones", "Speakers"
41555309216SHarry Butterworth };
41655309216SHarry Butterworth
41755309216SHarry Butterworth return snd_ctl_enum_info(info, 1, 3, names);
41855309216SHarry Butterworth }
41955309216SHarry Butterworth
output_switch_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)42055309216SHarry Butterworth static int output_switch_get(struct snd_kcontrol *kcontrol,
42155309216SHarry Butterworth struct snd_ctl_elem_value *ucontrol)
42255309216SHarry Butterworth {
42355309216SHarry Butterworth struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
42455309216SHarry Butterworth ucontrol->value.enumerated.item[0] = atc->output_switch_get(atc);
42555309216SHarry Butterworth return 0;
42655309216SHarry Butterworth }
42755309216SHarry Butterworth
output_switch_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)42855309216SHarry Butterworth static int output_switch_put(struct snd_kcontrol *kcontrol,
42955309216SHarry Butterworth struct snd_ctl_elem_value *ucontrol)
43055309216SHarry Butterworth {
43155309216SHarry Butterworth struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
43255309216SHarry Butterworth if (ucontrol->value.enumerated.item[0] > 2)
43355309216SHarry Butterworth return -EINVAL;
43455309216SHarry Butterworth return atc->output_switch_put(atc, ucontrol->value.enumerated.item[0]);
43555309216SHarry Butterworth }
43655309216SHarry Butterworth
43755309216SHarry Butterworth static struct snd_kcontrol_new output_ctl = {
43855309216SHarry Butterworth .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
43955309216SHarry Butterworth .name = "Analog Output Playback Enum",
44055309216SHarry Butterworth .info = output_switch_info,
44155309216SHarry Butterworth .get = output_switch_get,
44255309216SHarry Butterworth .put = output_switch_put,
44355309216SHarry Butterworth };
44455309216SHarry Butterworth
mic_source_switch_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * info)44555309216SHarry Butterworth static int mic_source_switch_info(struct snd_kcontrol *kcontrol,
44655309216SHarry Butterworth struct snd_ctl_elem_info *info)
44755309216SHarry Butterworth {
44855309216SHarry Butterworth static const char *const names[3] = {
44955309216SHarry Butterworth "Mic", "FP Mic", "Aux"
45055309216SHarry Butterworth };
45155309216SHarry Butterworth
45255309216SHarry Butterworth return snd_ctl_enum_info(info, 1, 3, names);
45355309216SHarry Butterworth }
45455309216SHarry Butterworth
mic_source_switch_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)45555309216SHarry Butterworth static int mic_source_switch_get(struct snd_kcontrol *kcontrol,
45655309216SHarry Butterworth struct snd_ctl_elem_value *ucontrol)
45755309216SHarry Butterworth {
45855309216SHarry Butterworth struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
45955309216SHarry Butterworth ucontrol->value.enumerated.item[0] = atc->mic_source_switch_get(atc);
46055309216SHarry Butterworth return 0;
46155309216SHarry Butterworth }
46255309216SHarry Butterworth
mic_source_switch_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)46355309216SHarry Butterworth static int mic_source_switch_put(struct snd_kcontrol *kcontrol,
46455309216SHarry Butterworth struct snd_ctl_elem_value *ucontrol)
46555309216SHarry Butterworth {
46655309216SHarry Butterworth struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
46755309216SHarry Butterworth if (ucontrol->value.enumerated.item[0] > 2)
46855309216SHarry Butterworth return -EINVAL;
46955309216SHarry Butterworth return atc->mic_source_switch_put(atc,
47055309216SHarry Butterworth ucontrol->value.enumerated.item[0]);
47155309216SHarry Butterworth }
47255309216SHarry Butterworth
47355309216SHarry Butterworth static struct snd_kcontrol_new mic_source_ctl = {
47455309216SHarry Butterworth .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
47555309216SHarry Butterworth .name = "Mic Source Capture Enum",
47655309216SHarry Butterworth .info = mic_source_switch_info,
47755309216SHarry Butterworth .get = mic_source_switch_get,
47855309216SHarry Butterworth .put = mic_source_switch_put,
47955309216SHarry Butterworth };
48055309216SHarry Butterworth
4818cc72361SWai Yew CHAY static void
do_line_mic_switch(struct ct_atc * atc,enum CTALSA_MIXER_CTL type)4828cc72361SWai Yew CHAY do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type)
4838cc72361SWai Yew CHAY {
4848cc72361SWai Yew CHAY
4858cc72361SWai Yew CHAY if (MIXER_LINEIN_C_S == type) {
4868cc72361SWai Yew CHAY atc->select_line_in(atc);
4878cc72361SWai Yew CHAY set_switch_state(atc->mixer, MIXER_MIC_C_S, 0);
4888cc72361SWai Yew CHAY snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
4898cc72361SWai Yew CHAY &kctls[1]->id);
4908cc72361SWai Yew CHAY } else if (MIXER_MIC_C_S == type) {
4918cc72361SWai Yew CHAY atc->select_mic_in(atc);
4928cc72361SWai Yew CHAY set_switch_state(atc->mixer, MIXER_LINEIN_C_S, 0);
4938cc72361SWai Yew CHAY snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
4948cc72361SWai Yew CHAY &kctls[0]->id);
4958cc72361SWai Yew CHAY }
4968cc72361SWai Yew CHAY }
4978cc72361SWai Yew CHAY
4988cc72361SWai Yew CHAY static void
do_digit_io_switch(struct ct_atc * atc,int state)4998cc72361SWai Yew CHAY do_digit_io_switch(struct ct_atc *atc, int state)
5008cc72361SWai Yew CHAY {
5018cc72361SWai Yew CHAY struct ct_mixer *mixer = atc->mixer;
5028cc72361SWai Yew CHAY
5038cc72361SWai Yew CHAY if (state) {
5048cc72361SWai Yew CHAY atc->select_digit_io(atc);
5058cc72361SWai Yew CHAY atc->spdif_out_unmute(atc,
5068cc72361SWai Yew CHAY get_switch_state(mixer, MIXER_SPDIFO_P_S));
5078cc72361SWai Yew CHAY atc->spdif_in_unmute(atc, 1);
5088cc72361SWai Yew CHAY atc->line_in_unmute(atc, 0);
5098cc72361SWai Yew CHAY return;
5108cc72361SWai Yew CHAY }
5118cc72361SWai Yew CHAY
5128cc72361SWai Yew CHAY if (get_switch_state(mixer, MIXER_LINEIN_C_S))
5138cc72361SWai Yew CHAY atc->select_line_in(atc);
5148cc72361SWai Yew CHAY else if (get_switch_state(mixer, MIXER_MIC_C_S))
5158cc72361SWai Yew CHAY atc->select_mic_in(atc);
5168cc72361SWai Yew CHAY
5178cc72361SWai Yew CHAY atc->spdif_out_unmute(atc, 0);
5188cc72361SWai Yew CHAY atc->spdif_in_unmute(atc, 0);
5198cc72361SWai Yew CHAY atc->line_in_unmute(atc, 1);
5208cc72361SWai Yew CHAY return;
5218cc72361SWai Yew CHAY }
5228cc72361SWai Yew CHAY
do_switch(struct ct_atc * atc,enum CTALSA_MIXER_CTL type,int state)52329959a09SWai Yew CHAY static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
52429959a09SWai Yew CHAY {
52529959a09SWai Yew CHAY struct ct_mixer *mixer = atc->mixer;
526b028b818SHarry Butterworth struct capabilities cap = atc->capabilities(atc);
52729959a09SWai Yew CHAY
52829959a09SWai Yew CHAY /* Do changes in mixer. */
52929959a09SWai Yew CHAY if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {
53029959a09SWai Yew CHAY if (state) {
53129959a09SWai Yew CHAY ct_mixer_recording_select(mixer,
53229959a09SWai Yew CHAY get_amixer_index(type));
53329959a09SWai Yew CHAY } else {
53429959a09SWai Yew CHAY ct_mixer_recording_unselect(mixer,
53529959a09SWai Yew CHAY get_amixer_index(type));
53629959a09SWai Yew CHAY }
53729959a09SWai Yew CHAY }
53829959a09SWai Yew CHAY /* Do changes out of mixer. */
539b028b818SHarry Butterworth if (!cap.dedicated_mic &&
54055309216SHarry Butterworth (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) {
54155309216SHarry Butterworth if (state)
54229959a09SWai Yew CHAY do_line_mic_switch(atc, type);
54355309216SHarry Butterworth atc->line_in_unmute(atc, state);
544b028b818SHarry Butterworth } else if (cap.dedicated_mic && (MIXER_LINEIN_C_S == type))
54555309216SHarry Butterworth atc->line_in_unmute(atc, state);
546b028b818SHarry Butterworth else if (cap.dedicated_mic && (MIXER_MIC_C_S == type))
54755309216SHarry Butterworth atc->mic_unmute(atc, state);
54855309216SHarry Butterworth else if (MIXER_SPDIFI_C_S == type)
54955309216SHarry Butterworth atc->spdif_in_unmute(atc, state);
55029959a09SWai Yew CHAY else if (MIXER_WAVEF_P_S == type)
55129959a09SWai Yew CHAY atc->line_front_unmute(atc, state);
55229959a09SWai Yew CHAY else if (MIXER_WAVES_P_S == type)
55329959a09SWai Yew CHAY atc->line_surround_unmute(atc, state);
55429959a09SWai Yew CHAY else if (MIXER_WAVEC_P_S == type)
55529959a09SWai Yew CHAY atc->line_clfe_unmute(atc, state);
55629959a09SWai Yew CHAY else if (MIXER_WAVER_P_S == type)
55729959a09SWai Yew CHAY atc->line_rear_unmute(atc, state);
55829959a09SWai Yew CHAY else if (MIXER_SPDIFO_P_S == type)
55929959a09SWai Yew CHAY atc->spdif_out_unmute(atc, state);
56029959a09SWai Yew CHAY else if (MIXER_DIGITAL_IO_S == type)
56129959a09SWai Yew CHAY do_digit_io_switch(atc, state);
56229959a09SWai Yew CHAY
56329959a09SWai Yew CHAY return;
56429959a09SWai Yew CHAY }
56529959a09SWai Yew CHAY
ct_alsa_mix_switch_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)5668cc72361SWai Yew CHAY static int ct_alsa_mix_switch_info(struct snd_kcontrol *kcontrol,
5678cc72361SWai Yew CHAY struct snd_ctl_elem_info *uinfo)
5688cc72361SWai Yew CHAY {
5698cc72361SWai Yew CHAY uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
5708cc72361SWai Yew CHAY uinfo->count = 1;
5718cc72361SWai Yew CHAY uinfo->value.integer.min = 0;
5728cc72361SWai Yew CHAY uinfo->value.integer.max = 1;
5738cc72361SWai Yew CHAY uinfo->value.integer.step = 1;
5748cc72361SWai Yew CHAY
5758cc72361SWai Yew CHAY return 0;
5768cc72361SWai Yew CHAY }
5778cc72361SWai Yew CHAY
ct_alsa_mix_switch_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)5788cc72361SWai Yew CHAY static int ct_alsa_mix_switch_get(struct snd_kcontrol *kcontrol,
5798cc72361SWai Yew CHAY struct snd_ctl_elem_value *ucontrol)
5808cc72361SWai Yew CHAY {
5818cc72361SWai Yew CHAY struct ct_mixer *mixer =
5828cc72361SWai Yew CHAY ((struct ct_atc *)snd_kcontrol_chip(kcontrol))->mixer;
5838cc72361SWai Yew CHAY enum CTALSA_MIXER_CTL type = kcontrol->private_value;
5848cc72361SWai Yew CHAY
5858cc72361SWai Yew CHAY ucontrol->value.integer.value[0] = get_switch_state(mixer, type);
5868cc72361SWai Yew CHAY return 0;
5878cc72361SWai Yew CHAY }
5888cc72361SWai Yew CHAY
ct_alsa_mix_switch_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)5898cc72361SWai Yew CHAY static int ct_alsa_mix_switch_put(struct snd_kcontrol *kcontrol,
5908cc72361SWai Yew CHAY struct snd_ctl_elem_value *ucontrol)
5918cc72361SWai Yew CHAY {
5928cc72361SWai Yew CHAY struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
5938cc72361SWai Yew CHAY struct ct_mixer *mixer = atc->mixer;
5948cc72361SWai Yew CHAY enum CTALSA_MIXER_CTL type = kcontrol->private_value;
595514eef9cSTakashi Iwai int state;
5968cc72361SWai Yew CHAY
5978cc72361SWai Yew CHAY state = ucontrol->value.integer.value[0];
5988cc72361SWai Yew CHAY if (get_switch_state(mixer, type) == state)
5998cc72361SWai Yew CHAY return 0;
6008cc72361SWai Yew CHAY
6018cc72361SWai Yew CHAY set_switch_state(mixer, type, state);
60229959a09SWai Yew CHAY do_switch(atc, type, state);
6038cc72361SWai Yew CHAY
6048cc72361SWai Yew CHAY return 1;
6058cc72361SWai Yew CHAY }
6068cc72361SWai Yew CHAY
6078cc72361SWai Yew CHAY static struct snd_kcontrol_new swh_ctl = {
6088cc72361SWai Yew CHAY .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
6098cc72361SWai Yew CHAY .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6108cc72361SWai Yew CHAY .info = ct_alsa_mix_switch_info,
6118cc72361SWai Yew CHAY .get = ct_alsa_mix_switch_get,
6128cc72361SWai Yew CHAY .put = ct_alsa_mix_switch_put
6138cc72361SWai Yew CHAY };
6148cc72361SWai Yew CHAY
ct_spdif_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)6158cc72361SWai Yew CHAY static int ct_spdif_info(struct snd_kcontrol *kcontrol,
6168cc72361SWai Yew CHAY struct snd_ctl_elem_info *uinfo)
6178cc72361SWai Yew CHAY {
6188cc72361SWai Yew CHAY uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
6198cc72361SWai Yew CHAY uinfo->count = 1;
6208cc72361SWai Yew CHAY return 0;
6218cc72361SWai Yew CHAY }
6228cc72361SWai Yew CHAY
ct_spdif_get_mask(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6238cc72361SWai Yew CHAY static int ct_spdif_get_mask(struct snd_kcontrol *kcontrol,
6248cc72361SWai Yew CHAY struct snd_ctl_elem_value *ucontrol)
6258cc72361SWai Yew CHAY {
6268cc72361SWai Yew CHAY ucontrol->value.iec958.status[0] = 0xff;
6278cc72361SWai Yew CHAY ucontrol->value.iec958.status[1] = 0xff;
6288cc72361SWai Yew CHAY ucontrol->value.iec958.status[2] = 0xff;
6298cc72361SWai Yew CHAY ucontrol->value.iec958.status[3] = 0xff;
6308cc72361SWai Yew CHAY return 0;
6318cc72361SWai Yew CHAY }
6328cc72361SWai Yew CHAY
ct_spdif_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6338cc72361SWai Yew CHAY static int ct_spdif_get(struct snd_kcontrol *kcontrol,
6348cc72361SWai Yew CHAY struct snd_ctl_elem_value *ucontrol)
6358cc72361SWai Yew CHAY {
6368cc72361SWai Yew CHAY struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
637514eef9cSTakashi Iwai unsigned int status;
6388cc72361SWai Yew CHAY
6398cc72361SWai Yew CHAY atc->spdif_out_get_status(atc, &status);
640f164753aSPrzemyslaw Bruski
641f164753aSPrzemyslaw Bruski if (status == 0)
642f164753aSPrzemyslaw Bruski status = SNDRV_PCM_DEFAULT_CON_SPDIF;
643f164753aSPrzemyslaw Bruski
6448cc72361SWai Yew CHAY ucontrol->value.iec958.status[0] = (status >> 0) & 0xff;
6458cc72361SWai Yew CHAY ucontrol->value.iec958.status[1] = (status >> 8) & 0xff;
6468cc72361SWai Yew CHAY ucontrol->value.iec958.status[2] = (status >> 16) & 0xff;
6478cc72361SWai Yew CHAY ucontrol->value.iec958.status[3] = (status >> 24) & 0xff;
6488cc72361SWai Yew CHAY
6498cc72361SWai Yew CHAY return 0;
6508cc72361SWai Yew CHAY }
6518cc72361SWai Yew CHAY
ct_spdif_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6528cc72361SWai Yew CHAY static int ct_spdif_put(struct snd_kcontrol *kcontrol,
6538cc72361SWai Yew CHAY struct snd_ctl_elem_value *ucontrol)
6548cc72361SWai Yew CHAY {
6558cc72361SWai Yew CHAY struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
656514eef9cSTakashi Iwai int change;
657514eef9cSTakashi Iwai unsigned int status, old_status;
6588cc72361SWai Yew CHAY
6598cc72361SWai Yew CHAY status = (ucontrol->value.iec958.status[0] << 0) |
6608cc72361SWai Yew CHAY (ucontrol->value.iec958.status[1] << 8) |
6618cc72361SWai Yew CHAY (ucontrol->value.iec958.status[2] << 16) |
6628cc72361SWai Yew CHAY (ucontrol->value.iec958.status[3] << 24);
6638cc72361SWai Yew CHAY
6648cc72361SWai Yew CHAY atc->spdif_out_get_status(atc, &old_status);
6658cc72361SWai Yew CHAY change = (old_status != status);
6668cc72361SWai Yew CHAY if (change)
6678cc72361SWai Yew CHAY atc->spdif_out_set_status(atc, status);
6688cc72361SWai Yew CHAY
6698cc72361SWai Yew CHAY return change;
6708cc72361SWai Yew CHAY }
6718cc72361SWai Yew CHAY
6728cc72361SWai Yew CHAY static struct snd_kcontrol_new iec958_mask_ctl = {
6738cc72361SWai Yew CHAY .access = SNDRV_CTL_ELEM_ACCESS_READ,
6748cc72361SWai Yew CHAY .iface = SNDRV_CTL_ELEM_IFACE_PCM,
6758cc72361SWai Yew CHAY .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
6768cc72361SWai Yew CHAY .count = 1,
6778cc72361SWai Yew CHAY .info = ct_spdif_info,
6788cc72361SWai Yew CHAY .get = ct_spdif_get_mask,
6798cc72361SWai Yew CHAY .private_value = MIXER_IEC958_MASK
6808cc72361SWai Yew CHAY };
6818cc72361SWai Yew CHAY
6828cc72361SWai Yew CHAY static struct snd_kcontrol_new iec958_default_ctl = {
6838cc72361SWai Yew CHAY .iface = SNDRV_CTL_ELEM_IFACE_PCM,
6848cc72361SWai Yew CHAY .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
6858cc72361SWai Yew CHAY .count = 1,
6868cc72361SWai Yew CHAY .info = ct_spdif_info,
687f164753aSPrzemyslaw Bruski .get = ct_spdif_get,
6888cc72361SWai Yew CHAY .put = ct_spdif_put,
6898cc72361SWai Yew CHAY .private_value = MIXER_IEC958_DEFAULT
6908cc72361SWai Yew CHAY };
6918cc72361SWai Yew CHAY
6928cc72361SWai Yew CHAY static struct snd_kcontrol_new iec958_ctl = {
6938cc72361SWai Yew CHAY .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
6948cc72361SWai Yew CHAY .iface = SNDRV_CTL_ELEM_IFACE_PCM,
6958cc72361SWai Yew CHAY .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
6968cc72361SWai Yew CHAY .count = 1,
6978cc72361SWai Yew CHAY .info = ct_spdif_info,
6988cc72361SWai Yew CHAY .get = ct_spdif_get,
6998cc72361SWai Yew CHAY .put = ct_spdif_put,
7008cc72361SWai Yew CHAY .private_value = MIXER_IEC958_STREAM
7018cc72361SWai Yew CHAY };
7028cc72361SWai Yew CHAY
7038cc72361SWai Yew CHAY #define NUM_IEC958_CTL 3
7048cc72361SWai Yew CHAY
7058cc72361SWai Yew CHAY static int
ct_mixer_kcontrol_new(struct ct_mixer * mixer,struct snd_kcontrol_new * new)7068cc72361SWai Yew CHAY ct_mixer_kcontrol_new(struct ct_mixer *mixer, struct snd_kcontrol_new *new)
7078cc72361SWai Yew CHAY {
708514eef9cSTakashi Iwai struct snd_kcontrol *kctl;
709514eef9cSTakashi Iwai int err;
7108cc72361SWai Yew CHAY
7118cc72361SWai Yew CHAY kctl = snd_ctl_new1(new, mixer->atc);
71235ebf6e7STakashi Iwai if (!kctl)
7138cc72361SWai Yew CHAY return -ENOMEM;
7148cc72361SWai Yew CHAY
7158cc72361SWai Yew CHAY if (SNDRV_CTL_ELEM_IFACE_PCM == kctl->id.iface)
7168cc72361SWai Yew CHAY kctl->id.device = IEC958;
7178cc72361SWai Yew CHAY
7188cc72361SWai Yew CHAY err = snd_ctl_add(mixer->atc->card, kctl);
7198cc72361SWai Yew CHAY if (err)
7208cc72361SWai Yew CHAY return err;
7218cc72361SWai Yew CHAY
7228cc72361SWai Yew CHAY switch (new->private_value) {
7238cc72361SWai Yew CHAY case MIXER_LINEIN_C_S:
7248cc72361SWai Yew CHAY kctls[0] = kctl; break;
7258cc72361SWai Yew CHAY case MIXER_MIC_C_S:
7268cc72361SWai Yew CHAY kctls[1] = kctl; break;
7278cc72361SWai Yew CHAY default:
7288cc72361SWai Yew CHAY break;
7298cc72361SWai Yew CHAY }
7308cc72361SWai Yew CHAY
7318cc72361SWai Yew CHAY return 0;
7328cc72361SWai Yew CHAY }
7338cc72361SWai Yew CHAY
ct_mixer_kcontrols_create(struct ct_mixer * mixer)7348cc72361SWai Yew CHAY static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
7358cc72361SWai Yew CHAY {
736514eef9cSTakashi Iwai enum CTALSA_MIXER_CTL type;
7378cc72361SWai Yew CHAY struct ct_atc *atc = mixer->atc;
738b028b818SHarry Butterworth struct capabilities cap = atc->capabilities(atc);
739514eef9cSTakashi Iwai int err;
7408cc72361SWai Yew CHAY
7418cc72361SWai Yew CHAY /* Create snd kcontrol instances on demand */
7428cc72361SWai Yew CHAY for (type = VOL_MIXER_START; type <= VOL_MIXER_END; type++) {
7438cc72361SWai Yew CHAY if (ct_kcontrol_init_table[type].ctl) {
7448cc72361SWai Yew CHAY vol_ctl.name = ct_kcontrol_init_table[type].name;
7458cc72361SWai Yew CHAY vol_ctl.private_value = (unsigned long)type;
7468cc72361SWai Yew CHAY err = ct_mixer_kcontrol_new(mixer, &vol_ctl);
7478cc72361SWai Yew CHAY if (err)
7488cc72361SWai Yew CHAY return err;
7498cc72361SWai Yew CHAY }
7508cc72361SWai Yew CHAY }
7518cc72361SWai Yew CHAY
752b028b818SHarry Butterworth ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = cap.digit_io_switch;
75355309216SHarry Butterworth
7548cc72361SWai Yew CHAY for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) {
7558cc72361SWai Yew CHAY if (ct_kcontrol_init_table[type].ctl) {
7568cc72361SWai Yew CHAY swh_ctl.name = ct_kcontrol_init_table[type].name;
7578cc72361SWai Yew CHAY swh_ctl.private_value = (unsigned long)type;
7588cc72361SWai Yew CHAY err = ct_mixer_kcontrol_new(mixer, &swh_ctl);
7598cc72361SWai Yew CHAY if (err)
7608cc72361SWai Yew CHAY return err;
7618cc72361SWai Yew CHAY }
7628cc72361SWai Yew CHAY }
7638cc72361SWai Yew CHAY
7648cc72361SWai Yew CHAY err = ct_mixer_kcontrol_new(mixer, &iec958_mask_ctl);
7658cc72361SWai Yew CHAY if (err)
7668cc72361SWai Yew CHAY return err;
7678cc72361SWai Yew CHAY
7688cc72361SWai Yew CHAY err = ct_mixer_kcontrol_new(mixer, &iec958_default_ctl);
7698cc72361SWai Yew CHAY if (err)
7708cc72361SWai Yew CHAY return err;
7718cc72361SWai Yew CHAY
7728cc72361SWai Yew CHAY err = ct_mixer_kcontrol_new(mixer, &iec958_ctl);
7738cc72361SWai Yew CHAY if (err)
7748cc72361SWai Yew CHAY return err;
7758cc72361SWai Yew CHAY
776b028b818SHarry Butterworth if (cap.output_switch) {
77755309216SHarry Butterworth err = ct_mixer_kcontrol_new(mixer, &output_ctl);
77855309216SHarry Butterworth if (err)
77955309216SHarry Butterworth return err;
78055309216SHarry Butterworth }
78155309216SHarry Butterworth
782b028b818SHarry Butterworth if (cap.mic_source_switch) {
78355309216SHarry Butterworth err = ct_mixer_kcontrol_new(mixer, &mic_source_ctl);
78455309216SHarry Butterworth if (err)
78555309216SHarry Butterworth return err;
78655309216SHarry Butterworth }
7878cc72361SWai Yew CHAY atc->line_front_unmute(atc, 1);
7888cc72361SWai Yew CHAY set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
7898cc72361SWai Yew CHAY atc->line_surround_unmute(atc, 0);
7908cc72361SWai Yew CHAY set_switch_state(mixer, MIXER_WAVES_P_S, 0);
7918cc72361SWai Yew CHAY atc->line_clfe_unmute(atc, 0);
7928cc72361SWai Yew CHAY set_switch_state(mixer, MIXER_WAVEC_P_S, 0);
7938cc72361SWai Yew CHAY atc->line_rear_unmute(atc, 0);
7948cc72361SWai Yew CHAY set_switch_state(mixer, MIXER_WAVER_P_S, 0);
7958cc72361SWai Yew CHAY atc->spdif_out_unmute(atc, 0);
7968cc72361SWai Yew CHAY set_switch_state(mixer, MIXER_SPDIFO_P_S, 0);
7978cc72361SWai Yew CHAY atc->line_in_unmute(atc, 0);
798b028b818SHarry Butterworth if (cap.dedicated_mic)
79955309216SHarry Butterworth atc->mic_unmute(atc, 0);
8008cc72361SWai Yew CHAY atc->spdif_in_unmute(atc, 0);
80155309216SHarry Butterworth set_switch_state(mixer, MIXER_PCM_C_S, 0);
80255309216SHarry Butterworth set_switch_state(mixer, MIXER_LINEIN_C_S, 0);
80355309216SHarry Butterworth set_switch_state(mixer, MIXER_SPDIFI_C_S, 0);
8048cc72361SWai Yew CHAY
8058cc72361SWai Yew CHAY return 0;
8068cc72361SWai Yew CHAY }
8078cc72361SWai Yew CHAY
8088cc72361SWai Yew CHAY static void
ct_mixer_recording_select(struct ct_mixer * mixer,enum CT_AMIXER_CTL type)8098cc72361SWai Yew CHAY ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)
8108cc72361SWai Yew CHAY {
811514eef9cSTakashi Iwai struct amixer *amix_d;
812514eef9cSTakashi Iwai struct sum *sum_c;
813514eef9cSTakashi Iwai int i;
8148cc72361SWai Yew CHAY
8158cc72361SWai Yew CHAY for (i = 0; i < 2; i++) {
8168cc72361SWai Yew CHAY amix_d = mixer->amixers[type*CHN_NUM+i];
8178cc72361SWai Yew CHAY sum_c = mixer->sums[SUM_IN_F_C*CHN_NUM+i];
8188cc72361SWai Yew CHAY amix_d->ops->set_sum(amix_d, sum_c);
8198cc72361SWai Yew CHAY amix_d->ops->commit_write(amix_d);
8208cc72361SWai Yew CHAY }
8218cc72361SWai Yew CHAY }
8228cc72361SWai Yew CHAY
8238cc72361SWai Yew CHAY static void
ct_mixer_recording_unselect(struct ct_mixer * mixer,enum CT_AMIXER_CTL type)8248cc72361SWai Yew CHAY ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)
8258cc72361SWai Yew CHAY {
826514eef9cSTakashi Iwai struct amixer *amix_d;
827514eef9cSTakashi Iwai int i;
8288cc72361SWai Yew CHAY
8298cc72361SWai Yew CHAY for (i = 0; i < 2; i++) {
8308cc72361SWai Yew CHAY amix_d = mixer->amixers[type*CHN_NUM+i];
8318cc72361SWai Yew CHAY amix_d->ops->set_sum(amix_d, NULL);
8328cc72361SWai Yew CHAY amix_d->ops->commit_write(amix_d);
8338cc72361SWai Yew CHAY }
8348cc72361SWai Yew CHAY }
8358cc72361SWai Yew CHAY
ct_mixer_get_resources(struct ct_mixer * mixer)8368cc72361SWai Yew CHAY static int ct_mixer_get_resources(struct ct_mixer *mixer)
8378cc72361SWai Yew CHAY {
838514eef9cSTakashi Iwai struct sum_mgr *sum_mgr;
839514eef9cSTakashi Iwai struct sum *sum;
8408cc72361SWai Yew CHAY struct sum_desc sum_desc = {0};
841514eef9cSTakashi Iwai struct amixer_mgr *amixer_mgr;
842514eef9cSTakashi Iwai struct amixer *amixer;
8438cc72361SWai Yew CHAY struct amixer_desc am_desc = {0};
844514eef9cSTakashi Iwai int err;
845514eef9cSTakashi Iwai int i;
8468cc72361SWai Yew CHAY
8478cc72361SWai Yew CHAY /* Allocate sum resources for mixer obj */
8488cc72361SWai Yew CHAY sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
8498cc72361SWai Yew CHAY sum_desc.msr = mixer->atc->msr;
8508cc72361SWai Yew CHAY for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
8518cc72361SWai Yew CHAY err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum);
8528cc72361SWai Yew CHAY if (err) {
8530cae90a9SSudip Mukherjee dev_err(mixer->atc->card->dev,
8540cae90a9SSudip Mukherjee "Failed to get sum resources for front output!\n");
8558cc72361SWai Yew CHAY break;
8568cc72361SWai Yew CHAY }
8578cc72361SWai Yew CHAY mixer->sums[i] = sum;
8588cc72361SWai Yew CHAY }
8598cc72361SWai Yew CHAY if (err)
8608cc72361SWai Yew CHAY goto error1;
8618cc72361SWai Yew CHAY
8628cc72361SWai Yew CHAY /* Allocate amixer resources for mixer obj */
8638cc72361SWai Yew CHAY amixer_mgr = (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];
8648cc72361SWai Yew CHAY am_desc.msr = mixer->atc->msr;
8658cc72361SWai Yew CHAY for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
8668cc72361SWai Yew CHAY err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer);
8678cc72361SWai Yew CHAY if (err) {
8680cae90a9SSudip Mukherjee dev_err(mixer->atc->card->dev,
8690cae90a9SSudip Mukherjee "Failed to get amixer resources for mixer obj!\n");
8708cc72361SWai Yew CHAY break;
8718cc72361SWai Yew CHAY }
8728cc72361SWai Yew CHAY mixer->amixers[i] = amixer;
8738cc72361SWai Yew CHAY }
8748cc72361SWai Yew CHAY if (err)
8758cc72361SWai Yew CHAY goto error2;
8768cc72361SWai Yew CHAY
8778cc72361SWai Yew CHAY return 0;
8788cc72361SWai Yew CHAY
8798cc72361SWai Yew CHAY error2:
8808cc72361SWai Yew CHAY for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
8818cc72361SWai Yew CHAY if (NULL != mixer->amixers[i]) {
8828cc72361SWai Yew CHAY amixer = mixer->amixers[i];
8838cc72361SWai Yew CHAY amixer_mgr->put_amixer(amixer_mgr, amixer);
8848cc72361SWai Yew CHAY mixer->amixers[i] = NULL;
8858cc72361SWai Yew CHAY }
8868cc72361SWai Yew CHAY }
8878cc72361SWai Yew CHAY error1:
8888cc72361SWai Yew CHAY for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
8898cc72361SWai Yew CHAY if (NULL != mixer->sums[i]) {
8908cc72361SWai Yew CHAY sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);
8918cc72361SWai Yew CHAY mixer->sums[i] = NULL;
8928cc72361SWai Yew CHAY }
8938cc72361SWai Yew CHAY }
8948cc72361SWai Yew CHAY
8958cc72361SWai Yew CHAY return err;
8968cc72361SWai Yew CHAY }
8978cc72361SWai Yew CHAY
ct_mixer_get_mem(struct ct_mixer ** rmixer)8988cc72361SWai Yew CHAY static int ct_mixer_get_mem(struct ct_mixer **rmixer)
8998cc72361SWai Yew CHAY {
900514eef9cSTakashi Iwai struct ct_mixer *mixer;
901514eef9cSTakashi Iwai int err;
9028cc72361SWai Yew CHAY
9038cc72361SWai Yew CHAY *rmixer = NULL;
9048cc72361SWai Yew CHAY /* Allocate mem for mixer obj */
9058cc72361SWai Yew CHAY mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
90635ebf6e7STakashi Iwai if (!mixer)
9078cc72361SWai Yew CHAY return -ENOMEM;
9088cc72361SWai Yew CHAY
9096396bb22SKees Cook mixer->amixers = kcalloc(NUM_CT_AMIXERS * CHN_NUM, sizeof(void *),
9108cc72361SWai Yew CHAY GFP_KERNEL);
91135ebf6e7STakashi Iwai if (!mixer->amixers) {
9128cc72361SWai Yew CHAY err = -ENOMEM;
9138cc72361SWai Yew CHAY goto error1;
9148cc72361SWai Yew CHAY }
9156396bb22SKees Cook mixer->sums = kcalloc(NUM_CT_SUMS * CHN_NUM, sizeof(void *),
9166396bb22SKees Cook GFP_KERNEL);
91735ebf6e7STakashi Iwai if (!mixer->sums) {
9188cc72361SWai Yew CHAY err = -ENOMEM;
9198cc72361SWai Yew CHAY goto error2;
9208cc72361SWai Yew CHAY }
9218cc72361SWai Yew CHAY
9228cc72361SWai Yew CHAY *rmixer = mixer;
9238cc72361SWai Yew CHAY return 0;
9248cc72361SWai Yew CHAY
9258cc72361SWai Yew CHAY error2:
9268cc72361SWai Yew CHAY kfree(mixer->amixers);
9278cc72361SWai Yew CHAY error1:
9288cc72361SWai Yew CHAY kfree(mixer);
9298cc72361SWai Yew CHAY return err;
9308cc72361SWai Yew CHAY }
9318cc72361SWai Yew CHAY
ct_mixer_topology_build(struct ct_mixer * mixer)9328cc72361SWai Yew CHAY static int ct_mixer_topology_build(struct ct_mixer *mixer)
9338cc72361SWai Yew CHAY {
934514eef9cSTakashi Iwai struct sum *sum;
935514eef9cSTakashi Iwai struct amixer *amix_d, *amix_s;
936514eef9cSTakashi Iwai enum CT_AMIXER_CTL i, j;
937a753af30SStefan Agner enum CT_SUM_CTL k;
9388cc72361SWai Yew CHAY
9398cc72361SWai Yew CHAY /* Build topology from destination to source */
9408cc72361SWai Yew CHAY
9418cc72361SWai Yew CHAY /* Set up Master mixer */
942a753af30SStefan Agner for (i = AMIXER_MASTER_F, k = SUM_IN_F;
943a753af30SStefan Agner i <= AMIXER_MASTER_S; i++, k++) {
9448cc72361SWai Yew CHAY amix_d = mixer->amixers[i*CHN_NUM];
945a753af30SStefan Agner sum = mixer->sums[k*CHN_NUM];
9468cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
9478cc72361SWai Yew CHAY amix_d = mixer->amixers[i*CHN_NUM+1];
948a753af30SStefan Agner sum = mixer->sums[k*CHN_NUM+1];
9498cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
9508cc72361SWai Yew CHAY }
9518cc72361SWai Yew CHAY
9528cc72361SWai Yew CHAY /* Set up Wave-out mixer */
9538cc72361SWai Yew CHAY for (i = AMIXER_WAVE_F, j = AMIXER_MASTER_F;
9548cc72361SWai Yew CHAY i <= AMIXER_WAVE_S; i++, j++) {
9558cc72361SWai Yew CHAY amix_d = mixer->amixers[i*CHN_NUM];
9568cc72361SWai Yew CHAY amix_s = mixer->amixers[j*CHN_NUM];
9578cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
9588cc72361SWai Yew CHAY amix_d = mixer->amixers[i*CHN_NUM+1];
9598cc72361SWai Yew CHAY amix_s = mixer->amixers[j*CHN_NUM+1];
9608cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
9618cc72361SWai Yew CHAY }
9628cc72361SWai Yew CHAY
9638cc72361SWai Yew CHAY /* Set up S/PDIF-out mixer */
9648cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM];
9658cc72361SWai Yew CHAY amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM];
9668cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
9678cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM+1];
9688cc72361SWai Yew CHAY amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM+1];
9698cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
9708cc72361SWai Yew CHAY
9718cc72361SWai Yew CHAY /* Set up PCM-in mixer */
972a753af30SStefan Agner for (i = AMIXER_PCM_F, k = SUM_IN_F; i <= AMIXER_PCM_S; i++, k++) {
9738cc72361SWai Yew CHAY amix_d = mixer->amixers[i*CHN_NUM];
974a753af30SStefan Agner sum = mixer->sums[k*CHN_NUM];
9758cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
9768cc72361SWai Yew CHAY amix_d = mixer->amixers[i*CHN_NUM+1];
977a753af30SStefan Agner sum = mixer->sums[k*CHN_NUM+1];
9788cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
9798cc72361SWai Yew CHAY }
9808cc72361SWai Yew CHAY
9818cc72361SWai Yew CHAY /* Set up Line-in mixer */
9828cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM];
9838cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F*CHN_NUM];
9848cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
9858cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM+1];
9868cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
9878cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
9888cc72361SWai Yew CHAY
9898cc72361SWai Yew CHAY /* Set up Mic-in mixer */
9908cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM];
9918cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F*CHN_NUM];
9928cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
9938cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM+1];
9948cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
9958cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
9968cc72361SWai Yew CHAY
9978cc72361SWai Yew CHAY /* Set up S/PDIF-in mixer */
9988cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM];
9998cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F*CHN_NUM];
10008cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
10018cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM+1];
10028cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
10038cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
10048cc72361SWai Yew CHAY
10058cc72361SWai Yew CHAY /* Set up Master recording mixer */
10068cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM];
10078cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
10088cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
10098cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM+1];
10108cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
10118cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
10128cc72361SWai Yew CHAY
10138cc72361SWai Yew CHAY /* Set up PCM-in recording mixer */
10148cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM];
10158cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
10168cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
10178cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM+1];
10188cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
10198cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
10208cc72361SWai Yew CHAY
10218cc72361SWai Yew CHAY /* Set up Line-in recording mixer */
10228cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM];
10238cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
10248cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
10258cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM+1];
10268cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
10278cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
10288cc72361SWai Yew CHAY
10298cc72361SWai Yew CHAY /* Set up Mic-in recording mixer */
10308cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM];
10318cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
10328cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
10338cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM+1];
10348cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
10358cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
10368cc72361SWai Yew CHAY
10378cc72361SWai Yew CHAY /* Set up S/PDIF-in recording mixer */
10388cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM];
10398cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
10408cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
10418cc72361SWai Yew CHAY amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM+1];
10428cc72361SWai Yew CHAY sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
10438cc72361SWai Yew CHAY amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
10448cc72361SWai Yew CHAY
10458cc72361SWai Yew CHAY return 0;
10468cc72361SWai Yew CHAY }
10478cc72361SWai Yew CHAY
mixer_set_input_port(struct amixer * amixer,struct rsc * rsc)10488cc72361SWai Yew CHAY static int mixer_set_input_port(struct amixer *amixer, struct rsc *rsc)
10498cc72361SWai Yew CHAY {
10508cc72361SWai Yew CHAY amixer->ops->set_input(amixer, rsc);
10518cc72361SWai Yew CHAY amixer->ops->commit_write(amixer);
10528cc72361SWai Yew CHAY
10538cc72361SWai Yew CHAY return 0;
10548cc72361SWai Yew CHAY }
10558cc72361SWai Yew CHAY
port_to_amixer(enum MIXER_PORT_T type)10568cc72361SWai Yew CHAY static enum CT_AMIXER_CTL port_to_amixer(enum MIXER_PORT_T type)
10578cc72361SWai Yew CHAY {
10588cc72361SWai Yew CHAY switch (type) {
10598cc72361SWai Yew CHAY case MIX_WAVE_FRONT: return AMIXER_WAVE_F;
10608cc72361SWai Yew CHAY case MIX_WAVE_SURROUND: return AMIXER_WAVE_S;
10618cc72361SWai Yew CHAY case MIX_WAVE_CENTLFE: return AMIXER_WAVE_C;
10628cc72361SWai Yew CHAY case MIX_WAVE_REAR: return AMIXER_WAVE_R;
10638cc72361SWai Yew CHAY case MIX_PCMO_FRONT: return AMIXER_MASTER_F_C;
10648cc72361SWai Yew CHAY case MIX_SPDIF_OUT: return AMIXER_SPDIFO;
10658cc72361SWai Yew CHAY case MIX_LINE_IN: return AMIXER_LINEIN;
10668cc72361SWai Yew CHAY case MIX_MIC_IN: return AMIXER_MIC;
10678cc72361SWai Yew CHAY case MIX_SPDIF_IN: return AMIXER_SPDIFI;
10688cc72361SWai Yew CHAY case MIX_PCMI_FRONT: return AMIXER_PCM_F;
10698cc72361SWai Yew CHAY case MIX_PCMI_SURROUND: return AMIXER_PCM_S;
10708cc72361SWai Yew CHAY case MIX_PCMI_CENTLFE: return AMIXER_PCM_C;
10718cc72361SWai Yew CHAY case MIX_PCMI_REAR: return AMIXER_PCM_R;
10728cc72361SWai Yew CHAY default: return 0;
10738cc72361SWai Yew CHAY }
10748cc72361SWai Yew CHAY }
10758cc72361SWai Yew CHAY
mixer_get_output_ports(struct ct_mixer * mixer,enum MIXER_PORT_T type,struct rsc ** rleft,struct rsc ** rright)10768cc72361SWai Yew CHAY static int mixer_get_output_ports(struct ct_mixer *mixer,
10778cc72361SWai Yew CHAY enum MIXER_PORT_T type,
10788cc72361SWai Yew CHAY struct rsc **rleft, struct rsc **rright)
10798cc72361SWai Yew CHAY {
10808cc72361SWai Yew CHAY enum CT_AMIXER_CTL amix = port_to_amixer(type);
10818cc72361SWai Yew CHAY
10828cc72361SWai Yew CHAY if (NULL != rleft)
10838cc72361SWai Yew CHAY *rleft = &((struct amixer *)mixer->amixers[amix*CHN_NUM])->rsc;
10848cc72361SWai Yew CHAY
10858cc72361SWai Yew CHAY if (NULL != rright)
10868cc72361SWai Yew CHAY *rright =
10878cc72361SWai Yew CHAY &((struct amixer *)mixer->amixers[amix*CHN_NUM+1])->rsc;
10888cc72361SWai Yew CHAY
10898cc72361SWai Yew CHAY return 0;
10908cc72361SWai Yew CHAY }
10918cc72361SWai Yew CHAY
mixer_set_input_left(struct ct_mixer * mixer,enum MIXER_PORT_T type,struct rsc * rsc)10928cc72361SWai Yew CHAY static int mixer_set_input_left(struct ct_mixer *mixer,
10938cc72361SWai Yew CHAY enum MIXER_PORT_T type, struct rsc *rsc)
10948cc72361SWai Yew CHAY {
10958cc72361SWai Yew CHAY enum CT_AMIXER_CTL amix = port_to_amixer(type);
10968cc72361SWai Yew CHAY
10978cc72361SWai Yew CHAY mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);
10988cc72361SWai Yew CHAY amix = get_recording_amixer(amix);
10998cc72361SWai Yew CHAY if (amix < NUM_CT_AMIXERS)
11008cc72361SWai Yew CHAY mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);
11018cc72361SWai Yew CHAY
11028cc72361SWai Yew CHAY return 0;
11038cc72361SWai Yew CHAY }
11048cc72361SWai Yew CHAY
11058cc72361SWai Yew CHAY static int
mixer_set_input_right(struct ct_mixer * mixer,enum MIXER_PORT_T type,struct rsc * rsc)11068cc72361SWai Yew CHAY mixer_set_input_right(struct ct_mixer *mixer,
11078cc72361SWai Yew CHAY enum MIXER_PORT_T type, struct rsc *rsc)
11088cc72361SWai Yew CHAY {
11098cc72361SWai Yew CHAY enum CT_AMIXER_CTL amix = port_to_amixer(type);
11108cc72361SWai Yew CHAY
11118cc72361SWai Yew CHAY mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);
11128cc72361SWai Yew CHAY amix = get_recording_amixer(amix);
11138cc72361SWai Yew CHAY if (amix < NUM_CT_AMIXERS)
11148cc72361SWai Yew CHAY mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);
11158cc72361SWai Yew CHAY
11168cc72361SWai Yew CHAY return 0;
11178cc72361SWai Yew CHAY }
11188cc72361SWai Yew CHAY
1119c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
mixer_resume(struct ct_mixer * mixer)112029959a09SWai Yew CHAY static int mixer_resume(struct ct_mixer *mixer)
112129959a09SWai Yew CHAY {
112229959a09SWai Yew CHAY int i, state;
112329959a09SWai Yew CHAY struct amixer *amixer;
112429959a09SWai Yew CHAY
112529959a09SWai Yew CHAY /* resume topology and volume gain. */
112629959a09SWai Yew CHAY for (i = 0; i < NUM_CT_AMIXERS*CHN_NUM; i++) {
112729959a09SWai Yew CHAY amixer = mixer->amixers[i];
112829959a09SWai Yew CHAY amixer->ops->commit_write(amixer);
112929959a09SWai Yew CHAY }
113029959a09SWai Yew CHAY
113129959a09SWai Yew CHAY /* resume switch state. */
113229959a09SWai Yew CHAY for (i = SWH_MIXER_START; i <= SWH_MIXER_END; i++) {
113329959a09SWai Yew CHAY state = get_switch_state(mixer, i);
113429959a09SWai Yew CHAY do_switch(mixer->atc, i, state);
113529959a09SWai Yew CHAY }
113629959a09SWai Yew CHAY
113729959a09SWai Yew CHAY return 0;
113829959a09SWai Yew CHAY }
113929959a09SWai Yew CHAY #endif
114029959a09SWai Yew CHAY
ct_mixer_destroy(struct ct_mixer * mixer)11418cc72361SWai Yew CHAY int ct_mixer_destroy(struct ct_mixer *mixer)
11428cc72361SWai Yew CHAY {
11438cc72361SWai Yew CHAY struct sum_mgr *sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
11448cc72361SWai Yew CHAY struct amixer_mgr *amixer_mgr =
11458cc72361SWai Yew CHAY (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];
1146514eef9cSTakashi Iwai struct amixer *amixer;
11478cc72361SWai Yew CHAY int i = 0;
11488cc72361SWai Yew CHAY
11498cc72361SWai Yew CHAY /* Release amixer resources */
11508cc72361SWai Yew CHAY for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
11518cc72361SWai Yew CHAY if (NULL != mixer->amixers[i]) {
11528cc72361SWai Yew CHAY amixer = mixer->amixers[i];
11538cc72361SWai Yew CHAY amixer_mgr->put_amixer(amixer_mgr, amixer);
11548cc72361SWai Yew CHAY }
11558cc72361SWai Yew CHAY }
11568cc72361SWai Yew CHAY
11578cc72361SWai Yew CHAY /* Release sum resources */
11588cc72361SWai Yew CHAY for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
11598cc72361SWai Yew CHAY if (NULL != mixer->sums[i])
11608cc72361SWai Yew CHAY sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);
11618cc72361SWai Yew CHAY }
11628cc72361SWai Yew CHAY
11638cc72361SWai Yew CHAY /* Release mem assigned to mixer object */
11648cc72361SWai Yew CHAY kfree(mixer->sums);
11658cc72361SWai Yew CHAY kfree(mixer->amixers);
11668cc72361SWai Yew CHAY kfree(mixer);
11678cc72361SWai Yew CHAY
11688cc72361SWai Yew CHAY return 0;
11698cc72361SWai Yew CHAY }
11708cc72361SWai Yew CHAY
ct_mixer_create(struct ct_atc * atc,struct ct_mixer ** rmixer)11718cc72361SWai Yew CHAY int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer)
11728cc72361SWai Yew CHAY {
1173514eef9cSTakashi Iwai struct ct_mixer *mixer;
1174514eef9cSTakashi Iwai int err;
11758cc72361SWai Yew CHAY
11768cc72361SWai Yew CHAY *rmixer = NULL;
11778cc72361SWai Yew CHAY
11788cc72361SWai Yew CHAY /* Allocate mem for mixer obj */
11798cc72361SWai Yew CHAY err = ct_mixer_get_mem(&mixer);
11808cc72361SWai Yew CHAY if (err)
11818cc72361SWai Yew CHAY return err;
11828cc72361SWai Yew CHAY
11838cc72361SWai Yew CHAY mixer->switch_state = 0;
11848cc72361SWai Yew CHAY mixer->atc = atc;
11858cc72361SWai Yew CHAY /* Set operations */
11868cc72361SWai Yew CHAY mixer->get_output_ports = mixer_get_output_ports;
11878cc72361SWai Yew CHAY mixer->set_input_left = mixer_set_input_left;
11888cc72361SWai Yew CHAY mixer->set_input_right = mixer_set_input_right;
1189c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
119029959a09SWai Yew CHAY mixer->resume = mixer_resume;
119129959a09SWai Yew CHAY #endif
11928cc72361SWai Yew CHAY
11938cc72361SWai Yew CHAY /* Allocate chip resources for mixer obj */
11948cc72361SWai Yew CHAY err = ct_mixer_get_resources(mixer);
11958cc72361SWai Yew CHAY if (err)
11968cc72361SWai Yew CHAY goto error;
11978cc72361SWai Yew CHAY
11988cc72361SWai Yew CHAY /* Build internal mixer topology */
11998cc72361SWai Yew CHAY ct_mixer_topology_build(mixer);
12008cc72361SWai Yew CHAY
12018cc72361SWai Yew CHAY *rmixer = mixer;
12028cc72361SWai Yew CHAY
12038cc72361SWai Yew CHAY return 0;
12048cc72361SWai Yew CHAY
12058cc72361SWai Yew CHAY error:
12068cc72361SWai Yew CHAY ct_mixer_destroy(mixer);
12078cc72361SWai Yew CHAY return err;
12088cc72361SWai Yew CHAY }
12098cc72361SWai Yew CHAY
ct_alsa_mix_create(struct ct_atc * atc,enum CTALSADEVS device,const char * device_name)12108cc72361SWai Yew CHAY int ct_alsa_mix_create(struct ct_atc *atc,
12118cc72361SWai Yew CHAY enum CTALSADEVS device,
12128cc72361SWai Yew CHAY const char *device_name)
12138cc72361SWai Yew CHAY {
1214514eef9cSTakashi Iwai int err;
12158cc72361SWai Yew CHAY
12168cc72361SWai Yew CHAY /* Create snd kcontrol instances on demand */
1217032abb51STakashi Iwai /* vol_ctl.device = swh_ctl.device = device; */ /* better w/ device 0 */
12188cc72361SWai Yew CHAY err = ct_mixer_kcontrols_create((struct ct_mixer *)atc->mixer);
12198cc72361SWai Yew CHAY if (err)
12208cc72361SWai Yew CHAY return err;
12218cc72361SWai Yew CHAY
12228cc72361SWai Yew CHAY strcpy(atc->card->mixername, device_name);
12238cc72361SWai Yew CHAY
12248cc72361SWai Yew CHAY return 0;
12258cc72361SWai Yew CHAY }
1226