]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
irqchip/renesas-rzv2h: Add suspend/resume support
authorBiju Das <biju.das.jz@bp.renesas.com>
Tue, 13 Jan 2026 12:53:12 +0000 (12:53 +0000)
committerThomas Gleixner <tglx@kernel.org>
Sun, 18 Jan 2026 13:39:18 +0000 (14:39 +0100)
On RZ/G3E using PSCI, s2ram powers down the SoC. Add suspend/resume
callbacks to restore IRQ type for NMI, TINT and external IRQ interrupts.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260113125315.359967-3-biju.das.jz@bp.renesas.com
drivers/irqchip/irq-renesas-rzv2h.c

index 0c44b6109842a6d2ffecf91d336a3aa629e2f0d5..69980a8ecccc00ad8846e03d12fca3e491488d62 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/reset.h>
 #include <linux/spinlock.h>
+#include <linux/syscore_ops.h>
 
 /* DT "interrupts" indexes */
 #define ICU_IRQ_START                          1
 #define ICU_RZG3E_TSSEL_MAX_VAL                        0x8c
 #define ICU_RZV2H_TSSEL_MAX_VAL                        0x55
 
+/**
+ * struct rzv2h_irqc_reg_cache - registers cache (necessary for suspend/resume)
+ * @nitsr: ICU_NITSR register
+ * @iitsr: ICU_IITSR register
+ * @titsr: ICU_TITSR registers
+ */
+struct rzv2h_irqc_reg_cache {
+       u32     nitsr;
+       u32     iitsr;
+       u32     titsr[2];
+};
+
 /**
  * struct rzv2h_hw_info - Interrupt Control Unit controller hardware info structure.
  * @tssel_lut:         TINT lookup table
@@ -118,13 +131,15 @@ struct rzv2h_hw_info {
  * @fwspec:    IRQ firmware specific data
  * @lock:      Lock to serialize access to hardware registers
  * @info:      Pointer to struct rzv2h_hw_info
+ * @cache:     Registers cache for suspend/resume
  */
-struct rzv2h_icu_priv {
+static struct rzv2h_icu_priv {
        void __iomem                    *base;
        struct irq_fwspec               fwspec[ICU_NUM_IRQ];
        raw_spinlock_t                  lock;
        const struct rzv2h_hw_info      *info;
-};
+       struct rzv2h_irqc_reg_cache     cache;
+} *rzv2h_icu_data;
 
 void rzv2h_icu_register_dma_req(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel,
                                u16 req_no)
@@ -412,6 +427,44 @@ static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type)
        return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
 }
 
+static int rzv2h_irqc_irq_suspend(void *data)
+{
+       struct rzv2h_irqc_reg_cache *cache = &rzv2h_icu_data->cache;
+       void __iomem *base = rzv2h_icu_data->base;
+
+       cache->nitsr = readl_relaxed(base + ICU_NITSR);
+       cache->iitsr = readl_relaxed(base + ICU_IITSR);
+       for (unsigned int i = 0; i < 2; i++)
+               cache->titsr[i] = readl_relaxed(base + rzv2h_icu_data->info->t_offs + ICU_TITSR(i));
+
+       return 0;
+}
+
+static void rzv2h_irqc_irq_resume(void *data)
+{
+       struct rzv2h_irqc_reg_cache *cache = &rzv2h_icu_data->cache;
+       void __iomem *base = rzv2h_icu_data->base;
+
+       /*
+        * Restore only interrupt type. TSSRx will be restored at the
+        * request of pin controller to avoid spurious interrupts due
+        * to invalid PIN states.
+        */
+       for (unsigned int i = 0; i < 2; i++)
+               writel_relaxed(cache->titsr[i], base + rzv2h_icu_data->info->t_offs + ICU_TITSR(i));
+       writel_relaxed(cache->iitsr, base + ICU_IITSR);
+       writel_relaxed(cache->nitsr, base + ICU_NITSR);
+}
+
+static const struct syscore_ops rzv2h_irqc_syscore_ops = {
+       .suspend        = rzv2h_irqc_irq_suspend,
+       .resume         = rzv2h_irqc_irq_resume,
+};
+
+static struct syscore rzv2h_irqc_syscore = {
+       .ops = &rzv2h_irqc_syscore_ops,
+};
+
 static const struct irq_chip rzv2h_icu_chip = {
        .name                   = "rzv2h-icu",
        .irq_eoi                = rzv2h_icu_eoi,
@@ -495,7 +548,6 @@ static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no
 {
        struct irq_domain *irq_domain, *parent_domain;
        struct device_node *node = pdev->dev.of_node;
-       struct rzv2h_icu_priv *rzv2h_icu_data;
        struct reset_control *resetn;
        int ret;
 
@@ -553,6 +605,8 @@ static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no
 
        rzv2h_icu_data->info = hw_info;
 
+       register_syscore(&rzv2h_irqc_syscore);
+
        /*
         * coccicheck complains about a missing put_device call before returning, but it's a false
         * positive. We still need &pdev->dev after successfully returning from this function.