mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
ASoC: renesas: rz-ssi: Fix channel swap issue in full duplex mode
The full duplex audio starts with half duplex mode and then switch to
full duplex mode (another FIFO reset) when both playback/capture
streams available leading to random audio left/right channel swap
issue. Fix this channel swap issue by detecting the full duplex
condition by populating struct dup variable in startup() callback
and synchronize starting both the play and capture at the same time
in rz_ssi_start().
Cc: stable@kernel.org
Fixes: 4f8cd05a43 ("ASoC: sh: rz-ssi: Add full duplex support")
Co-developed-by: Tony Tang <tony.tang.ks@renesas.com>
Signed-off-by: Tony Tang <tony.tang.ks@renesas.com>
Reviewed-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Link: https://patch.msgid.link/20251114073709.4376-2-biju.das.jz@bp.renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
@@ -133,6 +133,12 @@ struct rz_ssi_priv {
|
||||
bool bckp_rise; /* Bit clock polarity (SSICR.BCKP) */
|
||||
bool dma_rt;
|
||||
|
||||
struct {
|
||||
bool tx_active;
|
||||
bool rx_active;
|
||||
bool one_stream_triggered;
|
||||
} dup;
|
||||
|
||||
/* Full duplex communication support */
|
||||
struct {
|
||||
unsigned int rate;
|
||||
@@ -332,13 +338,12 @@ static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
|
||||
bool is_full_duplex;
|
||||
u32 ssicr, ssifcr;
|
||||
|
||||
is_full_duplex = rz_ssi_is_stream_running(&ssi->playback) ||
|
||||
rz_ssi_is_stream_running(&ssi->capture);
|
||||
is_full_duplex = ssi->dup.tx_active && ssi->dup.rx_active;
|
||||
ssicr = rz_ssi_reg_readl(ssi, SSICR);
|
||||
ssifcr = rz_ssi_reg_readl(ssi, SSIFCR);
|
||||
if (!is_full_duplex) {
|
||||
ssifcr &= ~0xF;
|
||||
} else {
|
||||
} else if (ssi->dup.one_stream_triggered) {
|
||||
rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0);
|
||||
rz_ssi_set_idle(ssi);
|
||||
ssifcr &= ~SSIFCR_FIFO_RST;
|
||||
@@ -374,12 +379,16 @@ static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
|
||||
SSISR_RUIRQ), 0);
|
||||
|
||||
strm->running = 1;
|
||||
if (is_full_duplex)
|
||||
ssicr |= SSICR_TEN | SSICR_REN;
|
||||
else
|
||||
if (!is_full_duplex) {
|
||||
ssicr |= is_play ? SSICR_TEN : SSICR_REN;
|
||||
|
||||
rz_ssi_reg_writel(ssi, SSICR, ssicr);
|
||||
rz_ssi_reg_writel(ssi, SSICR, ssicr);
|
||||
} else if (ssi->dup.one_stream_triggered) {
|
||||
ssicr |= SSICR_TEN | SSICR_REN;
|
||||
rz_ssi_reg_writel(ssi, SSICR, ssicr);
|
||||
ssi->dup.one_stream_triggered = false;
|
||||
} else {
|
||||
ssi->dup.one_stream_triggered = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -915,6 +924,30 @@ static int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rz_ssi_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
ssi->dup.tx_active = true;
|
||||
else
|
||||
ssi->dup.rx_active = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rz_ssi_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
ssi->dup.tx_active = false;
|
||||
else
|
||||
ssi->dup.rx_active = false;
|
||||
}
|
||||
|
||||
static bool rz_ssi_is_valid_hw_params(struct rz_ssi_priv *ssi, unsigned int rate,
|
||||
unsigned int channels,
|
||||
unsigned int sample_width,
|
||||
@@ -985,6 +1018,8 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops rz_ssi_dai_ops = {
|
||||
.startup = rz_ssi_startup,
|
||||
.shutdown = rz_ssi_shutdown,
|
||||
.trigger = rz_ssi_dai_trigger,
|
||||
.set_fmt = rz_ssi_dai_set_fmt,
|
||||
.hw_params = rz_ssi_dai_hw_params,
|
||||
|
||||
Reference in New Issue
Block a user