diff options
author | Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | 2021-02-15 16:52:07 +0000 |
---|---|---|
committer | Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | 2021-03-11 09:22:26 +0000 |
commit | 8a481032bfc4ddb410084d6ed37c964b7d427255 (patch) | |
tree | 9c27857fe48bf91eec4d2c5e27b934a3e8695e80 | |
parent | 6ca04b7167df182762f89cad9c02b8ddb49ca6a3 (diff) |
ASoC: codecs: lpass-rx-macro: add runtime pm support
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
-rw-r--r-- | sound/soc/codecs/lpass-rx-macro.c | 112 |
1 files changed, 90 insertions, 22 deletions
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index c9c21d22c2c45..8a89a5f898236 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -5,6 +5,7 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/clk.h> #include <sound/soc.h> #include <sound/pcm.h> @@ -363,7 +364,7 @@ #define CDC_RX_DSD1_CFG2 (0x0F8C) #define RX_MAX_OFFSET (0x0F8C) -#define MCLK_FREQ 9600000 +#define MCLK_FREQ 2*9600000 #define RX_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ @@ -608,7 +609,11 @@ struct rx_macro { int softclip_clk_users; struct regmap *regmap; - struct clk_bulk_data clks[RX_NUM_CLKS_MAX]; + struct clk *mclk; + struct clk *npl; + struct clk *macro; + struct clk *dcodec; + struct clk *fsgen; struct clk_hw hw; }; #define to_rx_macro(_hw) container_of(_hw, struct rx_macro, hw) @@ -3424,6 +3429,9 @@ static int swclk_gate_enable(struct clk_hw *hw) { struct rx_macro *rx = to_rx_macro(hw); + pm_runtime_get_sync(rx->dev); + clk_set_rate(rx->npl, MCLK_FREQ); + clk_prepare_enable(rx->npl); rx_macro_mclk_enable(rx, true); if (rx->reset_swr) regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, @@ -3437,6 +3445,8 @@ static int swclk_gate_enable(struct clk_hw *hw) regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL, CDC_RX_SWR_RESET_MASK, 0); rx->reset_swr = false; + pm_runtime_mark_last_busy(rx->dev); + pm_runtime_put_autosuspend(rx->dev); return 0; } @@ -3449,6 +3459,7 @@ static void swclk_gate_disable(struct clk_hw *hw) CDC_RX_SWR_CLK_EN_MASK, 0); rx_macro_mclk_enable(rx, false); + clk_disable_unprepare(rx->npl); } static int swclk_gate_is_enabled(struct clk_hw *hw) @@ -3486,7 +3497,7 @@ static struct clk *rx_macro_register_mclk_output(struct rx_macro *rx) struct clk_init_data init; int ret; - parent_clk_name = __clk_get_name(rx->clks[2].clk); + parent_clk_name = __clk_get_name(rx->mclk); init.name = clk_name; init.ops = &swclk_gate_ops; @@ -3526,17 +3537,21 @@ static int rx_macro_probe(struct platform_device *pdev) if (!rx) return -ENOMEM; - rx->clks[0].id = "macro"; - rx->clks[1].id = "dcodec"; - rx->clks[2].id = "mclk"; - rx->clks[3].id = "npl"; - rx->clks[4].id = "fsgen"; - - ret = devm_clk_bulk_get(dev, RX_NUM_CLKS_MAX, rx->clks); - if (ret) { - dev_err(dev, "Error getting RX Clocks (%d)\n", ret); - return ret; - } + rx->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(rx->mclk)) + return PTR_ERR(rx->mclk); + rx->npl = devm_clk_get(dev, "npl"); + if (IS_ERR(rx->npl)) + return PTR_ERR(rx->npl); + rx->macro = devm_clk_get(dev, "macro"); + if (IS_ERR(rx->macro)) + return PTR_ERR(rx->macro); + rx->dcodec = devm_clk_get(dev, "dcodec"); + if (IS_ERR(rx->dcodec)) + return PTR_ERR(rx->dcodec); + rx->fsgen = devm_clk_get(dev, "fsgen"); + if (IS_ERR(rx->fsgen)) + return PTR_ERR(rx->fsgen); base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) @@ -3550,20 +3565,35 @@ static int rx_macro_probe(struct platform_device *pdev) rx->dev = dev; /* set MCLK and NPL rates */ - clk_set_rate(rx->clks[2].clk, MCLK_FREQ); - clk_set_rate(rx->clks[3].clk, MCLK_FREQ); + clk_set_rate(rx->mclk, MCLK_FREQ); + clk_set_rate(rx->npl, MCLK_FREQ); - ret = clk_bulk_prepare_enable(RX_NUM_CLKS_MAX, rx->clks); - if (ret) - return ret; + clk_prepare_enable(rx->macro); + clk_prepare_enable(rx->dcodec); + clk_prepare_enable(rx->mclk); + clk_prepare_enable(rx->npl); + clk_prepare_enable(rx->fsgen); rx_macro_register_mclk_output(rx); ret = devm_snd_soc_register_component(dev, &rx_macro_component_drv, rx_macro_dai, ARRAY_SIZE(rx_macro_dai)); - if (ret) - clk_bulk_disable_unprepare(RX_NUM_CLKS_MAX, rx->clks); + if (ret) { + clk_disable_unprepare(rx->mclk); + clk_disable_unprepare(rx->npl); + clk_disable_unprepare(rx->macro); + clk_disable_unprepare(rx->dcodec); + clk_disable_unprepare(rx->fsgen); + + } + + pm_runtime_set_autosuspend_delay(dev, 30000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); return ret; } @@ -3573,7 +3603,13 @@ static int rx_macro_remove(struct platform_device *pdev) struct rx_macro *rx = dev_get_drvdata(&pdev->dev); of_clk_del_provider(pdev->dev.of_node); - clk_bulk_disable_unprepare(RX_NUM_CLKS_MAX, rx->clks); + + clk_disable_unprepare(rx->mclk); + clk_disable_unprepare(rx->npl); + clk_disable_unprepare(rx->macro); + clk_disable_unprepare(rx->dcodec); + clk_disable_unprepare(rx->fsgen); + return 0; } @@ -3582,12 +3618,44 @@ static const struct of_device_id rx_macro_dt_match[] = { { } }; +static int __maybe_unused rx_macro_runtime_suspend(struct device *dev) +{ + struct rx_macro *rx = dev_get_drvdata(dev); + regcache_cache_only(rx->regmap, true); + regcache_mark_dirty(rx->regmap); + + clk_disable_unprepare(rx->mclk); + clk_disable_unprepare(rx->npl); + clk_disable_unprepare(rx->fsgen); + + return 0; +} + +static int __maybe_unused rx_macro_runtime_resume(struct device *dev) +{ + struct rx_macro *rx = dev_get_drvdata(dev); + + clk_set_rate(rx->npl, MCLK_FREQ); + clk_set_rate(rx->mclk, MCLK_FREQ); + clk_prepare_enable(rx->mclk); + clk_prepare_enable(rx->npl); + clk_prepare_enable(rx->fsgen); + regcache_cache_only(rx->regmap, false); + regcache_sync(rx->regmap); + return 0; +} + + +static const struct dev_pm_ops rx_macro_pm_ops = { + SET_RUNTIME_PM_OPS(rx_macro_runtime_suspend, rx_macro_runtime_resume, NULL) +}; static struct platform_driver rx_macro_driver = { .driver = { .name = "rx_macro", .owner = THIS_MODULE, .of_match_table = rx_macro_dt_match, .suppress_bind_attrs = true, + .pm = &rx_macro_pm_ops, }, .probe = rx_macro_probe, .remove = rx_macro_remove, |