]> Pileus Git - ~andy/linux/blobdiff - arch/arm/mach-lpc32xx/irq.c
Merge tag 'gpio-for-v3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[~andy/linux] / arch / arm / mach-lpc32xx / irq.c
index d080cb1123dd184bef219710a730df47e123c27e..5b1cc35e6fba8603ab8c7faf5b25c09e6fd84eb7 100644 (file)
 #include <linux/irq.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
 
 #include <mach/irqs.h>
 #include <mach/hardware.h>
@@ -44,6 +49,9 @@
 #define SIC1_ATR_DEFAULT       0x00026000
 #define SIC2_ATR_DEFAULT       0x00000000
 
+static struct irq_domain *lpc32xx_mic_domain;
+static struct device_node *lpc32xx_mic_np;
+
 struct lpc32xx_event_group_regs {
        void __iomem *enab_reg;
        void __iomem *edge_reg;
@@ -203,7 +211,7 @@ static void lpc32xx_mask_irq(struct irq_data *d)
 {
        unsigned int reg, ctrl, mask;
 
-       get_controller(d->irq, &ctrl, &mask);
+       get_controller(d->hwirq, &ctrl, &mask);
 
        reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) & ~mask;
        __raw_writel(reg, LPC32XX_INTC_MASK(ctrl));
@@ -213,7 +221,7 @@ static void lpc32xx_unmask_irq(struct irq_data *d)
 {
        unsigned int reg, ctrl, mask;
 
-       get_controller(d->irq, &ctrl, &mask);
+       get_controller(d->hwirq, &ctrl, &mask);
 
        reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) | mask;
        __raw_writel(reg, LPC32XX_INTC_MASK(ctrl));
@@ -223,14 +231,14 @@ static void lpc32xx_ack_irq(struct irq_data *d)
 {
        unsigned int ctrl, mask;
 
-       get_controller(d->irq, &ctrl, &mask);
+       get_controller(d->hwirq, &ctrl, &mask);
 
        __raw_writel(mask, LPC32XX_INTC_RAW_STAT(ctrl));
 
        /* Also need to clear pending wake event */
-       if (lpc32xx_events[d->irq].mask != 0)
-               __raw_writel(lpc32xx_events[d->irq].mask,
-                       lpc32xx_events[d->irq].event_group->rawstat_reg);
+       if (lpc32xx_events[d->hwirq].mask != 0)
+               __raw_writel(lpc32xx_events[d->hwirq].mask,
+                       lpc32xx_events[d->hwirq].event_group->rawstat_reg);
 }
 
 static void __lpc32xx_set_irq_type(unsigned int irq, int use_high_level,
@@ -274,22 +282,22 @@ static int lpc32xx_set_irq_type(struct irq_data *d, unsigned int type)
        switch (type) {
        case IRQ_TYPE_EDGE_RISING:
                /* Rising edge sensitive */
-               __lpc32xx_set_irq_type(d->irq, 1, 1);
+               __lpc32xx_set_irq_type(d->hwirq, 1, 1);
                break;
 
        case IRQ_TYPE_EDGE_FALLING:
                /* Falling edge sensitive */
-               __lpc32xx_set_irq_type(d->irq, 0, 1);
+               __lpc32xx_set_irq_type(d->hwirq, 0, 1);
                break;
 
        case IRQ_TYPE_LEVEL_LOW:
                /* Low level sensitive */
-               __lpc32xx_set_irq_type(d->irq, 0, 0);
+               __lpc32xx_set_irq_type(d->hwirq, 0, 0);
                break;
 
        case IRQ_TYPE_LEVEL_HIGH:
                /* High level sensitive */
-               __lpc32xx_set_irq_type(d->irq, 1, 0);
+               __lpc32xx_set_irq_type(d->hwirq, 1, 0);
                break;
 
        /* Other modes are not supported */
@@ -298,7 +306,7 @@ static int lpc32xx_set_irq_type(struct irq_data *d, unsigned int type)
        }
 
        /* Ok to use the level handler for all types */
-       irq_set_handler(d->irq, handle_level_irq);
+       irq_set_handler(d->hwirq, handle_level_irq);
 
        return 0;
 }
@@ -307,33 +315,33 @@ static int lpc32xx_irq_wake(struct irq_data *d, unsigned int state)
 {
        unsigned long eventreg;
 
-       if (lpc32xx_events[d->irq].mask != 0) {
-               eventreg = __raw_readl(lpc32xx_events[d->irq].
+       if (lpc32xx_events[d->hwirq].mask != 0) {
+               eventreg = __raw_readl(lpc32xx_events[d->hwirq].
                        event_group->enab_reg);
 
                if (state)
-                       eventreg |= lpc32xx_events[d->irq].mask;
+                       eventreg |= lpc32xx_events[d->hwirq].mask;
                else {
-                       eventreg &= ~lpc32xx_events[d->irq].mask;
+                       eventreg &= ~lpc32xx_events[d->hwirq].mask;
 
                        /*
                         * When disabling the wakeup, clear the latched
                         * event
                         */
-                       __raw_writel(lpc32xx_events[d->irq].mask,
-                               lpc32xx_events[d->irq].
+                       __raw_writel(lpc32xx_events[d->hwirq].mask,
+                               lpc32xx_events[d->hwirq].
                                event_group->rawstat_reg);
                }
 
                __raw_writel(eventreg,
-                       lpc32xx_events[d->irq].event_group->enab_reg);
+                       lpc32xx_events[d->hwirq].event_group->enab_reg);
 
                return 0;
        }
 
        /* Clear event */
-       __raw_writel(lpc32xx_events[d->irq].mask,
-               lpc32xx_events[d->irq].event_group->rawstat_reg);
+       __raw_writel(lpc32xx_events[d->hwirq].mask,
+               lpc32xx_events[d->hwirq].event_group->rawstat_reg);
 
        return -ENODEV;
 }
@@ -353,6 +361,7 @@ static void __init lpc32xx_set_default_mappings(unsigned int apr,
 }
 
 static struct irq_chip lpc32xx_irq_chip = {
+       .name = "MIC",
        .irq_ack = lpc32xx_ack_irq,
        .irq_mask = lpc32xx_mask_irq,
        .irq_unmask = lpc32xx_unmask_irq,
@@ -386,9 +395,23 @@ static void lpc32xx_sic2_handler(unsigned int irq, struct irq_desc *desc)
        }
 }
 
+static int __init __lpc32xx_mic_of_init(struct device_node *node,
+                                       struct device_node *parent)
+{
+       lpc32xx_mic_np = node;
+
+       return 0;
+}
+
+static const struct of_device_id mic_of_match[] __initconst = {
+       { .compatible = "nxp,lpc3220-mic", .data = __lpc32xx_mic_of_init },
+       { }
+};
+
 void __init lpc32xx_init_irq(void)
 {
        unsigned int i;
+       int irq_base;
 
        /* Setup MIC */
        __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_MIC_BASE));
@@ -448,4 +471,19 @@ void __init lpc32xx_init_irq(void)
                LPC32XX_CLKPWR_PIN_RS);
        __raw_writel(__raw_readl(LPC32XX_CLKPWR_INT_RS),
                LPC32XX_CLKPWR_INT_RS);
+
+       of_irq_init(mic_of_match);
+
+       irq_base = irq_alloc_descs(-1, 0, NR_IRQS, 0);
+       if (irq_base < 0) {
+               pr_warn("Cannot allocate irq_descs, assuming pre-allocated\n");
+               irq_base = 0;
+       }
+
+       lpc32xx_mic_domain = irq_domain_add_legacy(lpc32xx_mic_np, NR_IRQS,
+                                                  irq_base, 0,
+                                                  &irq_domain_simple_ops,
+                                                  NULL);
+       if (!lpc32xx_mic_domain)
+               panic("Unable to add MIC irq domain\n");
 }