1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // |
3 | // tegra186_asrc.c - Tegra186 ASRC driver |
4 | // |
5 | // Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. |
6 | |
7 | #include <linux/clk.h> |
8 | #include <linux/delay.h> |
9 | #include <linux/device.h> |
10 | #include <linux/io.h> |
11 | #include <linux/mod_devicetable.h> |
12 | #include <linux/module.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/pm_runtime.h> |
15 | #include <linux/regmap.h> |
16 | #include <sound/core.h> |
17 | #include <sound/pcm.h> |
18 | #include <sound/pcm_params.h> |
19 | #include <sound/soc.h> |
20 | |
21 | #include "tegra186_asrc.h" |
22 | #include "tegra_cif.h" |
23 | |
24 | #define ASRC_STREAM_SOURCE_SELECT(id) \ |
25 | (TEGRA186_ASRC_CFG + ((id) * TEGRA186_ASRC_STREAM_STRIDE)) |
26 | |
27 | #define ASRC_STREAM_REG(reg, id) ((reg) + ((id) * TEGRA186_ASRC_STREAM_STRIDE)) |
28 | |
29 | #define ASRC_STREAM_REG_DEFAULTS(id) \ |
30 | { ASRC_STREAM_REG(TEGRA186_ASRC_CFG, id), \ |
31 | (((id) + 1) << 4) }, \ |
32 | { ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, id), \ |
33 | 0x1 }, \ |
34 | { ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, id), \ |
35 | 0x0 }, \ |
36 | { ASRC_STREAM_REG(TEGRA186_ASRC_MUTE_UNMUTE_DURATION, id), \ |
37 | 0x400 }, \ |
38 | { ASRC_STREAM_REG(TEGRA186_ASRC_RX_CIF_CTRL, id), \ |
39 | 0x7500 }, \ |
40 | { ASRC_STREAM_REG(TEGRA186_ASRC_TX_CIF_CTRL, id), \ |
41 | 0x7500 } |
42 | |
43 | static const struct reg_default tegra186_asrc_reg_defaults[] = { |
44 | ASRC_STREAM_REG_DEFAULTS(0), |
45 | ASRC_STREAM_REG_DEFAULTS(1), |
46 | ASRC_STREAM_REG_DEFAULTS(2), |
47 | ASRC_STREAM_REG_DEFAULTS(3), |
48 | ASRC_STREAM_REG_DEFAULTS(4), |
49 | ASRC_STREAM_REG_DEFAULTS(5), |
50 | |
51 | { TEGRA186_ASRC_GLOBAL_ENB, 0}, |
52 | { TEGRA186_ASRC_GLOBAL_SOFT_RESET, 0}, |
53 | { TEGRA186_ASRC_GLOBAL_CG, 0x1 }, |
54 | { TEGRA186_ASRC_GLOBAL_CFG, 0x0 }, |
55 | { TEGRA186_ASRC_GLOBAL_SCRATCH_ADDR, 0}, |
56 | { TEGRA186_ASRC_GLOBAL_SCRATCH_CFG, 0x0c207980 }, |
57 | { TEGRA186_ASRC_RATIO_UPD_RX_CIF_CTRL, 0x00115500 }, |
58 | { TEGRA186_ASRC_GLOBAL_INT_MASK, 0x0}, |
59 | { TEGRA186_ASRC_GLOBAL_INT_SET, 0x0}, |
60 | { TEGRA186_ASRC_GLOBAL_INT_CLEAR, 0x0}, |
61 | { TEGRA186_ASRC_GLOBAL_APR_CTRL, 0x0}, |
62 | { TEGRA186_ASRC_GLOBAL_APR_CTRL_ACCESS_CTRL, 0x0}, |
63 | { TEGRA186_ASRC_GLOBAL_DISARM_APR, 0x0}, |
64 | { TEGRA186_ASRC_GLOBAL_DISARM_APR_ACCESS_CTRL, 0x0}, |
65 | { TEGRA186_ASRC_GLOBAL_RATIO_WR_ACCESS, 0x0}, |
66 | { TEGRA186_ASRC_GLOBAL_RATIO_WR_ACCESS_CTRL, 0x0}, |
67 | { TEGRA186_ASRC_CYA, 0x0}, |
68 | }; |
69 | |
70 | static void tegra186_asrc_lock_stream(struct tegra186_asrc *asrc, |
71 | unsigned int id) |
72 | { |
73 | regmap_write(map: asrc->regmap, |
74 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_LOCK_STATUS, |
75 | id), |
76 | val: 1); |
77 | } |
78 | |
79 | static int __maybe_unused tegra186_asrc_runtime_suspend(struct device *dev) |
80 | { |
81 | struct tegra186_asrc *asrc = dev_get_drvdata(dev); |
82 | |
83 | regcache_cache_only(map: asrc->regmap, enable: true); |
84 | regcache_mark_dirty(map: asrc->regmap); |
85 | |
86 | return 0; |
87 | } |
88 | |
89 | static int __maybe_unused tegra186_asrc_runtime_resume(struct device *dev) |
90 | { |
91 | struct tegra186_asrc *asrc = dev_get_drvdata(dev); |
92 | int id; |
93 | |
94 | regcache_cache_only(map: asrc->regmap, enable: false); |
95 | |
96 | /* |
97 | * Below sequence is recommended after a runtime PM cycle. |
98 | * This otherwise leads to transfer failures. The cache |
99 | * sync is done after this to restore other settings. |
100 | */ |
101 | regmap_write(map: asrc->regmap, TEGRA186_ASRC_GLOBAL_SCRATCH_ADDR, |
102 | TEGRA186_ASRC_ARAM_START_ADDR); |
103 | regmap_write(map: asrc->regmap, TEGRA186_ASRC_GLOBAL_ENB, |
104 | TEGRA186_ASRC_GLOBAL_EN); |
105 | |
106 | regcache_sync(map: asrc->regmap); |
107 | |
108 | for (id = 0; id < TEGRA186_ASRC_STREAM_MAX; id++) { |
109 | if (asrc->lane[id].ratio_source != |
110 | TEGRA186_ASRC_RATIO_SOURCE_SW) |
111 | continue; |
112 | |
113 | regmap_write(map: asrc->regmap, |
114 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, |
115 | id), |
116 | val: asrc->lane[id].int_part); |
117 | |
118 | regmap_write(map: asrc->regmap, |
119 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, |
120 | id), |
121 | val: asrc->lane[id].frac_part); |
122 | |
123 | tegra186_asrc_lock_stream(asrc, id); |
124 | } |
125 | |
126 | return 0; |
127 | } |
128 | |
129 | static int tegra186_asrc_set_audio_cif(struct tegra186_asrc *asrc, |
130 | struct snd_pcm_hw_params *params, |
131 | unsigned int reg) |
132 | { |
133 | int channels, audio_bits; |
134 | struct tegra_cif_conf cif_conf; |
135 | |
136 | memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); |
137 | |
138 | channels = params_channels(p: params); |
139 | |
140 | switch (params_format(p: params)) { |
141 | case SNDRV_PCM_FORMAT_S16_LE: |
142 | audio_bits = TEGRA_ACIF_BITS_16; |
143 | break; |
144 | case SNDRV_PCM_FORMAT_S24_LE: |
145 | case SNDRV_PCM_FORMAT_S32_LE: |
146 | audio_bits = TEGRA_ACIF_BITS_32; |
147 | break; |
148 | default: |
149 | return -EINVAL; |
150 | } |
151 | |
152 | cif_conf.audio_ch = channels; |
153 | cif_conf.client_ch = channels; |
154 | cif_conf.audio_bits = audio_bits; |
155 | cif_conf.client_bits = TEGRA_ACIF_BITS_24; |
156 | |
157 | tegra_set_cif(regmap: asrc->regmap, reg, conf: &cif_conf); |
158 | |
159 | return 0; |
160 | } |
161 | |
162 | static int tegra186_asrc_in_hw_params(struct snd_pcm_substream *substream, |
163 | struct snd_pcm_hw_params *params, |
164 | struct snd_soc_dai *dai) |
165 | { |
166 | struct device *dev = dai->dev; |
167 | struct tegra186_asrc *asrc = snd_soc_dai_get_drvdata(dai); |
168 | int ret, id = dai->id; |
169 | |
170 | /* Set input threshold */ |
171 | regmap_write(map: asrc->regmap, |
172 | ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, dai->id), |
173 | val: asrc->lane[id].input_thresh); |
174 | |
175 | ret = tegra186_asrc_set_audio_cif(asrc, params, |
176 | ASRC_STREAM_REG(TEGRA186_ASRC_RX_CIF_CTRL, dai->id)); |
177 | if (ret) { |
178 | dev_err(dev, "Can't set ASRC RX%d CIF: %d\n" , dai->id, ret); |
179 | return ret; |
180 | } |
181 | |
182 | return ret; |
183 | } |
184 | |
185 | static int tegra186_asrc_out_hw_params(struct snd_pcm_substream *substream, |
186 | struct snd_pcm_hw_params *params, |
187 | struct snd_soc_dai *dai) |
188 | { |
189 | struct device *dev = dai->dev; |
190 | struct tegra186_asrc *asrc = snd_soc_dai_get_drvdata(dai); |
191 | int ret, id = dai->id - 7; |
192 | |
193 | /* Set output threshold */ |
194 | regmap_write(map: asrc->regmap, |
195 | ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, id), |
196 | val: asrc->lane[id].output_thresh); |
197 | |
198 | ret = tegra186_asrc_set_audio_cif(asrc, params, |
199 | ASRC_STREAM_REG(TEGRA186_ASRC_TX_CIF_CTRL, id)); |
200 | if (ret) { |
201 | dev_err(dev, "Can't set ASRC TX%d CIF: %d\n" , id, ret); |
202 | return ret; |
203 | } |
204 | |
205 | /* Set ENABLE_HW_RATIO_COMP */ |
206 | if (asrc->lane[id].hwcomp_disable) { |
207 | regmap_update_bits(map: asrc->regmap, |
208 | ASRC_STREAM_REG(TEGRA186_ASRC_CFG, id), |
209 | TEGRA186_ASRC_STREAM_ENABLE_HW_RATIO_COMP_MASK, |
210 | TEGRA186_ASRC_STREAM_ENABLE_HW_RATIO_COMP_DISABLE); |
211 | } else { |
212 | regmap_update_bits(map: asrc->regmap, |
213 | ASRC_STREAM_REG(TEGRA186_ASRC_CFG, id), |
214 | TEGRA186_ASRC_STREAM_ENABLE_HW_RATIO_COMP_MASK, |
215 | TEGRA186_ASRC_STREAM_ENABLE_HW_RATIO_COMP_ENABLE); |
216 | |
217 | regmap_write(map: asrc->regmap, |
218 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_COMP, id), |
219 | TEGRA186_ASRC_STREAM_DEFAULT_HW_COMP_BIAS_VALUE); |
220 | } |
221 | |
222 | /* Set lock */ |
223 | regmap_update_bits(map: asrc->regmap, |
224 | ASRC_STREAM_REG(TEGRA186_ASRC_CFG, id), |
225 | mask: 1, val: asrc->lane[id].ratio_source); |
226 | |
227 | if (asrc->lane[id].ratio_source == TEGRA186_ASRC_RATIO_SOURCE_SW) { |
228 | regmap_write(map: asrc->regmap, |
229 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, id), |
230 | val: asrc->lane[id].int_part); |
231 | regmap_write(map: asrc->regmap, |
232 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, id), |
233 | val: asrc->lane[id].frac_part); |
234 | tegra186_asrc_lock_stream(asrc, id); |
235 | } |
236 | |
237 | return ret; |
238 | } |
239 | |
240 | static int tegra186_asrc_get_ratio_source(struct snd_kcontrol *kcontrol, |
241 | struct snd_ctl_elem_value *ucontrol) |
242 | { |
243 | struct soc_enum *asrc_private = |
244 | (struct soc_enum *)kcontrol->private_value; |
245 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
246 | struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(c: cmpnt); |
247 | unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE; |
248 | |
249 | ucontrol->value.enumerated.item[0] = asrc->lane[id].ratio_source; |
250 | |
251 | return 0; |
252 | } |
253 | |
254 | static int tegra186_asrc_put_ratio_source(struct snd_kcontrol *kcontrol, |
255 | struct snd_ctl_elem_value *ucontrol) |
256 | { |
257 | struct soc_enum *asrc_private = |
258 | (struct soc_enum *)kcontrol->private_value; |
259 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
260 | struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(c: cmpnt); |
261 | unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE; |
262 | bool change = false; |
263 | |
264 | asrc->lane[id].ratio_source = ucontrol->value.enumerated.item[0]; |
265 | |
266 | regmap_update_bits_check(map: asrc->regmap, reg: asrc_private->reg, |
267 | TEGRA186_ASRC_STREAM_RATIO_TYPE_MASK, |
268 | val: asrc->lane[id].ratio_source, |
269 | change: &change); |
270 | |
271 | return change ? 1 : 0; |
272 | } |
273 | |
274 | static int tegra186_asrc_get_ratio_int(struct snd_kcontrol *kcontrol, |
275 | struct snd_ctl_elem_value *ucontrol) |
276 | { |
277 | struct soc_mixer_control *asrc_private = |
278 | (struct soc_mixer_control *)kcontrol->private_value; |
279 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
280 | struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(c: cmpnt); |
281 | unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE; |
282 | |
283 | regmap_read(map: asrc->regmap, |
284 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, id), |
285 | val: &asrc->lane[id].int_part); |
286 | |
287 | ucontrol->value.integer.value[0] = asrc->lane[id].int_part; |
288 | |
289 | return 0; |
290 | } |
291 | |
292 | static int tegra186_asrc_put_ratio_int(struct snd_kcontrol *kcontrol, |
293 | struct snd_ctl_elem_value *ucontrol) |
294 | { |
295 | struct soc_mixer_control *asrc_private = |
296 | (struct soc_mixer_control *)kcontrol->private_value; |
297 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
298 | struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(c: cmpnt); |
299 | unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE; |
300 | bool change = false; |
301 | |
302 | if (asrc->lane[id].ratio_source == TEGRA186_ASRC_RATIO_SOURCE_ARAD) { |
303 | dev_err(cmpnt->dev, |
304 | "Lane %d ratio source is ARAD, invalid SW update\n" , |
305 | id); |
306 | return -EINVAL; |
307 | } |
308 | |
309 | asrc->lane[id].int_part = ucontrol->value.integer.value[0]; |
310 | |
311 | regmap_update_bits_check(map: asrc->regmap, |
312 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, |
313 | id), |
314 | TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, |
315 | val: asrc->lane[id].int_part, change: &change); |
316 | |
317 | tegra186_asrc_lock_stream(asrc, id); |
318 | |
319 | return change ? 1 : 0; |
320 | } |
321 | |
322 | static int tegra186_asrc_get_ratio_frac(struct snd_kcontrol *kcontrol, |
323 | struct snd_ctl_elem_value *ucontrol) |
324 | { |
325 | struct soc_mreg_control *asrc_private = |
326 | (struct soc_mreg_control *)kcontrol->private_value; |
327 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
328 | struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(c: cmpnt); |
329 | unsigned int id = asrc_private->regbase / TEGRA186_ASRC_STREAM_STRIDE; |
330 | |
331 | regmap_read(map: asrc->regmap, |
332 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, id), |
333 | val: &asrc->lane[id].frac_part); |
334 | |
335 | ucontrol->value.integer.value[0] = asrc->lane[id].frac_part; |
336 | |
337 | return 0; |
338 | } |
339 | |
340 | static int tegra186_asrc_put_ratio_frac(struct snd_kcontrol *kcontrol, |
341 | struct snd_ctl_elem_value *ucontrol) |
342 | { |
343 | struct soc_mreg_control *asrc_private = |
344 | (struct soc_mreg_control *)kcontrol->private_value; |
345 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
346 | struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(c: cmpnt); |
347 | unsigned int id = asrc_private->regbase / TEGRA186_ASRC_STREAM_STRIDE; |
348 | bool change = false; |
349 | |
350 | if (asrc->lane[id].ratio_source == TEGRA186_ASRC_RATIO_SOURCE_ARAD) { |
351 | dev_err(cmpnt->dev, |
352 | "Lane %d ratio source is ARAD, invalid SW update\n" , |
353 | id); |
354 | return -EINVAL; |
355 | } |
356 | |
357 | asrc->lane[id].frac_part = ucontrol->value.integer.value[0]; |
358 | |
359 | regmap_update_bits_check(map: asrc->regmap, |
360 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, |
361 | id), |
362 | TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK, |
363 | val: asrc->lane[id].frac_part, change: &change); |
364 | |
365 | tegra186_asrc_lock_stream(asrc, id); |
366 | |
367 | return change ? 1 : 0; |
368 | } |
369 | |
370 | static int tegra186_asrc_get_hwcomp_disable(struct snd_kcontrol *kcontrol, |
371 | struct snd_ctl_elem_value *ucontrol) |
372 | { |
373 | struct soc_mixer_control *asrc_private = |
374 | (struct soc_mixer_control *)kcontrol->private_value; |
375 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
376 | struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(c: cmpnt); |
377 | unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE; |
378 | |
379 | ucontrol->value.integer.value[0] = asrc->lane[id].hwcomp_disable; |
380 | |
381 | return 0; |
382 | } |
383 | |
384 | static int tegra186_asrc_put_hwcomp_disable(struct snd_kcontrol *kcontrol, |
385 | struct snd_ctl_elem_value *ucontrol) |
386 | { |
387 | struct soc_mixer_control *asrc_private = |
388 | (struct soc_mixer_control *)kcontrol->private_value; |
389 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
390 | struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(c: cmpnt); |
391 | unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE; |
392 | int value = ucontrol->value.integer.value[0]; |
393 | |
394 | if (value == asrc->lane[id].hwcomp_disable) |
395 | return 0; |
396 | |
397 | asrc->lane[id].hwcomp_disable = value; |
398 | |
399 | return 1; |
400 | } |
401 | |
402 | static int tegra186_asrc_get_input_threshold(struct snd_kcontrol *kcontrol, |
403 | struct snd_ctl_elem_value *ucontrol) |
404 | { |
405 | struct soc_mixer_control *asrc_private = |
406 | (struct soc_mixer_control *)kcontrol->private_value; |
407 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
408 | struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(c: cmpnt); |
409 | unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE; |
410 | |
411 | ucontrol->value.integer.value[0] = (asrc->lane[id].input_thresh & 0x3); |
412 | |
413 | return 0; |
414 | } |
415 | |
416 | static int tegra186_asrc_put_input_threshold(struct snd_kcontrol *kcontrol, |
417 | struct snd_ctl_elem_value *ucontrol) |
418 | { |
419 | struct soc_mixer_control *asrc_private = |
420 | (struct soc_mixer_control *)kcontrol->private_value; |
421 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
422 | struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(c: cmpnt); |
423 | unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE; |
424 | int value = (asrc->lane[id].input_thresh & ~(0x3)) | |
425 | ucontrol->value.integer.value[0]; |
426 | |
427 | if (value == asrc->lane[id].input_thresh) |
428 | return 0; |
429 | |
430 | asrc->lane[id].input_thresh = value; |
431 | |
432 | return 1; |
433 | } |
434 | |
435 | static int tegra186_asrc_get_output_threshold(struct snd_kcontrol *kcontrol, |
436 | struct snd_ctl_elem_value *ucontrol) |
437 | { |
438 | struct soc_mixer_control *asrc_private = |
439 | (struct soc_mixer_control *)kcontrol->private_value; |
440 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
441 | struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(c: cmpnt); |
442 | unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE; |
443 | |
444 | ucontrol->value.integer.value[0] = (asrc->lane[id].output_thresh & 0x3); |
445 | |
446 | return 0; |
447 | } |
448 | |
449 | static int tegra186_asrc_put_output_threshold(struct snd_kcontrol *kcontrol, |
450 | struct snd_ctl_elem_value *ucontrol) |
451 | { |
452 | struct soc_mixer_control *asrc_private = |
453 | (struct soc_mixer_control *)kcontrol->private_value; |
454 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
455 | struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(c: cmpnt); |
456 | unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE; |
457 | int value = (asrc->lane[id].output_thresh & ~(0x3)) | |
458 | ucontrol->value.integer.value[0]; |
459 | |
460 | if (value == asrc->lane[id].output_thresh) |
461 | return 0; |
462 | |
463 | asrc->lane[id].output_thresh = value; |
464 | |
465 | return 1; |
466 | } |
467 | |
468 | static int tegra186_asrc_widget_event(struct snd_soc_dapm_widget *w, |
469 | struct snd_kcontrol *kcontrol, int event) |
470 | { |
471 | struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(dapm: w->dapm); |
472 | struct tegra186_asrc *asrc = dev_get_drvdata(dev: cmpnt->dev); |
473 | unsigned int id = |
474 | (w->reg - TEGRA186_ASRC_ENABLE) / TEGRA186_ASRC_STREAM_STRIDE; |
475 | |
476 | regmap_write(map: asrc->regmap, |
477 | ASRC_STREAM_REG(TEGRA186_ASRC_SOFT_RESET, id), |
478 | val: 0x1); |
479 | |
480 | return 0; |
481 | } |
482 | |
483 | static const struct snd_soc_dai_ops tegra186_asrc_in_dai_ops = { |
484 | .hw_params = tegra186_asrc_in_hw_params, |
485 | }; |
486 | |
487 | static const struct snd_soc_dai_ops tegra186_asrc_out_dai_ops = { |
488 | .hw_params = tegra186_asrc_out_hw_params, |
489 | }; |
490 | |
491 | #define IN_DAI(id) \ |
492 | { \ |
493 | .name = "ASRC-RX-CIF"#id, \ |
494 | .playback = { \ |
495 | .stream_name = "RX" #id "-CIF-Playback",\ |
496 | .channels_min = 1, \ |
497 | .channels_max = 12, \ |
498 | .rates = SNDRV_PCM_RATE_8000_192000, \ |
499 | .formats = SNDRV_PCM_FMTBIT_S8 | \ |
500 | SNDRV_PCM_FMTBIT_S16_LE | \ |
501 | SNDRV_PCM_FMTBIT_S24_LE | \ |
502 | SNDRV_PCM_FMTBIT_S32_LE, \ |
503 | }, \ |
504 | .capture = { \ |
505 | .stream_name = "RX" #id "-CIF-Capture", \ |
506 | .channels_min = 1, \ |
507 | .channels_max = 12, \ |
508 | .rates = SNDRV_PCM_RATE_8000_192000, \ |
509 | .formats = SNDRV_PCM_FMTBIT_S8 | \ |
510 | SNDRV_PCM_FMTBIT_S16_LE | \ |
511 | SNDRV_PCM_FMTBIT_S24_LE | \ |
512 | SNDRV_PCM_FMTBIT_S32_LE, \ |
513 | }, \ |
514 | .ops = &tegra186_asrc_in_dai_ops, \ |
515 | } |
516 | |
517 | #define OUT_DAI(id) \ |
518 | { \ |
519 | .name = "ASRC-TX-CIF"#id, \ |
520 | .playback = { \ |
521 | .stream_name = "TX" #id "-CIF-Playback",\ |
522 | .channels_min = 1, \ |
523 | .channels_max = 12, \ |
524 | .rates = SNDRV_PCM_RATE_8000_192000, \ |
525 | .formats = SNDRV_PCM_FMTBIT_S8 | \ |
526 | SNDRV_PCM_FMTBIT_S16_LE | \ |
527 | SNDRV_PCM_FMTBIT_S24_LE | \ |
528 | SNDRV_PCM_FMTBIT_S32_LE, \ |
529 | }, \ |
530 | .capture = { \ |
531 | .stream_name = "TX" #id "-CIF-Capture", \ |
532 | .channels_min = 1, \ |
533 | .channels_max = 12, \ |
534 | .rates = SNDRV_PCM_RATE_8000_192000, \ |
535 | .formats = SNDRV_PCM_FMTBIT_S8 | \ |
536 | SNDRV_PCM_FMTBIT_S16_LE | \ |
537 | SNDRV_PCM_FMTBIT_S24_LE | \ |
538 | SNDRV_PCM_FMTBIT_S32_LE, \ |
539 | }, \ |
540 | .ops = &tegra186_asrc_out_dai_ops, \ |
541 | } |
542 | |
543 | static struct snd_soc_dai_driver tegra186_asrc_dais[] = { |
544 | /* ASRC Input */ |
545 | IN_DAI(1), |
546 | IN_DAI(2), |
547 | IN_DAI(3), |
548 | IN_DAI(4), |
549 | IN_DAI(5), |
550 | IN_DAI(6), |
551 | IN_DAI(7), |
552 | /* ASRC Output */ |
553 | OUT_DAI(1), |
554 | OUT_DAI(2), |
555 | OUT_DAI(3), |
556 | OUT_DAI(4), |
557 | OUT_DAI(5), |
558 | OUT_DAI(6), |
559 | }; |
560 | |
561 | static const struct snd_soc_dapm_widget tegra186_asrc_widgets[] = { |
562 | SND_SOC_DAPM_AIF_IN("RX1" , NULL, 0, SND_SOC_NOPM, 0, 0), |
563 | SND_SOC_DAPM_AIF_IN("RX2" , NULL, 0, SND_SOC_NOPM, 0, 0), |
564 | SND_SOC_DAPM_AIF_IN("RX3" , NULL, 0, SND_SOC_NOPM, 0, 0), |
565 | SND_SOC_DAPM_AIF_IN("RX4" , NULL, 0, SND_SOC_NOPM, 0, 0), |
566 | SND_SOC_DAPM_AIF_IN("RX5" , NULL, 0, SND_SOC_NOPM, 0, 0), |
567 | SND_SOC_DAPM_AIF_IN("RX6" , NULL, 0, SND_SOC_NOPM, 0, 0), |
568 | SND_SOC_DAPM_AIF_IN("RX7" , NULL, 0, SND_SOC_NOPM, 0, 0), |
569 | |
570 | SND_SOC_DAPM_AIF_OUT_E("TX1" , NULL, 0, |
571 | ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 0), |
572 | TEGRA186_ASRC_STREAM_EN_SHIFT, 0, |
573 | tegra186_asrc_widget_event, |
574 | SND_SOC_DAPM_POST_PMD), |
575 | |
576 | SND_SOC_DAPM_AIF_OUT_E("TX2" , NULL, 0, |
577 | ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 1), |
578 | TEGRA186_ASRC_STREAM_EN_SHIFT, 0, |
579 | tegra186_asrc_widget_event, |
580 | SND_SOC_DAPM_POST_PMD), |
581 | |
582 | SND_SOC_DAPM_AIF_OUT_E("TX3" , NULL, 0, |
583 | ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 2), |
584 | TEGRA186_ASRC_STREAM_EN_SHIFT, 0, |
585 | tegra186_asrc_widget_event, |
586 | SND_SOC_DAPM_POST_PMD), |
587 | |
588 | SND_SOC_DAPM_AIF_OUT_E("TX4" , NULL, 0, |
589 | ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 3), |
590 | TEGRA186_ASRC_STREAM_EN_SHIFT, 0, |
591 | tegra186_asrc_widget_event, |
592 | SND_SOC_DAPM_POST_PMD), |
593 | |
594 | SND_SOC_DAPM_AIF_OUT_E("TX5" , NULL, 0, |
595 | ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 4), |
596 | TEGRA186_ASRC_STREAM_EN_SHIFT, 0, |
597 | tegra186_asrc_widget_event, |
598 | SND_SOC_DAPM_POST_PMD), |
599 | |
600 | SND_SOC_DAPM_AIF_OUT_E("TX6" , NULL, 0, |
601 | ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 5), |
602 | TEGRA186_ASRC_STREAM_EN_SHIFT, 0, |
603 | tegra186_asrc_widget_event, |
604 | SND_SOC_DAPM_POST_PMD), |
605 | |
606 | SND_SOC_DAPM_SPK("Depacketizer" , NULL), |
607 | }; |
608 | |
609 | #define ASRC_STREAM_ROUTE(id, sname) \ |
610 | { "RX" #id " XBAR-" sname, NULL, "RX" #id " XBAR-TX" }, \ |
611 | { "RX" #id "-CIF-" sname, NULL, "RX" #id " XBAR-" sname }, \ |
612 | { "RX" #id, NULL, "RX" #id "-CIF-" sname }, \ |
613 | { "TX" #id, NULL, "RX" #id }, \ |
614 | { "TX" #id "-CIF-" sname, NULL, "TX" #id }, \ |
615 | { "TX" #id " XBAR-" sname, NULL, "TX" #id "-CIF-" sname }, \ |
616 | { "TX" #id " XBAR-RX", NULL, "TX" #id " XBAR-" sname }, |
617 | |
618 | #define ASRC_ROUTE(id) \ |
619 | ASRC_STREAM_ROUTE(id, "Playback") \ |
620 | ASRC_STREAM_ROUTE(id, "Capture") |
621 | |
622 | #define ASRC_RATIO_ROUTE(sname) \ |
623 | { "RX7 XBAR-" sname, NULL, "RX7 XBAR-TX" }, \ |
624 | { "RX7-CIF-" sname, NULL, "RX7 XBAR-" sname }, \ |
625 | { "RX7", NULL, "RX7-CIF-" sname }, \ |
626 | { "Depacketizer", NULL, "RX7" }, |
627 | |
628 | static const struct snd_soc_dapm_route tegra186_asrc_routes[] = { |
629 | ASRC_ROUTE(1) |
630 | ASRC_ROUTE(2) |
631 | ASRC_ROUTE(3) |
632 | ASRC_ROUTE(4) |
633 | ASRC_ROUTE(5) |
634 | ASRC_ROUTE(6) |
635 | ASRC_RATIO_ROUTE("Playback" ) |
636 | ASRC_RATIO_ROUTE("Capture" ) |
637 | }; |
638 | |
639 | static const char * const tegra186_asrc_ratio_source_text[] = { |
640 | "ARAD" , |
641 | "SW" , |
642 | }; |
643 | |
644 | #define ASRC_SOURCE_DECL(name, id) \ |
645 | static const struct soc_enum name = \ |
646 | SOC_ENUM_SINGLE(ASRC_STREAM_SOURCE_SELECT(id), \ |
647 | 0, 2, tegra186_asrc_ratio_source_text) |
648 | |
649 | ASRC_SOURCE_DECL(src_select1, 0); |
650 | ASRC_SOURCE_DECL(src_select2, 1); |
651 | ASRC_SOURCE_DECL(src_select3, 2); |
652 | ASRC_SOURCE_DECL(src_select4, 3); |
653 | ASRC_SOURCE_DECL(src_select5, 4); |
654 | ASRC_SOURCE_DECL(src_select6, 5); |
655 | |
656 | #define SOC_SINGLE_EXT_FRAC(xname, xregbase, xmax, xget, xput) \ |
657 | { \ |
658 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
659 | .name = (xname), \ |
660 | .info = snd_soc_info_xr_sx, \ |
661 | .get = xget, \ |
662 | .put = xput, \ |
663 | \ |
664 | .private_value = (unsigned long)&(struct soc_mreg_control) \ |
665 | { \ |
666 | .regbase = xregbase, \ |
667 | .regcount = 1, \ |
668 | .nbits = 32, \ |
669 | .invert = 0, \ |
670 | .min = 0, \ |
671 | .max = xmax \ |
672 | } \ |
673 | } |
674 | |
675 | static const struct snd_kcontrol_new tegra186_asrc_controls[] = { |
676 | /* Controls for integer part of ratio */ |
677 | SOC_SINGLE_EXT("Ratio1 Integer Part" , |
678 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 0), |
679 | 0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0, |
680 | tegra186_asrc_get_ratio_int, |
681 | tegra186_asrc_put_ratio_int), |
682 | |
683 | SOC_SINGLE_EXT("Ratio2 Integer Part" , |
684 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 1), |
685 | 0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0, |
686 | tegra186_asrc_get_ratio_int, |
687 | tegra186_asrc_put_ratio_int), |
688 | |
689 | SOC_SINGLE_EXT("Ratio3 Integer Part" , |
690 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 2), |
691 | 0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0, |
692 | tegra186_asrc_get_ratio_int, |
693 | tegra186_asrc_put_ratio_int), |
694 | |
695 | SOC_SINGLE_EXT("Ratio4 Integer Part" , |
696 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 3), |
697 | 0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0, |
698 | tegra186_asrc_get_ratio_int, |
699 | tegra186_asrc_put_ratio_int), |
700 | |
701 | SOC_SINGLE_EXT("Ratio5 Integer Part" , |
702 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 4), |
703 | 0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0, |
704 | tegra186_asrc_get_ratio_int, |
705 | tegra186_asrc_put_ratio_int), |
706 | |
707 | SOC_SINGLE_EXT("Ratio6 Integer Part" , |
708 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 5), |
709 | 0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0, |
710 | tegra186_asrc_get_ratio_int, |
711 | tegra186_asrc_put_ratio_int), |
712 | |
713 | /* Controls for fractional part of ratio */ |
714 | SOC_SINGLE_EXT_FRAC("Ratio1 Fractional Part" , |
715 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 0), |
716 | TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK, |
717 | tegra186_asrc_get_ratio_frac, |
718 | tegra186_asrc_put_ratio_frac), |
719 | |
720 | SOC_SINGLE_EXT_FRAC("Ratio2 Fractional Part" , |
721 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 1), |
722 | TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK, |
723 | tegra186_asrc_get_ratio_frac, |
724 | tegra186_asrc_put_ratio_frac), |
725 | |
726 | SOC_SINGLE_EXT_FRAC("Ratio3 Fractional Part" , |
727 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 2), |
728 | TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK, |
729 | tegra186_asrc_get_ratio_frac, |
730 | tegra186_asrc_put_ratio_frac), |
731 | |
732 | SOC_SINGLE_EXT_FRAC("Ratio4 Fractional Part" , |
733 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 3), |
734 | TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK, |
735 | tegra186_asrc_get_ratio_frac, |
736 | tegra186_asrc_put_ratio_frac), |
737 | |
738 | SOC_SINGLE_EXT_FRAC("Ratio5 Fractional Part" , |
739 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 4), |
740 | TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK, |
741 | tegra186_asrc_get_ratio_frac, |
742 | tegra186_asrc_put_ratio_frac), |
743 | |
744 | SOC_SINGLE_EXT_FRAC("Ratio6 Fractional Part" , |
745 | ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 5), |
746 | TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK, |
747 | tegra186_asrc_get_ratio_frac, |
748 | tegra186_asrc_put_ratio_frac), |
749 | |
750 | /* Source of ratio provider */ |
751 | SOC_ENUM_EXT("Ratio1 Source" , src_select1, |
752 | tegra186_asrc_get_ratio_source, |
753 | tegra186_asrc_put_ratio_source), |
754 | |
755 | SOC_ENUM_EXT("Ratio2 Source" , src_select2, |
756 | tegra186_asrc_get_ratio_source, |
757 | tegra186_asrc_put_ratio_source), |
758 | |
759 | SOC_ENUM_EXT("Ratio3 Source" , src_select3, |
760 | tegra186_asrc_get_ratio_source, |
761 | tegra186_asrc_put_ratio_source), |
762 | |
763 | SOC_ENUM_EXT("Ratio4 Source" , src_select4, |
764 | tegra186_asrc_get_ratio_source, |
765 | tegra186_asrc_put_ratio_source), |
766 | |
767 | SOC_ENUM_EXT("Ratio5 Source" , src_select5, |
768 | tegra186_asrc_get_ratio_source, |
769 | tegra186_asrc_put_ratio_source), |
770 | |
771 | SOC_ENUM_EXT("Ratio6 Source" , src_select6, |
772 | tegra186_asrc_get_ratio_source, |
773 | tegra186_asrc_put_ratio_source), |
774 | |
775 | /* Disable HW managed overflow/underflow issue at input and output */ |
776 | SOC_SINGLE_EXT("Stream1 HW Component Disable" , |
777 | ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 0), 0, 1, 0, |
778 | tegra186_asrc_get_hwcomp_disable, |
779 | tegra186_asrc_put_hwcomp_disable), |
780 | |
781 | SOC_SINGLE_EXT("Stream2 HW Component Disable" , |
782 | ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 1), 0, 1, 0, |
783 | tegra186_asrc_get_hwcomp_disable, |
784 | tegra186_asrc_put_hwcomp_disable), |
785 | |
786 | SOC_SINGLE_EXT("Stream3 HW Component Disable" , |
787 | ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 2), 0, 1, 0, |
788 | tegra186_asrc_get_hwcomp_disable, |
789 | tegra186_asrc_put_hwcomp_disable), |
790 | |
791 | SOC_SINGLE_EXT("Stream4 HW Component Disable" , |
792 | ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 3), 0, 1, 0, |
793 | tegra186_asrc_get_hwcomp_disable, |
794 | tegra186_asrc_put_hwcomp_disable), |
795 | |
796 | SOC_SINGLE_EXT("Stream5 HW Component Disable" , |
797 | ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 4), 0, 1, 0, |
798 | tegra186_asrc_get_hwcomp_disable, |
799 | tegra186_asrc_put_hwcomp_disable), |
800 | |
801 | SOC_SINGLE_EXT("Stream6 HW Component Disable" , |
802 | ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 5), 0, 1, 0, |
803 | tegra186_asrc_get_hwcomp_disable, |
804 | tegra186_asrc_put_hwcomp_disable), |
805 | |
806 | /* Input threshold for watermark fields */ |
807 | SOC_SINGLE_EXT("Stream1 Input Threshold" , |
808 | ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 0), 0, 3, 0, |
809 | tegra186_asrc_get_input_threshold, |
810 | tegra186_asrc_put_input_threshold), |
811 | |
812 | SOC_SINGLE_EXT("Stream2 Input Threshold" , |
813 | ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 1), 0, 3, 0, |
814 | tegra186_asrc_get_input_threshold, |
815 | tegra186_asrc_put_input_threshold), |
816 | |
817 | SOC_SINGLE_EXT("Stream3 Input Threshold" , |
818 | ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 2), 0, 3, 0, |
819 | tegra186_asrc_get_input_threshold, |
820 | tegra186_asrc_put_input_threshold), |
821 | |
822 | SOC_SINGLE_EXT("Stream4 Input Threshold" , |
823 | ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 3), 0, 3, 0, |
824 | tegra186_asrc_get_input_threshold, |
825 | tegra186_asrc_put_input_threshold), |
826 | |
827 | SOC_SINGLE_EXT("Stream5 Input Threshold" , |
828 | ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 4), 0, 3, 0, |
829 | tegra186_asrc_get_input_threshold, |
830 | tegra186_asrc_put_input_threshold), |
831 | |
832 | SOC_SINGLE_EXT("Stream6 Input Threshold" , |
833 | ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 4), 0, 3, 0, |
834 | tegra186_asrc_get_input_threshold, |
835 | tegra186_asrc_put_input_threshold), |
836 | |
837 | /* Output threshold for watermark fields */ |
838 | SOC_SINGLE_EXT("Stream1 Output Threshold" , |
839 | ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 0), 0, 3, 0, |
840 | tegra186_asrc_get_output_threshold, |
841 | tegra186_asrc_put_output_threshold), |
842 | |
843 | SOC_SINGLE_EXT("Stream2 Output Threshold" , |
844 | ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 1), 0, 3, 0, |
845 | tegra186_asrc_get_output_threshold, |
846 | tegra186_asrc_put_output_threshold), |
847 | |
848 | SOC_SINGLE_EXT("Stream3 Output Threshold" , |
849 | ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 2), 0, 3, 0, |
850 | tegra186_asrc_get_output_threshold, |
851 | tegra186_asrc_put_output_threshold), |
852 | |
853 | SOC_SINGLE_EXT("Stream4 Output Threshold" , |
854 | ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 3), 0, 3, 0, |
855 | tegra186_asrc_get_output_threshold, |
856 | tegra186_asrc_put_output_threshold), |
857 | |
858 | SOC_SINGLE_EXT("Stream5 Output Threshold" , |
859 | ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 4), 0, 3, 0, |
860 | tegra186_asrc_get_output_threshold, |
861 | tegra186_asrc_put_output_threshold), |
862 | |
863 | SOC_SINGLE_EXT("Stream6 Output Threshold" , |
864 | ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 5), 0, 3, 0, |
865 | tegra186_asrc_get_output_threshold, |
866 | tegra186_asrc_put_output_threshold), |
867 | }; |
868 | |
869 | static const struct snd_soc_component_driver tegra186_asrc_cmpnt = { |
870 | .dapm_widgets = tegra186_asrc_widgets, |
871 | .num_dapm_widgets = ARRAY_SIZE(tegra186_asrc_widgets), |
872 | .dapm_routes = tegra186_asrc_routes, |
873 | .num_dapm_routes = ARRAY_SIZE(tegra186_asrc_routes), |
874 | .controls = tegra186_asrc_controls, |
875 | .num_controls = ARRAY_SIZE(tegra186_asrc_controls), |
876 | }; |
877 | |
878 | static bool tegra186_asrc_wr_reg(struct device *dev, unsigned int reg) |
879 | { |
880 | if (reg < TEGRA186_ASRC_STREAM_LIMIT) |
881 | reg %= TEGRA186_ASRC_STREAM_STRIDE; |
882 | |
883 | switch (reg) { |
884 | case TEGRA186_ASRC_CFG ... TEGRA186_ASRC_RATIO_COMP: |
885 | case TEGRA186_ASRC_RX_CIF_CTRL: |
886 | case TEGRA186_ASRC_TX_CIF_CTRL: |
887 | case TEGRA186_ASRC_ENABLE: |
888 | case TEGRA186_ASRC_SOFT_RESET: |
889 | case TEGRA186_ASRC_GLOBAL_ENB ... TEGRA186_ASRC_RATIO_UPD_RX_CIF_CTRL: |
890 | case TEGRA186_ASRC_GLOBAL_INT_MASK ... TEGRA186_ASRC_GLOBAL_INT_CLEAR: |
891 | case TEGRA186_ASRC_GLOBAL_APR_CTRL ... TEGRA186_ASRC_CYA: |
892 | return true; |
893 | default: |
894 | return false; |
895 | } |
896 | } |
897 | |
898 | static bool tegra186_asrc_rd_reg(struct device *dev, unsigned int reg) |
899 | { |
900 | if (reg < TEGRA186_ASRC_STREAM_LIMIT) |
901 | reg %= TEGRA186_ASRC_STREAM_STRIDE; |
902 | |
903 | if (tegra186_asrc_wr_reg(dev, reg)) |
904 | return true; |
905 | |
906 | switch (reg) { |
907 | case TEGRA186_ASRC_RX_STATUS: |
908 | case TEGRA186_ASRC_TX_STATUS: |
909 | case TEGRA186_ASRC_STATUS ... TEGRA186_ASRC_OUTSAMPLEBUF_CFG: |
910 | case TEGRA186_ASRC_RATIO_UPD_RX_STATUS: |
911 | case TEGRA186_ASRC_GLOBAL_STATUS ... TEGRA186_ASRC_GLOBAL_INT_STATUS: |
912 | case TEGRA186_ASRC_GLOBAL_TRANSFER_ERROR_LOG: |
913 | return true; |
914 | default: |
915 | return false; |
916 | } |
917 | } |
918 | |
919 | static bool tegra186_asrc_volatile_reg(struct device *dev, unsigned int reg) |
920 | { |
921 | if (reg < TEGRA186_ASRC_STREAM_LIMIT) |
922 | reg %= TEGRA186_ASRC_STREAM_STRIDE; |
923 | |
924 | switch (reg) { |
925 | case TEGRA186_ASRC_RX_STATUS: |
926 | case TEGRA186_ASRC_TX_STATUS: |
927 | case TEGRA186_ASRC_SOFT_RESET: |
928 | case TEGRA186_ASRC_RATIO_INT_PART: |
929 | case TEGRA186_ASRC_RATIO_FRAC_PART: |
930 | case TEGRA186_ASRC_STATUS: |
931 | case TEGRA186_ASRC_RATIO_LOCK_STATUS: |
932 | case TEGRA186_ASRC_RATIO_UPD_RX_STATUS: |
933 | case TEGRA186_ASRC_GLOBAL_SOFT_RESET: |
934 | case TEGRA186_ASRC_GLOBAL_STATUS: |
935 | case TEGRA186_ASRC_GLOBAL_STREAM_ENABLE_STATUS: |
936 | case TEGRA186_ASRC_GLOBAL_INT_STATUS: |
937 | case TEGRA186_ASRC_GLOBAL_TRANSFER_ERROR_LOG: |
938 | return true; |
939 | default: |
940 | return false; |
941 | } |
942 | } |
943 | |
944 | static const struct regmap_config tegra186_asrc_regmap_config = { |
945 | .reg_bits = 32, |
946 | .reg_stride = 4, |
947 | .val_bits = 32, |
948 | .max_register = TEGRA186_ASRC_CYA, |
949 | .writeable_reg = tegra186_asrc_wr_reg, |
950 | .readable_reg = tegra186_asrc_rd_reg, |
951 | .volatile_reg = tegra186_asrc_volatile_reg, |
952 | .reg_defaults = tegra186_asrc_reg_defaults, |
953 | .num_reg_defaults = ARRAY_SIZE(tegra186_asrc_reg_defaults), |
954 | .cache_type = REGCACHE_FLAT, |
955 | }; |
956 | |
957 | static const struct of_device_id tegra186_asrc_of_match[] = { |
958 | { .compatible = "nvidia,tegra186-asrc" }, |
959 | {}, |
960 | }; |
961 | MODULE_DEVICE_TABLE(of, tegra186_asrc_of_match); |
962 | |
963 | static int tegra186_asrc_platform_probe(struct platform_device *pdev) |
964 | { |
965 | struct device *dev = &pdev->dev; |
966 | struct tegra186_asrc *asrc; |
967 | void __iomem *regs; |
968 | unsigned int i; |
969 | int err; |
970 | |
971 | asrc = devm_kzalloc(dev, size: sizeof(*asrc), GFP_KERNEL); |
972 | if (!asrc) |
973 | return -ENOMEM; |
974 | |
975 | dev_set_drvdata(dev, data: asrc); |
976 | |
977 | regs = devm_platform_ioremap_resource(pdev, index: 0); |
978 | if (IS_ERR(ptr: regs)) |
979 | return PTR_ERR(ptr: regs); |
980 | |
981 | asrc->regmap = devm_regmap_init_mmio(dev, regs, |
982 | &tegra186_asrc_regmap_config); |
983 | if (IS_ERR(ptr: asrc->regmap)) { |
984 | dev_err(dev, "regmap init failed\n" ); |
985 | return PTR_ERR(ptr: asrc->regmap); |
986 | } |
987 | |
988 | regcache_cache_only(map: asrc->regmap, enable: true); |
989 | |
990 | regmap_write(map: asrc->regmap, TEGRA186_ASRC_GLOBAL_CFG, |
991 | TEGRA186_ASRC_GLOBAL_CFG_FRAC_32BIT_PRECISION); |
992 | |
993 | /* Initialize default output srate */ |
994 | for (i = 0; i < TEGRA186_ASRC_STREAM_MAX; i++) { |
995 | asrc->lane[i].ratio_source = TEGRA186_ASRC_RATIO_SOURCE_SW; |
996 | asrc->lane[i].int_part = 1; |
997 | asrc->lane[i].frac_part = 0; |
998 | asrc->lane[i].hwcomp_disable = 0; |
999 | asrc->lane[i].input_thresh = |
1000 | TEGRA186_ASRC_STREAM_DEFAULT_INPUT_HW_COMP_THRESH_CFG; |
1001 | asrc->lane[i].output_thresh = |
1002 | TEGRA186_ASRC_STREAM_DEFAULT_OUTPUT_HW_COMP_THRESH_CFG; |
1003 | } |
1004 | |
1005 | err = devm_snd_soc_register_component(dev, component_driver: &tegra186_asrc_cmpnt, |
1006 | dai_drv: tegra186_asrc_dais, |
1007 | ARRAY_SIZE(tegra186_asrc_dais)); |
1008 | if (err) { |
1009 | dev_err(dev, "can't register ASRC component, err: %d\n" , err); |
1010 | return err; |
1011 | } |
1012 | |
1013 | pm_runtime_enable(dev); |
1014 | |
1015 | return 0; |
1016 | } |
1017 | |
1018 | static void tegra186_asrc_platform_remove(struct platform_device *pdev) |
1019 | { |
1020 | pm_runtime_disable(dev: &pdev->dev); |
1021 | } |
1022 | |
1023 | static const struct dev_pm_ops tegra186_asrc_pm_ops = { |
1024 | SET_RUNTIME_PM_OPS(tegra186_asrc_runtime_suspend, |
1025 | tegra186_asrc_runtime_resume, NULL) |
1026 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
1027 | pm_runtime_force_resume) |
1028 | }; |
1029 | |
1030 | static struct platform_driver tegra186_asrc_driver = { |
1031 | .driver = { |
1032 | .name = "tegra186-asrc" , |
1033 | .of_match_table = tegra186_asrc_of_match, |
1034 | .pm = &tegra186_asrc_pm_ops, |
1035 | }, |
1036 | .probe = tegra186_asrc_platform_probe, |
1037 | .remove_new = tegra186_asrc_platform_remove, |
1038 | }; |
1039 | module_platform_driver(tegra186_asrc_driver) |
1040 | |
1041 | MODULE_AUTHOR("Junghyun Kim <juskim@nvidia.com>" ); |
1042 | MODULE_DESCRIPTION("Tegra186 ASRC ASoC driver" ); |
1043 | MODULE_LICENSE("GPL" ); |
1044 | |