1 // SPDX-License-Identifier: GPL-2.0-only 2 // SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 // 4 // tegra186_dspk.c - Tegra186 DSPK driver 5 6 #include <linux/clk.h> 7 #include <linux/device.h> 8 #include <linux/mod_devicetable.h> 9 #include <linux/module.h> 10 #include <linux/of.h> 11 #include <linux/platform_device.h> 12 #include <linux/pm_runtime.h> 13 #include <linux/regmap.h> 14 #include <sound/core.h> 15 #include <sound/pcm_params.h> 16 #include <sound/soc.h> 17 #include "tegra186_dspk.h" 18 #include "tegra_cif.h" 19 20 static const struct reg_default tegra186_dspk_reg_defaults[] = { 21 { TEGRA186_DSPK_RX_INT_MASK, 0x00000007 }, 22 { TEGRA186_DSPK_RX_CIF_CTRL, 0x00007700 }, 23 { TEGRA186_DSPK_CG, 0x00000001 }, 24 { TEGRA186_DSPK_CORE_CTRL, 0x00000310 }, 25 { TEGRA186_DSPK_CODEC_CTRL, 0x03000000 }, 26 }; 27 28 static int tegra186_dspk_get_fifo_th(struct snd_kcontrol *kcontrol, 29 struct snd_ctl_elem_value *ucontrol) 30 { 31 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 32 struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec); 33 34 ucontrol->value.integer.value[0] = dspk->rx_fifo_th; 35 36 return 0; 37 } 38 39 static int tegra186_dspk_put_fifo_th(struct snd_kcontrol *kcontrol, 40 struct snd_ctl_elem_value *ucontrol) 41 { 42 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 43 struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec); 44 int value = ucontrol->value.integer.value[0]; 45 46 if (value == dspk->rx_fifo_th) 47 return 0; 48 49 dspk->rx_fifo_th = value; 50 51 return 1; 52 } 53 54 static int tegra186_dspk_get_osr_val(struct snd_kcontrol *kcontrol, 55 struct snd_ctl_elem_value *ucontrol) 56 { 57 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 58 struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec); 59 60 ucontrol->value.enumerated.item[0] = dspk->osr_val; 61 62 return 0; 63 } 64 65 static int tegra186_dspk_put_osr_val(struct snd_kcontrol *kcontrol, 66 struct snd_ctl_elem_value *ucontrol) 67 { 68 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 69 struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec); 70 unsigned int value = ucontrol->value.enumerated.item[0]; 71 72 if (value == dspk->osr_val) 73 return 0; 74 75 dspk->osr_val = value; 76 77 return 1; 78 } 79 80 static int tegra186_dspk_get_pol_sel(struct snd_kcontrol *kcontrol, 81 struct snd_ctl_elem_value *ucontrol) 82 { 83 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 84 struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec); 85 86 ucontrol->value.enumerated.item[0] = dspk->lrsel; 87 88 return 0; 89 } 90 91 static int tegra186_dspk_put_pol_sel(struct snd_kcontrol *kcontrol, 92 struct snd_ctl_elem_value *ucontrol) 93 { 94 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 95 struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec); 96 unsigned int value = ucontrol->value.enumerated.item[0]; 97 98 if (value == dspk->lrsel) 99 return 0; 100 101 dspk->lrsel = value; 102 103 return 1; 104 } 105 106 static int tegra186_dspk_get_ch_sel(struct snd_kcontrol *kcontrol, 107 struct snd_ctl_elem_value *ucontrol) 108 { 109 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 110 struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec); 111 112 ucontrol->value.enumerated.item[0] = dspk->ch_sel; 113 114 return 0; 115 } 116 117 static int tegra186_dspk_put_ch_sel(struct snd_kcontrol *kcontrol, 118 struct snd_ctl_elem_value *ucontrol) 119 { 120 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 121 struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec); 122 unsigned int value = ucontrol->value.enumerated.item[0]; 123 124 if (value == dspk->ch_sel) 125 return 0; 126 127 dspk->ch_sel = value; 128 129 return 1; 130 } 131 132 static int tegra186_dspk_get_mono_to_stereo(struct snd_kcontrol *kcontrol, 133 struct snd_ctl_elem_value *ucontrol) 134 { 135 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 136 struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec); 137 138 ucontrol->value.enumerated.item[0] = dspk->mono_to_stereo; 139 140 return 0; 141 } 142 143 static int tegra186_dspk_put_mono_to_stereo(struct snd_kcontrol *kcontrol, 144 struct snd_ctl_elem_value *ucontrol) 145 { 146 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 147 struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec); 148 unsigned int value = ucontrol->value.enumerated.item[0]; 149 150 if (value == dspk->mono_to_stereo) 151 return 0; 152 153 dspk->mono_to_stereo = value; 154 155 return 1; 156 } 157 158 static int tegra186_dspk_get_stereo_to_mono(struct snd_kcontrol *kcontrol, 159 struct snd_ctl_elem_value *ucontrol) 160 { 161 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 162 struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec); 163 164 ucontrol->value.enumerated.item[0] = dspk->stereo_to_mono; 165 166 return 0; 167 } 168 169 static int tegra186_dspk_put_stereo_to_mono(struct snd_kcontrol *kcontrol, 170 struct snd_ctl_elem_value *ucontrol) 171 { 172 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 173 struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec); 174 unsigned int value = ucontrol->value.enumerated.item[0]; 175 176 if (value == dspk->stereo_to_mono) 177 return 0; 178 179 dspk->stereo_to_mono = value; 180 181 return 1; 182 } 183 184 static int __maybe_unused tegra186_dspk_runtime_suspend(struct device *dev) 185 { 186 struct tegra186_dspk *dspk = dev_get_drvdata(dev); 187 188 regcache_cache_only(dspk->regmap, true); 189 regcache_mark_dirty(dspk->regmap); 190 191 clk_disable_unprepare(dspk->clk_dspk); 192 193 return 0; 194 } 195 196 static int __maybe_unused tegra186_dspk_runtime_resume(struct device *dev) 197 { 198 struct tegra186_dspk *dspk = dev_get_drvdata(dev); 199 int err; 200 201 err = clk_prepare_enable(dspk->clk_dspk); 202 if (err) { 203 dev_err(dev, "failed to enable DSPK clock, err: %d\n", err); 204 return err; 205 } 206 207 regcache_cache_only(dspk->regmap, false); 208 regcache_sync(dspk->regmap); 209 210 return 0; 211 } 212 213 static int tegra186_dspk_hw_params(struct snd_pcm_substream *substream, 214 struct snd_pcm_hw_params *params, 215 struct snd_soc_dai *dai) 216 { 217 struct tegra186_dspk *dspk = snd_soc_dai_get_drvdata(dai); 218 unsigned int channels, srate, dspk_clk; 219 struct device *dev = dai->dev; 220 struct tegra_cif_conf cif_conf; 221 unsigned int max_th; 222 int err; 223 224 memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); 225 226 channels = params_channels(params); 227 cif_conf.audio_ch = channels; 228 229 /* Client channel */ 230 switch (dspk->ch_sel) { 231 case DSPK_CH_SELECT_LEFT: 232 case DSPK_CH_SELECT_RIGHT: 233 cif_conf.client_ch = 1; 234 break; 235 case DSPK_CH_SELECT_STEREO: 236 cif_conf.client_ch = 2; 237 break; 238 default: 239 dev_err(dev, "Invalid DSPK client channels\n"); 240 return -EINVAL; 241 } 242 243 switch (params_format(params)) { 244 case SNDRV_PCM_FORMAT_S16_LE: 245 cif_conf.audio_bits = TEGRA_ACIF_BITS_16; 246 cif_conf.client_bits = TEGRA_ACIF_BITS_16; 247 break; 248 case SNDRV_PCM_FORMAT_S32_LE: 249 cif_conf.audio_bits = TEGRA_ACIF_BITS_32; 250 cif_conf.client_bits = TEGRA_ACIF_BITS_24; 251 break; 252 default: 253 dev_err(dev, "unsupported format!\n"); 254 return -EOPNOTSUPP; 255 } 256 257 srate = params_rate(params); 258 259 /* RX FIFO threshold in terms of frames */ 260 max_th = (TEGRA186_DSPK_RX_FIFO_DEPTH / cif_conf.audio_ch) - 1; 261 262 if (dspk->rx_fifo_th > max_th) 263 dspk->rx_fifo_th = max_th; 264 265 cif_conf.threshold = dspk->rx_fifo_th; 266 cif_conf.mono_conv = dspk->mono_to_stereo; 267 cif_conf.stereo_conv = dspk->stereo_to_mono; 268 269 tegra_set_cif(dspk->regmap, TEGRA186_DSPK_RX_CIF_CTRL, 270 &cif_conf); 271 272 /* 273 * DSPK clock and PDM codec clock should be synchronous with 4:1 ratio, 274 * this is because it takes 4 clock cycles to send out one sample to 275 * codec by sigma delta modulator. Finally the clock rate is a multiple 276 * of 'Over Sampling Ratio', 'Sample Rate' and 'Interface Clock Ratio'. 277 */ 278 dspk_clk = (DSPK_OSR_FACTOR << dspk->osr_val) * srate * DSPK_CLK_RATIO; 279 280 err = clk_set_rate(dspk->clk_dspk, dspk_clk); 281 if (err) { 282 dev_err(dev, "can't set DSPK clock rate %u, err: %d\n", 283 dspk_clk, err); 284 285 return err; 286 } 287 288 regmap_update_bits(dspk->regmap, 289 /* Reg */ 290 TEGRA186_DSPK_CORE_CTRL, 291 /* Mask */ 292 TEGRA186_DSPK_OSR_MASK | 293 TEGRA186_DSPK_CHANNEL_SELECT_MASK | 294 TEGRA186_DSPK_CTRL_LRSEL_POLARITY_MASK, 295 /* Value */ 296 (dspk->osr_val << DSPK_OSR_SHIFT) | 297 ((dspk->ch_sel + 1) << CH_SEL_SHIFT) | 298 (dspk->lrsel << LRSEL_POL_SHIFT)); 299 300 return 0; 301 } 302 303 static const struct snd_soc_dai_ops tegra186_dspk_dai_ops = { 304 .hw_params = tegra186_dspk_hw_params, 305 }; 306 307 static struct snd_soc_dai_driver tegra186_dspk_dais[] = { 308 { 309 .name = "DSPK-CIF", 310 .playback = { 311 .stream_name = "CIF-Playback", 312 .channels_min = 1, 313 .channels_max = 2, 314 .rates = SNDRV_PCM_RATE_8000_48000, 315 .formats = SNDRV_PCM_FMTBIT_S16_LE | 316 SNDRV_PCM_FMTBIT_S32_LE, 317 }, 318 }, 319 { 320 .name = "DSPK-DAP", 321 .playback = { 322 .stream_name = "DAP-Playback", 323 .channels_min = 1, 324 .channels_max = 2, 325 .rates = SNDRV_PCM_RATE_8000_48000, 326 .formats = SNDRV_PCM_FMTBIT_S16_LE | 327 SNDRV_PCM_FMTBIT_S32_LE, 328 }, 329 .ops = &tegra186_dspk_dai_ops, 330 .symmetric_rate = 1, 331 }, 332 }; 333 334 static const struct snd_soc_dapm_widget tegra186_dspk_widgets[] = { 335 SND_SOC_DAPM_AIF_IN("RX", NULL, 0, TEGRA186_DSPK_ENABLE, 0, 0), 336 SND_SOC_DAPM_SPK("SPK", NULL), 337 }; 338 339 static const struct snd_soc_dapm_route tegra186_dspk_routes[] = { 340 { "XBAR-Playback", NULL, "XBAR-TX" }, 341 { "CIF-Playback", NULL, "XBAR-Playback" }, 342 { "RX", NULL, "CIF-Playback" }, 343 { "DAP-Playback", NULL, "RX" }, 344 { "SPK", NULL, "DAP-Playback" }, 345 }; 346 347 static const char * const tegra186_dspk_ch_sel_text[] = { 348 "Left", "Right", "Stereo", 349 }; 350 351 static const struct soc_enum tegra186_dspk_ch_sel_enum = 352 SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_ch_sel_text), 353 tegra186_dspk_ch_sel_text); 354 355 static const char * const tegra186_dspk_osr_text[] = { 356 "OSR_32", "OSR_64", "OSR_128", "OSR_256", 357 }; 358 359 static const struct soc_enum tegra186_dspk_osr_enum = 360 SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_osr_text), 361 tegra186_dspk_osr_text); 362 363 static const char * const tegra186_dspk_lrsel_text[] = { 364 "Left", "Right", 365 }; 366 367 static const char * const tegra186_dspk_mono_conv_text[] = { 368 "Zero", "Copy", 369 }; 370 371 static const struct soc_enum tegra186_dspk_mono_conv_enum = 372 SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 373 ARRAY_SIZE(tegra186_dspk_mono_conv_text), 374 tegra186_dspk_mono_conv_text); 375 376 static const char * const tegra186_dspk_stereo_conv_text[] = { 377 "CH0", "CH1", "AVG", 378 }; 379 380 static const struct soc_enum tegra186_dspk_stereo_conv_enum = 381 SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 382 ARRAY_SIZE(tegra186_dspk_stereo_conv_text), 383 tegra186_dspk_stereo_conv_text); 384 385 static const struct soc_enum tegra186_dspk_lrsel_enum = 386 SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_lrsel_text), 387 tegra186_dspk_lrsel_text); 388 389 static const struct snd_kcontrol_new tegrat186_dspk_controls[] = { 390 SOC_SINGLE_EXT("FIFO Threshold", SND_SOC_NOPM, 0, 391 TEGRA186_DSPK_RX_FIFO_DEPTH - 1, 0, 392 tegra186_dspk_get_fifo_th, tegra186_dspk_put_fifo_th), 393 SOC_ENUM_EXT("OSR Value", tegra186_dspk_osr_enum, 394 tegra186_dspk_get_osr_val, tegra186_dspk_put_osr_val), 395 SOC_ENUM_EXT("LR Polarity Select", tegra186_dspk_lrsel_enum, 396 tegra186_dspk_get_pol_sel, tegra186_dspk_put_pol_sel), 397 SOC_ENUM_EXT("Channel Select", tegra186_dspk_ch_sel_enum, 398 tegra186_dspk_get_ch_sel, tegra186_dspk_put_ch_sel), 399 SOC_ENUM_EXT("Mono To Stereo", tegra186_dspk_mono_conv_enum, 400 tegra186_dspk_get_mono_to_stereo, 401 tegra186_dspk_put_mono_to_stereo), 402 SOC_ENUM_EXT("Stereo To Mono", tegra186_dspk_stereo_conv_enum, 403 tegra186_dspk_get_stereo_to_mono, 404 tegra186_dspk_put_stereo_to_mono), 405 }; 406 407 static const struct snd_soc_component_driver tegra186_dspk_cmpnt = { 408 .dapm_widgets = tegra186_dspk_widgets, 409 .num_dapm_widgets = ARRAY_SIZE(tegra186_dspk_widgets), 410 .dapm_routes = tegra186_dspk_routes, 411 .num_dapm_routes = ARRAY_SIZE(tegra186_dspk_routes), 412 .controls = tegrat186_dspk_controls, 413 .num_controls = ARRAY_SIZE(tegrat186_dspk_controls), 414 }; 415 416 static bool tegra186_dspk_wr_reg(struct device *dev, unsigned int reg) 417 { 418 switch (reg) { 419 case TEGRA186_DSPK_RX_INT_MASK ... TEGRA186_DSPK_RX_CIF_CTRL: 420 case TEGRA186_DSPK_ENABLE ... TEGRA186_DSPK_CG: 421 case TEGRA186_DSPK_CORE_CTRL ... TEGRA186_DSPK_CODEC_CTRL: 422 return true; 423 default: 424 return false; 425 } 426 } 427 428 static bool tegra186_dspk_rd_reg(struct device *dev, unsigned int reg) 429 { 430 if (tegra186_dspk_wr_reg(dev, reg)) 431 return true; 432 433 switch (reg) { 434 case TEGRA186_DSPK_RX_STATUS: 435 case TEGRA186_DSPK_RX_INT_STATUS: 436 case TEGRA186_DSPK_STATUS: 437 case TEGRA186_DSPK_INT_STATUS: 438 return true; 439 default: 440 return false; 441 } 442 } 443 444 static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg) 445 { 446 switch (reg) { 447 case TEGRA186_DSPK_RX_STATUS: 448 case TEGRA186_DSPK_RX_INT_STATUS: 449 case TEGRA186_DSPK_STATUS: 450 case TEGRA186_DSPK_INT_STATUS: 451 return true; 452 default: 453 return false; 454 } 455 } 456 457 static const struct regmap_config tegra186_dspk_regmap = { 458 .reg_bits = 32, 459 .reg_stride = 4, 460 .val_bits = 32, 461 .max_register = TEGRA186_DSPK_CODEC_CTRL, 462 .writeable_reg = tegra186_dspk_wr_reg, 463 .readable_reg = tegra186_dspk_rd_reg, 464 .volatile_reg = tegra186_dspk_volatile_reg, 465 .reg_defaults = tegra186_dspk_reg_defaults, 466 .num_reg_defaults = ARRAY_SIZE(tegra186_dspk_reg_defaults), 467 .cache_type = REGCACHE_FLAT, 468 }; 469 470 static const struct of_device_id tegra186_dspk_of_match[] = { 471 { .compatible = "nvidia,tegra186-dspk" }, 472 {}, 473 }; 474 MODULE_DEVICE_TABLE(of, tegra186_dspk_of_match); 475 476 static int tegra186_dspk_platform_probe(struct platform_device *pdev) 477 { 478 struct device *dev = &pdev->dev; 479 struct tegra186_dspk *dspk; 480 void __iomem *regs; 481 int err; 482 483 dspk = devm_kzalloc(dev, sizeof(*dspk), GFP_KERNEL); 484 if (!dspk) 485 return -ENOMEM; 486 487 dspk->osr_val = DSPK_OSR_64; 488 dspk->lrsel = DSPK_LRSEL_LEFT; 489 dspk->ch_sel = DSPK_CH_SELECT_STEREO; 490 dspk->mono_to_stereo = 0; /* "Zero" */ 491 492 dev_set_drvdata(dev, dspk); 493 494 dspk->clk_dspk = devm_clk_get(dev, "dspk"); 495 if (IS_ERR(dspk->clk_dspk)) { 496 dev_err(dev, "can't retrieve DSPK clock\n"); 497 return PTR_ERR(dspk->clk_dspk); 498 } 499 500 regs = devm_platform_ioremap_resource(pdev, 0); 501 if (IS_ERR(regs)) 502 return PTR_ERR(regs); 503 504 dspk->regmap = devm_regmap_init_mmio(dev, regs, &tegra186_dspk_regmap); 505 if (IS_ERR(dspk->regmap)) { 506 dev_err(dev, "regmap init failed\n"); 507 return PTR_ERR(dspk->regmap); 508 } 509 510 regcache_cache_only(dspk->regmap, true); 511 512 err = devm_snd_soc_register_component(dev, &tegra186_dspk_cmpnt, 513 tegra186_dspk_dais, 514 ARRAY_SIZE(tegra186_dspk_dais)); 515 if (err) { 516 dev_err(dev, "can't register DSPK component, err: %d\n", 517 err); 518 return err; 519 } 520 521 pm_runtime_enable(dev); 522 523 return 0; 524 } 525 526 static void tegra186_dspk_platform_remove(struct platform_device *pdev) 527 { 528 pm_runtime_disable(&pdev->dev); 529 } 530 531 static const struct dev_pm_ops tegra186_dspk_pm_ops = { 532 SET_RUNTIME_PM_OPS(tegra186_dspk_runtime_suspend, 533 tegra186_dspk_runtime_resume, NULL) 534 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 535 pm_runtime_force_resume) 536 }; 537 538 static struct platform_driver tegra186_dspk_driver = { 539 .driver = { 540 .name = "tegra186-dspk", 541 .of_match_table = tegra186_dspk_of_match, 542 .pm = &tegra186_dspk_pm_ops, 543 }, 544 .probe = tegra186_dspk_platform_probe, 545 .remove_new = tegra186_dspk_platform_remove, 546 }; 547 module_platform_driver(tegra186_dspk_driver); 548 549 MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>"); 550 MODULE_AUTHOR("Sameer Pujar <spujar@nvidia.com>"); 551 MODULE_DESCRIPTION("Tegra186 ASoC DSPK driver"); 552 MODULE_LICENSE("GPL v2"); 553
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.