[PATCH v1 1/3] ASoC: codecs: lpass-wsa-macro: Switch to PM clock framework for runtime PM
From: Ajay Kumar Nandam
Date: Mon Apr 13 2026 - 08:19:02 EST
Convert the LPASS WSA macro codec driver to use the PM clock framework
for runtime power management.
The driver now relies on pm_clk helpers and runtime PM instead of
manually enabling and disabling macro, dcodec, mclk, npl, and fsgen
clocks. Runtime suspend and resume handling is delegated to the PM
core via pm_clk_suspend() and pm_clk_resume(), while existing runtime
PM callbacks continue to manage regcache state.
This ensures clocks are enabled only when the WSA macro is active,
improves power efficiency on LPASS platforms supporting LPI/island
modes, and aligns the driver with common ASoC runtime PM patterns used
across Qualcomm LPASS codec drivers.
Signed-off-by: Ajay Kumar Nandam <ajay.nandam@xxxxxxxxxxxxxxxx>
---
sound/soc/codecs/lpass-wsa-macro.c | 118 +++++++++--------------------
1 file changed, 37 insertions(+), 81 deletions(-)
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index 5ad0448af..6aa6c4d95 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -14,6 +14,7 @@
#include <sound/soc-dapm.h>
#include <linux/pm_runtime.h>
#include <linux/of_platform.h>
+#include <linux/pm_clock.h>
#include <sound/tlv.h>
#include "lpass-macro-common.h"
@@ -2529,15 +2530,15 @@ static const struct snd_soc_dapm_route wsa_audio_map[] = {
static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable)
{
struct regmap *regmap = wsa->regmap;
+ int ret;
- if (enable) {
- int ret;
+ ret = pm_runtime_get_sync(wsa->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(wsa->dev);
+ return ret;
+ }
- ret = clk_prepare_enable(wsa->mclk);
- if (ret) {
- dev_err(wsa->dev, "failed to enable mclk\n");
- return ret;
- }
+ if (enable) {
wsa_macro_mclk_enable(wsa, true);
regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
@@ -2548,9 +2549,10 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable)
regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
CDC_WSA_SWR_CLK_EN_MASK, 0);
wsa_macro_mclk_enable(wsa, false);
- clk_disable_unprepare(wsa->mclk);
}
+ pm_runtime_mark_last_busy(wsa->dev);
+ pm_runtime_put_autosuspend(wsa->dev);
return 0;
}
@@ -2774,25 +2776,23 @@ static int wsa_macro_probe(struct platform_device *pdev)
clk_set_rate(wsa->mclk, WSA_MACRO_MCLK_FREQ);
clk_set_rate(wsa->npl, WSA_MACRO_MCLK_FREQ);
- ret = clk_prepare_enable(wsa->macro);
+ ret = devm_pm_clk_create(dev);
if (ret)
- goto err;
+ return ret;
- ret = clk_prepare_enable(wsa->dcodec);
- if (ret)
- goto err_dcodec;
+ ret = of_pm_clk_add_clks(dev);
+ if (ret < 0)
+ return ret;
- ret = clk_prepare_enable(wsa->mclk);
- if (ret)
- goto err_mclk;
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_enable(dev);
- ret = clk_prepare_enable(wsa->npl);
- if (ret)
- goto err_npl;
- ret = clk_prepare_enable(wsa->fsgen);
- if (ret)
- goto err_fsgen;
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0) {
+ goto err_rpm_disable;
+ }
/* reset swr ip */
regmap_update_bits(wsa->regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
@@ -2809,44 +2809,26 @@ static int wsa_macro_probe(struct platform_device *pdev)
wsa_macro_dai,
ARRAY_SIZE(wsa_macro_dai));
if (ret)
- goto err_clkout;
-
- pm_runtime_set_autosuspend_delay(dev, 3000);
- pm_runtime_use_autosuspend(dev);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
+ goto err_rpm_put;
ret = wsa_macro_register_mclk_output(wsa);
if (ret)
- goto err_clkout;
+ goto err_rpm_put;
- return 0;
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
-err_clkout:
- clk_disable_unprepare(wsa->fsgen);
-err_fsgen:
- clk_disable_unprepare(wsa->npl);
-err_npl:
- clk_disable_unprepare(wsa->mclk);
-err_mclk:
- clk_disable_unprepare(wsa->dcodec);
-err_dcodec:
- clk_disable_unprepare(wsa->macro);
-err:
+ return 0;
+err_rpm_put:
+ pm_runtime_put_noidle(dev);
+err_rpm_disable:
+ pm_runtime_disable(dev);
return ret;
-
}
static void wsa_macro_remove(struct platform_device *pdev)
{
- struct wsa_macro *wsa = dev_get_drvdata(&pdev->dev);
-
- clk_disable_unprepare(wsa->macro);
- clk_disable_unprepare(wsa->dcodec);
- clk_disable_unprepare(wsa->mclk);
- clk_disable_unprepare(wsa->npl);
- clk_disable_unprepare(wsa->fsgen);
+ pm_runtime_disable(&pdev->dev);
}
static int wsa_macro_runtime_suspend(struct device *dev)
@@ -2856,11 +2838,7 @@ static int wsa_macro_runtime_suspend(struct device *dev)
regcache_cache_only(wsa->regmap, true);
regcache_mark_dirty(wsa->regmap);
- clk_disable_unprepare(wsa->fsgen);
- clk_disable_unprepare(wsa->npl);
- clk_disable_unprepare(wsa->mclk);
-
- return 0;
+ return pm_clk_suspend(dev);
}
static int wsa_macro_runtime_resume(struct device *dev)
@@ -2868,34 +2846,12 @@ static int wsa_macro_runtime_resume(struct device *dev)
struct wsa_macro *wsa = dev_get_drvdata(dev);
int ret;
- ret = clk_prepare_enable(wsa->mclk);
- if (ret) {
- dev_err(dev, "unable to prepare mclk\n");
- return ret;
- }
-
- ret = clk_prepare_enable(wsa->npl);
- if (ret) {
- dev_err(dev, "unable to prepare mclkx2\n");
- goto err_npl;
- }
-
- ret = clk_prepare_enable(wsa->fsgen);
- if (ret) {
- dev_err(dev, "unable to prepare fsgen\n");
- goto err_fsgen;
- }
-
regcache_cache_only(wsa->regmap, false);
- regcache_sync(wsa->regmap);
-
- return 0;
-err_fsgen:
- clk_disable_unprepare(wsa->npl);
-err_npl:
- clk_disable_unprepare(wsa->mclk);
+ ret = pm_clk_resume(dev);
+ if (ret)
+ return ret;
- return ret;
+ return regcache_sync(wsa->regmap);
}
static const struct dev_pm_ops wsa_macro_pm_ops = {
--
2.34.1