xref: /OK3568_Linux_fs/kernel/sound/soc/codecs/cpcap.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * ALSA SoC CPCAP codec driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2017 - 2018 Sebastian Reichel <sre@kernel.org>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Very loosely based on original driver from Motorola:
8*4882a593Smuzhiyun  * Copyright (C) 2007 - 2009 Motorola, Inc.
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/regmap.h>
13*4882a593Smuzhiyun #include <linux/platform_device.h>
14*4882a593Smuzhiyun #include <linux/mfd/motorola-cpcap.h>
15*4882a593Smuzhiyun #include <sound/core.h>
16*4882a593Smuzhiyun #include <sound/soc.h>
17*4882a593Smuzhiyun #include <sound/tlv.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun /* Register 513 CPCAP_REG_CC     --- CODEC */
20*4882a593Smuzhiyun #define CPCAP_BIT_CDC_CLK2                15
21*4882a593Smuzhiyun #define CPCAP_BIT_CDC_CLK1                14
22*4882a593Smuzhiyun #define CPCAP_BIT_CDC_CLK0                13
23*4882a593Smuzhiyun #define CPCAP_BIT_CDC_SR3                 12
24*4882a593Smuzhiyun #define CPCAP_BIT_CDC_SR2                 11
25*4882a593Smuzhiyun #define CPCAP_BIT_CDC_SR1                 10
26*4882a593Smuzhiyun #define CPCAP_BIT_CDC_SR0                 9
27*4882a593Smuzhiyun #define CPCAP_BIT_CDC_CLOCK_TREE_RESET    8
28*4882a593Smuzhiyun #define CPCAP_BIT_MIC2_CDC_EN             7
29*4882a593Smuzhiyun #define CPCAP_BIT_CDC_EN_RX               6
30*4882a593Smuzhiyun #define CPCAP_BIT_DF_RESET                5
31*4882a593Smuzhiyun #define CPCAP_BIT_MIC1_CDC_EN             4
32*4882a593Smuzhiyun #define CPCAP_BIT_AUDOHPF_1		  3
33*4882a593Smuzhiyun #define CPCAP_BIT_AUDOHPF_0		  2
34*4882a593Smuzhiyun #define CPCAP_BIT_AUDIHPF_1		  1
35*4882a593Smuzhiyun #define CPCAP_BIT_AUDIHPF_0		  0
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /* Register 514 CPCAP_REG_CDI    --- CODEC Digital Audio Interface */
38*4882a593Smuzhiyun #define CPCAP_BIT_CDC_PLL_SEL             15
39*4882a593Smuzhiyun #define CPCAP_BIT_CLK_IN_SEL              13
40*4882a593Smuzhiyun #define CPCAP_BIT_DIG_AUD_IN              12
41*4882a593Smuzhiyun #define CPCAP_BIT_CDC_CLK_EN              11
42*4882a593Smuzhiyun #define CPCAP_BIT_CDC_DIG_AUD_FS1         10
43*4882a593Smuzhiyun #define CPCAP_BIT_CDC_DIG_AUD_FS0         9
44*4882a593Smuzhiyun #define CPCAP_BIT_MIC2_TIMESLOT2          8
45*4882a593Smuzhiyun #define CPCAP_BIT_MIC2_TIMESLOT1          7
46*4882a593Smuzhiyun #define CPCAP_BIT_MIC2_TIMESLOT0          6
47*4882a593Smuzhiyun #define CPCAP_BIT_MIC1_RX_TIMESLOT2       5
48*4882a593Smuzhiyun #define CPCAP_BIT_MIC1_RX_TIMESLOT1       4
49*4882a593Smuzhiyun #define CPCAP_BIT_MIC1_RX_TIMESLOT0       3
50*4882a593Smuzhiyun #define CPCAP_BIT_FS_INV                  2
51*4882a593Smuzhiyun #define CPCAP_BIT_CLK_INV                 1
52*4882a593Smuzhiyun #define CPCAP_BIT_SMB_CDC                 0
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun /* Register 515 CPCAP_REG_SDAC   --- Stereo DAC */
55*4882a593Smuzhiyun #define CPCAP_BIT_FSYNC_CLK_IN_COMMON     11
56*4882a593Smuzhiyun #define CPCAP_BIT_SLAVE_PLL_CLK_INPUT     10
57*4882a593Smuzhiyun #define CPCAP_BIT_ST_CLOCK_TREE_RESET     9
58*4882a593Smuzhiyun #define CPCAP_BIT_DF_RESET_ST_DAC         8
59*4882a593Smuzhiyun #define CPCAP_BIT_ST_SR3                  7
60*4882a593Smuzhiyun #define CPCAP_BIT_ST_SR2                  6
61*4882a593Smuzhiyun #define CPCAP_BIT_ST_SR1                  5
62*4882a593Smuzhiyun #define CPCAP_BIT_ST_SR0                  4
63*4882a593Smuzhiyun #define CPCAP_BIT_ST_DAC_CLK2             3
64*4882a593Smuzhiyun #define CPCAP_BIT_ST_DAC_CLK1             2
65*4882a593Smuzhiyun #define CPCAP_BIT_ST_DAC_CLK0             1
66*4882a593Smuzhiyun #define CPCAP_BIT_ST_DAC_EN               0
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun /* Register 516 CPCAP_REG_SDACDI --- Stereo DAC Digital Audio Interface */
69*4882a593Smuzhiyun #define CPCAP_BIT_ST_L_TIMESLOT2          13
70*4882a593Smuzhiyun #define CPCAP_BIT_ST_L_TIMESLOT1          12
71*4882a593Smuzhiyun #define CPCAP_BIT_ST_L_TIMESLOT0          11
72*4882a593Smuzhiyun #define CPCAP_BIT_ST_R_TIMESLOT2          10
73*4882a593Smuzhiyun #define CPCAP_BIT_ST_R_TIMESLOT1          9
74*4882a593Smuzhiyun #define CPCAP_BIT_ST_R_TIMESLOT0          8
75*4882a593Smuzhiyun #define CPCAP_BIT_ST_DAC_CLK_IN_SEL       7
76*4882a593Smuzhiyun #define CPCAP_BIT_ST_FS_INV               6
77*4882a593Smuzhiyun #define CPCAP_BIT_ST_CLK_INV              5
78*4882a593Smuzhiyun #define CPCAP_BIT_ST_DIG_AUD_FS1          4
79*4882a593Smuzhiyun #define CPCAP_BIT_ST_DIG_AUD_FS0          3
80*4882a593Smuzhiyun #define CPCAP_BIT_DIG_AUD_IN_ST_DAC       2
81*4882a593Smuzhiyun #define CPCAP_BIT_ST_CLK_EN               1
82*4882a593Smuzhiyun #define CPCAP_BIT_SMB_ST_DAC              0
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun /* Register 517 CPCAP_REG_TXI    --- TX Interface */
85*4882a593Smuzhiyun #define CPCAP_BIT_PTT_TH		15
86*4882a593Smuzhiyun #define CPCAP_BIT_PTT_CMP_EN		14
87*4882a593Smuzhiyun #define CPCAP_BIT_HS_ID_TX		13
88*4882a593Smuzhiyun #define CPCAP_BIT_MB_ON2		12
89*4882a593Smuzhiyun #define CPCAP_BIT_MB_ON1L		11
90*4882a593Smuzhiyun #define CPCAP_BIT_MB_ON1R		10
91*4882a593Smuzhiyun #define CPCAP_BIT_RX_L_ENCODE		9
92*4882a593Smuzhiyun #define CPCAP_BIT_RX_R_ENCODE		8
93*4882a593Smuzhiyun #define CPCAP_BIT_MIC2_MUX		7
94*4882a593Smuzhiyun #define CPCAP_BIT_MIC2_PGA_EN		6
95*4882a593Smuzhiyun #define CPCAP_BIT_CDET_DIS		5
96*4882a593Smuzhiyun #define CPCAP_BIT_EMU_MIC_MUX		4
97*4882a593Smuzhiyun #define CPCAP_BIT_HS_MIC_MUX		3
98*4882a593Smuzhiyun #define CPCAP_BIT_MIC1_MUX		2
99*4882a593Smuzhiyun #define CPCAP_BIT_MIC1_PGA_EN		1
100*4882a593Smuzhiyun #define CPCAP_BIT_DLM			0
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun /* Register 518 CPCAP_REG_TXMP   --- Mic Gain */
103*4882a593Smuzhiyun #define CPCAP_BIT_MB_BIAS_R1              11
104*4882a593Smuzhiyun #define CPCAP_BIT_MB_BIAS_R0              10
105*4882a593Smuzhiyun #define CPCAP_BIT_MIC2_GAIN_4             9
106*4882a593Smuzhiyun #define CPCAP_BIT_MIC2_GAIN_3             8
107*4882a593Smuzhiyun #define CPCAP_BIT_MIC2_GAIN_2             7
108*4882a593Smuzhiyun #define CPCAP_BIT_MIC2_GAIN_1             6
109*4882a593Smuzhiyun #define CPCAP_BIT_MIC2_GAIN_0             5
110*4882a593Smuzhiyun #define CPCAP_BIT_MIC1_GAIN_4             4
111*4882a593Smuzhiyun #define CPCAP_BIT_MIC1_GAIN_3             3
112*4882a593Smuzhiyun #define CPCAP_BIT_MIC1_GAIN_2             2
113*4882a593Smuzhiyun #define CPCAP_BIT_MIC1_GAIN_1             1
114*4882a593Smuzhiyun #define CPCAP_BIT_MIC1_GAIN_0             0
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun /* Register 519 CPCAP_REG_RXOA   --- RX Output Amplifier */
117*4882a593Smuzhiyun #define CPCAP_BIT_UNUSED_519_15		15
118*4882a593Smuzhiyun #define CPCAP_BIT_UNUSED_519_14		14
119*4882a593Smuzhiyun #define CPCAP_BIT_UNUSED_519_13		13
120*4882a593Smuzhiyun #define CPCAP_BIT_STDAC_LOW_PWR_DISABLE	12
121*4882a593Smuzhiyun #define CPCAP_BIT_HS_LOW_PWR		11
122*4882a593Smuzhiyun #define CPCAP_BIT_HS_ID_RX		10
123*4882a593Smuzhiyun #define CPCAP_BIT_ST_HS_CP_EN		9
124*4882a593Smuzhiyun #define CPCAP_BIT_EMU_SPKR_R_EN		8
125*4882a593Smuzhiyun #define CPCAP_BIT_EMU_SPKR_L_EN		7
126*4882a593Smuzhiyun #define CPCAP_BIT_HS_L_EN		6
127*4882a593Smuzhiyun #define CPCAP_BIT_HS_R_EN		5
128*4882a593Smuzhiyun #define CPCAP_BIT_A4_LINEOUT_L_EN	4
129*4882a593Smuzhiyun #define CPCAP_BIT_A4_LINEOUT_R_EN	3
130*4882a593Smuzhiyun #define CPCAP_BIT_A2_LDSP_L_EN		2
131*4882a593Smuzhiyun #define CPCAP_BIT_A2_LDSP_R_EN		1
132*4882a593Smuzhiyun #define CPCAP_BIT_A1_EAR_EN		0
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun /* Register 520 CPCAP_REG_RXVC   --- RX Volume Control */
135*4882a593Smuzhiyun #define CPCAP_BIT_VOL_EXT3                15
136*4882a593Smuzhiyun #define CPCAP_BIT_VOL_EXT2                14
137*4882a593Smuzhiyun #define CPCAP_BIT_VOL_EXT1                13
138*4882a593Smuzhiyun #define CPCAP_BIT_VOL_EXT0                12
139*4882a593Smuzhiyun #define CPCAP_BIT_VOL_DAC3                11
140*4882a593Smuzhiyun #define CPCAP_BIT_VOL_DAC2                10
141*4882a593Smuzhiyun #define CPCAP_BIT_VOL_DAC1                9
142*4882a593Smuzhiyun #define CPCAP_BIT_VOL_DAC0                8
143*4882a593Smuzhiyun #define CPCAP_BIT_VOL_DAC_LSB_1dB1        7
144*4882a593Smuzhiyun #define CPCAP_BIT_VOL_DAC_LSB_1dB0        6
145*4882a593Smuzhiyun #define CPCAP_BIT_VOL_CDC3                5
146*4882a593Smuzhiyun #define CPCAP_BIT_VOL_CDC2                4
147*4882a593Smuzhiyun #define CPCAP_BIT_VOL_CDC1                3
148*4882a593Smuzhiyun #define CPCAP_BIT_VOL_CDC0                2
149*4882a593Smuzhiyun #define CPCAP_BIT_VOL_CDC_LSB_1dB1        1
150*4882a593Smuzhiyun #define CPCAP_BIT_VOL_CDC_LSB_1dB0        0
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun /* Register 521 CPCAP_REG_RXCOA  --- Codec to Output Amp Switches */
153*4882a593Smuzhiyun #define CPCAP_BIT_PGA_CDC_EN              10
154*4882a593Smuzhiyun #define CPCAP_BIT_CDC_SW                  9
155*4882a593Smuzhiyun #define CPCAP_BIT_PGA_OUTR_USBDP_CDC_SW   8
156*4882a593Smuzhiyun #define CPCAP_BIT_PGA_OUTL_USBDN_CDC_SW   7
157*4882a593Smuzhiyun #define CPCAP_BIT_ALEFT_HS_CDC_SW         6
158*4882a593Smuzhiyun #define CPCAP_BIT_ARIGHT_HS_CDC_SW        5
159*4882a593Smuzhiyun #define CPCAP_BIT_A4_LINEOUT_L_CDC_SW     4
160*4882a593Smuzhiyun #define CPCAP_BIT_A4_LINEOUT_R_CDC_SW     3
161*4882a593Smuzhiyun #define CPCAP_BIT_A2_LDSP_L_CDC_SW        2
162*4882a593Smuzhiyun #define CPCAP_BIT_A2_LDSP_R_CDC_SW        1
163*4882a593Smuzhiyun #define CPCAP_BIT_A1_EAR_CDC_SW           0
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun /* Register 522 CPCAP_REG_RXSDOA --- RX Stereo DAC to Output Amp Switches */
166*4882a593Smuzhiyun #define CPCAP_BIT_PGA_DAC_EN              12
167*4882a593Smuzhiyun #define CPCAP_BIT_ST_DAC_SW               11
168*4882a593Smuzhiyun #define CPCAP_BIT_MONO_DAC1               10
169*4882a593Smuzhiyun #define CPCAP_BIT_MONO_DAC0               9
170*4882a593Smuzhiyun #define CPCAP_BIT_PGA_OUTR_USBDP_DAC_SW   8
171*4882a593Smuzhiyun #define CPCAP_BIT_PGA_OUTL_USBDN_DAC_SW   7
172*4882a593Smuzhiyun #define CPCAP_BIT_ALEFT_HS_DAC_SW         6
173*4882a593Smuzhiyun #define CPCAP_BIT_ARIGHT_HS_DAC_SW        5
174*4882a593Smuzhiyun #define CPCAP_BIT_A4_LINEOUT_L_DAC_SW     4
175*4882a593Smuzhiyun #define CPCAP_BIT_A4_LINEOUT_R_DAC_SW     3
176*4882a593Smuzhiyun #define CPCAP_BIT_A2_LDSP_L_DAC_SW        2
177*4882a593Smuzhiyun #define CPCAP_BIT_A2_LDSP_R_DAC_SW        1
178*4882a593Smuzhiyun #define CPCAP_BIT_A1_EAR_DAC_SW           0
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun /* Register 523 CPCAP_REG_RXEPOA --- RX External PGA to Output Amp Switches */
181*4882a593Smuzhiyun #define CPCAP_BIT_PGA_EXT_L_EN            14
182*4882a593Smuzhiyun #define CPCAP_BIT_PGA_EXT_R_EN            13
183*4882a593Smuzhiyun #define CPCAP_BIT_PGA_IN_L_SW             12
184*4882a593Smuzhiyun #define CPCAP_BIT_PGA_IN_R_SW             11
185*4882a593Smuzhiyun #define CPCAP_BIT_MONO_EXT1               10
186*4882a593Smuzhiyun #define CPCAP_BIT_MONO_EXT0               9
187*4882a593Smuzhiyun #define CPCAP_BIT_PGA_OUTR_USBDP_EXT_SW   8
188*4882a593Smuzhiyun #define CPCAP_BIT_PGA_OUTL_USBDN_EXT_SW   7
189*4882a593Smuzhiyun #define CPCAP_BIT_ALEFT_HS_EXT_SW         6
190*4882a593Smuzhiyun #define CPCAP_BIT_ARIGHT_HS_EXT_SW        5
191*4882a593Smuzhiyun #define CPCAP_BIT_A4_LINEOUT_L_EXT_SW     4
192*4882a593Smuzhiyun #define CPCAP_BIT_A4_LINEOUT_R_EXT_SW     3
193*4882a593Smuzhiyun #define CPCAP_BIT_A2_LDSP_L_EXT_SW        2
194*4882a593Smuzhiyun #define CPCAP_BIT_A2_LDSP_R_EXT_SW        1
195*4882a593Smuzhiyun #define CPCAP_BIT_A1_EAR_EXT_SW           0
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun /* Register 525 CPCAP_REG_A2LA --- SPK Amplifier and Clock Config for Headset */
198*4882a593Smuzhiyun #define CPCAP_BIT_NCP_CLK_SYNC            7
199*4882a593Smuzhiyun #define CPCAP_BIT_A2_CLK_SYNC             6
200*4882a593Smuzhiyun #define CPCAP_BIT_A2_FREE_RUN             5
201*4882a593Smuzhiyun #define CPCAP_BIT_A2_CLK2                 4
202*4882a593Smuzhiyun #define CPCAP_BIT_A2_CLK1                 3
203*4882a593Smuzhiyun #define CPCAP_BIT_A2_CLK0                 2
204*4882a593Smuzhiyun #define CPCAP_BIT_A2_CLK_IN               1
205*4882a593Smuzhiyun #define CPCAP_BIT_A2_CONFIG               0
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun #define SLEEP_ACTIVATE_POWER 2
208*4882a593Smuzhiyun #define CLOCK_TREE_RESET_TIME 1
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun /* constants for ST delay workaround */
211*4882a593Smuzhiyun #define STM_STDAC_ACTIVATE_RAMP_TIME   1
212*4882a593Smuzhiyun #define STM_STDAC_EN_TEST_PRE          0x090C
213*4882a593Smuzhiyun #define STM_STDAC_EN_TEST_POST         0x0000
214*4882a593Smuzhiyun #define STM_STDAC_EN_ST_TEST1_PRE      0x2400
215*4882a593Smuzhiyun #define STM_STDAC_EN_ST_TEST1_POST     0x0400
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun struct cpcap_reg_info {
218*4882a593Smuzhiyun 	u16 reg;
219*4882a593Smuzhiyun 	u16 mask;
220*4882a593Smuzhiyun 	u16 val;
221*4882a593Smuzhiyun };
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun static const struct cpcap_reg_info cpcap_default_regs[] = {
224*4882a593Smuzhiyun 	{ CPCAP_REG_CC, 0xFFFF, 0x0000 },
225*4882a593Smuzhiyun 	{ CPCAP_REG_CC, 0xFFFF, 0x0000 },
226*4882a593Smuzhiyun 	{ CPCAP_REG_CDI, 0xBFFF, 0x0000 },
227*4882a593Smuzhiyun 	{ CPCAP_REG_SDAC, 0x0FFF, 0x0000 },
228*4882a593Smuzhiyun 	{ CPCAP_REG_SDACDI, 0x3FFF, 0x0000 },
229*4882a593Smuzhiyun 	{ CPCAP_REG_TXI, 0x0FDF, 0x0000 },
230*4882a593Smuzhiyun 	{ CPCAP_REG_TXMP, 0x0FFF, 0x0400 },
231*4882a593Smuzhiyun 	{ CPCAP_REG_RXOA, 0x01FF, 0x0000 },
232*4882a593Smuzhiyun 	{ CPCAP_REG_RXVC, 0xFF3C, 0x0000 },
233*4882a593Smuzhiyun 	{ CPCAP_REG_RXCOA, 0x07FF, 0x0000 },
234*4882a593Smuzhiyun 	{ CPCAP_REG_RXSDOA, 0x1FFF, 0x0000 },
235*4882a593Smuzhiyun 	{ CPCAP_REG_RXEPOA, 0x7FFF, 0x0000 },
236*4882a593Smuzhiyun 	{ CPCAP_REG_A2LA, BIT(CPCAP_BIT_A2_FREE_RUN),
237*4882a593Smuzhiyun 	  BIT(CPCAP_BIT_A2_FREE_RUN) },
238*4882a593Smuzhiyun };
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun enum cpcap_dai {
241*4882a593Smuzhiyun 	CPCAP_DAI_HIFI,
242*4882a593Smuzhiyun 	CPCAP_DAI_VOICE,
243*4882a593Smuzhiyun };
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun struct cpcap_audio {
246*4882a593Smuzhiyun 	struct snd_soc_component *component;
247*4882a593Smuzhiyun 	struct regmap *regmap;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	u16 vendor;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	int codec_clk_id;
252*4882a593Smuzhiyun 	int codec_freq;
253*4882a593Smuzhiyun 	int codec_format;
254*4882a593Smuzhiyun };
255*4882a593Smuzhiyun 
cpcap_st_workaround(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)256*4882a593Smuzhiyun static int cpcap_st_workaround(struct snd_soc_dapm_widget *w,
257*4882a593Smuzhiyun 			       struct snd_kcontrol *kcontrol, int event)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
260*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
261*4882a593Smuzhiyun 	int err = 0;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	/* Only CPCAP from ST requires workaround */
264*4882a593Smuzhiyun 	if (cpcap->vendor != CPCAP_VENDOR_ST)
265*4882a593Smuzhiyun 		return 0;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	switch (event) {
268*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMU:
269*4882a593Smuzhiyun 		err = regmap_write(cpcap->regmap, CPCAP_REG_TEST,
270*4882a593Smuzhiyun 				   STM_STDAC_EN_TEST_PRE);
271*4882a593Smuzhiyun 		if (err)
272*4882a593Smuzhiyun 			return err;
273*4882a593Smuzhiyun 		err = regmap_write(cpcap->regmap, CPCAP_REG_ST_TEST1,
274*4882a593Smuzhiyun 				   STM_STDAC_EN_ST_TEST1_PRE);
275*4882a593Smuzhiyun 		break;
276*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMU:
277*4882a593Smuzhiyun 		msleep(STM_STDAC_ACTIVATE_RAMP_TIME);
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 		err = regmap_write(cpcap->regmap, CPCAP_REG_ST_TEST1,
280*4882a593Smuzhiyun 				   STM_STDAC_EN_ST_TEST1_POST);
281*4882a593Smuzhiyun 		if (err)
282*4882a593Smuzhiyun 			return err;
283*4882a593Smuzhiyun 		err = regmap_write(cpcap->regmap, CPCAP_REG_TEST,
284*4882a593Smuzhiyun 				   STM_STDAC_EN_TEST_POST);
285*4882a593Smuzhiyun 		break;
286*4882a593Smuzhiyun 	default:
287*4882a593Smuzhiyun 		break;
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	return err;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun /* Capture Gain Control: 0dB to 31dB in 1dB steps */
294*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(mic_gain_tlv, 0, 100, 0);
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun /* Playback Gain Control: -33dB to 12dB in 3dB steps */
297*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(vol_tlv, -3300, 300, 0);
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_snd_controls[] = {
300*4882a593Smuzhiyun 	/* Playback Gain */
301*4882a593Smuzhiyun 	SOC_SINGLE_TLV("HiFi Playback Volume",
302*4882a593Smuzhiyun 		CPCAP_REG_RXVC, CPCAP_BIT_VOL_DAC0, 0xF, 0, vol_tlv),
303*4882a593Smuzhiyun 	SOC_SINGLE_TLV("Voice Playback Volume",
304*4882a593Smuzhiyun 		CPCAP_REG_RXVC, CPCAP_BIT_VOL_CDC0, 0xF, 0, vol_tlv),
305*4882a593Smuzhiyun 	SOC_SINGLE_TLV("Ext Playback Volume",
306*4882a593Smuzhiyun 		CPCAP_REG_RXVC, CPCAP_BIT_VOL_EXT0, 0xF, 0, vol_tlv),
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	/* Capture Gain */
309*4882a593Smuzhiyun 	SOC_SINGLE_TLV("Mic1 Capture Volume",
310*4882a593Smuzhiyun 		CPCAP_REG_TXMP, CPCAP_BIT_MIC1_GAIN_0, 0x1F, 0, mic_gain_tlv),
311*4882a593Smuzhiyun 	SOC_SINGLE_TLV("Mic2 Capture Volume",
312*4882a593Smuzhiyun 		CPCAP_REG_TXMP, CPCAP_BIT_MIC2_GAIN_0, 0x1F, 0, mic_gain_tlv),
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	/* Phase Invert */
315*4882a593Smuzhiyun 	SOC_SINGLE("Hifi Left Phase Invert Switch",
316*4882a593Smuzhiyun 		CPCAP_REG_RXSDOA, CPCAP_BIT_MONO_DAC0, 1, 0),
317*4882a593Smuzhiyun 	SOC_SINGLE("Ext Left Phase Invert Switch",
318*4882a593Smuzhiyun 		CPCAP_REG_RXEPOA, CPCAP_BIT_MONO_EXT0, 1, 0),
319*4882a593Smuzhiyun };
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun static const char * const cpcap_out_mux_texts[] = {
322*4882a593Smuzhiyun 	"Off", "Voice", "HiFi", "Ext"
323*4882a593Smuzhiyun };
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun static const char * const cpcap_in_right_mux_texts[] = {
326*4882a593Smuzhiyun 	"Off", "Mic 1", "Headset Mic", "EMU Mic", "Ext Right"
327*4882a593Smuzhiyun };
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun static const char * const cpcap_in_left_mux_texts[] = {
330*4882a593Smuzhiyun 	"Off", "Mic 2", "Ext Left"
331*4882a593Smuzhiyun };
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun /*
334*4882a593Smuzhiyun  * input muxes use unusual register layout, so that we need to use custom
335*4882a593Smuzhiyun  * getter/setter methods
336*4882a593Smuzhiyun  */
337*4882a593Smuzhiyun static SOC_ENUM_SINGLE_EXT_DECL(cpcap_input_left_mux_enum,
338*4882a593Smuzhiyun 				cpcap_in_left_mux_texts);
339*4882a593Smuzhiyun static SOC_ENUM_SINGLE_EXT_DECL(cpcap_input_right_mux_enum,
340*4882a593Smuzhiyun 				cpcap_in_right_mux_texts);
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun /*
343*4882a593Smuzhiyun  * mux uses same bit in CPCAP_REG_RXCOA, CPCAP_REG_RXSDOA & CPCAP_REG_RXEPOA;
344*4882a593Smuzhiyun  * even though the register layout makes it look like a mixer, this is a mux.
345*4882a593Smuzhiyun  * Enabling multiple inputs will result in no audio being forwarded.
346*4882a593Smuzhiyun  */
347*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(cpcap_earpiece_mux_enum, 0, 0, cpcap_out_mux_texts);
348*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(cpcap_spkr_r_mux_enum, 0, 1, cpcap_out_mux_texts);
349*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(cpcap_spkr_l_mux_enum, 0, 2, cpcap_out_mux_texts);
350*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(cpcap_line_r_mux_enum, 0, 3, cpcap_out_mux_texts);
351*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(cpcap_line_l_mux_enum, 0, 4, cpcap_out_mux_texts);
352*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(cpcap_hs_r_mux_enum, 0, 5, cpcap_out_mux_texts);
353*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(cpcap_hs_l_mux_enum, 0, 6, cpcap_out_mux_texts);
354*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(cpcap_emu_l_mux_enum, 0, 7, cpcap_out_mux_texts);
355*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(cpcap_emu_r_mux_enum, 0, 8, cpcap_out_mux_texts);
356*4882a593Smuzhiyun 
cpcap_output_mux_get_enum(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)357*4882a593Smuzhiyun static int cpcap_output_mux_get_enum(struct snd_kcontrol *kcontrol,
358*4882a593Smuzhiyun 				     struct snd_ctl_elem_value *ucontrol)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
361*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
362*4882a593Smuzhiyun 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
363*4882a593Smuzhiyun 	unsigned int shift = e->shift_l;
364*4882a593Smuzhiyun 	int reg_voice, reg_hifi, reg_ext, status;
365*4882a593Smuzhiyun 	int err;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	err = regmap_read(cpcap->regmap, CPCAP_REG_RXCOA, &reg_voice);
368*4882a593Smuzhiyun 	if (err)
369*4882a593Smuzhiyun 		return err;
370*4882a593Smuzhiyun 	err = regmap_read(cpcap->regmap, CPCAP_REG_RXSDOA, &reg_hifi);
371*4882a593Smuzhiyun 	if (err)
372*4882a593Smuzhiyun 		return err;
373*4882a593Smuzhiyun 	err = regmap_read(cpcap->regmap, CPCAP_REG_RXEPOA, &reg_ext);
374*4882a593Smuzhiyun 	if (err)
375*4882a593Smuzhiyun 		return err;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	reg_voice = (reg_voice >> shift) & 1;
378*4882a593Smuzhiyun 	reg_hifi = (reg_hifi >> shift) & 1;
379*4882a593Smuzhiyun 	reg_ext = (reg_ext >> shift) & 1;
380*4882a593Smuzhiyun 	status = reg_ext << 2 | reg_hifi << 1 | reg_voice;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	switch (status) {
383*4882a593Smuzhiyun 	case 0x04:
384*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 3;
385*4882a593Smuzhiyun 		break;
386*4882a593Smuzhiyun 	case 0x02:
387*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 2;
388*4882a593Smuzhiyun 		break;
389*4882a593Smuzhiyun 	case 0x01:
390*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 1;
391*4882a593Smuzhiyun 		break;
392*4882a593Smuzhiyun 	default:
393*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 0;
394*4882a593Smuzhiyun 		break;
395*4882a593Smuzhiyun 	}
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	return 0;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun 
cpcap_output_mux_put_enum(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)400*4882a593Smuzhiyun static int cpcap_output_mux_put_enum(struct snd_kcontrol *kcontrol,
401*4882a593Smuzhiyun 				     struct snd_ctl_elem_value *ucontrol)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
404*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
405*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm =
406*4882a593Smuzhiyun 		snd_soc_dapm_kcontrol_dapm(kcontrol);
407*4882a593Smuzhiyun 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
408*4882a593Smuzhiyun 	unsigned int muxval = ucontrol->value.enumerated.item[0];
409*4882a593Smuzhiyun 	unsigned int mask = BIT(e->shift_l);
410*4882a593Smuzhiyun 	u16 reg_voice = 0x00, reg_hifi = 0x00, reg_ext = 0x00;
411*4882a593Smuzhiyun 	int err;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	switch (muxval) {
414*4882a593Smuzhiyun 	case 1:
415*4882a593Smuzhiyun 		reg_voice = mask;
416*4882a593Smuzhiyun 		break;
417*4882a593Smuzhiyun 	case 2:
418*4882a593Smuzhiyun 		reg_hifi = mask;
419*4882a593Smuzhiyun 		break;
420*4882a593Smuzhiyun 	case 3:
421*4882a593Smuzhiyun 		reg_ext = mask;
422*4882a593Smuzhiyun 		break;
423*4882a593Smuzhiyun 	default:
424*4882a593Smuzhiyun 		break;
425*4882a593Smuzhiyun 	}
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA,
428*4882a593Smuzhiyun 				 mask, reg_voice);
429*4882a593Smuzhiyun 	if (err)
430*4882a593Smuzhiyun 		return err;
431*4882a593Smuzhiyun 	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXSDOA,
432*4882a593Smuzhiyun 				 mask, reg_hifi);
433*4882a593Smuzhiyun 	if (err)
434*4882a593Smuzhiyun 		return err;
435*4882a593Smuzhiyun 	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXEPOA,
436*4882a593Smuzhiyun 				 mask, reg_ext);
437*4882a593Smuzhiyun 	if (err)
438*4882a593Smuzhiyun 		return err;
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL);
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	return 0;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun 
cpcap_input_right_mux_get_enum(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)445*4882a593Smuzhiyun static int cpcap_input_right_mux_get_enum(struct snd_kcontrol *kcontrol,
446*4882a593Smuzhiyun 					  struct snd_ctl_elem_value *ucontrol)
447*4882a593Smuzhiyun {
448*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
449*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
450*4882a593Smuzhiyun 	int regval, mask;
451*4882a593Smuzhiyun 	int err;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	err = regmap_read(cpcap->regmap, CPCAP_REG_TXI, &regval);
454*4882a593Smuzhiyun 	if (err)
455*4882a593Smuzhiyun 		return err;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	mask = 0;
458*4882a593Smuzhiyun 	mask |= BIT(CPCAP_BIT_MIC1_MUX);
459*4882a593Smuzhiyun 	mask |= BIT(CPCAP_BIT_HS_MIC_MUX);
460*4882a593Smuzhiyun 	mask |= BIT(CPCAP_BIT_EMU_MIC_MUX);
461*4882a593Smuzhiyun 	mask |= BIT(CPCAP_BIT_RX_R_ENCODE);
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	switch (regval & mask) {
464*4882a593Smuzhiyun 	case BIT(CPCAP_BIT_RX_R_ENCODE):
465*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 4;
466*4882a593Smuzhiyun 		break;
467*4882a593Smuzhiyun 	case BIT(CPCAP_BIT_EMU_MIC_MUX):
468*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 3;
469*4882a593Smuzhiyun 		break;
470*4882a593Smuzhiyun 	case BIT(CPCAP_BIT_HS_MIC_MUX):
471*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 2;
472*4882a593Smuzhiyun 		break;
473*4882a593Smuzhiyun 	case BIT(CPCAP_BIT_MIC1_MUX):
474*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 1;
475*4882a593Smuzhiyun 		break;
476*4882a593Smuzhiyun 	default:
477*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 0;
478*4882a593Smuzhiyun 		break;
479*4882a593Smuzhiyun 	}
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	return 0;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun 
cpcap_input_right_mux_put_enum(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)484*4882a593Smuzhiyun static int cpcap_input_right_mux_put_enum(struct snd_kcontrol *kcontrol,
485*4882a593Smuzhiyun 					  struct snd_ctl_elem_value *ucontrol)
486*4882a593Smuzhiyun {
487*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
488*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
489*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm =
490*4882a593Smuzhiyun 		snd_soc_dapm_kcontrol_dapm(kcontrol);
491*4882a593Smuzhiyun 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
492*4882a593Smuzhiyun 	unsigned int muxval = ucontrol->value.enumerated.item[0];
493*4882a593Smuzhiyun 	int regval = 0, mask;
494*4882a593Smuzhiyun 	int err;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	mask = 0;
497*4882a593Smuzhiyun 	mask |= BIT(CPCAP_BIT_MIC1_MUX);
498*4882a593Smuzhiyun 	mask |= BIT(CPCAP_BIT_HS_MIC_MUX);
499*4882a593Smuzhiyun 	mask |= BIT(CPCAP_BIT_EMU_MIC_MUX);
500*4882a593Smuzhiyun 	mask |= BIT(CPCAP_BIT_RX_R_ENCODE);
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	switch (muxval) {
503*4882a593Smuzhiyun 	case 1:
504*4882a593Smuzhiyun 		regval = BIT(CPCAP_BIT_MIC1_MUX);
505*4882a593Smuzhiyun 		break;
506*4882a593Smuzhiyun 	case 2:
507*4882a593Smuzhiyun 		regval = BIT(CPCAP_BIT_HS_MIC_MUX);
508*4882a593Smuzhiyun 		break;
509*4882a593Smuzhiyun 	case 3:
510*4882a593Smuzhiyun 		regval = BIT(CPCAP_BIT_EMU_MIC_MUX);
511*4882a593Smuzhiyun 		break;
512*4882a593Smuzhiyun 	case 4:
513*4882a593Smuzhiyun 		regval = BIT(CPCAP_BIT_RX_R_ENCODE);
514*4882a593Smuzhiyun 		break;
515*4882a593Smuzhiyun 	default:
516*4882a593Smuzhiyun 		break;
517*4882a593Smuzhiyun 	}
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
520*4882a593Smuzhiyun 				 mask, regval);
521*4882a593Smuzhiyun 	if (err)
522*4882a593Smuzhiyun 		return err;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL);
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	return 0;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun 
cpcap_input_left_mux_get_enum(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)529*4882a593Smuzhiyun static int cpcap_input_left_mux_get_enum(struct snd_kcontrol *kcontrol,
530*4882a593Smuzhiyun 					 struct snd_ctl_elem_value *ucontrol)
531*4882a593Smuzhiyun {
532*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
533*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
534*4882a593Smuzhiyun 	int regval, mask;
535*4882a593Smuzhiyun 	int err;
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	err = regmap_read(cpcap->regmap, CPCAP_REG_TXI, &regval);
538*4882a593Smuzhiyun 	if (err)
539*4882a593Smuzhiyun 		return err;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	mask = 0;
542*4882a593Smuzhiyun 	mask |= BIT(CPCAP_BIT_MIC2_MUX);
543*4882a593Smuzhiyun 	mask |= BIT(CPCAP_BIT_RX_L_ENCODE);
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	switch (regval & mask) {
546*4882a593Smuzhiyun 	case BIT(CPCAP_BIT_RX_L_ENCODE):
547*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 2;
548*4882a593Smuzhiyun 		break;
549*4882a593Smuzhiyun 	case BIT(CPCAP_BIT_MIC2_MUX):
550*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 1;
551*4882a593Smuzhiyun 		break;
552*4882a593Smuzhiyun 	default:
553*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 0;
554*4882a593Smuzhiyun 		break;
555*4882a593Smuzhiyun 	}
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	return 0;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun 
cpcap_input_left_mux_put_enum(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)560*4882a593Smuzhiyun static int cpcap_input_left_mux_put_enum(struct snd_kcontrol *kcontrol,
561*4882a593Smuzhiyun 					 struct snd_ctl_elem_value *ucontrol)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
564*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
565*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm =
566*4882a593Smuzhiyun 		snd_soc_dapm_kcontrol_dapm(kcontrol);
567*4882a593Smuzhiyun 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
568*4882a593Smuzhiyun 	unsigned int muxval = ucontrol->value.enumerated.item[0];
569*4882a593Smuzhiyun 	int regval = 0, mask;
570*4882a593Smuzhiyun 	int err;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	mask = 0;
573*4882a593Smuzhiyun 	mask |= BIT(CPCAP_BIT_MIC2_MUX);
574*4882a593Smuzhiyun 	mask |= BIT(CPCAP_BIT_RX_L_ENCODE);
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	switch (muxval) {
577*4882a593Smuzhiyun 	case 1:
578*4882a593Smuzhiyun 		regval = BIT(CPCAP_BIT_MIC2_MUX);
579*4882a593Smuzhiyun 		break;
580*4882a593Smuzhiyun 	case 2:
581*4882a593Smuzhiyun 		regval = BIT(CPCAP_BIT_RX_L_ENCODE);
582*4882a593Smuzhiyun 		break;
583*4882a593Smuzhiyun 	default:
584*4882a593Smuzhiyun 		break;
585*4882a593Smuzhiyun 	}
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
588*4882a593Smuzhiyun 				 mask, regval);
589*4882a593Smuzhiyun 	if (err)
590*4882a593Smuzhiyun 		return err;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL);
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	return 0;
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_input_left_mux =
598*4882a593Smuzhiyun 	SOC_DAPM_ENUM_EXT("Input Left", cpcap_input_left_mux_enum,
599*4882a593Smuzhiyun 			  cpcap_input_left_mux_get_enum,
600*4882a593Smuzhiyun 			  cpcap_input_left_mux_put_enum);
601*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_input_right_mux =
602*4882a593Smuzhiyun 	SOC_DAPM_ENUM_EXT("Input Right", cpcap_input_right_mux_enum,
603*4882a593Smuzhiyun 			  cpcap_input_right_mux_get_enum,
604*4882a593Smuzhiyun 			  cpcap_input_right_mux_put_enum);
605*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_emu_left_mux =
606*4882a593Smuzhiyun 	SOC_DAPM_ENUM_EXT("EMU Left", cpcap_emu_l_mux_enum,
607*4882a593Smuzhiyun 			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
608*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_emu_right_mux =
609*4882a593Smuzhiyun 	SOC_DAPM_ENUM_EXT("EMU Right", cpcap_emu_r_mux_enum,
610*4882a593Smuzhiyun 			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
611*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_hs_left_mux =
612*4882a593Smuzhiyun 	SOC_DAPM_ENUM_EXT("Headset Left", cpcap_hs_l_mux_enum,
613*4882a593Smuzhiyun 			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
614*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_hs_right_mux =
615*4882a593Smuzhiyun 	SOC_DAPM_ENUM_EXT("Headset Right", cpcap_hs_r_mux_enum,
616*4882a593Smuzhiyun 			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
617*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_line_left_mux =
618*4882a593Smuzhiyun 	SOC_DAPM_ENUM_EXT("Line Left", cpcap_line_l_mux_enum,
619*4882a593Smuzhiyun 			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
620*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_line_right_mux =
621*4882a593Smuzhiyun 	SOC_DAPM_ENUM_EXT("Line Right", cpcap_line_r_mux_enum,
622*4882a593Smuzhiyun 			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
623*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_speaker_left_mux =
624*4882a593Smuzhiyun 	SOC_DAPM_ENUM_EXT("Speaker Left", cpcap_spkr_l_mux_enum,
625*4882a593Smuzhiyun 			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
626*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_speaker_right_mux =
627*4882a593Smuzhiyun 	SOC_DAPM_ENUM_EXT("Speaker Right", cpcap_spkr_r_mux_enum,
628*4882a593Smuzhiyun 			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
629*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_earpiece_mux =
630*4882a593Smuzhiyun 	SOC_DAPM_ENUM_EXT("Earpiece", cpcap_earpiece_mux_enum,
631*4882a593Smuzhiyun 			  cpcap_output_mux_get_enum, cpcap_output_mux_put_enum);
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_hifi_mono_mixer_controls[] = {
634*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("HiFi Mono Playback Switch",
635*4882a593Smuzhiyun 		CPCAP_REG_RXSDOA, CPCAP_BIT_MONO_DAC1, 1, 0),
636*4882a593Smuzhiyun };
637*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_ext_mono_mixer_controls[] = {
638*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Ext Mono Playback Switch",
639*4882a593Smuzhiyun 		CPCAP_REG_RXEPOA, CPCAP_BIT_MONO_EXT0, 1, 0),
640*4882a593Smuzhiyun };
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_extr_mute_control =
643*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Switch",
644*4882a593Smuzhiyun 		CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_IN_R_SW, 1, 0);
645*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_extl_mute_control =
646*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Switch",
647*4882a593Smuzhiyun 		CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_IN_L_SW, 1, 0);
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun static const struct snd_kcontrol_new cpcap_voice_loopback =
650*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Switch",
651*4882a593Smuzhiyun 		CPCAP_REG_TXI, CPCAP_BIT_DLM, 1, 0);
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun static const struct snd_soc_dapm_widget cpcap_dapm_widgets[] = {
654*4882a593Smuzhiyun 	/* DAIs */
655*4882a593Smuzhiyun 	SND_SOC_DAPM_AIF_IN("HiFi RX", NULL, 0, SND_SOC_NOPM, 0, 0),
656*4882a593Smuzhiyun 	SND_SOC_DAPM_AIF_IN("Voice RX", NULL, 0, SND_SOC_NOPM, 0, 0),
657*4882a593Smuzhiyun 	SND_SOC_DAPM_AIF_OUT("Voice TX", NULL, 0, SND_SOC_NOPM, 0, 0),
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	/* Power Supply */
660*4882a593Smuzhiyun 	SND_SOC_DAPM_REGULATOR_SUPPLY("VAUDIO", SLEEP_ACTIVATE_POWER, 0),
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	/* Highpass Filters */
663*4882a593Smuzhiyun 	SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Highpass Filter RX",
664*4882a593Smuzhiyun 		CPCAP_REG_CC, CPCAP_BIT_AUDIHPF_0, 0x3, 0x3, 0x0),
665*4882a593Smuzhiyun 	SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Highpass Filter TX",
666*4882a593Smuzhiyun 		CPCAP_REG_CC, CPCAP_BIT_AUDOHPF_0, 0x3, 0x3, 0x0),
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	/* Clocks */
669*4882a593Smuzhiyun 	SND_SOC_DAPM_SUPPLY("HiFi DAI Clock",
670*4882a593Smuzhiyun 		CPCAP_REG_SDACDI, CPCAP_BIT_ST_CLK_EN, 0, NULL, 0),
671*4882a593Smuzhiyun 	SND_SOC_DAPM_SUPPLY("Voice DAI Clock",
672*4882a593Smuzhiyun 		CPCAP_REG_CDI, CPCAP_BIT_CDC_CLK_EN, 0, NULL, 0),
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	/* Microphone Bias */
675*4882a593Smuzhiyun 	SND_SOC_DAPM_SUPPLY("MIC1R Bias",
676*4882a593Smuzhiyun 		CPCAP_REG_TXI, CPCAP_BIT_MB_ON1R, 0, NULL, 0),
677*4882a593Smuzhiyun 	SND_SOC_DAPM_SUPPLY("MIC1L Bias",
678*4882a593Smuzhiyun 		CPCAP_REG_TXI, CPCAP_BIT_MB_ON1L, 0, NULL, 0),
679*4882a593Smuzhiyun 	SND_SOC_DAPM_SUPPLY("MIC2 Bias",
680*4882a593Smuzhiyun 		CPCAP_REG_TXI, CPCAP_BIT_MB_ON2, 0, NULL, 0),
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 	/* Inputs */
683*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("MICR"),
684*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("HSMIC"),
685*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("EMUMIC"),
686*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("MICL"),
687*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("EXTR"),
688*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("EXTL"),
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun 	/* Capture Route */
691*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("Right Capture Route",
692*4882a593Smuzhiyun 		SND_SOC_NOPM, 0, 0, &cpcap_input_right_mux),
693*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("Left Capture Route",
694*4882a593Smuzhiyun 		SND_SOC_NOPM, 0, 0, &cpcap_input_left_mux),
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	/* Capture PGAs */
697*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA("Microphone 1 PGA",
698*4882a593Smuzhiyun 		CPCAP_REG_TXI, CPCAP_BIT_MIC1_PGA_EN, 0, NULL, 0),
699*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA("Microphone 2 PGA",
700*4882a593Smuzhiyun 		CPCAP_REG_TXI, CPCAP_BIT_MIC2_PGA_EN, 0, NULL, 0),
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	/* ADC */
703*4882a593Smuzhiyun 	SND_SOC_DAPM_ADC("ADC Right", NULL,
704*4882a593Smuzhiyun 		CPCAP_REG_CC, CPCAP_BIT_MIC1_CDC_EN, 0),
705*4882a593Smuzhiyun 	SND_SOC_DAPM_ADC("ADC Left", NULL,
706*4882a593Smuzhiyun 		CPCAP_REG_CC, CPCAP_BIT_MIC2_CDC_EN, 0),
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	/* DAC */
709*4882a593Smuzhiyun 	SND_SOC_DAPM_DAC_E("DAC HiFi", NULL,
710*4882a593Smuzhiyun 		CPCAP_REG_SDAC, CPCAP_BIT_ST_DAC_EN, 0,
711*4882a593Smuzhiyun 		cpcap_st_workaround,
712*4882a593Smuzhiyun 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
713*4882a593Smuzhiyun 	SND_SOC_DAPM_DAC_E("DAC Voice", NULL,
714*4882a593Smuzhiyun 		CPCAP_REG_CC, CPCAP_BIT_CDC_EN_RX, 0,
715*4882a593Smuzhiyun 		cpcap_st_workaround,
716*4882a593Smuzhiyun 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	/* Playback PGA */
719*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA("HiFi PGA",
720*4882a593Smuzhiyun 		CPCAP_REG_RXSDOA, CPCAP_BIT_PGA_DAC_EN, 0, NULL, 0),
721*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA("Voice PGA",
722*4882a593Smuzhiyun 		CPCAP_REG_RXCOA, CPCAP_BIT_PGA_CDC_EN, 0, NULL, 0),
723*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA_E("Ext Right PGA",
724*4882a593Smuzhiyun 		CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_EXT_R_EN, 0,
725*4882a593Smuzhiyun 		NULL, 0,
726*4882a593Smuzhiyun 		cpcap_st_workaround,
727*4882a593Smuzhiyun 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
728*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA_E("Ext Left PGA",
729*4882a593Smuzhiyun 		CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_EXT_L_EN, 0,
730*4882a593Smuzhiyun 		NULL, 0,
731*4882a593Smuzhiyun 		cpcap_st_workaround,
732*4882a593Smuzhiyun 		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	/* Playback Switch */
735*4882a593Smuzhiyun 	SND_SOC_DAPM_SWITCH("Ext Right Enable", SND_SOC_NOPM, 0, 0,
736*4882a593Smuzhiyun 		&cpcap_extr_mute_control),
737*4882a593Smuzhiyun 	SND_SOC_DAPM_SWITCH("Ext Left Enable", SND_SOC_NOPM, 0, 0,
738*4882a593Smuzhiyun 		&cpcap_extl_mute_control),
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	/* Loopback Switch */
741*4882a593Smuzhiyun 	SND_SOC_DAPM_SWITCH("Voice Loopback", SND_SOC_NOPM, 0, 0,
742*4882a593Smuzhiyun 		&cpcap_voice_loopback),
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun 	/* Mono Mixer */
745*4882a593Smuzhiyun 	SOC_MIXER_ARRAY("HiFi Mono Left Mixer", SND_SOC_NOPM, 0, 0,
746*4882a593Smuzhiyun 		cpcap_hifi_mono_mixer_controls),
747*4882a593Smuzhiyun 	SOC_MIXER_ARRAY("HiFi Mono Right Mixer", SND_SOC_NOPM, 0, 0,
748*4882a593Smuzhiyun 		cpcap_hifi_mono_mixer_controls),
749*4882a593Smuzhiyun 	SOC_MIXER_ARRAY("Ext Mono Left Mixer", SND_SOC_NOPM, 0, 0,
750*4882a593Smuzhiyun 		cpcap_ext_mono_mixer_controls),
751*4882a593Smuzhiyun 	SOC_MIXER_ARRAY("Ext Mono Right Mixer", SND_SOC_NOPM, 0, 0,
752*4882a593Smuzhiyun 		cpcap_ext_mono_mixer_controls),
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	/* Output Routes */
755*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("Earpiece Playback Route", SND_SOC_NOPM, 0, 0,
756*4882a593Smuzhiyun 		&cpcap_earpiece_mux),
757*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("Speaker Right Playback Route", SND_SOC_NOPM, 0, 0,
758*4882a593Smuzhiyun 		&cpcap_speaker_right_mux),
759*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("Speaker Left Playback Route", SND_SOC_NOPM, 0, 0,
760*4882a593Smuzhiyun 		&cpcap_speaker_left_mux),
761*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("Lineout Right Playback Route", SND_SOC_NOPM, 0, 0,
762*4882a593Smuzhiyun 		&cpcap_line_right_mux),
763*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("Lineout Left Playback Route", SND_SOC_NOPM, 0, 0,
764*4882a593Smuzhiyun 		&cpcap_line_left_mux),
765*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("Headset Right Playback Route", SND_SOC_NOPM, 0, 0,
766*4882a593Smuzhiyun 		&cpcap_hs_right_mux),
767*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("Headset Left Playback Route", SND_SOC_NOPM, 0, 0,
768*4882a593Smuzhiyun 		&cpcap_hs_left_mux),
769*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("EMU Right Playback Route", SND_SOC_NOPM, 0, 0,
770*4882a593Smuzhiyun 		&cpcap_emu_right_mux),
771*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("EMU Left Playback Route", SND_SOC_NOPM, 0, 0,
772*4882a593Smuzhiyun 		&cpcap_emu_left_mux),
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	/* Output Amplifier */
775*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA("Earpiece PGA",
776*4882a593Smuzhiyun 		CPCAP_REG_RXOA, CPCAP_BIT_A1_EAR_EN, 0, NULL, 0),
777*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA("Speaker Right PGA",
778*4882a593Smuzhiyun 		CPCAP_REG_RXOA, CPCAP_BIT_A2_LDSP_R_EN, 0, NULL, 0),
779*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA("Speaker Left PGA",
780*4882a593Smuzhiyun 		CPCAP_REG_RXOA, CPCAP_BIT_A2_LDSP_L_EN, 0, NULL, 0),
781*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA("Lineout Right PGA",
782*4882a593Smuzhiyun 		CPCAP_REG_RXOA, CPCAP_BIT_A4_LINEOUT_R_EN, 0, NULL, 0),
783*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA("Lineout Left PGA",
784*4882a593Smuzhiyun 		CPCAP_REG_RXOA, CPCAP_BIT_A4_LINEOUT_L_EN, 0, NULL, 0),
785*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA("Headset Right PGA",
786*4882a593Smuzhiyun 		CPCAP_REG_RXOA, CPCAP_BIT_HS_R_EN, 0, NULL, 0),
787*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA("Headset Left PGA",
788*4882a593Smuzhiyun 		CPCAP_REG_RXOA, CPCAP_BIT_HS_L_EN, 0, NULL, 0),
789*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA("EMU Right PGA",
790*4882a593Smuzhiyun 		CPCAP_REG_RXOA, CPCAP_BIT_EMU_SPKR_R_EN, 0, NULL, 0),
791*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA("EMU Left PGA",
792*4882a593Smuzhiyun 		CPCAP_REG_RXOA, CPCAP_BIT_EMU_SPKR_L_EN, 0, NULL, 0),
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	/* Headet Charge Pump */
795*4882a593Smuzhiyun 	SND_SOC_DAPM_SUPPLY("Headset Charge Pump",
796*4882a593Smuzhiyun 		CPCAP_REG_RXOA, CPCAP_BIT_ST_HS_CP_EN, 0, NULL, 0),
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	/* Outputs */
799*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("EP"),
800*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("SPKR"),
801*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("SPKL"),
802*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("LINER"),
803*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("LINEL"),
804*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("HSR"),
805*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("HSL"),
806*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("EMUR"),
807*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("EMUL"),
808*4882a593Smuzhiyun };
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun static const struct snd_soc_dapm_route intercon[] = {
811*4882a593Smuzhiyun 	/* Power Supply */
812*4882a593Smuzhiyun 	{"HiFi PGA", NULL, "VAUDIO"},
813*4882a593Smuzhiyun 	{"Voice PGA", NULL, "VAUDIO"},
814*4882a593Smuzhiyun 	{"Ext Right PGA", NULL, "VAUDIO"},
815*4882a593Smuzhiyun 	{"Ext Left PGA", NULL, "VAUDIO"},
816*4882a593Smuzhiyun 	{"Microphone 1 PGA", NULL, "VAUDIO"},
817*4882a593Smuzhiyun 	{"Microphone 2 PGA", NULL, "VAUDIO"},
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	/* Stream -> AIF */
820*4882a593Smuzhiyun 	{"HiFi RX", NULL, "HiFi Playback"},
821*4882a593Smuzhiyun 	{"Voice RX", NULL, "Voice Playback"},
822*4882a593Smuzhiyun 	{"Voice Capture", NULL, "Voice TX"},
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun 	/* AIF clocks */
825*4882a593Smuzhiyun 	{"HiFi RX", NULL, "HiFi DAI Clock"},
826*4882a593Smuzhiyun 	{"Voice RX", NULL, "Voice DAI Clock"},
827*4882a593Smuzhiyun 	{"Voice TX", NULL, "Voice DAI Clock"},
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun 	/* Digital Loopback */
830*4882a593Smuzhiyun 	{"Voice Loopback", "Switch", "Voice TX"},
831*4882a593Smuzhiyun 	{"Voice RX", NULL, "Voice Loopback"},
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	/* Highpass Filters */
834*4882a593Smuzhiyun 	{"Highpass Filter RX", NULL, "Voice RX"},
835*4882a593Smuzhiyun 	{"Voice TX", NULL, "Highpass Filter TX"},
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	/* AIF -> DAC mapping */
838*4882a593Smuzhiyun 	{"DAC HiFi", NULL, "HiFi RX"},
839*4882a593Smuzhiyun 	{"DAC Voice", NULL, "Highpass Filter RX"},
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	/* DAC -> PGA */
842*4882a593Smuzhiyun 	{"HiFi PGA", NULL, "DAC HiFi"},
843*4882a593Smuzhiyun 	{"Voice PGA", NULL, "DAC Voice"},
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	/* Ext Input -> PGA */
846*4882a593Smuzhiyun 	{"Ext Right PGA", NULL, "EXTR"},
847*4882a593Smuzhiyun 	{"Ext Left PGA", NULL, "EXTL"},
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	/* Ext PGA -> Ext Playback Switch */
850*4882a593Smuzhiyun 	{"Ext Right Enable", "Switch", "Ext Right PGA"},
851*4882a593Smuzhiyun 	{"Ext Left Enable", "Switch", "Ext Left PGA"},
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	/* HiFi PGA -> Mono Mixer */
854*4882a593Smuzhiyun 	{"HiFi Mono Left Mixer", NULL, "HiFi PGA"},
855*4882a593Smuzhiyun 	{"HiFi Mono Left Mixer", "HiFi Mono Playback Switch", "HiFi PGA"},
856*4882a593Smuzhiyun 	{"HiFi Mono Right Mixer", NULL, "HiFi PGA"},
857*4882a593Smuzhiyun 	{"HiFi Mono Right Mixer", "HiFi Mono Playback Switch", "HiFi PGA"},
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 	/* Ext Playback Switch -> Ext Mono Mixer */
860*4882a593Smuzhiyun 	{"Ext Mono Right Mixer", NULL, "Ext Right Enable"},
861*4882a593Smuzhiyun 	{"Ext Mono Right Mixer", "Ext Mono Playback Switch", "Ext Left Enable"},
862*4882a593Smuzhiyun 	{"Ext Mono Left Mixer", NULL, "Ext Left Enable"},
863*4882a593Smuzhiyun 	{"Ext Mono Left Mixer", "Ext Mono Playback Switch", "Ext Right Enable"},
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun 	/* HiFi Mono Mixer -> Output Route */
866*4882a593Smuzhiyun 	{"Earpiece Playback Route", "HiFi", "HiFi Mono Right Mixer"},
867*4882a593Smuzhiyun 	{"Speaker Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
868*4882a593Smuzhiyun 	{"Speaker Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
869*4882a593Smuzhiyun 	{"Lineout Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
870*4882a593Smuzhiyun 	{"Lineout Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
871*4882a593Smuzhiyun 	{"Headset Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
872*4882a593Smuzhiyun 	{"Headset Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
873*4882a593Smuzhiyun 	{"EMU Right Playback Route", "HiFi", "HiFi Mono Right Mixer"},
874*4882a593Smuzhiyun 	{"EMU Left Playback Route", "HiFi", "HiFi Mono Left Mixer"},
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun 	/* Voice PGA -> Output Route */
877*4882a593Smuzhiyun 	{"Earpiece Playback Route", "Voice", "Voice PGA"},
878*4882a593Smuzhiyun 	{"Speaker Right Playback Route", "Voice", "Voice PGA"},
879*4882a593Smuzhiyun 	{"Speaker Left Playback Route", "Voice", "Voice PGA"},
880*4882a593Smuzhiyun 	{"Lineout Right Playback Route", "Voice", "Voice PGA"},
881*4882a593Smuzhiyun 	{"Lineout Left Playback Route", "Voice", "Voice PGA"},
882*4882a593Smuzhiyun 	{"Headset Right Playback Route", "Voice", "Voice PGA"},
883*4882a593Smuzhiyun 	{"Headset Left Playback Route", "Voice", "Voice PGA"},
884*4882a593Smuzhiyun 	{"EMU Right Playback Route", "Voice", "Voice PGA"},
885*4882a593Smuzhiyun 	{"EMU Left Playback Route", "Voice", "Voice PGA"},
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun 	/* Ext Mono Mixer -> Output Route */
888*4882a593Smuzhiyun 	{"Earpiece Playback Route", "Ext", "Ext Mono Right Mixer"},
889*4882a593Smuzhiyun 	{"Speaker Right Playback Route", "Ext", "Ext Mono Right Mixer"},
890*4882a593Smuzhiyun 	{"Speaker Left Playback Route", "Ext", "Ext Mono Left Mixer"},
891*4882a593Smuzhiyun 	{"Lineout Right Playback Route", "Ext", "Ext Mono Right Mixer"},
892*4882a593Smuzhiyun 	{"Lineout Left Playback Route", "Ext", "Ext Mono Left Mixer"},
893*4882a593Smuzhiyun 	{"Headset Right Playback Route", "Ext", "Ext Mono Right Mixer"},
894*4882a593Smuzhiyun 	{"Headset Left Playback Route", "Ext", "Ext Mono Left Mixer"},
895*4882a593Smuzhiyun 	{"EMU Right Playback Route", "Ext", "Ext Mono Right Mixer"},
896*4882a593Smuzhiyun 	{"EMU Left Playback Route", "Ext", "Ext Mono Left Mixer"},
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	/* Output Route -> Output Amplifier */
899*4882a593Smuzhiyun 	{"Earpiece PGA", NULL, "Earpiece Playback Route"},
900*4882a593Smuzhiyun 	{"Speaker Right PGA", NULL, "Speaker Right Playback Route"},
901*4882a593Smuzhiyun 	{"Speaker Left PGA", NULL, "Speaker Left Playback Route"},
902*4882a593Smuzhiyun 	{"Lineout Right PGA", NULL, "Lineout Right Playback Route"},
903*4882a593Smuzhiyun 	{"Lineout Left PGA", NULL, "Lineout Left Playback Route"},
904*4882a593Smuzhiyun 	{"Headset Right PGA", NULL, "Headset Right Playback Route"},
905*4882a593Smuzhiyun 	{"Headset Left PGA", NULL, "Headset Left Playback Route"},
906*4882a593Smuzhiyun 	{"EMU Right PGA", NULL, "EMU Right Playback Route"},
907*4882a593Smuzhiyun 	{"EMU Left PGA", NULL, "EMU Left Playback Route"},
908*4882a593Smuzhiyun 
909*4882a593Smuzhiyun 	/* Output Amplifier -> Output */
910*4882a593Smuzhiyun 	{"EP", NULL, "Earpiece PGA"},
911*4882a593Smuzhiyun 	{"SPKR", NULL, "Speaker Right PGA"},
912*4882a593Smuzhiyun 	{"SPKL", NULL, "Speaker Left PGA"},
913*4882a593Smuzhiyun 	{"LINER", NULL, "Lineout Right PGA"},
914*4882a593Smuzhiyun 	{"LINEL", NULL, "Lineout Left PGA"},
915*4882a593Smuzhiyun 	{"HSR", NULL, "Headset Right PGA"},
916*4882a593Smuzhiyun 	{"HSL", NULL, "Headset Left PGA"},
917*4882a593Smuzhiyun 	{"EMUR", NULL, "EMU Right PGA"},
918*4882a593Smuzhiyun 	{"EMUL", NULL, "EMU Left PGA"},
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun 	/* Headset Charge Pump -> Headset */
921*4882a593Smuzhiyun 	{"HSR", NULL, "Headset Charge Pump"},
922*4882a593Smuzhiyun 	{"HSL", NULL, "Headset Charge Pump"},
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	/* Mic -> Mic Route */
925*4882a593Smuzhiyun 	{"Right Capture Route", "Mic 1", "MICR"},
926*4882a593Smuzhiyun 	{"Right Capture Route", "Headset Mic", "HSMIC"},
927*4882a593Smuzhiyun 	{"Right Capture Route", "EMU Mic", "EMUMIC"},
928*4882a593Smuzhiyun 	{"Right Capture Route", "Ext Right", "EXTR"},
929*4882a593Smuzhiyun 	{"Left Capture Route", "Mic 2", "MICL"},
930*4882a593Smuzhiyun 	{"Left Capture Route", "Ext Left", "EXTL"},
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun 	/* Input Route -> Microphone PGA */
933*4882a593Smuzhiyun 	{"Microphone 1 PGA", NULL, "Right Capture Route"},
934*4882a593Smuzhiyun 	{"Microphone 2 PGA", NULL, "Left Capture Route"},
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 	/* Microphone PGA -> ADC */
937*4882a593Smuzhiyun 	{"ADC Right", NULL, "Microphone 1 PGA"},
938*4882a593Smuzhiyun 	{"ADC Left", NULL, "Microphone 2 PGA"},
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun 	/* ADC -> Stream */
941*4882a593Smuzhiyun 	{"Highpass Filter TX", NULL, "ADC Right"},
942*4882a593Smuzhiyun 	{"Highpass Filter TX", NULL, "ADC Left"},
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 	/* Mic Bias */
945*4882a593Smuzhiyun 	{"MICL", NULL, "MIC1L Bias"},
946*4882a593Smuzhiyun 	{"MICR", NULL, "MIC1R Bias"},
947*4882a593Smuzhiyun };
948*4882a593Smuzhiyun 
cpcap_set_sysclk(struct cpcap_audio * cpcap,enum cpcap_dai dai,int clk_id,int freq)949*4882a593Smuzhiyun static int cpcap_set_sysclk(struct cpcap_audio *cpcap, enum cpcap_dai dai,
950*4882a593Smuzhiyun 			    int clk_id, int freq)
951*4882a593Smuzhiyun {
952*4882a593Smuzhiyun 	u16 clkfreqreg, clkfreqshift;
953*4882a593Smuzhiyun 	u16 clkfreqmask, clkfreqval;
954*4882a593Smuzhiyun 	u16 clkidreg, clkidshift;
955*4882a593Smuzhiyun 	u16 mask, val;
956*4882a593Smuzhiyun 	int err;
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 	switch (dai) {
959*4882a593Smuzhiyun 	case CPCAP_DAI_HIFI:
960*4882a593Smuzhiyun 		clkfreqreg = CPCAP_REG_SDAC;
961*4882a593Smuzhiyun 		clkfreqshift = CPCAP_BIT_ST_DAC_CLK0;
962*4882a593Smuzhiyun 		clkidreg = CPCAP_REG_SDACDI;
963*4882a593Smuzhiyun 		clkidshift = CPCAP_BIT_ST_DAC_CLK_IN_SEL;
964*4882a593Smuzhiyun 		break;
965*4882a593Smuzhiyun 	case CPCAP_DAI_VOICE:
966*4882a593Smuzhiyun 		clkfreqreg = CPCAP_REG_CC;
967*4882a593Smuzhiyun 		clkfreqshift = CPCAP_BIT_CDC_CLK0;
968*4882a593Smuzhiyun 		clkidreg = CPCAP_REG_CDI;
969*4882a593Smuzhiyun 		clkidshift = CPCAP_BIT_CLK_IN_SEL;
970*4882a593Smuzhiyun 		break;
971*4882a593Smuzhiyun 	default:
972*4882a593Smuzhiyun 		dev_err(cpcap->component->dev, "invalid DAI: %d", dai);
973*4882a593Smuzhiyun 		return -EINVAL;
974*4882a593Smuzhiyun 	}
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	/* setup clk id */
977*4882a593Smuzhiyun 	if (clk_id < 0 || clk_id > 1) {
978*4882a593Smuzhiyun 		dev_err(cpcap->component->dev, "invalid clk id %d", clk_id);
979*4882a593Smuzhiyun 		return -EINVAL;
980*4882a593Smuzhiyun 	}
981*4882a593Smuzhiyun 	err = regmap_update_bits(cpcap->regmap, clkidreg, BIT(clkidshift),
982*4882a593Smuzhiyun 				 clk_id ? BIT(clkidshift) : 0);
983*4882a593Smuzhiyun 	if (err)
984*4882a593Smuzhiyun 		return err;
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun 	/* enable PLL for Voice DAI */
987*4882a593Smuzhiyun 	if (dai == CPCAP_DAI_VOICE) {
988*4882a593Smuzhiyun 		mask = BIT(CPCAP_BIT_CDC_PLL_SEL);
989*4882a593Smuzhiyun 		val = BIT(CPCAP_BIT_CDC_PLL_SEL);
990*4882a593Smuzhiyun 		err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
991*4882a593Smuzhiyun 					 mask, val);
992*4882a593Smuzhiyun 		if (err)
993*4882a593Smuzhiyun 			return err;
994*4882a593Smuzhiyun 	}
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun 	/* setup frequency */
997*4882a593Smuzhiyun 	clkfreqmask = 0x7 << clkfreqshift;
998*4882a593Smuzhiyun 	switch (freq) {
999*4882a593Smuzhiyun 	case 15360000:
1000*4882a593Smuzhiyun 		clkfreqval = 0x01 << clkfreqshift;
1001*4882a593Smuzhiyun 		break;
1002*4882a593Smuzhiyun 	case 16800000:
1003*4882a593Smuzhiyun 		clkfreqval = 0x02 << clkfreqshift;
1004*4882a593Smuzhiyun 		break;
1005*4882a593Smuzhiyun 	case 19200000:
1006*4882a593Smuzhiyun 		clkfreqval = 0x03 << clkfreqshift;
1007*4882a593Smuzhiyun 		break;
1008*4882a593Smuzhiyun 	case 26000000:
1009*4882a593Smuzhiyun 		clkfreqval = 0x04 << clkfreqshift;
1010*4882a593Smuzhiyun 		break;
1011*4882a593Smuzhiyun 	case 33600000:
1012*4882a593Smuzhiyun 		clkfreqval = 0x05 << clkfreqshift;
1013*4882a593Smuzhiyun 		break;
1014*4882a593Smuzhiyun 	case 38400000:
1015*4882a593Smuzhiyun 		clkfreqval = 0x06 << clkfreqshift;
1016*4882a593Smuzhiyun 		break;
1017*4882a593Smuzhiyun 	default:
1018*4882a593Smuzhiyun 		dev_err(cpcap->component->dev, "unsupported freq %u", freq);
1019*4882a593Smuzhiyun 		return -EINVAL;
1020*4882a593Smuzhiyun 	}
1021*4882a593Smuzhiyun 
1022*4882a593Smuzhiyun 	err = regmap_update_bits(cpcap->regmap, clkfreqreg,
1023*4882a593Smuzhiyun 				 clkfreqmask, clkfreqval);
1024*4882a593Smuzhiyun 	if (err)
1025*4882a593Smuzhiyun 		return err;
1026*4882a593Smuzhiyun 
1027*4882a593Smuzhiyun 	if (dai == CPCAP_DAI_VOICE) {
1028*4882a593Smuzhiyun 		cpcap->codec_clk_id = clk_id;
1029*4882a593Smuzhiyun 		cpcap->codec_freq = freq;
1030*4882a593Smuzhiyun 	}
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun 	return 0;
1033*4882a593Smuzhiyun }
1034*4882a593Smuzhiyun 
cpcap_set_samprate(struct cpcap_audio * cpcap,enum cpcap_dai dai,int samplerate)1035*4882a593Smuzhiyun static int cpcap_set_samprate(struct cpcap_audio *cpcap, enum cpcap_dai dai,
1036*4882a593Smuzhiyun 			      int samplerate)
1037*4882a593Smuzhiyun {
1038*4882a593Smuzhiyun 	struct snd_soc_component *component = cpcap->component;
1039*4882a593Smuzhiyun 	u16 sampreg, sampmask, sampshift, sampval, sampreset;
1040*4882a593Smuzhiyun 	int err, sampreadval;
1041*4882a593Smuzhiyun 
1042*4882a593Smuzhiyun 	switch (dai) {
1043*4882a593Smuzhiyun 	case CPCAP_DAI_HIFI:
1044*4882a593Smuzhiyun 		sampreg = CPCAP_REG_SDAC;
1045*4882a593Smuzhiyun 		sampshift = CPCAP_BIT_ST_SR0;
1046*4882a593Smuzhiyun 		sampreset = BIT(CPCAP_BIT_DF_RESET_ST_DAC) |
1047*4882a593Smuzhiyun 			    BIT(CPCAP_BIT_ST_CLOCK_TREE_RESET);
1048*4882a593Smuzhiyun 		break;
1049*4882a593Smuzhiyun 	case CPCAP_DAI_VOICE:
1050*4882a593Smuzhiyun 		sampreg = CPCAP_REG_CC;
1051*4882a593Smuzhiyun 		sampshift = CPCAP_BIT_CDC_SR0;
1052*4882a593Smuzhiyun 		sampreset = BIT(CPCAP_BIT_DF_RESET) |
1053*4882a593Smuzhiyun 			    BIT(CPCAP_BIT_CDC_CLOCK_TREE_RESET);
1054*4882a593Smuzhiyun 		break;
1055*4882a593Smuzhiyun 	default:
1056*4882a593Smuzhiyun 		dev_err(component->dev, "invalid DAI: %d", dai);
1057*4882a593Smuzhiyun 		return -EINVAL;
1058*4882a593Smuzhiyun 	}
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun 	sampmask = 0xF << sampshift | sampreset;
1061*4882a593Smuzhiyun 	switch (samplerate) {
1062*4882a593Smuzhiyun 	case 48000:
1063*4882a593Smuzhiyun 		sampval = 0x8 << sampshift;
1064*4882a593Smuzhiyun 		break;
1065*4882a593Smuzhiyun 	case 44100:
1066*4882a593Smuzhiyun 		sampval = 0x7 << sampshift;
1067*4882a593Smuzhiyun 		break;
1068*4882a593Smuzhiyun 	case 32000:
1069*4882a593Smuzhiyun 		sampval = 0x6 << sampshift;
1070*4882a593Smuzhiyun 		break;
1071*4882a593Smuzhiyun 	case 24000:
1072*4882a593Smuzhiyun 		sampval = 0x5 << sampshift;
1073*4882a593Smuzhiyun 		break;
1074*4882a593Smuzhiyun 	case 22050:
1075*4882a593Smuzhiyun 		sampval = 0x4 << sampshift;
1076*4882a593Smuzhiyun 		break;
1077*4882a593Smuzhiyun 	case 16000:
1078*4882a593Smuzhiyun 		sampval = 0x3 << sampshift;
1079*4882a593Smuzhiyun 		break;
1080*4882a593Smuzhiyun 	case 12000:
1081*4882a593Smuzhiyun 		sampval = 0x2 << sampshift;
1082*4882a593Smuzhiyun 		break;
1083*4882a593Smuzhiyun 	case 11025:
1084*4882a593Smuzhiyun 		sampval = 0x1 << sampshift;
1085*4882a593Smuzhiyun 		break;
1086*4882a593Smuzhiyun 	case 8000:
1087*4882a593Smuzhiyun 		sampval = 0x0 << sampshift;
1088*4882a593Smuzhiyun 		break;
1089*4882a593Smuzhiyun 	default:
1090*4882a593Smuzhiyun 		dev_err(component->dev, "unsupported samplerate %d", samplerate);
1091*4882a593Smuzhiyun 		return -EINVAL;
1092*4882a593Smuzhiyun 	}
1093*4882a593Smuzhiyun 	err = regmap_update_bits(cpcap->regmap, sampreg,
1094*4882a593Smuzhiyun 				 sampmask, sampval | sampreset);
1095*4882a593Smuzhiyun 	if (err)
1096*4882a593Smuzhiyun 		return err;
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun 	/* Wait for clock tree reset to complete */
1099*4882a593Smuzhiyun 	mdelay(CLOCK_TREE_RESET_TIME);
1100*4882a593Smuzhiyun 
1101*4882a593Smuzhiyun 	err = regmap_read(cpcap->regmap, sampreg, &sampreadval);
1102*4882a593Smuzhiyun 	if (err)
1103*4882a593Smuzhiyun 		return err;
1104*4882a593Smuzhiyun 
1105*4882a593Smuzhiyun 	if (sampreadval & sampreset) {
1106*4882a593Smuzhiyun 		dev_err(component->dev, "reset self-clear failed: %04x",
1107*4882a593Smuzhiyun 			sampreadval);
1108*4882a593Smuzhiyun 		return -EIO;
1109*4882a593Smuzhiyun 	}
1110*4882a593Smuzhiyun 
1111*4882a593Smuzhiyun 	return 0;
1112*4882a593Smuzhiyun }
1113*4882a593Smuzhiyun 
cpcap_hifi_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)1114*4882a593Smuzhiyun static int cpcap_hifi_hw_params(struct snd_pcm_substream *substream,
1115*4882a593Smuzhiyun 				struct snd_pcm_hw_params *params,
1116*4882a593Smuzhiyun 				struct snd_soc_dai *dai)
1117*4882a593Smuzhiyun {
1118*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
1119*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
1120*4882a593Smuzhiyun 	int rate = params_rate(params);
1121*4882a593Smuzhiyun 
1122*4882a593Smuzhiyun 	dev_dbg(component->dev, "HiFi setup HW params: rate=%d", rate);
1123*4882a593Smuzhiyun 	return cpcap_set_samprate(cpcap, CPCAP_DAI_HIFI, rate);
1124*4882a593Smuzhiyun }
1125*4882a593Smuzhiyun 
cpcap_hifi_set_dai_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)1126*4882a593Smuzhiyun static int cpcap_hifi_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
1127*4882a593Smuzhiyun 				     unsigned int freq, int dir)
1128*4882a593Smuzhiyun {
1129*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
1130*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
1131*4882a593Smuzhiyun 	struct device *dev = component->dev;
1132*4882a593Smuzhiyun 
1133*4882a593Smuzhiyun 	dev_dbg(dev, "HiFi setup sysclk: clk_id=%u, freq=%u", clk_id, freq);
1134*4882a593Smuzhiyun 	return cpcap_set_sysclk(cpcap, CPCAP_DAI_HIFI, clk_id, freq);
1135*4882a593Smuzhiyun }
1136*4882a593Smuzhiyun 
cpcap_hifi_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)1137*4882a593Smuzhiyun static int cpcap_hifi_set_dai_fmt(struct snd_soc_dai *codec_dai,
1138*4882a593Smuzhiyun 				  unsigned int fmt)
1139*4882a593Smuzhiyun {
1140*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
1141*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
1142*4882a593Smuzhiyun 	struct device *dev = component->dev;
1143*4882a593Smuzhiyun 	static const u16 reg = CPCAP_REG_SDACDI;
1144*4882a593Smuzhiyun 	static const u16 mask =
1145*4882a593Smuzhiyun 		BIT(CPCAP_BIT_SMB_ST_DAC) |
1146*4882a593Smuzhiyun 		BIT(CPCAP_BIT_ST_CLK_INV) |
1147*4882a593Smuzhiyun 		BIT(CPCAP_BIT_ST_FS_INV) |
1148*4882a593Smuzhiyun 		BIT(CPCAP_BIT_ST_DIG_AUD_FS0) |
1149*4882a593Smuzhiyun 		BIT(CPCAP_BIT_ST_DIG_AUD_FS1) |
1150*4882a593Smuzhiyun 		BIT(CPCAP_BIT_ST_L_TIMESLOT0) |
1151*4882a593Smuzhiyun 		BIT(CPCAP_BIT_ST_L_TIMESLOT1) |
1152*4882a593Smuzhiyun 		BIT(CPCAP_BIT_ST_L_TIMESLOT2) |
1153*4882a593Smuzhiyun 		BIT(CPCAP_BIT_ST_R_TIMESLOT0) |
1154*4882a593Smuzhiyun 		BIT(CPCAP_BIT_ST_R_TIMESLOT1) |
1155*4882a593Smuzhiyun 		BIT(CPCAP_BIT_ST_R_TIMESLOT2);
1156*4882a593Smuzhiyun 	u16 val = 0x0000;
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun 	dev_dbg(dev, "HiFi setup dai format (%08x)", fmt);
1159*4882a593Smuzhiyun 
1160*4882a593Smuzhiyun 	/*
1161*4882a593Smuzhiyun 	 * "HiFi Playback" should always be configured as
1162*4882a593Smuzhiyun 	 * SND_SOC_DAIFMT_CBM_CFM - codec clk & frm master
1163*4882a593Smuzhiyun 	 * SND_SOC_DAIFMT_I2S - I2S mode
1164*4882a593Smuzhiyun 	 */
1165*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1166*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFM:
1167*4882a593Smuzhiyun 		val &= ~BIT(CPCAP_BIT_SMB_ST_DAC);
1168*4882a593Smuzhiyun 		break;
1169*4882a593Smuzhiyun 	default:
1170*4882a593Smuzhiyun 		dev_err(dev, "HiFi dai fmt failed: CPCAP should be master");
1171*4882a593Smuzhiyun 		return -EINVAL;
1172*4882a593Smuzhiyun 	}
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1175*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_IF:
1176*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_ST_FS_INV);
1177*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_ST_CLK_INV);
1178*4882a593Smuzhiyun 		break;
1179*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_NF:
1180*4882a593Smuzhiyun 		val &= ~BIT(CPCAP_BIT_ST_FS_INV);
1181*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_ST_CLK_INV);
1182*4882a593Smuzhiyun 		break;
1183*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_IF:
1184*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_ST_FS_INV);
1185*4882a593Smuzhiyun 		val &= ~BIT(CPCAP_BIT_ST_CLK_INV);
1186*4882a593Smuzhiyun 		break;
1187*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_NF:
1188*4882a593Smuzhiyun 		val &= ~BIT(CPCAP_BIT_ST_FS_INV);
1189*4882a593Smuzhiyun 		val &= ~BIT(CPCAP_BIT_ST_CLK_INV);
1190*4882a593Smuzhiyun 		break;
1191*4882a593Smuzhiyun 	default:
1192*4882a593Smuzhiyun 		dev_err(dev, "HiFi dai fmt failed: unsupported clock invert mode");
1193*4882a593Smuzhiyun 		return -EINVAL;
1194*4882a593Smuzhiyun 	}
1195*4882a593Smuzhiyun 
1196*4882a593Smuzhiyun 	if (val & BIT(CPCAP_BIT_ST_CLK_INV))
1197*4882a593Smuzhiyun 		val &= ~BIT(CPCAP_BIT_ST_CLK_INV);
1198*4882a593Smuzhiyun 	else
1199*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_ST_CLK_INV);
1200*4882a593Smuzhiyun 
1201*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1202*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S:
1203*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS0);
1204*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS1);
1205*4882a593Smuzhiyun 		break;
1206*4882a593Smuzhiyun 	default:
1207*4882a593Smuzhiyun 		/* 01 - 4 slots network mode */
1208*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS0);
1209*4882a593Smuzhiyun 		val &= ~BIT(CPCAP_BIT_ST_DIG_AUD_FS1);
1210*4882a593Smuzhiyun 		/* L on slot 1 */
1211*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_ST_L_TIMESLOT0);
1212*4882a593Smuzhiyun 		break;
1213*4882a593Smuzhiyun 	}
1214*4882a593Smuzhiyun 
1215*4882a593Smuzhiyun 	dev_dbg(dev, "HiFi dai format: val=%04x", val);
1216*4882a593Smuzhiyun 	return regmap_update_bits(cpcap->regmap, reg, mask, val);
1217*4882a593Smuzhiyun }
1218*4882a593Smuzhiyun 
cpcap_hifi_set_mute(struct snd_soc_dai * dai,int mute,int direction)1219*4882a593Smuzhiyun static int cpcap_hifi_set_mute(struct snd_soc_dai *dai, int mute, int direction)
1220*4882a593Smuzhiyun {
1221*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
1222*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
1223*4882a593Smuzhiyun 	static const u16 reg = CPCAP_REG_RXSDOA;
1224*4882a593Smuzhiyun 	static const u16 mask = BIT(CPCAP_BIT_ST_DAC_SW);
1225*4882a593Smuzhiyun 	u16 val;
1226*4882a593Smuzhiyun 
1227*4882a593Smuzhiyun 	if (mute)
1228*4882a593Smuzhiyun 		val = 0;
1229*4882a593Smuzhiyun 	else
1230*4882a593Smuzhiyun 		val = BIT(CPCAP_BIT_ST_DAC_SW);
1231*4882a593Smuzhiyun 
1232*4882a593Smuzhiyun 	dev_dbg(component->dev, "HiFi mute: %d", mute);
1233*4882a593Smuzhiyun 	return regmap_update_bits(cpcap->regmap, reg, mask, val);
1234*4882a593Smuzhiyun }
1235*4882a593Smuzhiyun 
1236*4882a593Smuzhiyun static const struct snd_soc_dai_ops cpcap_dai_hifi_ops = {
1237*4882a593Smuzhiyun 	.hw_params	= cpcap_hifi_hw_params,
1238*4882a593Smuzhiyun 	.set_sysclk	= cpcap_hifi_set_dai_sysclk,
1239*4882a593Smuzhiyun 	.set_fmt	= cpcap_hifi_set_dai_fmt,
1240*4882a593Smuzhiyun 	.mute_stream	= cpcap_hifi_set_mute,
1241*4882a593Smuzhiyun 	.no_capture_mute = 1,
1242*4882a593Smuzhiyun };
1243*4882a593Smuzhiyun 
cpcap_voice_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)1244*4882a593Smuzhiyun static int cpcap_voice_hw_params(struct snd_pcm_substream *substream,
1245*4882a593Smuzhiyun 				 struct snd_pcm_hw_params *params,
1246*4882a593Smuzhiyun 				 struct snd_soc_dai *dai)
1247*4882a593Smuzhiyun {
1248*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
1249*4882a593Smuzhiyun 	struct device *dev = component->dev;
1250*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
1251*4882a593Smuzhiyun 	static const u16 reg_cdi = CPCAP_REG_CDI;
1252*4882a593Smuzhiyun 	int rate = params_rate(params);
1253*4882a593Smuzhiyun 	int channels = params_channels(params);
1254*4882a593Smuzhiyun 	int direction = substream->stream;
1255*4882a593Smuzhiyun 	u16 val, mask;
1256*4882a593Smuzhiyun 	int err;
1257*4882a593Smuzhiyun 
1258*4882a593Smuzhiyun 	dev_dbg(dev, "Voice setup HW params: rate=%d, direction=%d, chan=%d",
1259*4882a593Smuzhiyun 		rate, direction, channels);
1260*4882a593Smuzhiyun 
1261*4882a593Smuzhiyun 	err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, rate);
1262*4882a593Smuzhiyun 	if (err)
1263*4882a593Smuzhiyun 		return err;
1264*4882a593Smuzhiyun 
1265*4882a593Smuzhiyun 	if (direction == SNDRV_PCM_STREAM_CAPTURE) {
1266*4882a593Smuzhiyun 		mask = 0x0000;
1267*4882a593Smuzhiyun 		mask |= BIT(CPCAP_BIT_MIC1_RX_TIMESLOT0);
1268*4882a593Smuzhiyun 		mask |= BIT(CPCAP_BIT_MIC1_RX_TIMESLOT1);
1269*4882a593Smuzhiyun 		mask |= BIT(CPCAP_BIT_MIC1_RX_TIMESLOT2);
1270*4882a593Smuzhiyun 		mask |= BIT(CPCAP_BIT_MIC2_TIMESLOT0);
1271*4882a593Smuzhiyun 		mask |= BIT(CPCAP_BIT_MIC2_TIMESLOT1);
1272*4882a593Smuzhiyun 		mask |= BIT(CPCAP_BIT_MIC2_TIMESLOT2);
1273*4882a593Smuzhiyun 		val = 0x0000;
1274*4882a593Smuzhiyun 		if (channels >= 2)
1275*4882a593Smuzhiyun 			val = BIT(CPCAP_BIT_MIC1_RX_TIMESLOT0);
1276*4882a593Smuzhiyun 		err = regmap_update_bits(cpcap->regmap, reg_cdi, mask, val);
1277*4882a593Smuzhiyun 		if (err)
1278*4882a593Smuzhiyun 			return err;
1279*4882a593Smuzhiyun 	}
1280*4882a593Smuzhiyun 
1281*4882a593Smuzhiyun 	return 0;
1282*4882a593Smuzhiyun }
1283*4882a593Smuzhiyun 
cpcap_voice_set_dai_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)1284*4882a593Smuzhiyun static int cpcap_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
1285*4882a593Smuzhiyun 				      unsigned int freq, int dir)
1286*4882a593Smuzhiyun {
1287*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
1288*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
1289*4882a593Smuzhiyun 
1290*4882a593Smuzhiyun 	dev_dbg(component->dev, "Voice setup sysclk: clk_id=%u, freq=%u",
1291*4882a593Smuzhiyun 		clk_id, freq);
1292*4882a593Smuzhiyun 	return cpcap_set_sysclk(cpcap, CPCAP_DAI_VOICE, clk_id, freq);
1293*4882a593Smuzhiyun }
1294*4882a593Smuzhiyun 
cpcap_voice_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)1295*4882a593Smuzhiyun static int cpcap_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
1296*4882a593Smuzhiyun 				   unsigned int fmt)
1297*4882a593Smuzhiyun {
1298*4882a593Smuzhiyun 	struct snd_soc_component *component = codec_dai->component;
1299*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
1300*4882a593Smuzhiyun 	static const u16 mask = BIT(CPCAP_BIT_SMB_CDC) |
1301*4882a593Smuzhiyun 				BIT(CPCAP_BIT_CLK_INV) |
1302*4882a593Smuzhiyun 				BIT(CPCAP_BIT_FS_INV) |
1303*4882a593Smuzhiyun 				BIT(CPCAP_BIT_CDC_DIG_AUD_FS0) |
1304*4882a593Smuzhiyun 				BIT(CPCAP_BIT_CDC_DIG_AUD_FS1);
1305*4882a593Smuzhiyun 	u16 val = 0x0000;
1306*4882a593Smuzhiyun 	int err;
1307*4882a593Smuzhiyun 
1308*4882a593Smuzhiyun 	dev_dbg(component->dev, "Voice setup dai format (%08x)", fmt);
1309*4882a593Smuzhiyun 
1310*4882a593Smuzhiyun 	/*
1311*4882a593Smuzhiyun 	 * "Voice Playback" and "Voice Capture" should always be
1312*4882a593Smuzhiyun 	 * configured as SND_SOC_DAIFMT_CBM_CFM - codec clk & frm
1313*4882a593Smuzhiyun 	 * master
1314*4882a593Smuzhiyun 	 */
1315*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1316*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFM:
1317*4882a593Smuzhiyun 		val &= ~BIT(CPCAP_BIT_SMB_CDC);
1318*4882a593Smuzhiyun 		break;
1319*4882a593Smuzhiyun 	default:
1320*4882a593Smuzhiyun 		dev_err(component->dev, "Voice dai fmt failed: CPCAP should be the master");
1321*4882a593Smuzhiyun 		val &= ~BIT(CPCAP_BIT_SMB_CDC);
1322*4882a593Smuzhiyun 		break;
1323*4882a593Smuzhiyun 	}
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1326*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_IF:
1327*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_CLK_INV);
1328*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_FS_INV);
1329*4882a593Smuzhiyun 		break;
1330*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_NF:
1331*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_CLK_INV);
1332*4882a593Smuzhiyun 		val &= ~BIT(CPCAP_BIT_FS_INV);
1333*4882a593Smuzhiyun 		break;
1334*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_IF:
1335*4882a593Smuzhiyun 		val &= ~BIT(CPCAP_BIT_CLK_INV);
1336*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_FS_INV);
1337*4882a593Smuzhiyun 		break;
1338*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_NF:
1339*4882a593Smuzhiyun 		val &= ~BIT(CPCAP_BIT_CLK_INV);
1340*4882a593Smuzhiyun 		val &= ~BIT(CPCAP_BIT_FS_INV);
1341*4882a593Smuzhiyun 		break;
1342*4882a593Smuzhiyun 	default:
1343*4882a593Smuzhiyun 		dev_err(component->dev, "Voice dai fmt failed: unsupported clock invert mode");
1344*4882a593Smuzhiyun 		break;
1345*4882a593Smuzhiyun 	}
1346*4882a593Smuzhiyun 
1347*4882a593Smuzhiyun 	if (val & BIT(CPCAP_BIT_CLK_INV))
1348*4882a593Smuzhiyun 		val &= ~BIT(CPCAP_BIT_CLK_INV);
1349*4882a593Smuzhiyun 	else
1350*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_CLK_INV);
1351*4882a593Smuzhiyun 
1352*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1353*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S:
1354*4882a593Smuzhiyun 		/* 11 - true I2S mode */
1355*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_CDC_DIG_AUD_FS0);
1356*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_CDC_DIG_AUD_FS1);
1357*4882a593Smuzhiyun 		break;
1358*4882a593Smuzhiyun 	default:
1359*4882a593Smuzhiyun 		/* 4 timeslots network mode */
1360*4882a593Smuzhiyun 		val |= BIT(CPCAP_BIT_CDC_DIG_AUD_FS0);
1361*4882a593Smuzhiyun 		val &= ~BIT(CPCAP_BIT_CDC_DIG_AUD_FS1);
1362*4882a593Smuzhiyun 		break;
1363*4882a593Smuzhiyun 	}
1364*4882a593Smuzhiyun 
1365*4882a593Smuzhiyun 	dev_dbg(component->dev, "Voice dai format: val=%04x", val);
1366*4882a593Smuzhiyun 	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI, mask, val);
1367*4882a593Smuzhiyun 	if (err)
1368*4882a593Smuzhiyun 		return err;
1369*4882a593Smuzhiyun 
1370*4882a593Smuzhiyun 	cpcap->codec_format = val;
1371*4882a593Smuzhiyun 	return 0;
1372*4882a593Smuzhiyun }
1373*4882a593Smuzhiyun 
cpcap_voice_set_mute(struct snd_soc_dai * dai,int mute,int direction)1374*4882a593Smuzhiyun static int cpcap_voice_set_mute(struct snd_soc_dai *dai,
1375*4882a593Smuzhiyun 				int mute, int direction)
1376*4882a593Smuzhiyun {
1377*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
1378*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
1379*4882a593Smuzhiyun 	static const u16 reg = CPCAP_REG_RXCOA;
1380*4882a593Smuzhiyun 	static const u16 mask = BIT(CPCAP_BIT_CDC_SW);
1381*4882a593Smuzhiyun 	u16 val;
1382*4882a593Smuzhiyun 
1383*4882a593Smuzhiyun 	if (mute)
1384*4882a593Smuzhiyun 		val = 0;
1385*4882a593Smuzhiyun 	else
1386*4882a593Smuzhiyun 		val = BIT(CPCAP_BIT_CDC_SW);
1387*4882a593Smuzhiyun 
1388*4882a593Smuzhiyun 	dev_dbg(component->dev, "Voice mute: %d", mute);
1389*4882a593Smuzhiyun 	return regmap_update_bits(cpcap->regmap, reg, mask, val);
1390*4882a593Smuzhiyun };
1391*4882a593Smuzhiyun 
1392*4882a593Smuzhiyun static const struct snd_soc_dai_ops cpcap_dai_voice_ops = {
1393*4882a593Smuzhiyun 	.hw_params	= cpcap_voice_hw_params,
1394*4882a593Smuzhiyun 	.set_sysclk	= cpcap_voice_set_dai_sysclk,
1395*4882a593Smuzhiyun 	.set_fmt	= cpcap_voice_set_dai_fmt,
1396*4882a593Smuzhiyun 	.mute_stream	= cpcap_voice_set_mute,
1397*4882a593Smuzhiyun 	.no_capture_mute = 1,
1398*4882a593Smuzhiyun };
1399*4882a593Smuzhiyun 
1400*4882a593Smuzhiyun static struct snd_soc_dai_driver cpcap_dai[] = {
1401*4882a593Smuzhiyun {
1402*4882a593Smuzhiyun 	.id = 0,
1403*4882a593Smuzhiyun 	.name = "cpcap-hifi",
1404*4882a593Smuzhiyun 	.playback = {
1405*4882a593Smuzhiyun 		.stream_name = "HiFi Playback",
1406*4882a593Smuzhiyun 		.channels_min = 2,
1407*4882a593Smuzhiyun 		.channels_max = 2,
1408*4882a593Smuzhiyun 		.rates = SNDRV_PCM_RATE_8000_48000,
1409*4882a593Smuzhiyun 		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE,
1410*4882a593Smuzhiyun 	},
1411*4882a593Smuzhiyun 	.ops = &cpcap_dai_hifi_ops,
1412*4882a593Smuzhiyun },
1413*4882a593Smuzhiyun {
1414*4882a593Smuzhiyun 	.id = 1,
1415*4882a593Smuzhiyun 	.name = "cpcap-voice",
1416*4882a593Smuzhiyun 	.playback = {
1417*4882a593Smuzhiyun 		.stream_name = "Voice Playback",
1418*4882a593Smuzhiyun 		.channels_min = 1,
1419*4882a593Smuzhiyun 		.channels_max = 1,
1420*4882a593Smuzhiyun 		.rates = SNDRV_PCM_RATE_8000_48000,
1421*4882a593Smuzhiyun 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
1422*4882a593Smuzhiyun 	},
1423*4882a593Smuzhiyun 	.capture = {
1424*4882a593Smuzhiyun 		.stream_name = "Voice Capture",
1425*4882a593Smuzhiyun 		.channels_min = 1,
1426*4882a593Smuzhiyun 		.channels_max = 2,
1427*4882a593Smuzhiyun 		.rates = SNDRV_PCM_RATE_8000_48000,
1428*4882a593Smuzhiyun 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
1429*4882a593Smuzhiyun 	},
1430*4882a593Smuzhiyun 	.ops = &cpcap_dai_voice_ops,
1431*4882a593Smuzhiyun },
1432*4882a593Smuzhiyun };
1433*4882a593Smuzhiyun 
cpcap_dai_mux(struct cpcap_audio * cpcap,bool swap_dai_configuration)1434*4882a593Smuzhiyun static int cpcap_dai_mux(struct cpcap_audio *cpcap, bool swap_dai_configuration)
1435*4882a593Smuzhiyun {
1436*4882a593Smuzhiyun 	u16 hifi_val, voice_val;
1437*4882a593Smuzhiyun 	u16 hifi_mask = BIT(CPCAP_BIT_DIG_AUD_IN_ST_DAC);
1438*4882a593Smuzhiyun 	u16 voice_mask = BIT(CPCAP_BIT_DIG_AUD_IN);
1439*4882a593Smuzhiyun 	int err;
1440*4882a593Smuzhiyun 
1441*4882a593Smuzhiyun 
1442*4882a593Smuzhiyun 
1443*4882a593Smuzhiyun 	if (!swap_dai_configuration) {
1444*4882a593Smuzhiyun 		/* Codec on DAI0, HiFi on DAI1 */
1445*4882a593Smuzhiyun 		voice_val = 0;
1446*4882a593Smuzhiyun 		hifi_val = hifi_mask;
1447*4882a593Smuzhiyun 	} else {
1448*4882a593Smuzhiyun 		/* Codec on DAI1, HiFi on DAI0 */
1449*4882a593Smuzhiyun 		voice_val = voice_mask;
1450*4882a593Smuzhiyun 		hifi_val = 0;
1451*4882a593Smuzhiyun 	}
1452*4882a593Smuzhiyun 
1453*4882a593Smuzhiyun 	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
1454*4882a593Smuzhiyun 				 voice_mask, voice_val);
1455*4882a593Smuzhiyun 	if (err)
1456*4882a593Smuzhiyun 		return err;
1457*4882a593Smuzhiyun 
1458*4882a593Smuzhiyun 	err = regmap_update_bits(cpcap->regmap, CPCAP_REG_SDACDI,
1459*4882a593Smuzhiyun 				 hifi_mask, hifi_val);
1460*4882a593Smuzhiyun 	if (err)
1461*4882a593Smuzhiyun 		return err;
1462*4882a593Smuzhiyun 
1463*4882a593Smuzhiyun 	return 0;
1464*4882a593Smuzhiyun }
1465*4882a593Smuzhiyun 
cpcap_audio_reset(struct snd_soc_component * component,bool swap_dai_configuration)1466*4882a593Smuzhiyun static int cpcap_audio_reset(struct snd_soc_component *component,
1467*4882a593Smuzhiyun 			     bool swap_dai_configuration)
1468*4882a593Smuzhiyun {
1469*4882a593Smuzhiyun 	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
1470*4882a593Smuzhiyun 	int i, err = 0;
1471*4882a593Smuzhiyun 
1472*4882a593Smuzhiyun 	dev_dbg(component->dev, "init audio codec");
1473*4882a593Smuzhiyun 
1474*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(cpcap_default_regs); i++) {
1475*4882a593Smuzhiyun 		err = regmap_update_bits(cpcap->regmap,
1476*4882a593Smuzhiyun 					 cpcap_default_regs[i].reg,
1477*4882a593Smuzhiyun 					 cpcap_default_regs[i].mask,
1478*4882a593Smuzhiyun 					 cpcap_default_regs[i].val);
1479*4882a593Smuzhiyun 		if (err)
1480*4882a593Smuzhiyun 			return err;
1481*4882a593Smuzhiyun 	}
1482*4882a593Smuzhiyun 
1483*4882a593Smuzhiyun 	/* setup default settings */
1484*4882a593Smuzhiyun 	err = cpcap_dai_mux(cpcap, swap_dai_configuration);
1485*4882a593Smuzhiyun 	if (err)
1486*4882a593Smuzhiyun 		return err;
1487*4882a593Smuzhiyun 
1488*4882a593Smuzhiyun 	err = cpcap_set_sysclk(cpcap, CPCAP_DAI_HIFI, 0, 26000000);
1489*4882a593Smuzhiyun 	if (err)
1490*4882a593Smuzhiyun 		return err;
1491*4882a593Smuzhiyun 	err = cpcap_set_sysclk(cpcap, CPCAP_DAI_VOICE, 0, 26000000);
1492*4882a593Smuzhiyun 	if (err)
1493*4882a593Smuzhiyun 		return err;
1494*4882a593Smuzhiyun 
1495*4882a593Smuzhiyun 	err = cpcap_set_samprate(cpcap, CPCAP_DAI_HIFI, 48000);
1496*4882a593Smuzhiyun 	if (err)
1497*4882a593Smuzhiyun 		return err;
1498*4882a593Smuzhiyun 
1499*4882a593Smuzhiyun 	err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, 48000);
1500*4882a593Smuzhiyun 	if (err)
1501*4882a593Smuzhiyun 		return err;
1502*4882a593Smuzhiyun 
1503*4882a593Smuzhiyun 	return 0;
1504*4882a593Smuzhiyun }
1505*4882a593Smuzhiyun 
cpcap_soc_probe(struct snd_soc_component * component)1506*4882a593Smuzhiyun static int cpcap_soc_probe(struct snd_soc_component *component)
1507*4882a593Smuzhiyun {
1508*4882a593Smuzhiyun 	struct cpcap_audio *cpcap;
1509*4882a593Smuzhiyun 	int err;
1510*4882a593Smuzhiyun 
1511*4882a593Smuzhiyun 	cpcap = devm_kzalloc(component->dev, sizeof(*cpcap), GFP_KERNEL);
1512*4882a593Smuzhiyun 	if (!cpcap)
1513*4882a593Smuzhiyun 		return -ENOMEM;
1514*4882a593Smuzhiyun 	snd_soc_component_set_drvdata(component, cpcap);
1515*4882a593Smuzhiyun 	cpcap->component = component;
1516*4882a593Smuzhiyun 
1517*4882a593Smuzhiyun 	cpcap->regmap = dev_get_regmap(component->dev->parent, NULL);
1518*4882a593Smuzhiyun 	if (!cpcap->regmap)
1519*4882a593Smuzhiyun 		return -ENODEV;
1520*4882a593Smuzhiyun 	snd_soc_component_init_regmap(component, cpcap->regmap);
1521*4882a593Smuzhiyun 
1522*4882a593Smuzhiyun 	err = cpcap_get_vendor(component->dev, cpcap->regmap, &cpcap->vendor);
1523*4882a593Smuzhiyun 	if (err)
1524*4882a593Smuzhiyun 		return err;
1525*4882a593Smuzhiyun 
1526*4882a593Smuzhiyun 	return cpcap_audio_reset(component, false);
1527*4882a593Smuzhiyun }
1528*4882a593Smuzhiyun 
1529*4882a593Smuzhiyun static struct snd_soc_component_driver soc_codec_dev_cpcap = {
1530*4882a593Smuzhiyun 	.probe			= cpcap_soc_probe,
1531*4882a593Smuzhiyun 	.controls		= cpcap_snd_controls,
1532*4882a593Smuzhiyun 	.num_controls		= ARRAY_SIZE(cpcap_snd_controls),
1533*4882a593Smuzhiyun 	.dapm_widgets		= cpcap_dapm_widgets,
1534*4882a593Smuzhiyun 	.num_dapm_widgets	= ARRAY_SIZE(cpcap_dapm_widgets),
1535*4882a593Smuzhiyun 	.dapm_routes		= intercon,
1536*4882a593Smuzhiyun 	.num_dapm_routes	= ARRAY_SIZE(intercon),
1537*4882a593Smuzhiyun 	.idle_bias_on		= 1,
1538*4882a593Smuzhiyun 	.use_pmdown_time	= 1,
1539*4882a593Smuzhiyun 	.endianness		= 1,
1540*4882a593Smuzhiyun 	.non_legacy_dai_naming	= 1,
1541*4882a593Smuzhiyun };
1542*4882a593Smuzhiyun 
cpcap_codec_probe(struct platform_device * pdev)1543*4882a593Smuzhiyun static int cpcap_codec_probe(struct platform_device *pdev)
1544*4882a593Smuzhiyun {
1545*4882a593Smuzhiyun 	struct device_node *codec_node =
1546*4882a593Smuzhiyun 		of_get_child_by_name(pdev->dev.parent->of_node, "audio-codec");
1547*4882a593Smuzhiyun 	if (!codec_node)
1548*4882a593Smuzhiyun 		return -ENODEV;
1549*4882a593Smuzhiyun 
1550*4882a593Smuzhiyun 	pdev->dev.of_node = codec_node;
1551*4882a593Smuzhiyun 
1552*4882a593Smuzhiyun 	return devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_cpcap,
1553*4882a593Smuzhiyun 				      cpcap_dai, ARRAY_SIZE(cpcap_dai));
1554*4882a593Smuzhiyun }
1555*4882a593Smuzhiyun 
1556*4882a593Smuzhiyun static struct platform_driver cpcap_codec_driver = {
1557*4882a593Smuzhiyun 	.probe		= cpcap_codec_probe,
1558*4882a593Smuzhiyun 	.driver		= {
1559*4882a593Smuzhiyun 		.name	= "cpcap-codec",
1560*4882a593Smuzhiyun 	},
1561*4882a593Smuzhiyun };
1562*4882a593Smuzhiyun module_platform_driver(cpcap_codec_driver);
1563*4882a593Smuzhiyun 
1564*4882a593Smuzhiyun MODULE_ALIAS("platform:cpcap-codec");
1565*4882a593Smuzhiyun MODULE_DESCRIPTION("ASoC CPCAP codec driver");
1566*4882a593Smuzhiyun MODULE_AUTHOR("Sebastian Reichel");
1567*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
1568