ASoC: sunxi: sun4i-i2s: swapped channels from second capture

From: Matteo Martelli
Date: Fri May 31 2024 - 06:49:39 EST


Hello everyone,
I am experiencing an issue with the Pine64 A64 i2s controller, which is
compatible with sun8i-h3-i2s. The Pine64 board is paired with an external codec
(ES8311), which can capture from a mono MIC. MIC data can be sent to both
channels or to only one selected channel. During the first capture everything
works fine, but since the second capture the channels are swapped: e.g. if MIC
data should be recorded on the left channel, it is recorded on the right
channel.

It seems it has nothing to do with the LRCLK which looks correct under the
logic state analyzer, also consider that playback does not show this issue.

It looks like the issue is due the RX FIFO: even after flushing the RX FIFO,
the first read sample is the last sample from previous capture. This likely
causes the channel swapping: the first read sample from the RX FIFO is
attributed to the left channel but it's an old sample, then the second read
sample from the RX FIFO which is the actual first sample from left channel gets
attributed to the right channel, and so on.

By adding an additional sample read operation after the RX FIFO flush the
channels get no longer swapped:
---
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 5f8d979585b6..a720daff3be9 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -961,10 +961,15 @@ static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s)
/* Flush RX FIFO */
regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
SUN4I_I2S_FIFO_CTRL_FLUSH_RX,
SUN4I_I2S_FIFO_CTRL_FLUSH_RX);

+ /* XXX: Additional dummy read otherwise first read is the last from
+ * previous capture, despite flush of the RX FIFO */
+ unsigned int sample;
+ regmap_read(i2s->regmap, SUN4I_I2S_FIFO_RX_REG, &sample);
+
/* Clear RX counter */
regmap_write(i2s->regmap, SUN4I_I2S_RX_CNT_REG, 0);

/* Enable RX Block */
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
---

I haven't found any reason for this in the User Manual and by debugging the
registers they look as expected, but maybe I am missing something.
Can this issue be reproduced by anyone else?

Running on linux asoc/for-next branch, commit:
47d09270d777 ("Merge remote-tracking branch 'asoc/for-6.9' into asoc-linus")

Best regards,
Matteo Martelli