[PATCH V2] ASoC: fsl_audmix: rework runtime PM handling in probe

From: shengjiu . wang

Date: Wed Jun 17 2026 - 22:33:27 EST


From: Shengjiu Wang <shengjiu.wang@xxxxxxx>

After pm_runtime_enable() the AUDMIX block is powered off and stays
suspended until the first runtime resume. Register writes issued between
probe() and the first resume (e.g. from DAPM or ALSA control paths)
target unpowered hardware and cause a system hang.

Fix this by calling pm_runtime_resume_and_get() immediately after
pm_runtime_enable() to power the hardware up and enable its clocks.
Release the reference afterwards with pm_runtime_put() to allow the
runtime PM framework to suspend the device and switch the regmap to
cache-only mode when idle.

When CONFIG_PM is disabled or runtime PM is not enabled, pm_runtime_*
calls are stubs that do not power up the hardware. Handle this case
explicitly by calling fsl_audmix_runtime_resume() directly so the
hardware is always initialised and its clocks are enabled, ensuring
register accesses succeed regardless of PM configuration.

Fixes: be1df61cf06ef ("ASoC: fsl: Add Audio Mixer CPU DAI driver")
Signed-off-by: Shengjiu Wang <shengjiu.wang@xxxxxxx>
---
Changes in v2:
- remove the call of regcache_cache_only in probe, rework the runtime
handling in probe, call the pm_runtime_put() to enable the cache only.
- refine the commit message

sound/soc/fsl/fsl_audmix.c | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c
index f819f33ec46b..2885cc10b02d 100644
--- a/sound/soc/fsl/fsl_audmix.c
+++ b/sound/soc/fsl/fsl_audmix.c
@@ -457,6 +457,9 @@ static const struct of_device_id fsl_audmix_ids[] = {
};
MODULE_DEVICE_TABLE(of, fsl_audmix_ids);

+static int fsl_audmix_runtime_resume(struct device *dev);
+static int fsl_audmix_runtime_suspend(struct device *dev);
+
static int fsl_audmix_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -488,13 +491,25 @@ static int fsl_audmix_probe(struct platform_device *pdev)
spin_lock_init(&priv->lock);
platform_set_drvdata(pdev, priv);
pm_runtime_enable(dev);
+ if (!pm_runtime_enabled(dev)) {
+ ret = fsl_audmix_runtime_resume(dev);
+ if (ret)
+ goto err_disable_pm;
+ }
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ goto err_pm_get_sync;
+
+ /* To enable regmap cache only when runtime PM enabled */
+ pm_runtime_put(dev);

ret = devm_snd_soc_register_component(dev, &fsl_audmix_component,
fsl_audmix_dai,
ARRAY_SIZE(fsl_audmix_dai));
if (ret) {
dev_err(dev, "failed to register ASoC DAI\n");
- goto err_disable_pm;
+ goto err_pm_get_sync;
}

/*
@@ -506,12 +521,15 @@ static int fsl_audmix_probe(struct platform_device *pdev)
if (IS_ERR(priv->pdev)) {
ret = PTR_ERR(priv->pdev);
dev_err(dev, "failed to register platform: %d\n", ret);
- goto err_disable_pm;
+ goto err_pm_get_sync;
}
}

return 0;

+err_pm_get_sync:
+ if (!pm_runtime_status_suspended(dev))
+ fsl_audmix_runtime_suspend(dev);
err_disable_pm:
pm_runtime_disable(dev);
return ret;
@@ -522,6 +540,8 @@ static void fsl_audmix_remove(struct platform_device *pdev)
struct fsl_audmix *priv = dev_get_drvdata(&pdev->dev);

pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ fsl_audmix_runtime_suspend(&pdev->dev);

if (priv->pdev)
platform_device_unregister(priv->pdev);
--
2.34.1