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, ®_voice);
368*4882a593Smuzhiyun if (err)
369*4882a593Smuzhiyun return err;
370*4882a593Smuzhiyun err = regmap_read(cpcap->regmap, CPCAP_REG_RXSDOA, ®_hifi);
371*4882a593Smuzhiyun if (err)
372*4882a593Smuzhiyun return err;
373*4882a593Smuzhiyun err = regmap_read(cpcap->regmap, CPCAP_REG_RXEPOA, ®_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, ®val);
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, ®val);
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