ASoC: tegra: I2S: Add Tegra264 support

Add Tegra264 I2S support with following changes:
- Add soc_data for Tegra264-specific variations
- Tegra264 I2S supports 32 audio channels, hence update the TDM config,
  CIF configuration API and DAI channel_max parameter.
- Register offsets and default values are updated to align with Tegra264.

Signed-off-by: Sheetal <sheetal@nvidia.com>
Link: https://patch.msgid.link/20250512051747.1026770-8-sheetal@nvidia.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Sheetal 2025-05-12 05:17:43 +00:00 committed by Mark Brown
parent 1fb500476f
commit b3354438d8
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 233 additions and 49 deletions

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. // SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES.
// All rights reserved. // All rights reserved.
// //
// tegra210_i2s.c - Tegra210 I2S driver // tegra210_i2s.c - Tegra210 I2S driver
@ -36,14 +36,28 @@ static const struct reg_default tegra210_i2s_reg_defaults[] = {
{ TEGRA210_I2S_CYA, 0x1 }, { TEGRA210_I2S_CYA, 0x1 },
}; };
static void tegra210_i2s_set_slot_ctrl(struct regmap *regmap, static const struct reg_default tegra264_i2s_reg_defaults[] = {
{ TEGRA210_I2S_RX_INT_MASK, 0x00000003 },
{ TEGRA210_I2S_RX_CIF_CTRL, 0x00003f00 },
{ TEGRA264_I2S_TX_INT_MASK, 0x00000003 },
{ TEGRA264_I2S_TX_CIF_CTRL, 0x00003f00 },
{ TEGRA264_I2S_CG, 0x1 },
{ TEGRA264_I2S_TIMING, 0x0000001f },
{ TEGRA264_I2S_ENABLE, 0x1 },
{ TEGRA264_I2S_RX_FIFO_WR_ACCESS_MODE, 0x1 },
{ TEGRA264_I2S_TX_FIFO_RD_ACCESS_MODE, 0x1 },
};
static void tegra210_i2s_set_slot_ctrl(struct tegra210_i2s *i2s,
unsigned int total_slots, unsigned int total_slots,
unsigned int tx_slot_mask, unsigned int tx_slot_mask,
unsigned int rx_slot_mask) unsigned int rx_slot_mask)
{ {
regmap_write(regmap, TEGRA210_I2S_SLOT_CTRL, total_slots - 1); regmap_write(i2s->regmap, TEGRA210_I2S_SLOT_CTRL + i2s->soc_data->i2s_ctrl_offset,
regmap_write(regmap, TEGRA210_I2S_TX_SLOT_CTRL, tx_slot_mask); total_slots - 1);
regmap_write(regmap, TEGRA210_I2S_RX_SLOT_CTRL, rx_slot_mask); regmap_write(i2s->regmap, TEGRA210_I2S_TX_SLOT_CTRL + i2s->soc_data->tx_offset,
tx_slot_mask);
regmap_write(i2s->regmap, TEGRA210_I2S_RX_SLOT_CTRL, rx_slot_mask);
} }
static int tegra210_i2s_set_clock_rate(struct device *dev, static int tegra210_i2s_set_clock_rate(struct device *dev,
@ -53,7 +67,7 @@ static int tegra210_i2s_set_clock_rate(struct device *dev,
unsigned int val; unsigned int val;
int err; int err;
regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val); regmap_read(i2s->regmap, TEGRA210_I2S_CTRL + i2s->soc_data->i2s_ctrl_offset, &val);
/* No need to set rates if I2S is being operated in slave */ /* No need to set rates if I2S is being operated in slave */
if (!(val & I2S_CTRL_MASTER_EN)) if (!(val & I2S_CTRL_MASTER_EN))
@ -100,15 +114,15 @@ static int tegra210_i2s_sw_reset(struct snd_soc_component *compnt,
cif_reg = TEGRA210_I2S_RX_CIF_CTRL; cif_reg = TEGRA210_I2S_RX_CIF_CTRL;
stream_reg = TEGRA210_I2S_RX_CTRL; stream_reg = TEGRA210_I2S_RX_CTRL;
} else { } else {
reset_reg = TEGRA210_I2S_TX_SOFT_RESET; reset_reg = TEGRA210_I2S_TX_SOFT_RESET + i2s->soc_data->tx_offset;
cif_reg = TEGRA210_I2S_TX_CIF_CTRL; cif_reg = TEGRA210_I2S_TX_CIF_CTRL + i2s->soc_data->tx_offset;
stream_reg = TEGRA210_I2S_TX_CTRL; stream_reg = TEGRA210_I2S_TX_CTRL + i2s->soc_data->tx_offset;
} }
/* Store CIF and I2S control values */ /* Store CIF and I2S control values */
regmap_read(i2s->regmap, cif_reg, &cif_ctrl); regmap_read(i2s->regmap, cif_reg, &cif_ctrl);
regmap_read(i2s->regmap, stream_reg, &stream_ctrl); regmap_read(i2s->regmap, stream_reg, &stream_ctrl);
regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &i2s_ctrl); regmap_read(i2s->regmap, TEGRA210_I2S_CTRL + i2s->soc_data->i2s_ctrl_offset, &i2s_ctrl);
/* Reset to make sure the previous transactions are clean */ /* Reset to make sure the previous transactions are clean */
regmap_update_bits(i2s->regmap, reset_reg, reset_mask, reset_en); regmap_update_bits(i2s->regmap, reset_reg, reset_mask, reset_en);
@ -125,7 +139,7 @@ static int tegra210_i2s_sw_reset(struct snd_soc_component *compnt,
/* Restore CIF and I2S control values */ /* Restore CIF and I2S control values */
regmap_write(i2s->regmap, cif_reg, cif_ctrl); regmap_write(i2s->regmap, cif_reg, cif_ctrl);
regmap_write(i2s->regmap, stream_reg, stream_ctrl); regmap_write(i2s->regmap, stream_reg, stream_ctrl);
regmap_write(i2s->regmap, TEGRA210_I2S_CTRL, i2s_ctrl); regmap_write(i2s->regmap, TEGRA210_I2S_CTRL + i2s->soc_data->i2s_ctrl_offset, i2s_ctrl);
return 0; return 0;
} }
@ -140,16 +154,13 @@ static int tegra210_i2s_init(struct snd_soc_dapm_widget *w,
int stream; int stream;
int err; int err;
switch (w->reg) { if (w->reg == TEGRA210_I2S_RX_ENABLE) {
case TEGRA210_I2S_RX_ENABLE:
stream = SNDRV_PCM_STREAM_PLAYBACK; stream = SNDRV_PCM_STREAM_PLAYBACK;
status_reg = TEGRA210_I2S_RX_STATUS; status_reg = TEGRA210_I2S_RX_STATUS;
break; } else if (w->reg == (TEGRA210_I2S_TX_ENABLE + i2s->soc_data->tx_offset)) {
case TEGRA210_I2S_TX_ENABLE:
stream = SNDRV_PCM_STREAM_CAPTURE; stream = SNDRV_PCM_STREAM_CAPTURE;
status_reg = TEGRA210_I2S_TX_STATUS; status_reg = TEGRA210_I2S_TX_STATUS + i2s->soc_data->tx_offset;
break; } else {
default:
return -EINVAL; return -EINVAL;
} }
@ -199,7 +210,7 @@ static void tegra210_i2s_set_data_offset(struct tegra210_i2s *i2s,
unsigned int data_offset) unsigned int data_offset)
{ {
/* Capture path */ /* Capture path */
regmap_update_bits(i2s->regmap, TEGRA210_I2S_TX_CTRL, regmap_update_bits(i2s->regmap, TEGRA210_I2S_TX_CTRL + i2s->soc_data->tx_offset,
I2S_CTRL_DATA_OFFSET_MASK, I2S_CTRL_DATA_OFFSET_MASK,
data_offset << I2S_DATA_SHIFT); data_offset << I2S_DATA_SHIFT);
@ -282,7 +293,8 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai,
return -EINVAL; return -EINVAL;
} }
regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, mask, val); regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL + i2s->soc_data->i2s_ctrl_offset,
mask, val);
i2s->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; i2s->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
@ -296,10 +308,10 @@ static int tegra210_i2s_set_tdm_slot(struct snd_soc_dai *dai,
struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai); struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
/* Copy the required tx and rx mask */ /* Copy the required tx and rx mask */
i2s->tx_mask = (tx_mask > DEFAULT_I2S_SLOT_MASK) ? i2s->tx_mask = (tx_mask > i2s->soc_data->slot_mask) ?
DEFAULT_I2S_SLOT_MASK : tx_mask; i2s->soc_data->slot_mask : tx_mask;
i2s->rx_mask = (rx_mask > DEFAULT_I2S_SLOT_MASK) ? i2s->rx_mask = (rx_mask > i2s->soc_data->slot_mask) ?
DEFAULT_I2S_SLOT_MASK : rx_mask; i2s->soc_data->slot_mask : rx_mask;
return 0; return 0;
} }
@ -327,8 +339,8 @@ static int tegra210_i2s_put_loopback(struct snd_kcontrol *kcontrol,
i2s->loopback = value; i2s->loopback = value;
regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, I2S_CTRL_LPBK_MASK, regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL + i2s->soc_data->i2s_ctrl_offset,
i2s->loopback << I2S_CTRL_LPBK_SHIFT); I2S_CTRL_LPBK_MASK, i2s->loopback << I2S_CTRL_LPBK_SHIFT);
return 1; return 1;
} }
@ -364,9 +376,9 @@ static int tegra210_i2s_put_fsync_width(struct snd_kcontrol *kcontrol,
* cases mixer control is used to update custom values. A value * cases mixer control is used to update custom values. A value
* of "N" here means, width is "N + 1" bit clock wide. * of "N" here means, width is "N + 1" bit clock wide.
*/ */
regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL + i2s->soc_data->i2s_ctrl_offset,
I2S_CTRL_FSYNC_WIDTH_MASK, i2s->soc_data->fsync_width_mask,
i2s->fsync_width << I2S_FSYNC_WIDTH_SHIFT); i2s->fsync_width << i2s->soc_data->fsync_width_shift);
return 1; return 1;
} }
@ -562,7 +574,7 @@ static int tegra210_i2s_set_timing_params(struct device *dev,
return err; return err;
} }
regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val); regmap_read(i2s->regmap, TEGRA210_I2S_CTRL + i2s->soc_data->i2s_ctrl_offset, &val);
/* /*
* For LRCK mode, channel bit count depends on number of bit clocks * For LRCK mode, channel bit count depends on number of bit clocks
@ -578,7 +590,7 @@ static int tegra210_i2s_set_timing_params(struct device *dev,
case I2S_CTRL_FRAME_FMT_FSYNC_MODE: case I2S_CTRL_FRAME_FMT_FSYNC_MODE:
bit_count = (bclk_rate / srate) - 1; bit_count = (bclk_rate / srate) - 1;
tegra210_i2s_set_slot_ctrl(i2s->regmap, channels, tegra210_i2s_set_slot_ctrl(i2s, channels,
i2s->tx_mask, i2s->rx_mask); i2s->tx_mask, i2s->rx_mask);
break; break;
default: default:
@ -591,7 +603,7 @@ static int tegra210_i2s_set_timing_params(struct device *dev,
return -EINVAL; return -EINVAL;
} }
regmap_write(i2s->regmap, TEGRA210_I2S_TIMING, regmap_write(i2s->regmap, TEGRA210_I2S_TIMING + i2s->soc_data->i2s_ctrl_offset,
bit_count << I2S_TIMING_CH_BIT_CNT_SHIFT); bit_count << I2S_TIMING_CH_BIT_CNT_SHIFT);
return 0; return 0;
@ -673,7 +685,7 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream,
} }
/* Program sample size */ /* Program sample size */
regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL + i2s->soc_data->i2s_ctrl_offset,
I2S_CTRL_BIT_SIZE_MASK, val); I2S_CTRL_BIT_SIZE_MASK, val);
srate = params_rate(params); srate = params_rate(params);
@ -697,13 +709,16 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream,
reg = TEGRA210_I2S_RX_CIF_CTRL; reg = TEGRA210_I2S_RX_CIF_CTRL;
} else { } else {
reg = TEGRA210_I2S_TX_CIF_CTRL; reg = TEGRA210_I2S_TX_CIF_CTRL + i2s->soc_data->tx_offset;
} }
cif_conf.mono_conv = i2s->mono_to_stereo[path]; cif_conf.mono_conv = i2s->mono_to_stereo[path];
cif_conf.stereo_conv = i2s->stereo_to_mono[path]; cif_conf.stereo_conv = i2s->stereo_to_mono[path];
tegra_set_cif(i2s->regmap, reg, &cif_conf); if (i2s->soc_data->max_ch == TEGRA264_I2S_MAX_CHANNEL)
tegra264_set_cif(i2s->regmap, reg, &cif_conf);
else
tegra_set_cif(i2s->regmap, reg, &cif_conf);
return tegra210_i2s_set_timing_params(dev, sample_size, srate, return tegra210_i2s_set_timing_params(dev, sample_size, srate,
cif_conf.client_ch); cif_conf.client_ch);
@ -808,13 +823,20 @@ static const struct snd_kcontrol_new tegra210_i2s_controls[] = {
tegra210_i2s_put_bclk_ratio), tegra210_i2s_put_bclk_ratio),
}; };
static const struct snd_soc_dapm_widget tegra210_i2s_widgets[] = { #define TEGRA_I2S_WIDGETS(tx_enable_reg) \
SND_SOC_DAPM_AIF_IN_E("RX", NULL, 0, TEGRA210_I2S_RX_ENABLE, SND_SOC_DAPM_AIF_IN_E("RX", NULL, 0, TEGRA210_I2S_RX_ENABLE, \
0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU), 0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU), \
SND_SOC_DAPM_AIF_OUT_E("TX", NULL, 0, TEGRA210_I2S_TX_ENABLE, SND_SOC_DAPM_AIF_OUT_E("TX", NULL, 0, tx_enable_reg, \
0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU), 0, 0, tegra210_i2s_init, SND_SOC_DAPM_PRE_PMU), \
SND_SOC_DAPM_MIC("MIC", NULL), SND_SOC_DAPM_MIC("MIC", NULL), \
SND_SOC_DAPM_SPK("SPK", NULL), SND_SOC_DAPM_SPK("SPK", NULL),
static const struct snd_soc_dapm_widget tegra210_i2s_widgets[] = {
TEGRA_I2S_WIDGETS(TEGRA210_I2S_TX_ENABLE)
};
static const struct snd_soc_dapm_widget tegra264_i2s_widgets[] = {
TEGRA_I2S_WIDGETS(TEGRA264_I2S_TX_ENABLE)
}; };
static const struct snd_soc_dapm_route tegra210_i2s_routes[] = { static const struct snd_soc_dapm_route tegra210_i2s_routes[] = {
@ -841,6 +863,15 @@ static const struct snd_soc_component_driver tegra210_i2s_cmpnt = {
.num_controls = ARRAY_SIZE(tegra210_i2s_controls), .num_controls = ARRAY_SIZE(tegra210_i2s_controls),
}; };
static const struct snd_soc_component_driver tegra264_i2s_cmpnt = {
.dapm_widgets = tegra264_i2s_widgets,
.num_dapm_widgets = ARRAY_SIZE(tegra264_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 bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg) static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg)
{ {
switch (reg) { switch (reg) {
@ -895,7 +926,68 @@ static bool tegra210_i2s_volatile_reg(struct device *dev, unsigned int reg)
} }
} }
static const struct regmap_config tegra210_i2s_regmap_config = { static bool tegra264_i2s_wr_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case TEGRA210_I2S_RX_ENABLE ... TEGRA210_I2S_RX_SOFT_RESET:
case TEGRA210_I2S_RX_INT_MASK ... TEGRA264_I2S_RX_CYA:
case TEGRA264_I2S_TX_ENABLE ... TEGRA264_I2S_TX_SOFT_RESET:
case TEGRA264_I2S_TX_INT_MASK ... TEGRA264_I2S_TX_FIFO_RD_ACCESS_MODE:
case TEGRA264_I2S_TX_FIFO_THRESHOLD ... TEGRA264_I2S_TX_CYA:
case TEGRA264_I2S_ENABLE ... TEGRA264_I2S_CG:
case TEGRA264_I2S_INT_SET ... TEGRA264_I2S_INT_MASK:
case TEGRA264_I2S_CTRL ... TEGRA264_I2S_CYA:
return true;
default:
return false;
};
}
static bool tegra264_i2s_rd_reg(struct device *dev, unsigned int reg)
{
if (tegra264_i2s_wr_reg(dev, reg))
return true;
switch (reg) {
case TEGRA210_I2S_RX_STATUS:
case TEGRA210_I2S_RX_INT_STATUS:
case TEGRA264_I2S_RX_CIF_FIFO_STATUS:
case TEGRA264_I2S_TX_STATUS:
case TEGRA264_I2S_TX_INT_STATUS:
case TEGRA264_I2S_TX_FIFO_RD_DATA:
case TEGRA264_I2S_TX_CIF_FIFO_STATUS:
case TEGRA264_I2S_STATUS:
case TEGRA264_I2S_INT_STATUS:
case TEGRA264_I2S_PIO_MODE_ENABLE:
case TEGRA264_I2S_PAD_MACRO_STATUS:
return true;
default:
return false;
};
}
static bool tegra264_i2s_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case TEGRA210_I2S_RX_SOFT_RESET:
case TEGRA210_I2S_RX_STATUS:
case TEGRA210_I2S_RX_INT_STATUS:
case TEGRA264_I2S_RX_CIF_FIFO_STATUS:
case TEGRA264_I2S_TX_STATUS:
case TEGRA264_I2S_TX_INT_STATUS:
case TEGRA264_I2S_TX_FIFO_RD_DATA:
case TEGRA264_I2S_TX_CIF_FIFO_STATUS:
case TEGRA264_I2S_STATUS:
case TEGRA264_I2S_INT_STATUS:
case TEGRA264_I2S_TX_SOFT_RESET:
case TEGRA264_I2S_PAD_MACRO_STATUS:
return true;
default:
return false;
};
}
static const struct regmap_config tegra210_regmap_conf = {
.reg_bits = 32, .reg_bits = 32,
.reg_stride = 4, .reg_stride = 4,
.val_bits = 32, .val_bits = 32,
@ -942,20 +1034,34 @@ static void tegra210_parse_client_convert(struct device *dev)
i2s->client_sample_format = simple_util_get_sample_fmt(&data); i2s->client_sample_format = simple_util_get_sample_fmt(&data);
} }
static const struct regmap_config tegra264_regmap_conf = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = TEGRA264_I2S_PAD_MACRO_STATUS,
.writeable_reg = tegra264_i2s_wr_reg,
.readable_reg = tegra264_i2s_rd_reg,
.volatile_reg = tegra264_i2s_volatile_reg,
.reg_defaults = tegra264_i2s_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(tegra264_i2s_reg_defaults),
.cache_type = REGCACHE_FLAT,
};
static int tegra210_i2s_probe(struct platform_device *pdev) static int tegra210_i2s_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct tegra210_i2s *i2s; struct tegra210_i2s *i2s;
void __iomem *regs; void __iomem *regs;
int err; int err, id;
i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL); i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
if (!i2s) if (!i2s)
return -ENOMEM; return -ENOMEM;
i2s->soc_data = of_device_get_match_data(&pdev->dev);
i2s->rx_fifo_th = DEFAULT_I2S_RX_FIFO_THRESHOLD; i2s->rx_fifo_th = DEFAULT_I2S_RX_FIFO_THRESHOLD;
i2s->tx_mask = DEFAULT_I2S_SLOT_MASK; i2s->tx_mask = i2s->soc_data->slot_mask;
i2s->rx_mask = DEFAULT_I2S_SLOT_MASK; i2s->rx_mask = i2s->soc_data->slot_mask;
i2s->loopback = false; i2s->loopback = false;
i2s->client_sample_format = -EINVAL; i2s->client_sample_format = -EINVAL;
@ -981,7 +1087,7 @@ static int tegra210_i2s_probe(struct platform_device *pdev)
return PTR_ERR(regs); return PTR_ERR(regs);
i2s->regmap = devm_regmap_init_mmio(dev, regs, i2s->regmap = devm_regmap_init_mmio(dev, regs,
&tegra210_i2s_regmap_config); i2s->soc_data->regmap_conf);
if (IS_ERR(i2s->regmap)) { if (IS_ERR(i2s->regmap)) {
dev_err(dev, "regmap init failed\n"); dev_err(dev, "regmap init failed\n");
return PTR_ERR(i2s->regmap); return PTR_ERR(i2s->regmap);
@ -991,7 +1097,13 @@ static int tegra210_i2s_probe(struct platform_device *pdev)
regcache_cache_only(i2s->regmap, true); regcache_cache_only(i2s->regmap, true);
err = devm_snd_soc_register_component(dev, &tegra210_i2s_cmpnt, /* Update the dais max channel as per soc */
for (id = 0; id < ARRAY_SIZE(tegra210_i2s_dais); id++) {
tegra210_i2s_dais[id].playback.channels_max = i2s->soc_data->max_ch;
tegra210_i2s_dais[id].capture.channels_max = i2s->soc_data->max_ch;
}
err = devm_snd_soc_register_component(dev, i2s->soc_data->i2s_cmpnt,
tegra210_i2s_dais, tegra210_i2s_dais,
ARRAY_SIZE(tegra210_i2s_dais)); ARRAY_SIZE(tegra210_i2s_dais));
if (err) { if (err) {
@ -1015,8 +1127,31 @@ static const struct dev_pm_ops tegra210_i2s_pm_ops = {
SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
}; };
static const struct tegra_i2s_soc_data soc_data_tegra210 = {
.regmap_conf = &tegra210_regmap_conf,
.i2s_cmpnt = &tegra210_i2s_cmpnt,
.max_ch = TEGRA210_I2S_MAX_CHANNEL,
.tx_offset = TEGRA210_I2S_TX_OFFSET,
.i2s_ctrl_offset = TEGRA210_I2S_CTRL_OFFSET,
.fsync_width_mask = I2S_CTRL_FSYNC_WIDTH_MASK,
.fsync_width_shift = I2S_FSYNC_WIDTH_SHIFT,
.slot_mask = DEFAULT_I2S_SLOT_MASK,
};
static const struct tegra_i2s_soc_data soc_data_tegra264 = {
.regmap_conf = &tegra264_regmap_conf,
.i2s_cmpnt = &tegra264_i2s_cmpnt,
.max_ch = TEGRA264_I2S_MAX_CHANNEL,
.tx_offset = TEGRA264_I2S_TX_OFFSET,
.i2s_ctrl_offset = TEGRA264_I2S_CTRL_OFFSET,
.fsync_width_mask = TEGRA264_I2S_CTRL_FSYNC_WIDTH_MASK,
.fsync_width_shift = TEGRA264_I2S_FSYNC_WIDTH_SHIFT,
.slot_mask = TEGRA264_DEFAULT_I2S_SLOT_MASK,
};
static const struct of_device_id tegra210_i2s_of_match[] = { static const struct of_device_id tegra210_i2s_of_match[] = {
{ .compatible = "nvidia,tegra210-i2s" }, { .compatible = "nvidia,tegra210-i2s", .data = &soc_data_tegra210 },
{ .compatible = "nvidia,tegra264-i2s", .data = &soc_data_tegra264 },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, tegra210_i2s_of_match); MODULE_DEVICE_TABLE(of, tegra210_i2s_of_match);

View File

@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only /* SPDX-License-Identifier: GPL-2.0-only
* SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. * SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES.
* All rights reserved. * All rights reserved.
* *
* tegra210_i2s.h - Definitions for Tegra210 I2S driver * tegra210_i2s.h - Definitions for Tegra210 I2S driver
@ -47,9 +47,38 @@
#define TEGRA210_I2S_CLK_TRIM 0xac #define TEGRA210_I2S_CLK_TRIM 0xac
#define TEGRA210_I2S_CYA 0xb0 #define TEGRA210_I2S_CYA 0xb0
/* T264 specific registers */
#define TEGRA264_I2S_RX_FIFO_WR_ACCESS_MODE 0x30
#define TEGRA264_I2S_RX_CYA 0x3c
#define TEGRA264_I2S_RX_CIF_FIFO_STATUS 0x40
#define TEGRA264_I2S_TX_ENABLE 0x80
#define TEGRA264_I2S_TX_SOFT_RESET 0x84
#define TEGRA264_I2S_TX_STATUS 0x8c
#define TEGRA264_I2S_TX_INT_STATUS 0x90
#define TEGRA264_I2S_TX_INT_MASK 0x94
#define TEGRA264_I2S_TX_CIF_CTRL 0xa0
#define TEGRA264_I2S_TX_FIFO_RD_ACCESS_MODE 0xb0
#define TEGRA264_I2S_TX_FIFO_RD_DATA 0xb4
#define TEGRA264_I2S_TX_FIFO_THRESHOLD 0xb8
#define TEGRA264_I2S_TX_CYA 0xbc
#define TEGRA264_I2S_TX_CIF_FIFO_STATUS 0xc0
#define TEGRA264_I2S_ENABLE 0x100
#define TEGRA264_I2S_CG 0x108
#define TEGRA264_I2S_STATUS 0x10c
#define TEGRA264_I2S_INT_STATUS 0x110
#define TEGRA264_I2S_INT_SET 0x114
#define TEGRA264_I2S_INT_MASK 0x11c
#define TEGRA264_I2S_CTRL 0x12c
#define TEGRA264_I2S_TIMING 0x130
#define TEGRA264_I2S_CYA 0x13c
#define TEGRA264_I2S_PIO_MODE_ENABLE 0x140
#define TEGRA264_I2S_PAD_MACRO_STATUS 0x144
/* Bit fields, shifts and masks */ /* Bit fields, shifts and masks */
#define I2S_DATA_SHIFT 8 #define I2S_DATA_SHIFT 8
#define I2S_CTRL_DATA_OFFSET_MASK (0x7ff << I2S_DATA_SHIFT) #define I2S_CTRL_DATA_OFFSET_MASK (0x7ff << I2S_DATA_SHIFT)
#define TEGRA264_I2S_FSYNC_WIDTH_SHIFT 23
#define TEGRA264_I2S_CTRL_FSYNC_WIDTH_MASK (0x1ff << TEGRA264_I2S_FSYNC_WIDTH_SHIFT)
#define I2S_EN_SHIFT 0 #define I2S_EN_SHIFT 0
#define I2S_EN_MASK BIT(I2S_EN_SHIFT) #define I2S_EN_MASK BIT(I2S_EN_SHIFT)
@ -102,6 +131,14 @@
#define DEFAULT_I2S_RX_FIFO_THRESHOLD 3 #define DEFAULT_I2S_RX_FIFO_THRESHOLD 3
#define DEFAULT_I2S_SLOT_MASK 0xffff #define DEFAULT_I2S_SLOT_MASK 0xffff
#define TEGRA210_I2S_TX_OFFSET 0
#define TEGRA210_I2S_CTRL_OFFSET 0
#define TEGRA210_I2S_MAX_CHANNEL 16
#define TEGRA264_DEFAULT_I2S_SLOT_MASK 0xffffffff
#define TEGRA264_I2S_TX_OFFSET 0x40
#define TEGRA264_I2S_CTRL_OFFSET 0x8c
#define TEGRA264_I2S_MAX_CHANNEL 32
enum tegra210_i2s_path { enum tegra210_i2s_path {
I2S_RX_PATH, I2S_RX_PATH,
@ -109,7 +146,19 @@ enum tegra210_i2s_path {
I2S_PATHS, I2S_PATHS,
}; };
struct tegra_i2s_soc_data {
const struct regmap_config *regmap_conf;
const struct snd_soc_component_driver *i2s_cmpnt;
unsigned int max_ch;
unsigned int tx_offset;
unsigned int i2s_ctrl_offset;
unsigned int fsync_width_mask;
unsigned int fsync_width_shift;
unsigned int slot_mask;
};
struct tegra210_i2s { struct tegra210_i2s {
const struct tegra_i2s_soc_data *soc_data;
struct clk *clk_i2s; struct clk *clk_i2s;
struct clk *clk_sync_input; struct clk *clk_sync_input;
struct regmap *regmap; struct regmap *regmap;