1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // ALSA SoC Texas Instruments TAS2563/TAS2781 Audio Smart Amplifier |
4 | // |
5 | // Copyright (C) 2022 - 2023 Texas Instruments Incorporated |
6 | // https://www.ti.com |
7 | // |
8 | // The TAS2563/TAS2781 driver implements a flexible and configurable |
9 | // algo coefficient setting for one, two, or even multiple |
10 | // TAS2563/TAS2781 chips. |
11 | // |
12 | // Author: Shenghao Ding <shenghao-ding@ti.com> |
13 | // Author: Kevin Lu <kevin-lu@ti.com> |
14 | // |
15 | |
16 | #include <linux/crc8.h> |
17 | #include <linux/firmware.h> |
18 | #include <linux/gpio/consumer.h> |
19 | #include <linux/i2c.h> |
20 | #include <linux/init.h> |
21 | #include <linux/interrupt.h> |
22 | #include <linux/module.h> |
23 | #include <linux/of.h> |
24 | #include <linux/of_gpio.h> |
25 | #include <linux/of_irq.h> |
26 | #include <linux/regmap.h> |
27 | #include <linux/slab.h> |
28 | #include <sound/pcm_params.h> |
29 | #include <sound/soc.h> |
30 | #include <sound/tas2781.h> |
31 | #include <sound/tlv.h> |
32 | #include <sound/tas2781-tlv.h> |
33 | |
34 | static const struct i2c_device_id tasdevice_id[] = { |
35 | { "tas2563" , TAS2563 }, |
36 | { "tas2781" , TAS2781 }, |
37 | {} |
38 | }; |
39 | MODULE_DEVICE_TABLE(i2c, tasdevice_id); |
40 | |
41 | #ifdef CONFIG_OF |
42 | static const struct of_device_id tasdevice_of_match[] = { |
43 | { .compatible = "ti,tas2563" }, |
44 | { .compatible = "ti,tas2781" }, |
45 | {}, |
46 | }; |
47 | MODULE_DEVICE_TABLE(of, tasdevice_of_match); |
48 | #endif |
49 | |
50 | /** |
51 | * tas2781_digital_getvol - get the volum control |
52 | * @kcontrol: control pointer |
53 | * @ucontrol: User data |
54 | * Customer Kcontrol for tas2781 is primarily for regmap booking, paging |
55 | * depends on internal regmap mechanism. |
56 | * tas2781 contains book and page two-level register map, especially |
57 | * book switching will set the register BXXP00R7F, after switching to the |
58 | * correct book, then leverage the mechanism for paging to access the |
59 | * register. |
60 | */ |
61 | static int tas2781_digital_getvol(struct snd_kcontrol *kcontrol, |
62 | struct snd_ctl_elem_value *ucontrol) |
63 | { |
64 | struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); |
65 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
66 | struct soc_mixer_control *mc = |
67 | (struct soc_mixer_control *)kcontrol->private_value; |
68 | |
69 | return tasdevice_digital_getvol(tas_priv, ucontrol, mc); |
70 | } |
71 | |
72 | static int tas2781_digital_putvol(struct snd_kcontrol *kcontrol, |
73 | struct snd_ctl_elem_value *ucontrol) |
74 | { |
75 | struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); |
76 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
77 | struct soc_mixer_control *mc = |
78 | (struct soc_mixer_control *)kcontrol->private_value; |
79 | |
80 | return tasdevice_digital_putvol(tas_priv, ucontrol, mc); |
81 | } |
82 | |
83 | static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol, |
84 | struct snd_ctl_elem_value *ucontrol) |
85 | { |
86 | struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); |
87 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
88 | struct soc_mixer_control *mc = |
89 | (struct soc_mixer_control *)kcontrol->private_value; |
90 | |
91 | return tasdevice_amp_getvol(tas_priv, ucontrol, mc); |
92 | } |
93 | |
94 | static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol, |
95 | struct snd_ctl_elem_value *ucontrol) |
96 | { |
97 | struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); |
98 | struct tasdevice_priv *tas_priv = |
99 | snd_soc_component_get_drvdata(c: codec); |
100 | struct soc_mixer_control *mc = |
101 | (struct soc_mixer_control *)kcontrol->private_value; |
102 | |
103 | return tasdevice_amp_putvol(tas_priv, ucontrol, mc); |
104 | } |
105 | |
106 | static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol, |
107 | struct snd_ctl_elem_value *ucontrol) |
108 | { |
109 | struct snd_soc_component *component = |
110 | snd_soc_kcontrol_component(kcontrol); |
111 | struct tasdevice_priv *tas_priv = |
112 | snd_soc_component_get_drvdata(c: component); |
113 | |
114 | ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status; |
115 | dev_dbg(tas_priv->dev, "%s : Force FWload %s\n" , __func__, |
116 | tas_priv->force_fwload_status ? "ON" : "OFF" ); |
117 | |
118 | return 0; |
119 | } |
120 | |
121 | static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol, |
122 | struct snd_ctl_elem_value *ucontrol) |
123 | { |
124 | struct snd_soc_component *component = |
125 | snd_soc_kcontrol_component(kcontrol); |
126 | struct tasdevice_priv *tas_priv = |
127 | snd_soc_component_get_drvdata(c: component); |
128 | bool change, val = (bool)ucontrol->value.integer.value[0]; |
129 | |
130 | if (tas_priv->force_fwload_status == val) |
131 | change = false; |
132 | else { |
133 | change = true; |
134 | tas_priv->force_fwload_status = val; |
135 | } |
136 | dev_dbg(tas_priv->dev, "%s : Force FWload %s\n" , __func__, |
137 | tas_priv->force_fwload_status ? "ON" : "OFF" ); |
138 | |
139 | return change; |
140 | } |
141 | |
142 | static const struct snd_kcontrol_new tas2781_snd_controls[] = { |
143 | SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain" , TAS2781_AMP_LEVEL, |
144 | 1, 0, 20, 0, tas2781_amp_getvol, |
145 | tas2781_amp_putvol, amp_vol_tlv), |
146 | SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain" , TAS2781_DVC_LVL, |
147 | 0, 0, 200, 1, tas2781_digital_getvol, |
148 | tas2781_digital_putvol, dvc_tlv), |
149 | SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load" , 0, |
150 | tas2781_force_fwload_get, tas2781_force_fwload_put), |
151 | }; |
152 | |
153 | static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol, |
154 | struct snd_ctl_elem_value *ucontrol) |
155 | { |
156 | struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); |
157 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
158 | int ret = 0; |
159 | |
160 | if (tas_priv->rcabin.profile_cfg_id != |
161 | ucontrol->value.integer.value[0]) { |
162 | tas_priv->rcabin.profile_cfg_id = |
163 | ucontrol->value.integer.value[0]; |
164 | ret = 1; |
165 | } |
166 | |
167 | return ret; |
168 | } |
169 | |
170 | static int tasdevice_info_programs(struct snd_kcontrol *kcontrol, |
171 | struct snd_ctl_elem_info *uinfo) |
172 | { |
173 | struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); |
174 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
175 | struct tasdevice_fw *tas_fw = tas_priv->fmw; |
176 | |
177 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
178 | uinfo->count = 1; |
179 | uinfo->value.integer.min = 0; |
180 | uinfo->value.integer.max = (int)tas_fw->nr_programs; |
181 | |
182 | return 0; |
183 | } |
184 | |
185 | static int tasdevice_info_configurations( |
186 | struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
187 | { |
188 | struct snd_soc_component *codec = |
189 | snd_soc_kcontrol_component(kcontrol); |
190 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
191 | struct tasdevice_fw *tas_fw = tas_priv->fmw; |
192 | |
193 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
194 | uinfo->count = 1; |
195 | uinfo->value.integer.min = 0; |
196 | uinfo->value.integer.max = (int)tas_fw->nr_configurations - 1; |
197 | |
198 | return 0; |
199 | } |
200 | |
201 | static int tasdevice_info_profile(struct snd_kcontrol *kcontrol, |
202 | struct snd_ctl_elem_info *uinfo) |
203 | { |
204 | struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); |
205 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
206 | |
207 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
208 | uinfo->count = 1; |
209 | uinfo->value.integer.min = 0; |
210 | uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1; |
211 | |
212 | return 0; |
213 | } |
214 | |
215 | static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol, |
216 | struct snd_ctl_elem_value *ucontrol) |
217 | { |
218 | struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); |
219 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
220 | |
221 | ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id; |
222 | |
223 | return 0; |
224 | } |
225 | |
226 | static int tasdevice_create_control(struct tasdevice_priv *tas_priv) |
227 | { |
228 | struct snd_kcontrol_new *prof_ctrls; |
229 | int nr_controls = 1; |
230 | int mix_index = 0; |
231 | int ret; |
232 | char *name; |
233 | |
234 | prof_ctrls = devm_kcalloc(dev: tas_priv->dev, n: nr_controls, |
235 | size: sizeof(prof_ctrls[0]), GFP_KERNEL); |
236 | if (!prof_ctrls) { |
237 | ret = -ENOMEM; |
238 | goto out; |
239 | } |
240 | |
241 | /* Create a mixer item for selecting the active profile */ |
242 | name = devm_kzalloc(dev: tas_priv->dev, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, |
243 | GFP_KERNEL); |
244 | if (!name) { |
245 | ret = -ENOMEM; |
246 | goto out; |
247 | } |
248 | scnprintf(buf: name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, fmt: "Speaker Profile Id" ); |
249 | prof_ctrls[mix_index].name = name; |
250 | prof_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
251 | prof_ctrls[mix_index].info = tasdevice_info_profile; |
252 | prof_ctrls[mix_index].get = tasdevice_get_profile_id; |
253 | prof_ctrls[mix_index].put = tasdevice_set_profile_id; |
254 | mix_index++; |
255 | |
256 | ret = snd_soc_add_component_controls(component: tas_priv->codec, |
257 | controls: prof_ctrls, num_controls: nr_controls < mix_index ? nr_controls : mix_index); |
258 | |
259 | out: |
260 | return ret; |
261 | } |
262 | |
263 | static int tasdevice_program_get(struct snd_kcontrol *kcontrol, |
264 | struct snd_ctl_elem_value *ucontrol) |
265 | { |
266 | struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); |
267 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
268 | |
269 | ucontrol->value.integer.value[0] = tas_priv->cur_prog; |
270 | |
271 | return 0; |
272 | } |
273 | |
274 | static int tasdevice_program_put(struct snd_kcontrol *kcontrol, |
275 | struct snd_ctl_elem_value *ucontrol) |
276 | { |
277 | struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); |
278 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
279 | unsigned int nr_program = ucontrol->value.integer.value[0]; |
280 | int ret = 0; |
281 | |
282 | if (tas_priv->cur_prog != nr_program) { |
283 | tas_priv->cur_prog = nr_program; |
284 | ret = 1; |
285 | } |
286 | |
287 | return ret; |
288 | } |
289 | |
290 | static int tasdevice_configuration_get(struct snd_kcontrol *kcontrol, |
291 | struct snd_ctl_elem_value *ucontrol) |
292 | { |
293 | |
294 | struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); |
295 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
296 | |
297 | ucontrol->value.integer.value[0] = tas_priv->cur_conf; |
298 | |
299 | return 0; |
300 | } |
301 | |
302 | static int tasdevice_configuration_put( |
303 | struct snd_kcontrol *kcontrol, |
304 | struct snd_ctl_elem_value *ucontrol) |
305 | { |
306 | struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); |
307 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
308 | unsigned int nr_configuration = ucontrol->value.integer.value[0]; |
309 | int ret = 0; |
310 | |
311 | if (tas_priv->cur_conf != nr_configuration) { |
312 | tas_priv->cur_conf = nr_configuration; |
313 | ret = 1; |
314 | } |
315 | |
316 | return ret; |
317 | } |
318 | |
319 | static int tasdevice_dsp_create_ctrls( |
320 | struct tasdevice_priv *tas_priv) |
321 | { |
322 | struct snd_kcontrol_new *dsp_ctrls; |
323 | char *prog_name, *conf_name; |
324 | int nr_controls = 2; |
325 | int mix_index = 0; |
326 | int ret; |
327 | |
328 | /* Alloc kcontrol via devm_kzalloc, which don't manually |
329 | * free the kcontrol |
330 | */ |
331 | dsp_ctrls = devm_kcalloc(dev: tas_priv->dev, n: nr_controls, |
332 | size: sizeof(dsp_ctrls[0]), GFP_KERNEL); |
333 | if (!dsp_ctrls) { |
334 | ret = -ENOMEM; |
335 | goto out; |
336 | } |
337 | |
338 | /* Create a mixer item for selecting the active profile */ |
339 | prog_name = devm_kzalloc(dev: tas_priv->dev, |
340 | SNDRV_CTL_ELEM_ID_NAME_MAXLEN, GFP_KERNEL); |
341 | conf_name = devm_kzalloc(dev: tas_priv->dev, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, |
342 | GFP_KERNEL); |
343 | if (!prog_name || !conf_name) { |
344 | ret = -ENOMEM; |
345 | goto out; |
346 | } |
347 | |
348 | scnprintf(buf: prog_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, |
349 | fmt: "Speaker Program Id" ); |
350 | dsp_ctrls[mix_index].name = prog_name; |
351 | dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
352 | dsp_ctrls[mix_index].info = tasdevice_info_programs; |
353 | dsp_ctrls[mix_index].get = tasdevice_program_get; |
354 | dsp_ctrls[mix_index].put = tasdevice_program_put; |
355 | mix_index++; |
356 | |
357 | scnprintf(buf: conf_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, |
358 | fmt: "Speaker Config Id" ); |
359 | dsp_ctrls[mix_index].name = conf_name; |
360 | dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
361 | dsp_ctrls[mix_index].info = tasdevice_info_configurations; |
362 | dsp_ctrls[mix_index].get = tasdevice_configuration_get; |
363 | dsp_ctrls[mix_index].put = tasdevice_configuration_put; |
364 | mix_index++; |
365 | |
366 | ret = snd_soc_add_component_controls(component: tas_priv->codec, controls: dsp_ctrls, |
367 | num_controls: nr_controls < mix_index ? nr_controls : mix_index); |
368 | |
369 | out: |
370 | return ret; |
371 | } |
372 | |
373 | static void tasdevice_fw_ready(const struct firmware *fmw, |
374 | void *context) |
375 | { |
376 | struct tasdevice_priv *tas_priv = context; |
377 | int ret = 0; |
378 | int i; |
379 | |
380 | mutex_lock(&tas_priv->codec_lock); |
381 | |
382 | ret = tasdevice_rca_parser(context: tas_priv, fmw); |
383 | if (ret) |
384 | goto out; |
385 | tasdevice_create_control(tas_priv); |
386 | |
387 | tasdevice_dsp_remove(context: tas_priv); |
388 | tasdevice_calbin_remove(context: tas_priv); |
389 | tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; |
390 | scnprintf(buf: tas_priv->coef_binaryname, size: 64, fmt: "%s_coef.bin" , |
391 | tas_priv->dev_name); |
392 | ret = tasdevice_dsp_parser(context: tas_priv); |
393 | if (ret) { |
394 | dev_err(tas_priv->dev, "dspfw load %s error\n" , |
395 | tas_priv->coef_binaryname); |
396 | tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; |
397 | goto out; |
398 | } |
399 | tasdevice_dsp_create_ctrls(tas_priv); |
400 | |
401 | tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; |
402 | |
403 | /* If calibrated data occurs error, dsp will still works with default |
404 | * calibrated data inside algo. |
405 | */ |
406 | for (i = 0; i < tas_priv->ndev; i++) { |
407 | scnprintf(buf: tas_priv->cal_binaryname[i], size: 64, fmt: "%s_cal_0x%02x.bin" , |
408 | tas_priv->dev_name, tas_priv->tasdevice[i].dev_addr); |
409 | ret = tas2781_load_calibration(context: tas_priv, |
410 | file_name: tas_priv->cal_binaryname[i], i); |
411 | if (ret != 0) |
412 | dev_err(tas_priv->dev, |
413 | "%s: load %s error, default will effect\n" , |
414 | __func__, tas_priv->cal_binaryname[i]); |
415 | } |
416 | |
417 | tasdevice_prmg_calibdata_load(context: tas_priv, prm_no: 0); |
418 | tas_priv->cur_prog = 0; |
419 | out: |
420 | if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) { |
421 | /*If DSP FW fail, kcontrol won't be created */ |
422 | tasdevice_config_info_remove(context: tas_priv); |
423 | tasdevice_dsp_remove(context: tas_priv); |
424 | } |
425 | mutex_unlock(lock: &tas_priv->codec_lock); |
426 | if (fmw) |
427 | release_firmware(fw: fmw); |
428 | } |
429 | |
430 | static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w, |
431 | struct snd_kcontrol *kcontrol, int event) |
432 | { |
433 | struct snd_soc_component *codec = snd_soc_dapm_to_component(dapm: w->dapm); |
434 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
435 | int state = 0; |
436 | |
437 | /* Codec Lock Hold */ |
438 | mutex_lock(&tas_priv->codec_lock); |
439 | if (event == SND_SOC_DAPM_PRE_PMD) |
440 | state = 1; |
441 | tasdevice_tuning_switch(context: tas_priv, state); |
442 | /* Codec Lock Release*/ |
443 | mutex_unlock(lock: &tas_priv->codec_lock); |
444 | |
445 | return 0; |
446 | } |
447 | |
448 | static const struct snd_soc_dapm_widget tasdevice_dapm_widgets[] = { |
449 | SND_SOC_DAPM_AIF_IN("ASI" , "ASI Playback" , 0, SND_SOC_NOPM, 0, 0), |
450 | SND_SOC_DAPM_AIF_OUT_E("ASI OUT" , "ASI Capture" , 0, SND_SOC_NOPM, |
451 | 0, 0, tasdevice_dapm_event, |
452 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
453 | SND_SOC_DAPM_SPK("SPK" , tasdevice_dapm_event), |
454 | SND_SOC_DAPM_OUTPUT("OUT" ), |
455 | SND_SOC_DAPM_INPUT("DMIC" ) |
456 | }; |
457 | |
458 | static const struct snd_soc_dapm_route tasdevice_audio_map[] = { |
459 | {"SPK" , NULL, "ASI" }, |
460 | {"OUT" , NULL, "SPK" }, |
461 | {"ASI OUT" , NULL, "DMIC" } |
462 | }; |
463 | |
464 | static int tasdevice_startup(struct snd_pcm_substream *substream, |
465 | struct snd_soc_dai *dai) |
466 | { |
467 | struct snd_soc_component *codec = dai->component; |
468 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
469 | int ret = 0; |
470 | |
471 | if (tas_priv->fw_state != TASDEVICE_DSP_FW_ALL_OK) { |
472 | dev_err(tas_priv->dev, "DSP bin file not loaded\n" ); |
473 | ret = -EINVAL; |
474 | } |
475 | |
476 | return ret; |
477 | } |
478 | |
479 | static int tasdevice_hw_params(struct snd_pcm_substream *substream, |
480 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) |
481 | { |
482 | struct tasdevice_priv *tas_priv = snd_soc_dai_get_drvdata(dai); |
483 | unsigned int slot_width; |
484 | unsigned int fsrate; |
485 | int bclk_rate; |
486 | int rc = 0; |
487 | |
488 | fsrate = params_rate(p: params); |
489 | switch (fsrate) { |
490 | case 48000: |
491 | case 44100: |
492 | break; |
493 | default: |
494 | dev_err(tas_priv->dev, "%s: incorrect sample rate = %u\n" , |
495 | __func__, fsrate); |
496 | rc = -EINVAL; |
497 | goto out; |
498 | } |
499 | |
500 | slot_width = params_width(p: params); |
501 | switch (slot_width) { |
502 | case 16: |
503 | case 20: |
504 | case 24: |
505 | case 32: |
506 | break; |
507 | default: |
508 | dev_err(tas_priv->dev, "%s: incorrect slot width = %u\n" , |
509 | __func__, slot_width); |
510 | rc = -EINVAL; |
511 | goto out; |
512 | } |
513 | |
514 | bclk_rate = snd_soc_params_to_bclk(parms: params); |
515 | if (bclk_rate < 0) { |
516 | dev_err(tas_priv->dev, "%s: incorrect bclk rate = %d\n" , |
517 | __func__, bclk_rate); |
518 | rc = bclk_rate; |
519 | goto out; |
520 | } |
521 | |
522 | out: |
523 | return rc; |
524 | } |
525 | |
526 | static int tasdevice_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
527 | int clk_id, unsigned int freq, int dir) |
528 | { |
529 | struct tasdevice_priv *tas_priv = snd_soc_dai_get_drvdata(dai: codec_dai); |
530 | |
531 | tas_priv->sysclk = freq; |
532 | |
533 | return 0; |
534 | } |
535 | |
536 | static const struct snd_soc_dai_ops tasdevice_dai_ops = { |
537 | .startup = tasdevice_startup, |
538 | .hw_params = tasdevice_hw_params, |
539 | .set_sysclk = tasdevice_set_dai_sysclk, |
540 | }; |
541 | |
542 | static struct snd_soc_dai_driver tasdevice_dai_driver[] = { |
543 | { |
544 | .name = "tas2781_codec" , |
545 | .id = 0, |
546 | .playback = { |
547 | .stream_name = "Playback" , |
548 | .channels_min = 1, |
549 | .channels_max = 4, |
550 | .rates = TASDEVICE_RATES, |
551 | .formats = TASDEVICE_FORMATS, |
552 | }, |
553 | .capture = { |
554 | .stream_name = "Capture" , |
555 | .channels_min = 1, |
556 | .channels_max = 4, |
557 | .rates = TASDEVICE_RATES, |
558 | .formats = TASDEVICE_FORMATS, |
559 | }, |
560 | .ops = &tasdevice_dai_ops, |
561 | .symmetric_rate = 1, |
562 | }, |
563 | }; |
564 | |
565 | static int tasdevice_codec_probe(struct snd_soc_component *codec) |
566 | { |
567 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
568 | |
569 | return tascodec_init(tas_priv, codec, THIS_MODULE, cont: tasdevice_fw_ready); |
570 | } |
571 | |
572 | static void tasdevice_deinit(void *context) |
573 | { |
574 | struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context; |
575 | |
576 | tasdevice_config_info_remove(context: tas_priv); |
577 | tasdevice_dsp_remove(context: tas_priv); |
578 | tasdevice_calbin_remove(context: tas_priv); |
579 | tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; |
580 | } |
581 | |
582 | static void tasdevice_codec_remove( |
583 | struct snd_soc_component *codec) |
584 | { |
585 | struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(c: codec); |
586 | |
587 | tasdevice_deinit(context: tas_priv); |
588 | } |
589 | |
590 | static const struct snd_soc_component_driver |
591 | soc_codec_driver_tasdevice = { |
592 | .probe = tasdevice_codec_probe, |
593 | .remove = tasdevice_codec_remove, |
594 | .controls = tas2781_snd_controls, |
595 | .num_controls = ARRAY_SIZE(tas2781_snd_controls), |
596 | .dapm_widgets = tasdevice_dapm_widgets, |
597 | .num_dapm_widgets = ARRAY_SIZE(tasdevice_dapm_widgets), |
598 | .dapm_routes = tasdevice_audio_map, |
599 | .num_dapm_routes = ARRAY_SIZE(tasdevice_audio_map), |
600 | .idle_bias_on = 1, |
601 | .endianness = 1, |
602 | }; |
603 | |
604 | static void tasdevice_parse_dt(struct tasdevice_priv *tas_priv) |
605 | { |
606 | struct i2c_client *client = (struct i2c_client *)tas_priv->client; |
607 | unsigned int dev_addrs[TASDEVICE_MAX_CHANNELS]; |
608 | int rc, i, ndev = 0; |
609 | |
610 | if (tas_priv->isacpi) { |
611 | ndev = device_property_read_u32_array(dev: &client->dev, |
612 | propname: "ti,audio-slots" , NULL, nval: 0); |
613 | if (ndev <= 0) { |
614 | ndev = 1; |
615 | dev_addrs[0] = client->addr; |
616 | } else { |
617 | ndev = (ndev < ARRAY_SIZE(dev_addrs)) |
618 | ? ndev : ARRAY_SIZE(dev_addrs); |
619 | ndev = device_property_read_u32_array(dev: &client->dev, |
620 | propname: "ti,audio-slots" , val: dev_addrs, nval: ndev); |
621 | } |
622 | |
623 | tas_priv->irq_info.irq_gpio = |
624 | acpi_dev_gpio_irq_get(ACPI_COMPANION(&client->dev), index: 0); |
625 | } else { |
626 | struct device_node *np = tas_priv->dev->of_node; |
627 | #ifdef CONFIG_OF |
628 | const __be32 *reg, *reg_end; |
629 | int len, sw, aw; |
630 | |
631 | aw = of_n_addr_cells(np); |
632 | sw = of_n_size_cells(np); |
633 | if (sw == 0) { |
634 | reg = (const __be32 *)of_get_property(node: np, |
635 | name: "reg" , lenp: &len); |
636 | reg_end = reg + len/sizeof(*reg); |
637 | ndev = 0; |
638 | do { |
639 | dev_addrs[ndev] = of_read_number(cell: reg, size: aw); |
640 | reg += aw; |
641 | ndev++; |
642 | } while (reg < reg_end); |
643 | } else { |
644 | ndev = 1; |
645 | dev_addrs[0] = client->addr; |
646 | } |
647 | #else |
648 | ndev = 1; |
649 | dev_addrs[0] = client->addr; |
650 | #endif |
651 | tas_priv->irq_info.irq_gpio = of_irq_get(dev: np, index: 0); |
652 | } |
653 | tas_priv->ndev = ndev; |
654 | for (i = 0; i < ndev; i++) |
655 | tas_priv->tasdevice[i].dev_addr = dev_addrs[i]; |
656 | |
657 | tas_priv->reset = devm_gpiod_get_optional(dev: &client->dev, |
658 | con_id: "reset-gpios" , flags: GPIOD_OUT_HIGH); |
659 | if (IS_ERR(ptr: tas_priv->reset)) |
660 | dev_err(tas_priv->dev, "%s Can't get reset GPIO\n" , |
661 | __func__); |
662 | |
663 | strcpy(p: tas_priv->dev_name, q: tasdevice_id[tas_priv->chip_id].name); |
664 | |
665 | if (gpio_is_valid(number: tas_priv->irq_info.irq_gpio)) { |
666 | rc = gpio_request(gpio: tas_priv->irq_info.irq_gpio, |
667 | label: "AUDEV-IRQ" ); |
668 | if (!rc) { |
669 | gpio_direction_input( |
670 | gpio: tas_priv->irq_info.irq_gpio); |
671 | |
672 | tas_priv->irq_info.irq = |
673 | gpio_to_irq(gpio: tas_priv->irq_info.irq_gpio); |
674 | } else |
675 | dev_err(tas_priv->dev, "%s: GPIO %d request error\n" , |
676 | __func__, tas_priv->irq_info.irq_gpio); |
677 | } else |
678 | dev_err(tas_priv->dev, |
679 | "Looking up irq-gpio property failed %d\n" , |
680 | tas_priv->irq_info.irq_gpio); |
681 | } |
682 | |
683 | static int tasdevice_i2c_probe(struct i2c_client *i2c) |
684 | { |
685 | const struct i2c_device_id *id = i2c_match_id(id: tasdevice_id, client: i2c); |
686 | const struct acpi_device_id *acpi_id; |
687 | struct tasdevice_priv *tas_priv; |
688 | int ret; |
689 | |
690 | tas_priv = tasdevice_kzalloc(i2c); |
691 | if (!tas_priv) |
692 | return -ENOMEM; |
693 | |
694 | dev_set_drvdata(dev: &i2c->dev, data: tas_priv); |
695 | |
696 | if (ACPI_HANDLE(&i2c->dev)) { |
697 | acpi_id = acpi_match_device(ids: i2c->dev.driver->acpi_match_table, |
698 | dev: &i2c->dev); |
699 | if (!acpi_id) { |
700 | dev_err(&i2c->dev, "No driver data\n" ); |
701 | ret = -EINVAL; |
702 | goto err; |
703 | } |
704 | tas_priv->chip_id = acpi_id->driver_data; |
705 | tas_priv->isacpi = true; |
706 | } else { |
707 | tas_priv->chip_id = id ? id->driver_data : 0; |
708 | tas_priv->isacpi = false; |
709 | } |
710 | |
711 | tasdevice_parse_dt(tas_priv); |
712 | |
713 | ret = tasdevice_init(tas_priv); |
714 | if (ret) |
715 | goto err; |
716 | |
717 | ret = devm_snd_soc_register_component(dev: tas_priv->dev, |
718 | component_driver: &soc_codec_driver_tasdevice, |
719 | dai_drv: tasdevice_dai_driver, ARRAY_SIZE(tasdevice_dai_driver)); |
720 | if (ret) { |
721 | dev_err(tas_priv->dev, "%s: codec register error:0x%08x\n" , |
722 | __func__, ret); |
723 | goto err; |
724 | } |
725 | err: |
726 | if (ret < 0) |
727 | tasdevice_remove(tas_priv); |
728 | return ret; |
729 | } |
730 | |
731 | static void tasdevice_i2c_remove(struct i2c_client *client) |
732 | { |
733 | struct tasdevice_priv *tas_priv = i2c_get_clientdata(client); |
734 | |
735 | tasdevice_remove(tas_priv); |
736 | } |
737 | |
738 | #ifdef CONFIG_ACPI |
739 | static const struct acpi_device_id tasdevice_acpi_match[] = { |
740 | { "TAS2781" , TAS2781 }, |
741 | {}, |
742 | }; |
743 | |
744 | MODULE_DEVICE_TABLE(acpi, tasdevice_acpi_match); |
745 | #endif |
746 | |
747 | static struct i2c_driver tasdevice_i2c_driver = { |
748 | .driver = { |
749 | .name = "tas2781-codec" , |
750 | .of_match_table = of_match_ptr(tasdevice_of_match), |
751 | #ifdef CONFIG_ACPI |
752 | .acpi_match_table = ACPI_PTR(tasdevice_acpi_match), |
753 | #endif |
754 | }, |
755 | .probe = tasdevice_i2c_probe, |
756 | .remove = tasdevice_i2c_remove, |
757 | .id_table = tasdevice_id, |
758 | }; |
759 | |
760 | module_i2c_driver(tasdevice_i2c_driver); |
761 | |
762 | MODULE_AUTHOR("Shenghao Ding <shenghao-ding@ti.com>" ); |
763 | MODULE_AUTHOR("Kevin Lu <kevin-lu@ti.com>" ); |
764 | MODULE_DESCRIPTION("ASoC TAS2781 Driver" ); |
765 | MODULE_LICENSE("GPL" ); |
766 | MODULE_IMPORT_NS(SND_SOC_TAS2781_FMWLIB); |
767 | |