From 48aa220b8b7e58afbefa7115a80a9434359d0510 Mon Sep 17 00:00:00 2001 From: XiaoTan Luo Date: Fri, 12 Jul 2024 10:57:22 +0800 Subject: [PATCH] ASoC: rockchip: pdm_v2: Fix clk glitch on runtime PM For controller which is managed by PD (power-domain), when PD off, the controller is reset to the default status, and the FRAC-DIV is a fixed value(1/20). Once the mclk is enabled, there are some high freq cycle leak, to fix this issue, we use the pinctrl-idle to block these cycles until the config has been come back to the normal state. Ref: commit 1f8e86a5ea59 ("ASoC: rockchip: pdm: Fix clk glitch on runtime PM") Signed-off-by: XiaoTan Luo Change-Id: I8b1226896d8ca20293335a879452df732801f712 --- sound/soc/rockchip/rockchip_pdm_v2.c | 44 ++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/sound/soc/rockchip/rockchip_pdm_v2.c b/sound/soc/rockchip/rockchip_pdm_v2.c index 334445f364a0..59b1be75c1ac 100644 --- a/sound/soc/rockchip/rockchip_pdm_v2.c +++ b/sound/soc/rockchip/rockchip_pdm_v2.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,7 @@ #include #include "rockchip_pdm_v2.h" +#include "rockchip_utils.h" #define PDM_V2_DMA_BURST_SIZE (8) /* size * width: 8*4 = 32 bytes */ #define PDM_V2_PATH_MAX (4) @@ -65,6 +67,8 @@ struct rk_pdm_v2_dev { struct regmap *regmap; struct snd_dmaengine_dai_dma_data capture_dma_data; struct reset_control *reset; + struct pinctrl *pinctrl; + struct pinctrl_state *clk_state; unsigned int start_delay_ms; unsigned int clk_ref_frq; unsigned int quirks; @@ -490,6 +494,33 @@ static const struct snd_soc_component_driver rockchip_pdm_v2_component = { .legacy_dai_naming = 1, }; +static int rockchip_pdm_v2_pinctrl_select_clk_state(struct device *dev) +{ + struct rk_pdm_v2_dev *pdm = dev_get_drvdata(dev); + + if (IS_ERR_OR_NULL(pdm->pinctrl) || !pdm->clk_state) + return 0; + /* + * A necessary delay to make sure the correct + * frac div has been applied when resume from + * power down. + */ + udelay(10); + + /* + * Must disable the clk to avoid clk glitch + * when pinctrl switch from gpio to pdm clk. + */ + + rockchip_utils_clk_gate_endisable(pdm->dev, pdm->clk_out, 0); + udelay(10); + pinctrl_select_state(pdm->pinctrl, pdm->clk_state); + udelay(10); + rockchip_utils_clk_gate_endisable(pdm->dev, pdm->clk_out, 1); + + return 0; +} + static int rockchip_pdm_v2_runtime_suspend(struct device *dev) { struct rk_pdm_v2_dev *pdm = dev_get_drvdata(dev); @@ -499,6 +530,8 @@ static int rockchip_pdm_v2_runtime_suspend(struct device *dev) clk_disable_unprepare(pdm->hclk); clk_disable_unprepare(pdm->clk_out); + pinctrl_pm_select_idle_state(dev); + return 0; } @@ -527,6 +560,8 @@ static int rockchip_pdm_v2_runtime_resume(struct device *dev) rockchip_pdm_v2_rxctrl(pdm, 0); + rockchip_pdm_v2_pinctrl_select_clk_state(dev); + return 0; err_regmap: @@ -745,6 +780,15 @@ static int rockchip_pdm_v2_probe(struct platform_device *pdev) pdm->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, pdm); + pdm->pinctrl = devm_pinctrl_get(&pdev->dev); + if (!IS_ERR_OR_NULL(pdm->pinctrl)) { + pdm->clk_state = pinctrl_lookup_state(pdm->pinctrl, "clk"); + if (IS_ERR(pdm->clk_state)) { + pdm->clk_state = NULL; + dev_warn(pdm->dev, "Have no clk pinctrl state\n"); + } + } + pdm->start_delay_ms = PDM_V2_START_DELAY_MS_DEFAULT; pdm->clk = devm_clk_get(&pdev->dev, "pdm_clk");