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