[PATCH] gpio: rockchip: restore interrupt settings after hibernation
Heiko Stuebner
heiko at sntech.de
Sat Nov 7 06:38:38 PST 2026
Am Samstag, 7. November 2026, 06:55:00 Mitteleuropäische Normalzeit schrieb Igor Velkov via B4 Relay:
> 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>
This looks sensible in general, but I wonder what happens with the other
registers of the gpio-controller here after hibernation?
Like does the direction + output value, debounce get restored from
some other means?
Heiko
> ---
> 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,
>
More information about the Linux-rockchip
mailing list