1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // tegra210_adx.c - Tegra210 ADX driver 4 // 5 // Copyright (c) 2021-2023 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 24 static 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 36 static 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 53 static 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 88 static 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 98 static 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 110 static int tegra210_adx_set_audio_cif(struct snd_soc_dai *dai, 111 unsigned int channels, 112 snd_pcm_format_t 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 148 static 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 157 static 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 166 static 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 /* 179 * TODO: Simplify this logic to just return from bytes_map[] 180 * 181 * Presently below is required since bytes_map[] is 182 * tightly packed and cannot store the control value of 256. 183 * Byte mask state is used to know if 256 needs to be returned. 184 * Note that for control value of 256, the put() call stores 0 185 * in the bytes_map[] and disables the corresponding bit in 186 * byte_mask[]. 187 */ 188 if (enabled) 189 ucontrol->value.integer.value[0] = bytes_map[mc->reg]; 190 else 191 ucontrol->value.integer.value[0] = 256; 192 193 return 0; 194 } 195 196 static int tegra210_adx_put_byte_map(struct snd_kcontrol *kcontrol, 197 struct snd_ctl_elem_value *ucontrol) 198 { 199 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 200 struct tegra210_adx *adx = snd_soc_component_get_drvdata(cmpnt); 201 unsigned char *bytes_map = (unsigned char *)&adx->map; 202 int value = ucontrol->value.integer.value[0]; 203 struct soc_mixer_control *mc = 204 (struct soc_mixer_control *)kcontrol->private_value; 205 unsigned int mask_val = adx->byte_mask[mc->reg / 32]; 206 207 if (value >= 0 && value <= 255) 208 mask_val |= (1 << (mc->reg % 32)); 209 else 210 mask_val &= ~(1 << (mc->reg % 32)); 211 212 if (mask_val == adx->byte_mask[mc->reg / 32]) 213 return 0; 214 215 /* Update byte map and slot */ 216 bytes_map[mc->reg] = value % 256; 217 adx->byte_mask[mc->reg / 32] = mask_val; 218 219 return 1; 220 } 221 222 static const struct snd_soc_dai_ops tegra210_adx_in_dai_ops = { 223 .hw_params = tegra210_adx_in_hw_params, 224 .startup = tegra210_adx_startup, 225 }; 226 227 static const struct snd_soc_dai_ops tegra210_adx_out_dai_ops = { 228 .hw_params = tegra210_adx_out_hw_params, 229 }; 230 231 #define IN_DAI \ 232 { \ 233 .name = "ADX-RX-CIF", \ 234 .playback = { \ 235 .stream_name = "RX-CIF-Playback", \ 236 .channels_min = 1, \ 237 .channels_max = 16, \ 238 .rates = SNDRV_PCM_RATE_8000_192000, \ 239 .formats = SNDRV_PCM_FMTBIT_S8 | \ 240 SNDRV_PCM_FMTBIT_S16_LE | \ 241 SNDRV_PCM_FMTBIT_S32_LE, \ 242 }, \ 243 .capture = { \ 244 .stream_name = "RX-CIF-Capture", \ 245 .channels_min = 1, \ 246 .channels_max = 16, \ 247 .rates = SNDRV_PCM_RATE_8000_192000, \ 248 .formats = SNDRV_PCM_FMTBIT_S8 | \ 249 SNDRV_PCM_FMTBIT_S16_LE | \ 250 SNDRV_PCM_FMTBIT_S32_LE, \ 251 }, \ 252 .ops = &tegra210_adx_in_dai_ops, \ 253 } 254 255 #define OUT_DAI(id) \ 256 { \ 257 .name = "ADX-TX" #id "-CIF", \ 258 .playback = { \ 259 .stream_name = "TX" #id "-CIF-Playback",\ 260 .channels_min = 1, \ 261 .channels_max = 16, \ 262 .rates = SNDRV_PCM_RATE_8000_192000, \ 263 .formats = SNDRV_PCM_FMTBIT_S8 | \ 264 SNDRV_PCM_FMTBIT_S16_LE | \ 265 SNDRV_PCM_FMTBIT_S32_LE, \ 266 }, \ 267 .capture = { \ 268 .stream_name = "TX" #id "-CIF-Capture", \ 269 .channels_min = 1, \ 270 .channels_max = 16, \ 271 .rates = SNDRV_PCM_RATE_8000_192000, \ 272 .formats = SNDRV_PCM_FMTBIT_S8 | \ 273 SNDRV_PCM_FMTBIT_S16_LE | \ 274 SNDRV_PCM_FMTBIT_S32_LE, \ 275 }, \ 276 .ops = &tegra210_adx_out_dai_ops, \ 277 } 278 279 static struct snd_soc_dai_driver tegra210_adx_dais[] = { 280 IN_DAI, 281 OUT_DAI(1), 282 OUT_DAI(2), 283 OUT_DAI(3), 284 OUT_DAI(4), 285 }; 286 287 static const struct snd_soc_dapm_widget tegra210_adx_widgets[] = { 288 SND_SOC_DAPM_AIF_IN("RX", NULL, 0, TEGRA210_ADX_ENABLE, 289 TEGRA210_ADX_ENABLE_SHIFT, 0), 290 SND_SOC_DAPM_AIF_OUT("TX1", NULL, 0, TEGRA210_ADX_CTRL, 0, 0), 291 SND_SOC_DAPM_AIF_OUT("TX2", NULL, 0, TEGRA210_ADX_CTRL, 1, 0), 292 SND_SOC_DAPM_AIF_OUT("TX3", NULL, 0, TEGRA210_ADX_CTRL, 2, 0), 293 SND_SOC_DAPM_AIF_OUT("TX4", NULL, 0, TEGRA210_ADX_CTRL, 3, 0), 294 }; 295 296 #define STREAM_ROUTES(id, sname) \ 297 { "XBAR-" sname, NULL, "XBAR-TX" }, \ 298 { "RX-CIF-" sname, NULL, "XBAR-" sname }, \ 299 { "RX", NULL, "RX-CIF-" sname }, \ 300 { "TX" #id, NULL, "RX" }, \ 301 { "TX" #id "-CIF-" sname, NULL, "TX" #id }, \ 302 { "TX" #id " XBAR-" sname, NULL, "TX" #id "-CIF-" sname }, \ 303 { "TX" #id " XBAR-RX", NULL, "TX" #id " XBAR-" sname } 304 305 #define ADX_ROUTES(id) \ 306 STREAM_ROUTES(id, "Playback"), \ 307 STREAM_ROUTES(id, "Capture") 308 309 #define STREAM_ROUTES(id, sname) \ 310 { "XBAR-" sname, NULL, "XBAR-TX" }, \ 311 { "RX-CIF-" sname, NULL, "XBAR-" sname }, \ 312 { "RX", NULL, "RX-CIF-" sname }, \ 313 { "TX" #id, NULL, "RX" }, \ 314 { "TX" #id "-CIF-" sname, NULL, "TX" #id }, \ 315 { "TX" #id " XBAR-" sname, NULL, "TX" #id "-CIF-" sname }, \ 316 { "TX" #id " XBAR-RX", NULL, "TX" #id " XBAR-" sname } 317 318 #define ADX_ROUTES(id) \ 319 STREAM_ROUTES(id, "Playback"), \ 320 STREAM_ROUTES(id, "Capture") 321 322 static const struct snd_soc_dapm_route tegra210_adx_routes[] = { 323 ADX_ROUTES(1), 324 ADX_ROUTES(2), 325 ADX_ROUTES(3), 326 ADX_ROUTES(4), 327 }; 328 329 #define TEGRA210_ADX_BYTE_MAP_CTRL(reg) \ 330 SOC_SINGLE_EXT("Byte Map " #reg, reg, 0, 256, 0, \ 331 tegra210_adx_get_byte_map, \ 332 tegra210_adx_put_byte_map) 333 334 static struct snd_kcontrol_new tegra210_adx_controls[] = { 335 TEGRA210_ADX_BYTE_MAP_CTRL(0), 336 TEGRA210_ADX_BYTE_MAP_CTRL(1), 337 TEGRA210_ADX_BYTE_MAP_CTRL(2), 338 TEGRA210_ADX_BYTE_MAP_CTRL(3), 339 TEGRA210_ADX_BYTE_MAP_CTRL(4), 340 TEGRA210_ADX_BYTE_MAP_CTRL(5), 341 TEGRA210_ADX_BYTE_MAP_CTRL(6), 342 TEGRA210_ADX_BYTE_MAP_CTRL(7), 343 TEGRA210_ADX_BYTE_MAP_CTRL(8), 344 TEGRA210_ADX_BYTE_MAP_CTRL(9), 345 TEGRA210_ADX_BYTE_MAP_CTRL(10), 346 TEGRA210_ADX_BYTE_MAP_CTRL(11), 347 TEGRA210_ADX_BYTE_MAP_CTRL(12), 348 TEGRA210_ADX_BYTE_MAP_CTRL(13), 349 TEGRA210_ADX_BYTE_MAP_CTRL(14), 350 TEGRA210_ADX_BYTE_MAP_CTRL(15), 351 TEGRA210_ADX_BYTE_MAP_CTRL(16), 352 TEGRA210_ADX_BYTE_MAP_CTRL(17), 353 TEGRA210_ADX_BYTE_MAP_CTRL(18), 354 TEGRA210_ADX_BYTE_MAP_CTRL(19), 355 TEGRA210_ADX_BYTE_MAP_CTRL(20), 356 TEGRA210_ADX_BYTE_MAP_CTRL(21), 357 TEGRA210_ADX_BYTE_MAP_CTRL(22), 358 TEGRA210_ADX_BYTE_MAP_CTRL(23), 359 TEGRA210_ADX_BYTE_MAP_CTRL(24), 360 TEGRA210_ADX_BYTE_MAP_CTRL(25), 361 TEGRA210_ADX_BYTE_MAP_CTRL(26), 362 TEGRA210_ADX_BYTE_MAP_CTRL(27), 363 TEGRA210_ADX_BYTE_MAP_CTRL(28), 364 TEGRA210_ADX_BYTE_MAP_CTRL(29), 365 TEGRA210_ADX_BYTE_MAP_CTRL(30), 366 TEGRA210_ADX_BYTE_MAP_CTRL(31), 367 TEGRA210_ADX_BYTE_MAP_CTRL(32), 368 TEGRA210_ADX_BYTE_MAP_CTRL(33), 369 TEGRA210_ADX_BYTE_MAP_CTRL(34), 370 TEGRA210_ADX_BYTE_MAP_CTRL(35), 371 TEGRA210_ADX_BYTE_MAP_CTRL(36), 372 TEGRA210_ADX_BYTE_MAP_CTRL(37), 373 TEGRA210_ADX_BYTE_MAP_CTRL(38), 374 TEGRA210_ADX_BYTE_MAP_CTRL(39), 375 TEGRA210_ADX_BYTE_MAP_CTRL(40), 376 TEGRA210_ADX_BYTE_MAP_CTRL(41), 377 TEGRA210_ADX_BYTE_MAP_CTRL(42), 378 TEGRA210_ADX_BYTE_MAP_CTRL(43), 379 TEGRA210_ADX_BYTE_MAP_CTRL(44), 380 TEGRA210_ADX_BYTE_MAP_CTRL(45), 381 TEGRA210_ADX_BYTE_MAP_CTRL(46), 382 TEGRA210_ADX_BYTE_MAP_CTRL(47), 383 TEGRA210_ADX_BYTE_MAP_CTRL(48), 384 TEGRA210_ADX_BYTE_MAP_CTRL(49), 385 TEGRA210_ADX_BYTE_MAP_CTRL(50), 386 TEGRA210_ADX_BYTE_MAP_CTRL(51), 387 TEGRA210_ADX_BYTE_MAP_CTRL(52), 388 TEGRA210_ADX_BYTE_MAP_CTRL(53), 389 TEGRA210_ADX_BYTE_MAP_CTRL(54), 390 TEGRA210_ADX_BYTE_MAP_CTRL(55), 391 TEGRA210_ADX_BYTE_MAP_CTRL(56), 392 TEGRA210_ADX_BYTE_MAP_CTRL(57), 393 TEGRA210_ADX_BYTE_MAP_CTRL(58), 394 TEGRA210_ADX_BYTE_MAP_CTRL(59), 395 TEGRA210_ADX_BYTE_MAP_CTRL(60), 396 TEGRA210_ADX_BYTE_MAP_CTRL(61), 397 TEGRA210_ADX_BYTE_MAP_CTRL(62), 398 TEGRA210_ADX_BYTE_MAP_CTRL(63), 399 }; 400 401 static const struct snd_soc_component_driver tegra210_adx_cmpnt = { 402 .dapm_widgets = tegra210_adx_widgets, 403 .num_dapm_widgets = ARRAY_SIZE(tegra210_adx_widgets), 404 .dapm_routes = tegra210_adx_routes, 405 .num_dapm_routes = ARRAY_SIZE(tegra210_adx_routes), 406 .controls = tegra210_adx_controls, 407 .num_controls = ARRAY_SIZE(tegra210_adx_controls), 408 }; 409 410 static bool tegra210_adx_wr_reg(struct device *dev, 411 unsigned int reg) 412 { 413 switch (reg) { 414 case TEGRA210_ADX_TX_INT_MASK ... TEGRA210_ADX_TX4_CIF_CTRL: 415 case TEGRA210_ADX_RX_INT_MASK ... TEGRA210_ADX_RX_CIF_CTRL: 416 case TEGRA210_ADX_ENABLE ... TEGRA210_ADX_CG: 417 case TEGRA210_ADX_CTRL ... TEGRA210_ADX_IN_BYTE_EN1: 418 case TEGRA210_ADX_CFG_RAM_CTRL ... TEGRA210_ADX_CFG_RAM_DATA: 419 return true; 420 default: 421 return false; 422 } 423 } 424 425 static bool tegra210_adx_rd_reg(struct device *dev, 426 unsigned int reg) 427 { 428 switch (reg) { 429 case TEGRA210_ADX_RX_STATUS ... TEGRA210_ADX_CFG_RAM_DATA: 430 return true; 431 default: 432 return false; 433 } 434 } 435 436 static bool tegra210_adx_volatile_reg(struct device *dev, 437 unsigned int reg) 438 { 439 switch (reg) { 440 case TEGRA210_ADX_RX_STATUS: 441 case TEGRA210_ADX_RX_INT_STATUS: 442 case TEGRA210_ADX_RX_INT_SET: 443 case TEGRA210_ADX_TX_STATUS: 444 case TEGRA210_ADX_TX_INT_STATUS: 445 case TEGRA210_ADX_TX_INT_SET: 446 case TEGRA210_ADX_SOFT_RESET: 447 case TEGRA210_ADX_STATUS: 448 case TEGRA210_ADX_INT_STATUS: 449 case TEGRA210_ADX_CFG_RAM_CTRL: 450 case TEGRA210_ADX_CFG_RAM_DATA: 451 return true; 452 default: 453 break; 454 } 455 456 return false; 457 } 458 459 static const struct regmap_config tegra210_adx_regmap_config = { 460 .reg_bits = 32, 461 .reg_stride = 4, 462 .val_bits = 32, 463 .max_register = TEGRA210_ADX_CFG_RAM_DATA, 464 .writeable_reg = tegra210_adx_wr_reg, 465 .readable_reg = tegra210_adx_rd_reg, 466 .volatile_reg = tegra210_adx_volatile_reg, 467 .reg_defaults = tegra210_adx_reg_defaults, 468 .num_reg_defaults = ARRAY_SIZE(tegra210_adx_reg_defaults), 469 .cache_type = REGCACHE_FLAT, 470 }; 471 472 static const struct of_device_id tegra210_adx_of_match[] = { 473 { .compatible = "nvidia,tegra210-adx" }, 474 {}, 475 }; 476 MODULE_DEVICE_TABLE(of, tegra210_adx_of_match); 477 478 static int tegra210_adx_platform_probe(struct platform_device *pdev) 479 { 480 struct device *dev = &pdev->dev; 481 struct tegra210_adx *adx; 482 void __iomem *regs; 483 int err; 484 485 adx = devm_kzalloc(dev, sizeof(*adx), GFP_KERNEL); 486 if (!adx) 487 return -ENOMEM; 488 489 dev_set_drvdata(dev, adx); 490 491 regs = devm_platform_ioremap_resource(pdev, 0); 492 if (IS_ERR(regs)) 493 return PTR_ERR(regs); 494 495 adx->regmap = devm_regmap_init_mmio(dev, regs, 496 &tegra210_adx_regmap_config); 497 if (IS_ERR(adx->regmap)) { 498 dev_err(dev, "regmap init failed\n"); 499 return PTR_ERR(adx->regmap); 500 } 501 502 regcache_cache_only(adx->regmap, true); 503 504 err = devm_snd_soc_register_component(dev, &tegra210_adx_cmpnt, 505 tegra210_adx_dais, 506 ARRAY_SIZE(tegra210_adx_dais)); 507 if (err) { 508 dev_err(dev, "can't register ADX component, err: %d\n", err); 509 return err; 510 } 511 512 pm_runtime_enable(dev); 513 514 return 0; 515 } 516 517 static void tegra210_adx_platform_remove(struct platform_device *pdev) 518 { 519 pm_runtime_disable(&pdev->dev); 520 } 521 522 static const struct dev_pm_ops tegra210_adx_pm_ops = { 523 SET_RUNTIME_PM_OPS(tegra210_adx_runtime_suspend, 524 tegra210_adx_runtime_resume, NULL) 525 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 526 pm_runtime_force_resume) 527 }; 528 529 static struct platform_driver tegra210_adx_driver = { 530 .driver = { 531 .name = "tegra210-adx", 532 .of_match_table = tegra210_adx_of_match, 533 .pm = &tegra210_adx_pm_ops, 534 }, 535 .probe = tegra210_adx_platform_probe, 536 .remove_new = tegra210_adx_platform_remove, 537 }; 538 module_platform_driver(tegra210_adx_driver); 539 540 MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>"); 541 MODULE_DESCRIPTION("Tegra210 ADX ASoC driver"); 542 MODULE_LICENSE("GPL v2"); 543