diff options
Diffstat (limited to 'arch/arm/mach-lpc32xx/irq.c')
-rw-r--r-- | arch/arm/mach-lpc32xx/irq.c | 103 |
1 files changed, 80 insertions, 23 deletions
diff --git a/arch/arm/mach-lpc32xx/irq.c b/arch/arm/mach-lpc32xx/irq.c index 4eae566dfdc..5b1cc35e6fb 100644 --- a/arch/arm/mach-lpc32xx/irq.c +++ b/arch/arm/mach-lpc32xx/irq.c @@ -22,6 +22,11 @@ #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; @@ -118,6 +126,10 @@ static const struct lpc32xx_event_info lpc32xx_events[NR_IRQS] = { .event_group = &lpc32xx_event_pin_regs, .mask = LPC32XX_CLKPWR_EXTSRC_GPI_06_BIT, }, + [IRQ_LPC32XX_GPI_28] = { + .event_group = &lpc32xx_event_pin_regs, + .mask = LPC32XX_CLKPWR_EXTSRC_GPI_28_BIT, + }, [IRQ_LPC32XX_GPIO_00] = { .event_group = &lpc32xx_event_int_regs, .mask = LPC32XX_CLKPWR_INTSRC_GPIO_00_BIT, @@ -146,6 +158,10 @@ static const struct lpc32xx_event_info lpc32xx_events[NR_IRQS] = { .event_group = &lpc32xx_event_int_regs, .mask = LPC32XX_CLKPWR_INTSRC_KEY_BIT, }, + [IRQ_LPC32XX_ETHERNET] = { + .event_group = &lpc32xx_event_int_regs, + .mask = LPC32XX_CLKPWR_INTSRC_MAC_BIT, + }, [IRQ_LPC32XX_USB_OTG_ATX] = { .event_group = &lpc32xx_event_int_regs, .mask = LPC32XX_CLKPWR_INTSRC_USBATXINT_BIT, @@ -195,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)); @@ -205,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)); @@ -215,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, @@ -266,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 */ @@ -290,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; } @@ -299,24 +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; - else - eventreg &= ~lpc32xx_events[d->irq].mask; + eventreg |= lpc32xx_events[d->hwirq].mask; + else { + eventreg &= ~lpc32xx_events[d->hwirq].mask; + + /* + * When disabling the wakeup, clear the latched + * event + */ + __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; } @@ -336,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, @@ -369,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)); @@ -380,13 +420,15 @@ void __init lpc32xx_init_irq(void) /* Setup SIC1 */ __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC1_BASE)); - __raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC1_BASE)); - __raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC1_BASE)); + __raw_writel(SIC1_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC1_BASE)); + __raw_writel(SIC1_ATR_DEFAULT, + LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC1_BASE)); /* Setup SIC2 */ __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC2_BASE)); - __raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC2_BASE)); - __raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC2_BASE)); + __raw_writel(SIC2_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC2_BASE)); + __raw_writel(SIC2_ATR_DEFAULT, + LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC2_BASE)); /* Configure supported IRQ's */ for (i = 0; i < NR_IRQS; i++) { @@ -429,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"); } |