ASoC: tegra: Fix wrong value type in I2S

commit 8a2c2fa0c5331445c801e9241f2bb4e0e2a895a8 upstream.

The enum controls are expected to use enumerated value type.
Update relevant references in control get/put callbacks.

Fixes: c0bfa98349d1 ("ASoC: tegra: Add Tegra210 based I2S driver")
Suggested-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sameer Pujar <spujar@nvidia.com>
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/1637219231-406-3-git-send-email-spujar@nvidia.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Sameer Pujar
2021-11-18 12:36:57 +05:30
parent 75d1e83e5e
commit d7d7cc0ad3

View File

@@ -2,7 +2,7 @@
// //
// tegra210_i2s.c - Tegra210 I2S driver // tegra210_i2s.c - Tegra210 I2S driver
// //
// Copyright (c) 2020-2021 NVIDIA CORPORATION. All rights reserved. // Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/device.h> #include <linux/device.h>
@@ -17,12 +17,6 @@
#include "tegra210_i2s.h" #include "tegra210_i2s.h"
#include "tegra_cif.h" #include "tegra_cif.h"
#if IS_ENABLED(CONFIG_TEGRA_DPCM)
#define TEGRA_PLAYBACK_STREAM SNDRV_PCM_STREAM_PLAYBACK
#else
#define TEGRA_PLAYBACK_STREAM SNDRV_PCM_STREAM_CAPTURE
#endif
static const struct reg_default tegra210_i2s_reg_defaults[] = { static const struct reg_default tegra210_i2s_reg_defaults[] = {
{ TEGRA210_I2S_RX_INT_MASK, 0x00000003 }, { TEGRA210_I2S_RX_INT_MASK, 0x00000003 },
{ TEGRA210_I2S_RX_CIF_CTRL, 0x00007700 }, { TEGRA210_I2S_RX_CIF_CTRL, 0x00007700 },
@@ -323,38 +317,27 @@ static int tegra210_i2s_get_control(struct snd_kcontrol *kcontrol,
{ {
struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol); struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt); struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
long *uctl_val = &ucontrol->value.integer.value[0];
if (strstr(kcontrol->id.name, "Loopback")) if (strstr(kcontrol->id.name, "Loopback"))
*uctl_val = i2s->loopback; ucontrol->value.integer.value[0] = i2s->loopback;
else if (strstr(kcontrol->id.name, "Sample Rate"))
*uctl_val = i2s->srate_override;
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, "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, "FSYNC Width")) else if (strstr(kcontrol->id.name, "FSYNC Width"))
*uctl_val = i2s->fsync_width; ucontrol->value.integer.value[0] = i2s->fsync_width;
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]; ucontrol->value.enumerated.item[0] =
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]; ucontrol->value.enumerated.item[0] =
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]; ucontrol->value.enumerated.item[0] =
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]; ucontrol->value.enumerated.item[0] =
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; ucontrol->value.integer.value[0] = i2s->rx_fifo_th;
else if (strstr(kcontrol->id.name, "BCLK Ratio")) else if (strstr(kcontrol->id.name, "BCLK Ratio"))
*uctl_val = i2s->bclk_ratio; ucontrol->value.integer.value[0] = i2s->bclk_ratio;
return 0; return 0;
} }
@@ -364,17 +347,14 @@ static int tegra210_i2s_put_control(struct snd_kcontrol *kcontrol,
{ {
struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol); struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt); struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
int value = ucontrol->value.integer.value[0];
if (strstr(kcontrol->id.name, "Loopback")) { if (strstr(kcontrol->id.name, "Loopback")) {
i2s->loopback = value; i2s->loopback = ucontrol->value.integer.value[0];
regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
I2S_CTRL_LPBK_MASK, I2S_CTRL_LPBK_MASK,
i2s->loopback << I2S_CTRL_LPBK_SHIFT); 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")) { } else if (strstr(kcontrol->id.name, "FSYNC Width")) {
/* /*
* Frame sync width is used only for FSYNC modes and not * Frame sync width is used only for FSYNC modes and not
@@ -384,69 +364,33 @@ static int tegra210_i2s_put_control(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.
*/ */
i2s->fsync_width = value; i2s->fsync_width = ucontrol->value.integer.value[0];
regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
I2S_CTRL_FSYNC_WIDTH_MASK, I2S_CTRL_FSYNC_WIDTH_MASK,
i2s->fsync_width << I2S_FSYNC_WIDTH_SHIFT); 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")) {
i2s->audio_fmt_override[I2S_TX_PATH] = value;
} 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")) {
i2s->audio_ch_override[I2S_TX_PATH] = value;
} 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; i2s->stereo_to_mono[I2S_TX_PATH] =
ucontrol->value.enumerated.item[0];
} 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; i2s->mono_to_stereo[I2S_TX_PATH] =
ucontrol->value.enumerated.item[0];
} 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; i2s->stereo_to_mono[I2S_RX_PATH] =
ucontrol->value.enumerated.item[0];
} 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; i2s->mono_to_stereo[I2S_RX_PATH] =
ucontrol->value.enumerated.item[0];
} else if (strstr(kcontrol->id.name, "Playback FIFO Threshold")) { } else if (strstr(kcontrol->id.name, "Playback FIFO Threshold")) {
i2s->rx_fifo_th = value; i2s->rx_fifo_th = ucontrol->value.integer.value[0];
} else if (strstr(kcontrol->id.name, "BCLK Ratio")) { } else if (strstr(kcontrol->id.name, "BCLK Ratio")) {
i2s->bclk_ratio = value; i2s->bclk_ratio = ucontrol->value.integer.value[0];
} }
return 0; return 0;
} }
static const char * const tegra210_i2s_format_text[] = {
"None",
"16",
"32",
};
static const unsigned int tegra210_cif_fmt[] = {
0,
TEGRA_ACIF_BITS_16,
TEGRA_ACIF_BITS_32,
};
static const unsigned int tegra210_i2s_bit_fmt[] = {
0,
I2S_BITS_16,
I2S_BITS_32,
};
static const unsigned int tegra210_i2s_sample_size[] = {
0,
16,
32,
};
static const struct soc_enum tegra210_i2s_format_enum =
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, static int tegra210_i2s_set_timing_params(struct device *dev,
unsigned int sample_size, unsigned int sample_size,
unsigned int srate, unsigned int srate,
@@ -541,22 +485,6 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream,
cif_conf.audio_bits = TEGRA_ACIF_BITS_16; cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
cif_conf.client_bits = TEGRA_ACIF_BITS_16; cif_conf.client_bits = TEGRA_ACIF_BITS_16;
break; break;
case SNDRV_PCM_FORMAT_S24_LE:
val = I2S_BITS_24;
/*
* I2S bit clock is derived from PLLA_OUT0 and size of
* 24 bits results in fractional value and the clock
* is not accurate with this. To have integer clock
* division below is used. It means there are additional
* bit clocks (8 cycles) which are ignored. Codec picks
* up data for other channel when LRCK signal toggles.
*/
sample_size = 32;
cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
cif_conf.client_bits = TEGRA_ACIF_BITS_24;
break;
case SNDRV_PCM_FORMAT_S32_LE: case SNDRV_PCM_FORMAT_S32_LE:
val = I2S_BITS_32; val = I2S_BITS_32;
sample_size = 32; sample_size = 32;
@@ -568,41 +496,19 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
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->client_fmt_override];
}
/* Program sample size */ /* Program sample size */
regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
I2S_CTRL_BIT_SIZE_MASK, val); I2S_CTRL_BIT_SIZE_MASK, val);
srate = params_rate(params); srate = params_rate(params);
/* Override rate, channel and audio bit params as applicable */
if (i2s->srate_override)
srate = i2s->srate_override;
if (i2s->audio_ch_override[path])
cif_conf.audio_ch = i2s->audio_ch_override[path];
if (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]];
/* For playback I2S RX-CIF and for capture TX-CIF is used */ /* For playback I2S RX-CIF and for capture TX-CIF is used */
if (substream->stream == TEGRA_PLAYBACK_STREAM) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
path = I2S_RX_PATH; path = I2S_RX_PATH;
else else
path = I2S_TX_PATH; path = I2S_TX_PATH;
if (substream->stream == TEGRA_PLAYBACK_STREAM) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
unsigned int max_th; unsigned int max_th;
/* FIFO threshold in terms of frames */ /* FIFO threshold in terms of frames */
@@ -634,87 +540,51 @@ static const struct snd_soc_dai_ops tegra210_i2s_dai_ops = {
.set_tdm_slot = tegra210_i2s_set_tdm_slot, .set_tdm_slot = tegra210_i2s_set_tdm_slot,
}; };
/*
* 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[] = { static struct snd_soc_dai_driver tegra210_i2s_dais[] = {
{
.name = "I2S-CIF",
.playback = {
.stream_name = "CIF-Playback",
.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_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.capture = {
.stream_name = "CIF-Capture",
.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_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
},
{ {
.name = "I2S-DAP", .name = "I2S-CIF",
.playback = { .playback = {
.stream_name = "DAP-Playback", .stream_name = "CIF-Playback",
.channels_min = 1, .channels_min = 1,
.channels_max = 16, .channels_max = 16,
.rates = SNDRV_PCM_RATE_8000_192000, .rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S8 | .formats = SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
SNDRV_PCM_FMTBIT_S32_LE, },
}, .capture = {
.capture = { .stream_name = "CIF-Capture",
.stream_name = "DAP-Capture", .channels_min = 1,
.channels_min = 1, .channels_max = 16,
.channels_max = 16, .rates = SNDRV_PCM_RATE_8000_192000,
.rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 |
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
SNDRV_PCM_FMTBIT_S24_LE | },
SNDRV_PCM_FMTBIT_S32_LE, },
},
.ops = &tegra210_i2s_dai_ops,
.symmetric_rates = 1,
},
{ {
.name = "DUMMY", .name = "I2S-DAP",
.playback = { .playback = {
.stream_name = "Dummy-Playback", .stream_name = "DAP-Playback",
.channels_min = 1, .channels_min = 1,
.channels_max = 16, .channels_max = 16,
.rates = SNDRV_PCM_RATE_8000_192000, .rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S8 | .formats = SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
SNDRV_PCM_FMTBIT_S32_LE, },
}, .capture = {
.capture = { .stream_name = "DAP-Capture",
.stream_name = "Dummy-Capture", .channels_min = 1,
.channels_min = 1, .channels_max = 16,
.channels_max = 16, .rates = SNDRV_PCM_RATE_8000_192000,
.rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 |
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
SNDRV_PCM_FMTBIT_S24_LE | },
SNDRV_PCM_FMTBIT_S32_LE, .ops = &tegra210_i2s_dai_ops,
}, .symmetric_rates = 1,
}, },
}; };
static const char * const tegra210_i2s_stereo_conv_text[] = { static const char * const tegra210_i2s_stereo_conv_text[] = {
@@ -738,20 +608,6 @@ static const struct snd_kcontrol_new tegra210_i2s_controls[] = {
tegra210_i2s_put_control), tegra210_i2s_put_control),
SOC_SINGLE_EXT("FSYNC Width", 0, 0, 255, 0, tegra210_i2s_get_control, SOC_SINGLE_EXT("FSYNC Width", 0, 0, 255, 0, tegra210_i2s_get_control,
tegra210_i2s_put_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_control, tegra210_i2s_put_control),
SOC_ENUM_EXT("Capture Audio Bit Format", tegra210_i2s_format_enum,
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_control, tegra210_i2s_put_control),
SOC_SINGLE_EXT("Capture Audio Channels", 0, 0, 16, 0,
tegra210_i2s_get_control, tegra210_i2s_put_control),
SOC_SINGLE_EXT("Client Channels", 0, 0, 16, 0,
tegra210_i2s_get_control, tegra210_i2s_put_control),
SOC_ENUM_EXT("Capture Stereo To Mono", tegra210_i2s_stereo_conv_enum, SOC_ENUM_EXT("Capture Stereo To Mono", tegra210_i2s_stereo_conv_enum,
tegra210_i2s_get_control, tegra210_i2s_put_control), tegra210_i2s_get_control, tegra210_i2s_put_control),
SOC_ENUM_EXT("Capture Mono To Stereo", tegra210_i2s_mono_conv_enum, SOC_ENUM_EXT("Capture Mono To Stereo", tegra210_i2s_mono_conv_enum,
@@ -773,32 +629,21 @@ static const struct snd_soc_dapm_widget tegra210_i2s_widgets[] = {
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_route tegra210_i2s_routes[] = { static const struct snd_soc_dapm_route tegra210_i2s_routes[] = {
#if IS_ENABLED(CONFIG_TEGRA_DPCM)
/* Playback route from XBAR */ /* Playback route from XBAR */
{ "XBAR-Playback", NULL, "XBAR-TX" }, { "XBAR-Playback", NULL, "XBAR-TX" },
{ "CIF-Playback", NULL, "XBAR-Playback" }, { "CIF-Playback", NULL, "XBAR-Playback" },
/* Capture route to XBAR */
{ "XBAR-RX", NULL, "XBAR-Capture" },
{ "XBAR-Capture", NULL, "CIF-Capture" },
{ "RX", NULL, "CIF-Playback" }, { "RX", NULL, "CIF-Playback" },
{ "DAP-Playback", NULL, "RX" }, { "DAP-Playback", NULL, "RX" },
{ "SPK", NULL, "DAP-Playback" }, { "SPK", NULL, "DAP-Playback" },
/* Capture route to XBAR */
{ "XBAR-RX", NULL, "XBAR-Capture" },
{ "XBAR-Capture", NULL, "CIF-Capture" },
{ "CIF-Capture", NULL, "TX" }, { "CIF-Capture", NULL, "TX" },
{ "TX", NULL, "DAP-Capture" }, { "TX", NULL, "DAP-Capture" },
{ "DAP-Capture", NULL, "MIC" }, { "DAP-Capture", NULL, "MIC" },
#else
{ "RX", NULL, "CIF-Playback" },
{ "DAP-Capture", NULL, "RX" },
{ "CIF-Capture", NULL, "TX" },
{ "TX", NULL, "DAP-Playback" },
{ "Dummy-Capture", NULL, "MIC" },
{ "SPK", NULL, "Dummy-Playback" },
#endif
}; };
static const struct snd_soc_component_driver tegra210_i2s_cmpnt = { static const struct snd_soc_component_driver tegra210_i2s_cmpnt = {