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
43static 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
70static 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
79static 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
89static 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
129static 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
162static 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
185static 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
240static 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
254static 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
274static 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
292static 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
322static 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
340static 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
370static 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
384static 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
402static 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
416static 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
435static 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
449static 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
468static 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
483static const struct snd_soc_dai_ops tegra186_asrc_in_dai_ops = {
484 .hw_params = tegra186_asrc_in_hw_params,
485};
486
487static 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
543static 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
561static 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
628static 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
639static 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
649ASRC_SOURCE_DECL(src_select1, 0);
650ASRC_SOURCE_DECL(src_select2, 1);
651ASRC_SOURCE_DECL(src_select3, 2);
652ASRC_SOURCE_DECL(src_select4, 3);
653ASRC_SOURCE_DECL(src_select5, 4);
654ASRC_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
675static 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
869static 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
878static 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
898static 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
919static 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
944static 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
957static const struct of_device_id tegra186_asrc_of_match[] = {
958 { .compatible = "nvidia,tegra186-asrc" },
959 {},
960};
961MODULE_DEVICE_TABLE(of, tegra186_asrc_of_match);
962
963static 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
1018static void tegra186_asrc_platform_remove(struct platform_device *pdev)
1019{
1020 pm_runtime_disable(dev: &pdev->dev);
1021}
1022
1023static 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
1030static 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};
1039module_platform_driver(tegra186_asrc_driver)
1040
1041MODULE_AUTHOR("Junghyun Kim <juskim@nvidia.com>");
1042MODULE_DESCRIPTION("Tegra186 ASRC ASoC driver");
1043MODULE_LICENSE("GPL");
1044

source code of linux/sound/soc/tegra/tegra186_asrc.c