xref: /openbmc/linux/drivers/irqchip/irq-lpc32xx.c (revision fbb6b31a)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright 2015-2016 Vladimir Zapolskiy <vz@mleia.com>
4  */
5 
6 #define pr_fmt(fmt) "%s: " fmt, __func__
7 
8 #include <linux/io.h>
9 #include <linux/irqchip.h>
10 #include <linux/irqchip/chained_irq.h>
11 #include <linux/of_address.h>
12 #include <linux/of_irq.h>
13 #include <linux/of_platform.h>
14 #include <linux/seq_file.h>
15 #include <linux/slab.h>
16 #include <asm/exception.h>
17 
18 #define LPC32XX_INTC_MASK		0x00
19 #define LPC32XX_INTC_RAW		0x04
20 #define LPC32XX_INTC_STAT		0x08
21 #define LPC32XX_INTC_POL		0x0C
22 #define LPC32XX_INTC_TYPE		0x10
23 #define LPC32XX_INTC_FIQ		0x14
24 
25 #define NR_LPC32XX_IC_IRQS		32
26 
27 struct lpc32xx_irq_chip {
28 	void __iomem *base;
29 	phys_addr_t addr;
30 	struct irq_domain *domain;
31 };
32 
33 static struct lpc32xx_irq_chip *lpc32xx_mic_irqc;
34 
35 static inline u32 lpc32xx_ic_read(struct lpc32xx_irq_chip *ic, u32 reg)
36 {
37 	return readl_relaxed(ic->base + reg);
38 }
39 
40 static inline void lpc32xx_ic_write(struct lpc32xx_irq_chip *ic,
41 				    u32 reg, u32 val)
42 {
43 	writel_relaxed(val, ic->base + reg);
44 }
45 
46 static void lpc32xx_irq_mask(struct irq_data *d)
47 {
48 	struct lpc32xx_irq_chip *ic = irq_data_get_irq_chip_data(d);
49 	u32 val, mask = BIT(d->hwirq);
50 
51 	val = lpc32xx_ic_read(ic, LPC32XX_INTC_MASK) & ~mask;
52 	lpc32xx_ic_write(ic, LPC32XX_INTC_MASK, val);
53 }
54 
55 static void lpc32xx_irq_unmask(struct irq_data *d)
56 {
57 	struct lpc32xx_irq_chip *ic = irq_data_get_irq_chip_data(d);
58 	u32 val, mask = BIT(d->hwirq);
59 
60 	val = lpc32xx_ic_read(ic, LPC32XX_INTC_MASK) | mask;
61 	lpc32xx_ic_write(ic, LPC32XX_INTC_MASK, val);
62 }
63 
64 static void lpc32xx_irq_ack(struct irq_data *d)
65 {
66 	struct lpc32xx_irq_chip *ic = irq_data_get_irq_chip_data(d);
67 	u32 mask = BIT(d->hwirq);
68 
69 	lpc32xx_ic_write(ic, LPC32XX_INTC_RAW, mask);
70 }
71 
72 static int lpc32xx_irq_set_type(struct irq_data *d, unsigned int type)
73 {
74 	struct lpc32xx_irq_chip *ic = irq_data_get_irq_chip_data(d);
75 	u32 val, mask = BIT(d->hwirq);
76 	bool high, edge;
77 
78 	switch (type) {
79 	case IRQ_TYPE_EDGE_RISING:
80 		edge = true;
81 		high = true;
82 		break;
83 	case IRQ_TYPE_EDGE_FALLING:
84 		edge = true;
85 		high = false;
86 		break;
87 	case IRQ_TYPE_LEVEL_HIGH:
88 		edge = false;
89 		high = true;
90 		break;
91 	case IRQ_TYPE_LEVEL_LOW:
92 		edge = false;
93 		high = false;
94 		break;
95 	default:
96 		pr_info("unsupported irq type %d\n", type);
97 		return -EINVAL;
98 	}
99 
100 	irqd_set_trigger_type(d, type);
101 
102 	val = lpc32xx_ic_read(ic, LPC32XX_INTC_POL);
103 	if (high)
104 		val |= mask;
105 	else
106 		val &= ~mask;
107 	lpc32xx_ic_write(ic, LPC32XX_INTC_POL, val);
108 
109 	val = lpc32xx_ic_read(ic, LPC32XX_INTC_TYPE);
110 	if (edge) {
111 		val |= mask;
112 		irq_set_handler_locked(d, handle_edge_irq);
113 	} else {
114 		val &= ~mask;
115 		irq_set_handler_locked(d, handle_level_irq);
116 	}
117 	lpc32xx_ic_write(ic, LPC32XX_INTC_TYPE, val);
118 
119 	return 0;
120 }
121 
122 static void lpc32xx_irq_print_chip(struct irq_data *d, struct seq_file *p)
123 {
124 	struct lpc32xx_irq_chip *ic = irq_data_get_irq_chip_data(d);
125 
126 	if (ic == lpc32xx_mic_irqc)
127 		seq_printf(p, "%08x.mic", ic->addr);
128 	else
129 		seq_printf(p, "%08x.sic", ic->addr);
130 }
131 
132 static const struct irq_chip lpc32xx_chip = {
133 	.irq_ack	= lpc32xx_irq_ack,
134 	.irq_mask	= lpc32xx_irq_mask,
135 	.irq_unmask	= lpc32xx_irq_unmask,
136 	.irq_set_type	= lpc32xx_irq_set_type,
137 	.irq_print_chip	= lpc32xx_irq_print_chip,
138 };
139 
140 static void __exception_irq_entry lpc32xx_handle_irq(struct pt_regs *regs)
141 {
142 	struct lpc32xx_irq_chip *ic = lpc32xx_mic_irqc;
143 	u32 hwirq = lpc32xx_ic_read(ic, LPC32XX_INTC_STAT), irq;
144 
145 	while (hwirq) {
146 		irq = __ffs(hwirq);
147 		hwirq &= ~BIT(irq);
148 		generic_handle_domain_irq(lpc32xx_mic_irqc->domain, irq);
149 	}
150 }
151 
152 static void lpc32xx_sic_handler(struct irq_desc *desc)
153 {
154 	struct lpc32xx_irq_chip *ic = irq_desc_get_handler_data(desc);
155 	struct irq_chip *chip = irq_desc_get_chip(desc);
156 	u32 hwirq = lpc32xx_ic_read(ic, LPC32XX_INTC_STAT), irq;
157 
158 	chained_irq_enter(chip, desc);
159 
160 	while (hwirq) {
161 		irq = __ffs(hwirq);
162 		hwirq &= ~BIT(irq);
163 		generic_handle_domain_irq(ic->domain, irq);
164 	}
165 
166 	chained_irq_exit(chip, desc);
167 }
168 
169 static int lpc32xx_irq_domain_map(struct irq_domain *id, unsigned int virq,
170 				  irq_hw_number_t hw)
171 {
172 	struct lpc32xx_irq_chip *ic = id->host_data;
173 
174 	irq_set_chip_data(virq, ic);
175 	irq_set_chip_and_handler(virq, &lpc32xx_chip, handle_level_irq);
176 	irq_set_status_flags(virq, IRQ_LEVEL);
177 	irq_set_noprobe(virq);
178 
179 	return 0;
180 }
181 
182 static void lpc32xx_irq_domain_unmap(struct irq_domain *id, unsigned int virq)
183 {
184 	irq_set_chip_and_handler(virq, NULL, NULL);
185 }
186 
187 static const struct irq_domain_ops lpc32xx_irq_domain_ops = {
188 	.map    = lpc32xx_irq_domain_map,
189 	.unmap	= lpc32xx_irq_domain_unmap,
190 	.xlate  = irq_domain_xlate_twocell,
191 };
192 
193 static int __init lpc32xx_of_ic_init(struct device_node *node,
194 				     struct device_node *parent)
195 {
196 	struct lpc32xx_irq_chip *irqc;
197 	bool is_mic = of_device_is_compatible(node, "nxp,lpc3220-mic");
198 	const __be32 *reg = of_get_property(node, "reg", NULL);
199 	u32 parent_irq, i, addr = reg ? be32_to_cpu(*reg) : 0;
200 
201 	irqc = kzalloc(sizeof(*irqc), GFP_KERNEL);
202 	if (!irqc)
203 		return -ENOMEM;
204 
205 	irqc->addr = addr;
206 	irqc->base = of_iomap(node, 0);
207 	if (!irqc->base) {
208 		pr_err("%pOF: unable to map registers\n", node);
209 		kfree(irqc);
210 		return -EINVAL;
211 	}
212 
213 	irqc->domain = irq_domain_add_linear(node, NR_LPC32XX_IC_IRQS,
214 					     &lpc32xx_irq_domain_ops, irqc);
215 	if (!irqc->domain) {
216 		pr_err("unable to add irq domain\n");
217 		iounmap(irqc->base);
218 		kfree(irqc);
219 		return -ENODEV;
220 	}
221 
222 	if (is_mic) {
223 		lpc32xx_mic_irqc = irqc;
224 		set_handle_irq(lpc32xx_handle_irq);
225 	} else {
226 		for (i = 0; i < of_irq_count(node); i++) {
227 			parent_irq = irq_of_parse_and_map(node, i);
228 			if (parent_irq)
229 				irq_set_chained_handler_and_data(parent_irq,
230 						 lpc32xx_sic_handler, irqc);
231 		}
232 	}
233 
234 	lpc32xx_ic_write(irqc, LPC32XX_INTC_MASK, 0x00);
235 	lpc32xx_ic_write(irqc, LPC32XX_INTC_POL,  0x00);
236 	lpc32xx_ic_write(irqc, LPC32XX_INTC_TYPE, 0x00);
237 
238 	return 0;
239 }
240 
241 IRQCHIP_DECLARE(nxp_lpc32xx_mic, "nxp,lpc3220-mic", lpc32xx_of_ic_init);
242 IRQCHIP_DECLARE(nxp_lpc32xx_sic, "nxp,lpc3220-sic", lpc32xx_of_ic_init);
243