irqchip/renesas-rzv2h: Add suspend/resume support

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
This commit is contained in:
Biju Das 2026-01-13 12:53:12 +00:00 committed by Thomas Gleixner
parent a384f2ed88
commit 3a74e73b86

View 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
@ -89,6 +90,18 @@
#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.