]>
Commit | Line | Data |
---|---|---|
150db8c5 SK |
1 | /* Copyright (c) 2016, The Linux Foundation. All rights reserved. |
2 | * | |
3 | * This program is free software; you can redistribute it and/or modify | |
4 | * it under the terms of the GNU General Public License version 2 and | |
5 | * only version 2 as published by the Free Software Foundation. | |
6 | * | |
7 | * This program is distributed in the hope that it will be useful, | |
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | * GNU General Public License for more details. | |
11 | */ | |
12 | ||
13 | #include <linux/module.h> | |
14 | #include <linux/err.h> | |
15 | #include <linux/kernel.h> | |
16 | #include <linux/delay.h> | |
17 | #include <linux/types.h> | |
18 | #include <linux/clk.h> | |
19 | #include <linux/of.h> | |
20 | #include <linux/platform_device.h> | |
21 | #include <linux/regmap.h> | |
22 | #include <linux/mfd/syscon.h> | |
23 | #include <sound/soc.h> | |
24 | #include <sound/pcm.h> | |
25 | #include <sound/pcm_params.h> | |
26 | #include <sound/tlv.h> | |
27 | ||
28 | #define LPASS_CDC_CLK_RX_RESET_CTL (0x000) | |
29 | #define LPASS_CDC_CLK_TX_RESET_B1_CTL (0x004) | |
30 | #define CLK_RX_RESET_B1_CTL_TX1_RESET_MASK BIT(0) | |
31 | #define CLK_RX_RESET_B1_CTL_TX2_RESET_MASK BIT(1) | |
32 | #define LPASS_CDC_CLK_DMIC_B1_CTL (0x008) | |
33 | #define DMIC_B1_CTL_DMIC0_CLK_SEL_MASK GENMASK(3, 1) | |
34 | #define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV2 (0x0 << 1) | |
35 | #define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3 (0x1 << 1) | |
36 | #define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV4 (0x2 << 1) | |
37 | #define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV6 (0x3 << 1) | |
38 | #define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV16 (0x4 << 1) | |
39 | #define DMIC_B1_CTL_DMIC0_CLK_EN_MASK BIT(0) | |
40 | #define DMIC_B1_CTL_DMIC0_CLK_EN_ENABLE BIT(0) | |
41 | ||
42 | #define LPASS_CDC_CLK_RX_I2S_CTL (0x00C) | |
43 | #define RX_I2S_CTL_RX_I2S_MODE_MASK BIT(5) | |
44 | #define RX_I2S_CTL_RX_I2S_MODE_16 BIT(5) | |
45 | #define RX_I2S_CTL_RX_I2S_MODE_32 0 | |
46 | #define RX_I2S_CTL_RX_I2S_FS_RATE_MASK GENMASK(2, 0) | |
47 | #define RX_I2S_CTL_RX_I2S_FS_RATE_F_8_KHZ 0x0 | |
48 | #define RX_I2S_CTL_RX_I2S_FS_RATE_F_16_KHZ 0x1 | |
49 | #define RX_I2S_CTL_RX_I2S_FS_RATE_F_32_KHZ 0x2 | |
50 | #define RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ 0x3 | |
51 | #define RX_I2S_CTL_RX_I2S_FS_RATE_F_96_KHZ 0x4 | |
52 | #define RX_I2S_CTL_RX_I2S_FS_RATE_F_192_KHZ 0x5 | |
53 | #define LPASS_CDC_CLK_TX_I2S_CTL (0x010) | |
54 | #define TX_I2S_CTL_TX_I2S_MODE_MASK BIT(5) | |
55 | #define TX_I2S_CTL_TX_I2S_MODE_16 BIT(5) | |
56 | #define TX_I2S_CTL_TX_I2S_MODE_32 0 | |
57 | #define TX_I2S_CTL_TX_I2S_FS_RATE_MASK GENMASK(2, 0) | |
58 | #define TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ 0x0 | |
59 | #define TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ 0x1 | |
60 | #define TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ 0x2 | |
61 | #define TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ 0x3 | |
62 | #define TX_I2S_CTL_TX_I2S_FS_RATE_F_96_KHZ 0x4 | |
63 | #define TX_I2S_CTL_TX_I2S_FS_RATE_F_192_KHZ 0x5 | |
64 | ||
65 | #define LPASS_CDC_CLK_OTHR_RESET_B1_CTL (0x014) | |
66 | #define LPASS_CDC_CLK_TX_CLK_EN_B1_CTL (0x018) | |
67 | #define LPASS_CDC_CLK_OTHR_CTL (0x01C) | |
68 | #define LPASS_CDC_CLK_RX_B1_CTL (0x020) | |
69 | #define LPASS_CDC_CLK_MCLK_CTL (0x024) | |
70 | #define MCLK_CTL_MCLK_EN_MASK BIT(0) | |
71 | #define MCLK_CTL_MCLK_EN_ENABLE BIT(0) | |
72 | #define MCLK_CTL_MCLK_EN_DISABLE 0 | |
73 | #define LPASS_CDC_CLK_PDM_CTL (0x028) | |
74 | #define LPASS_CDC_CLK_PDM_CTL_PDM_EN_MASK BIT(0) | |
75 | #define LPASS_CDC_CLK_PDM_CTL_PDM_EN BIT(0) | |
76 | #define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK BIT(1) | |
77 | #define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB BIT(1) | |
78 | #define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_PDM_CLK 0 | |
79 | ||
80 | #define LPASS_CDC_CLK_SD_CTL (0x02C) | |
81 | #define LPASS_CDC_RX1_B1_CTL (0x040) | |
82 | #define LPASS_CDC_RX2_B1_CTL (0x060) | |
83 | #define LPASS_CDC_RX3_B1_CTL (0x080) | |
84 | #define LPASS_CDC_RX1_B2_CTL (0x044) | |
85 | #define LPASS_CDC_RX2_B2_CTL (0x064) | |
86 | #define LPASS_CDC_RX3_B2_CTL (0x084) | |
87 | #define LPASS_CDC_RX1_B3_CTL (0x048) | |
88 | #define LPASS_CDC_RX2_B3_CTL (0x068) | |
89 | #define LPASS_CDC_RX3_B3_CTL (0x088) | |
90 | #define LPASS_CDC_RX1_B4_CTL (0x04C) | |
91 | #define LPASS_CDC_RX2_B4_CTL (0x06C) | |
92 | #define LPASS_CDC_RX3_B4_CTL (0x08C) | |
93 | #define LPASS_CDC_RX1_B5_CTL (0x050) | |
94 | #define LPASS_CDC_RX2_B5_CTL (0x070) | |
95 | #define LPASS_CDC_RX3_B5_CTL (0x090) | |
96 | #define LPASS_CDC_RX1_B6_CTL (0x054) | |
97 | #define RXn_B6_CTL_MUTE_MASK BIT(0) | |
98 | #define RXn_B6_CTL_MUTE_ENABLE BIT(0) | |
99 | #define RXn_B6_CTL_MUTE_DISABLE 0 | |
100 | #define LPASS_CDC_RX2_B6_CTL (0x074) | |
101 | #define LPASS_CDC_RX3_B6_CTL (0x094) | |
102 | #define LPASS_CDC_RX1_VOL_CTL_B1_CTL (0x058) | |
103 | #define LPASS_CDC_RX2_VOL_CTL_B1_CTL (0x078) | |
104 | #define LPASS_CDC_RX3_VOL_CTL_B1_CTL (0x098) | |
105 | #define LPASS_CDC_RX1_VOL_CTL_B2_CTL (0x05C) | |
106 | #define LPASS_CDC_RX2_VOL_CTL_B2_CTL (0x07C) | |
107 | #define LPASS_CDC_RX3_VOL_CTL_B2_CTL (0x09C) | |
108 | #define LPASS_CDC_TOP_GAIN_UPDATE (0x0A0) | |
109 | #define LPASS_CDC_TOP_CTL (0x0A4) | |
110 | #define TOP_CTL_DIG_MCLK_FREQ_MASK BIT(0) | |
111 | #define TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ 0 | |
112 | #define TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ BIT(0) | |
113 | ||
114 | #define LPASS_CDC_DEBUG_DESER1_CTL (0x0E0) | |
115 | #define LPASS_CDC_DEBUG_DESER2_CTL (0x0E4) | |
116 | #define LPASS_CDC_DEBUG_B1_CTL_CFG (0x0E8) | |
117 | #define LPASS_CDC_DEBUG_B2_CTL_CFG (0x0EC) | |
118 | #define LPASS_CDC_DEBUG_B3_CTL_CFG (0x0F0) | |
119 | #define LPASS_CDC_IIR1_GAIN_B1_CTL (0x100) | |
120 | #define LPASS_CDC_IIR2_GAIN_B1_CTL (0x140) | |
121 | #define LPASS_CDC_IIR1_GAIN_B2_CTL (0x104) | |
122 | #define LPASS_CDC_IIR2_GAIN_B2_CTL (0x144) | |
123 | #define LPASS_CDC_IIR1_GAIN_B3_CTL (0x108) | |
124 | #define LPASS_CDC_IIR2_GAIN_B3_CTL (0x148) | |
125 | #define LPASS_CDC_IIR1_GAIN_B4_CTL (0x10C) | |
126 | #define LPASS_CDC_IIR2_GAIN_B4_CTL (0x14C) | |
127 | #define LPASS_CDC_IIR1_GAIN_B5_CTL (0x110) | |
128 | #define LPASS_CDC_IIR2_GAIN_B5_CTL (0x150) | |
129 | #define LPASS_CDC_IIR1_GAIN_B6_CTL (0x114) | |
130 | #define LPASS_CDC_IIR2_GAIN_B6_CTL (0x154) | |
131 | #define LPASS_CDC_IIR1_GAIN_B7_CTL (0x118) | |
132 | #define LPASS_CDC_IIR2_GAIN_B7_CTL (0x158) | |
133 | #define LPASS_CDC_IIR1_GAIN_B8_CTL (0x11C) | |
134 | #define LPASS_CDC_IIR2_GAIN_B8_CTL (0x15C) | |
135 | #define LPASS_CDC_IIR1_CTL (0x120) | |
136 | #define LPASS_CDC_IIR2_CTL (0x160) | |
137 | #define LPASS_CDC_IIR1_GAIN_TIMER_CTL (0x124) | |
138 | #define LPASS_CDC_IIR2_GAIN_TIMER_CTL (0x164) | |
139 | #define LPASS_CDC_IIR1_COEF_B1_CTL (0x128) | |
140 | #define LPASS_CDC_IIR2_COEF_B1_CTL (0x168) | |
141 | #define LPASS_CDC_IIR1_COEF_B2_CTL (0x12C) | |
142 | #define LPASS_CDC_IIR2_COEF_B2_CTL (0x16C) | |
143 | #define LPASS_CDC_CONN_RX1_B1_CTL (0x180) | |
144 | #define LPASS_CDC_CONN_RX1_B2_CTL (0x184) | |
145 | #define LPASS_CDC_CONN_RX1_B3_CTL (0x188) | |
146 | #define LPASS_CDC_CONN_RX2_B1_CTL (0x18C) | |
147 | #define LPASS_CDC_CONN_RX2_B2_CTL (0x190) | |
148 | #define LPASS_CDC_CONN_RX2_B3_CTL (0x194) | |
149 | #define LPASS_CDC_CONN_RX3_B1_CTL (0x198) | |
150 | #define LPASS_CDC_CONN_RX3_B2_CTL (0x19C) | |
151 | #define LPASS_CDC_CONN_TX_B1_CTL (0x1A0) | |
152 | #define LPASS_CDC_CONN_EQ1_B1_CTL (0x1A8) | |
153 | #define LPASS_CDC_CONN_EQ1_B2_CTL (0x1AC) | |
154 | #define LPASS_CDC_CONN_EQ1_B3_CTL (0x1B0) | |
155 | #define LPASS_CDC_CONN_EQ1_B4_CTL (0x1B4) | |
156 | #define LPASS_CDC_CONN_EQ2_B1_CTL (0x1B8) | |
157 | #define LPASS_CDC_CONN_EQ2_B2_CTL (0x1BC) | |
158 | #define LPASS_CDC_CONN_EQ2_B3_CTL (0x1C0) | |
159 | #define LPASS_CDC_CONN_EQ2_B4_CTL (0x1C4) | |
160 | #define LPASS_CDC_CONN_TX_I2S_SD1_CTL (0x1C8) | |
161 | #define LPASS_CDC_TX1_VOL_CTL_TIMER (0x280) | |
162 | #define LPASS_CDC_TX2_VOL_CTL_TIMER (0x2A0) | |
163 | #define LPASS_CDC_TX1_VOL_CTL_GAIN (0x284) | |
164 | #define LPASS_CDC_TX2_VOL_CTL_GAIN (0x2A4) | |
165 | #define LPASS_CDC_TX1_VOL_CTL_CFG (0x288) | |
166 | #define TX_VOL_CTL_CFG_MUTE_EN_MASK BIT(0) | |
167 | #define TX_VOL_CTL_CFG_MUTE_EN_ENABLE BIT(0) | |
168 | ||
169 | #define LPASS_CDC_TX2_VOL_CTL_CFG (0x2A8) | |
170 | #define LPASS_CDC_TX1_MUX_CTL (0x28C) | |
171 | #define TX_MUX_CTL_CUT_OFF_FREQ_MASK GENMASK(5, 4) | |
172 | #define TX_MUX_CTL_CUT_OFF_FREQ_SHIFT 4 | |
173 | #define TX_MUX_CTL_CF_NEG_3DB_4HZ (0x0 << 4) | |
174 | #define TX_MUX_CTL_CF_NEG_3DB_75HZ (0x1 << 4) | |
175 | #define TX_MUX_CTL_CF_NEG_3DB_150HZ (0x2 << 4) | |
176 | #define TX_MUX_CTL_HPF_BP_SEL_MASK BIT(3) | |
177 | #define TX_MUX_CTL_HPF_BP_SEL_BYPASS BIT(3) | |
178 | #define TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS 0 | |
179 | ||
180 | #define LPASS_CDC_TX2_MUX_CTL (0x2AC) | |
181 | #define LPASS_CDC_TX1_CLK_FS_CTL (0x290) | |
182 | #define LPASS_CDC_TX2_CLK_FS_CTL (0x2B0) | |
183 | #define LPASS_CDC_TX1_DMIC_CTL (0x294) | |
184 | #define LPASS_CDC_TX2_DMIC_CTL (0x2B4) | |
185 | #define TXN_DMIC_CTL_CLK_SEL_MASK GENMASK(2, 0) | |
186 | #define TXN_DMIC_CTL_CLK_SEL_DIV2 0x0 | |
187 | #define TXN_DMIC_CTL_CLK_SEL_DIV3 0x1 | |
188 | #define TXN_DMIC_CTL_CLK_SEL_DIV4 0x2 | |
189 | #define TXN_DMIC_CTL_CLK_SEL_DIV6 0x3 | |
190 | #define TXN_DMIC_CTL_CLK_SEL_DIV16 0x4 | |
191 | ||
192 | #define MSM8916_WCD_DIGITAL_RATES (SNDRV_PCM_RATE_8000 | \ | |
193 | SNDRV_PCM_RATE_16000 | \ | |
194 | SNDRV_PCM_RATE_32000 | \ | |
195 | SNDRV_PCM_RATE_48000) | |
196 | #define MSM8916_WCD_DIGITAL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ | |
51f493ae | 197 | SNDRV_PCM_FMTBIT_S32_LE) |
150db8c5 SK |
198 | |
199 | struct msm8916_wcd_digital_priv { | |
200 | struct clk *ahbclk, *mclk; | |
201 | }; | |
202 | ||
203 | static const unsigned long rx_gain_reg[] = { | |
204 | LPASS_CDC_RX1_VOL_CTL_B2_CTL, | |
205 | LPASS_CDC_RX2_VOL_CTL_B2_CTL, | |
206 | LPASS_CDC_RX3_VOL_CTL_B2_CTL, | |
207 | }; | |
208 | ||
209 | static const unsigned long tx_gain_reg[] = { | |
210 | LPASS_CDC_TX1_VOL_CTL_GAIN, | |
211 | LPASS_CDC_TX2_VOL_CTL_GAIN, | |
212 | }; | |
213 | ||
214 | static const char *const rx_mix1_text[] = { | |
215 | "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3" | |
216 | }; | |
217 | ||
218 | static const char *const dec_mux_text[] = { | |
219 | "ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2" | |
220 | }; | |
3a88a375 SK |
221 | |
222 | static const char *const cic_mux_text[] = { "AMIC", "DMIC" }; | |
150db8c5 SK |
223 | static const char *const rx_mix2_text[] = { "ZERO", "IIR1", "IIR2" }; |
224 | static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; | |
225 | ||
226 | /* RX1 MIX1 */ | |
227 | static const struct soc_enum rx_mix1_inp_enum[] = { | |
228 | SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text), | |
229 | SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 3, 6, rx_mix1_text), | |
230 | SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text), | |
231 | }; | |
232 | ||
233 | /* RX1 MIX2 */ | |
234 | static const struct soc_enum rx_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( | |
235 | LPASS_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text); | |
236 | ||
237 | /* RX2 MIX1 */ | |
238 | static const struct soc_enum rx2_mix1_inp_enum[] = { | |
239 | SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text), | |
240 | SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text), | |
f53ee247 | 241 | SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B2_CTL, 0, 6, rx_mix1_text), |
150db8c5 SK |
242 | }; |
243 | ||
244 | /* RX2 MIX2 */ | |
245 | static const struct soc_enum rx2_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( | |
246 | LPASS_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text); | |
247 | ||
248 | /* RX3 MIX1 */ | |
249 | static const struct soc_enum rx3_mix1_inp_enum[] = { | |
250 | SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text), | |
251 | SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text), | |
f53ee247 | 252 | SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B2_CTL, 0, 6, rx_mix1_text), |
150db8c5 SK |
253 | }; |
254 | ||
255 | /* DEC */ | |
256 | static const struct soc_enum dec1_mux_enum = SOC_ENUM_SINGLE( | |
257 | LPASS_CDC_CONN_TX_B1_CTL, 0, 6, dec_mux_text); | |
258 | static const struct soc_enum dec2_mux_enum = SOC_ENUM_SINGLE( | |
259 | LPASS_CDC_CONN_TX_B1_CTL, 3, 6, dec_mux_text); | |
260 | ||
3a88a375 SK |
261 | /* CIC */ |
262 | static const struct soc_enum cic1_mux_enum = SOC_ENUM_SINGLE( | |
263 | LPASS_CDC_TX1_MUX_CTL, 0, 2, cic_mux_text); | |
264 | static const struct soc_enum cic2_mux_enum = SOC_ENUM_SINGLE( | |
265 | LPASS_CDC_TX2_MUX_CTL, 0, 2, cic_mux_text); | |
266 | ||
150db8c5 SK |
267 | /* RDAC2 MUX */ |
268 | static const struct snd_kcontrol_new dec1_mux = SOC_DAPM_ENUM( | |
269 | "DEC1 MUX Mux", dec1_mux_enum); | |
270 | static const struct snd_kcontrol_new dec2_mux = SOC_DAPM_ENUM( | |
271 | "DEC2 MUX Mux", dec2_mux_enum); | |
3a88a375 SK |
272 | static const struct snd_kcontrol_new cic1_mux = SOC_DAPM_ENUM( |
273 | "CIC1 MUX Mux", cic1_mux_enum); | |
274 | static const struct snd_kcontrol_new cic2_mux = SOC_DAPM_ENUM( | |
275 | "CIC2 MUX Mux", cic2_mux_enum); | |
150db8c5 SK |
276 | static const struct snd_kcontrol_new rx_mix1_inp1_mux = SOC_DAPM_ENUM( |
277 | "RX1 MIX1 INP1 Mux", rx_mix1_inp_enum[0]); | |
278 | static const struct snd_kcontrol_new rx_mix1_inp2_mux = SOC_DAPM_ENUM( | |
279 | "RX1 MIX1 INP2 Mux", rx_mix1_inp_enum[1]); | |
280 | static const struct snd_kcontrol_new rx_mix1_inp3_mux = SOC_DAPM_ENUM( | |
281 | "RX1 MIX1 INP3 Mux", rx_mix1_inp_enum[2]); | |
282 | static const struct snd_kcontrol_new rx2_mix1_inp1_mux = SOC_DAPM_ENUM( | |
283 | "RX2 MIX1 INP1 Mux", rx2_mix1_inp_enum[0]); | |
284 | static const struct snd_kcontrol_new rx2_mix1_inp2_mux = SOC_DAPM_ENUM( | |
285 | "RX2 MIX1 INP2 Mux", rx2_mix1_inp_enum[1]); | |
286 | static const struct snd_kcontrol_new rx2_mix1_inp3_mux = SOC_DAPM_ENUM( | |
287 | "RX2 MIX1 INP3 Mux", rx2_mix1_inp_enum[2]); | |
288 | static const struct snd_kcontrol_new rx3_mix1_inp1_mux = SOC_DAPM_ENUM( | |
289 | "RX3 MIX1 INP1 Mux", rx3_mix1_inp_enum[0]); | |
290 | static const struct snd_kcontrol_new rx3_mix1_inp2_mux = SOC_DAPM_ENUM( | |
291 | "RX3 MIX1 INP2 Mux", rx3_mix1_inp_enum[1]); | |
292 | static const struct snd_kcontrol_new rx3_mix1_inp3_mux = SOC_DAPM_ENUM( | |
293 | "RX3 MIX1 INP3 Mux", rx3_mix1_inp_enum[2]); | |
294 | ||
295 | /* Digital Gain control -38.4 dB to +38.4 dB in 0.3 dB steps */ | |
296 | static const DECLARE_TLV_DB_SCALE(digital_gain, -3840, 30, 0); | |
297 | ||
298 | /* Cutoff Freq for High Pass Filter at -3dB */ | |
299 | static const char * const hpf_cutoff_text[] = { | |
300 | "4Hz", "75Hz", "150Hz", | |
301 | }; | |
302 | ||
303 | static SOC_ENUM_SINGLE_DECL(tx1_hpf_cutoff_enum, LPASS_CDC_TX1_MUX_CTL, 4, | |
304 | hpf_cutoff_text); | |
305 | static SOC_ENUM_SINGLE_DECL(tx2_hpf_cutoff_enum, LPASS_CDC_TX2_MUX_CTL, 4, | |
306 | hpf_cutoff_text); | |
307 | ||
308 | /* cut off for dc blocker inside rx chain */ | |
309 | static const char * const dc_blocker_cutoff_text[] = { | |
310 | "4Hz", "75Hz", "150Hz", | |
311 | }; | |
312 | ||
313 | static SOC_ENUM_SINGLE_DECL(rx1_dcb_cutoff_enum, LPASS_CDC_RX1_B4_CTL, 0, | |
314 | dc_blocker_cutoff_text); | |
315 | static SOC_ENUM_SINGLE_DECL(rx2_dcb_cutoff_enum, LPASS_CDC_RX2_B4_CTL, 0, | |
316 | dc_blocker_cutoff_text); | |
317 | static SOC_ENUM_SINGLE_DECL(rx3_dcb_cutoff_enum, LPASS_CDC_RX3_B4_CTL, 0, | |
318 | dc_blocker_cutoff_text); | |
319 | ||
320 | static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = { | |
321 | SOC_SINGLE_S8_TLV("RX1 Digital Volume", LPASS_CDC_RX1_VOL_CTL_B2_CTL, | |
322 | -128, 127, digital_gain), | |
323 | SOC_SINGLE_S8_TLV("RX2 Digital Volume", LPASS_CDC_RX2_VOL_CTL_B2_CTL, | |
324 | -128, 127, digital_gain), | |
325 | SOC_SINGLE_S8_TLV("RX3 Digital Volume", LPASS_CDC_RX3_VOL_CTL_B2_CTL, | |
326 | -128, 127, digital_gain), | |
327 | SOC_SINGLE_S8_TLV("TX1 Digital Volume", LPASS_CDC_TX1_VOL_CTL_GAIN, | |
328 | -128, 127, digital_gain), | |
329 | SOC_SINGLE_S8_TLV("TX2 Digital Volume", LPASS_CDC_TX2_VOL_CTL_GAIN, | |
330 | -128, 127, digital_gain), | |
331 | SOC_ENUM("TX1 HPF Cutoff", tx1_hpf_cutoff_enum), | |
332 | SOC_ENUM("TX2 HPF Cutoff", tx2_hpf_cutoff_enum), | |
333 | SOC_SINGLE("TX1 HPF Switch", LPASS_CDC_TX1_MUX_CTL, 3, 1, 0), | |
334 | SOC_SINGLE("TX2 HPF Switch", LPASS_CDC_TX2_MUX_CTL, 3, 1, 0), | |
335 | SOC_ENUM("RX1 DCB Cutoff", rx1_dcb_cutoff_enum), | |
336 | SOC_ENUM("RX2 DCB Cutoff", rx2_dcb_cutoff_enum), | |
337 | SOC_ENUM("RX3 DCB Cutoff", rx3_dcb_cutoff_enum), | |
338 | SOC_SINGLE("RX1 DCB Switch", LPASS_CDC_RX1_B5_CTL, 2, 1, 0), | |
339 | SOC_SINGLE("RX2 DCB Switch", LPASS_CDC_RX2_B5_CTL, 2, 1, 0), | |
340 | SOC_SINGLE("RX3 DCB Switch", LPASS_CDC_RX3_B5_CTL, 2, 1, 0), | |
341 | SOC_SINGLE("RX1 Mute Switch", LPASS_CDC_RX1_B6_CTL, 0, 1, 0), | |
342 | SOC_SINGLE("RX2 Mute Switch", LPASS_CDC_RX2_B6_CTL, 0, 1, 0), | |
343 | SOC_SINGLE("RX3 Mute Switch", LPASS_CDC_RX3_B6_CTL, 0, 1, 0), | |
344 | }; | |
345 | ||
346 | static int msm8916_wcd_digital_enable_interpolator( | |
347 | struct snd_soc_dapm_widget *w, | |
348 | struct snd_kcontrol *kcontrol, | |
349 | int event) | |
350 | { | |
351 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | |
352 | ||
353 | switch (event) { | |
354 | case SND_SOC_DAPM_POST_PMU: | |
355 | /* apply the digital gain after the interpolator is enabled */ | |
356 | usleep_range(10000, 10100); | |
357 | snd_soc_write(codec, rx_gain_reg[w->shift], | |
358 | snd_soc_read(codec, rx_gain_reg[w->shift])); | |
359 | break; | |
360 | } | |
361 | return 0; | |
362 | } | |
363 | ||
364 | static int msm8916_wcd_digital_enable_dec(struct snd_soc_dapm_widget *w, | |
365 | struct snd_kcontrol *kcontrol, | |
366 | int event) | |
367 | { | |
368 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | |
369 | unsigned int decimator = w->shift + 1; | |
370 | u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg; | |
371 | u8 dec_hpf_cut_of_freq; | |
372 | ||
373 | dec_reset_reg = LPASS_CDC_CLK_TX_RESET_B1_CTL; | |
374 | tx_vol_ctl_reg = LPASS_CDC_TX1_VOL_CTL_CFG + 32 * (decimator - 1); | |
375 | tx_mux_ctl_reg = LPASS_CDC_TX1_MUX_CTL + 32 * (decimator - 1); | |
376 | ||
377 | switch (event) { | |
378 | case SND_SOC_DAPM_PRE_PMU: | |
379 | /* Enable TX digital mute */ | |
380 | snd_soc_update_bits(codec, tx_vol_ctl_reg, | |
381 | TX_VOL_CTL_CFG_MUTE_EN_MASK, | |
382 | TX_VOL_CTL_CFG_MUTE_EN_ENABLE); | |
383 | dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg) & | |
384 | TX_MUX_CTL_CUT_OFF_FREQ_MASK; | |
385 | dec_hpf_cut_of_freq >>= TX_MUX_CTL_CUT_OFF_FREQ_SHIFT; | |
386 | if (dec_hpf_cut_of_freq != TX_MUX_CTL_CF_NEG_3DB_150HZ) { | |
387 | /* set cut of freq to CF_MIN_3DB_150HZ (0x1) */ | |
388 | snd_soc_update_bits(codec, tx_mux_ctl_reg, | |
389 | TX_MUX_CTL_CUT_OFF_FREQ_MASK, | |
390 | TX_MUX_CTL_CF_NEG_3DB_150HZ); | |
391 | } | |
392 | break; | |
393 | case SND_SOC_DAPM_POST_PMU: | |
394 | /* enable HPF */ | |
395 | snd_soc_update_bits(codec, tx_mux_ctl_reg, | |
396 | TX_MUX_CTL_HPF_BP_SEL_MASK, | |
397 | TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS); | |
398 | /* apply the digital gain after the decimator is enabled */ | |
399 | snd_soc_write(codec, tx_gain_reg[w->shift], | |
400 | snd_soc_read(codec, tx_gain_reg[w->shift])); | |
401 | snd_soc_update_bits(codec, tx_vol_ctl_reg, | |
402 | TX_VOL_CTL_CFG_MUTE_EN_MASK, 0); | |
403 | break; | |
404 | case SND_SOC_DAPM_PRE_PMD: | |
405 | snd_soc_update_bits(codec, tx_vol_ctl_reg, | |
406 | TX_VOL_CTL_CFG_MUTE_EN_MASK, | |
407 | TX_VOL_CTL_CFG_MUTE_EN_ENABLE); | |
408 | snd_soc_update_bits(codec, tx_mux_ctl_reg, | |
409 | TX_MUX_CTL_HPF_BP_SEL_MASK, | |
410 | TX_MUX_CTL_HPF_BP_SEL_BYPASS); | |
411 | break; | |
412 | case SND_SOC_DAPM_POST_PMD: | |
413 | snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, | |
414 | 1 << w->shift); | |
415 | snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0); | |
416 | snd_soc_update_bits(codec, tx_mux_ctl_reg, | |
417 | TX_MUX_CTL_HPF_BP_SEL_MASK, | |
418 | TX_MUX_CTL_HPF_BP_SEL_BYPASS); | |
419 | snd_soc_update_bits(codec, tx_vol_ctl_reg, | |
420 | TX_VOL_CTL_CFG_MUTE_EN_MASK, 0); | |
421 | break; | |
422 | } | |
423 | ||
424 | return 0; | |
425 | } | |
426 | ||
427 | static int msm8916_wcd_digital_enable_dmic(struct snd_soc_dapm_widget *w, | |
428 | struct snd_kcontrol *kcontrol, | |
429 | int event) | |
430 | { | |
431 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | |
432 | unsigned int dmic; | |
433 | int ret; | |
434 | /* get dmic number out of widget name */ | |
435 | char *dmic_num = strpbrk(w->name, "12"); | |
436 | ||
437 | if (dmic_num == NULL) { | |
438 | dev_err(codec->dev, "Invalid DMIC\n"); | |
439 | return -EINVAL; | |
440 | } | |
441 | ret = kstrtouint(dmic_num, 10, &dmic); | |
442 | if (ret < 0 || dmic > 2) { | |
443 | dev_err(codec->dev, "Invalid DMIC line on the codec\n"); | |
444 | return -EINVAL; | |
445 | } | |
446 | ||
447 | switch (event) { | |
448 | case SND_SOC_DAPM_PRE_PMU: | |
449 | snd_soc_update_bits(codec, LPASS_CDC_CLK_DMIC_B1_CTL, | |
450 | DMIC_B1_CTL_DMIC0_CLK_SEL_MASK, | |
451 | DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3); | |
452 | switch (dmic) { | |
453 | case 1: | |
454 | snd_soc_update_bits(codec, LPASS_CDC_TX1_DMIC_CTL, | |
455 | TXN_DMIC_CTL_CLK_SEL_MASK, | |
456 | TXN_DMIC_CTL_CLK_SEL_DIV3); | |
457 | break; | |
458 | case 2: | |
459 | snd_soc_update_bits(codec, LPASS_CDC_TX2_DMIC_CTL, | |
460 | TXN_DMIC_CTL_CLK_SEL_MASK, | |
461 | TXN_DMIC_CTL_CLK_SEL_DIV3); | |
462 | break; | |
463 | } | |
464 | break; | |
465 | } | |
466 | ||
467 | return 0; | |
468 | } | |
469 | ||
470 | static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = { | |
471 | /*RX stuff */ | |
472 | SND_SOC_DAPM_AIF_IN("I2S RX1", NULL, 0, SND_SOC_NOPM, 0, 0), | |
473 | SND_SOC_DAPM_AIF_IN("I2S RX2", NULL, 0, SND_SOC_NOPM, 0, 0), | |
474 | SND_SOC_DAPM_AIF_IN("I2S RX3", NULL, 0, SND_SOC_NOPM, 0, 0), | |
475 | ||
476 | SND_SOC_DAPM_OUTPUT("PDM_RX1"), | |
477 | SND_SOC_DAPM_OUTPUT("PDM_RX2"), | |
478 | SND_SOC_DAPM_OUTPUT("PDM_RX3"), | |
479 | ||
480 | SND_SOC_DAPM_INPUT("LPASS_PDM_TX"), | |
481 | ||
482 | SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), | |
483 | SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), | |
484 | SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), | |
485 | ||
486 | /* Interpolator */ | |
487 | SND_SOC_DAPM_MIXER_E("RX1 INT", LPASS_CDC_CLK_RX_B1_CTL, 0, 0, NULL, | |
488 | 0, msm8916_wcd_digital_enable_interpolator, | |
489 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | |
490 | SND_SOC_DAPM_MIXER_E("RX2 INT", LPASS_CDC_CLK_RX_B1_CTL, 1, 0, NULL, | |
491 | 0, msm8916_wcd_digital_enable_interpolator, | |
492 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | |
493 | SND_SOC_DAPM_MIXER_E("RX3 INT", LPASS_CDC_CLK_RX_B1_CTL, 2, 0, NULL, | |
494 | 0, msm8916_wcd_digital_enable_interpolator, | |
495 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | |
496 | SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0, | |
497 | &rx_mix1_inp1_mux), | |
498 | SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0, | |
499 | &rx_mix1_inp2_mux), | |
500 | SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0, | |
501 | &rx_mix1_inp3_mux), | |
502 | SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0, | |
503 | &rx2_mix1_inp1_mux), | |
504 | SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0, | |
505 | &rx2_mix1_inp2_mux), | |
506 | SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0, | |
507 | &rx2_mix1_inp3_mux), | |
508 | SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0, | |
509 | &rx3_mix1_inp1_mux), | |
510 | SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0, | |
511 | &rx3_mix1_inp2_mux), | |
512 | SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0, | |
513 | &rx3_mix1_inp3_mux), | |
514 | ||
3a88a375 SK |
515 | SND_SOC_DAPM_MUX("CIC1 MUX", SND_SOC_NOPM, 0, 0, &cic1_mux), |
516 | SND_SOC_DAPM_MUX("CIC2 MUX", SND_SOC_NOPM, 0, 0, &cic2_mux), | |
150db8c5 SK |
517 | /* TX */ |
518 | SND_SOC_DAPM_MIXER("ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), | |
519 | SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), | |
520 | SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), | |
521 | ||
522 | SND_SOC_DAPM_MUX_E("DEC1 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0, | |
523 | &dec1_mux, msm8916_wcd_digital_enable_dec, | |
524 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | |
525 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), | |
526 | SND_SOC_DAPM_MUX_E("DEC2 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0, | |
527 | &dec2_mux, msm8916_wcd_digital_enable_dec, | |
528 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | |
529 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), | |
530 | SND_SOC_DAPM_AIF_OUT("I2S TX1", NULL, 0, SND_SOC_NOPM, 0, 0), | |
531 | SND_SOC_DAPM_AIF_OUT("I2S TX2", NULL, 0, SND_SOC_NOPM, 0, 0), | |
532 | SND_SOC_DAPM_AIF_OUT("I2S TX3", NULL, 0, SND_SOC_NOPM, 0, 0), | |
533 | ||
534 | /* Digital Mic Inputs */ | |
535 | SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, | |
536 | msm8916_wcd_digital_enable_dmic, | |
537 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | |
538 | SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0, | |
539 | msm8916_wcd_digital_enable_dmic, | |
540 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | |
541 | SND_SOC_DAPM_SUPPLY("DMIC_CLK", LPASS_CDC_CLK_DMIC_B1_CTL, 0, 0, | |
542 | NULL, 0), | |
543 | SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", LPASS_CDC_CLK_RX_I2S_CTL, | |
544 | 4, 0, NULL, 0), | |
545 | SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", LPASS_CDC_CLK_TX_I2S_CTL, 4, 0, | |
546 | NULL, 0), | |
547 | ||
548 | SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, NULL, 0), | |
549 | SND_SOC_DAPM_SUPPLY("PDM_CLK", LPASS_CDC_CLK_PDM_CTL, 0, 0, NULL, 0), | |
550 | /* Connectivity Clock */ | |
551 | SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, LPASS_CDC_CLK_OTHR_CTL, 2, 0, | |
552 | NULL, 0), | |
3a88a375 SK |
553 | SND_SOC_DAPM_MIC("Digital Mic1", NULL), |
554 | SND_SOC_DAPM_MIC("Digital Mic2", NULL), | |
150db8c5 SK |
555 | |
556 | }; | |
557 | ||
ba9b8c42 | 558 | static int msm8916_wcd_digital_get_clks(struct platform_device *pdev, |
150db8c5 SK |
559 | struct msm8916_wcd_digital_priv *priv) |
560 | { | |
561 | struct device *dev = &pdev->dev; | |
562 | ||
563 | priv->ahbclk = devm_clk_get(dev, "ahbix-clk"); | |
564 | if (IS_ERR(priv->ahbclk)) { | |
565 | dev_err(dev, "failed to get ahbix clk\n"); | |
566 | return PTR_ERR(priv->ahbclk); | |
567 | } | |
568 | ||
569 | priv->mclk = devm_clk_get(dev, "mclk"); | |
570 | if (IS_ERR(priv->mclk)) { | |
571 | dev_err(dev, "failed to get mclk\n"); | |
572 | return PTR_ERR(priv->mclk); | |
573 | } | |
574 | ||
575 | return 0; | |
576 | } | |
577 | ||
578 | static int msm8916_wcd_digital_codec_probe(struct snd_soc_codec *codec) | |
579 | { | |
580 | struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(codec->dev); | |
581 | ||
582 | snd_soc_codec_set_drvdata(codec, priv); | |
583 | ||
584 | return 0; | |
585 | } | |
586 | ||
2032ce4d SK |
587 | static int msm8916_wcd_digital_codec_set_sysclk(struct snd_soc_codec *codec, |
588 | int clk_id, int source, | |
589 | unsigned int freq, int dir) | |
590 | { | |
591 | struct msm8916_wcd_digital_priv *p = dev_get_drvdata(codec->dev); | |
592 | ||
593 | return clk_set_rate(p->mclk, freq); | |
594 | } | |
595 | ||
150db8c5 SK |
596 | static int msm8916_wcd_digital_hw_params(struct snd_pcm_substream *substream, |
597 | struct snd_pcm_hw_params *params, | |
598 | struct snd_soc_dai *dai) | |
599 | { | |
600 | u8 tx_fs_rate; | |
601 | u8 rx_fs_rate; | |
602 | ||
603 | switch (params_rate(params)) { | |
604 | case 8000: | |
605 | tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ; | |
606 | rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_8_KHZ; | |
607 | break; | |
608 | case 16000: | |
609 | tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ; | |
610 | rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_16_KHZ; | |
611 | break; | |
612 | case 32000: | |
613 | tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ; | |
614 | rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_32_KHZ; | |
615 | break; | |
616 | case 48000: | |
617 | tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ; | |
618 | rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ; | |
619 | break; | |
620 | default: | |
621 | dev_err(dai->codec->dev, "Invalid sampling rate %d\n", | |
622 | params_rate(params)); | |
623 | return -EINVAL; | |
624 | } | |
625 | ||
626 | switch (substream->stream) { | |
627 | case SNDRV_PCM_STREAM_CAPTURE: | |
628 | snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, | |
629 | TX_I2S_CTL_TX_I2S_FS_RATE_MASK, tx_fs_rate); | |
630 | break; | |
631 | case SNDRV_PCM_STREAM_PLAYBACK: | |
632 | snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL, | |
633 | RX_I2S_CTL_RX_I2S_FS_RATE_MASK, rx_fs_rate); | |
634 | break; | |
635 | default: | |
636 | return -EINVAL; | |
637 | } | |
638 | ||
639 | switch (params_format(params)) { | |
640 | case SNDRV_PCM_FORMAT_S16_LE: | |
641 | snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, | |
642 | TX_I2S_CTL_TX_I2S_MODE_MASK, | |
643 | TX_I2S_CTL_TX_I2S_MODE_16); | |
644 | snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL, | |
645 | RX_I2S_CTL_RX_I2S_MODE_MASK, | |
646 | RX_I2S_CTL_RX_I2S_MODE_16); | |
647 | break; | |
51f493ae | 648 | case SNDRV_PCM_FORMAT_S32_LE: |
150db8c5 SK |
649 | snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, |
650 | TX_I2S_CTL_TX_I2S_MODE_MASK, | |
651 | TX_I2S_CTL_TX_I2S_MODE_32); | |
652 | snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL, | |
653 | RX_I2S_CTL_RX_I2S_MODE_MASK, | |
654 | RX_I2S_CTL_RX_I2S_MODE_32); | |
655 | break; | |
656 | default: | |
657 | dev_err(dai->dev, "%s: wrong format selected\n", __func__); | |
658 | return -EINVAL; | |
659 | } | |
660 | ||
661 | return 0; | |
662 | } | |
663 | ||
664 | static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = { | |
665 | ||
666 | {"I2S RX1", NULL, "AIF1 Playback"}, | |
667 | {"I2S RX2", NULL, "AIF1 Playback"}, | |
668 | {"I2S RX3", NULL, "AIF1 Playback"}, | |
669 | ||
670 | {"AIF1 Capture", NULL, "I2S TX1"}, | |
671 | {"AIF1 Capture", NULL, "I2S TX2"}, | |
672 | {"AIF1 Capture", NULL, "I2S TX3"}, | |
673 | ||
3a88a375 SK |
674 | {"CIC1 MUX", "DMIC", "DEC1 MUX"}, |
675 | {"CIC1 MUX", "AMIC", "DEC1 MUX"}, | |
676 | {"CIC2 MUX", "DMIC", "DEC2 MUX"}, | |
677 | {"CIC2 MUX", "AMIC", "DEC2 MUX"}, | |
678 | ||
150db8c5 SK |
679 | /* Decimator Inputs */ |
680 | {"DEC1 MUX", "DMIC1", "DMIC1"}, | |
681 | {"DEC1 MUX", "DMIC2", "DMIC2"}, | |
682 | {"DEC1 MUX", "ADC1", "ADC1"}, | |
683 | {"DEC1 MUX", "ADC2", "ADC2"}, | |
684 | {"DEC1 MUX", "ADC3", "ADC3"}, | |
685 | {"DEC1 MUX", NULL, "CDC_CONN"}, | |
686 | ||
687 | {"DEC2 MUX", "DMIC1", "DMIC1"}, | |
688 | {"DEC2 MUX", "DMIC2", "DMIC2"}, | |
689 | {"DEC2 MUX", "ADC1", "ADC1"}, | |
690 | {"DEC2 MUX", "ADC2", "ADC2"}, | |
691 | {"DEC2 MUX", "ADC3", "ADC3"}, | |
692 | {"DEC2 MUX", NULL, "CDC_CONN"}, | |
693 | ||
694 | {"DMIC1", NULL, "DMIC_CLK"}, | |
695 | {"DMIC2", NULL, "DMIC_CLK"}, | |
696 | ||
3a88a375 SK |
697 | {"I2S TX1", NULL, "CIC1 MUX"}, |
698 | {"I2S TX2", NULL, "CIC2 MUX"}, | |
150db8c5 SK |
699 | |
700 | {"I2S TX1", NULL, "TX_I2S_CLK"}, | |
701 | {"I2S TX2", NULL, "TX_I2S_CLK"}, | |
702 | ||
703 | {"TX_I2S_CLK", NULL, "MCLK"}, | |
704 | {"TX_I2S_CLK", NULL, "PDM_CLK"}, | |
705 | ||
706 | {"ADC1", NULL, "LPASS_PDM_TX"}, | |
707 | {"ADC2", NULL, "LPASS_PDM_TX"}, | |
708 | {"ADC3", NULL, "LPASS_PDM_TX"}, | |
709 | ||
710 | {"I2S RX1", NULL, "RX_I2S_CLK"}, | |
711 | {"I2S RX2", NULL, "RX_I2S_CLK"}, | |
712 | {"I2S RX3", NULL, "RX_I2S_CLK"}, | |
713 | ||
714 | {"RX_I2S_CLK", NULL, "PDM_CLK"}, | |
715 | {"RX_I2S_CLK", NULL, "MCLK"}, | |
716 | {"RX_I2S_CLK", NULL, "CDC_CONN"}, | |
717 | ||
718 | /* RX1 PATH.. */ | |
719 | {"PDM_RX1", NULL, "RX1 INT"}, | |
720 | {"RX1 INT", NULL, "RX1 MIX1"}, | |
721 | ||
722 | {"RX1 MIX1", NULL, "RX1 MIX1 INP1"}, | |
723 | {"RX1 MIX1", NULL, "RX1 MIX1 INP2"}, | |
724 | {"RX1 MIX1", NULL, "RX1 MIX1 INP3"}, | |
725 | ||
726 | {"RX1 MIX1 INP1", "RX1", "I2S RX1"}, | |
727 | {"RX1 MIX1 INP1", "RX2", "I2S RX2"}, | |
728 | {"RX1 MIX1 INP1", "RX3", "I2S RX3"}, | |
729 | ||
730 | {"RX1 MIX1 INP2", "RX1", "I2S RX1"}, | |
731 | {"RX1 MIX1 INP2", "RX2", "I2S RX2"}, | |
732 | {"RX1 MIX1 INP2", "RX3", "I2S RX3"}, | |
733 | ||
734 | {"RX1 MIX1 INP3", "RX1", "I2S RX1"}, | |
735 | {"RX1 MIX1 INP3", "RX2", "I2S RX2"}, | |
736 | {"RX1 MIX1 INP3", "RX3", "I2S RX3"}, | |
737 | ||
738 | /* RX2 PATH */ | |
739 | {"PDM_RX2", NULL, "RX2 INT"}, | |
740 | {"RX2 INT", NULL, "RX2 MIX1"}, | |
741 | ||
742 | {"RX2 MIX1", NULL, "RX2 MIX1 INP1"}, | |
743 | {"RX2 MIX1", NULL, "RX2 MIX1 INP2"}, | |
744 | {"RX2 MIX1", NULL, "RX2 MIX1 INP3"}, | |
745 | ||
746 | {"RX2 MIX1 INP1", "RX1", "I2S RX1"}, | |
747 | {"RX2 MIX1 INP1", "RX2", "I2S RX2"}, | |
748 | {"RX2 MIX1 INP1", "RX3", "I2S RX3"}, | |
749 | ||
750 | {"RX2 MIX1 INP2", "RX1", "I2S RX1"}, | |
751 | {"RX2 MIX1 INP2", "RX2", "I2S RX2"}, | |
752 | {"RX2 MIX1 INP2", "RX3", "I2S RX3"}, | |
753 | ||
754 | {"RX2 MIX1 INP3", "RX1", "I2S RX1"}, | |
755 | {"RX2 MIX1 INP3", "RX2", "I2S RX2"}, | |
756 | {"RX2 MIX1 INP3", "RX3", "I2S RX3"}, | |
757 | ||
758 | /* RX3 PATH */ | |
759 | {"PDM_RX3", NULL, "RX3 INT"}, | |
760 | {"RX3 INT", NULL, "RX3 MIX1"}, | |
761 | ||
762 | {"RX3 MIX1", NULL, "RX3 MIX1 INP1"}, | |
763 | {"RX3 MIX1", NULL, "RX3 MIX1 INP2"}, | |
764 | {"RX3 MIX1", NULL, "RX3 MIX1 INP3"}, | |
765 | ||
766 | {"RX3 MIX1 INP1", "RX1", "I2S RX1"}, | |
767 | {"RX3 MIX1 INP1", "RX2", "I2S RX2"}, | |
768 | {"RX3 MIX1 INP1", "RX3", "I2S RX3"}, | |
769 | ||
770 | {"RX3 MIX1 INP2", "RX1", "I2S RX1"}, | |
771 | {"RX3 MIX1 INP2", "RX2", "I2S RX2"}, | |
772 | {"RX3 MIX1 INP2", "RX3", "I2S RX3"}, | |
773 | ||
774 | {"RX3 MIX1 INP3", "RX1", "I2S RX1"}, | |
775 | {"RX3 MIX1 INP3", "RX2", "I2S RX2"}, | |
776 | {"RX3 MIX1 INP3", "RX3", "I2S RX3"}, | |
777 | ||
778 | }; | |
779 | ||
780 | static int msm8916_wcd_digital_startup(struct snd_pcm_substream *substream, | |
781 | struct snd_soc_dai *dai) | |
782 | { | |
783 | struct snd_soc_codec *codec = dai->codec; | |
784 | struct msm8916_wcd_digital_priv *msm8916_wcd; | |
785 | unsigned long mclk_rate; | |
786 | ||
787 | msm8916_wcd = snd_soc_codec_get_drvdata(codec); | |
788 | snd_soc_update_bits(codec, LPASS_CDC_CLK_MCLK_CTL, | |
789 | MCLK_CTL_MCLK_EN_MASK, | |
790 | MCLK_CTL_MCLK_EN_ENABLE); | |
791 | snd_soc_update_bits(codec, LPASS_CDC_CLK_PDM_CTL, | |
792 | LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, | |
793 | LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB); | |
794 | ||
795 | mclk_rate = clk_get_rate(msm8916_wcd->mclk); | |
796 | switch (mclk_rate) { | |
797 | case 12288000: | |
798 | snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL, | |
799 | TOP_CTL_DIG_MCLK_FREQ_MASK, | |
800 | TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ); | |
801 | break; | |
802 | case 9600000: | |
803 | snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL, | |
804 | TOP_CTL_DIG_MCLK_FREQ_MASK, | |
805 | TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ); | |
806 | break; | |
807 | default: | |
808 | dev_err(codec->dev, "Invalid mclk rate %ld\n", mclk_rate); | |
809 | break; | |
810 | } | |
811 | return 0; | |
812 | } | |
813 | ||
814 | static void msm8916_wcd_digital_shutdown(struct snd_pcm_substream *substream, | |
815 | struct snd_soc_dai *dai) | |
816 | { | |
817 | snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_PDM_CTL, | |
818 | LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, 0); | |
819 | } | |
820 | ||
a9689bb8 | 821 | static const struct snd_soc_dai_ops msm8916_wcd_digital_dai_ops = { |
150db8c5 SK |
822 | .startup = msm8916_wcd_digital_startup, |
823 | .shutdown = msm8916_wcd_digital_shutdown, | |
824 | .hw_params = msm8916_wcd_digital_hw_params, | |
825 | }; | |
826 | ||
827 | static struct snd_soc_dai_driver msm8916_wcd_digital_dai[] = { | |
828 | [0] = { | |
829 | .name = "msm8916_wcd_digital_i2s_rx1", | |
830 | .id = 0, | |
831 | .playback = { | |
832 | .stream_name = "AIF1 Playback", | |
833 | .rates = MSM8916_WCD_DIGITAL_RATES, | |
834 | .formats = MSM8916_WCD_DIGITAL_FORMATS, | |
835 | .channels_min = 1, | |
836 | .channels_max = 3, | |
837 | }, | |
838 | .ops = &msm8916_wcd_digital_dai_ops, | |
839 | }, | |
840 | [1] = { | |
841 | .name = "msm8916_wcd_digital_i2s_tx1", | |
842 | .id = 1, | |
843 | .capture = { | |
844 | .stream_name = "AIF1 Capture", | |
845 | .rates = MSM8916_WCD_DIGITAL_RATES, | |
846 | .formats = MSM8916_WCD_DIGITAL_FORMATS, | |
847 | .channels_min = 1, | |
848 | .channels_max = 4, | |
849 | }, | |
850 | .ops = &msm8916_wcd_digital_dai_ops, | |
851 | }, | |
852 | }; | |
853 | ||
a180ba45 | 854 | static const struct snd_soc_codec_driver msm8916_wcd_digital = { |
150db8c5 | 855 | .probe = msm8916_wcd_digital_codec_probe, |
2032ce4d | 856 | .set_sysclk = msm8916_wcd_digital_codec_set_sysclk, |
150db8c5 SK |
857 | .component_driver = { |
858 | .controls = msm8916_wcd_digital_snd_controls, | |
859 | .num_controls = ARRAY_SIZE(msm8916_wcd_digital_snd_controls), | |
860 | .dapm_widgets = msm8916_wcd_digital_dapm_widgets, | |
861 | .num_dapm_widgets = | |
862 | ARRAY_SIZE(msm8916_wcd_digital_dapm_widgets), | |
863 | .dapm_routes = msm8916_wcd_digital_audio_map, | |
864 | .num_dapm_routes = ARRAY_SIZE(msm8916_wcd_digital_audio_map), | |
865 | }, | |
866 | }; | |
867 | ||
868 | static const struct regmap_config msm8916_codec_regmap_config = { | |
869 | .reg_bits = 32, | |
870 | .reg_stride = 4, | |
871 | .val_bits = 32, | |
872 | .max_register = LPASS_CDC_TX2_DMIC_CTL, | |
873 | .cache_type = REGCACHE_FLAT, | |
874 | }; | |
875 | ||
876 | static int msm8916_wcd_digital_probe(struct platform_device *pdev) | |
877 | { | |
878 | struct msm8916_wcd_digital_priv *priv; | |
879 | struct device *dev = &pdev->dev; | |
880 | void __iomem *base; | |
881 | struct resource *mem_res; | |
882 | struct regmap *digital_map; | |
883 | int ret; | |
884 | ||
885 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
886 | if (!priv) | |
887 | return -ENOMEM; | |
888 | ||
889 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
890 | base = devm_ioremap_resource(&pdev->dev, mem_res); | |
891 | if (IS_ERR(base)) | |
892 | return PTR_ERR(base); | |
893 | ||
894 | digital_map = | |
895 | devm_regmap_init_mmio(&pdev->dev, base, | |
896 | &msm8916_codec_regmap_config); | |
897 | if (IS_ERR(digital_map)) | |
898 | return PTR_ERR(digital_map); | |
899 | ||
ba9b8c42 | 900 | ret = msm8916_wcd_digital_get_clks(pdev, priv); |
150db8c5 SK |
901 | if (ret < 0) |
902 | return ret; | |
903 | ||
904 | ret = clk_prepare_enable(priv->ahbclk); | |
905 | if (ret < 0) { | |
906 | dev_err(dev, "failed to enable ahbclk %d\n", ret); | |
907 | return ret; | |
908 | } | |
909 | ||
910 | ret = clk_prepare_enable(priv->mclk); | |
911 | if (ret < 0) { | |
912 | dev_err(dev, "failed to enable mclk %d\n", ret); | |
913 | return ret; | |
914 | } | |
915 | ||
916 | dev_set_drvdata(dev, priv); | |
917 | ||
918 | return snd_soc_register_codec(dev, &msm8916_wcd_digital, | |
919 | msm8916_wcd_digital_dai, | |
920 | ARRAY_SIZE(msm8916_wcd_digital_dai)); | |
921 | } | |
922 | ||
923 | static int msm8916_wcd_digital_remove(struct platform_device *pdev) | |
924 | { | |
925 | struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(&pdev->dev); | |
926 | ||
927 | snd_soc_unregister_codec(&pdev->dev); | |
928 | clk_disable_unprepare(priv->mclk); | |
929 | clk_disable_unprepare(priv->ahbclk); | |
930 | ||
931 | return 0; | |
932 | } | |
933 | ||
934 | static const struct of_device_id msm8916_wcd_digital_match_table[] = { | |
935 | { .compatible = "qcom,msm8916-wcd-digital-codec" }, | |
936 | { } | |
937 | }; | |
938 | ||
939 | MODULE_DEVICE_TABLE(of, msm8916_wcd_digital_match_table); | |
940 | ||
941 | static struct platform_driver msm8916_wcd_digital_driver = { | |
942 | .driver = { | |
943 | .name = "msm8916-wcd-digital-codec", | |
944 | .of_match_table = msm8916_wcd_digital_match_table, | |
945 | }, | |
946 | .probe = msm8916_wcd_digital_probe, | |
947 | .remove = msm8916_wcd_digital_remove, | |
948 | }; | |
949 | ||
950 | module_platform_driver(msm8916_wcd_digital_driver); | |
951 | ||
952 | MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>"); | |
953 | MODULE_DESCRIPTION("MSM8916 WCD Digital Codec driver"); | |
954 | MODULE_LICENSE("GPL v2"); |