mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
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 1f8e86a5ea ("ASoC: rockchip: pdm: Fix clk glitch on runtime PM")
Signed-off-by: XiaoTan Luo <lxt@rock-chips.com>
Change-Id: I8b1226896d8ca20293335a879452df732801f712
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
#include <linux/mfd/syscon.h>
|
#include <linux/mfd/syscon.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/pinctrl/consumer.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/rational.h>
|
#include <linux/rational.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
@@ -19,6 +20,7 @@
|
|||||||
#include <sound/tlv.h>
|
#include <sound/tlv.h>
|
||||||
|
|
||||||
#include "rockchip_pdm_v2.h"
|
#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_DMA_BURST_SIZE (8) /* size * width: 8*4 = 32 bytes */
|
||||||
#define PDM_V2_PATH_MAX (4)
|
#define PDM_V2_PATH_MAX (4)
|
||||||
@@ -65,6 +67,8 @@ struct rk_pdm_v2_dev {
|
|||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
struct snd_dmaengine_dai_dma_data capture_dma_data;
|
struct snd_dmaengine_dai_dma_data capture_dma_data;
|
||||||
struct reset_control *reset;
|
struct reset_control *reset;
|
||||||
|
struct pinctrl *pinctrl;
|
||||||
|
struct pinctrl_state *clk_state;
|
||||||
unsigned int start_delay_ms;
|
unsigned int start_delay_ms;
|
||||||
unsigned int clk_ref_frq;
|
unsigned int clk_ref_frq;
|
||||||
unsigned int quirks;
|
unsigned int quirks;
|
||||||
@@ -490,6 +494,33 @@ static const struct snd_soc_component_driver rockchip_pdm_v2_component = {
|
|||||||
.legacy_dai_naming = 1,
|
.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)
|
static int rockchip_pdm_v2_runtime_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct rk_pdm_v2_dev *pdm = dev_get_drvdata(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->hclk);
|
||||||
clk_disable_unprepare(pdm->clk_out);
|
clk_disable_unprepare(pdm->clk_out);
|
||||||
|
|
||||||
|
pinctrl_pm_select_idle_state(dev);
|
||||||
|
|
||||||
return 0;
|
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_rxctrl(pdm, 0);
|
||||||
|
|
||||||
|
rockchip_pdm_v2_pinctrl_select_clk_state(dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_regmap:
|
err_regmap:
|
||||||
@@ -745,6 +780,15 @@ static int rockchip_pdm_v2_probe(struct platform_device *pdev)
|
|||||||
pdm->dev = &pdev->dev;
|
pdm->dev = &pdev->dev;
|
||||||
dev_set_drvdata(&pdev->dev, pdm);
|
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->start_delay_ms = PDM_V2_START_DELAY_MS_DEFAULT;
|
||||||
|
|
||||||
pdm->clk = devm_clk_get(&pdev->dev, "pdm_clk");
|
pdm->clk = devm_clk_get(&pdev->dev, "pdm_clk");
|
||||||
|
|||||||
Reference in New Issue
Block a user