]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ASoC: stm32_sai: fix incorrect BCLK polarity for DSP_A/B, LEFT_J
authorTomasz Merta <tomasz.merta@arrow.com>
Wed, 8 Apr 2026 08:40:56 +0000 (10:40 +0200)
committerMark Brown <broonie@kernel.org>
Wed, 8 Apr 2026 12:24:21 +0000 (13:24 +0100)
The STM32 SAI driver do not set the clock strobing bit (CKSTR) for DSP_A,
DSP_B and LEFT_J formats, causing data to be sampled on the wrong BCLK
edge when SND_SOC_DAIFMT_NB_NF is used.

Per ALSA convention, NB_NF requires sampling on the rising BCLK edge.
The STM32MP25 SAI reference manual states that CKSTR=1 is required for
signals received by the SAI to be sampled on the SCK rising edge.
Without setting CKSTR=1, the SAI samples on the falling edge, violating
the NB_NF convention. For comparison, the NXP FSL SAI driver correctly
sets FSL_SAI_CR2_BCP for DSP_A, DSP_B and LEFT_J, consistent with its
I2S handling.

This patch adds SAI_XCR1_CKSTR for DSP_A, DSP_B and LEFT_J in
stm32_sai_set_dai_fmt which was verified empirically with a cs47l35 codec.
RIGHT_J (LSB) is not investigated and addressed by this patch.

Note: the STM32 I2S driver (stm32_i2s_set_dai_fmt) may have the same issue
for DSP_A mode, as I2S_CGFR_CKPOL is not set. This has not been verified
and is left for a separate investigation.

Signed-off-by: Tomasz Merta <tommerta@gmail.com>
Link: https://patch.msgid.link/20260408084056.20588-1-tommerta@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/stm/stm32_sai_sub.c

index 450e1585edeee08561f05cd582427d2bcf2c5e29..3e82fa90e719afa678b2098ce59856b76a4d801a 100644 (file)
@@ -802,6 +802,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
                break;
        /* Left justified */
        case SND_SOC_DAIFMT_MSB:
+               cr1 |= SAI_XCR1_CKSTR;
                frcr |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSDEF;
                break;
        /* Right justified */
@@ -809,9 +810,11 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
                frcr |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSDEF;
                break;
        case SND_SOC_DAIFMT_DSP_A:
+               cr1 |= SAI_XCR1_CKSTR;
                frcr |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSOFF;
                break;
        case SND_SOC_DAIFMT_DSP_B:
+               cr1 |= SAI_XCR1_CKSTR;
                frcr |= SAI_XFRCR_FSPOL;
                break;
        default: