553 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2// SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.3//4// tegra186_dspk.c - Tegra186 DSPK driver5 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 20static 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 28static 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 39static 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 54static 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 65static 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 80static 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 91static 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 106static 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 117static 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 132static 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 143static 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 158static 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 169static 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 184static 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 196static 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 213static 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 to275 * codec by sigma delta modulator. Finally the clock rate is a multiple276 * 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 303static const struct snd_soc_dai_ops tegra186_dspk_dai_ops = {304 .hw_params = tegra186_dspk_hw_params,305};306 307static 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 334static 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 339static 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 347static const char * const tegra186_dspk_ch_sel_text[] = {348 "Left", "Right", "Stereo",349};350 351static 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 355static const char * const tegra186_dspk_osr_text[] = {356 "OSR_32", "OSR_64", "OSR_128", "OSR_256",357};358 359static 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 363static const char * const tegra186_dspk_lrsel_text[] = {364 "Left", "Right",365};366 367static const char * const tegra186_dspk_mono_conv_text[] = {368 "Zero", "Copy",369};370 371static 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 376static const char * const tegra186_dspk_stereo_conv_text[] = {377 "CH0", "CH1", "AVG",378};379 380static 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 385static 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 389static 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 407static 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 416static 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 428static 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 444static 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 457static 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 470static const struct of_device_id tegra186_dspk_of_match[] = {471 { .compatible = "nvidia,tegra186-dspk" },472 {},473};474MODULE_DEVICE_TABLE(of, tegra186_dspk_of_match);475 476static 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 526static void tegra186_dspk_platform_remove(struct platform_device *pdev)527{528 pm_runtime_disable(&pdev->dev);529}530 531static 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 538static 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 = tegra186_dspk_platform_remove,546};547module_platform_driver(tegra186_dspk_driver);548 549MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>");550MODULE_AUTHOR("Sameer Pujar <spujar@nvidia.com>");551MODULE_DESCRIPTION("Tegra186 ASoC DSPK driver");552MODULE_LICENSE("GPL v2");553