1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * cs53l30.c -- CS53l30 ALSA Soc Audio driver |
4 | * |
5 | * Copyright 2015 Cirrus Logic, Inc. |
6 | * |
7 | * Authors: Paul Handrigan <Paul.Handrigan@cirrus.com>, |
8 | * Tim Howe <Tim.Howe@cirrus.com> |
9 | */ |
10 | |
11 | #include <linux/clk.h> |
12 | #include <linux/delay.h> |
13 | #include <linux/i2c.h> |
14 | #include <linux/module.h> |
15 | #include <linux/of_gpio.h> |
16 | #include <linux/gpio/consumer.h> |
17 | #include <linux/regulator/consumer.h> |
18 | #include <sound/pcm_params.h> |
19 | #include <sound/soc.h> |
20 | #include <sound/tlv.h> |
21 | |
22 | #include "cs53l30.h" |
23 | #include "cirrus_legacy.h" |
24 | |
25 | #define CS53L30_NUM_SUPPLIES 2 |
26 | static const char *const cs53l30_supply_names[CS53L30_NUM_SUPPLIES] = { |
27 | "VA" , |
28 | "VP" , |
29 | }; |
30 | |
31 | struct cs53l30_private { |
32 | struct regulator_bulk_data supplies[CS53L30_NUM_SUPPLIES]; |
33 | struct regmap *regmap; |
34 | struct gpio_desc *reset_gpio; |
35 | struct gpio_desc *mute_gpio; |
36 | struct clk *mclk; |
37 | bool use_sdout2; |
38 | u32 mclk_rate; |
39 | }; |
40 | |
41 | static const struct reg_default cs53l30_reg_defaults[] = { |
42 | { CS53L30_PWRCTL, CS53L30_PWRCTL_DEFAULT }, |
43 | { CS53L30_MCLKCTL, CS53L30_MCLKCTL_DEFAULT }, |
44 | { CS53L30_INT_SR_CTL, CS53L30_INT_SR_CTL_DEFAULT }, |
45 | { CS53L30_MICBIAS_CTL, CS53L30_MICBIAS_CTL_DEFAULT }, |
46 | { CS53L30_ASPCFG_CTL, CS53L30_ASPCFG_CTL_DEFAULT }, |
47 | { CS53L30_ASP_CTL1, CS53L30_ASP_CTL1_DEFAULT }, |
48 | { CS53L30_ASP_TDMTX_CTL1, CS53L30_ASP_TDMTX_CTLx_DEFAULT }, |
49 | { CS53L30_ASP_TDMTX_CTL2, CS53L30_ASP_TDMTX_CTLx_DEFAULT }, |
50 | { CS53L30_ASP_TDMTX_CTL3, CS53L30_ASP_TDMTX_CTLx_DEFAULT }, |
51 | { CS53L30_ASP_TDMTX_CTL4, CS53L30_ASP_TDMTX_CTLx_DEFAULT }, |
52 | { CS53L30_ASP_TDMTX_EN1, CS53L30_ASP_TDMTX_ENx_DEFAULT }, |
53 | { CS53L30_ASP_TDMTX_EN2, CS53L30_ASP_TDMTX_ENx_DEFAULT }, |
54 | { CS53L30_ASP_TDMTX_EN3, CS53L30_ASP_TDMTX_ENx_DEFAULT }, |
55 | { CS53L30_ASP_TDMTX_EN4, CS53L30_ASP_TDMTX_ENx_DEFAULT }, |
56 | { CS53L30_ASP_TDMTX_EN5, CS53L30_ASP_TDMTX_ENx_DEFAULT }, |
57 | { CS53L30_ASP_TDMTX_EN6, CS53L30_ASP_TDMTX_ENx_DEFAULT }, |
58 | { CS53L30_ASP_CTL2, CS53L30_ASP_CTL2_DEFAULT }, |
59 | { CS53L30_SFT_RAMP, CS53L30_SFT_RMP_DEFAULT }, |
60 | { CS53L30_LRCK_CTL1, CS53L30_LRCK_CTLx_DEFAULT }, |
61 | { CS53L30_LRCK_CTL2, CS53L30_LRCK_CTLx_DEFAULT }, |
62 | { CS53L30_MUTEP_CTL1, CS53L30_MUTEP_CTL1_DEFAULT }, |
63 | { CS53L30_MUTEP_CTL2, CS53L30_MUTEP_CTL2_DEFAULT }, |
64 | { CS53L30_INBIAS_CTL1, CS53L30_INBIAS_CTL1_DEFAULT }, |
65 | { CS53L30_INBIAS_CTL2, CS53L30_INBIAS_CTL2_DEFAULT }, |
66 | { CS53L30_DMIC1_STR_CTL, CS53L30_DMIC1_STR_CTL_DEFAULT }, |
67 | { CS53L30_DMIC2_STR_CTL, CS53L30_DMIC2_STR_CTL_DEFAULT }, |
68 | { CS53L30_ADCDMIC1_CTL1, CS53L30_ADCDMICx_CTL1_DEFAULT }, |
69 | { CS53L30_ADCDMIC1_CTL2, CS53L30_ADCDMIC1_CTL2_DEFAULT }, |
70 | { CS53L30_ADC1_CTL3, CS53L30_ADCx_CTL3_DEFAULT }, |
71 | { CS53L30_ADC1_NG_CTL, CS53L30_ADCx_NG_CTL_DEFAULT }, |
72 | { CS53L30_ADC1A_AFE_CTL, CS53L30_ADCxy_AFE_CTL_DEFAULT }, |
73 | { CS53L30_ADC1B_AFE_CTL, CS53L30_ADCxy_AFE_CTL_DEFAULT }, |
74 | { CS53L30_ADC1A_DIG_VOL, CS53L30_ADCxy_DIG_VOL_DEFAULT }, |
75 | { CS53L30_ADC1B_DIG_VOL, CS53L30_ADCxy_DIG_VOL_DEFAULT }, |
76 | { CS53L30_ADCDMIC2_CTL1, CS53L30_ADCDMICx_CTL1_DEFAULT }, |
77 | { CS53L30_ADCDMIC2_CTL2, CS53L30_ADCDMIC1_CTL2_DEFAULT }, |
78 | { CS53L30_ADC2_CTL3, CS53L30_ADCx_CTL3_DEFAULT }, |
79 | { CS53L30_ADC2_NG_CTL, CS53L30_ADCx_NG_CTL_DEFAULT }, |
80 | { CS53L30_ADC2A_AFE_CTL, CS53L30_ADCxy_AFE_CTL_DEFAULT }, |
81 | { CS53L30_ADC2B_AFE_CTL, CS53L30_ADCxy_AFE_CTL_DEFAULT }, |
82 | { CS53L30_ADC2A_DIG_VOL, CS53L30_ADCxy_DIG_VOL_DEFAULT }, |
83 | { CS53L30_ADC2B_DIG_VOL, CS53L30_ADCxy_DIG_VOL_DEFAULT }, |
84 | { CS53L30_INT_MASK, CS53L30_DEVICE_INT_MASK }, |
85 | }; |
86 | |
87 | static bool cs53l30_volatile_register(struct device *dev, unsigned int reg) |
88 | { |
89 | if (reg == CS53L30_IS) |
90 | return true; |
91 | else |
92 | return false; |
93 | } |
94 | |
95 | static bool cs53l30_writeable_register(struct device *dev, unsigned int reg) |
96 | { |
97 | switch (reg) { |
98 | case CS53L30_DEVID_AB: |
99 | case CS53L30_DEVID_CD: |
100 | case CS53L30_DEVID_E: |
101 | case CS53L30_REVID: |
102 | case CS53L30_IS: |
103 | return false; |
104 | default: |
105 | return true; |
106 | } |
107 | } |
108 | |
109 | static bool cs53l30_readable_register(struct device *dev, unsigned int reg) |
110 | { |
111 | switch (reg) { |
112 | case CS53L30_DEVID_AB: |
113 | case CS53L30_DEVID_CD: |
114 | case CS53L30_DEVID_E: |
115 | case CS53L30_REVID: |
116 | case CS53L30_PWRCTL: |
117 | case CS53L30_MCLKCTL: |
118 | case CS53L30_INT_SR_CTL: |
119 | case CS53L30_MICBIAS_CTL: |
120 | case CS53L30_ASPCFG_CTL: |
121 | case CS53L30_ASP_CTL1: |
122 | case CS53L30_ASP_TDMTX_CTL1: |
123 | case CS53L30_ASP_TDMTX_CTL2: |
124 | case CS53L30_ASP_TDMTX_CTL3: |
125 | case CS53L30_ASP_TDMTX_CTL4: |
126 | case CS53L30_ASP_TDMTX_EN1: |
127 | case CS53L30_ASP_TDMTX_EN2: |
128 | case CS53L30_ASP_TDMTX_EN3: |
129 | case CS53L30_ASP_TDMTX_EN4: |
130 | case CS53L30_ASP_TDMTX_EN5: |
131 | case CS53L30_ASP_TDMTX_EN6: |
132 | case CS53L30_ASP_CTL2: |
133 | case CS53L30_SFT_RAMP: |
134 | case CS53L30_LRCK_CTL1: |
135 | case CS53L30_LRCK_CTL2: |
136 | case CS53L30_MUTEP_CTL1: |
137 | case CS53L30_MUTEP_CTL2: |
138 | case CS53L30_INBIAS_CTL1: |
139 | case CS53L30_INBIAS_CTL2: |
140 | case CS53L30_DMIC1_STR_CTL: |
141 | case CS53L30_DMIC2_STR_CTL: |
142 | case CS53L30_ADCDMIC1_CTL1: |
143 | case CS53L30_ADCDMIC1_CTL2: |
144 | case CS53L30_ADC1_CTL3: |
145 | case CS53L30_ADC1_NG_CTL: |
146 | case CS53L30_ADC1A_AFE_CTL: |
147 | case CS53L30_ADC1B_AFE_CTL: |
148 | case CS53L30_ADC1A_DIG_VOL: |
149 | case CS53L30_ADC1B_DIG_VOL: |
150 | case CS53L30_ADCDMIC2_CTL1: |
151 | case CS53L30_ADCDMIC2_CTL2: |
152 | case CS53L30_ADC2_CTL3: |
153 | case CS53L30_ADC2_NG_CTL: |
154 | case CS53L30_ADC2A_AFE_CTL: |
155 | case CS53L30_ADC2B_AFE_CTL: |
156 | case CS53L30_ADC2A_DIG_VOL: |
157 | case CS53L30_ADC2B_DIG_VOL: |
158 | case CS53L30_INT_MASK: |
159 | return true; |
160 | default: |
161 | return false; |
162 | } |
163 | } |
164 | |
165 | static DECLARE_TLV_DB_SCALE(adc_boost_tlv, 0, 2000, 0); |
166 | static DECLARE_TLV_DB_SCALE(adc_ng_boost_tlv, 0, 3000, 0); |
167 | static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0); |
168 | static DECLARE_TLV_DB_SCALE(dig_tlv, -9600, 100, 1); |
169 | static DECLARE_TLV_DB_SCALE(pga_preamp_tlv, 0, 10000, 0); |
170 | |
171 | static const char * const input1_sel_text[] = { |
172 | "DMIC1 On AB In" , |
173 | "DMIC1 On A In" , |
174 | "DMIC1 On B In" , |
175 | "ADC1 On AB In" , |
176 | "ADC1 On A In" , |
177 | "ADC1 On B In" , |
178 | "DMIC1 Off ADC1 Off" , |
179 | }; |
180 | |
181 | static unsigned int const input1_sel_values[] = { |
182 | CS53L30_CH_TYPE, |
183 | CS53L30_ADCxB_PDN | CS53L30_CH_TYPE, |
184 | CS53L30_ADCxA_PDN | CS53L30_CH_TYPE, |
185 | CS53L30_DMICx_PDN, |
186 | CS53L30_ADCxB_PDN | CS53L30_DMICx_PDN, |
187 | CS53L30_ADCxA_PDN | CS53L30_DMICx_PDN, |
188 | CS53L30_ADCxA_PDN | CS53L30_ADCxB_PDN | CS53L30_DMICx_PDN, |
189 | }; |
190 | |
191 | static const char * const input2_sel_text[] = { |
192 | "DMIC2 On AB In" , |
193 | "DMIC2 On A In" , |
194 | "DMIC2 On B In" , |
195 | "ADC2 On AB In" , |
196 | "ADC2 On A In" , |
197 | "ADC2 On B In" , |
198 | "DMIC2 Off ADC2 Off" , |
199 | }; |
200 | |
201 | static unsigned int const input2_sel_values[] = { |
202 | 0x0, |
203 | CS53L30_ADCxB_PDN, |
204 | CS53L30_ADCxA_PDN, |
205 | CS53L30_DMICx_PDN, |
206 | CS53L30_ADCxB_PDN | CS53L30_DMICx_PDN, |
207 | CS53L30_ADCxA_PDN | CS53L30_DMICx_PDN, |
208 | CS53L30_ADCxA_PDN | CS53L30_ADCxB_PDN | CS53L30_DMICx_PDN, |
209 | }; |
210 | |
211 | static const char * const input1_route_sel_text[] = { |
212 | "ADC1_SEL" , "DMIC1_SEL" , |
213 | }; |
214 | |
215 | static const struct soc_enum input1_route_sel_enum = |
216 | SOC_ENUM_SINGLE(CS53L30_ADCDMIC1_CTL1, CS53L30_CH_TYPE_SHIFT, |
217 | ARRAY_SIZE(input1_route_sel_text), |
218 | input1_route_sel_text); |
219 | |
220 | static SOC_VALUE_ENUM_SINGLE_DECL(input1_sel_enum, CS53L30_ADCDMIC1_CTL1, 0, |
221 | CS53L30_ADCDMICx_PDN_MASK, input1_sel_text, |
222 | input1_sel_values); |
223 | |
224 | static const struct snd_kcontrol_new input1_route_sel_mux = |
225 | SOC_DAPM_ENUM("Input 1 Route" , input1_route_sel_enum); |
226 | |
227 | static const char * const input2_route_sel_text[] = { |
228 | "ADC2_SEL" , "DMIC2_SEL" , |
229 | }; |
230 | |
231 | /* Note: CS53L30_ADCDMIC1_CTL1 CH_TYPE controls inputs 1 and 2 */ |
232 | static const struct soc_enum input2_route_sel_enum = |
233 | SOC_ENUM_SINGLE(CS53L30_ADCDMIC1_CTL1, 0, |
234 | ARRAY_SIZE(input2_route_sel_text), |
235 | input2_route_sel_text); |
236 | |
237 | static SOC_VALUE_ENUM_SINGLE_DECL(input2_sel_enum, CS53L30_ADCDMIC2_CTL1, 0, |
238 | CS53L30_ADCDMICx_PDN_MASK, input2_sel_text, |
239 | input2_sel_values); |
240 | |
241 | static const struct snd_kcontrol_new input2_route_sel_mux = |
242 | SOC_DAPM_ENUM("Input 2 Route" , input2_route_sel_enum); |
243 | |
244 | /* |
245 | * TB = 6144*(MCLK(int) scaling factor)/MCLK(internal) |
246 | * TB - Time base |
247 | * NOTE: If MCLK_INT_SCALE = 0, then TB=1 |
248 | */ |
249 | static const char * const cs53l30_ng_delay_text[] = { |
250 | "TB*50ms" , "TB*100ms" , "TB*150ms" , "TB*200ms" , |
251 | }; |
252 | |
253 | static const struct soc_enum adc1_ng_delay_enum = |
254 | SOC_ENUM_SINGLE(CS53L30_ADC1_NG_CTL, CS53L30_ADCx_NG_DELAY_SHIFT, |
255 | ARRAY_SIZE(cs53l30_ng_delay_text), |
256 | cs53l30_ng_delay_text); |
257 | |
258 | static const struct soc_enum adc2_ng_delay_enum = |
259 | SOC_ENUM_SINGLE(CS53L30_ADC2_NG_CTL, CS53L30_ADCx_NG_DELAY_SHIFT, |
260 | ARRAY_SIZE(cs53l30_ng_delay_text), |
261 | cs53l30_ng_delay_text); |
262 | |
263 | /* The noise gate threshold selected will depend on NG Boost */ |
264 | static const char * const cs53l30_ng_thres_text[] = { |
265 | "-64dB/-34dB" , "-66dB/-36dB" , "-70dB/-40dB" , "-73dB/-43dB" , |
266 | "-76dB/-46dB" , "-82dB/-52dB" , "-58dB" , "-64dB" , |
267 | }; |
268 | |
269 | static const struct soc_enum adc1_ng_thres_enum = |
270 | SOC_ENUM_SINGLE(CS53L30_ADC1_NG_CTL, CS53L30_ADCx_NG_THRESH_SHIFT, |
271 | ARRAY_SIZE(cs53l30_ng_thres_text), |
272 | cs53l30_ng_thres_text); |
273 | |
274 | static const struct soc_enum adc2_ng_thres_enum = |
275 | SOC_ENUM_SINGLE(CS53L30_ADC2_NG_CTL, CS53L30_ADCx_NG_THRESH_SHIFT, |
276 | ARRAY_SIZE(cs53l30_ng_thres_text), |
277 | cs53l30_ng_thres_text); |
278 | |
279 | /* Corner frequencies are with an Fs of 48kHz. */ |
280 | static const char * const hpf_corner_freq_text[] = { |
281 | "1.86Hz" , "120Hz" , "235Hz" , "466Hz" , |
282 | }; |
283 | |
284 | static const struct soc_enum adc1_hpf_enum = |
285 | SOC_ENUM_SINGLE(CS53L30_ADC1_CTL3, CS53L30_ADCx_HPF_CF_SHIFT, |
286 | ARRAY_SIZE(hpf_corner_freq_text), hpf_corner_freq_text); |
287 | |
288 | static const struct soc_enum adc2_hpf_enum = |
289 | SOC_ENUM_SINGLE(CS53L30_ADC2_CTL3, CS53L30_ADCx_HPF_CF_SHIFT, |
290 | ARRAY_SIZE(hpf_corner_freq_text), hpf_corner_freq_text); |
291 | |
292 | static const struct snd_kcontrol_new cs53l30_snd_controls[] = { |
293 | SOC_SINGLE("Digital Soft-Ramp Switch" , CS53L30_SFT_RAMP, |
294 | CS53L30_DIGSFT_SHIFT, 1, 0), |
295 | SOC_SINGLE("ADC1 Noise Gate Ganging Switch" , CS53L30_ADC1_CTL3, |
296 | CS53L30_ADCx_NG_ALL_SHIFT, 1, 0), |
297 | SOC_SINGLE("ADC2 Noise Gate Ganging Switch" , CS53L30_ADC2_CTL3, |
298 | CS53L30_ADCx_NG_ALL_SHIFT, 1, 0), |
299 | SOC_SINGLE("ADC1A Noise Gate Enable Switch" , CS53L30_ADC1_NG_CTL, |
300 | CS53L30_ADCxA_NG_SHIFT, 1, 0), |
301 | SOC_SINGLE("ADC1B Noise Gate Enable Switch" , CS53L30_ADC1_NG_CTL, |
302 | CS53L30_ADCxB_NG_SHIFT, 1, 0), |
303 | SOC_SINGLE("ADC2A Noise Gate Enable Switch" , CS53L30_ADC2_NG_CTL, |
304 | CS53L30_ADCxA_NG_SHIFT, 1, 0), |
305 | SOC_SINGLE("ADC2B Noise Gate Enable Switch" , CS53L30_ADC2_NG_CTL, |
306 | CS53L30_ADCxB_NG_SHIFT, 1, 0), |
307 | SOC_SINGLE("ADC1 Notch Filter Switch" , CS53L30_ADCDMIC1_CTL2, |
308 | CS53L30_ADCx_NOTCH_DIS_SHIFT, 1, 1), |
309 | SOC_SINGLE("ADC2 Notch Filter Switch" , CS53L30_ADCDMIC2_CTL2, |
310 | CS53L30_ADCx_NOTCH_DIS_SHIFT, 1, 1), |
311 | SOC_SINGLE("ADC1A Invert Switch" , CS53L30_ADCDMIC1_CTL2, |
312 | CS53L30_ADCxA_INV_SHIFT, 1, 0), |
313 | SOC_SINGLE("ADC1B Invert Switch" , CS53L30_ADCDMIC1_CTL2, |
314 | CS53L30_ADCxB_INV_SHIFT, 1, 0), |
315 | SOC_SINGLE("ADC2A Invert Switch" , CS53L30_ADCDMIC2_CTL2, |
316 | CS53L30_ADCxA_INV_SHIFT, 1, 0), |
317 | SOC_SINGLE("ADC2B Invert Switch" , CS53L30_ADCDMIC2_CTL2, |
318 | CS53L30_ADCxB_INV_SHIFT, 1, 0), |
319 | |
320 | SOC_SINGLE_TLV("ADC1A Digital Boost Volume" , CS53L30_ADCDMIC1_CTL2, |
321 | CS53L30_ADCxA_DIG_BOOST_SHIFT, 1, 0, adc_boost_tlv), |
322 | SOC_SINGLE_TLV("ADC1B Digital Boost Volume" , CS53L30_ADCDMIC1_CTL2, |
323 | CS53L30_ADCxB_DIG_BOOST_SHIFT, 1, 0, adc_boost_tlv), |
324 | SOC_SINGLE_TLV("ADC2A Digital Boost Volume" , CS53L30_ADCDMIC2_CTL2, |
325 | CS53L30_ADCxA_DIG_BOOST_SHIFT, 1, 0, adc_boost_tlv), |
326 | SOC_SINGLE_TLV("ADC2B Digital Boost Volume" , CS53L30_ADCDMIC2_CTL2, |
327 | CS53L30_ADCxB_DIG_BOOST_SHIFT, 1, 0, adc_boost_tlv), |
328 | SOC_SINGLE_TLV("ADC1 NG Boost Volume" , CS53L30_ADC1_NG_CTL, |
329 | CS53L30_ADCx_NG_BOOST_SHIFT, 1, 0, adc_ng_boost_tlv), |
330 | SOC_SINGLE_TLV("ADC2 NG Boost Volume" , CS53L30_ADC2_NG_CTL, |
331 | CS53L30_ADCx_NG_BOOST_SHIFT, 1, 0, adc_ng_boost_tlv), |
332 | |
333 | SOC_DOUBLE_R_TLV("ADC1 Preamplifier Volume" , CS53L30_ADC1A_AFE_CTL, |
334 | CS53L30_ADC1B_AFE_CTL, CS53L30_ADCxy_PREAMP_SHIFT, |
335 | 2, 0, pga_preamp_tlv), |
336 | SOC_DOUBLE_R_TLV("ADC2 Preamplifier Volume" , CS53L30_ADC2A_AFE_CTL, |
337 | CS53L30_ADC2B_AFE_CTL, CS53L30_ADCxy_PREAMP_SHIFT, |
338 | 2, 0, pga_preamp_tlv), |
339 | |
340 | SOC_ENUM("Input 1 Channel Select" , input1_sel_enum), |
341 | SOC_ENUM("Input 2 Channel Select" , input2_sel_enum), |
342 | |
343 | SOC_ENUM("ADC1 HPF Select" , adc1_hpf_enum), |
344 | SOC_ENUM("ADC2 HPF Select" , adc2_hpf_enum), |
345 | SOC_ENUM("ADC1 NG Threshold" , adc1_ng_thres_enum), |
346 | SOC_ENUM("ADC2 NG Threshold" , adc2_ng_thres_enum), |
347 | SOC_ENUM("ADC1 NG Delay" , adc1_ng_delay_enum), |
348 | SOC_ENUM("ADC2 NG Delay" , adc2_ng_delay_enum), |
349 | |
350 | SOC_SINGLE_SX_TLV("ADC1A PGA Volume" , |
351 | CS53L30_ADC1A_AFE_CTL, 0, 0x34, 0x24, pga_tlv), |
352 | SOC_SINGLE_SX_TLV("ADC1B PGA Volume" , |
353 | CS53L30_ADC1B_AFE_CTL, 0, 0x34, 0x24, pga_tlv), |
354 | SOC_SINGLE_SX_TLV("ADC2A PGA Volume" , |
355 | CS53L30_ADC2A_AFE_CTL, 0, 0x34, 0x24, pga_tlv), |
356 | SOC_SINGLE_SX_TLV("ADC2B PGA Volume" , |
357 | CS53L30_ADC2B_AFE_CTL, 0, 0x34, 0x24, pga_tlv), |
358 | |
359 | SOC_SINGLE_SX_TLV("ADC1A Digital Volume" , |
360 | CS53L30_ADC1A_DIG_VOL, 0, 0xA0, 0x6C, dig_tlv), |
361 | SOC_SINGLE_SX_TLV("ADC1B Digital Volume" , |
362 | CS53L30_ADC1B_DIG_VOL, 0, 0xA0, 0x6C, dig_tlv), |
363 | SOC_SINGLE_SX_TLV("ADC2A Digital Volume" , |
364 | CS53L30_ADC2A_DIG_VOL, 0, 0xA0, 0x6C, dig_tlv), |
365 | SOC_SINGLE_SX_TLV("ADC2B Digital Volume" , |
366 | CS53L30_ADC2B_DIG_VOL, 0, 0xA0, 0x6C, dig_tlv), |
367 | }; |
368 | |
369 | static const struct snd_soc_dapm_widget cs53l30_dapm_widgets[] = { |
370 | SND_SOC_DAPM_INPUT("IN1_DMIC1" ), |
371 | SND_SOC_DAPM_INPUT("IN2" ), |
372 | SND_SOC_DAPM_INPUT("IN3_DMIC2" ), |
373 | SND_SOC_DAPM_INPUT("IN4" ), |
374 | SND_SOC_DAPM_SUPPLY("MIC1 Bias" , CS53L30_MICBIAS_CTL, |
375 | CS53L30_MIC1_BIAS_PDN_SHIFT, 1, NULL, 0), |
376 | SND_SOC_DAPM_SUPPLY("MIC2 Bias" , CS53L30_MICBIAS_CTL, |
377 | CS53L30_MIC2_BIAS_PDN_SHIFT, 1, NULL, 0), |
378 | SND_SOC_DAPM_SUPPLY("MIC3 Bias" , CS53L30_MICBIAS_CTL, |
379 | CS53L30_MIC3_BIAS_PDN_SHIFT, 1, NULL, 0), |
380 | SND_SOC_DAPM_SUPPLY("MIC4 Bias" , CS53L30_MICBIAS_CTL, |
381 | CS53L30_MIC4_BIAS_PDN_SHIFT, 1, NULL, 0), |
382 | |
383 | SND_SOC_DAPM_AIF_OUT("ASP_SDOUT1" , NULL, 0, CS53L30_ASP_CTL1, |
384 | CS53L30_ASP_SDOUTx_PDN_SHIFT, 1), |
385 | SND_SOC_DAPM_AIF_OUT("ASP_SDOUT2" , NULL, 0, CS53L30_ASP_CTL2, |
386 | CS53L30_ASP_SDOUTx_PDN_SHIFT, 1), |
387 | |
388 | SND_SOC_DAPM_MUX("Input Mux 1" , SND_SOC_NOPM, 0, 0, |
389 | &input1_route_sel_mux), |
390 | SND_SOC_DAPM_MUX("Input Mux 2" , SND_SOC_NOPM, 0, 0, |
391 | &input2_route_sel_mux), |
392 | |
393 | SND_SOC_DAPM_ADC("ADC1A" , NULL, CS53L30_ADCDMIC1_CTL1, |
394 | CS53L30_ADCxA_PDN_SHIFT, 1), |
395 | SND_SOC_DAPM_ADC("ADC1B" , NULL, CS53L30_ADCDMIC1_CTL1, |
396 | CS53L30_ADCxB_PDN_SHIFT, 1), |
397 | SND_SOC_DAPM_ADC("ADC2A" , NULL, CS53L30_ADCDMIC2_CTL1, |
398 | CS53L30_ADCxA_PDN_SHIFT, 1), |
399 | SND_SOC_DAPM_ADC("ADC2B" , NULL, CS53L30_ADCDMIC2_CTL1, |
400 | CS53L30_ADCxB_PDN_SHIFT, 1), |
401 | SND_SOC_DAPM_ADC("DMIC1" , NULL, CS53L30_ADCDMIC1_CTL1, |
402 | CS53L30_DMICx_PDN_SHIFT, 1), |
403 | SND_SOC_DAPM_ADC("DMIC2" , NULL, CS53L30_ADCDMIC2_CTL1, |
404 | CS53L30_DMICx_PDN_SHIFT, 1), |
405 | }; |
406 | |
407 | static const struct snd_soc_dapm_route cs53l30_dapm_routes[] = { |
408 | /* ADC Input Paths */ |
409 | {"ADC1A" , NULL, "IN1_DMIC1" }, |
410 | {"Input Mux 1" , "ADC1_SEL" , "ADC1A" }, |
411 | {"ADC1B" , NULL, "IN2" }, |
412 | |
413 | {"ADC2A" , NULL, "IN3_DMIC2" }, |
414 | {"Input Mux 2" , "ADC2_SEL" , "ADC2A" }, |
415 | {"ADC2B" , NULL, "IN4" }, |
416 | |
417 | /* MIC Bias Paths */ |
418 | {"ADC1A" , NULL, "MIC1 Bias" }, |
419 | {"ADC1B" , NULL, "MIC2 Bias" }, |
420 | {"ADC2A" , NULL, "MIC3 Bias" }, |
421 | {"ADC2B" , NULL, "MIC4 Bias" }, |
422 | |
423 | /* DMIC Paths */ |
424 | {"DMIC1" , NULL, "IN1_DMIC1" }, |
425 | {"Input Mux 1" , "DMIC1_SEL" , "DMIC1" }, |
426 | |
427 | {"DMIC2" , NULL, "IN3_DMIC2" }, |
428 | {"Input Mux 2" , "DMIC2_SEL" , "DMIC2" }, |
429 | }; |
430 | |
431 | static const struct snd_soc_dapm_route cs53l30_dapm_routes_sdout1[] = { |
432 | /* Output Paths when using SDOUT1 only */ |
433 | {"ASP_SDOUT1" , NULL, "ADC1A" }, |
434 | {"ASP_SDOUT1" , NULL, "Input Mux 1" }, |
435 | {"ASP_SDOUT1" , NULL, "ADC1B" }, |
436 | |
437 | {"ASP_SDOUT1" , NULL, "ADC2A" }, |
438 | {"ASP_SDOUT1" , NULL, "Input Mux 2" }, |
439 | {"ASP_SDOUT1" , NULL, "ADC2B" }, |
440 | |
441 | {"Capture" , NULL, "ASP_SDOUT1" }, |
442 | }; |
443 | |
444 | static const struct snd_soc_dapm_route cs53l30_dapm_routes_sdout2[] = { |
445 | /* Output Paths when using both SDOUT1 and SDOUT2 */ |
446 | {"ASP_SDOUT1" , NULL, "ADC1A" }, |
447 | {"ASP_SDOUT1" , NULL, "Input Mux 1" }, |
448 | {"ASP_SDOUT1" , NULL, "ADC1B" }, |
449 | |
450 | {"ASP_SDOUT2" , NULL, "ADC2A" }, |
451 | {"ASP_SDOUT2" , NULL, "Input Mux 2" }, |
452 | {"ASP_SDOUT2" , NULL, "ADC2B" }, |
453 | |
454 | {"Capture" , NULL, "ASP_SDOUT1" }, |
455 | {"Capture" , NULL, "ASP_SDOUT2" }, |
456 | }; |
457 | |
458 | struct cs53l30_mclk_div { |
459 | u32 mclk_rate; |
460 | u32 srate; |
461 | u8 asp_rate; |
462 | u8 internal_fs_ratio; |
463 | u8 mclk_int_scale; |
464 | }; |
465 | |
466 | static const struct cs53l30_mclk_div cs53l30_mclk_coeffs[] = { |
467 | /* NOTE: Enable MCLK_INT_SCALE to save power. */ |
468 | |
469 | /* MCLK, Sample Rate, asp_rate, internal_fs_ratio, mclk_int_scale */ |
470 | {5644800, 11025, 0x4, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
471 | {5644800, 22050, 0x8, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
472 | {5644800, 44100, 0xC, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
473 | |
474 | {6000000, 8000, 0x1, 0, CS53L30_MCLK_INT_SCALE}, |
475 | {6000000, 11025, 0x2, 0, CS53L30_MCLK_INT_SCALE}, |
476 | {6000000, 12000, 0x4, 0, CS53L30_MCLK_INT_SCALE}, |
477 | {6000000, 16000, 0x5, 0, CS53L30_MCLK_INT_SCALE}, |
478 | {6000000, 22050, 0x6, 0, CS53L30_MCLK_INT_SCALE}, |
479 | {6000000, 24000, 0x8, 0, CS53L30_MCLK_INT_SCALE}, |
480 | {6000000, 32000, 0x9, 0, CS53L30_MCLK_INT_SCALE}, |
481 | {6000000, 44100, 0xA, 0, CS53L30_MCLK_INT_SCALE}, |
482 | {6000000, 48000, 0xC, 0, CS53L30_MCLK_INT_SCALE}, |
483 | |
484 | {6144000, 8000, 0x1, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
485 | {6144000, 11025, 0x2, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
486 | {6144000, 12000, 0x4, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
487 | {6144000, 16000, 0x5, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
488 | {6144000, 22050, 0x6, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
489 | {6144000, 24000, 0x8, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
490 | {6144000, 32000, 0x9, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
491 | {6144000, 44100, 0xA, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
492 | {6144000, 48000, 0xC, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
493 | |
494 | {6400000, 8000, 0x1, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
495 | {6400000, 11025, 0x2, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
496 | {6400000, 12000, 0x4, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
497 | {6400000, 16000, 0x5, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
498 | {6400000, 22050, 0x6, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
499 | {6400000, 24000, 0x8, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
500 | {6400000, 32000, 0x9, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
501 | {6400000, 44100, 0xA, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
502 | {6400000, 48000, 0xC, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, |
503 | }; |
504 | |
505 | struct cs53l30_mclkx_div { |
506 | u32 mclkx; |
507 | u8 ratio; |
508 | u8 mclkdiv; |
509 | }; |
510 | |
511 | static const struct cs53l30_mclkx_div cs53l30_mclkx_coeffs[] = { |
512 | {5644800, 1, CS53L30_MCLK_DIV_BY_1}, |
513 | {6000000, 1, CS53L30_MCLK_DIV_BY_1}, |
514 | {6144000, 1, CS53L30_MCLK_DIV_BY_1}, |
515 | {11289600, 2, CS53L30_MCLK_DIV_BY_2}, |
516 | {12288000, 2, CS53L30_MCLK_DIV_BY_2}, |
517 | {12000000, 2, CS53L30_MCLK_DIV_BY_2}, |
518 | {19200000, 3, CS53L30_MCLK_DIV_BY_3}, |
519 | }; |
520 | |
521 | static int cs53l30_get_mclkx_coeff(int mclkx) |
522 | { |
523 | int i; |
524 | |
525 | for (i = 0; i < ARRAY_SIZE(cs53l30_mclkx_coeffs); i++) { |
526 | if (cs53l30_mclkx_coeffs[i].mclkx == mclkx) |
527 | return i; |
528 | } |
529 | |
530 | return -EINVAL; |
531 | } |
532 | |
533 | static int cs53l30_get_mclk_coeff(int mclk_rate, int srate) |
534 | { |
535 | int i; |
536 | |
537 | for (i = 0; i < ARRAY_SIZE(cs53l30_mclk_coeffs); i++) { |
538 | if (cs53l30_mclk_coeffs[i].mclk_rate == mclk_rate && |
539 | cs53l30_mclk_coeffs[i].srate == srate) |
540 | return i; |
541 | } |
542 | |
543 | return -EINVAL; |
544 | } |
545 | |
546 | static int cs53l30_set_sysclk(struct snd_soc_dai *dai, |
547 | int clk_id, unsigned int freq, int dir) |
548 | { |
549 | struct cs53l30_private *priv = snd_soc_component_get_drvdata(c: dai->component); |
550 | int mclkx_coeff; |
551 | u32 mclk_rate; |
552 | |
553 | /* MCLKX -> MCLK */ |
554 | mclkx_coeff = cs53l30_get_mclkx_coeff(mclkx: freq); |
555 | if (mclkx_coeff < 0) |
556 | return mclkx_coeff; |
557 | |
558 | mclk_rate = cs53l30_mclkx_coeffs[mclkx_coeff].mclkx / |
559 | cs53l30_mclkx_coeffs[mclkx_coeff].ratio; |
560 | |
561 | regmap_update_bits(map: priv->regmap, CS53L30_MCLKCTL, |
562 | CS53L30_MCLK_DIV_MASK, |
563 | val: cs53l30_mclkx_coeffs[mclkx_coeff].mclkdiv); |
564 | |
565 | priv->mclk_rate = mclk_rate; |
566 | |
567 | return 0; |
568 | } |
569 | |
570 | static int cs53l30_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
571 | { |
572 | struct cs53l30_private *priv = snd_soc_component_get_drvdata(c: dai->component); |
573 | u8 aspcfg = 0, aspctl1 = 0; |
574 | |
575 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
576 | case SND_SOC_DAIFMT_CBM_CFM: |
577 | aspcfg |= CS53L30_ASP_MS; |
578 | break; |
579 | case SND_SOC_DAIFMT_CBS_CFS: |
580 | break; |
581 | default: |
582 | return -EINVAL; |
583 | } |
584 | |
585 | /* DAI mode */ |
586 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
587 | case SND_SOC_DAIFMT_I2S: |
588 | /* Set TDM_PDN to turn off TDM mode -- Reset default */ |
589 | aspctl1 |= CS53L30_ASP_TDM_PDN; |
590 | break; |
591 | case SND_SOC_DAIFMT_DSP_A: |
592 | /* |
593 | * Clear TDM_PDN to turn on TDM mode; Use ASP_SCLK_INV = 0 |
594 | * with SHIFT_LEFT = 1 combination as Figure 4-13 shows in |
595 | * the CS53L30 datasheet |
596 | */ |
597 | aspctl1 |= CS53L30_SHIFT_LEFT; |
598 | break; |
599 | default: |
600 | return -EINVAL; |
601 | } |
602 | |
603 | /* Check to see if the SCLK is inverted */ |
604 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
605 | case SND_SOC_DAIFMT_IB_NF: |
606 | case SND_SOC_DAIFMT_IB_IF: |
607 | aspcfg ^= CS53L30_ASP_SCLK_INV; |
608 | break; |
609 | default: |
610 | break; |
611 | } |
612 | |
613 | regmap_update_bits(map: priv->regmap, CS53L30_ASPCFG_CTL, |
614 | CS53L30_ASP_MS | CS53L30_ASP_SCLK_INV, val: aspcfg); |
615 | |
616 | regmap_update_bits(map: priv->regmap, CS53L30_ASP_CTL1, |
617 | CS53L30_ASP_TDM_PDN | CS53L30_SHIFT_LEFT, val: aspctl1); |
618 | |
619 | return 0; |
620 | } |
621 | |
622 | static int cs53l30_pcm_hw_params(struct snd_pcm_substream *substream, |
623 | struct snd_pcm_hw_params *params, |
624 | struct snd_soc_dai *dai) |
625 | { |
626 | struct cs53l30_private *priv = snd_soc_component_get_drvdata(c: dai->component); |
627 | int srate = params_rate(p: params); |
628 | int mclk_coeff; |
629 | |
630 | /* MCLK -> srate */ |
631 | mclk_coeff = cs53l30_get_mclk_coeff(mclk_rate: priv->mclk_rate, srate); |
632 | if (mclk_coeff < 0) |
633 | return -EINVAL; |
634 | |
635 | regmap_update_bits(map: priv->regmap, CS53L30_INT_SR_CTL, |
636 | CS53L30_INTRNL_FS_RATIO_MASK, |
637 | val: cs53l30_mclk_coeffs[mclk_coeff].internal_fs_ratio); |
638 | |
639 | regmap_update_bits(map: priv->regmap, CS53L30_MCLKCTL, |
640 | CS53L30_MCLK_INT_SCALE_MASK, |
641 | val: cs53l30_mclk_coeffs[mclk_coeff].mclk_int_scale); |
642 | |
643 | regmap_update_bits(map: priv->regmap, CS53L30_ASPCFG_CTL, |
644 | CS53L30_ASP_RATE_MASK, |
645 | val: cs53l30_mclk_coeffs[mclk_coeff].asp_rate); |
646 | |
647 | return 0; |
648 | } |
649 | |
650 | static int cs53l30_set_bias_level(struct snd_soc_component *component, |
651 | enum snd_soc_bias_level level) |
652 | { |
653 | struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); |
654 | struct cs53l30_private *priv = snd_soc_component_get_drvdata(c: component); |
655 | unsigned int reg; |
656 | int i, inter_max_check, ret; |
657 | |
658 | switch (level) { |
659 | case SND_SOC_BIAS_ON: |
660 | break; |
661 | case SND_SOC_BIAS_PREPARE: |
662 | if (dapm->bias_level == SND_SOC_BIAS_STANDBY) |
663 | regmap_update_bits(map: priv->regmap, CS53L30_PWRCTL, |
664 | CS53L30_PDN_LP_MASK, val: 0); |
665 | break; |
666 | case SND_SOC_BIAS_STANDBY: |
667 | if (dapm->bias_level == SND_SOC_BIAS_OFF) { |
668 | ret = clk_prepare_enable(clk: priv->mclk); |
669 | if (ret) { |
670 | dev_err(component->dev, |
671 | "failed to enable MCLK: %d\n" , ret); |
672 | return ret; |
673 | } |
674 | regmap_update_bits(map: priv->regmap, CS53L30_MCLKCTL, |
675 | CS53L30_MCLK_DIS_MASK, val: 0); |
676 | regmap_update_bits(map: priv->regmap, CS53L30_PWRCTL, |
677 | CS53L30_PDN_ULP_MASK, val: 0); |
678 | msleep(msecs: 50); |
679 | } else { |
680 | regmap_update_bits(map: priv->regmap, CS53L30_PWRCTL, |
681 | CS53L30_PDN_ULP_MASK, |
682 | CS53L30_PDN_ULP); |
683 | } |
684 | break; |
685 | case SND_SOC_BIAS_OFF: |
686 | regmap_update_bits(map: priv->regmap, CS53L30_INT_MASK, |
687 | CS53L30_PDN_DONE, val: 0); |
688 | /* |
689 | * If digital softramp is set, the amount of time required |
690 | * for power down increases and depends on the digital |
691 | * volume setting. |
692 | */ |
693 | |
694 | /* Set the max possible time if digsft is set */ |
695 | regmap_read(map: priv->regmap, CS53L30_SFT_RAMP, val: ®); |
696 | if (reg & CS53L30_DIGSFT_MASK) |
697 | inter_max_check = CS53L30_PDN_POLL_MAX; |
698 | else |
699 | inter_max_check = 10; |
700 | |
701 | regmap_update_bits(map: priv->regmap, CS53L30_PWRCTL, |
702 | CS53L30_PDN_ULP_MASK, |
703 | CS53L30_PDN_ULP); |
704 | /* PDN_DONE will take a min of 20ms to be set.*/ |
705 | msleep(msecs: 20); |
706 | /* Clr status */ |
707 | regmap_read(map: priv->regmap, CS53L30_IS, val: ®); |
708 | for (i = 0; i < inter_max_check; i++) { |
709 | if (inter_max_check < 10) { |
710 | usleep_range(min: 1000, max: 1100); |
711 | regmap_read(map: priv->regmap, CS53L30_IS, val: ®); |
712 | if (reg & CS53L30_PDN_DONE) |
713 | break; |
714 | } else { |
715 | usleep_range(min: 10000, max: 10100); |
716 | regmap_read(map: priv->regmap, CS53L30_IS, val: ®); |
717 | if (reg & CS53L30_PDN_DONE) |
718 | break; |
719 | } |
720 | } |
721 | /* PDN_DONE is set. We now can disable the MCLK */ |
722 | regmap_update_bits(map: priv->regmap, CS53L30_INT_MASK, |
723 | CS53L30_PDN_DONE, CS53L30_PDN_DONE); |
724 | regmap_update_bits(map: priv->regmap, CS53L30_MCLKCTL, |
725 | CS53L30_MCLK_DIS_MASK, |
726 | CS53L30_MCLK_DIS); |
727 | clk_disable_unprepare(clk: priv->mclk); |
728 | break; |
729 | } |
730 | |
731 | return 0; |
732 | } |
733 | |
734 | static int cs53l30_set_tristate(struct snd_soc_dai *dai, int tristate) |
735 | { |
736 | struct cs53l30_private *priv = snd_soc_component_get_drvdata(c: dai->component); |
737 | u8 val = tristate ? CS53L30_ASP_3ST : 0; |
738 | |
739 | return regmap_update_bits(map: priv->regmap, CS53L30_ASP_CTL1, |
740 | CS53L30_ASP_3ST_MASK, val); |
741 | } |
742 | |
743 | static unsigned int const cs53l30_src_rates[] = { |
744 | 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 |
745 | }; |
746 | |
747 | static const struct snd_pcm_hw_constraint_list src_constraints = { |
748 | .count = ARRAY_SIZE(cs53l30_src_rates), |
749 | .list = cs53l30_src_rates, |
750 | }; |
751 | |
752 | static int cs53l30_pcm_startup(struct snd_pcm_substream *substream, |
753 | struct snd_soc_dai *dai) |
754 | { |
755 | snd_pcm_hw_constraint_list(runtime: substream->runtime, cond: 0, |
756 | SNDRV_PCM_HW_PARAM_RATE, l: &src_constraints); |
757 | |
758 | return 0; |
759 | } |
760 | |
761 | /* |
762 | * Note: CS53L30 counts the slot number per byte while ASoC counts the slot |
763 | * number per slot_width. So there is a difference between the slots of ASoC |
764 | * and the slots of CS53L30. |
765 | */ |
766 | static int cs53l30_set_dai_tdm_slot(struct snd_soc_dai *dai, |
767 | unsigned int tx_mask, unsigned int rx_mask, |
768 | int slots, int slot_width) |
769 | { |
770 | struct cs53l30_private *priv = snd_soc_component_get_drvdata(c: dai->component); |
771 | unsigned int loc[CS53L30_TDM_SLOT_MAX] = {48, 48, 48, 48}; |
772 | unsigned int slot_next, slot_step; |
773 | u64 tx_enable = 0; |
774 | int i; |
775 | |
776 | if (!rx_mask) { |
777 | dev_err(dai->dev, "rx masks must not be 0\n" ); |
778 | return -EINVAL; |
779 | } |
780 | |
781 | /* Assuming slot_width is not supposed to be greater than 64 */ |
782 | if (slots <= 0 || slot_width <= 0 || slot_width > 64) { |
783 | dev_err(dai->dev, "invalid slot number or slot width\n" ); |
784 | return -EINVAL; |
785 | } |
786 | |
787 | if (slot_width & 0x7) { |
788 | dev_err(dai->dev, "slot width must count in byte\n" ); |
789 | return -EINVAL; |
790 | } |
791 | |
792 | /* How many bytes in each ASoC slot */ |
793 | slot_step = slot_width >> 3; |
794 | |
795 | for (i = 0; rx_mask && i < CS53L30_TDM_SLOT_MAX; i++) { |
796 | /* Find the first slot from LSB */ |
797 | slot_next = __ffs(rx_mask); |
798 | /* Save the slot location by converting to CS53L30 slot */ |
799 | loc[i] = slot_next * slot_step; |
800 | /* Create the mask of CS53L30 slot */ |
801 | tx_enable |= (u64)((u64)(1 << slot_step) - 1) << (u64)loc[i]; |
802 | /* Clear this slot from rx_mask */ |
803 | rx_mask &= ~(1 << slot_next); |
804 | } |
805 | |
806 | /* Error out to avoid slot shift */ |
807 | if (rx_mask && i == CS53L30_TDM_SLOT_MAX) { |
808 | dev_err(dai->dev, "rx_mask exceeds max slot number: %d\n" , |
809 | CS53L30_TDM_SLOT_MAX); |
810 | return -EINVAL; |
811 | } |
812 | |
813 | /* Validate the last active CS53L30 slot */ |
814 | slot_next = loc[i - 1] + slot_step - 1; |
815 | if (slot_next > 47) { |
816 | dev_err(dai->dev, "slot selection out of bounds: %u\n" , |
817 | slot_next); |
818 | return -EINVAL; |
819 | } |
820 | |
821 | for (i = 0; i < CS53L30_TDM_SLOT_MAX && loc[i] != 48; i++) { |
822 | regmap_update_bits(map: priv->regmap, CS53L30_ASP_TDMTX_CTL(i), |
823 | CS53L30_ASP_CHx_TX_LOC_MASK, val: loc[i]); |
824 | dev_dbg(dai->dev, "loc[%d]=%x\n" , i, loc[i]); |
825 | } |
826 | |
827 | for (i = 0; i < CS53L30_ASP_TDMTX_ENx_MAX && tx_enable; i++) { |
828 | regmap_write(map: priv->regmap, CS53L30_ASP_TDMTX_ENx(i), |
829 | val: tx_enable & 0xff); |
830 | tx_enable >>= 8; |
831 | dev_dbg(dai->dev, "en_reg=%x, tx_enable=%llx\n" , |
832 | CS53L30_ASP_TDMTX_ENx(i), tx_enable & 0xff); |
833 | } |
834 | |
835 | return 0; |
836 | } |
837 | |
838 | static int cs53l30_mute_stream(struct snd_soc_dai *dai, int mute, int stream) |
839 | { |
840 | struct cs53l30_private *priv = snd_soc_component_get_drvdata(c: dai->component); |
841 | |
842 | gpiod_set_value_cansleep(desc: priv->mute_gpio, value: mute); |
843 | |
844 | return 0; |
845 | } |
846 | |
847 | /* SNDRV_PCM_RATE_KNOT -> 12000, 24000 Hz, limit with constraint list */ |
848 | #define CS53L30_RATES (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT) |
849 | |
850 | #define CS53L30_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
851 | SNDRV_PCM_FMTBIT_S24_LE) |
852 | |
853 | static const struct snd_soc_dai_ops cs53l30_ops = { |
854 | .startup = cs53l30_pcm_startup, |
855 | .hw_params = cs53l30_pcm_hw_params, |
856 | .set_fmt = cs53l30_set_dai_fmt, |
857 | .set_sysclk = cs53l30_set_sysclk, |
858 | .set_tristate = cs53l30_set_tristate, |
859 | .set_tdm_slot = cs53l30_set_dai_tdm_slot, |
860 | .mute_stream = cs53l30_mute_stream, |
861 | }; |
862 | |
863 | static struct snd_soc_dai_driver cs53l30_dai = { |
864 | .name = "cs53l30" , |
865 | .capture = { |
866 | .stream_name = "Capture" , |
867 | .channels_min = 1, |
868 | .channels_max = 4, |
869 | .rates = CS53L30_RATES, |
870 | .formats = CS53L30_FORMATS, |
871 | }, |
872 | .ops = &cs53l30_ops, |
873 | .symmetric_rate = 1, |
874 | }; |
875 | |
876 | static int cs53l30_component_probe(struct snd_soc_component *component) |
877 | { |
878 | struct cs53l30_private *priv = snd_soc_component_get_drvdata(c: component); |
879 | struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); |
880 | |
881 | if (priv->use_sdout2) |
882 | snd_soc_dapm_add_routes(dapm, route: cs53l30_dapm_routes_sdout2, |
883 | ARRAY_SIZE(cs53l30_dapm_routes_sdout2)); |
884 | else |
885 | snd_soc_dapm_add_routes(dapm, route: cs53l30_dapm_routes_sdout1, |
886 | ARRAY_SIZE(cs53l30_dapm_routes_sdout1)); |
887 | |
888 | return 0; |
889 | } |
890 | |
891 | static const struct snd_soc_component_driver cs53l30_driver = { |
892 | .probe = cs53l30_component_probe, |
893 | .set_bias_level = cs53l30_set_bias_level, |
894 | .controls = cs53l30_snd_controls, |
895 | .num_controls = ARRAY_SIZE(cs53l30_snd_controls), |
896 | .dapm_widgets = cs53l30_dapm_widgets, |
897 | .num_dapm_widgets = ARRAY_SIZE(cs53l30_dapm_widgets), |
898 | .dapm_routes = cs53l30_dapm_routes, |
899 | .num_dapm_routes = ARRAY_SIZE(cs53l30_dapm_routes), |
900 | .use_pmdown_time = 1, |
901 | .endianness = 1, |
902 | }; |
903 | |
904 | static struct regmap_config cs53l30_regmap = { |
905 | .reg_bits = 8, |
906 | .val_bits = 8, |
907 | |
908 | .max_register = CS53L30_MAX_REGISTER, |
909 | .reg_defaults = cs53l30_reg_defaults, |
910 | .num_reg_defaults = ARRAY_SIZE(cs53l30_reg_defaults), |
911 | .volatile_reg = cs53l30_volatile_register, |
912 | .writeable_reg = cs53l30_writeable_register, |
913 | .readable_reg = cs53l30_readable_register, |
914 | .cache_type = REGCACHE_MAPLE, |
915 | |
916 | .use_single_read = true, |
917 | .use_single_write = true, |
918 | }; |
919 | |
920 | static int cs53l30_i2c_probe(struct i2c_client *client) |
921 | { |
922 | const struct device_node *np = client->dev.of_node; |
923 | struct device *dev = &client->dev; |
924 | struct cs53l30_private *cs53l30; |
925 | unsigned int reg; |
926 | int ret = 0, i, devid; |
927 | u8 val; |
928 | |
929 | cs53l30 = devm_kzalloc(dev, size: sizeof(*cs53l30), GFP_KERNEL); |
930 | if (!cs53l30) |
931 | return -ENOMEM; |
932 | |
933 | for (i = 0; i < ARRAY_SIZE(cs53l30->supplies); i++) |
934 | cs53l30->supplies[i].supply = cs53l30_supply_names[i]; |
935 | |
936 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs53l30->supplies), |
937 | consumers: cs53l30->supplies); |
938 | if (ret) { |
939 | dev_err(dev, "failed to get supplies: %d\n" , ret); |
940 | return ret; |
941 | } |
942 | |
943 | ret = regulator_bulk_enable(ARRAY_SIZE(cs53l30->supplies), |
944 | consumers: cs53l30->supplies); |
945 | if (ret) { |
946 | dev_err(dev, "failed to enable supplies: %d\n" , ret); |
947 | return ret; |
948 | } |
949 | |
950 | /* Reset the Device */ |
951 | cs53l30->reset_gpio = devm_gpiod_get_optional(dev, con_id: "reset" , |
952 | flags: GPIOD_OUT_LOW); |
953 | if (IS_ERR(ptr: cs53l30->reset_gpio)) { |
954 | ret = PTR_ERR(ptr: cs53l30->reset_gpio); |
955 | goto error_supplies; |
956 | } |
957 | |
958 | gpiod_set_value_cansleep(desc: cs53l30->reset_gpio, value: 1); |
959 | |
960 | i2c_set_clientdata(client, data: cs53l30); |
961 | |
962 | cs53l30->mclk_rate = 0; |
963 | |
964 | cs53l30->regmap = devm_regmap_init_i2c(client, &cs53l30_regmap); |
965 | if (IS_ERR(ptr: cs53l30->regmap)) { |
966 | ret = PTR_ERR(ptr: cs53l30->regmap); |
967 | dev_err(dev, "regmap_init() failed: %d\n" , ret); |
968 | goto error; |
969 | } |
970 | |
971 | /* Initialize codec */ |
972 | devid = cirrus_read_device_id(regmap: cs53l30->regmap, CS53L30_DEVID_AB); |
973 | if (devid < 0) { |
974 | ret = devid; |
975 | dev_err(dev, "Failed to read device ID: %d\n" , ret); |
976 | goto error; |
977 | } |
978 | |
979 | if (devid != CS53L30_DEVID) { |
980 | ret = -ENODEV; |
981 | dev_err(dev, "Device ID (%X). Expected %X\n" , |
982 | devid, CS53L30_DEVID); |
983 | goto error; |
984 | } |
985 | |
986 | ret = regmap_read(map: cs53l30->regmap, CS53L30_REVID, val: ®); |
987 | if (ret < 0) { |
988 | dev_err(dev, "failed to get Revision ID: %d\n" , ret); |
989 | goto error; |
990 | } |
991 | |
992 | /* Check if MCLK provided */ |
993 | cs53l30->mclk = devm_clk_get_optional(dev, id: "mclk" ); |
994 | if (IS_ERR(ptr: cs53l30->mclk)) { |
995 | ret = PTR_ERR(ptr: cs53l30->mclk); |
996 | goto error; |
997 | } |
998 | |
999 | /* Fetch the MUTE control */ |
1000 | cs53l30->mute_gpio = devm_gpiod_get_optional(dev, con_id: "mute" , |
1001 | flags: GPIOD_OUT_HIGH); |
1002 | if (IS_ERR(ptr: cs53l30->mute_gpio)) { |
1003 | ret = PTR_ERR(ptr: cs53l30->mute_gpio); |
1004 | goto error; |
1005 | } |
1006 | |
1007 | if (cs53l30->mute_gpio) { |
1008 | /* Enable MUTE controls via MUTE pin */ |
1009 | regmap_write(map: cs53l30->regmap, CS53L30_MUTEP_CTL1, |
1010 | CS53L30_MUTEP_CTL1_MUTEALL); |
1011 | /* Flip the polarity of MUTE pin */ |
1012 | if (gpiod_is_active_low(desc: cs53l30->mute_gpio)) |
1013 | regmap_update_bits(map: cs53l30->regmap, CS53L30_MUTEP_CTL2, |
1014 | CS53L30_MUTE_PIN_POLARITY, val: 0); |
1015 | } |
1016 | |
1017 | if (!of_property_read_u8(np, propname: "cirrus,micbias-lvl" , out_value: &val)) |
1018 | regmap_update_bits(map: cs53l30->regmap, CS53L30_MICBIAS_CTL, |
1019 | CS53L30_MIC_BIAS_CTRL_MASK, val); |
1020 | |
1021 | if (of_property_read_bool(np, propname: "cirrus,use-sdout2" )) |
1022 | cs53l30->use_sdout2 = true; |
1023 | |
1024 | dev_info(dev, "Cirrus Logic CS53L30, Revision: %02X\n" , reg & 0xFF); |
1025 | |
1026 | ret = devm_snd_soc_register_component(dev, component_driver: &cs53l30_driver, dai_drv: &cs53l30_dai, num_dai: 1); |
1027 | if (ret) { |
1028 | dev_err(dev, "failed to register component: %d\n" , ret); |
1029 | goto error; |
1030 | } |
1031 | |
1032 | return 0; |
1033 | |
1034 | error: |
1035 | gpiod_set_value_cansleep(desc: cs53l30->reset_gpio, value: 0); |
1036 | error_supplies: |
1037 | regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies), |
1038 | consumers: cs53l30->supplies); |
1039 | return ret; |
1040 | } |
1041 | |
1042 | static void cs53l30_i2c_remove(struct i2c_client *client) |
1043 | { |
1044 | struct cs53l30_private *cs53l30 = i2c_get_clientdata(client); |
1045 | |
1046 | /* Hold down reset */ |
1047 | gpiod_set_value_cansleep(desc: cs53l30->reset_gpio, value: 0); |
1048 | |
1049 | regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies), |
1050 | consumers: cs53l30->supplies); |
1051 | } |
1052 | |
1053 | #ifdef CONFIG_PM |
1054 | static int cs53l30_runtime_suspend(struct device *dev) |
1055 | { |
1056 | struct cs53l30_private *cs53l30 = dev_get_drvdata(dev); |
1057 | |
1058 | regcache_cache_only(map: cs53l30->regmap, enable: true); |
1059 | |
1060 | /* Hold down reset */ |
1061 | gpiod_set_value_cansleep(desc: cs53l30->reset_gpio, value: 0); |
1062 | |
1063 | regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies), |
1064 | consumers: cs53l30->supplies); |
1065 | |
1066 | return 0; |
1067 | } |
1068 | |
1069 | static int cs53l30_runtime_resume(struct device *dev) |
1070 | { |
1071 | struct cs53l30_private *cs53l30 = dev_get_drvdata(dev); |
1072 | int ret; |
1073 | |
1074 | ret = regulator_bulk_enable(ARRAY_SIZE(cs53l30->supplies), |
1075 | consumers: cs53l30->supplies); |
1076 | if (ret) { |
1077 | dev_err(dev, "failed to enable supplies: %d\n" , ret); |
1078 | return ret; |
1079 | } |
1080 | |
1081 | gpiod_set_value_cansleep(desc: cs53l30->reset_gpio, value: 1); |
1082 | |
1083 | regcache_cache_only(map: cs53l30->regmap, enable: false); |
1084 | ret = regcache_sync(map: cs53l30->regmap); |
1085 | if (ret) { |
1086 | dev_err(dev, "failed to synchronize regcache: %d\n" , ret); |
1087 | return ret; |
1088 | } |
1089 | |
1090 | return 0; |
1091 | } |
1092 | #endif |
1093 | |
1094 | static const struct dev_pm_ops cs53l30_runtime_pm = { |
1095 | SET_RUNTIME_PM_OPS(cs53l30_runtime_suspend, cs53l30_runtime_resume, |
1096 | NULL) |
1097 | }; |
1098 | |
1099 | static const struct of_device_id cs53l30_of_match[] = { |
1100 | { .compatible = "cirrus,cs53l30" , }, |
1101 | {}, |
1102 | }; |
1103 | |
1104 | MODULE_DEVICE_TABLE(of, cs53l30_of_match); |
1105 | |
1106 | static const struct i2c_device_id cs53l30_id[] = { |
1107 | { "cs53l30" , 0 }, |
1108 | {} |
1109 | }; |
1110 | |
1111 | MODULE_DEVICE_TABLE(i2c, cs53l30_id); |
1112 | |
1113 | static struct i2c_driver cs53l30_i2c_driver = { |
1114 | .driver = { |
1115 | .name = "cs53l30" , |
1116 | .of_match_table = cs53l30_of_match, |
1117 | .pm = &cs53l30_runtime_pm, |
1118 | }, |
1119 | .id_table = cs53l30_id, |
1120 | .probe = cs53l30_i2c_probe, |
1121 | .remove = cs53l30_i2c_remove, |
1122 | }; |
1123 | |
1124 | module_i2c_driver(cs53l30_i2c_driver); |
1125 | |
1126 | MODULE_DESCRIPTION("ASoC CS53L30 driver" ); |
1127 | MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <Paul.Handrigan@cirrus.com>" ); |
1128 | MODULE_LICENSE("GPL" ); |
1129 | |