On Fri, Jul 10, 2026 at 3:08 PM Chancel Liu <[email protected]> wrote: > > From: Chancel Liu <[email protected]> > > When the BCLK divider ratio is 1:1, fsl_sai_set_bclk() enables bypass > mode by setting BYP, but never clears the bit. The BYP=1 value remains > in the regcache, and is restored by regcache_sync() on the next runtime > resume. > > Since BYP=1 combined with BCD=1 immediately outputs the ungated MCLK > as BCLK without waiting for BCE/TE/RE to be enabled, the clock is > driven prematurely before the stream is fully configured, causing > noise on some codecs. > > Fix this by clearing BYP and BCI in fsl_sai_hw_free() taking into > account sync mode and the opposite stream's state, so that the regcache > holds BYP=0 before runtime suspend and regcache_sync() on resume will > not restore bypass mode prematurely. > > Fixes: a50b7926d015 ("ASoC: fsl_sai: implement 1:1 bclk:mclk ratio support") > Cc: [email protected] > Signed-off-by: Chancel Liu <[email protected]>
Thanks for the update. Reviewed-by: Shengjiu Wang <[email protected]> Best regards Shengjiu Wang > --- > Changes in v2: > - Move BYP/BCI clearing from fsl_sai_config_disable() (trigger path) > to fsl_sai_hw_free() to avoid breaking pause/suspend-resume cycles > where hw_params() is not called again on unpause/resume. > > sound/soc/fsl/fsl_sai.c | 29 +++++++++++++++++++++++++---- > 1 file changed, 25 insertions(+), 4 deletions(-) > > diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c > index 9661602b53c5..d232c8f53061 100644 > --- a/sound/soc/fsl/fsl_sai.c > +++ b/sound/soc/fsl/fsl_sai.c > @@ -808,6 +808,8 @@ static int fsl_sai_hw_free(struct snd_pcm_substream > *substream, > struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); > bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; > unsigned int ofs = sai->soc_data->reg_offset; > + int adir = tx ? RX : TX; > + int dir = tx ? TX : RX; > > /* Clear xMR to avoid channel swap with mclk_with_tere enabled case */ > regmap_write(sai->regmap, FSL_SAI_xMR(tx), 0); > @@ -815,10 +817,29 @@ static int fsl_sai_hw_free(struct snd_pcm_substream > *substream, > regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), > FSL_SAI_CR3_TRCE_MASK, 0); > > - if (!sai->is_consumer_mode[tx] && > - sai->mclk_streams & BIT(substream->stream)) { > - clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]); > - sai->mclk_streams &= ~BIT(substream->stream); > + if (!sai->is_consumer_mode[tx]) { > + bool adir_active = !!(sai->mclk_streams & > BIT(!substream->stream)); > + /* > + * If opposite stream provides clocks for synchronous mode and > + * it is inactive, Clear BYP and BCI > + */ > + if (fsl_sai_dir_is_synced(sai, adir) && !adir_active) > + regmap_update_bits(sai->regmap, FSL_SAI_xCR2(!tx, > ofs), > + FSL_SAI_CR2_BCI | FSL_SAI_CR2_BYP, > 0); > + /* > + * Clear BYP and BCI of current stream if either of: > + * 1. current stream doesn't provide clocks for synchronous > mode > + * 2. current stream provides clocks for synchronous mode but > no > + * more stream is active. > + */ > + if (!fsl_sai_dir_is_synced(sai, dir) || !adir_active) > + regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), > + FSL_SAI_CR2_BCI | FSL_SAI_CR2_BYP, > 0); > + > + if (sai->mclk_streams & BIT(substream->stream)) { > + > clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]); > + sai->mclk_streams &= ~BIT(substream->stream); > + } > } > > return 0; > -- > 2.50.1 >
