mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 10:31:46 +09:00
ASoC: rockchip: i2s-tdm: Fix the clk glitch on Calibrate case
BACKGROUND
A short clk giltch (~200us) found on the mclk calibrate case in
kernel 5.10.
mclk-12.288M - mclk-49.152M (~200us) - mclk-12.288M
The root cause is:
clk_set_rate(mclk_parent, 49.152M)
clk_set_rate(mclk, 12.288M)
Prefer to get the mclk rate div from mclk_parent rate, Unfortunately,
the latter will change the mclk_parent rate again in kernel 5.10.
So, do not change mclk parent's rate when it is multiple mclk already,
let clk framework handle it.
e.g.
mclk: clk_i2s1_8ch_tx mclk_parent: clk_i2s_8ch_tx_src
clk_i2s1_8ch_tx_src 0 0 0 12288000
clk_i2s1_8ch_tx_mux 0 0 0 12288000
clk_i2s1_8ch_rx 0 0 0 12288000
Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
Change-Id: Ie9e869a48b65e287e60545626e92c9090ab02229
This commit is contained in:
@@ -67,6 +67,7 @@
|
||||
#define MULTIPLEX_CH_MAX 10
|
||||
#define CLK_PPM_MIN (-1000)
|
||||
#define CLK_PPM_MAX (1000)
|
||||
#define CLK_SHIFT_RATE_HZ_MAX 5
|
||||
#define MAXBURST_PER_FIFO 8
|
||||
#define WAIT_TIME_MS_MAX 10000
|
||||
|
||||
@@ -1448,14 +1449,29 @@ static int rockchip_i2s_tdm_calibrate_mclk(struct rk_i2s_tdm_dev *i2s_tdm,
|
||||
unsigned int mclk_root_freq;
|
||||
unsigned int mclk_root_initial_freq;
|
||||
unsigned int mclk_parent_freq;
|
||||
unsigned int mclk_freq, freq, freq_req;
|
||||
unsigned int div, delta;
|
||||
u64 ppm;
|
||||
int ret;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
mclk_parent = i2s_tdm->mclk_tx_src;
|
||||
else
|
||||
mclk_freq = i2s_tdm->mclk_tx_freq;
|
||||
} else {
|
||||
mclk_parent = i2s_tdm->mclk_rx_src;
|
||||
mclk_freq = i2s_tdm->mclk_rx_freq;
|
||||
}
|
||||
|
||||
switch (i2s_tdm->clk_trcm) {
|
||||
case I2S_CKR_TRCM_TXONLY:
|
||||
mclk_parent = i2s_tdm->mclk_tx_src;
|
||||
mclk_freq = i2s_tdm->mclk_tx_freq;
|
||||
break;
|
||||
case I2S_CKR_TRCM_RXONLY:
|
||||
mclk_parent = i2s_tdm->mclk_rx_src;
|
||||
mclk_freq = i2s_tdm->mclk_rx_freq;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (lrck_freq) {
|
||||
case 8000:
|
||||
@@ -1514,7 +1530,17 @@ static int rockchip_i2s_tdm_calibrate_mclk(struct rk_i2s_tdm_dev *i2s_tdm,
|
||||
i2s_tdm->mclk_root1_freq = clk_get_rate(i2s_tdm->mclk_root1);
|
||||
}
|
||||
|
||||
return clk_set_rate(mclk_parent, mclk_parent_freq);
|
||||
freq = clk_get_rate(mclk_parent);
|
||||
div = DIV_ROUND_CLOSEST(freq, mclk_freq);
|
||||
freq_req = mclk_freq * div;
|
||||
if (freq < freq_req - CLK_SHIFT_RATE_HZ_MAX ||
|
||||
freq > freq_req + CLK_SHIFT_RATE_HZ_MAX) {
|
||||
dev_dbg(i2s_tdm->dev, "Change mclk parent freq from %d to %d\n",
|
||||
freq, mclk_parent_freq);
|
||||
ret = clk_set_rate(mclk_parent, mclk_parent_freq);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_i2s_tdm_mclk_reparent(struct rk_i2s_tdm_dev *i2s_tdm)
|
||||
|
||||
Reference in New Issue
Block a user