From 3324809cd045722b7b0a90e674f27d739373e246 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Fri, 16 Jun 2023 09:28:23 +0800 Subject: [PATCH] ASoC: rockchip: i2s-tdm: Fix register write failed on QUIRKS_ALWAYS_ON CLK_ALWAYS_ON should be placed after all registers write done, because this situation will enable XFER bit which will make some registers(depend on XFER) write failed. Fixes: 3644caf8debb ("ASoC: rockchip: i2s-tdm: Add support for clk always-on") Signed-off-by: Sugar Zhang Change-Id: Iffcfed18d3805ee575df4e8cf267d4ef6a3fa866 --- sound/soc/rockchip/rockchip_i2s_tdm.c | 79 +++++++++++++++++---------- 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index cc27fdab6a89..ab3441d01205 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -2212,6 +2212,44 @@ static irqreturn_t rockchip_i2s_tdm_isr(int irq, void *devid) return IRQ_HANDLED; } +static int rockchip_i2s_tdm_keep_clk_always_on(struct rk_i2s_tdm_dev *i2s_tdm) +{ + unsigned int mclk_rate = DEFAULT_FS * DEFAULT_MCLK_FS; + unsigned int bclk_rate = i2s_tdm->frame_width * DEFAULT_FS; + unsigned int div_lrck = i2s_tdm->frame_width; + unsigned int div_bclk; + int ret; + + div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate); + + /* assign generic freq */ + clk_set_rate(i2s_tdm->mclk_rx, mclk_rate); + clk_set_rate(i2s_tdm->mclk_tx, mclk_rate); + + ret = rockchip_i2s_tdm_mclk_reparent(i2s_tdm); + if (ret) + return ret; + + regmap_update_bits(i2s_tdm->regmap, I2S_CLKDIV, + I2S_CLKDIV_RXM_MASK | I2S_CLKDIV_TXM_MASK, + I2S_CLKDIV_RXM(div_bclk) | I2S_CLKDIV_TXM(div_bclk)); + regmap_update_bits(i2s_tdm->regmap, I2S_CKR, + I2S_CKR_RSD_MASK | I2S_CKR_TSD_MASK, + I2S_CKR_RSD(div_lrck) | I2S_CKR_TSD(div_lrck)); + + if (i2s_tdm->clk_trcm) + rockchip_i2s_tdm_xfer_trcm_start(i2s_tdm); + else + rockchip_i2s_tdm_xfer_start(i2s_tdm, SNDRV_PCM_STREAM_PLAYBACK); + + pm_runtime_forbid(i2s_tdm->dev); + + dev_info(i2s_tdm->dev, "CLK-ALWAYS-ON: mclk: %d, bclk: %d, fsync: %d\n", + mclk_rate, bclk_rate, DEFAULT_FS); + + return 0; +} + static int rockchip_i2s_tdm_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -2404,36 +2442,6 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); - if (i2s_tdm->quirks & QUIRK_ALWAYS_ON) { - unsigned int rate = DEFAULT_FS * DEFAULT_MCLK_FS; - unsigned int div_bclk = DEFAULT_FS * DEFAULT_MCLK_FS; - unsigned int div_lrck = i2s_tdm->frame_width; - - div_bclk = DIV_ROUND_CLOSEST(rate, div_lrck * DEFAULT_FS); - - /* assign generic freq */ - clk_set_rate(i2s_tdm->mclk_rx, rate); - clk_set_rate(i2s_tdm->mclk_tx, rate); - - ret = rockchip_i2s_tdm_mclk_reparent(i2s_tdm); - if (ret) - goto err_suspend; - - regmap_update_bits(i2s_tdm->regmap, I2S_CLKDIV, - I2S_CLKDIV_RXM_MASK | I2S_CLKDIV_TXM_MASK, - I2S_CLKDIV_RXM(div_bclk) | I2S_CLKDIV_TXM(div_bclk)); - regmap_update_bits(i2s_tdm->regmap, I2S_CKR, - I2S_CKR_RSD_MASK | I2S_CKR_TSD_MASK, - I2S_CKR_RSD(div_lrck) | I2S_CKR_TSD(div_lrck)); - - if (i2s_tdm->clk_trcm) - rockchip_i2s_tdm_xfer_trcm_start(i2s_tdm); - else - rockchip_i2s_tdm_xfer_start(i2s_tdm, SNDRV_PCM_STREAM_PLAYBACK); - - pm_runtime_forbid(&pdev->dev); - } - regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK, I2S_DMACR_TDL(16)); regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK, @@ -2444,6 +2452,17 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev) if (i2s_tdm->soc_data && i2s_tdm->soc_data->init) i2s_tdm->soc_data->init(&pdev->dev, res->start); + /* + * CLK_ALWAYS_ON should be placed after all registers write done, + * because this situation will enable XFER bit which will make + * some registers(depend on XFER) write failed. + */ + if (i2s_tdm->quirks & QUIRK_ALWAYS_ON) { + ret = rockchip_i2s_tdm_keep_clk_always_on(i2s_tdm); + if (ret) + goto err_suspend; + } + ret = devm_snd_soc_register_component(&pdev->dev, &rockchip_i2s_tdm_component, i2s_tdm->dai, 1);