From c003b7fd8a4446c5008995699abde2cbf6a8e0d9 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Tue, 28 Feb 2023 17:50:49 +0800 Subject: [PATCH] ASoC: rockchip: i2s-tdm: Fix FIFO Clear failed on SLAVE mode sometimes The previous idea about FIFO clear on SLAVE mode is: 1, Switch to MASTER mode 2, Do FIFO clear 3, Switch to SLAVE mode But, there is a risk that drivers don't set mclk on SLAVE mode, the mclk from PLL maybe a very high freq (higher than controllers' signoff freq) that make controller work unexpected. This patch allow set mclk freq for MASTER / SLAVE mode to fix it. and, of course, there is no side effect. This patch also simplify the clear routine by merging clear step 1/2 into a single one. Fixes: 0a0a0b76064c ("ASoC: rockchip: i2s-tdm: Fix FIFO clear error on SLAVE mode") Signed-off-by: Sugar Zhang Change-Id: I8488b039e1e21a632bfd2a1c48c86b343fded17a --- sound/soc/rockchip/rockchip_i2s_tdm.c | 61 +++++++++++---------------- 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index 83128bcf00f5..d15b777d5b70 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -397,17 +397,6 @@ static int rockchip_i2s_tdm_clear(struct rk_i2s_tdm_dev *i2s_tdm, return -EINVAL; } - regmap_update_bits(i2s_tdm->regmap, I2S_CLR, clr, clr); - ret = regmap_read_poll_timeout_atomic(i2s_tdm->regmap, I2S_CLR, val, - !(val & clr), 10, 100); - if (ret < 0) { - dev_warn(i2s_tdm->dev, "failed to clear %u\n", clr); - goto clear2; - } - - return 0; - -clear2: /* * Workaround for FIFO clear on SLAVE mode: * @@ -420,24 +409,24 @@ clear2: * * Now we choose plan B here. */ - if (!i2s_tdm->is_master_mode) { + if (!i2s_tdm->is_master_mode) regmap_update_bits(i2s_tdm->regmap, I2S_CKR, I2S_CKR_MSS_MASK, I2S_CKR_MSS_MASTER); - - ret = regmap_read_poll_timeout_atomic(i2s_tdm->regmap, I2S_CLR, val, - !(val & clr), 10, 100); - + regmap_update_bits(i2s_tdm->regmap, I2S_CLR, clr, clr); + ret = regmap_read_poll_timeout_atomic(i2s_tdm->regmap, I2S_CLR, val, + !(val & clr), 10, 100); + if (!i2s_tdm->is_master_mode) regmap_update_bits(i2s_tdm->regmap, I2S_CKR, I2S_CKR_MSS_MASK, I2S_CKR_MSS_SLAVE); - if (ret < 0) { - dev_warn(i2s_tdm->dev, "failed to clear on slave mode %u\n", clr); - goto reset; - } - - return 0; + if (ret < 0) { + dev_warn(i2s_tdm->dev, "failed to clear %u on %s mode\n", + clr, i2s_tdm->is_master_mode ? "master" : "slave"); + goto reset; } + return 0; + reset: if (i2s_tdm->clk_trcm) rockchip_i2s_tdm_sync_reset(i2s_tdm); @@ -1251,24 +1240,22 @@ static int rockchip_i2s_tdm_hw_params(struct snd_pcm_substream *substream, dma_data = snd_soc_dai_get_dma_data(dai, substream); dma_data->maxburst = MAXBURST_PER_FIFO * params_channels(params) / 2; - if (i2s_tdm->is_master_mode) { - if (i2s_tdm->mclk_calibrate) - rockchip_i2s_tdm_calibrate_mclk(i2s_tdm, substream, - params_rate(params)); + if (i2s_tdm->mclk_calibrate) + rockchip_i2s_tdm_calibrate_mclk(i2s_tdm, substream, + params_rate(params)); - ret = rockchip_i2s_tdm_set_mclk(i2s_tdm, substream, &mclk); - if (ret) - goto err; + ret = rockchip_i2s_tdm_set_mclk(i2s_tdm, substream, &mclk); + if (ret) + goto err; - mclk_rate = clk_get_rate(mclk); - bclk_rate = i2s_tdm->bclk_fs * params_rate(params); - if (!bclk_rate) { - ret = -EINVAL; - goto err; - } - div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate); - div_lrck = bclk_rate / params_rate(params); + mclk_rate = clk_get_rate(mclk); + bclk_rate = i2s_tdm->bclk_fs * params_rate(params); + if (!bclk_rate) { + ret = -EINVAL; + goto err; } + div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate); + div_lrck = bclk_rate / params_rate(params); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: