From: Armando De Leon <auribe84@gmail.com>
To: dmitry.torokhov@gmail.com
Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org,
Armando De Leon <learmand@amazon.com>
Subject: [PATCH] Input: gpio-keys - add hibernation support
Date: Mon, 6 Apr 2026 09:04:37 -0700 [thread overview]
Message-ID: <20260406160437.3084755-1-learmand@amazon.com> (raw)
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
next reply other threads:[~2026-04-06 16:08 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-06 16:04 Armando De Leon [this message]
2026-04-06 16:24 ` [PATCH] Input: gpio-keys - add hibernation support 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260406160437.3084755-1-learmand@amazon.com \
--to=auribe84@gmail.com \
--cc=dmitry.torokhov@gmail.com \
--cc=learmand@amazon.com \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox