xref: /openbmc/linux/drivers/irqchip/irq-atmel-aic5.c (revision b1479ebb772003461f0458a0b3a68cb1c4036288)
1*b1479ebbSBoris BREZILLON /*
2*b1479ebbSBoris BREZILLON  * Atmel AT91 AIC5 (Advanced Interrupt Controller) driver
3*b1479ebbSBoris BREZILLON  *
4*b1479ebbSBoris BREZILLON  *  Copyright (C) 2004 SAN People
5*b1479ebbSBoris BREZILLON  *  Copyright (C) 2004 ATMEL
6*b1479ebbSBoris BREZILLON  *  Copyright (C) Rick Bronson
7*b1479ebbSBoris BREZILLON  *  Copyright (C) 2014 Free Electrons
8*b1479ebbSBoris BREZILLON  *
9*b1479ebbSBoris BREZILLON  *  Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
10*b1479ebbSBoris BREZILLON  *
11*b1479ebbSBoris BREZILLON  * This file is licensed under the terms of the GNU General Public
12*b1479ebbSBoris BREZILLON  * License version 2.  This program is licensed "as is" without any
13*b1479ebbSBoris BREZILLON  * warranty of any kind, whether express or implied.
14*b1479ebbSBoris BREZILLON  */
15*b1479ebbSBoris BREZILLON 
16*b1479ebbSBoris BREZILLON #include <linux/init.h>
17*b1479ebbSBoris BREZILLON #include <linux/module.h>
18*b1479ebbSBoris BREZILLON #include <linux/mm.h>
19*b1479ebbSBoris BREZILLON #include <linux/bitmap.h>
20*b1479ebbSBoris BREZILLON #include <linux/types.h>
21*b1479ebbSBoris BREZILLON #include <linux/irq.h>
22*b1479ebbSBoris BREZILLON #include <linux/of.h>
23*b1479ebbSBoris BREZILLON #include <linux/of_address.h>
24*b1479ebbSBoris BREZILLON #include <linux/of_irq.h>
25*b1479ebbSBoris BREZILLON #include <linux/irqdomain.h>
26*b1479ebbSBoris BREZILLON #include <linux/err.h>
27*b1479ebbSBoris BREZILLON #include <linux/slab.h>
28*b1479ebbSBoris BREZILLON #include <linux/io.h>
29*b1479ebbSBoris BREZILLON 
30*b1479ebbSBoris BREZILLON #include <asm/exception.h>
31*b1479ebbSBoris BREZILLON #include <asm/mach/irq.h>
32*b1479ebbSBoris BREZILLON 
33*b1479ebbSBoris BREZILLON #include "irq-atmel-aic-common.h"
34*b1479ebbSBoris BREZILLON #include "irqchip.h"
35*b1479ebbSBoris BREZILLON 
36*b1479ebbSBoris BREZILLON /* Number of irq lines managed by AIC */
37*b1479ebbSBoris BREZILLON #define NR_AIC5_IRQS	128
38*b1479ebbSBoris BREZILLON 
39*b1479ebbSBoris BREZILLON #define AT91_AIC5_SSR		0x0
40*b1479ebbSBoris BREZILLON #define AT91_AIC5_INTSEL_MSK	(0x7f << 0)
41*b1479ebbSBoris BREZILLON 
42*b1479ebbSBoris BREZILLON #define AT91_AIC5_SMR			0x4
43*b1479ebbSBoris BREZILLON 
44*b1479ebbSBoris BREZILLON #define AT91_AIC5_SVR			0x8
45*b1479ebbSBoris BREZILLON #define AT91_AIC5_IVR			0x10
46*b1479ebbSBoris BREZILLON #define AT91_AIC5_FVR			0x14
47*b1479ebbSBoris BREZILLON #define AT91_AIC5_ISR			0x18
48*b1479ebbSBoris BREZILLON 
49*b1479ebbSBoris BREZILLON #define AT91_AIC5_IPR0			0x20
50*b1479ebbSBoris BREZILLON #define AT91_AIC5_IPR1			0x24
51*b1479ebbSBoris BREZILLON #define AT91_AIC5_IPR2			0x28
52*b1479ebbSBoris BREZILLON #define AT91_AIC5_IPR3			0x2c
53*b1479ebbSBoris BREZILLON #define AT91_AIC5_IMR			0x30
54*b1479ebbSBoris BREZILLON #define AT91_AIC5_CISR			0x34
55*b1479ebbSBoris BREZILLON 
56*b1479ebbSBoris BREZILLON #define AT91_AIC5_IECR			0x40
57*b1479ebbSBoris BREZILLON #define AT91_AIC5_IDCR			0x44
58*b1479ebbSBoris BREZILLON #define AT91_AIC5_ICCR			0x48
59*b1479ebbSBoris BREZILLON #define AT91_AIC5_ISCR			0x4c
60*b1479ebbSBoris BREZILLON #define AT91_AIC5_EOICR			0x38
61*b1479ebbSBoris BREZILLON #define AT91_AIC5_SPU			0x3c
62*b1479ebbSBoris BREZILLON #define AT91_AIC5_DCR			0x6c
63*b1479ebbSBoris BREZILLON 
64*b1479ebbSBoris BREZILLON #define AT91_AIC5_FFER			0x50
65*b1479ebbSBoris BREZILLON #define AT91_AIC5_FFDR			0x54
66*b1479ebbSBoris BREZILLON #define AT91_AIC5_FFSR			0x58
67*b1479ebbSBoris BREZILLON 
68*b1479ebbSBoris BREZILLON static struct irq_domain *aic5_domain;
69*b1479ebbSBoris BREZILLON 
70*b1479ebbSBoris BREZILLON static asmlinkage void __exception_irq_entry
71*b1479ebbSBoris BREZILLON aic5_handle(struct pt_regs *regs)
72*b1479ebbSBoris BREZILLON {
73*b1479ebbSBoris BREZILLON 	struct irq_domain_chip_generic *dgc = aic5_domain->gc;
74*b1479ebbSBoris BREZILLON 	struct irq_chip_generic *gc = dgc->gc[0];
75*b1479ebbSBoris BREZILLON 	u32 irqnr;
76*b1479ebbSBoris BREZILLON 	u32 irqstat;
77*b1479ebbSBoris BREZILLON 
78*b1479ebbSBoris BREZILLON 	irqnr = irq_reg_readl(gc->reg_base + AT91_AIC5_IVR);
79*b1479ebbSBoris BREZILLON 	irqstat = irq_reg_readl(gc->reg_base + AT91_AIC5_ISR);
80*b1479ebbSBoris BREZILLON 
81*b1479ebbSBoris BREZILLON 	irqnr = irq_find_mapping(aic5_domain, irqnr);
82*b1479ebbSBoris BREZILLON 
83*b1479ebbSBoris BREZILLON 	if (!irqstat)
84*b1479ebbSBoris BREZILLON 		irq_reg_writel(0, gc->reg_base + AT91_AIC5_EOICR);
85*b1479ebbSBoris BREZILLON 	else
86*b1479ebbSBoris BREZILLON 		handle_IRQ(irqnr, regs);
87*b1479ebbSBoris BREZILLON }
88*b1479ebbSBoris BREZILLON 
89*b1479ebbSBoris BREZILLON static void aic5_mask(struct irq_data *d)
90*b1479ebbSBoris BREZILLON {
91*b1479ebbSBoris BREZILLON 	struct irq_domain *domain = d->domain;
92*b1479ebbSBoris BREZILLON 	struct irq_domain_chip_generic *dgc = domain->gc;
93*b1479ebbSBoris BREZILLON 	struct irq_chip_generic *gc = dgc->gc[0];
94*b1479ebbSBoris BREZILLON 
95*b1479ebbSBoris BREZILLON 	/* Disable interrupt on AIC5 */
96*b1479ebbSBoris BREZILLON 	irq_gc_lock(gc);
97*b1479ebbSBoris BREZILLON 	irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR);
98*b1479ebbSBoris BREZILLON 	irq_reg_writel(1, gc->reg_base + AT91_AIC5_IDCR);
99*b1479ebbSBoris BREZILLON 	gc->mask_cache &= ~d->mask;
100*b1479ebbSBoris BREZILLON 	irq_gc_unlock(gc);
101*b1479ebbSBoris BREZILLON }
102*b1479ebbSBoris BREZILLON 
103*b1479ebbSBoris BREZILLON static void aic5_unmask(struct irq_data *d)
104*b1479ebbSBoris BREZILLON {
105*b1479ebbSBoris BREZILLON 	struct irq_domain *domain = d->domain;
106*b1479ebbSBoris BREZILLON 	struct irq_domain_chip_generic *dgc = domain->gc;
107*b1479ebbSBoris BREZILLON 	struct irq_chip_generic *gc = dgc->gc[0];
108*b1479ebbSBoris BREZILLON 
109*b1479ebbSBoris BREZILLON 	/* Enable interrupt on AIC5 */
110*b1479ebbSBoris BREZILLON 	irq_gc_lock(gc);
111*b1479ebbSBoris BREZILLON 	irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR);
112*b1479ebbSBoris BREZILLON 	irq_reg_writel(1, gc->reg_base + AT91_AIC5_IECR);
113*b1479ebbSBoris BREZILLON 	gc->mask_cache |= d->mask;
114*b1479ebbSBoris BREZILLON 	irq_gc_unlock(gc);
115*b1479ebbSBoris BREZILLON }
116*b1479ebbSBoris BREZILLON 
117*b1479ebbSBoris BREZILLON static int aic5_retrigger(struct irq_data *d)
118*b1479ebbSBoris BREZILLON {
119*b1479ebbSBoris BREZILLON 	struct irq_domain *domain = d->domain;
120*b1479ebbSBoris BREZILLON 	struct irq_domain_chip_generic *dgc = domain->gc;
121*b1479ebbSBoris BREZILLON 	struct irq_chip_generic *gc = dgc->gc[0];
122*b1479ebbSBoris BREZILLON 
123*b1479ebbSBoris BREZILLON 	/* Enable interrupt on AIC5 */
124*b1479ebbSBoris BREZILLON 	irq_gc_lock(gc);
125*b1479ebbSBoris BREZILLON 	irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR);
126*b1479ebbSBoris BREZILLON 	irq_reg_writel(1, gc->reg_base + AT91_AIC5_ISCR);
127*b1479ebbSBoris BREZILLON 	irq_gc_unlock(gc);
128*b1479ebbSBoris BREZILLON 
129*b1479ebbSBoris BREZILLON 	return 0;
130*b1479ebbSBoris BREZILLON }
131*b1479ebbSBoris BREZILLON 
132*b1479ebbSBoris BREZILLON static int aic5_set_type(struct irq_data *d, unsigned type)
133*b1479ebbSBoris BREZILLON {
134*b1479ebbSBoris BREZILLON 	struct irq_domain *domain = d->domain;
135*b1479ebbSBoris BREZILLON 	struct irq_domain_chip_generic *dgc = domain->gc;
136*b1479ebbSBoris BREZILLON 	struct irq_chip_generic *gc = dgc->gc[0];
137*b1479ebbSBoris BREZILLON 	unsigned int smr;
138*b1479ebbSBoris BREZILLON 	int ret;
139*b1479ebbSBoris BREZILLON 
140*b1479ebbSBoris BREZILLON 	irq_gc_lock(gc);
141*b1479ebbSBoris BREZILLON 	irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR);
142*b1479ebbSBoris BREZILLON 	smr = irq_reg_readl(gc->reg_base + AT91_AIC5_SMR);
143*b1479ebbSBoris BREZILLON 	ret = aic_common_set_type(d, type, &smr);
144*b1479ebbSBoris BREZILLON 	if (!ret)
145*b1479ebbSBoris BREZILLON 		irq_reg_writel(smr, gc->reg_base + AT91_AIC5_SMR);
146*b1479ebbSBoris BREZILLON 	irq_gc_unlock(gc);
147*b1479ebbSBoris BREZILLON 
148*b1479ebbSBoris BREZILLON 	return ret;
149*b1479ebbSBoris BREZILLON }
150*b1479ebbSBoris BREZILLON 
151*b1479ebbSBoris BREZILLON #ifdef CONFIG_PM
152*b1479ebbSBoris BREZILLON static void aic5_suspend(struct irq_data *d)
153*b1479ebbSBoris BREZILLON {
154*b1479ebbSBoris BREZILLON 	struct irq_domain *domain = d->domain;
155*b1479ebbSBoris BREZILLON 	struct irq_domain_chip_generic *dgc = domain->gc;
156*b1479ebbSBoris BREZILLON 	struct irq_chip_generic *bgc = dgc->gc[0];
157*b1479ebbSBoris BREZILLON 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
158*b1479ebbSBoris BREZILLON 	int i;
159*b1479ebbSBoris BREZILLON 	u32 mask;
160*b1479ebbSBoris BREZILLON 
161*b1479ebbSBoris BREZILLON 	irq_gc_lock(bgc);
162*b1479ebbSBoris BREZILLON 	for (i = 0; i < dgc->irqs_per_chip; i++) {
163*b1479ebbSBoris BREZILLON 		mask = 1 << i;
164*b1479ebbSBoris BREZILLON 		if ((mask & gc->mask_cache) == (mask & gc->wake_active))
165*b1479ebbSBoris BREZILLON 			continue;
166*b1479ebbSBoris BREZILLON 
167*b1479ebbSBoris BREZILLON 		irq_reg_writel(i + gc->irq_base,
168*b1479ebbSBoris BREZILLON 			       bgc->reg_base + AT91_AIC5_SSR);
169*b1479ebbSBoris BREZILLON 		if (mask & gc->wake_active)
170*b1479ebbSBoris BREZILLON 			irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IECR);
171*b1479ebbSBoris BREZILLON 		else
172*b1479ebbSBoris BREZILLON 			irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IDCR);
173*b1479ebbSBoris BREZILLON 	}
174*b1479ebbSBoris BREZILLON 	irq_gc_unlock(bgc);
175*b1479ebbSBoris BREZILLON }
176*b1479ebbSBoris BREZILLON 
177*b1479ebbSBoris BREZILLON static void aic5_resume(struct irq_data *d)
178*b1479ebbSBoris BREZILLON {
179*b1479ebbSBoris BREZILLON 	struct irq_domain *domain = d->domain;
180*b1479ebbSBoris BREZILLON 	struct irq_domain_chip_generic *dgc = domain->gc;
181*b1479ebbSBoris BREZILLON 	struct irq_chip_generic *bgc = dgc->gc[0];
182*b1479ebbSBoris BREZILLON 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
183*b1479ebbSBoris BREZILLON 	int i;
184*b1479ebbSBoris BREZILLON 	u32 mask;
185*b1479ebbSBoris BREZILLON 
186*b1479ebbSBoris BREZILLON 	irq_gc_lock(bgc);
187*b1479ebbSBoris BREZILLON 	for (i = 0; i < dgc->irqs_per_chip; i++) {
188*b1479ebbSBoris BREZILLON 		mask = 1 << i;
189*b1479ebbSBoris BREZILLON 		if ((mask & gc->mask_cache) == (mask & gc->wake_active))
190*b1479ebbSBoris BREZILLON 			continue;
191*b1479ebbSBoris BREZILLON 
192*b1479ebbSBoris BREZILLON 		irq_reg_writel(i + gc->irq_base,
193*b1479ebbSBoris BREZILLON 			       bgc->reg_base + AT91_AIC5_SSR);
194*b1479ebbSBoris BREZILLON 		if (mask & gc->mask_cache)
195*b1479ebbSBoris BREZILLON 			irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IECR);
196*b1479ebbSBoris BREZILLON 		else
197*b1479ebbSBoris BREZILLON 			irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IDCR);
198*b1479ebbSBoris BREZILLON 	}
199*b1479ebbSBoris BREZILLON 	irq_gc_unlock(bgc);
200*b1479ebbSBoris BREZILLON }
201*b1479ebbSBoris BREZILLON 
202*b1479ebbSBoris BREZILLON static void aic5_pm_shutdown(struct irq_data *d)
203*b1479ebbSBoris BREZILLON {
204*b1479ebbSBoris BREZILLON 	struct irq_domain *domain = d->domain;
205*b1479ebbSBoris BREZILLON 	struct irq_domain_chip_generic *dgc = domain->gc;
206*b1479ebbSBoris BREZILLON 	struct irq_chip_generic *bgc = dgc->gc[0];
207*b1479ebbSBoris BREZILLON 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
208*b1479ebbSBoris BREZILLON 	int i;
209*b1479ebbSBoris BREZILLON 
210*b1479ebbSBoris BREZILLON 	irq_gc_lock(bgc);
211*b1479ebbSBoris BREZILLON 	for (i = 0; i < dgc->irqs_per_chip; i++) {
212*b1479ebbSBoris BREZILLON 		irq_reg_writel(i + gc->irq_base,
213*b1479ebbSBoris BREZILLON 			       bgc->reg_base + AT91_AIC5_SSR);
214*b1479ebbSBoris BREZILLON 		irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IDCR);
215*b1479ebbSBoris BREZILLON 		irq_reg_writel(1, bgc->reg_base + AT91_AIC5_ICCR);
216*b1479ebbSBoris BREZILLON 	}
217*b1479ebbSBoris BREZILLON 	irq_gc_unlock(bgc);
218*b1479ebbSBoris BREZILLON }
219*b1479ebbSBoris BREZILLON #else
220*b1479ebbSBoris BREZILLON #define aic5_suspend		NULL
221*b1479ebbSBoris BREZILLON #define aic5_resume		NULL
222*b1479ebbSBoris BREZILLON #define aic5_pm_shutdown	NULL
223*b1479ebbSBoris BREZILLON #endif /* CONFIG_PM */
224*b1479ebbSBoris BREZILLON 
225*b1479ebbSBoris BREZILLON static void __init aic5_hw_init(struct irq_domain *domain)
226*b1479ebbSBoris BREZILLON {
227*b1479ebbSBoris BREZILLON 	struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0);
228*b1479ebbSBoris BREZILLON 	int i;
229*b1479ebbSBoris BREZILLON 
230*b1479ebbSBoris BREZILLON 	/*
231*b1479ebbSBoris BREZILLON 	 * Perform 8 End Of Interrupt Command to make sure AIC
232*b1479ebbSBoris BREZILLON 	 * will not Lock out nIRQ
233*b1479ebbSBoris BREZILLON 	 */
234*b1479ebbSBoris BREZILLON 	for (i = 0; i < 8; i++)
235*b1479ebbSBoris BREZILLON 		irq_reg_writel(0, gc->reg_base + AT91_AIC5_EOICR);
236*b1479ebbSBoris BREZILLON 
237*b1479ebbSBoris BREZILLON 	/*
238*b1479ebbSBoris BREZILLON 	 * Spurious Interrupt ID in Spurious Vector Register.
239*b1479ebbSBoris BREZILLON 	 * When there is no current interrupt, the IRQ Vector Register
240*b1479ebbSBoris BREZILLON 	 * reads the value stored in AIC_SPU
241*b1479ebbSBoris BREZILLON 	 */
242*b1479ebbSBoris BREZILLON 	irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC5_SPU);
243*b1479ebbSBoris BREZILLON 
244*b1479ebbSBoris BREZILLON 	/* No debugging in AIC: Debug (Protect) Control Register */
245*b1479ebbSBoris BREZILLON 	irq_reg_writel(0, gc->reg_base + AT91_AIC5_DCR);
246*b1479ebbSBoris BREZILLON 
247*b1479ebbSBoris BREZILLON 	/* Disable and clear all interrupts initially */
248*b1479ebbSBoris BREZILLON 	for (i = 0; i < domain->revmap_size; i++) {
249*b1479ebbSBoris BREZILLON 		irq_reg_writel(i, gc->reg_base + AT91_AIC5_SSR);
250*b1479ebbSBoris BREZILLON 		irq_reg_writel(i, gc->reg_base + AT91_AIC5_SVR);
251*b1479ebbSBoris BREZILLON 		irq_reg_writel(1, gc->reg_base + AT91_AIC5_IDCR);
252*b1479ebbSBoris BREZILLON 		irq_reg_writel(1, gc->reg_base + AT91_AIC5_ICCR);
253*b1479ebbSBoris BREZILLON 	}
254*b1479ebbSBoris BREZILLON }
255*b1479ebbSBoris BREZILLON 
256*b1479ebbSBoris BREZILLON static int aic5_irq_domain_xlate(struct irq_domain *d,
257*b1479ebbSBoris BREZILLON 				 struct device_node *ctrlr,
258*b1479ebbSBoris BREZILLON 				 const u32 *intspec, unsigned int intsize,
259*b1479ebbSBoris BREZILLON 				 irq_hw_number_t *out_hwirq,
260*b1479ebbSBoris BREZILLON 				 unsigned int *out_type)
261*b1479ebbSBoris BREZILLON {
262*b1479ebbSBoris BREZILLON 	struct irq_domain_chip_generic *dgc = d->gc;
263*b1479ebbSBoris BREZILLON 	struct irq_chip_generic *gc;
264*b1479ebbSBoris BREZILLON 	unsigned smr;
265*b1479ebbSBoris BREZILLON 	int ret;
266*b1479ebbSBoris BREZILLON 
267*b1479ebbSBoris BREZILLON 	if (!dgc)
268*b1479ebbSBoris BREZILLON 		return -EINVAL;
269*b1479ebbSBoris BREZILLON 
270*b1479ebbSBoris BREZILLON 	ret = aic_common_irq_domain_xlate(d, ctrlr, intspec, intsize,
271*b1479ebbSBoris BREZILLON 					  out_hwirq, out_type);
272*b1479ebbSBoris BREZILLON 	if (ret)
273*b1479ebbSBoris BREZILLON 		return ret;
274*b1479ebbSBoris BREZILLON 
275*b1479ebbSBoris BREZILLON 	gc = dgc->gc[0];
276*b1479ebbSBoris BREZILLON 
277*b1479ebbSBoris BREZILLON 	irq_gc_lock(gc);
278*b1479ebbSBoris BREZILLON 	irq_reg_writel(*out_hwirq, gc->reg_base + AT91_AIC5_SSR);
279*b1479ebbSBoris BREZILLON 	smr = irq_reg_readl(gc->reg_base + AT91_AIC5_SMR);
280*b1479ebbSBoris BREZILLON 	ret = aic_common_set_priority(intspec[2], &smr);
281*b1479ebbSBoris BREZILLON 	if (!ret)
282*b1479ebbSBoris BREZILLON 		irq_reg_writel(intspec[2] | smr, gc->reg_base + AT91_AIC5_SMR);
283*b1479ebbSBoris BREZILLON 	irq_gc_unlock(gc);
284*b1479ebbSBoris BREZILLON 
285*b1479ebbSBoris BREZILLON 	return ret;
286*b1479ebbSBoris BREZILLON }
287*b1479ebbSBoris BREZILLON 
288*b1479ebbSBoris BREZILLON static const struct irq_domain_ops aic5_irq_ops = {
289*b1479ebbSBoris BREZILLON 	.map	= irq_map_generic_chip,
290*b1479ebbSBoris BREZILLON 	.xlate	= aic5_irq_domain_xlate,
291*b1479ebbSBoris BREZILLON };
292*b1479ebbSBoris BREZILLON 
293*b1479ebbSBoris BREZILLON static int __init aic5_of_init(struct device_node *node,
294*b1479ebbSBoris BREZILLON 			       struct device_node *parent,
295*b1479ebbSBoris BREZILLON 			       int nirqs)
296*b1479ebbSBoris BREZILLON {
297*b1479ebbSBoris BREZILLON 	struct irq_chip_generic *gc;
298*b1479ebbSBoris BREZILLON 	struct irq_domain *domain;
299*b1479ebbSBoris BREZILLON 	int nchips;
300*b1479ebbSBoris BREZILLON 	int i;
301*b1479ebbSBoris BREZILLON 
302*b1479ebbSBoris BREZILLON 	if (nirqs > NR_AIC5_IRQS)
303*b1479ebbSBoris BREZILLON 		return -EINVAL;
304*b1479ebbSBoris BREZILLON 
305*b1479ebbSBoris BREZILLON 	if (aic5_domain)
306*b1479ebbSBoris BREZILLON 		return -EEXIST;
307*b1479ebbSBoris BREZILLON 
308*b1479ebbSBoris BREZILLON 	domain = aic_common_of_init(node, &aic5_irq_ops, "atmel-aic5",
309*b1479ebbSBoris BREZILLON 				    nirqs);
310*b1479ebbSBoris BREZILLON 	if (IS_ERR(domain))
311*b1479ebbSBoris BREZILLON 		return PTR_ERR(domain);
312*b1479ebbSBoris BREZILLON 
313*b1479ebbSBoris BREZILLON 	aic5_domain = domain;
314*b1479ebbSBoris BREZILLON 	nchips = aic5_domain->revmap_size / 32;
315*b1479ebbSBoris BREZILLON 	for (i = 0; i < nchips; i++) {
316*b1479ebbSBoris BREZILLON 		gc = irq_get_domain_generic_chip(domain, i * 32);
317*b1479ebbSBoris BREZILLON 
318*b1479ebbSBoris BREZILLON 		gc->chip_types[0].regs.eoi = AT91_AIC5_EOICR;
319*b1479ebbSBoris BREZILLON 		gc->chip_types[0].chip.irq_mask = aic5_mask;
320*b1479ebbSBoris BREZILLON 		gc->chip_types[0].chip.irq_unmask = aic5_unmask;
321*b1479ebbSBoris BREZILLON 		gc->chip_types[0].chip.irq_retrigger = aic5_retrigger;
322*b1479ebbSBoris BREZILLON 		gc->chip_types[0].chip.irq_set_type = aic5_set_type;
323*b1479ebbSBoris BREZILLON 		gc->chip_types[0].chip.irq_suspend = aic5_suspend;
324*b1479ebbSBoris BREZILLON 		gc->chip_types[0].chip.irq_resume = aic5_resume;
325*b1479ebbSBoris BREZILLON 		gc->chip_types[0].chip.irq_pm_shutdown = aic5_pm_shutdown;
326*b1479ebbSBoris BREZILLON 	}
327*b1479ebbSBoris BREZILLON 
328*b1479ebbSBoris BREZILLON 	aic5_hw_init(domain);
329*b1479ebbSBoris BREZILLON 	set_handle_irq(aic5_handle);
330*b1479ebbSBoris BREZILLON 
331*b1479ebbSBoris BREZILLON 	return 0;
332*b1479ebbSBoris BREZILLON }
333*b1479ebbSBoris BREZILLON 
334*b1479ebbSBoris BREZILLON #define NR_SAMA5D3_IRQS		50
335*b1479ebbSBoris BREZILLON 
336*b1479ebbSBoris BREZILLON static int __init sama5d3_aic5_of_init(struct device_node *node,
337*b1479ebbSBoris BREZILLON 				       struct device_node *parent)
338*b1479ebbSBoris BREZILLON {
339*b1479ebbSBoris BREZILLON 	return aic5_of_init(node, parent, NR_SAMA5D3_IRQS);
340*b1479ebbSBoris BREZILLON }
341*b1479ebbSBoris BREZILLON IRQCHIP_DECLARE(sama5d3_aic5, "atmel,sama5d3-aic", sama5d3_aic5_of_init);
342