Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 804 lines 24 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2// SPDX-FileCopyrightText: Copyright (c) 2021-2025 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 37static 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 49static const struct reg_default tegra264_amx_reg_defaults[] = { 50 { TEGRA210_AMX_RX_INT_MASK, 0x0000000f}, 51 { TEGRA210_AMX_RX1_CIF_CTRL, 0x00003800}, 52 { TEGRA210_AMX_RX2_CIF_CTRL, 0x00003800}, 53 { TEGRA210_AMX_RX3_CIF_CTRL, 0x00003800}, 54 { TEGRA210_AMX_RX4_CIF_CTRL, 0x00003800}, 55 { TEGRA210_AMX_TX_INT_MASK, 0x00000001}, 56 { TEGRA210_AMX_TX_CIF_CTRL, 0x00003800}, 57 { TEGRA210_AMX_CG, 0x1}, 58 { TEGRA264_AMX_CFG_RAM_CTRL, 0x00004000}, 59}; 60 61static void tegra210_amx_write_map_ram(struct tegra210_amx *amx) 62{ 63 int i; 64 65 regmap_write(amx->regmap, TEGRA210_AMX_CFG_RAM_CTRL + amx->soc_data->reg_offset, 66 TEGRA210_AMX_CFG_RAM_CTRL_SEQ_ACCESS_EN | 67 TEGRA210_AMX_CFG_RAM_CTRL_ADDR_INIT_EN | 68 TEGRA210_AMX_CFG_RAM_CTRL_RW_WRITE); 69 70 for (i = 0; i < amx->soc_data->ram_depth; i++) 71 regmap_write(amx->regmap, TEGRA210_AMX_CFG_RAM_DATA + amx->soc_data->reg_offset, 72 amx->map[i]); 73 74 for (i = 0; i < amx->soc_data->byte_mask_size; i++) 75 regmap_write(amx->regmap, 76 TEGRA210_AMX_OUT_BYTE_EN0 + (i * TEGRA210_AMX_AUDIOCIF_CH_STRIDE), 77 amx->byte_mask[i]); 78} 79 80static int tegra210_amx_startup(struct snd_pcm_substream *substream, 81 struct snd_soc_dai *dai) 82{ 83 struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); 84 unsigned int val; 85 int err; 86 87 /* Ensure if AMX is disabled */ 88 err = regmap_read_poll_timeout(amx->regmap, TEGRA210_AMX_STATUS, val, 89 !(val & 0x1), 10, 10000); 90 if (err < 0) { 91 dev_err(dai->dev, "failed to stop AMX, err = %d\n", err); 92 return err; 93 } 94 95 /* 96 * Soft Reset: Below performs module soft reset which clears 97 * all FSM logic, flushes flow control of FIFO and resets the 98 * state register. It also brings module back to disabled 99 * state (without flushing the data in the pipe). 100 */ 101 regmap_update_bits(amx->regmap, TEGRA210_AMX_SOFT_RESET, 102 TEGRA210_AMX_SOFT_RESET_SOFT_RESET_MASK, 103 TEGRA210_AMX_SOFT_RESET_SOFT_EN); 104 105 err = regmap_read_poll_timeout(amx->regmap, TEGRA210_AMX_SOFT_RESET, 106 val, !(val & 0x1), 10, 10000); 107 if (err < 0) { 108 dev_err(dai->dev, "failed to reset AMX, err = %d\n", err); 109 return err; 110 } 111 112 return 0; 113} 114 115static int tegra210_amx_runtime_suspend(struct device *dev) 116{ 117 struct tegra210_amx *amx = dev_get_drvdata(dev); 118 119 regcache_cache_only(amx->regmap, true); 120 regcache_mark_dirty(amx->regmap); 121 122 return 0; 123} 124 125static int tegra210_amx_runtime_resume(struct device *dev) 126{ 127 struct tegra210_amx *amx = dev_get_drvdata(dev); 128 129 regcache_cache_only(amx->regmap, false); 130 regcache_sync(amx->regmap); 131 132 regmap_update_bits(amx->regmap, 133 TEGRA210_AMX_CTRL, 134 TEGRA210_AMX_CTRL_RX_DEP_MASK, 135 TEGRA210_AMX_WAIT_ON_ANY << TEGRA210_AMX_CTRL_RX_DEP_SHIFT); 136 137 tegra210_amx_write_map_ram(amx); 138 139 return 0; 140} 141 142static int tegra210_amx_set_audio_cif(struct snd_soc_dai *dai, 143 struct snd_pcm_hw_params *params, 144 unsigned int reg) 145{ 146 struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); 147 int channels, audio_bits; 148 struct tegra_cif_conf cif_conf; 149 150 memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); 151 152 channels = params_channels(params); 153 154 switch (params_format(params)) { 155 case SNDRV_PCM_FORMAT_S8: 156 audio_bits = TEGRA_ACIF_BITS_8; 157 break; 158 case SNDRV_PCM_FORMAT_S16_LE: 159 audio_bits = TEGRA_ACIF_BITS_16; 160 break; 161 case SNDRV_PCM_FORMAT_S24_LE: 162 case SNDRV_PCM_FORMAT_S32_LE: 163 audio_bits = TEGRA_ACIF_BITS_32; 164 break; 165 default: 166 dev_err(dai->dev, "unsupported format: %d\n", 167 params_format(params)); 168 return -EINVAL; 169 } 170 171 cif_conf.audio_ch = channels; 172 cif_conf.client_ch = channels; 173 cif_conf.audio_bits = audio_bits; 174 cif_conf.client_bits = audio_bits; 175 176 if (amx->soc_data->max_ch == TEGRA264_AMX_MAX_CHANNEL) 177 tegra264_set_cif(amx->regmap, reg, &cif_conf); 178 else 179 tegra_set_cif(amx->regmap, reg, &cif_conf); 180 181 return 0; 182} 183 184static int tegra210_amx_in_hw_params(struct snd_pcm_substream *substream, 185 struct snd_pcm_hw_params *params, 186 struct snd_soc_dai *dai) 187{ 188 struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); 189 190 if (amx->soc_data->auto_disable) { 191 regmap_write(amx->regmap, 192 AMX_CH_REG(dai->id, TEGRA194_AMX_RX1_FRAME_PERIOD + 193 amx->soc_data->reg_offset), 194 TEGRA194_MAX_FRAME_IDLE_COUNT); 195 regmap_write(amx->regmap, TEGRA210_AMX_CYA + amx->soc_data->reg_offset, 1); 196 } 197 198 return tegra210_amx_set_audio_cif(dai, params, 199 AMX_CH_REG(dai->id, TEGRA210_AMX_RX1_CIF_CTRL)); 200} 201 202static int tegra210_amx_out_hw_params(struct snd_pcm_substream *substream, 203 struct snd_pcm_hw_params *params, 204 struct snd_soc_dai *dai) 205{ 206 return tegra210_amx_set_audio_cif(dai, params, 207 TEGRA210_AMX_TX_CIF_CTRL); 208} 209 210static int tegra210_amx_get_byte_map(struct snd_kcontrol *kcontrol, 211 struct snd_ctl_elem_value *ucontrol) 212{ 213 struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol); 214 struct soc_mixer_control *mc = 215 (struct soc_mixer_control *)kcontrol->private_value; 216 struct tegra210_amx *amx = snd_soc_component_get_drvdata(cmpnt); 217 unsigned char *bytes_map = (unsigned char *)amx->map; 218 int reg = mc->reg; 219 int enabled; 220 221 enabled = amx->byte_mask[reg / 32] & (1 << (reg % 32)); 222 223 /* 224 * TODO: Simplify this logic to just return from bytes_map[] 225 * 226 * Presently below is required since bytes_map[] is 227 * tightly packed and cannot store the control value of 256. 228 * Byte mask state is used to know if 256 needs to be returned. 229 * Note that for control value of 256, the put() call stores 0 230 * in the bytes_map[] and disables the corresponding bit in 231 * byte_mask[]. 232 */ 233 if (enabled) 234 ucontrol->value.integer.value[0] = bytes_map[reg]; 235 else 236 ucontrol->value.integer.value[0] = 256; 237 238 return 0; 239} 240 241static int tegra210_amx_put_byte_map(struct snd_kcontrol *kcontrol, 242 struct snd_ctl_elem_value *ucontrol) 243{ 244 struct soc_mixer_control *mc = 245 (struct soc_mixer_control *)kcontrol->private_value; 246 struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol); 247 struct tegra210_amx *amx = snd_soc_component_get_drvdata(cmpnt); 248 unsigned char *bytes_map = (unsigned char *)amx->map; 249 int reg = mc->reg; 250 int value = ucontrol->value.integer.value[0]; 251 unsigned int mask_val = amx->byte_mask[reg / 32]; 252 253 if (value >= 0 && value <= 255) 254 mask_val |= (1 << (reg % 32)); 255 else 256 mask_val &= ~(1 << (reg % 32)); 257 258 if (mask_val == amx->byte_mask[reg / 32]) 259 return 0; 260 261 /* Update byte map and slot */ 262 bytes_map[reg] = value % 256; 263 amx->byte_mask[reg / 32] = mask_val; 264 265 return 1; 266} 267 268static const struct snd_soc_dai_ops tegra210_amx_out_dai_ops = { 269 .hw_params = tegra210_amx_out_hw_params, 270 .startup = tegra210_amx_startup, 271}; 272 273static const struct snd_soc_dai_ops tegra210_amx_in_dai_ops = { 274 .hw_params = tegra210_amx_in_hw_params, 275}; 276 277#define IN_DAI(id) \ 278 { \ 279 .name = "AMX-RX-CIF" #id, \ 280 .playback = { \ 281 .stream_name = "RX" #id "-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_S24_LE | \ 288 SNDRV_PCM_FMTBIT_S32_LE, \ 289 }, \ 290 .capture = { \ 291 .stream_name = "RX" #id "-CIF-Capture", \ 292 .channels_min = 1, \ 293 .channels_max = 16, \ 294 .rates = SNDRV_PCM_RATE_8000_192000, \ 295 .formats = SNDRV_PCM_FMTBIT_S8 | \ 296 SNDRV_PCM_FMTBIT_S16_LE | \ 297 SNDRV_PCM_FMTBIT_S24_LE | \ 298 SNDRV_PCM_FMTBIT_S32_LE, \ 299 }, \ 300 .ops = &tegra210_amx_in_dai_ops, \ 301 } 302 303#define OUT_DAI \ 304 { \ 305 .name = "AMX-TX-CIF", \ 306 .playback = { \ 307 .stream_name = "TX-CIF-Playback", \ 308 .channels_min = 1, \ 309 .channels_max = 16, \ 310 .rates = SNDRV_PCM_RATE_8000_192000, \ 311 .formats = SNDRV_PCM_FMTBIT_S8 | \ 312 SNDRV_PCM_FMTBIT_S16_LE | \ 313 SNDRV_PCM_FMTBIT_S24_LE | \ 314 SNDRV_PCM_FMTBIT_S32_LE, \ 315 }, \ 316 .capture = { \ 317 .stream_name = "TX-CIF-Capture", \ 318 .channels_min = 1, \ 319 .channels_max = 16, \ 320 .rates = SNDRV_PCM_RATE_8000_192000, \ 321 .formats = SNDRV_PCM_FMTBIT_S8 | \ 322 SNDRV_PCM_FMTBIT_S16_LE | \ 323 SNDRV_PCM_FMTBIT_S24_LE | \ 324 SNDRV_PCM_FMTBIT_S32_LE, \ 325 }, \ 326 .ops = &tegra210_amx_out_dai_ops, \ 327 } 328 329static struct snd_soc_dai_driver tegra210_amx_dais[] = { 330 IN_DAI(1), 331 IN_DAI(2), 332 IN_DAI(3), 333 IN_DAI(4), 334 OUT_DAI, 335}; 336 337static const struct snd_soc_dapm_widget tegra210_amx_widgets[] = { 338 SND_SOC_DAPM_AIF_IN("RX1", NULL, 0, TEGRA210_AMX_CTRL, 0, 0), 339 SND_SOC_DAPM_AIF_IN("RX2", NULL, 0, TEGRA210_AMX_CTRL, 1, 0), 340 SND_SOC_DAPM_AIF_IN("RX3", NULL, 0, TEGRA210_AMX_CTRL, 2, 0), 341 SND_SOC_DAPM_AIF_IN("RX4", NULL, 0, TEGRA210_AMX_CTRL, 3, 0), 342 SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_AMX_ENABLE, 343 TEGRA210_AMX_ENABLE_SHIFT, 0), 344}; 345 346#define STREAM_ROUTES(id, sname) \ 347 { "RX" #id " XBAR-" sname, NULL, "RX" #id " XBAR-TX" }, \ 348 { "RX" #id "-CIF-" sname, NULL, "RX" #id " XBAR-" sname },\ 349 { "RX" #id, NULL, "RX" #id "-CIF-" sname }, \ 350 { "TX", NULL, "RX" #id }, \ 351 { "TX-CIF-" sname, NULL, "TX" }, \ 352 { "XBAR-" sname, NULL, "TX-CIF-" sname }, \ 353 { "XBAR-RX", NULL, "XBAR-" sname } 354 355#define AMX_ROUTES(id) \ 356 STREAM_ROUTES(id, "Playback"), \ 357 STREAM_ROUTES(id, "Capture") 358 359static const struct snd_soc_dapm_route tegra210_amx_routes[] = { 360 AMX_ROUTES(1), 361 AMX_ROUTES(2), 362 AMX_ROUTES(3), 363 AMX_ROUTES(4), 364}; 365 366#define TEGRA210_AMX_BYTE_MAP_CTRL(reg) \ 367 SOC_SINGLE_EXT("Byte Map " #reg, reg, 0, 256, 0, \ 368 tegra210_amx_get_byte_map, \ 369 tegra210_amx_put_byte_map) 370 371static struct snd_kcontrol_new tegra210_amx_controls[] = { 372 TEGRA210_AMX_BYTE_MAP_CTRL(0), 373 TEGRA210_AMX_BYTE_MAP_CTRL(1), 374 TEGRA210_AMX_BYTE_MAP_CTRL(2), 375 TEGRA210_AMX_BYTE_MAP_CTRL(3), 376 TEGRA210_AMX_BYTE_MAP_CTRL(4), 377 TEGRA210_AMX_BYTE_MAP_CTRL(5), 378 TEGRA210_AMX_BYTE_MAP_CTRL(6), 379 TEGRA210_AMX_BYTE_MAP_CTRL(7), 380 TEGRA210_AMX_BYTE_MAP_CTRL(8), 381 TEGRA210_AMX_BYTE_MAP_CTRL(9), 382 TEGRA210_AMX_BYTE_MAP_CTRL(10), 383 TEGRA210_AMX_BYTE_MAP_CTRL(11), 384 TEGRA210_AMX_BYTE_MAP_CTRL(12), 385 TEGRA210_AMX_BYTE_MAP_CTRL(13), 386 TEGRA210_AMX_BYTE_MAP_CTRL(14), 387 TEGRA210_AMX_BYTE_MAP_CTRL(15), 388 TEGRA210_AMX_BYTE_MAP_CTRL(16), 389 TEGRA210_AMX_BYTE_MAP_CTRL(17), 390 TEGRA210_AMX_BYTE_MAP_CTRL(18), 391 TEGRA210_AMX_BYTE_MAP_CTRL(19), 392 TEGRA210_AMX_BYTE_MAP_CTRL(20), 393 TEGRA210_AMX_BYTE_MAP_CTRL(21), 394 TEGRA210_AMX_BYTE_MAP_CTRL(22), 395 TEGRA210_AMX_BYTE_MAP_CTRL(23), 396 TEGRA210_AMX_BYTE_MAP_CTRL(24), 397 TEGRA210_AMX_BYTE_MAP_CTRL(25), 398 TEGRA210_AMX_BYTE_MAP_CTRL(26), 399 TEGRA210_AMX_BYTE_MAP_CTRL(27), 400 TEGRA210_AMX_BYTE_MAP_CTRL(28), 401 TEGRA210_AMX_BYTE_MAP_CTRL(29), 402 TEGRA210_AMX_BYTE_MAP_CTRL(30), 403 TEGRA210_AMX_BYTE_MAP_CTRL(31), 404 TEGRA210_AMX_BYTE_MAP_CTRL(32), 405 TEGRA210_AMX_BYTE_MAP_CTRL(33), 406 TEGRA210_AMX_BYTE_MAP_CTRL(34), 407 TEGRA210_AMX_BYTE_MAP_CTRL(35), 408 TEGRA210_AMX_BYTE_MAP_CTRL(36), 409 TEGRA210_AMX_BYTE_MAP_CTRL(37), 410 TEGRA210_AMX_BYTE_MAP_CTRL(38), 411 TEGRA210_AMX_BYTE_MAP_CTRL(39), 412 TEGRA210_AMX_BYTE_MAP_CTRL(40), 413 TEGRA210_AMX_BYTE_MAP_CTRL(41), 414 TEGRA210_AMX_BYTE_MAP_CTRL(42), 415 TEGRA210_AMX_BYTE_MAP_CTRL(43), 416 TEGRA210_AMX_BYTE_MAP_CTRL(44), 417 TEGRA210_AMX_BYTE_MAP_CTRL(45), 418 TEGRA210_AMX_BYTE_MAP_CTRL(46), 419 TEGRA210_AMX_BYTE_MAP_CTRL(47), 420 TEGRA210_AMX_BYTE_MAP_CTRL(48), 421 TEGRA210_AMX_BYTE_MAP_CTRL(49), 422 TEGRA210_AMX_BYTE_MAP_CTRL(50), 423 TEGRA210_AMX_BYTE_MAP_CTRL(51), 424 TEGRA210_AMX_BYTE_MAP_CTRL(52), 425 TEGRA210_AMX_BYTE_MAP_CTRL(53), 426 TEGRA210_AMX_BYTE_MAP_CTRL(54), 427 TEGRA210_AMX_BYTE_MAP_CTRL(55), 428 TEGRA210_AMX_BYTE_MAP_CTRL(56), 429 TEGRA210_AMX_BYTE_MAP_CTRL(57), 430 TEGRA210_AMX_BYTE_MAP_CTRL(58), 431 TEGRA210_AMX_BYTE_MAP_CTRL(59), 432 TEGRA210_AMX_BYTE_MAP_CTRL(60), 433 TEGRA210_AMX_BYTE_MAP_CTRL(61), 434 TEGRA210_AMX_BYTE_MAP_CTRL(62), 435 TEGRA210_AMX_BYTE_MAP_CTRL(63), 436}; 437 438static struct snd_kcontrol_new tegra264_amx_controls[] = { 439 TEGRA210_AMX_BYTE_MAP_CTRL(64), 440 TEGRA210_AMX_BYTE_MAP_CTRL(65), 441 TEGRA210_AMX_BYTE_MAP_CTRL(66), 442 TEGRA210_AMX_BYTE_MAP_CTRL(67), 443 TEGRA210_AMX_BYTE_MAP_CTRL(68), 444 TEGRA210_AMX_BYTE_MAP_CTRL(69), 445 TEGRA210_AMX_BYTE_MAP_CTRL(70), 446 TEGRA210_AMX_BYTE_MAP_CTRL(71), 447 TEGRA210_AMX_BYTE_MAP_CTRL(72), 448 TEGRA210_AMX_BYTE_MAP_CTRL(73), 449 TEGRA210_AMX_BYTE_MAP_CTRL(74), 450 TEGRA210_AMX_BYTE_MAP_CTRL(75), 451 TEGRA210_AMX_BYTE_MAP_CTRL(76), 452 TEGRA210_AMX_BYTE_MAP_CTRL(77), 453 TEGRA210_AMX_BYTE_MAP_CTRL(78), 454 TEGRA210_AMX_BYTE_MAP_CTRL(79), 455 TEGRA210_AMX_BYTE_MAP_CTRL(80), 456 TEGRA210_AMX_BYTE_MAP_CTRL(81), 457 TEGRA210_AMX_BYTE_MAP_CTRL(82), 458 TEGRA210_AMX_BYTE_MAP_CTRL(83), 459 TEGRA210_AMX_BYTE_MAP_CTRL(84), 460 TEGRA210_AMX_BYTE_MAP_CTRL(85), 461 TEGRA210_AMX_BYTE_MAP_CTRL(86), 462 TEGRA210_AMX_BYTE_MAP_CTRL(87), 463 TEGRA210_AMX_BYTE_MAP_CTRL(88), 464 TEGRA210_AMX_BYTE_MAP_CTRL(89), 465 TEGRA210_AMX_BYTE_MAP_CTRL(90), 466 TEGRA210_AMX_BYTE_MAP_CTRL(91), 467 TEGRA210_AMX_BYTE_MAP_CTRL(92), 468 TEGRA210_AMX_BYTE_MAP_CTRL(93), 469 TEGRA210_AMX_BYTE_MAP_CTRL(94), 470 TEGRA210_AMX_BYTE_MAP_CTRL(95), 471 TEGRA210_AMX_BYTE_MAP_CTRL(96), 472 TEGRA210_AMX_BYTE_MAP_CTRL(97), 473 TEGRA210_AMX_BYTE_MAP_CTRL(98), 474 TEGRA210_AMX_BYTE_MAP_CTRL(99), 475 TEGRA210_AMX_BYTE_MAP_CTRL(100), 476 TEGRA210_AMX_BYTE_MAP_CTRL(101), 477 TEGRA210_AMX_BYTE_MAP_CTRL(102), 478 TEGRA210_AMX_BYTE_MAP_CTRL(103), 479 TEGRA210_AMX_BYTE_MAP_CTRL(104), 480 TEGRA210_AMX_BYTE_MAP_CTRL(105), 481 TEGRA210_AMX_BYTE_MAP_CTRL(106), 482 TEGRA210_AMX_BYTE_MAP_CTRL(107), 483 TEGRA210_AMX_BYTE_MAP_CTRL(108), 484 TEGRA210_AMX_BYTE_MAP_CTRL(109), 485 TEGRA210_AMX_BYTE_MAP_CTRL(110), 486 TEGRA210_AMX_BYTE_MAP_CTRL(111), 487 TEGRA210_AMX_BYTE_MAP_CTRL(112), 488 TEGRA210_AMX_BYTE_MAP_CTRL(113), 489 TEGRA210_AMX_BYTE_MAP_CTRL(114), 490 TEGRA210_AMX_BYTE_MAP_CTRL(115), 491 TEGRA210_AMX_BYTE_MAP_CTRL(116), 492 TEGRA210_AMX_BYTE_MAP_CTRL(117), 493 TEGRA210_AMX_BYTE_MAP_CTRL(118), 494 TEGRA210_AMX_BYTE_MAP_CTRL(119), 495 TEGRA210_AMX_BYTE_MAP_CTRL(120), 496 TEGRA210_AMX_BYTE_MAP_CTRL(121), 497 TEGRA210_AMX_BYTE_MAP_CTRL(122), 498 TEGRA210_AMX_BYTE_MAP_CTRL(123), 499 TEGRA210_AMX_BYTE_MAP_CTRL(124), 500 TEGRA210_AMX_BYTE_MAP_CTRL(125), 501 TEGRA210_AMX_BYTE_MAP_CTRL(126), 502 TEGRA210_AMX_BYTE_MAP_CTRL(127), 503}; 504 505static int tegra210_amx_component_probe(struct snd_soc_component *component) 506{ 507 struct tegra210_amx *amx = snd_soc_component_get_drvdata(component); 508 int err = 0; 509 510 if (amx->soc_data->num_controls) { 511 err = snd_soc_add_component_controls(component, amx->soc_data->controls, 512 amx->soc_data->num_controls); 513 if (err) 514 dev_err(component->dev, "can't add AMX controls, err: %d\n", err); 515 } 516 517 return err; 518} 519 520static const struct snd_soc_component_driver tegra210_amx_cmpnt = { 521 .probe = tegra210_amx_component_probe, 522 .dapm_widgets = tegra210_amx_widgets, 523 .num_dapm_widgets = ARRAY_SIZE(tegra210_amx_widgets), 524 .dapm_routes = tegra210_amx_routes, 525 .num_dapm_routes = ARRAY_SIZE(tegra210_amx_routes), 526 .controls = tegra210_amx_controls, 527 .num_controls = ARRAY_SIZE(tegra210_amx_controls), 528}; 529 530static bool tegra210_amx_wr_reg(struct device *dev, unsigned int reg) 531{ 532 switch (reg) { 533 case TEGRA210_AMX_RX_INT_MASK ... TEGRA210_AMX_RX4_CIF_CTRL: 534 case TEGRA210_AMX_TX_INT_MASK ... TEGRA210_AMX_CG: 535 case TEGRA210_AMX_CTRL ... TEGRA210_AMX_CYA: 536 case TEGRA210_AMX_CFG_RAM_CTRL ... TEGRA210_AMX_CFG_RAM_DATA: 537 return true; 538 default: 539 return false; 540 } 541} 542 543static bool tegra194_amx_wr_reg(struct device *dev, unsigned int reg) 544{ 545 switch (reg) { 546 case TEGRA194_AMX_RX1_FRAME_PERIOD ... TEGRA194_AMX_RX4_FRAME_PERIOD: 547 return true; 548 default: 549 return tegra210_amx_wr_reg(dev, reg); 550 } 551} 552 553static bool tegra264_amx_wr_reg(struct device *dev, 554 unsigned int reg) 555{ 556 switch (reg) { 557 case TEGRA210_AMX_RX_INT_MASK ... TEGRA210_AMX_RX4_CIF_CTRL: 558 case TEGRA210_AMX_TX_INT_MASK ... TEGRA210_AMX_TX_CIF_CTRL: 559 case TEGRA210_AMX_ENABLE ... TEGRA210_AMX_CG: 560 case TEGRA210_AMX_CTRL ... TEGRA264_AMX_STREAMS_AUTO_DISABLE: 561 case TEGRA264_AMX_CFG_RAM_CTRL ... TEGRA264_AMX_CFG_RAM_DATA: 562 case TEGRA264_AMX_RX1_FRAME_PERIOD ... TEGRA264_AMX_RX4_FRAME_PERIOD: 563 return true; 564 default: 565 return false; 566 } 567} 568 569static bool tegra210_amx_rd_reg(struct device *dev, unsigned int reg) 570{ 571 switch (reg) { 572 case TEGRA210_AMX_RX_STATUS ... TEGRA210_AMX_CFG_RAM_DATA: 573 return true; 574 default: 575 return false; 576 } 577} 578 579static bool tegra194_amx_rd_reg(struct device *dev, unsigned int reg) 580{ 581 switch (reg) { 582 case TEGRA194_AMX_RX1_FRAME_PERIOD ... TEGRA194_AMX_RX4_FRAME_PERIOD: 583 return true; 584 default: 585 return tegra210_amx_rd_reg(dev, reg); 586 } 587} 588 589static bool tegra264_amx_rd_reg(struct device *dev, 590 unsigned int reg) 591{ 592 switch (reg) { 593 case TEGRA210_AMX_RX_STATUS ... TEGRA210_AMX_RX4_CIF_CTRL: 594 case TEGRA210_AMX_TX_STATUS ... TEGRA210_AMX_TX_CIF_CTRL: 595 case TEGRA210_AMX_ENABLE ... TEGRA210_AMX_INT_STATUS: 596 case TEGRA210_AMX_CTRL ... TEGRA264_AMX_CFG_RAM_DATA: 597 case TEGRA264_AMX_RX1_FRAME_PERIOD ... TEGRA264_AMX_RX4_FRAME_PERIOD: 598 return true; 599 default: 600 return false; 601 } 602} 603 604static bool tegra210_amx_volatile_reg(struct device *dev, unsigned int reg) 605{ 606 switch (reg) { 607 case TEGRA210_AMX_RX_STATUS: 608 case TEGRA210_AMX_RX_INT_STATUS: 609 case TEGRA210_AMX_RX_INT_SET: 610 case TEGRA210_AMX_TX_STATUS: 611 case TEGRA210_AMX_TX_INT_STATUS: 612 case TEGRA210_AMX_TX_INT_SET: 613 case TEGRA210_AMX_SOFT_RESET: 614 case TEGRA210_AMX_STATUS: 615 case TEGRA210_AMX_INT_STATUS: 616 case TEGRA210_AMX_CFG_RAM_CTRL: 617 case TEGRA210_AMX_CFG_RAM_DATA: 618 return true; 619 default: 620 break; 621 } 622 623 return false; 624} 625 626static bool tegra264_amx_volatile_reg(struct device *dev, 627 unsigned int reg) 628{ 629 switch (reg) { 630 case TEGRA210_AMX_RX_STATUS: 631 case TEGRA210_AMX_RX_INT_STATUS: 632 case TEGRA210_AMX_RX_INT_SET: 633 case TEGRA210_AMX_TX_STATUS: 634 case TEGRA210_AMX_TX_INT_STATUS: 635 case TEGRA210_AMX_TX_INT_SET: 636 case TEGRA210_AMX_SOFT_RESET: 637 case TEGRA210_AMX_STATUS: 638 case TEGRA210_AMX_INT_STATUS: 639 case TEGRA264_AMX_CFG_RAM_CTRL: 640 case TEGRA264_AMX_CFG_RAM_DATA: 641 return true; 642 default: 643 break; 644 } 645 646 return false; 647} 648 649static const struct regmap_config tegra210_amx_regmap_config = { 650 .reg_bits = 32, 651 .reg_stride = 4, 652 .val_bits = 32, 653 .max_register = TEGRA210_AMX_CFG_RAM_DATA, 654 .writeable_reg = tegra210_amx_wr_reg, 655 .readable_reg = tegra210_amx_rd_reg, 656 .volatile_reg = tegra210_amx_volatile_reg, 657 .reg_defaults = tegra210_amx_reg_defaults, 658 .num_reg_defaults = ARRAY_SIZE(tegra210_amx_reg_defaults), 659 .reg_default_cb = regmap_default_zero_cb, 660 .cache_type = REGCACHE_FLAT, 661}; 662 663static const struct regmap_config tegra194_amx_regmap_config = { 664 .reg_bits = 32, 665 .reg_stride = 4, 666 .val_bits = 32, 667 .max_register = TEGRA194_AMX_RX4_LAST_FRAME_PERIOD, 668 .writeable_reg = tegra194_amx_wr_reg, 669 .readable_reg = tegra194_amx_rd_reg, 670 .volatile_reg = tegra210_amx_volatile_reg, 671 .reg_defaults = tegra210_amx_reg_defaults, 672 .num_reg_defaults = ARRAY_SIZE(tegra210_amx_reg_defaults), 673 .reg_default_cb = regmap_default_zero_cb, 674 .cache_type = REGCACHE_FLAT, 675}; 676 677static const struct regmap_config tegra264_amx_regmap_config = { 678 .reg_bits = 32, 679 .reg_stride = 4, 680 .val_bits = 32, 681 .max_register = TEGRA264_AMX_RX4_LAST_FRAME_PERIOD, 682 .writeable_reg = tegra264_amx_wr_reg, 683 .readable_reg = tegra264_amx_rd_reg, 684 .volatile_reg = tegra264_amx_volatile_reg, 685 .reg_defaults = tegra264_amx_reg_defaults, 686 .num_reg_defaults = ARRAY_SIZE(tegra264_amx_reg_defaults), 687 .reg_default_cb = regmap_default_zero_cb, 688 .cache_type = REGCACHE_FLAT, 689}; 690 691static const struct tegra210_amx_soc_data soc_data_tegra210 = { 692 .regmap_conf = &tegra210_amx_regmap_config, 693 .max_ch = TEGRA210_AMX_MAX_CHANNEL, 694 .ram_depth = TEGRA210_AMX_RAM_DEPTH, 695 .byte_mask_size = TEGRA210_AMX_BYTE_MASK_COUNT, 696 .reg_offset = TEGRA210_AMX_AUTO_DISABLE_OFFSET, 697}; 698 699static const struct tegra210_amx_soc_data soc_data_tegra194 = { 700 .regmap_conf = &tegra194_amx_regmap_config, 701 .auto_disable = true, 702 .max_ch = TEGRA210_AMX_MAX_CHANNEL, 703 .ram_depth = TEGRA210_AMX_RAM_DEPTH, 704 .byte_mask_size = TEGRA210_AMX_BYTE_MASK_COUNT, 705 .reg_offset = TEGRA210_AMX_AUTO_DISABLE_OFFSET, 706}; 707 708static const struct tegra210_amx_soc_data soc_data_tegra264 = { 709 .regmap_conf = &tegra264_amx_regmap_config, 710 .auto_disable = true, 711 .max_ch = TEGRA264_AMX_MAX_CHANNEL, 712 .ram_depth = TEGRA264_AMX_RAM_DEPTH, 713 .byte_mask_size = TEGRA264_AMX_BYTE_MASK_COUNT, 714 .reg_offset = TEGRA264_AMX_AUTO_DISABLE_OFFSET, 715 .controls = tegra264_amx_controls, 716 .num_controls = ARRAY_SIZE(tegra264_amx_controls), 717}; 718 719static const struct of_device_id tegra210_amx_of_match[] = { 720 { .compatible = "nvidia,tegra210-amx", .data = &soc_data_tegra210 }, 721 { .compatible = "nvidia,tegra194-amx", .data = &soc_data_tegra194 }, 722 { .compatible = "nvidia,tegra264-amx", .data = &soc_data_tegra264 }, 723 {}, 724}; 725MODULE_DEVICE_TABLE(of, tegra210_amx_of_match); 726 727static int tegra210_amx_platform_probe(struct platform_device *pdev) 728{ 729 struct device *dev = &pdev->dev; 730 struct tegra210_amx *amx; 731 void __iomem *regs; 732 int err; 733 734 amx = devm_kzalloc(dev, sizeof(*amx), GFP_KERNEL); 735 if (!amx) 736 return -ENOMEM; 737 738 amx->soc_data = device_get_match_data(dev); 739 740 dev_set_drvdata(dev, amx); 741 742 regs = devm_platform_ioremap_resource(pdev, 0); 743 if (IS_ERR(regs)) 744 return PTR_ERR(regs); 745 746 amx->regmap = devm_regmap_init_mmio(dev, regs, 747 amx->soc_data->regmap_conf); 748 if (IS_ERR(amx->regmap)) 749 return dev_err_probe(dev, PTR_ERR(amx->regmap), 750 "regmap init failed\n"); 751 752 regcache_cache_only(amx->regmap, true); 753 754 amx->map = devm_kzalloc(dev, amx->soc_data->ram_depth * sizeof(*amx->map), 755 GFP_KERNEL); 756 if (!amx->map) 757 return -ENOMEM; 758 759 amx->byte_mask = devm_kzalloc(dev, 760 amx->soc_data->byte_mask_size * sizeof(*amx->byte_mask), 761 GFP_KERNEL); 762 if (!amx->byte_mask) 763 return -ENOMEM; 764 765 tegra210_amx_dais[TEGRA_AMX_OUT_DAI_ID].capture.channels_max = 766 amx->soc_data->max_ch; 767 768 err = devm_snd_soc_register_component(dev, &tegra210_amx_cmpnt, 769 tegra210_amx_dais, 770 ARRAY_SIZE(tegra210_amx_dais)); 771 if (err) 772 return dev_err_probe(dev, err, 773 "can't register AMX component\n"); 774 775 pm_runtime_enable(dev); 776 777 return 0; 778} 779 780static void tegra210_amx_platform_remove(struct platform_device *pdev) 781{ 782 pm_runtime_disable(&pdev->dev); 783} 784 785static const struct dev_pm_ops tegra210_amx_pm_ops = { 786 RUNTIME_PM_OPS(tegra210_amx_runtime_suspend, 787 tegra210_amx_runtime_resume, NULL) 788 SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) 789}; 790 791static struct platform_driver tegra210_amx_driver = { 792 .driver = { 793 .name = "tegra210-amx", 794 .of_match_table = tegra210_amx_of_match, 795 .pm = pm_ptr(&tegra210_amx_pm_ops), 796 }, 797 .probe = tegra210_amx_platform_probe, 798 .remove = tegra210_amx_platform_remove, 799}; 800module_platform_driver(tegra210_amx_driver); 801 802MODULE_AUTHOR("Songhee Baek <sbaek@nvidia.com>"); 803MODULE_DESCRIPTION("Tegra210 AMX ASoC driver"); 804MODULE_LICENSE("GPL v2");