[PATCH] gpio: rockchip: restore interrupt settings after hibernation
Igor Velkov via B4 Relay
devnull+iav.iav.lv at kernel.org
Fri Nov 6 21:55:00 PST 2026
From: Igor Velkov <iav at iav.lv>
Restore from hibernation follows a cold boot. The boot kernel probes
the GPIO banks, sets every interrupt enable bit, leaves the trigger of
each line it did not request at the reset value, and then hands over
to the image. The image restores only the interrupt masks, so a line
it had set up for both edges comes back with the reset trigger.
On ODROID-M1 the headphone detect line (GPIO0_B0) is requested for
both edges and is low with nothing plugged in. After a power loss in
hybrid sleep its reset trigger fires again as soon as the edge handler
acknowledges it, and the system does not come back. With this patch
the board resumed 4 of 4 times, without it 0 of 5.
Save the interrupt enable, type, polarity and both-edge registers with
the masks and write them back before unmasking. In a normal suspend
the bank keeps its registers, so this writes back what is already
there. For lines that emulate both edges on GPIO v1, take the polarity
from the current pin level.
Fixes: 936ee2675eee ("gpio/rockchip: add driver for rockchip gpio")
Cc: stable at vger.kernel.org
Signed-off-by: Igor Velkov <iav at iav.lv>
---
Tested on ODROID-M1 (RK3568, GPIO v2): hybrid sleep with power removed
during sleep 4/4, deep sleep 10/10. The GPIO v1 path was not tested on
hardware.
---
drivers/gpio/gpio-rockchip.c | 21 +++++++++++++++++++++
drivers/pinctrl/pinctrl-rockchip.h | 8 ++++++++
2 files changed, 29 insertions(+)
diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index 0f46ff095a24..83a5cc8f3fe6 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -489,6 +489,11 @@ static void rockchip_irq_suspend(struct irq_data *d)
struct rockchip_pin_bank *bank = gc->private;
bank->saved_masks = irq_reg_readl(gc, bank->gpio_regs->int_mask);
+ bank->saved_en = rockchip_gpio_readl(bank, bank->gpio_regs->int_en);
+ bank->saved_type = rockchip_gpio_readl(bank, bank->gpio_regs->int_type);
+ bank->saved_polarity = rockchip_gpio_readl(bank, bank->gpio_regs->int_polarity);
+ if (bank->gpio_type == GPIO_TYPE_V2)
+ bank->saved_bothedge = rockchip_gpio_readl(bank, bank->gpio_regs->int_bothedge);
irq_reg_writel(gc, ~gc->wake_active, bank->gpio_regs->int_mask);
}
@@ -496,7 +501,23 @@ static void rockchip_irq_resume(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct rockchip_pin_bank *bank = gc->private;
+ u32 polarity = bank->saved_polarity;
+
+ /*
+ * Restore from hibernation follows a cold boot: write the enables and
+ * the trigger back before we unmask.
+ */
+ if (bank->toggle_edge_mode) {
+ u32 data = readl(bank->reg_base + bank->gpio_regs->ext_port);
+ polarity &= ~bank->toggle_edge_mode;
+ polarity |= ~data & bank->toggle_edge_mode;
+ }
+ rockchip_gpio_writel(bank, bank->saved_en, bank->gpio_regs->int_en);
+ rockchip_gpio_writel(bank, bank->saved_type, bank->gpio_regs->int_type);
+ rockchip_gpio_writel(bank, polarity, bank->gpio_regs->int_polarity);
+ if (bank->gpio_type == GPIO_TYPE_V2)
+ rockchip_gpio_writel(bank, bank->saved_bothedge, bank->gpio_regs->int_bothedge);
irq_reg_writel(gc, bank->saved_masks, bank->gpio_regs->int_mask);
}
diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h
index 950097699643..ea280843fcb9 100644
--- a/drivers/pinctrl/pinctrl-rockchip.h
+++ b/drivers/pinctrl/pinctrl-rockchip.h
@@ -303,6 +303,10 @@ struct rockchip_drv {
* @db_clk: clock of the gpio debounce
* @irq: interrupt of the gpio bank
* @saved_masks: Saved content of GPIO_INTEN at suspend time.
+ * @saved_en: interrupt enables, saved at suspend time.
+ * @saved_type: interrupt level/edge type, saved at suspend time.
+ * @saved_polarity: interrupt polarity, saved at suspend time.
+ * @saved_bothedge: interrupt both-edge enables (GPIO v2), saved at suspend time.
* @pin_base: first pin number
* @nr_pins: number of pins in this bank
* @name: name of the bank
@@ -332,6 +336,10 @@ struct rockchip_pin_bank {
struct clk *db_clk;
int irq;
u32 saved_masks;
+ u32 saved_en;
+ u32 saved_type;
+ u32 saved_polarity;
+ u32 saved_bothedge;
u32 pin_base;
u8 nr_pins;
char *name;
---
base-commit: 0fa38ba784896f2fc32c9dacd33822f844b21906
change-id: 20261107-b4-gpio-rockchip-hib-705c3fd52b49
Best regards,
--
Igor Velkov <iav at iav.lv>
More information about the Linux-rockchip
mailing list