1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // tscs42xx.c -- TSCS42xx ALSA SoC Audio driver |
3 | // Copyright 2017 Tempo Semiconductor, Inc. |
4 | // Author: Steven Eckhoff <steven.eckhoff.opensource@gmail.com> |
5 | |
6 | #include <linux/kernel.h> |
7 | #include <linux/device.h> |
8 | #include <linux/regmap.h> |
9 | #include <linux/i2c.h> |
10 | #include <linux/err.h> |
11 | #include <linux/string.h> |
12 | #include <linux/module.h> |
13 | #include <linux/delay.h> |
14 | #include <linux/mutex.h> |
15 | #include <linux/clk.h> |
16 | #include <sound/tlv.h> |
17 | #include <sound/pcm_params.h> |
18 | #include <sound/soc.h> |
19 | #include <sound/soc-dapm.h> |
20 | |
21 | #include "tscs42xx.h" |
22 | |
23 | #define COEFF_SIZE 3 |
24 | #define BIQUAD_COEFF_COUNT 5 |
25 | #define BIQUAD_SIZE (COEFF_SIZE * BIQUAD_COEFF_COUNT) |
26 | |
27 | #define COEFF_RAM_MAX_ADDR 0xcd |
28 | #define COEFF_RAM_COEFF_COUNT (COEFF_RAM_MAX_ADDR + 1) |
29 | #define COEFF_RAM_SIZE (COEFF_SIZE * COEFF_RAM_COEFF_COUNT) |
30 | |
31 | struct tscs42xx { |
32 | |
33 | int bclk_ratio; |
34 | int samplerate; |
35 | struct mutex audio_params_lock; |
36 | |
37 | u8 coeff_ram[COEFF_RAM_SIZE]; |
38 | bool coeff_ram_synced; |
39 | struct mutex coeff_ram_lock; |
40 | |
41 | struct mutex pll_lock; |
42 | |
43 | struct regmap *regmap; |
44 | |
45 | struct clk *sysclk; |
46 | int sysclk_src_id; |
47 | }; |
48 | |
49 | struct coeff_ram_ctl { |
50 | unsigned int addr; |
51 | struct soc_bytes_ext bytes_ext; |
52 | }; |
53 | |
54 | static bool tscs42xx_volatile(struct device *dev, unsigned int reg) |
55 | { |
56 | switch (reg) { |
57 | case R_DACCRWRL: |
58 | case R_DACCRWRM: |
59 | case R_DACCRWRH: |
60 | case R_DACCRRDL: |
61 | case R_DACCRRDM: |
62 | case R_DACCRRDH: |
63 | case R_DACCRSTAT: |
64 | case R_DACCRADDR: |
65 | case R_PLLCTL0: |
66 | return true; |
67 | default: |
68 | return false; |
69 | } |
70 | } |
71 | |
72 | static bool tscs42xx_precious(struct device *dev, unsigned int reg) |
73 | { |
74 | switch (reg) { |
75 | case R_DACCRWRL: |
76 | case R_DACCRWRM: |
77 | case R_DACCRWRH: |
78 | case R_DACCRRDL: |
79 | case R_DACCRRDM: |
80 | case R_DACCRRDH: |
81 | return true; |
82 | default: |
83 | return false; |
84 | } |
85 | } |
86 | |
87 | static const struct regmap_config tscs42xx_regmap = { |
88 | .reg_bits = 8, |
89 | .val_bits = 8, |
90 | |
91 | .volatile_reg = tscs42xx_volatile, |
92 | .precious_reg = tscs42xx_precious, |
93 | .max_register = R_DACMBCREL3H, |
94 | |
95 | .cache_type = REGCACHE_RBTREE, |
96 | .can_multi_write = true, |
97 | }; |
98 | |
99 | #define MAX_PLL_LOCK_20MS_WAITS 1 |
100 | static bool plls_locked(struct snd_soc_component *component) |
101 | { |
102 | int ret; |
103 | int count = MAX_PLL_LOCK_20MS_WAITS; |
104 | |
105 | do { |
106 | ret = snd_soc_component_read(component, R_PLLCTL0); |
107 | if (ret < 0) { |
108 | dev_err(component->dev, |
109 | "Failed to read PLL lock status (%d)\n" , ret); |
110 | return false; |
111 | } else if (ret > 0) { |
112 | return true; |
113 | } |
114 | msleep(msecs: 20); |
115 | } while (count--); |
116 | |
117 | return false; |
118 | } |
119 | |
120 | static int sample_rate_to_pll_freq_out(int sample_rate) |
121 | { |
122 | switch (sample_rate) { |
123 | case 11025: |
124 | case 22050: |
125 | case 44100: |
126 | case 88200: |
127 | return 112896000; |
128 | case 8000: |
129 | case 16000: |
130 | case 32000: |
131 | case 48000: |
132 | case 96000: |
133 | return 122880000; |
134 | default: |
135 | return -EINVAL; |
136 | } |
137 | } |
138 | |
139 | #define DACCRSTAT_MAX_TRYS 10 |
140 | static int write_coeff_ram(struct snd_soc_component *component, u8 *coeff_ram, |
141 | unsigned int addr, unsigned int coeff_cnt) |
142 | { |
143 | struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(c: component); |
144 | int cnt; |
145 | int trys; |
146 | int ret; |
147 | |
148 | for (cnt = 0; cnt < coeff_cnt; cnt++, addr++) { |
149 | |
150 | for (trys = 0; trys < DACCRSTAT_MAX_TRYS; trys++) { |
151 | ret = snd_soc_component_read(component, R_DACCRSTAT); |
152 | if (ret < 0) { |
153 | dev_err(component->dev, |
154 | "Failed to read stat (%d)\n" , ret); |
155 | return ret; |
156 | } |
157 | if (!ret) |
158 | break; |
159 | } |
160 | |
161 | if (trys == DACCRSTAT_MAX_TRYS) { |
162 | ret = -EIO; |
163 | dev_err(component->dev, |
164 | "dac coefficient write error (%d)\n" , ret); |
165 | return ret; |
166 | } |
167 | |
168 | ret = regmap_write(map: tscs42xx->regmap, R_DACCRADDR, val: addr); |
169 | if (ret < 0) { |
170 | dev_err(component->dev, |
171 | "Failed to write dac ram address (%d)\n" , ret); |
172 | return ret; |
173 | } |
174 | |
175 | ret = regmap_bulk_write(map: tscs42xx->regmap, R_DACCRWRL, |
176 | val: &coeff_ram[addr * COEFF_SIZE], |
177 | COEFF_SIZE); |
178 | if (ret < 0) { |
179 | dev_err(component->dev, |
180 | "Failed to write dac ram (%d)\n" , ret); |
181 | return ret; |
182 | } |
183 | } |
184 | |
185 | return 0; |
186 | } |
187 | |
188 | static int power_up_audio_plls(struct snd_soc_component *component) |
189 | { |
190 | struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(c: component); |
191 | int freq_out; |
192 | int ret; |
193 | unsigned int mask; |
194 | unsigned int val; |
195 | |
196 | freq_out = sample_rate_to_pll_freq_out(sample_rate: tscs42xx->samplerate); |
197 | switch (freq_out) { |
198 | case 122880000: /* 48k */ |
199 | mask = RM_PLLCTL1C_PDB_PLL1; |
200 | val = RV_PLLCTL1C_PDB_PLL1_ENABLE; |
201 | break; |
202 | case 112896000: /* 44.1k */ |
203 | mask = RM_PLLCTL1C_PDB_PLL2; |
204 | val = RV_PLLCTL1C_PDB_PLL2_ENABLE; |
205 | break; |
206 | default: |
207 | ret = -EINVAL; |
208 | dev_err(component->dev, |
209 | "Unrecognized PLL output freq (%d)\n" , ret); |
210 | return ret; |
211 | } |
212 | |
213 | mutex_lock(&tscs42xx->pll_lock); |
214 | |
215 | ret = snd_soc_component_update_bits(component, R_PLLCTL1C, mask, val); |
216 | if (ret < 0) { |
217 | dev_err(component->dev, "Failed to turn PLL on (%d)\n" , ret); |
218 | goto exit; |
219 | } |
220 | |
221 | if (!plls_locked(component)) { |
222 | dev_err(component->dev, "Failed to lock plls\n" ); |
223 | ret = -ENOMSG; |
224 | goto exit; |
225 | } |
226 | |
227 | ret = 0; |
228 | exit: |
229 | mutex_unlock(lock: &tscs42xx->pll_lock); |
230 | |
231 | return ret; |
232 | } |
233 | |
234 | static int power_down_audio_plls(struct snd_soc_component *component) |
235 | { |
236 | struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(c: component); |
237 | int ret; |
238 | |
239 | mutex_lock(&tscs42xx->pll_lock); |
240 | |
241 | ret = snd_soc_component_update_bits(component, R_PLLCTL1C, |
242 | RM_PLLCTL1C_PDB_PLL1, |
243 | RV_PLLCTL1C_PDB_PLL1_DISABLE); |
244 | if (ret < 0) { |
245 | dev_err(component->dev, "Failed to turn PLL off (%d)\n" , ret); |
246 | goto exit; |
247 | } |
248 | ret = snd_soc_component_update_bits(component, R_PLLCTL1C, |
249 | RM_PLLCTL1C_PDB_PLL2, |
250 | RV_PLLCTL1C_PDB_PLL2_DISABLE); |
251 | if (ret < 0) { |
252 | dev_err(component->dev, "Failed to turn PLL off (%d)\n" , ret); |
253 | goto exit; |
254 | } |
255 | |
256 | ret = 0; |
257 | exit: |
258 | mutex_unlock(lock: &tscs42xx->pll_lock); |
259 | |
260 | return ret; |
261 | } |
262 | |
263 | static int coeff_ram_get(struct snd_kcontrol *kcontrol, |
264 | struct snd_ctl_elem_value *ucontrol) |
265 | { |
266 | struct snd_soc_component *component = |
267 | snd_soc_kcontrol_component(kcontrol); |
268 | struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(c: component); |
269 | struct coeff_ram_ctl *ctl = |
270 | (struct coeff_ram_ctl *)kcontrol->private_value; |
271 | struct soc_bytes_ext *params = &ctl->bytes_ext; |
272 | |
273 | mutex_lock(&tscs42xx->coeff_ram_lock); |
274 | |
275 | memcpy(ucontrol->value.bytes.data, |
276 | &tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE], params->max); |
277 | |
278 | mutex_unlock(lock: &tscs42xx->coeff_ram_lock); |
279 | |
280 | return 0; |
281 | } |
282 | |
283 | static int coeff_ram_put(struct snd_kcontrol *kcontrol, |
284 | struct snd_ctl_elem_value *ucontrol) |
285 | { |
286 | struct snd_soc_component *component = |
287 | snd_soc_kcontrol_component(kcontrol); |
288 | struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(c: component); |
289 | struct coeff_ram_ctl *ctl = |
290 | (struct coeff_ram_ctl *)kcontrol->private_value; |
291 | struct soc_bytes_ext *params = &ctl->bytes_ext; |
292 | unsigned int coeff_cnt = params->max / COEFF_SIZE; |
293 | int ret; |
294 | |
295 | mutex_lock(&tscs42xx->coeff_ram_lock); |
296 | |
297 | tscs42xx->coeff_ram_synced = false; |
298 | |
299 | memcpy(&tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE], |
300 | ucontrol->value.bytes.data, params->max); |
301 | |
302 | mutex_lock(&tscs42xx->pll_lock); |
303 | |
304 | if (plls_locked(component)) { |
305 | ret = write_coeff_ram(component, coeff_ram: tscs42xx->coeff_ram, |
306 | addr: ctl->addr, coeff_cnt); |
307 | if (ret < 0) { |
308 | dev_err(component->dev, |
309 | "Failed to flush coeff ram cache (%d)\n" , ret); |
310 | goto exit; |
311 | } |
312 | tscs42xx->coeff_ram_synced = true; |
313 | } |
314 | |
315 | ret = 0; |
316 | exit: |
317 | mutex_unlock(lock: &tscs42xx->pll_lock); |
318 | |
319 | mutex_unlock(lock: &tscs42xx->coeff_ram_lock); |
320 | |
321 | return ret; |
322 | } |
323 | |
324 | /* Input L Capture Route */ |
325 | static char const * const input_select_text[] = { |
326 | "Line 1" , "Line 2" , "Line 3" , "D2S" |
327 | }; |
328 | |
329 | static const struct soc_enum left_input_select_enum = |
330 | SOC_ENUM_SINGLE(R_INSELL, FB_INSELL, ARRAY_SIZE(input_select_text), |
331 | input_select_text); |
332 | |
333 | static const struct snd_kcontrol_new left_input_select = |
334 | SOC_DAPM_ENUM("LEFT_INPUT_SELECT_ENUM" , left_input_select_enum); |
335 | |
336 | /* Input R Capture Route */ |
337 | static const struct soc_enum right_input_select_enum = |
338 | SOC_ENUM_SINGLE(R_INSELR, FB_INSELR, ARRAY_SIZE(input_select_text), |
339 | input_select_text); |
340 | |
341 | static const struct snd_kcontrol_new right_input_select = |
342 | SOC_DAPM_ENUM("RIGHT_INPUT_SELECT_ENUM" , right_input_select_enum); |
343 | |
344 | /* Input Channel Mapping */ |
345 | static char const * const ch_map_select_text[] = { |
346 | "Normal" , "Left to Right" , "Right to Left" , "Swap" |
347 | }; |
348 | |
349 | static const struct soc_enum ch_map_select_enum = |
350 | SOC_ENUM_SINGLE(R_AIC2, FB_AIC2_ADCDSEL, ARRAY_SIZE(ch_map_select_text), |
351 | ch_map_select_text); |
352 | |
353 | static int dapm_vref_event(struct snd_soc_dapm_widget *w, |
354 | struct snd_kcontrol *kcontrol, int event) |
355 | { |
356 | msleep(msecs: 20); |
357 | return 0; |
358 | } |
359 | |
360 | static int dapm_micb_event(struct snd_soc_dapm_widget *w, |
361 | struct snd_kcontrol *kcontrol, int event) |
362 | { |
363 | msleep(msecs: 20); |
364 | return 0; |
365 | } |
366 | |
367 | static int pll_event(struct snd_soc_dapm_widget *w, |
368 | struct snd_kcontrol *kcontrol, int event) |
369 | { |
370 | struct snd_soc_component *component = |
371 | snd_soc_dapm_to_component(dapm: w->dapm); |
372 | int ret; |
373 | |
374 | if (SND_SOC_DAPM_EVENT_ON(event)) |
375 | ret = power_up_audio_plls(component); |
376 | else |
377 | ret = power_down_audio_plls(component); |
378 | |
379 | return ret; |
380 | } |
381 | |
382 | static int dac_event(struct snd_soc_dapm_widget *w, |
383 | struct snd_kcontrol *kcontrol, int event) |
384 | { |
385 | struct snd_soc_component *component = |
386 | snd_soc_dapm_to_component(dapm: w->dapm); |
387 | struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(c: component); |
388 | int ret; |
389 | |
390 | mutex_lock(&tscs42xx->coeff_ram_lock); |
391 | |
392 | if (!tscs42xx->coeff_ram_synced) { |
393 | ret = write_coeff_ram(component, coeff_ram: tscs42xx->coeff_ram, addr: 0x00, |
394 | COEFF_RAM_COEFF_COUNT); |
395 | if (ret < 0) |
396 | goto exit; |
397 | tscs42xx->coeff_ram_synced = true; |
398 | } |
399 | |
400 | ret = 0; |
401 | exit: |
402 | mutex_unlock(lock: &tscs42xx->coeff_ram_lock); |
403 | |
404 | return ret; |
405 | } |
406 | |
407 | static const struct snd_soc_dapm_widget tscs42xx_dapm_widgets[] = { |
408 | /* Vref */ |
409 | SND_SOC_DAPM_SUPPLY_S("Vref" , 1, R_PWRM2, FB_PWRM2_VREF, 0, |
410 | dapm_vref_event, SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), |
411 | |
412 | /* PLL */ |
413 | SND_SOC_DAPM_SUPPLY("PLL" , SND_SOC_NOPM, 0, 0, pll_event, |
414 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
415 | |
416 | /* Headphone */ |
417 | SND_SOC_DAPM_DAC_E("DAC L" , "HiFi Playback" , R_PWRM2, FB_PWRM2_HPL, 0, |
418 | dac_event, SND_SOC_DAPM_POST_PMU), |
419 | SND_SOC_DAPM_DAC_E("DAC R" , "HiFi Playback" , R_PWRM2, FB_PWRM2_HPR, 0, |
420 | dac_event, SND_SOC_DAPM_POST_PMU), |
421 | SND_SOC_DAPM_OUTPUT("Headphone L" ), |
422 | SND_SOC_DAPM_OUTPUT("Headphone R" ), |
423 | |
424 | /* Speaker */ |
425 | SND_SOC_DAPM_DAC_E("ClassD L" , "HiFi Playback" , |
426 | R_PWRM2, FB_PWRM2_SPKL, 0, |
427 | dac_event, SND_SOC_DAPM_POST_PMU), |
428 | SND_SOC_DAPM_DAC_E("ClassD R" , "HiFi Playback" , |
429 | R_PWRM2, FB_PWRM2_SPKR, 0, |
430 | dac_event, SND_SOC_DAPM_POST_PMU), |
431 | SND_SOC_DAPM_OUTPUT("Speaker L" ), |
432 | SND_SOC_DAPM_OUTPUT("Speaker R" ), |
433 | |
434 | /* Capture */ |
435 | SND_SOC_DAPM_PGA("Analog In PGA L" , R_PWRM1, FB_PWRM1_PGAL, 0, NULL, 0), |
436 | SND_SOC_DAPM_PGA("Analog In PGA R" , R_PWRM1, FB_PWRM1_PGAR, 0, NULL, 0), |
437 | SND_SOC_DAPM_PGA("Analog Boost L" , R_PWRM1, FB_PWRM1_BSTL, 0, NULL, 0), |
438 | SND_SOC_DAPM_PGA("Analog Boost R" , R_PWRM1, FB_PWRM1_BSTR, 0, NULL, 0), |
439 | SND_SOC_DAPM_PGA("ADC Mute" , R_CNVRTR0, FB_CNVRTR0_HPOR, true, NULL, 0), |
440 | SND_SOC_DAPM_ADC("ADC L" , "HiFi Capture" , R_PWRM1, FB_PWRM1_ADCL, 0), |
441 | SND_SOC_DAPM_ADC("ADC R" , "HiFi Capture" , R_PWRM1, FB_PWRM1_ADCR, 0), |
442 | |
443 | /* Capture Input */ |
444 | SND_SOC_DAPM_MUX("Input L Capture Route" , R_PWRM2, |
445 | FB_PWRM2_INSELL, 0, &left_input_select), |
446 | SND_SOC_DAPM_MUX("Input R Capture Route" , R_PWRM2, |
447 | FB_PWRM2_INSELR, 0, &right_input_select), |
448 | |
449 | /* Digital Mic */ |
450 | SND_SOC_DAPM_SUPPLY_S("Digital Mic Enable" , 2, R_DMICCTL, |
451 | FB_DMICCTL_DMICEN, 0, NULL, |
452 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), |
453 | |
454 | /* Analog Mic */ |
455 | SND_SOC_DAPM_SUPPLY_S("Mic Bias" , 2, R_PWRM1, FB_PWRM1_MICB, |
456 | 0, dapm_micb_event, SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), |
457 | |
458 | /* Line In */ |
459 | SND_SOC_DAPM_INPUT("Line In 1 L" ), |
460 | SND_SOC_DAPM_INPUT("Line In 1 R" ), |
461 | SND_SOC_DAPM_INPUT("Line In 2 L" ), |
462 | SND_SOC_DAPM_INPUT("Line In 2 R" ), |
463 | SND_SOC_DAPM_INPUT("Line In 3 L" ), |
464 | SND_SOC_DAPM_INPUT("Line In 3 R" ), |
465 | }; |
466 | |
467 | static const struct snd_soc_dapm_route tscs42xx_intercon[] = { |
468 | {"DAC L" , NULL, "PLL" }, |
469 | {"DAC R" , NULL, "PLL" }, |
470 | {"DAC L" , NULL, "Vref" }, |
471 | {"DAC R" , NULL, "Vref" }, |
472 | {"Headphone L" , NULL, "DAC L" }, |
473 | {"Headphone R" , NULL, "DAC R" }, |
474 | |
475 | {"ClassD L" , NULL, "PLL" }, |
476 | {"ClassD R" , NULL, "PLL" }, |
477 | {"ClassD L" , NULL, "Vref" }, |
478 | {"ClassD R" , NULL, "Vref" }, |
479 | {"Speaker L" , NULL, "ClassD L" }, |
480 | {"Speaker R" , NULL, "ClassD R" }, |
481 | |
482 | {"Input L Capture Route" , NULL, "Vref" }, |
483 | {"Input R Capture Route" , NULL, "Vref" }, |
484 | |
485 | {"Mic Bias" , NULL, "Vref" }, |
486 | |
487 | {"Input L Capture Route" , "Line 1" , "Line In 1 L" }, |
488 | {"Input R Capture Route" , "Line 1" , "Line In 1 R" }, |
489 | {"Input L Capture Route" , "Line 2" , "Line In 2 L" }, |
490 | {"Input R Capture Route" , "Line 2" , "Line In 2 R" }, |
491 | {"Input L Capture Route" , "Line 3" , "Line In 3 L" }, |
492 | {"Input R Capture Route" , "Line 3" , "Line In 3 R" }, |
493 | |
494 | {"Analog In PGA L" , NULL, "Input L Capture Route" }, |
495 | {"Analog In PGA R" , NULL, "Input R Capture Route" }, |
496 | {"Analog Boost L" , NULL, "Analog In PGA L" }, |
497 | {"Analog Boost R" , NULL, "Analog In PGA R" }, |
498 | {"ADC Mute" , NULL, "Analog Boost L" }, |
499 | {"ADC Mute" , NULL, "Analog Boost R" }, |
500 | {"ADC L" , NULL, "PLL" }, |
501 | {"ADC R" , NULL, "PLL" }, |
502 | {"ADC L" , NULL, "ADC Mute" }, |
503 | {"ADC R" , NULL, "ADC Mute" }, |
504 | }; |
505 | |
506 | /************ |
507 | * CONTROLS * |
508 | ************/ |
509 | |
510 | static char const * const eq_band_enable_text[] = { |
511 | "Prescale only" , |
512 | "Band1" , |
513 | "Band1:2" , |
514 | "Band1:3" , |
515 | "Band1:4" , |
516 | "Band1:5" , |
517 | "Band1:6" , |
518 | }; |
519 | |
520 | static char const * const level_detection_text[] = { |
521 | "Average" , |
522 | "Peak" , |
523 | }; |
524 | |
525 | static char const * const level_detection_window_text[] = { |
526 | "512 Samples" , |
527 | "64 Samples" , |
528 | }; |
529 | |
530 | static char const * const compressor_ratio_text[] = { |
531 | "Reserved" , "1.5:1" , "2:1" , "3:1" , "4:1" , "5:1" , "6:1" , |
532 | "7:1" , "8:1" , "9:1" , "10:1" , "11:1" , "12:1" , "13:1" , "14:1" , |
533 | "15:1" , "16:1" , "17:1" , "18:1" , "19:1" , "20:1" , |
534 | }; |
535 | |
536 | static DECLARE_TLV_DB_SCALE(hpvol_scale, -8850, 75, 0); |
537 | static DECLARE_TLV_DB_SCALE(spkvol_scale, -7725, 75, 0); |
538 | static DECLARE_TLV_DB_SCALE(dacvol_scale, -9563, 38, 0); |
539 | static DECLARE_TLV_DB_SCALE(adcvol_scale, -7125, 38, 0); |
540 | static DECLARE_TLV_DB_SCALE(invol_scale, -1725, 75, 0); |
541 | static DECLARE_TLV_DB_SCALE(mic_boost_scale, 0, 1000, 0); |
542 | static DECLARE_TLV_DB_MINMAX(mugain_scale, 0, 4650); |
543 | static DECLARE_TLV_DB_MINMAX(compth_scale, -9562, 0); |
544 | |
545 | static const struct soc_enum eq1_band_enable_enum = |
546 | SOC_ENUM_SINGLE(R_CONFIG1, FB_CONFIG1_EQ1_BE, |
547 | ARRAY_SIZE(eq_band_enable_text), eq_band_enable_text); |
548 | |
549 | static const struct soc_enum eq2_band_enable_enum = |
550 | SOC_ENUM_SINGLE(R_CONFIG1, FB_CONFIG1_EQ2_BE, |
551 | ARRAY_SIZE(eq_band_enable_text), eq_band_enable_text); |
552 | |
553 | static const struct soc_enum cle_level_detection_enum = |
554 | SOC_ENUM_SINGLE(R_CLECTL, FB_CLECTL_LVL_MODE, |
555 | ARRAY_SIZE(level_detection_text), |
556 | level_detection_text); |
557 | |
558 | static const struct soc_enum cle_level_detection_window_enum = |
559 | SOC_ENUM_SINGLE(R_CLECTL, FB_CLECTL_WINDOWSEL, |
560 | ARRAY_SIZE(level_detection_window_text), |
561 | level_detection_window_text); |
562 | |
563 | static const struct soc_enum mbc_level_detection_enums[] = { |
564 | SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_LVLMODE1, |
565 | ARRAY_SIZE(level_detection_text), |
566 | level_detection_text), |
567 | SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_LVLMODE2, |
568 | ARRAY_SIZE(level_detection_text), |
569 | level_detection_text), |
570 | SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_LVLMODE3, |
571 | ARRAY_SIZE(level_detection_text), |
572 | level_detection_text), |
573 | }; |
574 | |
575 | static const struct soc_enum mbc_level_detection_window_enums[] = { |
576 | SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_WINSEL1, |
577 | ARRAY_SIZE(level_detection_window_text), |
578 | level_detection_window_text), |
579 | SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_WINSEL2, |
580 | ARRAY_SIZE(level_detection_window_text), |
581 | level_detection_window_text), |
582 | SOC_ENUM_SINGLE(R_DACMBCCTL, FB_DACMBCCTL_WINSEL3, |
583 | ARRAY_SIZE(level_detection_window_text), |
584 | level_detection_window_text), |
585 | }; |
586 | |
587 | static const struct soc_enum compressor_ratio_enum = |
588 | SOC_ENUM_SINGLE(R_CMPRAT, FB_CMPRAT, |
589 | ARRAY_SIZE(compressor_ratio_text), compressor_ratio_text); |
590 | |
591 | static const struct soc_enum dac_mbc1_compressor_ratio_enum = |
592 | SOC_ENUM_SINGLE(R_DACMBCRAT1, FB_DACMBCRAT1_RATIO, |
593 | ARRAY_SIZE(compressor_ratio_text), compressor_ratio_text); |
594 | |
595 | static const struct soc_enum dac_mbc2_compressor_ratio_enum = |
596 | SOC_ENUM_SINGLE(R_DACMBCRAT2, FB_DACMBCRAT2_RATIO, |
597 | ARRAY_SIZE(compressor_ratio_text), compressor_ratio_text); |
598 | |
599 | static const struct soc_enum dac_mbc3_compressor_ratio_enum = |
600 | SOC_ENUM_SINGLE(R_DACMBCRAT3, FB_DACMBCRAT3_RATIO, |
601 | ARRAY_SIZE(compressor_ratio_text), compressor_ratio_text); |
602 | |
603 | static int bytes_info_ext(struct snd_kcontrol *kcontrol, |
604 | struct snd_ctl_elem_info *ucontrol) |
605 | { |
606 | struct coeff_ram_ctl *ctl = |
607 | (struct coeff_ram_ctl *)kcontrol->private_value; |
608 | struct soc_bytes_ext *params = &ctl->bytes_ext; |
609 | |
610 | ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES; |
611 | ucontrol->count = params->max; |
612 | |
613 | return 0; |
614 | } |
615 | |
616 | #define COEFF_RAM_CTL(xname, xcount, xaddr) \ |
617 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
618 | .info = bytes_info_ext, \ |
619 | .get = coeff_ram_get, .put = coeff_ram_put, \ |
620 | .private_value = (unsigned long)&(struct coeff_ram_ctl) { \ |
621 | .addr = xaddr, \ |
622 | .bytes_ext = {.max = xcount, }, \ |
623 | } \ |
624 | } |
625 | |
626 | static const struct snd_kcontrol_new tscs42xx_snd_controls[] = { |
627 | /* Volumes */ |
628 | SOC_DOUBLE_R_TLV("Headphone Volume" , R_HPVOLL, R_HPVOLR, |
629 | FB_HPVOLL, 0x7F, 0, hpvol_scale), |
630 | SOC_DOUBLE_R_TLV("Speaker Volume" , R_SPKVOLL, R_SPKVOLR, |
631 | FB_SPKVOLL, 0x7F, 0, spkvol_scale), |
632 | SOC_DOUBLE_R_TLV("Master Volume" , R_DACVOLL, R_DACVOLR, |
633 | FB_DACVOLL, 0xFF, 0, dacvol_scale), |
634 | SOC_DOUBLE_R_TLV("PCM Volume" , R_ADCVOLL, R_ADCVOLR, |
635 | FB_ADCVOLL, 0xFF, 0, adcvol_scale), |
636 | SOC_DOUBLE_R_TLV("Input Volume" , R_INVOLL, R_INVOLR, |
637 | FB_INVOLL, 0x3F, 0, invol_scale), |
638 | |
639 | /* INSEL */ |
640 | SOC_DOUBLE_R_TLV("Mic Boost Volume" , R_INSELL, R_INSELR, |
641 | FB_INSELL_MICBSTL, FV_INSELL_MICBSTL_30DB, |
642 | 0, mic_boost_scale), |
643 | |
644 | /* Input Channel Map */ |
645 | SOC_ENUM("Input Channel Map" , ch_map_select_enum), |
646 | |
647 | /* Mic Bias */ |
648 | SOC_SINGLE("Mic Bias Boost Switch" , 0x71, 0x07, 1, 0), |
649 | |
650 | /* Headphone Auto Switching */ |
651 | SOC_SINGLE("Headphone Auto Switching Switch" , |
652 | R_CTL, FB_CTL_HPSWEN, 1, 0), |
653 | SOC_SINGLE("Headphone Detect Polarity Toggle Switch" , |
654 | R_CTL, FB_CTL_HPSWPOL, 1, 0), |
655 | |
656 | /* Coefficient Ram */ |
657 | COEFF_RAM_CTL("Cascade1L BiQuad1" , BIQUAD_SIZE, 0x00), |
658 | COEFF_RAM_CTL("Cascade1L BiQuad2" , BIQUAD_SIZE, 0x05), |
659 | COEFF_RAM_CTL("Cascade1L BiQuad3" , BIQUAD_SIZE, 0x0a), |
660 | COEFF_RAM_CTL("Cascade1L BiQuad4" , BIQUAD_SIZE, 0x0f), |
661 | COEFF_RAM_CTL("Cascade1L BiQuad5" , BIQUAD_SIZE, 0x14), |
662 | COEFF_RAM_CTL("Cascade1L BiQuad6" , BIQUAD_SIZE, 0x19), |
663 | |
664 | COEFF_RAM_CTL("Cascade1R BiQuad1" , BIQUAD_SIZE, 0x20), |
665 | COEFF_RAM_CTL("Cascade1R BiQuad2" , BIQUAD_SIZE, 0x25), |
666 | COEFF_RAM_CTL("Cascade1R BiQuad3" , BIQUAD_SIZE, 0x2a), |
667 | COEFF_RAM_CTL("Cascade1R BiQuad4" , BIQUAD_SIZE, 0x2f), |
668 | COEFF_RAM_CTL("Cascade1R BiQuad5" , BIQUAD_SIZE, 0x34), |
669 | COEFF_RAM_CTL("Cascade1R BiQuad6" , BIQUAD_SIZE, 0x39), |
670 | |
671 | COEFF_RAM_CTL("Cascade1L Prescale" , COEFF_SIZE, 0x1f), |
672 | COEFF_RAM_CTL("Cascade1R Prescale" , COEFF_SIZE, 0x3f), |
673 | |
674 | COEFF_RAM_CTL("Cascade2L BiQuad1" , BIQUAD_SIZE, 0x40), |
675 | COEFF_RAM_CTL("Cascade2L BiQuad2" , BIQUAD_SIZE, 0x45), |
676 | COEFF_RAM_CTL("Cascade2L BiQuad3" , BIQUAD_SIZE, 0x4a), |
677 | COEFF_RAM_CTL("Cascade2L BiQuad4" , BIQUAD_SIZE, 0x4f), |
678 | COEFF_RAM_CTL("Cascade2L BiQuad5" , BIQUAD_SIZE, 0x54), |
679 | COEFF_RAM_CTL("Cascade2L BiQuad6" , BIQUAD_SIZE, 0x59), |
680 | |
681 | COEFF_RAM_CTL("Cascade2R BiQuad1" , BIQUAD_SIZE, 0x60), |
682 | COEFF_RAM_CTL("Cascade2R BiQuad2" , BIQUAD_SIZE, 0x65), |
683 | COEFF_RAM_CTL("Cascade2R BiQuad3" , BIQUAD_SIZE, 0x6a), |
684 | COEFF_RAM_CTL("Cascade2R BiQuad4" , BIQUAD_SIZE, 0x6f), |
685 | COEFF_RAM_CTL("Cascade2R BiQuad5" , BIQUAD_SIZE, 0x74), |
686 | COEFF_RAM_CTL("Cascade2R BiQuad6" , BIQUAD_SIZE, 0x79), |
687 | |
688 | COEFF_RAM_CTL("Cascade2L Prescale" , COEFF_SIZE, 0x5f), |
689 | COEFF_RAM_CTL("Cascade2R Prescale" , COEFF_SIZE, 0x7f), |
690 | |
691 | COEFF_RAM_CTL("Bass Extraction BiQuad1" , BIQUAD_SIZE, 0x80), |
692 | COEFF_RAM_CTL("Bass Extraction BiQuad2" , BIQUAD_SIZE, 0x85), |
693 | |
694 | COEFF_RAM_CTL("Bass Non Linear Function 1" , COEFF_SIZE, 0x8a), |
695 | COEFF_RAM_CTL("Bass Non Linear Function 2" , COEFF_SIZE, 0x8b), |
696 | |
697 | COEFF_RAM_CTL("Bass Limiter BiQuad" , BIQUAD_SIZE, 0x8c), |
698 | |
699 | COEFF_RAM_CTL("Bass Cut Off BiQuad" , BIQUAD_SIZE, 0x91), |
700 | |
701 | COEFF_RAM_CTL("Bass Mix" , COEFF_SIZE, 0x96), |
702 | |
703 | COEFF_RAM_CTL("Treb Extraction BiQuad1" , BIQUAD_SIZE, 0x97), |
704 | COEFF_RAM_CTL("Treb Extraction BiQuad2" , BIQUAD_SIZE, 0x9c), |
705 | |
706 | COEFF_RAM_CTL("Treb Non Linear Function 1" , COEFF_SIZE, 0xa1), |
707 | COEFF_RAM_CTL("Treb Non Linear Function 2" , COEFF_SIZE, 0xa2), |
708 | |
709 | COEFF_RAM_CTL("Treb Limiter BiQuad" , BIQUAD_SIZE, 0xa3), |
710 | |
711 | COEFF_RAM_CTL("Treb Cut Off BiQuad" , BIQUAD_SIZE, 0xa8), |
712 | |
713 | COEFF_RAM_CTL("Treb Mix" , COEFF_SIZE, 0xad), |
714 | |
715 | COEFF_RAM_CTL("3D" , COEFF_SIZE, 0xae), |
716 | |
717 | COEFF_RAM_CTL("3D Mix" , COEFF_SIZE, 0xaf), |
718 | |
719 | COEFF_RAM_CTL("MBC1 BiQuad1" , BIQUAD_SIZE, 0xb0), |
720 | COEFF_RAM_CTL("MBC1 BiQuad2" , BIQUAD_SIZE, 0xb5), |
721 | |
722 | COEFF_RAM_CTL("MBC2 BiQuad1" , BIQUAD_SIZE, 0xba), |
723 | COEFF_RAM_CTL("MBC2 BiQuad2" , BIQUAD_SIZE, 0xbf), |
724 | |
725 | COEFF_RAM_CTL("MBC3 BiQuad1" , BIQUAD_SIZE, 0xc4), |
726 | COEFF_RAM_CTL("MBC3 BiQuad2" , BIQUAD_SIZE, 0xc9), |
727 | |
728 | /* EQ */ |
729 | SOC_SINGLE("EQ1 Switch" , R_CONFIG1, FB_CONFIG1_EQ1_EN, 1, 0), |
730 | SOC_SINGLE("EQ2 Switch" , R_CONFIG1, FB_CONFIG1_EQ2_EN, 1, 0), |
731 | SOC_ENUM("EQ1 Band Enable" , eq1_band_enable_enum), |
732 | SOC_ENUM("EQ2 Band Enable" , eq2_band_enable_enum), |
733 | |
734 | /* CLE */ |
735 | SOC_ENUM("CLE Level Detect" , |
736 | cle_level_detection_enum), |
737 | SOC_ENUM("CLE Level Detect Win" , |
738 | cle_level_detection_window_enum), |
739 | SOC_SINGLE("Expander Switch" , |
740 | R_CLECTL, FB_CLECTL_EXP_EN, 1, 0), |
741 | SOC_SINGLE("Limiter Switch" , |
742 | R_CLECTL, FB_CLECTL_LIMIT_EN, 1, 0), |
743 | SOC_SINGLE("Comp Switch" , |
744 | R_CLECTL, FB_CLECTL_COMP_EN, 1, 0), |
745 | SOC_SINGLE_TLV("CLE Make-Up Gain Volume" , |
746 | R_MUGAIN, FB_MUGAIN_CLEMUG, 0x1f, 0, mugain_scale), |
747 | SOC_SINGLE_TLV("Comp Thresh Volume" , |
748 | R_COMPTH, FB_COMPTH, 0xff, 0, compth_scale), |
749 | SOC_ENUM("Comp Ratio" , compressor_ratio_enum), |
750 | SND_SOC_BYTES("Comp Atk Time" , R_CATKTCL, 2), |
751 | |
752 | /* Effects */ |
753 | SOC_SINGLE("3D Switch" , R_FXCTL, FB_FXCTL_3DEN, 1, 0), |
754 | SOC_SINGLE("Treble Switch" , R_FXCTL, FB_FXCTL_TEEN, 1, 0), |
755 | SOC_SINGLE("Treble Bypass Switch" , R_FXCTL, FB_FXCTL_TNLFBYPASS, 1, 0), |
756 | SOC_SINGLE("Bass Switch" , R_FXCTL, FB_FXCTL_BEEN, 1, 0), |
757 | SOC_SINGLE("Bass Bypass Switch" , R_FXCTL, FB_FXCTL_BNLFBYPASS, 1, 0), |
758 | |
759 | /* MBC */ |
760 | SOC_SINGLE("MBC Band1 Switch" , R_DACMBCEN, FB_DACMBCEN_MBCEN1, 1, 0), |
761 | SOC_SINGLE("MBC Band2 Switch" , R_DACMBCEN, FB_DACMBCEN_MBCEN2, 1, 0), |
762 | SOC_SINGLE("MBC Band3 Switch" , R_DACMBCEN, FB_DACMBCEN_MBCEN3, 1, 0), |
763 | SOC_ENUM("MBC Band1 Level Detect" , |
764 | mbc_level_detection_enums[0]), |
765 | SOC_ENUM("MBC Band2 Level Detect" , |
766 | mbc_level_detection_enums[1]), |
767 | SOC_ENUM("MBC Band3 Level Detect" , |
768 | mbc_level_detection_enums[2]), |
769 | SOC_ENUM("MBC Band1 Level Detect Win" , |
770 | mbc_level_detection_window_enums[0]), |
771 | SOC_ENUM("MBC Band2 Level Detect Win" , |
772 | mbc_level_detection_window_enums[1]), |
773 | SOC_ENUM("MBC Band3 Level Detect Win" , |
774 | mbc_level_detection_window_enums[2]), |
775 | |
776 | SOC_SINGLE("MBC1 Phase Invert Switch" , |
777 | R_DACMBCMUG1, FB_DACMBCMUG1_PHASE, 1, 0), |
778 | SOC_SINGLE_TLV("DAC MBC1 Make-Up Gain Volume" , |
779 | R_DACMBCMUG1, FB_DACMBCMUG1_MUGAIN, 0x1f, 0, mugain_scale), |
780 | SOC_SINGLE_TLV("DAC MBC1 Comp Thresh Volume" , |
781 | R_DACMBCTHR1, FB_DACMBCTHR1_THRESH, 0xff, 0, compth_scale), |
782 | SOC_ENUM("DAC MBC1 Comp Ratio" , |
783 | dac_mbc1_compressor_ratio_enum), |
784 | SND_SOC_BYTES("DAC MBC1 Comp Atk Time" , R_DACMBCATK1L, 2), |
785 | SND_SOC_BYTES("DAC MBC1 Comp Rel Time Const" , |
786 | R_DACMBCREL1L, 2), |
787 | |
788 | SOC_SINGLE("MBC2 Phase Invert Switch" , |
789 | R_DACMBCMUG2, FB_DACMBCMUG2_PHASE, 1, 0), |
790 | SOC_SINGLE_TLV("DAC MBC2 Make-Up Gain Volume" , |
791 | R_DACMBCMUG2, FB_DACMBCMUG2_MUGAIN, 0x1f, 0, mugain_scale), |
792 | SOC_SINGLE_TLV("DAC MBC2 Comp Thresh Volume" , |
793 | R_DACMBCTHR2, FB_DACMBCTHR2_THRESH, 0xff, 0, compth_scale), |
794 | SOC_ENUM("DAC MBC2 Comp Ratio" , |
795 | dac_mbc2_compressor_ratio_enum), |
796 | SND_SOC_BYTES("DAC MBC2 Comp Atk Time" , R_DACMBCATK2L, 2), |
797 | SND_SOC_BYTES("DAC MBC2 Comp Rel Time Const" , |
798 | R_DACMBCREL2L, 2), |
799 | |
800 | SOC_SINGLE("MBC3 Phase Invert Switch" , |
801 | R_DACMBCMUG3, FB_DACMBCMUG3_PHASE, 1, 0), |
802 | SOC_SINGLE_TLV("DAC MBC3 Make-Up Gain Volume" , |
803 | R_DACMBCMUG3, FB_DACMBCMUG3_MUGAIN, 0x1f, 0, mugain_scale), |
804 | SOC_SINGLE_TLV("DAC MBC3 Comp Thresh Volume" , |
805 | R_DACMBCTHR3, FB_DACMBCTHR3_THRESH, 0xff, 0, compth_scale), |
806 | SOC_ENUM("DAC MBC3 Comp Ratio" , |
807 | dac_mbc3_compressor_ratio_enum), |
808 | SND_SOC_BYTES("DAC MBC3 Comp Atk Time" , R_DACMBCATK3L, 2), |
809 | SND_SOC_BYTES("DAC MBC3 Comp Rel Time Const" , |
810 | R_DACMBCREL3L, 2), |
811 | }; |
812 | |
813 | static int setup_sample_format(struct snd_soc_component *component, |
814 | snd_pcm_format_t format) |
815 | { |
816 | unsigned int width; |
817 | int ret; |
818 | |
819 | switch (format) { |
820 | case SNDRV_PCM_FORMAT_S16_LE: |
821 | width = RV_AIC1_WL_16; |
822 | break; |
823 | case SNDRV_PCM_FORMAT_S20_3LE: |
824 | width = RV_AIC1_WL_20; |
825 | break; |
826 | case SNDRV_PCM_FORMAT_S24_LE: |
827 | width = RV_AIC1_WL_24; |
828 | break; |
829 | case SNDRV_PCM_FORMAT_S32_LE: |
830 | width = RV_AIC1_WL_32; |
831 | break; |
832 | default: |
833 | ret = -EINVAL; |
834 | dev_err(component->dev, "Unsupported format width (%d)\n" , ret); |
835 | return ret; |
836 | } |
837 | ret = snd_soc_component_update_bits(component, |
838 | R_AIC1, RM_AIC1_WL, val: width); |
839 | if (ret < 0) { |
840 | dev_err(component->dev, |
841 | "Failed to set sample width (%d)\n" , ret); |
842 | return ret; |
843 | } |
844 | |
845 | return 0; |
846 | } |
847 | |
848 | static int setup_sample_rate(struct snd_soc_component *component, |
849 | unsigned int rate) |
850 | { |
851 | struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(c: component); |
852 | unsigned int br, bm; |
853 | int ret; |
854 | |
855 | switch (rate) { |
856 | case 8000: |
857 | br = RV_DACSR_DBR_32; |
858 | bm = RV_DACSR_DBM_PT25; |
859 | break; |
860 | case 16000: |
861 | br = RV_DACSR_DBR_32; |
862 | bm = RV_DACSR_DBM_PT5; |
863 | break; |
864 | case 24000: |
865 | br = RV_DACSR_DBR_48; |
866 | bm = RV_DACSR_DBM_PT5; |
867 | break; |
868 | case 32000: |
869 | br = RV_DACSR_DBR_32; |
870 | bm = RV_DACSR_DBM_1; |
871 | break; |
872 | case 48000: |
873 | br = RV_DACSR_DBR_48; |
874 | bm = RV_DACSR_DBM_1; |
875 | break; |
876 | case 96000: |
877 | br = RV_DACSR_DBR_48; |
878 | bm = RV_DACSR_DBM_2; |
879 | break; |
880 | case 11025: |
881 | br = RV_DACSR_DBR_44_1; |
882 | bm = RV_DACSR_DBM_PT25; |
883 | break; |
884 | case 22050: |
885 | br = RV_DACSR_DBR_44_1; |
886 | bm = RV_DACSR_DBM_PT5; |
887 | break; |
888 | case 44100: |
889 | br = RV_DACSR_DBR_44_1; |
890 | bm = RV_DACSR_DBM_1; |
891 | break; |
892 | case 88200: |
893 | br = RV_DACSR_DBR_44_1; |
894 | bm = RV_DACSR_DBM_2; |
895 | break; |
896 | default: |
897 | dev_err(component->dev, "Unsupported sample rate %d\n" , rate); |
898 | return -EINVAL; |
899 | } |
900 | |
901 | /* DAC and ADC share bit and frame clock */ |
902 | ret = snd_soc_component_update_bits(component, |
903 | R_DACSR, RM_DACSR_DBR, val: br); |
904 | if (ret < 0) { |
905 | dev_err(component->dev, |
906 | "Failed to update register (%d)\n" , ret); |
907 | return ret; |
908 | } |
909 | ret = snd_soc_component_update_bits(component, |
910 | R_DACSR, RM_DACSR_DBM, val: bm); |
911 | if (ret < 0) { |
912 | dev_err(component->dev, |
913 | "Failed to update register (%d)\n" , ret); |
914 | return ret; |
915 | } |
916 | ret = snd_soc_component_update_bits(component, |
917 | R_ADCSR, RM_DACSR_DBR, val: br); |
918 | if (ret < 0) { |
919 | dev_err(component->dev, |
920 | "Failed to update register (%d)\n" , ret); |
921 | return ret; |
922 | } |
923 | ret = snd_soc_component_update_bits(component, |
924 | R_ADCSR, RM_DACSR_DBM, val: bm); |
925 | if (ret < 0) { |
926 | dev_err(component->dev, |
927 | "Failed to update register (%d)\n" , ret); |
928 | return ret; |
929 | } |
930 | |
931 | mutex_lock(&tscs42xx->audio_params_lock); |
932 | |
933 | tscs42xx->samplerate = rate; |
934 | |
935 | mutex_unlock(lock: &tscs42xx->audio_params_lock); |
936 | |
937 | return 0; |
938 | } |
939 | |
940 | struct reg_setting { |
941 | unsigned int addr; |
942 | unsigned int val; |
943 | unsigned int mask; |
944 | }; |
945 | |
946 | #define PLL_REG_SETTINGS_COUNT 13 |
947 | struct pll_ctl { |
948 | int input_freq; |
949 | struct reg_setting settings[PLL_REG_SETTINGS_COUNT]; |
950 | }; |
951 | |
952 | #define PLL_CTL(f, rt, rd, r1b_l, r9, ra, rb, \ |
953 | rc, r12, r1b_h, re, rf, r10, r11) \ |
954 | { \ |
955 | .input_freq = f, \ |
956 | .settings = { \ |
957 | {R_TIMEBASE, rt, 0xFF}, \ |
958 | {R_PLLCTLD, rd, 0xFF}, \ |
959 | {R_PLLCTL1B, r1b_l, 0x0F}, \ |
960 | {R_PLLCTL9, r9, 0xFF}, \ |
961 | {R_PLLCTLA, ra, 0xFF}, \ |
962 | {R_PLLCTLB, rb, 0xFF}, \ |
963 | {R_PLLCTLC, rc, 0xFF}, \ |
964 | {R_PLLCTL12, r12, 0xFF}, \ |
965 | {R_PLLCTL1B, r1b_h, 0xF0}, \ |
966 | {R_PLLCTLE, re, 0xFF}, \ |
967 | {R_PLLCTLF, rf, 0xFF}, \ |
968 | {R_PLLCTL10, r10, 0xFF}, \ |
969 | {R_PLLCTL11, r11, 0xFF}, \ |
970 | }, \ |
971 | } |
972 | |
973 | static const struct pll_ctl pll_ctls[] = { |
974 | PLL_CTL(1411200, 0x05, |
975 | 0x39, 0x04, 0x07, 0x02, 0xC3, 0x04, |
976 | 0x1B, 0x10, 0x03, 0x03, 0xD0, 0x02), |
977 | PLL_CTL(1536000, 0x05, |
978 | 0x1A, 0x04, 0x02, 0x03, 0xE0, 0x01, |
979 | 0x1A, 0x10, 0x02, 0x03, 0xB9, 0x01), |
980 | PLL_CTL(2822400, 0x0A, |
981 | 0x23, 0x04, 0x07, 0x04, 0xC3, 0x04, |
982 | 0x22, 0x10, 0x05, 0x03, 0x58, 0x02), |
983 | PLL_CTL(3072000, 0x0B, |
984 | 0x22, 0x04, 0x07, 0x03, 0x48, 0x03, |
985 | 0x1A, 0x10, 0x04, 0x03, 0xB9, 0x01), |
986 | PLL_CTL(5644800, 0x15, |
987 | 0x23, 0x04, 0x0E, 0x04, 0xC3, 0x04, |
988 | 0x1A, 0x10, 0x08, 0x03, 0xE0, 0x01), |
989 | PLL_CTL(6144000, 0x17, |
990 | 0x1A, 0x04, 0x08, 0x03, 0xE0, 0x01, |
991 | 0x1A, 0x10, 0x08, 0x03, 0xB9, 0x01), |
992 | PLL_CTL(12000000, 0x2E, |
993 | 0x1B, 0x04, 0x19, 0x03, 0x00, 0x03, |
994 | 0x2A, 0x10, 0x19, 0x05, 0x98, 0x04), |
995 | PLL_CTL(19200000, 0x4A, |
996 | 0x13, 0x04, 0x14, 0x03, 0x80, 0x01, |
997 | 0x1A, 0x10, 0x19, 0x03, 0xB9, 0x01), |
998 | PLL_CTL(22000000, 0x55, |
999 | 0x2A, 0x04, 0x37, 0x05, 0x00, 0x06, |
1000 | 0x22, 0x10, 0x26, 0x03, 0x49, 0x02), |
1001 | PLL_CTL(22579200, 0x57, |
1002 | 0x22, 0x04, 0x31, 0x03, 0x20, 0x03, |
1003 | 0x1A, 0x10, 0x1D, 0x03, 0xB3, 0x01), |
1004 | PLL_CTL(24000000, 0x5D, |
1005 | 0x13, 0x04, 0x19, 0x03, 0x80, 0x01, |
1006 | 0x1B, 0x10, 0x19, 0x05, 0x4C, 0x02), |
1007 | PLL_CTL(24576000, 0x5F, |
1008 | 0x13, 0x04, 0x1D, 0x03, 0xB3, 0x01, |
1009 | 0x22, 0x10, 0x40, 0x03, 0x72, 0x03), |
1010 | PLL_CTL(27000000, 0x68, |
1011 | 0x22, 0x04, 0x4B, 0x03, 0x00, 0x04, |
1012 | 0x2A, 0x10, 0x7D, 0x03, 0x20, 0x06), |
1013 | PLL_CTL(36000000, 0x8C, |
1014 | 0x1B, 0x04, 0x4B, 0x03, 0x00, 0x03, |
1015 | 0x2A, 0x10, 0x7D, 0x03, 0x98, 0x04), |
1016 | PLL_CTL(25000000, 0x61, |
1017 | 0x1B, 0x04, 0x37, 0x03, 0x2B, 0x03, |
1018 | 0x1A, 0x10, 0x2A, 0x03, 0x39, 0x02), |
1019 | PLL_CTL(26000000, 0x65, |
1020 | 0x23, 0x04, 0x41, 0x05, 0x00, 0x06, |
1021 | 0x1A, 0x10, 0x26, 0x03, 0xEF, 0x01), |
1022 | PLL_CTL(12288000, 0x2F, |
1023 | 0x1A, 0x04, 0x12, 0x03, 0x1C, 0x02, |
1024 | 0x22, 0x10, 0x20, 0x03, 0x72, 0x03), |
1025 | PLL_CTL(40000000, 0x9B, |
1026 | 0x22, 0x08, 0x7D, 0x03, 0x80, 0x04, |
1027 | 0x23, 0x10, 0x7D, 0x05, 0xE4, 0x06), |
1028 | PLL_CTL(512000, 0x01, |
1029 | 0x22, 0x04, 0x01, 0x03, 0xD0, 0x02, |
1030 | 0x1B, 0x10, 0x01, 0x04, 0x72, 0x03), |
1031 | PLL_CTL(705600, 0x02, |
1032 | 0x22, 0x04, 0x02, 0x03, 0x15, 0x04, |
1033 | 0x22, 0x10, 0x01, 0x04, 0x80, 0x02), |
1034 | PLL_CTL(1024000, 0x03, |
1035 | 0x22, 0x04, 0x02, 0x03, 0xD0, 0x02, |
1036 | 0x1B, 0x10, 0x02, 0x04, 0x72, 0x03), |
1037 | PLL_CTL(2048000, 0x07, |
1038 | 0x22, 0x04, 0x04, 0x03, 0xD0, 0x02, |
1039 | 0x1B, 0x10, 0x04, 0x04, 0x72, 0x03), |
1040 | PLL_CTL(2400000, 0x08, |
1041 | 0x22, 0x04, 0x05, 0x03, 0x00, 0x03, |
1042 | 0x23, 0x10, 0x05, 0x05, 0x98, 0x04), |
1043 | }; |
1044 | |
1045 | static const struct pll_ctl *get_pll_ctl(int input_freq) |
1046 | { |
1047 | int i; |
1048 | const struct pll_ctl *pll_ctl = NULL; |
1049 | |
1050 | for (i = 0; i < ARRAY_SIZE(pll_ctls); ++i) |
1051 | if (input_freq == pll_ctls[i].input_freq) { |
1052 | pll_ctl = &pll_ctls[i]; |
1053 | break; |
1054 | } |
1055 | |
1056 | return pll_ctl; |
1057 | } |
1058 | |
1059 | static int set_pll_ctl_from_input_freq(struct snd_soc_component *component, |
1060 | const int input_freq) |
1061 | { |
1062 | int ret; |
1063 | int i; |
1064 | const struct pll_ctl *pll_ctl; |
1065 | |
1066 | pll_ctl = get_pll_ctl(input_freq); |
1067 | if (!pll_ctl) { |
1068 | ret = -EINVAL; |
1069 | dev_err(component->dev, "No PLL input entry for %d (%d)\n" , |
1070 | input_freq, ret); |
1071 | return ret; |
1072 | } |
1073 | |
1074 | for (i = 0; i < PLL_REG_SETTINGS_COUNT; ++i) { |
1075 | ret = snd_soc_component_update_bits(component, |
1076 | reg: pll_ctl->settings[i].addr, |
1077 | mask: pll_ctl->settings[i].mask, |
1078 | val: pll_ctl->settings[i].val); |
1079 | if (ret < 0) { |
1080 | dev_err(component->dev, "Failed to set pll ctl (%d)\n" , |
1081 | ret); |
1082 | return ret; |
1083 | } |
1084 | } |
1085 | |
1086 | return 0; |
1087 | } |
1088 | |
1089 | static int tscs42xx_hw_params(struct snd_pcm_substream *substream, |
1090 | struct snd_pcm_hw_params *params, |
1091 | struct snd_soc_dai *codec_dai) |
1092 | { |
1093 | struct snd_soc_component *component = codec_dai->component; |
1094 | int ret; |
1095 | |
1096 | ret = setup_sample_format(component, format: params_format(p: params)); |
1097 | if (ret < 0) { |
1098 | dev_err(component->dev, "Failed to setup sample format (%d)\n" , |
1099 | ret); |
1100 | return ret; |
1101 | } |
1102 | |
1103 | ret = setup_sample_rate(component, rate: params_rate(p: params)); |
1104 | if (ret < 0) { |
1105 | dev_err(component->dev, |
1106 | "Failed to setup sample rate (%d)\n" , ret); |
1107 | return ret; |
1108 | } |
1109 | |
1110 | return 0; |
1111 | } |
1112 | |
1113 | static inline int dac_mute(struct snd_soc_component *component) |
1114 | { |
1115 | int ret; |
1116 | |
1117 | ret = snd_soc_component_update_bits(component, |
1118 | R_CNVRTR1, RM_CNVRTR1_DACMU, |
1119 | RV_CNVRTR1_DACMU_ENABLE); |
1120 | if (ret < 0) { |
1121 | dev_err(component->dev, "Failed to mute DAC (%d)\n" , |
1122 | ret); |
1123 | return ret; |
1124 | } |
1125 | |
1126 | return 0; |
1127 | } |
1128 | |
1129 | static inline int dac_unmute(struct snd_soc_component *component) |
1130 | { |
1131 | int ret; |
1132 | |
1133 | ret = snd_soc_component_update_bits(component, |
1134 | R_CNVRTR1, RM_CNVRTR1_DACMU, |
1135 | RV_CNVRTR1_DACMU_DISABLE); |
1136 | if (ret < 0) { |
1137 | dev_err(component->dev, "Failed to unmute DAC (%d)\n" , |
1138 | ret); |
1139 | return ret; |
1140 | } |
1141 | |
1142 | return 0; |
1143 | } |
1144 | |
1145 | static inline int adc_mute(struct snd_soc_component *component) |
1146 | { |
1147 | int ret; |
1148 | |
1149 | ret = snd_soc_component_update_bits(component, |
1150 | R_CNVRTR0, RM_CNVRTR0_ADCMU, RV_CNVRTR0_ADCMU_ENABLE); |
1151 | if (ret < 0) { |
1152 | dev_err(component->dev, "Failed to mute ADC (%d)\n" , |
1153 | ret); |
1154 | return ret; |
1155 | } |
1156 | |
1157 | return 0; |
1158 | } |
1159 | |
1160 | static inline int adc_unmute(struct snd_soc_component *component) |
1161 | { |
1162 | int ret; |
1163 | |
1164 | ret = snd_soc_component_update_bits(component, |
1165 | R_CNVRTR0, RM_CNVRTR0_ADCMU, RV_CNVRTR0_ADCMU_DISABLE); |
1166 | if (ret < 0) { |
1167 | dev_err(component->dev, "Failed to unmute ADC (%d)\n" , |
1168 | ret); |
1169 | return ret; |
1170 | } |
1171 | |
1172 | return 0; |
1173 | } |
1174 | |
1175 | static int tscs42xx_mute_stream(struct snd_soc_dai *dai, int mute, int stream) |
1176 | { |
1177 | struct snd_soc_component *component = dai->component; |
1178 | int ret; |
1179 | |
1180 | if (mute) |
1181 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
1182 | ret = dac_mute(component); |
1183 | else |
1184 | ret = adc_mute(component); |
1185 | else |
1186 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
1187 | ret = dac_unmute(component); |
1188 | else |
1189 | ret = adc_unmute(component); |
1190 | |
1191 | return ret; |
1192 | } |
1193 | |
1194 | static int tscs42xx_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1195 | unsigned int fmt) |
1196 | { |
1197 | struct snd_soc_component *component = codec_dai->component; |
1198 | int ret; |
1199 | |
1200 | /* Consumer mode not supported since it needs always-on frame clock */ |
1201 | switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { |
1202 | case SND_SOC_DAIFMT_CBP_CFP: |
1203 | ret = snd_soc_component_update_bits(component, |
1204 | R_AIC1, RM_AIC1_MS, RV_AIC1_MS_MASTER); |
1205 | if (ret < 0) { |
1206 | dev_err(component->dev, |
1207 | "Failed to set codec DAI master (%d)\n" , ret); |
1208 | return ret; |
1209 | } |
1210 | break; |
1211 | default: |
1212 | ret = -EINVAL; |
1213 | dev_err(component->dev, "Unsupported format (%d)\n" , ret); |
1214 | return ret; |
1215 | } |
1216 | |
1217 | return 0; |
1218 | } |
1219 | |
1220 | static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai, |
1221 | unsigned int ratio) |
1222 | { |
1223 | struct snd_soc_component *component = codec_dai->component; |
1224 | struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(c: component); |
1225 | unsigned int value; |
1226 | int ret = 0; |
1227 | |
1228 | switch (ratio) { |
1229 | case 32: |
1230 | value = RV_DACSR_DBCM_32; |
1231 | break; |
1232 | case 40: |
1233 | value = RV_DACSR_DBCM_40; |
1234 | break; |
1235 | case 64: |
1236 | value = RV_DACSR_DBCM_64; |
1237 | break; |
1238 | default: |
1239 | dev_err(component->dev, "Unsupported bclk ratio (%d)\n" , ret); |
1240 | return -EINVAL; |
1241 | } |
1242 | |
1243 | ret = snd_soc_component_update_bits(component, |
1244 | R_DACSR, RM_DACSR_DBCM, val: value); |
1245 | if (ret < 0) { |
1246 | dev_err(component->dev, |
1247 | "Failed to set DAC BCLK ratio (%d)\n" , ret); |
1248 | return ret; |
1249 | } |
1250 | ret = snd_soc_component_update_bits(component, |
1251 | R_ADCSR, RM_ADCSR_ABCM, val: value); |
1252 | if (ret < 0) { |
1253 | dev_err(component->dev, |
1254 | "Failed to set ADC BCLK ratio (%d)\n" , ret); |
1255 | return ret; |
1256 | } |
1257 | |
1258 | mutex_lock(&tscs42xx->audio_params_lock); |
1259 | |
1260 | tscs42xx->bclk_ratio = ratio; |
1261 | |
1262 | mutex_unlock(lock: &tscs42xx->audio_params_lock); |
1263 | |
1264 | return 0; |
1265 | } |
1266 | |
1267 | static const struct snd_soc_dai_ops tscs42xx_dai_ops = { |
1268 | .hw_params = tscs42xx_hw_params, |
1269 | .mute_stream = tscs42xx_mute_stream, |
1270 | .set_fmt = tscs42xx_set_dai_fmt, |
1271 | .set_bclk_ratio = tscs42xx_set_dai_bclk_ratio, |
1272 | }; |
1273 | |
1274 | static int part_is_valid(struct tscs42xx *tscs42xx) |
1275 | { |
1276 | int val; |
1277 | int ret; |
1278 | unsigned int reg; |
1279 | |
1280 | ret = regmap_read(map: tscs42xx->regmap, R_DEVIDH, val: ®); |
1281 | if (ret < 0) |
1282 | return ret; |
1283 | |
1284 | val = reg << 8; |
1285 | ret = regmap_read(map: tscs42xx->regmap, R_DEVIDL, val: ®); |
1286 | if (ret < 0) |
1287 | return ret; |
1288 | |
1289 | val |= reg; |
1290 | |
1291 | switch (val) { |
1292 | case 0x4A74: |
1293 | case 0x4A73: |
1294 | return true; |
1295 | default: |
1296 | return false; |
1297 | } |
1298 | } |
1299 | |
1300 | static int set_sysclk(struct snd_soc_component *component) |
1301 | { |
1302 | struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(c: component); |
1303 | unsigned long freq; |
1304 | int ret; |
1305 | |
1306 | switch (tscs42xx->sysclk_src_id) { |
1307 | case TSCS42XX_PLL_SRC_XTAL: |
1308 | case TSCS42XX_PLL_SRC_MCLK1: |
1309 | ret = snd_soc_component_write(component, R_PLLREFSEL, |
1310 | RV_PLLREFSEL_PLL1_REF_SEL_XTAL_MCLK1 | |
1311 | RV_PLLREFSEL_PLL2_REF_SEL_XTAL_MCLK1); |
1312 | if (ret < 0) { |
1313 | dev_err(component->dev, |
1314 | "Failed to set pll reference input (%d)\n" , |
1315 | ret); |
1316 | return ret; |
1317 | } |
1318 | break; |
1319 | case TSCS42XX_PLL_SRC_MCLK2: |
1320 | ret = snd_soc_component_write(component, R_PLLREFSEL, |
1321 | RV_PLLREFSEL_PLL1_REF_SEL_MCLK2 | |
1322 | RV_PLLREFSEL_PLL2_REF_SEL_MCLK2); |
1323 | if (ret < 0) { |
1324 | dev_err(component->dev, |
1325 | "Failed to set PLL reference (%d)\n" , ret); |
1326 | return ret; |
1327 | } |
1328 | break; |
1329 | default: |
1330 | dev_err(component->dev, "pll src is unsupported\n" ); |
1331 | return -EINVAL; |
1332 | } |
1333 | |
1334 | freq = clk_get_rate(clk: tscs42xx->sysclk); |
1335 | ret = set_pll_ctl_from_input_freq(component, input_freq: freq); |
1336 | if (ret < 0) { |
1337 | dev_err(component->dev, |
1338 | "Failed to setup PLL input freq (%d)\n" , ret); |
1339 | return ret; |
1340 | } |
1341 | |
1342 | return 0; |
1343 | } |
1344 | |
1345 | static int tscs42xx_probe(struct snd_soc_component *component) |
1346 | { |
1347 | return set_sysclk(component); |
1348 | } |
1349 | |
1350 | static const struct snd_soc_component_driver soc_codec_dev_tscs42xx = { |
1351 | .probe = tscs42xx_probe, |
1352 | .dapm_widgets = tscs42xx_dapm_widgets, |
1353 | .num_dapm_widgets = ARRAY_SIZE(tscs42xx_dapm_widgets), |
1354 | .dapm_routes = tscs42xx_intercon, |
1355 | .num_dapm_routes = ARRAY_SIZE(tscs42xx_intercon), |
1356 | .controls = tscs42xx_snd_controls, |
1357 | .num_controls = ARRAY_SIZE(tscs42xx_snd_controls), |
1358 | .idle_bias_on = 1, |
1359 | .use_pmdown_time = 1, |
1360 | .endianness = 1, |
1361 | }; |
1362 | |
1363 | static inline void init_coeff_ram_cache(struct tscs42xx *tscs42xx) |
1364 | { |
1365 | static const u8 norm_addrs[] = { |
1366 | 0x00, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1f, 0x20, 0x25, 0x2a, |
1367 | 0x2f, 0x34, 0x39, 0x3f, 0x40, 0x45, 0x4a, 0x4f, 0x54, 0x59, |
1368 | 0x5f, 0x60, 0x65, 0x6a, 0x6f, 0x74, 0x79, 0x7f, 0x80, 0x85, |
1369 | 0x8c, 0x91, 0x96, 0x97, 0x9c, 0xa3, 0xa8, 0xad, 0xaf, 0xb0, |
1370 | 0xb5, 0xba, 0xbf, 0xc4, 0xc9, |
1371 | }; |
1372 | u8 *coeff_ram = tscs42xx->coeff_ram; |
1373 | int i; |
1374 | |
1375 | for (i = 0; i < ARRAY_SIZE(norm_addrs); i++) |
1376 | coeff_ram[((norm_addrs[i] + 1) * COEFF_SIZE) - 1] = 0x40; |
1377 | } |
1378 | |
1379 | #define TSCS42XX_RATES SNDRV_PCM_RATE_8000_96000 |
1380 | |
1381 | #define TSCS42XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ |
1382 | | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
1383 | |
1384 | static struct snd_soc_dai_driver tscs42xx_dai = { |
1385 | .name = "tscs42xx-HiFi" , |
1386 | .playback = { |
1387 | .stream_name = "HiFi Playback" , |
1388 | .channels_min = 2, |
1389 | .channels_max = 2, |
1390 | .rates = TSCS42XX_RATES, |
1391 | .formats = TSCS42XX_FORMATS,}, |
1392 | .capture = { |
1393 | .stream_name = "HiFi Capture" , |
1394 | .channels_min = 2, |
1395 | .channels_max = 2, |
1396 | .rates = TSCS42XX_RATES, |
1397 | .formats = TSCS42XX_FORMATS,}, |
1398 | .ops = &tscs42xx_dai_ops, |
1399 | .symmetric_rate = 1, |
1400 | .symmetric_channels = 1, |
1401 | .symmetric_sample_bits = 1, |
1402 | }; |
1403 | |
1404 | static const struct reg_sequence tscs42xx_patch[] = { |
1405 | { R_AIC2, RV_AIC2_BLRCM_DAC_BCLK_LRCLK_SHARED }, |
1406 | }; |
1407 | |
1408 | static char const * const src_names[TSCS42XX_PLL_SRC_CNT] = { |
1409 | "xtal" , "mclk1" , "mclk2" }; |
1410 | |
1411 | static int tscs42xx_i2c_probe(struct i2c_client *i2c) |
1412 | { |
1413 | struct tscs42xx *tscs42xx; |
1414 | int src; |
1415 | int ret; |
1416 | |
1417 | tscs42xx = devm_kzalloc(dev: &i2c->dev, size: sizeof(*tscs42xx), GFP_KERNEL); |
1418 | if (!tscs42xx) { |
1419 | ret = -ENOMEM; |
1420 | dev_err(&i2c->dev, |
1421 | "Failed to allocate memory for data (%d)\n" , ret); |
1422 | return ret; |
1423 | } |
1424 | i2c_set_clientdata(client: i2c, data: tscs42xx); |
1425 | |
1426 | for (src = TSCS42XX_PLL_SRC_XTAL; src < TSCS42XX_PLL_SRC_CNT; src++) { |
1427 | tscs42xx->sysclk = devm_clk_get(dev: &i2c->dev, id: src_names[src]); |
1428 | if (!IS_ERR(ptr: tscs42xx->sysclk)) { |
1429 | break; |
1430 | } else if (PTR_ERR(ptr: tscs42xx->sysclk) != -ENOENT) { |
1431 | ret = PTR_ERR(ptr: tscs42xx->sysclk); |
1432 | dev_err(&i2c->dev, "Failed to get sysclk (%d)\n" , ret); |
1433 | return ret; |
1434 | } |
1435 | } |
1436 | if (src == TSCS42XX_PLL_SRC_CNT) { |
1437 | ret = -EINVAL; |
1438 | dev_err(&i2c->dev, "Failed to get a valid clock name (%d)\n" , |
1439 | ret); |
1440 | return ret; |
1441 | } |
1442 | tscs42xx->sysclk_src_id = src; |
1443 | |
1444 | tscs42xx->regmap = devm_regmap_init_i2c(i2c, &tscs42xx_regmap); |
1445 | if (IS_ERR(ptr: tscs42xx->regmap)) { |
1446 | ret = PTR_ERR(ptr: tscs42xx->regmap); |
1447 | dev_err(&i2c->dev, "Failed to allocate regmap (%d)\n" , ret); |
1448 | return ret; |
1449 | } |
1450 | |
1451 | init_coeff_ram_cache(tscs42xx); |
1452 | |
1453 | ret = part_is_valid(tscs42xx); |
1454 | if (ret <= 0) { |
1455 | dev_err(&i2c->dev, "No valid part (%d)\n" , ret); |
1456 | ret = -ENODEV; |
1457 | return ret; |
1458 | } |
1459 | |
1460 | ret = regmap_write(map: tscs42xx->regmap, R_RESET, RV_RESET_ENABLE); |
1461 | if (ret < 0) { |
1462 | dev_err(&i2c->dev, "Failed to reset device (%d)\n" , ret); |
1463 | return ret; |
1464 | } |
1465 | |
1466 | ret = regmap_register_patch(map: tscs42xx->regmap, regs: tscs42xx_patch, |
1467 | ARRAY_SIZE(tscs42xx_patch)); |
1468 | if (ret < 0) { |
1469 | dev_err(&i2c->dev, "Failed to apply patch (%d)\n" , ret); |
1470 | return ret; |
1471 | } |
1472 | |
1473 | mutex_init(&tscs42xx->audio_params_lock); |
1474 | mutex_init(&tscs42xx->coeff_ram_lock); |
1475 | mutex_init(&tscs42xx->pll_lock); |
1476 | |
1477 | ret = devm_snd_soc_register_component(dev: &i2c->dev, |
1478 | component_driver: &soc_codec_dev_tscs42xx, dai_drv: &tscs42xx_dai, num_dai: 1); |
1479 | if (ret) { |
1480 | dev_err(&i2c->dev, "Failed to register codec (%d)\n" , ret); |
1481 | return ret; |
1482 | } |
1483 | |
1484 | return 0; |
1485 | } |
1486 | |
1487 | static const struct i2c_device_id tscs42xx_i2c_id[] = { |
1488 | { "tscs42A1" , 0 }, |
1489 | { "tscs42A2" , 0 }, |
1490 | { } |
1491 | }; |
1492 | MODULE_DEVICE_TABLE(i2c, tscs42xx_i2c_id); |
1493 | |
1494 | static const struct of_device_id tscs42xx_of_match[] = { |
1495 | { .compatible = "tempo,tscs42A1" , }, |
1496 | { .compatible = "tempo,tscs42A2" , }, |
1497 | { } |
1498 | }; |
1499 | MODULE_DEVICE_TABLE(of, tscs42xx_of_match); |
1500 | |
1501 | static struct i2c_driver tscs42xx_i2c_driver = { |
1502 | .driver = { |
1503 | .name = "tscs42xx" , |
1504 | .of_match_table = tscs42xx_of_match, |
1505 | }, |
1506 | .probe = tscs42xx_i2c_probe, |
1507 | .id_table = tscs42xx_i2c_id, |
1508 | }; |
1509 | |
1510 | module_i2c_driver(tscs42xx_i2c_driver); |
1511 | |
1512 | MODULE_AUTHOR("Tempo Semiconductor <steven.eckhoff.opensource@gmail.com" ); |
1513 | MODULE_DESCRIPTION("ASoC TSCS42xx driver" ); |
1514 | MODULE_LICENSE("GPL" ); |
1515 | |