* [PATCH v6 RESEND 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework
@ 2026-05-22 20:46 Ajay Kumar Nandam
2026-05-22 20:46 ` [PATCH v6 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs Ajay Kumar Nandam
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: Ajay Kumar Nandam @ 2026-05-22 20:46 UTC (permalink / raw)
To: Bjorn Andersson, Linus Walleij
Cc: linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik,
ajay.nandam
This series converts LPASS LPI pinctrl runtime clock handling to the PM
clock framework and ensures GPIO register accesses runtime-resume the
block before MMIO.
The series is intentionally ordered for bisect safety:
- patch 1 wires runtime PM ops in LPASS LPI variant drivers
- patch 2 updates the shared core to use pm_clk + runtime PM guarded
register access paths and adds the PM_CLK Kconfig dependency
After this conversion, LPASS LPI variants sharing the common core use a
consistent DT clock flow via of_pm_clk_add_clks() together with
pm_clk_suspend()/pm_clk_resume() and autosuspend.
Testing:
- Runtime behavior validated on Kodiak (sc7280).
- Wider runtime testing on other LPASS LPI variants is welcome.
Link: https://lore.kernel.org/r/20260513140009.3841770-1-ajay.nandam@oss.qualcomm.com
Resend only: previous post was mistakenly sent as an inline reply; no
code changes.
Changes since v5:
- Rebased to current linux-next and refreshed the shared-core conversion
patch to apply cleanly on top of latest LPASS LPI mux-path updates
- Include SM6350 in the preparatory LPASS LPI per-SoC runtime PM hook
wiring set so all in-tree LPASS LPI variants are covered
- Keep PM_CLK dependency under PINCTRL_LPASS_LPI where shared core PM
clock APIs are introduced
Ajay Kumar Nandam (2):
pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs
pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM
drivers/pinctrl/qcom/Kconfig | 1 +
drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 144 ++++++++++++------
.../pinctrl/qcom/pinctrl-milos-lpass-lpi.c | 7 +
.../pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c | 19 ++-
.../pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c | 15 +-
.../pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c | 7 +
.../pinctrl/qcom/pinctrl-sdm670-lpass-lpi.c | 7 +
.../pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c | 7 +
.../pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c | 7 +
.../pinctrl/qcom/pinctrl-sm6350-lpass-lpi.c | 7 +
.../pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 15 +-
.../pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c | 15 +-
.../pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c | 15 +-
.../pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c | 15 +-
14 files changed, 209 insertions(+), 72 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH v6 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs 2026-05-22 20:46 [PATCH v6 RESEND 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Ajay Kumar Nandam @ 2026-05-22 20:46 ` Ajay Kumar Nandam 2026-06-15 23:50 ` Dmitry Baryshkov 2026-05-22 20:46 ` [PATCH v6 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM Ajay Kumar Nandam ` (2 subsequent siblings) 3 siblings, 1 reply; 13+ messages in thread From: Ajay Kumar Nandam @ 2026-05-22 20:46 UTC (permalink / raw) To: Bjorn Andersson, Linus Walleij Cc: linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik, ajay.nandam, Konrad Dybcio The LPASS LPI core conversion to PM clock framework relies on variant drivers wiring runtime PM callbacks. Hook up runtime PM callbacks for the LPASS LPI variant drivers touched in this patch so they are prepared for the shared core conversion. This commit is a preparatory NOP on its own, as runtime PM is still disabled on these devices until the following core conversion patch. This is a mechanical per-variant driver update that relies on the same generic PM clock flow (of_pm_clk_add_clks() + pm_clk_suspend/ pm_clk_resume()) and DT-provided clocks. Runtime behavior was validated on Kodiak (sc7280). Suggested-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com> --- .../pinctrl/qcom/pinctrl-milos-lpass-lpi.c | 7 +++++++ .../pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c | 19 +++++++++++++------ .../pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c | 15 +++++++++++---- .../pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c | 7 +++++++ .../pinctrl/qcom/pinctrl-sdm670-lpass-lpi.c | 7 +++++++ .../pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c | 7 +++++++ .../pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c | 7 +++++++ .../pinctrl/qcom/pinctrl-sm6350-lpass-lpi.c | 7 +++++++ .../pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 15 +++++++++++---- .../pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c | 15 +++++++++++---- .../pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c | 15 +++++++++++---- .../pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c | 15 +++++++++++---- 12 files changed, 110 insertions(+), 26 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-milos-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-milos-lpass-lpi.c index 3bf6fe0cf1bb..72b8ffd97860 100644 --- a/drivers/pinctrl/qcom/pinctrl-milos-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-milos-lpass-lpi.c @@ -7,6 +7,8 @@ #include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_clock.h> +#include <linux/pm_runtime.h> #include "pinctrl-lpass-lpi.h" @@ -203,10 +205,15 @@ static const struct of_device_id lpi_pinctrl_of_match[] = { }; MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match); +static const struct dev_pm_ops lpi_pinctrl_pm_ops = { + RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + static struct platform_driver lpi_pinctrl_driver = { .driver = { .name = "qcom-milos-lpass-lpi-pinctrl", .of_match_table = lpi_pinctrl_of_match, + .pm = pm_ptr(&lpi_pinctrl_pm_ops), }, .probe = lpi_pinctrl_probe, .remove = lpi_pinctrl_remove, diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c index 750f410311a8..a61df10d46cb 100644 --- a/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c @@ -7,6 +7,8 @@ #include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_clock.h> +#include <linux/pm_runtime.h> #include "pinctrl-lpass-lpi.h" @@ -129,20 +131,25 @@ static const struct lpi_pinctrl_variant_data sc7280_lpi_data = { static const struct of_device_id lpi_pinctrl_of_match[] = { { - .compatible = "qcom,sc7280-lpass-lpi-pinctrl", - .data = &sc7280_lpi_data, + .compatible = "qcom,sc7280-lpass-lpi-pinctrl", + .data = &sc7280_lpi_data, }, { - .compatible = "qcom,sm8350-lpass-lpi-pinctrl", - .data = &sc7280_lpi_data, + .compatible = "qcom,sm8350-lpass-lpi-pinctrl", + .data = &sc7280_lpi_data, }, { } }; MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match); +static const struct dev_pm_ops lpi_pinctrl_pm_ops = { + RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + static struct platform_driver lpi_pinctrl_driver = { .driver = { - .name = "qcom-sc7280-lpass-lpi-pinctrl", - .of_match_table = lpi_pinctrl_of_match, + .name = "qcom-sc7280-lpass-lpi-pinctrl", + .of_match_table = lpi_pinctrl_of_match, + .pm = pm_ptr(&lpi_pinctrl_pm_ops), }, .probe = lpi_pinctrl_probe, .remove = lpi_pinctrl_remove, diff --git a/drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c index 0e839b6aaaf4..27c47710365e 100644 --- a/drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c @@ -6,6 +6,8 @@ #include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_clock.h> +#include <linux/pm_runtime.h> #include "pinctrl-lpass-lpi.h" @@ -166,17 +168,22 @@ static const struct lpi_pinctrl_variant_data sc8280xp_lpi_data = { static const struct of_device_id lpi_pinctrl_of_match[] = { { - .compatible = "qcom,sc8280xp-lpass-lpi-pinctrl", - .data = &sc8280xp_lpi_data, + .compatible = "qcom,sc8280xp-lpass-lpi-pinctrl", + .data = &sc8280xp_lpi_data, }, { } }; MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match); +static const struct dev_pm_ops lpi_pinctrl_pm_ops = { + RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + static struct platform_driver lpi_pinctrl_driver = { .driver = { - .name = "qcom-sc8280xp-lpass-lpi-pinctrl", - .of_match_table = lpi_pinctrl_of_match, + .name = "qcom-sc8280xp-lpass-lpi-pinctrl", + .of_match_table = lpi_pinctrl_of_match, + .pm = pm_ptr(&lpi_pinctrl_pm_ops), }, .probe = lpi_pinctrl_probe, .remove = lpi_pinctrl_remove, diff --git a/drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c index 65411abfbfac..7b5aacaae7d7 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c @@ -10,6 +10,8 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/pm_clock.h> +#include <linux/pm_runtime.h> #include <linux/pinctrl/pinctrl.h> #include "pinctrl-lpass-lpi.h" @@ -145,10 +147,15 @@ static const struct of_device_id sdm660_lpi_pinctrl_of_match[] = { }; MODULE_DEVICE_TABLE(of, sdm660_lpi_pinctrl_of_match); +static const struct dev_pm_ops lpi_pinctrl_pm_ops = { + RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + static struct platform_driver sdm660_lpi_pinctrl_driver = { .driver = { .name = "qcom-sdm660-lpass-lpi-pinctrl", .of_match_table = sdm660_lpi_pinctrl_of_match, + .pm = pm_ptr(&lpi_pinctrl_pm_ops), }, .probe = lpi_pinctrl_probe, .remove = lpi_pinctrl_remove, diff --git a/drivers/pinctrl/qcom/pinctrl-sdm670-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sdm670-lpass-lpi.c index 858146c408d0..0a31f7ad2e0d 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm670-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm670-lpass-lpi.c @@ -7,6 +7,8 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/pm_clock.h> +#include <linux/pm_runtime.h> #include <linux/pinctrl/pinctrl.h> #include "pinctrl-lpass-lpi.h" @@ -151,10 +153,15 @@ static const struct of_device_id sdm670_lpi_pinctrl_of_match[] = { }; MODULE_DEVICE_TABLE(of, sdm670_lpi_pinctrl_of_match); +static const struct dev_pm_ops lpi_pinctrl_pm_ops = { + RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + static struct platform_driver sdm670_lpi_pinctrl_driver = { .driver = { .name = "qcom-sdm670-lpass-lpi-pinctrl", .of_match_table = sdm670_lpi_pinctrl_of_match, + .pm = pm_ptr(&lpi_pinctrl_pm_ops), }, .probe = lpi_pinctrl_probe, .remove = lpi_pinctrl_remove, diff --git a/drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c index c0e178be9cfc..75bafa62426a 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c @@ -7,6 +7,8 @@ #include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_clock.h> +#include <linux/pm_runtime.h> #include "pinctrl-lpass-lpi.h" @@ -221,10 +223,15 @@ static const struct of_device_id lpi_pinctrl_of_match[] = { }; MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match); +static const struct dev_pm_ops lpi_pinctrl_pm_ops = { + RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + static struct platform_driver lpi_pinctrl_driver = { .driver = { .name = "qcom-sm4250-lpass-lpi-pinctrl", .of_match_table = lpi_pinctrl_of_match, + .pm = pm_ptr(&lpi_pinctrl_pm_ops), }, .probe = lpi_pinctrl_probe, .remove = lpi_pinctrl_remove, diff --git a/drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c index b7d9186861a2..05435ea6e17a 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c @@ -7,6 +7,8 @@ #include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_clock.h> +#include <linux/pm_runtime.h> #include "pinctrl-lpass-lpi.h" @@ -141,10 +143,15 @@ static const struct of_device_id lpi_pinctrl_of_match[] = { }; MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match); +static const struct dev_pm_ops lpi_pinctrl_pm_ops = { + RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + static struct platform_driver lpi_pinctrl_driver = { .driver = { .name = "qcom-sm6115-lpass-lpi-pinctrl", .of_match_table = lpi_pinctrl_of_match, + .pm = pm_ptr(&lpi_pinctrl_pm_ops), }, .probe = lpi_pinctrl_probe, .remove = lpi_pinctrl_remove, diff --git a/drivers/pinctrl/qcom/pinctrl-sm6350-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm6350-lpass-lpi.c index 4d06abcfedfd..946b23084304 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm6350-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6350-lpass-lpi.c @@ -6,6 +6,8 @@ #include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_clock.h> +#include <linux/pm_runtime.h> #include "pinctrl-lpass-lpi.h" @@ -135,10 +137,15 @@ static const struct of_device_id lpi_pinctrl_of_match[] = { }; MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match); +static const struct dev_pm_ops lpi_pinctrl_pm_ops = { + RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + static struct platform_driver lpi_pinctrl_driver = { .driver = { .name = "qcom-sm6350-lpass-lpi-pinctrl", .of_match_table = lpi_pinctrl_of_match, + .pm = pm_ptr(&lpi_pinctrl_pm_ops), }, .probe = lpi_pinctrl_probe, .remove = lpi_pinctrl_remove, diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c index c27452eece3e..454de788be21 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c @@ -7,6 +7,8 @@ #include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_clock.h> +#include <linux/pm_runtime.h> #include "pinctrl-lpass-lpi.h" @@ -127,17 +129,22 @@ static const struct lpi_pinctrl_variant_data sm8250_lpi_data = { static const struct of_device_id lpi_pinctrl_of_match[] = { { - .compatible = "qcom,sm8250-lpass-lpi-pinctrl", - .data = &sm8250_lpi_data, + .compatible = "qcom,sm8250-lpass-lpi-pinctrl", + .data = &sm8250_lpi_data, }, { } }; MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match); +static const struct dev_pm_ops lpi_pinctrl_pm_ops = { + RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + static struct platform_driver lpi_pinctrl_driver = { .driver = { - .name = "qcom-sm8250-lpass-lpi-pinctrl", - .of_match_table = lpi_pinctrl_of_match, + .name = "qcom-sm8250-lpass-lpi-pinctrl", + .of_match_table = lpi_pinctrl_of_match, + .pm = pm_ptr(&lpi_pinctrl_pm_ops), }, .probe = lpi_pinctrl_probe, .remove = lpi_pinctrl_remove, diff --git a/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c index 439f6541622e..834eee8dcce9 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c @@ -6,6 +6,8 @@ #include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_clock.h> +#include <linux/pm_runtime.h> #include "pinctrl-lpass-lpi.h" @@ -195,17 +197,22 @@ static const struct lpi_pinctrl_variant_data sm8450_lpi_data = { static const struct of_device_id lpi_pinctrl_of_match[] = { { - .compatible = "qcom,sm8450-lpass-lpi-pinctrl", - .data = &sm8450_lpi_data, + .compatible = "qcom,sm8450-lpass-lpi-pinctrl", + .data = &sm8450_lpi_data, }, { } }; MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match); +static const struct dev_pm_ops lpi_pinctrl_pm_ops = { + RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + static struct platform_driver lpi_pinctrl_driver = { .driver = { - .name = "qcom-sm8450-lpass-lpi-pinctrl", - .of_match_table = lpi_pinctrl_of_match, + .name = "qcom-sm8450-lpass-lpi-pinctrl", + .of_match_table = lpi_pinctrl_of_match, + .pm = pm_ptr(&lpi_pinctrl_pm_ops), }, .probe = lpi_pinctrl_probe, .remove = lpi_pinctrl_remove, diff --git a/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c index 73065919c8c2..875e04e5d2b9 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c @@ -6,6 +6,8 @@ #include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_clock.h> +#include <linux/pm_runtime.h> #include "pinctrl-lpass-lpi.h" @@ -203,17 +205,22 @@ static const struct lpi_pinctrl_variant_data sm8550_lpi_data = { static const struct of_device_id lpi_pinctrl_of_match[] = { { - .compatible = "qcom,sm8550-lpass-lpi-pinctrl", - .data = &sm8550_lpi_data, + .compatible = "qcom,sm8550-lpass-lpi-pinctrl", + .data = &sm8550_lpi_data, }, { } }; MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match); +static const struct dev_pm_ops lpi_pinctrl_pm_ops = { + RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + static struct platform_driver lpi_pinctrl_driver = { .driver = { - .name = "qcom-sm8550-lpass-lpi-pinctrl", - .of_match_table = lpi_pinctrl_of_match, + .name = "qcom-sm8550-lpass-lpi-pinctrl", + .of_match_table = lpi_pinctrl_of_match, + .pm = pm_ptr(&lpi_pinctrl_pm_ops), }, .probe = lpi_pinctrl_probe, .remove = lpi_pinctrl_remove, diff --git a/drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c index f9fcedf5a65d..bc7889c993d0 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c @@ -6,6 +6,8 @@ #include <linux/gpio/driver.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_clock.h> +#include <linux/pm_runtime.h> #include "pinctrl-lpass-lpi.h" @@ -210,17 +212,22 @@ static const struct lpi_pinctrl_variant_data sm8650_lpi_data = { static const struct of_device_id lpi_pinctrl_of_match[] = { { - .compatible = "qcom,sm8650-lpass-lpi-pinctrl", - .data = &sm8650_lpi_data, + .compatible = "qcom,sm8650-lpass-lpi-pinctrl", + .data = &sm8650_lpi_data, }, { } }; MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match); +static const struct dev_pm_ops lpi_pinctrl_pm_ops = { + RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + static struct platform_driver lpi_pinctrl_driver = { .driver = { - .name = "qcom-sm8650-lpass-lpi-pinctrl", - .of_match_table = lpi_pinctrl_of_match, + .name = "qcom-sm8650-lpass-lpi-pinctrl", + .of_match_table = lpi_pinctrl_of_match, + .pm = pm_ptr(&lpi_pinctrl_pm_ops), }, .probe = lpi_pinctrl_probe, .remove = lpi_pinctrl_remove, -- 2.34.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v6 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs 2026-05-22 20:46 ` [PATCH v6 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs Ajay Kumar Nandam @ 2026-06-15 23:50 ` Dmitry Baryshkov 0 siblings, 0 replies; 13+ messages in thread From: Dmitry Baryshkov @ 2026-06-15 23:50 UTC (permalink / raw) To: Ajay Kumar Nandam Cc: Bjorn Andersson, Linus Walleij, linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik, Konrad Dybcio On Sat, May 23, 2026 at 02:16:43AM +0530, Ajay Kumar Nandam wrote: > The LPASS LPI core conversion to PM clock framework relies on variant > drivers wiring runtime PM callbacks. > > Hook up runtime PM callbacks for the LPASS LPI variant drivers touched > in this patch so they are prepared for the shared core conversion. > > This commit is a preparatory NOP on its own, as runtime PM is still > disabled on these devices until the following core conversion patch. > > This is a mechanical per-variant driver update that relies on the > same generic PM clock flow (of_pm_clk_add_clks() + pm_clk_suspend/ > pm_clk_resume()) and DT-provided clocks. > > Runtime behavior was validated on Kodiak (sc7280). > > Suggested-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> > Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com> > --- > .../pinctrl/qcom/pinctrl-milos-lpass-lpi.c | 7 +++++++ > .../pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c | 19 +++++++++++++------ > .../pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c | 15 +++++++++++---- > .../pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c | 7 +++++++ > .../pinctrl/qcom/pinctrl-sdm670-lpass-lpi.c | 7 +++++++ > .../pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c | 7 +++++++ > .../pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c | 7 +++++++ > .../pinctrl/qcom/pinctrl-sm6350-lpass-lpi.c | 7 +++++++ > .../pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 15 +++++++++++---- > .../pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c | 15 +++++++++++---- > .../pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c | 15 +++++++++++---- > .../pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c | 15 +++++++++++---- > 12 files changed, 110 insertions(+), 26 deletions(-) > > diff --git a/drivers/pinctrl/qcom/pinctrl-milos-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-milos-lpass-lpi.c > index 3bf6fe0cf1bb..72b8ffd97860 100644 > --- a/drivers/pinctrl/qcom/pinctrl-milos-lpass-lpi.c > +++ b/drivers/pinctrl/qcom/pinctrl-milos-lpass-lpi.c > @@ -7,6 +7,8 @@ > #include <linux/gpio/driver.h> > #include <linux/module.h> > #include <linux/platform_device.h> > +#include <linux/pm_clock.h> > +#include <linux/pm_runtime.h> > > #include "pinctrl-lpass-lpi.h" > > @@ -203,10 +205,15 @@ static const struct of_device_id lpi_pinctrl_of_match[] = { > }; > MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match); > > +static const struct dev_pm_ops lpi_pinctrl_pm_ops = { > + RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) > +}; > + > static struct platform_driver lpi_pinctrl_driver = { > .driver = { > .name = "qcom-milos-lpass-lpi-pinctrl", > .of_match_table = lpi_pinctrl_of_match, > + .pm = pm_ptr(&lpi_pinctrl_pm_ops), > }, > .probe = lpi_pinctrl_probe, > .remove = lpi_pinctrl_remove, > diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c > index 750f410311a8..a61df10d46cb 100644 > --- a/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c > +++ b/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c > @@ -7,6 +7,8 @@ > #include <linux/gpio/driver.h> > #include <linux/module.h> > #include <linux/platform_device.h> > +#include <linux/pm_clock.h> > +#include <linux/pm_runtime.h> > > #include "pinctrl-lpass-lpi.h" > > @@ -129,20 +131,25 @@ static const struct lpi_pinctrl_variant_data sc7280_lpi_data = { > > static const struct of_device_id lpi_pinctrl_of_match[] = { > { > - .compatible = "qcom,sc7280-lpass-lpi-pinctrl", > - .data = &sc7280_lpi_data, > + .compatible = "qcom,sc7280-lpass-lpi-pinctrl", > + .data = &sc7280_lpi_data, Split whitespace changes to a separate patch. Never mix cleanups (like the whitespace or formatting) and the sensible changes in a single patch. > }, { > - .compatible = "qcom,sm8350-lpass-lpi-pinctrl", > - .data = &sc7280_lpi_data, > + .compatible = "qcom,sm8350-lpass-lpi-pinctrl", > + .data = &sc7280_lpi_data, > }, > { } > }; > MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match); > -- With best wishes Dmitry ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v6 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM 2026-05-22 20:46 [PATCH v6 RESEND 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Ajay Kumar Nandam 2026-05-22 20:46 ` [PATCH v6 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs Ajay Kumar Nandam @ 2026-05-22 20:46 ` Ajay Kumar Nandam 2026-06-09 23:12 ` Nathan Chancellor 2026-06-10 6:18 ` Krzysztof Kozlowski 2026-05-26 9:37 ` [PATCH v6 RESEND 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Linus Walleij 2026-06-08 8:47 ` Linus Walleij 3 siblings, 2 replies; 13+ messages in thread From: Ajay Kumar Nandam @ 2026-05-22 20:46 UTC (permalink / raw) To: Bjorn Andersson, Linus Walleij Cc: linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik, ajay.nandam, Konrad Dybcio Convert the LPASS LPI pinctrl driver to use the PM clock framework for runtime power management. This allows the LPASS LPI pinctrl driver to drop clock votes when idle, improves power efficiency on platforms using LPASS LPI island mode, and aligns the driver with common runtime PM patterns used across Qualcomm LPASS subsystems. Guard GPIO register read/write helpers and slew-rate register programming with synchronous runtime PM calls so the device is active during MMIO operations whenever autosuspend is enabled. Make PINCTRL_LPASS_LPI depend on PM_CLK, since this patch introduces direct PM clock API use in the shared core. Suggested-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com> --- drivers/pinctrl/qcom/Kconfig | 1 + drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 144 +++++++++++++++-------- 2 files changed, 99 insertions(+), 46 deletions(-) diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index a09e840a01c6..18db350222b9 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -55,6 +55,7 @@ config PINCTRL_LPASS_LPI select PINCONF select GENERIC_PINCONF select GENERIC_PINCTRL_GROUPS + depends on PM_CLK depends on GPIOLIB help This is the pinctrl, pinmux, pinconf and gpiolib driver for the diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c index 15ced5027579..4d758fd117c4 100644 --- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c @@ -11,10 +11,13 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/seq_file.h> +#include <linux/cleanup.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinmux.h> +#include <linux/pm_clock.h> +#include <linux/pm_runtime.h> #include "../pinctrl-utils.h" @@ -22,7 +25,6 @@ #define MAX_NR_GPIO 32 #define GPIO_FUNC 0 -#define MAX_LPI_NUM_CLKS 2 struct lpi_pinctrl { struct device *dev; @@ -31,15 +33,14 @@ struct lpi_pinctrl { struct pinctrl_desc desc; char __iomem *tlmm_base; char __iomem *slew_base; - struct clk_bulk_data clks[MAX_LPI_NUM_CLKS]; /* Protects from concurrent register updates */ struct mutex lock; DECLARE_BITMAP(ever_gpio, MAX_NR_GPIO); const struct lpi_pinctrl_variant_data *data; }; -static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin, - unsigned int addr) +static void __iomem *lpi_gpio_reg(struct lpi_pinctrl *state, + unsigned int pin, unsigned int addr) { u32 pin_offset; @@ -48,22 +49,48 @@ static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin, else pin_offset = LPI_TLMM_REG_OFFSET * pin; - return ioread32(state->tlmm_base + pin_offset + addr); + return state->tlmm_base + pin_offset + addr; +} + +static void __lpi_gpio_read(struct lpi_pinctrl *state, + unsigned int pin, unsigned int addr, u32 *val) +{ + *val = ioread32(lpi_gpio_reg(state, pin, addr)); +} + +static void __lpi_gpio_write(struct lpi_pinctrl *state, + unsigned int pin, unsigned int addr, + unsigned int val) +{ + iowrite32(val, lpi_gpio_reg(state, pin, addr)); +} + +static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin, + unsigned int addr, u32 *val) +{ + int ret; + + ret = pm_runtime_resume_and_get(state->dev); + if (ret < 0) + return ret; + + __lpi_gpio_read(state, pin, addr, val); + + return pm_runtime_put_autosuspend(state->dev); } static int lpi_gpio_write(struct lpi_pinctrl *state, unsigned int pin, unsigned int addr, unsigned int val) { - u32 pin_offset; + int ret; - if (state->data->flags & LPI_FLAG_USE_PREDEFINED_PIN_OFFSET) - pin_offset = state->data->groups[pin].pin_offset; - else - pin_offset = LPI_TLMM_REG_OFFSET * pin; + ret = pm_runtime_resume_and_get(state->dev); + if (ret < 0) + return ret; - iowrite32(val, state->tlmm_base + pin_offset + addr); + __lpi_gpio_write(state, pin, addr, val); - return 0; + return pm_runtime_put_autosuspend(state->dev); } static const struct pinctrl_ops lpi_gpio_pinctrl_ops = { @@ -107,8 +134,8 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function, { struct lpi_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); const struct lpi_pingroup *g = &pctrl->data->groups[group]; - u32 val; - int i, pin = g->pin; + u32 io_val, val; + int i, pin = g->pin, ret; for (i = 0; i < g->nfuncs; i++) { if (g->funcs[i] == function) @@ -118,8 +145,12 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function, if (WARN_ON(i == g->nfuncs)) return -EINVAL; - mutex_lock(&pctrl->lock); - val = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG); + ret = pm_runtime_resume_and_get(pctrl->dev); + if (ret < 0) + return ret; + + guard(mutex)(&pctrl->lock); + __lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG, &val); /* * If this is the first time muxing to GPIO and the direction is @@ -129,24 +160,25 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function, */ if (i == GPIO_FUNC && (val & LPI_GPIO_OE_MASK) && !test_and_set_bit(group, pctrl->ever_gpio)) { - u32 io_val = lpi_gpio_read(pctrl, group, LPI_GPIO_VALUE_REG); + __lpi_gpio_read(pctrl, group, LPI_GPIO_VALUE_REG, &io_val); if (io_val & LPI_GPIO_VALUE_IN_MASK) { if (!(io_val & LPI_GPIO_VALUE_OUT_MASK)) - lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, - io_val | LPI_GPIO_VALUE_OUT_MASK); + __lpi_gpio_write(pctrl, group, + LPI_GPIO_VALUE_REG, + io_val | LPI_GPIO_VALUE_OUT_MASK); } else { if (io_val & LPI_GPIO_VALUE_OUT_MASK) - lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, - io_val & ~LPI_GPIO_VALUE_OUT_MASK); + __lpi_gpio_write(pctrl, group, + LPI_GPIO_VALUE_REG, + io_val & ~LPI_GPIO_VALUE_OUT_MASK); } } u32p_replace_bits(&val, i, LPI_GPIO_FUNCTION_MASK); - lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val); - mutex_unlock(&pctrl->lock); + __lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val); - return 0; + return pm_runtime_put_autosuspend(pctrl->dev); } static const struct pinmux_ops lpi_gpio_pinmux_ops = { @@ -162,11 +194,15 @@ static int lpi_config_get(struct pinctrl_dev *pctldev, unsigned int param = pinconf_to_config_param(*config); struct lpi_pinctrl *state = dev_get_drvdata(pctldev->dev); unsigned int arg = 0; + u32 ctl_reg; int is_out; int pull; - u32 ctl_reg; + int ret; + + ret = lpi_gpio_read(state, pin, LPI_GPIO_CFG_REG, &ctl_reg); + if (ret) + return ret; - ctl_reg = lpi_gpio_read(state, pin, LPI_GPIO_CFG_REG); is_out = ctl_reg & LPI_GPIO_OE_MASK; pull = FIELD_GET(LPI_GPIO_PULL_MASK, ctl_reg); @@ -197,6 +233,7 @@ static int lpi_config_get(struct pinctrl_dev *pctldev, } *config = pinconf_to_config_packed(param, arg); + return 0; } @@ -206,7 +243,7 @@ static int lpi_config_set_slew_rate(struct lpi_pinctrl *pctrl, { unsigned long sval; void __iomem *reg; - int slew_offset; + int slew_offset, ret; if (slew > LPI_SLEW_RATE_MAX) { dev_err(pctrl->dev, "invalid slew rate %u for pin: %d\n", @@ -225,6 +262,10 @@ static int lpi_config_set_slew_rate(struct lpi_pinctrl *pctrl, else reg = pctrl->slew_base + LPI_SLEW_RATE_CTL_REG; + ret = pm_runtime_resume_and_get(pctrl->dev); + if (ret < 0) + return ret; + mutex_lock(&pctrl->lock); sval = ioread32(reg); @@ -234,7 +275,7 @@ static int lpi_config_set_slew_rate(struct lpi_pinctrl *pctrl, mutex_unlock(&pctrl->lock); - return 0; + return pm_runtime_put_autosuspend(pctrl->dev); } static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, @@ -244,8 +285,8 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, unsigned int param, arg, pullup = LPI_GPIO_BIAS_DISABLE, strength = 2; bool value, output_enabled = false; const struct lpi_pingroup *g; - int i, ret; u32 val; + int i, ret; g = &pctrl->data->groups[group]; for (i = 0; i < nconfs; i++) { @@ -289,23 +330,26 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, * As per Hardware Programming Guide, when configuring pin as output, * set the pin value before setting output-enable (OE). */ + ret = pm_runtime_resume_and_get(pctrl->dev); + if (ret < 0) + return ret; + + guard(mutex)(&pctrl->lock); if (output_enabled) { val = u32_encode_bits(value ? 1 : 0, LPI_GPIO_VALUE_OUT_MASK); - lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val); + __lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val); } - mutex_lock(&pctrl->lock); - val = lpi_gpio_read(pctrl, group, LPI_GPIO_CFG_REG); + __lpi_gpio_read(pctrl, group, LPI_GPIO_CFG_REG, &val); u32p_replace_bits(&val, pullup, LPI_GPIO_PULL_MASK); u32p_replace_bits(&val, LPI_GPIO_DS_TO_VAL(strength), LPI_GPIO_OUT_STRENGTH_MASK); u32p_replace_bits(&val, output_enabled, LPI_GPIO_OE_MASK); - lpi_gpio_write(pctrl, group, LPI_GPIO_CFG_REG, val); - mutex_unlock(&pctrl->lock); + __lpi_gpio_write(pctrl, group, LPI_GPIO_CFG_REG, val); - return 0; + return pm_runtime_put_autosuspend(pctrl->dev); } static const struct pinconf_ops lpi_gpio_pinconf_ops = { @@ -354,9 +398,14 @@ static int lpi_gpio_direction_output(struct gpio_chip *chip, static int lpi_gpio_get(struct gpio_chip *chip, unsigned int pin) { struct lpi_pinctrl *state = gpiochip_get_data(chip); + u32 val; + int ret; + + ret = lpi_gpio_read(state, pin, LPI_GPIO_VALUE_REG, &val); + if (ret) + return ret; - return lpi_gpio_read(state, pin, LPI_GPIO_VALUE_REG) & - LPI_GPIO_VALUE_IN_MASK; + return val & LPI_GPIO_VALUE_IN_MASK; } static int lpi_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) @@ -399,7 +448,9 @@ static void lpi_gpio_dbg_show_one(struct seq_file *s, pctldev = pctldev ? : state->ctrl; pindesc = pctldev->desc->pins[offset]; - ctl_reg = lpi_gpio_read(state, offset, LPI_GPIO_CFG_REG); + if (lpi_gpio_read(state, offset, LPI_GPIO_CFG_REG, &ctl_reg)) + return; + is_out = ctl_reg & LPI_GPIO_OE_MASK; func = FIELD_GET(LPI_GPIO_FUNCTION_MASK, ctl_reg); @@ -482,9 +533,6 @@ int lpi_pinctrl_probe(struct platform_device *pdev) pctrl->data = data; pctrl->dev = &pdev->dev; - pctrl->clks[0].id = "core"; - pctrl->clks[1].id = "audio"; - pctrl->tlmm_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pctrl->tlmm_base)) return dev_err_probe(dev, PTR_ERR(pctrl->tlmm_base), @@ -497,13 +545,19 @@ int lpi_pinctrl_probe(struct platform_device *pdev) "Slew resource not provided\n"); } - ret = devm_clk_bulk_get_optional(dev, MAX_LPI_NUM_CLKS, pctrl->clks); + ret = devm_pm_clk_create(dev); if (ret) return ret; - ret = clk_bulk_prepare_enable(MAX_LPI_NUM_CLKS, pctrl->clks); + ret = of_pm_clk_add_clks(dev); + if (ret < 0 && ret != -ENODEV) + return ret; + + pm_runtime_set_autosuspend_delay(dev, 100); + pm_runtime_use_autosuspend(dev); + ret = devm_pm_runtime_enable(dev); if (ret) - return dev_err_probe(dev, ret, "Can't enable clocks\n"); + return ret; pctrl->desc.pctlops = &lpi_gpio_pinctrl_ops; pctrl->desc.pmxops = &lpi_gpio_pinmux_ops; @@ -542,7 +596,6 @@ int lpi_pinctrl_probe(struct platform_device *pdev) err_pinctrl: mutex_destroy(&pctrl->lock); - clk_bulk_disable_unprepare(MAX_LPI_NUM_CLKS, pctrl->clks); return ret; } @@ -554,7 +607,6 @@ void lpi_pinctrl_remove(struct platform_device *pdev) int i; mutex_destroy(&pctrl->lock); - clk_bulk_disable_unprepare(MAX_LPI_NUM_CLKS, pctrl->clks); for (i = 0; i < pctrl->data->npins; i++) pinctrl_generic_remove_group(pctrl->ctrl, i); -- 2.34.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v6 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM 2026-05-22 20:46 ` [PATCH v6 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM Ajay Kumar Nandam @ 2026-06-09 23:12 ` Nathan Chancellor 2026-06-10 8:14 ` Ajay Kumar Nandam 2026-06-10 6:18 ` Krzysztof Kozlowski 1 sibling, 1 reply; 13+ messages in thread From: Nathan Chancellor @ 2026-06-09 23:12 UTC (permalink / raw) To: Ajay Kumar Nandam, Linus Walleij Cc: Bjorn Andersson, linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik, Konrad Dybcio Hi Ajay, On Sat, May 23, 2026 at 02:16:44AM +0530, Ajay Kumar Nandam wrote: ... > diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c > index 15ced5027579..4d758fd117c4 100644 > --- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c > +++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c ... > @@ -48,22 +49,48 @@ static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin, > else > pin_offset = LPI_TLMM_REG_OFFSET * pin; > > - return ioread32(state->tlmm_base + pin_offset + addr); > + return state->tlmm_base + pin_offset + addr; > +} > + > +static void __lpi_gpio_read(struct lpi_pinctrl *state, > + unsigned int pin, unsigned int addr, u32 *val) > +{ > + *val = ioread32(lpi_gpio_reg(state, pin, addr)); > +} > + > +static void __lpi_gpio_write(struct lpi_pinctrl *state, > + unsigned int pin, unsigned int addr, > + unsigned int val) > +{ > + iowrite32(val, lpi_gpio_reg(state, pin, addr)); > +} > + > +static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin, > + unsigned int addr, u32 *val) > +{ > + int ret; > + > + ret = pm_runtime_resume_and_get(state->dev); > + if (ret < 0) > + return ret; > + > + __lpi_gpio_read(state, pin, addr, val); > + > + return pm_runtime_put_autosuspend(state->dev); > } > > static int lpi_gpio_write(struct lpi_pinctrl *state, unsigned int pin, > unsigned int addr, unsigned int val) > { > - u32 pin_offset; > + int ret; > > - if (state->data->flags & LPI_FLAG_USE_PREDEFINED_PIN_OFFSET) > - pin_offset = state->data->groups[pin].pin_offset; > - else > - pin_offset = LPI_TLMM_REG_OFFSET * pin; > + ret = pm_runtime_resume_and_get(state->dev); > + if (ret < 0) > + return ret; > > - iowrite32(val, state->tlmm_base + pin_offset + addr); > + __lpi_gpio_write(state, pin, addr, val); > > - return 0; > + return pm_runtime_put_autosuspend(state->dev); > } > > static const struct pinctrl_ops lpi_gpio_pinctrl_ops = { After this change landed in -next as commit b719ede389d8 ("pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM"), there is a warning that lpi_gpio_write() is completely unused, breaking the build: drivers/pinctrl/qcom/pinctrl-lpass-lpi.c:82:12: error: 'lpi_gpio_write' defined but not used [-Werror=unused-function] 82 | static int lpi_gpio_write(struct lpi_pinctrl *state, unsigned int pin, | ^~~~~~~~~~~~~~ cc1: all warnings being treated as errors Seems legitimate, is this intended? $ rg lpi_gpio_write drivers/pinctrl/qcom/pinctrl-lpass-lpi.c 61:static void __lpi_gpio_write(struct lpi_pinctrl *state, 82:static int lpi_gpio_write(struct lpi_pinctrl *state, unsigned int pin, 91: __lpi_gpio_write(state, pin, addr, val); 167: __lpi_gpio_write(pctrl, group, 172: __lpi_gpio_write(pctrl, group, 179: __lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val); 340: __lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val); 350: __lpi_gpio_write(pctrl, group, LPI_GPIO_CFG_REG, val); -- Cheers, Nathan ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM 2026-06-09 23:12 ` Nathan Chancellor @ 2026-06-10 8:14 ` Ajay Kumar Nandam 0 siblings, 0 replies; 13+ messages in thread From: Ajay Kumar Nandam @ 2026-06-10 8:14 UTC (permalink / raw) To: Nathan Chancellor, Linus Walleij Cc: Bjorn Andersson, linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik, Konrad Dybcio On 6/10/2026 4:42 AM, Nathan Chancellor wrote: > Hi Ajay, > > On Sat, May 23, 2026 at 02:16:44AM +0530, Ajay Kumar Nandam wrote: > ... >> diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c >> index 15ced5027579..4d758fd117c4 100644 >> --- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c >> +++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c > ... >> @@ -48,22 +49,48 @@ static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin, >> else >> pin_offset = LPI_TLMM_REG_OFFSET * pin; >> >> - return ioread32(state->tlmm_base + pin_offset + addr); >> + return state->tlmm_base + pin_offset + addr; >> +} >> + >> +static void __lpi_gpio_read(struct lpi_pinctrl *state, >> + unsigned int pin, unsigned int addr, u32 *val) >> +{ >> + *val = ioread32(lpi_gpio_reg(state, pin, addr)); >> +} >> + >> +static void __lpi_gpio_write(struct lpi_pinctrl *state, >> + unsigned int pin, unsigned int addr, >> + unsigned int val) >> +{ >> + iowrite32(val, lpi_gpio_reg(state, pin, addr)); >> +} >> + >> +static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin, >> + unsigned int addr, u32 *val) >> +{ >> + int ret; >> + >> + ret = pm_runtime_resume_and_get(state->dev); >> + if (ret < 0) >> + return ret; >> + >> + __lpi_gpio_read(state, pin, addr, val); >> + >> + return pm_runtime_put_autosuspend(state->dev); >> } >> >> static int lpi_gpio_write(struct lpi_pinctrl *state, unsigned int pin, >> unsigned int addr, unsigned int val) >> { >> - u32 pin_offset; >> + int ret; >> >> - if (state->data->flags & LPI_FLAG_USE_PREDEFINED_PIN_OFFSET) >> - pin_offset = state->data->groups[pin].pin_offset; >> - else >> - pin_offset = LPI_TLMM_REG_OFFSET * pin; >> + ret = pm_runtime_resume_and_get(state->dev); >> + if (ret < 0) >> + return ret; >> >> - iowrite32(val, state->tlmm_base + pin_offset + addr); >> + __lpi_gpio_write(state, pin, addr, val); >> >> - return 0; >> + return pm_runtime_put_autosuspend(state->dev); >> } >> >> static const struct pinctrl_ops lpi_gpio_pinctrl_ops = { > > After this change landed in -next as commit b719ede389d8 ("pinctrl: > qcom: lpass-lpi: Switch to PM clock framework for runtime PM"), there is > a warning that lpi_gpio_write() is completely unused, breaking the > build: > > drivers/pinctrl/qcom/pinctrl-lpass-lpi.c:82:12: error: 'lpi_gpio_write' defined but not used [-Werror=unused-function] > 82 | static int lpi_gpio_write(struct lpi_pinctrl *state, unsigned int pin, > | ^~~~~~~~~~~~~~ > cc1: all warnings being treated as errors > > Seems legitimate, is this intended? > > $ rg lpi_gpio_write drivers/pinctrl/qcom/pinctrl-lpass-lpi.c > 61:static void __lpi_gpio_write(struct lpi_pinctrl *state, > 82:static int lpi_gpio_write(struct lpi_pinctrl *state, unsigned int pin, > 91: __lpi_gpio_write(state, pin, addr, val); > 167: __lpi_gpio_write(pctrl, group, > 172: __lpi_gpio_write(pctrl, group, > 179: __lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val); > 340: __lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val); > 350: __lpi_gpio_write(pctrl, group, LPI_GPIO_CFG_REG, val); Hi Nathan, Thanks for catching this. You're right — lpi_gpio_write() became unused after the runtime PM refactor, which triggers -Wunused-function with W=1/Werror builds. I’ve sent a follow-up fix to remove the unused helper: https://lore.kernel.org/all/20260610080809.2588640-1-ajay.nandam@oss.qualcomm.com/ Thanks again for the report and testing. > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM 2026-05-22 20:46 ` [PATCH v6 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM Ajay Kumar Nandam 2026-06-09 23:12 ` Nathan Chancellor @ 2026-06-10 6:18 ` Krzysztof Kozlowski 2026-06-10 8:17 ` Ajay Kumar Nandam 1 sibling, 1 reply; 13+ messages in thread From: Krzysztof Kozlowski @ 2026-06-10 6:18 UTC (permalink / raw) To: Ajay Kumar Nandam, Bjorn Andersson, Linus Walleij Cc: linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik, Konrad Dybcio On 22/05/2026 22:46, Ajay Kumar Nandam wrote: > Convert the LPASS LPI pinctrl driver to use the PM clock framework for > runtime power management. > > This allows the LPASS LPI pinctrl driver to drop clock votes when idle, > improves power efficiency on platforms using LPASS LPI island mode, and > aligns the driver with common runtime PM patterns used across Qualcomm > LPASS subsystems. > > Guard GPIO register read/write helpers and slew-rate register programming > with synchronous runtime PM calls so the device is active during MMIO > operations whenever autosuspend is enabled. > > Make PINCTRL_LPASS_LPI depend on PM_CLK, since this patch introduces > direct PM clock API use in the shared core. > > Suggested-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> > Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com> > --- > drivers/pinctrl/qcom/Kconfig | 1 + > drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 144 +++++++++++++++-------- > 2 files changed, 99 insertions(+), 46 deletions(-) > It looks this introduces new build warnings: https://krzk.eu/#/builders/151/builds/303/steps/11/logs/stdio Which you might have been notified about more than two weeks ago: https://lore.kernel.org/all/202605241040.1av35pgK-lkp@intel.com/ Best regards, Krzysztof ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM 2026-06-10 6:18 ` Krzysztof Kozlowski @ 2026-06-10 8:17 ` Ajay Kumar Nandam 0 siblings, 0 replies; 13+ messages in thread From: Ajay Kumar Nandam @ 2026-06-10 8:17 UTC (permalink / raw) To: Krzysztof Kozlowski, Bjorn Andersson, Linus Walleij Cc: linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik, Konrad Dybcio On 6/10/2026 11:48 AM, Krzysztof Kozlowski wrote: > On 22/05/2026 22:46, Ajay Kumar Nandam wrote: >> Convert the LPASS LPI pinctrl driver to use the PM clock framework for >> runtime power management. >> >> This allows the LPASS LPI pinctrl driver to drop clock votes when idle, >> improves power efficiency on platforms using LPASS LPI island mode, and >> aligns the driver with common runtime PM patterns used across Qualcomm >> LPASS subsystems. >> >> Guard GPIO register read/write helpers and slew-rate register programming >> with synchronous runtime PM calls so the device is active during MMIO >> operations whenever autosuspend is enabled. >> >> Make PINCTRL_LPASS_LPI depend on PM_CLK, since this patch introduces >> direct PM clock API use in the shared core. >> >> Suggested-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> >> Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com> >> --- >> drivers/pinctrl/qcom/Kconfig | 1 + >> drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 144 +++++++++++++++-------- >> 2 files changed, 99 insertions(+), 46 deletions(-) >> > > > It looks this introduces new build warnings: > https://krzk.eu/#/builders/151/builds/303/steps/11/logs/stdio > > Which you might have been notified about more than two weeks ago: > https://lore.kernel.org/all/202605241040.1av35pgK-lkp@intel.com/ > > Best regards, > Krzysztof Hi Krzysztof, Thanks for the report. You're right — this was introduced by the runtime PM refactor, and the unused lpi_gpio_write() was also reported earlier by the Intel CI. I've addressed this with a follow-up fix removing the unused helper: https://lore.kernel.org/all/20260610080809.2588640-1-ajay.nandam@oss.qualcomm.com/ > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 RESEND 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework 2026-05-22 20:46 [PATCH v6 RESEND 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Ajay Kumar Nandam 2026-05-22 20:46 ` [PATCH v6 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs Ajay Kumar Nandam 2026-05-22 20:46 ` [PATCH v6 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM Ajay Kumar Nandam @ 2026-05-26 9:37 ` Linus Walleij 2026-06-15 15:54 ` Bartosz Golaszewski 2026-06-08 8:47 ` Linus Walleij 3 siblings, 1 reply; 13+ messages in thread From: Linus Walleij @ 2026-05-26 9:37 UTC (permalink / raw) To: Ajay Kumar Nandam Cc: Bjorn Andersson, linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik On Fri, May 22, 2026 at 10:47 PM Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com> wrote: > This series converts LPASS LPI pinctrl runtime clock handling to the PM > clock framework and ensures GPIO register accesses runtime-resume the > block before MMIO. I hope I can get some feedback from the Qualcomm maintainers or I will feel tempted to just apply this... Actually the volume of Qualcomm patches has gone up the recent months so I'm starting to feel like I need a Qualcomm submaintainer who does the nice things that Geert does for Renesas and Krzysztof does for Samsung Exynos and collect the Qcom/MSM patches and send pull request to me. Think about it! (I know very well Bjorn and Krzysztof have enough to do alread, so maybe someone else?) Yours, Linus Walleij ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 RESEND 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework 2026-05-26 9:37 ` [PATCH v6 RESEND 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Linus Walleij @ 2026-06-15 15:54 ` Bartosz Golaszewski 2026-06-15 22:37 ` Linus Walleij 0 siblings, 1 reply; 13+ messages in thread From: Bartosz Golaszewski @ 2026-06-15 15:54 UTC (permalink / raw) To: Linus Walleij Cc: Bjorn Andersson, linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik, Ajay Kumar Nandam On Tue, 26 May 2026 11:37:43 +0200, Linus Walleij <linusw@kernel.org> said: > On Fri, May 22, 2026 at 10:47 PM Ajay Kumar Nandam > <ajay.nandam@oss.qualcomm.com> wrote: > >> This series converts LPASS LPI pinctrl runtime clock handling to the PM >> clock framework and ensures GPIO register accesses runtime-resume the >> block before MMIO. > > I hope I can get some feedback from the Qualcomm maintainers > or I will feel tempted to just apply this... > > Actually the volume of Qualcomm patches has gone up the recent > months so I'm starting to feel like I need a Qualcomm submaintainer > who does the nice things that Geert does for Renesas and Krzysztof > does for Samsung Exynos and collect the Qcom/MSM patches and > send pull request to me. Think about it! (I know very well Bjorn and > Krzysztof have enough to do alread, so maybe someone else?) > Hi! I've been volunteered to do this. If you agree, should I have a separate tree like for Renesas and Samsung and make pull-requests to you? Bart ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 RESEND 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework 2026-06-15 15:54 ` Bartosz Golaszewski @ 2026-06-15 22:37 ` Linus Walleij 0 siblings, 0 replies; 13+ messages in thread From: Linus Walleij @ 2026-06-15 22:37 UTC (permalink / raw) To: Bartosz Golaszewski Cc: Bjorn Andersson, linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik, Ajay Kumar Nandam On Mon, Jun 15, 2026 at 5:54 PM Bartosz Golaszewski <brgl@kernel.org> wrote: > > Actually the volume of Qualcomm patches has gone up the recent > > months so I'm starting to feel like I need a Qualcomm submaintainer > > who does the nice things that Geert does for Renesas and Krzysztof > > does for Samsung Exynos and collect the Qcom/MSM patches and > > send pull request to me. Think about it! (I know very well Bjorn and > > Krzysztof have enough to do alread, so maybe someone else?) > > Hi! > > I've been volunteered to do this. If you agree, should I have a separate tree > like for Renesas and Samsung and make pull-requests to you? Excellent choice, I trust this maintainer a lot :D Yes just set up some tree on kernel org (or use a branch on one of your existing ones if it makes more sense) and send signed pull request from there. Chain of trust with GPG keys is already in place. Yours, Linus Walleij ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 RESEND 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework 2026-05-22 20:46 [PATCH v6 RESEND 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Ajay Kumar Nandam ` (2 preceding siblings ...) 2026-05-26 9:37 ` [PATCH v6 RESEND 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Linus Walleij @ 2026-06-08 8:47 ` Linus Walleij 3 siblings, 0 replies; 13+ messages in thread From: Linus Walleij @ 2026-06-08 8:47 UTC (permalink / raw) To: Ajay Kumar Nandam Cc: Bjorn Andersson, linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik On Fri, May 22, 2026 at 10:47 PM Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com> wrote: > This series converts LPASS LPI pinctrl runtime clock handling to the PM > clock framework and ensures GPIO register accesses runtime-resume the > block before MMIO. No reaction from maintainers so patches applied! Yours, Linus Walleij ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v5 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework @ 2026-05-13 14:00 Ajay Kumar Nandam 2026-05-22 20:33 ` [PATCH v6 " Ajay Kumar Nandam 0 siblings, 1 reply; 13+ messages in thread From: Ajay Kumar Nandam @ 2026-05-13 14:00 UTC (permalink / raw) To: Bjorn Andersson, Linus Walleij; +Cc: linux-arm-msm, linux-gpio, linux-kernel This series converts LPASS LPI pinctrl runtime clock handling to the PM clock framework and ensures GPIO register accesses runtime-resume the block before MMIO. The series is intentionally ordered for bisect safety: - patch 1 wires runtime PM ops in LPASS LPI variant drivers - patch 2 updates the shared core to use pm_clk + runtime PM access paths and completes sc7280 wiring After this conversion, LPASS LPI variants sharing the common core use a consistent DT clock flow via of_pm_clk_add_clks() together with pm_clk_suspend()/pm_clk_resume() and autosuspend. Testing: - Runtime behavior validated on Kodiak (sc7280). - Wider runtime testing on other LPASS LPI variants is welcome. --- Changes in v5: - Send as a proper standalone v5 series with cover letter. - Fix indentation in newly added .of_match/.pm blocks in: sc7280, sc8280xp, sm8250, sm8450, sm8550, sm8650 variants. - Simplify pm_runtime_put_autosuspend() return handling in lpi_gpio_read(), lpi_gpio_write(), and lpi_config_set_slew_rate() in the shared LPASS LPI core, per review suggestion. - No functional changes. Links to previous revisions: - v4: https://lore.kernel.org/r/20260508113636.3561383-1-ajay.nandam@oss.qualcomm.com - v3: https://lore.kernel.org/r/20260508113636.3561383-1-ajay.nandam@oss.qualcomm.com - v2: https://lore.kernel.org/r/20260420123135.350446-1-ajay.nandam@oss.qualcomm.com - v1: https://lore.kernel.org/r/20260413122233.375945-1-ajay.nandam@oss.qualcomm.com Ajay Kumar Nandam (2): pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 114 +++++++++++------- .../pinctrl/qcom/pinctrl-milos-lpass-lpi.c | 7 ++ .../pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c | 19 ++- .../pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c | 15 ++- .../pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c | 7 ++ .../pinctrl/qcom/pinctrl-sdm670-lpass-lpi.c | 7 ++ .../pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c | 7 ++ .../pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c | 7 ++ .../pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 15 ++- .../pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c | 15 ++- .../pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c | 15 ++- .../pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c | 15 ++- 12 files changed, 176 insertions(+), 67 deletions(-) -- 2.34.1 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v6 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework 2026-05-13 14:00 [PATCH v5 " Ajay Kumar Nandam @ 2026-05-22 20:33 ` Ajay Kumar Nandam 2026-05-22 20:33 ` [PATCH v6 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM Ajay Kumar Nandam 0 siblings, 1 reply; 13+ messages in thread From: Ajay Kumar Nandam @ 2026-05-22 20:33 UTC (permalink / raw) To: Bjorn Andersson, Linus Walleij Cc: linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik, ajay.nandam This series converts LPASS LPI pinctrl runtime clock handling to the PM clock framework and ensures GPIO register accesses runtime-resume the block before MMIO. The series is intentionally ordered for bisect safety: - patch 1 wires runtime PM ops in LPASS LPI variant drivers - patch 2 updates the shared core to use pm_clk + runtime PM guarded register access paths and adds the PM_CLK Kconfig dependency After this conversion, LPASS LPI variants sharing the common core use a consistent DT clock flow via of_pm_clk_add_clks() together with pm_clk_suspend()/pm_clk_resume() and autosuspend. Testing: - Runtime behavior validated on Kodiak (sc7280). - Wider runtime testing on other LPASS LPI variants is welcome. Link: https://lore.kernel.org/r/20260513140009.3841770-1-ajay.nandam@oss.qualcomm.com Changes since v5: - Rebased to current linux-next and refreshed the shared-core conversion patch to apply cleanly on top of latest LPASS LPI mux-path updates - Include SM6350 in the preparatory LPASS LPI per-SoC runtime PM hook wiring set so all in-tree LPASS LPI variants are covered - Keep PM_CLK dependency under PINCTRL_LPASS_LPI where shared core PM clock APIs are introduced Ajay Kumar Nandam (2): pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM drivers/pinctrl/qcom/Kconfig | 1 + drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 144 ++++++++++++------ .../pinctrl/qcom/pinctrl-milos-lpass-lpi.c | 7 + .../pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c | 19 ++- .../pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c | 15 +- .../pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c | 7 + .../pinctrl/qcom/pinctrl-sdm670-lpass-lpi.c | 7 + .../pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c | 7 + .../pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c | 7 + .../pinctrl/qcom/pinctrl-sm6350-lpass-lpi.c | 7 + .../pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 15 +- .../pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c | 15 +- .../pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c | 15 +- .../pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c | 15 +- 14 files changed, 209 insertions(+), 72 deletions(-) -- 2.34.1 ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v6 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM 2026-05-22 20:33 ` [PATCH v6 " Ajay Kumar Nandam @ 2026-05-22 20:33 ` Ajay Kumar Nandam 0 siblings, 0 replies; 13+ messages in thread From: Ajay Kumar Nandam @ 2026-05-22 20:33 UTC (permalink / raw) To: Bjorn Andersson, Linus Walleij Cc: linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik, ajay.nandam, Konrad Dybcio Convert the LPASS LPI pinctrl driver to use the PM clock framework for runtime power management. This allows the LPASS LPI pinctrl driver to drop clock votes when idle, improves power efficiency on platforms using LPASS LPI island mode, and aligns the driver with common runtime PM patterns used across Qualcomm LPASS subsystems. Guard GPIO register read/write helpers and slew-rate register programming with synchronous runtime PM calls so the device is active during MMIO operations whenever autosuspend is enabled. Make PINCTRL_LPASS_LPI depend on PM_CLK, since this patch introduces direct PM clock API use in the shared core. Suggested-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com> --- drivers/pinctrl/qcom/Kconfig | 1 + drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 144 +++++++++++++++-------- 2 files changed, 99 insertions(+), 46 deletions(-) diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index a09e840a01c6..18db350222b9 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -55,6 +55,7 @@ config PINCTRL_LPASS_LPI select PINCONF select GENERIC_PINCONF select GENERIC_PINCTRL_GROUPS + depends on PM_CLK depends on GPIOLIB help This is the pinctrl, pinmux, pinconf and gpiolib driver for the diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c index 15ced5027579..4d758fd117c4 100644 --- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c @@ -11,10 +11,13 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/seq_file.h> +#include <linux/cleanup.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinmux.h> +#include <linux/pm_clock.h> +#include <linux/pm_runtime.h> #include "../pinctrl-utils.h" @@ -22,7 +25,6 @@ #define MAX_NR_GPIO 32 #define GPIO_FUNC 0 -#define MAX_LPI_NUM_CLKS 2 struct lpi_pinctrl { struct device *dev; @@ -31,15 +33,14 @@ struct lpi_pinctrl { struct pinctrl_desc desc; char __iomem *tlmm_base; char __iomem *slew_base; - struct clk_bulk_data clks[MAX_LPI_NUM_CLKS]; /* Protects from concurrent register updates */ struct mutex lock; DECLARE_BITMAP(ever_gpio, MAX_NR_GPIO); const struct lpi_pinctrl_variant_data *data; }; -static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin, - unsigned int addr) +static void __iomem *lpi_gpio_reg(struct lpi_pinctrl *state, + unsigned int pin, unsigned int addr) { u32 pin_offset; @@ -48,22 +49,48 @@ static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin, else pin_offset = LPI_TLMM_REG_OFFSET * pin; - return ioread32(state->tlmm_base + pin_offset + addr); + return state->tlmm_base + pin_offset + addr; +} + +static void __lpi_gpio_read(struct lpi_pinctrl *state, + unsigned int pin, unsigned int addr, u32 *val) +{ + *val = ioread32(lpi_gpio_reg(state, pin, addr)); +} + +static void __lpi_gpio_write(struct lpi_pinctrl *state, + unsigned int pin, unsigned int addr, + unsigned int val) +{ + iowrite32(val, lpi_gpio_reg(state, pin, addr)); +} + +static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin, + unsigned int addr, u32 *val) +{ + int ret; + + ret = pm_runtime_resume_and_get(state->dev); + if (ret < 0) + return ret; + + __lpi_gpio_read(state, pin, addr, val); + + return pm_runtime_put_autosuspend(state->dev); } static int lpi_gpio_write(struct lpi_pinctrl *state, unsigned int pin, unsigned int addr, unsigned int val) { - u32 pin_offset; + int ret; - if (state->data->flags & LPI_FLAG_USE_PREDEFINED_PIN_OFFSET) - pin_offset = state->data->groups[pin].pin_offset; - else - pin_offset = LPI_TLMM_REG_OFFSET * pin; + ret = pm_runtime_resume_and_get(state->dev); + if (ret < 0) + return ret; - iowrite32(val, state->tlmm_base + pin_offset + addr); + __lpi_gpio_write(state, pin, addr, val); - return 0; + return pm_runtime_put_autosuspend(state->dev); } static const struct pinctrl_ops lpi_gpio_pinctrl_ops = { @@ -107,8 +134,8 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function, { struct lpi_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); const struct lpi_pingroup *g = &pctrl->data->groups[group]; - u32 val; - int i, pin = g->pin; + u32 io_val, val; + int i, pin = g->pin, ret; for (i = 0; i < g->nfuncs; i++) { if (g->funcs[i] == function) @@ -118,8 +145,12 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function, if (WARN_ON(i == g->nfuncs)) return -EINVAL; - mutex_lock(&pctrl->lock); - val = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG); + ret = pm_runtime_resume_and_get(pctrl->dev); + if (ret < 0) + return ret; + + guard(mutex)(&pctrl->lock); + __lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG, &val); /* * If this is the first time muxing to GPIO and the direction is @@ -129,24 +160,25 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function, */ if (i == GPIO_FUNC && (val & LPI_GPIO_OE_MASK) && !test_and_set_bit(group, pctrl->ever_gpio)) { - u32 io_val = lpi_gpio_read(pctrl, group, LPI_GPIO_VALUE_REG); + __lpi_gpio_read(pctrl, group, LPI_GPIO_VALUE_REG, &io_val); if (io_val & LPI_GPIO_VALUE_IN_MASK) { if (!(io_val & LPI_GPIO_VALUE_OUT_MASK)) - lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, - io_val | LPI_GPIO_VALUE_OUT_MASK); + __lpi_gpio_write(pctrl, group, + LPI_GPIO_VALUE_REG, + io_val | LPI_GPIO_VALUE_OUT_MASK); } else { if (io_val & LPI_GPIO_VALUE_OUT_MASK) - lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, - io_val & ~LPI_GPIO_VALUE_OUT_MASK); + __lpi_gpio_write(pctrl, group, + LPI_GPIO_VALUE_REG, + io_val & ~LPI_GPIO_VALUE_OUT_MASK); } } u32p_replace_bits(&val, i, LPI_GPIO_FUNCTION_MASK); - lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val); - mutex_unlock(&pctrl->lock); + __lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val); - return 0; + return pm_runtime_put_autosuspend(pctrl->dev); } static const struct pinmux_ops lpi_gpio_pinmux_ops = { @@ -162,11 +194,15 @@ static int lpi_config_get(struct pinctrl_dev *pctldev, unsigned int param = pinconf_to_config_param(*config); struct lpi_pinctrl *state = dev_get_drvdata(pctldev->dev); unsigned int arg = 0; + u32 ctl_reg; int is_out; int pull; - u32 ctl_reg; + int ret; + + ret = lpi_gpio_read(state, pin, LPI_GPIO_CFG_REG, &ctl_reg); + if (ret) + return ret; - ctl_reg = lpi_gpio_read(state, pin, LPI_GPIO_CFG_REG); is_out = ctl_reg & LPI_GPIO_OE_MASK; pull = FIELD_GET(LPI_GPIO_PULL_MASK, ctl_reg); @@ -197,6 +233,7 @@ static int lpi_config_get(struct pinctrl_dev *pctldev, } *config = pinconf_to_config_packed(param, arg); + return 0; } @@ -206,7 +243,7 @@ static int lpi_config_set_slew_rate(struct lpi_pinctrl *pctrl, { unsigned long sval; void __iomem *reg; - int slew_offset; + int slew_offset, ret; if (slew > LPI_SLEW_RATE_MAX) { dev_err(pctrl->dev, "invalid slew rate %u for pin: %d\n", @@ -225,6 +262,10 @@ static int lpi_config_set_slew_rate(struct lpi_pinctrl *pctrl, else reg = pctrl->slew_base + LPI_SLEW_RATE_CTL_REG; + ret = pm_runtime_resume_and_get(pctrl->dev); + if (ret < 0) + return ret; + mutex_lock(&pctrl->lock); sval = ioread32(reg); @@ -234,7 +275,7 @@ static int lpi_config_set_slew_rate(struct lpi_pinctrl *pctrl, mutex_unlock(&pctrl->lock); - return 0; + return pm_runtime_put_autosuspend(pctrl->dev); } static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, @@ -244,8 +285,8 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, unsigned int param, arg, pullup = LPI_GPIO_BIAS_DISABLE, strength = 2; bool value, output_enabled = false; const struct lpi_pingroup *g; - int i, ret; u32 val; + int i, ret; g = &pctrl->data->groups[group]; for (i = 0; i < nconfs; i++) { @@ -289,23 +330,26 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, * As per Hardware Programming Guide, when configuring pin as output, * set the pin value before setting output-enable (OE). */ + ret = pm_runtime_resume_and_get(pctrl->dev); + if (ret < 0) + return ret; + + guard(mutex)(&pctrl->lock); if (output_enabled) { val = u32_encode_bits(value ? 1 : 0, LPI_GPIO_VALUE_OUT_MASK); - lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val); + __lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val); } - mutex_lock(&pctrl->lock); - val = lpi_gpio_read(pctrl, group, LPI_GPIO_CFG_REG); + __lpi_gpio_read(pctrl, group, LPI_GPIO_CFG_REG, &val); u32p_replace_bits(&val, pullup, LPI_GPIO_PULL_MASK); u32p_replace_bits(&val, LPI_GPIO_DS_TO_VAL(strength), LPI_GPIO_OUT_STRENGTH_MASK); u32p_replace_bits(&val, output_enabled, LPI_GPIO_OE_MASK); - lpi_gpio_write(pctrl, group, LPI_GPIO_CFG_REG, val); - mutex_unlock(&pctrl->lock); + __lpi_gpio_write(pctrl, group, LPI_GPIO_CFG_REG, val); - return 0; + return pm_runtime_put_autosuspend(pctrl->dev); } static const struct pinconf_ops lpi_gpio_pinconf_ops = { @@ -354,9 +398,14 @@ static int lpi_gpio_direction_output(struct gpio_chip *chip, static int lpi_gpio_get(struct gpio_chip *chip, unsigned int pin) { struct lpi_pinctrl *state = gpiochip_get_data(chip); + u32 val; + int ret; + + ret = lpi_gpio_read(state, pin, LPI_GPIO_VALUE_REG, &val); + if (ret) + return ret; - return lpi_gpio_read(state, pin, LPI_GPIO_VALUE_REG) & - LPI_GPIO_VALUE_IN_MASK; + return val & LPI_GPIO_VALUE_IN_MASK; } static int lpi_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) @@ -399,7 +448,9 @@ static void lpi_gpio_dbg_show_one(struct seq_file *s, pctldev = pctldev ? : state->ctrl; pindesc = pctldev->desc->pins[offset]; - ctl_reg = lpi_gpio_read(state, offset, LPI_GPIO_CFG_REG); + if (lpi_gpio_read(state, offset, LPI_GPIO_CFG_REG, &ctl_reg)) + return; + is_out = ctl_reg & LPI_GPIO_OE_MASK; func = FIELD_GET(LPI_GPIO_FUNCTION_MASK, ctl_reg); @@ -482,9 +533,6 @@ int lpi_pinctrl_probe(struct platform_device *pdev) pctrl->data = data; pctrl->dev = &pdev->dev; - pctrl->clks[0].id = "core"; - pctrl->clks[1].id = "audio"; - pctrl->tlmm_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pctrl->tlmm_base)) return dev_err_probe(dev, PTR_ERR(pctrl->tlmm_base), @@ -497,13 +545,19 @@ int lpi_pinctrl_probe(struct platform_device *pdev) "Slew resource not provided\n"); } - ret = devm_clk_bulk_get_optional(dev, MAX_LPI_NUM_CLKS, pctrl->clks); + ret = devm_pm_clk_create(dev); if (ret) return ret; - ret = clk_bulk_prepare_enable(MAX_LPI_NUM_CLKS, pctrl->clks); + ret = of_pm_clk_add_clks(dev); + if (ret < 0 && ret != -ENODEV) + return ret; + + pm_runtime_set_autosuspend_delay(dev, 100); + pm_runtime_use_autosuspend(dev); + ret = devm_pm_runtime_enable(dev); if (ret) - return dev_err_probe(dev, ret, "Can't enable clocks\n"); + return ret; pctrl->desc.pctlops = &lpi_gpio_pinctrl_ops; pctrl->desc.pmxops = &lpi_gpio_pinmux_ops; @@ -542,7 +596,6 @@ int lpi_pinctrl_probe(struct platform_device *pdev) err_pinctrl: mutex_destroy(&pctrl->lock); - clk_bulk_disable_unprepare(MAX_LPI_NUM_CLKS, pctrl->clks); return ret; } @@ -554,7 +607,6 @@ void lpi_pinctrl_remove(struct platform_device *pdev) int i; mutex_destroy(&pctrl->lock); - clk_bulk_disable_unprepare(MAX_LPI_NUM_CLKS, pctrl->clks); for (i = 0; i < pctrl->data->npins; i++) pinctrl_generic_remove_group(pctrl->ctrl, i); -- 2.34.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-06-15 23:50 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-05-22 20:46 [PATCH v6 RESEND 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Ajay Kumar Nandam 2026-05-22 20:46 ` [PATCH v6 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs Ajay Kumar Nandam 2026-06-15 23:50 ` Dmitry Baryshkov 2026-05-22 20:46 ` [PATCH v6 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM Ajay Kumar Nandam 2026-06-09 23:12 ` Nathan Chancellor 2026-06-10 8:14 ` Ajay Kumar Nandam 2026-06-10 6:18 ` Krzysztof Kozlowski 2026-06-10 8:17 ` Ajay Kumar Nandam 2026-05-26 9:37 ` [PATCH v6 RESEND 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Linus Walleij 2026-06-15 15:54 ` Bartosz Golaszewski 2026-06-15 22:37 ` Linus Walleij 2026-06-08 8:47 ` Linus Walleij -- strict thread matches above, loose matches on Subject: below -- 2026-05-13 14:00 [PATCH v5 " Ajay Kumar Nandam 2026-05-22 20:33 ` [PATCH v6 " Ajay Kumar Nandam 2026-05-22 20:33 ` [PATCH v6 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM Ajay Kumar Nandam
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox