1 // SPDX-License-Identifier: GPL-2.0-only 2 // SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. 3 // All rights reserved. 4 // 5 // tegra210_amx.c - Tegra210 AMX driver 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_amx.h" 21 #include "tegra_cif.h" 22 23 /* 24 * The counter is in terms of AHUB clock cycles. If a frame is not 25 * received within these clock cycles, the AMX input channel gets 26 * automatically disabled. For now the counter is calculated as a 27 * function of sample rate (8 kHz) and AHUB clock (49.152 MHz). 28 * If later an accurate number is needed, the counter needs to be 29 * calculated at runtime. 30 * 31 * count = ahub_clk / sample_rate 32 */ 33 #define TEGRA194_MAX_FRAME_IDLE_COUNT 0x1800 34 35 #define AMX_CH_REG(id, reg) ((reg) + ((id) * TEGRA210_AMX_AUDIOCIF_CH_STRIDE)) 36 37 static const struct reg_default tegra210_amx_reg_defaults[] = { 38 { TEGRA210_AMX_RX_INT_MASK, 0x0000000f}, 39 { TEGRA210_AMX_RX1_CIF_CTRL, 0x00007000}, 40 { TEGRA210_AMX_RX2_CIF_CTRL, 0x00007000}, 41 { TEGRA210_AMX_RX3_CIF_CTRL, 0x00007000}, 42 { TEGRA210_AMX_RX4_CIF_CTRL, 0x00007000}, 43 { TEGRA210_AMX_TX_INT_MASK, 0x00000001}, 44 { TEGRA210_AMX_TX_CIF_CTRL, 0x00007000}, 45 { TEGRA210_AMX_CG, 0x1}, 46 { TEGRA210_AMX_CFG_RAM_CTRL, 0x00004000}, 47 }; 48 49 static void tegra210_amx_write_map_ram(struct tegra210_amx *amx) 50 { 51 int i; 52 53 regmap_write(amx->regmap, TEGRA210_AMX_CFG_RAM_CTRL, 54 TEGRA210_AMX_CFG_RAM_CTRL_SEQ_ACCESS_EN | 55 TEGRA210_AMX_CFG_RAM_CTRL_ADDR_INIT_EN | 56 TEGRA210_AMX_CFG_RAM_CTRL_RW_WRITE); 57 58 for (i = 0; i < TEGRA210_AMX_RAM_DEPTH; i++) 59 regmap_write(amx->regmap, TEGRA210_AMX_CFG_RAM_DATA, 60 amx->map[i]); 61 62 regmap_write(amx->regmap, TEGRA210_AMX_OUT_BYTE_EN0, amx->byte_mask[0]); 63 regmap_write(amx->regmap, TEGRA210_AMX_OUT_BYTE_EN1, amx->byte_mask[1]); 64 } 65 66 static int tegra210_amx_startup(struct snd_pcm_substream *substream, 67 struct snd_soc_dai *dai) 68 { 69 struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); 70 unsigned int val; 71 int err; 72 73 /* Ensure if AMX is disabled */ 74 err = regmap_read_poll_timeout(amx->regmap, TEGRA210_AMX_STATUS, val, 75 !(val & 0x1), 10, 10000); 76 if (err < 0) { 77 dev_err(dai->dev, "failed to stop AMX, err = %d\n", err); 78 return err; 79 } 80 81 /* 82 * Soft Reset: Below performs module soft reset which clears 83 * all FSM logic, flushes flow control of FIFO and resets the 84 * state register. It also brings module back to disabled 85 * state (without flushing the data in the pipe). 86 */ 87 regmap_update_bits(amx->regmap, TEGRA210_AMX_SOFT_RESET, 88 TEGRA210_AMX_SOFT_RESET_SOFT_RESET_MASK, 89 TEGRA210_AMX_SOFT_RESET_SOFT_EN); 90 91 err = regmap_read_poll_timeout(amx->regmap, TEGRA210_AMX_SOFT_RESET, 92 val, !(val & 0x1), 10, 10000); 93 if (err < 0) { 94 dev_err(dai->dev, "failed to reset AMX, err = %d\n", err); 95 return err; 96 } 97 98 return 0; 99 } 100 101 static int __maybe_unused tegra210_amx_runtime_suspend(struct device *dev) 102 { 103 struct tegra210_amx *amx = dev_get_drvdata(dev); 104 105 regcache_cache_only(amx->regmap, true); 106 regcache_mark_dirty(amx->regmap); 107 108 return 0; 109 } 110 111 static int __maybe_unused tegra210_amx_runtime_resume(struct device *dev) 112 { 113 struct tegra210_amx *amx = dev_get_drvdata(dev); 114 115 regcache_cache_only(amx->regmap, false); 116 regcache_sync(amx->regmap); 117 118 regmap_update_bits(amx->regmap, 119 TEGRA210_AMX_CTRL, 120 TEGRA210_AMX_CTRL_RX_DEP_MASK, 121 TEGRA210_AMX_WAIT_ON_ANY << TEGRA210_AMX_CTRL_RX_DEP_SHIFT); 122 123 tegra210_amx_write_map_ram(amx); 124 125 return 0; 126 } 127 128 static int tegra210_amx_set_audio_cif(struct snd_soc_dai *dai, 129 struct snd_pcm_hw_params *params, 130 unsigned int reg) 131 { 132 struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); 133 int channels, audio_bits; 134 struct tegra_cif_conf cif_conf; 135 136 memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); 137 138 channels = params_channels(params); 139 140 switch (params_format(params)) { 141 case SNDRV_PCM_FORMAT_S8: 142 audio_bits = TEGRA_ACIF_BITS_8; 143 break; 144 case SNDRV_PCM_FORMAT_S16_LE: 145 audio_bits = TEGRA_ACIF_BITS_16; 146 break; 147 case SNDRV_PCM_FORMAT_S24_LE: 148 case SNDRV_PCM_FORMAT_S32_LE: 149 audio_bits = TEGRA_ACIF_BITS_32; 150 break; 151 default: 152 return -EINVAL; 153 } 154 155 cif_conf.audio_ch = channels; 156 cif_conf.client_ch = channels; 157 cif_conf.audio_bits = audio_bits; 158 cif_conf.client_bits = audio_bits; 159 160 tegra_set_cif(amx->regmap, reg, &cif_conf); 161 162 return 0; 163 } 164 165 static int tegra210_amx_in_hw_params(struct snd_pcm_substream *substream, 166 struct snd_pcm_hw_params *params, 167 struct snd_soc_dai *dai) 168 { 169 struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); 170 171 if (amx->soc_data->auto_disable) { 172 regmap_write(amx->regmap, 173 AMX_CH_REG(dai->id, TEGRA194_AMX_RX1_FRAME_PERIOD), 174 TEGRA194_MAX_FRAME_IDLE_COUNT); 175 regmap_write(amx->regmap, TEGRA210_AMX_CYA, 1); 176 } 177 178 return tegra210_amx_set_audio_cif(dai, params, 179 AMX_CH_REG(dai->id, TEGRA210_AMX_RX1_CIF_CTRL)); 180 } 181 182 static int tegra210_amx_out_hw_params(struct snd_pcm_substream *substream, 183 struct snd_pcm_hw_params *params, 184 struct snd_soc_dai *dai) 185 { 186 return tegra210_amx_set_audio_cif(dai, params, 187 TEGRA210_AMX_TX_CIF_CTRL); 188 } 189 190 static int tegra210_amx_get_byte_map(struct snd_kcontrol *kcontrol, 191 struct snd_ctl_elem_value *ucontrol) 192 { 193 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 194 struct soc_mixer_control *mc = 195 (struct soc_mixer_control *)kcontrol->private_value; 196 struct tegra210_amx *amx = snd_soc_component_get_drvdata(cmpnt); 197 unsigned char *bytes_map = (unsigned char *)&amx->map; 198 int reg = mc->reg; 199 int enabled; 200 201 if (reg > 31) 202 enabled = amx->byte_mask[1] & (1 << (reg - 32)); 203 else 204 enabled = amx->byte_mask[0] & (1 << reg); 205 206 /* 207 * TODO: Simplify this logic to just return from bytes_map[] 208 * 209 * Presently below is required since bytes_map[] is 210 * tightly packed and cannot store the control value of 256. 211 * Byte mask state is used to know if 256 needs to be returned. 212 * Note that for control value of 256, the put() call stores 0 213 * in the bytes_map[] and disables the corresponding bit in 214 * byte_mask[]. 215 */ 216 if (enabled) 217 ucontrol->value.integer.value[0] = bytes_map[reg]; 218 else 219 ucontrol->value.integer.value[0] = 256; 220 221 return 0; 222 } 223 224 static int tegra210_amx_put_byte_map(struct snd_kcontrol *kcontrol, 225 struct snd_ctl_elem_value *ucontrol) 226 { 227 struct soc_mixer_control *mc = 228 (struct soc_mixer_control *)kcontrol->private_value; 229 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 230 struct tegra210_amx *amx = snd_soc_component_get_drvdata(cmpnt); 231 unsigned char *bytes_map = (unsigned char *)&amx->map; 232 int reg = mc->reg; 233 int value = ucontrol->value.integer.value[0]; 234 unsigned int mask_val = amx->byte_mask[reg / 32]; 235 236 if (value >= 0 && value <= 255) 237 mask_val |= (1 << (reg % 32)); 238 else 239 mask_val &= ~(1 << (reg % 32)); 240 241 if (mask_val == amx->byte_mask[reg / 32]) 242 return 0; 243 244 /* Update byte map and slot */ 245 bytes_map[reg] = value % 256; 246 amx->byte_mask[reg / 32] = mask_val; 247 248 return 1; 249 } 250 251 static const struct snd_soc_dai_ops tegra210_amx_out_dai_ops = { 252 .hw_params = tegra210_amx_out_hw_params, 253 .startup = tegra210_amx_startup, 254 }; 255 256 static const struct snd_soc_dai_ops tegra210_amx_in_dai_ops = { 257 .hw_params = tegra210_amx_in_hw_params, 258 }; 259 260 #define IN_DAI(id) \ 261 { \ 262 .name = "AMX-RX-CIF" #id, \ 263 .playback = { \ 264 .stream_name = "RX" #id "-CIF-Playback",\ 265 .channels_min = 1, \ 266 .channels_max = 16, \ 267 .rates = SNDRV_PCM_RATE_8000_192000, \ 268 .formats = SNDRV_PCM_FMTBIT_S8 | \ 269 SNDRV_PCM_FMTBIT_S16_LE | \ 270 SNDRV_PCM_FMTBIT_S24_LE | \ 271 SNDRV_PCM_FMTBIT_S32_LE, \ 272 }, \ 273 .capture = { \ 274 .stream_name = "RX" #id "-CIF-Capture", \ 275 .channels_min = 1, \ 276 .channels_max = 16, \ 277 .rates = SNDRV_PCM_RATE_8000_192000, \ 278 .formats = SNDRV_PCM_FMTBIT_S8 | \ 279 SNDRV_PCM_FMTBIT_S16_LE | \ 280 SNDRV_PCM_FMTBIT_S24_LE | \ 281 SNDRV_PCM_FMTBIT_S32_LE, \ 282 }, \ 283 .ops = &tegra210_amx_in_dai_ops, \ 284 } 285 286 #define OUT_DAI \ 287 { \ 288 .name = "AMX-TX-CIF", \ 289 .playback = { \ 290 .stream_name = "TX-CIF-Playback", \ 291 .channels_min = 1, \ 292 .channels_max = 16, \ 293 .rates = SNDRV_PCM_RATE_8000_192000, \ 294 .formats = SNDRV_PCM_FMTBIT_S8 | \ 295 SNDRV_PCM_FMTBIT_S16_LE | \ 296 SNDRV_PCM_FMTBIT_S24_LE | \ 297 SNDRV_PCM_FMTBIT_S32_LE, \ 298 }, \ 299 .capture = { \ 300 .stream_name = "TX-CIF-Capture", \ 301 .channels_min = 1, \ 302 .channels_max = 16, \ 303 .rates = SNDRV_PCM_RATE_8000_192000, \ 304 .formats = SNDRV_PCM_FMTBIT_S8 | \ 305 SNDRV_PCM_FMTBIT_S16_LE | \ 306 SNDRV_PCM_FMTBIT_S24_LE | \ 307 SNDRV_PCM_FMTBIT_S32_LE, \ 308 }, \ 309 .ops = &tegra210_amx_out_dai_ops, \ 310 } 311 312 static struct snd_soc_dai_driver tegra210_amx_dais[] = { 313 IN_DAI(1), 314 IN_DAI(2), 315 IN_DAI(3), 316 IN_DAI(4), 317 OUT_DAI, 318 }; 319 320 static const struct snd_soc_dapm_widget tegra210_amx_widgets[] = { 321 SND_SOC_DAPM_AIF_IN("RX1", NULL, 0, TEGRA210_AMX_CTRL, 0, 0), 322 SND_SOC_DAPM_AIF_IN("RX2", NULL, 0, TEGRA210_AMX_CTRL, 1, 0), 323 SND_SOC_DAPM_AIF_IN("RX3", NULL, 0, TEGRA210_AMX_CTRL, 2, 0), 324 SND_SOC_DAPM_AIF_IN("RX4", NULL, 0, TEGRA210_AMX_CTRL, 3, 0), 325 SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_AMX_ENABLE, 326 TEGRA210_AMX_ENABLE_SHIFT, 0), 327 }; 328 329 #define STREAM_ROUTES(id, sname) \ 330 { "RX" #id " XBAR-" sname, NULL, "RX" #id " XBAR-TX" }, \ 331 { "RX" #id "-CIF-" sname, NULL, "RX" #id " XBAR-" sname },\ 332 { "RX" #id, NULL, "RX" #id "-CIF-" sname }, \ 333 { "TX", NULL, "RX" #id }, \ 334 { "TX-CIF-" sname, NULL, "TX" }, \ 335 { "XBAR-" sname, NULL, "TX-CIF-" sname }, \ 336 { "XBAR-RX", NULL, "XBAR-" sname } 337 338 #define AMX_ROUTES(id) \ 339 STREAM_ROUTES(id, "Playback"), \ 340 STREAM_ROUTES(id, "Capture") 341 342 static const struct snd_soc_dapm_route tegra210_amx_routes[] = { 343 AMX_ROUTES(1), 344 AMX_ROUTES(2), 345 AMX_ROUTES(3), 346 AMX_ROUTES(4), 347 }; 348 349 #define TEGRA210_AMX_BYTE_MAP_CTRL(reg) \ 350 SOC_SINGLE_EXT("Byte Map " #reg, reg, 0, 256, 0, \ 351 tegra210_amx_get_byte_map, \ 352 tegra210_amx_put_byte_map) 353 354 static struct snd_kcontrol_new tegra210_amx_controls[] = { 355 TEGRA210_AMX_BYTE_MAP_CTRL(0), 356 TEGRA210_AMX_BYTE_MAP_CTRL(1), 357 TEGRA210_AMX_BYTE_MAP_CTRL(2), 358 TEGRA210_AMX_BYTE_MAP_CTRL(3), 359 TEGRA210_AMX_BYTE_MAP_CTRL(4), 360 TEGRA210_AMX_BYTE_MAP_CTRL(5), 361 TEGRA210_AMX_BYTE_MAP_CTRL(6), 362 TEGRA210_AMX_BYTE_MAP_CTRL(7), 363 TEGRA210_AMX_BYTE_MAP_CTRL(8), 364 TEGRA210_AMX_BYTE_MAP_CTRL(9), 365 TEGRA210_AMX_BYTE_MAP_CTRL(10), 366 TEGRA210_AMX_BYTE_MAP_CTRL(11), 367 TEGRA210_AMX_BYTE_MAP_CTRL(12), 368 TEGRA210_AMX_BYTE_MAP_CTRL(13), 369 TEGRA210_AMX_BYTE_MAP_CTRL(14), 370 TEGRA210_AMX_BYTE_MAP_CTRL(15), 371 TEGRA210_AMX_BYTE_MAP_CTRL(16), 372 TEGRA210_AMX_BYTE_MAP_CTRL(17), 373 TEGRA210_AMX_BYTE_MAP_CTRL(18), 374 TEGRA210_AMX_BYTE_MAP_CTRL(19), 375 TEGRA210_AMX_BYTE_MAP_CTRL(20), 376 TEGRA210_AMX_BYTE_MAP_CTRL(21), 377 TEGRA210_AMX_BYTE_MAP_CTRL(22), 378 TEGRA210_AMX_BYTE_MAP_CTRL(23), 379 TEGRA210_AMX_BYTE_MAP_CTRL(24), 380 TEGRA210_AMX_BYTE_MAP_CTRL(25), 381 TEGRA210_AMX_BYTE_MAP_CTRL(26), 382 TEGRA210_AMX_BYTE_MAP_CTRL(27), 383 TEGRA210_AMX_BYTE_MAP_CTRL(28), 384 TEGRA210_AMX_BYTE_MAP_CTRL(29), 385 TEGRA210_AMX_BYTE_MAP_CTRL(30), 386 TEGRA210_AMX_BYTE_MAP_CTRL(31), 387 TEGRA210_AMX_BYTE_MAP_CTRL(32), 388 TEGRA210_AMX_BYTE_MAP_CTRL(33), 389 TEGRA210_AMX_BYTE_MAP_CTRL(34), 390 TEGRA210_AMX_BYTE_MAP_CTRL(35), 391 TEGRA210_AMX_BYTE_MAP_CTRL(36), 392 TEGRA210_AMX_BYTE_MAP_CTRL(37), 393 TEGRA210_AMX_BYTE_MAP_CTRL(38), 394 TEGRA210_AMX_BYTE_MAP_CTRL(39), 395 TEGRA210_AMX_BYTE_MAP_CTRL(40), 396 TEGRA210_AMX_BYTE_MAP_CTRL(41), 397 TEGRA210_AMX_BYTE_MAP_CTRL(42), 398 TEGRA210_AMX_BYTE_MAP_CTRL(43), 399 TEGRA210_AMX_BYTE_MAP_CTRL(44), 400 TEGRA210_AMX_BYTE_MAP_CTRL(45), 401 TEGRA210_AMX_BYTE_MAP_CTRL(46), 402 TEGRA210_AMX_BYTE_MAP_CTRL(47), 403 TEGRA210_AMX_BYTE_MAP_CTRL(48), 404 TEGRA210_AMX_BYTE_MAP_CTRL(49), 405 TEGRA210_AMX_BYTE_MAP_CTRL(50), 406 TEGRA210_AMX_BYTE_MAP_CTRL(51), 407 TEGRA210_AMX_BYTE_MAP_CTRL(52), 408 TEGRA210_AMX_BYTE_MAP_CTRL(53), 409 TEGRA210_AMX_BYTE_MAP_CTRL(54), 410 TEGRA210_AMX_BYTE_MAP_CTRL(55), 411 TEGRA210_AMX_BYTE_MAP_CTRL(56), 412 TEGRA210_AMX_BYTE_MAP_CTRL(57), 413 TEGRA210_AMX_BYTE_MAP_CTRL(58), 414 TEGRA210_AMX_BYTE_MAP_CTRL(59), 415 TEGRA210_AMX_BYTE_MAP_CTRL(60), 416 TEGRA210_AMX_BYTE_MAP_CTRL(61), 417 TEGRA210_AMX_BYTE_MAP_CTRL(62), 418 TEGRA210_AMX_BYTE_MAP_CTRL(63), 419 }; 420 421 static const struct snd_soc_component_driver tegra210_amx_cmpnt = { 422 .dapm_widgets = tegra210_amx_widgets, 423 .num_dapm_widgets = ARRAY_SIZE(tegra210_amx_widgets), 424 .dapm_routes = tegra210_amx_routes, 425 .num_dapm_routes = ARRAY_SIZE(tegra210_amx_routes), 426 .controls = tegra210_amx_controls, 427 .num_controls = ARRAY_SIZE(tegra210_amx_controls), 428 }; 429 430 static bool tegra210_amx_wr_reg(struct device *dev, unsigned int reg) 431 { 432 switch (reg) { 433 case TEGRA210_AMX_RX_INT_MASK ... TEGRA210_AMX_RX4_CIF_CTRL: 434 case TEGRA210_AMX_TX_INT_MASK ... TEGRA210_AMX_CG: 435 case TEGRA210_AMX_CTRL ... TEGRA210_AMX_CYA: 436 case TEGRA210_AMX_CFG_RAM_CTRL ... TEGRA210_AMX_CFG_RAM_DATA: 437 return true; 438 default: 439 return false; 440 } 441 } 442 443 static bool tegra194_amx_wr_reg(struct device *dev, unsigned int reg) 444 { 445 switch (reg) { 446 case TEGRA194_AMX_RX1_FRAME_PERIOD ... TEGRA194_AMX_RX4_FRAME_PERIOD: 447 return true; 448 default: 449 return tegra210_amx_wr_reg(dev, reg); 450 } 451 } 452 453 static bool tegra210_amx_rd_reg(struct device *dev, unsigned int reg) 454 { 455 switch (reg) { 456 case TEGRA210_AMX_RX_STATUS ... TEGRA210_AMX_CFG_RAM_DATA: 457 return true; 458 default: 459 return false; 460 } 461 } 462 463 static bool tegra194_amx_rd_reg(struct device *dev, unsigned int reg) 464 { 465 switch (reg) { 466 case TEGRA194_AMX_RX1_FRAME_PERIOD ... TEGRA194_AMX_RX4_FRAME_PERIOD: 467 return true; 468 default: 469 return tegra210_amx_rd_reg(dev, reg); 470 } 471 } 472 473 static bool tegra210_amx_volatile_reg(struct device *dev, unsigned int reg) 474 { 475 switch (reg) { 476 case TEGRA210_AMX_RX_STATUS: 477 case TEGRA210_AMX_RX_INT_STATUS: 478 case TEGRA210_AMX_RX_INT_SET: 479 case TEGRA210_AMX_TX_STATUS: 480 case TEGRA210_AMX_TX_INT_STATUS: 481 case TEGRA210_AMX_TX_INT_SET: 482 case TEGRA210_AMX_SOFT_RESET: 483 case TEGRA210_AMX_STATUS: 484 case TEGRA210_AMX_INT_STATUS: 485 case TEGRA210_AMX_CFG_RAM_CTRL: 486 case TEGRA210_AMX_CFG_RAM_DATA: 487 return true; 488 default: 489 break; 490 } 491 492 return false; 493 } 494 495 static const struct regmap_config tegra210_amx_regmap_config = { 496 .reg_bits = 32, 497 .reg_stride = 4, 498 .val_bits = 32, 499 .max_register = TEGRA210_AMX_CFG_RAM_DATA, 500 .writeable_reg = tegra210_amx_wr_reg, 501 .readable_reg = tegra210_amx_rd_reg, 502 .volatile_reg = tegra210_amx_volatile_reg, 503 .reg_defaults = tegra210_amx_reg_defaults, 504 .num_reg_defaults = ARRAY_SIZE(tegra210_amx_reg_defaults), 505 .cache_type = REGCACHE_FLAT, 506 }; 507 508 static const struct regmap_config tegra194_amx_regmap_config = { 509 .reg_bits = 32, 510 .reg_stride = 4, 511 .val_bits = 32, 512 .max_register = TEGRA194_AMX_RX4_LAST_FRAME_PERIOD, 513 .writeable_reg = tegra194_amx_wr_reg, 514 .readable_reg = tegra194_amx_rd_reg, 515 .volatile_reg = tegra210_amx_volatile_reg, 516 .reg_defaults = tegra210_amx_reg_defaults, 517 .num_reg_defaults = ARRAY_SIZE(tegra210_amx_reg_defaults), 518 .cache_type = REGCACHE_FLAT, 519 }; 520 521 static const struct tegra210_amx_soc_data soc_data_tegra210 = { 522 .regmap_conf = &tegra210_amx_regmap_config, 523 }; 524 525 static const struct tegra210_amx_soc_data soc_data_tegra194 = { 526 .regmap_conf = &tegra194_amx_regmap_config, 527 .auto_disable = true, 528 }; 529 530 static const struct of_device_id tegra210_amx_of_match[] = { 531 { .compatible = "nvidia,tegra210-amx", .data = &soc_data_tegra210 }, 532 { .compatible = "nvidia,tegra194-amx", .data = &soc_data_tegra194 }, 533 {}, 534 }; 535 MODULE_DEVICE_TABLE(of, tegra210_amx_of_match); 536 537 static int tegra210_amx_platform_probe(struct platform_device *pdev) 538 { 539 struct device *dev = &pdev->dev; 540 struct tegra210_amx *amx; 541 void __iomem *regs; 542 int err; 543 544 amx = devm_kzalloc(dev, sizeof(*amx), GFP_KERNEL); 545 if (!amx) 546 return -ENOMEM; 547 548 amx->soc_data = device_get_match_data(dev); 549 550 dev_set_drvdata(dev, amx); 551 552 regs = devm_platform_ioremap_resource(pdev, 0); 553 if (IS_ERR(regs)) 554 return PTR_ERR(regs); 555 556 amx->regmap = devm_regmap_init_mmio(dev, regs, 557 amx->soc_data->regmap_conf); 558 if (IS_ERR(amx->regmap)) { 559 dev_err(dev, "regmap init failed\n"); 560 return PTR_ERR(amx->regmap); 561 } 562 563 regcache_cache_only(amx->regmap, true); 564 565 err = devm_snd_soc_register_component(dev, &tegra210_amx_cmpnt, 566 tegra210_amx_dais, 567 ARRAY_SIZE(tegra210_amx_dais)); 568 if (err) { 569 dev_err(dev, "can't register AMX component, err: %d\n", err); 570 return err; 571 } 572 573 pm_runtime_enable(dev); 574 575 return 0; 576 } 577 578 static void tegra210_amx_platform_remove(struct platform_device *pdev) 579 { 580 pm_runtime_disable(&pdev->dev); 581 } 582 583 static const struct dev_pm_ops tegra210_amx_pm_ops = { 584 SET_RUNTIME_PM_OPS(tegra210_amx_runtime_suspend, 585 tegra210_amx_runtime_resume, NULL) 586 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 587 pm_runtime_force_resume) 588 }; 589 590 static struct platform_driver tegra210_amx_driver = { 591 .driver = { 592 .name = "tegra210-amx", 593 .of_match_table = tegra210_amx_of_match, 594 .pm = &tegra210_amx_pm_ops, 595 }, 596 .probe = tegra210_amx_platform_probe, 597 .remove = tegra210_amx_platform_remove, 598 }; 599 module_platform_driver(tegra210_amx_driver); 600 601 MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>"); 602 MODULE_DESCRIPTION("Tegra210 AMX ASoC driver"); 603 MODULE_LICENSE("GPL v2"); 604