cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tegra186_dspk.c (15332B)


      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");