mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
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:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user