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