[RFC v11 1/4] gpio: mpfs: Add interrupt support

Linus Walleij linusw at kernel.org
Mon Mar 2 01:44:45 PST 2026


Hi Conor,

overall this looks okay, but one detail here:

On Fri, Feb 27, 2026 at 3:53 PM Conor Dooley <conor at kernel.org> wrote:

> From: Conor Dooley <conor.dooley at microchip.com>
>
> Add support for interrupts to the PolarFire SoC GPIO driver. Each GPIO
> has an independent interrupt that is wired to an interrupt mux that sits
> between the controllers and the PLIC. The SoC has more GPIO lines than
> connections from the mux to the PLIC, so some GPIOs must share PLIC
> interrupts. The configuration is not static and is set at runtime,
> conventionally by the platform's firmware. CoreGPIO, the version
> intended for use in the FPGA fabric has two interrupt output ports, one
> is IO_NUM bits wide, as is used in the hardened cores, and the other is
> a single bit with all lines ORed together.
>
> Signed-off-by: Conor Dooley <conor.dooley at microchip.com>
> ---
> Doing the chained thing kinda covers all the bases at the expense of the
> "direct" mode interrupts that have a dedicated connection to the PLIC.

Chained kinda thing, OK...


> +static irqreturn_t mpfs_gpio_irq_handler(int irq, void *data)

static void mpfs_gpio_irq_handler(struct irq_desc *desc)

> +{
> +       struct mpfs_gpio_chip *mpfs_gpio = data;
> +       unsigned int handled = 0;
> +       unsigned long status;
> +       u32 val;
> +       int i;
> +
struct irq_chip *irqchip = irq_desc_get_chip(desc);

chained_irq_enter(irqchip, desc)

> +       regmap_read(mpfs_gpio->regs, MPFS_IRQ_REG, &val);
> +       status = val;
> +       for_each_set_bit(i, &status, MPFS_MAX_NUM_GPIO) {
> +               regmap_write(mpfs_gpio->regs, MPFS_IRQ_REG, BIT(i));
> +               generic_handle_domain_irq(mpfs_gpio->gc.irq.domain, i);
> +               handled++;
> +       }

chained_irq_exit(irqchip, desc)

(no return value)

>  static int mpfs_gpio_probe(struct platform_device *pdev)
>  {
>         struct device *dev = &pdev->dev;
> +       struct device_node *node = pdev->dev.of_node;
>         struct mpfs_gpio_chip *mpfs_gpio;
> +       struct gpio_irq_chip *girq;
>         struct clk *clk;
>         void __iomem *base;
> -       int ngpios;
> +       int ngpios, nirqs, ret;
>
>         mpfs_gpio = devm_kzalloc(dev, sizeof(*mpfs_gpio), GFP_KERNEL);
>         if (!mpfs_gpio)
> @@ -157,6 +243,39 @@ static int mpfs_gpio_probe(struct platform_device *pdev)
>         mpfs_gpio->gc.parent = dev;
>         mpfs_gpio->gc.owner = THIS_MODULE;
>
> +       nirqs = of_irq_count(node);
> +       if (nirqs > MPFS_MAX_NUM_GPIO)
> +               return -ENXIO;
> +
> +       girq = &mpfs_gpio->gc.irq;
> +       girq->num_parents = nirqs;
> +
> +       if (girq->num_parents) {
> +               gpio_irq_chip_set_chip(girq, &mpfs_gpio_irqchip);
> +
> +               girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents,
> +                                            sizeof(*girq->parents), GFP_KERNEL);
> +               if (!girq->parents)
> +                       return -ENOMEM;
> +
> +               for (int i = 0; i < girq->num_parents; i++) {
> +                       ret = platform_get_irq(pdev, i);
> +                       if (ret < 0)
> +                               return ret;
> +
> +                       girq->parents[i] = ret;
> +                       ret = devm_request_irq(dev, girq->parents[i], mpfs_gpio_irq_handler,
> +                                              IRQF_SHARED, NULL, mpfs_gpio);
> +                       if (ret)
> +                               return dev_err_probe(dev, ret,
> +                                                    "failed to request irq for line %u\n",
> +                                                    i);
> +               }

Why do this instead of letting the core do the multi-parent chaining without
explicitly requesting the IRQs like e.g. gpio-dwapb.c does for the
multi-parent case?

Yours,
Linus Walleij



More information about the linux-riscv mailing list