Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0-only
  2//
  3// tegra186_dspk.c - Tegra186 DSPK driver
  4//
  5// Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
  6
  7#include <linux/clk.h>
  8#include <linux/device.h>
  9#include <linux/module.h>
 10#include <linux/of.h>
 11#include <linux/of_device.h>
 12#include <linux/platform_device.h>
 13#include <linux/pm_runtime.h>
 14#include <linux/regmap.h>
 15#include <sound/core.h>
 16#include <sound/pcm_params.h>
 17#include <sound/soc.h>
 18#include "tegra186_dspk.h"
 19#include "tegra_cif.h"
 20
 21static const struct reg_default tegra186_dspk_reg_defaults[] = {
 22	{ TEGRA186_DSPK_RX_INT_MASK, 0x00000007 },
 23	{ TEGRA186_DSPK_RX_CIF_CTRL, 0x00007700 },
 24	{ TEGRA186_DSPK_CG,	     0x00000001 },
 25	{ TEGRA186_DSPK_CORE_CTRL,   0x00000310 },
 26	{ TEGRA186_DSPK_CODEC_CTRL,  0x03000000 },
 27};
 28
 29static int tegra186_dspk_get_fifo_th(struct snd_kcontrol *kcontrol,
 30				     struct snd_ctl_elem_value *ucontrol)
 31{
 32	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 33	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
 34
 35	ucontrol->value.integer.value[0] = dspk->rx_fifo_th;
 36
 37	return 0;
 38}
 39
 40static int tegra186_dspk_put_fifo_th(struct snd_kcontrol *kcontrol,
 41				     struct snd_ctl_elem_value *ucontrol)
 42{
 43	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 44	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
 45	int value = ucontrol->value.integer.value[0];
 46
 47	if (value == dspk->rx_fifo_th)
 48		return 0;
 49
 50	dspk->rx_fifo_th = value;
 51
 52	return 1;
 53}
 54
 55static int tegra186_dspk_get_osr_val(struct snd_kcontrol *kcontrol,
 56				     struct snd_ctl_elem_value *ucontrol)
 57{
 58	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 59	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
 60
 61	ucontrol->value.enumerated.item[0] = dspk->osr_val;
 62
 63	return 0;
 64}
 65
 66static int tegra186_dspk_put_osr_val(struct snd_kcontrol *kcontrol,
 67				     struct snd_ctl_elem_value *ucontrol)
 68{
 69	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 70	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
 71	unsigned int value = ucontrol->value.enumerated.item[0];
 72
 73	if (value == dspk->osr_val)
 74		return 0;
 75
 76	dspk->osr_val = value;
 77
 78	return 1;
 79}
 80
 81static int tegra186_dspk_get_pol_sel(struct snd_kcontrol *kcontrol,
 82				     struct snd_ctl_elem_value *ucontrol)
 83{
 84	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 85	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
 86
 87	ucontrol->value.enumerated.item[0] = dspk->lrsel;
 88
 89	return 0;
 90}
 91
 92static int tegra186_dspk_put_pol_sel(struct snd_kcontrol *kcontrol,
 93				     struct snd_ctl_elem_value *ucontrol)
 94{
 95	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 96	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
 97	unsigned int value = ucontrol->value.enumerated.item[0];
 98
 99	if (value == dspk->lrsel)
100		return 0;
101
102	dspk->lrsel = value;
103
104	return 1;
105}
106
107static int tegra186_dspk_get_ch_sel(struct snd_kcontrol *kcontrol,
108				    struct snd_ctl_elem_value *ucontrol)
109{
110	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
111	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
112
113	ucontrol->value.enumerated.item[0] = dspk->ch_sel;
114
115	return 0;
116}
117
118static int tegra186_dspk_put_ch_sel(struct snd_kcontrol *kcontrol,
119				    struct snd_ctl_elem_value *ucontrol)
120{
121	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
122	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
123	unsigned int value = ucontrol->value.enumerated.item[0];
124
125	if (value == dspk->ch_sel)
126		return 0;
127
128	dspk->ch_sel = value;
129
130	return 1;
131}
132
133static int tegra186_dspk_get_mono_to_stereo(struct snd_kcontrol *kcontrol,
134					    struct snd_ctl_elem_value *ucontrol)
135{
136	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
137	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
138
139	ucontrol->value.enumerated.item[0] = dspk->mono_to_stereo;
140
141	return 0;
142}
143
144static int tegra186_dspk_put_mono_to_stereo(struct snd_kcontrol *kcontrol,
145					    struct snd_ctl_elem_value *ucontrol)
146{
147	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
148	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
149	unsigned int value = ucontrol->value.enumerated.item[0];
150
151	if (value == dspk->mono_to_stereo)
152		return 0;
153
154	dspk->mono_to_stereo = value;
155
156	return 1;
157}
158
159static int tegra186_dspk_get_stereo_to_mono(struct snd_kcontrol *kcontrol,
160					    struct snd_ctl_elem_value *ucontrol)
161{
162	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
163	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
164
165	ucontrol->value.enumerated.item[0] = dspk->stereo_to_mono;
166
167	return 0;
168}
169
170static int tegra186_dspk_put_stereo_to_mono(struct snd_kcontrol *kcontrol,
171					    struct snd_ctl_elem_value *ucontrol)
172{
173	struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
174	struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
175	unsigned int value = ucontrol->value.enumerated.item[0];
176
177	if (value == dspk->stereo_to_mono)
178		return 0;
179
180	dspk->stereo_to_mono = value;
181
182	return 1;
183}
184
185static int __maybe_unused tegra186_dspk_runtime_suspend(struct device *dev)
186{
187	struct tegra186_dspk *dspk = dev_get_drvdata(dev);
188
189	regcache_cache_only(dspk->regmap, true);
190	regcache_mark_dirty(dspk->regmap);
191
192	clk_disable_unprepare(dspk->clk_dspk);
193
194	return 0;
195}
196
197static int __maybe_unused tegra186_dspk_runtime_resume(struct device *dev)
198{
199	struct tegra186_dspk *dspk = dev_get_drvdata(dev);
200	int err;
201
202	err = clk_prepare_enable(dspk->clk_dspk);
203	if (err) {
204		dev_err(dev, "failed to enable DSPK clock, err: %d\n", err);
205		return err;
206	}
207
208	regcache_cache_only(dspk->regmap, false);
209	regcache_sync(dspk->regmap);
210
211	return 0;
212}
213
214static int tegra186_dspk_hw_params(struct snd_pcm_substream *substream,
215				   struct snd_pcm_hw_params *params,
216				   struct snd_soc_dai *dai)
217{
218	struct tegra186_dspk *dspk = snd_soc_dai_get_drvdata(dai);
219	unsigned int channels, srate, dspk_clk;
220	struct device *dev = dai->dev;
221	struct tegra_cif_conf cif_conf;
222	unsigned int max_th;
223	int err;
224
225	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
226
227	channels = params_channels(params);
228	cif_conf.audio_ch = channels;
229
230	/* Client channel */
231	switch (dspk->ch_sel) {
232	case DSPK_CH_SELECT_LEFT:
233	case DSPK_CH_SELECT_RIGHT:
234		cif_conf.client_ch = 1;
235		break;
236	case DSPK_CH_SELECT_STEREO:
237		cif_conf.client_ch = 2;
238		break;
239	default:
240		dev_err(dev, "Invalid DSPK client channels\n");
241		return -EINVAL;
242	}
243
244	cif_conf.client_bits = TEGRA_ACIF_BITS_24;
245
246	switch (params_format(params)) {
247	case SNDRV_PCM_FORMAT_S16_LE:
248		cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
249		break;
250	case SNDRV_PCM_FORMAT_S32_LE:
251		cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
252		break;
253	default:
254		dev_err(dev, "unsupported format!\n");
255		return -EOPNOTSUPP;
256	}
257
258	srate = params_rate(params);
259
260	/* RX FIFO threshold in terms of frames */
261	max_th = (TEGRA186_DSPK_RX_FIFO_DEPTH / cif_conf.audio_ch) - 1;
262
263	if (dspk->rx_fifo_th > max_th)
264		dspk->rx_fifo_th = max_th;
265
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;
269
270	tegra_set_cif(dspk->regmap, TEGRA186_DSPK_RX_CIF_CTRL,
271		      &cif_conf);
272
273	/*
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'.
278	 */
279	dspk_clk = (DSPK_OSR_FACTOR << dspk->osr_val) * srate * DSPK_CLK_RATIO;
280
281	err = clk_set_rate(dspk->clk_dspk, dspk_clk);
282	if (err) {
283		dev_err(dev, "can't set DSPK clock rate %u, err: %d\n",
284			dspk_clk, err);
285
286		return err;
287	}
288
289	regmap_update_bits(dspk->regmap,
290			   /* Reg */
291			   TEGRA186_DSPK_CORE_CTRL,
292			   /* Mask */
293			   TEGRA186_DSPK_OSR_MASK |
294			   TEGRA186_DSPK_CHANNEL_SELECT_MASK |
295			   TEGRA186_DSPK_CTRL_LRSEL_POLARITY_MASK,
296			   /* Value */
297			   (dspk->osr_val << DSPK_OSR_SHIFT) |
298			   ((dspk->ch_sel + 1) << CH_SEL_SHIFT) |
299			   (dspk->lrsel << LRSEL_POL_SHIFT));
300
301	return 0;
302}
303
304static const struct snd_soc_dai_ops tegra186_dspk_dai_ops = {
305	.hw_params	= tegra186_dspk_hw_params,
306};
307
308static struct snd_soc_dai_driver tegra186_dspk_dais[] = {
309	{
310	    .name = "DSPK-CIF",
311	    .playback = {
312		.stream_name = "CIF-Playback",
313		.channels_min = 1,
314		.channels_max = 2,
315		.rates = SNDRV_PCM_RATE_8000_48000,
316		.formats = SNDRV_PCM_FMTBIT_S16_LE |
317			   SNDRV_PCM_FMTBIT_S32_LE,
318	    },
319	},
320	{
321	    .name = "DSPK-DAP",
322	    .playback = {
323		.stream_name = "DAP-Playback",
324		.channels_min = 1,
325		.channels_max = 2,
326		.rates = SNDRV_PCM_RATE_8000_48000,
327		.formats = SNDRV_PCM_FMTBIT_S16_LE |
328			   SNDRV_PCM_FMTBIT_S32_LE,
329	    },
330	    .ops = &tegra186_dspk_dai_ops,
331	    .symmetric_rate = 1,
332	},
333};
334
335static const struct snd_soc_dapm_widget tegra186_dspk_widgets[] = {
336	SND_SOC_DAPM_AIF_IN("RX", NULL, 0, TEGRA186_DSPK_ENABLE, 0, 0),
337	SND_SOC_DAPM_SPK("SPK", NULL),
338};
339
340static const struct snd_soc_dapm_route tegra186_dspk_routes[] = {
341	{ "XBAR-Playback",	NULL,	"XBAR-TX" },
342	{ "CIF-Playback",	NULL,	"XBAR-Playback" },
343	{ "RX",			NULL,	"CIF-Playback" },
344	{ "DAP-Playback",	NULL,	"RX" },
345	{ "SPK",		NULL,	"DAP-Playback" },
346};
347
348static const char * const tegra186_dspk_ch_sel_text[] = {
349	"Left", "Right", "Stereo",
350};
351
352static const struct soc_enum tegra186_dspk_ch_sel_enum =
353	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_ch_sel_text),
354			tegra186_dspk_ch_sel_text);
355
356static const char * const tegra186_dspk_osr_text[] = {
357	"OSR_32", "OSR_64", "OSR_128", "OSR_256",
358};
359
360static const struct soc_enum tegra186_dspk_osr_enum =
361	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_osr_text),
362			tegra186_dspk_osr_text);
363
364static const char * const tegra186_dspk_lrsel_text[] = {
365	"Left", "Right",
366};
367
368static const char * const tegra186_dspk_mono_conv_text[] = {
369	"Zero", "Copy",
370};
371
372static const struct soc_enum tegra186_dspk_mono_conv_enum =
373	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
374			ARRAY_SIZE(tegra186_dspk_mono_conv_text),
375			tegra186_dspk_mono_conv_text);
376
377static const char * const tegra186_dspk_stereo_conv_text[] = {
378	"CH0", "CH1", "AVG",
379};
380
381static const struct soc_enum tegra186_dspk_stereo_conv_enum =
382	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
383			ARRAY_SIZE(tegra186_dspk_stereo_conv_text),
384			tegra186_dspk_stereo_conv_text);
385
386static const struct soc_enum tegra186_dspk_lrsel_enum =
387	SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_lrsel_text),
388			tegra186_dspk_lrsel_text);
389
390static const struct snd_kcontrol_new tegrat186_dspk_controls[] = {
391	SOC_SINGLE_EXT("FIFO Threshold", SND_SOC_NOPM, 0,
392		       TEGRA186_DSPK_RX_FIFO_DEPTH - 1, 0,
393		       tegra186_dspk_get_fifo_th, tegra186_dspk_put_fifo_th),
394	SOC_ENUM_EXT("OSR Value", tegra186_dspk_osr_enum,
395		     tegra186_dspk_get_osr_val, tegra186_dspk_put_osr_val),
396	SOC_ENUM_EXT("LR Polarity Select", tegra186_dspk_lrsel_enum,
397		     tegra186_dspk_get_pol_sel, tegra186_dspk_put_pol_sel),
398	SOC_ENUM_EXT("Channel Select", tegra186_dspk_ch_sel_enum,
399		     tegra186_dspk_get_ch_sel, tegra186_dspk_put_ch_sel),
400	SOC_ENUM_EXT("Mono To Stereo", tegra186_dspk_mono_conv_enum,
401		     tegra186_dspk_get_mono_to_stereo,
402		     tegra186_dspk_put_mono_to_stereo),
403	SOC_ENUM_EXT("Stereo To Mono", tegra186_dspk_stereo_conv_enum,
404		     tegra186_dspk_get_stereo_to_mono,
405		     tegra186_dspk_put_stereo_to_mono),
406};
407
408static const struct snd_soc_component_driver tegra186_dspk_cmpnt = {
409	.dapm_widgets = tegra186_dspk_widgets,
410	.num_dapm_widgets = ARRAY_SIZE(tegra186_dspk_widgets),
411	.dapm_routes = tegra186_dspk_routes,
412	.num_dapm_routes = ARRAY_SIZE(tegra186_dspk_routes),
413	.controls = tegrat186_dspk_controls,
414	.num_controls = ARRAY_SIZE(tegrat186_dspk_controls),
415};
416
417static bool tegra186_dspk_wr_reg(struct device *dev, unsigned int reg)
418{
419	switch (reg) {
420	case TEGRA186_DSPK_RX_INT_MASK ... TEGRA186_DSPK_RX_CIF_CTRL:
421	case TEGRA186_DSPK_ENABLE ... TEGRA186_DSPK_CG:
422	case TEGRA186_DSPK_CORE_CTRL ... TEGRA186_DSPK_CODEC_CTRL:
423		return true;
424	default:
425		return false;
426	}
427}
428
429static bool tegra186_dspk_rd_reg(struct device *dev, unsigned int reg)
430{
431	if (tegra186_dspk_wr_reg(dev, reg))
432		return true;
433
434	switch (reg) {
435	case TEGRA186_DSPK_RX_STATUS:
436	case TEGRA186_DSPK_RX_INT_STATUS:
437	case TEGRA186_DSPK_STATUS:
438	case TEGRA186_DSPK_INT_STATUS:
439		return true;
440	default:
441		return false;
442	}
443}
444
445static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg)
446{
447	switch (reg) {
448	case TEGRA186_DSPK_RX_STATUS:
449	case TEGRA186_DSPK_RX_INT_STATUS:
450	case TEGRA186_DSPK_STATUS:
451	case TEGRA186_DSPK_INT_STATUS:
452		return true;
453	default:
454		return false;
455	}
456}
457
458static const struct regmap_config tegra186_dspk_regmap = {
459	.reg_bits		= 32,
460	.reg_stride		= 4,
461	.val_bits		= 32,
462	.max_register		= TEGRA186_DSPK_CODEC_CTRL,
463	.writeable_reg		= tegra186_dspk_wr_reg,
464	.readable_reg		= tegra186_dspk_rd_reg,
465	.volatile_reg		= tegra186_dspk_volatile_reg,
466	.reg_defaults		= tegra186_dspk_reg_defaults,
467	.num_reg_defaults	= ARRAY_SIZE(tegra186_dspk_reg_defaults),
468	.cache_type		= REGCACHE_FLAT,
469};
470
471static const struct of_device_id tegra186_dspk_of_match[] = {
472	{ .compatible = "nvidia,tegra186-dspk" },
473	{},
474};
475MODULE_DEVICE_TABLE(of, tegra186_dspk_of_match);
476
477static int tegra186_dspk_platform_probe(struct platform_device *pdev)
478{
479	struct device *dev = &pdev->dev;
480	struct tegra186_dspk *dspk;
481	void __iomem *regs;
482	int err;
483
484	dspk = devm_kzalloc(dev, sizeof(*dspk), GFP_KERNEL);
485	if (!dspk)
486		return -ENOMEM;
487
488	dspk->osr_val = DSPK_OSR_64;
489	dspk->lrsel = DSPK_LRSEL_LEFT;
490	dspk->ch_sel = DSPK_CH_SELECT_STEREO;
491	dspk->mono_to_stereo = 0; /* "Zero" */
492
493	dev_set_drvdata(dev, dspk);
494
495	dspk->clk_dspk = devm_clk_get(dev, "dspk");
496	if (IS_ERR(dspk->clk_dspk)) {
497		dev_err(dev, "can't retrieve DSPK clock\n");
498		return PTR_ERR(dspk->clk_dspk);
499	}
500
501	regs = devm_platform_ioremap_resource(pdev, 0);
502	if (IS_ERR(regs))
503		return PTR_ERR(regs);
504
505	dspk->regmap = devm_regmap_init_mmio(dev, regs, &tegra186_dspk_regmap);
506	if (IS_ERR(dspk->regmap)) {
507		dev_err(dev, "regmap init failed\n");
508		return PTR_ERR(dspk->regmap);
509	}
510
511	regcache_cache_only(dspk->regmap, true);
512
513	err = devm_snd_soc_register_component(dev, &tegra186_dspk_cmpnt,
514					      tegra186_dspk_dais,
515					      ARRAY_SIZE(tegra186_dspk_dais));
516	if (err) {
517		dev_err(dev, "can't register DSPK component, err: %d\n",
518			err);
519		return err;
520	}
521
522	pm_runtime_enable(dev);
523
524	return 0;
525}
526
527static int tegra186_dspk_platform_remove(struct platform_device *pdev)
528{
529	pm_runtime_disable(&pdev->dev);
530
531	return 0;
532}
533
534static 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)
539};
540
541static struct platform_driver tegra186_dspk_driver = {
542	.driver = {
543		.name = "tegra186-dspk",
544		.of_match_table = tegra186_dspk_of_match,
545		.pm = &tegra186_dspk_pm_ops,
546	},
547	.probe = tegra186_dspk_platform_probe,
548	.remove = tegra186_dspk_platform_remove,
549};
550module_platform_driver(tegra186_dspk_driver);
551
552MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>");
553MODULE_AUTHOR("Sameer Pujar <spujar@nvidia.com>");
554MODULE_DESCRIPTION("Tegra186 ASoC DSPK driver");
555MODULE_LICENSE("GPL v2");