From: Herman van Hazendonk <github.com@herrie.org>
To: sboyd@kernel.org
Cc: Herman van Hazendonk <github.com@herrie.org>,
Bjorn Andersson <andersson@kernel.org>,
Michael Turquette <mturquette@baylibre.com>,
linux-arm-msm@vger.kernel.org, linux-clk@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH 3/3] clk: qcom: lcc-msm8960: re-apply PLL4 mux on resume
Date: Tue, 2 Jun 2026 06:50:01 +0200 [thread overview]
Message-ID: <20260602045002.290918-4-github.com@herrie.org> (raw)
In-Reply-To: <20260602045002.290918-1-github.com@herrie.org>
The LPASS power domain on the MSM8x60 family is collapsed during
system sleep, which resets the LPASS Primary PLL Mux register at 0xc4
to its hardware default of 0 (PXO). The probe path arms this register
to 0x1 (PLL4) and the rest of the LCC clock tree assumes that
selection; after the first suspend/resume cycle every LCC clock
silently returns sourced from PXO at 27 MHz, with no diagnostic, and
audio produces wrong rates until the next reboot.
Add a resume PM op that re-asserts PLL4 on the mux. The single
register write is idempotent on platforms that do not exhibit the
power-collapse (the mux is already at 0x1 from probe), so it is safe
to run unconditionally for all compatibles. Stash the regmap in
drvdata during probe so resume can write without walking the
clock-provider tree.
dev_err / raw errno are used here (not dev_err_probe) because resume
cannot defer.
Use pm_ptr(), not pm_sleep_ptr(), to assign the dev_pm_ops pointer.
pm_ptr() is the correct macro for conditionally compiling the .pm
struct pointer based on CONFIG_PM; pm_sleep_ptr() is intended for
gating individual function pointers inside the struct on
CONFIG_PM_SLEEP.
Signed-off-by: Herman van Hazendonk <github.com@herrie.org>
---
drivers/clk/qcom/lcc-msm8960.c | 39 ++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c
index 1e0873ce1cc2..7bfb396b09e2 100644
--- a/drivers/clk/qcom/lcc-msm8960.c
+++ b/drivers/clk/qcom/lcc-msm8960.c
@@ -10,6 +10,7 @@
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/pm.h>
#include <linux/clk-provider.h>
#include <linux/regmap.h>
@@ -525,6 +526,13 @@ static int lcc_msm8960_probe(struct platform_device *pdev)
if (ret)
goto err_unclaim;
+ /*
+ * Stash the regmap so lcc_msm8960_resume() can re-apply the
+ * LPASS Primary PLL mux selection without having to walk the
+ * clock-provider tree. qcom_cc_really_probe() does not touch
+ * platform drvdata, so this is safe.
+ */
+ platform_set_drvdata(pdev, regmap);
return 0;
err_unclaim:
@@ -552,12 +560,43 @@ static void lcc_msm8960_remove(struct platform_device *pdev)
mutex_unlock(&lcc_msm8960_bound_lock);
}
+/*
+ * The LPASS power domain on at least the MSM8x60 family is collapsed
+ * during system sleep, which resets the LPASS Primary PLL Mux at 0xc4
+ * to its hardware default of 0 (PXO). Without re-asserting PLL4 here
+ * every LCC clock would silently come back sourced from PXO at 27 MHz
+ * and audio would produce wrong rates until the next reboot. The
+ * single-register write is idempotent on platforms that do not exhibit
+ * the collapse (the mux is already at 0x1 from probe), so it is safe
+ * to run unconditionally.
+ *
+ * Resume cannot defer; log with dev_err and propagate the raw errno
+ * rather than dev_err_probe (which silences EPROBE_DEFER).
+ */
+static int lcc_msm8960_resume(struct device *dev)
+{
+ struct regmap *regmap = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regmap_write(regmap, 0xc4, 0x1);
+ if (ret)
+ dev_err(dev,
+ "failed to re-select PLL4 on LPASS Primary PLL Mux on resume: %d\n",
+ ret);
+ return ret;
+}
+
+static const struct dev_pm_ops lcc_msm8960_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(NULL, lcc_msm8960_resume)
+};
+
static struct platform_driver lcc_msm8960_driver = {
.probe = lcc_msm8960_probe,
.remove = lcc_msm8960_remove,
.driver = {
.name = "lcc-msm8960",
.of_match_table = lcc_msm8960_match_table,
+ .pm = pm_ptr(&lcc_msm8960_pm_ops),
/*
* The probe path mutates file-static clk_rcg structures
* (.freq_tbl pointers selected from the PLL4 L-register,
--
2.43.0
prev parent reply other threads:[~2026-06-02 4:57 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20260602045002.290918-1-github.com@herrie.org>
2026-06-02 4:49 ` [PATCH 1/3] clk: qcom: lcc-msm8960: check regmap_read/regmap_write return values in probe Herman van Hazendonk
2026-06-02 4:50 ` [PATCH 2/3] clk: qcom: lcc-msm8960: serialise probe and block sysfs rebind Herman van Hazendonk
2026-06-02 4:50 ` Herman van Hazendonk [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260602045002.290918-4-github.com@herrie.org \
--to=github.com@herrie.org \
--cc=andersson@kernel.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-clk@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mturquette@baylibre.com \
--cc=sboyd@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox