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