aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-at91/irq.c
diff options
context:
space:
mode:
authorNicolas Ferre <nicolas.ferre@atmel.com>2011-11-22 16:26:09 -0500
committerNicolas Ferre <nicolas.ferre@atmel.com>2012-03-01 07:29:00 -0500
commite261501d05bd2df244d31e0866b1e81776766ecf (patch)
treec0699ee7b1f2c8a58ff25c5dd2a0ab211a5b423d /arch/arm/mach-at91/irq.c
parent89d4a1753b6632327f18d6c8e0842b366b736621 (diff)
ARM: at91/aic: add irq domain and device tree support
Add an irqdomain for the AIC interrupt controller. The device tree support is mapping the registers and is using the irq_domain_add_legacy() to manage hwirq translation. The documentation is describing the meaning of the two cells required for using this "interrupt-controller" in a device tree node. Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Diffstat (limited to 'arch/arm/mach-at91/irq.c')
-rw-r--r--arch/arm/mach-at91/irq.c74
1 files changed, 61 insertions, 13 deletions
diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
index be6b639ecd7b..46682fafa96f 100644
--- a/arch/arm/mach-at91/irq.c
+++ b/arch/arm/mach-at91/irq.c
@@ -24,6 +24,12 @@
24#include <linux/module.h> 24#include <linux/module.h>
25#include <linux/mm.h> 25#include <linux/mm.h>
26#include <linux/types.h> 26#include <linux/types.h>
27#include <linux/irq.h>
28#include <linux/of.h>
29#include <linux/of_address.h>
30#include <linux/of_irq.h>
31#include <linux/irqdomain.h>
32#include <linux/err.h>
27 33
28#include <mach/hardware.h> 34#include <mach/hardware.h>
29#include <asm/irq.h> 35#include <asm/irq.h>
@@ -34,22 +40,24 @@
34#include <asm/mach/map.h> 40#include <asm/mach/map.h>
35 41
36void __iomem *at91_aic_base; 42void __iomem *at91_aic_base;
43static struct irq_domain *at91_aic_domain;
44static struct device_node *at91_aic_np;
37 45
38static void at91_aic_mask_irq(struct irq_data *d) 46static void at91_aic_mask_irq(struct irq_data *d)
39{ 47{
40 /* Disable interrupt on AIC */ 48 /* Disable interrupt on AIC */
41 at91_aic_write(AT91_AIC_IDCR, 1 << d->irq); 49 at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq);
42} 50}
43 51
44static void at91_aic_unmask_irq(struct irq_data *d) 52static void at91_aic_unmask_irq(struct irq_data *d)
45{ 53{
46 /* Enable interrupt on AIC */ 54 /* Enable interrupt on AIC */
47 at91_aic_write(AT91_AIC_IECR, 1 << d->irq); 55 at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq);
48} 56}
49 57
50unsigned int at91_extern_irq; 58unsigned int at91_extern_irq;
51 59
52#define is_extern_irq(irq) ((1 << (irq)) & at91_extern_irq) 60#define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq)
53 61
54static int at91_aic_set_type(struct irq_data *d, unsigned type) 62static int at91_aic_set_type(struct irq_data *d, unsigned type)
55{ 63{
@@ -63,13 +71,13 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type)
63 srctype = AT91_AIC_SRCTYPE_RISING; 71 srctype = AT91_AIC_SRCTYPE_RISING;
64 break; 72 break;
65 case IRQ_TYPE_LEVEL_LOW: 73 case IRQ_TYPE_LEVEL_LOW:
66 if ((d->irq == AT91_ID_FIQ) || is_extern_irq(d->irq)) /* only supported on external interrupts */ 74 if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */
67 srctype = AT91_AIC_SRCTYPE_LOW; 75 srctype = AT91_AIC_SRCTYPE_LOW;
68 else 76 else
69 return -EINVAL; 77 return -EINVAL;
70 break; 78 break;
71 case IRQ_TYPE_EDGE_FALLING: 79 case IRQ_TYPE_EDGE_FALLING:
72 if ((d->irq == AT91_ID_FIQ) || is_extern_irq(d->irq)) /* only supported on external interrupts */ 80 if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */
73 srctype = AT91_AIC_SRCTYPE_FALLING; 81 srctype = AT91_AIC_SRCTYPE_FALLING;
74 else 82 else
75 return -EINVAL; 83 return -EINVAL;
@@ -78,8 +86,8 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type)
78 return -EINVAL; 86 return -EINVAL;
79 } 87 }
80 88
81 smr = at91_aic_read(AT91_AIC_SMR(d->irq)) & ~AT91_AIC_SRCTYPE; 89 smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE;
82 at91_aic_write(AT91_AIC_SMR(d->irq), smr | srctype); 90 at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
83 return 0; 91 return 0;
84} 92}
85 93
@@ -90,13 +98,13 @@ static u32 backups;
90 98
91static int at91_aic_set_wake(struct irq_data *d, unsigned value) 99static int at91_aic_set_wake(struct irq_data *d, unsigned value)
92{ 100{
93 if (unlikely(d->irq >= 32)) 101 if (unlikely(d->hwirq >= NR_AIC_IRQS))
94 return -EINVAL; 102 return -EINVAL;
95 103
96 if (value) 104 if (value)
97 wakeups |= (1 << d->irq); 105 wakeups |= (1 << d->hwirq);
98 else 106 else
99 wakeups &= ~(1 << d->irq); 107 wakeups &= ~(1 << d->hwirq);
100 108
101 return 0; 109 return 0;
102} 110}
@@ -127,24 +135,64 @@ static struct irq_chip at91_aic_chip = {
127 .irq_set_wake = at91_aic_set_wake, 135 .irq_set_wake = at91_aic_set_wake,
128}; 136};
129 137
138#if defined(CONFIG_OF)
139static int __init __at91_aic_of_init(struct device_node *node,
140 struct device_node *parent)
141{
142 at91_aic_base = of_iomap(node, 0);
143 at91_aic_np = node;
144
145 return 0;
146}
147
148static const struct of_device_id aic_ids[] __initconst = {
149 { .compatible = "atmel,at91rm9200-aic", .data = __at91_aic_of_init },
150 { /*sentinel*/ }
151};
152
153static void __init at91_aic_of_init(void)
154{
155 of_irq_init(aic_ids);
156}
157#else
158static void __init at91_aic_of_init(void) {}
159#endif
160
130/* 161/*
131 * Initialize the AIC interrupt controller. 162 * Initialize the AIC interrupt controller.
132 */ 163 */
133void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS]) 164void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
134{ 165{
135 unsigned int i; 166 unsigned int i;
167 int irq_base;
136 168
137 at91_aic_base = ioremap(AT91_AIC, 512); 169 if (of_have_populated_dt())
170 at91_aic_of_init();
171 else
172 at91_aic_base = ioremap(AT91_AIC, 512);
138 173
139 if (!at91_aic_base) 174 if (!at91_aic_base)
140 panic("Impossible to ioremap AT91_AIC\n"); 175 panic("Unable to ioremap AIC registers\n");
176
177 /* Add irq domain for AIC */
178 irq_base = irq_alloc_descs(-1, 0, NR_AIC_IRQS, 0);
179 if (irq_base < 0) {
180 WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n");
181 irq_base = 0;
182 }
183 at91_aic_domain = irq_domain_add_legacy(at91_aic_np, NR_AIC_IRQS,
184 irq_base, 0,
185 &irq_domain_simple_ops, NULL);
186
187 if (!at91_aic_domain)
188 panic("Unable to add AIC irq domain\n");
141 189
142 /* 190 /*
143 * The IVR is used by macro get_irqnr_and_base to read and verify. 191 * The IVR is used by macro get_irqnr_and_base to read and verify.
144 * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred. 192 * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
145 */ 193 */
146 for (i = 0; i < NR_AIC_IRQS; i++) { 194 for (i = 0; i < NR_AIC_IRQS; i++) {
147 /* Put irq number in Source Vector Register: */ 195 /* Put hardware irq number in Source Vector Register: */
148 at91_aic_write(AT91_AIC_SVR(i), i); 196 at91_aic_write(AT91_AIC_SVR(i), i);
149 /* Active Low interrupt, with the specified priority */ 197 /* Active Low interrupt, with the specified priority */
150 at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]); 198 at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);