mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +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;
|
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:
|
* Workaround for FIFO clear on SLAVE mode:
|
||||||
*
|
*
|
||||||
@@ -420,24 +409,24 @@ clear2:
|
|||||||
*
|
*
|
||||||
* Now we choose plan B here.
|
* 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,
|
regmap_update_bits(i2s_tdm->regmap, I2S_CKR,
|
||||||
I2S_CKR_MSS_MASK, I2S_CKR_MSS_MASTER);
|
I2S_CKR_MSS_MASK, I2S_CKR_MSS_MASTER);
|
||||||
|
regmap_update_bits(i2s_tdm->regmap, I2S_CLR, clr, clr);
|
||||||
ret = regmap_read_poll_timeout_atomic(i2s_tdm->regmap, I2S_CLR, val,
|
ret = regmap_read_poll_timeout_atomic(i2s_tdm->regmap, I2S_CLR, val,
|
||||||
!(val & clr), 10, 100);
|
!(val & clr), 10, 100);
|
||||||
|
if (!i2s_tdm->is_master_mode)
|
||||||
regmap_update_bits(i2s_tdm->regmap, I2S_CKR,
|
regmap_update_bits(i2s_tdm->regmap, I2S_CKR,
|
||||||
I2S_CKR_MSS_MASK, I2S_CKR_MSS_SLAVE);
|
I2S_CKR_MSS_MASK, I2S_CKR_MSS_SLAVE);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_warn(i2s_tdm->dev, "failed to clear on slave mode %u\n", clr);
|
dev_warn(i2s_tdm->dev, "failed to clear %u on %s mode\n",
|
||||||
goto reset;
|
clr, i2s_tdm->is_master_mode ? "master" : "slave");
|
||||||
}
|
goto reset;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
reset:
|
reset:
|
||||||
if (i2s_tdm->clk_trcm)
|
if (i2s_tdm->clk_trcm)
|
||||||
rockchip_i2s_tdm_sync_reset(i2s_tdm);
|
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 = snd_soc_dai_get_dma_data(dai, substream);
|
||||||
dma_data->maxburst = MAXBURST_PER_FIFO * params_channels(params) / 2;
|
dma_data->maxburst = MAXBURST_PER_FIFO * params_channels(params) / 2;
|
||||||
|
|
||||||
if (i2s_tdm->is_master_mode) {
|
if (i2s_tdm->mclk_calibrate)
|
||||||
if (i2s_tdm->mclk_calibrate)
|
rockchip_i2s_tdm_calibrate_mclk(i2s_tdm, substream,
|
||||||
rockchip_i2s_tdm_calibrate_mclk(i2s_tdm, substream,
|
params_rate(params));
|
||||||
params_rate(params));
|
|
||||||
|
|
||||||
ret = rockchip_i2s_tdm_set_mclk(i2s_tdm, substream, &mclk);
|
ret = rockchip_i2s_tdm_set_mclk(i2s_tdm, substream, &mclk);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
mclk_rate = clk_get_rate(mclk);
|
mclk_rate = clk_get_rate(mclk);
|
||||||
bclk_rate = i2s_tdm->bclk_fs * params_rate(params);
|
bclk_rate = i2s_tdm->bclk_fs * params_rate(params);
|
||||||
if (!bclk_rate) {
|
if (!bclk_rate) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
|
||||||
div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
|
|
||||||
div_lrck = bclk_rate / params_rate(params);
|
|
||||||
}
|
}
|
||||||
|
div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
|
||||||
|
div_lrck = bclk_rate / params_rate(params);
|
||||||
|
|
||||||
switch (params_format(params)) {
|
switch (params_format(params)) {
|
||||||
case SNDRV_PCM_FORMAT_S8:
|
case SNDRV_PCM_FORMAT_S8:
|
||||||
|
|||||||
Reference in New Issue
Block a user