2 * linux/arch/arm/mach-at91/irq.c
4 * Copyright (C) 2004 SAN People
5 * Copyright (C) 2004 ATMEL
6 * Copyright (C) Rick Bronson
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <linux/init.h>
24 #include <linux/module.h>
26 #include <linux/types.h>
27 #include <linux/irq.h>
29 #include <linux/of_address.h>
30 #include <linux/of_irq.h>
31 #include <linux/irqdomain.h>
32 #include <linux/err.h>
33 #include <linux/slab.h>
35 #include <mach/hardware.h>
37 #include <asm/setup.h>
39 #include <asm/exception.h>
40 #include <asm/mach/arch.h>
41 #include <asm/mach/irq.h>
42 #include <asm/mach/map.h>
44 void __iomem
*at91_aic_base
;
45 static struct irq_domain
*at91_aic_domain
;
46 static struct device_node
*at91_aic_np
;
47 static unsigned int *at91_aic_irq_priorities
;
49 asmlinkage
void __exception_irq_entry
at91_aic_handle_irq(struct pt_regs
*regs
)
54 irqnr
= at91_aic_read(AT91_AIC_IVR
);
55 irqstat
= at91_aic_read(AT91_AIC_ISR
);
58 * ISR value is 0 when there is no current interrupt or when there is
59 * a spurious interrupt
62 at91_aic_write(AT91_AIC_EOICR
, 0);
64 handle_IRQ(irqnr
, regs
);
67 static void at91_aic_mask_irq(struct irq_data
*d
)
69 /* Disable interrupt on AIC */
70 at91_aic_write(AT91_AIC_IDCR
, 1 << d
->hwirq
);
73 static void at91_aic_unmask_irq(struct irq_data
*d
)
75 /* Enable interrupt on AIC */
76 at91_aic_write(AT91_AIC_IECR
, 1 << d
->hwirq
);
79 static void at91_aic_eoi(struct irq_data
*d
)
82 * Mark end-of-interrupt on AIC, the controller doesn't care about
83 * the value written. Moreover it's a write-only register.
85 at91_aic_write(AT91_AIC_EOICR
, 0);
88 unsigned int at91_extern_irq
;
90 #define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq)
92 static int at91_aic_set_type(struct irq_data
*d
, unsigned type
)
94 unsigned int smr
, srctype
;
97 case IRQ_TYPE_LEVEL_HIGH
:
98 srctype
= AT91_AIC_SRCTYPE_HIGH
;
100 case IRQ_TYPE_EDGE_RISING
:
101 srctype
= AT91_AIC_SRCTYPE_RISING
;
103 case IRQ_TYPE_LEVEL_LOW
:
104 if ((d
->hwirq
== AT91_ID_FIQ
) || is_extern_irq(d
->hwirq
)) /* only supported on external interrupts */
105 srctype
= AT91_AIC_SRCTYPE_LOW
;
109 case IRQ_TYPE_EDGE_FALLING
:
110 if ((d
->hwirq
== AT91_ID_FIQ
) || is_extern_irq(d
->hwirq
)) /* only supported on external interrupts */
111 srctype
= AT91_AIC_SRCTYPE_FALLING
;
119 smr
= at91_aic_read(AT91_AIC_SMR(d
->hwirq
)) & ~AT91_AIC_SRCTYPE
;
120 at91_aic_write(AT91_AIC_SMR(d
->hwirq
), smr
| srctype
);
129 static int at91_aic_set_wake(struct irq_data
*d
, unsigned value
)
131 if (unlikely(d
->hwirq
>= NR_AIC_IRQS
))
135 wakeups
|= (1 << d
->hwirq
);
137 wakeups
&= ~(1 << d
->hwirq
);
142 void at91_irq_suspend(void)
144 backups
= at91_aic_read(AT91_AIC_IMR
);
145 at91_aic_write(AT91_AIC_IDCR
, backups
);
146 at91_aic_write(AT91_AIC_IECR
, wakeups
);
149 void at91_irq_resume(void)
151 at91_aic_write(AT91_AIC_IDCR
, wakeups
);
152 at91_aic_write(AT91_AIC_IECR
, backups
);
156 #define at91_aic_set_wake NULL
159 static struct irq_chip at91_aic_chip
= {
161 .irq_mask
= at91_aic_mask_irq
,
162 .irq_unmask
= at91_aic_unmask_irq
,
163 .irq_set_type
= at91_aic_set_type
,
164 .irq_set_wake
= at91_aic_set_wake
,
165 .irq_eoi
= at91_aic_eoi
,
168 static void __init
at91_aic_hw_init(unsigned int spu_vector
)
173 * Perform 8 End Of Interrupt Command to make sure AIC
174 * will not Lock out nIRQ
176 for (i
= 0; i
< 8; i
++)
177 at91_aic_write(AT91_AIC_EOICR
, 0);
180 * Spurious Interrupt ID in Spurious Vector Register.
181 * When there is no current interrupt, the IRQ Vector Register
182 * reads the value stored in AIC_SPU
184 at91_aic_write(AT91_AIC_SPU
, spu_vector
);
186 /* No debugging in AIC: Debug (Protect) Control Register */
187 at91_aic_write(AT91_AIC_DCR
, 0);
189 /* Disable and clear all interrupts initially */
190 at91_aic_write(AT91_AIC_IDCR
, 0xFFFFFFFF);
191 at91_aic_write(AT91_AIC_ICCR
, 0xFFFFFFFF);
194 #if defined(CONFIG_OF)
195 static int at91_aic_irq_map(struct irq_domain
*h
, unsigned int virq
,
198 /* Put virq number in Source Vector Register */
199 at91_aic_write(AT91_AIC_SVR(hw
), virq
);
201 /* Active Low interrupt, with priority */
202 at91_aic_write(AT91_AIC_SMR(hw
),
203 AT91_AIC_SRCTYPE_LOW
| at91_aic_irq_priorities
[hw
]);
205 irq_set_chip_and_handler(virq
, &at91_aic_chip
, handle_fasteoi_irq
);
206 set_irq_flags(virq
, IRQF_VALID
| IRQF_PROBE
);
211 static int at91_aic_irq_domain_xlate(struct irq_domain
*d
, struct device_node
*ctrlr
,
212 const u32
*intspec
, unsigned int intsize
,
213 irq_hw_number_t
*out_hwirq
, unsigned int *out_type
)
215 if (WARN_ON(intsize
< 3))
217 if (WARN_ON(intspec
[0] >= NR_AIC_IRQS
))
219 if (WARN_ON((intspec
[2] < AT91_AIC_IRQ_MIN_PRIORITY
)
220 || (intspec
[2] > AT91_AIC_IRQ_MAX_PRIORITY
)))
223 *out_hwirq
= intspec
[0];
224 *out_type
= intspec
[1] & IRQ_TYPE_SENSE_MASK
;
225 at91_aic_irq_priorities
[*out_hwirq
] = intspec
[2];
230 static struct irq_domain_ops at91_aic_irq_ops
= {
231 .map
= at91_aic_irq_map
,
232 .xlate
= at91_aic_irq_domain_xlate
,
235 int __init
at91_aic_of_init(struct device_node
*node
,
236 struct device_node
*parent
)
238 struct property
*prop
;
242 at91_aic_irq_priorities
= kzalloc(NR_AIC_IRQS
243 * sizeof(*at91_aic_irq_priorities
),
245 if (!at91_aic_irq_priorities
)
248 at91_aic_base
= of_iomap(node
, 0);
251 at91_aic_domain
= irq_domain_add_linear(at91_aic_np
, NR_AIC_IRQS
,
252 &at91_aic_irq_ops
, NULL
);
253 if (!at91_aic_domain
)
254 panic("Unable to add AIC irq domain (DT)\n");
257 of_property_for_each_u32(node
, "atmel,external-irqs", prop
, p
, val
) {
259 pr_warn("AIC: external irq %d > 31 skip it\n", val
);
261 at91_extern_irq
|= (1 << val
);
264 irq_set_default_host(at91_aic_domain
);
266 at91_aic_hw_init(NR_AIC_IRQS
);
273 * Initialize the AIC interrupt controller.
275 void __init
at91_aic_init(unsigned int priority
[NR_AIC_IRQS
])
280 at91_aic_base
= ioremap(AT91_AIC
, 512);
282 panic("Unable to ioremap AIC registers\n");
284 /* Add irq domain for AIC */
285 irq_base
= irq_alloc_descs(-1, 0, NR_AIC_IRQS
, 0);
287 WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n");
290 at91_aic_domain
= irq_domain_add_legacy(at91_aic_np
, NR_AIC_IRQS
,
292 &irq_domain_simple_ops
, NULL
);
294 if (!at91_aic_domain
)
295 panic("Unable to add AIC irq domain\n");
297 irq_set_default_host(at91_aic_domain
);
300 * The IVR is used by macro get_irqnr_and_base to read and verify.
301 * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
303 for (i
= 0; i
< NR_AIC_IRQS
; i
++) {
304 /* Put hardware irq number in Source Vector Register: */
305 at91_aic_write(AT91_AIC_SVR(i
), i
);
306 /* Active Low interrupt, with the specified priority */
307 at91_aic_write(AT91_AIC_SMR(i
), AT91_AIC_SRCTYPE_LOW
| priority
[i
]);
309 irq_set_chip_and_handler(i
, &at91_aic_chip
, handle_fasteoi_irq
);
310 set_irq_flags(i
, IRQF_VALID
| IRQF_PROBE
);
313 at91_aic_hw_init(NR_AIC_IRQS
);