public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Input: gpio-keys - add hibernation support
@ 2026-04-06 16:04 Armando De Leon
  2026-04-06 16:24 ` Dmitry Torokhov
  0 siblings, 1 reply; 6+ messages in thread
From: Armando De Leon @ 2026-04-06 16:04 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: linux-input, linux-kernel, Armando De Leon

The gpio-keys driver uses DEFINE_SIMPLE_DEV_PM_OPS which maps .freeze
and .restore to the same callbacks as .suspend and .resume. This is
insufficient for hibernation (suspend-to-disk) because the SoC is fully
powered off, unlike suspend-to-RAM where hardware state is preserved.

After hibernation resume, GPIO keys fail to function correctly because
the interrupt controller (e.g. GIC) is fully re-initialized during
restore, resetting all IRQ trigger type configurations to defaults.
GPIO keys require IRQ_TYPE_EDGE_BOTH for proper press/release detection,
but after the interrupt controller re-initialization only a single edge
remains active. This causes buttons to report only release events but
not press events, or vice versa.

The existing gpio_keys_button_disable_wakeup() does restore
IRQ_TYPE_EDGE_BOTH, but only when wakeup_trigger_type is non-zero.
When the device tree does not specify wakeup-event-action (the common
case), wakeup_trigger_type defaults to zero and the IRQ type
restoration is skipped entirely.

Fix this by implementing dedicated .freeze and .restore callbacks:

- gpio_keys_freeze(): Marks all buttons as suspended before the
  hibernate image is created. Unlike .suspend, it does not configure
  wakeup IRQs since the SoC will be powered off.

- gpio_keys_restore(): Re-applies the pinctrl default state to restore
  GPIO pin configuration, explicitly reconfigures IRQ trigger type to
  IRQ_TYPE_EDGE_BOTH for all GPIO-backed buttons, clears the suspended
  flag, and re-syncs current GPIO state with the input subsystem.

The .thaw callback reuses gpio_keys_resume() since the SoC remains
powered when hibernation is aborted and hardware state is intact.

Signed-off-by: Armando De Leon <learmand@amazon.com>
---
 drivers/input/keyboard/gpio_keys.c | 60 +++++++++++++++++++++++++++++-
 1 file changed, 59 insertions(+), 1 deletion(-)

diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index e19617485..9fb77c9aa 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -27,6 +27,7 @@
 #include <linux/gpio/consumer.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/spinlock.h>
 #include <dt-bindings/input/gpio-keys.h>
 
@@ -1088,7 +1089,64 @@ static int gpio_keys_resume(struct device *dev)
 	return 0;
 }
 
-static DEFINE_SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
+static int gpio_keys_freeze(struct device *dev)
+{
+	struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
+	struct gpio_button_data *bdata;
+	int i;
+
+	for (i = 0; i < ddata->pdata->nbuttons; i++) {
+		bdata = &ddata->data[i];
+		bdata->suspended = true;
+	}
+
+	return 0;
+}
+
+static int gpio_keys_restore(struct device *dev)
+{
+	struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
+	struct gpio_button_data *bdata;
+	int error;
+	int i;
+
+	error = pinctrl_pm_select_default_state(dev);
+	if (error)
+		dev_warn(dev, "failed to restore pinctrl default state: %d\n",
+			 error);
+
+	for (i = 0; i < ddata->pdata->nbuttons; i++) {
+		bdata = &ddata->data[i];
+		bdata->suspended = false;
+
+		/*
+		 * After hibernation the interrupt controller is
+		 * re-initialized and loses its configuration.
+		 * Restore dual-edge triggering for GPIO-backed
+		 * buttons so both press and release are detected.
+		 */
+		if (bdata->gpiod) {
+			error = irq_set_irq_type(bdata->irq,
+						 IRQ_TYPE_EDGE_BOTH);
+			if (error)
+				dev_warn(dev,
+					 "failed to restore IRQ %d trigger: %d\n",
+					 bdata->irq, error);
+		}
+	}
+
+	gpio_keys_report_state(ddata);
+	return 0;
+}
+
+static const struct dev_pm_ops gpio_keys_pm_ops = {
+	.suspend	= gpio_keys_suspend,
+	.resume		= gpio_keys_resume,
+	.freeze		= gpio_keys_freeze,
+	.restore	= gpio_keys_restore,
+	.thaw		= gpio_keys_resume,
+	.poweroff	= gpio_keys_suspend,
+};
 
 static void gpio_keys_shutdown(struct platform_device *pdev)
 {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-04-07  4:31 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-06 16:04 [PATCH] Input: gpio-keys - add hibernation support Armando De Leon
2026-04-06 16:24 ` Dmitry Torokhov
2026-04-06 16:58   ` Armando De Leon
2026-04-06 18:18     ` Dmitry Torokhov
2026-04-06 20:39   ` Armando De Leon
2026-04-07  4:31     ` Dmitry Torokhov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox