1 // SPDX-License-Identifier: GPL-2.0-only
2 // SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4 // tegra186_dspk.c - Tegra186 DSPK driver
7 #include <linux/device.h>
8 #include <linux/mod_devicetable.h>
9 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/pm_runtime.h>
13 #include <linux/regmap.h>
14 #include <sound/core.h>
15 #include <sound/pcm_params.h>
16 #include <sound/soc.h>
17 #include "tegra186_dspk.h"
18 #include "tegra_cif.h"
20 static const struct reg_default tegra186_dspk_reg_defaults
[] = {
21 { TEGRA186_DSPK_RX_INT_MASK
, 0x00000007 },
22 { TEGRA186_DSPK_RX_CIF_CTRL
, 0x00007700 },
23 { TEGRA186_DSPK_CG
, 0x00000001 },
24 { TEGRA186_DSPK_CORE_CTRL
, 0x00000310 },
25 { TEGRA186_DSPK_CODEC_CTRL
, 0x03000000 },
28 static int tegra186_dspk_get_fifo_th(struct snd_kcontrol
*kcontrol
,
29 struct snd_ctl_elem_value
*ucontrol
)
31 struct snd_soc_component
*codec
= snd_soc_kcontrol_component(kcontrol
);
32 struct tegra186_dspk
*dspk
= snd_soc_component_get_drvdata(codec
);
34 ucontrol
->value
.integer
.value
[0] = dspk
->rx_fifo_th
;
39 static int tegra186_dspk_put_fifo_th(struct snd_kcontrol
*kcontrol
,
40 struct snd_ctl_elem_value
*ucontrol
)
42 struct snd_soc_component
*codec
= snd_soc_kcontrol_component(kcontrol
);
43 struct tegra186_dspk
*dspk
= snd_soc_component_get_drvdata(codec
);
44 int value
= ucontrol
->value
.integer
.value
[0];
46 if (value
== dspk
->rx_fifo_th
)
49 dspk
->rx_fifo_th
= value
;
54 static int tegra186_dspk_get_osr_val(struct snd_kcontrol
*kcontrol
,
55 struct snd_ctl_elem_value
*ucontrol
)
57 struct snd_soc_component
*codec
= snd_soc_kcontrol_component(kcontrol
);
58 struct tegra186_dspk
*dspk
= snd_soc_component_get_drvdata(codec
);
60 ucontrol
->value
.enumerated
.item
[0] = dspk
->osr_val
;
65 static int tegra186_dspk_put_osr_val(struct snd_kcontrol
*kcontrol
,
66 struct snd_ctl_elem_value
*ucontrol
)
68 struct snd_soc_component
*codec
= snd_soc_kcontrol_component(kcontrol
);
69 struct tegra186_dspk
*dspk
= snd_soc_component_get_drvdata(codec
);
70 unsigned int value
= ucontrol
->value
.enumerated
.item
[0];
72 if (value
== dspk
->osr_val
)
75 dspk
->osr_val
= value
;
80 static int tegra186_dspk_get_pol_sel(struct snd_kcontrol
*kcontrol
,
81 struct snd_ctl_elem_value
*ucontrol
)
83 struct snd_soc_component
*codec
= snd_soc_kcontrol_component(kcontrol
);
84 struct tegra186_dspk
*dspk
= snd_soc_component_get_drvdata(codec
);
86 ucontrol
->value
.enumerated
.item
[0] = dspk
->lrsel
;
91 static int tegra186_dspk_put_pol_sel(struct snd_kcontrol
*kcontrol
,
92 struct snd_ctl_elem_value
*ucontrol
)
94 struct snd_soc_component
*codec
= snd_soc_kcontrol_component(kcontrol
);
95 struct tegra186_dspk
*dspk
= snd_soc_component_get_drvdata(codec
);
96 unsigned int value
= ucontrol
->value
.enumerated
.item
[0];
98 if (value
== dspk
->lrsel
)
106 static int tegra186_dspk_get_ch_sel(struct snd_kcontrol
*kcontrol
,
107 struct snd_ctl_elem_value
*ucontrol
)
109 struct snd_soc_component
*codec
= snd_soc_kcontrol_component(kcontrol
);
110 struct tegra186_dspk
*dspk
= snd_soc_component_get_drvdata(codec
);
112 ucontrol
->value
.enumerated
.item
[0] = dspk
->ch_sel
;
117 static int tegra186_dspk_put_ch_sel(struct snd_kcontrol
*kcontrol
,
118 struct snd_ctl_elem_value
*ucontrol
)
120 struct snd_soc_component
*codec
= snd_soc_kcontrol_component(kcontrol
);
121 struct tegra186_dspk
*dspk
= snd_soc_component_get_drvdata(codec
);
122 unsigned int value
= ucontrol
->value
.enumerated
.item
[0];
124 if (value
== dspk
->ch_sel
)
127 dspk
->ch_sel
= value
;
132 static int tegra186_dspk_get_mono_to_stereo(struct snd_kcontrol
*kcontrol
,
133 struct snd_ctl_elem_value
*ucontrol
)
135 struct snd_soc_component
*codec
= snd_soc_kcontrol_component(kcontrol
);
136 struct tegra186_dspk
*dspk
= snd_soc_component_get_drvdata(codec
);
138 ucontrol
->value
.enumerated
.item
[0] = dspk
->mono_to_stereo
;
143 static int tegra186_dspk_put_mono_to_stereo(struct snd_kcontrol
*kcontrol
,
144 struct snd_ctl_elem_value
*ucontrol
)
146 struct snd_soc_component
*codec
= snd_soc_kcontrol_component(kcontrol
);
147 struct tegra186_dspk
*dspk
= snd_soc_component_get_drvdata(codec
);
148 unsigned int value
= ucontrol
->value
.enumerated
.item
[0];
150 if (value
== dspk
->mono_to_stereo
)
153 dspk
->mono_to_stereo
= value
;
158 static int tegra186_dspk_get_stereo_to_mono(struct snd_kcontrol
*kcontrol
,
159 struct snd_ctl_elem_value
*ucontrol
)
161 struct snd_soc_component
*codec
= snd_soc_kcontrol_component(kcontrol
);
162 struct tegra186_dspk
*dspk
= snd_soc_component_get_drvdata(codec
);
164 ucontrol
->value
.enumerated
.item
[0] = dspk
->stereo_to_mono
;
169 static int tegra186_dspk_put_stereo_to_mono(struct snd_kcontrol
*kcontrol
,
170 struct snd_ctl_elem_value
*ucontrol
)
172 struct snd_soc_component
*codec
= snd_soc_kcontrol_component(kcontrol
);
173 struct tegra186_dspk
*dspk
= snd_soc_component_get_drvdata(codec
);
174 unsigned int value
= ucontrol
->value
.enumerated
.item
[0];
176 if (value
== dspk
->stereo_to_mono
)
179 dspk
->stereo_to_mono
= value
;
184 static int __maybe_unused
tegra186_dspk_runtime_suspend(struct device
*dev
)
186 struct tegra186_dspk
*dspk
= dev_get_drvdata(dev
);
188 regcache_cache_only(dspk
->regmap
, true);
189 regcache_mark_dirty(dspk
->regmap
);
191 clk_disable_unprepare(dspk
->clk_dspk
);
196 static int __maybe_unused
tegra186_dspk_runtime_resume(struct device
*dev
)
198 struct tegra186_dspk
*dspk
= dev_get_drvdata(dev
);
201 err
= clk_prepare_enable(dspk
->clk_dspk
);
203 dev_err(dev
, "failed to enable DSPK clock, err: %d\n", err
);
207 regcache_cache_only(dspk
->regmap
, false);
208 regcache_sync(dspk
->regmap
);
213 static int tegra186_dspk_hw_params(struct snd_pcm_substream
*substream
,
214 struct snd_pcm_hw_params
*params
,
215 struct snd_soc_dai
*dai
)
217 struct tegra186_dspk
*dspk
= snd_soc_dai_get_drvdata(dai
);
218 unsigned int channels
, srate
, dspk_clk
;
219 struct device
*dev
= dai
->dev
;
220 struct tegra_cif_conf cif_conf
;
224 memset(&cif_conf
, 0, sizeof(struct tegra_cif_conf
));
226 channels
= params_channels(params
);
227 cif_conf
.audio_ch
= channels
;
230 switch (dspk
->ch_sel
) {
231 case DSPK_CH_SELECT_LEFT
:
232 case DSPK_CH_SELECT_RIGHT
:
233 cif_conf
.client_ch
= 1;
235 case DSPK_CH_SELECT_STEREO
:
236 cif_conf
.client_ch
= 2;
239 dev_err(dev
, "Invalid DSPK client channels\n");
243 switch (params_format(params
)) {
244 case SNDRV_PCM_FORMAT_S16_LE
:
245 cif_conf
.audio_bits
= TEGRA_ACIF_BITS_16
;
246 cif_conf
.client_bits
= TEGRA_ACIF_BITS_16
;
248 case SNDRV_PCM_FORMAT_S24_LE
:
249 case SNDRV_PCM_FORMAT_S32_LE
:
250 cif_conf
.audio_bits
= TEGRA_ACIF_BITS_32
;
251 cif_conf
.client_bits
= TEGRA_ACIF_BITS_24
;
254 dev_err(dev
, "unsupported format!\n");
258 srate
= params_rate(params
);
260 /* RX FIFO threshold in terms of frames */
261 max_th
= (TEGRA186_DSPK_RX_FIFO_DEPTH
/ cif_conf
.audio_ch
) - 1;
263 if (dspk
->rx_fifo_th
> max_th
)
264 dspk
->rx_fifo_th
= max_th
;
266 cif_conf
.threshold
= dspk
->rx_fifo_th
;
267 cif_conf
.mono_conv
= dspk
->mono_to_stereo
;
268 cif_conf
.stereo_conv
= dspk
->stereo_to_mono
;
270 tegra_set_cif(dspk
->regmap
, TEGRA186_DSPK_RX_CIF_CTRL
,
274 * DSPK clock and PDM codec clock should be synchronous with 4:1 ratio,
275 * this is because it takes 4 clock cycles to send out one sample to
276 * codec by sigma delta modulator. Finally the clock rate is a multiple
277 * of 'Over Sampling Ratio', 'Sample Rate' and 'Interface Clock Ratio'.
279 dspk_clk
= (DSPK_OSR_FACTOR
<< dspk
->osr_val
) * srate
* DSPK_CLK_RATIO
;
281 err
= clk_set_rate(dspk
->clk_dspk
, dspk_clk
);
283 dev_err(dev
, "can't set DSPK clock rate %u, err: %d\n",
289 regmap_update_bits(dspk
->regmap
,
291 TEGRA186_DSPK_CORE_CTRL
,
293 TEGRA186_DSPK_OSR_MASK
|
294 TEGRA186_DSPK_CHANNEL_SELECT_MASK
|
295 TEGRA186_DSPK_CTRL_LRSEL_POLARITY_MASK
,
297 (dspk
->osr_val
<< DSPK_OSR_SHIFT
) |
298 ((dspk
->ch_sel
+ 1) << CH_SEL_SHIFT
) |
299 (dspk
->lrsel
<< LRSEL_POL_SHIFT
));
304 static const struct snd_soc_dai_ops tegra186_dspk_dai_ops
= {
305 .hw_params
= tegra186_dspk_hw_params
,
308 static struct snd_soc_dai_driver tegra186_dspk_dais
[] = {
312 .stream_name
= "CIF-Playback",
315 .rates
= SNDRV_PCM_RATE_8000_48000
,
316 .formats
= SNDRV_PCM_FMTBIT_S16_LE
|
317 SNDRV_PCM_FMTBIT_S24_LE
|
318 SNDRV_PCM_FMTBIT_S32_LE
,
324 .stream_name
= "DAP-Playback",
327 .rates
= SNDRV_PCM_RATE_8000_48000
,
328 .formats
= SNDRV_PCM_FMTBIT_S16_LE
|
329 SNDRV_PCM_FMTBIT_S24_LE
|
330 SNDRV_PCM_FMTBIT_S32_LE
,
332 .ops
= &tegra186_dspk_dai_ops
,
337 static const struct snd_soc_dapm_widget tegra186_dspk_widgets
[] = {
338 SND_SOC_DAPM_AIF_IN("RX", NULL
, 0, TEGRA186_DSPK_ENABLE
, 0, 0),
339 SND_SOC_DAPM_SPK("SPK", NULL
),
342 static const struct snd_soc_dapm_route tegra186_dspk_routes
[] = {
343 { "XBAR-Playback", NULL
, "XBAR-TX" },
344 { "CIF-Playback", NULL
, "XBAR-Playback" },
345 { "RX", NULL
, "CIF-Playback" },
346 { "DAP-Playback", NULL
, "RX" },
347 { "SPK", NULL
, "DAP-Playback" },
350 static const char * const tegra186_dspk_ch_sel_text
[] = {
351 "Left", "Right", "Stereo",
354 static const struct soc_enum tegra186_dspk_ch_sel_enum
=
355 SOC_ENUM_SINGLE(SND_SOC_NOPM
, 0, ARRAY_SIZE(tegra186_dspk_ch_sel_text
),
356 tegra186_dspk_ch_sel_text
);
358 static const char * const tegra186_dspk_osr_text
[] = {
359 "OSR_32", "OSR_64", "OSR_128", "OSR_256",
362 static const struct soc_enum tegra186_dspk_osr_enum
=
363 SOC_ENUM_SINGLE(SND_SOC_NOPM
, 0, ARRAY_SIZE(tegra186_dspk_osr_text
),
364 tegra186_dspk_osr_text
);
366 static const char * const tegra186_dspk_lrsel_text
[] = {
370 static const char * const tegra186_dspk_mono_conv_text
[] = {
374 static const struct soc_enum tegra186_dspk_mono_conv_enum
=
375 SOC_ENUM_SINGLE(SND_SOC_NOPM
, 0,
376 ARRAY_SIZE(tegra186_dspk_mono_conv_text
),
377 tegra186_dspk_mono_conv_text
);
379 static const char * const tegra186_dspk_stereo_conv_text
[] = {
383 static const struct soc_enum tegra186_dspk_stereo_conv_enum
=
384 SOC_ENUM_SINGLE(SND_SOC_NOPM
, 0,
385 ARRAY_SIZE(tegra186_dspk_stereo_conv_text
),
386 tegra186_dspk_stereo_conv_text
);
388 static const struct soc_enum tegra186_dspk_lrsel_enum
=
389 SOC_ENUM_SINGLE(SND_SOC_NOPM
, 0, ARRAY_SIZE(tegra186_dspk_lrsel_text
),
390 tegra186_dspk_lrsel_text
);
392 static const struct snd_kcontrol_new tegrat186_dspk_controls
[] = {
393 SOC_SINGLE_EXT("FIFO Threshold", SND_SOC_NOPM
, 0,
394 TEGRA186_DSPK_RX_FIFO_DEPTH
- 1, 0,
395 tegra186_dspk_get_fifo_th
, tegra186_dspk_put_fifo_th
),
396 SOC_ENUM_EXT("OSR Value", tegra186_dspk_osr_enum
,
397 tegra186_dspk_get_osr_val
, tegra186_dspk_put_osr_val
),
398 SOC_ENUM_EXT("LR Polarity Select", tegra186_dspk_lrsel_enum
,
399 tegra186_dspk_get_pol_sel
, tegra186_dspk_put_pol_sel
),
400 SOC_ENUM_EXT("Channel Select", tegra186_dspk_ch_sel_enum
,
401 tegra186_dspk_get_ch_sel
, tegra186_dspk_put_ch_sel
),
402 SOC_ENUM_EXT("Mono To Stereo", tegra186_dspk_mono_conv_enum
,
403 tegra186_dspk_get_mono_to_stereo
,
404 tegra186_dspk_put_mono_to_stereo
),
405 SOC_ENUM_EXT("Stereo To Mono", tegra186_dspk_stereo_conv_enum
,
406 tegra186_dspk_get_stereo_to_mono
,
407 tegra186_dspk_put_stereo_to_mono
),
410 static const struct snd_soc_component_driver tegra186_dspk_cmpnt
= {
411 .dapm_widgets
= tegra186_dspk_widgets
,
412 .num_dapm_widgets
= ARRAY_SIZE(tegra186_dspk_widgets
),
413 .dapm_routes
= tegra186_dspk_routes
,
414 .num_dapm_routes
= ARRAY_SIZE(tegra186_dspk_routes
),
415 .controls
= tegrat186_dspk_controls
,
416 .num_controls
= ARRAY_SIZE(tegrat186_dspk_controls
),
419 static bool tegra186_dspk_wr_reg(struct device
*dev
, unsigned int reg
)
422 case TEGRA186_DSPK_RX_INT_MASK
... TEGRA186_DSPK_RX_CIF_CTRL
:
423 case TEGRA186_DSPK_ENABLE
... TEGRA186_DSPK_CG
:
424 case TEGRA186_DSPK_CORE_CTRL
... TEGRA186_DSPK_CODEC_CTRL
:
431 static bool tegra186_dspk_rd_reg(struct device
*dev
, unsigned int reg
)
433 if (tegra186_dspk_wr_reg(dev
, reg
))
437 case TEGRA186_DSPK_RX_STATUS
:
438 case TEGRA186_DSPK_RX_INT_STATUS
:
439 case TEGRA186_DSPK_STATUS
:
440 case TEGRA186_DSPK_INT_STATUS
:
447 static bool tegra186_dspk_volatile_reg(struct device
*dev
, unsigned int reg
)
450 case TEGRA186_DSPK_RX_STATUS
:
451 case TEGRA186_DSPK_RX_INT_STATUS
:
452 case TEGRA186_DSPK_STATUS
:
453 case TEGRA186_DSPK_INT_STATUS
:
460 static const struct regmap_config tegra186_dspk_regmap
= {
464 .max_register
= TEGRA186_DSPK_CODEC_CTRL
,
465 .writeable_reg
= tegra186_dspk_wr_reg
,
466 .readable_reg
= tegra186_dspk_rd_reg
,
467 .volatile_reg
= tegra186_dspk_volatile_reg
,
468 .reg_defaults
= tegra186_dspk_reg_defaults
,
469 .num_reg_defaults
= ARRAY_SIZE(tegra186_dspk_reg_defaults
),
470 .cache_type
= REGCACHE_FLAT
,
473 static const struct of_device_id tegra186_dspk_of_match
[] = {
474 { .compatible
= "nvidia,tegra186-dspk" },
477 MODULE_DEVICE_TABLE(of
, tegra186_dspk_of_match
);
479 static int tegra186_dspk_platform_probe(struct platform_device
*pdev
)
481 struct device
*dev
= &pdev
->dev
;
482 struct tegra186_dspk
*dspk
;
486 dspk
= devm_kzalloc(dev
, sizeof(*dspk
), GFP_KERNEL
);
490 dspk
->osr_val
= DSPK_OSR_64
;
491 dspk
->lrsel
= DSPK_LRSEL_LEFT
;
492 dspk
->ch_sel
= DSPK_CH_SELECT_STEREO
;
493 dspk
->mono_to_stereo
= 0; /* "Zero" */
495 dev_set_drvdata(dev
, dspk
);
497 dspk
->clk_dspk
= devm_clk_get(dev
, "dspk");
498 if (IS_ERR(dspk
->clk_dspk
)) {
499 dev_err(dev
, "can't retrieve DSPK clock\n");
500 return PTR_ERR(dspk
->clk_dspk
);
503 regs
= devm_platform_ioremap_resource(pdev
, 0);
505 return PTR_ERR(regs
);
507 dspk
->regmap
= devm_regmap_init_mmio(dev
, regs
, &tegra186_dspk_regmap
);
508 if (IS_ERR(dspk
->regmap
)) {
509 dev_err(dev
, "regmap init failed\n");
510 return PTR_ERR(dspk
->regmap
);
513 regcache_cache_only(dspk
->regmap
, true);
515 err
= devm_snd_soc_register_component(dev
, &tegra186_dspk_cmpnt
,
517 ARRAY_SIZE(tegra186_dspk_dais
));
519 dev_err(dev
, "can't register DSPK component, err: %d\n",
524 pm_runtime_enable(dev
);
529 static void tegra186_dspk_platform_remove(struct platform_device
*pdev
)
531 pm_runtime_disable(&pdev
->dev
);
534 static const struct dev_pm_ops tegra186_dspk_pm_ops
= {
535 SET_RUNTIME_PM_OPS(tegra186_dspk_runtime_suspend
,
536 tegra186_dspk_runtime_resume
, NULL
)
537 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend
,
538 pm_runtime_force_resume
)
541 static struct platform_driver tegra186_dspk_driver
= {
543 .name
= "tegra186-dspk",
544 .of_match_table
= tegra186_dspk_of_match
,
545 .pm
= &tegra186_dspk_pm_ops
,
547 .probe
= tegra186_dspk_platform_probe
,
548 .remove
= tegra186_dspk_platform_remove
,
550 module_platform_driver(tegra186_dspk_driver
);
552 MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>");
553 MODULE_AUTHOR("Sameer Pujar <spujar@nvidia.com>");
554 MODULE_DESCRIPTION("Tegra186 ASoC DSPK driver");
555 MODULE_LICENSE("GPL v2");