The QUICC Engine provides interrupts for a few I/O ports. This is
handled via a separate interrupt ID and managed via a triplet of
dedicated registers hosted by the SoC.
Implement an interrupt driver for it for that those IRQs can then
be linked to the related GPIOs.
The number of ports for which interrupts are supported depends on
the microcontroller:
- mpc8323 has 10 interrupts
- mpc8360 has 28 interrupts
- mpc8568 has 18 interrupts
So add this information as data of the compatible.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
drivers/soc/fsl/qe/Makefile | 2 +-
drivers/soc/fsl/qe/qe_ports_ic.c | 156 +++++++++++++++++++++++++++++++
2 files changed, 157 insertions(+), 1 deletion(-)
create mode 100644 drivers/soc/fsl/qe/qe_ports_ic.c
diff --git a/drivers/soc/fsl/qe/Makefile b/drivers/soc/fsl/qe/Makefile
index ec8506e131136..901a9c40d5eb7 100644
--- a/drivers/soc/fsl/qe/Makefile
+++ b/drivers/soc/fsl/qe/Makefile
@@ -11,4 +11,4 @@ obj-$(CONFIG_UCC_SLOW) += ucc_slow.o
obj-$(CONFIG_UCC_FAST) += ucc_fast.o
obj-$(CONFIG_QE_TDM) += qe_tdm.o
obj-$(CONFIG_QE_USB) += usb.o
-obj-$(CONFIG_QE_GPIO) += gpio.o
+obj-$(CONFIG_QE_GPIO) += gpio.o qe_ports_ic.o
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
new file mode 100644
index 0000000000000..2ab82ac259564
--- /dev/null
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * QUICC ENGINE I/O Ports Interrupt Controller
+ *
+ * Copyright (c) 2025 Christophe Leroy CS GROUP France (christophe.leroy@csgroup.eu)
+ */
+
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/platform_device.h>
+
+/* QE IC registers offset */
+#define CEPIER 0x0c
+#define CEPIMR 0x10
+#define CEPICR 0x14
+
+struct qepic_data {
+ void __iomem *reg;
+ struct irq_domain *host;
+};
+
+static void qepic_mask(struct irq_data *d)
+{
+ struct qepic_data *data = irq_data_get_irq_chip_data(d);
+
+ clrbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d)));
+}
+
+static void qepic_unmask(struct irq_data *d)
+{
+ struct qepic_data *data = irq_data_get_irq_chip_data(d);
+
+ setbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d)));
+}
+
+static void qepic_end(struct irq_data *d)
+{
+ struct qepic_data *data = irq_data_get_irq_chip_data(d);
+
+ out_be32(data->reg + CEPIER, 1 << (31 - irqd_to_hwirq(d)));
+}
+
+static int qepic_set_type(struct irq_data *d, unsigned int flow_type)
+{
+ struct qepic_data *data = irq_data_get_irq_chip_data(d);
+ unsigned int vec = (unsigned int)irqd_to_hwirq(d);
+
+ switch (flow_type & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_EDGE_FALLING:
+ setbits32(data->reg + CEPICR, 1 << (31 - vec));
+ return 0;
+ case IRQ_TYPE_EDGE_BOTH:
+ case IRQ_TYPE_NONE:
+ clrbits32(data->reg + CEPICR, 1 << (31 - vec));
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static struct irq_chip qepic = {
+ .name = "QEPIC",
+ .irq_mask = qepic_mask,
+ .irq_unmask = qepic_unmask,
+ .irq_eoi = qepic_end,
+ .irq_set_type = qepic_set_type,
+};
+
+static int qepic_get_irq(struct irq_desc *desc)
+{
+ struct qepic_data *data = irq_desc_get_handler_data(desc);
+ u32 event = in_be32(data->reg + CEPIER);
+
+ if (!event)
+ return -1;
+
+ return irq_find_mapping(data->host, 32 - ffs(event));
+}
+
+static void qepic_cascade(struct irq_desc *desc)
+{
+ generic_handle_irq(qepic_get_irq(desc));
+}
+
+static int qepic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw)
+{
+ irq_set_chip_data(virq, h->host_data);
+ irq_set_chip_and_handler(virq, &qepic, handle_fasteoi_irq);
+ return 0;
+}
+
+static const struct irq_domain_ops qepic_host_ops = {
+ .map = qepic_host_map,
+};
+
+static int qepic_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct qepic_data *data;
+ int irq;
+ int nb;
+
+ nb = (int)of_device_get_match_data(dev);
+ if (nb < 1 || nb > 32)
+ return -EINVAL;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->reg = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(data->reg))
+ return PTR_ERR(data->reg);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ data->host = irq_domain_add_linear(dev->of_node, nb, &qepic_host_ops, data);
+ if (!data->host)
+ return -ENODEV;
+
+ irq_set_handler_data(irq, data);
+ irq_set_chained_handler(irq, qepic_cascade);
+
+ return 0;
+}
+
+static const struct of_device_id qepic_match[] = {
+ {
+ .compatible = "fsl,mpc8323-qe-ports-ic",
+ .data = (void *)10,
+ },
+ {
+ .compatible = "fsl,mpc8360-qe-ports-ic",
+ .data = (void *)28,
+ },
+ {
+ .compatible = "fsl,mpc8568-qe-ports-ic",
+ .data = (void *)18,
+ },
+ {},
+};
+
+static struct platform_driver qepic_driver = {
+ .driver = {
+ .name = "qe_ports_ic",
+ .of_match_table = qepic_match,
+ },
+ .probe = qepic_probe,
+};
+
+static int __init qepic_init(void)
+{
+ return platform_driver_register(&qepic_driver);
+}
+arch_initcall(qepic_init);
--
2.49.0
Hi Christophe, kernel test robot noticed the following build warnings: [auto build test WARNING on robh/for-next] [also build test WARNING on linus/master v6.17-rc1 next-20250813] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Christophe-Leroy/soc-fsl-qe-Add-an-interrupt-controller-for-QUICC-Engine-Ports/20250812-195423 base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next patch link: https://lore.kernel.org/r/1dcc9528e97d228ea7889caa00cc254ef0375ed4.1754996033.git.christophe.leroy%40csgroup.eu patch subject: [PATCH 1/4] soc: fsl: qe: Add an interrupt controller for QUICC Engine Ports config: powerpc64-randconfig-002-20250813 (https://download.01.org/0day-ci/archive/20250813/202508131517.P1Nfz0RF-lkp@intel.com/config) compiler: powerpc64-linux-gcc (GCC) 8.5.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250813/202508131517.P1Nfz0RF-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202508131517.P1Nfz0RF-lkp@intel.com/ All warnings (new ones prefixed by >>): drivers/soc/fsl/qe/qe_ports_ic.c: In function 'qepic_probe': >> drivers/soc/fsl/qe/qe_ports_ic.c:102:7: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] nb = (int)of_device_get_match_data(dev); ^ vim +102 drivers/soc/fsl/qe/qe_ports_ic.c 94 95 static int qepic_probe(struct platform_device *pdev) 96 { 97 struct device *dev = &pdev->dev; 98 struct qepic_data *data; 99 int irq; 100 int nb; 101 > 102 nb = (int)of_device_get_match_data(dev); 103 if (nb < 1 || nb > 32) 104 return -EINVAL; 105 106 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 107 if (!data) 108 return -ENOMEM; 109 110 data->reg = devm_platform_ioremap_resource(pdev, 0); 111 if (IS_ERR(data->reg)) 112 return PTR_ERR(data->reg); 113 114 irq = platform_get_irq(pdev, 0); 115 if (irq < 0) 116 return irq; 117 118 data->host = irq_domain_add_linear(dev->of_node, nb, &qepic_host_ops, data); 119 if (!data->host) 120 return -ENODEV; 121 122 irq_set_handler_data(irq, data); 123 irq_set_chained_handler(irq, qepic_cascade); 124 125 return 0; 126 } 127 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
© 2016 - 2025 Red Hat, Inc.