Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: rockchip: i2s_tdm: Re-add the set_sysclk callback

In commit
9e2ab4b18ebd ("ASoC: rockchip: i2s-tdm: Fix inaccurate sampling rates"),
the set_sysclk callback was removed as considered unused as the mclk rate
can be set in the hw_params callback.
The difference between hw_params and set_sysclk is that the former is
called with the audio sampling rate set in the params (e.g.: 48000 Hz)
while the latter is called with a clock rate already computed with
sampling_rate * mclk-fs (e.g.: 48000 * 256)

For HDMI audio using the Rockchip I2S TDM driver, the mclk-fs value must
be set to 128 instead of the default 256, and that value is set in the
device tree at the machine driver level (like a simple-audio-card
compatible node).
Therefore, the i2s_tdm driver has no idea that another mclk-fs value can
be configured and simply computes the mclk rate in the hw_params callback
with DEFAULT_MCLK_FS * params_rate(params), which is wrong for HDMI
audio.

Re-add the set_sysclk callback so that the mclk rate is computed by the
machine driver which has the correct mclk-fs value set in its device tree
node.

Fixes: 9e2ab4b18ebd ("ASoC: rockchip: i2s-tdm: Fix inaccurate sampling rates")
Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com>
Link: https://patch.msgid.link/20250117163102.65807-1-detlev.casanova@collabora.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Detlev Casanova and committed by
Mark Brown
5323186e d1e7dce2

+29 -2
+29 -2
sound/soc/rockchip/rockchip_i2s_tdm.c
··· 22 22 23 23 #define DRV_NAME "rockchip-i2s-tdm" 24 24 25 - #define DEFAULT_MCLK_FS 256 26 25 #define CH_GRP_MAX 4 /* The max channel 8 / 2 */ 27 26 #define MULTIPLEX_CH_MAX 10 28 27 ··· 69 70 bool has_playback; 70 71 bool has_capture; 71 72 struct snd_soc_dai_driver *dai; 73 + unsigned int mclk_rx_freq; 74 + unsigned int mclk_tx_freq; 72 75 }; 73 76 74 77 static int to_ch_num(unsigned int val) ··· 618 617 return 0; 619 618 } 620 619 620 + static int rockchip_i2s_tdm_set_sysclk(struct snd_soc_dai *cpu_dai, int stream, 621 + unsigned int freq, int dir) 622 + { 623 + struct rk_i2s_tdm_dev *i2s_tdm = to_info(cpu_dai); 624 + 625 + if (i2s_tdm->clk_trcm) { 626 + i2s_tdm->mclk_tx_freq = freq; 627 + i2s_tdm->mclk_rx_freq = freq; 628 + } else { 629 + if (stream == SNDRV_PCM_STREAM_PLAYBACK) 630 + i2s_tdm->mclk_tx_freq = freq; 631 + else 632 + i2s_tdm->mclk_rx_freq = freq; 633 + } 634 + 635 + dev_dbg(i2s_tdm->dev, "The target mclk_%s freq is: %d\n", 636 + stream ? "rx" : "tx", freq); 637 + 638 + return 0; 639 + } 640 + 621 641 static int rockchip_i2s_tdm_hw_params(struct snd_pcm_substream *substream, 622 642 struct snd_pcm_hw_params *params, 623 643 struct snd_soc_dai *dai) ··· 653 631 654 632 if (i2s_tdm->clk_trcm == TRCM_TX) { 655 633 mclk = i2s_tdm->mclk_tx; 634 + mclk_rate = i2s_tdm->mclk_tx_freq; 656 635 } else if (i2s_tdm->clk_trcm == TRCM_RX) { 657 636 mclk = i2s_tdm->mclk_rx; 637 + mclk_rate = i2s_tdm->mclk_rx_freq; 658 638 } else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 659 639 mclk = i2s_tdm->mclk_tx; 640 + mclk_rate = i2s_tdm->mclk_tx_freq; 660 641 } else { 661 642 mclk = i2s_tdm->mclk_rx; 643 + mclk_rate = i2s_tdm->mclk_rx_freq; 662 644 } 663 645 664 - err = clk_set_rate(mclk, DEFAULT_MCLK_FS * params_rate(params)); 646 + err = clk_set_rate(mclk, mclk_rate); 665 647 if (err) 666 648 return err; 667 649 ··· 825 799 .hw_params = rockchip_i2s_tdm_hw_params, 826 800 .set_bclk_ratio = rockchip_i2s_tdm_set_bclk_ratio, 827 801 .set_fmt = rockchip_i2s_tdm_set_fmt, 802 + .set_sysclk = rockchip_i2s_tdm_set_sysclk, 828 803 .set_tdm_slot = rockchip_dai_tdm_slot, 829 804 .trigger = rockchip_i2s_tdm_trigger, 830 805 };