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