diff options
Diffstat (limited to 'arch/arm/mach-sa1100/irq.c')
-rw-r--r-- | arch/arm/mach-sa1100/irq.c | 229 |
1 files changed, 130 insertions, 99 deletions
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c index 2124f1fc2fbe..63e2901db416 100644 --- a/arch/arm/mach-sa1100/irq.c +++ b/arch/arm/mach-sa1100/irq.c @@ -14,17 +14,73 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/ioport.h> #include <linux/syscore_ops.h> #include <mach/hardware.h> #include <mach/irqs.h> #include <asm/mach/irq.h> +#include <asm/exception.h> #include "generic.h" /* + * We don't need to ACK IRQs on the SA1100 unless they're GPIOs + * this is for internal IRQs i.e. from IRQ LCD to RTCAlrm. + */ +static void sa1100_mask_irq(struct irq_data *d) +{ + ICMR &= ~BIT(d->hwirq); +} + +static void sa1100_unmask_irq(struct irq_data *d) +{ + ICMR |= BIT(d->hwirq); +} + +/* + * Apart form GPIOs, only the RTC alarm can be a wakeup event. + */ +static int sa1100_set_wake(struct irq_data *d, unsigned int on) +{ + if (BIT(d->hwirq) == IC_RTCAlrm) { + if (on) + PWER |= PWER_RTC; + else + PWER &= ~PWER_RTC; + return 0; + } + return -EINVAL; +} + +static struct irq_chip sa1100_normal_chip = { + .name = "SC", + .irq_ack = sa1100_mask_irq, + .irq_mask = sa1100_mask_irq, + .irq_unmask = sa1100_unmask_irq, + .irq_set_wake = sa1100_set_wake, +}; + +static int sa1100_normal_irqdomain_map(struct irq_domain *d, + unsigned int irq, irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, &sa1100_normal_chip, + handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + + return 0; +} + +static struct irq_domain_ops sa1100_normal_irqdomain_ops = { + .map = sa1100_normal_irqdomain_map, + .xlate = irq_domain_xlate_onetwocell, +}; + +static struct irq_domain *sa1100_normal_irqdomain; + +/* * SA1100 GPIO edge detection for IRQs: * IRQs are generated on Falling-Edge, Rising-Edge, or both. * Use this instead of directly setting GRER/GFER. @@ -33,20 +89,11 @@ static int GPIO_IRQ_rising_edge; static int GPIO_IRQ_falling_edge; static int GPIO_IRQ_mask = (1 << 11) - 1; -/* - * To get the GPIO number from an IRQ number - */ -#define GPIO_11_27_IRQ(i) ((i) - 21) -#define GPIO11_27_MASK(irq) (1 << GPIO_11_27_IRQ(irq)) - static int sa1100_gpio_type(struct irq_data *d, unsigned int type) { unsigned int mask; - if (d->irq <= 10) - mask = 1 << d->irq; - else - mask = GPIO11_27_MASK(d->irq); + mask = BIT(d->hwirq); if (type == IRQ_TYPE_PROBE) { if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask) @@ -70,41 +117,51 @@ static int sa1100_gpio_type(struct irq_data *d, unsigned int type) } /* - * GPIO IRQs must be acknowledged. This is for IRQs from 0 to 10. + * GPIO IRQs must be acknowledged. */ -static void sa1100_low_gpio_ack(struct irq_data *d) -{ - GEDR = (1 << d->irq); -} - -static void sa1100_low_gpio_mask(struct irq_data *d) -{ - ICMR &= ~(1 << d->irq); -} - -static void sa1100_low_gpio_unmask(struct irq_data *d) +static void sa1100_gpio_ack(struct irq_data *d) { - ICMR |= 1 << d->irq; + GEDR = BIT(d->hwirq); } -static int sa1100_low_gpio_wake(struct irq_data *d, unsigned int on) +static int sa1100_gpio_wake(struct irq_data *d, unsigned int on) { if (on) - PWER |= 1 << d->irq; + PWER |= BIT(d->hwirq); else - PWER &= ~(1 << d->irq); + PWER &= ~BIT(d->hwirq); return 0; } +/* + * This is for IRQs from 0 to 10. + */ static struct irq_chip sa1100_low_gpio_chip = { .name = "GPIO-l", - .irq_ack = sa1100_low_gpio_ack, - .irq_mask = sa1100_low_gpio_mask, - .irq_unmask = sa1100_low_gpio_unmask, + .irq_ack = sa1100_gpio_ack, + .irq_mask = sa1100_mask_irq, + .irq_unmask = sa1100_unmask_irq, .irq_set_type = sa1100_gpio_type, - .irq_set_wake = sa1100_low_gpio_wake, + .irq_set_wake = sa1100_gpio_wake, +}; + +static int sa1100_low_gpio_irqdomain_map(struct irq_domain *d, + unsigned int irq, irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, &sa1100_low_gpio_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + + return 0; +} + +static struct irq_domain_ops sa1100_low_gpio_irqdomain_ops = { + .map = sa1100_low_gpio_irqdomain_map, + .xlate = irq_domain_xlate_onetwocell, }; +static struct irq_domain *sa1100_low_gpio_irqdomain; + /* * IRQ11 (GPIO11 through 27) handler. We enter here with the * irq_controller_lock held, and IRQs disabled. Decode the IRQ @@ -141,16 +198,9 @@ sa1100_high_gpio_handler(unsigned int irq, struct irq_desc *desc) * In addition, the IRQs are all collected up into one bit in the * interrupt controller registers. */ -static void sa1100_high_gpio_ack(struct irq_data *d) -{ - unsigned int mask = GPIO11_27_MASK(d->irq); - - GEDR = mask; -} - static void sa1100_high_gpio_mask(struct irq_data *d) { - unsigned int mask = GPIO11_27_MASK(d->irq); + unsigned int mask = BIT(d->hwirq); GPIO_IRQ_mask &= ~mask; @@ -160,7 +210,7 @@ static void sa1100_high_gpio_mask(struct irq_data *d) static void sa1100_high_gpio_unmask(struct irq_data *d) { - unsigned int mask = GPIO11_27_MASK(d->irq); + unsigned int mask = BIT(d->hwirq); GPIO_IRQ_mask |= mask; @@ -168,61 +218,32 @@ static void sa1100_high_gpio_unmask(struct irq_data *d) GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; } -static int sa1100_high_gpio_wake(struct irq_data *d, unsigned int on) -{ - if (on) - PWER |= GPIO11_27_MASK(d->irq); - else - PWER &= ~GPIO11_27_MASK(d->irq); - return 0; -} - static struct irq_chip sa1100_high_gpio_chip = { .name = "GPIO-h", - .irq_ack = sa1100_high_gpio_ack, + .irq_ack = sa1100_gpio_ack, .irq_mask = sa1100_high_gpio_mask, .irq_unmask = sa1100_high_gpio_unmask, .irq_set_type = sa1100_gpio_type, - .irq_set_wake = sa1100_high_gpio_wake, + .irq_set_wake = sa1100_gpio_wake, }; -/* - * We don't need to ACK IRQs on the SA1100 unless they're GPIOs - * this is for internal IRQs i.e. from 11 to 31. - */ -static void sa1100_mask_irq(struct irq_data *d) -{ - ICMR &= ~(1 << d->irq); -} - -static void sa1100_unmask_irq(struct irq_data *d) +static int sa1100_high_gpio_irqdomain_map(struct irq_domain *d, + unsigned int irq, irq_hw_number_t hwirq) { - ICMR |= (1 << d->irq); -} + irq_set_chip_and_handler(irq, &sa1100_high_gpio_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); -/* - * Apart form GPIOs, only the RTC alarm can be a wakeup event. - */ -static int sa1100_set_wake(struct irq_data *d, unsigned int on) -{ - if (d->irq == IRQ_RTCAlrm) { - if (on) - PWER |= PWER_RTC; - else - PWER &= ~PWER_RTC; - return 0; - } - return -EINVAL; + return 0; } -static struct irq_chip sa1100_normal_chip = { - .name = "SC", - .irq_ack = sa1100_mask_irq, - .irq_mask = sa1100_mask_irq, - .irq_unmask = sa1100_unmask_irq, - .irq_set_wake = sa1100_set_wake, +static struct irq_domain_ops sa1100_high_gpio_irqdomain_ops = { + .map = sa1100_high_gpio_irqdomain_map, + .xlate = irq_domain_xlate_onetwocell, }; +static struct irq_domain *sa1100_high_gpio_irqdomain; + static struct resource irq_resource = DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs"); @@ -291,10 +312,25 @@ static int __init sa1100irq_init_devicefs(void) device_initcall(sa1100irq_init_devicefs); -void __init sa1100_init_irq(void) +static asmlinkage void __exception_irq_entry +sa1100_handle_irq(struct pt_regs *regs) { - unsigned int irq; + uint32_t icip, icmr, mask; + + do { + icip = (ICIP); + icmr = (ICMR); + mask = icip & icmr; + + if (mask == 0) + break; + + handle_IRQ(ffs(mask) - 1 + IRQ_GPIO0, regs); + } while (1); +} +void __init sa1100_init_irq(void) +{ request_resource(&iomem_resource, &irq_resource); /* disable all IRQs */ @@ -314,29 +350,24 @@ void __init sa1100_init_irq(void) */ ICCR = 1; - for (irq = 0; irq <= 10; irq++) { - irq_set_chip_and_handler(irq, &sa1100_low_gpio_chip, - handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - } + sa1100_low_gpio_irqdomain = irq_domain_add_legacy(NULL, + 11, IRQ_GPIO0, 0, + &sa1100_low_gpio_irqdomain_ops, NULL); - for (irq = 12; irq <= 31; irq++) { - irq_set_chip_and_handler(irq, &sa1100_normal_chip, - handle_level_irq); - set_irq_flags(irq, IRQF_VALID); - } + sa1100_normal_irqdomain = irq_domain_add_legacy(NULL, + 21, IRQ_GPIO11_27, 11, + &sa1100_normal_irqdomain_ops, NULL); - for (irq = 32; irq <= 48; irq++) { - irq_set_chip_and_handler(irq, &sa1100_high_gpio_chip, - handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - } + sa1100_high_gpio_irqdomain = irq_domain_add_legacy(NULL, + 17, IRQ_GPIO11, 11, + &sa1100_high_gpio_irqdomain_ops, NULL); /* * Install handler for GPIO 11-27 edge detect interrupts */ - irq_set_chip(IRQ_GPIO11_27, &sa1100_normal_chip); irq_set_chained_handler(IRQ_GPIO11_27, sa1100_high_gpio_handler); + set_handle_irq(sa1100_handle_irq); + sa1100_init_gpio(); } |