From: Heiko Stuebner <heiko@sntech.de>
To: Linus Walleij <linusw@kernel.org>,
Bartosz Golaszewski <brgl@kernel.org>,
iav@iav.lv
Cc: Jianqun Xu <jay.xu@rock-chips.com>,
linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-rockchip@lists.infradead.org, linux-kernel@vger.kernel.org,
Igor Velkov <iav@iav.lv>,
stable@vger.kernel.org
Subject: Re: [PATCH] gpio: rockchip: restore interrupt settings after hibernation
Date: Sat, 07 Nov 2026 15:38:38 +0100 [thread overview]
Message-ID: <9970336.2WqB4rESCP@phil> (raw)
In-Reply-To: <20261107-b4-gpio-rockchip-hib-v1-1-19f4d163a55e@iav.lv>
Am Samstag, 7. November 2026, 06:55:00 Mitteleuropäische Normalzeit schrieb Igor Velkov via B4 Relay:
> From: Igor Velkov <iav@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@vger.kernel.org
> Signed-off-by: Igor Velkov <iav@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,
>
WARNING: multiple messages have this Message-ID (diff)
From: Heiko Stuebner <heiko@sntech.de>
To: Linus Walleij <linusw@kernel.org>,
Bartosz Golaszewski <brgl@kernel.org>,
iav@iav.lv
Cc: Jianqun Xu <jay.xu@rock-chips.com>,
linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-rockchip@lists.infradead.org, linux-kernel@vger.kernel.org,
Igor Velkov <iav@iav.lv>,
stable@vger.kernel.org
Subject: Re: [PATCH] gpio: rockchip: restore interrupt settings after hibernation
Date: Sat, 07 Nov 2026 15:38:38 +0100 [thread overview]
Message-ID: <9970336.2WqB4rESCP@phil> (raw)
In-Reply-To: <20261107-b4-gpio-rockchip-hib-v1-1-19f4d163a55e@iav.lv>
Am Samstag, 7. November 2026, 06:55:00 Mitteleuropäische Normalzeit schrieb Igor Velkov via B4 Relay:
> From: Igor Velkov <iav@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@vger.kernel.org
> Signed-off-by: Igor Velkov <iav@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,
>
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
next prev parent reply other threads:[~2026-11-07 14:38 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-07 5:55 [PATCH] gpio: rockchip: restore interrupt settings after hibernation Igor Velkov
2026-11-07 5:55 ` Igor Velkov via B4 Relay
2026-11-07 5:55 ` Igor Velkov via B4 Relay
2026-11-07 6:09 ` sashiko-bot
2026-11-07 14:38 ` Heiko Stuebner [this message]
2026-11-07 14:38 ` Heiko Stuebner
2026-11-08 5:27 ` Igor Velkov
2026-11-08 5:27 ` Igor Velkov
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=9970336.2WqB4rESCP@phil \
--to=heiko@sntech.de \
--cc=brgl@kernel.org \
--cc=iav@iav.lv \
--cc=jay.xu@rock-chips.com \
--cc=linusw@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rockchip@lists.infradead.org \
--cc=stable@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.