121 lines
4.5 KiB
Diff
121 lines
4.5 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= <peron.clem@gmail.com>
|
|
Date: Fri, 30 Oct 2020 15:46:35 +0100
|
|
Subject: [PATCH] ASoC: sun4i-i2s: Change set_chan_cfg() params
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
As slots and slot_width can be set manually using set_tdm().
|
|
These values are then kept in sun4i_i2s struct.
|
|
So we need to check if these values are set or not.
|
|
|
|
This is not done actually and will trigger a bug.
|
|
For example, if we set to the simple soundcard in the device-tree
|
|
dai-tdm-slot-width = <32> and then start a stream using S16_LE,
|
|
currently we would calculate BCLK for 32-bit slots, but program
|
|
lrck_period for 16-bit slots, making the sample rate double what we
|
|
expected.
|
|
|
|
To fix this, we need to check if these values are set or not but as
|
|
this logic is already done by the caller. Avoid duplicating this
|
|
logic and just pass the required values as params to set_chan_cfg().
|
|
|
|
Suggested-by: Samuel Holland <samuel@sholland.org>
|
|
Acked-by: Maxime Ripard <mripard@kernel.org>
|
|
Signed-off-by: Clément Péron <peron.clem@gmail.com>
|
|
Link: https://lore.kernel.org/r/20201030144648.397824-3-peron.clem@gmail.com
|
|
Signed-off-by: Mark Brown <broonie@kernel.org>
|
|
---
|
|
sound/soc/sunxi/sun4i-i2s.c | 32 ++++++++++++++++++--------------
|
|
1 file changed, 18 insertions(+), 14 deletions(-)
|
|
|
|
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
|
|
index a994b5cf87b3..4ff2068779fd 100644
|
|
--- a/sound/soc/sunxi/sun4i-i2s.c
|
|
+++ b/sound/soc/sunxi/sun4i-i2s.c
|
|
@@ -162,8 +162,15 @@ struct sun4i_i2s_quirks {
|
|
unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *);
|
|
s8 (*get_sr)(const struct sun4i_i2s *, int);
|
|
s8 (*get_wss)(const struct sun4i_i2s *, int);
|
|
- int (*set_chan_cfg)(const struct sun4i_i2s *,
|
|
- const struct snd_pcm_hw_params *);
|
|
+
|
|
+ /*
|
|
+ * In the set_chan_cfg() function pointer:
|
|
+ * @slots: channels per frame + padding slots, regardless of format
|
|
+ * @slot_width: bits per sample + padding bits, regardless of format
|
|
+ */
|
|
+ int (*set_chan_cfg)(const struct sun4i_i2s *i2s,
|
|
+ unsigned int channels, unsigned int slots,
|
|
+ unsigned int slot_width);
|
|
int (*set_fmt)(const struct sun4i_i2s *, unsigned int);
|
|
};
|
|
|
|
@@ -399,10 +406,9 @@ static s8 sun8i_i2s_get_sr_wss(const struct sun4i_i2s *i2s, int width)
|
|
}
|
|
|
|
static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
|
|
- const struct snd_pcm_hw_params *params)
|
|
+ unsigned int channels, unsigned int slots,
|
|
+ unsigned int slot_width)
|
|
{
|
|
- unsigned int channels = params_channels(params);
|
|
-
|
|
/* Map the channels for playback and capture */
|
|
regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210);
|
|
regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210);
|
|
@@ -419,15 +425,11 @@ static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
|
|
}
|
|
|
|
static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
|
|
- const struct snd_pcm_hw_params *params)
|
|
+ unsigned int channels, unsigned int slots,
|
|
+ unsigned int slot_width)
|
|
{
|
|
- unsigned int channels = params_channels(params);
|
|
- unsigned int slots = channels;
|
|
unsigned int lrck_period;
|
|
|
|
- if (i2s->slots)
|
|
- slots = i2s->slots;
|
|
-
|
|
/* Map the channels for playback and capture */
|
|
regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);
|
|
regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210);
|
|
@@ -450,13 +452,13 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
|
|
switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {
|
|
case SND_SOC_DAIFMT_DSP_A:
|
|
case SND_SOC_DAIFMT_DSP_B:
|
|
- lrck_period = params_physical_width(params) * slots;
|
|
+ lrck_period = slot_width * slots;
|
|
break;
|
|
|
|
case SND_SOC_DAIFMT_LEFT_J:
|
|
case SND_SOC_DAIFMT_RIGHT_J:
|
|
case SND_SOC_DAIFMT_I2S:
|
|
- lrck_period = params_physical_width(params);
|
|
+ lrck_period = slot_width;
|
|
break;
|
|
|
|
default:
|
|
@@ -482,7 +484,9 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
|
|
unsigned int word_size = params_width(params);
|
|
unsigned int slot_width = params_physical_width(params);
|
|
unsigned int channels = params_channels(params);
|
|
+
|
|
unsigned int slots = channels;
|
|
+
|
|
int ret, sr, wss;
|
|
u32 width;
|
|
|
|
@@ -492,7 +496,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
|
|
if (i2s->slot_width)
|
|
slot_width = i2s->slot_width;
|
|
|
|
- ret = i2s->variant->set_chan_cfg(i2s, params);
|
|
+ ret = i2s->variant->set_chan_cfg(i2s, channels, slots, slot_width);
|
|
if (ret < 0) {
|
|
dev_err(dai->dev, "Invalid channel configuration\n");
|
|
return ret;
|