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