1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // TLV320ADCX140 Sound driver |
3 | // Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com/ |
4 | |
5 | #include <linux/module.h> |
6 | #include <linux/moduleparam.h> |
7 | #include <linux/init.h> |
8 | #include <linux/delay.h> |
9 | #include <linux/pm.h> |
10 | #include <linux/i2c.h> |
11 | #include <linux/gpio/consumer.h> |
12 | #include <linux/regulator/consumer.h> |
13 | #include <linux/acpi.h> |
14 | #include <linux/of.h> |
15 | #include <linux/of_gpio.h> |
16 | #include <linux/slab.h> |
17 | #include <sound/core.h> |
18 | #include <sound/pcm.h> |
19 | #include <sound/pcm_params.h> |
20 | #include <sound/soc.h> |
21 | #include <sound/initval.h> |
22 | #include <sound/tlv.h> |
23 | |
24 | #include "tlv320adcx140.h" |
25 | |
26 | struct adcx140_priv { |
27 | struct snd_soc_component *component; |
28 | struct regulator *supply_areg; |
29 | struct gpio_desc *gpio_reset; |
30 | struct regmap *regmap; |
31 | struct device *dev; |
32 | |
33 | bool micbias_vg; |
34 | bool phase_calib_on; |
35 | |
36 | unsigned int dai_fmt; |
37 | unsigned int slot_width; |
38 | }; |
39 | |
40 | static const char * const gpo_config_names[] = { |
41 | "ti,gpo-config-1" , |
42 | "ti,gpo-config-2" , |
43 | "ti,gpo-config-3" , |
44 | "ti,gpo-config-4" , |
45 | }; |
46 | |
47 | static const struct reg_default adcx140_reg_defaults[] = { |
48 | { ADCX140_PAGE_SELECT, 0x00 }, |
49 | { ADCX140_SW_RESET, 0x00 }, |
50 | { ADCX140_SLEEP_CFG, 0x00 }, |
51 | { ADCX140_SHDN_CFG, 0x05 }, |
52 | { ADCX140_ASI_CFG0, 0x30 }, |
53 | { ADCX140_ASI_CFG1, 0x00 }, |
54 | { ADCX140_ASI_CFG2, 0x00 }, |
55 | { ADCX140_ASI_CH1, 0x00 }, |
56 | { ADCX140_ASI_CH2, 0x01 }, |
57 | { ADCX140_ASI_CH3, 0x02 }, |
58 | { ADCX140_ASI_CH4, 0x03 }, |
59 | { ADCX140_ASI_CH5, 0x04 }, |
60 | { ADCX140_ASI_CH6, 0x05 }, |
61 | { ADCX140_ASI_CH7, 0x06 }, |
62 | { ADCX140_ASI_CH8, 0x07 }, |
63 | { ADCX140_MST_CFG0, 0x02 }, |
64 | { ADCX140_MST_CFG1, 0x48 }, |
65 | { ADCX140_ASI_STS, 0xff }, |
66 | { ADCX140_CLK_SRC, 0x10 }, |
67 | { ADCX140_PDMCLK_CFG, 0x40 }, |
68 | { ADCX140_PDM_CFG, 0x00 }, |
69 | { ADCX140_GPIO_CFG0, 0x22 }, |
70 | { ADCX140_GPO_CFG0, 0x00 }, |
71 | { ADCX140_GPO_CFG1, 0x00 }, |
72 | { ADCX140_GPO_CFG2, 0x00 }, |
73 | { ADCX140_GPO_CFG3, 0x00 }, |
74 | { ADCX140_GPO_VAL, 0x00 }, |
75 | { ADCX140_GPIO_MON, 0x00 }, |
76 | { ADCX140_GPI_CFG0, 0x00 }, |
77 | { ADCX140_GPI_CFG1, 0x00 }, |
78 | { ADCX140_GPI_MON, 0x00 }, |
79 | { ADCX140_INT_CFG, 0x00 }, |
80 | { ADCX140_INT_MASK0, 0xff }, |
81 | { ADCX140_INT_LTCH0, 0x00 }, |
82 | { ADCX140_BIAS_CFG, 0x00 }, |
83 | { ADCX140_CH1_CFG0, 0x00 }, |
84 | { ADCX140_CH1_CFG1, 0x00 }, |
85 | { ADCX140_CH1_CFG2, 0xc9 }, |
86 | { ADCX140_CH1_CFG3, 0x80 }, |
87 | { ADCX140_CH1_CFG4, 0x00 }, |
88 | { ADCX140_CH2_CFG0, 0x00 }, |
89 | { ADCX140_CH2_CFG1, 0x00 }, |
90 | { ADCX140_CH2_CFG2, 0xc9 }, |
91 | { ADCX140_CH2_CFG3, 0x80 }, |
92 | { ADCX140_CH2_CFG4, 0x00 }, |
93 | { ADCX140_CH3_CFG0, 0x00 }, |
94 | { ADCX140_CH3_CFG1, 0x00 }, |
95 | { ADCX140_CH3_CFG2, 0xc9 }, |
96 | { ADCX140_CH3_CFG3, 0x80 }, |
97 | { ADCX140_CH3_CFG4, 0x00 }, |
98 | { ADCX140_CH4_CFG0, 0x00 }, |
99 | { ADCX140_CH4_CFG1, 0x00 }, |
100 | { ADCX140_CH4_CFG2, 0xc9 }, |
101 | { ADCX140_CH4_CFG3, 0x80 }, |
102 | { ADCX140_CH4_CFG4, 0x00 }, |
103 | { ADCX140_CH5_CFG2, 0xc9 }, |
104 | { ADCX140_CH5_CFG3, 0x80 }, |
105 | { ADCX140_CH5_CFG4, 0x00 }, |
106 | { ADCX140_CH6_CFG2, 0xc9 }, |
107 | { ADCX140_CH6_CFG3, 0x80 }, |
108 | { ADCX140_CH6_CFG4, 0x00 }, |
109 | { ADCX140_CH7_CFG2, 0xc9 }, |
110 | { ADCX140_CH7_CFG3, 0x80 }, |
111 | { ADCX140_CH7_CFG4, 0x00 }, |
112 | { ADCX140_CH8_CFG2, 0xc9 }, |
113 | { ADCX140_CH8_CFG3, 0x80 }, |
114 | { ADCX140_CH8_CFG4, 0x00 }, |
115 | { ADCX140_DSP_CFG0, 0x01 }, |
116 | { ADCX140_DSP_CFG1, 0x40 }, |
117 | { ADCX140_DRE_CFG0, 0x7b }, |
118 | { ADCX140_AGC_CFG0, 0xe7 }, |
119 | { ADCX140_IN_CH_EN, 0xf0 }, |
120 | { ADCX140_ASI_OUT_CH_EN, 0x00 }, |
121 | { ADCX140_PWR_CFG, 0x00 }, |
122 | { ADCX140_DEV_STS0, 0x00 }, |
123 | { ADCX140_DEV_STS1, 0x80 }, |
124 | }; |
125 | |
126 | static const struct regmap_range_cfg adcx140_ranges[] = { |
127 | { |
128 | .range_min = 0, |
129 | .range_max = 12 * 128, |
130 | .selector_reg = ADCX140_PAGE_SELECT, |
131 | .selector_mask = 0xff, |
132 | .selector_shift = 0, |
133 | .window_start = 0, |
134 | .window_len = 128, |
135 | }, |
136 | }; |
137 | |
138 | static bool adcx140_volatile(struct device *dev, unsigned int reg) |
139 | { |
140 | switch (reg) { |
141 | case ADCX140_SW_RESET: |
142 | case ADCX140_DEV_STS0: |
143 | case ADCX140_DEV_STS1: |
144 | case ADCX140_ASI_STS: |
145 | return true; |
146 | default: |
147 | return false; |
148 | } |
149 | } |
150 | |
151 | static const struct regmap_config adcx140_i2c_regmap = { |
152 | .reg_bits = 8, |
153 | .val_bits = 8, |
154 | .reg_defaults = adcx140_reg_defaults, |
155 | .num_reg_defaults = ARRAY_SIZE(adcx140_reg_defaults), |
156 | .cache_type = REGCACHE_FLAT, |
157 | .ranges = adcx140_ranges, |
158 | .num_ranges = ARRAY_SIZE(adcx140_ranges), |
159 | .max_register = 12 * 128, |
160 | .volatile_reg = adcx140_volatile, |
161 | }; |
162 | |
163 | /* Digital Volume control. From -100 to 27 dB in 0.5 dB steps */ |
164 | static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10050, 50, 0); |
165 | |
166 | /* ADC gain. From 0 to 42 dB in 1 dB steps */ |
167 | static DECLARE_TLV_DB_SCALE(adc_tlv, 0, 100, 0); |
168 | |
169 | /* DRE Level. From -12 dB to -66 dB in 1 dB steps */ |
170 | static DECLARE_TLV_DB_SCALE(dre_thresh_tlv, -6600, 100, 0); |
171 | /* DRE Max Gain. From 2 dB to 26 dB in 2 dB steps */ |
172 | static DECLARE_TLV_DB_SCALE(dre_gain_tlv, 200, 200, 0); |
173 | |
174 | /* AGC Level. From -6 dB to -36 dB in 2 dB steps */ |
175 | static DECLARE_TLV_DB_SCALE(agc_thresh_tlv, -3600, 200, 0); |
176 | /* AGC Max Gain. From 3 dB to 42 dB in 3 dB steps */ |
177 | static DECLARE_TLV_DB_SCALE(agc_gain_tlv, 300, 300, 0); |
178 | |
179 | static const char * const decimation_filter_text[] = { |
180 | "Linear Phase" , "Low Latency" , "Ultra-low Latency" |
181 | }; |
182 | |
183 | static SOC_ENUM_SINGLE_DECL(decimation_filter_enum, ADCX140_DSP_CFG0, 4, |
184 | decimation_filter_text); |
185 | |
186 | static const struct snd_kcontrol_new decimation_filter_controls[] = { |
187 | SOC_DAPM_ENUM("Decimation Filter" , decimation_filter_enum), |
188 | }; |
189 | |
190 | static const char * const pdmclk_text[] = { |
191 | "2.8224 MHz" , "1.4112 MHz" , "705.6 kHz" , "5.6448 MHz" |
192 | }; |
193 | |
194 | static SOC_ENUM_SINGLE_DECL(pdmclk_select_enum, ADCX140_PDMCLK_CFG, 0, |
195 | pdmclk_text); |
196 | |
197 | static const struct snd_kcontrol_new pdmclk_div_controls[] = { |
198 | SOC_DAPM_ENUM("PDM Clk Divider Select" , pdmclk_select_enum), |
199 | }; |
200 | |
201 | static const char * const resistor_text[] = { |
202 | "2.5 kOhm" , "10 kOhm" , "20 kOhm" |
203 | }; |
204 | |
205 | static SOC_ENUM_SINGLE_DECL(in1_resistor_enum, ADCX140_CH1_CFG0, 2, |
206 | resistor_text); |
207 | static SOC_ENUM_SINGLE_DECL(in2_resistor_enum, ADCX140_CH2_CFG0, 2, |
208 | resistor_text); |
209 | static SOC_ENUM_SINGLE_DECL(in3_resistor_enum, ADCX140_CH3_CFG0, 2, |
210 | resistor_text); |
211 | static SOC_ENUM_SINGLE_DECL(in4_resistor_enum, ADCX140_CH4_CFG0, 2, |
212 | resistor_text); |
213 | |
214 | static const struct snd_kcontrol_new in1_resistor_controls[] = { |
215 | SOC_DAPM_ENUM("CH1 Resistor Select" , in1_resistor_enum), |
216 | }; |
217 | static const struct snd_kcontrol_new in2_resistor_controls[] = { |
218 | SOC_DAPM_ENUM("CH2 Resistor Select" , in2_resistor_enum), |
219 | }; |
220 | static const struct snd_kcontrol_new in3_resistor_controls[] = { |
221 | SOC_DAPM_ENUM("CH3 Resistor Select" , in3_resistor_enum), |
222 | }; |
223 | static const struct snd_kcontrol_new in4_resistor_controls[] = { |
224 | SOC_DAPM_ENUM("CH4 Resistor Select" , in4_resistor_enum), |
225 | }; |
226 | |
227 | /* Analog/Digital Selection */ |
228 | static const char * const adcx140_mic_sel_text[] = {"Analog" , "Line In" , "Digital" }; |
229 | static const char * const adcx140_analog_sel_text[] = {"Analog" , "Line In" }; |
230 | |
231 | static SOC_ENUM_SINGLE_DECL(adcx140_mic1p_enum, |
232 | ADCX140_CH1_CFG0, 5, |
233 | adcx140_mic_sel_text); |
234 | |
235 | static const struct snd_kcontrol_new adcx140_dapm_mic1p_control = |
236 | SOC_DAPM_ENUM("MIC1P MUX" , adcx140_mic1p_enum); |
237 | |
238 | static SOC_ENUM_SINGLE_DECL(adcx140_mic1_analog_enum, |
239 | ADCX140_CH1_CFG0, 7, |
240 | adcx140_analog_sel_text); |
241 | |
242 | static const struct snd_kcontrol_new adcx140_dapm_mic1_analog_control = |
243 | SOC_DAPM_ENUM("MIC1 Analog MUX" , adcx140_mic1_analog_enum); |
244 | |
245 | static SOC_ENUM_SINGLE_DECL(adcx140_mic1m_enum, |
246 | ADCX140_CH1_CFG0, 5, |
247 | adcx140_mic_sel_text); |
248 | |
249 | static const struct snd_kcontrol_new adcx140_dapm_mic1m_control = |
250 | SOC_DAPM_ENUM("MIC1M MUX" , adcx140_mic1m_enum); |
251 | |
252 | static SOC_ENUM_SINGLE_DECL(adcx140_mic2p_enum, |
253 | ADCX140_CH2_CFG0, 5, |
254 | adcx140_mic_sel_text); |
255 | |
256 | static const struct snd_kcontrol_new adcx140_dapm_mic2p_control = |
257 | SOC_DAPM_ENUM("MIC2P MUX" , adcx140_mic2p_enum); |
258 | |
259 | static SOC_ENUM_SINGLE_DECL(adcx140_mic2_analog_enum, |
260 | ADCX140_CH2_CFG0, 7, |
261 | adcx140_analog_sel_text); |
262 | |
263 | static const struct snd_kcontrol_new adcx140_dapm_mic2_analog_control = |
264 | SOC_DAPM_ENUM("MIC2 Analog MUX" , adcx140_mic2_analog_enum); |
265 | |
266 | static SOC_ENUM_SINGLE_DECL(adcx140_mic2m_enum, |
267 | ADCX140_CH2_CFG0, 5, |
268 | adcx140_mic_sel_text); |
269 | |
270 | static const struct snd_kcontrol_new adcx140_dapm_mic2m_control = |
271 | SOC_DAPM_ENUM("MIC2M MUX" , adcx140_mic2m_enum); |
272 | |
273 | static SOC_ENUM_SINGLE_DECL(adcx140_mic3p_enum, |
274 | ADCX140_CH3_CFG0, 5, |
275 | adcx140_mic_sel_text); |
276 | |
277 | static const struct snd_kcontrol_new adcx140_dapm_mic3p_control = |
278 | SOC_DAPM_ENUM("MIC3P MUX" , adcx140_mic3p_enum); |
279 | |
280 | static SOC_ENUM_SINGLE_DECL(adcx140_mic3_analog_enum, |
281 | ADCX140_CH3_CFG0, 7, |
282 | adcx140_analog_sel_text); |
283 | |
284 | static const struct snd_kcontrol_new adcx140_dapm_mic3_analog_control = |
285 | SOC_DAPM_ENUM("MIC3 Analog MUX" , adcx140_mic3_analog_enum); |
286 | |
287 | static SOC_ENUM_SINGLE_DECL(adcx140_mic3m_enum, |
288 | ADCX140_CH3_CFG0, 5, |
289 | adcx140_mic_sel_text); |
290 | |
291 | static const struct snd_kcontrol_new adcx140_dapm_mic3m_control = |
292 | SOC_DAPM_ENUM("MIC3M MUX" , adcx140_mic3m_enum); |
293 | |
294 | static SOC_ENUM_SINGLE_DECL(adcx140_mic4p_enum, |
295 | ADCX140_CH4_CFG0, 5, |
296 | adcx140_mic_sel_text); |
297 | |
298 | static const struct snd_kcontrol_new adcx140_dapm_mic4p_control = |
299 | SOC_DAPM_ENUM("MIC4P MUX" , adcx140_mic4p_enum); |
300 | |
301 | static SOC_ENUM_SINGLE_DECL(adcx140_mic4_analog_enum, |
302 | ADCX140_CH4_CFG0, 7, |
303 | adcx140_analog_sel_text); |
304 | |
305 | static const struct snd_kcontrol_new adcx140_dapm_mic4_analog_control = |
306 | SOC_DAPM_ENUM("MIC4 Analog MUX" , adcx140_mic4_analog_enum); |
307 | |
308 | static SOC_ENUM_SINGLE_DECL(adcx140_mic4m_enum, |
309 | ADCX140_CH4_CFG0, 5, |
310 | adcx140_mic_sel_text); |
311 | |
312 | static const struct snd_kcontrol_new adcx140_dapm_mic4m_control = |
313 | SOC_DAPM_ENUM("MIC4M MUX" , adcx140_mic4m_enum); |
314 | |
315 | static const struct snd_kcontrol_new adcx140_dapm_ch1_en_switch = |
316 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 7, 1, 0); |
317 | static const struct snd_kcontrol_new adcx140_dapm_ch2_en_switch = |
318 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 6, 1, 0); |
319 | static const struct snd_kcontrol_new adcx140_dapm_ch3_en_switch = |
320 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 5, 1, 0); |
321 | static const struct snd_kcontrol_new adcx140_dapm_ch4_en_switch = |
322 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 4, 1, 0); |
323 | static const struct snd_kcontrol_new adcx140_dapm_ch5_en_switch = |
324 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 3, 1, 0); |
325 | static const struct snd_kcontrol_new adcx140_dapm_ch6_en_switch = |
326 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 2, 1, 0); |
327 | static const struct snd_kcontrol_new adcx140_dapm_ch7_en_switch = |
328 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 1, 1, 0); |
329 | static const struct snd_kcontrol_new adcx140_dapm_ch8_en_switch = |
330 | SOC_DAPM_SINGLE("Switch" , ADCX140_ASI_OUT_CH_EN, 0, 1, 0); |
331 | |
332 | static const struct snd_kcontrol_new adcx140_dapm_ch1_dre_en_switch = |
333 | SOC_DAPM_SINGLE("Switch" , ADCX140_CH1_CFG0, 0, 1, 0); |
334 | static const struct snd_kcontrol_new adcx140_dapm_ch2_dre_en_switch = |
335 | SOC_DAPM_SINGLE("Switch" , ADCX140_CH2_CFG0, 0, 1, 0); |
336 | static const struct snd_kcontrol_new adcx140_dapm_ch3_dre_en_switch = |
337 | SOC_DAPM_SINGLE("Switch" , ADCX140_CH3_CFG0, 0, 1, 0); |
338 | static const struct snd_kcontrol_new adcx140_dapm_ch4_dre_en_switch = |
339 | SOC_DAPM_SINGLE("Switch" , ADCX140_CH4_CFG0, 0, 1, 0); |
340 | |
341 | static const struct snd_kcontrol_new adcx140_dapm_dre_en_switch = |
342 | SOC_DAPM_SINGLE("Switch" , ADCX140_DSP_CFG1, 3, 1, 0); |
343 | |
344 | /* Output Mixer */ |
345 | static const struct snd_kcontrol_new adcx140_output_mixer_controls[] = { |
346 | SOC_DAPM_SINGLE("Digital CH1 Switch" , 0, 0, 0, 0), |
347 | SOC_DAPM_SINGLE("Digital CH2 Switch" , 0, 0, 0, 0), |
348 | SOC_DAPM_SINGLE("Digital CH3 Switch" , 0, 0, 0, 0), |
349 | SOC_DAPM_SINGLE("Digital CH4 Switch" , 0, 0, 0, 0), |
350 | }; |
351 | |
352 | static const struct snd_soc_dapm_widget adcx140_dapm_widgets[] = { |
353 | /* Analog Differential Inputs */ |
354 | SND_SOC_DAPM_INPUT("MIC1P" ), |
355 | SND_SOC_DAPM_INPUT("MIC1M" ), |
356 | SND_SOC_DAPM_INPUT("MIC2P" ), |
357 | SND_SOC_DAPM_INPUT("MIC2M" ), |
358 | SND_SOC_DAPM_INPUT("MIC3P" ), |
359 | SND_SOC_DAPM_INPUT("MIC3M" ), |
360 | SND_SOC_DAPM_INPUT("MIC4P" ), |
361 | SND_SOC_DAPM_INPUT("MIC4M" ), |
362 | |
363 | SND_SOC_DAPM_OUTPUT("CH1_OUT" ), |
364 | SND_SOC_DAPM_OUTPUT("CH2_OUT" ), |
365 | SND_SOC_DAPM_OUTPUT("CH3_OUT" ), |
366 | SND_SOC_DAPM_OUTPUT("CH4_OUT" ), |
367 | SND_SOC_DAPM_OUTPUT("CH5_OUT" ), |
368 | SND_SOC_DAPM_OUTPUT("CH6_OUT" ), |
369 | SND_SOC_DAPM_OUTPUT("CH7_OUT" ), |
370 | SND_SOC_DAPM_OUTPUT("CH8_OUT" ), |
371 | |
372 | SND_SOC_DAPM_MIXER("Output Mixer" , SND_SOC_NOPM, 0, 0, |
373 | &adcx140_output_mixer_controls[0], |
374 | ARRAY_SIZE(adcx140_output_mixer_controls)), |
375 | |
376 | /* Input Selection to MIC_PGA */ |
377 | SND_SOC_DAPM_MUX("MIC1P Input Mux" , SND_SOC_NOPM, 0, 0, |
378 | &adcx140_dapm_mic1p_control), |
379 | SND_SOC_DAPM_MUX("MIC2P Input Mux" , SND_SOC_NOPM, 0, 0, |
380 | &adcx140_dapm_mic2p_control), |
381 | SND_SOC_DAPM_MUX("MIC3P Input Mux" , SND_SOC_NOPM, 0, 0, |
382 | &adcx140_dapm_mic3p_control), |
383 | SND_SOC_DAPM_MUX("MIC4P Input Mux" , SND_SOC_NOPM, 0, 0, |
384 | &adcx140_dapm_mic4p_control), |
385 | |
386 | /* Input Selection to MIC_PGA */ |
387 | SND_SOC_DAPM_MUX("MIC1 Analog Mux" , SND_SOC_NOPM, 0, 0, |
388 | &adcx140_dapm_mic1_analog_control), |
389 | SND_SOC_DAPM_MUX("MIC2 Analog Mux" , SND_SOC_NOPM, 0, 0, |
390 | &adcx140_dapm_mic2_analog_control), |
391 | SND_SOC_DAPM_MUX("MIC3 Analog Mux" , SND_SOC_NOPM, 0, 0, |
392 | &adcx140_dapm_mic3_analog_control), |
393 | SND_SOC_DAPM_MUX("MIC4 Analog Mux" , SND_SOC_NOPM, 0, 0, |
394 | &adcx140_dapm_mic4_analog_control), |
395 | |
396 | SND_SOC_DAPM_MUX("MIC1M Input Mux" , SND_SOC_NOPM, 0, 0, |
397 | &adcx140_dapm_mic1m_control), |
398 | SND_SOC_DAPM_MUX("MIC2M Input Mux" , SND_SOC_NOPM, 0, 0, |
399 | &adcx140_dapm_mic2m_control), |
400 | SND_SOC_DAPM_MUX("MIC3M Input Mux" , SND_SOC_NOPM, 0, 0, |
401 | &adcx140_dapm_mic3m_control), |
402 | SND_SOC_DAPM_MUX("MIC4M Input Mux" , SND_SOC_NOPM, 0, 0, |
403 | &adcx140_dapm_mic4m_control), |
404 | |
405 | SND_SOC_DAPM_PGA("MIC_GAIN_CTL_CH1" , SND_SOC_NOPM, 0, 0, NULL, 0), |
406 | SND_SOC_DAPM_PGA("MIC_GAIN_CTL_CH2" , SND_SOC_NOPM, 0, 0, NULL, 0), |
407 | SND_SOC_DAPM_PGA("MIC_GAIN_CTL_CH3" , SND_SOC_NOPM, 0, 0, NULL, 0), |
408 | SND_SOC_DAPM_PGA("MIC_GAIN_CTL_CH4" , SND_SOC_NOPM, 0, 0, NULL, 0), |
409 | |
410 | SND_SOC_DAPM_ADC("CH1_ADC" , "CH1 Capture" , ADCX140_IN_CH_EN, 7, 0), |
411 | SND_SOC_DAPM_ADC("CH2_ADC" , "CH2 Capture" , ADCX140_IN_CH_EN, 6, 0), |
412 | SND_SOC_DAPM_ADC("CH3_ADC" , "CH3 Capture" , ADCX140_IN_CH_EN, 5, 0), |
413 | SND_SOC_DAPM_ADC("CH4_ADC" , "CH4 Capture" , ADCX140_IN_CH_EN, 4, 0), |
414 | |
415 | SND_SOC_DAPM_ADC("CH1_DIG" , "CH1 Capture" , ADCX140_IN_CH_EN, 7, 0), |
416 | SND_SOC_DAPM_ADC("CH2_DIG" , "CH2 Capture" , ADCX140_IN_CH_EN, 6, 0), |
417 | SND_SOC_DAPM_ADC("CH3_DIG" , "CH3 Capture" , ADCX140_IN_CH_EN, 5, 0), |
418 | SND_SOC_DAPM_ADC("CH4_DIG" , "CH4 Capture" , ADCX140_IN_CH_EN, 4, 0), |
419 | SND_SOC_DAPM_ADC("CH5_DIG" , "CH5 Capture" , ADCX140_IN_CH_EN, 3, 0), |
420 | SND_SOC_DAPM_ADC("CH6_DIG" , "CH6 Capture" , ADCX140_IN_CH_EN, 2, 0), |
421 | SND_SOC_DAPM_ADC("CH7_DIG" , "CH7 Capture" , ADCX140_IN_CH_EN, 1, 0), |
422 | SND_SOC_DAPM_ADC("CH8_DIG" , "CH8 Capture" , ADCX140_IN_CH_EN, 0, 0), |
423 | |
424 | |
425 | SND_SOC_DAPM_SWITCH("CH1_ASI_EN" , SND_SOC_NOPM, 0, 0, |
426 | &adcx140_dapm_ch1_en_switch), |
427 | SND_SOC_DAPM_SWITCH("CH2_ASI_EN" , SND_SOC_NOPM, 0, 0, |
428 | &adcx140_dapm_ch2_en_switch), |
429 | SND_SOC_DAPM_SWITCH("CH3_ASI_EN" , SND_SOC_NOPM, 0, 0, |
430 | &adcx140_dapm_ch3_en_switch), |
431 | SND_SOC_DAPM_SWITCH("CH4_ASI_EN" , SND_SOC_NOPM, 0, 0, |
432 | &adcx140_dapm_ch4_en_switch), |
433 | |
434 | SND_SOC_DAPM_SWITCH("CH5_ASI_EN" , SND_SOC_NOPM, 0, 0, |
435 | &adcx140_dapm_ch5_en_switch), |
436 | SND_SOC_DAPM_SWITCH("CH6_ASI_EN" , SND_SOC_NOPM, 0, 0, |
437 | &adcx140_dapm_ch6_en_switch), |
438 | SND_SOC_DAPM_SWITCH("CH7_ASI_EN" , SND_SOC_NOPM, 0, 0, |
439 | &adcx140_dapm_ch7_en_switch), |
440 | SND_SOC_DAPM_SWITCH("CH8_ASI_EN" , SND_SOC_NOPM, 0, 0, |
441 | &adcx140_dapm_ch8_en_switch), |
442 | |
443 | SND_SOC_DAPM_SWITCH("DRE_ENABLE" , SND_SOC_NOPM, 0, 0, |
444 | &adcx140_dapm_dre_en_switch), |
445 | |
446 | SND_SOC_DAPM_SWITCH("CH1_DRE_EN" , SND_SOC_NOPM, 0, 0, |
447 | &adcx140_dapm_ch1_dre_en_switch), |
448 | SND_SOC_DAPM_SWITCH("CH2_DRE_EN" , SND_SOC_NOPM, 0, 0, |
449 | &adcx140_dapm_ch2_dre_en_switch), |
450 | SND_SOC_DAPM_SWITCH("CH3_DRE_EN" , SND_SOC_NOPM, 0, 0, |
451 | &adcx140_dapm_ch3_dre_en_switch), |
452 | SND_SOC_DAPM_SWITCH("CH4_DRE_EN" , SND_SOC_NOPM, 0, 0, |
453 | &adcx140_dapm_ch4_dre_en_switch), |
454 | |
455 | SND_SOC_DAPM_MUX("IN1 Analog Mic Resistor" , SND_SOC_NOPM, 0, 0, |
456 | in1_resistor_controls), |
457 | SND_SOC_DAPM_MUX("IN2 Analog Mic Resistor" , SND_SOC_NOPM, 0, 0, |
458 | in2_resistor_controls), |
459 | SND_SOC_DAPM_MUX("IN3 Analog Mic Resistor" , SND_SOC_NOPM, 0, 0, |
460 | in3_resistor_controls), |
461 | SND_SOC_DAPM_MUX("IN4 Analog Mic Resistor" , SND_SOC_NOPM, 0, 0, |
462 | in4_resistor_controls), |
463 | |
464 | SND_SOC_DAPM_MUX("PDM Clk Div Select" , SND_SOC_NOPM, 0, 0, |
465 | pdmclk_div_controls), |
466 | |
467 | SND_SOC_DAPM_MUX("Decimation Filter" , SND_SOC_NOPM, 0, 0, |
468 | decimation_filter_controls), |
469 | }; |
470 | |
471 | static const struct snd_soc_dapm_route adcx140_audio_map[] = { |
472 | /* Outputs */ |
473 | {"CH1_OUT" , NULL, "Output Mixer" }, |
474 | {"CH2_OUT" , NULL, "Output Mixer" }, |
475 | {"CH3_OUT" , NULL, "Output Mixer" }, |
476 | {"CH4_OUT" , NULL, "Output Mixer" }, |
477 | |
478 | {"CH1_ASI_EN" , "Switch" , "CH1_ADC" }, |
479 | {"CH2_ASI_EN" , "Switch" , "CH2_ADC" }, |
480 | {"CH3_ASI_EN" , "Switch" , "CH3_ADC" }, |
481 | {"CH4_ASI_EN" , "Switch" , "CH4_ADC" }, |
482 | |
483 | {"CH1_ASI_EN" , "Switch" , "CH1_DIG" }, |
484 | {"CH2_ASI_EN" , "Switch" , "CH2_DIG" }, |
485 | {"CH3_ASI_EN" , "Switch" , "CH3_DIG" }, |
486 | {"CH4_ASI_EN" , "Switch" , "CH4_DIG" }, |
487 | {"CH5_ASI_EN" , "Switch" , "CH5_DIG" }, |
488 | {"CH6_ASI_EN" , "Switch" , "CH6_DIG" }, |
489 | {"CH7_ASI_EN" , "Switch" , "CH7_DIG" }, |
490 | {"CH8_ASI_EN" , "Switch" , "CH8_DIG" }, |
491 | |
492 | {"CH5_ASI_EN" , "Switch" , "CH5_OUT" }, |
493 | {"CH6_ASI_EN" , "Switch" , "CH6_OUT" }, |
494 | {"CH7_ASI_EN" , "Switch" , "CH7_OUT" }, |
495 | {"CH8_ASI_EN" , "Switch" , "CH8_OUT" }, |
496 | |
497 | {"Decimation Filter" , "Linear Phase" , "DRE_ENABLE" }, |
498 | {"Decimation Filter" , "Low Latency" , "DRE_ENABLE" }, |
499 | {"Decimation Filter" , "Ultra-low Latency" , "DRE_ENABLE" }, |
500 | |
501 | {"DRE_ENABLE" , "Switch" , "CH1_DRE_EN" }, |
502 | {"DRE_ENABLE" , "Switch" , "CH2_DRE_EN" }, |
503 | {"DRE_ENABLE" , "Switch" , "CH3_DRE_EN" }, |
504 | {"DRE_ENABLE" , "Switch" , "CH4_DRE_EN" }, |
505 | |
506 | {"CH1_DRE_EN" , "Switch" , "CH1_ADC" }, |
507 | {"CH2_DRE_EN" , "Switch" , "CH2_ADC" }, |
508 | {"CH3_DRE_EN" , "Switch" , "CH3_ADC" }, |
509 | {"CH4_DRE_EN" , "Switch" , "CH4_ADC" }, |
510 | |
511 | /* Mic input */ |
512 | {"CH1_ADC" , NULL, "MIC_GAIN_CTL_CH1" }, |
513 | {"CH2_ADC" , NULL, "MIC_GAIN_CTL_CH2" }, |
514 | {"CH3_ADC" , NULL, "MIC_GAIN_CTL_CH3" }, |
515 | {"CH4_ADC" , NULL, "MIC_GAIN_CTL_CH4" }, |
516 | |
517 | {"MIC_GAIN_CTL_CH1" , NULL, "IN1 Analog Mic Resistor" }, |
518 | {"MIC_GAIN_CTL_CH1" , NULL, "IN1 Analog Mic Resistor" }, |
519 | {"MIC_GAIN_CTL_CH2" , NULL, "IN2 Analog Mic Resistor" }, |
520 | {"MIC_GAIN_CTL_CH2" , NULL, "IN2 Analog Mic Resistor" }, |
521 | {"MIC_GAIN_CTL_CH3" , NULL, "IN3 Analog Mic Resistor" }, |
522 | {"MIC_GAIN_CTL_CH3" , NULL, "IN3 Analog Mic Resistor" }, |
523 | {"MIC_GAIN_CTL_CH4" , NULL, "IN4 Analog Mic Resistor" }, |
524 | {"MIC_GAIN_CTL_CH4" , NULL, "IN4 Analog Mic Resistor" }, |
525 | |
526 | {"IN1 Analog Mic Resistor" , "2.5 kOhm" , "MIC1P Input Mux" }, |
527 | {"IN1 Analog Mic Resistor" , "10 kOhm" , "MIC1P Input Mux" }, |
528 | {"IN1 Analog Mic Resistor" , "20 kOhm" , "MIC1P Input Mux" }, |
529 | |
530 | {"IN1 Analog Mic Resistor" , "2.5 kOhm" , "MIC1M Input Mux" }, |
531 | {"IN1 Analog Mic Resistor" , "10 kOhm" , "MIC1M Input Mux" }, |
532 | {"IN1 Analog Mic Resistor" , "20 kOhm" , "MIC1M Input Mux" }, |
533 | |
534 | {"IN2 Analog Mic Resistor" , "2.5 kOhm" , "MIC2P Input Mux" }, |
535 | {"IN2 Analog Mic Resistor" , "10 kOhm" , "MIC2P Input Mux" }, |
536 | {"IN2 Analog Mic Resistor" , "20 kOhm" , "MIC2P Input Mux" }, |
537 | |
538 | {"IN2 Analog Mic Resistor" , "2.5 kOhm" , "MIC2M Input Mux" }, |
539 | {"IN2 Analog Mic Resistor" , "10 kOhm" , "MIC2M Input Mux" }, |
540 | {"IN2 Analog Mic Resistor" , "20 kOhm" , "MIC2M Input Mux" }, |
541 | |
542 | {"IN3 Analog Mic Resistor" , "2.5 kOhm" , "MIC3P Input Mux" }, |
543 | {"IN3 Analog Mic Resistor" , "10 kOhm" , "MIC3P Input Mux" }, |
544 | {"IN3 Analog Mic Resistor" , "20 kOhm" , "MIC3P Input Mux" }, |
545 | |
546 | {"IN3 Analog Mic Resistor" , "2.5 kOhm" , "MIC3M Input Mux" }, |
547 | {"IN3 Analog Mic Resistor" , "10 kOhm" , "MIC3M Input Mux" }, |
548 | {"IN3 Analog Mic Resistor" , "20 kOhm" , "MIC3M Input Mux" }, |
549 | |
550 | {"IN4 Analog Mic Resistor" , "2.5 kOhm" , "MIC4P Input Mux" }, |
551 | {"IN4 Analog Mic Resistor" , "10 kOhm" , "MIC4P Input Mux" }, |
552 | {"IN4 Analog Mic Resistor" , "20 kOhm" , "MIC4P Input Mux" }, |
553 | |
554 | {"IN4 Analog Mic Resistor" , "2.5 kOhm" , "MIC4M Input Mux" }, |
555 | {"IN4 Analog Mic Resistor" , "10 kOhm" , "MIC4M Input Mux" }, |
556 | {"IN4 Analog Mic Resistor" , "20 kOhm" , "MIC4M Input Mux" }, |
557 | |
558 | {"PDM Clk Div Select" , "2.8224 MHz" , "MIC1P Input Mux" }, |
559 | {"PDM Clk Div Select" , "1.4112 MHz" , "MIC1P Input Mux" }, |
560 | {"PDM Clk Div Select" , "705.6 kHz" , "MIC1P Input Mux" }, |
561 | {"PDM Clk Div Select" , "5.6448 MHz" , "MIC1P Input Mux" }, |
562 | |
563 | {"MIC1P Input Mux" , NULL, "CH1_DIG" }, |
564 | {"MIC1M Input Mux" , NULL, "CH2_DIG" }, |
565 | {"MIC2P Input Mux" , NULL, "CH3_DIG" }, |
566 | {"MIC2M Input Mux" , NULL, "CH4_DIG" }, |
567 | {"MIC3P Input Mux" , NULL, "CH5_DIG" }, |
568 | {"MIC3M Input Mux" , NULL, "CH6_DIG" }, |
569 | {"MIC4P Input Mux" , NULL, "CH7_DIG" }, |
570 | {"MIC4M Input Mux" , NULL, "CH8_DIG" }, |
571 | |
572 | {"MIC1 Analog Mux" , "Line In" , "MIC1P" }, |
573 | {"MIC2 Analog Mux" , "Line In" , "MIC2P" }, |
574 | {"MIC3 Analog Mux" , "Line In" , "MIC3P" }, |
575 | {"MIC4 Analog Mux" , "Line In" , "MIC4P" }, |
576 | |
577 | {"MIC1P Input Mux" , "Analog" , "MIC1P" }, |
578 | {"MIC1M Input Mux" , "Analog" , "MIC1M" }, |
579 | {"MIC2P Input Mux" , "Analog" , "MIC2P" }, |
580 | {"MIC2M Input Mux" , "Analog" , "MIC2M" }, |
581 | {"MIC3P Input Mux" , "Analog" , "MIC3P" }, |
582 | {"MIC3M Input Mux" , "Analog" , "MIC3M" }, |
583 | {"MIC4P Input Mux" , "Analog" , "MIC4P" }, |
584 | {"MIC4M Input Mux" , "Analog" , "MIC4M" }, |
585 | |
586 | {"MIC1P Input Mux" , "Digital" , "MIC1P" }, |
587 | {"MIC1M Input Mux" , "Digital" , "MIC1M" }, |
588 | {"MIC2P Input Mux" , "Digital" , "MIC2P" }, |
589 | {"MIC2M Input Mux" , "Digital" , "MIC2M" }, |
590 | {"MIC3P Input Mux" , "Digital" , "MIC3P" }, |
591 | {"MIC3M Input Mux" , "Digital" , "MIC3M" }, |
592 | {"MIC4P Input Mux" , "Digital" , "MIC4P" }, |
593 | {"MIC4M Input Mux" , "Digital" , "MIC4M" }, |
594 | }; |
595 | |
596 | #define ADCX140_PHASE_CALIB_SWITCH(xname) {\ |
597 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
598 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\ |
599 | .info = adcx140_phase_calib_info, \ |
600 | .get = adcx140_phase_calib_get, \ |
601 | .put = adcx140_phase_calib_put} |
602 | |
603 | static int adcx140_phase_calib_info(struct snd_kcontrol *kcontrol, |
604 | struct snd_ctl_elem_info *uinfo) |
605 | { |
606 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
607 | uinfo->count = 1; |
608 | uinfo->value.integer.min = 0; |
609 | uinfo->value.integer.max = 1; |
610 | return 0; |
611 | } |
612 | |
613 | static int adcx140_phase_calib_get(struct snd_kcontrol *kcontrol, |
614 | struct snd_ctl_elem_value *value) |
615 | { |
616 | struct snd_soc_component *codec = |
617 | snd_soc_kcontrol_component(kcontrol); |
618 | struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(c: codec); |
619 | |
620 | value->value.integer.value[0] = adcx140->phase_calib_on ? 1 : 0; |
621 | |
622 | |
623 | return 0; |
624 | } |
625 | |
626 | static int adcx140_phase_calib_put(struct snd_kcontrol *kcontrol, |
627 | struct snd_ctl_elem_value *value) |
628 | { |
629 | struct snd_soc_component *codec |
630 | = snd_soc_kcontrol_component(kcontrol); |
631 | struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(c: codec); |
632 | |
633 | bool v = value->value.integer.value[0] ? true : false; |
634 | |
635 | if (adcx140->phase_calib_on != v) { |
636 | adcx140->phase_calib_on = v; |
637 | return 1; |
638 | } |
639 | return 0; |
640 | } |
641 | |
642 | static const struct snd_kcontrol_new adcx140_snd_controls[] = { |
643 | SOC_SINGLE_TLV("Analog CH1 Mic Gain Volume" , ADCX140_CH1_CFG1, 2, 42, 0, |
644 | adc_tlv), |
645 | SOC_SINGLE_TLV("Analog CH2 Mic Gain Volume" , ADCX140_CH2_CFG1, 2, 42, 0, |
646 | adc_tlv), |
647 | SOC_SINGLE_TLV("Analog CH3 Mic Gain Volume" , ADCX140_CH3_CFG1, 2, 42, 0, |
648 | adc_tlv), |
649 | SOC_SINGLE_TLV("Analog CH4 Mic Gain Volume" , ADCX140_CH4_CFG1, 2, 42, 0, |
650 | adc_tlv), |
651 | |
652 | SOC_SINGLE_TLV("DRE Threshold" , ADCX140_DRE_CFG0, 4, 9, 0, |
653 | dre_thresh_tlv), |
654 | SOC_SINGLE_TLV("DRE Max Gain" , ADCX140_DRE_CFG0, 0, 12, 0, |
655 | dre_gain_tlv), |
656 | |
657 | SOC_SINGLE_TLV("AGC Threshold" , ADCX140_AGC_CFG0, 4, 15, 0, |
658 | agc_thresh_tlv), |
659 | SOC_SINGLE_TLV("AGC Max Gain" , ADCX140_AGC_CFG0, 0, 13, 0, |
660 | agc_gain_tlv), |
661 | |
662 | SOC_SINGLE_TLV("Digital CH1 Out Volume" , ADCX140_CH1_CFG2, |
663 | 0, 0xff, 0, dig_vol_tlv), |
664 | SOC_SINGLE_TLV("Digital CH2 Out Volume" , ADCX140_CH2_CFG2, |
665 | 0, 0xff, 0, dig_vol_tlv), |
666 | SOC_SINGLE_TLV("Digital CH3 Out Volume" , ADCX140_CH3_CFG2, |
667 | 0, 0xff, 0, dig_vol_tlv), |
668 | SOC_SINGLE_TLV("Digital CH4 Out Volume" , ADCX140_CH4_CFG2, |
669 | 0, 0xff, 0, dig_vol_tlv), |
670 | SOC_SINGLE_TLV("Digital CH5 Out Volume" , ADCX140_CH5_CFG2, |
671 | 0, 0xff, 0, dig_vol_tlv), |
672 | SOC_SINGLE_TLV("Digital CH6 Out Volume" , ADCX140_CH6_CFG2, |
673 | 0, 0xff, 0, dig_vol_tlv), |
674 | SOC_SINGLE_TLV("Digital CH7 Out Volume" , ADCX140_CH7_CFG2, |
675 | 0, 0xff, 0, dig_vol_tlv), |
676 | SOC_SINGLE_TLV("Digital CH8 Out Volume" , ADCX140_CH8_CFG2, |
677 | 0, 0xff, 0, dig_vol_tlv), |
678 | ADCX140_PHASE_CALIB_SWITCH("Phase Calibration Switch" ), |
679 | }; |
680 | |
681 | static int adcx140_reset(struct adcx140_priv *adcx140) |
682 | { |
683 | int ret = 0; |
684 | |
685 | if (adcx140->gpio_reset) { |
686 | gpiod_direction_output(desc: adcx140->gpio_reset, value: 0); |
687 | /* 8.4.1: wait for hw shutdown (25ms) + >= 1ms */ |
688 | usleep_range(min: 30000, max: 100000); |
689 | gpiod_direction_output(desc: adcx140->gpio_reset, value: 1); |
690 | } else { |
691 | ret = regmap_write(map: adcx140->regmap, ADCX140_SW_RESET, |
692 | ADCX140_RESET); |
693 | } |
694 | |
695 | /* 8.4.2: wait >= 10 ms after entering sleep mode. */ |
696 | usleep_range(min: 10000, max: 100000); |
697 | |
698 | return ret; |
699 | } |
700 | |
701 | static void adcx140_pwr_ctrl(struct adcx140_priv *adcx140, bool power_state) |
702 | { |
703 | int pwr_ctrl = 0; |
704 | int ret = 0; |
705 | struct snd_soc_component *component = adcx140->component; |
706 | |
707 | if (power_state) |
708 | pwr_ctrl = ADCX140_PWR_CFG_ADC_PDZ | ADCX140_PWR_CFG_PLL_PDZ; |
709 | |
710 | if (adcx140->micbias_vg && power_state) |
711 | pwr_ctrl |= ADCX140_PWR_CFG_BIAS_PDZ; |
712 | |
713 | if (pwr_ctrl) { |
714 | ret = regmap_write(map: adcx140->regmap, ADCX140_PHASE_CALIB, |
715 | val: adcx140->phase_calib_on ? 0x00 : 0x40); |
716 | if (ret) |
717 | dev_err(component->dev, "%s: register write error %d\n" , |
718 | __func__, ret); |
719 | } |
720 | |
721 | regmap_update_bits(map: adcx140->regmap, ADCX140_PWR_CFG, |
722 | ADCX140_PWR_CTRL_MSK, val: pwr_ctrl); |
723 | } |
724 | |
725 | static int adcx140_hw_params(struct snd_pcm_substream *substream, |
726 | struct snd_pcm_hw_params *params, |
727 | struct snd_soc_dai *dai) |
728 | { |
729 | struct snd_soc_component *component = dai->component; |
730 | struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(c: component); |
731 | u8 data = 0; |
732 | |
733 | switch (params_width(p: params)) { |
734 | case 16: |
735 | data = ADCX140_16_BIT_WORD; |
736 | break; |
737 | case 20: |
738 | data = ADCX140_20_BIT_WORD; |
739 | break; |
740 | case 24: |
741 | data = ADCX140_24_BIT_WORD; |
742 | break; |
743 | case 32: |
744 | data = ADCX140_32_BIT_WORD; |
745 | break; |
746 | default: |
747 | dev_err(component->dev, "%s: Unsupported width %d\n" , |
748 | __func__, params_width(params)); |
749 | return -EINVAL; |
750 | } |
751 | |
752 | adcx140_pwr_ctrl(adcx140, power_state: false); |
753 | |
754 | snd_soc_component_update_bits(component, ADCX140_ASI_CFG0, |
755 | ADCX140_WORD_LEN_MSK, val: data); |
756 | |
757 | adcx140_pwr_ctrl(adcx140, power_state: true); |
758 | |
759 | return 0; |
760 | } |
761 | |
762 | static int adcx140_set_dai_fmt(struct snd_soc_dai *codec_dai, |
763 | unsigned int fmt) |
764 | { |
765 | struct snd_soc_component *component = codec_dai->component; |
766 | struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(c: component); |
767 | u8 iface_reg1 = 0; |
768 | u8 iface_reg2 = 0; |
769 | int offset = 0; |
770 | bool inverted_bclk = false; |
771 | |
772 | /* set master/slave audio interface */ |
773 | switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { |
774 | case SND_SOC_DAIFMT_CBP_CFP: |
775 | iface_reg2 |= ADCX140_BCLK_FSYNC_MASTER; |
776 | break; |
777 | case SND_SOC_DAIFMT_CBC_CFC: |
778 | break; |
779 | default: |
780 | dev_err(component->dev, "Invalid DAI clock provider\n" ); |
781 | return -EINVAL; |
782 | } |
783 | |
784 | /* interface format */ |
785 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
786 | case SND_SOC_DAIFMT_I2S: |
787 | iface_reg1 |= ADCX140_I2S_MODE_BIT; |
788 | break; |
789 | case SND_SOC_DAIFMT_LEFT_J: |
790 | iface_reg1 |= ADCX140_LEFT_JUST_BIT; |
791 | break; |
792 | case SND_SOC_DAIFMT_DSP_A: |
793 | offset = 1; |
794 | inverted_bclk = true; |
795 | break; |
796 | case SND_SOC_DAIFMT_DSP_B: |
797 | inverted_bclk = true; |
798 | break; |
799 | default: |
800 | dev_err(component->dev, "Invalid DAI interface format\n" ); |
801 | return -EINVAL; |
802 | } |
803 | |
804 | /* signal polarity */ |
805 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
806 | case SND_SOC_DAIFMT_IB_NF: |
807 | case SND_SOC_DAIFMT_IB_IF: |
808 | inverted_bclk = !inverted_bclk; |
809 | break; |
810 | case SND_SOC_DAIFMT_NB_IF: |
811 | iface_reg1 |= ADCX140_FSYNCINV_BIT; |
812 | break; |
813 | case SND_SOC_DAIFMT_NB_NF: |
814 | break; |
815 | default: |
816 | dev_err(component->dev, "Invalid DAI clock signal polarity\n" ); |
817 | return -EINVAL; |
818 | } |
819 | |
820 | if (inverted_bclk) |
821 | iface_reg1 |= ADCX140_BCLKINV_BIT; |
822 | |
823 | adcx140->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; |
824 | |
825 | adcx140_pwr_ctrl(adcx140, power_state: false); |
826 | |
827 | snd_soc_component_update_bits(component, ADCX140_ASI_CFG0, |
828 | ADCX140_FSYNCINV_BIT | |
829 | ADCX140_BCLKINV_BIT | |
830 | ADCX140_ASI_FORMAT_MSK, |
831 | val: iface_reg1); |
832 | snd_soc_component_update_bits(component, ADCX140_MST_CFG0, |
833 | ADCX140_BCLK_FSYNC_MASTER, val: iface_reg2); |
834 | |
835 | /* Configure data offset */ |
836 | snd_soc_component_update_bits(component, ADCX140_ASI_CFG1, |
837 | ADCX140_TX_OFFSET_MASK, val: offset); |
838 | |
839 | adcx140_pwr_ctrl(adcx140, power_state: true); |
840 | |
841 | return 0; |
842 | } |
843 | |
844 | static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai, |
845 | unsigned int tx_mask, unsigned int rx_mask, |
846 | int slots, int slot_width) |
847 | { |
848 | struct snd_soc_component *component = codec_dai->component; |
849 | struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(c: component); |
850 | |
851 | /* |
852 | * The chip itself supports arbitrary masks, but the driver currently |
853 | * only supports adjacent slots beginning at the first slot. |
854 | */ |
855 | if (tx_mask != GENMASK(__fls(tx_mask), 0)) { |
856 | dev_err(component->dev, "Only lower adjacent slots are supported\n" ); |
857 | return -EINVAL; |
858 | } |
859 | |
860 | switch (slot_width) { |
861 | case 16: |
862 | case 20: |
863 | case 24: |
864 | case 32: |
865 | break; |
866 | default: |
867 | dev_err(component->dev, "Unsupported slot width %d\n" , slot_width); |
868 | return -EINVAL; |
869 | } |
870 | |
871 | adcx140->slot_width = slot_width; |
872 | |
873 | return 0; |
874 | } |
875 | |
876 | static const struct snd_soc_dai_ops adcx140_dai_ops = { |
877 | .hw_params = adcx140_hw_params, |
878 | .set_fmt = adcx140_set_dai_fmt, |
879 | .set_tdm_slot = adcx140_set_dai_tdm_slot, |
880 | }; |
881 | |
882 | static int adcx140_configure_gpo(struct adcx140_priv *adcx140) |
883 | { |
884 | u32 gpo_outputs[ADCX140_NUM_GPOS]; |
885 | u32 gpo_output_val = 0; |
886 | int ret; |
887 | int i; |
888 | |
889 | for (i = 0; i < ADCX140_NUM_GPOS; i++) { |
890 | ret = device_property_read_u32_array(dev: adcx140->dev, |
891 | propname: gpo_config_names[i], |
892 | val: gpo_outputs, |
893 | ADCX140_NUM_GPO_CFGS); |
894 | if (ret) |
895 | continue; |
896 | |
897 | if (gpo_outputs[0] > ADCX140_GPO_CFG_MAX) { |
898 | dev_err(adcx140->dev, "GPO%d config out of range\n" , i + 1); |
899 | return -EINVAL; |
900 | } |
901 | |
902 | if (gpo_outputs[1] > ADCX140_GPO_DRV_MAX) { |
903 | dev_err(adcx140->dev, "GPO%d drive out of range\n" , i + 1); |
904 | return -EINVAL; |
905 | } |
906 | |
907 | gpo_output_val = gpo_outputs[0] << ADCX140_GPO_SHIFT | |
908 | gpo_outputs[1]; |
909 | ret = regmap_write(map: adcx140->regmap, ADCX140_GPO_CFG0 + i, |
910 | val: gpo_output_val); |
911 | if (ret) |
912 | return ret; |
913 | } |
914 | |
915 | return 0; |
916 | |
917 | } |
918 | |
919 | static int adcx140_configure_gpio(struct adcx140_priv *adcx140) |
920 | { |
921 | int gpio_count = 0; |
922 | u32 gpio_outputs[ADCX140_NUM_GPIO_CFGS]; |
923 | u32 gpio_output_val = 0; |
924 | int ret; |
925 | |
926 | gpio_count = device_property_count_u32(dev: adcx140->dev, |
927 | propname: "ti,gpio-config" ); |
928 | if (gpio_count <= 0) |
929 | return 0; |
930 | |
931 | if (gpio_count != ADCX140_NUM_GPIO_CFGS) |
932 | return -EINVAL; |
933 | |
934 | ret = device_property_read_u32_array(dev: adcx140->dev, propname: "ti,gpio-config" , |
935 | val: gpio_outputs, nval: gpio_count); |
936 | if (ret) |
937 | return ret; |
938 | |
939 | if (gpio_outputs[0] > ADCX140_GPIO_CFG_MAX) { |
940 | dev_err(adcx140->dev, "GPIO config out of range\n" ); |
941 | return -EINVAL; |
942 | } |
943 | |
944 | if (gpio_outputs[1] > ADCX140_GPIO_DRV_MAX) { |
945 | dev_err(adcx140->dev, "GPIO drive out of range\n" ); |
946 | return -EINVAL; |
947 | } |
948 | |
949 | gpio_output_val = gpio_outputs[0] << ADCX140_GPIO_SHIFT |
950 | | gpio_outputs[1]; |
951 | |
952 | return regmap_write(map: adcx140->regmap, ADCX140_GPIO_CFG0, val: gpio_output_val); |
953 | } |
954 | |
955 | static int adcx140_codec_probe(struct snd_soc_component *component) |
956 | { |
957 | struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(c: component); |
958 | int sleep_cfg_val = ADCX140_WAKE_DEV; |
959 | u32 bias_source; |
960 | u32 vref_source; |
961 | u8 bias_cfg; |
962 | int pdm_count; |
963 | u32 pdm_edges[ADCX140_NUM_PDM_EDGES]; |
964 | u32 pdm_edge_val = 0; |
965 | int gpi_count; |
966 | u32 gpi_inputs[ADCX140_NUM_GPI_PINS]; |
967 | u32 gpi_input_val = 0; |
968 | int i; |
969 | int ret; |
970 | bool tx_high_z; |
971 | |
972 | ret = device_property_read_u32(dev: adcx140->dev, propname: "ti,mic-bias-source" , |
973 | val: &bias_source); |
974 | if (ret || bias_source > ADCX140_MIC_BIAS_VAL_AVDD) { |
975 | bias_source = ADCX140_MIC_BIAS_VAL_VREF; |
976 | adcx140->micbias_vg = false; |
977 | } else { |
978 | adcx140->micbias_vg = true; |
979 | } |
980 | |
981 | ret = device_property_read_u32(dev: adcx140->dev, propname: "ti,vref-source" , |
982 | val: &vref_source); |
983 | if (ret) |
984 | vref_source = ADCX140_MIC_BIAS_VREF_275V; |
985 | |
986 | if (vref_source > ADCX140_MIC_BIAS_VREF_1375V) { |
987 | dev_err(adcx140->dev, "Mic Bias source value is invalid\n" ); |
988 | return -EINVAL; |
989 | } |
990 | |
991 | bias_cfg = bias_source << ADCX140_MIC_BIAS_SHIFT | vref_source; |
992 | |
993 | ret = adcx140_reset(adcx140); |
994 | if (ret) |
995 | goto out; |
996 | |
997 | if (adcx140->supply_areg == NULL) |
998 | sleep_cfg_val |= ADCX140_AREG_INTERNAL; |
999 | |
1000 | ret = regmap_write(map: adcx140->regmap, ADCX140_SLEEP_CFG, val: sleep_cfg_val); |
1001 | if (ret) { |
1002 | dev_err(adcx140->dev, "setting sleep config failed %d\n" , ret); |
1003 | goto out; |
1004 | } |
1005 | |
1006 | /* 8.4.3: Wait >= 1ms after entering active mode. */ |
1007 | usleep_range(min: 1000, max: 100000); |
1008 | |
1009 | pdm_count = device_property_count_u32(dev: adcx140->dev, |
1010 | propname: "ti,pdm-edge-select" ); |
1011 | if (pdm_count <= ADCX140_NUM_PDM_EDGES && pdm_count > 0) { |
1012 | ret = device_property_read_u32_array(dev: adcx140->dev, |
1013 | propname: "ti,pdm-edge-select" , |
1014 | val: pdm_edges, nval: pdm_count); |
1015 | if (ret) |
1016 | return ret; |
1017 | |
1018 | for (i = 0; i < pdm_count; i++) |
1019 | pdm_edge_val |= pdm_edges[i] << (ADCX140_PDM_EDGE_SHIFT - i); |
1020 | |
1021 | ret = regmap_write(map: adcx140->regmap, ADCX140_PDM_CFG, |
1022 | val: pdm_edge_val); |
1023 | if (ret) |
1024 | return ret; |
1025 | } |
1026 | |
1027 | gpi_count = device_property_count_u32(dev: adcx140->dev, propname: "ti,gpi-config" ); |
1028 | if (gpi_count <= ADCX140_NUM_GPI_PINS && gpi_count > 0) { |
1029 | ret = device_property_read_u32_array(dev: adcx140->dev, |
1030 | propname: "ti,gpi-config" , |
1031 | val: gpi_inputs, nval: gpi_count); |
1032 | if (ret) |
1033 | return ret; |
1034 | |
1035 | gpi_input_val = gpi_inputs[ADCX140_GPI1_INDEX] << ADCX140_GPI_SHIFT | |
1036 | gpi_inputs[ADCX140_GPI2_INDEX]; |
1037 | |
1038 | ret = regmap_write(map: adcx140->regmap, ADCX140_GPI_CFG0, |
1039 | val: gpi_input_val); |
1040 | if (ret) |
1041 | return ret; |
1042 | |
1043 | gpi_input_val = gpi_inputs[ADCX140_GPI3_INDEX] << ADCX140_GPI_SHIFT | |
1044 | gpi_inputs[ADCX140_GPI4_INDEX]; |
1045 | |
1046 | ret = regmap_write(map: adcx140->regmap, ADCX140_GPI_CFG1, |
1047 | val: gpi_input_val); |
1048 | if (ret) |
1049 | return ret; |
1050 | } |
1051 | |
1052 | ret = adcx140_configure_gpio(adcx140); |
1053 | if (ret) |
1054 | return ret; |
1055 | |
1056 | ret = adcx140_configure_gpo(adcx140); |
1057 | if (ret) |
1058 | goto out; |
1059 | |
1060 | ret = regmap_update_bits(map: adcx140->regmap, ADCX140_BIAS_CFG, |
1061 | ADCX140_MIC_BIAS_VAL_MSK | |
1062 | ADCX140_MIC_BIAS_VREF_MSK, val: bias_cfg); |
1063 | if (ret) |
1064 | dev_err(adcx140->dev, "setting MIC bias failed %d\n" , ret); |
1065 | |
1066 | tx_high_z = device_property_read_bool(dev: adcx140->dev, propname: "ti,asi-tx-drive" ); |
1067 | if (tx_high_z) { |
1068 | ret = regmap_update_bits(map: adcx140->regmap, ADCX140_ASI_CFG0, |
1069 | ADCX140_TX_FILL, ADCX140_TX_FILL); |
1070 | if (ret) { |
1071 | dev_err(adcx140->dev, "Setting Tx drive failed %d\n" , ret); |
1072 | goto out; |
1073 | } |
1074 | } |
1075 | |
1076 | adcx140_pwr_ctrl(adcx140, power_state: true); |
1077 | out: |
1078 | return ret; |
1079 | } |
1080 | |
1081 | static int adcx140_set_bias_level(struct snd_soc_component *component, |
1082 | enum snd_soc_bias_level level) |
1083 | { |
1084 | struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(c: component); |
1085 | |
1086 | switch (level) { |
1087 | case SND_SOC_BIAS_ON: |
1088 | case SND_SOC_BIAS_PREPARE: |
1089 | case SND_SOC_BIAS_STANDBY: |
1090 | adcx140_pwr_ctrl(adcx140, power_state: true); |
1091 | break; |
1092 | case SND_SOC_BIAS_OFF: |
1093 | adcx140_pwr_ctrl(adcx140, power_state: false); |
1094 | break; |
1095 | } |
1096 | |
1097 | return 0; |
1098 | } |
1099 | |
1100 | static const struct snd_soc_component_driver soc_codec_driver_adcx140 = { |
1101 | .probe = adcx140_codec_probe, |
1102 | .set_bias_level = adcx140_set_bias_level, |
1103 | .controls = adcx140_snd_controls, |
1104 | .num_controls = ARRAY_SIZE(adcx140_snd_controls), |
1105 | .dapm_widgets = adcx140_dapm_widgets, |
1106 | .num_dapm_widgets = ARRAY_SIZE(adcx140_dapm_widgets), |
1107 | .dapm_routes = adcx140_audio_map, |
1108 | .num_dapm_routes = ARRAY_SIZE(adcx140_audio_map), |
1109 | .suspend_bias_off = 1, |
1110 | .idle_bias_on = 0, |
1111 | .use_pmdown_time = 1, |
1112 | .endianness = 1, |
1113 | }; |
1114 | |
1115 | static struct snd_soc_dai_driver adcx140_dai_driver[] = { |
1116 | { |
1117 | .name = "tlv320adcx140-codec" , |
1118 | .capture = { |
1119 | .stream_name = "Capture" , |
1120 | .channels_min = 2, |
1121 | .channels_max = ADCX140_MAX_CHANNELS, |
1122 | .rates = ADCX140_RATES, |
1123 | .formats = ADCX140_FORMATS, |
1124 | }, |
1125 | .ops = &adcx140_dai_ops, |
1126 | .symmetric_rate = 1, |
1127 | } |
1128 | }; |
1129 | |
1130 | #ifdef CONFIG_OF |
1131 | static const struct of_device_id tlv320adcx140_of_match[] = { |
1132 | { .compatible = "ti,tlv320adc3140" }, |
1133 | { .compatible = "ti,tlv320adc5140" }, |
1134 | { .compatible = "ti,tlv320adc6140" }, |
1135 | {}, |
1136 | }; |
1137 | MODULE_DEVICE_TABLE(of, tlv320adcx140_of_match); |
1138 | #endif |
1139 | |
1140 | static void adcx140_disable_regulator(void *arg) |
1141 | { |
1142 | struct adcx140_priv *adcx140 = arg; |
1143 | |
1144 | regulator_disable(regulator: adcx140->supply_areg); |
1145 | } |
1146 | |
1147 | static int adcx140_i2c_probe(struct i2c_client *i2c) |
1148 | { |
1149 | struct adcx140_priv *adcx140; |
1150 | int ret; |
1151 | |
1152 | adcx140 = devm_kzalloc(dev: &i2c->dev, size: sizeof(*adcx140), GFP_KERNEL); |
1153 | if (!adcx140) |
1154 | return -ENOMEM; |
1155 | |
1156 | adcx140->phase_calib_on = false; |
1157 | adcx140->dev = &i2c->dev; |
1158 | |
1159 | adcx140->gpio_reset = devm_gpiod_get_optional(dev: adcx140->dev, |
1160 | con_id: "reset" , flags: GPIOD_OUT_LOW); |
1161 | if (IS_ERR(ptr: adcx140->gpio_reset)) |
1162 | dev_info(&i2c->dev, "Reset GPIO not defined\n" ); |
1163 | |
1164 | adcx140->supply_areg = devm_regulator_get_optional(dev: adcx140->dev, |
1165 | id: "areg" ); |
1166 | if (IS_ERR(ptr: adcx140->supply_areg)) { |
1167 | if (PTR_ERR(ptr: adcx140->supply_areg) == -EPROBE_DEFER) |
1168 | return -EPROBE_DEFER; |
1169 | |
1170 | adcx140->supply_areg = NULL; |
1171 | } else { |
1172 | ret = regulator_enable(regulator: adcx140->supply_areg); |
1173 | if (ret) { |
1174 | dev_err(adcx140->dev, "Failed to enable areg\n" ); |
1175 | return ret; |
1176 | } |
1177 | |
1178 | ret = devm_add_action_or_reset(&i2c->dev, adcx140_disable_regulator, adcx140); |
1179 | if (ret) |
1180 | return ret; |
1181 | } |
1182 | |
1183 | adcx140->regmap = devm_regmap_init_i2c(i2c, &adcx140_i2c_regmap); |
1184 | if (IS_ERR(ptr: adcx140->regmap)) { |
1185 | ret = PTR_ERR(ptr: adcx140->regmap); |
1186 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n" , |
1187 | ret); |
1188 | return ret; |
1189 | } |
1190 | |
1191 | i2c_set_clientdata(client: i2c, data: adcx140); |
1192 | |
1193 | return devm_snd_soc_register_component(dev: &i2c->dev, |
1194 | component_driver: &soc_codec_driver_adcx140, |
1195 | dai_drv: adcx140_dai_driver, num_dai: 1); |
1196 | } |
1197 | |
1198 | static const struct i2c_device_id adcx140_i2c_id[] = { |
1199 | { "tlv320adc3140" , 0 }, |
1200 | { "tlv320adc5140" , 1 }, |
1201 | { "tlv320adc6140" , 2 }, |
1202 | {} |
1203 | }; |
1204 | MODULE_DEVICE_TABLE(i2c, adcx140_i2c_id); |
1205 | |
1206 | static struct i2c_driver adcx140_i2c_driver = { |
1207 | .driver = { |
1208 | .name = "tlv320adcx140-codec" , |
1209 | .of_match_table = of_match_ptr(tlv320adcx140_of_match), |
1210 | }, |
1211 | .probe = adcx140_i2c_probe, |
1212 | .id_table = adcx140_i2c_id, |
1213 | }; |
1214 | module_i2c_driver(adcx140_i2c_driver); |
1215 | |
1216 | MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>" ); |
1217 | MODULE_DESCRIPTION("ASoC TLV320ADCX140 CODEC Driver" ); |
1218 | MODULE_LICENSE("GPL v2" ); |
1219 | |