[PATCH 2/2] ASoC: codecs: lpass-rx-macro: switch to PM clock framework for runtime PM

From: Ajay Kumar Nandam

Date: Fri Jul 03 2026 - 07:16:28 EST


Convert the LPASS RX macro codec driver to runtime PM clock management
using the PM clock framework.

Replace manual macro/dcodec/mclk/npl/fsgen clock toggling with PM clock
helpers and runtime PM callbacks. Keep the SWR gate runtime PM reference
from SWR clock enable until disable so autosuspend does not gate clocks
while SWR is still prepared.

Set autosuspend delay to 100 ms so PM-clock-managed votes are dropped soon
after idle while still avoiding suspend/resume churn on short gaps.

Add a PM_CLK dependency to SND_SOC_LPASS_RX_MACRO since this patch
introduces PM clock APIs.

Tighten error unwind by checking pm_runtime_put_sync_suspend() in probe
and by restoring regcache state if pm_clk_resume()/regcache_sync() fails.

Drop the now-empty rx_macro_remove() callback since all clock cleanup
is handled by PM clock framework and devm.

Co-developed-by: Ravi Hothi <ravi.hothi@xxxxxxxxxxxxxxxx>
Signed-off-by: Ravi Hothi <ravi.hothi@xxxxxxxxxxxxxxxx>
Signed-off-by: Ajay Kumar Nandam <ajay.nandam@xxxxxxxxxxxxxxxx>
---
sound/soc/codecs/lpass-rx-macro.c | 114 ++++++++++++++------------------------
1 file changed, 42 insertions(+), 72 deletions(-)

diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
index 6233aa9f5bc6..9122b07626ec 100644
--- a/sound/soc/codecs/lpass-rx-macro.c
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -6,6 +6,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <sound/soc.h>
@@ -3671,11 +3672,9 @@ static int swclk_gate_enable(struct clk_hw *hw)
struct rx_macro *rx = to_rx_macro(hw);
int ret;

- ret = clk_prepare_enable(rx->mclk);
- if (ret) {
- dev_err(rx->dev, "unable to prepare mclk\n");
+ ret = pm_runtime_resume_and_get(rx->dev);
+ if (ret < 0)
return ret;
- }

rx_macro_mclk_enable(rx, true);

@@ -3693,7 +3692,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->mclk);
+ pm_runtime_put_autosuspend(rx->dev);
}

static int swclk_gate_is_enabled(struct clk_hw *hw)
@@ -3865,27 +3864,26 @@ static int rx_macro_probe(struct platform_device *pdev)

/* set MCLK and NPL rates */
clk_set_rate(rx->mclk, MCLK_FREQ);
- clk_set_rate(rx->npl, MCLK_FREQ);
+ if (rx->npl)
+ clk_set_rate(rx->npl, MCLK_FREQ);

- ret = clk_prepare_enable(rx->macro);
+ ret = devm_pm_clk_create(dev);
if (ret)
return ret;

- ret = clk_prepare_enable(rx->dcodec);
- if (ret)
- goto err_dcodec;
-
- ret = clk_prepare_enable(rx->mclk);
- if (ret)
- goto err_mclk;
+ ret = of_pm_clk_add_clks(dev);
+ if (ret < 0)
+ return ret;

- ret = clk_prepare_enable(rx->npl);
+ pm_runtime_set_autosuspend_delay(dev, 100);
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_pm_runtime_enable(dev);
if (ret)
- goto err_npl;
+ return ret;

- ret = clk_prepare_enable(rx->fsgen);
+ ret = pm_runtime_resume_and_get(dev);
if (ret)
- goto err_fsgen;
+ return ret;

/* reset swr block */
regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
@@ -3902,46 +3900,25 @@ static int rx_macro_probe(struct platform_device *pdev)
rx_macro_dai,
ARRAY_SIZE(rx_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 = rx_macro_register_mclk_output(rx);
if (ret)
- goto err_clkout;
+ goto err_rpm_put;
+
+ ret = pm_runtime_put_autosuspend(dev);
+ if (ret < 0)
+ dev_warn(dev, "runtime PM put failed after probe: %d\n", ret);

return 0;

-err_clkout:
- clk_disable_unprepare(rx->fsgen);
-err_fsgen:
- clk_disable_unprepare(rx->npl);
-err_npl:
- clk_disable_unprepare(rx->mclk);
-err_mclk:
- clk_disable_unprepare(rx->dcodec);
-err_dcodec:
- clk_disable_unprepare(rx->macro);
+err_rpm_put:
+ if (pm_runtime_put_sync_suspend(dev) < 0)
+ dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n");

return ret;
}

-static void rx_macro_remove(struct platform_device *pdev)
-{
- struct rx_macro *rx = dev_get_drvdata(&pdev->dev);
-
- clk_disable_unprepare(rx->mclk);
- clk_disable_unprepare(rx->npl);
- clk_disable_unprepare(rx->fsgen);
- clk_disable_unprepare(rx->macro);
- clk_disable_unprepare(rx->dcodec);
-}
-
static const struct of_device_id rx_macro_dt_match[] = {
{
.compatible = "qcom,sc7280-lpass-rx-macro",
@@ -3969,13 +3946,17 @@ MODULE_DEVICE_TABLE(of, rx_macro_dt_match);
static int rx_macro_runtime_suspend(struct device *dev)
{
struct rx_macro *rx = dev_get_drvdata(dev);
+ int ret;

regcache_cache_only(rx->regmap, true);
- regcache_mark_dirty(rx->regmap);

- clk_disable_unprepare(rx->fsgen);
- clk_disable_unprepare(rx->npl);
- clk_disable_unprepare(rx->mclk);
+ ret = pm_clk_suspend(dev);
+ if (ret) {
+ regcache_cache_only(rx->regmap, false);
+ return ret;
+ }
+
+ regcache_mark_dirty(rx->regmap);

return 0;
}
@@ -3985,33 +3966,23 @@ static int rx_macro_runtime_resume(struct device *dev)
struct rx_macro *rx = dev_get_drvdata(dev);
int ret;

- ret = clk_prepare_enable(rx->mclk);
+ ret = pm_clk_resume(dev);
if (ret) {
- dev_err(dev, "unable to prepare mclk\n");
+ regcache_cache_only(rx->regmap, true);
+ regcache_mark_dirty(rx->regmap);
return ret;
}

- ret = clk_prepare_enable(rx->npl);
- if (ret) {
- dev_err(dev, "unable to prepare mclkx2\n");
- goto err_npl;
- }
-
- ret = clk_prepare_enable(rx->fsgen);
+ regcache_cache_only(rx->regmap, false);
+ ret = regcache_sync(rx->regmap);
if (ret) {
- dev_err(dev, "unable to prepare fsgen\n");
- goto err_fsgen;
+ regcache_cache_only(rx->regmap, true);
+ regcache_mark_dirty(rx->regmap);
+ pm_clk_suspend(dev);
+ return ret;
}
- regcache_cache_only(rx->regmap, false);
- regcache_sync(rx->regmap);

return 0;
-err_fsgen:
- clk_disable_unprepare(rx->npl);
-err_npl:
- clk_disable_unprepare(rx->mclk);
-
- return ret;
}

static const struct dev_pm_ops rx_macro_pm_ops = {
@@ -4026,7 +3997,6 @@ static struct platform_driver rx_macro_driver = {
.pm = pm_ptr(&rx_macro_pm_ops),
},
.probe = rx_macro_probe,
- .remove = rx_macro_remove,
};

module_platform_driver(rx_macro_driver);

--
2.34.1