diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c
index 1447985a..3cdb4bca 100644
--- a/sound/soc/tegra/tegra186_dspk.c
+++ b/sound/soc/tegra/tegra186_dspk.c
@@ -1,88 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * tegra186_dspk_alt.c - Tegra186 DSPK driver
+ * tegra186_dspk.c - Tegra186 DSPK driver
*
- * Copyright (c) 2015-2019 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
*/
+
#include
#include
-#include
#include
#include
+#include
#include
#include
#include
#include
-#include
#include
#include
-#include
-#include
-#include
-
-#include "tegra210_xbar_alt.h"
-#include "tegra186_dspk_alt.h"
-#include "ahub_unit_fpga_clock.h"
-
-#define DRV_NAME "tegra186-dspk"
+#include "tegra186_dspk.h"
+#include "tegra_cif.h"
static const struct reg_default tegra186_dspk_reg_defaults[] = {
- { TEGRA186_DSPK_AXBAR_RX_INT_MASK, 0x00000007},
- { TEGRA186_DSPK_AXBAR_RX_CIF_CTRL, 0x00007700},
- { TEGRA186_DSPK_CG, 0x00000001},
- { TEGRA186_DSPK_CORE_CTRL, 0x00000310},
- { TEGRA186_DSPK_CODEC_CTRL, 0x03000000},
- { TEGRA186_DSPK_SDM_COEF_A_2, 0x000013bb},
- { TEGRA186_DSPK_SDM_COEF_A_3, 0x00001cbf},
- { TEGRA186_DSPK_SDM_COEF_A_4, 0x000029d7},
- { TEGRA186_DSPK_SDM_COEF_A_5, 0x00003782},
- { TEGRA186_DSPK_SDM_COEF_C_1, 0x000000a6},
- { TEGRA186_DSPK_SDM_COEF_C_2, 0x00001959},
- { TEGRA186_DSPK_SDM_COEF_C_3, 0x00002b9f},
- { TEGRA186_DSPK_SDM_COEF_C_4, 0x00004218},
- { TEGRA186_DSPK_SDM_COEF_G_1, 0x00000074},
- { TEGRA186_DSPK_SDM_COEF_G_2, 0x0000007d},
+ { TEGRA186_DSPK_RX_INT_MASK, 0x00000007 },
+ { TEGRA186_DSPK_RX_CIF_CTRL, 0x00007700 },
+ { TEGRA186_DSPK_CG, 0x00000001 },
+ { TEGRA186_DSPK_CORE_CTRL, 0x00000310 },
+ { TEGRA186_DSPK_CODEC_CTRL, 0x03000000 },
};
static int tegra186_dspk_get_control(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct tegra186_dspk *dspk = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
- if (strstr(kcontrol->id.name, "Rx fifo threshold"))
+ if (strstr(kcontrol->id.name, "FIFO Threshold"))
ucontrol->value.integer.value[0] = dspk->rx_fifo_th;
else if (strstr(kcontrol->id.name, "OSR Value"))
ucontrol->value.integer.value[0] = dspk->osr_val;
+ else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+ ucontrol->value.integer.value[0] = dspk->lrsel;
+ else if (strstr(kcontrol->id.name, "Sample Rate"))
+ ucontrol->value.integer.value[0] = dspk->srate_override;
+ else if (strstr(kcontrol->id.name, "Audio Channels"))
+ ucontrol->value.integer.value[0] = dspk->audio_ch_override;
+ else if (strstr(kcontrol->id.name, "Channel Select"))
+ ucontrol->value.integer.value[0] = dspk->ch_sel;
+ else if (strstr(kcontrol->id.name, "Audio Bit Format"))
+ ucontrol->value.integer.value[0] = dspk->audio_fmt_override;
+ else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+ ucontrol->value.integer.value[0] = dspk->mono_to_stereo;
+ else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+ ucontrol->value.integer.value[0] = dspk->stereo_to_mono;
return 0;
}
static int tegra186_dspk_put_control(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct tegra186_dspk *dspk = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
int val = ucontrol->value.integer.value[0];
- if (strstr(kcontrol->id.name, "Rx fifo threshold")) {
- if (val >= 0 && val < TEGRA186_DSPK_RX_FIFO_DEPTH)
- dspk->rx_fifo_th = val;
- else
- return -EINVAL;
- } else if (strstr(kcontrol->id.name, "OSR Value"))
+ if (strstr(kcontrol->id.name, "FIFO Threshold"))
+ dspk->rx_fifo_th = val;
+ else if (strstr(kcontrol->id.name, "OSR Value"))
dspk->osr_val = val;
+ else if (strstr(kcontrol->id.name, "LR Polarity Select"))
+ dspk->lrsel = val;
+ else if (strstr(kcontrol->id.name, "Sample Rate"))
+ dspk->srate_override = val;
+ else if (strstr(kcontrol->id.name, "Audio Channels"))
+ dspk->audio_ch_override = val;
+ else if (strstr(kcontrol->id.name, "Channel Select"))
+ dspk->ch_sel = val;
+ else if (strstr(kcontrol->id.name, "Audio Bit Format"))
+ dspk->audio_fmt_override = val;
+ else if (strstr(kcontrol->id.name, "Mono To Stereo"))
+ dspk->mono_to_stereo = val;
+ else if (strstr(kcontrol->id.name, "Stereo To Mono"))
+ dspk->stereo_to_mono = val;
return 0;
}
@@ -94,8 +92,7 @@ static int tegra186_dspk_runtime_suspend(struct device *dev)
regcache_cache_only(dspk->regmap, true);
regcache_mark_dirty(dspk->regmap);
- if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga()))
- clk_disable_unprepare(dspk->clk_dspk);
+ clk_disable_unprepare(dspk->clk_dspk);
return 0;
}
@@ -103,14 +100,12 @@ static int tegra186_dspk_runtime_suspend(struct device *dev)
static int tegra186_dspk_runtime_resume(struct device *dev)
{
struct tegra186_dspk *dspk = dev_get_drvdata(dev);
- int ret;
+ int err;
- if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
- ret = clk_prepare_enable(dspk->clk_dspk);
- if (ret) {
- dev_err(dev, "clk_enable failed: %d\n", ret);
- return ret;
- }
+ err = clk_prepare_enable(dspk->clk_dspk);
+ if (err) {
+ dev_err(dev, "failed to enable DSPK clock, err: %d\n", err);
+ return err;
}
regcache_cache_only(dspk->regmap, false);
@@ -119,114 +114,129 @@ static int tegra186_dspk_runtime_resume(struct device *dev)
return 0;
}
-static int tegra186_dspk_set_audio_cif(struct tegra186_dspk *dspk,
- struct snd_pcm_hw_params *params,
- unsigned int reg, struct snd_soc_dai *dai)
+static const unsigned int tegra186_dspk_fmts[] = {
+ 0,
+ TEGRA_ACIF_BITS_16,
+ TEGRA_ACIF_BITS_32,
+};
+
+static int tegra186_dspk_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
{
- int channels, max_th;
- struct tegra210_xbar_cif_conf cif_conf;
+ struct tegra186_dspk *dspk = snd_soc_dai_get_drvdata(dai);
+ unsigned int channels, srate, dspk_clk;
struct device *dev = dai->dev;
+ struct tegra_cif_conf cif_conf;
+ unsigned int max_th;
+ int err;
+
+ memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
channels = params_channels(params);
- memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf));
- cif_conf.audio_channels = channels;
- cif_conf.client_channels = channels;
- cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_24;
+ cif_conf.audio_ch = channels;
- /* RX FIFO threshold interms of frames */
- max_th = (TEGRA186_DSPK_RX_FIFO_DEPTH / channels) - 1;
- max_th = (max_th < 0) ? 0 : max_th;
- if (dspk->rx_fifo_th > max_th) { /* error handling */
- cif_conf.threshold = max_th;
- dspk->rx_fifo_th = max_th;
- } else
- cif_conf.threshold = dspk->rx_fifo_th;
+ /* Override audio channel */
+ if (dspk->audio_ch_override)
+ cif_conf.audio_ch = dspk->audio_ch_override;
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_16;
- cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_16;
+ /* Client channel */
+ switch (dspk->ch_sel) {
+ case DSPK_CH_SELECT_LEFT:
+ case DSPK_CH_SELECT_RIGHT:
+ cif_conf.client_ch = 1;
break;
- case SNDRV_PCM_FORMAT_S32_LE:
- cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_32;
+ case DSPK_CH_SELECT_STEREO:
+ cif_conf.client_ch = 2;
break;
default:
- dev_err(dev, "Wrong format!\n");
+ dev_err(dev, "Invalid DSPK client channels\n");
return -EINVAL;
}
- tegra210_xbar_set_cif(dspk->regmap, TEGRA186_DSPK_AXBAR_RX_CIF_CTRL,
- &cif_conf);
- return 0;
-}
+ cif_conf.client_bits = TEGRA_ACIF_BITS_24;
-static int tegra186_dspk_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct device *dev = dai->dev;
- struct tegra186_dspk *dspk = snd_soc_dai_get_drvdata(dai);
- int ret;
-
- if (dspk->prod_name != NULL) {
- ret = tegra_pinctrl_config_prod(dev, dspk->prod_name);
- if (ret < 0)
- dev_warn(dev, "Failed to set %s setting\n",
- dspk->prod_name);
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+ cif_conf.client_bits = TEGRA_ACIF_BITS_16;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+ break;
+ default:
+ dev_err(dev, "unsupported format!\n");
+ return -ENOTSUPP;
}
- return 0;
-}
+ /* Audio bit format override */
+ if (dspk->audio_fmt_override)
+ cif_conf.audio_bits =
+ tegra186_dspk_fmts[dspk->audio_fmt_override];
-static int tegra186_dspk_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct device *dev = dai->dev;
- struct tegra186_dspk *dspk = snd_soc_dai_get_drvdata(dai);
- int channels, srate, ret, dspk_clk;
- int osr = dspk->osr_val;
- int interface_clk_ratio = 4; /* dspk interface clock should be fsout*4 */
-
- channels = params_channels(params);
srate = params_rate(params);
- dspk_clk = (1 << (5+osr)) * srate * interface_clk_ratio;
+ /* Sample rate override */
+ if (dspk->srate_override)
+ srate = dspk->srate_override;
- if ((tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
- program_dspk_clk(dspk_clk);
- } else {
- ret = clk_set_rate(dspk->clk_dspk, dspk_clk);
- if (ret) {
- dev_err(dev, "Can't set dspk clock rate: %d\n", ret);
- return ret;
- }
+ /* RX FIFO threshold in terms of frames */
+ max_th = (TEGRA186_DSPK_RX_FIFO_DEPTH / cif_conf.audio_ch) - 1;
+
+ if (dspk->rx_fifo_th > max_th)
+ dspk->rx_fifo_th = max_th;
+
+ cif_conf.threshold = dspk->rx_fifo_th;
+ cif_conf.mono_conv = dspk->mono_to_stereo;
+ cif_conf.stereo_conv = dspk->stereo_to_mono;
+
+ tegra_set_cif(dspk->regmap, TEGRA186_DSPK_RX_CIF_CTRL,
+ &cif_conf);
+
+ /*
+ * DSPK clock and PDM codec clock should be synchronous with 4:1 ratio,
+ * this is because it takes 4 clock cycles to send out one sample to
+ * codec by sigma delta modulator. Finally the clock rate is a multiple
+ * of 'Over Sampling Ratio', 'Sample Rate' and 'Interface Clock Ratio'.
+ */
+ dspk_clk = (DSPK_OSR_FACTOR << dspk->osr_val) * srate * DSPK_CLK_RATIO;
+
+ err = clk_set_rate(dspk->clk_dspk, dspk_clk);
+ if (err) {
+ dev_err(dev, "can't set DSPK clock rate %u, err: %d\n",
+ dspk_clk, err);
+
+ return err;
}
regmap_update_bits(dspk->regmap,
- TEGRA186_DSPK_CORE_CTRL,
- TEGRA186_DSPK_OSR_MASK,
- osr << TEGRA186_DSPK_OSR_SHIFT);
+ /* Reg */
+ TEGRA186_DSPK_CORE_CTRL,
+ /* Mask */
+ TEGRA186_DSPK_OSR_MASK |
+ TEGRA186_DSPK_CHANNEL_SELECT_MASK |
+ TEGRA186_DSPK_CTRL_LRSEL_POLARITY_MASK,
+ /* Value */
+ (dspk->osr_val << DSPK_OSR_SHIFT) |
+ ((dspk->ch_sel + 1) << CH_SEL_SHIFT) |
+ (dspk->lrsel << LRSEL_POL_SHIFT));
- regmap_update_bits(dspk->regmap,
- TEGRA186_DSPK_CORE_CTRL,
- TEGRA186_DSPK_CHANNEL_SELECT_MASK,
- ((1 << channels) - 1) <<
- TEGRA186_DSPK_CHANNEL_SELECT_SHIFT);
-
- /* program cif control register */
- ret = tegra186_dspk_set_audio_cif(dspk, params,
- TEGRA186_DSPK_AXBAR_RX_CIF_CTRL,
- dai);
-
- if (ret)
- dev_err(dev, "Can't set dspk RX CIF: %d\n", ret);
- return ret;
+ return 0;
}
-static struct snd_soc_dai_ops tegra186_dspk_dai_ops = {
+static const struct snd_soc_dai_ops tegra186_dspk_dai_ops = {
.hw_params = tegra186_dspk_hw_params,
- .startup = tegra186_dspk_startup,
};
+/*
+ * Three DAIs are exposed
+ * 1. "CIF" DAI for connecting with XBAR
+ * 2. "DAP" DAI for connecting with CODEC
+ * 3. "DUMMY_SINK" can be used when no external
+ * codec connection is available. In such case
+ * "DAP" is connected with "DUMMY_SINK"
+ * Order of these DAIs should not be changed, since DAI links in DT refer
+ * to these DAIs depending on the index.
+ */
static struct snd_soc_dai_driver tegra186_dspk_dais[] = {
{
.name = "CIF",
@@ -252,33 +262,6 @@ static struct snd_soc_dai_driver tegra186_dspk_dais[] = {
.ops = &tegra186_dspk_dai_ops,
.symmetric_rates = 1,
},
- /* The second DAI is used when the output of the DSPK is connected
- * to two mono codecs. When the output of the DSPK is connected to
- * a single stereo codec, then only the first DAI should be used.
- */
- {
- .name = "CIF2",
- .playback = {
- .stream_name = "CIF2 Receive",
- .channels_min = 1,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
- },
- },
- {
- .name = "DAP2",
- .capture = {
- .stream_name = "DAP2 Transmit",
- .channels_min = 1,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
- },
- .symmetric_rates = 1,
- },
{
.name = "DUMMY_SINK",
.playback = {
@@ -294,74 +277,107 @@ static struct snd_soc_dai_driver tegra186_dspk_dais[] = {
static const struct snd_soc_dapm_widget tegra186_dspk_widgets[] = {
SND_SOC_DAPM_AIF_OUT("DAP TX", NULL, 0, TEGRA186_DSPK_ENABLE, 0, 0),
- SND_SOC_DAPM_AIF_OUT("DAP2 TX", NULL, 0, 0, 0, 0),
SND_SOC_DAPM_SPK("Dummy Output", NULL),
};
static const struct snd_soc_dapm_route tegra186_dspk_routes[] = {
- { "DAP TX", NULL, "CIF Receive" },
+ { "DAP TX", NULL, "CIF Receive" },
{ "DAP Transmit", NULL, "DAP TX" },
- { "DAP2 TX", NULL, "CIF2 Receive" },
- { "DAP2 Transmit", NULL, "DAP2 TX" },
- { "Dummy Output", NULL, "Dummy Playback" },
+ { "Dummy Output", NULL, "Dummy Playback" },
};
+static const char * const tegra186_dspk_format_text[] = {
+ "None",
+ "16",
+ "32",
+};
+
+static const struct soc_enum tegra186_dspk_format_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_format_text),
+ tegra186_dspk_format_text);
+
+static const char * const tegra186_dspk_ch_sel_text[] = {
+ "Left", "Right", "Stereo",
+};
+
+static const struct soc_enum tegra186_dspk_ch_sel_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_ch_sel_text),
+ tegra186_dspk_ch_sel_text);
+
static const char * const tegra186_dspk_osr_text[] = {
"OSR_32", "OSR_64", "OSR_128", "OSR_256",
};
static const struct soc_enum tegra186_dspk_osr_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
- ARRAY_SIZE(tegra186_dspk_osr_text),
- tegra186_dspk_osr_text);
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_osr_text),
+ tegra186_dspk_osr_text);
-#define NV_SOC_SINGLE_RANGE_EXT(xname, xmin, xmax, xget, xput) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
- .info = snd_soc_info_xr_sx, .get = xget, .put = xput, \
- .private_value = (unsigned long)&(struct soc_mixer_control) \
- {.invert = 0, .min = xmin, .max = xmax, \
- .platform_max = xmax} \
-}
+static const char * const tegra186_dspk_lrsel_text[] = {
+ "Left", "Right",
+};
+
+static const char * const tegra186_dspk_mono_conv_text[] = {
+ "ZERO", "COPY",
+};
+
+static const struct soc_enum tegra186_dspk_mono_conv_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ ARRAY_SIZE(tegra186_dspk_mono_conv_text),
+ tegra186_dspk_mono_conv_text);
+
+static const char * const tegra186_dspk_stereo_conv_text[] = {
+ "CH0", "CH1", "AVG",
+};
+
+static const struct soc_enum tegra186_dspk_stereo_conv_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+ ARRAY_SIZE(tegra186_dspk_stereo_conv_text),
+ tegra186_dspk_stereo_conv_text);
+
+static const struct soc_enum tegra186_dspk_lrsel_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra186_dspk_lrsel_text),
+ tegra186_dspk_lrsel_text);
static const struct snd_kcontrol_new tegrat186_dspk_controls[] = {
- NV_SOC_SINGLE_RANGE_EXT("Rx fifo threshold", 0,
- TEGRA186_DSPK_RX_FIFO_DEPTH - 1, tegra186_dspk_get_control,
- tegra186_dspk_put_control),
+ SOC_SINGLE_EXT("FIFO Threshold", SND_SOC_NOPM, 0,
+ TEGRA186_DSPK_RX_FIFO_DEPTH - 1, 0,
+ tegra186_dspk_get_control, tegra186_dspk_put_control),
SOC_ENUM_EXT("OSR Value", tegra186_dspk_osr_enum,
- tegra186_dspk_get_control, tegra186_dspk_put_control),
+ tegra186_dspk_get_control, tegra186_dspk_put_control),
+ SOC_ENUM_EXT("LR Polarity Select", tegra186_dspk_lrsel_enum,
+ tegra186_dspk_get_control, tegra186_dspk_put_control),
+ SOC_SINGLE_EXT("Sample Rate", SND_SOC_NOPM, 0, 48000, 0,
+ tegra186_dspk_get_control, tegra186_dspk_put_control),
+ SOC_SINGLE_EXT("Audio Channels", SND_SOC_NOPM, 0, 2, 0,
+ tegra186_dspk_get_control, tegra186_dspk_put_control),
+ SOC_ENUM_EXT("Channel Select", tegra186_dspk_ch_sel_enum,
+ tegra186_dspk_get_control, tegra186_dspk_put_control),
+ SOC_ENUM_EXT("Audio Bit Format", tegra186_dspk_format_enum,
+ tegra186_dspk_get_control, tegra186_dspk_put_control),
+ SOC_ENUM_EXT("Mono To Stereo", tegra186_dspk_mono_conv_enum,
+ tegra186_dspk_get_control, tegra186_dspk_put_control),
+ SOC_ENUM_EXT("Stereo To Mono", tegra186_dspk_stereo_conv_enum,
+ tegra186_dspk_get_control, tegra186_dspk_put_control),
};
-static struct snd_soc_codec_driver tegra186_dspk_codec = {
- .idle_bias_off = 1,
- .component_driver = {
- .dapm_widgets = tegra186_dspk_widgets,
- .num_dapm_widgets = ARRAY_SIZE(tegra186_dspk_widgets),
- .dapm_routes = tegra186_dspk_routes,
- .num_dapm_routes = ARRAY_SIZE(tegra186_dspk_routes),
- .controls = tegrat186_dspk_controls,
- .num_controls = ARRAY_SIZE(tegrat186_dspk_controls),
- },
+static const struct snd_soc_component_driver tegra186_dspk_cmpnt = {
+ .dapm_widgets = tegra186_dspk_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tegra186_dspk_widgets),
+ .dapm_routes = tegra186_dspk_routes,
+ .num_dapm_routes = ARRAY_SIZE(tegra186_dspk_routes),
+ .controls = tegrat186_dspk_controls,
+ .num_controls = ARRAY_SIZE(tegrat186_dspk_controls),
};
-/* Regmap callback functions */
static bool tegra186_dspk_wr_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
- case TEGRA186_DSPK_AXBAR_RX_INT_MASK:
- case TEGRA186_DSPK_AXBAR_RX_INT_SET:
- case TEGRA186_DSPK_AXBAR_RX_INT_CLEAR:
- case TEGRA186_DSPK_AXBAR_RX_CIF_CTRL:
- case TEGRA186_DSPK_AXBAR_RX_CYA:
- case TEGRA186_DSPK_ENABLE:
- case TEGRA186_DSPK_SOFT_RESET:
- case TEGRA186_DSPK_CG:
+ case TEGRA186_DSPK_RX_INT_MASK ... TEGRA186_DSPK_RX_CIF_CTRL:
+ case TEGRA186_DSPK_ENABLE ... TEGRA186_DSPK_CG:
+ case TEGRA186_DSPK_CORE_CTRL ... TEGRA186_DSPK_CODEC_CTRL:
return true;
default:
- if (((reg % 4) == 0) && (reg >= TEGRA186_DSPK_CORE_CTRL) &&
- (reg <= TEGRA186_DSPK_SDM_COEF_G_2))
- return true;
- else
- return false;
+ return false;
};
}
@@ -371,27 +387,8 @@ static bool tegra186_dspk_rd_reg(struct device *dev, unsigned int reg)
return true;
switch (reg) {
- case TEGRA186_DSPK_AXBAR_RX_STATUS:
- case TEGRA186_DSPK_AXBAR_RX_INT_STATUS:
- case TEGRA186_DSPK_AXBAR_RX_CIF_FIFO_STATUS:
- case TEGRA186_DSPK_STATUS:
- case TEGRA186_DSPK_INT_STATUS:
- return true;
- default:
- if (((reg % 4) == 0) && (reg >= TEGRA186_DSPK_DEBUG_STATUS) &&
- (reg <= TEGRA186_DSPK_DEBUG_STAGE4_CNTR))
- return true;
- else
- return false;
- };
-}
-
-static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case TEGRA186_DSPK_AXBAR_RX_STATUS:
- case TEGRA186_DSPK_AXBAR_RX_INT_STATUS:
- case TEGRA186_DSPK_AXBAR_RX_CIF_FIFO_STATUS:
+ case TEGRA186_DSPK_RX_STATUS:
+ case TEGRA186_DSPK_RX_INT_STATUS:
case TEGRA186_DSPK_STATUS:
case TEGRA186_DSPK_INT_STATUS:
return true;
@@ -400,114 +397,105 @@ static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg)
};
}
-static const struct regmap_config tegra186_dspk_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = TEGRA186_DSPK_DEBUG_STAGE4_CNTR,
- .writeable_reg = tegra186_dspk_wr_reg,
- .readable_reg = tegra186_dspk_rd_reg,
- .volatile_reg = tegra186_dspk_volatile_reg,
- .precious_reg = NULL,
- .reg_defaults = tegra186_dspk_reg_defaults,
- .num_reg_defaults = ARRAY_SIZE(tegra186_dspk_reg_defaults),
- .cache_type = REGCACHE_FLAT,
+static bool tegra186_dspk_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA186_DSPK_RX_STATUS:
+ case TEGRA186_DSPK_RX_INT_STATUS:
+ case TEGRA186_DSPK_STATUS:
+ case TEGRA186_DSPK_INT_STATUS:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static const struct regmap_config tegra186_dspk_regmap = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = TEGRA186_DSPK_CODEC_CTRL,
+ .writeable_reg = tegra186_dspk_wr_reg,
+ .readable_reg = tegra186_dspk_rd_reg,
+ .volatile_reg = tegra186_dspk_volatile_reg,
+ .reg_defaults = tegra186_dspk_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(tegra186_dspk_reg_defaults),
+ .cache_type = REGCACHE_FLAT,
};
static const struct of_device_id tegra186_dspk_of_match[] = {
{ .compatible = "nvidia,tegra186-dspk" },
{},
};
+MODULE_DEVICE_TABLE(of, tegra186_dspk_of_match);
static int tegra186_dspk_platform_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct tegra186_dspk *dspk;
- struct device_node *np = pdev->dev.of_node;
- struct resource *mem;
void __iomem *regs;
- int ret = 0;
- const struct of_device_id *match;
+ int err;
- match = of_match_device(tegra186_dspk_of_match, &pdev->dev);
- if (!match) {
- dev_err(&pdev->dev, "Error: No device match found\n");
- return -ENODEV;
- }
-
- dspk = devm_kzalloc(&pdev->dev, sizeof(*dspk), GFP_KERNEL);
+ dspk = devm_kzalloc(dev, sizeof(*dspk), GFP_KERNEL);
if (!dspk)
return -ENOMEM;
- dspk->prod_name = NULL;
- dspk->rx_fifo_th = 0;
- dspk->osr_val = TEGRA186_DSPK_OSR_64;
- dev_set_drvdata(&pdev->dev, dspk);
+ dspk->osr_val = DSPK_OSR_64;
+ dspk->lrsel = DSPK_LRSEL_LEFT;
+ dspk->ch_sel = DSPK_CH_SELECT_STEREO;
+ dspk->mono_to_stereo = 0; /* "ZERO" */
- if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
- dspk->clk_dspk = devm_clk_get(&pdev->dev, "dspk");
- if (IS_ERR(dspk->clk_dspk)) {
- dev_err(&pdev->dev, "Can't retrieve dspk clock\n");
- return PTR_ERR(dspk->clk_dspk);
- }
+ dev_set_drvdata(dev, dspk);
+
+ dspk->clk_dspk = devm_clk_get(dev, "dspk");
+ if (IS_ERR(dspk->clk_dspk)) {
+ dev_err(dev, "can't retrieve DSPK clock\n");
+ return PTR_ERR(dspk->clk_dspk);
}
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- regs = devm_ioremap_resource(&pdev->dev, mem);
+ regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
return PTR_ERR(regs);
- dspk->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
- &tegra186_dspk_regmap_config);
+
+ dspk->regmap = devm_regmap_init_mmio(dev, regs, &tegra186_dspk_regmap);
if (IS_ERR(dspk->regmap)) {
- dev_err(&pdev->dev, "regmap init failed\n");
+ dev_err(dev, "regmap init failed\n");
return PTR_ERR(dspk->regmap);
}
+
regcache_cache_only(dspk->regmap, true);
- pm_runtime_enable(&pdev->dev);
- ret = snd_soc_register_codec(&pdev->dev, &tegra186_dspk_codec,
- tegra186_dspk_dais,
- ARRAY_SIZE(tegra186_dspk_dais));
- if (ret != 0) {
- dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret);
- pm_runtime_disable(&pdev->dev);
- return ret;
+ err = devm_snd_soc_register_component(dev, &tegra186_dspk_cmpnt,
+ tegra186_dspk_dais,
+ ARRAY_SIZE(tegra186_dspk_dais));
+ if (err) {
+ dev_err(dev, "can't register DSPK component, err: %d\n",
+ err);
+ return err;
}
- if (of_property_read_string(np, "prod-name", &dspk->prod_name) == 0) {
- ret = tegra_pinctrl_config_prod(&pdev->dev, dspk->prod_name);
- if (ret < 0)
- dev_warn(&pdev->dev, "Failed to set %s setting\n",
- dspk->prod_name);
- }
+ pm_runtime_enable(dev);
return 0;
}
static int tegra186_dspk_platform_remove(struct platform_device *pdev)
{
- struct tegra186_dspk *dspk;
-
- dspk = dev_get_drvdata(&pdev->dev);
- snd_soc_unregister_codec(&pdev->dev);
-
pm_runtime_disable(&pdev->dev);
- if (!pm_runtime_status_suspended(&pdev->dev))
- tegra186_dspk_runtime_suspend(&pdev->dev);
return 0;
}
static const struct dev_pm_ops tegra186_dspk_pm_ops = {
SET_RUNTIME_PM_OPS(tegra186_dspk_runtime_suspend,
- tegra186_dspk_runtime_resume, NULL)
- SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ tegra186_dspk_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
};
static struct platform_driver tegra186_dspk_driver = {
.driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
+ .name = "tegra186-dspk",
.of_match_table = tegra186_dspk_of_match,
.pm = &tegra186_dspk_pm_ops,
},
@@ -516,9 +504,7 @@ static struct platform_driver tegra186_dspk_driver = {
};
module_platform_driver(tegra186_dspk_driver);
-
MODULE_AUTHOR("Mohan Kumar ");
-MODULE_DESCRIPTION("Tegra186 DSPK ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_DEVICE_TABLE(of, tegra186_dspk_of_match);
+MODULE_AUTHOR("Sameer Pujar ");
+MODULE_DESCRIPTION("Tegra186 ASoC DSPK driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra186_dspk.h b/sound/soc/tegra/tegra186_dspk.h
index 520912f6..ad48c23c 100644
--- a/sound/soc/tegra/tegra186_dspk.h
+++ b/sound/soc/tegra/tegra186_dspk.h
@@ -1,182 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * tegra186_dspk_alt.h - Definitions for Tegra186 DSPK driver
+ * tegra186_dspk.h - Definitions for Tegra186 DSPK driver
*
- * Copyright (c) 2015-2019 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
*/
-#ifndef __TEGRA186_DSPK_ALT_H__
-#define __TEGRA186_DSPK_ALT_H__
+#ifndef __TEGRA186_DSPK_H__
+#define __TEGRA186_DSPK_H__
/* Register offsets from DSPK BASE */
-#define TEGRA186_DSPK_AXBAR_RX_STATUS 0x0c
-#define TEGRA186_DSPK_AXBAR_RX_INT_STATUS 0x10
-#define TEGRA186_DSPK_AXBAR_RX_INT_MASK 0x14
-#define TEGRA186_DSPK_AXBAR_RX_INT_SET 0x18
-#define TEGRA186_DSPK_AXBAR_RX_INT_CLEAR 0x1c
-#define TEGRA186_DSPK_AXBAR_RX_CIF_CTRL 0x20
-#define TEGRA186_DSPK_AXBAR_RX_CYA 0x24
-#define TEGRA186_DSPK_AXBAR_RX_CIF_FIFO_STATUS 0x28
-
-#define TEGRA186_DSPK_ENABLE 0x40
-#define TEGRA186_DSPK_SOFT_RESET 0x44
-#define TEGRA186_DSPK_CG 0x48
-#define TEGRA186_DSPK_STATUS 0x4c
-#define TEGRA186_DSPK_INT_STATUS 0x50
-#define TEGRA186_DSPK_CORE_CTRL 0x60
-#define TEGRA186_DSPK_CODEC_CTRL 0x64
-#define TEGRA186_DSPK_CODEC_DATA 0x68
-#define TEGRA186_DSPK_CODEC_ENABLE 0x6c
-#define TEGRA186_DSPK_CLK_TRIM 0x70
-#define TEGRA186_DSPK_SDM_COEF_A_2 0x74
-#define TEGRA186_DSPK_SDM_COEF_A_3 0x78
-#define TEGRA186_DSPK_SDM_COEF_A_4 0x7c
-#define TEGRA186_DSPK_SDM_COEF_A_5 0x80
-#define TEGRA186_DSPK_SDM_COEF_C_1 0x84
-#define TEGRA186_DSPK_SDM_COEF_C_2 0x88
-#define TEGRA186_DSPK_SDM_COEF_C_3 0x8c
-#define TEGRA186_DSPK_SDM_COEF_C_4 0x90
-#define TEGRA186_DSPK_SDM_COEF_G_1 0x94
-#define TEGRA186_DSPK_SDM_COEF_G_2 0x98
-#define TEGRA186_DSPK_DEBUG_STATUS 0x9c
-#define TEGRA186_DSPK_DEBUG_CIF_CNTR 0xa0
-#define TEGRA186_DSPK_DEBUG_STAGE1_CNTR 0xa4
-#define TEGRA186_DSPK_DEBUG_STAGE2_CNTR 0xa8
-#define TEGRA186_DSPK_DEBUG_STAGE3_CNTR 0xac
-#define TEGRA186_DSPK_DEBUG_STAGE4_CNTR 0xb0
-
-/* Constants for DSPK */
-#define TEGRA186_DSPK_OSR_32 0
-#define TEGRA186_DSPK_OSR_64 1
-#define TEGRA186_DSPK_OSR_128 2
-#define TEGRA186_DSPK_OSR_256 3
-
-/* DSPK ENABLE Register field */
-#define TEGRA186_DSPK_ENABLE_EN BIT(0)
-
-/* DSPK SOFT RESET field */
-#define TEGRA186_DSPK_SOFT_RESET_EN BIT(0)
-
-/* DSPK CG field */
-#define TEGRA186_DSPK_CG_SLCG_EN BIT(0)
-
-/* DSPK STATUS fields */
-#define TEGRA186_DSPK_CODEC_CONFIG_DONE_SHIFT 14
-#define TEGRA186_DSPK_CODEC_CONFIG_DONE_MASK (0x1 << TEGRA186_DSPK_CODEC_CONFIG_DONE_SHIFT)
-
-#define TEGRA186_DSPK_SLCG_CLKEN_SHIFT 12
-#define TEGRA186_DSPK_SLCG_CLKEN_MASK (0x1 << TEGRA186_DSPK_SLCG_CLKEN_SHIFT)
-
-#define TEGRA186_DSPK_RX_CIF_FULL_SHIFT 10
-#define TEGRA186_DSPK_RX_CIF_FULL_MASK (0x1 << TEGRA186_DSPK_RX_CIF_FULL_SHIFT)
-
-#define TEGRA186_DSPK_RX_CIF_EMPTY_SHIFT 9
-#define TEGRA186_DSPK_RX_CIF_EMPTY_MASK (0x1 << TEGRA186_DSPK_RX_CIF_EMPTY_SHIFT)
-
-#define TEGRA186_DSPK_RX_ENABLED_SHIFT 8
-#define TEGRA186_DSPK_RX_ENABLED_MASK (0x1 << TEGRA186_DSPK_RX_ENABLED_SHIFT)
-
-/* DSPK INT STATUS fields */
-#define TEGRA186_DSPK_INT_CODEC_CONFIG_DONE_SHIFT 12
-#define TEGRA186_DSPK_INT_CODEC_CONFIG_DONE_MASK (0x1 << TEGRA186_DSPK_INT_CODEC_CONFIG_DONE_SHIFT)
-
-#define TEGRA186_DSPK_RX_CIF_FIFO_UNDERRUN_SHIFT 9
-#define TEGRA186_DSPK_RX_CIF_FIFO_UNDERRUN_MASK (0x1 << TEGRA186_DSPK_RX_CIF_FIFO_UNDERRUN_SHIFT)
-
-#define TEGRA186_DSPK_RX_DONE_SHIFT 8
-#define TEGRA186_DSPK_RX_DONE_MASK (0x1 << TEGRA186_DSPK_RX_DONE_SHIFT)
+#define TEGRA186_DSPK_RX_STATUS 0x0c
+#define TEGRA186_DSPK_RX_INT_STATUS 0x10
+#define TEGRA186_DSPK_RX_INT_MASK 0x14
+#define TEGRA186_DSPK_RX_INT_SET 0x18
+#define TEGRA186_DSPK_RX_INT_CLEAR 0x1c
+#define TEGRA186_DSPK_RX_CIF_CTRL 0x20
+#define TEGRA186_DSPK_ENABLE 0x40
+#define TEGRA186_DSPK_SOFT_RESET 0x44
+#define TEGRA186_DSPK_CG 0x48
+#define TEGRA186_DSPK_STATUS 0x4c
+#define TEGRA186_DSPK_INT_STATUS 0x50
+#define TEGRA186_DSPK_CORE_CTRL 0x60
+#define TEGRA186_DSPK_CODEC_CTRL 0x64
/* DSPK CORE CONTROL fields */
-#define TEGRA186_DSPK_GAIN1_SHIFT 28
-#define TEGRA186_DSPK_GAIN1_MASK (0x7 << TEGRA186_DSPK_GAIN1_SHIFT)
+#define CH_SEL_SHIFT 8
+#define TEGRA186_DSPK_CHANNEL_SELECT_MASK (0x3 << CH_SEL_SHIFT)
+#define DSPK_OSR_SHIFT 4
+#define TEGRA186_DSPK_OSR_MASK (0x3 << DSPK_OSR_SHIFT)
+#define LRSEL_POL_SHIFT 0
+#define TEGRA186_DSPK_CTRL_LRSEL_POLARITY_MASK (0x1 << LRSEL_POL_SHIFT)
+#define TEGRA186_DSPK_RX_FIFO_DEPTH 64
-#define TEGRA186_DSPK_GAIN2_SHIFT 24
-#define TEGRA186_DSPK_GAIN2_MASK (0x7 << TEGRA186_DSPK_GAIN2_SHIFT)
+#define DSPK_OSR_FACTOR 32
-#define TEGRA186_DSPK_GAIN3_SHIFT 20
-#define TEGRA186_DSPK_GAIN3_MASK (0x7 << TEGRA186_DSPK_GAIN3_SHIFT)
+/* DSPK interface clock ratio */
+#define DSPK_CLK_RATIO 4
-#define TEGRA186_DSPK_FILTER_MODE_SHIFT 16
-#define TEGRA186_DSPK_FILTER_MODE_MASK (0x1 << TEGRA186_DSPK_FILTER_MODE_SHIFT)
+enum tegra_dspk_osr {
+ DSPK_OSR_32,
+ DSPK_OSR_64,
+ DSPK_OSR_128,
+ DSPK_OSR_256,
+};
-#define TEGRA186_DSPK_CHANNEL_SELECT_SHIFT 8
-#define TEGRA186_DSPK_CHANNEL_SELECT_MASK (0x3 << TEGRA186_DSPK_CHANNEL_SELECT_SHIFT)
+enum tegra_dspk_ch_sel {
+ DSPK_CH_SELECT_LEFT,
+ DSPK_CH_SELECT_RIGHT,
+ DSPK_CH_SELECT_STEREO,
+};
-#define TEGRA186_DSPK_OSR_SHIFT 4
-#define TEGRA186_DSPK_OSR_MASK (0x3 << TEGRA186_DSPK_OSR_SHIFT)
-
-#define TEGRA186_DSPK_LRSEL_POLARITY_SHIFT 0
-#define TEGRA186_DSPK_LRSEL_POLARITY_MASK (0x1 << TEGRA186_DSPK_LRSEL_POLARITY_SHIFT)
-
-/* DSPK CODEC CONTROL fileds */
-#define TEGRA186_DSPK_CODEC_CHANNEL_SELECT_SHIFT 24
-#define TEGRA186_DSPK_CODEC_CHANNEL_SELECT_MASK (0x3 << TEGRA186_DSPK_CODEC_CHANNEL_SELECT_SHIFT)
-
-#define TEGRA186_DSPK_CODEC_BIT_ORDER_SHIFT 16
-#define TEGRA186_DSPK_CODEC_BIT_MASK (0x1 << TEGRA186_DSPK_CODEC_BIT_ORDER_SHIFT)
-
-#define TEGRA186_DSPK_CODEC_CONFIG_MODE_SHIFT 12
-#define TEGRA186_DSPK_CODEC_CONFIG_MODE_MASK (0x1 << TEGRA186_DSPK_CODEC_CONFIG_MODE_SHIFT)
-
-#define TEGRA186_DSPK_CODEC_CONFIG_REP_NUM_SHIFT 0
-#define TEGRA186_DSPK_CODEC_CONFIG_REP_NUM_MASK (0xff << TEGRA186_DSPK_CODEC_CONFIG_REP_NUM_SHIFT)
-
-/* DSPK CODEC ENABLE fields */
-#define TEGRA186_DSPK_CODEC_ENABLE_SHIFT 0
-#define TEGRA186_DSPK_CODEC_ENABLE_MASK (0x1 << TEGRA186_DSPK_CODEC_ENABLE_SHIFT)
-
-/* DSPL CLK TRIM field */
-#define TEGRA186_DSPK_CLK_TRIM_SHIFT 0
-#define TEGRA186_DSPK_CLK_TRIM_MASK (0x1f << TEGRA186_DSPK_CLK_TRIM_SHIFT)
-
-/* DSPK DEBUG Register fields*/
-#define TEGRA186_DSPK_DEBUG_STATUS_SHIFT 0
-#define TEGRA186_DSPK_DEBUG_STATUS_MASK (0xff << TEGRA186_DSPK_DEBUG_STATUS_SHIFT)
-
-#define TEGRA186_DSPK_DEBUG_CIF_CH0_SHIFT 16
-#define TEGRA186_DSPK_DEBUG_CIF_CH0_MASK (0xffff << TEGRA186_DSPK_DEBUG_CIF_CH0_SHIFT)
-#define TEGRA186_DSPK_DEBUG_CIF_CH1_SHIFT 0
-#define TEGRA186_DSPK_DEBUG_CIF_CH1_MASK (0xffff << TEGRA186_DSPK_DEBUG_CIF_CH1_SHIFT)
-
-#define TEGRA186_DSPK_DEBUG_STAGE1_CH0_SHIFT 16
-#define TEGRA186_DSPK_DEBUG_STAGE1_CH0_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE1_CH0_SHIFT)
-#define TEGRA186_DSPK_DEBUG_STAGE1_CH1_SHIFT 0
-#define TEGRA186_DSPK_DEBUG_STAGE1_CH1_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE1_CH1_SHIFT)
-
-#define TEGRA186_DSPK_DEBUG_STAGE2_CH0_SHIFT 16
-#define TEGRA186_DSPK_DEBUG_STAGE2_CH0_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE2_CH0_SHIFT)
-#define TEGRA186_DSPK_DEBUG_STAGE2_CH1_SHIFT 0
-#define TEGRA186_DSPK_DEBUG_STAGE2_CH1_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE2_CH1_SHIFT)
-
-#define TEGRA186_DSPK_DEBUG_STAGE3_CH0_SHIFT 16
-#define TEGRA186_DSPK_DEBUG_STAGE3_CH0_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE3_CH0_SHIFT)
-#define TEGRA186_DSPK_DEBUG_STAGE3_CH1_SHIFT 0
-#define TEGRA186_DSPK_DEBUG_STAGE3_CH1_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE3_CH1_SHIFT)
-
-#define TEGRA186_DSPK_DEBUG_STAGE4_CH0_SHIFT 16
-#define TEGRA186_DSPK_DEBUG_STAGE4_CH0_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE4_CH0_SHIFT)
-#define TEGRA186_DSPK_DEBUG_STAGE4_CH1_SHIFT 0
-#define TEGRA186_DSPK_DEBUG_STAGE4_CH1_MASK (0xffff << TEGRA186_DSPK_DEBUG_STAGE4_CH1_SHIFT)
-
-#define TEGRA186_DSPK_RX_FIFO_DEPTH 4
+enum tegra_dspk_lrsel {
+ DSPK_LRSEL_LEFT,
+ DSPK_LRSEL_RIGHT,
+};
struct tegra186_dspk {
- struct clk *clk_dspk;
- struct regmap *regmap;
- const char *prod_name;
- unsigned int rx_fifo_th; /* threshold in terms of frames */
- unsigned int osr_val; /* osr value */
+ unsigned int rx_fifo_th;
+ unsigned int osr_val;
+ unsigned int lrsel;
+ unsigned int srate_override;
+ unsigned int audio_ch_override;
+ unsigned int ch_sel; /* Used for client channel override */
+ unsigned int audio_fmt_override;
+ unsigned int mono_to_stereo;
+ unsigned int stereo_to_mono;
+ struct clk *clk_dspk;
+ struct regmap *regmap;
};
#endif
diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c
index 28210884..cd819ab0 100644
--- a/sound/soc/tegra/tegra210_admaif.c
+++ b/sound/soc/tegra/tegra210_admaif.c
@@ -1,37 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * tegra210_admaif_alt.c - Tegra ADMAIF driver
+ * tegra210_admaif.c - Tegra ADMAIF driver
*
- * Copyright (c) 2014-2020 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
*/
+#include
#include
-#include
#include
#include
#include
#include
#include
-#include
#include
-
-#include "tegra_pcm_alt.h"
-#include "tegra210_xbar_alt.h"
-#include "tegra_isomgr_bw_alt.h"
-#include "tegra210_admaif_alt.h"
-
-#define DRV_NAME "tegra210-ape-admaif"
+#include
+#include "tegra210_admaif.h"
+#include "tegra_cif.h"
+#include "tegra_pcm.h"
#define CH_REG(offset, reg, id) \
((offset) + (reg) + (TEGRA_ADMAIF_CHANNEL_REG_STRIDE * (id)))
@@ -40,25 +26,23 @@
#define CH_RX_REG(reg, id) CH_REG(admaif->soc_data->rx_base, reg, id)
-#define REG_IOVA(reg) (admaif->base_addr + (reg))
-
#define REG_DEFAULTS(id, rx_ctrl, tx_ctrl, tx_base, rx_base) \
- { CH_REG(rx_base, TEGRA_ADMAIF_XBAR_RX_INT_MASK, id), 0x00000001}, \
- { CH_REG(rx_base, TEGRA_ADMAIF_CHAN_ACIF_RX_CTRL, id), 0x00007700}, \
- { CH_REG(rx_base, TEGRA_ADMAIF_XBAR_RX_FIFO_CTRL, id), rx_ctrl}, \
- { CH_REG(tx_base, TEGRA_ADMAIF_XBAR_TX_INT_MASK, id), 0x00000001}, \
- { CH_REG(tx_base, TEGRA_ADMAIF_CHAN_ACIF_TX_CTRL, id), 0x00007700}, \
- { CH_REG(tx_base, TEGRA_ADMAIF_XBAR_TX_FIFO_CTRL, id), tx_ctrl}
+ { CH_REG(rx_base, TEGRA_ADMAIF_RX_INT_MASK, id), 0x00000001 }, \
+ { CH_REG(rx_base, TEGRA_ADMAIF_CH_ACIF_RX_CTRL, id), 0x00007700 }, \
+ { CH_REG(rx_base, TEGRA_ADMAIF_RX_FIFO_CTRL, id), rx_ctrl }, \
+ { CH_REG(tx_base, TEGRA_ADMAIF_TX_INT_MASK, id), 0x00000001 }, \
+ { CH_REG(tx_base, TEGRA_ADMAIF_CH_ACIF_TX_CTRL, id), 0x00007700 }, \
+ { CH_REG(tx_base, TEGRA_ADMAIF_TX_FIFO_CTRL, id), tx_ctrl }
#define ADMAIF_REG_DEFAULTS(id, chip) \
- REG_DEFAULTS((id - 1), \
+ REG_DEFAULTS((id) - 1, \
chip ## _ADMAIF_RX ## id ## _FIFO_CTRL_REG_DEFAULT, \
chip ## _ADMAIF_TX ## id ## _FIFO_CTRL_REG_DEFAULT, \
- chip ## _ADMAIF_XBAR_TX_BASE, \
- chip ## _ADMAIF_XBAR_RX_BASE)
+ chip ## _ADMAIF_TX_BASE, \
+ chip ## _ADMAIF_RX_BASE)
static const struct reg_default tegra186_admaif_reg_defaults[] = {
- {(TEGRA_ADMAIF_GLOBAL_CG_0+TEGRA186_ADMAIF_GLOBAL_BASE), 0x00000003},
+ {(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA186_ADMAIF_GLOBAL_BASE), 0x00000003},
ADMAIF_REG_DEFAULTS(1, TEGRA186),
ADMAIF_REG_DEFAULTS(2, TEGRA186),
ADMAIF_REG_DEFAULTS(3, TEGRA186),
@@ -82,7 +66,7 @@ static const struct reg_default tegra186_admaif_reg_defaults[] = {
};
static const struct reg_default tegra210_admaif_reg_defaults[] = {
- {(TEGRA_ADMAIF_GLOBAL_CG_0+TEGRA210_ADMAIF_GLOBAL_BASE), 0x00000003},
+ {(TEGRA_ADMAIF_GLOBAL_CG_0 + TEGRA210_ADMAIF_GLOBAL_BASE), 0x00000003},
ADMAIF_REG_DEFAULTS(1, TEGRA210),
ADMAIF_REG_DEFAULTS(2, TEGRA210),
ADMAIF_REG_DEFAULTS(3, TEGRA210),
@@ -109,22 +93,23 @@ static bool tegra_admaif_wr_reg(struct device *dev, unsigned int reg)
if ((reg >= rx_base) && (reg < rx_max)) {
reg = (reg - rx_base) % ch_stride;
- if ((reg == TEGRA_ADMAIF_XBAR_RX_ENABLE) ||
- (reg == TEGRA_ADMAIF_XBAR_RX_FIFO_CTRL) ||
- (reg == TEGRA_ADMAIF_XBAR_RX_SOFT_RESET) ||
- (reg == TEGRA_ADMAIF_CHAN_ACIF_RX_CTRL))
+ if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
+ (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||
+ (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||
+ (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))
return true;
} else if ((reg >= tx_base) && (reg < tx_max)) {
reg = (reg - tx_base) % ch_stride;
- if ((reg == TEGRA_ADMAIF_XBAR_TX_ENABLE) ||
- (reg == TEGRA_ADMAIF_XBAR_TX_FIFO_CTRL) ||
- (reg == TEGRA_ADMAIF_XBAR_TX_SOFT_RESET) ||
- (reg == TEGRA_ADMAIF_CHAN_ACIF_TX_CTRL))
+ if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
+ (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||
+ (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||
+ (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))
return true;
} else if ((reg >= global_base) && (reg < reg_max)) {
if (reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE))
return true;
}
+
return false;
}
@@ -142,21 +127,21 @@ static bool tegra_admaif_rd_reg(struct device *dev, unsigned int reg)
if ((reg >= rx_base) && (reg < rx_max)) {
reg = (reg - rx_base) % ch_stride;
- if ((reg == TEGRA_ADMAIF_XBAR_RX_ENABLE) ||
- (reg == TEGRA_ADMAIF_XBAR_RX_STATUS) ||
- (reg == TEGRA_ADMAIF_XBAR_RX_INT_STATUS) ||
- (reg == TEGRA_ADMAIF_XBAR_RX_FIFO_CTRL) ||
- (reg == TEGRA_ADMAIF_XBAR_RX_SOFT_RESET) ||
- (reg == TEGRA_ADMAIF_CHAN_ACIF_RX_CTRL))
+ if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
+ (reg == TEGRA_ADMAIF_RX_STATUS) ||
+ (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||
+ (reg == TEGRA_ADMAIF_RX_FIFO_CTRL) ||
+ (reg == TEGRA_ADMAIF_RX_SOFT_RESET) ||
+ (reg == TEGRA_ADMAIF_CH_ACIF_RX_CTRL))
return true;
} else if ((reg >= tx_base) && (reg < tx_max)) {
reg = (reg - tx_base) % ch_stride;
- if ((reg == TEGRA_ADMAIF_XBAR_TX_ENABLE) ||
- (reg == TEGRA_ADMAIF_XBAR_TX_STATUS) ||
- (reg == TEGRA_ADMAIF_XBAR_TX_INT_STATUS) ||
- (reg == TEGRA_ADMAIF_XBAR_TX_FIFO_CTRL) ||
- (reg == TEGRA_ADMAIF_XBAR_TX_SOFT_RESET) ||
- (reg == TEGRA_ADMAIF_CHAN_ACIF_TX_CTRL))
+ if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
+ (reg == TEGRA_ADMAIF_TX_STATUS) ||
+ (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||
+ (reg == TEGRA_ADMAIF_TX_FIFO_CTRL) ||
+ (reg == TEGRA_ADMAIF_TX_SOFT_RESET) ||
+ (reg == TEGRA_ADMAIF_CH_ACIF_TX_CTRL))
return true;
} else if ((reg >= global_base) && (reg < reg_max)) {
if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_ENABLE)) ||
@@ -168,6 +153,7 @@ static bool tegra_admaif_rd_reg(struct device *dev, unsigned int reg)
TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))
return true;
}
+
return false;
}
@@ -185,17 +171,17 @@ static bool tegra_admaif_volatile_reg(struct device *dev, unsigned int reg)
if ((reg >= rx_base) && (reg < rx_max)) {
reg = (reg - rx_base) % ch_stride;
- if ((reg == TEGRA_ADMAIF_XBAR_RX_ENABLE) ||
- (reg == TEGRA_ADMAIF_XBAR_RX_STATUS) ||
- (reg == TEGRA_ADMAIF_XBAR_RX_INT_STATUS) ||
- (reg == TEGRA_ADMAIF_XBAR_RX_SOFT_RESET))
+ if ((reg == TEGRA_ADMAIF_RX_ENABLE) ||
+ (reg == TEGRA_ADMAIF_RX_STATUS) ||
+ (reg == TEGRA_ADMAIF_RX_INT_STATUS) ||
+ (reg == TEGRA_ADMAIF_RX_SOFT_RESET))
return true;
} else if ((reg >= tx_base) && (reg < tx_max)) {
reg = (reg - tx_base) % ch_stride;
- if ((reg == TEGRA_ADMAIF_XBAR_TX_ENABLE) ||
- (reg == TEGRA_ADMAIF_XBAR_TX_STATUS) ||
- (reg == TEGRA_ADMAIF_XBAR_TX_INT_STATUS) ||
- (reg == TEGRA_ADMAIF_XBAR_TX_SOFT_RESET))
+ if ((reg == TEGRA_ADMAIF_TX_ENABLE) ||
+ (reg == TEGRA_ADMAIF_TX_STATUS) ||
+ (reg == TEGRA_ADMAIF_TX_INT_STATUS) ||
+ (reg == TEGRA_ADMAIF_TX_SOFT_RESET))
return true;
} else if ((reg >= global_base) && (reg < reg_max)) {
if ((reg == (global_base + TEGRA_ADMAIF_GLOBAL_STATUS)) ||
@@ -205,33 +191,34 @@ static bool tegra_admaif_volatile_reg(struct device *dev, unsigned int reg)
TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS)))
return true;
}
+
return false;
}
static const struct regmap_config tegra210_admaif_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = TEGRA210_ADMAIF_LAST_REG,
- .writeable_reg = tegra_admaif_wr_reg,
- .readable_reg = tegra_admaif_rd_reg,
- .volatile_reg = tegra_admaif_volatile_reg,
- .reg_defaults = tegra210_admaif_reg_defaults,
- .num_reg_defaults = TEGRA210_ADMAIF_CHANNEL_COUNT * 6 + 1,
- .cache_type = REGCACHE_FLAT,
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = TEGRA210_ADMAIF_LAST_REG,
+ .writeable_reg = tegra_admaif_wr_reg,
+ .readable_reg = tegra_admaif_rd_reg,
+ .volatile_reg = tegra_admaif_volatile_reg,
+ .reg_defaults = tegra210_admaif_reg_defaults,
+ .num_reg_defaults = TEGRA210_ADMAIF_CHANNEL_COUNT * 6 + 1,
+ .cache_type = REGCACHE_FLAT,
};
static const struct regmap_config tegra186_admaif_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = TEGRA186_ADMAIF_LAST_REG,
- .writeable_reg = tegra_admaif_wr_reg,
- .readable_reg = tegra_admaif_rd_reg,
- .volatile_reg = tegra_admaif_volatile_reg,
- .reg_defaults = tegra186_admaif_reg_defaults,
- .num_reg_defaults = TEGRA186_ADMAIF_CHANNEL_COUNT * 6 + 1,
- .cache_type = REGCACHE_FLAT,
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = TEGRA186_ADMAIF_LAST_REG,
+ .writeable_reg = tegra_admaif_wr_reg,
+ .readable_reg = tegra_admaif_rd_reg,
+ .volatile_reg = tegra_admaif_volatile_reg,
+ .reg_defaults = tegra186_admaif_reg_defaults,
+ .num_reg_defaults = TEGRA186_ADMAIF_CHANNEL_COUNT * 6 + 1,
+ .cache_type = REGCACHE_FLAT,
};
static int tegra_admaif_runtime_suspend(struct device *dev)
@@ -255,32 +242,20 @@ static int tegra_admaif_runtime_resume(struct device *dev)
}
static int tegra_admaif_set_pack_mode(struct regmap *map, unsigned int reg,
- int valid_bit)
+ int valid_bit)
{
switch (valid_bit) {
case DATA_8BIT:
- regmap_update_bits(map, reg,
- TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN_MASK,
- TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN);
- regmap_update_bits(map, reg,
- TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN_MASK,
- 0);
+ regmap_update_bits(map, reg, PACK8_EN_MASK, PACK8_EN);
+ regmap_update_bits(map, reg, PACK16_EN_MASK, 0);
break;
case DATA_16BIT:
- regmap_update_bits(map, reg,
- TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN_MASK,
- TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN);
- regmap_update_bits(map, reg,
- TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN_MASK,
- 0);
+ regmap_update_bits(map, reg, PACK16_EN_MASK, PACK16_EN);
+ regmap_update_bits(map, reg, PACK8_EN_MASK, 0);
break;
case DATA_32BIT:
- regmap_update_bits(map, reg,
- TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN_MASK,
- 0);
- regmap_update_bits(map, reg,
- TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN_MASK,
- 0);
+ regmap_update_bits(map, reg, PACK16_EN_MASK, 0);
+ regmap_update_bits(map, reg, PACK8_EN_MASK, 0);
break;
default:
return -EINVAL;
@@ -289,85 +264,63 @@ static int tegra_admaif_set_pack_mode(struct regmap *map, unsigned int reg,
return 0;
}
-static int tegra_admaif_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
-
- if (admaif->soc_data->is_isomgr_client)
- tegra_isomgr_adma_setbw(substream, true);
-
- return 0;
-}
-
-static void tegra_admaif_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
-
- if (admaif->soc_data->is_isomgr_client)
- tegra_isomgr_adma_setbw(substream, false);
-}
-
static int tegra_admaif_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
{
struct device *dev = dai->dev;
struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
- struct tegra210_xbar_cif_conf cif_conf;
+ struct tegra_cif_conf cif_conf;
unsigned int reg, path;
int valid_bit, channels;
- memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf));
+ memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
- cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_8;
- cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_8;
+ cif_conf.audio_bits = TEGRA_ACIF_BITS_8;
+ cif_conf.client_bits = TEGRA_ACIF_BITS_8;
valid_bit = DATA_8BIT;
break;
case SNDRV_PCM_FORMAT_S16_LE:
- cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_16;
- cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_16;
+ cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+ cif_conf.client_bits = TEGRA_ACIF_BITS_16;
valid_bit = DATA_16BIT;
break;
case SNDRV_PCM_FORMAT_S32_LE:
- cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_32;
- cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_32;
+ cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+ cif_conf.client_bits = TEGRA_ACIF_BITS_32;
valid_bit = DATA_32BIT;
break;
default:
- dev_err(dev, "Wrong format!\n");
- return -EINVAL;
+ dev_err(dev, "unsupported format!\n");
+ return -ENOTSUPP;
}
channels = params_channels(params);
- cif_conf.client_channels = channels;
- cif_conf.audio_channels = channels;
+ cif_conf.client_ch = channels;
+ cif_conf.audio_ch = channels;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
path = ADMAIF_TX_PATH;
- reg = CH_TX_REG(TEGRA_ADMAIF_CHAN_ACIF_TX_CTRL, dai->id);
+ reg = CH_TX_REG(TEGRA_ADMAIF_CH_ACIF_TX_CTRL, dai->id);
} else {
path = ADMAIF_RX_PATH;
- reg = CH_RX_REG(TEGRA_ADMAIF_CHAN_ACIF_RX_CTRL, dai->id);
+ reg = CH_RX_REG(TEGRA_ADMAIF_CH_ACIF_RX_CTRL, dai->id);
}
if (admaif->audio_ch_override[path][dai->id])
- cif_conf.audio_channels =
- admaif->audio_ch_override[path][dai->id];
+ cif_conf.audio_ch = admaif->audio_ch_override[path][dai->id];
if (admaif->client_ch_override[path][dai->id])
- cif_conf.client_channels =
- admaif->client_ch_override[path][dai->id];
+ cif_conf.client_ch = admaif->client_ch_override[path][dai->id];
cif_conf.mono_conv = admaif->mono_to_stereo[path][dai->id];
cif_conf.stereo_conv = admaif->stereo_to_mono[path][dai->id];
tegra_admaif_set_pack_mode(admaif->regmap, reg, valid_bit);
- tegra210_xbar_set_cif(admaif->regmap, reg, &cif_conf);
+ tegra_set_cif(admaif->regmap, reg, &cif_conf);
return 0;
}
@@ -379,14 +332,14 @@ static int tegra_admaif_start(struct snd_soc_dai *dai, int direction)
switch (direction) {
case SNDRV_PCM_STREAM_PLAYBACK:
- mask = TEGRA_ADMAIF_XBAR_TX_ENABLE_MASK;
- val = TEGRA_ADMAIF_XBAR_TX_EN;
- reg = CH_TX_REG(TEGRA_ADMAIF_XBAR_TX_ENABLE, dai->id);
+ mask = TX_ENABLE_MASK;
+ val = TX_ENABLE;
+ reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);
break;
case SNDRV_PCM_STREAM_CAPTURE:
- mask = TEGRA_ADMAIF_XBAR_RX_ENABLE_MASK;
- val = TEGRA_ADMAIF_XBAR_RX_EN;
- reg = CH_RX_REG(TEGRA_ADMAIF_XBAR_RX_ENABLE, dai->id);
+ mask = RX_ENABLE_MASK;
+ val = RX_ENABLE;
+ reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);
break;
default:
return -EINVAL;
@@ -400,61 +353,59 @@ static int tegra_admaif_start(struct snd_soc_dai *dai, int direction)
static int tegra_admaif_stop(struct snd_soc_dai *dai, int direction)
{
struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
- unsigned int enable_reg, status_reg, reset_reg, mask, val, enable;
+ unsigned int enable_reg, status_reg, reset_reg, mask, val;
char *dir_name;
- int ret;
+ int err, enable;
switch (direction) {
case SNDRV_PCM_STREAM_PLAYBACK:
- mask = TEGRA_ADMAIF_XBAR_TX_ENABLE_MASK;
- enable = TEGRA_ADMAIF_XBAR_TX_EN;
+ mask = TX_ENABLE_MASK;
+ enable = TX_ENABLE;
dir_name = "TX";
- enable_reg = CH_TX_REG(TEGRA_ADMAIF_XBAR_TX_ENABLE, dai->id);
- status_reg = CH_TX_REG(TEGRA_ADMAIF_XBAR_TX_STATUS, dai->id);
- reset_reg = CH_TX_REG(TEGRA_ADMAIF_XBAR_TX_SOFT_RESET, dai->id);
+ enable_reg = CH_TX_REG(TEGRA_ADMAIF_TX_ENABLE, dai->id);
+ status_reg = CH_TX_REG(TEGRA_ADMAIF_TX_STATUS, dai->id);
+ reset_reg = CH_TX_REG(TEGRA_ADMAIF_TX_SOFT_RESET, dai->id);
break;
case SNDRV_PCM_STREAM_CAPTURE:
- mask = TEGRA_ADMAIF_XBAR_RX_ENABLE_MASK;
- enable = TEGRA_ADMAIF_XBAR_RX_EN;
+ mask = RX_ENABLE_MASK;
+ enable = RX_ENABLE;
dir_name = "RX";
- enable_reg = CH_RX_REG(TEGRA_ADMAIF_XBAR_RX_ENABLE, dai->id);
- status_reg = CH_RX_REG(TEGRA_ADMAIF_XBAR_RX_STATUS, dai->id);
- reset_reg = CH_RX_REG(TEGRA_ADMAIF_XBAR_RX_SOFT_RESET, dai->id);
+ enable_reg = CH_RX_REG(TEGRA_ADMAIF_RX_ENABLE, dai->id);
+ status_reg = CH_RX_REG(TEGRA_ADMAIF_RX_STATUS, dai->id);
+ reset_reg = CH_RX_REG(TEGRA_ADMAIF_RX_SOFT_RESET, dai->id);
break;
default:
return -EINVAL;
}
- /* disable TX/RX channel */
+ /* Disable TX/RX channel */
regmap_update_bits(admaif->regmap, enable_reg, mask, ~enable);
- /* wait until ADMAIF TX/RX status is disabled */
- ret = regmap_read_poll_timeout_atomic(admaif->regmap, status_reg, val,
+ /* Wait until ADMAIF TX/RX status is disabled */
+ err = regmap_read_poll_timeout_atomic(admaif->regmap, status_reg, val,
!(val & enable), 10, 10000);
-
- /* Timeout may be hit if sink gets closed/blocked ahead of source */
- if (ret < 0)
+ if (err < 0)
dev_warn(dai->dev, "timeout: failed to disable ADMAIF%d_%s\n",
dai->id + 1, dir_name);
/* SW reset */
regmap_update_bits(admaif->regmap, reset_reg, SW_RESET_MASK, SW_RESET);
- /* wait till SW reset is complete */
- ret = regmap_read_poll_timeout_atomic(admaif->regmap, reset_reg, val,
+ /* Wait till SW reset is complete */
+ err = regmap_read_poll_timeout_atomic(admaif->regmap, reset_reg, val,
!(val & SW_RESET_MASK & SW_RESET),
10, 10000);
- if (ret < 0) {
+ if (err) {
dev_err(dai->dev, "timeout: SW reset failed for ADMAIF%d_%s\n",
dai->id + 1, dir_name);
- return ret;
+ return err;
}
return 0;
}
static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *dai)
{
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -470,21 +421,19 @@ static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd,
}
}
-static struct snd_soc_dai_ops tegra_admaif_dai_ops = {
+static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {
.hw_params = tegra_admaif_hw_params,
.trigger = tegra_admaif_trigger,
- .shutdown = tegra_admaif_shutdown,
- .prepare = tegra_admaif_prepare,
};
-static int tegra_admaif_get_format(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int tegra_admaif_get_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
- struct tegra_admaif *admaif = snd_soc_codec_get_drvdata(codec);
+ struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
long *uctl_val = &ucontrol->value.integer.value[0];
if (strstr(kcontrol->id.name, "Playback Audio Channels"))
@@ -495,26 +444,26 @@ static int tegra_admaif_get_format(struct snd_kcontrol *kcontrol,
*uctl_val = admaif->client_ch_override[ADMAIF_TX_PATH][mc->reg];
else if (strstr(kcontrol->id.name, "Capture Client Channels"))
*uctl_val = admaif->client_ch_override[ADMAIF_RX_PATH][mc->reg];
- else if (strstr(kcontrol->id.name, "Playback mono to stereo"))
+ else if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
*uctl_val = admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg];
- else if (strstr(kcontrol->id.name, "Playback stereo to mono"))
- *uctl_val = admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg];
- else if (strstr(kcontrol->id.name, "Capture mono to stereo"))
+ else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
*uctl_val = admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg];
- else if (strstr(kcontrol->id.name, "Capture stereo to mono"))
+ else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
+ *uctl_val = admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg];
+ else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
*uctl_val = admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg];
return 0;
}
-static int tegra_admaif_put_format(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int tegra_admaif_put_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct tegra_admaif *admaif = snd_soc_codec_get_drvdata(codec);
+ struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
int value = ucontrol->value.integer.value[0];
if (strstr(kcontrol->id.name, "Playback Audio Channels"))
@@ -525,90 +474,18 @@ static int tegra_admaif_put_format(struct snd_kcontrol *kcontrol,
admaif->client_ch_override[ADMAIF_TX_PATH][mc->reg] = value;
else if (strstr(kcontrol->id.name, "Capture Client Channels"))
admaif->client_ch_override[ADMAIF_RX_PATH][mc->reg] = value;
- else if (strstr(kcontrol->id.name, "Playback mono to stereo"))
+ else if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value;
- else if (strstr(kcontrol->id.name, "Playback stereo to mono"))
- admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value;
- else if (strstr(kcontrol->id.name, "Capture mono to stereo"))
+ else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value;
- else if (strstr(kcontrol->id.name, "Capture stereo to mono"))
+ else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
+ admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value;
+ else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value;
return 0;
}
-static void tegra_admaif_reg_dump(struct tegra_admaif *admaif)
-{
- int i, stride;
- int ret;
- int tx_offset = admaif->soc_data->tx_base;
-
- ret = pm_runtime_get_sync(admaif->dev->parent);
- if (ret < 0) {
- dev_err(admaif->dev, "parent get_sync failed: %d\n", ret);
- return;
- }
-
- pr_info("=========ADMAIF reg dump=========\n");
-
- for (i = 0; i < admaif->soc_data->num_ch; i++) {
- stride = (i * TEGRA_ADMAIF_CHANNEL_REG_STRIDE);
- pr_info("RX%d_Enable = %#x\n", i+1,
- readl(admaif->base_addr +
- TEGRA_ADMAIF_XBAR_RX_ENABLE + stride));
- pr_info("RX%d_STATUS = %#x\n", i+1,
- readl(admaif->base_addr +
- TEGRA_ADMAIF_XBAR_RX_STATUS + stride));
- pr_info("RX%d_CIF_CTRL = %#x\n", i+1,
- readl(admaif->base_addr +
- TEGRA_ADMAIF_CHAN_ACIF_RX_CTRL + stride));
- pr_info("RX%d_FIFO_CTRL = %#x\n", i+1,
- readl(admaif->base_addr +
- TEGRA_ADMAIF_XBAR_RX_FIFO_CTRL + stride));
- pr_info("TX%d_Enable = %#x\n", i+1,
- readl(admaif->base_addr + tx_offset +
- TEGRA_ADMAIF_XBAR_TX_ENABLE + stride));
- pr_info("TX%d_STATUS = %#x\n", i+1,
- readl(admaif->base_addr + tx_offset +
- TEGRA_ADMAIF_XBAR_TX_STATUS + stride));
- pr_info("TX%d_CIF_CTRL = %#x\n", i+1,
- readl(admaif->base_addr + tx_offset +
- TEGRA_ADMAIF_CHAN_ACIF_TX_CTRL + stride));
- pr_info("TX%d_FIFO_CTRL = %#x\n", i+1,
- readl(admaif->base_addr + tx_offset +
- TEGRA_ADMAIF_XBAR_TX_FIFO_CTRL + stride));
- }
- pm_runtime_put_sync(admaif->dev->parent);
-}
-static int tegra210_ape_dump_reg_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct tegra_admaif *admaif = snd_soc_codec_get_drvdata(codec);
-
- ucontrol->value.integer.value[0] = admaif->reg_dump_flag;
-
- return 0;
-}
-
-static int tegra210_ape_dump_reg_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct tegra_admaif *admaif = snd_soc_codec_get_drvdata(codec);
-
- admaif->reg_dump_flag = ucontrol->value.integer.value[0];
-
- if (admaif->reg_dump_flag) {
-#if IS_ENABLED(CONFIG_TEGRA210_ADMA)
- tegra_adma_dump_ch_reg();
-#endif
- tegra_admaif_reg_dump(admaif);
- }
-
- return 0;
-}
-
static int tegra_admaif_dai_probe(struct snd_soc_dai *dai)
{
struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
@@ -619,7 +496,7 @@ static int tegra_admaif_dai_probe(struct snd_soc_dai *dai)
return 0;
}
-#define ADMAIF_DAI(id) \
+#define ADMAIF_DAI(id) \
{ \
.name = "ADMAIF" #id, \
.probe = tegra_admaif_dai_probe, \
@@ -636,62 +513,15 @@ static int tegra_admaif_dai_probe(struct snd_soc_dai *dai)
.stream_name = "Capture " #id, \
.channels_min = 1, \
.channels_max = 16, \
- .rates = SNDRV_PCM_RATE_8000_192000, \
- .formats = SNDRV_PCM_FMTBIT_S8 | \
- SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S32_LE, \
+ .rates = SNDRV_PCM_RATE_8000_192000, \
+ .formats = SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE, \
}, \
.ops = &tegra_admaif_dai_ops, \
}
-#define ADMAIF_CODEC_FIFO_DAI(id) \
- { \
- .name = "ADMAIF" #id " FIFO", \
- .playback = { \
- .stream_name = "ADMAIF" #id " FIFO Transmit", \
- .channels_min = 1, \
- .channels_max = 16, \
- .rates = SNDRV_PCM_RATE_8000_192000, \
- .formats = SNDRV_PCM_FMTBIT_S8 | \
- SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S32_LE, \
- }, \
- .capture = { \
- .stream_name = "ADMAIF" #id " FIFO Receive", \
- .channels_min = 1, \
- .channels_max = 16, \
- .rates = SNDRV_PCM_RATE_8000_192000, \
- .formats = SNDRV_PCM_FMTBIT_S8 | \
- SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S32_LE, \
- }, \
- .ops = &tegra_admaif_dai_ops, \
- }
-
-#define ADMAIF_CODEC_CIF_DAI(id) \
- { \
- .name = "ADMAIF" #id " CIF", \
- .playback = { \
- .stream_name = "ADMAIF" #id " CIF Transmit", \
- .channels_min = 1, \
- .channels_max = 16, \
- .rates = SNDRV_PCM_RATE_8000_192000, \
- .formats = SNDRV_PCM_FMTBIT_S8 | \
- SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S32_LE, \
- }, \
- .capture = { \
- .stream_name = "ADMAIF" #id " CIF Receive", \
- .channels_min = 1, \
- .channels_max = 16, \
- .rates = SNDRV_PCM_RATE_8000_192000, \
- .formats = SNDRV_PCM_FMTBIT_S8 | \
- SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S32_LE, \
- }, \
- }
-
-static struct snd_soc_dai_driver tegra210_admaif_codec_dais[] = {
+static struct snd_soc_dai_driver tegra210_admaif_cmpnt_dais[] = {
ADMAIF_DAI(1),
ADMAIF_DAI(2),
ADMAIF_DAI(3),
@@ -702,29 +532,9 @@ static struct snd_soc_dai_driver tegra210_admaif_codec_dais[] = {
ADMAIF_DAI(8),
ADMAIF_DAI(9),
ADMAIF_DAI(10),
- ADMAIF_CODEC_FIFO_DAI(1),
- ADMAIF_CODEC_FIFO_DAI(2),
- ADMAIF_CODEC_FIFO_DAI(3),
- ADMAIF_CODEC_FIFO_DAI(4),
- ADMAIF_CODEC_FIFO_DAI(5),
- ADMAIF_CODEC_FIFO_DAI(6),
- ADMAIF_CODEC_FIFO_DAI(7),
- ADMAIF_CODEC_FIFO_DAI(8),
- ADMAIF_CODEC_FIFO_DAI(9),
- ADMAIF_CODEC_FIFO_DAI(10),
- ADMAIF_CODEC_CIF_DAI(1),
- ADMAIF_CODEC_CIF_DAI(2),
- ADMAIF_CODEC_CIF_DAI(3),
- ADMAIF_CODEC_CIF_DAI(4),
- ADMAIF_CODEC_CIF_DAI(5),
- ADMAIF_CODEC_CIF_DAI(6),
- ADMAIF_CODEC_CIF_DAI(7),
- ADMAIF_CODEC_CIF_DAI(8),
- ADMAIF_CODEC_CIF_DAI(9),
- ADMAIF_CODEC_CIF_DAI(10),
};
-static struct snd_soc_dai_driver tegra186_admaif_codec_dais[] = {
+static struct snd_soc_dai_driver tegra186_admaif_cmpnt_dais[] = {
ADMAIF_DAI(1),
ADMAIF_DAI(2),
ADMAIF_DAI(3),
@@ -745,110 +555,6 @@ static struct snd_soc_dai_driver tegra186_admaif_codec_dais[] = {
ADMAIF_DAI(18),
ADMAIF_DAI(19),
ADMAIF_DAI(20),
- ADMAIF_CODEC_FIFO_DAI(1),
- ADMAIF_CODEC_FIFO_DAI(2),
- ADMAIF_CODEC_FIFO_DAI(3),
- ADMAIF_CODEC_FIFO_DAI(4),
- ADMAIF_CODEC_FIFO_DAI(5),
- ADMAIF_CODEC_FIFO_DAI(6),
- ADMAIF_CODEC_FIFO_DAI(7),
- ADMAIF_CODEC_FIFO_DAI(8),
- ADMAIF_CODEC_FIFO_DAI(9),
- ADMAIF_CODEC_FIFO_DAI(10),
- ADMAIF_CODEC_FIFO_DAI(11),
- ADMAIF_CODEC_FIFO_DAI(12),
- ADMAIF_CODEC_FIFO_DAI(13),
- ADMAIF_CODEC_FIFO_DAI(14),
- ADMAIF_CODEC_FIFO_DAI(15),
- ADMAIF_CODEC_FIFO_DAI(16),
- ADMAIF_CODEC_FIFO_DAI(17),
- ADMAIF_CODEC_FIFO_DAI(18),
- ADMAIF_CODEC_FIFO_DAI(19),
- ADMAIF_CODEC_FIFO_DAI(20),
- ADMAIF_CODEC_CIF_DAI(1),
- ADMAIF_CODEC_CIF_DAI(2),
- ADMAIF_CODEC_CIF_DAI(3),
- ADMAIF_CODEC_CIF_DAI(4),
- ADMAIF_CODEC_CIF_DAI(5),
- ADMAIF_CODEC_CIF_DAI(6),
- ADMAIF_CODEC_CIF_DAI(7),
- ADMAIF_CODEC_CIF_DAI(8),
- ADMAIF_CODEC_CIF_DAI(9),
- ADMAIF_CODEC_CIF_DAI(10),
- ADMAIF_CODEC_CIF_DAI(11),
- ADMAIF_CODEC_CIF_DAI(12),
- ADMAIF_CODEC_CIF_DAI(13),
- ADMAIF_CODEC_CIF_DAI(14),
- ADMAIF_CODEC_CIF_DAI(15),
- ADMAIF_CODEC_CIF_DAI(16),
- ADMAIF_CODEC_CIF_DAI(17),
- ADMAIF_CODEC_CIF_DAI(18),
- ADMAIF_CODEC_CIF_DAI(19),
- ADMAIF_CODEC_CIF_DAI(20),
-};
-
-#define ADMAIF_WIDGETS(id) \
- SND_SOC_DAPM_AIF_IN("ADMAIF" #id " FIFO RX", NULL, 0, \
- SND_SOC_NOPM, 0, 0), \
- SND_SOC_DAPM_AIF_OUT("ADMAIF" #id " FIFO TX", NULL, 0, \
- SND_SOC_NOPM, 0, 0), \
- SND_SOC_DAPM_AIF_IN("ADMAIF" #id " CIF RX", NULL, 0, \
- SND_SOC_NOPM, 0, 0), \
- SND_SOC_DAPM_AIF_OUT("ADMAIF" #id " CIF TX", NULL, 0, \
- SND_SOC_NOPM, 0, 0)
-
-static const struct snd_soc_dapm_widget tegra_admaif_widgets[] = {
- ADMAIF_WIDGETS(1),
- ADMAIF_WIDGETS(2),
- ADMAIF_WIDGETS(3),
- ADMAIF_WIDGETS(4),
- ADMAIF_WIDGETS(5),
- ADMAIF_WIDGETS(6),
- ADMAIF_WIDGETS(7),
- ADMAIF_WIDGETS(8),
- ADMAIF_WIDGETS(9),
- ADMAIF_WIDGETS(10),
- ADMAIF_WIDGETS(11),
- ADMAIF_WIDGETS(12),
- ADMAIF_WIDGETS(13),
- ADMAIF_WIDGETS(14),
- ADMAIF_WIDGETS(15),
- ADMAIF_WIDGETS(16),
- ADMAIF_WIDGETS(17),
- ADMAIF_WIDGETS(18),
- ADMAIF_WIDGETS(19),
- ADMAIF_WIDGETS(20)
-};
-
-#define ADMAIF_ROUTES(id) \
- { "ADMAIF" #id " FIFO RX", NULL, "ADMAIF" #id " FIFO Transmit" }, \
- { "ADMAIF" #id " CIF TX", NULL, "ADMAIF" #id " FIFO RX" },\
- { "ADMAIF" #id " CIF Receive", NULL, "ADMAIF" #id " CIF TX" }, \
- { "ADMAIF" #id " CIF RX", NULL, "ADMAIF" #id " CIF Transmit" }, \
- { "ADMAIF" #id " FIFO TX", NULL, "ADMAIF" #id " CIF RX" }, \
- { "ADMAIF" #id " FIFO Receive", NULL, "ADMAIF" #id " FIFO TX" } \
-
-static const struct snd_soc_dapm_route tegra_admaif_routes[] = {
- ADMAIF_ROUTES(1),
- ADMAIF_ROUTES(2),
- ADMAIF_ROUTES(3),
- ADMAIF_ROUTES(4),
- ADMAIF_ROUTES(5),
- ADMAIF_ROUTES(6),
- ADMAIF_ROUTES(7),
- ADMAIF_ROUTES(8),
- ADMAIF_ROUTES(9),
- ADMAIF_ROUTES(10),
- ADMAIF_ROUTES(11),
- ADMAIF_ROUTES(12),
- ADMAIF_ROUTES(13),
- ADMAIF_ROUTES(14),
- ADMAIF_ROUTES(15),
- ADMAIF_ROUTES(16),
- ADMAIF_ROUTES(17),
- ADMAIF_ROUTES(18),
- ADMAIF_ROUTES(19),
- ADMAIF_ROUTES(20)
};
static const char * const tegra_admaif_stereo_conv_text[] = {
@@ -859,32 +565,22 @@ static const char * const tegra_admaif_mono_conv_text[] = {
"ZERO", "COPY",
};
-static const struct soc_enum tegra_admaif_mono_conv_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
- ARRAY_SIZE(tegra_admaif_mono_conv_text),
- tegra_admaif_mono_conv_text);
-
-static const struct soc_enum tegra_admaif_stereo_conv_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
- ARRAY_SIZE(tegra_admaif_stereo_conv_text),
- tegra_admaif_stereo_conv_text);
-
-#define TEGRA_ADMAIF_CHANNEL_CTRL(reg) \
- SOC_SINGLE_EXT("ADMAIF" #reg " Playback Audio Channels", reg - 1, \
- 0, 16, 0, tegra_admaif_get_format, \
- tegra_admaif_put_format), \
- SOC_SINGLE_EXT("ADMAIF" #reg " Capture Audio Channels", reg - 1, \
- 0, 16, 0, tegra_admaif_get_format, \
- tegra_admaif_put_format), \
- SOC_SINGLE_EXT("ADMAIF" #reg " Playback Client Channels", reg - 1, \
- 0, 16, 0, tegra_admaif_get_format, \
- tegra_admaif_put_format), \
- SOC_SINGLE_EXT("ADMAIF" #reg " Capture Client Channels", reg - 1, \
- 0, 16, 0, tegra_admaif_get_format, \
- tegra_admaif_put_format)
+#define TEGRA_ADMAIF_CHANNEL_CTRL(reg) \
+ SOC_SINGLE_EXT("ADMAIF" #reg " Playback Audio Channels", reg - 1, \
+ 0, 16, 0, tegra_admaif_get_control, \
+ tegra_admaif_put_control), \
+ SOC_SINGLE_EXT("ADMAIF" #reg " Capture Audio Channels", reg - 1, \
+ 0, 16, 0, tegra_admaif_get_control, \
+ tegra_admaif_put_control), \
+ SOC_SINGLE_EXT("ADMAIF" #reg " Playback Client Channels", reg - 1,\
+ 0, 16, 0, tegra_admaif_get_control, \
+ tegra_admaif_put_control), \
+ SOC_SINGLE_EXT("ADMAIF" #reg " Capture Client Channels", reg - 1, \
+ 0, 16, 0, tegra_admaif_get_control, \
+ tegra_admaif_put_control)
/*
- * below macro is added to avoid looping over all ADMAIFx controls related
+ * Below macro is added to avoid looping over all ADMAIFx controls related
* to mono/stereo conversions in get()/put() callbacks.
*/
#define NV_SOC_ENUM_EXT(xname, xreg, xhandler_get, xhandler_put, xenum_text) \
@@ -899,17 +595,17 @@ static const struct soc_enum tegra_admaif_stereo_conv_enum =
}
#define TEGRA_ADMAIF_CIF_CTRL(reg) \
- NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback mono to stereo conv", reg - 1,\
- tegra_admaif_get_format, tegra_admaif_put_format, \
+ NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Mono To Stereo", reg - 1,\
+ tegra_admaif_get_control, tegra_admaif_put_control, \
tegra_admaif_mono_conv_text), \
- NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback stereo to mono conv", reg - 1,\
- tegra_admaif_get_format, tegra_admaif_put_format, \
+ NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Stereo To Mono", reg - 1,\
+ tegra_admaif_get_control, tegra_admaif_put_control, \
tegra_admaif_stereo_conv_text), \
- NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture mono to stereo conv", reg - 1, \
- tegra_admaif_get_format, tegra_admaif_put_format, \
+ NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Mono To Stereo", reg - 1, \
+ tegra_admaif_get_control, tegra_admaif_put_control, \
tegra_admaif_mono_conv_text), \
- NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture stereo to mono conv", reg - 1, \
- tegra_admaif_get_format, tegra_admaif_put_format, \
+ NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Stereo To Mono", reg - 1, \
+ tegra_admaif_get_control, tegra_admaif_put_control, \
tegra_admaif_stereo_conv_text)
static struct snd_kcontrol_new tegra210_admaif_controls[] = {
@@ -933,8 +629,6 @@ static struct snd_kcontrol_new tegra210_admaif_controls[] = {
TEGRA_ADMAIF_CIF_CTRL(8),
TEGRA_ADMAIF_CIF_CTRL(9),
TEGRA_ADMAIF_CIF_CTRL(10),
- SOC_SINGLE_EXT("APE Reg Dump", SND_SOC_NOPM, 0, 1, 0,
- tegra210_ape_dump_reg_get, tegra210_ape_dump_reg_put),
};
static struct snd_kcontrol_new tegra186_admaif_controls[] = {
@@ -978,97 +672,81 @@ static struct snd_kcontrol_new tegra186_admaif_controls[] = {
TEGRA_ADMAIF_CIF_CTRL(18),
TEGRA_ADMAIF_CIF_CTRL(19),
TEGRA_ADMAIF_CIF_CTRL(20),
- SOC_SINGLE_EXT("APE Reg Dump", SND_SOC_NOPM, 0, 1, 0,
- tegra210_ape_dump_reg_get, tegra210_ape_dump_reg_put),
};
-static struct snd_soc_codec_driver tegra210_admaif_codec = {
- .idle_bias_off = 1,
- .component_driver = {
- .dapm_widgets = tegra_admaif_widgets,
- .num_dapm_widgets = TEGRA210_ADMAIF_CHANNEL_COUNT * 4,
- .dapm_routes = tegra_admaif_routes,
- .num_dapm_routes = TEGRA210_ADMAIF_CHANNEL_COUNT * 6,
- .controls = tegra210_admaif_controls,
- .num_controls = ARRAY_SIZE(tegra210_admaif_controls),
- },
+extern const struct snd_pcm_ops tegra_pcm_ops;
+
+static const struct snd_soc_component_driver tegra210_admaif_cmpnt = {
+ .controls = tegra210_admaif_controls,
+ .num_controls = ARRAY_SIZE(tegra210_admaif_controls),
+ .pcm_new = tegra_pcm_new,
+ .pcm_free = tegra_pcm_free,
+ .ops = &tegra_pcm_ops,
};
-static struct snd_soc_codec_driver tegra186_admaif_codec = {
- .idle_bias_off = 1,
- .component_driver = {
- .dapm_widgets = tegra_admaif_widgets,
- .num_dapm_widgets = TEGRA186_ADMAIF_CHANNEL_COUNT * 4,
- .dapm_routes = tegra_admaif_routes,
- .num_dapm_routes = TEGRA186_ADMAIF_CHANNEL_COUNT * 6,
- .controls = tegra186_admaif_controls,
- .num_controls = ARRAY_SIZE(tegra186_admaif_controls),
- },
+static const struct snd_soc_component_driver tegra186_admaif_cmpnt = {
+ .controls = tegra186_admaif_controls,
+ .num_controls = ARRAY_SIZE(tegra186_admaif_controls),
+ .pcm_new = tegra_pcm_new,
+ .pcm_free = tegra_pcm_free,
+ .ops = &tegra_pcm_ops,
};
-static struct tegra_admaif_soc_data soc_data_tegra210 = {
- .num_ch = TEGRA210_ADMAIF_CHANNEL_COUNT,
- .admaif_codec = &tegra210_admaif_codec,
- .codec_dais = tegra210_admaif_codec_dais,
- .regmap_conf = &tegra210_admaif_regmap_config,
- .global_base = TEGRA210_ADMAIF_GLOBAL_BASE,
- .tx_base = TEGRA210_ADMAIF_XBAR_TX_BASE,
- .rx_base = TEGRA210_ADMAIF_XBAR_RX_BASE,
- .is_isomgr_client = false,
+static const struct tegra_admaif_soc_data soc_data_tegra210 = {
+ .num_ch = TEGRA210_ADMAIF_CHANNEL_COUNT,
+ .cmpnt = &tegra210_admaif_cmpnt,
+ .dais = tegra210_admaif_cmpnt_dais,
+ .regmap_conf = &tegra210_admaif_regmap_config,
+ .global_base = TEGRA210_ADMAIF_GLOBAL_BASE,
+ .tx_base = TEGRA210_ADMAIF_TX_BASE,
+ .rx_base = TEGRA210_ADMAIF_RX_BASE,
};
-static struct tegra_admaif_soc_data soc_data_tegra186 = {
- .num_ch = TEGRA186_ADMAIF_CHANNEL_COUNT,
- .admaif_codec = &tegra186_admaif_codec,
- .codec_dais = tegra186_admaif_codec_dais,
- .regmap_conf = &tegra186_admaif_regmap_config,
- .global_base = TEGRA186_ADMAIF_GLOBAL_BASE,
- .tx_base = TEGRA186_ADMAIF_XBAR_TX_BASE,
- .rx_base = TEGRA186_ADMAIF_XBAR_RX_BASE,
- .is_isomgr_client = true,
+static const struct tegra_admaif_soc_data soc_data_tegra186 = {
+ .num_ch = TEGRA186_ADMAIF_CHANNEL_COUNT,
+ .cmpnt = &tegra186_admaif_cmpnt,
+ .dais = tegra186_admaif_cmpnt_dais,
+ .regmap_conf = &tegra186_admaif_regmap_config,
+ .global_base = TEGRA186_ADMAIF_GLOBAL_BASE,
+ .tx_base = TEGRA186_ADMAIF_TX_BASE,
+ .rx_base = TEGRA186_ADMAIF_RX_BASE,
};
-
static const struct of_device_id tegra_admaif_of_match[] = {
{ .compatible = "nvidia,tegra210-admaif", .data = &soc_data_tegra210 },
{ .compatible = "nvidia,tegra186-admaif", .data = &soc_data_tegra186 },
{},
};
+MODULE_DEVICE_TABLE(of, tegra_admaif_of_match);
static int tegra_admaif_probe(struct platform_device *pdev)
{
- int ret, i;
struct tegra_admaif *admaif;
void __iomem *regs;
struct resource *res;
- const struct of_device_id *match;
- unsigned int buffer_size;
-
- match = of_match_device(tegra_admaif_of_match, &pdev->dev);
- if (!match) {
- dev_err(&pdev->dev, "Error: No device match found\n");
- return -ENODEV;
- }
+ int err, i;
admaif = devm_kzalloc(&pdev->dev, sizeof(*admaif), GFP_KERNEL);
if (!admaif)
return -ENOMEM;
- admaif->dev = &pdev->dev;
- admaif->soc_data = (struct tegra_admaif_soc_data *)match->data;
+ admaif->soc_data = of_device_get_match_data(&pdev->dev);
+
dev_set_drvdata(&pdev->dev, admaif);
- admaif->capture_dma_data = devm_kzalloc(&pdev->dev,
- sizeof(struct tegra_alt_pcm_dma_params) *
- admaif->soc_data->num_ch,
- GFP_KERNEL);
+ admaif->capture_dma_data =
+ devm_kcalloc(&pdev->dev,
+ admaif->soc_data->num_ch,
+ sizeof(struct snd_dmaengine_dai_dma_data),
+ GFP_KERNEL);
if (!admaif->capture_dma_data)
return -ENOMEM;
- admaif->playback_dma_data = devm_kzalloc(&pdev->dev,
- sizeof(struct tegra_alt_pcm_dma_params) *
- admaif->soc_data->num_ch,
- GFP_KERNEL);
+ admaif->playback_dma_data =
+ devm_kcalloc(&pdev->dev,
+ admaif->soc_data->num_ch,
+ sizeof(struct snd_dmaengine_dai_dma_data),
+ GFP_KERNEL);
if (!admaif->playback_dma_data)
return -ENOMEM;
@@ -1099,113 +777,72 @@ static int tegra_admaif_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(regs))
return PTR_ERR(regs);
- admaif->base_addr = regs;
+
admaif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
admaif->soc_data->regmap_conf);
if (IS_ERR(admaif->regmap)) {
dev_err(&pdev->dev, "regmap init failed\n");
return PTR_ERR(admaif->regmap);
}
+
regcache_cache_only(admaif->regmap, true);
- if (admaif->soc_data->is_isomgr_client)
- tegra_isomgr_adma_register();
-
- for (i = 0; i < admaif->soc_data->num_ch; i++) {
- admaif->playback_dma_data[i].addr = res->start +
- CH_TX_REG(TEGRA_ADMAIF_XBAR_TX_FIFO_WRITE, i);
-
- admaif->capture_dma_data[i].addr = res->start +
- CH_RX_REG(TEGRA_ADMAIF_XBAR_RX_FIFO_READ, i);
-
- admaif->playback_dma_data[i].width = 32;
- admaif->playback_dma_data[i].req_sel = i + 1;
- ret = of_property_read_string_index(pdev->dev.of_node,
- "dma-names",
- (i * 2) + 1,
- &admaif->playback_dma_data[i].chan_name);
- if (ret < 0) {
- dev_err(&pdev->dev,
- "Missing property nvidia,dma-names\n");
- return ret;
- }
- buffer_size = 0;
- if (of_property_read_u32_index(pdev->dev.of_node,
- "dma-buffer-size",
- (i * 2) + 1,
- &buffer_size) < 0) {
- dev_dbg(&pdev->dev,
- "Missing property nvidia,dma-buffer-size\n");
- }
- admaif->playback_dma_data[i].buffer_size = buffer_size;
-
- admaif->capture_dma_data[i].width = 32;
- admaif->capture_dma_data[i].req_sel = i + 1;
- ret = of_property_read_string_index(pdev->dev.of_node,
- "dma-names",
- (i * 2),
- &admaif->capture_dma_data[i].chan_name);
- if (ret < 0) {
- dev_err(&pdev->dev,
- "Missing property nvidia,dma-names\n");
- return ret;
- }
- buffer_size = 0;
- if (of_property_read_u32_index(pdev->dev.of_node,
- "dma-buffer-size",
- (i * 2),
- &buffer_size) < 0) {
- dev_dbg(&pdev->dev,
- "Missing property nvidia,dma-buffer-size\n");
- }
- admaif->capture_dma_data[i].buffer_size = buffer_size;
- }
-
regmap_update_bits(admaif->regmap, admaif->soc_data->global_base +
TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1);
- pm_runtime_enable(&pdev->dev);
- ret = snd_soc_register_codec(&pdev->dev, admaif->soc_data->admaif_codec,
- admaif->soc_data->codec_dais,
- admaif->soc_data->num_ch * 3);
- if (ret != 0) {
- dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret);
- goto pm_disable;
+ for (i = 0; i < admaif->soc_data->num_ch; i++) {
+ admaif->playback_dma_data[i].addr = res->start +
+ CH_TX_REG(TEGRA_ADMAIF_TX_FIFO_WRITE, i);
+
+ admaif->capture_dma_data[i].addr = res->start +
+ CH_RX_REG(TEGRA_ADMAIF_RX_FIFO_READ, i);
+
+ admaif->playback_dma_data[i].addr_width = 32;
+
+ if (of_property_read_string_index(pdev->dev.of_node,
+ "dma-names", (i * 2) + 1,
+ &admaif->playback_dma_data[i].chan_name) < 0) {
+ dev_err(&pdev->dev,
+ "missing property nvidia,dma-names\n");
+
+ return -ENODEV;
+ }
+
+ admaif->capture_dma_data[i].addr_width = 32;
+
+ if (of_property_read_string_index(pdev->dev.of_node,
+ "dma-names",
+ (i * 2),
+ &admaif->capture_dma_data[i].chan_name) < 0) {
+ dev_err(&pdev->dev,
+ "missing property nvidia,dma-names\n");
+
+ return -ENODEV;
+ }
}
- ret = tegra_alt_pcm_platform_register(&pdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
- goto unregister_codec;
+ err = devm_snd_soc_register_component(&pdev->dev,
+ admaif->soc_data->cmpnt,
+ admaif->soc_data->dais,
+ admaif->soc_data->num_ch);
+ if (err) {
+ dev_err(&pdev->dev,
+ "can't register ADMAIF component, err: %d\n", err);
+ return err;
}
+ pm_runtime_enable(&pdev->dev);
+
return 0;
-
-unregister_codec:
- snd_soc_unregister_codec(&pdev->dev);
-pm_disable:
- pm_runtime_disable(&pdev->dev);
-
- return ret;
}
static int tegra_admaif_remove(struct platform_device *pdev)
{
- struct tegra_admaif *admaif = dev_get_drvdata(&pdev->dev);
-
- if (admaif->soc_data->is_isomgr_client)
- tegra_isomgr_adma_unregister();
-
- snd_soc_unregister_codec(&pdev->dev);
-
- tegra_alt_pcm_platform_unregister(&pdev->dev);
-
pm_runtime_disable(&pdev->dev);
- if (!pm_runtime_status_suspended(&pdev->dev))
- tegra_admaif_runtime_suspend(&pdev->dev);
return 0;
}
@@ -1213,24 +850,21 @@ static int tegra_admaif_remove(struct platform_device *pdev)
static const struct dev_pm_ops tegra_admaif_pm_ops = {
SET_RUNTIME_PM_OPS(tegra_admaif_runtime_suspend,
tegra_admaif_runtime_resume, NULL)
- SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
};
static struct platform_driver tegra_admaif_driver = {
.probe = tegra_admaif_probe,
.remove = tegra_admaif_remove,
.driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
+ .name = "tegra210-admaif",
.of_match_table = tegra_admaif_of_match,
.pm = &tegra_admaif_pm_ops,
},
};
module_platform_driver(tegra_admaif_driver);
-MODULE_DEVICE_TABLE(of, tegra_admaif_of_match);
MODULE_AUTHOR("Songhee Baek ");
-MODULE_DESCRIPTION("Tegra ADMAIF driver");
+MODULE_DESCRIPTION("Tegra210 ASoC ADMAIF driver");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra210_admaif.h b/sound/soc/tegra/tegra210_admaif.h
index 5afe983e..e9622d10 100644
--- a/sound/soc/tegra/tegra210_admaif.h
+++ b/sound/soc/tegra/tegra210_admaif.h
@@ -1,156 +1,132 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * tegra210_admaif_alt.h - Tegra ADMAIF registers
+ * tegra210_admaif.h - Tegra ADMAIF registers
*
- * Copyright (c) 2014-2019 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
*/
-#ifndef __TEGRA_ADMAIF_ALT_H__
-#define __TEGRA_ADMAIF_ALT_H__
+#ifndef __TEGRA_ADMAIF_H__
+#define __TEGRA_ADMAIF_H__
-#define TEGRA_ADMAIF_CHANNEL_REG_STRIDE 0x40
-
-#define TEGRA210_ADMAIF_LAST_REG 0x75f
-#define TEGRA186_ADMAIF_LAST_REG 0xd5f
-
-#define TEGRA210_ADMAIF_CHANNEL_COUNT 10
-#define TEGRA186_ADMAIF_CHANNEL_COUNT 20
-
-#define TEGRA210_ADMAIF_XBAR_RX_BASE 0x0
-#define TEGRA210_ADMAIF_XBAR_TX_BASE 0x300
-#define TEGRA210_ADMAIF_GLOBAL_BASE 0x700
-
-#define TEGRA186_ADMAIF_XBAR_RX_BASE 0x0
-#define TEGRA186_ADMAIF_XBAR_TX_BASE 0x500
-#define TEGRA186_ADMAIF_GLOBAL_BASE 0xd00
-
-#define TEGRA_ADMAIF_XBAR_RX_ENABLE 0x0
-#define TEGRA_ADMAIF_XBAR_RX_SOFT_RESET 0x4
-#define TEGRA_ADMAIF_XBAR_RX_STATUS 0xc
-#define TEGRA_ADMAIF_XBAR_RX_INT_STATUS 0x10
-#define TEGRA_ADMAIF_XBAR_RX_INT_MASK 0x14
-#define TEGRA_ADMAIF_XBAR_RX_INT_SET 0x18
-#define TEGRA_ADMAIF_XBAR_RX_INT_CLEAR 0x1c
-#define TEGRA_ADMAIF_CHAN_ACIF_RX_CTRL 0x20
-#define TEGRA_ADMAIF_XBAR_RX_FIFO_CTRL 0x28
-#define TEGRA_ADMAIF_XBAR_RX_FIFO_READ 0x2c
-#define TEGRA_ADMAIF_GLOBAL_ENABLE 0x0
-#define TEGRA_ADMAIF_GLOBAL_CG_0 0x8
-#define TEGRA_ADMAIF_GLOBAL_STATUS 0x10
-#define TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS 0x20
-#define TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS 0x24
-
-#define TEGRA_ADMAIF_XBAR_TX_ENABLE 0x0
-#define TEGRA_ADMAIF_XBAR_TX_SOFT_RESET 0x4
-#define TEGRA_ADMAIF_XBAR_TX_STATUS 0xc
-#define TEGRA_ADMAIF_XBAR_TX_INT_STATUS 0x10
-#define TEGRA_ADMAIF_XBAR_TX_INT_MASK 0x14
-#define TEGRA_ADMAIF_XBAR_TX_INT_SET 0x18
-#define TEGRA_ADMAIF_XBAR_TX_INT_CLEAR 0x1c
-#define TEGRA_ADMAIF_CHAN_ACIF_TX_CTRL 0x20
-#define TEGRA_ADMAIF_XBAR_TX_FIFO_CTRL 0x28
-#define TEGRA_ADMAIF_XBAR_TX_FIFO_WRITE 0x2c
-
-#define TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN_SHIFT 31
-#define TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN_MASK \
- (1 << TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN_SHIFT)
-#define TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN \
- (1 << TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK8_EN_SHIFT)
-#define TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN_SHIFT 30
-#define TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN_MASK \
- (1 << TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN_SHIFT)
-#define TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN \
- (1 << TEGRA_ADMAIF_CHAN_ACIF_CTRL_PACK16_EN_SHIFT)
-
-#define TEGRA_ADMAIF_XBAR_TX_ENABLE_SHIFT 0
-#define TEGRA_ADMAIF_XBAR_TX_EN \
- (1 << TEGRA_ADMAIF_XBAR_TX_ENABLE_SHIFT)
-#define TEGRA_ADMAIF_XBAR_TX_ENABLE_MASK \
- (1 << TEGRA_ADMAIF_XBAR_TX_ENABLE_SHIFT)
-
-#define TEGRA_ADMAIF_XBAR_RX_ENABLE_SHIFT 0
-#define TEGRA_ADMAIF_XBAR_RX_EN \
- (1 << TEGRA_ADMAIF_XBAR_RX_ENABLE_SHIFT)
-#define TEGRA_ADMAIF_XBAR_RX_ENABLE_MASK \
- (1 << TEGRA_ADMAIF_XBAR_RX_ENABLE_SHIFT)
-
-#define SW_RESET_MASK 1
-#define SW_RESET 1
-
-#define TEGRA210_ADMAIF_RX1_FIFO_CTRL_REG_DEFAULT 0x00000300
-#define TEGRA210_ADMAIF_RX2_FIFO_CTRL_REG_DEFAULT 0x00000304
-#define TEGRA210_ADMAIF_RX3_FIFO_CTRL_REG_DEFAULT 0x00000208
-#define TEGRA210_ADMAIF_RX4_FIFO_CTRL_REG_DEFAULT 0x0000020b
-#define TEGRA210_ADMAIF_RX5_FIFO_CTRL_REG_DEFAULT 0x0000020e
-#define TEGRA210_ADMAIF_RX6_FIFO_CTRL_REG_DEFAULT 0x00000211
-#define TEGRA210_ADMAIF_RX7_FIFO_CTRL_REG_DEFAULT 0x00000214
-#define TEGRA210_ADMAIF_RX8_FIFO_CTRL_REG_DEFAULT 0x00000217
-#define TEGRA210_ADMAIF_RX9_FIFO_CTRL_REG_DEFAULT 0x0000021a
-#define TEGRA210_ADMAIF_RX10_FIFO_CTRL_REG_DEFAULT 0x0000021d
-
-#define TEGRA210_ADMAIF_TX1_FIFO_CTRL_REG_DEFAULT 0x02000300
-#define TEGRA210_ADMAIF_TX2_FIFO_CTRL_REG_DEFAULT 0x02000304
-#define TEGRA210_ADMAIF_TX3_FIFO_CTRL_REG_DEFAULT 0x01800208
-#define TEGRA210_ADMAIF_TX4_FIFO_CTRL_REG_DEFAULT 0x0180020b
-#define TEGRA210_ADMAIF_TX5_FIFO_CTRL_REG_DEFAULT 0x0180020e
-#define TEGRA210_ADMAIF_TX6_FIFO_CTRL_REG_DEFAULT 0x01800211
-#define TEGRA210_ADMAIF_TX7_FIFO_CTRL_REG_DEFAULT 0x01800214
-#define TEGRA210_ADMAIF_TX8_FIFO_CTRL_REG_DEFAULT 0x01800217
-#define TEGRA210_ADMAIF_TX9_FIFO_CTRL_REG_DEFAULT 0x0180021a
-#define TEGRA210_ADMAIF_TX10_FIFO_CTRL_REG_DEFAULT 0x0180021d
-
-#define TEGRA186_ADMAIF_RX1_FIFO_CTRL_REG_DEFAULT 0x00000300
-#define TEGRA186_ADMAIF_RX2_FIFO_CTRL_REG_DEFAULT 0x00000304
-#define TEGRA186_ADMAIF_RX3_FIFO_CTRL_REG_DEFAULT 0x00000308
-#define TEGRA186_ADMAIF_RX4_FIFO_CTRL_REG_DEFAULT 0x0000030c
-#define TEGRA186_ADMAIF_RX5_FIFO_CTRL_REG_DEFAULT 0x00000210
-#define TEGRA186_ADMAIF_RX6_FIFO_CTRL_REG_DEFAULT 0x00000213
-#define TEGRA186_ADMAIF_RX7_FIFO_CTRL_REG_DEFAULT 0x00000216
-#define TEGRA186_ADMAIF_RX8_FIFO_CTRL_REG_DEFAULT 0x00000219
-#define TEGRA186_ADMAIF_RX9_FIFO_CTRL_REG_DEFAULT 0x0000021c
-#define TEGRA186_ADMAIF_RX10_FIFO_CTRL_REG_DEFAULT 0x0000021f
-#define TEGRA186_ADMAIF_RX11_FIFO_CTRL_REG_DEFAULT 0x00000222
-#define TEGRA186_ADMAIF_RX12_FIFO_CTRL_REG_DEFAULT 0x00000225
-#define TEGRA186_ADMAIF_RX13_FIFO_CTRL_REG_DEFAULT 0x00000228
-#define TEGRA186_ADMAIF_RX14_FIFO_CTRL_REG_DEFAULT 0x0000022b
-#define TEGRA186_ADMAIF_RX15_FIFO_CTRL_REG_DEFAULT 0x0000022e
-#define TEGRA186_ADMAIF_RX16_FIFO_CTRL_REG_DEFAULT 0x00000231
-#define TEGRA186_ADMAIF_RX17_FIFO_CTRL_REG_DEFAULT 0x00000234
-#define TEGRA186_ADMAIF_RX18_FIFO_CTRL_REG_DEFAULT 0x00000237
-#define TEGRA186_ADMAIF_RX19_FIFO_CTRL_REG_DEFAULT 0x0000023a
-#define TEGRA186_ADMAIF_RX20_FIFO_CTRL_REG_DEFAULT 0x0000023d
-
-#define TEGRA186_ADMAIF_TX1_FIFO_CTRL_REG_DEFAULT 0x02000300
-#define TEGRA186_ADMAIF_TX2_FIFO_CTRL_REG_DEFAULT 0x02000304
-#define TEGRA186_ADMAIF_TX3_FIFO_CTRL_REG_DEFAULT 0x02000308
-#define TEGRA186_ADMAIF_TX4_FIFO_CTRL_REG_DEFAULT 0x0200030c
-#define TEGRA186_ADMAIF_TX5_FIFO_CTRL_REG_DEFAULT 0x01800210
-#define TEGRA186_ADMAIF_TX6_FIFO_CTRL_REG_DEFAULT 0x01800213
-#define TEGRA186_ADMAIF_TX7_FIFO_CTRL_REG_DEFAULT 0x01800216
-#define TEGRA186_ADMAIF_TX8_FIFO_CTRL_REG_DEFAULT 0x01800219
-#define TEGRA186_ADMAIF_TX9_FIFO_CTRL_REG_DEFAULT 0x0180021c
-#define TEGRA186_ADMAIF_TX10_FIFO_CTRL_REG_DEFAULT 0x0180021f
-#define TEGRA186_ADMAIF_TX11_FIFO_CTRL_REG_DEFAULT 0x01800222
-#define TEGRA186_ADMAIF_TX12_FIFO_CTRL_REG_DEFAULT 0x01800225
-#define TEGRA186_ADMAIF_TX13_FIFO_CTRL_REG_DEFAULT 0x01800228
-#define TEGRA186_ADMAIF_TX14_FIFO_CTRL_REG_DEFAULT 0x0180022b
-#define TEGRA186_ADMAIF_TX15_FIFO_CTRL_REG_DEFAULT 0x0180022e
-#define TEGRA186_ADMAIF_TX16_FIFO_CTRL_REG_DEFAULT 0x01800231
-#define TEGRA186_ADMAIF_TX17_FIFO_CTRL_REG_DEFAULT 0x01800234
-#define TEGRA186_ADMAIF_TX18_FIFO_CTRL_REG_DEFAULT 0x01800237
-#define TEGRA186_ADMAIF_TX19_FIFO_CTRL_REG_DEFAULT 0x0180023a
-#define TEGRA186_ADMAIF_TX20_FIFO_CTRL_REG_DEFAULT 0x0180023d
+#define TEGRA_ADMAIF_CHANNEL_REG_STRIDE 0x40
+/* Tegra210 specific */
+#define TEGRA210_ADMAIF_LAST_REG 0x75f
+#define TEGRA210_ADMAIF_CHANNEL_COUNT 10
+#define TEGRA210_ADMAIF_RX_BASE 0x0
+#define TEGRA210_ADMAIF_TX_BASE 0x300
+#define TEGRA210_ADMAIF_GLOBAL_BASE 0x700
+/* Tegra186 specific */
+#define TEGRA186_ADMAIF_LAST_REG 0xd5f
+#define TEGRA186_ADMAIF_CHANNEL_COUNT 20
+#define TEGRA186_ADMAIF_RX_BASE 0x0
+#define TEGRA186_ADMAIF_TX_BASE 0x500
+#define TEGRA186_ADMAIF_GLOBAL_BASE 0xd00
+/* Global registers */
+#define TEGRA_ADMAIF_GLOBAL_ENABLE 0x0
+#define TEGRA_ADMAIF_GLOBAL_CG_0 0x8
+#define TEGRA_ADMAIF_GLOBAL_STATUS 0x10
+#define TEGRA_ADMAIF_GLOBAL_RX_ENABLE_STATUS 0x20
+#define TEGRA_ADMAIF_GLOBAL_TX_ENABLE_STATUS 0x24
+/* RX channel registers */
+#define TEGRA_ADMAIF_RX_ENABLE 0x0
+#define TEGRA_ADMAIF_RX_SOFT_RESET 0x4
+#define TEGRA_ADMAIF_RX_STATUS 0xc
+#define TEGRA_ADMAIF_RX_INT_STATUS 0x10
+#define TEGRA_ADMAIF_RX_INT_MASK 0x14
+#define TEGRA_ADMAIF_RX_INT_SET 0x18
+#define TEGRA_ADMAIF_RX_INT_CLEAR 0x1c
+#define TEGRA_ADMAIF_CH_ACIF_RX_CTRL 0x20
+#define TEGRA_ADMAIF_RX_FIFO_CTRL 0x28
+#define TEGRA_ADMAIF_RX_FIFO_READ 0x2c
+/* TX channel registers */
+#define TEGRA_ADMAIF_TX_ENABLE 0x0
+#define TEGRA_ADMAIF_TX_SOFT_RESET 0x4
+#define TEGRA_ADMAIF_TX_STATUS 0xc
+#define TEGRA_ADMAIF_TX_INT_STATUS 0x10
+#define TEGRA_ADMAIF_TX_INT_MASK 0x14
+#define TEGRA_ADMAIF_TX_INT_SET 0x18
+#define TEGRA_ADMAIF_TX_INT_CLEAR 0x1c
+#define TEGRA_ADMAIF_CH_ACIF_TX_CTRL 0x20
+#define TEGRA_ADMAIF_TX_FIFO_CTRL 0x28
+#define TEGRA_ADMAIF_TX_FIFO_WRITE 0x2c
+/* Bit fields */
+#define PACK8_EN_SHIFT 31
+#define PACK8_EN_MASK BIT(PACK8_EN_SHIFT)
+#define PACK8_EN BIT(PACK8_EN_SHIFT)
+#define PACK16_EN_SHIFT 30
+#define PACK16_EN_MASK BIT(PACK16_EN_SHIFT)
+#define PACK16_EN BIT(PACK16_EN_SHIFT)
+#define TX_ENABLE_SHIFT 0
+#define TX_ENABLE_MASK BIT(TX_ENABLE_SHIFT)
+#define TX_ENABLE BIT(TX_ENABLE_SHIFT)
+#define RX_ENABLE_SHIFT 0
+#define RX_ENABLE_MASK BIT(RX_ENABLE_SHIFT)
+#define RX_ENABLE BIT(RX_ENABLE_SHIFT)
+#define SW_RESET_MASK 1
+#define SW_RESET 1
+/* Default values - Tegra210 */
+#define TEGRA210_ADMAIF_RX1_FIFO_CTRL_REG_DEFAULT 0x00000300
+#define TEGRA210_ADMAIF_RX2_FIFO_CTRL_REG_DEFAULT 0x00000304
+#define TEGRA210_ADMAIF_RX3_FIFO_CTRL_REG_DEFAULT 0x00000208
+#define TEGRA210_ADMAIF_RX4_FIFO_CTRL_REG_DEFAULT 0x0000020b
+#define TEGRA210_ADMAIF_RX5_FIFO_CTRL_REG_DEFAULT 0x0000020e
+#define TEGRA210_ADMAIF_RX6_FIFO_CTRL_REG_DEFAULT 0x00000211
+#define TEGRA210_ADMAIF_RX7_FIFO_CTRL_REG_DEFAULT 0x00000214
+#define TEGRA210_ADMAIF_RX8_FIFO_CTRL_REG_DEFAULT 0x00000217
+#define TEGRA210_ADMAIF_RX9_FIFO_CTRL_REG_DEFAULT 0x0000021a
+#define TEGRA210_ADMAIF_RX10_FIFO_CTRL_REG_DEFAULT 0x0000021d
+#define TEGRA210_ADMAIF_TX1_FIFO_CTRL_REG_DEFAULT 0x02000300
+#define TEGRA210_ADMAIF_TX2_FIFO_CTRL_REG_DEFAULT 0x02000304
+#define TEGRA210_ADMAIF_TX3_FIFO_CTRL_REG_DEFAULT 0x01800208
+#define TEGRA210_ADMAIF_TX4_FIFO_CTRL_REG_DEFAULT 0x0180020b
+#define TEGRA210_ADMAIF_TX5_FIFO_CTRL_REG_DEFAULT 0x0180020e
+#define TEGRA210_ADMAIF_TX6_FIFO_CTRL_REG_DEFAULT 0x01800211
+#define TEGRA210_ADMAIF_TX7_FIFO_CTRL_REG_DEFAULT 0x01800214
+#define TEGRA210_ADMAIF_TX8_FIFO_CTRL_REG_DEFAULT 0x01800217
+#define TEGRA210_ADMAIF_TX9_FIFO_CTRL_REG_DEFAULT 0x0180021a
+#define TEGRA210_ADMAIF_TX10_FIFO_CTRL_REG_DEFAULT 0x0180021d
+/* Default values - Tegra186 */
+#define TEGRA186_ADMAIF_RX1_FIFO_CTRL_REG_DEFAULT 0x00000300
+#define TEGRA186_ADMAIF_RX2_FIFO_CTRL_REG_DEFAULT 0x00000304
+#define TEGRA186_ADMAIF_RX3_FIFO_CTRL_REG_DEFAULT 0x00000308
+#define TEGRA186_ADMAIF_RX4_FIFO_CTRL_REG_DEFAULT 0x0000030c
+#define TEGRA186_ADMAIF_RX5_FIFO_CTRL_REG_DEFAULT 0x00000210
+#define TEGRA186_ADMAIF_RX6_FIFO_CTRL_REG_DEFAULT 0x00000213
+#define TEGRA186_ADMAIF_RX7_FIFO_CTRL_REG_DEFAULT 0x00000216
+#define TEGRA186_ADMAIF_RX8_FIFO_CTRL_REG_DEFAULT 0x00000219
+#define TEGRA186_ADMAIF_RX9_FIFO_CTRL_REG_DEFAULT 0x0000021c
+#define TEGRA186_ADMAIF_RX10_FIFO_CTRL_REG_DEFAULT 0x0000021f
+#define TEGRA186_ADMAIF_RX11_FIFO_CTRL_REG_DEFAULT 0x00000222
+#define TEGRA186_ADMAIF_RX12_FIFO_CTRL_REG_DEFAULT 0x00000225
+#define TEGRA186_ADMAIF_RX13_FIFO_CTRL_REG_DEFAULT 0x00000228
+#define TEGRA186_ADMAIF_RX14_FIFO_CTRL_REG_DEFAULT 0x0000022b
+#define TEGRA186_ADMAIF_RX15_FIFO_CTRL_REG_DEFAULT 0x0000022e
+#define TEGRA186_ADMAIF_RX16_FIFO_CTRL_REG_DEFAULT 0x00000231
+#define TEGRA186_ADMAIF_RX17_FIFO_CTRL_REG_DEFAULT 0x00000234
+#define TEGRA186_ADMAIF_RX18_FIFO_CTRL_REG_DEFAULT 0x00000237
+#define TEGRA186_ADMAIF_RX19_FIFO_CTRL_REG_DEFAULT 0x0000023a
+#define TEGRA186_ADMAIF_RX20_FIFO_CTRL_REG_DEFAULT 0x0000023d
+#define TEGRA186_ADMAIF_TX1_FIFO_CTRL_REG_DEFAULT 0x02000300
+#define TEGRA186_ADMAIF_TX2_FIFO_CTRL_REG_DEFAULT 0x02000304
+#define TEGRA186_ADMAIF_TX3_FIFO_CTRL_REG_DEFAULT 0x02000308
+#define TEGRA186_ADMAIF_TX4_FIFO_CTRL_REG_DEFAULT 0x0200030c
+#define TEGRA186_ADMAIF_TX5_FIFO_CTRL_REG_DEFAULT 0x01800210
+#define TEGRA186_ADMAIF_TX6_FIFO_CTRL_REG_DEFAULT 0x01800213
+#define TEGRA186_ADMAIF_TX7_FIFO_CTRL_REG_DEFAULT 0x01800216
+#define TEGRA186_ADMAIF_TX8_FIFO_CTRL_REG_DEFAULT 0x01800219
+#define TEGRA186_ADMAIF_TX9_FIFO_CTRL_REG_DEFAULT 0x0180021c
+#define TEGRA186_ADMAIF_TX10_FIFO_CTRL_REG_DEFAULT 0x0180021f
+#define TEGRA186_ADMAIF_TX11_FIFO_CTRL_REG_DEFAULT 0x01800222
+#define TEGRA186_ADMAIF_TX12_FIFO_CTRL_REG_DEFAULT 0x01800225
+#define TEGRA186_ADMAIF_TX13_FIFO_CTRL_REG_DEFAULT 0x01800228
+#define TEGRA186_ADMAIF_TX14_FIFO_CTRL_REG_DEFAULT 0x0180022b
+#define TEGRA186_ADMAIF_TX15_FIFO_CTRL_REG_DEFAULT 0x0180022e
+#define TEGRA186_ADMAIF_TX16_FIFO_CTRL_REG_DEFAULT 0x01800231
+#define TEGRA186_ADMAIF_TX17_FIFO_CTRL_REG_DEFAULT 0x01800234
+#define TEGRA186_ADMAIF_TX18_FIFO_CTRL_REG_DEFAULT 0x01800237
+#define TEGRA186_ADMAIF_TX19_FIFO_CTRL_REG_DEFAULT 0x0180023a
+#define TEGRA186_ADMAIF_TX20_FIFO_CTRL_REG_DEFAULT 0x0180023d
enum {
DATA_8BIT,
@@ -165,31 +141,24 @@ enum {
};
struct tegra_admaif_soc_data {
- unsigned int num_ch;
- struct snd_soc_dai_driver *codec_dais;
- struct snd_soc_codec_driver *admaif_codec;
+ const struct snd_soc_component_driver *cmpnt;
const struct regmap_config *regmap_conf;
- bool is_isomgr_client;
+ struct snd_soc_dai_driver *dais;
unsigned int global_base;
unsigned int tx_base;
unsigned int rx_base;
+ unsigned int num_ch;
};
struct tegra_admaif {
- /* regmap for admaif */
- struct regmap *regmap;
- struct device *dev;
- struct tegra_alt_pcm_dma_params *capture_dma_data;
- struct tegra_alt_pcm_dma_params *playback_dma_data;
+ struct snd_dmaengine_dai_dma_data *capture_dma_data;
+ struct snd_dmaengine_dai_dma_data *playback_dma_data;
const struct tegra_admaif_soc_data *soc_data;
unsigned int *audio_ch_override[ADMAIF_PATHS];
unsigned int *client_ch_override[ADMAIF_PATHS];
unsigned int *mono_to_stereo[ADMAIF_PATHS];
unsigned int *stereo_to_mono[ADMAIF_PATHS];
- int reg_dump_flag;
- void __iomem *base_addr;
+ struct regmap *regmap;
};
-extern void tegra_adma_dump_ch_reg(void);
-
#endif
diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c
new file mode 100644
index 00000000..e1358ea7
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ahub.c
@@ -0,0 +1,651 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * tegra210_ahub.c - Tegra210 AHUB driver
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "tegra210_ahub.h"
+
+static int tegra_ahub_get_value_enum(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *uctl)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_kcontrol_component(kctl);
+ struct tegra_ahub *ahub = snd_soc_component_get_drvdata(cmpnt);
+ struct soc_enum *e = (struct soc_enum *)kctl->private_value;
+ unsigned int reg, i, bit_pos = 0;
+
+ /*
+ * Find the bit position of current MUX input.
+ * If nothing is set, position would be 0 and it corresponds to 'None'.
+ */
+ for (i = 0; i < ahub->soc_data->reg_count; i++) {
+ unsigned int reg_val;
+
+ reg = e->reg + (TEGRA210_XBAR_PART1_RX * i);
+ snd_soc_component_read(cmpnt, reg, ®_val);
+ reg_val &= ahub->soc_data->mask[i];
+
+ if (reg_val) {
+ bit_pos = ffs(reg_val) +
+ (8 * cmpnt->val_bytes * i);
+ break;
+ }
+ }
+
+ /* Find index related to the item in array *_ahub_mux_texts[] */
+ for (i = 0; i < e->items; i++) {
+ if (bit_pos == e->values[i]) {
+ uctl->value.enumerated.item[0] = i;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int tegra_ahub_put_value_enum(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *uctl)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_kcontrol_component(kctl);
+ struct tegra_ahub *ahub = snd_soc_component_get_drvdata(cmpnt);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctl);
+ struct soc_enum *e = (struct soc_enum *)kctl->private_value;
+ struct snd_soc_dapm_update update[TEGRA_XBAR_UPDATE_MAX_REG] = { };
+ unsigned int *item = uctl->value.enumerated.item;
+ unsigned int value = e->values[item[0]];
+ unsigned int i, bit_pos, reg_idx = 0, reg_val = 0;
+
+ if (item[0] >= e->items)
+ return -EINVAL;
+
+ if (value) {
+ /* Get the register index and value to set */
+ reg_idx = (value - 1) / (8 * cmpnt->val_bytes);
+ bit_pos = (value - 1) % (8 * cmpnt->val_bytes);
+ reg_val = BIT(bit_pos);
+ }
+
+ /*
+ * Run through all parts of a MUX register to find the state changes.
+ * There will be an additional update if new MUX input value is from
+ * different part of the MUX register.
+ */
+ for (i = 0; i < ahub->soc_data->reg_count; i++) {
+ update[i].reg = e->reg + (TEGRA210_XBAR_PART1_RX * i);
+ update[i].val = (i == reg_idx) ? reg_val : 0;
+ update[i].mask = ahub->soc_data->mask[i];
+ update[i].kcontrol = kctl;
+
+ /* Update widget power if state has changed */
+ if (snd_soc_component_test_bits(cmpnt, update[i].reg,
+ update[i].mask, update[i].val))
+ snd_soc_dapm_mux_update_power(dapm, kctl, item[0], e,
+ &update[i]);
+ }
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver tegra210_ahub_dais[] = {
+ DAI(ADMAIF1),
+ DAI(ADMAIF2),
+ DAI(ADMAIF3),
+ DAI(ADMAIF4),
+ DAI(ADMAIF5),
+ DAI(ADMAIF6),
+ DAI(ADMAIF7),
+ DAI(ADMAIF8),
+ DAI(ADMAIF9),
+ DAI(ADMAIF10),
+ DAI(I2S1),
+ DAI(I2S2),
+ DAI(I2S3),
+ DAI(I2S4),
+ DAI(I2S5),
+ DAI(DMIC1),
+ DAI(DMIC2),
+ DAI(DMIC3),
+};
+
+static struct snd_soc_dai_driver tegra186_ahub_dais[] = {
+ DAI(ADMAIF1),
+ DAI(ADMAIF2),
+ DAI(ADMAIF3),
+ DAI(ADMAIF4),
+ DAI(ADMAIF5),
+ DAI(ADMAIF6),
+ DAI(ADMAIF7),
+ DAI(ADMAIF8),
+ DAI(ADMAIF9),
+ DAI(ADMAIF10),
+ DAI(ADMAIF11),
+ DAI(ADMAIF12),
+ DAI(ADMAIF13),
+ DAI(ADMAIF14),
+ DAI(ADMAIF15),
+ DAI(ADMAIF16),
+ DAI(ADMAIF17),
+ DAI(ADMAIF18),
+ DAI(ADMAIF19),
+ DAI(ADMAIF20),
+ DAI(I2S1),
+ DAI(I2S2),
+ DAI(I2S3),
+ DAI(I2S4),
+ DAI(I2S5),
+ DAI(I2S6),
+ DAI(DMIC1),
+ DAI(DMIC2),
+ DAI(DMIC3),
+ DAI(DMIC4),
+ DAI(DSPK1),
+ DAI(DSPK2),
+};
+
+static const char * const tegra210_ahub_mux_texts[] = {
+ "None",
+ "ADMAIF1",
+ "ADMAIF2",
+ "ADMAIF3",
+ "ADMAIF4",
+ "ADMAIF5",
+ "ADMAIF6",
+ "ADMAIF7",
+ "ADMAIF8",
+ "ADMAIF9",
+ "ADMAIF10",
+ "I2S1",
+ "I2S2",
+ "I2S3",
+ "I2S4",
+ "I2S5",
+ "DMIC1",
+ "DMIC2",
+ "DMIC3",
+};
+
+static const char * const tegra186_ahub_mux_texts[] = {
+ "None",
+ "ADMAIF1",
+ "ADMAIF2",
+ "ADMAIF3",
+ "ADMAIF4",
+ "ADMAIF5",
+ "ADMAIF6",
+ "ADMAIF7",
+ "ADMAIF8",
+ "ADMAIF9",
+ "ADMAIF10",
+ "ADMAIF11",
+ "ADMAIF12",
+ "ADMAIF13",
+ "ADMAIF14",
+ "ADMAIF15",
+ "ADMAIF16",
+ "I2S1",
+ "I2S2",
+ "I2S3",
+ "I2S4",
+ "I2S5",
+ "I2S6",
+ "ADMAIF17",
+ "ADMAIF18",
+ "ADMAIF19",
+ "ADMAIF20",
+ "DMIC1",
+ "DMIC2",
+ "DMIC3",
+ "DMIC4",
+};
+
+static const unsigned int tegra210_ahub_mux_values[] = {
+ 0,
+ MUX_VALUE(0, 0),
+ MUX_VALUE(0, 1),
+ MUX_VALUE(0, 2),
+ MUX_VALUE(0, 3),
+ MUX_VALUE(0, 4),
+ MUX_VALUE(0, 5),
+ MUX_VALUE(0, 6),
+ MUX_VALUE(0, 7),
+ MUX_VALUE(0, 8),
+ MUX_VALUE(0, 9),
+ MUX_VALUE(0, 16),
+ MUX_VALUE(0, 17),
+ MUX_VALUE(0, 18),
+ MUX_VALUE(0, 19),
+ MUX_VALUE(0, 20),
+};
+
+static const unsigned int tegra186_ahub_mux_values[] = {
+ 0,
+ MUX_VALUE(0, 0),
+ MUX_VALUE(0, 1),
+ MUX_VALUE(0, 2),
+ MUX_VALUE(0, 3),
+ MUX_VALUE(0, 4),
+ MUX_VALUE(0, 5),
+ MUX_VALUE(0, 6),
+ MUX_VALUE(0, 7),
+ MUX_VALUE(0, 8),
+ MUX_VALUE(0, 9),
+ MUX_VALUE(0, 10),
+ MUX_VALUE(0, 11),
+ MUX_VALUE(0, 12),
+ MUX_VALUE(0, 13),
+ MUX_VALUE(0, 14),
+ MUX_VALUE(0, 15),
+ MUX_VALUE(0, 16),
+ MUX_VALUE(0, 17),
+ MUX_VALUE(0, 18),
+ MUX_VALUE(0, 19),
+ MUX_VALUE(0, 20),
+ MUX_VALUE(0, 21),
+ MUX_VALUE(3, 16),
+ MUX_VALUE(3, 17),
+ MUX_VALUE(3, 18),
+ MUX_VALUE(3, 19),
+ MUX_VALUE(2, 18),
+ MUX_VALUE(2, 19),
+ MUX_VALUE(2, 20),
+ MUX_VALUE(2, 21),
+};
+
+/* Controls for t210 */
+MUX_ENUM_CTRL_DECL(t210_admaif1_tx, 0x00);
+MUX_ENUM_CTRL_DECL(t210_admaif2_tx, 0x01);
+MUX_ENUM_CTRL_DECL(t210_admaif3_tx, 0x02);
+MUX_ENUM_CTRL_DECL(t210_admaif4_tx, 0x03);
+MUX_ENUM_CTRL_DECL(t210_admaif5_tx, 0x04);
+MUX_ENUM_CTRL_DECL(t210_admaif6_tx, 0x05);
+MUX_ENUM_CTRL_DECL(t210_admaif7_tx, 0x06);
+MUX_ENUM_CTRL_DECL(t210_admaif8_tx, 0x07);
+MUX_ENUM_CTRL_DECL(t210_admaif9_tx, 0x08);
+MUX_ENUM_CTRL_DECL(t210_admaif10_tx, 0x09);
+MUX_ENUM_CTRL_DECL(t210_i2s1_tx, 0x10);
+MUX_ENUM_CTRL_DECL(t210_i2s2_tx, 0x11);
+MUX_ENUM_CTRL_DECL(t210_i2s3_tx, 0x12);
+MUX_ENUM_CTRL_DECL(t210_i2s4_tx, 0x13);
+MUX_ENUM_CTRL_DECL(t210_i2s5_tx, 0x14);
+
+/* Controls for t186 */
+MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00);
+MUX_ENUM_CTRL_DECL_186(t186_admaif2_tx, 0x01);
+MUX_ENUM_CTRL_DECL_186(t186_admaif3_tx, 0x02);
+MUX_ENUM_CTRL_DECL_186(t186_admaif4_tx, 0x03);
+MUX_ENUM_CTRL_DECL_186(t186_admaif5_tx, 0x04);
+MUX_ENUM_CTRL_DECL_186(t186_admaif6_tx, 0x05);
+MUX_ENUM_CTRL_DECL_186(t186_admaif7_tx, 0x06);
+MUX_ENUM_CTRL_DECL_186(t186_admaif8_tx, 0x07);
+MUX_ENUM_CTRL_DECL_186(t186_admaif9_tx, 0x08);
+MUX_ENUM_CTRL_DECL_186(t186_admaif10_tx, 0x09);
+MUX_ENUM_CTRL_DECL_186(t186_i2s1_tx, 0x10);
+MUX_ENUM_CTRL_DECL_186(t186_i2s2_tx, 0x11);
+MUX_ENUM_CTRL_DECL_186(t186_i2s3_tx, 0x12);
+MUX_ENUM_CTRL_DECL_186(t186_i2s4_tx, 0x13);
+MUX_ENUM_CTRL_DECL_186(t186_i2s5_tx, 0x14);
+MUX_ENUM_CTRL_DECL_186(t186_admaif11_tx, 0x0a);
+MUX_ENUM_CTRL_DECL_186(t186_admaif12_tx, 0x0b);
+MUX_ENUM_CTRL_DECL_186(t186_admaif13_tx, 0x0c);
+MUX_ENUM_CTRL_DECL_186(t186_admaif14_tx, 0x0d);
+MUX_ENUM_CTRL_DECL_186(t186_admaif15_tx, 0x0e);
+MUX_ENUM_CTRL_DECL_186(t186_admaif16_tx, 0x0f);
+MUX_ENUM_CTRL_DECL_186(t186_i2s6_tx, 0x15);
+MUX_ENUM_CTRL_DECL_186(t186_dspk1_tx, 0x30);
+MUX_ENUM_CTRL_DECL_186(t186_dspk2_tx, 0x31);
+MUX_ENUM_CTRL_DECL_186(t186_admaif17_tx, 0x68);
+MUX_ENUM_CTRL_DECL_186(t186_admaif18_tx, 0x69);
+MUX_ENUM_CTRL_DECL_186(t186_admaif19_tx, 0x6a);
+MUX_ENUM_CTRL_DECL_186(t186_admaif20_tx, 0x6b);
+
+/*
+ * The number of entries in, and order of, this array is closely tied to the
+ * calculation of tegra210_ahub_codec.num_dapm_widgets near the end of
+ * tegra210_ahub_probe()
+ */
+static const struct snd_soc_dapm_widget tegra210_ahub_widgets[] = {
+ WIDGETS("ADMAIF1", t210_admaif1_tx),
+ WIDGETS("ADMAIF2", t210_admaif2_tx),
+ WIDGETS("ADMAIF3", t210_admaif3_tx),
+ WIDGETS("ADMAIF4", t210_admaif4_tx),
+ WIDGETS("ADMAIF5", t210_admaif5_tx),
+ WIDGETS("ADMAIF6", t210_admaif6_tx),
+ WIDGETS("ADMAIF7", t210_admaif7_tx),
+ WIDGETS("ADMAIF8", t210_admaif8_tx),
+ WIDGETS("ADMAIF9", t210_admaif9_tx),
+ WIDGETS("ADMAIF10", t210_admaif10_tx),
+ WIDGETS("I2S1", t210_i2s1_tx),
+ WIDGETS("I2S2", t210_i2s2_tx),
+ WIDGETS("I2S3", t210_i2s3_tx),
+ WIDGETS("I2S4", t210_i2s4_tx),
+ WIDGETS("I2S5", t210_i2s5_tx),
+ TX_WIDGETS("DMIC1"),
+ TX_WIDGETS("DMIC2"),
+ TX_WIDGETS("DMIC3"),
+};
+
+static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = {
+ WIDGETS("ADMAIF1", t186_admaif1_tx),
+ WIDGETS("ADMAIF2", t186_admaif2_tx),
+ WIDGETS("ADMAIF3", t186_admaif3_tx),
+ WIDGETS("ADMAIF4", t186_admaif4_tx),
+ WIDGETS("ADMAIF5", t186_admaif5_tx),
+ WIDGETS("ADMAIF6", t186_admaif6_tx),
+ WIDGETS("ADMAIF7", t186_admaif7_tx),
+ WIDGETS("ADMAIF8", t186_admaif8_tx),
+ WIDGETS("ADMAIF9", t186_admaif9_tx),
+ WIDGETS("ADMAIF10", t186_admaif10_tx),
+ WIDGETS("ADMAIF11", t186_admaif11_tx),
+ WIDGETS("ADMAIF12", t186_admaif12_tx),
+ WIDGETS("ADMAIF13", t186_admaif13_tx),
+ WIDGETS("ADMAIF14", t186_admaif14_tx),
+ WIDGETS("ADMAIF15", t186_admaif15_tx),
+ WIDGETS("ADMAIF16", t186_admaif16_tx),
+ WIDGETS("ADMAIF17", t186_admaif17_tx),
+ WIDGETS("ADMAIF18", t186_admaif18_tx),
+ WIDGETS("ADMAIF19", t186_admaif19_tx),
+ WIDGETS("ADMAIF20", t186_admaif20_tx),
+ WIDGETS("I2S1", t186_i2s1_tx),
+ WIDGETS("I2S2", t186_i2s2_tx),
+ WIDGETS("I2S3", t186_i2s3_tx),
+ WIDGETS("I2S4", t186_i2s4_tx),
+ WIDGETS("I2S5", t186_i2s5_tx),
+ WIDGETS("I2S6", t186_i2s6_tx),
+ TX_WIDGETS("DMIC1"),
+ TX_WIDGETS("DMIC2"),
+ TX_WIDGETS("DMIC3"),
+ TX_WIDGETS("DMIC4"),
+ WIDGETS("DSPK1", t186_dspk1_tx),
+ WIDGETS("DSPK2", t186_dspk2_tx),
+};
+
+#define TEGRA_COMMON_ROUTES(name) \
+ { name " RX", NULL, name " Receive" }, \
+ { name " Transmit", NULL, name " TX" }, \
+ { name " TX", NULL, name " Mux" }, \
+ { name " Mux", "ADMAIF1", "ADMAIF1 RX" }, \
+ { name " Mux", "ADMAIF2", "ADMAIF2 RX" }, \
+ { name " Mux", "ADMAIF3", "ADMAIF3 RX" }, \
+ { name " Mux", "ADMAIF4", "ADMAIF4 RX" }, \
+ { name " Mux", "ADMAIF5", "ADMAIF5 RX" }, \
+ { name " Mux", "ADMAIF6", "ADMAIF6 RX" }, \
+ { name " Mux", "ADMAIF7", "ADMAIF7 RX" }, \
+ { name " Mux", "ADMAIF8", "ADMAIF8 RX" }, \
+ { name " Mux", "ADMAIF9", "ADMAIF9 RX" }, \
+ { name " Mux", "ADMAIF10", "ADMAIF10 RX" }, \
+ { name " Mux", "I2S1", "I2S1 RX" }, \
+ { name " Mux", "I2S2", "I2S2 RX" }, \
+ { name " Mux", "I2S3", "I2S3 RX" }, \
+ { name " Mux", "I2S4", "I2S4 RX" }, \
+ { name " Mux", "I2S5", "I2S5 RX" }, \
+ { name " Mux", "DMIC1", "DMIC1 RX" }, \
+ { name " Mux", "DMIC2", "DMIC2 RX" }, \
+ { name " Mux", "DMIC3", "DMIC3 RX" },
+
+#define TEGRA186_ONLY_ROUTES(name) \
+ { name " Mux", "ADMAIF11", "ADMAIF11 RX" }, \
+ { name " Mux", "ADMAIF12", "ADMAIF12 RX" }, \
+ { name " Mux", "ADMAIF13", "ADMAIF13 RX" }, \
+ { name " Mux", "ADMAIF14", "ADMAIF14 RX" }, \
+ { name " Mux", "ADMAIF15", "ADMAIF15 RX" }, \
+ { name " Mux", "ADMAIF16", "ADMAIF16 RX" }, \
+ { name " Mux", "ADMAIF17", "ADMAIF17 RX" }, \
+ { name " Mux", "ADMAIF18", "ADMAIF18 RX" }, \
+ { name " Mux", "ADMAIF19", "ADMAIF19 RX" }, \
+ { name " Mux", "ADMAIF20", "ADMAIF20 RX" }, \
+ { name " Mux", "I2S6", "I2S6 RX" }, \
+ { name " Mux", "DMIC4", "DMIC4 RX" },
+
+#define TEGRA210_ROUTES(name) \
+ TEGRA_COMMON_ROUTES(name)
+
+#define TEGRA186_ROUTES(name) \
+ TEGRA_COMMON_ROUTES(name) \
+ TEGRA186_ONLY_ROUTES(name)
+
+#define IN_OUT_ROUTES(name) \
+ { name " RX", NULL, name " Receive" }, \
+ { name " Transmit", NULL, name " TX" },
+
+/*
+ * The number of entries in, and order of, this array is closely tied to the
+ * calculation of tegra210_ahub_codec.num_dapm_routes near the end of
+ * tegra210_ahub_probe()
+ */
+static const struct snd_soc_dapm_route tegra210_ahub_routes[] = {
+ TEGRA210_ROUTES("ADMAIF1")
+ TEGRA210_ROUTES("ADMAIF2")
+ TEGRA210_ROUTES("ADMAIF3")
+ TEGRA210_ROUTES("ADMAIF4")
+ TEGRA210_ROUTES("ADMAIF5")
+ TEGRA210_ROUTES("ADMAIF6")
+ TEGRA210_ROUTES("ADMAIF7")
+ TEGRA210_ROUTES("ADMAIF8")
+ TEGRA210_ROUTES("ADMAIF9")
+ TEGRA210_ROUTES("ADMAIF10")
+ TEGRA210_ROUTES("I2S1")
+ TEGRA210_ROUTES("I2S2")
+ TEGRA210_ROUTES("I2S3")
+ TEGRA210_ROUTES("I2S4")
+ TEGRA210_ROUTES("I2S5")
+ IN_OUT_ROUTES("DMIC1")
+ IN_OUT_ROUTES("DMIC2")
+ IN_OUT_ROUTES("DMIC3")
+};
+
+static const struct snd_soc_dapm_route tegra186_ahub_routes[] = {
+ TEGRA186_ROUTES("ADMAIF1")
+ TEGRA186_ROUTES("ADMAIF2")
+ TEGRA186_ROUTES("ADMAIF3")
+ TEGRA186_ROUTES("ADMAIF4")
+ TEGRA186_ROUTES("ADMAIF5")
+ TEGRA186_ROUTES("ADMAIF6")
+ TEGRA186_ROUTES("ADMAIF7")
+ TEGRA186_ROUTES("ADMAIF8")
+ TEGRA186_ROUTES("ADMAIF9")
+ TEGRA186_ROUTES("ADMAIF10")
+ TEGRA186_ROUTES("ADMAIF11")
+ TEGRA186_ROUTES("ADMAIF12")
+ TEGRA186_ROUTES("ADMAIF13")
+ TEGRA186_ROUTES("ADMAIF14")
+ TEGRA186_ROUTES("ADMAIF15")
+ TEGRA186_ROUTES("ADMAIF16")
+ TEGRA186_ROUTES("ADMAIF17")
+ TEGRA186_ROUTES("ADMAIF18")
+ TEGRA186_ROUTES("ADMAIF19")
+ TEGRA186_ROUTES("ADMAIF20")
+ TEGRA186_ROUTES("I2S1")
+ TEGRA186_ROUTES("I2S2")
+ TEGRA186_ROUTES("I2S3")
+ TEGRA186_ROUTES("I2S4")
+ TEGRA186_ROUTES("I2S5")
+ TEGRA186_ROUTES("I2S6")
+ TEGRA186_ROUTES("DSPK1")
+ TEGRA186_ROUTES("DSPK2")
+ IN_OUT_ROUTES("DMIC1")
+ IN_OUT_ROUTES("DMIC2")
+ IN_OUT_ROUTES("DMIC3")
+ IN_OUT_ROUTES("DMIC4")
+};
+
+static const struct snd_soc_component_driver tegra210_ahub_component = {
+ .dapm_widgets = tegra210_ahub_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tegra210_ahub_widgets),
+ .dapm_routes = tegra210_ahub_routes,
+ .num_dapm_routes = ARRAY_SIZE(tegra210_ahub_routes),
+};
+
+static const struct snd_soc_component_driver tegra186_ahub_component = {
+ .dapm_widgets = tegra186_ahub_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tegra186_ahub_widgets),
+ .dapm_routes = tegra186_ahub_routes,
+ .num_dapm_routes = ARRAY_SIZE(tegra186_ahub_routes),
+};
+
+static const struct regmap_config tegra210_ahub_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = TEGRA210_MAX_REGISTER_ADDR,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static const struct regmap_config tegra186_ahub_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = TEGRA186_MAX_REGISTER_ADDR,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static const struct tegra_ahub_soc_data soc_data_tegra210 = {
+ .cmpnt_drv = &tegra210_ahub_component,
+ .dai_drv = tegra210_ahub_dais,
+ .num_dais = ARRAY_SIZE(tegra210_ahub_dais),
+ .regmap_config = &tegra210_ahub_regmap_config,
+ .mask[0] = TEGRA210_XBAR_REG_MASK_0,
+ .mask[1] = TEGRA210_XBAR_REG_MASK_1,
+ .mask[2] = TEGRA210_XBAR_REG_MASK_2,
+ .mask[3] = TEGRA210_XBAR_REG_MASK_3,
+ .reg_count = TEGRA210_XBAR_UPDATE_MAX_REG,
+};
+
+static const struct tegra_ahub_soc_data soc_data_tegra186 = {
+ .cmpnt_drv = &tegra186_ahub_component,
+ .dai_drv = tegra186_ahub_dais,
+ .num_dais = ARRAY_SIZE(tegra186_ahub_dais),
+ .regmap_config = &tegra186_ahub_regmap_config,
+ .mask[0] = TEGRA186_XBAR_REG_MASK_0,
+ .mask[1] = TEGRA186_XBAR_REG_MASK_1,
+ .mask[2] = TEGRA186_XBAR_REG_MASK_2,
+ .mask[3] = TEGRA186_XBAR_REG_MASK_3,
+ .reg_count = TEGRA186_XBAR_UPDATE_MAX_REG,
+};
+
+static const struct of_device_id tegra_ahub_of_match[] = {
+ { .compatible = "nvidia,tegra210-ahub", .data = &soc_data_tegra210 },
+ { .compatible = "nvidia,tegra186-ahub", .data = &soc_data_tegra186 },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tegra_ahub_of_match);
+
+static int tegra_ahub_runtime_suspend(struct device *dev)
+{
+ struct tegra_ahub *ahub = dev_get_drvdata(dev);
+
+ regcache_cache_only(ahub->regmap, true);
+ regcache_mark_dirty(ahub->regmap);
+
+ clk_disable_unprepare(ahub->clk);
+
+ return 0;
+}
+
+static int tegra_ahub_runtime_resume(struct device *dev)
+{
+ struct tegra_ahub *ahub = dev_get_drvdata(dev);
+ int err;
+
+ err = clk_prepare_enable(ahub->clk);
+ if (err) {
+ dev_err(dev, "failed to enable AHUB clock, err: %d\n", err);
+ return err;
+ }
+
+ regcache_cache_only(ahub->regmap, false);
+ regcache_sync(ahub->regmap);
+
+ return 0;
+}
+
+static int tegra_ahub_probe(struct platform_device *pdev)
+{
+ struct tegra_ahub *ahub;
+ void __iomem *regs;
+ int err;
+
+ ahub = devm_kzalloc(&pdev->dev, sizeof(*ahub), GFP_KERNEL);
+ if (!ahub)
+ return -ENOMEM;
+
+ ahub->soc_data = of_device_get_match_data(&pdev->dev);
+
+ platform_set_drvdata(pdev, ahub);
+
+ ahub->clk = devm_clk_get(&pdev->dev, "ahub");
+ if (IS_ERR(ahub->clk)) {
+ dev_err(&pdev->dev, "can't retrieve AHUB clock\n");
+ return PTR_ERR(ahub->clk);
+ }
+
+ regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ ahub->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+ ahub->soc_data->regmap_config);
+ if (IS_ERR(ahub->regmap)) {
+ dev_err(&pdev->dev, "regmap init failed\n");
+ return PTR_ERR(ahub->regmap);
+ }
+
+ regcache_cache_only(ahub->regmap, true);
+
+ err = devm_snd_soc_register_component(&pdev->dev,
+ ahub->soc_data->cmpnt_drv,
+ ahub->soc_data->dai_drv,
+ ahub->soc_data->num_dais);
+ if (err) {
+ dev_err(&pdev->dev, "can't register AHUB component, err: %d\n",
+ err);
+ return err;
+ }
+
+ err = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ if (err)
+ return err;
+
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+}
+
+static int tegra_ahub_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops tegra_ahub_pm_ops = {
+ SET_RUNTIME_PM_OPS(tegra_ahub_runtime_suspend,
+ tegra_ahub_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
+static struct platform_driver tegra_ahub_driver = {
+ .probe = tegra_ahub_probe,
+ .remove = tegra_ahub_remove,
+ .driver = {
+ .name = "tegra210-ahub",
+ .of_match_table = tegra_ahub_of_match,
+ .pm = &tegra_ahub_pm_ops,
+ },
+};
+module_platform_driver(tegra_ahub_driver);
+
+MODULE_AUTHOR("Stephen Warren ");
+MODULE_AUTHOR("Mohan Kumar ");
+MODULE_DESCRIPTION("Tegra210 ASoC AHUB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra210_ahub.h b/sound/soc/tegra/tegra210_ahub.h
new file mode 100644
index 00000000..d0fb35ca
--- /dev/null
+++ b/sound/soc/tegra/tegra210_ahub.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_ahub.h - TEGRA210 AHUB
+ *
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_AHUB__H__
+#define __TEGRA210_AHUB__H__
+
+/* Tegra210 specific */
+#define TEGRA210_XBAR_PART1_RX 0x200
+#define TEGRA210_XBAR_PART2_RX 0x400
+#define TEGRA210_XBAR_RX_STRIDE 0x4
+#define TEGRA210_XBAR_AUDIO_RX_COUNT 90
+#define TEGRA210_XBAR_REG_MASK_0 0xf1f03ff
+#define TEGRA210_XBAR_REG_MASK_1 0x3f30031f
+#define TEGRA210_XBAR_REG_MASK_2 0xff1cf313
+#define TEGRA210_XBAR_REG_MASK_3 0x0
+#define TEGRA210_XBAR_UPDATE_MAX_REG 3
+/* Tegra186 specific */
+#define TEGRA186_XBAR_PART3_RX 0x600
+#define TEGRA186_XBAR_AUDIO_RX_COUNT 115
+#define TEGRA186_XBAR_REG_MASK_0 0xf3fffff
+#define TEGRA186_XBAR_REG_MASK_1 0x3f310f1f
+#define TEGRA186_XBAR_REG_MASK_2 0xff3cf311
+#define TEGRA186_XBAR_REG_MASK_3 0x3f0f00ff
+#define TEGRA186_XBAR_UPDATE_MAX_REG 4
+
+#define TEGRA_XBAR_UPDATE_MAX_REG (TEGRA186_XBAR_UPDATE_MAX_REG)
+
+#define TEGRA186_MAX_REGISTER_ADDR (TEGRA186_XBAR_PART3_RX + \
+ (TEGRA210_XBAR_RX_STRIDE * (TEGRA186_XBAR_AUDIO_RX_COUNT - 1)))
+
+#define TEGRA210_MAX_REGISTER_ADDR (TEGRA210_XBAR_PART2_RX + \
+ (TEGRA210_XBAR_RX_STRIDE * (TEGRA210_XBAR_AUDIO_RX_COUNT - 1)))
+
+#define MUX_REG(id) (TEGRA210_XBAR_RX_STRIDE * (id))
+
+#define MUX_VALUE(npart, nbit) (1 + (nbit) + (npart) * 32)
+
+#define DAI(sname) \
+ { \
+ .name = #sname, \
+ .playback = { \
+ .stream_name = #sname " Receive", \
+ .channels_min = 1, \
+ .channels_max = 16, \
+ .rates = SNDRV_PCM_RATE_8000_192000, \
+ .formats = SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE, \
+ }, \
+ .capture = { \
+ .stream_name = #sname " Transmit", \
+ .channels_min = 1, \
+ .channels_max = 16, \
+ .rates = SNDRV_PCM_RATE_8000_192000, \
+ .formats = SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE, \
+ }, \
+ }
+
+#define SOC_VALUE_ENUM_WIDE(xreg, shift, xmax, xtexts, xvalues) \
+ { \
+ .reg = xreg, \
+ .shift_l = shift, \
+ .shift_r = shift, \
+ .items = xmax, \
+ .texts = xtexts, \
+ .values = xvalues, \
+ .mask = xmax ? roundup_pow_of_two(xmax) - 1 : 0 \
+ }
+
+#define SOC_VALUE_ENUM_WIDE_DECL(name, xreg, shift, xtexts, xvalues) \
+ static struct soc_enum name = \
+ SOC_VALUE_ENUM_WIDE(xreg, shift, ARRAY_SIZE(xtexts), \
+ xtexts, xvalues)
+
+#define MUX_ENUM_CTRL_DECL(ename, id) \
+ SOC_VALUE_ENUM_WIDE_DECL(ename##_enum, MUX_REG(id), 0, \
+ tegra210_ahub_mux_texts, \
+ tegra210_ahub_mux_values); \
+ static const struct snd_kcontrol_new ename##_control = \
+ SOC_DAPM_ENUM_EXT("Route", ename##_enum, \
+ tegra_ahub_get_value_enum, \
+ tegra_ahub_put_value_enum)
+
+#define MUX_ENUM_CTRL_DECL_186(ename, id) \
+ SOC_VALUE_ENUM_WIDE_DECL(ename##_enum, MUX_REG(id), 0, \
+ tegra186_ahub_mux_texts, \
+ tegra186_ahub_mux_values); \
+ static const struct snd_kcontrol_new ename##_control = \
+ SOC_DAPM_ENUM_EXT("Route", ename##_enum, \
+ tegra_ahub_get_value_enum, \
+ tegra_ahub_put_value_enum)
+
+#define WIDGETS(sname, ename) \
+ SND_SOC_DAPM_AIF_IN(sname " RX", NULL, 0, SND_SOC_NOPM, 0, 0), \
+ SND_SOC_DAPM_AIF_OUT(sname " TX", NULL, 0, SND_SOC_NOPM, 0, 0), \
+ SND_SOC_DAPM_MUX(sname " Mux", SND_SOC_NOPM, 0, 0, \
+ &ename##_control)
+
+#define TX_WIDGETS(sname) \
+ SND_SOC_DAPM_AIF_IN(sname " RX", NULL, 0, SND_SOC_NOPM, 0, 0), \
+ SND_SOC_DAPM_AIF_OUT(sname " TX", NULL, 0, SND_SOC_NOPM, 0, 0)
+
+struct tegra_ahub_soc_data {
+ const struct regmap_config *regmap_config;
+ const struct snd_soc_component_driver *cmpnt_drv;
+ struct snd_soc_dai_driver *dai_drv;
+ unsigned int mask[4];
+ unsigned int reg_count;
+ unsigned int num_dais;
+};
+
+struct tegra_ahub {
+ const struct tegra_ahub_soc_data *soc_data;
+ struct regmap *regmap;
+ struct clk *clk;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c
index 11469c38..f7a217a4 100644
--- a/sound/soc/tegra/tegra210_dmic.c
+++ b/sound/soc/tegra/tegra210_dmic.c
@@ -1,70 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * tegra210_dmic_alt.c - Tegra210 DMIC driver
+ * tegra210_dmic.c - Tegra210 DMIC driver
*
- * Copyright (c) 2014-2019 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
*/
#include
#include
-#include
#include
-#include
+#include
#include
#include
#include
-#include
#include
-#include
#include
#include
-#include
-#include
-
-#include "tegra210_xbar_alt.h"
-#include "tegra210_dmic_alt.h"
-#include "ahub_unit_fpga_clock.h"
-
-#define DRV_NAME "tegra210-dmic"
+#include "tegra210_dmic.h"
+#include "tegra_cif.h"
static const struct reg_default tegra210_dmic_reg_defaults[] = {
- { TEGRA210_DMIC_TX_INT_MASK, 0x00000001},
- { TEGRA210_DMIC_TX_CIF_CTRL, 0x00007700},
- { TEGRA210_DMIC_CG, 0x1},
- { TEGRA210_DMIC_CTRL, 0x00000301},
- { TEGRA210_DMIC_DCR_FILTER_GAIN, 0x00800000},
- { TEGRA210_DMIC_DCR_BIQUAD_0_COEF_0, 0x00800000},
- { TEGRA210_DMIC_DCR_BIQUAD_0_COEF_1, 0xff800000},
- { TEGRA210_DMIC_DCR_BIQUAD_0_COEF_3, 0xff800347},
- { TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4, 0xffc0ff97},
- { TEGRA210_DMIC_LP_FILTER_GAIN, 0x004c255a},
- { TEGRA210_DMIC_LP_BIQUAD_0_COEF_0, 0x00800000},
- { TEGRA210_DMIC_LP_BIQUAD_0_COEF_1, 0x00ffa74b},
- { TEGRA210_DMIC_LP_BIQUAD_0_COEF_2, 0x00800000},
- { TEGRA210_DMIC_LP_BIQUAD_0_COEF_3, 0x009e382a},
- { TEGRA210_DMIC_LP_BIQUAD_0_COEF_4, 0x00380f38},
- { TEGRA210_DMIC_LP_BIQUAD_1_COEF_0, 0x00800000},
- { TEGRA210_DMIC_LP_BIQUAD_1_COEF_1, 0x00fe1178},
- { TEGRA210_DMIC_LP_BIQUAD_1_COEF_2, 0x00800000},
- { TEGRA210_DMIC_LP_BIQUAD_1_COEF_3, 0x00e05f02},
- { TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, 0x006fc80d},
- { TEGRA210_DMIC_CORRECTION_FILTER_GAIN, 0x010628f6},
- { TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_0, 0x00800000},
- { TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_3, 0x0067ffff},
- { TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_0, 0x00800000},
- { TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_1, 0x0048f5c2},
- { TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_3, 0x00562394},
- { TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_4, 0x00169446},
+ { TEGRA210_DMIC_TX_INT_MASK, 0x00000001 },
+ { TEGRA210_DMIC_TX_CIF_CTRL, 0x00007700 },
+ { TEGRA210_DMIC_CG, 0x1 },
+ { TEGRA210_DMIC_CTRL, 0x00000301 },
+ /* Below enables all filters - DCR, LP and SC */
+ { TEGRA210_DMIC_DBG_CTRL, 0xe },
+ /* Below as per latest POR value */
+ { TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4, 0x0 },
+ /* LP filter is configured for pass through and used to apply gain */
+ { TEGRA210_DMIC_LP_BIQUAD_0_COEF_0, 0x00800000 },
+ { TEGRA210_DMIC_LP_BIQUAD_0_COEF_1, 0x0 },
+ { TEGRA210_DMIC_LP_BIQUAD_0_COEF_2, 0x0 },
+ { TEGRA210_DMIC_LP_BIQUAD_0_COEF_3, 0x0 },
+ { TEGRA210_DMIC_LP_BIQUAD_0_COEF_4, 0x0 },
+ { TEGRA210_DMIC_LP_BIQUAD_1_COEF_0, 0x00800000 },
+ { TEGRA210_DMIC_LP_BIQUAD_1_COEF_1, 0x0 },
+ { TEGRA210_DMIC_LP_BIQUAD_1_COEF_2, 0x0 },
+ { TEGRA210_DMIC_LP_BIQUAD_1_COEF_3, 0x0 },
+ { TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, 0x0 },
};
static int tegra210_dmic_runtime_suspend(struct device *dev)
@@ -74,8 +47,7 @@ static int tegra210_dmic_runtime_suspend(struct device *dev)
regcache_cache_only(dmic->regmap, true);
regcache_mark_dirty(dmic->regmap);
- if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga()))
- clk_disable_unprepare(dmic->clk_dmic);
+ clk_disable_unprepare(dmic->clk_dmic);
return 0;
}
@@ -83,14 +55,12 @@ static int tegra210_dmic_runtime_suspend(struct device *dev)
static int tegra210_dmic_runtime_resume(struct device *dev)
{
struct tegra210_dmic *dmic = dev_get_drvdata(dev);
- int ret;
+ int err;
- if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
- ret = clk_prepare_enable(dmic->clk_dmic);
- if (ret) {
- dev_err(dev, "clk_enable failed: %d\n", ret);
- return ret;
- }
+ err = clk_prepare_enable(dmic->clk_dmic);
+ if (err) {
+ dev_err(dev, "failed to enable DMIC clock, err: %d\n", err);
+ return err;
}
regcache_cache_only(dmic->regmap, false);
@@ -99,221 +69,176 @@ static int tegra210_dmic_runtime_resume(struct device *dev)
return 0;
}
-static const int tegra210_dmic_fmt_values[] = {
+static const unsigned int tegra210_dmic_fmts[] = {
0,
- TEGRA210_AUDIOCIF_BITS_16,
- TEGRA210_AUDIOCIF_BITS_32,
+ TEGRA_ACIF_BITS_16,
+ TEGRA_ACIF_BITS_32,
};
-static int tegra210_dmic_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct device *dev = dai->dev;
- struct tegra210_dmic *dmic = snd_soc_dai_get_drvdata(dai);
- int ret;
-
- if (dmic->prod_name != NULL) {
- ret = tegra_pinctrl_config_prod(dev, dmic->prod_name);
- if (ret < 0) {
- dev_warn(dev, "Failed to set %s setting\n",
- dmic->prod_name);
- }
- }
-
- return 0;
-}
-
static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
{
- struct device *dev = dai->dev;
struct tegra210_dmic *dmic = snd_soc_dai_get_drvdata(dai);
- int srate, dmic_clk, osr = dmic->osr_val, ret;
- struct tegra210_xbar_cif_conf cif_conf;
- unsigned long long boost_gain;
- unsigned int channels;
+ unsigned int srate, clk_rate, channels;
+ struct tegra_cif_conf cif_conf;
+ unsigned long long gain_q23 = DEFAULT_GAIN_Q23;
+ int err;
- memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf));
-
- srate = params_rate(params);
- if (dmic->sample_rate_via_control)
- srate = dmic->sample_rate_via_control;
- dmic_clk = (1 << (6+osr)) * srate;
+ memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
channels = params_channels(params);
- if (dmic->channels_via_control)
- channels = dmic->channels_via_control;
- cif_conf.audio_channels = channels;
+
+ cif_conf.audio_ch = channels;
+ if (dmic->audio_ch_override)
+ cif_conf.audio_ch = dmic->audio_ch_override;
switch (dmic->ch_select) {
case DMIC_CH_SELECT_LEFT:
case DMIC_CH_SELECT_RIGHT:
- cif_conf.client_channels = 1;
+ cif_conf.client_ch = 1;
break;
case DMIC_CH_SELECT_STEREO:
- cif_conf.client_channels = 2;
+ cif_conf.client_ch = 2;
break;
default:
- dev_err(dev, "unsupported ch_select value\n");
+ dev_err(dai->dev, "invalid DMIC client channels\n");
return -EINVAL;
}
- if ((tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
- program_dmic_gpio();
- program_dmic_clk(dmic_clk);
- } else {
- ret = clk_set_rate(dmic->clk_dmic, dmic_clk);
- if (ret) {
- dev_err(dev, "Can't set dmic clock rate: %d\n", ret);
- return ret;
- }
+ srate = params_rate(params);
+ if (dmic->srate_override)
+ srate = dmic->srate_override;
+
+ /*
+ * DMIC clock rate is a multiple of 'Over Sampling Ratio' and
+ * 'Sample Rate'. The supported OSR values are 64, 128 and 256.
+ */
+ clk_rate = (DMIC_OSR_FACTOR << dmic->osr_val) * srate;
+
+ err = clk_set_rate(dmic->clk_dmic, clk_rate);
+ if (err) {
+ dev_err(dai->dev, "can't set DMIC clock rate %u, err: %d\n",
+ clk_rate, err);
+ return err;
}
- regmap_update_bits(dmic->regmap, TEGRA210_DMIC_CTRL,
- TEGRA210_DMIC_CTRL_LRSEL_POLARITY_MASK,
- dmic->lrsel << LRSEL_POL_SHIFT);
- regmap_update_bits(dmic->regmap, TEGRA210_DMIC_CTRL,
- TEGRA210_DMIC_CTRL_OSR_MASK, osr << OSR_SHIFT);
- regmap_update_bits(dmic->regmap, TEGRA210_DMIC_DBG_CTRL,
- TEGRA210_DMIC_DBG_CTRL_SC_ENABLE,
- TEGRA210_DMIC_DBG_CTRL_SC_ENABLE);
- regmap_update_bits(dmic->regmap, TEGRA210_DMIC_DBG_CTRL,
- TEGRA210_DMIC_DBG_CTRL_DCR_ENABLE,
- TEGRA210_DMIC_DBG_CTRL_DCR_ENABLE);
- regmap_update_bits(dmic->regmap, TEGRA210_DMIC_CTRL,
+ regmap_update_bits(dmic->regmap,
+ /* Reg */
+ TEGRA210_DMIC_CTRL,
+ /* Mask */
+ TEGRA210_DMIC_CTRL_LRSEL_POLARITY_MASK |
+ TEGRA210_DMIC_CTRL_OSR_MASK |
TEGRA210_DMIC_CTRL_CHANNEL_SELECT_MASK,
- (dmic->ch_select + 1) << CH_SEL_SHIFT);
+ /* Value */
+ (dmic->lrsel << LRSEL_POL_SHIFT) |
+ (dmic->osr_val << OSR_SHIFT) |
+ ((dmic->ch_select + 1) << CH_SEL_SHIFT));
+
+ /*
+ * Use LP filter gain register to apply boost.
+ * Boost Gain control has 100x factor.
+ */
+ if (dmic->boost_gain)
+ gain_q23 = (gain_q23 * dmic->boost_gain) / 100;
- /* Configure LPF for passthrough and use */
- /* its gain register for applying boost; */
- /* Boost Gain control has 100x factor */
- boost_gain = 0x00800000;
- if (dmic->boost_gain > 0) {
- boost_gain = ((boost_gain * dmic->boost_gain) / 100);
- if (boost_gain > 0x7FFFFFFF) {
- dev_warn(dev, "Boost Gain overflow\n");
- boost_gain = 0x7FFFFFFF;
- }
- }
regmap_write(dmic->regmap, TEGRA210_DMIC_LP_FILTER_GAIN,
- (unsigned int)boost_gain);
-
- regmap_update_bits(dmic->regmap, TEGRA210_DMIC_DBG_CTRL,
- TEGRA210_DMIC_DBG_CTRL_LP_ENABLE,
- TEGRA210_DMIC_DBG_CTRL_LP_ENABLE);
-
- /* Configure the two biquads for passthrough, */
- /* i.e. b0=1, b1=0, b2=0, a1=0, a2=0 */
- regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_0_COEF_0,
- 0x00800000);
- regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_0_COEF_1,
- 0x00000000);
- regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_0_COEF_2,
- 0x00000000);
- regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_0_COEF_3,
- 0x00000000);
- regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_0_COEF_4,
- 0x00000000);
- regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_1_COEF_0,
- 0x00800000);
- regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_1_COEF_1,
- 0x00000000);
- regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_1_COEF_2,
- 0x00000000);
- regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_1_COEF_3,
- 0x00000000);
- regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_1_COEF_4,
- 0x00000000);
+ (unsigned int)gain_q23);
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
- cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_16;
+ cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
break;
case SNDRV_PCM_FORMAT_S32_LE:
- cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_32;
+ cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
break;
default:
- dev_err(dev, "Wrong format!\n");
- return -EINVAL;
+ dev_err(dai->dev, "unsupported format!\n");
+ return -ENOTSUPP;
}
- if (dmic->format_out)
- cif_conf.audio_bits = tegra210_dmic_fmt_values[dmic->format_out];
- cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_24;
+ if (dmic->audio_bits_override)
+ cif_conf.audio_bits =
+ tegra210_dmic_fmts[dmic->audio_bits_override];
+
+ cif_conf.client_bits = TEGRA_ACIF_BITS_24;
cif_conf.mono_conv = dmic->mono_to_stereo;
cif_conf.stereo_conv = dmic->stereo_to_mono;
- tegra210_xbar_set_cif(dmic->regmap, TEGRA210_DMIC_TX_CIF_CTRL,
- &cif_conf);
+ tegra_set_cif(dmic->regmap, TEGRA210_DMIC_TX_CIF_CTRL, &cif_conf);
return 0;
}
static int tegra210_dmic_get_control(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct tegra210_dmic *dmic = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
- if (strstr(kcontrol->id.name, "Boost"))
+ if (strstr(kcontrol->id.name, "Boost Gain"))
ucontrol->value.integer.value[0] = dmic->boost_gain;
- else if (strstr(kcontrol->id.name, "Controller Channel Select"))
+ else if (strstr(kcontrol->id.name, "Channel Select"))
ucontrol->value.integer.value[0] = dmic->ch_select;
- else if (strstr(kcontrol->id.name, "Capture mono to stereo"))
+ else if (strstr(kcontrol->id.name, "Mono To Stereo"))
ucontrol->value.integer.value[0] = dmic->mono_to_stereo;
- else if (strstr(kcontrol->id.name, "Capture stereo to mono"))
+ else if (strstr(kcontrol->id.name, "Stereo To Mono"))
ucontrol->value.integer.value[0] = dmic->stereo_to_mono;
- else if (strstr(kcontrol->id.name, "output bit format"))
- ucontrol->value.integer.value[0] = dmic->format_out;
+ else if (strstr(kcontrol->id.name, "Audio Bit Format"))
+ ucontrol->value.integer.value[0] = dmic->audio_bits_override;
else if (strstr(kcontrol->id.name, "Sample Rate"))
- ucontrol->value.integer.value[0] =
- dmic->sample_rate_via_control;
- else if (strstr(kcontrol->id.name, "Channels"))
- ucontrol->value.integer.value[0] =
- dmic->channels_via_control;
+ ucontrol->value.integer.value[0] = dmic->srate_override;
+ else if (strstr(kcontrol->id.name, "Audio Channels"))
+ ucontrol->value.integer.value[0] = dmic->audio_ch_override;
else if (strstr(kcontrol->id.name, "OSR Value"))
ucontrol->value.integer.value[0] = dmic->osr_val;
- else if (strstr(kcontrol->id.name, "LR Select"))
+ else if (strstr(kcontrol->id.name, "LR Polarity Select"))
ucontrol->value.integer.value[0] = dmic->lrsel;
return 0;
}
static int tegra210_dmic_put_control(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct tegra210_dmic *dmic = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
int value = ucontrol->value.integer.value[0];
- if (strstr(kcontrol->id.name, "Boost"))
+ if (strstr(kcontrol->id.name, "Boost Gain"))
dmic->boost_gain = value;
- else if (strstr(kcontrol->id.name, "Controller Channel Select"))
+ else if (strstr(kcontrol->id.name, "Channel Select"))
dmic->ch_select = ucontrol->value.integer.value[0];
- else if (strstr(kcontrol->id.name, "Capture mono to stereo"))
+ else if (strstr(kcontrol->id.name, "Mono To Stereo"))
dmic->mono_to_stereo = value;
- else if (strstr(kcontrol->id.name, "Capture stereo to mono"))
+ else if (strstr(kcontrol->id.name, "Stereo To Mono"))
dmic->stereo_to_mono = value;
- else if (strstr(kcontrol->id.name, "output bit format"))
- dmic->format_out = value;
+ else if (strstr(kcontrol->id.name, "Audio Bit Format"))
+ dmic->audio_bits_override = value;
else if (strstr(kcontrol->id.name, "Sample Rate"))
- dmic->sample_rate_via_control = value;
- else if (strstr(kcontrol->id.name, "Channels"))
- dmic->channels_via_control = value;
+ dmic->srate_override = value;
+ else if (strstr(kcontrol->id.name, "Audio Channels"))
+ dmic->audio_ch_override = value;
else if (strstr(kcontrol->id.name, "OSR Value"))
dmic->osr_val = value;
- else if (strstr(kcontrol->id.name, "LR Select"))
+ else if (strstr(kcontrol->id.name, "LR Polarity Select"))
dmic->lrsel = value;
return 0;
}
-static struct snd_soc_dai_ops tegra210_dmic_dai_ops = {
+static const struct snd_soc_dai_ops tegra210_dmic_dai_ops = {
.hw_params = tegra210_dmic_hw_params,
- .startup = tegra210_dmic_startup,
};
+/*
+ * Three DAIs are exposed
+ * 1. "CIF" DAI for connecting with XBAR
+ * 2. "DAP" DAI for connecting with CODEC
+ * 3. "DUMMY_SOURCE" can be used when no external
+ * codec connection is available. In such case
+ * "DAP" is connected with "DUMMY_SOURCE"
+ */
static struct snd_soc_dai_driver tegra210_dmic_dais[] = {
{
.name = "CIF",
@@ -322,7 +247,8 @@ static struct snd_soc_dai_driver tegra210_dmic_dais[] = {
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &tegra210_dmic_dai_ops,
.symmetric_rates = 1,
@@ -334,10 +260,9 @@ static struct snd_soc_dai_driver tegra210_dmic_dais[] = {
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
},
- .ops = &tegra210_dmic_dai_ops,
- .symmetric_rates = 1,
},
{
.name = "DUMMY_SOURCE",
@@ -346,32 +271,29 @@ static struct snd_soc_dai_driver tegra210_dmic_dais[] = {
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
},
}
};
static const struct snd_soc_dapm_widget tegra210_dmic_widgets[] = {
- SND_SOC_DAPM_AIF_OUT("DMIC TX", NULL, 0, SND_SOC_NOPM,
- 0, 0),
- SND_SOC_DAPM_AIF_IN("DMIC RX", NULL, 0, TEGRA210_DMIC_ENABLE,
- 0, 0),
+ SND_SOC_DAPM_AIF_IN("DMIC TX", NULL, 0, TEGRA210_DMIC_ENABLE, 0, 0),
SND_SOC_DAPM_MIC("Dummy Input", NULL),
};
static const struct snd_soc_dapm_route tegra210_dmic_routes[] = {
- { "DMIC RX", NULL, "DMIC Receive" },
- { "DMIC TX", NULL, "DMIC RX" },
+ { "DMIC TX", NULL, "DMIC Receive" },
{ "DMIC Transmit", NULL, "DMIC TX" },
{ "Dummy Capture", NULL, "Dummy Input" },
};
static const char * const tegra210_dmic_ch_select[] = {
- "L", "R", "Stereo",
+ "Left", "Right", "Stereo",
};
static const struct soc_enum tegra210_dmic_ch_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra210_dmic_ch_select),
+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_ch_select),
tegra210_dmic_ch_select);
static const char * const tegra210_dmic_mono_conv_text[] = {
@@ -383,13 +305,11 @@ static const char * const tegra210_dmic_stereo_conv_text[] = {
};
static const struct soc_enum tegra210_dmic_mono_conv_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
- ARRAY_SIZE(tegra210_dmic_mono_conv_text),
+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_mono_conv_text),
tegra210_dmic_mono_conv_text);
static const struct soc_enum tegra210_dmic_stereo_conv_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
- ARRAY_SIZE(tegra210_dmic_stereo_conv_text),
+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_stereo_conv_text),
tegra210_dmic_stereo_conv_text);
static const char * const tegra210_dmic_format_text[] = {
@@ -399,7 +319,7 @@ static const char * const tegra210_dmic_format_text[] = {
};
static const struct soc_enum tegra210_dmic_format_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra210_dmic_format_text),
+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_format_text),
tegra210_dmic_format_text);
static const char * const tegra210_dmic_osr_text[] = {
@@ -407,7 +327,7 @@ static const char * const tegra210_dmic_osr_text[] = {
};
static const struct soc_enum tegra210_dmic_osr_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra210_dmic_osr_text),
+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_osr_text),
tegra210_dmic_osr_text);
static const char * const tegra210_dmic_lrsel_text[] = {
@@ -415,88 +335,68 @@ static const char * const tegra210_dmic_lrsel_text[] = {
};
static const struct soc_enum tegra210_dmic_lrsel_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra210_dmic_lrsel_text),
+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_dmic_lrsel_text),
tegra210_dmic_lrsel_text);
static const struct snd_kcontrol_new tegra210_dmic_controls[] = {
- SOC_SINGLE_EXT("Boost Gain", 0, 0, 25599, 0, tegra210_dmic_get_control,
- tegra210_dmic_put_control),
- SOC_ENUM_EXT("Controller Channel Select", tegra210_dmic_ch_enum,
+ SOC_SINGLE_EXT("Boost Gain", 0, 0, MAX_BOOST_GAIN, 0,
+ tegra210_dmic_get_control, tegra210_dmic_put_control),
+ SOC_ENUM_EXT("Channel Select", tegra210_dmic_ch_enum,
tegra210_dmic_get_control, tegra210_dmic_put_control),
- SOC_ENUM_EXT("Capture mono to stereo conv",
+ SOC_ENUM_EXT("Mono To Stereo",
tegra210_dmic_mono_conv_enum, tegra210_dmic_get_control,
tegra210_dmic_put_control),
- SOC_ENUM_EXT("Capture stereo to mono conv",
+ SOC_ENUM_EXT("Stereo To Mono",
tegra210_dmic_stereo_conv_enum, tegra210_dmic_get_control,
tegra210_dmic_put_control),
- SOC_ENUM_EXT("output bit format", tegra210_dmic_format_enum,
+ SOC_ENUM_EXT("Audio Bit Format", tegra210_dmic_format_enum,
tegra210_dmic_get_control, tegra210_dmic_put_control),
SOC_SINGLE_EXT("Sample Rate", 0, 0, 48000, 0, tegra210_dmic_get_control,
tegra210_dmic_put_control),
- SOC_SINGLE_EXT("Channels", 0, 0, 2, 0, tegra210_dmic_get_control,
+ SOC_SINGLE_EXT("Audio Channels", 0, 0, 2, 0, tegra210_dmic_get_control,
tegra210_dmic_put_control),
SOC_ENUM_EXT("OSR Value", tegra210_dmic_osr_enum,
tegra210_dmic_get_control, tegra210_dmic_put_control),
- SOC_ENUM_EXT("LR Select", tegra210_dmic_lrsel_enum,
+ SOC_ENUM_EXT("LR Polarity Select", tegra210_dmic_lrsel_enum,
tegra210_dmic_get_control, tegra210_dmic_put_control),
};
-static struct snd_soc_codec_driver tegra210_dmic_codec = {
- .idle_bias_off = 1,
- .component_driver = {
- .dapm_widgets = tegra210_dmic_widgets,
- .num_dapm_widgets = ARRAY_SIZE(tegra210_dmic_widgets),
- .dapm_routes = tegra210_dmic_routes,
- .num_dapm_routes = ARRAY_SIZE(tegra210_dmic_routes),
- .controls = tegra210_dmic_controls,
- .num_controls = ARRAY_SIZE(tegra210_dmic_controls),
- },
+static const struct snd_soc_component_driver tegra210_dmic_compnt = {
+ .dapm_widgets = tegra210_dmic_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tegra210_dmic_widgets),
+ .dapm_routes = tegra210_dmic_routes,
+ .num_dapm_routes = ARRAY_SIZE(tegra210_dmic_routes),
+ .controls = tegra210_dmic_controls,
+ .num_controls = ARRAY_SIZE(tegra210_dmic_controls),
};
-/* Regmap callback functions */
static bool tegra210_dmic_wr_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
- case TEGRA210_DMIC_TX_INT_MASK:
- case TEGRA210_DMIC_TX_INT_SET:
- case TEGRA210_DMIC_TX_INT_CLEAR:
- case TEGRA210_DMIC_TX_CIF_CTRL:
- case TEGRA210_DMIC_ENABLE:
- case TEGRA210_DMIC_SOFT_RESET:
- case TEGRA210_DMIC_CG:
+ case TEGRA210_DMIC_TX_INT_MASK ... TEGRA210_DMIC_TX_CIF_CTRL:
+ case TEGRA210_DMIC_ENABLE ... TEGRA210_DMIC_CG:
case TEGRA210_DMIC_CTRL:
+ case TEGRA210_DMIC_DBG_CTRL:
+ case TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4 ... TEGRA210_DMIC_LP_BIQUAD_1_COEF_4:
return true;
default:
- if (((reg % 4) == 0) && (reg >= TEGRA210_DMIC_DBG_CTRL) &&
- (reg <= TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_4))
- return true;
- else
- return false;
+ return false;
};
}
static bool tegra210_dmic_rd_reg(struct device *dev, unsigned int reg)
{
+ if (tegra210_dmic_wr_reg(dev, reg))
+ return true;
+
switch (reg) {
case TEGRA210_DMIC_TX_STATUS:
case TEGRA210_DMIC_TX_INT_STATUS:
- case TEGRA210_DMIC_TX_INT_MASK:
- case TEGRA210_DMIC_TX_INT_SET:
- case TEGRA210_DMIC_TX_INT_CLEAR:
- case TEGRA210_DMIC_TX_CIF_CTRL:
- case TEGRA210_DMIC_ENABLE:
- case TEGRA210_DMIC_SOFT_RESET:
- case TEGRA210_DMIC_CG:
case TEGRA210_DMIC_STATUS:
case TEGRA210_DMIC_INT_STATUS:
- case TEGRA210_DMIC_CTRL:
return true;
default:
- if (((reg % 4) == 0) && (reg >= TEGRA210_DMIC_DBG_CTRL) &&
- (reg <= TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_4))
- return true;
- else
- return false;
+ return false;
};
}
@@ -519,11 +419,10 @@ static const struct regmap_config tegra210_dmic_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
- .max_register = TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_4,
+ .max_register = TEGRA210_DMIC_LP_BIQUAD_1_COEF_4,
.writeable_reg = tegra210_dmic_wr_reg,
.readable_reg = tegra210_dmic_rd_reg,
.volatile_reg = tegra210_dmic_volatile_reg,
- .precious_reg = NULL,
.reg_defaults = tegra210_dmic_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(tegra210_dmic_reg_defaults),
.cache_type = REGCACHE_FLAT,
@@ -533,85 +432,62 @@ static const struct of_device_id tegra210_dmic_of_match[] = {
{ .compatible = "nvidia,tegra210-dmic" },
{},
};
+MODULE_DEVICE_TABLE(of, tegra210_dmic_of_match);
-static int tegra210_dmic_platform_probe(struct platform_device *pdev)
+static int tegra210_dmic_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct tegra210_dmic *dmic;
- struct device_node *np = pdev->dev.of_node;
- struct resource *mem;
void __iomem *regs;
- int ret = 0;
- const struct of_device_id *match;
+ int err;
- match = of_match_device(tegra210_dmic_of_match, &pdev->dev);
- if (!match) {
- dev_err(&pdev->dev, "Error: No device match found\n");
- return -ENODEV;
- }
-
- dmic = devm_kzalloc(&pdev->dev, sizeof(*dmic), GFP_KERNEL);
+ dmic = devm_kzalloc(dev, sizeof(*dmic), GFP_KERNEL);
if (!dmic)
return -ENOMEM;
- dmic->prod_name = NULL;
dmic->osr_val = DMIC_OSR_64;
dmic->ch_select = DMIC_CH_SELECT_STEREO;
- dev_set_drvdata(&pdev->dev, dmic);
+ dmic->lrsel = DMIC_LRSEL_LEFT;
+ dmic->boost_gain = 0;
+ dmic->stereo_to_mono = 0; /* "CH0" */
- if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
- dmic->clk_dmic = devm_clk_get(&pdev->dev, "dmic");
- if (IS_ERR(dmic->clk_dmic)) {
- dev_err(&pdev->dev, "Can't retrieve dmic clock\n");
- return PTR_ERR(dmic->clk_dmic);
- }
+ dev_set_drvdata(dev, dmic);
+
+ dmic->clk_dmic = devm_clk_get(dev, "dmic");
+ if (IS_ERR(dmic->clk_dmic)) {
+ dev_err(dev, "can't retrieve DMIC clock\n");
+ return PTR_ERR(dmic->clk_dmic);
}
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- regs = devm_ioremap_resource(&pdev->dev, mem);
+ regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
return PTR_ERR(regs);
- dmic->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+
+ dmic->regmap = devm_regmap_init_mmio(dev, regs,
&tegra210_dmic_regmap_config);
if (IS_ERR(dmic->regmap)) {
- dev_err(&pdev->dev, "regmap init failed\n");
+ dev_err(dev, "regmap init failed\n");
return PTR_ERR(dmic->regmap);
}
+
regcache_cache_only(dmic->regmap, true);
- /* Below patch is as per latest POR value */
- regmap_write(dmic->regmap, TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4,
- 0x00000000);
-
- pm_runtime_enable(&pdev->dev);
- ret = snd_soc_register_codec(&pdev->dev, &tegra210_dmic_codec,
- tegra210_dmic_dais,
- ARRAY_SIZE(tegra210_dmic_dais));
- if (ret != 0) {
- dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret);
- pm_runtime_disable(&pdev->dev);
- return ret;
+ err = devm_snd_soc_register_component(dev, &tegra210_dmic_compnt,
+ tegra210_dmic_dais,
+ ARRAY_SIZE(tegra210_dmic_dais));
+ if (err) {
+ dev_err(dev, "can't register DMIC component, err: %d\n", err);
+ return err;
}
- if (of_property_read_string(np, "prod-name", &dmic->prod_name) == 0) {
- ret = tegra_pinctrl_config_prod(&pdev->dev, dmic->prod_name);
- if (ret < 0)
- dev_warn(&pdev->dev, "Failed to set %s setting\n",
- dmic->prod_name);
- }
+ pm_runtime_enable(dev);
return 0;
}
-static int tegra210_dmic_platform_remove(struct platform_device *pdev)
+static int tegra210_dmic_remove(struct platform_device *pdev)
{
- struct tegra210_dmic *dmic;
-
- dmic = dev_get_drvdata(&pdev->dev);
- snd_soc_unregister_codec(&pdev->dev);
-
pm_runtime_disable(&pdev->dev);
- if (!pm_runtime_status_suspended(&pdev->dev))
- tegra210_dmic_runtime_suspend(&pdev->dev);
return 0;
}
@@ -619,24 +495,21 @@ static int tegra210_dmic_platform_remove(struct platform_device *pdev)
static const struct dev_pm_ops tegra210_dmic_pm_ops = {
SET_RUNTIME_PM_OPS(tegra210_dmic_runtime_suspend,
tegra210_dmic_runtime_resume, NULL)
- SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
};
static struct platform_driver tegra210_dmic_driver = {
.driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
+ .name = "tegra210-dmic",
.of_match_table = tegra210_dmic_of_match,
.pm = &tegra210_dmic_pm_ops,
},
- .probe = tegra210_dmic_platform_probe,
- .remove = tegra210_dmic_platform_remove,
+ .probe = tegra210_dmic_probe,
+ .remove = tegra210_dmic_remove,
};
module_platform_driver(tegra210_dmic_driver)
MODULE_AUTHOR("Rahul Mittal ");
-MODULE_DESCRIPTION("Tegra210 DMIC ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_DEVICE_TABLE(of, tegra210_dmic_of_match);
+MODULE_DESCRIPTION("Tegra210 ASoC DMIC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra210_dmic.h b/sound/soc/tegra/tegra210_dmic.h
index abe611f3..a08d1364 100644
--- a/sound/soc/tegra/tegra210_dmic.h
+++ b/sound/soc/tegra/tegra210_dmic.h
@@ -1,23 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * tegra210_dmic_alt.h - Definitions for Tegra210 DMIC driver
+ * tegra210_dmic.h - Definitions for Tegra210 DMIC driver
*
- * Copyright (c) 2014-2019 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
*/
-#ifndef __TEGRA210_DMIC_ALT_H__
-#define __TEGRA210_DMIC_ALT_H__
+#ifndef __TEGRA210_DMIC_H__
+#define __TEGRA210_DMIC_H__
/* Register offsets from DMIC BASE */
#define TEGRA210_DMIC_TX_STATUS 0x0c
@@ -33,11 +23,6 @@
#define TEGRA210_DMIC_INT_STATUS 0x50
#define TEGRA210_DMIC_CTRL 0x64
#define TEGRA210_DMIC_DBG_CTRL 0x70
-#define TEGRA210_DMIC_DCR_FILTER_GAIN 0x74
-#define TEGRA210_DMIC_DCR_BIQUAD_0_COEF_0 0x78
-#define TEGRA210_DMIC_DCR_BIQUAD_0_COEF_1 0x7c
-#define TEGRA210_DMIC_DCR_BIQUAD_0_COEF_2 0x80
-#define TEGRA210_DMIC_DCR_BIQUAD_0_COEF_3 0x84
#define TEGRA210_DMIC_DCR_BIQUAD_0_COEF_4 0x88
#define TEGRA210_DMIC_LP_FILTER_GAIN 0x8c
#define TEGRA210_DMIC_LP_BIQUAD_0_COEF_0 0x90
@@ -50,17 +35,6 @@
#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_2 0xac
#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_3 0xb0
#define TEGRA210_DMIC_LP_BIQUAD_1_COEF_4 0xb4
-#define TEGRA210_DMIC_CORRECTION_FILTER_GAIN 0xb8
-#define TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_0 0xbc
-#define TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_1 0xc0
-#define TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_2 0xc4
-#define TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_3 0xc8
-#define TEGRA210_DMIC_CORRECTION_BIQUAD_0_COEF_4 0xcc
-#define TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_0 0xd0
-#define TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_1 0xd4
-#define TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_2 0xd8
-#define TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_3 0xdc
-#define TEGRA210_DMIC_CORRECTION_BIQUAD_1_COEF_4 0xe0
/* Fields in TEGRA210_DMIC_CTRL */
#define CH_SEL_SHIFT 8
@@ -69,11 +43,13 @@
#define TEGRA210_DMIC_CTRL_LRSEL_POLARITY_MASK (0x1 << LRSEL_POL_SHIFT)
#define OSR_SHIFT 0
#define TEGRA210_DMIC_CTRL_OSR_MASK (0x3 << OSR_SHIFT)
-/* Fields in TEGRA210_DMIC_DBG_CTRL */
-#define TEGRA210_DMIC_DBG_CTRL_DCR_ENABLE BIT(3)
-#define TEGRA210_DMIC_DBG_CTRL_LP_ENABLE BIT(2)
-#define TEGRA210_DMIC_DBG_CTRL_SC_ENABLE BIT(1)
-#define TEGRA210_DMIC_DBG_CTRL_BYPASS BIT(0)
+
+#define DMIC_OSR_FACTOR 64
+
+#define DEFAULT_GAIN_Q23 0x800000
+
+/* Max boost gain factor used for mixer control */
+#define MAX_BOOST_GAIN 25599
enum tegra_dmic_ch_select {
DMIC_CH_SELECT_LEFT,
@@ -87,19 +63,23 @@ enum tegra_dmic_osr {
DMIC_OSR_256,
};
+enum tegra_dmic_lrsel {
+ DMIC_LRSEL_LEFT,
+ DMIC_LRSEL_RIGHT,
+};
+
struct tegra210_dmic {
struct clk *clk_dmic;
struct regmap *regmap;
- const char *prod_name;
- int boost_gain; /* with 100x factor */
- unsigned int ch_select;
+ unsigned int audio_ch_override;
+ unsigned int audio_bits_override;
+ unsigned int srate_override;
unsigned int mono_to_stereo;
unsigned int stereo_to_mono;
- unsigned int sample_rate_via_control;
- unsigned int channels_via_control;
- unsigned int osr_val; /* osr value */
- int lrsel;
- int format_out;
+ unsigned int boost_gain;
+ unsigned int ch_select;
+ unsigned int osr_val;
+ unsigned int lrsel;
};
#endif
diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
index 31a8effe..dfdb6fd9 100644
--- a/sound/soc/tegra/tegra210_i2s.c
+++ b/sound/soc/tegra/tegra210_i2s.c
@@ -1,154 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* tegra210_i2s.c - Tegra210 I2S driver
*
- * Copyright (c) 2014-2020 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
*/
#include
#include
-#include
#include
-#include
+#include
#include
#include
#include
#include
-#include
#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "tegra210_xbar_alt.h"
-#include "tegra210_i2s_alt.h"
-
-#define DRV_NAME "tegra210-i2s"
+#include "tegra210_i2s.h"
+#include "tegra_cif.h"
static const struct reg_default tegra210_i2s_reg_defaults[] = {
- { TEGRA210_I2S_AXBAR_RX_INT_MASK, 0x00000003},
- { TEGRA210_I2S_AXBAR_RX_CIF_CTRL, 0x00007700},
- { TEGRA210_I2S_AXBAR_TX_INT_MASK, 0x00000003},
- { TEGRA210_I2S_AXBAR_TX_CIF_CTRL, 0x00007700},
- { TEGRA210_I2S_CG, 0x1},
- { TEGRA210_I2S_TIMING, 0x0000001f},
- { TEGRA210_I2S_ENABLE, 0x1},
+ { TEGRA210_I2S_RX_INT_MASK, 0x00000003 },
+ { TEGRA210_I2S_RX_CIF_CTRL, 0x00007700 },
+ { TEGRA210_I2S_TX_INT_MASK, 0x00000003 },
+ { TEGRA210_I2S_TX_CIF_CTRL, 0x00007700 },
+ { TEGRA210_I2S_CG, 0x1 },
+ { TEGRA210_I2S_TIMING, 0x0000001f },
+ { TEGRA210_I2S_ENABLE, 0x1 },
/*
* Below update does not have any effect on Tegra186 and Tegra194.
* On Tegra210, I2S4 has "i2s4a" and "i2s4b" pins and below update
* is required to select i2s4b for it to be functional for I2S
* operation.
*/
- { TEGRA210_I2S_CYA, 0x1},
+ { TEGRA210_I2S_CYA, 0x1 },
};
static void tegra210_i2s_set_slot_ctrl(struct regmap *regmap,
- unsigned int total_slots,
- unsigned int tx_slot_mask,
- unsigned int rx_slot_mask)
+ unsigned int total_slots,
+ unsigned int tx_slot_mask,
+ unsigned int rx_slot_mask)
{
regmap_write(regmap, TEGRA210_I2S_SLOT_CTRL, total_slots - 1);
- regmap_write(regmap, TEGRA210_I2S_AXBAR_TX_SLOT_CTRL,
- tx_slot_mask);
- regmap_write(regmap, TEGRA210_I2S_AXBAR_RX_SLOT_CTRL,
- rx_slot_mask);
+ regmap_write(regmap, TEGRA210_I2S_TX_SLOT_CTRL, tx_slot_mask);
+ regmap_write(regmap, TEGRA210_I2S_RX_SLOT_CTRL, rx_slot_mask);
}
-static int tegra210_i2s_set_clock_rate(struct device *dev, int clock_rate)
+static int tegra210_i2s_set_clock_rate(struct device *dev,
+ unsigned int clock_rate)
{
- unsigned int val;
struct tegra210_i2s *i2s = dev_get_drvdata(dev);
- int ret;
+ unsigned int val;
+ int err;
regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val);
- val &= TEGRA210_I2S_CTRL_MASTER_EN;
- /* no need to set rates if I2S is being operated in slave */
- if (!val)
+ /* No need to set rates if I2S is being operated in slave */
+ if (!(val & I2S_CTRL_MASTER_EN))
return 0;
- /* skip for fpga units */
- if (tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())
- return 0;
-
- ret = clk_set_rate(i2s->clk_i2s, clock_rate);
- if (ret) {
- dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
- return ret;
+ err = clk_set_rate(i2s->clk_i2s, clock_rate);
+ if (err) {
+ dev_err(dev, "can't set I2S bit clock rate %u, err: %d\n",
+ clock_rate, err);
+ return err;
}
if (!IS_ERR(i2s->clk_sync_input)) {
/*
- * other I/O modules in AHUB can use i2s bclk as reference
+ * Other I/O modules in AHUB can use i2s bclk as reference
* clock. Below sets sync input clock rate as per bclk,
* which can be used as input to other I/O modules.
*/
- ret = clk_set_rate(i2s->clk_sync_input, clock_rate);
- if (ret) {
- dev_err(dev, "Can't set I2S sync input clock rate\n");
- return ret;
+ err = clk_set_rate(i2s->clk_sync_input, clock_rate);
+ if (err) {
+ dev_err(dev,
+ "can't set I2S sync input rate %u, err = %d\n",
+ clock_rate, err);
+ return err;
}
}
return 0;
}
-static int tegra210_i2s_sw_reset(struct snd_soc_codec *codec, bool is_playback)
+static int tegra210_i2s_sw_reset(struct snd_soc_component *compnt,
+ bool is_playback)
{
- struct device *dev = codec->dev;
+ struct device *dev = compnt->dev;
struct tegra210_i2s *i2s = dev_get_drvdata(dev);
+ unsigned int reset_mask = I2S_SOFT_RESET_MASK;
+ unsigned int reset_en = I2S_SOFT_RESET_EN;
unsigned int reset_reg, cif_reg, stream_reg;
unsigned int cif_ctrl, stream_ctrl, i2s_ctrl, val;
- unsigned int reset_mask, reset_en;
- int ret;
+ int err;
if (is_playback) {
- reset_mask = TEGRA210_I2S_AXBAR_RX_SOFT_RESET_MASK;
- reset_en = TEGRA210_I2S_AXBAR_RX_SOFT_RESET_EN;
- reset_reg = TEGRA210_I2S_AXBAR_RX_SOFT_RESET;
- cif_reg = TEGRA210_I2S_AXBAR_RX_CIF_CTRL;
- stream_reg = TEGRA210_I2S_AXBAR_RX_CTRL;
+ reset_reg = TEGRA210_I2S_RX_SOFT_RESET;
+ cif_reg = TEGRA210_I2S_RX_CIF_CTRL;
+ stream_reg = TEGRA210_I2S_RX_CTRL;
} else {
- reset_mask = TEGRA210_I2S_AXBAR_TX_SOFT_RESET_MASK;
- reset_en = TEGRA210_I2S_AXBAR_TX_SOFT_RESET_EN;
- reset_reg = TEGRA210_I2S_AXBAR_TX_SOFT_RESET;
- cif_reg = TEGRA210_I2S_AXBAR_TX_CIF_CTRL;
- stream_reg = TEGRA210_I2S_AXBAR_TX_CTRL;
+ reset_reg = TEGRA210_I2S_TX_SOFT_RESET;
+ cif_reg = TEGRA210_I2S_TX_CIF_CTRL;
+ stream_reg = TEGRA210_I2S_TX_CTRL;
}
- /* store */
+ /* Store CIF and I2S control values */
regmap_read(i2s->regmap, cif_reg, &cif_ctrl);
regmap_read(i2s->regmap, stream_reg, &stream_ctrl);
regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &i2s_ctrl);
- /* SW reset */
+ /* Reset to make sure the previous transactions are clean */
regmap_update_bits(i2s->regmap, reset_reg, reset_mask, reset_en);
- ret = regmap_read_poll_timeout(i2s->regmap, reset_reg, val,
+ err = regmap_read_poll_timeout(i2s->regmap, reset_reg, val,
!(val & reset_mask & reset_en),
10, 10000);
- if (ret < 0) {
+ if (err) {
dev_err(dev, "timeout: failed to reset I2S for %s\n",
is_playback ? "playback" : "capture");
- return ret;
+ return err;
}
- /* restore */
+ /* Restore CIF and I2S control values */
regmap_write(i2s->regmap, cif_reg, cif_ctrl);
regmap_write(i2s->regmap, stream_reg, stream_ctrl);
regmap_write(i2s->regmap, TEGRA210_I2S_CTRL, i2s_ctrl);
@@ -159,42 +133,37 @@ static int tegra210_i2s_sw_reset(struct snd_soc_codec *codec, bool is_playback)
static int tegra210_i2s_init(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
- struct device *dev = codec->dev;
+ struct snd_soc_component *compnt = snd_soc_dapm_to_component(w->dapm);
+ struct device *dev = compnt->dev;
struct tegra210_i2s *i2s = dev_get_drvdata(dev);
unsigned int val, status_reg;
bool is_playback;
- int ret;
+ int err;
switch (w->reg) {
- case TEGRA210_I2S_AXBAR_RX_ENABLE:
+ case TEGRA210_I2S_RX_ENABLE:
is_playback = true;
- status_reg = TEGRA210_I2S_AXBAR_RX_STATUS;
+ status_reg = TEGRA210_I2S_RX_STATUS;
break;
- case TEGRA210_I2S_AXBAR_TX_ENABLE:
+ case TEGRA210_I2S_TX_ENABLE:
is_playback = false;
- status_reg = TEGRA210_I2S_AXBAR_TX_STATUS;
+ status_reg = TEGRA210_I2S_TX_STATUS;
break;
default:
return -EINVAL;
}
- /* ensure I2S is in disabled state before new session */
- ret = regmap_read_poll_timeout(i2s->regmap, status_reg, val,
- !(val & TEGRA210_I2S_EN_MASK & TEGRA210_I2S_EN),
- 10, 10000);
- if (ret < 0) {
+ /* Ensure I2S is in disabled state before new session */
+ err = regmap_read_poll_timeout(i2s->regmap, status_reg, val,
+ !(val & I2S_EN_MASK & I2S_EN),
+ 10, 10000);
+ if (err) {
dev_err(dev, "timeout: previous I2S %s is still active\n",
is_playback ? "playback" : "capture");
- return ret;
+ return err;
}
- /* SW reset */
- ret = tegra210_i2s_sw_reset(codec, is_playback);
- if (ret < 0)
- return ret;
-
- return 0;
+ return tegra210_i2s_sw_reset(compnt, is_playback);
}
static int tegra210_i2s_runtime_suspend(struct device *dev)
@@ -202,10 +171,9 @@ static int tegra210_i2s_runtime_suspend(struct device *dev)
struct tegra210_i2s *i2s = dev_get_drvdata(dev);
regcache_cache_only(i2s->regmap, true);
- if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
- regcache_mark_dirty(i2s->regmap);
- clk_disable_unprepare(i2s->clk_i2s);
- }
+ regcache_mark_dirty(i2s->regmap);
+
+ clk_disable_unprepare(i2s->clk_i2s);
return 0;
}
@@ -213,14 +181,12 @@ static int tegra210_i2s_runtime_suspend(struct device *dev)
static int tegra210_i2s_runtime_resume(struct device *dev)
{
struct tegra210_i2s *i2s = dev_get_drvdata(dev);
- int ret;
+ int err;
- if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
- ret = clk_prepare_enable(i2s->clk_i2s);
- if (ret) {
- dev_err(dev, "clk_enable failed: %d\n", ret);
- return ret;
- }
+ err = clk_prepare_enable(i2s->clk_i2s);
+ if (err) {
+ dev_err(dev, "failed to enable I2S bit clock, err: %d\n", err);
+ return err;
}
regcache_cache_only(i2s->regmap, false);
@@ -232,16 +198,14 @@ static int tegra210_i2s_runtime_resume(struct device *dev)
static void tegra210_i2s_set_data_offset(struct tegra210_i2s *i2s,
unsigned int data_offset)
{
- unsigned int reg, mask, shift;
+ unsigned int mask = I2S_CTRL_DATA_OFFSET_MASK;
+ unsigned int shift = I2S_DATA_SHIFT;
+ unsigned int reg;
- reg = TEGRA210_I2S_AXBAR_TX_CTRL;
- mask = TEGRA210_I2S_AXBAR_TX_CTRL_DATA_OFFSET_MASK;
- shift = TEGRA210_I2S_AXBAR_TX_CTRL_DATA_OFFSET_SHIFT;
+ reg = TEGRA210_I2S_TX_CTRL;
regmap_update_bits(i2s->regmap, reg, mask, data_offset << shift);
- reg = TEGRA210_I2S_AXBAR_RX_CTRL;
- mask = TEGRA210_I2S_AXBAR_RX_CTRL_DATA_OFFSET_MASK;
- shift = TEGRA210_I2S_AXBAR_RX_CTRL_DATA_OFFSET_SHIFT;
+ reg = TEGRA210_I2S_RX_CTRL;
regmap_update_bits(i2s->regmap, reg, mask, data_offset << shift);
}
@@ -251,35 +215,34 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai,
struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
unsigned int mask, val;
- mask = TEGRA210_I2S_CTRL_MASTER_EN_MASK;
+ mask = I2S_CTRL_MASTER_EN_MASK;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
val = 0;
break;
case SND_SOC_DAIFMT_CBM_CFM:
- val = TEGRA210_I2S_CTRL_MASTER_EN;
+ val = I2S_CTRL_MASTER_EN;
break;
default:
return -EINVAL;
}
- mask |= TEGRA210_I2S_CTRL_FRAME_FORMAT_MASK |
- TEGRA210_I2S_CTRL_LRCK_POLARITY_MASK;
+ mask |= I2S_CTRL_FRAME_FMT_MASK | I2S_CTRL_LRCK_POL_MASK;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_A:
- val |= TEGRA210_I2S_CTRL_FRAME_FORMAT_FSYNC_MODE;
- val |= TEGRA210_I2S_CTRL_LRCK_POLARITY_HIGH;
+ val |= I2S_CTRL_FRAME_FMT_FSYNC_MODE;
+ val |= I2S_CTRL_LRCK_POL_HIGH;
tegra210_i2s_set_data_offset(i2s, 1);
break;
case SND_SOC_DAIFMT_DSP_B:
- val |= TEGRA210_I2S_CTRL_FRAME_FORMAT_FSYNC_MODE;
- val |= TEGRA210_I2S_CTRL_LRCK_POLARITY_HIGH;
+ val |= I2S_CTRL_FRAME_FMT_FSYNC_MODE;
+ val |= I2S_CTRL_LRCK_POL_HIGH;
tegra210_i2s_set_data_offset(i2s, 0);
break;
/* I2S mode has data offset of 1 */
case SND_SOC_DAIFMT_I2S:
- val |= TEGRA210_I2S_CTRL_FRAME_FORMAT_LRCK_MODE;
- val |= TEGRA210_I2S_CTRL_LRCK_POLARITY_LOW;
+ val |= I2S_CTRL_FRAME_FMT_LRCK_MODE;
+ val |= I2S_CTRL_LRCK_POL_LOW;
tegra210_i2s_set_data_offset(i2s, 1);
break;
/*
@@ -287,33 +250,33 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai,
* and the bclk ratio, and so is set when hw_params is called.
*/
case SND_SOC_DAIFMT_RIGHT_J:
- val |= TEGRA210_I2S_CTRL_FRAME_FORMAT_LRCK_MODE;
- val |= TEGRA210_I2S_CTRL_LRCK_POLARITY_HIGH;
+ val |= I2S_CTRL_FRAME_FMT_LRCK_MODE;
+ val |= I2S_CTRL_LRCK_POL_HIGH;
break;
case SND_SOC_DAIFMT_LEFT_J:
- val |= TEGRA210_I2S_CTRL_FRAME_FORMAT_LRCK_MODE;
- val |= TEGRA210_I2S_CTRL_LRCK_POLARITY_HIGH;
+ val |= I2S_CTRL_FRAME_FMT_LRCK_MODE;
+ val |= I2S_CTRL_LRCK_POL_HIGH;
tegra210_i2s_set_data_offset(i2s, 0);
break;
default:
return -EINVAL;
}
- mask |= TEGRA210_I2S_CTRL_EDGE_CTRL_MASK;
+ mask |= I2S_CTRL_EDGE_CTRL_MASK;
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
- val |= TEGRA210_I2S_CTRL_EDGE_CTRL_POS_EDGE;
+ val |= I2S_CTRL_EDGE_CTRL_POS_EDGE;
break;
case SND_SOC_DAIFMT_NB_IF:
- val |= TEGRA210_I2S_CTRL_EDGE_CTRL_POS_EDGE;
- val ^= TEGRA210_I2S_CTRL_LRCK_POLARITY_MASK;
+ val |= I2S_CTRL_EDGE_CTRL_POS_EDGE;
+ val ^= I2S_CTRL_LRCK_POL_MASK;
break;
case SND_SOC_DAIFMT_IB_NF:
- val |= TEGRA210_I2S_CTRL_EDGE_CTRL_NEG_EDGE;
+ val |= I2S_CTRL_EDGE_CTRL_NEG_EDGE;
break;
case SND_SOC_DAIFMT_IB_IF:
- val |= TEGRA210_I2S_CTRL_EDGE_CTRL_NEG_EDGE;
- val ^= TEGRA210_I2S_CTRL_LRCK_POLARITY_MASK;
+ val |= I2S_CTRL_EDGE_CTRL_NEG_EDGE;
+ val ^= I2S_CTRL_LRCK_POL_MASK;
break;
default:
return -EINVAL;
@@ -321,20 +284,22 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai,
regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, mask, val);
- i2s->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+ i2s->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
return 0;
}
static int tegra210_i2s_set_tdm_slot(struct snd_soc_dai *dai,
- unsigned int tx_mask, unsigned int rx_mask,
- int slots, int slot_width)
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
{
struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- /* copy the required tx and rx mask */
- i2s->tx_mask = (tx_mask > 0xFFFF) ? 0xFFFF : tx_mask;
- i2s->rx_mask = (rx_mask > 0xFFFF) ? 0xFFFF : rx_mask;
+ /* Copy the required tx and rx mask */
+ i2s->tx_mask = (tx_mask > DEFAULT_I2S_SLOT_MASK) ?
+ DEFAULT_I2S_SLOT_MASK : tx_mask;
+ i2s->rx_mask = (rx_mask > DEFAULT_I2S_SLOT_MASK) ?
+ DEFAULT_I2S_SLOT_MASK : rx_mask;
return 0;
}
@@ -349,37 +314,40 @@ static int tegra210_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
return 0;
}
-static int tegra210_i2s_get_format(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int tegra210_i2s_get_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
long *uctl_val = &ucontrol->value.integer.value[0];
- /* get the format control flag */
- if (strstr(kcontrol->id.name, "Playback Audio Bit Format"))
+ if (strstr(kcontrol->id.name, "Loopback"))
+ *uctl_val = i2s->loopback;
+ else if (strstr(kcontrol->id.name, "Sample Rate"))
+ *uctl_val = i2s->srate_override;
+ else if (strstr(kcontrol->id.name, "FSYNC Width"))
+ *uctl_val = i2s->fsync_width;
+ else if (strstr(kcontrol->id.name, "Playback Audio Bit Format"))
*uctl_val = i2s->audio_fmt_override[I2S_RX_PATH];
else if (strstr(kcontrol->id.name, "Capture Audio Bit Format"))
*uctl_val = i2s->audio_fmt_override[I2S_TX_PATH];
- else if (strstr(kcontrol->id.name, "codec"))
- *uctl_val = i2s->codec_bit_format;
- else if (strstr(kcontrol->id.name, "Sample Rate"))
- *uctl_val = i2s->sample_rate_via_control;
+ else if (strstr(kcontrol->id.name, "Client Bit Format"))
+ *uctl_val = i2s->client_fmt_override;
else if (strstr(kcontrol->id.name, "Playback Audio Channels"))
*uctl_val = i2s->audio_ch_override[I2S_RX_PATH];
else if (strstr(kcontrol->id.name, "Capture Audio Channels"))
*uctl_val = i2s->audio_ch_override[I2S_TX_PATH];
else if (strstr(kcontrol->id.name, "Client Channels"))
*uctl_val = i2s->client_ch_override;
- else if (strstr(kcontrol->id.name, "Capture stereo to mono"))
+ else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
*uctl_val = i2s->stereo_to_mono[I2S_TX_PATH];
- else if (strstr(kcontrol->id.name, "Capture mono to stereo"))
+ else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
*uctl_val = i2s->mono_to_stereo[I2S_TX_PATH];
- else if (strstr(kcontrol->id.name, "Playback stereo to mono"))
+ else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
*uctl_val = i2s->stereo_to_mono[I2S_RX_PATH];
- else if (strstr(kcontrol->id.name, "Playback mono to stereo"))
+ else if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
*uctl_val = i2s->mono_to_stereo[I2S_RX_PATH];
- else if (strstr(kcontrol->id.name, "Playback FIFO threshold"))
+ else if (strstr(kcontrol->id.name, "Playback FIFO Threshold"))
*uctl_val = i2s->rx_fifo_th;
else if (strstr(kcontrol->id.name, "BCLK Ratio"))
*uctl_val = i2s->bclk_ratio;
@@ -387,43 +355,62 @@ static int tegra210_i2s_get_format(struct snd_kcontrol *kcontrol,
return 0;
}
-static int tegra210_i2s_put_format(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int tegra210_i2s_put_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+ struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
int value = ucontrol->value.integer.value[0];
- /* set the format control flag */
- if (strstr(kcontrol->id.name, "Playback Audio Bit Format"))
+ if (strstr(kcontrol->id.name, "Loopback")) {
+ i2s->loopback = value;
+
+ regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+ I2S_CTRL_LPBK_MASK,
+ i2s->loopback << I2S_CTRL_LPBK_SHIFT);
+
+ } else if (strstr(kcontrol->id.name, "Sample Rate")) {
+ i2s->srate_override = value;
+ } else if (strstr(kcontrol->id.name, "FSYNC Width")) {
+ /*
+ * Frame sync width is used only for FSYNC modes and not
+ * applicable for LRCK modes. Reset value for this field is "0",
+ * which means the width is one bit clock wide.
+ * The width requirement may depend on the codec and in such
+ * cases mixer control is used to update custom values. A value
+ * of "N" here means, width is "N + 1" bit clock wide.
+ */
+ i2s->fsync_width = value;
+
+ regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+ I2S_CTRL_FSYNC_WIDTH_MASK,
+ i2s->fsync_width << I2S_FSYNC_WIDTH_SHIFT);
+
+ } else if (strstr(kcontrol->id.name, "Playback Audio Bit Format")) {
i2s->audio_fmt_override[I2S_RX_PATH] = value;
- else if (strstr(kcontrol->id.name, "Capture Audio Bit Format"))
+ } else if (strstr(kcontrol->id.name, "Capture Audio Bit Format")) {
i2s->audio_fmt_override[I2S_TX_PATH] = value;
- else if (strstr(kcontrol->id.name, "codec"))
- i2s->codec_bit_format = value;
- else if (strstr(kcontrol->id.name, "Sample Rate"))
- i2s->sample_rate_via_control = value;
- else if (strstr(kcontrol->id.name, "Playback Audio Channels"))
+ } else if (strstr(kcontrol->id.name, "Client Bit Format")) {
+ i2s->client_fmt_override = value;
+ } else if (strstr(kcontrol->id.name, "Playback Audio Channels")) {
i2s->audio_ch_override[I2S_RX_PATH] = value;
- else if (strstr(kcontrol->id.name, "Capture Audio Channels"))
+ } else if (strstr(kcontrol->id.name, "Capture Audio Channels")) {
i2s->audio_ch_override[I2S_TX_PATH] = value;
- else if (strstr(kcontrol->id.name, "Client Channels"))
+ } else if (strstr(kcontrol->id.name, "Client Channels")) {
i2s->client_ch_override = value;
- else if (strstr(kcontrol->id.name, "Capture stereo to mono"))
+ } else if (strstr(kcontrol->id.name, "Capture Stereo To Mono")) {
i2s->stereo_to_mono[I2S_TX_PATH] = value;
- else if (strstr(kcontrol->id.name, "Capture mono to stereo"))
+ } else if (strstr(kcontrol->id.name, "Capture Mono To Stereo")) {
i2s->mono_to_stereo[I2S_TX_PATH] = value;
- else if (strstr(kcontrol->id.name, "Playback stereo to mono"))
+ } else if (strstr(kcontrol->id.name, "Playback Stereo To Mono")) {
i2s->stereo_to_mono[I2S_RX_PATH] = value;
- else if (strstr(kcontrol->id.name, "Playback mono to stereo"))
+ } else if (strstr(kcontrol->id.name, "Playback Mono To Stereo")) {
i2s->mono_to_stereo[I2S_RX_PATH] = value;
- else if (strstr(kcontrol->id.name, "Playback FIFO threshold")) {
- if (value >= 0 && value < TEGRA210_I2S_RX_FIFO_DEPTH)
- i2s->rx_fifo_th = value;
- else
- return -EINVAL;
- } else if (strstr(kcontrol->id.name, "BCLK Ratio"))
+ } else if (strstr(kcontrol->id.name, "Playback FIFO Threshold")) {
+ i2s->rx_fifo_th = value;
+ } else if (strstr(kcontrol->id.name, "BCLK Ratio")) {
i2s->bclk_ratio = value;
+ }
return 0;
}
@@ -434,75 +421,27 @@ static const char * const tegra210_i2s_format_text[] = {
"32",
};
-static const int tegra210_cif_fmt[] = {
+static const unsigned int tegra210_cif_fmt[] = {
0,
- TEGRA210_AUDIOCIF_BITS_16,
- TEGRA210_AUDIOCIF_BITS_32,
+ TEGRA_ACIF_BITS_16,
+ TEGRA_ACIF_BITS_32,
};
-static const int tegra210_i2s_bit_fmt[] = {
+static const unsigned int tegra210_i2s_bit_fmt[] = {
0,
- TEGRA210_I2S_CTRL_BIT_SIZE_16,
- TEGRA210_I2S_CTRL_BIT_SIZE_32,
+ I2S_BITS_16,
+ I2S_BITS_32,
};
-static const int tegra210_i2s_sample_size[] = {
+static const unsigned int tegra210_i2s_sample_size[] = {
0,
16,
32,
};
static const struct soc_enum tegra210_i2s_format_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
- ARRAY_SIZE(tegra210_i2s_format_text),
- tegra210_i2s_format_text);
-
-static int tegra210_i2s_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct device *dev = dai->dev;
- struct tegra210_i2s *i2s = dev_get_drvdata(dev);
- int ret;
-
- if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga()) &&
- !i2s->loopback) {
- if (i2s->prod_name != NULL) {
- ret = tegra_pinctrl_config_prod(dev, i2s->prod_name);
- if (ret < 0) {
- dev_warn(dev, "Failed to set %s setting\n",
- i2s->prod_name);
- }
- }
-
- if (i2s->num_supplies > 0) {
- ret = regulator_bulk_enable(i2s->num_supplies,
- i2s->supplies);
- if (ret < 0)
- dev_err(dev, "failed to enable i2s io regulator\n");
- }
- }
-
- return 0;
-}
-
-static void tegra210_i2s_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct device *dev = dai->dev;
- struct tegra210_i2s *i2s = dev_get_drvdata(dev);
- int ret;
-
- if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
- if (i2s->num_supplies > 0) {
- ret = regulator_bulk_disable(i2s->num_supplies,
- i2s->supplies);
- if (ret < 0) {
- dev_err(dev,
- "failed to disable i2s io regulator\n");
- }
- }
- }
-}
+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_i2s_format_text),
+ tegra210_i2s_format_text);
static int tegra210_i2s_set_timing_params(struct device *dev,
unsigned int sample_size,
@@ -511,22 +450,22 @@ static int tegra210_i2s_set_timing_params(struct device *dev,
{
struct tegra210_i2s *i2s = dev_get_drvdata(dev);
unsigned int val, bit_count, bclk_rate, num_bclk = sample_size;
- int ret;
+ int err;
if (i2s->bclk_ratio)
num_bclk *= i2s->bclk_ratio;
- if (i2s->format == SND_SOC_DAIFMT_RIGHT_J)
+ if (i2s->dai_fmt == SND_SOC_DAIFMT_RIGHT_J)
tegra210_i2s_set_data_offset(i2s, num_bclk - sample_size);
/* I2S bit clock rate */
bclk_rate = srate * channels * num_bclk;
- ret = tegra210_i2s_set_clock_rate(dev, bclk_rate);
- if (ret) {
- dev_err(dev, "Can't set I2S bit clock rate for %u, err: %d\n",
- bclk_rate, ret);
- return ret;
+ err = tegra210_i2s_set_clock_rate(dev, bclk_rate);
+ if (err) {
+ dev_err(dev, "can't set I2S bit clock rate %u, err: %d\n",
+ bclk_rate, err);
+ return err;
}
regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val);
@@ -538,28 +477,28 @@ static int tegra210_i2s_set_timing_params(struct device *dev,
* mode or the number of bit clocks in one TDM frame.
*
*/
- switch (val & TEGRA210_I2S_CTRL_FRAME_FORMAT_MASK) {
- case TEGRA210_I2S_CTRL_FRAME_FORMAT_LRCK_MODE:
+ switch (val & I2S_CTRL_FRAME_FMT_MASK) {
+ case I2S_CTRL_FRAME_FMT_LRCK_MODE:
bit_count = (bclk_rate / (srate * 2)) - 1;
break;
- case TEGRA210_I2S_CTRL_FRAME_FORMAT_FSYNC_MODE:
+ case I2S_CTRL_FRAME_FMT_FSYNC_MODE:
bit_count = (bclk_rate / srate) - 1;
tegra210_i2s_set_slot_ctrl(i2s->regmap, channels,
i2s->tx_mask, i2s->rx_mask);
break;
default:
- dev_err(dev, "invalid I2S mode\n");
+ dev_err(dev, "invalid I2S frame format\n");
return -EINVAL;
}
- if (bit_count > TEGRA210_I2S_TIMING_CHANNEL_BIT_CNT_MASK) {
- dev_err(dev, "invalid channel bit count %u\n", bit_count);
+ if (bit_count > I2S_TIMING_CH_BIT_CNT_MASK) {
+ dev_err(dev, "invalid I2S channel bit count %u\n", bit_count);
return -EINVAL;
}
regmap_write(i2s->regmap, TEGRA210_I2S_TIMING,
- bit_count << TEGRA210_I2S_TIMING_CHANNEL_BIT_CNT_SHIFT);
+ bit_count << I2S_TIMING_CH_BIT_CNT_SHIFT);
return 0;
}
@@ -571,58 +510,61 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream,
struct device *dev = dai->dev;
struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
unsigned int sample_size, channels, srate, val, reg, path;
- struct tegra210_xbar_cif_conf cif_conf;
- int ret, max_th;
+ struct tegra_cif_conf cif_conf;
- memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf));
+ memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
channels = params_channels(params);
if (channels < 1) {
- dev_err(dev, "Doesn't support %d channels\n", channels);
+ dev_err(dev, "invalid I2S %d channel configuration\n",
+ channels);
return -EINVAL;
}
- cif_conf.audio_channels = channels;
- cif_conf.client_channels = channels;
+ cif_conf.audio_ch = channels;
+ cif_conf.client_ch = channels;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
- val = TEGRA210_I2S_CTRL_BIT_SIZE_8;
+ val = I2S_BITS_8;
sample_size = 8;
- cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_8;
- cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_8;
+ cif_conf.audio_bits = TEGRA_ACIF_BITS_8;
+ cif_conf.client_bits = TEGRA_ACIF_BITS_8;
break;
case SNDRV_PCM_FORMAT_S16_LE:
- val = TEGRA210_I2S_CTRL_BIT_SIZE_16;
+ val = I2S_BITS_16;
sample_size = 16;
- cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_16;
- cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_16;
+ cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
+ cif_conf.client_bits = TEGRA_ACIF_BITS_16;
break;
case SNDRV_PCM_FORMAT_S32_LE:
- val = TEGRA210_I2S_CTRL_BIT_SIZE_32;
+ val = I2S_BITS_32;
sample_size = 32;
- cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_32;
- cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_32;
+ cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
+ cif_conf.client_bits = TEGRA_ACIF_BITS_32;
break;
default:
- dev_err(dev, "Wrong format!\n");
- return -EINVAL;
+ dev_err(dev, "unsupported format!\n");
+ return -ENOTSUPP;
}
- if (i2s->codec_bit_format) {
- val = tegra210_i2s_bit_fmt[i2s->codec_bit_format];
- sample_size = tegra210_i2s_sample_size[i2s->codec_bit_format];
+ if (i2s->client_fmt_override) {
+ val = tegra210_i2s_bit_fmt[i2s->client_fmt_override];
+ sample_size =
+ tegra210_i2s_sample_size[i2s->client_fmt_override];
cif_conf.client_bits =
- tegra210_cif_fmt[i2s->codec_bit_format];
+ tegra210_cif_fmt[i2s->client_fmt_override];
}
+ /* Program sample size */
regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
- TEGRA210_I2S_CTRL_BIT_SIZE_MASK, val);
+ I2S_CTRL_BIT_SIZE_MASK, val);
srate = params_rate(params);
- if (i2s->sample_rate_via_control)
- srate = i2s->sample_rate_via_control;
+ /* Override rate, channel and audio bit params as applicable */
+ if (i2s->srate_override)
+ srate = i2s->srate_override;
/*
* For playback I2S RX-CIF and for capture TX-CIF is used.
@@ -633,55 +575,56 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream,
I2S_RX_PATH : I2S_TX_PATH;
if (i2s->audio_ch_override[path])
- cif_conf.audio_channels = i2s->audio_ch_override[path];
+ cif_conf.audio_ch = i2s->audio_ch_override[path];
if (i2s->client_ch_override)
- cif_conf.client_channels = i2s->client_ch_override;
+ cif_conf.client_ch = i2s->client_ch_override;
if (i2s->audio_fmt_override[path])
cif_conf.audio_bits =
tegra210_cif_fmt[i2s->audio_fmt_override[path]];
- /* As a COCEC DAI, CAPTURE is transmit */
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- unsigned int audio_ch = cif_conf.audio_channels;
+ unsigned int max_th;
- reg = TEGRA210_I2S_AXBAR_RX_CIF_CTRL;
+ /* FIFO threshold in terms of frames */
+ max_th = (I2S_RX_FIFO_DEPTH / cif_conf.audio_ch) - 1;
- /* RX FIFO threshold interms of frames */
- max_th = (TEGRA210_I2S_RX_FIFO_DEPTH / audio_ch) - 1;
- if (max_th < 0)
- return -EINVAL;
-
- if (i2s->rx_fifo_th > max_th) /* error handling */
+ if (i2s->rx_fifo_th > max_th)
i2s->rx_fifo_th = max_th;
cif_conf.threshold = i2s->rx_fifo_th;
- } else
- reg = TEGRA210_I2S_AXBAR_TX_CIF_CTRL;
- cif_conf.stereo_conv = i2s->stereo_to_mono[path];
+ reg = TEGRA210_I2S_RX_CIF_CTRL;
+ } else {
+ reg = TEGRA210_I2S_TX_CIF_CTRL;
+ }
+
cif_conf.mono_conv = i2s->mono_to_stereo[path];
+ cif_conf.stereo_conv = i2s->stereo_to_mono[path];
- tegra210_xbar_set_cif(i2s->regmap, reg, &cif_conf);
+ tegra_set_cif(i2s->regmap, reg, &cif_conf);
- ret = tegra210_i2s_set_timing_params(dev, sample_size, srate,
- cif_conf.client_channels);
- if (ret < 0)
- return ret;
-
- return 0;
+ return tegra210_i2s_set_timing_params(dev, sample_size, srate,
+ cif_conf.client_ch);
}
-static struct snd_soc_dai_ops tegra210_i2s_dai_ops = {
+static const struct snd_soc_dai_ops tegra210_i2s_dai_ops = {
.set_fmt = tegra210_i2s_set_fmt,
.hw_params = tegra210_i2s_hw_params,
.set_bclk_ratio = tegra210_i2s_set_dai_bclk_ratio,
.set_tdm_slot = tegra210_i2s_set_tdm_slot,
- .startup = tegra210_i2s_startup,
- .shutdown = tegra210_i2s_shutdown,
};
+/*
+ * Three DAIs are exposed
+ * 1. "CIF" DAI for connecting with XBAR
+ * 2. "DAP" DAI for connecting with CODEC
+ * 3. "DUMMY" can be used when no external codec connection is
+ * available. In such case "DAP" is connected with "DUMMY".
+ * Order of these DAIs should not be changed, since DAI links in DT refer
+ * to these DAIs depending on the index.
+ */
static struct snd_soc_dai_driver tegra210_i2s_dais[] = {
{
.name = "CIF",
@@ -750,89 +693,6 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = {
},
};
-static int tegra210_i2s_loopback_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec);
-
- ucontrol->value.integer.value[0] = i2s->loopback;
-
- return 0;
-}
-
-static int tegra210_i2s_loopback_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec);
-
- i2s->loopback = ucontrol->value.integer.value[0];
-
- regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
- TEGRA210_I2S_CTRL_LPBK_MASK,
- i2s->loopback << TEGRA210_I2S_CTRL_LPBK_SHIFT);
-
- return 0;
-}
-
-static int tegra210_i2s_get_bclk_ratio(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec);
-
- ucontrol->value.integer.value[0] = i2s->bclk_ratio;
-
- return 0;
-}
-
-static int tegra210_i2s_put_bclk_ratio(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec);
-
- i2s->bclk_ratio = ucontrol->value.integer.value[0];
-
- return 0;
-}
-
-static int tegra210_i2s_fsync_width_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec);
-
- ucontrol->value.integer.value[0] = i2s->fsync_width;
-
- return 0;
-}
-
-static int tegra210_i2s_fsync_width_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
- struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec);
-
- i2s->fsync_width = ucontrol->value.integer.value[0];
-
- /*
- * frame sync width is used only for FSYNC modes and not applicable
- * for LRCK modes. Reset value for this field is "0", which means
- * the width is one bit clock wide. The width requirement may depend
- * on the codec and in such cases mixer control is used to update
- * custom values. A value of "N" here means, width is "N + 1" bit
- * clock wide.
- */
- regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
- TEGRA210_I2S_CTRL_FSYNC_WIDTH_MASK,
- i2s->fsync_width <<
- TEGRA210_I2S_CTRL_FSYNC_WIDTH_SHIFT);
-
- return 0;
-}
-
static const char * const tegra210_i2s_stereo_conv_text[] = {
"CH0", "CH1", "AVG",
};
@@ -842,131 +702,89 @@ static const char * const tegra210_i2s_mono_conv_text[] = {
};
static const struct soc_enum tegra210_i2s_mono_conv_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
- ARRAY_SIZE(tegra210_i2s_mono_conv_text),
- tegra210_i2s_mono_conv_text);
+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_i2s_mono_conv_text),
+ tegra210_i2s_mono_conv_text);
static const struct soc_enum tegra210_i2s_stereo_conv_enum =
- SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
- ARRAY_SIZE(tegra210_i2s_stereo_conv_text),
- tegra210_i2s_stereo_conv_text);
-
-#define NV_SOC_SINGLE_RANGE_EXT(xname, xmin, xmax, xget, xput) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
- .info = snd_soc_info_xr_sx, .get = xget, .put = xput, \
- .private_value = (unsigned long)&(struct soc_mixer_control) \
- {.invert = 0, .min = xmin, .max = xmax, \
- .platform_max = xmax}}
+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(tegra210_i2s_stereo_conv_text),
+ tegra210_i2s_stereo_conv_text);
static const struct snd_kcontrol_new tegra210_i2s_controls[] = {
- SOC_SINGLE_EXT("Loopback", SND_SOC_NOPM, 0, 1, 0,
- tegra210_i2s_loopback_get, tegra210_i2s_loopback_put),
+ SOC_SINGLE_EXT("Loopback", 0, 0, 1, 0, tegra210_i2s_get_control,
+ tegra210_i2s_put_control),
+ SOC_SINGLE_EXT("FSYNC Width", 0, 0, 255, 0, tegra210_i2s_get_control,
+ tegra210_i2s_put_control),
+ SOC_SINGLE_EXT("Sample Rate", 0, 0, 192000, 0, tegra210_i2s_get_control,
+ tegra210_i2s_put_control),
SOC_ENUM_EXT("Playback Audio Bit Format", tegra210_i2s_format_enum,
- tegra210_i2s_get_format, tegra210_i2s_put_format),
+ tegra210_i2s_get_control, tegra210_i2s_put_control),
SOC_ENUM_EXT("Capture Audio Bit Format", tegra210_i2s_format_enum,
- tegra210_i2s_get_format, tegra210_i2s_put_format),
- SOC_ENUM_EXT("codec bit format", tegra210_i2s_format_enum,
- tegra210_i2s_get_format, tegra210_i2s_put_format),
- SOC_SINGLE_EXT("fsync width", SND_SOC_NOPM, 0, 255, 0,
- tegra210_i2s_fsync_width_get, tegra210_i2s_fsync_width_put),
- SOC_SINGLE_EXT("Sample Rate", 0, 0, 192000, 0,
- tegra210_i2s_get_format, tegra210_i2s_put_format),
+ tegra210_i2s_get_control, tegra210_i2s_put_control),
+ SOC_ENUM_EXT("Client Bit Format", tegra210_i2s_format_enum,
+ tegra210_i2s_get_control, tegra210_i2s_put_control),
SOC_SINGLE_EXT("Playback Audio Channels", 0, 0, 16, 0,
- tegra210_i2s_get_format, tegra210_i2s_put_format),
+ tegra210_i2s_get_control, tegra210_i2s_put_control),
SOC_SINGLE_EXT("Capture Audio Channels", 0, 0, 16, 0,
- tegra210_i2s_get_format, tegra210_i2s_put_format),
+ tegra210_i2s_get_control, tegra210_i2s_put_control),
SOC_SINGLE_EXT("Client Channels", 0, 0, 16, 0,
- tegra210_i2s_get_format, tegra210_i2s_put_format),
- SOC_SINGLE_EXT("BCLK Ratio", SND_SOC_NOPM, 0, INT_MAX, 0,
- tegra210_i2s_get_bclk_ratio,
- tegra210_i2s_put_bclk_ratio),
- SOC_ENUM_EXT("Capture stereo to mono conv",
- tegra210_i2s_stereo_conv_enum, tegra210_i2s_get_format,
- tegra210_i2s_put_format),
- SOC_ENUM_EXT("Capture mono to stereo conv",
- tegra210_i2s_mono_conv_enum, tegra210_i2s_get_format,
- tegra210_i2s_put_format),
- SOC_ENUM_EXT("Playback stereo to mono conv",
- tegra210_i2s_stereo_conv_enum, tegra210_i2s_get_format,
- tegra210_i2s_put_format),
- SOC_ENUM_EXT("Playback mono to stereo conv",
- tegra210_i2s_mono_conv_enum, tegra210_i2s_get_format,
- tegra210_i2s_put_format),
- NV_SOC_SINGLE_RANGE_EXT("Playback FIFO threshold", 0,
- TEGRA210_I2S_RX_FIFO_DEPTH - 1,
- tegra210_i2s_get_format,
- tegra210_i2s_put_format),
+ tegra210_i2s_get_control, tegra210_i2s_put_control),
+ SOC_ENUM_EXT("Capture Stereo To Mono", tegra210_i2s_stereo_conv_enum,
+ tegra210_i2s_get_control, tegra210_i2s_put_control),
+ SOC_ENUM_EXT("Capture Mono To Stereo", tegra210_i2s_mono_conv_enum,
+ tegra210_i2s_get_control, tegra210_i2s_put_control),
+ SOC_ENUM_EXT("Playback Stereo To Mono", tegra210_i2s_stereo_conv_enum,
+ tegra210_i2s_get_control, tegra210_i2s_put_control),
+ SOC_ENUM_EXT("Playback Mono To Stereo", tegra210_i2s_mono_conv_enum,
+ tegra210_i2s_get_control, tegra210_i2s_put_control),
+ SOC_SINGLE_EXT("Playback FIFO Threshold", 0, 0, I2S_RX_FIFO_DEPTH - 1,
+ 0, tegra210_i2s_get_control, tegra210_i2s_put_control),
+ SOC_SINGLE_EXT("BCLK Ratio", 0, 0, INT_MAX, 0, tegra210_i2s_get_control,
+ tegra210_i2s_put_control),
};
static const struct snd_soc_dapm_widget tegra210_i2s_widgets[] = {
- SND_SOC_DAPM_AIF_IN("CIF RX", NULL, 0, SND_SOC_NOPM,
- 0, 0),
- SND_SOC_DAPM_AIF_OUT("CIF TX", NULL, 0, SND_SOC_NOPM,
- 0, 0),
- SND_SOC_DAPM_AIF_IN_E("DAP RX", NULL, 0, TEGRA210_I2S_AXBAR_TX_ENABLE,
- TEGRA210_I2S_AXBAR_TX_EN_SHIFT, 0,
- tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_AIF_OUT_E("DAP TX", NULL, 0, TEGRA210_I2S_AXBAR_RX_ENABLE,
- TEGRA210_I2S_AXBAR_RX_EN_SHIFT, 0,
- tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_AIF_IN("CIF RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("CIF TX", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN_E("DAP RX", NULL, 0, TEGRA210_I2S_TX_ENABLE,
+ 0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_AIF_OUT_E("DAP TX", NULL, 0, TEGRA210_I2S_RX_ENABLE,
+ 0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MIC("Dummy Input", NULL),
SND_SOC_DAPM_SPK("Dummy Output", NULL),
};
static const struct snd_soc_dapm_route tegra210_i2s_routes[] = {
- { "CIF RX", NULL, "CIF Receive" },
- { "DAP TX", NULL, "CIF RX" },
+ { "CIF RX", NULL, "CIF Receive" },
+ { "DAP TX", NULL, "CIF RX" },
{ "DAP Transmit", NULL, "DAP TX" },
- { "DAP RX", NULL, "DAP Receive" },
- { "CIF TX", NULL, "DAP RX" },
+ { "DAP RX", NULL, "DAP Receive" },
+ { "CIF TX", NULL, "DAP RX" },
{ "CIF Transmit", NULL, "CIF TX" },
- {"Dummy Capture", NULL, "Dummy Input"},
- {"Dummy Output", NULL, "Dummy Playback"},
+ { "Dummy Capture", NULL, "Dummy Input" },
+ { "Dummy Output", NULL, "Dummy Playback" },
};
-static struct snd_soc_codec_driver tegra210_i2s_codec = {
- .idle_bias_off = 1,
- .component_driver = {
- .dapm_widgets = tegra210_i2s_widgets,
- .num_dapm_widgets = ARRAY_SIZE(tegra210_i2s_widgets),
- .dapm_routes = tegra210_i2s_routes,
- .num_dapm_routes = ARRAY_SIZE(tegra210_i2s_routes),
- .controls = tegra210_i2s_controls,
- .num_controls = ARRAY_SIZE(tegra210_i2s_controls),
- },
+static const struct snd_soc_component_driver tegra210_i2s_cmpnt = {
+ .dapm_widgets = tegra210_i2s_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tegra210_i2s_widgets),
+ .dapm_routes = tegra210_i2s_routes,
+ .num_dapm_routes = ARRAY_SIZE(tegra210_i2s_routes),
+ .controls = tegra210_i2s_controls,
+ .num_controls = ARRAY_SIZE(tegra210_i2s_controls),
+ .non_legacy_dai_naming = 1,
};
static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
- case TEGRA210_I2S_AXBAR_RX_ENABLE:
- case TEGRA210_I2S_AXBAR_RX_SOFT_RESET:
- case TEGRA210_I2S_AXBAR_RX_INT_MASK:
- case TEGRA210_I2S_AXBAR_RX_INT_SET:
- case TEGRA210_I2S_AXBAR_RX_INT_CLEAR:
- case TEGRA210_I2S_AXBAR_RX_CIF_CTRL:
- case TEGRA210_I2S_AXBAR_RX_CTRL:
- case TEGRA210_I2S_AXBAR_RX_SLOT_CTRL:
- case TEGRA210_I2S_AXBAR_RX_CLK_TRIM:
- case TEGRA210_I2S_AXBAR_TX_ENABLE:
- case TEGRA210_I2S_AXBAR_TX_SOFT_RESET:
- case TEGRA210_I2S_AXBAR_TX_INT_MASK:
- case TEGRA210_I2S_AXBAR_TX_INT_SET:
- case TEGRA210_I2S_AXBAR_TX_INT_CLEAR:
- case TEGRA210_I2S_AXBAR_TX_CIF_CTRL:
- case TEGRA210_I2S_AXBAR_TX_CTRL:
- case TEGRA210_I2S_AXBAR_TX_SLOT_CTRL:
- case TEGRA210_I2S_AXBAR_TX_CLK_TRIM:
- case TEGRA210_I2S_ENABLE:
- case TEGRA210_I2S_SOFT_RESET:
- case TEGRA210_I2S_CG:
- case TEGRA210_I2S_CTRL:
- case TEGRA210_I2S_TIMING:
- case TEGRA210_I2S_SLOT_CTRL:
- case TEGRA210_I2S_CLK_TRIM:
- case TEGRA210_I2S_CYA:
+ case TEGRA210_I2S_RX_ENABLE ... TEGRA210_I2S_RX_SOFT_RESET:
+ case TEGRA210_I2S_RX_INT_MASK ... TEGRA210_I2S_RX_CLK_TRIM:
+ case TEGRA210_I2S_TX_ENABLE ... TEGRA210_I2S_TX_SOFT_RESET:
+ case TEGRA210_I2S_TX_INT_MASK ... TEGRA210_I2S_TX_CLK_TRIM:
+ case TEGRA210_I2S_ENABLE ... TEGRA210_I2S_CG:
+ case TEGRA210_I2S_CTRL ... TEGRA210_I2S_CYA:
return true;
default:
return false;
@@ -975,41 +793,18 @@ static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg)
static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg)
{
+ if (tegra210_i2s_wr_reg(dev, reg))
+ return true;
+
switch (reg) {
- case TEGRA210_I2S_AXBAR_RX_STATUS:
- case TEGRA210_I2S_AXBAR_RX_CIF_FIFO_STATUS:
- case TEGRA210_I2S_AXBAR_RX_ENABLE:
- case TEGRA210_I2S_AXBAR_RX_INT_MASK:
- case TEGRA210_I2S_AXBAR_RX_INT_SET:
- case TEGRA210_I2S_AXBAR_RX_INT_CLEAR:
- case TEGRA210_I2S_AXBAR_RX_CIF_CTRL:
- case TEGRA210_I2S_AXBAR_RX_CTRL:
- case TEGRA210_I2S_AXBAR_RX_SLOT_CTRL:
- case TEGRA210_I2S_AXBAR_RX_CLK_TRIM:
- case TEGRA210_I2S_AXBAR_RX_INT_STATUS:
- case TEGRA210_I2S_AXBAR_RX_SOFT_RESET:
- case TEGRA210_I2S_AXBAR_TX_STATUS:
- case TEGRA210_I2S_AXBAR_TX_CIF_FIFO_STATUS:
- case TEGRA210_I2S_AXBAR_TX_ENABLE:
- case TEGRA210_I2S_AXBAR_TX_INT_MASK:
- case TEGRA210_I2S_AXBAR_TX_INT_SET:
- case TEGRA210_I2S_AXBAR_TX_INT_CLEAR:
- case TEGRA210_I2S_AXBAR_TX_CIF_CTRL:
- case TEGRA210_I2S_AXBAR_TX_CTRL:
- case TEGRA210_I2S_AXBAR_TX_SLOT_CTRL:
- case TEGRA210_I2S_AXBAR_TX_CLK_TRIM:
- case TEGRA210_I2S_AXBAR_TX_INT_STATUS:
- case TEGRA210_I2S_AXBAR_TX_SOFT_RESET:
- case TEGRA210_I2S_ENABLE:
+ case TEGRA210_I2S_RX_STATUS:
+ case TEGRA210_I2S_RX_INT_STATUS:
+ case TEGRA210_I2S_RX_CIF_FIFO_STATUS:
+ case TEGRA210_I2S_TX_STATUS:
+ case TEGRA210_I2S_TX_INT_STATUS:
+ case TEGRA210_I2S_TX_CIF_FIFO_STATUS:
case TEGRA210_I2S_STATUS:
- case TEGRA210_I2S_SOFT_RESET:
- case TEGRA210_I2S_CG:
- case TEGRA210_I2S_CTRL:
- case TEGRA210_I2S_TIMING:
- case TEGRA210_I2S_SLOT_CTRL:
- case TEGRA210_I2S_CLK_TRIM:
case TEGRA210_I2S_INT_STATUS:
- case TEGRA210_I2S_CYA:
return true;
default:
return false;
@@ -1019,13 +814,16 @@ static bool tegra210_i2s_rd_reg(struct device *dev, unsigned int reg)
static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
- case TEGRA210_I2S_AXBAR_RX_INT_STATUS:
- case TEGRA210_I2S_AXBAR_RX_STATUS:
- case TEGRA210_I2S_AXBAR_TX_STATUS:
- case TEGRA210_I2S_AXBAR_TX_INT_STATUS:
+ case TEGRA210_I2S_RX_STATUS:
+ case TEGRA210_I2S_RX_INT_STATUS:
+ case TEGRA210_I2S_RX_CIF_FIFO_STATUS:
+ case TEGRA210_I2S_TX_STATUS:
+ case TEGRA210_I2S_TX_INT_STATUS:
+ case TEGRA210_I2S_TX_CIF_FIFO_STATUS:
+ case TEGRA210_I2S_STATUS:
case TEGRA210_I2S_INT_STATUS:
- case TEGRA210_I2S_AXBAR_RX_SOFT_RESET:
- case TEGRA210_I2S_AXBAR_TX_SOFT_RESET:
+ case TEGRA210_I2S_RX_SOFT_RESET:
+ case TEGRA210_I2S_TX_SOFT_RESET:
return true;
default:
return false;
@@ -1033,131 +831,86 @@ static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg)
}
static const struct regmap_config tegra210_i2s_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = TEGRA210_I2S_CYA,
- .writeable_reg = tegra210_i2s_wr_reg,
- .readable_reg = tegra210_i2s_rd_reg,
- .volatile_reg = tegra210_i2s_volatile_reg,
- .reg_defaults = tegra210_i2s_reg_defaults,
- .num_reg_defaults = ARRAY_SIZE(tegra210_i2s_reg_defaults),
- .cache_type = REGCACHE_FLAT,
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = TEGRA210_I2S_CYA,
+ .writeable_reg = tegra210_i2s_wr_reg,
+ .readable_reg = tegra210_i2s_rd_reg,
+ .volatile_reg = tegra210_i2s_volatile_reg,
+ .reg_defaults = tegra210_i2s_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(tegra210_i2s_reg_defaults),
+ .cache_type = REGCACHE_FLAT,
};
static const struct of_device_id tegra210_i2s_of_match[] = {
{ .compatible = "nvidia,tegra210-i2s" },
{},
};
+MODULE_DEVICE_TABLE(of, tegra210_i2s_of_match);
-static int tegra210_i2s_platform_probe(struct platform_device *pdev)
+static int tegra210_i2s_probe(struct platform_device *pdev)
{
- const struct of_device_id *match;
- struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
struct tegra210_i2s *i2s;
- struct resource *mem;
- struct property *prop;
void __iomem *regs;
- int ret = 0, count = 0, num_supplies;
- const char *supply;
+ int err;
- match = of_match_device(tegra210_i2s_of_match, &pdev->dev);
- if (!match) {
- dev_err(&pdev->dev, "Error: No device match found\n");
- return -ENODEV;
- }
-
- i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
+ i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
if (!i2s)
return -ENOMEM;
- i2s->tx_mask = i2s->rx_mask = 0xFFFF;
- i2s->loopback = 0;
- i2s->prod_name = NULL;
- /* default threshold settings */
- i2s->rx_fifo_th = 3;
- dev_set_drvdata(&pdev->dev, i2s);
+ i2s->rx_fifo_th = DEFAULT_I2S_RX_FIFO_THRESHOLD;
+ i2s->tx_mask = DEFAULT_I2S_SLOT_MASK;
+ i2s->rx_mask = DEFAULT_I2S_SLOT_MASK;
+ i2s->loopback = false;
- if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
- i2s->clk_i2s = devm_clk_get(&pdev->dev, "i2s");
- if (IS_ERR(i2s->clk_i2s)) {
- dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
- return PTR_ERR(i2s->clk_i2s);
- }
- i2s->clk_sync_input =
- devm_clk_get(&pdev->dev, "clk_sync_input");
- if (IS_ERR(i2s->clk_sync_input))
- dev_dbg(&pdev->dev, "Can't get i2s sync input clock\n");
+ dev_set_drvdata(dev, i2s);
+
+ i2s->clk_i2s = devm_clk_get(dev, "i2s");
+ if (IS_ERR(i2s->clk_i2s)) {
+ dev_err(dev, "can't retrieve I2S bit clock\n");
+ return PTR_ERR(i2s->clk_i2s);
}
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- regs = devm_ioremap_resource(&pdev->dev, mem);
+ /*
+ * Not an error, as this clock is needed only when some other I/O
+ * requires input clock from current I2S instance, which is
+ * configurable from DT.
+ */
+ i2s->clk_sync_input = devm_clk_get(dev, "sync_input");
+ if (IS_ERR(i2s->clk_sync_input))
+ dev_dbg(dev, "can't retrieve I2S sync input clock\n");
+
+ regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
return PTR_ERR(regs);
- i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+ i2s->regmap = devm_regmap_init_mmio(dev, regs,
&tegra210_i2s_regmap_config);
if (IS_ERR(i2s->regmap)) {
- dev_err(&pdev->dev, "regmap init failed\n");
+ dev_err(dev, "regmap init failed\n");
return PTR_ERR(i2s->regmap);
}
+
regcache_cache_only(i2s->regmap, true);
- if (of_property_read_u32(pdev->dev.of_node, "bclk-ratio",
- &i2s->bclk_ratio) < 0) {
- dev_dbg(&pdev->dev, "Missing prop bclk-ratio for I2S\n");
- i2s->bclk_ratio = 1;
+ err = devm_snd_soc_register_component(dev, &tegra210_i2s_cmpnt,
+ tegra210_i2s_dais,
+ ARRAY_SIZE(tegra210_i2s_dais));
+ if (err) {
+ dev_err(dev, "can't register I2S component, err: %d\n", err);
+ return err;
}
- if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {
- if (of_property_read_string(np, "prod-name",
- &i2s->prod_name) == 0)
- tegra_pinctrl_config_prod(&pdev->dev, i2s->prod_name);
-
- num_supplies = of_property_count_strings(np,
- "regulator-supplies");
- if (num_supplies > 0) {
- i2s->num_supplies = num_supplies;
- i2s->supplies = devm_kzalloc(&pdev->dev, num_supplies *
- sizeof(*i2s->supplies),
- GFP_KERNEL);
- if (!i2s->supplies)
- return -ENOMEM;
-
- of_property_for_each_string(np, "regulator-supplies",
- prop, supply)
- i2s->supplies[count++].supply = supply;
-
- ret = devm_regulator_bulk_get(&pdev->dev,
- i2s->num_supplies,
- i2s->supplies);
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to get supplies: %d\n", ret);
- return ret;
- }
- }
- }
- pm_runtime_enable(&pdev->dev);
- ret = snd_soc_register_codec(&pdev->dev, &tegra210_i2s_codec,
- tegra210_i2s_dais,
- ARRAY_SIZE(tegra210_i2s_dais));
- if (ret != 0) {
- dev_err(&pdev->dev, "Could not register CODEC: %d\n", ret);
- pm_runtime_disable(&pdev->dev);
- return ret;
- }
+ pm_runtime_enable(dev);
return 0;
}
-static int tegra210_i2s_platform_remove(struct platform_device *pdev)
+static int tegra210_i2s_remove(struct platform_device *pdev)
{
- snd_soc_unregister_codec(&pdev->dev);
-
pm_runtime_disable(&pdev->dev);
- if (!pm_runtime_status_suspended(&pdev->dev))
- tegra210_i2s_runtime_suspend(&pdev->dev);
return 0;
}
@@ -1165,24 +918,21 @@ static int tegra210_i2s_platform_remove(struct platform_device *pdev)
static const struct dev_pm_ops tegra210_i2s_pm_ops = {
SET_RUNTIME_PM_OPS(tegra210_i2s_runtime_suspend,
tegra210_i2s_runtime_resume, NULL)
- SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
};
static struct platform_driver tegra210_i2s_driver = {
.driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
+ .name = "tegra210-i2s",
.of_match_table = tegra210_i2s_of_match,
.pm = &tegra210_i2s_pm_ops,
},
- .probe = tegra210_i2s_platform_probe,
- .remove = tegra210_i2s_platform_remove,
+ .probe = tegra210_i2s_probe,
+ .remove = tegra210_i2s_remove,
};
module_platform_driver(tegra210_i2s_driver)
MODULE_AUTHOR("Songhee Baek ");
-MODULE_DESCRIPTION("Tegra210 I2S ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_DEVICE_TABLE(of, tegra210_i2s_of_match);
+MODULE_DESCRIPTION("Tegra210 ASoC I2S driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra210_i2s.h b/sound/soc/tegra/tegra210_i2s.h
index e3b0de7b..67454a24 100644
--- a/sound/soc/tegra/tegra210_i2s.h
+++ b/sound/soc/tegra/tegra210_i2s.h
@@ -1,185 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * tegra210_i2s_alt.h - Definitions for Tegra210 I2S driver
+ * tegra210_i2s.h - Definitions for Tegra210 I2S driver
*
- * Copyright (c) 2014-2020 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
*/
-#ifndef __TEGRA210_I2S_ALT_H__
-#define __TEGRA210_I2S_ALT_H__
+#ifndef __TEGRA210_I2S_H__
+#define __TEGRA210_I2S_H__
-/* Register offsets from TEGRA210_I2S*_BASE */
+/* Register offsets from I2S*_BASE */
+#define TEGRA210_I2S_RX_ENABLE 0x0
+#define TEGRA210_I2S_RX_SOFT_RESET 0x4
+#define TEGRA210_I2S_RX_STATUS 0x0c
+#define TEGRA210_I2S_RX_INT_STATUS 0x10
+#define TEGRA210_I2S_RX_INT_MASK 0x14
+#define TEGRA210_I2S_RX_INT_SET 0x18
+#define TEGRA210_I2S_RX_INT_CLEAR 0x1c
+#define TEGRA210_I2S_RX_CIF_CTRL 0x20
+#define TEGRA210_I2S_RX_CTRL 0x24
+#define TEGRA210_I2S_RX_SLOT_CTRL 0x28
+#define TEGRA210_I2S_RX_CLK_TRIM 0x2c
+#define TEGRA210_I2S_RX_CYA 0x30
+#define TEGRA210_I2S_RX_CIF_FIFO_STATUS 0x34
+#define TEGRA210_I2S_TX_ENABLE 0x40
+#define TEGRA210_I2S_TX_SOFT_RESET 0x44
+#define TEGRA210_I2S_TX_STATUS 0x4c
+#define TEGRA210_I2S_TX_INT_STATUS 0x50
+#define TEGRA210_I2S_TX_INT_MASK 0x54
+#define TEGRA210_I2S_TX_INT_SET 0x58
+#define TEGRA210_I2S_TX_INT_CLEAR 0x5c
+#define TEGRA210_I2S_TX_CIF_CTRL 0x60
+#define TEGRA210_I2S_TX_CTRL 0x64
+#define TEGRA210_I2S_TX_SLOT_CTRL 0x68
+#define TEGRA210_I2S_TX_CLK_TRIM 0x6c
+#define TEGRA210_I2S_TX_CYA 0x70
+#define TEGRA210_I2S_TX_CIF_FIFO_STATUS 0x74
+#define TEGRA210_I2S_ENABLE 0x80
+#define TEGRA210_I2S_SOFT_RESET 0x84
+#define TEGRA210_I2S_CG 0x88
+#define TEGRA210_I2S_STATUS 0x8c
+#define TEGRA210_I2S_INT_STATUS 0x90
+#define TEGRA210_I2S_CTRL 0xa0
+#define TEGRA210_I2S_TIMING 0xa4
+#define TEGRA210_I2S_SLOT_CTRL 0xa8
+#define TEGRA210_I2S_CLK_TRIM 0xac
+#define TEGRA210_I2S_CYA 0xb0
-#define TEGRA210_I2S_AXBAR_RX_ENABLE 0x0
-#define TEGRA210_I2S_AXBAR_RX_SOFT_RESET 0x4
-#define TEGRA210_I2S_AXBAR_RX_STATUS 0x0c
-#define TEGRA210_I2S_AXBAR_RX_INT_STATUS 0x10
-#define TEGRA210_I2S_AXBAR_RX_INT_MASK 0x14
-#define TEGRA210_I2S_AXBAR_RX_INT_SET 0x18
-#define TEGRA210_I2S_AXBAR_RX_INT_CLEAR 0x1c
-#define TEGRA210_I2S_AXBAR_RX_CIF_CTRL 0x20
-#define TEGRA210_I2S_AXBAR_RX_CTRL 0x24
-#define TEGRA210_I2S_AXBAR_RX_SLOT_CTRL 0x28
-#define TEGRA210_I2S_AXBAR_RX_CLK_TRIM 0x2c
-#define TEGRA210_I2S_AXBAR_RX_CYA 0x30
-#define TEGRA210_I2S_AXBAR_RX_CIF_FIFO_STATUS 0x34
-#define TEGRA210_I2S_AXBAR_TX_ENABLE 0x40
-#define TEGRA210_I2S_AXBAR_TX_SOFT_RESET 0x44
-#define TEGRA210_I2S_AXBAR_TX_STATUS 0x4c
-#define TEGRA210_I2S_AXBAR_TX_INT_STATUS 0x50
-#define TEGRA210_I2S_AXBAR_TX_INT_MASK 0x54
-#define TEGRA210_I2S_AXBAR_TX_INT_SET 0x58
-#define TEGRA210_I2S_AXBAR_TX_INT_CLEAR 0x5c
-#define TEGRA210_I2S_AXBAR_TX_CIF_CTRL 0x60
-#define TEGRA210_I2S_AXBAR_TX_CTRL 0x64
-#define TEGRA210_I2S_AXBAR_TX_SLOT_CTRL 0x68
-#define TEGRA210_I2S_AXBAR_TX_CLK_TRIM 0x6c
-#define TEGRA210_I2S_AXBAR_TX_CYA 0x70
-#define TEGRA210_I2S_AXBAR_TX_CIF_FIFO_STATUS 0x74
-#define TEGRA210_I2S_ENABLE 0x80
-#define TEGRA210_I2S_SOFT_RESET 0x84
-#define TEGRA210_I2S_CG 0x88
-#define TEGRA210_I2S_STATUS 0x8c
-#define TEGRA210_I2S_INT_STATUS 0x90
-#define TEGRA210_I2S_CTRL 0xa0
-#define TEGRA210_I2S_TIMING 0xa4
-#define TEGRA210_I2S_SLOT_CTRL 0xa8
-#define TEGRA210_I2S_CLK_TRIM 0xac
-#define TEGRA210_I2S_CYA 0xb0
+/* Bit fields, shifts and masks */
+#define I2S_DATA_SHIFT 8
+#define I2S_CTRL_DATA_OFFSET_MASK (0x7ff << I2S_DATA_SHIFT)
-/*
- * I2S_AXBAAR_RX registers are with respect to AXBAR.
- * The data is coming from AXBAR to I2S for playback.
- */
+#define I2S_EN_SHIFT 0
+#define I2S_EN_MASK BIT(I2S_EN_SHIFT)
+#define I2S_EN BIT(I2S_EN_SHIFT)
-/* Fields in TEGRA210_I2S_AXBAR_RX_ENABLE */
-#define TEGRA210_I2S_AXBAR_RX_EN_SHIFT 0
-#define TEGRA210_I2S_AXBAR_RX_EN (1 << TEGRA210_I2S_AXBAR_RX_EN_SHIFT)
+#define I2S_FSYNC_WIDTH_SHIFT 24
+#define I2S_CTRL_FSYNC_WIDTH_MASK (0xff << I2S_FSYNC_WIDTH_SHIFT)
-/* Fields in TEGRA210_I2S_AXBAR_RX_CTRL */
-#define TEGRA210_I2S_AXBAR_RX_CTRL_DATA_OFFSET_SHIFT 8
-#define TEGRA210_I2S_AXBAR_RX_CTRL_DATA_OFFSET_MASK (0x7ff << TEGRA210_I2S_AXBAR_RX_CTRL_DATA_OFFSET_SHIFT)
+#define I2S_POS_EDGE 0
+#define I2S_NEG_EDGE 1
+#define I2S_EDGE_SHIFT 20
+#define I2S_CTRL_EDGE_CTRL_MASK BIT(I2S_EDGE_SHIFT)
+#define I2S_CTRL_EDGE_CTRL_POS_EDGE (I2S_POS_EDGE << I2S_EDGE_SHIFT)
+#define I2S_CTRL_EDGE_CTRL_NEG_EDGE (I2S_NEG_EDGE << I2S_EDGE_SHIFT)
-#define TEGRA210_I2S_AXBAR_RX_CTRL_MASK_BITS_SHIFT 4
+#define I2S_FMT_LRCK 0
+#define I2S_FMT_FSYNC 1
+#define I2S_FMT_SHIFT 12
+#define I2S_CTRL_FRAME_FMT_MASK (7 << I2S_FMT_SHIFT)
+#define I2S_CTRL_FRAME_FMT_LRCK_MODE (I2S_FMT_LRCK << I2S_FMT_SHIFT)
+#define I2S_CTRL_FRAME_FMT_FSYNC_MODE (I2S_FMT_FSYNC << I2S_FMT_SHIFT)
-#define TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_SHIFT 1
-#define TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_MASK (3 << TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_SHIFT)
-#define TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_NOHIGHZ (0 << TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_SHIFT)
-#define TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_HIGHZ (1 << TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_SHIFT)
-#define TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_HIGHZ_ON_HALF_BIT_CLK (2 << TEGRA210_I2S_AXBAR_RX_CTRL_HIGHZ_CTRL_SHIFT)
+#define I2S_CTRL_MASTER_EN_SHIFT 10
+#define I2S_CTRL_MASTER_EN_MASK BIT(I2S_CTRL_MASTER_EN_SHIFT)
+#define I2S_CTRL_MASTER_EN BIT(I2S_CTRL_MASTER_EN_SHIFT)
-#define TEGRA210_I2S_AXBAR_RX_CTRL_BIT_ORDER_SHIFT 0
-#define TEGRA210_I2S_AXBAR_RX_CTRL_BIT_ORDER_MASK (1 << TEGRA210_I2S_AXBAR_RX_CTRL_BIT_ORDER_SHIFT)
-#define TEGRA210_I2S_AXBAR_RX_CTRL_BIT_ORDER_MSB_FIRST (0 << TEGRA210_I2S_AXBAR_RX_CTRL_BIT_ORDER_SHIFT)
-#define TEGRA210_I2S_AXBAR_RX_CTRL_BIT_ORDER_LSB_FIRST (1 << TEGRA210_I2S_AXBAR_RX_CTRL_BIT_ORDER_SHIFT)
+#define I2S_CTRL_LRCK_POL_SHIFT 9
+#define I2S_CTRL_LRCK_POL_MASK BIT(I2S_CTRL_LRCK_POL_SHIFT)
+#define I2S_CTRL_LRCK_POL_LOW (0 << I2S_CTRL_LRCK_POL_SHIFT)
+#define I2S_CTRL_LRCK_POL_HIGH BIT(I2S_CTRL_LRCK_POL_SHIFT)
-/*
- * I2S_AXBAAR_TX registers are with respect to AXBAR.
- * The data is goint to AXBAR from I2S for capture.
- */
+#define I2S_CTRL_LPBK_SHIFT 8
+#define I2S_CTRL_LPBK_MASK BIT(I2S_CTRL_LPBK_SHIFT)
+#define I2S_CTRL_LPBK_EN BIT(I2S_CTRL_LPBK_SHIFT)
-/* Fields in TEGRA210_I2S_AXBAR_TX_ENABLE */
-#define TEGRA210_I2S_AXBAR_TX_EN_SHIFT 0
-#define TEGRA210_I2S_AXBAR_TX_EN (1 << TEGRA210_I2S_AXBAR_TX_EN_SHIFT)
+#define I2S_BITS_8 1
+#define I2S_BITS_16 3
+#define I2S_BITS_32 7
+#define I2S_CTRL_BIT_SIZE_MASK 0x7
-/* Fields in TEGRA210_I2S_AXBAR_TX_CTRL */
-#define TEGRA210_I2S_AXBAR_TX_CTRL_DATA_OFFSET_SHIFT 8
-#define TEGRA210_I2S_AXBAR_TX_CTRL_DATA_OFFSET_MASK (0x7ff << TEGRA210_I2S_AXBAR_TX_CTRL_DATA_OFFSET_SHIFT)
+#define I2S_TIMING_CH_BIT_CNT_MASK 0x7ff
+#define I2S_TIMING_CH_BIT_CNT_SHIFT 0
-#define TEGRA210_I2S_AXBAR_TX_CTRL_MASK_BITS_SHIFT 4
+#define I2S_SOFT_RESET_SHIFT 0
+#define I2S_SOFT_RESET_MASK BIT(I2S_SOFT_RESET_SHIFT)
+#define I2S_SOFT_RESET_EN BIT(I2S_SOFT_RESET_SHIFT)
-#define TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_SHIFT 1
-#define TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_MASK (3 << TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_SHIFT)
-#define TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_NOHIGHZ (0 << TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_SHIFT)
-#define TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_HIGHZ (1 << TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_SHIFT)
-#define TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_HIGHZ_ON_HALF_BIT_CLK (2 << TEGRA210_I2S_AXBAR_TX_CTRL_HIGHZ_CTRL_SHIFT)
+#define I2S_RX_FIFO_DEPTH 64
+#define DEFAULT_I2S_RX_FIFO_THRESHOLD 3
-#define TEGRA210_I2S_AXBAR_TX_CTRL_BIT_ORDER_SHIFT 0
-#define TEGRA210_I2S_AXBAR_TX_CTRL_BIT_ORDER_MASK (1 << TEGRA210_I2S_AXBAR_TX_CTRL_BIT_ORDER_SHIFT)
-#define TEGRA210_I2S_AXBAR_TX_CTRL_BIT_ORDER_MSB_FIRST (0 << TEGRA210_I2S_AXBAR_TX_CTRL_BIT_ORDER_SHIFT)
-#define TEGRA210_I2S_AXBAR_TX_CTRL_BIT_ORDER_LSB_FIRST (1 << TEGRA210_I2S_AXBAR_TX_CTRL_BIT_ORDER_SHIFT)
-
-/* Fields in TEGRA210_I2S_ENABLE */
-#define TEGRA210_I2S_EN_SHIFT 0
-#define TEGRA210_I2S_EN_MASK (1 << TEGRA210_I2S_EN_SHIFT)
-#define TEGRA210_I2S_EN (1 << TEGRA210_I2S_EN_SHIFT)
-
-/* Fields in TEGRA210_I2S_CTRL */
-#define TEGRA210_I2S_CTRL_FSYNC_WIDTH_SHIFT 24
-#define TEGRA210_I2S_CTRL_FSYNC_WIDTH_MASK (0xff << TEGRA210_I2S_CTRL_FSYNC_WIDTH_SHIFT)
-
-#define TEGRA210_I2S_POS_EDGE 0
-#define TEGRA210_I2S_NEG_EDGE 1
-#define TEGRA210_I2S_CTRL_EDGE_CTRL_SHIFT 20
-#define TEGRA210_I2S_CTRL_EDGE_CTRL_MASK (1 << TEGRA210_I2S_CTRL_EDGE_CTRL_SHIFT)
-#define TEGRA210_I2S_CTRL_EDGE_CTRL_POS_EDGE (TEGRA210_I2S_POS_EDGE << TEGRA210_I2S_CTRL_EDGE_CTRL_SHIFT)
-#define TEGRA210_I2S_CTRL_EDGE_CTRL_NEG_EDGE (TEGRA210_I2S_NEG_EDGE << TEGRA210_I2S_CTRL_EDGE_CTRL_SHIFT)
-
-#define TEGRA210_I2S_CTRL_PIPE_MACRO_EN_SHIFT 19
-#define TEGRA210_I2S_CTRL_PIPE_MACRO_EN (1 << TEGRA210_I2S_CTRL_PIPE_MACRO_EN_SHIFT)
-
-#define TEGRA210_I2S_FRAME_FORMAT_LRCK 0
-#define TEGRA210_I2S_FRAME_FORMAT_FSYNC 1
-#define TEGRA210_I2S_CTRL_FRAME_FORMAT_SHIFT 12
-#define TEGRA210_I2S_CTRL_FRAME_FORMAT_MASK (7 << TEGRA210_I2S_CTRL_FRAME_FORMAT_SHIFT)
-#define TEGRA210_I2S_CTRL_FRAME_FORMAT_LRCK_MODE (TEGRA210_I2S_FRAME_FORMAT_LRCK << TEGRA210_I2S_CTRL_FRAME_FORMAT_SHIFT)
-#define TEGRA210_I2S_CTRL_FRAME_FORMAT_FSYNC_MODE (TEGRA210_I2S_FRAME_FORMAT_FSYNC << TEGRA210_I2S_CTRL_FRAME_FORMAT_SHIFT)
-
-#define TEGRA210_I2S_CTRL_MASTER_EN_SHIFT 10
-#define TEGRA210_I2S_CTRL_MASTER_EN_MASK (1 << TEGRA210_I2S_CTRL_MASTER_EN_SHIFT)
-#define TEGRA210_I2S_CTRL_MASTER_EN (1 << TEGRA210_I2S_CTRL_MASTER_EN_SHIFT)
-#define TEGRA210_I2S_CTRL_SLAVE_EN (1 << TEGRA210_I2S_CTRL_MASTER_EN_SHIFT)
-
-#define TEGRA210_I2S_CTRL_LRCK_POLARITY_SHIFT 9
-#define TEGRA210_I2S_CTRL_LRCK_POLARITY_MASK (1 << TEGRA210_I2S_CTRL_LRCK_POLARITY_SHIFT)
-#define TEGRA210_I2S_CTRL_LRCK_POLARITY_LOW (0 << TEGRA210_I2S_CTRL_LRCK_POLARITY_SHIFT)
-#define TEGRA210_I2S_CTRL_LRCK_POLARITY_HIGH (1 << TEGRA210_I2S_CTRL_LRCK_POLARITY_SHIFT)
-
-#define TEGRA210_I2S_CTRL_LPBK_SHIFT 8
-#define TEGRA210_I2S_CTRL_LPBK_MASK (1 << TEGRA210_I2S_CTRL_LPBK_SHIFT)
-#define TEGRA210_I2S_CTRL_LPBK_EN (1 << TEGRA210_I2S_CTRL_LPBK_SHIFT)
-
-#define TEGRA210_I2S_BITS_8 1
-#define TEGRA210_I2S_BITS_16 3
-#define TEGRA210_I2S_BITS_32 7
-#define TEGRA210_I2S_CTRL_BIT_SIZE_SHIFT 0
-#define TEGRA210_I2S_CTRL_BIT_SIZE_MASK (7 << TEGRA210_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA210_I2S_CTRL_BIT_SIZE_8 (TEGRA210_I2S_BITS_8 << TEGRA210_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA210_I2S_CTRL_BIT_SIZE_16 (TEGRA210_I2S_BITS_16 << TEGRA210_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA210_I2S_CTRL_BIT_SIZE_32 (TEGRA210_I2S_BITS_32 << TEGRA210_I2S_CTRL_BIT_SIZE_SHIFT)
-
-/* Fields in TEGRA210_I2S_TIMING */
-#define TEGRA210_I2S_TIMING_CHANNEL_BIT_CNT_MASK 0x3ff
-#define TEGRA210_I2S_TIMING_CHANNEL_BIT_CNT_SHIFT 0
-
-/* Fields in TEGRA210_I2S_RX_SOFT_RESET */
-#define TEGRA210_I2S_AXBAR_RX_SOFT_RESET_SHIFT 0
-#define TEGRA210_I2S_AXBAR_RX_SOFT_RESET_MASK (1 << TEGRA210_I2S_AXBAR_RX_SOFT_RESET_SHIFT)
-#define TEGRA210_I2S_AXBAR_RX_SOFT_RESET_EN (1 << TEGRA210_I2S_AXBAR_RX_SOFT_RESET_SHIFT)
-#define TEGRA210_I2S_AXBAR_RX_SOFT_RESET_DEFAULT (0 << TEGRA210_I2S_AXBAR_RX_SOFT_RESET_SHIFT)
-
-/* Fields in TEGRA210_I2S_TX_SOFT_RESET */
-#define TEGRA210_I2S_AXBAR_TX_SOFT_RESET_SHIFT 0
-#define TEGRA210_I2S_AXBAR_TX_SOFT_RESET_MASK (1 << TEGRA210_I2S_AXBAR_TX_SOFT_RESET_SHIFT)
-#define TEGRA210_I2S_AXBAR_TX_SOFT_RESET_EN (1 << TEGRA210_I2S_AXBAR_TX_SOFT_RESET_SHIFT)
-#define TEGRA210_I2S_AXBAR_TX_SOFT_RESET_DEFAULT (0 << TEGRA210_I2S_AXBAR_TX_SOFT_RESET_SHIFT)
-
-/* Fields in TEGRA210_I2S_SLOT_CTRL */
-#define TEGRA210_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT 0
-#define TEGRA210_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK 0xf
-
-#define TEGRA210_I2S_RX_FIFO_DEPTH 64
+#define DEFAULT_I2S_SLOT_MASK 0xffff
enum tegra210_i2s_path {
I2S_RX_PATH,
@@ -191,24 +112,21 @@ struct tegra210_i2s {
struct clk *clk_i2s;
struct clk *clk_sync_input;
struct regmap *regmap;
- const char *prod_name;
- struct regulator_bulk_data *supplies;
- struct notifier_block slgc_notifier;
- int num_supplies;
- int bclk_ratio;
- int audio_fmt_override[I2S_PATHS];
- int codec_bit_format;
- int sample_rate_via_control;
- int audio_ch_override[I2S_PATHS];
- int client_ch_override; /* common for both TX and RX */
- int stereo_to_mono[I2S_PATHS];
- int mono_to_stereo[I2S_PATHS];
+ unsigned int stereo_to_mono[I2S_PATHS];
+ unsigned int mono_to_stereo[I2S_PATHS];
+ unsigned int audio_ch_override[I2S_PATHS];
+ unsigned int audio_fmt_override[I2S_PATHS];
+ /* Client overrides are common for TX and RX paths */
+ unsigned int client_ch_override;
+ unsigned int client_fmt_override;
+ unsigned int srate_override;
+ unsigned int dai_fmt;
unsigned int fsync_width;
+ unsigned int bclk_ratio;
unsigned int tx_mask;
unsigned int rx_mask;
+ unsigned int rx_fifo_th;
bool loopback;
- unsigned int format;
- unsigned int rx_fifo_th; /* should be programmed interms of frames */
};
#endif