From 3300cecb864233d370731dd1a3cc94b9835ed5f1 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Fri, 28 Apr 2023 18:34:49 +0800 Subject: [PATCH] ASoC: rockchip: sai: Fix BCLK glitch After FS idle, should wait at least 2 BCLK cycle to make sure the CLK gate operation done, and then disable mclk. Otherwise, the BCLK is still ungated. once the mclk is enabled, there maybe a risk that a few BCLK cycle leak. especially for low speed situation, such as 8k samplerate. The best way is to use delay per samplerate, but, the max time is quite a tiny value, so, let's make it simple to use the max time. the max BCLK cycle time is: 31us @ 8K-8Bit (64K BCLK) udelay(40); Should wait for one BCLK ready after DIV and then ungate clk to achieve the clean clk. the max BCLK cycle time is: 15.6us @ 8K-8Bit (64K BCLK) udelay(20); Increase the max timeout to 1ms to fix FS idle failed. because it's not enough for 8k samplerate. rockchip-sai ff810000.sai: Failed to idle FS Signed-off-by: Sugar Zhang Change-Id: Ia9da291dd8586236bb32cc0376a6de389f2f0a40 --- sound/soc/rockchip/rockchip_sai.c | 40 +++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c index 57c9ff1a7136..54907fd05a8b 100644 --- a/sound/soc/rockchip/rockchip_sai.c +++ b/sound/soc/rockchip/rockchip_sai.c @@ -27,6 +27,7 @@ #define MAXBURST_PER_FIFO 8 #define DEFAULT_FS 48000 +#define TIMEOUT_US 1000 #define QUIRK_ALWAYS_ON BIT(0) enum fpw_mode { @@ -81,11 +82,26 @@ static int sai_runtime_suspend(struct device *dev) SAI_XFER_FSS_DIS); ret = regmap_read_poll_timeout_atomic(sai->regmap, SAI_XFER, val, - (val & SAI_XFER_FS_IDLE), 10, 100); + (val & SAI_XFER_FS_IDLE), 10, TIMEOUT_US); if (ret < 0) dev_warn(sai->dev, "Failed to idle FS\n"); regcache_cache_only(sai->regmap, true); + /* + * After FS idle, should wait at least 2 BCLK cycle to make sure + * the CLK gate operation done, and then disable mclk. + * + * Otherwise, the BCLK is still ungated. once the mclk is enabled, + * there maybe a risk that a few BCLK cycle leak. especially for + * low speed situation, such as 8k samplerate. + * + * The best way is to use delay per samplerate, but, the max time + * is quite a tiny value, so, let's make it simple to use the max + * time. + * + * The max BCLK cycle time is: 31us @ 8K-8Bit (64K BCLK) + */ + udelay(40); clk_disable_unprepare(sai->mclk); clk_disable_unprepare(sai->hclk); @@ -111,7 +127,7 @@ static int sai_runtime_resume(struct device *dev) if (ret) goto err_regmap; - if (sai->is_master_mode) + if (sai->quirks & QUIRK_ALWAYS_ON && sai->is_master_mode) regmap_update_bits(sai->regmap, SAI_XFER, SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK, @@ -204,7 +220,7 @@ static int rockchip_sai_clear(struct rk_sai_dev *sai, unsigned int clr) regmap_update_bits(sai->regmap, SAI_CLR, clr, clr); ret = regmap_read_poll_timeout_atomic(sai->regmap, SAI_CLR, val, - !(val & clr), 10, 100); + !(val & clr), 10, TIMEOUT_US); if (ret < 0) { dev_warn(sai->dev, "Failed to clear %u\n", clr); goto reset; @@ -250,7 +266,7 @@ static void rockchip_sai_xfer_stop(struct rk_sai_dev *sai, int stream) regmap_update_bits(sai->regmap, SAI_XFER, msk, val); ret = regmap_read_poll_timeout_atomic(sai->regmap, SAI_XFER, val, - (val & idle), 10, 100); + (val & idle), 10, TIMEOUT_US); if (ret < 0) dev_warn(sai->dev, "Failed to idle stream %d\n", stream); @@ -488,6 +504,22 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK, SAI_CKR_MDIV(div_bclk)); + /* + * Should wait for one BCLK ready after DIV and then ungate + * output clk to achieve the clean clk. + * + * The best way is to use delay per samplerate, but, the max time + * is quite a tiny value, so, let's make it simple to use the max + * time. + * + * The max BCLK cycle time is: 15.6us @ 8K-8Bit (64K BCLK) + */ + udelay(20); + regmap_update_bits(sai->regmap, SAI_XFER, + SAI_XFER_CLK_MASK | + SAI_XFER_FSS_MASK, + SAI_XFER_CLK_EN | + SAI_XFER_FSS_EN); } return 0;