mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +09:00
ASoC: rockchip: pdm: 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. Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com> Change-Id: I4e34129277cffa7bc443b6addfb1e26b70bf546e
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#include <linux/clk/rockchip.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/rational.h>
|
||||
#include <linux/regmap.h>
|
||||
@@ -48,6 +49,8 @@ struct rk_pdm_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 filter_delay_ms;
|
||||
enum rk_pdm_version version;
|
||||
@@ -723,6 +726,31 @@ static const struct snd_soc_component_driver rockchip_pdm_component = {
|
||||
.name = "rockchip-pdm",
|
||||
};
|
||||
|
||||
static int rockchip_pdm_pinctrl_select_clk_state(struct device *dev)
|
||||
{
|
||||
struct rk_pdm_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.
|
||||
*/
|
||||
clk_disable_unprepare(pdm->clk);
|
||||
pinctrl_select_state(pdm->pinctrl, pdm->clk_state);
|
||||
clk_prepare_enable(pdm->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_pdm_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct rk_pdm_dev *pdm = dev_get_drvdata(dev);
|
||||
@@ -731,6 +759,8 @@ static int rockchip_pdm_runtime_suspend(struct device *dev)
|
||||
clk_disable_unprepare(pdm->clk);
|
||||
clk_disable_unprepare(pdm->hclk);
|
||||
|
||||
pinctrl_pm_select_idle_state(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -755,6 +785,8 @@ static int rockchip_pdm_runtime_resume(struct device *dev)
|
||||
|
||||
rockchip_pdm_rxctrl(pdm, 0);
|
||||
|
||||
rockchip_pdm_pinctrl_select_clk_state(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_regmap:
|
||||
@@ -936,6 +968,15 @@ static int rockchip_pdm_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_dbg(pdm->dev, "Have no clk pinctrl state\n");
|
||||
}
|
||||
}
|
||||
|
||||
pdm->start_delay_ms = PDM_START_DELAY_MS_DEFAULT;
|
||||
pdm->filter_delay_ms = PDM_FILTER_DELAY_MS_MIN;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user