aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-at91/irq.c
diff options
context:
space:
mode:
authorNicolas Ferre <nicolas.ferre@atmel.com>2012-02-14 12:08:14 -0500
committerNicolas Ferre <nicolas.ferre@atmel.com>2012-03-01 07:29:03 -0500
commit8014d6f4dd074d4d248d3de7f63348fa2568476b (patch)
tree7803070e93c4955e7b37eb4f4e81e4d1411aeb98 /arch/arm/mach-at91/irq.c
parent34bc485ca143c4773fc2afbbeb41e50f86445d0d (diff)
ARM: at91: AIC and GPIO IRQ device tree initialization
Both AIC and GPIO controllers are now using the standard of_irq_init() function to initialize IRQs in case of DT use. The DT specific initialization functions are now separated from the non-DT case and are now using "linear" irq domains. The .map() irqdomain operation is responsible for positioning the IRQ handlers. In AIC case, the Linux IRQ number is directly programmed in the hardware to avoid an additional reverse mapping operation. The AIC position its irq domain as the "default" irq domain. For DT case, the priority is not yet filled in the SMR. It will be the subject of another patch. Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Diffstat (limited to 'arch/arm/mach-at91/irq.c')
-rw-r--r--arch/arm/mach-at91/irq.c90
1 files changed, 58 insertions, 32 deletions
diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
index 46682fafa96f..cfcfcbe36269 100644
--- a/arch/arm/mach-at91/irq.c
+++ b/arch/arm/mach-at91/irq.c
@@ -135,27 +135,70 @@ static struct irq_chip at91_aic_chip = {
135 .irq_set_wake = at91_aic_set_wake, 135 .irq_set_wake = at91_aic_set_wake,
136}; 136};
137 137
138static void __init at91_aic_hw_init(unsigned int spu_vector)
139{
140 int i;
141
142 /*
143 * Perform 8 End Of Interrupt Command to make sure AIC
144 * will not Lock out nIRQ
145 */
146 for (i = 0; i < 8; i++)
147 at91_aic_write(AT91_AIC_EOICR, 0);
148
149 /*
150 * Spurious Interrupt ID in Spurious Vector Register.
151 * When there is no current interrupt, the IRQ Vector Register
152 * reads the value stored in AIC_SPU
153 */
154 at91_aic_write(AT91_AIC_SPU, spu_vector);
155
156 /* No debugging in AIC: Debug (Protect) Control Register */
157 at91_aic_write(AT91_AIC_DCR, 0);
158
159 /* Disable and clear all interrupts initially */
160 at91_aic_write(AT91_AIC_IDCR, 0xFFFFFFFF);
161 at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
162}
163
138#if defined(CONFIG_OF) 164#if defined(CONFIG_OF)
139static int __init __at91_aic_of_init(struct device_node *node, 165static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
140 struct device_node *parent) 166 irq_hw_number_t hw)
141{ 167{
142 at91_aic_base = of_iomap(node, 0); 168 /* Put virq number in Source Vector Register */
143 at91_aic_np = node; 169 at91_aic_write(AT91_AIC_SVR(hw), virq);
170
171 /* Active Low interrupt, without priority */
172 at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW);
173
174 irq_set_chip_and_handler(virq, &at91_aic_chip, handle_level_irq);
175 set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
144 176
145 return 0; 177 return 0;
146} 178}
147 179
148static const struct of_device_id aic_ids[] __initconst = { 180static struct irq_domain_ops at91_aic_irq_ops = {
149 { .compatible = "atmel,at91rm9200-aic", .data = __at91_aic_of_init }, 181 .map = at91_aic_irq_map,
150 { /*sentinel*/ } 182 .xlate = irq_domain_xlate_twocell,
151}; 183};
152 184
153static void __init at91_aic_of_init(void) 185int __init at91_aic_of_init(struct device_node *node,
186 struct device_node *parent)
154{ 187{
155 of_irq_init(aic_ids); 188 at91_aic_base = of_iomap(node, 0);
189 at91_aic_np = node;
190
191 at91_aic_domain = irq_domain_add_linear(at91_aic_np, NR_AIC_IRQS,
192 &at91_aic_irq_ops, NULL);
193 if (!at91_aic_domain)
194 panic("Unable to add AIC irq domain (DT)\n");
195
196 irq_set_default_host(at91_aic_domain);
197
198 at91_aic_hw_init(NR_AIC_IRQS);
199
200 return 0;
156} 201}
157#else
158static void __init at91_aic_of_init(void) {}
159#endif 202#endif
160 203
161/* 204/*
@@ -166,11 +209,7 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
166 unsigned int i; 209 unsigned int i;
167 int irq_base; 210 int irq_base;
168 211
169 if (of_have_populated_dt()) 212 at91_aic_base = ioremap(AT91_AIC, 512);
170 at91_aic_of_init();
171 else
172 at91_aic_base = ioremap(AT91_AIC, 512);
173
174 if (!at91_aic_base) 213 if (!at91_aic_base)
175 panic("Unable to ioremap AIC registers\n"); 214 panic("Unable to ioremap AIC registers\n");
176 215
@@ -187,6 +226,8 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
187 if (!at91_aic_domain) 226 if (!at91_aic_domain)
188 panic("Unable to add AIC irq domain\n"); 227 panic("Unable to add AIC irq domain\n");
189 228
229 irq_set_default_host(at91_aic_domain);
230
190 /* 231 /*
191 * The IVR is used by macro get_irqnr_and_base to read and verify. 232 * The IVR is used by macro get_irqnr_and_base to read and verify.
192 * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred. 233 * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
@@ -199,22 +240,7 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
199 240
200 irq_set_chip_and_handler(i, &at91_aic_chip, handle_level_irq); 241 irq_set_chip_and_handler(i, &at91_aic_chip, handle_level_irq);
201 set_irq_flags(i, IRQF_VALID | IRQF_PROBE); 242 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
202
203 /* Perform 8 End Of Interrupt Command to make sure AIC will not Lock out nIRQ */
204 if (i < 8)
205 at91_aic_write(AT91_AIC_EOICR, 0);
206 } 243 }
207 244
208 /* 245 at91_aic_hw_init(NR_AIC_IRQS);
209 * Spurious Interrupt ID in Spurious Vector Register is NR_AIC_IRQS
210 * When there is no current interrupt, the IRQ Vector Register reads the value stored in AIC_SPU
211 */
212 at91_aic_write(AT91_AIC_SPU, NR_AIC_IRQS);
213
214 /* No debugging in AIC: Debug (Protect) Control Register */
215 at91_aic_write(AT91_AIC_DCR, 0);
216
217 /* Disable and clear all interrupts initially */
218 at91_aic_write(AT91_AIC_IDCR, 0xFFFFFFFF);
219 at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
220} 246}