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_mvc.c - Tegra210 MVC 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_mvc.h" 21 #include "tegra_cif.h" 22 23 static const struct reg_default tegra210_mvc_reg_defaults[] = { 24 { TEGRA210_MVC_RX_INT_MASK, 0x00000001}, 25 { TEGRA210_MVC_RX_CIF_CTRL, 0x00007700}, 26 { TEGRA210_MVC_TX_INT_MASK, 0x00000001}, 27 { TEGRA210_MVC_TX_CIF_CTRL, 0x00007700}, 28 { TEGRA210_MVC_CG, 0x1}, 29 { TEGRA210_MVC_CTRL, TEGRA210_MVC_CTRL_DEFAULT}, 30 { TEGRA210_MVC_INIT_VOL, 0x00800000}, 31 { TEGRA210_MVC_TARGET_VOL, 0x00800000}, 32 { TEGRA210_MVC_DURATION, 0x000012c0}, 33 { TEGRA210_MVC_DURATION_INV, 0x0006d3a0}, 34 { TEGRA210_MVC_POLY_N1, 0x0000007d}, 35 { TEGRA210_MVC_POLY_N2, 0x00000271}, 36 { TEGRA210_MVC_PEAK_CTRL, 0x000012c0}, 37 { TEGRA210_MVC_CFG_RAM_CTRL, 0x00004000}, 38 }; 39 40 static const struct tegra210_mvc_gain_params gain_params = { 41 .poly_coeff = { 23738319, 659403, -3680, 42 15546680, 2530732, -120985, 43 12048422, 5527252, -785042 }, 44 .poly_n1 = 16, 45 .poly_n2 = 63, 46 .duration = 150, 47 .duration_inv = 14316558, 48 }; 49 50 static int __maybe_unused tegra210_mvc_runtime_suspend(struct device *dev) 51 { 52 struct tegra210_mvc *mvc = dev_get_drvdata(dev); 53 54 regmap_read(mvc->regmap, TEGRA210_MVC_CTRL, &(mvc->ctrl_value)); 55 56 regcache_cache_only(mvc->regmap, true); 57 regcache_mark_dirty(mvc->regmap); 58 59 return 0; 60 } 61 62 static int __maybe_unused tegra210_mvc_runtime_resume(struct device *dev) 63 { 64 struct tegra210_mvc *mvc = dev_get_drvdata(dev); 65 66 regcache_cache_only(mvc->regmap, false); 67 regcache_sync(mvc->regmap); 68 69 regmap_write(mvc->regmap, TEGRA210_MVC_CTRL, mvc->ctrl_value); 70 regmap_update_bits(mvc->regmap, 71 TEGRA210_MVC_SWITCH, 72 TEGRA210_MVC_VOLUME_SWITCH_MASK, 73 TEGRA210_MVC_VOLUME_SWITCH_TRIGGER); 74 75 return 0; 76 } 77 78 static void tegra210_mvc_write_ram(struct regmap *regmap) 79 { 80 int i; 81 82 regmap_write(regmap, TEGRA210_MVC_CFG_RAM_CTRL, 83 TEGRA210_MVC_CFG_RAM_CTRL_SEQ_ACCESS_EN | 84 TEGRA210_MVC_CFG_RAM_CTRL_ADDR_INIT_EN | 85 TEGRA210_MVC_CFG_RAM_CTRL_RW_WRITE); 86 87 for (i = 0; i < NUM_GAIN_POLY_COEFFS; i++) 88 regmap_write(regmap, TEGRA210_MVC_CFG_RAM_DATA, 89 gain_params.poly_coeff[i]); 90 } 91 92 static void tegra210_mvc_conv_vol(struct tegra210_mvc *mvc, u8 chan, s32 val) 93 { 94 /* 95 * Volume control read from mixer control is with 96 * 100x scaling; for CURVE_POLY the reg range 97 * is 0-100 (linear, Q24) and for CURVE_LINEAR 98 * it is -120dB to +40dB (Q8) 99 */ 100 if (mvc->curve_type == CURVE_POLY) { 101 if (val > 10000) 102 val = 10000; 103 mvc->volume[chan] = ((val * (1<<8)) / 100) << 16; 104 } else { 105 val -= 12000; 106 mvc->volume[chan] = (val * (1<<8)) / 100; 107 } 108 } 109 110 static u32 tegra210_mvc_get_ctrl_reg(struct snd_kcontrol *kcontrol) 111 { 112 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 113 struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); 114 u32 val; 115 116 pm_runtime_get_sync(cmpnt->dev); 117 regmap_read(mvc->regmap, TEGRA210_MVC_CTRL, &val); 118 pm_runtime_put(cmpnt->dev); 119 120 return val; 121 } 122 123 static int tegra210_mvc_get_mute(struct snd_kcontrol *kcontrol, 124 struct snd_ctl_elem_value *ucontrol) 125 { 126 u32 val = tegra210_mvc_get_ctrl_reg(kcontrol); 127 u8 mute_mask = TEGRA210_GET_MUTE_VAL(val); 128 129 /* 130 * If per channel control is enabled, then return 131 * exact mute/unmute setting of all channels. 132 * 133 * Else report setting based on CH0 bit to reflect 134 * the correct HW state. 135 */ 136 if (val & TEGRA210_MVC_PER_CHAN_CTRL_EN) { 137 ucontrol->value.integer.value[0] = mute_mask; 138 } else { 139 if (mute_mask & TEGRA210_MVC_CH0_MUTE_EN) 140 ucontrol->value.integer.value[0] = 141 TEGRA210_MUTE_MASK_EN; 142 else 143 ucontrol->value.integer.value[0] = 0; 144 } 145 146 return 0; 147 } 148 149 static int tegra210_mvc_get_master_mute(struct snd_kcontrol *kcontrol, 150 struct snd_ctl_elem_value *ucontrol) 151 { 152 u32 val = tegra210_mvc_get_ctrl_reg(kcontrol); 153 u8 mute_mask = TEGRA210_GET_MUTE_VAL(val); 154 155 /* 156 * If per channel control is disabled, then return 157 * master mute/unmute setting based on CH0 bit. 158 * 159 * Else report settings based on state of all 160 * channels. 161 */ 162 if (!(val & TEGRA210_MVC_PER_CHAN_CTRL_EN)) { 163 ucontrol->value.integer.value[0] = 164 mute_mask & TEGRA210_MVC_CH0_MUTE_EN; 165 } else { 166 if (mute_mask == TEGRA210_MUTE_MASK_EN) 167 ucontrol->value.integer.value[0] = 168 TEGRA210_MVC_CH0_MUTE_EN; 169 else 170 ucontrol->value.integer.value[0] = 0; 171 } 172 173 return 0; 174 } 175 176 static int tegra210_mvc_volume_switch_timeout(struct snd_soc_component *cmpnt) 177 { 178 struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); 179 u32 value; 180 int err; 181 182 err = regmap_read_poll_timeout(mvc->regmap, TEGRA210_MVC_SWITCH, 183 value, !(value & TEGRA210_MVC_VOLUME_SWITCH_MASK), 184 10, 10000); 185 if (err < 0) 186 dev_err(cmpnt->dev, 187 "Volume switch trigger is still active, err = %d\n", 188 err); 189 190 return err; 191 } 192 193 static int tegra210_mvc_update_mute(struct snd_kcontrol *kcontrol, 194 struct snd_ctl_elem_value *ucontrol, 195 bool per_chan_ctrl) 196 { 197 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 198 struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); 199 u32 mute_val = ucontrol->value.integer.value[0]; 200 u32 per_ch_ctrl_val; 201 bool change = false; 202 int err; 203 204 pm_runtime_get_sync(cmpnt->dev); 205 206 err = tegra210_mvc_volume_switch_timeout(cmpnt); 207 if (err < 0) 208 goto end; 209 210 if (per_chan_ctrl) { 211 per_ch_ctrl_val = TEGRA210_MVC_PER_CHAN_CTRL_EN; 212 } else { 213 per_ch_ctrl_val = 0; 214 215 if (mute_val) 216 mute_val = TEGRA210_MUTE_MASK_EN; 217 } 218 219 regmap_update_bits_check(mvc->regmap, TEGRA210_MVC_CTRL, 220 TEGRA210_MVC_MUTE_MASK, 221 mute_val << TEGRA210_MVC_MUTE_SHIFT, 222 &change); 223 224 if (change) { 225 regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL, 226 TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK, 227 per_ch_ctrl_val); 228 229 regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH, 230 TEGRA210_MVC_VOLUME_SWITCH_MASK, 231 TEGRA210_MVC_VOLUME_SWITCH_TRIGGER); 232 } 233 234 end: 235 pm_runtime_put(cmpnt->dev); 236 237 if (err < 0) 238 return err; 239 240 if (change) 241 return 1; 242 243 return 0; 244 } 245 246 static int tegra210_mvc_put_mute(struct snd_kcontrol *kcontrol, 247 struct snd_ctl_elem_value *ucontrol) 248 { 249 return tegra210_mvc_update_mute(kcontrol, ucontrol, true); 250 } 251 252 static int tegra210_mvc_put_master_mute(struct snd_kcontrol *kcontrol, 253 struct snd_ctl_elem_value *ucontrol) 254 { 255 return tegra210_mvc_update_mute(kcontrol, ucontrol, false); 256 } 257 258 static int tegra210_mvc_get_vol(struct snd_kcontrol *kcontrol, 259 struct snd_ctl_elem_value *ucontrol) 260 { 261 struct soc_mixer_control *mc = 262 (struct soc_mixer_control *)kcontrol->private_value; 263 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 264 struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); 265 u8 chan = TEGRA210_MVC_GET_CHAN(mc->reg, TEGRA210_MVC_TARGET_VOL); 266 s32 val = mvc->volume[chan]; 267 268 if (mvc->curve_type == CURVE_POLY) { 269 val = ((val >> 16) * 100) >> 8; 270 } else { 271 val = (val * 100) >> 8; 272 val += 12000; 273 } 274 275 ucontrol->value.integer.value[0] = val; 276 277 return 0; 278 } 279 280 static int tegra210_mvc_get_master_vol(struct snd_kcontrol *kcontrol, 281 struct snd_ctl_elem_value *ucontrol) 282 { 283 return tegra210_mvc_get_vol(kcontrol, ucontrol); 284 } 285 286 static int tegra210_mvc_update_vol(struct snd_kcontrol *kcontrol, 287 struct snd_ctl_elem_value *ucontrol, 288 bool per_ch_enable) 289 { 290 struct soc_mixer_control *mc = 291 (struct soc_mixer_control *)kcontrol->private_value; 292 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 293 struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); 294 u8 chan = TEGRA210_MVC_GET_CHAN(mc->reg, TEGRA210_MVC_TARGET_VOL); 295 int old_volume = mvc->volume[chan]; 296 int err, i; 297 298 pm_runtime_get_sync(cmpnt->dev); 299 300 err = tegra210_mvc_volume_switch_timeout(cmpnt); 301 if (err < 0) 302 goto end; 303 304 tegra210_mvc_conv_vol(mvc, chan, ucontrol->value.integer.value[0]); 305 306 if (mvc->volume[chan] == old_volume) { 307 err = 0; 308 goto end; 309 } 310 311 if (per_ch_enable) { 312 regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL, 313 TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK, 314 TEGRA210_MVC_PER_CHAN_CTRL_EN); 315 } else { 316 regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL, 317 TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK, 0); 318 319 for (i = 1; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++) 320 mvc->volume[i] = mvc->volume[chan]; 321 } 322 323 /* Configure init volume same as target volume */ 324 regmap_write(mvc->regmap, 325 TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_INIT_VOL, chan), 326 mvc->volume[chan]); 327 328 regmap_write(mvc->regmap, mc->reg, mvc->volume[chan]); 329 330 regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH, 331 TEGRA210_MVC_VOLUME_SWITCH_MASK, 332 TEGRA210_MVC_VOLUME_SWITCH_TRIGGER); 333 334 err = 1; 335 336 end: 337 pm_runtime_put(cmpnt->dev); 338 339 return err; 340 } 341 342 static int tegra210_mvc_put_vol(struct snd_kcontrol *kcontrol, 343 struct snd_ctl_elem_value *ucontrol) 344 { 345 return tegra210_mvc_update_vol(kcontrol, ucontrol, true); 346 } 347 348 static int tegra210_mvc_put_master_vol(struct snd_kcontrol *kcontrol, 349 struct snd_ctl_elem_value *ucontrol) 350 { 351 return tegra210_mvc_update_vol(kcontrol, ucontrol, false); 352 } 353 354 static void tegra210_mvc_reset_vol_settings(struct tegra210_mvc *mvc, 355 struct device *dev) 356 { 357 int i; 358 359 /* Change volume to default init for new curve type */ 360 if (mvc->curve_type == CURVE_POLY) { 361 for (i = 0; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++) 362 mvc->volume[i] = TEGRA210_MVC_INIT_VOL_DEFAULT_POLY; 363 } else { 364 for (i = 0; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++) 365 mvc->volume[i] = TEGRA210_MVC_INIT_VOL_DEFAULT_LINEAR; 366 } 367 368 pm_runtime_get_sync(dev); 369 370 /* Program curve type */ 371 regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL, 372 TEGRA210_MVC_CURVE_TYPE_MASK, 373 mvc->curve_type << 374 TEGRA210_MVC_CURVE_TYPE_SHIFT); 375 376 /* Init volume for all channels */ 377 for (i = 0; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++) { 378 regmap_write(mvc->regmap, 379 TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_INIT_VOL, i), 380 mvc->volume[i]); 381 regmap_write(mvc->regmap, 382 TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_TARGET_VOL, i), 383 mvc->volume[i]); 384 } 385 386 /* Trigger volume switch */ 387 regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH, 388 TEGRA210_MVC_VOLUME_SWITCH_MASK, 389 TEGRA210_MVC_VOLUME_SWITCH_TRIGGER); 390 391 pm_runtime_put(dev); 392 } 393 394 static int tegra210_mvc_get_curve_type(struct snd_kcontrol *kcontrol, 395 struct snd_ctl_elem_value *ucontrol) 396 { 397 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 398 struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); 399 400 ucontrol->value.enumerated.item[0] = mvc->curve_type; 401 402 return 0; 403 } 404 405 static int tegra210_mvc_put_curve_type(struct snd_kcontrol *kcontrol, 406 struct snd_ctl_elem_value *ucontrol) 407 { 408 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 409 struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); 410 unsigned int value; 411 412 regmap_read(mvc->regmap, TEGRA210_MVC_ENABLE, &value); 413 if (value & TEGRA210_MVC_EN) { 414 dev_err(cmpnt->dev, 415 "Curve type can't be set when MVC is running\n"); 416 return -EINVAL; 417 } 418 419 if (mvc->curve_type == ucontrol->value.enumerated.item[0]) 420 return 0; 421 422 mvc->curve_type = ucontrol->value.enumerated.item[0]; 423 424 tegra210_mvc_reset_vol_settings(mvc, cmpnt->dev); 425 426 return 1; 427 } 428 429 static int tegra210_mvc_set_audio_cif(struct tegra210_mvc *mvc, 430 struct snd_pcm_hw_params *params, 431 unsigned int reg) 432 { 433 unsigned int channels, audio_bits; 434 struct tegra_cif_conf cif_conf; 435 436 memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); 437 438 channels = params_channels(params); 439 440 switch (params_format(params)) { 441 case SNDRV_PCM_FORMAT_S16_LE: 442 audio_bits = TEGRA_ACIF_BITS_16; 443 break; 444 case SNDRV_PCM_FORMAT_S24_LE: 445 case SNDRV_PCM_FORMAT_S32_LE: 446 audio_bits = TEGRA_ACIF_BITS_32; 447 break; 448 default: 449 return -EINVAL; 450 } 451 452 cif_conf.audio_ch = channels; 453 cif_conf.client_ch = channels; 454 cif_conf.audio_bits = audio_bits; 455 cif_conf.client_bits = audio_bits; 456 457 tegra_set_cif(mvc->regmap, reg, &cif_conf); 458 459 return 0; 460 } 461 462 static int tegra210_mvc_hw_params(struct snd_pcm_substream *substream, 463 struct snd_pcm_hw_params *params, 464 struct snd_soc_dai *dai) 465 { 466 struct device *dev = dai->dev; 467 struct tegra210_mvc *mvc = snd_soc_dai_get_drvdata(dai); 468 int err, val; 469 470 /* 471 * Soft Reset: Below performs module soft reset which clears 472 * all FSM logic, flushes flow control of FIFO and resets the 473 * state register. It also brings module back to disabled 474 * state (without flushing the data in the pipe). 475 */ 476 regmap_write(mvc->regmap, TEGRA210_MVC_SOFT_RESET, 1); 477 478 err = regmap_read_poll_timeout(mvc->regmap, TEGRA210_MVC_SOFT_RESET, 479 val, !val, 10, 10000); 480 if (err < 0) { 481 dev_err(dev, "SW reset failed, err = %d\n", err); 482 return err; 483 } 484 485 /* Set RX CIF */ 486 err = tegra210_mvc_set_audio_cif(mvc, params, TEGRA210_MVC_RX_CIF_CTRL); 487 if (err) { 488 dev_err(dev, "Can't set MVC RX CIF: %d\n", err); 489 return err; 490 } 491 492 /* Set TX CIF */ 493 err = tegra210_mvc_set_audio_cif(mvc, params, TEGRA210_MVC_TX_CIF_CTRL); 494 if (err) { 495 dev_err(dev, "Can't set MVC TX CIF: %d\n", err); 496 return err; 497 } 498 499 tegra210_mvc_write_ram(mvc->regmap); 500 501 /* Program poly_n1, poly_n2, duration */ 502 regmap_write(mvc->regmap, TEGRA210_MVC_POLY_N1, gain_params.poly_n1); 503 regmap_write(mvc->regmap, TEGRA210_MVC_POLY_N2, gain_params.poly_n2); 504 regmap_write(mvc->regmap, TEGRA210_MVC_DURATION, gain_params.duration); 505 506 /* Program duration_inv */ 507 regmap_write(mvc->regmap, TEGRA210_MVC_DURATION_INV, 508 gain_params.duration_inv); 509 510 return 0; 511 } 512 513 static const struct snd_soc_dai_ops tegra210_mvc_dai_ops = { 514 .hw_params = tegra210_mvc_hw_params, 515 }; 516 517 static const char * const tegra210_mvc_curve_type_text[] = { 518 "Poly", 519 "Linear", 520 }; 521 522 static const struct soc_enum tegra210_mvc_curve_type_ctrl = 523 SOC_ENUM_SINGLE_EXT(2, tegra210_mvc_curve_type_text); 524 525 #define TEGRA210_MVC_VOL_CTRL(chan) \ 526 SOC_SINGLE_EXT("Channel" #chan " Volume", \ 527 TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_TARGET_VOL, \ 528 (chan - 1)), \ 529 0, 16000, 0, tegra210_mvc_get_vol, \ 530 tegra210_mvc_put_vol) 531 532 static const struct snd_kcontrol_new tegra210_mvc_vol_ctrl[] = { 533 /* Per channel volume control */ 534 TEGRA210_MVC_VOL_CTRL(1), 535 TEGRA210_MVC_VOL_CTRL(2), 536 TEGRA210_MVC_VOL_CTRL(3), 537 TEGRA210_MVC_VOL_CTRL(4), 538 TEGRA210_MVC_VOL_CTRL(5), 539 TEGRA210_MVC_VOL_CTRL(6), 540 TEGRA210_MVC_VOL_CTRL(7), 541 TEGRA210_MVC_VOL_CTRL(8), 542 543 /* Per channel mute */ 544 SOC_SINGLE_EXT("Per Chan Mute Mask", 545 TEGRA210_MVC_CTRL, 0, TEGRA210_MUTE_MASK_EN, 0, 546 tegra210_mvc_get_mute, tegra210_mvc_put_mute), 547 548 /* Master volume */ 549 SOC_SINGLE_EXT("Volume", TEGRA210_MVC_TARGET_VOL, 0, 16000, 0, 550 tegra210_mvc_get_master_vol, 551 tegra210_mvc_put_master_vol), 552 553 /* Master mute */ 554 SOC_SINGLE_EXT("Mute", TEGRA210_MVC_CTRL, 0, 1, 0, 555 tegra210_mvc_get_master_mute, 556 tegra210_mvc_put_master_mute), 557 558 SOC_ENUM_EXT("Curve Type", tegra210_mvc_curve_type_ctrl, 559 tegra210_mvc_get_curve_type, tegra210_mvc_put_curve_type), 560 }; 561 562 static struct snd_soc_dai_driver tegra210_mvc_dais[] = { 563 /* Input */ 564 { 565 .name = "MVC-RX-CIF", 566 .playback = { 567 .stream_name = "RX-CIF-Playback", 568 .channels_min = 1, 569 .channels_max = 8, 570 .rates = SNDRV_PCM_RATE_8000_192000, 571 .formats = SNDRV_PCM_FMTBIT_S8 | 572 SNDRV_PCM_FMTBIT_S16_LE | 573 SNDRV_PCM_FMTBIT_S24_LE | 574 SNDRV_PCM_FMTBIT_S32_LE, 575 }, 576 .capture = { 577 .stream_name = "RX-CIF-Capture", 578 .channels_min = 1, 579 .channels_max = 8, 580 .rates = SNDRV_PCM_RATE_8000_192000, 581 .formats = SNDRV_PCM_FMTBIT_S8 | 582 SNDRV_PCM_FMTBIT_S16_LE | 583 SNDRV_PCM_FMTBIT_S24_LE | 584 SNDRV_PCM_FMTBIT_S32_LE, 585 }, 586 }, 587 588 /* Output */ 589 { 590 .name = "MVC-TX-CIF", 591 .playback = { 592 .stream_name = "TX-CIF-Playback", 593 .channels_min = 1, 594 .channels_max = 8, 595 .rates = SNDRV_PCM_RATE_8000_192000, 596 .formats = SNDRV_PCM_FMTBIT_S8 | 597 SNDRV_PCM_FMTBIT_S16_LE | 598 SNDRV_PCM_FMTBIT_S24_LE | 599 SNDRV_PCM_FMTBIT_S32_LE, 600 }, 601 .capture = { 602 .stream_name = "TX-CIF-Capture", 603 .channels_min = 1, 604 .channels_max = 8, 605 .rates = SNDRV_PCM_RATE_8000_192000, 606 .formats = SNDRV_PCM_FMTBIT_S8 | 607 SNDRV_PCM_FMTBIT_S16_LE | 608 SNDRV_PCM_FMTBIT_S24_LE | 609 SNDRV_PCM_FMTBIT_S32_LE, 610 }, 611 .ops = &tegra210_mvc_dai_ops, 612 } 613 }; 614 615 static const struct snd_soc_dapm_widget tegra210_mvc_widgets[] = { 616 SND_SOC_DAPM_AIF_IN("RX", NULL, 0, SND_SOC_NOPM, 0, 0), 617 SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_MVC_ENABLE, 618 TEGRA210_MVC_EN_SHIFT, 0), 619 }; 620 621 #define MVC_ROUTES(sname) \ 622 { "RX XBAR-" sname, NULL, "XBAR-TX" }, \ 623 { "RX-CIF-" sname, NULL, "RX XBAR-" sname }, \ 624 { "RX", NULL, "RX-CIF-" sname }, \ 625 { "TX-CIF-" sname, NULL, "TX" }, \ 626 { "TX XBAR-" sname, NULL, "TX-CIF-" sname }, \ 627 { "XBAR-RX", NULL, "TX XBAR-" sname } 628 629 static const struct snd_soc_dapm_route tegra210_mvc_routes[] = { 630 { "TX", NULL, "RX" }, 631 MVC_ROUTES("Playback"), 632 MVC_ROUTES("Capture"), 633 }; 634 635 static const struct snd_soc_component_driver tegra210_mvc_cmpnt = { 636 .dapm_widgets = tegra210_mvc_widgets, 637 .num_dapm_widgets = ARRAY_SIZE(tegra210_mvc_widgets), 638 .dapm_routes = tegra210_mvc_routes, 639 .num_dapm_routes = ARRAY_SIZE(tegra210_mvc_routes), 640 .controls = tegra210_mvc_vol_ctrl, 641 .num_controls = ARRAY_SIZE(tegra210_mvc_vol_ctrl), 642 }; 643 644 static bool tegra210_mvc_rd_reg(struct device *dev, unsigned int reg) 645 { 646 switch (reg) { 647 case TEGRA210_MVC_RX_STATUS ... TEGRA210_MVC_CONFIG_ERR_TYPE: 648 return true; 649 default: 650 return false; 651 }; 652 } 653 654 static bool tegra210_mvc_wr_reg(struct device *dev, unsigned int reg) 655 { 656 switch (reg) { 657 case TEGRA210_MVC_RX_INT_MASK ... TEGRA210_MVC_RX_CIF_CTRL: 658 case TEGRA210_MVC_TX_INT_MASK ... TEGRA210_MVC_TX_CIF_CTRL: 659 case TEGRA210_MVC_ENABLE ... TEGRA210_MVC_CG: 660 case TEGRA210_MVC_CTRL ... TEGRA210_MVC_CFG_RAM_DATA: 661 return true; 662 default: 663 return false; 664 } 665 } 666 667 static bool tegra210_mvc_volatile_reg(struct device *dev, unsigned int reg) 668 { 669 switch (reg) { 670 case TEGRA210_MVC_RX_STATUS: 671 case TEGRA210_MVC_RX_INT_STATUS: 672 case TEGRA210_MVC_RX_INT_SET: 673 674 case TEGRA210_MVC_TX_STATUS: 675 case TEGRA210_MVC_TX_INT_STATUS: 676 case TEGRA210_MVC_TX_INT_SET: 677 678 case TEGRA210_MVC_SOFT_RESET: 679 case TEGRA210_MVC_STATUS: 680 case TEGRA210_MVC_INT_STATUS: 681 case TEGRA210_MVC_SWITCH: 682 case TEGRA210_MVC_CFG_RAM_CTRL: 683 case TEGRA210_MVC_CFG_RAM_DATA: 684 case TEGRA210_MVC_PEAK_VALUE: 685 case TEGRA210_MVC_CTRL: 686 return true; 687 default: 688 return false; 689 } 690 } 691 692 static const struct regmap_config tegra210_mvc_regmap_config = { 693 .reg_bits = 32, 694 .reg_stride = 4, 695 .val_bits = 32, 696 .max_register = TEGRA210_MVC_CONFIG_ERR_TYPE, 697 .writeable_reg = tegra210_mvc_wr_reg, 698 .readable_reg = tegra210_mvc_rd_reg, 699 .volatile_reg = tegra210_mvc_volatile_reg, 700 .reg_defaults = tegra210_mvc_reg_defaults, 701 .num_reg_defaults = ARRAY_SIZE(tegra210_mvc_reg_defaults), 702 .cache_type = REGCACHE_FLAT, 703 }; 704 705 static const struct of_device_id tegra210_mvc_of_match[] = { 706 { .compatible = "nvidia,tegra210-mvc" }, 707 {}, 708 }; 709 MODULE_DEVICE_TABLE(of, tegra210_mvc_of_match); 710 711 static int tegra210_mvc_platform_probe(struct platform_device *pdev) 712 { 713 struct device *dev = &pdev->dev; 714 struct tegra210_mvc *mvc; 715 void __iomem *regs; 716 int err; 717 718 mvc = devm_kzalloc(dev, sizeof(*mvc), GFP_KERNEL); 719 if (!mvc) 720 return -ENOMEM; 721 722 dev_set_drvdata(dev, mvc); 723 724 mvc->curve_type = CURVE_LINEAR; 725 mvc->ctrl_value = TEGRA210_MVC_CTRL_DEFAULT; 726 727 regs = devm_platform_ioremap_resource(pdev, 0); 728 if (IS_ERR(regs)) 729 return PTR_ERR(regs); 730 731 mvc->regmap = devm_regmap_init_mmio(dev, regs, 732 &tegra210_mvc_regmap_config); 733 if (IS_ERR(mvc->regmap)) { 734 dev_err(dev, "regmap init failed\n"); 735 return PTR_ERR(mvc->regmap); 736 } 737 738 regcache_cache_only(mvc->regmap, true); 739 740 err = devm_snd_soc_register_component(dev, &tegra210_mvc_cmpnt, 741 tegra210_mvc_dais, 742 ARRAY_SIZE(tegra210_mvc_dais)); 743 if (err) { 744 dev_err(dev, "can't register MVC component, err: %d\n", err); 745 return err; 746 } 747 748 pm_runtime_enable(dev); 749 750 tegra210_mvc_reset_vol_settings(mvc, &pdev->dev); 751 752 return 0; 753 } 754 755 static void tegra210_mvc_platform_remove(struct platform_device *pdev) 756 { 757 pm_runtime_disable(&pdev->dev); 758 } 759 760 static const struct dev_pm_ops tegra210_mvc_pm_ops = { 761 SET_RUNTIME_PM_OPS(tegra210_mvc_runtime_suspend, 762 tegra210_mvc_runtime_resume, NULL) 763 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 764 pm_runtime_force_resume) 765 }; 766 767 static struct platform_driver tegra210_mvc_driver = { 768 .driver = { 769 .name = "tegra210-mvc", 770 .of_match_table = tegra210_mvc_of_match, 771 .pm = &tegra210_mvc_pm_ops, 772 }, 773 .probe = tegra210_mvc_platform_probe, 774 .remove = tegra210_mvc_platform_remove, 775 }; 776 module_platform_driver(tegra210_mvc_driver) 777 778 MODULE_AUTHOR("Arun Shamanna Lakshmi <aruns@nvidia.com>"); 779 MODULE_DESCRIPTION("Tegra210 MVC ASoC driver"); 780 MODULE_LICENSE("GPL v2"); 781