diff options
author | Nicolas Ferre <nicolas.ferre@atmel.com> | 2011-11-22 16:26:09 -0500 |
---|---|---|
committer | Nicolas Ferre <nicolas.ferre@atmel.com> | 2012-03-01 07:29:00 -0500 |
commit | e261501d05bd2df244d31e0866b1e81776766ecf (patch) | |
tree | c0699ee7b1f2c8a58ff25c5dd2a0ab211a5b423d /arch/arm/mach-at91/irq.c | |
parent | 89d4a1753b6632327f18d6c8e0842b366b736621 (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.c | 74 |
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 | ||
36 | void __iomem *at91_aic_base; | 42 | void __iomem *at91_aic_base; |
43 | static struct irq_domain *at91_aic_domain; | ||
44 | static struct device_node *at91_aic_np; | ||
37 | 45 | ||
38 | static void at91_aic_mask_irq(struct irq_data *d) | 46 | static 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 | ||
44 | static void at91_aic_unmask_irq(struct irq_data *d) | 52 | static 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 | ||
50 | unsigned int at91_extern_irq; | 58 | unsigned 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 | ||
54 | static int at91_aic_set_type(struct irq_data *d, unsigned type) | 62 | static 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 | ||
91 | static int at91_aic_set_wake(struct irq_data *d, unsigned value) | 99 | static 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) | ||
139 | static 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 | |||
148 | static const struct of_device_id aic_ids[] __initconst = { | ||
149 | { .compatible = "atmel,at91rm9200-aic", .data = __at91_aic_of_init }, | ||
150 | { /*sentinel*/ } | ||
151 | }; | ||
152 | |||
153 | static void __init at91_aic_of_init(void) | ||
154 | { | ||
155 | of_irq_init(aic_ids); | ||
156 | } | ||
157 | #else | ||
158 | static 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 | */ |
133 | void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS]) | 164 | void __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]); |