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: 0a0a0b7606 ("ASoC: rockchip: i2s-tdm: Fix FIFO clear error on SLAVE mode")

Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
Change-Id: I8488b039e1e21a632bfd2a1c48c86b343fded17a
This commit is contained in:
Sugar Zhang
2023-02-28 17:50:49 +08:00
committed by Tao Huang
parent fce76cf947
commit c003b7fd8a

View File

@@ -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: