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:
Sugar Zhang
2024-07-20 11:55:10 +08:00
committed by Tao Huang
parent c06d283fd2
commit 42568b67f3

View File

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