* [PATCH v3 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on remaining SoCs
2026-05-08 11:36 [PATCH v3 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Ajay Kumar Nandam
@ 2026-05-08 11:36 ` Ajay Kumar Nandam
2026-05-08 13:41 ` Konrad Dybcio
2026-05-13 12:48 ` Dmitry Baryshkov
2026-05-08 11:36 ` [PATCH v3 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM Ajay Kumar Nandam
` (3 subsequent siblings)
4 siblings, 2 replies; 16+ messages in thread
From: Ajay Kumar Nandam @ 2026-05-08 11:36 UTC (permalink / raw)
To: Bjorn Andersson, Linus Walleij; +Cc: linux-arm-msm, linux-gpio, linux-kernel
The LPASS LPI core conversion to PM clock framework relies on variant
drivers wiring runtime PM callbacks.
Hook up runtime PM callbacks for the remaining LPASS LPI variant
drivers so all SoCs using the common core get consistent pm_clk based
clock handling:
- milos
- sdm660
- sdm670
- sc8280xp
- sm4250
- sm6115
- sm8250
- sm8450
- sm8550
- sm8650
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).
Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
---
drivers/pinctrl/qcom/pinctrl-milos-lpass-lpi.c | 7 +++++++
drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c | 11 +++++++++--
drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c | 7 +++++++
drivers/pinctrl/qcom/pinctrl-sdm670-lpass-lpi.c | 7 +++++++
drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c | 7 +++++++
drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c | 7 +++++++
drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 11 +++++++++--
drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c | 11 +++++++++--
drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c | 11 +++++++++--
drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c | 11 +++++++++--
10 files changed, 80 insertions(+), 10 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-sc8280xp-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c
index 0e839b6aaaf4..1a61316c8c47 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"
@@ -173,10 +175,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-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-sm8250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c
index c27452eece3e..656f22da7dde 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"
@@ -134,10 +136,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-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..a79f99ec6df9 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"
@@ -202,10 +204,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-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..9037ef0020da 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"
@@ -210,10 +212,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-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..513ddc99dd37 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"
@@ -217,10 +219,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-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] 16+ messages in thread* Re: [PATCH v3 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on remaining SoCs
2026-05-08 11:36 ` [PATCH v3 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on remaining SoCs Ajay Kumar Nandam
@ 2026-05-08 13:41 ` Konrad Dybcio
2026-05-13 13:50 ` Ajay Kumar Nandam
2026-05-13 12:48 ` Dmitry Baryshkov
1 sibling, 1 reply; 16+ messages in thread
From: Konrad Dybcio @ 2026-05-08 13:41 UTC (permalink / raw)
To: Ajay Kumar Nandam, Bjorn Andersson, Linus Walleij
Cc: linux-arm-msm, linux-gpio, linux-kernel
On 5/8/26 1:36 PM, 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 remaining LPASS LPI variant
> drivers so all SoCs using the common core get consistent pm_clk based
> clock handling:
> - milos
> - sdm660
> - sdm670
> - sc8280xp
> - sm4250
> - sm6115
> - sm8250
> - sm8450
> - sm8550
> - sm8650
This list can be removed, as we can deduce it from the diffstat
easily
> 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.
Please mention that this commit alone is a preparatory NOP, since runtime
PM is currently disabled for those devices
> Runtime behavior was validated on Kodiak (sc7280).
>
> Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
> ---
Please remove the word remaining from the subject and commit message,
as it no longer matches
Konrad
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v3 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on remaining SoCs
2026-05-08 13:41 ` Konrad Dybcio
@ 2026-05-13 13:50 ` Ajay Kumar Nandam
0 siblings, 0 replies; 16+ messages in thread
From: Ajay Kumar Nandam @ 2026-05-13 13:50 UTC (permalink / raw)
To: Konrad Dybcio, Bjorn Andersson, Linus Walleij
Cc: linux-arm-msm, linux-gpio, linux-kernel
On 5/8/2026 7:11 PM, Konrad Dybcio wrote:
> On 5/8/26 1:36 PM, 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 remaining LPASS LPI variant
>> drivers so all SoCs using the common core get consistent pm_clk based
>> clock handling:
>> - milos
>> - sdm660
>> - sdm670
>> - sc8280xp
>> - sm4250
>> - sm6115
>> - sm8250
>> - sm8450
>> - sm8550
>> - sm8650
>
> This list can be removed, as we can deduce it from the diffstat
> easily
ACK , will remove in next version
>
>> 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.
>
> Please mention that this commit alone is a preparatory NOP, since runtime
> PM is currently disabled for those devices
>
>> Runtime behavior was validated on Kodiak (sc7280).
>>
>> Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
>> ---
>
> Please remove the word remaining from the subject and commit message,
> as it no longer matches
>
ACK, will update in next version
Thanks
Ajay Kumar
> Konrad
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v3 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on remaining SoCs
2026-05-08 11:36 ` [PATCH v3 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on remaining SoCs Ajay Kumar Nandam
2026-05-08 13:41 ` Konrad Dybcio
@ 2026-05-13 12:48 ` Dmitry Baryshkov
2026-05-13 13:55 ` Ajay Kumar Nandam
1 sibling, 1 reply; 16+ messages in thread
From: Dmitry Baryshkov @ 2026-05-13 12:48 UTC (permalink / raw)
To: Ajay Kumar Nandam
Cc: Bjorn Andersson, Linus Walleij, linux-arm-msm, linux-gpio,
linux-kernel
On Fri, May 08, 2026 at 05:06:35PM +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 remaining LPASS LPI variant
> drivers so all SoCs using the common core get consistent pm_clk based
> clock handling:
> - milos
> - sdm660
> - sdm670
> - sc8280xp
> - sm4250
> - sm6115
> - sm8250
> - sm8450
> - sm8550
> - sm8650
>
> 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).
>
> Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
> ---
> drivers/pinctrl/qcom/pinctrl-milos-lpass-lpi.c | 7 +++++++
> drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c | 11 +++++++++--
> drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c | 7 +++++++
> drivers/pinctrl/qcom/pinctrl-sdm670-lpass-lpi.c | 7 +++++++
> drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c | 7 +++++++
> drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c | 7 +++++++
> drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 11 +++++++++--
> drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c | 11 +++++++++--
> drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c | 11 +++++++++--
> drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c | 11 +++++++++--
> 10 files changed, 80 insertions(+), 10 deletions(-)
>
> @@ -173,10 +175,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-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),
Incorrect indentation
> },
> .probe = lpi_pinctrl_probe,
> .remove = lpi_pinctrl_remove,
> @@ -134,10 +136,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-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),
Incorrect indentation
> },
> .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..a79f99ec6df9 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"
>
> @@ -202,10 +204,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-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),
Incorrect indentation
> },
> .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..9037ef0020da 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"
>
> @@ -210,10 +212,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-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),
Incorrect indentation
> },
> .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..513ddc99dd37 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"
>
> @@ -217,10 +219,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-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),
Incorrect indentation
> },
> .probe = lpi_pinctrl_probe,
> .remove = lpi_pinctrl_remove,
> --
> 2.34.1
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v3 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on remaining SoCs
2026-05-13 12:48 ` Dmitry Baryshkov
@ 2026-05-13 13:55 ` Ajay Kumar Nandam
0 siblings, 0 replies; 16+ messages in thread
From: Ajay Kumar Nandam @ 2026-05-13 13:55 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Bjorn Andersson, Linus Walleij, linux-arm-msm, linux-gpio,
linux-kernel
On 5/13/2026 6:18 PM, Dmitry Baryshkov wrote:
> On Fri, May 08, 2026 at 05:06:35PM +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 remaining LPASS LPI variant
>> drivers so all SoCs using the common core get consistent pm_clk based
>> clock handling:
>> - milos
>> - sdm660
>> - sdm670
>> - sc8280xp
>> - sm4250
>> - sm6115
>> - sm8250
>> - sm8450
>> - sm8550
>> - sm8650
>>
>> 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).
>>
>> Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
>> ---
>> drivers/pinctrl/qcom/pinctrl-milos-lpass-lpi.c | 7 +++++++
>> drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c | 11 +++++++++--
>> drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c | 7 +++++++
>> drivers/pinctrl/qcom/pinctrl-sdm670-lpass-lpi.c | 7 +++++++
>> drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c | 7 +++++++
>> drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c | 7 +++++++
>> drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 11 +++++++++--
>> drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c | 11 +++++++++--
>> drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c | 11 +++++++++--
>> drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c | 11 +++++++++--
>> 10 files changed, 80 insertions(+), 10 deletions(-)
>>
>> @@ -173,10 +175,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-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),
>
> Incorrect indentation
>
>> },
>> .probe = lpi_pinctrl_probe,
>> .remove = lpi_pinctrl_remove,
>
>> @@ -134,10 +136,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-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),
>
> Incorrect indentation
ACK, fixed in V5.
>
>> },
>> .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..a79f99ec6df9 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"
>>
>> @@ -202,10 +204,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-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),
>
> Incorrect indentation
ACK, fixed in V5.
>
>> },
>> .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..9037ef0020da 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"
>>
>> @@ -210,10 +212,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-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),
>
> Incorrect indentation
ACK, fixed in V5.
>
>> },
>> .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..513ddc99dd37 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"
>>
>> @@ -217,10 +219,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-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),
>
> Incorrect indentation
ACK, fixed in V5.
Thanks
Ajay Kumar
>
>> },
>> .probe = lpi_pinctrl_probe,
>> .remove = lpi_pinctrl_remove,
>> --
>> 2.34.1
>>
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM
2026-05-08 11:36 [PATCH v3 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Ajay Kumar Nandam
2026-05-08 11:36 ` [PATCH v3 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on remaining SoCs Ajay Kumar Nandam
@ 2026-05-08 11:36 ` Ajay Kumar Nandam
2026-05-08 13:40 ` Konrad Dybcio
2026-05-13 12:25 ` [PATCH v4 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Ajay Kumar Nandam
` (2 subsequent siblings)
4 siblings, 1 reply; 16+ messages in thread
From: Ajay Kumar Nandam @ 2026-05-08 11:36 UTC (permalink / raw)
To: Bjorn Andersson, Linus Walleij; +Cc: linux-arm-msm, linux-gpio, linux-kernel
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.
Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
---
drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 109 +++++++++++++-----
.../pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c | 7 ++
2 files changed, 84 insertions(+), 32 deletions(-)
diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
index 15ced5027579..cd5dd18fd149 100644
--- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
@@ -15,6 +15,8 @@
#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 +24,6 @@
#define MAX_NR_GPIO 32
#define GPIO_FUNC 0
-#define MAX_LPI_NUM_CLKS 2
struct lpi_pinctrl {
struct device *dev;
@@ -31,7 +32,6 @@ 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);
@@ -39,29 +39,43 @@ struct lpi_pinctrl {
};
static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin,
- unsigned int addr)
+ unsigned int addr, u32 *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;
- return ioread32(state->tlmm_base + pin_offset + addr);
+ ret = pm_runtime_resume_and_get(state->dev);
+ if (ret < 0)
+ return ret;
+
+ *val = ioread32(state->tlmm_base + pin_offset + addr);
+ pm_runtime_put_autosuspend(state->dev);
+
+ return 0;
}
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);
+ pm_runtime_put_autosuspend(state->dev);
return 0;
}
@@ -107,8 +121,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 val, io_val;
+ int i, pin = g->pin, ret;
for (i = 0; i < g->nfuncs; i++) {
if (g->funcs[i] == function)
@@ -119,7 +133,9 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
return -EINVAL;
mutex_lock(&pctrl->lock);
- val = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG);
+ ret = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG, &val);
+ if (ret)
+ goto unlock;
/*
* If this is the first time muxing to GPIO and the direction is
@@ -129,24 +145,32 @@ 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);
+ ret = lpi_gpio_read(pctrl, group, LPI_GPIO_VALUE_REG, &io_val);
+ if (ret)
+ goto unlock;
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);
+ ret = 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);
+ ret = lpi_gpio_write(pctrl, group,
+ LPI_GPIO_VALUE_REG,
+ io_val & ~LPI_GPIO_VALUE_OUT_MASK);
}
+ if (ret)
+ goto unlock;
}
u32p_replace_bits(&val, i, LPI_GPIO_FUNCTION_MASK);
- lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val);
+ ret = lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val);
+
+unlock:
mutex_unlock(&pctrl->lock);
- return 0;
+ return ret;
}
static const struct pinmux_ops lpi_gpio_pinmux_ops = {
@@ -162,11 +186,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;
+ int ret;
int is_out;
int pull;
u32 ctl_reg;
- ctl_reg = lpi_gpio_read(state, pin, LPI_GPIO_CFG_REG);
+ ret = lpi_gpio_read(state, pin, LPI_GPIO_CFG_REG, &ctl_reg);
+ if (ret)
+ return ret;
+
is_out = ctl_reg & LPI_GPIO_OE_MASK;
pull = FIELD_GET(LPI_GPIO_PULL_MASK, ctl_reg);
@@ -206,7 +234,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 +253,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);
@@ -233,6 +265,7 @@ static int lpi_config_set_slew_rate(struct lpi_pinctrl *pctrl,
iowrite32(sval, reg);
mutex_unlock(&pctrl->lock);
+ pm_runtime_put_autosuspend(pctrl->dev);
return 0;
}
@@ -291,21 +324,27 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group,
*/
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);
+ ret = lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val);
+ if (ret)
+ return ret;
}
mutex_lock(&pctrl->lock);
- val = lpi_gpio_read(pctrl, group, LPI_GPIO_CFG_REG);
+ ret = lpi_gpio_read(pctrl, group, LPI_GPIO_CFG_REG, &val);
+ if (ret)
+ goto unlock;
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);
+ ret = lpi_gpio_write(pctrl, group, LPI_GPIO_CFG_REG, val);
+
+unlock:
mutex_unlock(&pctrl->lock);
- return 0;
+ return ret;
}
static const struct pinconf_ops lpi_gpio_pinconf_ops = {
@@ -354,9 +393,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;
- return lpi_gpio_read(state, pin, LPI_GPIO_VALUE_REG) &
- LPI_GPIO_VALUE_IN_MASK;
+ ret = lpi_gpio_read(state, pin, LPI_GPIO_VALUE_REG, &val);
+ if (ret)
+ return ret;
+
+ return val & LPI_GPIO_VALUE_IN_MASK;
}
static int lpi_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)
@@ -399,7 +443,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 +528,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 +540,17 @@ 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);
- if (ret)
- return dev_err_probe(dev, ret, "Can't enable clocks\n");
+ 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);
+ devm_pm_runtime_enable(dev);
pctrl->desc.pctlops = &lpi_gpio_pinctrl_ops;
pctrl->desc.pmxops = &lpi_gpio_pinmux_ops;
@@ -542,7 +589,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 +600,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);
diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c
index 750f410311a8..64a200dd8f41 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"
@@ -139,10 +141,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-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,
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v3 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM
2026-05-08 11:36 ` [PATCH v3 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM Ajay Kumar Nandam
@ 2026-05-08 13:40 ` Konrad Dybcio
2026-05-13 13:49 ` Ajay Kumar Nandam
0 siblings, 1 reply; 16+ messages in thread
From: Konrad Dybcio @ 2026-05-08 13:40 UTC (permalink / raw)
To: Ajay Kumar Nandam, Bjorn Andersson, Linus Walleij
Cc: linux-arm-msm, linux-gpio, linux-kernel
On 5/8/26 1:36 PM, 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.
>
> Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
> ---
[...]
> for (i = 0; i < g->nfuncs; i++) {
> if (g->funcs[i] == function)
> @@ -119,7 +133,9 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
> return -EINVAL;
>
> mutex_lock(&pctrl->lock);
> - val = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG);
> + ret = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG, &val);
> + if (ret)
> + goto unlock;
Please remove the mutex_unlock/goto calls and replace the
mutex_lock with guard(mutex)(&pctrl->lock) instead. This will use
the scoped cleanup mechanism and let you simply return directly,
shrinking the diff
[...]
> + pm_runtime_set_autosuspend_delay(dev, 100);
> + pm_runtime_use_autosuspend(dev);
> + devm_pm_runtime_enable(dev);
devm_pm_runtime_enable() can fail, please check its return code
nota bene pm_runtime_put_autosuspend() also can, but it's much less of
a problem
I gave this patchset a spin on 8280 CRD and seems to work fine, nice!
Konrad
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v3 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM
2026-05-08 13:40 ` Konrad Dybcio
@ 2026-05-13 13:49 ` Ajay Kumar Nandam
0 siblings, 0 replies; 16+ messages in thread
From: Ajay Kumar Nandam @ 2026-05-13 13:49 UTC (permalink / raw)
To: Konrad Dybcio, Bjorn Andersson, Linus Walleij
Cc: linux-arm-msm, linux-gpio, linux-kernel
On 5/8/2026 7:10 PM, Konrad Dybcio wrote:
> On 5/8/26 1:36 PM, 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.
>>
>> Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
>> ---
>
> [...]
>
>> for (i = 0; i < g->nfuncs; i++) {
>> if (g->funcs[i] == function)
>> @@ -119,7 +133,9 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
>> return -EINVAL;
>>
>> mutex_lock(&pctrl->lock);
>> - val = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG);
>> + ret = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG, &val);
>> + if (ret)
>> + goto unlock;
>
> Please remove the mutex_unlock/goto calls and replace the
> mutex_lock with guard(mutex)(&pctrl->lock) instead. This will use
> the scoped cleanup mechanism and let you simply return directly,
> shrinking the diff
ACK, will update in next version.
>
> [...]
>
>> + pm_runtime_set_autosuspend_delay(dev, 100);
>> + pm_runtime_use_autosuspend(dev);
>> + devm_pm_runtime_enable(dev);
>
> devm_pm_runtime_enable() can fail, please check its return code
>
> nota bene pm_runtime_put_autosuspend() also can, but it's much less of
> a problem
ACK, will update in next version
Thanks
Ajay Kumar Nandam
>
> I gave this patchset a spin on 8280 CRD and seems to work fine, nice!
>
> Konrad
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v4 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework
2026-05-08 11:36 [PATCH v3 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Ajay Kumar Nandam
2026-05-08 11:36 ` [PATCH v3 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on remaining SoCs Ajay Kumar Nandam
2026-05-08 11:36 ` [PATCH v3 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM Ajay Kumar Nandam
@ 2026-05-13 12:25 ` Ajay Kumar Nandam
2026-05-13 12:25 ` [PATCH v4 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs Ajay Kumar Nandam
2026-05-13 12:25 ` [PATCH v4 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM Ajay Kumar Nandam
4 siblings, 0 replies; 16+ messages in thread
From: Ajay Kumar Nandam @ 2026-05-13 12:25 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 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.
---
v3: https://lore.kernel.org/r/20260508113636.3561383-1-ajay.nandam@oss.qualcomm.com
Link: https://lore.kernel.org/r/20260508113636.3561383-1-ajay.nandam@oss.qualcomm.com
Changes since v3:
- Clarified patch 1 commit message scope to the LPASS LPI variants
updated in patch 1.
- Explicitly documented patch 1 as a preparatory NOP until patch 2
enables runtime PM in the shared core.
- Called out sc7280 PM-ops wiring in patch 2 to avoid ordering
ambiguity in patch 1.
- Updated patch 2 to use scoped locking (`guard(mutex)`) in shared-core
register programming paths.
- Updated patch 2 to propagate fallible runtime-PM calls
(`pm_runtime_put_autosuspend()` / `devm_pm_runtime_enable()`).
v2: https://lore.kernel.org/all/20260420123135.350446-1-ajay.nandam@oss.qualcomm.com/
v1: https://lore.kernel.org/r/20260413122233.375945-1-ajay.nandam@oss.qualcomm.com
Changes since v2:
- Reordered for bisect safety so per-variant PM-ops wiring lands before
shared core conversion.
- Dropped the standalone "Resume clocks for GPIO access" patch and folded
that behavior into the core conversion patch.
- Added preparatory PM-ops wiring in patch 1 for
milos/sdm660/sdm670 variants.
- Updated patch 1 message to remove explicit SoC list, drop "remaining"
wording, and state that patch 1 is a preparatory NOP by itself.
- Updated patch 2 per review to use scoped locking and to handle fallible
devm_pm_runtime_enable().
- Rebased on latest linux-next.
Testing:
- Runtime behavior validated on Kodiak (sc7280).
- Wider runtime testing on other LPASS LPI variants is welcome.
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 | 81 ++++++++++-------
.../pinctrl/qcom/pinctrl-milos-lpass-lpi.c | 7 ++
.../pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c | 7 ++
.../pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c | 11 +-
.../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 | 11 +-
.../pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c | 11 +-
.../pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c | 11 +-
.../pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c | 11 +-
12 files changed, 168 insertions(+), 47 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v4 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs
2026-05-08 11:36 [PATCH v3 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Ajay Kumar Nandam
` (2 preceding siblings ...)
2026-05-13 12:25 ` [PATCH v4 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Ajay Kumar Nandam
@ 2026-05-13 12:25 ` Ajay Kumar Nandam
2026-05-13 12:51 ` Dmitry Baryshkov
2026-05-13 12:25 ` [PATCH v4 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM Ajay Kumar Nandam
4 siblings, 1 reply; 16+ messages in thread
From: Ajay Kumar Nandam @ 2026-05-13 12:25 UTC (permalink / raw)
To: Bjorn Andersson, Linus Walleij
Cc: linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik,
ajay.nandam
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.
sc7280 wiring is completed in the following patch.
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).
Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
---
drivers/pinctrl/qcom/pinctrl-milos-lpass-lpi.c | 7 +++++++
drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c | 11 +++++++++--
drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c | 7 +++++++
drivers/pinctrl/qcom/pinctrl-sdm670-lpass-lpi.c | 7 +++++++
drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c | 7 +++++++
drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c | 7 +++++++
drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 11 +++++++++--
drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c | 11 +++++++++--
drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c | 11 +++++++++--
drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c | 11 +++++++++--
10 files changed, 80 insertions(+), 10 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-sc8280xp-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c
index 0e839b6aaaf4..1a61316c8c47 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"
@@ -173,10 +175,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-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-sm8250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c
index c27452eece3e..656f22da7dde 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"
@@ -134,10 +136,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-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..a79f99ec6df9 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"
@@ -202,10 +204,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-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..9037ef0020da 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"
@@ -210,10 +212,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-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..513ddc99dd37 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"
@@ -217,10 +219,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-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] 16+ messages in thread* Re: [PATCH v4 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs
2026-05-13 12:25 ` [PATCH v4 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs Ajay Kumar Nandam
@ 2026-05-13 12:51 ` Dmitry Baryshkov
2026-05-13 13:53 ` Ajay Kumar Nandam
0 siblings, 1 reply; 16+ messages in thread
From: Dmitry Baryshkov @ 2026-05-13 12:51 UTC (permalink / raw)
To: Ajay Kumar Nandam
Cc: Bjorn Andersson, Linus Walleij, linux-arm-msm, linux-gpio,
linux-kernel, mohammad.rafi.shaik
On Wed, May 13, 2026 at 05:55:25PM +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.
> sc7280 wiring is completed in the following patch.
>
> 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).
>
> Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
> ---
> drivers/pinctrl/qcom/pinctrl-milos-lpass-lpi.c | 7 +++++++
> drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c | 11 +++++++++--
> drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c | 7 +++++++
> drivers/pinctrl/qcom/pinctrl-sdm670-lpass-lpi.c | 7 +++++++
> drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c | 7 +++++++
> drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c | 7 +++++++
> drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 11 +++++++++--
> drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c | 11 +++++++++--
> drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c | 11 +++++++++--
> drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c | 11 +++++++++--
> 10 files changed, 80 insertions(+), 10 deletions(-)
Please don't send new iterations of the patches in reply to the previous
thread. You also didn't send the cover letter, making it harder to
track the changes. Please switch to the b4 tool.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v4 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs
2026-05-13 12:51 ` Dmitry Baryshkov
@ 2026-05-13 13:53 ` Ajay Kumar Nandam
0 siblings, 0 replies; 16+ messages in thread
From: Ajay Kumar Nandam @ 2026-05-13 13:53 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Bjorn Andersson, Linus Walleij, linux-arm-msm, linux-gpio,
linux-kernel, mohammad.rafi.shaik
On 5/13/2026 6:21 PM, Dmitry Baryshkov wrote:
> On Wed, May 13, 2026 at 05:55:25PM +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.
>> sc7280 wiring is completed in the following patch.
>>
>> 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).
>>
>> Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
>> ---
>> drivers/pinctrl/qcom/pinctrl-milos-lpass-lpi.c | 7 +++++++
>> drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c | 11 +++++++++--
>> drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c | 7 +++++++
>> drivers/pinctrl/qcom/pinctrl-sdm670-lpass-lpi.c | 7 +++++++
>> drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c | 7 +++++++
>> drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c | 7 +++++++
>> drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c | 11 +++++++++--
>> drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c | 11 +++++++++--
>> drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c | 11 +++++++++--
>> drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c | 11 +++++++++--
>> 10 files changed, 80 insertions(+), 10 deletions(-)
>
> Please don't send new iterations of the patches in reply to the previous
> thread. You also didn't send the cover letter, making it harder to
> track the changes. Please switch to the b4 tool.
>
Thanks for pointing this out.
I resent as a proper standalone v5 series with a 0/2 cover letter;
Thanks
Ajay Kumar
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v4 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM
2026-05-08 11:36 [PATCH v3 0/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework Ajay Kumar Nandam
` (3 preceding siblings ...)
2026-05-13 12:25 ` [PATCH v4 1/2] pinctrl: qcom: lpass-lpi: Enable runtime PM hooks on LPASS LPI SoCs Ajay Kumar Nandam
@ 2026-05-13 12:25 ` Ajay Kumar Nandam
2026-05-13 12:52 ` Dmitry Baryshkov
4 siblings, 1 reply; 16+ messages in thread
From: Ajay Kumar Nandam @ 2026-05-13 12:25 UTC (permalink / raw)
To: Bjorn Andersson, Linus Walleij
Cc: linux-arm-msm, linux-gpio, linux-kernel, mohammad.rafi.shaik,
ajay.nandam
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.
Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
---
drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 118 ++++++++++++------
.../pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c | 7 ++
2 files changed, 88 insertions(+), 37 deletions(-)
diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
index 15ced5027579..d95e28926d38 100644
--- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
@@ -15,6 +15,9 @@
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinmux.h>
+#include <linux/cleanup.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,7 +33,6 @@ 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);
@@ -39,29 +40,47 @@ struct lpi_pinctrl {
};
static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin,
- unsigned int addr)
+ unsigned int addr, u32 *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;
- return ioread32(state->tlmm_base + pin_offset + addr);
+ ret = pm_runtime_resume_and_get(state->dev);
+ if (ret < 0)
+ return ret;
+
+ *val = ioread32(state->tlmm_base + pin_offset + addr);
+ ret = pm_runtime_put_autosuspend(state->dev);
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
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);
+ ret = pm_runtime_put_autosuspend(state->dev);
+ if (ret < 0)
+ return ret;
return 0;
}
@@ -107,8 +126,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 val, io_val;
+ int i, pin = g->pin, ret;
for (i = 0; i < g->nfuncs; i++) {
if (g->funcs[i] == function)
@@ -118,8 +137,10 @@ 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);
+ guard(mutex)(&pctrl->lock);
+ ret = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG, &val);
+ if (ret)
+ return ret;
/*
* If this is the first time muxing to GPIO and the direction is
@@ -129,24 +150,27 @@ 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);
+ ret = lpi_gpio_read(pctrl, group, LPI_GPIO_VALUE_REG, &io_val);
+ if (ret)
+ return ret;
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);
+ ret = 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);
+ ret = lpi_gpio_write(pctrl, group,
+ LPI_GPIO_VALUE_REG,
+ io_val & ~LPI_GPIO_VALUE_OUT_MASK);
}
+ if (ret)
+ return ret;
}
u32p_replace_bits(&val, i, LPI_GPIO_FUNCTION_MASK);
- lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val);
- mutex_unlock(&pctrl->lock);
-
- return 0;
+ return lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val);
}
static const struct pinmux_ops lpi_gpio_pinmux_ops = {
@@ -162,11 +186,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;
+ int ret;
int is_out;
int pull;
u32 ctl_reg;
- ctl_reg = lpi_gpio_read(state, pin, LPI_GPIO_CFG_REG);
+ ret = lpi_gpio_read(state, pin, LPI_GPIO_CFG_REG, &ctl_reg);
+ if (ret)
+ return ret;
+
is_out = ctl_reg & LPI_GPIO_OE_MASK;
pull = FIELD_GET(LPI_GPIO_PULL_MASK, ctl_reg);
@@ -206,7 +234,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 +253,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);
@@ -233,6 +265,9 @@ static int lpi_config_set_slew_rate(struct lpi_pinctrl *pctrl,
iowrite32(sval, reg);
mutex_unlock(&pctrl->lock);
+ ret = pm_runtime_put_autosuspend(pctrl->dev);
+ if (ret < 0)
+ return ret;
return 0;
}
@@ -291,21 +326,22 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group,
*/
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);
+ ret = lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val);
+ if (ret)
+ return ret;
}
- mutex_lock(&pctrl->lock);
- val = lpi_gpio_read(pctrl, group, LPI_GPIO_CFG_REG);
+ guard(mutex)(&pctrl->lock);
+ ret = lpi_gpio_read(pctrl, group, LPI_GPIO_CFG_REG, &val);
+ if (ret)
+ return ret;
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);
-
- return 0;
+ return lpi_gpio_write(pctrl, group, LPI_GPIO_CFG_REG, val);
}
static const struct pinconf_ops lpi_gpio_pinconf_ops = {
@@ -354,9 +390,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 +440,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 +525,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 +537,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 +588,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 +599,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);
diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c
index 750f410311a8..64a200dd8f41 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"
@@ -139,10 +141,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-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,
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v4 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM
2026-05-13 12:25 ` [PATCH v4 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM Ajay Kumar Nandam
@ 2026-05-13 12:52 ` Dmitry Baryshkov
2026-05-13 13:53 ` Ajay Kumar Nandam
0 siblings, 1 reply; 16+ messages in thread
From: Dmitry Baryshkov @ 2026-05-13 12:52 UTC (permalink / raw)
To: Ajay Kumar Nandam
Cc: Bjorn Andersson, Linus Walleij, linux-arm-msm, linux-gpio,
linux-kernel, mohammad.rafi.shaik
On Wed, May 13, 2026 at 05:55:26PM +0530, 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.
>
> Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
> ---
> drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 118 ++++++++++++------
> .../pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c | 7 ++
> 2 files changed, 88 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
> index 15ced5027579..d95e28926d38 100644
> --- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
> +++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
> @@ -15,6 +15,9 @@
> #include <linux/pinctrl/pinconf-generic.h>
> #include <linux/pinctrl/pinconf.h>
> #include <linux/pinctrl/pinmux.h>
> +#include <linux/cleanup.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,7 +33,6 @@ 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);
> @@ -39,29 +40,47 @@ struct lpi_pinctrl {
> };
>
> static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin,
> - unsigned int addr)
> + unsigned int addr, u32 *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;
>
> - return ioread32(state->tlmm_base + pin_offset + addr);
> + ret = pm_runtime_resume_and_get(state->dev);
> + if (ret < 0)
> + return ret;
> +
> + *val = ioread32(state->tlmm_base + pin_offset + addr);
> + ret = pm_runtime_put_autosuspend(state->dev);
> + if (ret < 0)
> + return ret;
> +
> + return 0;
Just `return pm_runtime_put_autosuspend(state->dev)`, no need for extra
ifs.
> }
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v4 2/2] pinctrl: qcom: lpass-lpi: Switch to PM clock framework for runtime PM
2026-05-13 12:52 ` Dmitry Baryshkov
@ 2026-05-13 13:53 ` Ajay Kumar Nandam
0 siblings, 0 replies; 16+ messages in thread
From: Ajay Kumar Nandam @ 2026-05-13 13:53 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Bjorn Andersson, Linus Walleij, linux-arm-msm, linux-gpio,
linux-kernel, mohammad.rafi.shaik
On 5/13/2026 6:22 PM, Dmitry Baryshkov wrote:
> On Wed, May 13, 2026 at 05:55:26PM +0530, 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.
>>
>> Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
>> ---
>> drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 118 ++++++++++++------
>> .../pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c | 7 ++
>> 2 files changed, 88 insertions(+), 37 deletions(-)
>>
>> diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
>> index 15ced5027579..d95e28926d38 100644
>> --- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
>> +++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
>> @@ -15,6 +15,9 @@
>> #include <linux/pinctrl/pinconf-generic.h>
>> #include <linux/pinctrl/pinconf.h>
>> #include <linux/pinctrl/pinmux.h>
>> +#include <linux/cleanup.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,7 +33,6 @@ 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);
>> @@ -39,29 +40,47 @@ struct lpi_pinctrl {
>> };
>>
>> static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin,
>> - unsigned int addr)
>> + unsigned int addr, u32 *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;
>>
>> - return ioread32(state->tlmm_base + pin_offset + addr);
>> + ret = pm_runtime_resume_and_get(state->dev);
>> + if (ret < 0)
>> + return ret;
>> +
>> + *val = ioread32(state->tlmm_base + pin_offset + addr);
>> + ret = pm_runtime_put_autosuspend(state->dev);
>> + if (ret < 0)
>> + return ret;
>> +
>> + return 0;
>
> Just `return pm_runtime_put_autosuspend(state->dev)`, no need for extra
> ifs.
>
ACK, Addressed in V5.
Thanks
Ajay Kumar
>> }
>>
>
^ permalink raw reply [flat|nested] 16+ messages in thread