aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2021-02-15 16:52:07 +0000
committerSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2021-03-11 09:22:26 +0000
commit8a481032bfc4ddb410084d6ed37c964b7d427255 (patch)
tree9c27857fe48bf91eec4d2c5e27b934a3e8695e80
parent6ca04b7167df182762f89cad9c02b8ddb49ca6a3 (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.c112
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,