[PATCH 2/2] pps: clients: gpio: release pins to idle state on remove and shutdown

From: Eliav Farber

Date: Wed Sep 16 2026 - 10:01:43 EST


Some boards route the PPS input GPIO through a pin controller and mux it
to another function when the pps-gpio driver is not bound. The driver core
already applies the "default" pinctrl state before probe, so the pins are
muxed for GPIO/PPS use while the driver is bound without any driver change.

Nothing, however, hands the pins back when the driver is unbound or the
system is shut down. Select the "idle" pinctrl state in both remove() and
shutdown() so a board can describe the alternate mux there and have it
restored, for example before kexec.

pinctrl_pm_select_idle_state() is a no-op for devices that have no pin
controller or no "idle" state, so boards that do not use this are
unaffected. The "idle" state is only looked up and selectable when
CONFIG_PM is enabled; without CONFIG_PM the helper compiles to a no-op and
the pins simply retain their "default" mux.

Signed-off-by: Eliav Farber <farbere@xxxxxxxxxx>
---
drivers/pps/clients/pps-gpio.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)

diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c
index 73ec2c7335e5..bdedbed82d82 100644
--- a/drivers/pps/clients/pps-gpio.c
+++ b/drivers/pps/clients/pps-gpio.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/pps_kernel.h>
#include <linux/gpio/consumer.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/list.h>
#include <linux/property.h>
#include <linux/timer.h>
@@ -216,9 +217,26 @@ static void pps_gpio_remove(struct platform_device *pdev)
timer_delete_sync(&data->echo_timer);
/* reset echo pin in any case */
gpiod_set_value(data->echo_pin, 0);
+ /*
+ * Release the pins to their "idle" state, if the board defines one, so
+ * they are handed back to whatever function uses them while pps-gpio is
+ * not bound. Boards that do not describe an idle pinctrl state are
+ * unaffected. The "default" (active) state is applied automatically by
+ * the driver core before probe.
+ */
+ pinctrl_pm_select_idle_state(&pdev->dev);
dev_info(&pdev->dev, "removed IRQ %d as PPS source\n", data->irq);
}

+static void pps_gpio_shutdown(struct platform_device *pdev)
+{
+ /*
+ * Leave the pins in their "idle" state on shutdown so a subsequent
+ * kernel (e.g. after kexec) finds the pin controller in a known state.
+ */
+ pinctrl_pm_select_idle_state(&pdev->dev);
+}
+
static const struct of_device_id pps_gpio_dt_ids[] = {
{ .compatible = "pps-gpio", },
{ /* sentinel */ }
@@ -228,6 +246,7 @@ MODULE_DEVICE_TABLE(of, pps_gpio_dt_ids);
static struct platform_driver pps_gpio_driver = {
.probe = pps_gpio_probe,
.remove = pps_gpio_remove,
+ .shutdown = pps_gpio_shutdown,
.driver = {
.name = PPS_GPIO_NAME,
.of_match_table = pps_gpio_dt_ids,
--
2.47.3