From: Conor Dooley <conor@kernel.org>
To: linux-gpio@vger.kernel.org
Cc: conor@kernel.org, Conor Dooley <conor.dooley@microchip.com>,
Thomas Gleixner <tglx@linutronix.de>,
Herve Codina <herve.codina@bootlin.com>,
Daire McNamara <daire.mcnamara@microchip.com>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Paul Walmsley <pjw@kernel.org>,
Palmer Dabbelt <palmer@dabbelt.com>,
Albert Ou <aou@eecs.berkeley.edu>,
Alexandre Ghiti <alex@ghiti.fr>,
Linus Walleij <linusw@kernel.org>,
Bartosz Golaszewski <brgl@kernel.org>,
linux-riscv@lists.infradead.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [RFC v11 1/4] gpio: mpfs: Add interrupt support
Date: Fri, 27 Feb 2026 14:52:27 +0000 [thread overview]
Message-ID: <20260227-divinely-drift-93307c6763d8@spud> (raw)
In-Reply-To: <20260227-ajar-wolverine-7ce1ebd79821@spud>
From: Conor Dooley <conor.dooley@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@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.
---
drivers/gpio/Kconfig | 1 +
drivers/gpio/gpio-mpfs.c | 125 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 123 insertions(+), 3 deletions(-)
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index b45fb799e36c1..1d1239323f615 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -572,6 +572,7 @@ config GPIO_PL061
config GPIO_POLARFIRE_SOC
bool "Microchip FPGA GPIO support"
select REGMAP_MMIO
+ select GPIOLIB_IRQCHIP
help
Say yes here to support the GPIO controllers on Microchip FPGAs.
diff --git a/drivers/gpio/gpio-mpfs.c b/drivers/gpio/gpio-mpfs.c
index 9468795b96348..d19249dd0c87d 100644
--- a/drivers/gpio/gpio-mpfs.c
+++ b/drivers/gpio/gpio-mpfs.c
@@ -9,8 +9,9 @@
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
-#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/mod_devicetable.h>
+#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
@@ -18,7 +19,7 @@
#define MPFS_GPIO_CTRL(i) (0x4 * (i))
#define MPFS_MAX_NUM_GPIO 32
-#define MPFS_GPIO_EN_INT 3
+#define MPFS_GPIO_EN_INT BIT(3)
#define MPFS_GPIO_EN_OUT_BUF BIT(2)
#define MPFS_GPIO_EN_IN BIT(1)
#define MPFS_GPIO_EN_OUT BIT(0)
@@ -52,6 +53,7 @@ static const struct regmap_config mpfs_gpio_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
+ .use_raw_spinlock = true,
};
static int mpfs_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio_index)
@@ -114,13 +116,97 @@ static int mpfs_gpio_set(struct gpio_chip *gc, unsigned int gpio_index, int valu
return ret;
}
+static int mpfs_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
+ int gpio_index = irqd_to_hwirq(data) % 32;
+ u32 interrupt_type;
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_BOTH:
+ interrupt_type = MPFS_GPIO_TYPE_INT_EDGE_BOTH;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ interrupt_type = MPFS_GPIO_TYPE_INT_EDGE_NEG;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ interrupt_type = MPFS_GPIO_TYPE_INT_EDGE_POS;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ interrupt_type = MPFS_GPIO_TYPE_INT_LEVEL_HIGH;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ interrupt_type = MPFS_GPIO_TYPE_INT_LEVEL_LOW;
+ break;
+ }
+
+ regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index),
+ MPFS_GPIO_TYPE_INT_MASK, interrupt_type);
+
+ return 0;
+}
+
+static void mpfs_gpio_irq_unmask(struct irq_data *data)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
+ int gpio_index = irqd_to_hwirq(data) % 32;
+
+ gpiochip_enable_irq(gc, gpio_index);
+ mpfs_gpio_direction_input(gc, gpio_index);
+ regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index),
+ MPFS_GPIO_EN_INT, MPFS_GPIO_EN_INT);
+}
+
+static void mpfs_gpio_irq_mask(struct irq_data *data)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
+ int gpio_index = irqd_to_hwirq(data) % 32;
+
+ regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index),
+ MPFS_GPIO_EN_INT, 0);
+ gpiochip_disable_irq(gc, gpio_index);
+}
+
+static const struct irq_chip mpfs_gpio_irqchip = {
+ .name = "MPFS GPIO",
+ .irq_set_type = mpfs_gpio_irq_set_type,
+ .irq_mask = mpfs_gpio_irq_mask,
+ .irq_unmask = mpfs_gpio_irq_unmask,
+ .flags = IRQCHIP_IMMUTABLE | IRQCHIP_MASK_ON_SUSPEND,
+ GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
+static irqreturn_t mpfs_gpio_irq_handler(int irq, void *data)
+{
+ struct mpfs_gpio_chip *mpfs_gpio = data;
+ unsigned int handled = 0;
+ unsigned long status;
+ u32 val;
+ int i;
+
+ 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++;
+ }
+
+ return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
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);
+ }
+
+ girq->handler = handle_level_irq;
+ girq->default_type = IRQ_TYPE_NONE;
+ }
+
return devm_gpiochip_add_data(dev, &mpfs_gpio->gc, mpfs_gpio);
}
--
2.51.0
next prev parent reply other threads:[~2026-02-27 14:53 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-27 14:52 [RFC v11 0/4] PolarFire SoC GPIO interrupt support Conor Dooley
2026-02-27 14:52 ` Conor Dooley [this message]
2026-03-02 8:55 ` [RFC v11 1/4] gpio: mpfs: Add " Herve Codina
2026-03-02 9:44 ` Linus Walleij
2026-02-27 14:52 ` [RFC v11 2/4] dt-bindings: soc: microchip: document PolarFire SoC's gpio interrupt mux Conor Dooley
2026-03-02 9:02 ` Herve Codina
2026-02-27 14:52 ` [RFC v11 3/4] soc: microchip: add mpfs gpio interrupt mux driver Conor Dooley
2026-03-02 9:58 ` Herve Codina
2026-03-02 11:22 ` Conor Dooley
2026-02-27 14:52 ` [RFC v11 4/4] riscv: dts: microchip: update mpfs gpio interrupts to better match the SoC Conor Dooley
2026-03-02 9:47 ` [RFC v11 0/4] PolarFire SoC GPIO interrupt support Linus Walleij
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=20260227-divinely-drift-93307c6763d8@spud \
--to=conor@kernel.org \
--cc=alex@ghiti.fr \
--cc=aou@eecs.berkeley.edu \
--cc=brgl@kernel.org \
--cc=conor.dooley@microchip.com \
--cc=daire.mcnamara@microchip.com \
--cc=devicetree@vger.kernel.org \
--cc=herve.codina@bootlin.com \
--cc=krzk+dt@kernel.org \
--cc=linusw@kernel.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=palmer@dabbelt.com \
--cc=pjw@kernel.org \
--cc=robh@kernel.org \
--cc=tglx@linutronix.de \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox