[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