1044 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// tegra186_asrc.c - Tegra186 ASRC driver4//5// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.6 7#include <linux/clk.h>8#include <linux/delay.h>9#include <linux/device.h>10#include <linux/io.h>11#include <linux/mod_devicetable.h>12#include <linux/module.h>13#include <linux/platform_device.h>14#include <linux/pm_runtime.h>15#include <linux/regmap.h>16#include <sound/core.h>17#include <sound/pcm.h>18#include <sound/pcm_params.h>19#include <sound/soc.h>20 21#include "tegra186_asrc.h"22#include "tegra_cif.h"23 24#define ASRC_STREAM_SOURCE_SELECT(id) \25 (TEGRA186_ASRC_CFG + ((id) * TEGRA186_ASRC_STREAM_STRIDE))26 27#define ASRC_STREAM_REG(reg, id) ((reg) + ((id) * TEGRA186_ASRC_STREAM_STRIDE))28 29#define ASRC_STREAM_REG_DEFAULTS(id) \30 { ASRC_STREAM_REG(TEGRA186_ASRC_CFG, id), \31 (((id) + 1) << 4) }, \32 { ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, id), \33 0x1 }, \34 { ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, id), \35 0x0 }, \36 { ASRC_STREAM_REG(TEGRA186_ASRC_MUTE_UNMUTE_DURATION, id), \37 0x400 }, \38 { ASRC_STREAM_REG(TEGRA186_ASRC_RX_CIF_CTRL, id), \39 0x7500 }, \40 { ASRC_STREAM_REG(TEGRA186_ASRC_TX_CIF_CTRL, id), \41 0x7500 }42 43static const struct reg_default tegra186_asrc_reg_defaults[] = {44 ASRC_STREAM_REG_DEFAULTS(0),45 ASRC_STREAM_REG_DEFAULTS(1),46 ASRC_STREAM_REG_DEFAULTS(2),47 ASRC_STREAM_REG_DEFAULTS(3),48 ASRC_STREAM_REG_DEFAULTS(4),49 ASRC_STREAM_REG_DEFAULTS(5),50 51 { TEGRA186_ASRC_GLOBAL_ENB, 0},52 { TEGRA186_ASRC_GLOBAL_SOFT_RESET, 0},53 { TEGRA186_ASRC_GLOBAL_CG, 0x1 },54 { TEGRA186_ASRC_GLOBAL_CFG, 0x0 },55 { TEGRA186_ASRC_GLOBAL_SCRATCH_ADDR, 0},56 { TEGRA186_ASRC_GLOBAL_SCRATCH_CFG, 0x0c207980 },57 { TEGRA186_ASRC_RATIO_UPD_RX_CIF_CTRL, 0x00115500 },58 { TEGRA186_ASRC_GLOBAL_INT_MASK, 0x0},59 { TEGRA186_ASRC_GLOBAL_INT_SET, 0x0},60 { TEGRA186_ASRC_GLOBAL_INT_CLEAR, 0x0},61 { TEGRA186_ASRC_GLOBAL_APR_CTRL, 0x0},62 { TEGRA186_ASRC_GLOBAL_APR_CTRL_ACCESS_CTRL, 0x0},63 { TEGRA186_ASRC_GLOBAL_DISARM_APR, 0x0},64 { TEGRA186_ASRC_GLOBAL_DISARM_APR_ACCESS_CTRL, 0x0},65 { TEGRA186_ASRC_GLOBAL_RATIO_WR_ACCESS, 0x0},66 { TEGRA186_ASRC_GLOBAL_RATIO_WR_ACCESS_CTRL, 0x0},67 { TEGRA186_ASRC_CYA, 0x0},68};69 70static void tegra186_asrc_lock_stream(struct tegra186_asrc *asrc,71 unsigned int id)72{73 regmap_write(asrc->regmap,74 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_LOCK_STATUS,75 id),76 1);77}78 79static int __maybe_unused tegra186_asrc_runtime_suspend(struct device *dev)80{81 struct tegra186_asrc *asrc = dev_get_drvdata(dev);82 83 regcache_cache_only(asrc->regmap, true);84 regcache_mark_dirty(asrc->regmap);85 86 return 0;87}88 89static int __maybe_unused tegra186_asrc_runtime_resume(struct device *dev)90{91 struct tegra186_asrc *asrc = dev_get_drvdata(dev);92 int id;93 94 regcache_cache_only(asrc->regmap, false);95 96 /*97 * Below sequence is recommended after a runtime PM cycle.98 * This otherwise leads to transfer failures. The cache99 * sync is done after this to restore other settings.100 */101 regmap_write(asrc->regmap, TEGRA186_ASRC_GLOBAL_SCRATCH_ADDR,102 TEGRA186_ASRC_ARAM_START_ADDR);103 regmap_write(asrc->regmap, TEGRA186_ASRC_GLOBAL_ENB,104 TEGRA186_ASRC_GLOBAL_EN);105 106 regcache_sync(asrc->regmap);107 108 for (id = 0; id < TEGRA186_ASRC_STREAM_MAX; id++) {109 if (asrc->lane[id].ratio_source !=110 TEGRA186_ASRC_RATIO_SOURCE_SW)111 continue;112 113 regmap_write(asrc->regmap,114 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART,115 id),116 asrc->lane[id].int_part);117 118 regmap_write(asrc->regmap,119 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART,120 id),121 asrc->lane[id].frac_part);122 123 tegra186_asrc_lock_stream(asrc, id);124 }125 126 return 0;127}128 129static int tegra186_asrc_set_audio_cif(struct tegra186_asrc *asrc,130 struct snd_pcm_hw_params *params,131 unsigned int reg)132{133 int channels, audio_bits;134 struct tegra_cif_conf cif_conf;135 136 memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));137 138 channels = params_channels(params);139 140 switch (params_format(params)) {141 case SNDRV_PCM_FORMAT_S16_LE:142 audio_bits = TEGRA_ACIF_BITS_16;143 break;144 case SNDRV_PCM_FORMAT_S24_LE:145 case SNDRV_PCM_FORMAT_S32_LE:146 audio_bits = TEGRA_ACIF_BITS_32;147 break;148 default:149 return -EINVAL;150 }151 152 cif_conf.audio_ch = channels;153 cif_conf.client_ch = channels;154 cif_conf.audio_bits = audio_bits;155 cif_conf.client_bits = TEGRA_ACIF_BITS_24;156 157 tegra_set_cif(asrc->regmap, reg, &cif_conf);158 159 return 0;160}161 162static int tegra186_asrc_in_hw_params(struct snd_pcm_substream *substream,163 struct snd_pcm_hw_params *params,164 struct snd_soc_dai *dai)165{166 struct device *dev = dai->dev;167 struct tegra186_asrc *asrc = snd_soc_dai_get_drvdata(dai);168 int ret, id = dai->id;169 170 /* Set input threshold */171 regmap_write(asrc->regmap,172 ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, dai->id),173 asrc->lane[id].input_thresh);174 175 ret = tegra186_asrc_set_audio_cif(asrc, params,176 ASRC_STREAM_REG(TEGRA186_ASRC_RX_CIF_CTRL, dai->id));177 if (ret) {178 dev_err(dev, "Can't set ASRC RX%d CIF: %d\n", dai->id, ret);179 return ret;180 }181 182 return ret;183}184 185static int tegra186_asrc_out_hw_params(struct snd_pcm_substream *substream,186 struct snd_pcm_hw_params *params,187 struct snd_soc_dai *dai)188{189 struct device *dev = dai->dev;190 struct tegra186_asrc *asrc = snd_soc_dai_get_drvdata(dai);191 int ret, id = dai->id - 7;192 193 /* Set output threshold */194 regmap_write(asrc->regmap,195 ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, id),196 asrc->lane[id].output_thresh);197 198 ret = tegra186_asrc_set_audio_cif(asrc, params,199 ASRC_STREAM_REG(TEGRA186_ASRC_TX_CIF_CTRL, id));200 if (ret) {201 dev_err(dev, "Can't set ASRC TX%d CIF: %d\n", id, ret);202 return ret;203 }204 205 /* Set ENABLE_HW_RATIO_COMP */206 if (asrc->lane[id].hwcomp_disable) {207 regmap_update_bits(asrc->regmap,208 ASRC_STREAM_REG(TEGRA186_ASRC_CFG, id),209 TEGRA186_ASRC_STREAM_ENABLE_HW_RATIO_COMP_MASK,210 TEGRA186_ASRC_STREAM_ENABLE_HW_RATIO_COMP_DISABLE);211 } else {212 regmap_update_bits(asrc->regmap,213 ASRC_STREAM_REG(TEGRA186_ASRC_CFG, id),214 TEGRA186_ASRC_STREAM_ENABLE_HW_RATIO_COMP_MASK,215 TEGRA186_ASRC_STREAM_ENABLE_HW_RATIO_COMP_ENABLE);216 217 regmap_write(asrc->regmap,218 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_COMP, id),219 TEGRA186_ASRC_STREAM_DEFAULT_HW_COMP_BIAS_VALUE);220 }221 222 /* Set lock */223 regmap_update_bits(asrc->regmap,224 ASRC_STREAM_REG(TEGRA186_ASRC_CFG, id),225 1, asrc->lane[id].ratio_source);226 227 if (asrc->lane[id].ratio_source == TEGRA186_ASRC_RATIO_SOURCE_SW) {228 regmap_write(asrc->regmap,229 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, id),230 asrc->lane[id].int_part);231 regmap_write(asrc->regmap,232 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, id),233 asrc->lane[id].frac_part);234 tegra186_asrc_lock_stream(asrc, id);235 }236 237 return ret;238}239 240static int tegra186_asrc_get_ratio_source(struct snd_kcontrol *kcontrol,241 struct snd_ctl_elem_value *ucontrol)242{243 struct soc_enum *asrc_private =244 (struct soc_enum *)kcontrol->private_value;245 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);246 struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);247 unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;248 249 ucontrol->value.enumerated.item[0] = asrc->lane[id].ratio_source;250 251 return 0;252}253 254static int tegra186_asrc_put_ratio_source(struct snd_kcontrol *kcontrol,255 struct snd_ctl_elem_value *ucontrol)256{257 struct soc_enum *asrc_private =258 (struct soc_enum *)kcontrol->private_value;259 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);260 struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);261 unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;262 bool change = false;263 264 asrc->lane[id].ratio_source = ucontrol->value.enumerated.item[0];265 266 regmap_update_bits_check(asrc->regmap, asrc_private->reg,267 TEGRA186_ASRC_STREAM_RATIO_TYPE_MASK,268 asrc->lane[id].ratio_source,269 &change);270 271 return change ? 1 : 0;272}273 274static int tegra186_asrc_get_ratio_int(struct snd_kcontrol *kcontrol,275 struct snd_ctl_elem_value *ucontrol)276{277 struct soc_mixer_control *asrc_private =278 (struct soc_mixer_control *)kcontrol->private_value;279 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);280 struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);281 unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;282 283 regmap_read(asrc->regmap,284 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, id),285 &asrc->lane[id].int_part);286 287 ucontrol->value.integer.value[0] = asrc->lane[id].int_part;288 289 return 0;290}291 292static int tegra186_asrc_put_ratio_int(struct snd_kcontrol *kcontrol,293 struct snd_ctl_elem_value *ucontrol)294{295 struct soc_mixer_control *asrc_private =296 (struct soc_mixer_control *)kcontrol->private_value;297 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);298 struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);299 unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;300 bool change = false;301 302 if (asrc->lane[id].ratio_source == TEGRA186_ASRC_RATIO_SOURCE_ARAD) {303 dev_err(cmpnt->dev,304 "Lane %d ratio source is ARAD, invalid SW update\n",305 id);306 return -EINVAL;307 }308 309 asrc->lane[id].int_part = ucontrol->value.integer.value[0];310 311 regmap_update_bits_check(asrc->regmap,312 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART,313 id),314 TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK,315 asrc->lane[id].int_part, &change);316 317 tegra186_asrc_lock_stream(asrc, id);318 319 return change ? 1 : 0;320}321 322static int tegra186_asrc_get_ratio_frac(struct snd_kcontrol *kcontrol,323 struct snd_ctl_elem_value *ucontrol)324{325 struct soc_mreg_control *asrc_private =326 (struct soc_mreg_control *)kcontrol->private_value;327 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);328 struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);329 unsigned int id = asrc_private->regbase / TEGRA186_ASRC_STREAM_STRIDE;330 331 regmap_read(asrc->regmap,332 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, id),333 &asrc->lane[id].frac_part);334 335 ucontrol->value.integer.value[0] = asrc->lane[id].frac_part;336 337 return 0;338}339 340static int tegra186_asrc_put_ratio_frac(struct snd_kcontrol *kcontrol,341 struct snd_ctl_elem_value *ucontrol)342{343 struct soc_mreg_control *asrc_private =344 (struct soc_mreg_control *)kcontrol->private_value;345 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);346 struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);347 unsigned int id = asrc_private->regbase / TEGRA186_ASRC_STREAM_STRIDE;348 bool change = false;349 350 if (asrc->lane[id].ratio_source == TEGRA186_ASRC_RATIO_SOURCE_ARAD) {351 dev_err(cmpnt->dev,352 "Lane %d ratio source is ARAD, invalid SW update\n",353 id);354 return -EINVAL;355 }356 357 asrc->lane[id].frac_part = ucontrol->value.integer.value[0];358 359 regmap_update_bits_check(asrc->regmap,360 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART,361 id),362 TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK,363 asrc->lane[id].frac_part, &change);364 365 tegra186_asrc_lock_stream(asrc, id);366 367 return change ? 1 : 0;368}369 370static int tegra186_asrc_get_hwcomp_disable(struct snd_kcontrol *kcontrol,371 struct snd_ctl_elem_value *ucontrol)372{373 struct soc_mixer_control *asrc_private =374 (struct soc_mixer_control *)kcontrol->private_value;375 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);376 struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);377 unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;378 379 ucontrol->value.integer.value[0] = asrc->lane[id].hwcomp_disable;380 381 return 0;382}383 384static int tegra186_asrc_put_hwcomp_disable(struct snd_kcontrol *kcontrol,385 struct snd_ctl_elem_value *ucontrol)386{387 struct soc_mixer_control *asrc_private =388 (struct soc_mixer_control *)kcontrol->private_value;389 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);390 struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);391 unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;392 int value = ucontrol->value.integer.value[0];393 394 if (value == asrc->lane[id].hwcomp_disable)395 return 0;396 397 asrc->lane[id].hwcomp_disable = value;398 399 return 1;400}401 402static int tegra186_asrc_get_input_threshold(struct snd_kcontrol *kcontrol,403 struct snd_ctl_elem_value *ucontrol)404{405 struct soc_mixer_control *asrc_private =406 (struct soc_mixer_control *)kcontrol->private_value;407 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);408 struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);409 unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;410 411 ucontrol->value.integer.value[0] = (asrc->lane[id].input_thresh & 0x3);412 413 return 0;414}415 416static int tegra186_asrc_put_input_threshold(struct snd_kcontrol *kcontrol,417 struct snd_ctl_elem_value *ucontrol)418{419 struct soc_mixer_control *asrc_private =420 (struct soc_mixer_control *)kcontrol->private_value;421 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);422 struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);423 unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;424 int value = (asrc->lane[id].input_thresh & ~(0x3)) |425 ucontrol->value.integer.value[0];426 427 if (value == asrc->lane[id].input_thresh)428 return 0;429 430 asrc->lane[id].input_thresh = value;431 432 return 1;433}434 435static int tegra186_asrc_get_output_threshold(struct snd_kcontrol *kcontrol,436 struct snd_ctl_elem_value *ucontrol)437{438 struct soc_mixer_control *asrc_private =439 (struct soc_mixer_control *)kcontrol->private_value;440 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);441 struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);442 unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;443 444 ucontrol->value.integer.value[0] = (asrc->lane[id].output_thresh & 0x3);445 446 return 0;447}448 449static int tegra186_asrc_put_output_threshold(struct snd_kcontrol *kcontrol,450 struct snd_ctl_elem_value *ucontrol)451{452 struct soc_mixer_control *asrc_private =453 (struct soc_mixer_control *)kcontrol->private_value;454 struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);455 struct tegra186_asrc *asrc = snd_soc_component_get_drvdata(cmpnt);456 unsigned int id = asrc_private->reg / TEGRA186_ASRC_STREAM_STRIDE;457 int value = (asrc->lane[id].output_thresh & ~(0x3)) |458 ucontrol->value.integer.value[0];459 460 if (value == asrc->lane[id].output_thresh)461 return 0;462 463 asrc->lane[id].output_thresh = value;464 465 return 1;466}467 468static int tegra186_asrc_widget_event(struct snd_soc_dapm_widget *w,469 struct snd_kcontrol *kcontrol, int event)470{471 struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);472 struct tegra186_asrc *asrc = dev_get_drvdata(cmpnt->dev);473 unsigned int id =474 (w->reg - TEGRA186_ASRC_ENABLE) / TEGRA186_ASRC_STREAM_STRIDE;475 476 regmap_write(asrc->regmap,477 ASRC_STREAM_REG(TEGRA186_ASRC_SOFT_RESET, id),478 0x1);479 480 return 0;481}482 483static const struct snd_soc_dai_ops tegra186_asrc_in_dai_ops = {484 .hw_params = tegra186_asrc_in_hw_params,485};486 487static const struct snd_soc_dai_ops tegra186_asrc_out_dai_ops = {488 .hw_params = tegra186_asrc_out_hw_params,489};490 491#define IN_DAI(id) \492 { \493 .name = "ASRC-RX-CIF"#id, \494 .playback = { \495 .stream_name = "RX" #id "-CIF-Playback",\496 .channels_min = 1, \497 .channels_max = 12, \498 .rates = SNDRV_PCM_RATE_8000_192000, \499 .formats = SNDRV_PCM_FMTBIT_S8 | \500 SNDRV_PCM_FMTBIT_S16_LE | \501 SNDRV_PCM_FMTBIT_S24_LE | \502 SNDRV_PCM_FMTBIT_S32_LE, \503 }, \504 .capture = { \505 .stream_name = "RX" #id "-CIF-Capture", \506 .channels_min = 1, \507 .channels_max = 12, \508 .rates = SNDRV_PCM_RATE_8000_192000, \509 .formats = SNDRV_PCM_FMTBIT_S8 | \510 SNDRV_PCM_FMTBIT_S16_LE | \511 SNDRV_PCM_FMTBIT_S24_LE | \512 SNDRV_PCM_FMTBIT_S32_LE, \513 }, \514 .ops = &tegra186_asrc_in_dai_ops, \515 }516 517#define OUT_DAI(id) \518 { \519 .name = "ASRC-TX-CIF"#id, \520 .playback = { \521 .stream_name = "TX" #id "-CIF-Playback",\522 .channels_min = 1, \523 .channels_max = 12, \524 .rates = SNDRV_PCM_RATE_8000_192000, \525 .formats = SNDRV_PCM_FMTBIT_S8 | \526 SNDRV_PCM_FMTBIT_S16_LE | \527 SNDRV_PCM_FMTBIT_S24_LE | \528 SNDRV_PCM_FMTBIT_S32_LE, \529 }, \530 .capture = { \531 .stream_name = "TX" #id "-CIF-Capture", \532 .channels_min = 1, \533 .channels_max = 12, \534 .rates = SNDRV_PCM_RATE_8000_192000, \535 .formats = SNDRV_PCM_FMTBIT_S8 | \536 SNDRV_PCM_FMTBIT_S16_LE | \537 SNDRV_PCM_FMTBIT_S24_LE | \538 SNDRV_PCM_FMTBIT_S32_LE, \539 }, \540 .ops = &tegra186_asrc_out_dai_ops, \541 }542 543static struct snd_soc_dai_driver tegra186_asrc_dais[] = {544 /* ASRC Input */545 IN_DAI(1),546 IN_DAI(2),547 IN_DAI(3),548 IN_DAI(4),549 IN_DAI(5),550 IN_DAI(6),551 IN_DAI(7),552 /* ASRC Output */553 OUT_DAI(1),554 OUT_DAI(2),555 OUT_DAI(3),556 OUT_DAI(4),557 OUT_DAI(5),558 OUT_DAI(6),559};560 561static const struct snd_soc_dapm_widget tegra186_asrc_widgets[] = {562 SND_SOC_DAPM_AIF_IN("RX1", NULL, 0, SND_SOC_NOPM, 0, 0),563 SND_SOC_DAPM_AIF_IN("RX2", NULL, 0, SND_SOC_NOPM, 0, 0),564 SND_SOC_DAPM_AIF_IN("RX3", NULL, 0, SND_SOC_NOPM, 0, 0),565 SND_SOC_DAPM_AIF_IN("RX4", NULL, 0, SND_SOC_NOPM, 0, 0),566 SND_SOC_DAPM_AIF_IN("RX5", NULL, 0, SND_SOC_NOPM, 0, 0),567 SND_SOC_DAPM_AIF_IN("RX6", NULL, 0, SND_SOC_NOPM, 0, 0),568 SND_SOC_DAPM_AIF_IN("RX7", NULL, 0, SND_SOC_NOPM, 0, 0),569 570 SND_SOC_DAPM_AIF_OUT_E("TX1", NULL, 0,571 ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 0),572 TEGRA186_ASRC_STREAM_EN_SHIFT, 0,573 tegra186_asrc_widget_event,574 SND_SOC_DAPM_POST_PMD),575 576 SND_SOC_DAPM_AIF_OUT_E("TX2", NULL, 0,577 ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 1),578 TEGRA186_ASRC_STREAM_EN_SHIFT, 0,579 tegra186_asrc_widget_event,580 SND_SOC_DAPM_POST_PMD),581 582 SND_SOC_DAPM_AIF_OUT_E("TX3", NULL, 0,583 ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 2),584 TEGRA186_ASRC_STREAM_EN_SHIFT, 0,585 tegra186_asrc_widget_event,586 SND_SOC_DAPM_POST_PMD),587 588 SND_SOC_DAPM_AIF_OUT_E("TX4", NULL, 0,589 ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 3),590 TEGRA186_ASRC_STREAM_EN_SHIFT, 0,591 tegra186_asrc_widget_event,592 SND_SOC_DAPM_POST_PMD),593 594 SND_SOC_DAPM_AIF_OUT_E("TX5", NULL, 0,595 ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 4),596 TEGRA186_ASRC_STREAM_EN_SHIFT, 0,597 tegra186_asrc_widget_event,598 SND_SOC_DAPM_POST_PMD),599 600 SND_SOC_DAPM_AIF_OUT_E("TX6", NULL, 0,601 ASRC_STREAM_REG(TEGRA186_ASRC_ENABLE, 5),602 TEGRA186_ASRC_STREAM_EN_SHIFT, 0,603 tegra186_asrc_widget_event,604 SND_SOC_DAPM_POST_PMD),605 606 SND_SOC_DAPM_SPK("Depacketizer", NULL),607};608 609#define ASRC_STREAM_ROUTE(id, sname) \610 { "RX" #id " XBAR-" sname, NULL, "RX" #id " XBAR-TX" }, \611 { "RX" #id "-CIF-" sname, NULL, "RX" #id " XBAR-" sname }, \612 { "RX" #id, NULL, "RX" #id "-CIF-" sname }, \613 { "TX" #id, NULL, "RX" #id }, \614 { "TX" #id "-CIF-" sname, NULL, "TX" #id }, \615 { "TX" #id " XBAR-" sname, NULL, "TX" #id "-CIF-" sname }, \616 { "TX" #id " XBAR-RX", NULL, "TX" #id " XBAR-" sname },617 618#define ASRC_ROUTE(id) \619 ASRC_STREAM_ROUTE(id, "Playback") \620 ASRC_STREAM_ROUTE(id, "Capture")621 622#define ASRC_RATIO_ROUTE(sname) \623 { "RX7 XBAR-" sname, NULL, "RX7 XBAR-TX" }, \624 { "RX7-CIF-" sname, NULL, "RX7 XBAR-" sname }, \625 { "RX7", NULL, "RX7-CIF-" sname }, \626 { "Depacketizer", NULL, "RX7" },627 628static const struct snd_soc_dapm_route tegra186_asrc_routes[] = {629 ASRC_ROUTE(1)630 ASRC_ROUTE(2)631 ASRC_ROUTE(3)632 ASRC_ROUTE(4)633 ASRC_ROUTE(5)634 ASRC_ROUTE(6)635 ASRC_RATIO_ROUTE("Playback")636 ASRC_RATIO_ROUTE("Capture")637};638 639static const char * const tegra186_asrc_ratio_source_text[] = {640 "ARAD",641 "SW",642};643 644#define ASRC_SOURCE_DECL(name, id) \645 static const struct soc_enum name = \646 SOC_ENUM_SINGLE(ASRC_STREAM_SOURCE_SELECT(id), \647 0, 2, tegra186_asrc_ratio_source_text)648 649ASRC_SOURCE_DECL(src_select1, 0);650ASRC_SOURCE_DECL(src_select2, 1);651ASRC_SOURCE_DECL(src_select3, 2);652ASRC_SOURCE_DECL(src_select4, 3);653ASRC_SOURCE_DECL(src_select5, 4);654ASRC_SOURCE_DECL(src_select6, 5);655 656#define SOC_SINGLE_EXT_FRAC(xname, xregbase, xmax, xget, xput) \657{ \658 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \659 .name = (xname), \660 .info = snd_soc_info_xr_sx, \661 .get = xget, \662 .put = xput, \663 \664 .private_value = (unsigned long)&(struct soc_mreg_control) \665 { \666 .regbase = xregbase, \667 .regcount = 1, \668 .nbits = 32, \669 .invert = 0, \670 .min = 0, \671 .max = xmax \672 } \673}674 675static const struct snd_kcontrol_new tegra186_asrc_controls[] = {676 /* Controls for integer part of ratio */677 SOC_SINGLE_EXT("Ratio1 Integer Part",678 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 0),679 0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0,680 tegra186_asrc_get_ratio_int,681 tegra186_asrc_put_ratio_int),682 683 SOC_SINGLE_EXT("Ratio2 Integer Part",684 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 1),685 0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0,686 tegra186_asrc_get_ratio_int,687 tegra186_asrc_put_ratio_int),688 689 SOC_SINGLE_EXT("Ratio3 Integer Part",690 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 2),691 0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0,692 tegra186_asrc_get_ratio_int,693 tegra186_asrc_put_ratio_int),694 695 SOC_SINGLE_EXT("Ratio4 Integer Part",696 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 3),697 0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0,698 tegra186_asrc_get_ratio_int,699 tegra186_asrc_put_ratio_int),700 701 SOC_SINGLE_EXT("Ratio5 Integer Part",702 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 4),703 0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0,704 tegra186_asrc_get_ratio_int,705 tegra186_asrc_put_ratio_int),706 707 SOC_SINGLE_EXT("Ratio6 Integer Part",708 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_INT_PART, 5),709 0, TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK, 0,710 tegra186_asrc_get_ratio_int,711 tegra186_asrc_put_ratio_int),712 713 /* Controls for fractional part of ratio */714 SOC_SINGLE_EXT_FRAC("Ratio1 Fractional Part",715 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 0),716 TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK,717 tegra186_asrc_get_ratio_frac,718 tegra186_asrc_put_ratio_frac),719 720 SOC_SINGLE_EXT_FRAC("Ratio2 Fractional Part",721 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 1),722 TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK,723 tegra186_asrc_get_ratio_frac,724 tegra186_asrc_put_ratio_frac),725 726 SOC_SINGLE_EXT_FRAC("Ratio3 Fractional Part",727 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 2),728 TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK,729 tegra186_asrc_get_ratio_frac,730 tegra186_asrc_put_ratio_frac),731 732 SOC_SINGLE_EXT_FRAC("Ratio4 Fractional Part",733 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 3),734 TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK,735 tegra186_asrc_get_ratio_frac,736 tegra186_asrc_put_ratio_frac),737 738 SOC_SINGLE_EXT_FRAC("Ratio5 Fractional Part",739 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 4),740 TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK,741 tegra186_asrc_get_ratio_frac,742 tegra186_asrc_put_ratio_frac),743 744 SOC_SINGLE_EXT_FRAC("Ratio6 Fractional Part",745 ASRC_STREAM_REG(TEGRA186_ASRC_RATIO_FRAC_PART, 5),746 TEGRA186_ASRC_STREAM_RATIO_FRAC_PART_MASK,747 tegra186_asrc_get_ratio_frac,748 tegra186_asrc_put_ratio_frac),749 750 /* Source of ratio provider */751 SOC_ENUM_EXT("Ratio1 Source", src_select1,752 tegra186_asrc_get_ratio_source,753 tegra186_asrc_put_ratio_source),754 755 SOC_ENUM_EXT("Ratio2 Source", src_select2,756 tegra186_asrc_get_ratio_source,757 tegra186_asrc_put_ratio_source),758 759 SOC_ENUM_EXT("Ratio3 Source", src_select3,760 tegra186_asrc_get_ratio_source,761 tegra186_asrc_put_ratio_source),762 763 SOC_ENUM_EXT("Ratio4 Source", src_select4,764 tegra186_asrc_get_ratio_source,765 tegra186_asrc_put_ratio_source),766 767 SOC_ENUM_EXT("Ratio5 Source", src_select5,768 tegra186_asrc_get_ratio_source,769 tegra186_asrc_put_ratio_source),770 771 SOC_ENUM_EXT("Ratio6 Source", src_select6,772 tegra186_asrc_get_ratio_source,773 tegra186_asrc_put_ratio_source),774 775 /* Disable HW managed overflow/underflow issue at input and output */776 SOC_SINGLE_EXT("Stream1 HW Component Disable",777 ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 0), 0, 1, 0,778 tegra186_asrc_get_hwcomp_disable,779 tegra186_asrc_put_hwcomp_disable),780 781 SOC_SINGLE_EXT("Stream2 HW Component Disable",782 ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 1), 0, 1, 0,783 tegra186_asrc_get_hwcomp_disable,784 tegra186_asrc_put_hwcomp_disable),785 786 SOC_SINGLE_EXT("Stream3 HW Component Disable",787 ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 2), 0, 1, 0,788 tegra186_asrc_get_hwcomp_disable,789 tegra186_asrc_put_hwcomp_disable),790 791 SOC_SINGLE_EXT("Stream4 HW Component Disable",792 ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 3), 0, 1, 0,793 tegra186_asrc_get_hwcomp_disable,794 tegra186_asrc_put_hwcomp_disable),795 796 SOC_SINGLE_EXT("Stream5 HW Component Disable",797 ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 4), 0, 1, 0,798 tegra186_asrc_get_hwcomp_disable,799 tegra186_asrc_put_hwcomp_disable),800 801 SOC_SINGLE_EXT("Stream6 HW Component Disable",802 ASRC_STREAM_REG(TEGRA186_ASRC_CFG, 5), 0, 1, 0,803 tegra186_asrc_get_hwcomp_disable,804 tegra186_asrc_put_hwcomp_disable),805 806 /* Input threshold for watermark fields */807 SOC_SINGLE_EXT("Stream1 Input Threshold",808 ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 0), 0, 3, 0,809 tegra186_asrc_get_input_threshold,810 tegra186_asrc_put_input_threshold),811 812 SOC_SINGLE_EXT("Stream2 Input Threshold",813 ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 1), 0, 3, 0,814 tegra186_asrc_get_input_threshold,815 tegra186_asrc_put_input_threshold),816 817 SOC_SINGLE_EXT("Stream3 Input Threshold",818 ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 2), 0, 3, 0,819 tegra186_asrc_get_input_threshold,820 tegra186_asrc_put_input_threshold),821 822 SOC_SINGLE_EXT("Stream4 Input Threshold",823 ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 3), 0, 3, 0,824 tegra186_asrc_get_input_threshold,825 tegra186_asrc_put_input_threshold),826 827 SOC_SINGLE_EXT("Stream5 Input Threshold",828 ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 4), 0, 3, 0,829 tegra186_asrc_get_input_threshold,830 tegra186_asrc_put_input_threshold),831 832 SOC_SINGLE_EXT("Stream6 Input Threshold",833 ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 4), 0, 3, 0,834 tegra186_asrc_get_input_threshold,835 tegra186_asrc_put_input_threshold),836 837 /* Output threshold for watermark fields */838 SOC_SINGLE_EXT("Stream1 Output Threshold",839 ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 0), 0, 3, 0,840 tegra186_asrc_get_output_threshold,841 tegra186_asrc_put_output_threshold),842 843 SOC_SINGLE_EXT("Stream2 Output Threshold",844 ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 1), 0, 3, 0,845 tegra186_asrc_get_output_threshold,846 tegra186_asrc_put_output_threshold),847 848 SOC_SINGLE_EXT("Stream3 Output Threshold",849 ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 2), 0, 3, 0,850 tegra186_asrc_get_output_threshold,851 tegra186_asrc_put_output_threshold),852 853 SOC_SINGLE_EXT("Stream4 Output Threshold",854 ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 3), 0, 3, 0,855 tegra186_asrc_get_output_threshold,856 tegra186_asrc_put_output_threshold),857 858 SOC_SINGLE_EXT("Stream5 Output Threshold",859 ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 4), 0, 3, 0,860 tegra186_asrc_get_output_threshold,861 tegra186_asrc_put_output_threshold),862 863 SOC_SINGLE_EXT("Stream6 Output Threshold",864 ASRC_STREAM_REG(TEGRA186_ASRC_TX_THRESHOLD, 5), 0, 3, 0,865 tegra186_asrc_get_output_threshold,866 tegra186_asrc_put_output_threshold),867};868 869static const struct snd_soc_component_driver tegra186_asrc_cmpnt = {870 .dapm_widgets = tegra186_asrc_widgets,871 .num_dapm_widgets = ARRAY_SIZE(tegra186_asrc_widgets),872 .dapm_routes = tegra186_asrc_routes,873 .num_dapm_routes = ARRAY_SIZE(tegra186_asrc_routes),874 .controls = tegra186_asrc_controls,875 .num_controls = ARRAY_SIZE(tegra186_asrc_controls),876};877 878static bool tegra186_asrc_wr_reg(struct device *dev, unsigned int reg)879{880 if (reg < TEGRA186_ASRC_STREAM_LIMIT)881 reg %= TEGRA186_ASRC_STREAM_STRIDE;882 883 switch (reg) {884 case TEGRA186_ASRC_CFG ... TEGRA186_ASRC_RATIO_COMP:885 case TEGRA186_ASRC_RX_CIF_CTRL:886 case TEGRA186_ASRC_TX_CIF_CTRL:887 case TEGRA186_ASRC_ENABLE:888 case TEGRA186_ASRC_SOFT_RESET:889 case TEGRA186_ASRC_GLOBAL_ENB ... TEGRA186_ASRC_RATIO_UPD_RX_CIF_CTRL:890 case TEGRA186_ASRC_GLOBAL_INT_MASK ... TEGRA186_ASRC_GLOBAL_INT_CLEAR:891 case TEGRA186_ASRC_GLOBAL_APR_CTRL ... TEGRA186_ASRC_CYA:892 return true;893 default:894 return false;895 }896}897 898static bool tegra186_asrc_rd_reg(struct device *dev, unsigned int reg)899{900 if (reg < TEGRA186_ASRC_STREAM_LIMIT)901 reg %= TEGRA186_ASRC_STREAM_STRIDE;902 903 if (tegra186_asrc_wr_reg(dev, reg))904 return true;905 906 switch (reg) {907 case TEGRA186_ASRC_RX_STATUS:908 case TEGRA186_ASRC_TX_STATUS:909 case TEGRA186_ASRC_STATUS ... TEGRA186_ASRC_OUTSAMPLEBUF_CFG:910 case TEGRA186_ASRC_RATIO_UPD_RX_STATUS:911 case TEGRA186_ASRC_GLOBAL_STATUS ... TEGRA186_ASRC_GLOBAL_INT_STATUS:912 case TEGRA186_ASRC_GLOBAL_TRANSFER_ERROR_LOG:913 return true;914 default:915 return false;916 }917}918 919static bool tegra186_asrc_volatile_reg(struct device *dev, unsigned int reg)920{921 if (reg < TEGRA186_ASRC_STREAM_LIMIT)922 reg %= TEGRA186_ASRC_STREAM_STRIDE;923 924 switch (reg) {925 case TEGRA186_ASRC_RX_STATUS:926 case TEGRA186_ASRC_TX_STATUS:927 case TEGRA186_ASRC_SOFT_RESET:928 case TEGRA186_ASRC_RATIO_INT_PART:929 case TEGRA186_ASRC_RATIO_FRAC_PART:930 case TEGRA186_ASRC_STATUS:931 case TEGRA186_ASRC_RATIO_LOCK_STATUS:932 case TEGRA186_ASRC_RATIO_UPD_RX_STATUS:933 case TEGRA186_ASRC_GLOBAL_SOFT_RESET:934 case TEGRA186_ASRC_GLOBAL_STATUS:935 case TEGRA186_ASRC_GLOBAL_STREAM_ENABLE_STATUS:936 case TEGRA186_ASRC_GLOBAL_INT_STATUS:937 case TEGRA186_ASRC_GLOBAL_TRANSFER_ERROR_LOG:938 return true;939 default:940 return false;941 }942}943 944static const struct regmap_config tegra186_asrc_regmap_config = {945 .reg_bits = 32,946 .reg_stride = 4,947 .val_bits = 32,948 .max_register = TEGRA186_ASRC_CYA,949 .writeable_reg = tegra186_asrc_wr_reg,950 .readable_reg = tegra186_asrc_rd_reg,951 .volatile_reg = tegra186_asrc_volatile_reg,952 .reg_defaults = tegra186_asrc_reg_defaults,953 .num_reg_defaults = ARRAY_SIZE(tegra186_asrc_reg_defaults),954 .cache_type = REGCACHE_FLAT,955};956 957static const struct of_device_id tegra186_asrc_of_match[] = {958 { .compatible = "nvidia,tegra186-asrc" },959 {},960};961MODULE_DEVICE_TABLE(of, tegra186_asrc_of_match);962 963static int tegra186_asrc_platform_probe(struct platform_device *pdev)964{965 struct device *dev = &pdev->dev;966 struct tegra186_asrc *asrc;967 void __iomem *regs;968 unsigned int i;969 int err;970 971 asrc = devm_kzalloc(dev, sizeof(*asrc), GFP_KERNEL);972 if (!asrc)973 return -ENOMEM;974 975 dev_set_drvdata(dev, asrc);976 977 regs = devm_platform_ioremap_resource(pdev, 0);978 if (IS_ERR(regs))979 return PTR_ERR(regs);980 981 asrc->regmap = devm_regmap_init_mmio(dev, regs,982 &tegra186_asrc_regmap_config);983 if (IS_ERR(asrc->regmap)) {984 dev_err(dev, "regmap init failed\n");985 return PTR_ERR(asrc->regmap);986 }987 988 regcache_cache_only(asrc->regmap, true);989 990 regmap_write(asrc->regmap, TEGRA186_ASRC_GLOBAL_CFG,991 TEGRA186_ASRC_GLOBAL_CFG_FRAC_32BIT_PRECISION);992 993 /* Initialize default output srate */994 for (i = 0; i < TEGRA186_ASRC_STREAM_MAX; i++) {995 asrc->lane[i].ratio_source = TEGRA186_ASRC_RATIO_SOURCE_SW;996 asrc->lane[i].int_part = 1;997 asrc->lane[i].frac_part = 0;998 asrc->lane[i].hwcomp_disable = 0;999 asrc->lane[i].input_thresh =1000 TEGRA186_ASRC_STREAM_DEFAULT_INPUT_HW_COMP_THRESH_CFG;1001 asrc->lane[i].output_thresh =1002 TEGRA186_ASRC_STREAM_DEFAULT_OUTPUT_HW_COMP_THRESH_CFG;1003 }1004 1005 err = devm_snd_soc_register_component(dev, &tegra186_asrc_cmpnt,1006 tegra186_asrc_dais,1007 ARRAY_SIZE(tegra186_asrc_dais));1008 if (err) {1009 dev_err(dev, "can't register ASRC component, err: %d\n", err);1010 return err;1011 }1012 1013 pm_runtime_enable(dev);1014 1015 return 0;1016}1017 1018static void tegra186_asrc_platform_remove(struct platform_device *pdev)1019{1020 pm_runtime_disable(&pdev->dev);1021}1022 1023static const struct dev_pm_ops tegra186_asrc_pm_ops = {1024 SET_RUNTIME_PM_OPS(tegra186_asrc_runtime_suspend,1025 tegra186_asrc_runtime_resume, NULL)1026 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,1027 pm_runtime_force_resume)1028};1029 1030static struct platform_driver tegra186_asrc_driver = {1031 .driver = {1032 .name = "tegra186-asrc",1033 .of_match_table = tegra186_asrc_of_match,1034 .pm = &tegra186_asrc_pm_ops,1035 },1036 .probe = tegra186_asrc_platform_probe,1037 .remove = tegra186_asrc_platform_remove,1038};1039module_platform_driver(tegra186_asrc_driver)1040 1041MODULE_AUTHOR("Junghyun Kim <juskim@nvidia.com>");1042MODULE_DESCRIPTION("Tegra186 ASRC ASoC driver");1043MODULE_LICENSE("GPL");1044