aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-at91/irq.c
diff options
context:
space:
mode:
authorNicolas Ferre <nicolas.ferre@atmel.com>2012-02-14 18:08:14 +0100
committerNicolas Ferre <nicolas.ferre@atmel.com>2012-03-01 13:29:03 +0100
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 46682fafa96..cfcfcbe3626 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 = {
.irq_set_wake = at91_aic_set_wake,
};
+static void __init at91_aic_hw_init(unsigned int spu_vector)
+{
+ int i;
+
+ /*
+ * Perform 8 End Of Interrupt Command to make sure AIC
+ * will not Lock out nIRQ
+ */
+ for (i = 0; i < 8; i++)
+ at91_aic_write(AT91_AIC_EOICR, 0);
+
+ /*
+ * Spurious Interrupt ID in Spurious Vector Register.
+ * When there is no current interrupt, the IRQ Vector Register
+ * reads the value stored in AIC_SPU
+ */
+ at91_aic_write(AT91_AIC_SPU, spu_vector);
+
+ /* No debugging in AIC: Debug (Protect) Control Register */
+ at91_aic_write(AT91_AIC_DCR, 0);
+
+ /* Disable and clear all interrupts initially */
+ at91_aic_write(AT91_AIC_IDCR, 0xFFFFFFFF);
+ at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
+}
+
#if defined(CONFIG_OF)
-static int __init __at91_aic_of_init(struct device_node *node,
- struct device_node *parent)
+static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
{
- at91_aic_base = of_iomap(node, 0);
- at91_aic_np = node;
+ /* Put virq number in Source Vector Register */
+ at91_aic_write(AT91_AIC_SVR(hw), virq);
+
+ /* Active Low interrupt, without priority */
+ at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW);
+
+ irq_set_chip_and_handler(virq, &at91_aic_chip, handle_level_irq);
+ set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
return 0;
}
-static const struct of_device_id aic_ids[] __initconst = {
- { .compatible = "atmel,at91rm9200-aic", .data = __at91_aic_of_init },
- { /*sentinel*/ }
+static struct irq_domain_ops at91_aic_irq_ops = {
+ .map = at91_aic_irq_map,
+ .xlate = irq_domain_xlate_twocell,
};
-static void __init at91_aic_of_init(void)
+int __init at91_aic_of_init(struct device_node *node,
+ struct device_node *parent)
{
- of_irq_init(aic_ids);
+ at91_aic_base = of_iomap(node, 0);
+ at91_aic_np = node;
+
+ at91_aic_domain = irq_domain_add_linear(at91_aic_np, NR_AIC_IRQS,
+ &at91_aic_irq_ops, NULL);
+ if (!at91_aic_domain)
+ panic("Unable to add AIC irq domain (DT)\n");
+
+ irq_set_default_host(at91_aic_domain);
+
+ at91_aic_hw_init(NR_AIC_IRQS);
+
+ return 0;
}
-#else
-static void __init at91_aic_of_init(void) {}
#endif
/*
@@ -166,11 +209,7 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
unsigned int i;
int irq_base;
- if (of_have_populated_dt())
- at91_aic_of_init();
- else
- at91_aic_base = ioremap(AT91_AIC, 512);
-
+ at91_aic_base = ioremap(AT91_AIC, 512);
if (!at91_aic_base)
panic("Unable to ioremap AIC registers\n");
@@ -187,6 +226,8 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
if (!at91_aic_domain)
panic("Unable to add AIC irq domain\n");
+ irq_set_default_host(at91_aic_domain);
+
/*
* The IVR is used by macro get_irqnr_and_base to read and verify.
* 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])
irq_set_chip_and_handler(i, &at91_aic_chip, handle_level_irq);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
-
- /* Perform 8 End Of Interrupt Command to make sure AIC will not Lock out nIRQ */
- if (i < 8)
- at91_aic_write(AT91_AIC_EOICR, 0);
}
- /*
- * Spurious Interrupt ID in Spurious Vector Register is NR_AIC_IRQS
- * When there is no current interrupt, the IRQ Vector Register reads the value stored in AIC_SPU
- */
- at91_aic_write(AT91_AIC_SPU, NR_AIC_IRQS);
-
- /* No debugging in AIC: Debug (Protect) Control Register */
- at91_aic_write(AT91_AIC_DCR, 0);
-
- /* Disable and clear all interrupts initially */
- at91_aic_write(AT91_AIC_IDCR, 0xFFFFFFFF);
- at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
+ at91_aic_hw_init(NR_AIC_IRQS);
}