diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 876fc83ad264..2595d0e76c7d 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -75,6 +75,7 @@ struct rk_i2s_dev { struct pinctrl *pinctrl; struct pinctrl_state *bclk_on; struct pinctrl_state *bclk_off; + struct pinctrl_state *clk_state; unsigned int clk_trcm; unsigned int mclk_root_rate; @@ -129,6 +130,20 @@ static int i2s_runtime_suspend(struct device *dev) regcache_cache_only(i2s->regmap, true); clk_disable_unprepare(i2s->mclk); + pinctrl_pm_select_idle_state(dev); + + return 0; +} + +static int rockchip_i2s_pinctrl_select_clk_state(struct device *dev) +{ + struct rk_i2s_dev *i2s = dev_get_drvdata(dev); + + if (IS_ERR_OR_NULL(i2s->pinctrl) || !i2s->clk_state) + return 0; + + pinctrl_select_state(i2s->pinctrl, i2s->clk_state); + return 0; } @@ -137,6 +152,13 @@ static int i2s_runtime_resume(struct device *dev) struct rk_i2s_dev *i2s = dev_get_drvdata(dev); int ret; + /* + * pinctrl default state is invoked by ASoC framework, so, + * we just handle clk state here if DT assigned. + */ + if (i2s->is_master_mode) + rockchip_i2s_pinctrl_select_clk_state(dev); + ret = clk_prepare_enable(i2s->mclk); if (ret) { dev_err(i2s->dev, "clock enable failed %d\n", ret); @@ -150,6 +172,13 @@ static int i2s_runtime_resume(struct device *dev) if (ret) clk_disable_unprepare(i2s->mclk); + /* + * should be placed after regcache sync done to back + * to the slave mode and then enable clk state. + */ + if (!i2s->is_master_mode) + rockchip_i2s_pinctrl_select_clk_state(dev); + return ret; } @@ -1202,6 +1231,12 @@ static int rockchip_i2s_probe(struct platform_device *pdev) return -EINVAL; } } + + i2s->clk_state = pinctrl_lookup_state(i2s->pinctrl, "clk"); + if (IS_ERR(i2s->clk_state)) { + i2s->clk_state = NULL; + dev_dbg(i2s->dev, "Have no clk pinctrl state\n"); + } } else { dev_dbg(&pdev->dev, "failed to find i2s pinctrl\n"); }