Commit 36d31213 authored by Russell King's avatar Russell King

ARM: sa1111: implement support for sparse IRQs

Implement the necessary allocation/freeing functionality to support
sparse IRQs with the SA-1111 device.  On non-sparse IRQ platforms,
this allows us to dynamically allocate from within the available IRQ
number space.
Acked-by: default avatarNicolas Pitre <nico@linaro.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent f03ecaa0
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/irq.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -28,9 +29,8 @@ ...@@ -28,9 +29,8 @@
#include <linux/io.h> #include <linux/io.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/irq.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/mach-types.h>
#include <asm/sizes.h> #include <asm/sizes.h>
#include <asm/hardware/sa1111.h> #include <asm/hardware/sa1111.h>
...@@ -86,6 +86,7 @@ ...@@ -86,6 +86,7 @@
#define IRQ_S1_CD_VALID (52) #define IRQ_S1_CD_VALID (52)
#define IRQ_S0_BVD1_STSCHG (53) #define IRQ_S0_BVD1_STSCHG (53)
#define IRQ_S1_BVD1_STSCHG (54) #define IRQ_S1_BVD1_STSCHG (54)
#define SA1111_IRQ_NR (55)
extern void sa1110_mb_enable(void); extern void sa1110_mb_enable(void);
extern void sa1110_mb_disable(void); extern void sa1110_mb_disable(void);
...@@ -435,16 +436,28 @@ static struct irq_chip sa1111_high_chip = { ...@@ -435,16 +436,28 @@ static struct irq_chip sa1111_high_chip = {
.irq_set_wake = sa1111_wake_highirq, .irq_set_wake = sa1111_wake_highirq,
}; };
static void sa1111_setup_irq(struct sa1111 *sachip) static int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base)
{ {
void __iomem *irqbase = sachip->base + SA1111_INTC; void __iomem *irqbase = sachip->base + SA1111_INTC;
unsigned i, irq; unsigned i, irq;
int ret;
/* /*
* We're guaranteed that this region hasn't been taken. * We're guaranteed that this region hasn't been taken.
*/ */
request_mem_region(sachip->phys + SA1111_INTC, 512, "irq"); request_mem_region(sachip->phys + SA1111_INTC, 512, "irq");
ret = irq_alloc_descs(-1, irq_base, SA1111_IRQ_NR, -1);
if (ret <= 0) {
dev_err(sachip->dev, "unable to allocate %u irqs: %d\n",
SA1111_IRQ_NR, ret);
if (ret == 0)
ret = -EINVAL;
return ret;
}
sachip->irq_base = ret;
/* disable all IRQs */ /* disable all IRQs */
sa1111_writel(0, irqbase + SA1111_INTEN0); sa1111_writel(0, irqbase + SA1111_INTEN0);
sa1111_writel(0, irqbase + SA1111_INTEN1); sa1111_writel(0, irqbase + SA1111_INTEN1);
...@@ -486,6 +499,11 @@ static void sa1111_setup_irq(struct sa1111 *sachip) ...@@ -486,6 +499,11 @@ static void sa1111_setup_irq(struct sa1111 *sachip)
irq_set_irq_type(sachip->irq, IRQ_TYPE_EDGE_RISING); irq_set_irq_type(sachip->irq, IRQ_TYPE_EDGE_RISING);
irq_set_handler_data(sachip->irq, sachip); irq_set_handler_data(sachip->irq, sachip);
irq_set_chained_handler(sachip->irq, sa1111_irq_handler); irq_set_chained_handler(sachip->irq, sa1111_irq_handler);
dev_info(sachip->dev, "Providing IRQ%u-%u\n",
sachip->irq_base, sachip->irq_base + SA1111_IRQ_NR - 1);
return 0;
} }
/* /*
...@@ -740,7 +758,6 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) ...@@ -740,7 +758,6 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
sachip->phys = mem->start; sachip->phys = mem->start;
sachip->irq = irq; sachip->irq = irq;
sachip->irq_base = pd->irq_base;
/* /*
* Map the whole region. This also maps the * Map the whole region. This also maps the
...@@ -771,6 +788,16 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) ...@@ -771,6 +788,16 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
*/ */
sa1111_wake(sachip); sa1111_wake(sachip);
/*
* The interrupt controller must be initialised before any
* other device to ensure that the interrupts are available.
*/
if (sachip->irq != NO_IRQ) {
ret = sa1111_setup_irq(sachip, pd->irq_base);
if (ret)
goto err_unmap;
}
#ifdef CONFIG_ARCH_SA1100 #ifdef CONFIG_ARCH_SA1100
{ {
unsigned int val; unsigned int val;
...@@ -801,13 +828,6 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) ...@@ -801,13 +828,6 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq)
} }
#endif #endif
/*
* The interrupt controller must be initialised before any
* other device to ensure that the interrupts are available.
*/
if (sachip->irq != NO_IRQ)
sa1111_setup_irq(sachip);
g_sa1111 = sachip; g_sa1111 = sachip;
has_devs = ~0; has_devs = ~0;
...@@ -858,6 +878,7 @@ static void __sa1111_remove(struct sa1111 *sachip) ...@@ -858,6 +878,7 @@ static void __sa1111_remove(struct sa1111 *sachip)
if (sachip->irq != NO_IRQ) { if (sachip->irq != NO_IRQ) {
irq_set_chained_handler(sachip->irq, NULL); irq_set_chained_handler(sachip->irq, NULL);
irq_set_handler_data(sachip->irq, NULL); irq_set_handler_data(sachip->irq, NULL);
irq_free_descs(sachip->irq_base, SA1111_IRQ_NR);
release_mem_region(sachip->phys + SA1111_INTC, 512); release_mem_region(sachip->phys + SA1111_INTC, 512);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment