Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

soc: fsl: qe: Add an interrupt controller for QUICC Engine Ports

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 so that those IRQs can then
be linked to the related GPIOs.

Link: https://lore.kernel.org/r/63f19db21a91729d91b3df336a56a7eb4206e561.1767804922.git.chleroy@kernel.org
Signed-off-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>

+143 -1
+1 -1
drivers/soc/fsl/qe/Makefile
··· 11 11 obj-$(CONFIG_UCC_FAST) += ucc_fast.o 12 12 obj-$(CONFIG_QE_TDM) += qe_tdm.o 13 13 obj-$(CONFIG_QE_USB) += usb.o 14 - obj-$(CONFIG_QE_GPIO) += gpio.o 14 + obj-$(CONFIG_QE_GPIO) += gpio.o qe_ports_ic.o
+142
drivers/soc/fsl/qe/qe_ports_ic.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * QUICC ENGINE I/O Ports Interrupt Controller 4 + * 5 + * Copyright (c) 2025 Christophe Leroy CS GROUP France (christophe.leroy@csgroup.eu) 6 + */ 7 + 8 + #include <linux/irq.h> 9 + #include <linux/irqdomain.h> 10 + #include <linux/platform_device.h> 11 + 12 + /* QE IC registers offset */ 13 + #define CEPIER 0x0c 14 + #define CEPIMR 0x10 15 + #define CEPICR 0x14 16 + 17 + struct qepic_data { 18 + void __iomem *reg; 19 + struct irq_domain *host; 20 + }; 21 + 22 + static void qepic_mask(struct irq_data *d) 23 + { 24 + struct qepic_data *data = irq_data_get_irq_chip_data(d); 25 + 26 + clrbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d))); 27 + } 28 + 29 + static void qepic_unmask(struct irq_data *d) 30 + { 31 + struct qepic_data *data = irq_data_get_irq_chip_data(d); 32 + 33 + setbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d))); 34 + } 35 + 36 + static void qepic_end(struct irq_data *d) 37 + { 38 + struct qepic_data *data = irq_data_get_irq_chip_data(d); 39 + 40 + out_be32(data->reg + CEPIER, 1 << (31 - irqd_to_hwirq(d))); 41 + } 42 + 43 + static int qepic_set_type(struct irq_data *d, unsigned int flow_type) 44 + { 45 + struct qepic_data *data = irq_data_get_irq_chip_data(d); 46 + unsigned int vec = (unsigned int)irqd_to_hwirq(d); 47 + 48 + switch (flow_type & IRQ_TYPE_SENSE_MASK) { 49 + case IRQ_TYPE_EDGE_FALLING: 50 + setbits32(data->reg + CEPICR, 1 << (31 - vec)); 51 + return 0; 52 + case IRQ_TYPE_EDGE_BOTH: 53 + case IRQ_TYPE_NONE: 54 + clrbits32(data->reg + CEPICR, 1 << (31 - vec)); 55 + return 0; 56 + } 57 + return -EINVAL; 58 + } 59 + 60 + static struct irq_chip qepic = { 61 + .name = "QEPIC", 62 + .irq_mask = qepic_mask, 63 + .irq_unmask = qepic_unmask, 64 + .irq_eoi = qepic_end, 65 + .irq_set_type = qepic_set_type, 66 + }; 67 + 68 + static int qepic_get_irq(struct irq_desc *desc) 69 + { 70 + struct qepic_data *data = irq_desc_get_handler_data(desc); 71 + u32 event = in_be32(data->reg + CEPIER); 72 + 73 + if (!event) 74 + return -1; 75 + 76 + return irq_find_mapping(data->host, 32 - ffs(event)); 77 + } 78 + 79 + static void qepic_cascade(struct irq_desc *desc) 80 + { 81 + generic_handle_irq(qepic_get_irq(desc)); 82 + } 83 + 84 + static int qepic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) 85 + { 86 + irq_set_chip_data(virq, h->host_data); 87 + irq_set_chip_and_handler(virq, &qepic, handle_fasteoi_irq); 88 + return 0; 89 + } 90 + 91 + static const struct irq_domain_ops qepic_host_ops = { 92 + .map = qepic_host_map, 93 + }; 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 + 101 + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 102 + if (!data) 103 + return -ENOMEM; 104 + 105 + data->reg = devm_platform_ioremap_resource(pdev, 0); 106 + if (IS_ERR(data->reg)) 107 + return PTR_ERR(data->reg); 108 + 109 + irq = platform_get_irq(pdev, 0); 110 + if (irq < 0) 111 + return irq; 112 + 113 + data->host = irq_domain_add_linear(dev->of_node, 32, &qepic_host_ops, data); 114 + if (!data->host) 115 + return -ENODEV; 116 + 117 + irq_set_handler_data(irq, data); 118 + irq_set_chained_handler(irq, qepic_cascade); 119 + 120 + return 0; 121 + } 122 + 123 + static const struct of_device_id qepic_match[] = { 124 + { 125 + .compatible = "fsl,mpc8323-qe-ports-ic", 126 + }, 127 + {}, 128 + }; 129 + 130 + static struct platform_driver qepic_driver = { 131 + .driver = { 132 + .name = "qe_ports_ic", 133 + .of_match_table = qepic_match, 134 + }, 135 + .probe = qepic_probe, 136 + }; 137 + 138 + static int __init qepic_init(void) 139 + { 140 + return platform_driver_register(&qepic_driver); 141 + } 142 + arch_initcall(qepic_init);