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