Hi Fabrizio, On Thu, Oct 10, 2024 at 1:08 AM Fabrizio Castro <fabrizio.castro.jz@xxxxxxxxxxx> wrote: > Add driver for the Renesas RZ/V2H(P) Interrupt Control Unit (ICU). > > This driver supports the external interrupts NMI, IRQn, and TINTn. > > Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@xxxxxxxxxxx> > --- > > v2->v3: > * Reworked line breaks > * Improved performance of rzv2h_icu_eoi > * Replaced raw_spin_lock with guards > * Improved the style of rzv2h_icu_domain_ops > * Removed put_device from the successful path of rzv2h_icu_init Thanks for the update! > --- /dev/null > +++ b/drivers/irqchip/irq-renesas-rzv2h.c > +static void rzv2h_clear_irq_int(struct rzv2h_icu_priv *priv, unsigned int hwirq) > +{ > + unsigned int irq_nr = hwirq - ICU_IRQ_START; > + u32 isctr, iitsr, iitsel; > + u32 bit = BIT(irq_nr); > + > + isctr = readl_relaxed(priv->base + ICU_ISCTR); > + iitsr = readl_relaxed(priv->base + ICU_IITSR); > + iitsel = ICU_IITSR_IITSEL_GET(iitsr, irq_nr); > + > + /* > + * When level sensing is used, the interrupt flag gets automatically cleared when the > + * interrupt signal is de-asserted by the source of the interrupt request, therefore clear > + * the interrupt only for edge triggered interrupts. > + */ > + if ((isctr & bit) && (iitsel != ICU_IRQ_LEVEL_LOW)) > + writel_relaxed(bit, priv->base + ICU_ISCLR); > +} Given you already manually inlined one call of this function in this v2, I am not sure it's worthwhile to keep this helper. Manually inlining the single remaining call would drop some boilerplate. > + > +static int rzv2h_irq_set_type(struct irq_data *d, unsigned int type) > +{ > + struct rzv2h_icu_priv *priv = irq_data_to_priv(d); > + unsigned int hwirq = irqd_to_hwirq(d); > + u32 irq_nr = hwirq - ICU_IRQ_START; > + u32 iitsr, sense; > + > + switch (type & IRQ_TYPE_SENSE_MASK) { > + case IRQ_TYPE_LEVEL_LOW: > + sense = ICU_IRQ_LEVEL_LOW; > + break; > + > + case IRQ_TYPE_EDGE_FALLING: > + sense = ICU_IRQ_EDGE_FALLING; > + break; > + > + case IRQ_TYPE_EDGE_RISING: > + sense = ICU_IRQ_EDGE_RISING; > + break; > + > + case IRQ_TYPE_EDGE_BOTH: > + sense = ICU_IRQ_EDGE_BOTH; > + break; > + > + default: > + return -EINVAL; > + } > + > + guard(raw_spinlock)(&priv->lock); > + iitsr = readl_relaxed(priv->base + ICU_IITSR); > + iitsr &= ~ICU_IITSR_IITSEL_MASK(irq_nr); > + iitsr |= ICU_IITSR_IITSEL_PREP(sense, irq_nr); > + rzv2h_clear_irq_int(priv, hwirq); > + writel_relaxed(iitsr, priv->base + ICU_IITSR); > + > + return 0; > +} > + > +static void rzv2h_clear_tint_int(struct rzv2h_icu_priv *priv, unsigned int hwirq) > +{ > + unsigned int tint_nr = hwirq - ICU_TINT_START; > + int titsel_n = ICU_TITSR_TITSEL_N(tint_nr); > + u32 tsctr, titsr, titsel; > + u32 bit = BIT(tint_nr); > + int k = tint_nr / 16; > + > + tsctr = readl_relaxed(priv->base + ICU_TSCTR); > + titsr = readl_relaxed(priv->base + ICU_TITSR(k)); > + titsel = ICU_TITSR_TITSEL_GET(titsr, titsel_n); > + > + /* > + * Writing 1 to the corresponding flag from register ICU_TSCTR only has effect if > + * TSTATn = 1b and if it's a rising edge or a falling edge interrupt. > + */ > + if ((tsctr & bit) && ((titsel == ICU_TINT_EDGE_RISING) || > + (titsel == ICU_TINT_EDGE_FALLING))) > + writel_relaxed(bit, priv->base + ICU_TSCLR); > +} Likewise. > + > +static int rzv2h_tint_set_type(struct irq_data *d, unsigned int type) > +{ > + u32 titsr, titsr_k, titsel_n, tien; > + struct rzv2h_icu_priv *priv; > + u32 tssr, tssr_k, tssel_n; > + unsigned int hwirq; > + u32 tint, sense; > + int tint_nr; > + > + switch (type & IRQ_TYPE_SENSE_MASK) { > + case IRQ_TYPE_LEVEL_LOW: > + sense = ICU_TINT_LEVEL_LOW; > + break; > + > + case IRQ_TYPE_LEVEL_HIGH: > + sense = ICU_TINT_LEVEL_HIGH; > + break; > + > + case IRQ_TYPE_EDGE_RISING: > + sense = ICU_TINT_EDGE_RISING; > + break; > + > + case IRQ_TYPE_EDGE_FALLING: > + sense = ICU_TINT_EDGE_FALLING; > + break; > + > + default: > + return -EINVAL; > + } > + > + tint = (u32)(uintptr_t)irq_data_get_irq_chip_data(d); > + if (tint > ICU_PB5_TINT) > + return -EINVAL; > + > + priv = irq_data_to_priv(d); > + hwirq = irqd_to_hwirq(d); > + > + tint_nr = hwirq - ICU_TINT_START; > + > + tssr_k = ICU_TSSR_K(tint_nr); > + tssel_n = ICU_TSSR_TSSEL_N(tint_nr); > + > + titsr_k = ICU_TITSR_K(tint_nr); > + titsel_n = ICU_TITSR_TITSEL_N(tint_nr); > + tien = ICU_TSSR_TIEN(titsel_n); > + > + guard(raw_spinlock)(&priv->lock); > + > + tssr = readl_relaxed(priv->base + ICU_TSSR(tssr_k)); > + tssr &= ~(ICU_TSSR_TSSEL_MASK(tssel_n) | tien); > + tssr |= ICU_TSSR_TSSEL_PREP(tint, tssel_n); > + > + writel_relaxed(tssr, priv->base + ICU_TSSR(tssr_k)); > + > + titsr = readl_relaxed(priv->base + ICU_TITSR(titsr_k)); > + titsr &= ~ICU_TITSR_TITSEL_MASK(titsel_n); > + titsr |= ICU_TITSR_TITSEL_PREP(sense, titsel_n); > + > + writel_relaxed(titsr, priv->base + ICU_TITSR(titsr_k)); > + > + rzv2h_clear_tint_int(priv, hwirq); > + > + writel_relaxed(tssr | tien, priv->base + ICU_TSSR(tssr_k)); > + > + return 0; > +} Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds