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

tegra210_adx.c (15174B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2//
      3// tegra210_adx.c - Tegra210 ADX driver
      4//
      5// Copyright (c) 2021 NVIDIA CORPORATION.  All rights reserved.
      6
      7#include <linux/clk.h>
      8#include <linux/device.h>
      9#include <linux/io.h>
     10#include <linux/module.h>
     11#include <linux/of.h>
     12#include <linux/of_device.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 "tegra210_adx.h"
     22#include "tegra_cif.h"
     23
     24static const struct reg_default tegra210_adx_reg_defaults[] = {
     25	{ TEGRA210_ADX_RX_INT_MASK, 0x00000001},
     26	{ TEGRA210_ADX_RX_CIF_CTRL, 0x00007000},
     27	{ TEGRA210_ADX_TX_INT_MASK, 0x0000000f },
     28	{ TEGRA210_ADX_TX1_CIF_CTRL, 0x00007000},
     29	{ TEGRA210_ADX_TX2_CIF_CTRL, 0x00007000},
     30	{ TEGRA210_ADX_TX3_CIF_CTRL, 0x00007000},
     31	{ TEGRA210_ADX_TX4_CIF_CTRL, 0x00007000},
     32	{ TEGRA210_ADX_CG, 0x1},
     33	{ TEGRA210_ADX_CFG_RAM_CTRL, 0x00004000},
     34};
     35
     36static void tegra210_adx_write_map_ram(struct tegra210_adx *adx)
     37{
     38	int i;
     39
     40	regmap_write(adx->regmap, TEGRA210_ADX_CFG_RAM_CTRL,
     41		     TEGRA210_ADX_CFG_RAM_CTRL_SEQ_ACCESS_EN |
     42		     TEGRA210_ADX_CFG_RAM_CTRL_ADDR_INIT_EN |
     43		     TEGRA210_ADX_CFG_RAM_CTRL_RW_WRITE);
     44
     45	for (i = 0; i < TEGRA210_ADX_RAM_DEPTH; i++)
     46		regmap_write(adx->regmap, TEGRA210_ADX_CFG_RAM_DATA,
     47			     adx->map[i]);
     48
     49	regmap_write(adx->regmap, TEGRA210_ADX_IN_BYTE_EN0, adx->byte_mask[0]);
     50	regmap_write(adx->regmap, TEGRA210_ADX_IN_BYTE_EN1, adx->byte_mask[1]);
     51}
     52
     53static int tegra210_adx_startup(struct snd_pcm_substream *substream,
     54				struct snd_soc_dai *dai)
     55{
     56	struct tegra210_adx *adx = snd_soc_dai_get_drvdata(dai);
     57	unsigned int val;
     58	int err;
     59
     60	/* Ensure if ADX status is disabled */
     61	err = regmap_read_poll_timeout_atomic(adx->regmap, TEGRA210_ADX_STATUS,
     62					      val, !(val & 0x1), 10, 10000);
     63	if (err < 0) {
     64		dev_err(dai->dev, "failed to stop ADX, err = %d\n", err);
     65		return err;
     66	}
     67
     68	/*
     69	 * Soft Reset: Below performs module soft reset which clears
     70	 * all FSM logic, flushes flow control of FIFO and resets the
     71	 * state register. It also brings module back to disabled
     72	 * state (without flushing the data in the pipe).
     73	 */
     74	regmap_update_bits(adx->regmap, TEGRA210_ADX_SOFT_RESET,
     75			   TEGRA210_ADX_SOFT_RESET_SOFT_RESET_MASK,
     76			   TEGRA210_ADX_SOFT_RESET_SOFT_EN);
     77
     78	err = regmap_read_poll_timeout(adx->regmap, TEGRA210_ADX_SOFT_RESET,
     79				       val, !(val & 0x1), 10, 10000);
     80	if (err < 0) {
     81		dev_err(dai->dev, "failed to reset ADX, err = %d\n", err);
     82		return err;
     83	}
     84
     85	return 0;
     86}
     87
     88static int __maybe_unused tegra210_adx_runtime_suspend(struct device *dev)
     89{
     90	struct tegra210_adx *adx = dev_get_drvdata(dev);
     91
     92	regcache_cache_only(adx->regmap, true);
     93	regcache_mark_dirty(adx->regmap);
     94
     95	return 0;
     96}
     97
     98static int __maybe_unused tegra210_adx_runtime_resume(struct device *dev)
     99{
    100	struct tegra210_adx *adx = dev_get_drvdata(dev);
    101
    102	regcache_cache_only(adx->regmap, false);
    103	regcache_sync(adx->regmap);
    104
    105	tegra210_adx_write_map_ram(adx);
    106
    107	return 0;
    108}
    109
    110static int tegra210_adx_set_audio_cif(struct snd_soc_dai *dai,
    111				      unsigned int channels,
    112				      unsigned int format,
    113				      unsigned int reg)
    114{
    115	struct tegra210_adx *adx = snd_soc_dai_get_drvdata(dai);
    116	struct tegra_cif_conf cif_conf;
    117	int audio_bits;
    118
    119	memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
    120
    121	if (channels < 1 || channels > 16)
    122		return -EINVAL;
    123
    124	switch (format) {
    125	case SNDRV_PCM_FORMAT_S8:
    126		audio_bits = TEGRA_ACIF_BITS_8;
    127		break;
    128	case SNDRV_PCM_FORMAT_S16_LE:
    129		audio_bits = TEGRA_ACIF_BITS_16;
    130		break;
    131	case SNDRV_PCM_FORMAT_S32_LE:
    132		audio_bits = TEGRA_ACIF_BITS_32;
    133		break;
    134	default:
    135		return -EINVAL;
    136	}
    137
    138	cif_conf.audio_ch = channels;
    139	cif_conf.client_ch = channels;
    140	cif_conf.audio_bits = audio_bits;
    141	cif_conf.client_bits = audio_bits;
    142
    143	tegra_set_cif(adx->regmap, reg, &cif_conf);
    144
    145	return 0;
    146}
    147
    148static int tegra210_adx_out_hw_params(struct snd_pcm_substream *substream,
    149				      struct snd_pcm_hw_params *params,
    150				      struct snd_soc_dai *dai)
    151{
    152	return tegra210_adx_set_audio_cif(dai, params_channels(params),
    153			params_format(params),
    154			TEGRA210_ADX_TX1_CIF_CTRL + ((dai->id - 1) * TEGRA210_ADX_AUDIOCIF_CH_STRIDE));
    155}
    156
    157static int tegra210_adx_in_hw_params(struct snd_pcm_substream *substream,
    158				     struct snd_pcm_hw_params *params,
    159				     struct snd_soc_dai *dai)
    160{
    161	return tegra210_adx_set_audio_cif(dai, params_channels(params),
    162					  params_format(params),
    163					  TEGRA210_ADX_RX_CIF_CTRL);
    164}
    165
    166static int tegra210_adx_get_byte_map(struct snd_kcontrol *kcontrol,
    167				     struct snd_ctl_elem_value *ucontrol)
    168{
    169	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
    170	struct tegra210_adx *adx = snd_soc_component_get_drvdata(cmpnt);
    171	struct soc_mixer_control *mc;
    172	unsigned char *bytes_map = (unsigned char *)&adx->map;
    173	int enabled;
    174
    175	mc = (struct soc_mixer_control *)kcontrol->private_value;
    176	enabled = adx->byte_mask[mc->reg / 32] & (1 << (mc->reg % 32));
    177
    178	if (enabled)
    179		ucontrol->value.integer.value[0] = bytes_map[mc->reg];
    180	else
    181		ucontrol->value.integer.value[0] = 0;
    182
    183	return 0;
    184}
    185
    186static int tegra210_adx_put_byte_map(struct snd_kcontrol *kcontrol,
    187				     struct snd_ctl_elem_value *ucontrol)
    188{
    189	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
    190	struct tegra210_adx *adx = snd_soc_component_get_drvdata(cmpnt);
    191	unsigned char *bytes_map = (unsigned char *)&adx->map;
    192	int value = ucontrol->value.integer.value[0];
    193	struct soc_mixer_control *mc =
    194		(struct soc_mixer_control *)kcontrol->private_value;;
    195
    196	if (value == bytes_map[mc->reg])
    197		return 0;
    198
    199	if (value >= 0 && value <= 255) {
    200		/* update byte map and enable slot */
    201		bytes_map[mc->reg] = value;
    202		adx->byte_mask[mc->reg / 32] |= (1 << (mc->reg % 32));
    203	} else {
    204		/* reset byte map and disable slot */
    205		bytes_map[mc->reg] = 0;
    206		adx->byte_mask[mc->reg / 32] &= ~(1 << (mc->reg % 32));
    207	}
    208
    209	return 1;
    210}
    211
    212static const struct snd_soc_dai_ops tegra210_adx_in_dai_ops = {
    213	.hw_params	= tegra210_adx_in_hw_params,
    214	.startup	= tegra210_adx_startup,
    215};
    216
    217static const struct snd_soc_dai_ops tegra210_adx_out_dai_ops = {
    218	.hw_params	= tegra210_adx_out_hw_params,
    219};
    220
    221#define IN_DAI							\
    222	{							\
    223		.name = "ADX-RX-CIF",				\
    224		.playback = {					\
    225			.stream_name = "RX-CIF-Playback",	\
    226			.channels_min = 1,			\
    227			.channels_max = 16,			\
    228			.rates = SNDRV_PCM_RATE_8000_192000,	\
    229			.formats = SNDRV_PCM_FMTBIT_S8 |	\
    230				   SNDRV_PCM_FMTBIT_S16_LE |	\
    231				   SNDRV_PCM_FMTBIT_S32_LE,	\
    232		},						\
    233		.capture = {					\
    234			.stream_name = "RX-CIF-Capture",	\
    235			.channels_min = 1,			\
    236			.channels_max = 16,			\
    237			.rates = SNDRV_PCM_RATE_8000_192000,	\
    238			.formats = SNDRV_PCM_FMTBIT_S8 |	\
    239				   SNDRV_PCM_FMTBIT_S16_LE |	\
    240				   SNDRV_PCM_FMTBIT_S32_LE,	\
    241		},						\
    242		.ops = &tegra210_adx_in_dai_ops,		\
    243	}
    244
    245#define OUT_DAI(id)						\
    246	{							\
    247		.name = "ADX-TX" #id "-CIF",			\
    248		.playback = {					\
    249			.stream_name = "TX" #id "-CIF-Playback",\
    250			.channels_min = 1,			\
    251			.channels_max = 16,			\
    252			.rates = SNDRV_PCM_RATE_8000_192000,	\
    253			.formats = SNDRV_PCM_FMTBIT_S8 |	\
    254				   SNDRV_PCM_FMTBIT_S16_LE |	\
    255				   SNDRV_PCM_FMTBIT_S32_LE,	\
    256		},						\
    257		.capture = {					\
    258			.stream_name = "TX" #id "-CIF-Capture",	\
    259			.channels_min = 1,			\
    260			.channels_max = 16,			\
    261			.rates = SNDRV_PCM_RATE_8000_192000,	\
    262			.formats = SNDRV_PCM_FMTBIT_S8 |	\
    263				   SNDRV_PCM_FMTBIT_S16_LE |	\
    264				   SNDRV_PCM_FMTBIT_S32_LE,	\
    265		},						\
    266		.ops = &tegra210_adx_out_dai_ops,		\
    267	}
    268
    269static struct snd_soc_dai_driver tegra210_adx_dais[] = {
    270	IN_DAI,
    271	OUT_DAI(1),
    272	OUT_DAI(2),
    273	OUT_DAI(3),
    274	OUT_DAI(4),
    275};
    276
    277static const struct snd_soc_dapm_widget tegra210_adx_widgets[] = {
    278	SND_SOC_DAPM_AIF_IN("RX", NULL, 0, TEGRA210_ADX_ENABLE,
    279			    TEGRA210_ADX_ENABLE_SHIFT, 0),
    280	SND_SOC_DAPM_AIF_OUT("TX1", NULL, 0, TEGRA210_ADX_CTRL, 0, 0),
    281	SND_SOC_DAPM_AIF_OUT("TX2", NULL, 0, TEGRA210_ADX_CTRL, 1, 0),
    282	SND_SOC_DAPM_AIF_OUT("TX3", NULL, 0, TEGRA210_ADX_CTRL, 2, 0),
    283	SND_SOC_DAPM_AIF_OUT("TX4", NULL, 0, TEGRA210_ADX_CTRL, 3, 0),
    284};
    285
    286#define STREAM_ROUTES(id, sname)					  \
    287	{ "XBAR-" sname,		NULL,	"XBAR-TX" },		  \
    288	{ "RX-CIF-" sname,		NULL,	"XBAR-" sname },	  \
    289	{ "RX",				NULL,	"RX-CIF-" sname },	  \
    290	{ "TX" #id,			NULL,	"RX" },			  \
    291	{ "TX" #id "-CIF-" sname,	NULL,	"TX" #id },		  \
    292	{ "TX" #id " XBAR-" sname,	NULL,	"TX" #id "-CIF-" sname }, \
    293	{ "TX" #id " XBAR-RX",		NULL,	"TX" #id " XBAR-" sname }
    294
    295#define ADX_ROUTES(id)			\
    296	STREAM_ROUTES(id, "Playback"),	\
    297	STREAM_ROUTES(id, "Capture")
    298
    299#define STREAM_ROUTES(id, sname)					  \
    300	{ "XBAR-" sname,		NULL,	"XBAR-TX" },		  \
    301	{ "RX-CIF-" sname,		NULL,	"XBAR-" sname },	  \
    302	{ "RX",				NULL,	"RX-CIF-" sname },	  \
    303	{ "TX" #id,			NULL,	"RX" },			  \
    304	{ "TX" #id "-CIF-" sname,	NULL,	"TX" #id },		  \
    305	{ "TX" #id " XBAR-" sname,	NULL,	"TX" #id "-CIF-" sname }, \
    306	{ "TX" #id " XBAR-RX",		NULL,	"TX" #id " XBAR-" sname }
    307
    308#define ADX_ROUTES(id)			\
    309	STREAM_ROUTES(id, "Playback"),	\
    310	STREAM_ROUTES(id, "Capture")
    311
    312static const struct snd_soc_dapm_route tegra210_adx_routes[] = {
    313	ADX_ROUTES(1),
    314	ADX_ROUTES(2),
    315	ADX_ROUTES(3),
    316	ADX_ROUTES(4),
    317};
    318
    319#define TEGRA210_ADX_BYTE_MAP_CTRL(reg)			 \
    320	SOC_SINGLE_EXT("Byte Map " #reg, reg, 0, 256, 0, \
    321		       tegra210_adx_get_byte_map,	 \
    322		       tegra210_adx_put_byte_map)
    323
    324static struct snd_kcontrol_new tegra210_adx_controls[] = {
    325	TEGRA210_ADX_BYTE_MAP_CTRL(0),
    326	TEGRA210_ADX_BYTE_MAP_CTRL(1),
    327	TEGRA210_ADX_BYTE_MAP_CTRL(2),
    328	TEGRA210_ADX_BYTE_MAP_CTRL(3),
    329	TEGRA210_ADX_BYTE_MAP_CTRL(4),
    330	TEGRA210_ADX_BYTE_MAP_CTRL(5),
    331	TEGRA210_ADX_BYTE_MAP_CTRL(6),
    332	TEGRA210_ADX_BYTE_MAP_CTRL(7),
    333	TEGRA210_ADX_BYTE_MAP_CTRL(8),
    334	TEGRA210_ADX_BYTE_MAP_CTRL(9),
    335	TEGRA210_ADX_BYTE_MAP_CTRL(10),
    336	TEGRA210_ADX_BYTE_MAP_CTRL(11),
    337	TEGRA210_ADX_BYTE_MAP_CTRL(12),
    338	TEGRA210_ADX_BYTE_MAP_CTRL(13),
    339	TEGRA210_ADX_BYTE_MAP_CTRL(14),
    340	TEGRA210_ADX_BYTE_MAP_CTRL(15),
    341	TEGRA210_ADX_BYTE_MAP_CTRL(16),
    342	TEGRA210_ADX_BYTE_MAP_CTRL(17),
    343	TEGRA210_ADX_BYTE_MAP_CTRL(18),
    344	TEGRA210_ADX_BYTE_MAP_CTRL(19),
    345	TEGRA210_ADX_BYTE_MAP_CTRL(20),
    346	TEGRA210_ADX_BYTE_MAP_CTRL(21),
    347	TEGRA210_ADX_BYTE_MAP_CTRL(22),
    348	TEGRA210_ADX_BYTE_MAP_CTRL(23),
    349	TEGRA210_ADX_BYTE_MAP_CTRL(24),
    350	TEGRA210_ADX_BYTE_MAP_CTRL(25),
    351	TEGRA210_ADX_BYTE_MAP_CTRL(26),
    352	TEGRA210_ADX_BYTE_MAP_CTRL(27),
    353	TEGRA210_ADX_BYTE_MAP_CTRL(28),
    354	TEGRA210_ADX_BYTE_MAP_CTRL(29),
    355	TEGRA210_ADX_BYTE_MAP_CTRL(30),
    356	TEGRA210_ADX_BYTE_MAP_CTRL(31),
    357	TEGRA210_ADX_BYTE_MAP_CTRL(32),
    358	TEGRA210_ADX_BYTE_MAP_CTRL(33),
    359	TEGRA210_ADX_BYTE_MAP_CTRL(34),
    360	TEGRA210_ADX_BYTE_MAP_CTRL(35),
    361	TEGRA210_ADX_BYTE_MAP_CTRL(36),
    362	TEGRA210_ADX_BYTE_MAP_CTRL(37),
    363	TEGRA210_ADX_BYTE_MAP_CTRL(38),
    364	TEGRA210_ADX_BYTE_MAP_CTRL(39),
    365	TEGRA210_ADX_BYTE_MAP_CTRL(40),
    366	TEGRA210_ADX_BYTE_MAP_CTRL(41),
    367	TEGRA210_ADX_BYTE_MAP_CTRL(42),
    368	TEGRA210_ADX_BYTE_MAP_CTRL(43),
    369	TEGRA210_ADX_BYTE_MAP_CTRL(44),
    370	TEGRA210_ADX_BYTE_MAP_CTRL(45),
    371	TEGRA210_ADX_BYTE_MAP_CTRL(46),
    372	TEGRA210_ADX_BYTE_MAP_CTRL(47),
    373	TEGRA210_ADX_BYTE_MAP_CTRL(48),
    374	TEGRA210_ADX_BYTE_MAP_CTRL(49),
    375	TEGRA210_ADX_BYTE_MAP_CTRL(50),
    376	TEGRA210_ADX_BYTE_MAP_CTRL(51),
    377	TEGRA210_ADX_BYTE_MAP_CTRL(52),
    378	TEGRA210_ADX_BYTE_MAP_CTRL(53),
    379	TEGRA210_ADX_BYTE_MAP_CTRL(54),
    380	TEGRA210_ADX_BYTE_MAP_CTRL(55),
    381	TEGRA210_ADX_BYTE_MAP_CTRL(56),
    382	TEGRA210_ADX_BYTE_MAP_CTRL(57),
    383	TEGRA210_ADX_BYTE_MAP_CTRL(58),
    384	TEGRA210_ADX_BYTE_MAP_CTRL(59),
    385	TEGRA210_ADX_BYTE_MAP_CTRL(60),
    386	TEGRA210_ADX_BYTE_MAP_CTRL(61),
    387	TEGRA210_ADX_BYTE_MAP_CTRL(62),
    388	TEGRA210_ADX_BYTE_MAP_CTRL(63),
    389};
    390
    391static const struct snd_soc_component_driver tegra210_adx_cmpnt = {
    392	.dapm_widgets		= tegra210_adx_widgets,
    393	.num_dapm_widgets	= ARRAY_SIZE(tegra210_adx_widgets),
    394	.dapm_routes		= tegra210_adx_routes,
    395	.num_dapm_routes	= ARRAY_SIZE(tegra210_adx_routes),
    396	.controls		= tegra210_adx_controls,
    397	.num_controls		= ARRAY_SIZE(tegra210_adx_controls),
    398};
    399
    400static bool tegra210_adx_wr_reg(struct device *dev,
    401				unsigned int reg)
    402{
    403	switch (reg) {
    404	case TEGRA210_ADX_TX_INT_MASK ... TEGRA210_ADX_TX4_CIF_CTRL:
    405	case TEGRA210_ADX_RX_INT_MASK ... TEGRA210_ADX_RX_CIF_CTRL:
    406	case TEGRA210_ADX_ENABLE ... TEGRA210_ADX_CG:
    407	case TEGRA210_ADX_CTRL ... TEGRA210_ADX_IN_BYTE_EN1:
    408	case TEGRA210_ADX_CFG_RAM_CTRL ... TEGRA210_ADX_CFG_RAM_DATA:
    409		return true;
    410	default:
    411		return false;
    412	}
    413}
    414
    415static bool tegra210_adx_rd_reg(struct device *dev,
    416				unsigned int reg)
    417{
    418	switch (reg) {
    419	case TEGRA210_ADX_RX_STATUS ... TEGRA210_ADX_CFG_RAM_DATA:
    420		return true;
    421	default:
    422		return false;
    423	}
    424}
    425
    426static bool tegra210_adx_volatile_reg(struct device *dev,
    427				unsigned int reg)
    428{
    429	switch (reg) {
    430	case TEGRA210_ADX_RX_STATUS:
    431	case TEGRA210_ADX_RX_INT_STATUS:
    432	case TEGRA210_ADX_RX_INT_SET:
    433	case TEGRA210_ADX_TX_STATUS:
    434	case TEGRA210_ADX_TX_INT_STATUS:
    435	case TEGRA210_ADX_TX_INT_SET:
    436	case TEGRA210_ADX_SOFT_RESET:
    437	case TEGRA210_ADX_STATUS:
    438	case TEGRA210_ADX_INT_STATUS:
    439	case TEGRA210_ADX_CFG_RAM_CTRL:
    440	case TEGRA210_ADX_CFG_RAM_DATA:
    441		return true;
    442	default:
    443		break;
    444	}
    445
    446	return false;
    447}
    448
    449static const struct regmap_config tegra210_adx_regmap_config = {
    450	.reg_bits		= 32,
    451	.reg_stride		= 4,
    452	.val_bits		= 32,
    453	.max_register		= TEGRA210_ADX_CFG_RAM_DATA,
    454	.writeable_reg		= tegra210_adx_wr_reg,
    455	.readable_reg		= tegra210_adx_rd_reg,
    456	.volatile_reg		= tegra210_adx_volatile_reg,
    457	.reg_defaults		= tegra210_adx_reg_defaults,
    458	.num_reg_defaults	= ARRAY_SIZE(tegra210_adx_reg_defaults),
    459	.cache_type		= REGCACHE_FLAT,
    460};
    461
    462static const struct of_device_id tegra210_adx_of_match[] = {
    463	{ .compatible = "nvidia,tegra210-adx" },
    464	{},
    465};
    466MODULE_DEVICE_TABLE(of, tegra210_adx_of_match);
    467
    468static int tegra210_adx_platform_probe(struct platform_device *pdev)
    469{
    470	struct device *dev = &pdev->dev;
    471	struct tegra210_adx *adx;
    472	void __iomem *regs;
    473	int err;
    474
    475	adx = devm_kzalloc(dev, sizeof(*adx), GFP_KERNEL);
    476	if (!adx)
    477		return -ENOMEM;
    478
    479	dev_set_drvdata(dev, adx);
    480
    481	regs = devm_platform_ioremap_resource(pdev, 0);
    482	if (IS_ERR(regs))
    483		return PTR_ERR(regs);
    484
    485	adx->regmap = devm_regmap_init_mmio(dev, regs,
    486					    &tegra210_adx_regmap_config);
    487	if (IS_ERR(adx->regmap)) {
    488		dev_err(dev, "regmap init failed\n");
    489		return PTR_ERR(adx->regmap);
    490	}
    491
    492	regcache_cache_only(adx->regmap, true);
    493
    494	err = devm_snd_soc_register_component(dev, &tegra210_adx_cmpnt,
    495					      tegra210_adx_dais,
    496					      ARRAY_SIZE(tegra210_adx_dais));
    497	if (err) {
    498		dev_err(dev, "can't register ADX component, err: %d\n", err);
    499		return err;
    500	}
    501
    502	pm_runtime_enable(dev);
    503
    504	return 0;
    505}
    506
    507static int tegra210_adx_platform_remove(struct platform_device *pdev)
    508{
    509	pm_runtime_disable(&pdev->dev);
    510
    511	return 0;
    512}
    513
    514static const struct dev_pm_ops tegra210_adx_pm_ops = {
    515	SET_RUNTIME_PM_OPS(tegra210_adx_runtime_suspend,
    516			   tegra210_adx_runtime_resume, NULL)
    517	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
    518				pm_runtime_force_resume)
    519};
    520
    521static struct platform_driver tegra210_adx_driver = {
    522	.driver = {
    523		.name = "tegra210-adx",
    524		.of_match_table = tegra210_adx_of_match,
    525		.pm = &tegra210_adx_pm_ops,
    526	},
    527	.probe = tegra210_adx_platform_probe,
    528	.remove = tegra210_adx_platform_remove,
    529};
    530module_platform_driver(tegra210_adx_driver);
    531
    532MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>");
    533MODULE_DESCRIPTION("Tegra210 ADX ASoC driver");
    534MODULE_LICENSE("GPL v2");