linux/sound/soc/tegra/tegra210_adx.c
<<
>>
Prefs
   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");
 535