Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 //
0003 // tegra210_adx.c - Tegra210 ADX driver
0004 //
0005 // Copyright (c) 2021 NVIDIA CORPORATION.  All rights reserved.
0006 
0007 #include <linux/clk.h>
0008 #include <linux/device.h>
0009 #include <linux/io.h>
0010 #include <linux/module.h>
0011 #include <linux/of.h>
0012 #include <linux/of_device.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/pm_runtime.h>
0015 #include <linux/regmap.h>
0016 #include <sound/core.h>
0017 #include <sound/pcm.h>
0018 #include <sound/pcm_params.h>
0019 #include <sound/soc.h>
0020 
0021 #include "tegra210_adx.h"
0022 #include "tegra_cif.h"
0023 
0024 static const struct reg_default tegra210_adx_reg_defaults[] = {
0025     { TEGRA210_ADX_RX_INT_MASK, 0x00000001},
0026     { TEGRA210_ADX_RX_CIF_CTRL, 0x00007000},
0027     { TEGRA210_ADX_TX_INT_MASK, 0x0000000f },
0028     { TEGRA210_ADX_TX1_CIF_CTRL, 0x00007000},
0029     { TEGRA210_ADX_TX2_CIF_CTRL, 0x00007000},
0030     { TEGRA210_ADX_TX3_CIF_CTRL, 0x00007000},
0031     { TEGRA210_ADX_TX4_CIF_CTRL, 0x00007000},
0032     { TEGRA210_ADX_CG, 0x1},
0033     { TEGRA210_ADX_CFG_RAM_CTRL, 0x00004000},
0034 };
0035 
0036 static void tegra210_adx_write_map_ram(struct tegra210_adx *adx)
0037 {
0038     int i;
0039 
0040     regmap_write(adx->regmap, TEGRA210_ADX_CFG_RAM_CTRL,
0041              TEGRA210_ADX_CFG_RAM_CTRL_SEQ_ACCESS_EN |
0042              TEGRA210_ADX_CFG_RAM_CTRL_ADDR_INIT_EN |
0043              TEGRA210_ADX_CFG_RAM_CTRL_RW_WRITE);
0044 
0045     for (i = 0; i < TEGRA210_ADX_RAM_DEPTH; i++)
0046         regmap_write(adx->regmap, TEGRA210_ADX_CFG_RAM_DATA,
0047                  adx->map[i]);
0048 
0049     regmap_write(adx->regmap, TEGRA210_ADX_IN_BYTE_EN0, adx->byte_mask[0]);
0050     regmap_write(adx->regmap, TEGRA210_ADX_IN_BYTE_EN1, adx->byte_mask[1]);
0051 }
0052 
0053 static int tegra210_adx_startup(struct snd_pcm_substream *substream,
0054                 struct snd_soc_dai *dai)
0055 {
0056     struct tegra210_adx *adx = snd_soc_dai_get_drvdata(dai);
0057     unsigned int val;
0058     int err;
0059 
0060     /* Ensure if ADX status is disabled */
0061     err = regmap_read_poll_timeout_atomic(adx->regmap, TEGRA210_ADX_STATUS,
0062                           val, !(val & 0x1), 10, 10000);
0063     if (err < 0) {
0064         dev_err(dai->dev, "failed to stop ADX, err = %d\n", err);
0065         return err;
0066     }
0067 
0068     /*
0069      * Soft Reset: Below performs module soft reset which clears
0070      * all FSM logic, flushes flow control of FIFO and resets the
0071      * state register. It also brings module back to disabled
0072      * state (without flushing the data in the pipe).
0073      */
0074     regmap_update_bits(adx->regmap, TEGRA210_ADX_SOFT_RESET,
0075                TEGRA210_ADX_SOFT_RESET_SOFT_RESET_MASK,
0076                TEGRA210_ADX_SOFT_RESET_SOFT_EN);
0077 
0078     err = regmap_read_poll_timeout(adx->regmap, TEGRA210_ADX_SOFT_RESET,
0079                        val, !(val & 0x1), 10, 10000);
0080     if (err < 0) {
0081         dev_err(dai->dev, "failed to reset ADX, err = %d\n", err);
0082         return err;
0083     }
0084 
0085     return 0;
0086 }
0087 
0088 static int __maybe_unused tegra210_adx_runtime_suspend(struct device *dev)
0089 {
0090     struct tegra210_adx *adx = dev_get_drvdata(dev);
0091 
0092     regcache_cache_only(adx->regmap, true);
0093     regcache_mark_dirty(adx->regmap);
0094 
0095     return 0;
0096 }
0097 
0098 static int __maybe_unused tegra210_adx_runtime_resume(struct device *dev)
0099 {
0100     struct tegra210_adx *adx = dev_get_drvdata(dev);
0101 
0102     regcache_cache_only(adx->regmap, false);
0103     regcache_sync(adx->regmap);
0104 
0105     tegra210_adx_write_map_ram(adx);
0106 
0107     return 0;
0108 }
0109 
0110 static int tegra210_adx_set_audio_cif(struct snd_soc_dai *dai,
0111                       unsigned int channels,
0112                       unsigned int format,
0113                       unsigned int reg)
0114 {
0115     struct tegra210_adx *adx = snd_soc_dai_get_drvdata(dai);
0116     struct tegra_cif_conf cif_conf;
0117     int audio_bits;
0118 
0119     memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
0120 
0121     if (channels < 1 || channels > 16)
0122         return -EINVAL;
0123 
0124     switch (format) {
0125     case SNDRV_PCM_FORMAT_S8:
0126         audio_bits = TEGRA_ACIF_BITS_8;
0127         break;
0128     case SNDRV_PCM_FORMAT_S16_LE:
0129         audio_bits = TEGRA_ACIF_BITS_16;
0130         break;
0131     case SNDRV_PCM_FORMAT_S32_LE:
0132         audio_bits = TEGRA_ACIF_BITS_32;
0133         break;
0134     default:
0135         return -EINVAL;
0136     }
0137 
0138     cif_conf.audio_ch = channels;
0139     cif_conf.client_ch = channels;
0140     cif_conf.audio_bits = audio_bits;
0141     cif_conf.client_bits = audio_bits;
0142 
0143     tegra_set_cif(adx->regmap, reg, &cif_conf);
0144 
0145     return 0;
0146 }
0147 
0148 static int tegra210_adx_out_hw_params(struct snd_pcm_substream *substream,
0149                       struct snd_pcm_hw_params *params,
0150                       struct snd_soc_dai *dai)
0151 {
0152     return tegra210_adx_set_audio_cif(dai, params_channels(params),
0153             params_format(params),
0154             TEGRA210_ADX_TX1_CIF_CTRL + ((dai->id - 1) * TEGRA210_ADX_AUDIOCIF_CH_STRIDE));
0155 }
0156 
0157 static int tegra210_adx_in_hw_params(struct snd_pcm_substream *substream,
0158                      struct snd_pcm_hw_params *params,
0159                      struct snd_soc_dai *dai)
0160 {
0161     return tegra210_adx_set_audio_cif(dai, params_channels(params),
0162                       params_format(params),
0163                       TEGRA210_ADX_RX_CIF_CTRL);
0164 }
0165 
0166 static int tegra210_adx_get_byte_map(struct snd_kcontrol *kcontrol,
0167                      struct snd_ctl_elem_value *ucontrol)
0168 {
0169     struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
0170     struct tegra210_adx *adx = snd_soc_component_get_drvdata(cmpnt);
0171     struct soc_mixer_control *mc;
0172     unsigned char *bytes_map = (unsigned char *)&adx->map;
0173     int enabled;
0174 
0175     mc = (struct soc_mixer_control *)kcontrol->private_value;
0176     enabled = adx->byte_mask[mc->reg / 32] & (1 << (mc->reg % 32));
0177 
0178     if (enabled)
0179         ucontrol->value.integer.value[0] = bytes_map[mc->reg];
0180     else
0181         ucontrol->value.integer.value[0] = 0;
0182 
0183     return 0;
0184 }
0185 
0186 static int tegra210_adx_put_byte_map(struct snd_kcontrol *kcontrol,
0187                      struct snd_ctl_elem_value *ucontrol)
0188 {
0189     struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
0190     struct tegra210_adx *adx = snd_soc_component_get_drvdata(cmpnt);
0191     unsigned char *bytes_map = (unsigned char *)&adx->map;
0192     int value = ucontrol->value.integer.value[0];
0193     struct soc_mixer_control *mc =
0194         (struct soc_mixer_control *)kcontrol->private_value;
0195 
0196     if (value == bytes_map[mc->reg])
0197         return 0;
0198 
0199     if (value >= 0 && value <= 255) {
0200         /* update byte map and enable slot */
0201         bytes_map[mc->reg] = value;
0202         adx->byte_mask[mc->reg / 32] |= (1 << (mc->reg % 32));
0203     } else {
0204         /* reset byte map and disable slot */
0205         bytes_map[mc->reg] = 0;
0206         adx->byte_mask[mc->reg / 32] &= ~(1 << (mc->reg % 32));
0207     }
0208 
0209     return 1;
0210 }
0211 
0212 static const struct snd_soc_dai_ops tegra210_adx_in_dai_ops = {
0213     .hw_params  = tegra210_adx_in_hw_params,
0214     .startup    = tegra210_adx_startup,
0215 };
0216 
0217 static const struct snd_soc_dai_ops tegra210_adx_out_dai_ops = {
0218     .hw_params  = tegra210_adx_out_hw_params,
0219 };
0220 
0221 #define IN_DAI                          \
0222     {                           \
0223         .name = "ADX-RX-CIF",               \
0224         .playback = {                   \
0225             .stream_name = "RX-CIF-Playback",   \
0226             .channels_min = 1,          \
0227             .channels_max = 16,         \
0228             .rates = SNDRV_PCM_RATE_8000_192000,    \
0229             .formats = SNDRV_PCM_FMTBIT_S8 |    \
0230                    SNDRV_PCM_FMTBIT_S16_LE |    \
0231                    SNDRV_PCM_FMTBIT_S32_LE, \
0232         },                      \
0233         .capture = {                    \
0234             .stream_name = "RX-CIF-Capture",    \
0235             .channels_min = 1,          \
0236             .channels_max = 16,         \
0237             .rates = SNDRV_PCM_RATE_8000_192000,    \
0238             .formats = SNDRV_PCM_FMTBIT_S8 |    \
0239                    SNDRV_PCM_FMTBIT_S16_LE |    \
0240                    SNDRV_PCM_FMTBIT_S32_LE, \
0241         },                      \
0242         .ops = &tegra210_adx_in_dai_ops,        \
0243     }
0244 
0245 #define OUT_DAI(id)                     \
0246     {                           \
0247         .name = "ADX-TX" #id "-CIF",            \
0248         .playback = {                   \
0249             .stream_name = "TX" #id "-CIF-Playback",\
0250             .channels_min = 1,          \
0251             .channels_max = 16,         \
0252             .rates = SNDRV_PCM_RATE_8000_192000,    \
0253             .formats = SNDRV_PCM_FMTBIT_S8 |    \
0254                    SNDRV_PCM_FMTBIT_S16_LE |    \
0255                    SNDRV_PCM_FMTBIT_S32_LE, \
0256         },                      \
0257         .capture = {                    \
0258             .stream_name = "TX" #id "-CIF-Capture", \
0259             .channels_min = 1,          \
0260             .channels_max = 16,         \
0261             .rates = SNDRV_PCM_RATE_8000_192000,    \
0262             .formats = SNDRV_PCM_FMTBIT_S8 |    \
0263                    SNDRV_PCM_FMTBIT_S16_LE |    \
0264                    SNDRV_PCM_FMTBIT_S32_LE, \
0265         },                      \
0266         .ops = &tegra210_adx_out_dai_ops,       \
0267     }
0268 
0269 static struct snd_soc_dai_driver tegra210_adx_dais[] = {
0270     IN_DAI,
0271     OUT_DAI(1),
0272     OUT_DAI(2),
0273     OUT_DAI(3),
0274     OUT_DAI(4),
0275 };
0276 
0277 static const struct snd_soc_dapm_widget tegra210_adx_widgets[] = {
0278     SND_SOC_DAPM_AIF_IN("RX", NULL, 0, TEGRA210_ADX_ENABLE,
0279                 TEGRA210_ADX_ENABLE_SHIFT, 0),
0280     SND_SOC_DAPM_AIF_OUT("TX1", NULL, 0, TEGRA210_ADX_CTRL, 0, 0),
0281     SND_SOC_DAPM_AIF_OUT("TX2", NULL, 0, TEGRA210_ADX_CTRL, 1, 0),
0282     SND_SOC_DAPM_AIF_OUT("TX3", NULL, 0, TEGRA210_ADX_CTRL, 2, 0),
0283     SND_SOC_DAPM_AIF_OUT("TX4", NULL, 0, TEGRA210_ADX_CTRL, 3, 0),
0284 };
0285 
0286 #define STREAM_ROUTES(id, sname)                      \
0287     { "XBAR-" sname,        NULL,   "XBAR-TX" },          \
0288     { "RX-CIF-" sname,      NULL,   "XBAR-" sname },      \
0289     { "RX",             NULL,   "RX-CIF-" sname },    \
0290     { "TX" #id,         NULL,   "RX" },           \
0291     { "TX" #id "-CIF-" sname,   NULL,   "TX" #id },       \
0292     { "TX" #id " XBAR-" sname,  NULL,   "TX" #id "-CIF-" sname }, \
0293     { "TX" #id " XBAR-RX",      NULL,   "TX" #id " XBAR-" sname }
0294 
0295 #define ADX_ROUTES(id)          \
0296     STREAM_ROUTES(id, "Playback"),  \
0297     STREAM_ROUTES(id, "Capture")
0298 
0299 #define STREAM_ROUTES(id, sname)                      \
0300     { "XBAR-" sname,        NULL,   "XBAR-TX" },          \
0301     { "RX-CIF-" sname,      NULL,   "XBAR-" sname },      \
0302     { "RX",             NULL,   "RX-CIF-" sname },    \
0303     { "TX" #id,         NULL,   "RX" },           \
0304     { "TX" #id "-CIF-" sname,   NULL,   "TX" #id },       \
0305     { "TX" #id " XBAR-" sname,  NULL,   "TX" #id "-CIF-" sname }, \
0306     { "TX" #id " XBAR-RX",      NULL,   "TX" #id " XBAR-" sname }
0307 
0308 #define ADX_ROUTES(id)          \
0309     STREAM_ROUTES(id, "Playback"),  \
0310     STREAM_ROUTES(id, "Capture")
0311 
0312 static const struct snd_soc_dapm_route tegra210_adx_routes[] = {
0313     ADX_ROUTES(1),
0314     ADX_ROUTES(2),
0315     ADX_ROUTES(3),
0316     ADX_ROUTES(4),
0317 };
0318 
0319 #define TEGRA210_ADX_BYTE_MAP_CTRL(reg)          \
0320     SOC_SINGLE_EXT("Byte Map " #reg, reg, 0, 256, 0, \
0321                tegra210_adx_get_byte_map,    \
0322                tegra210_adx_put_byte_map)
0323 
0324 static struct snd_kcontrol_new tegra210_adx_controls[] = {
0325     TEGRA210_ADX_BYTE_MAP_CTRL(0),
0326     TEGRA210_ADX_BYTE_MAP_CTRL(1),
0327     TEGRA210_ADX_BYTE_MAP_CTRL(2),
0328     TEGRA210_ADX_BYTE_MAP_CTRL(3),
0329     TEGRA210_ADX_BYTE_MAP_CTRL(4),
0330     TEGRA210_ADX_BYTE_MAP_CTRL(5),
0331     TEGRA210_ADX_BYTE_MAP_CTRL(6),
0332     TEGRA210_ADX_BYTE_MAP_CTRL(7),
0333     TEGRA210_ADX_BYTE_MAP_CTRL(8),
0334     TEGRA210_ADX_BYTE_MAP_CTRL(9),
0335     TEGRA210_ADX_BYTE_MAP_CTRL(10),
0336     TEGRA210_ADX_BYTE_MAP_CTRL(11),
0337     TEGRA210_ADX_BYTE_MAP_CTRL(12),
0338     TEGRA210_ADX_BYTE_MAP_CTRL(13),
0339     TEGRA210_ADX_BYTE_MAP_CTRL(14),
0340     TEGRA210_ADX_BYTE_MAP_CTRL(15),
0341     TEGRA210_ADX_BYTE_MAP_CTRL(16),
0342     TEGRA210_ADX_BYTE_MAP_CTRL(17),
0343     TEGRA210_ADX_BYTE_MAP_CTRL(18),
0344     TEGRA210_ADX_BYTE_MAP_CTRL(19),
0345     TEGRA210_ADX_BYTE_MAP_CTRL(20),
0346     TEGRA210_ADX_BYTE_MAP_CTRL(21),
0347     TEGRA210_ADX_BYTE_MAP_CTRL(22),
0348     TEGRA210_ADX_BYTE_MAP_CTRL(23),
0349     TEGRA210_ADX_BYTE_MAP_CTRL(24),
0350     TEGRA210_ADX_BYTE_MAP_CTRL(25),
0351     TEGRA210_ADX_BYTE_MAP_CTRL(26),
0352     TEGRA210_ADX_BYTE_MAP_CTRL(27),
0353     TEGRA210_ADX_BYTE_MAP_CTRL(28),
0354     TEGRA210_ADX_BYTE_MAP_CTRL(29),
0355     TEGRA210_ADX_BYTE_MAP_CTRL(30),
0356     TEGRA210_ADX_BYTE_MAP_CTRL(31),
0357     TEGRA210_ADX_BYTE_MAP_CTRL(32),
0358     TEGRA210_ADX_BYTE_MAP_CTRL(33),
0359     TEGRA210_ADX_BYTE_MAP_CTRL(34),
0360     TEGRA210_ADX_BYTE_MAP_CTRL(35),
0361     TEGRA210_ADX_BYTE_MAP_CTRL(36),
0362     TEGRA210_ADX_BYTE_MAP_CTRL(37),
0363     TEGRA210_ADX_BYTE_MAP_CTRL(38),
0364     TEGRA210_ADX_BYTE_MAP_CTRL(39),
0365     TEGRA210_ADX_BYTE_MAP_CTRL(40),
0366     TEGRA210_ADX_BYTE_MAP_CTRL(41),
0367     TEGRA210_ADX_BYTE_MAP_CTRL(42),
0368     TEGRA210_ADX_BYTE_MAP_CTRL(43),
0369     TEGRA210_ADX_BYTE_MAP_CTRL(44),
0370     TEGRA210_ADX_BYTE_MAP_CTRL(45),
0371     TEGRA210_ADX_BYTE_MAP_CTRL(46),
0372     TEGRA210_ADX_BYTE_MAP_CTRL(47),
0373     TEGRA210_ADX_BYTE_MAP_CTRL(48),
0374     TEGRA210_ADX_BYTE_MAP_CTRL(49),
0375     TEGRA210_ADX_BYTE_MAP_CTRL(50),
0376     TEGRA210_ADX_BYTE_MAP_CTRL(51),
0377     TEGRA210_ADX_BYTE_MAP_CTRL(52),
0378     TEGRA210_ADX_BYTE_MAP_CTRL(53),
0379     TEGRA210_ADX_BYTE_MAP_CTRL(54),
0380     TEGRA210_ADX_BYTE_MAP_CTRL(55),
0381     TEGRA210_ADX_BYTE_MAP_CTRL(56),
0382     TEGRA210_ADX_BYTE_MAP_CTRL(57),
0383     TEGRA210_ADX_BYTE_MAP_CTRL(58),
0384     TEGRA210_ADX_BYTE_MAP_CTRL(59),
0385     TEGRA210_ADX_BYTE_MAP_CTRL(60),
0386     TEGRA210_ADX_BYTE_MAP_CTRL(61),
0387     TEGRA210_ADX_BYTE_MAP_CTRL(62),
0388     TEGRA210_ADX_BYTE_MAP_CTRL(63),
0389 };
0390 
0391 static const struct snd_soc_component_driver tegra210_adx_cmpnt = {
0392     .dapm_widgets       = tegra210_adx_widgets,
0393     .num_dapm_widgets   = ARRAY_SIZE(tegra210_adx_widgets),
0394     .dapm_routes        = tegra210_adx_routes,
0395     .num_dapm_routes    = ARRAY_SIZE(tegra210_adx_routes),
0396     .controls       = tegra210_adx_controls,
0397     .num_controls       = ARRAY_SIZE(tegra210_adx_controls),
0398 };
0399 
0400 static bool tegra210_adx_wr_reg(struct device *dev,
0401                 unsigned int reg)
0402 {
0403     switch (reg) {
0404     case TEGRA210_ADX_TX_INT_MASK ... TEGRA210_ADX_TX4_CIF_CTRL:
0405     case TEGRA210_ADX_RX_INT_MASK ... TEGRA210_ADX_RX_CIF_CTRL:
0406     case TEGRA210_ADX_ENABLE ... TEGRA210_ADX_CG:
0407     case TEGRA210_ADX_CTRL ... TEGRA210_ADX_IN_BYTE_EN1:
0408     case TEGRA210_ADX_CFG_RAM_CTRL ... TEGRA210_ADX_CFG_RAM_DATA:
0409         return true;
0410     default:
0411         return false;
0412     }
0413 }
0414 
0415 static bool tegra210_adx_rd_reg(struct device *dev,
0416                 unsigned int reg)
0417 {
0418     switch (reg) {
0419     case TEGRA210_ADX_RX_STATUS ... TEGRA210_ADX_CFG_RAM_DATA:
0420         return true;
0421     default:
0422         return false;
0423     }
0424 }
0425 
0426 static bool tegra210_adx_volatile_reg(struct device *dev,
0427                 unsigned int reg)
0428 {
0429     switch (reg) {
0430     case TEGRA210_ADX_RX_STATUS:
0431     case TEGRA210_ADX_RX_INT_STATUS:
0432     case TEGRA210_ADX_RX_INT_SET:
0433     case TEGRA210_ADX_TX_STATUS:
0434     case TEGRA210_ADX_TX_INT_STATUS:
0435     case TEGRA210_ADX_TX_INT_SET:
0436     case TEGRA210_ADX_SOFT_RESET:
0437     case TEGRA210_ADX_STATUS:
0438     case TEGRA210_ADX_INT_STATUS:
0439     case TEGRA210_ADX_CFG_RAM_CTRL:
0440     case TEGRA210_ADX_CFG_RAM_DATA:
0441         return true;
0442     default:
0443         break;
0444     }
0445 
0446     return false;
0447 }
0448 
0449 static const struct regmap_config tegra210_adx_regmap_config = {
0450     .reg_bits       = 32,
0451     .reg_stride     = 4,
0452     .val_bits       = 32,
0453     .max_register       = TEGRA210_ADX_CFG_RAM_DATA,
0454     .writeable_reg      = tegra210_adx_wr_reg,
0455     .readable_reg       = tegra210_adx_rd_reg,
0456     .volatile_reg       = tegra210_adx_volatile_reg,
0457     .reg_defaults       = tegra210_adx_reg_defaults,
0458     .num_reg_defaults   = ARRAY_SIZE(tegra210_adx_reg_defaults),
0459     .cache_type     = REGCACHE_FLAT,
0460 };
0461 
0462 static const struct of_device_id tegra210_adx_of_match[] = {
0463     { .compatible = "nvidia,tegra210-adx" },
0464     {},
0465 };
0466 MODULE_DEVICE_TABLE(of, tegra210_adx_of_match);
0467 
0468 static int tegra210_adx_platform_probe(struct platform_device *pdev)
0469 {
0470     struct device *dev = &pdev->dev;
0471     struct tegra210_adx *adx;
0472     void __iomem *regs;
0473     int err;
0474 
0475     adx = devm_kzalloc(dev, sizeof(*adx), GFP_KERNEL);
0476     if (!adx)
0477         return -ENOMEM;
0478 
0479     dev_set_drvdata(dev, adx);
0480 
0481     regs = devm_platform_ioremap_resource(pdev, 0);
0482     if (IS_ERR(regs))
0483         return PTR_ERR(regs);
0484 
0485     adx->regmap = devm_regmap_init_mmio(dev, regs,
0486                         &tegra210_adx_regmap_config);
0487     if (IS_ERR(adx->regmap)) {
0488         dev_err(dev, "regmap init failed\n");
0489         return PTR_ERR(adx->regmap);
0490     }
0491 
0492     regcache_cache_only(adx->regmap, true);
0493 
0494     err = devm_snd_soc_register_component(dev, &tegra210_adx_cmpnt,
0495                           tegra210_adx_dais,
0496                           ARRAY_SIZE(tegra210_adx_dais));
0497     if (err) {
0498         dev_err(dev, "can't register ADX component, err: %d\n", err);
0499         return err;
0500     }
0501 
0502     pm_runtime_enable(dev);
0503 
0504     return 0;
0505 }
0506 
0507 static int tegra210_adx_platform_remove(struct platform_device *pdev)
0508 {
0509     pm_runtime_disable(&pdev->dev);
0510 
0511     return 0;
0512 }
0513 
0514 static const struct dev_pm_ops tegra210_adx_pm_ops = {
0515     SET_RUNTIME_PM_OPS(tegra210_adx_runtime_suspend,
0516                tegra210_adx_runtime_resume, NULL)
0517     SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
0518                 pm_runtime_force_resume)
0519 };
0520 
0521 static struct platform_driver tegra210_adx_driver = {
0522     .driver = {
0523         .name = "tegra210-adx",
0524         .of_match_table = tegra210_adx_of_match,
0525         .pm = &tegra210_adx_pm_ops,
0526     },
0527     .probe = tegra210_adx_platform_probe,
0528     .remove = tegra210_adx_platform_remove,
0529 };
0530 module_platform_driver(tegra210_adx_driver);
0531 
0532 MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>");
0533 MODULE_DESCRIPTION("Tegra210 ADX ASoC driver");
0534 MODULE_LICENSE("GPL v2");