diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-01-24 16:25:20 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-02-09 10:34:50 -0500 |
commit | 36d312130228504a223de44739c807b0353248c1 (patch) | |
tree | e2599b3ba8c759bb4598cd9a803a5067403a76d6 /arch/arm/common/sa1111.c | |
parent | f03ecaa0aa3a3b74b9b9e8341cf7919516c902d5 (diff) |
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: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/common/sa1111.c')
-rw-r--r-- | arch/arm/common/sa1111.c | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index d3a8f5e26487..b64a3360c8c2 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c | |||
@@ -16,6 +16,7 @@ | |||
16 | */ | 16 | */ |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/irq.h> | ||
19 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
20 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
21 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
@@ -28,9 +29,8 @@ | |||
28 | #include <linux/io.h> | 29 | #include <linux/io.h> |
29 | 30 | ||
30 | #include <mach/hardware.h> | 31 | #include <mach/hardware.h> |
31 | #include <asm/mach-types.h> | ||
32 | #include <asm/irq.h> | ||
33 | #include <asm/mach/irq.h> | 32 | #include <asm/mach/irq.h> |
33 | #include <asm/mach-types.h> | ||
34 | #include <asm/sizes.h> | 34 | #include <asm/sizes.h> |
35 | 35 | ||
36 | #include <asm/hardware/sa1111.h> | 36 | #include <asm/hardware/sa1111.h> |
@@ -86,6 +86,7 @@ | |||
86 | #define IRQ_S1_CD_VALID (52) | 86 | #define IRQ_S1_CD_VALID (52) |
87 | #define IRQ_S0_BVD1_STSCHG (53) | 87 | #define IRQ_S0_BVD1_STSCHG (53) |
88 | #define IRQ_S1_BVD1_STSCHG (54) | 88 | #define IRQ_S1_BVD1_STSCHG (54) |
89 | #define SA1111_IRQ_NR (55) | ||
89 | 90 | ||
90 | extern void sa1110_mb_enable(void); | 91 | extern void sa1110_mb_enable(void); |
91 | extern void sa1110_mb_disable(void); | 92 | extern void sa1110_mb_disable(void); |
@@ -435,16 +436,28 @@ static struct irq_chip sa1111_high_chip = { | |||
435 | .irq_set_wake = sa1111_wake_highirq, | 436 | .irq_set_wake = sa1111_wake_highirq, |
436 | }; | 437 | }; |
437 | 438 | ||
438 | static void sa1111_setup_irq(struct sa1111 *sachip) | 439 | static int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base) |
439 | { | 440 | { |
440 | void __iomem *irqbase = sachip->base + SA1111_INTC; | 441 | void __iomem *irqbase = sachip->base + SA1111_INTC; |
441 | unsigned i, irq; | 442 | unsigned i, irq; |
443 | int ret; | ||
442 | 444 | ||
443 | /* | 445 | /* |
444 | * We're guaranteed that this region hasn't been taken. | 446 | * We're guaranteed that this region hasn't been taken. |
445 | */ | 447 | */ |
446 | request_mem_region(sachip->phys + SA1111_INTC, 512, "irq"); | 448 | request_mem_region(sachip->phys + SA1111_INTC, 512, "irq"); |
447 | 449 | ||
450 | ret = irq_alloc_descs(-1, irq_base, SA1111_IRQ_NR, -1); | ||
451 | if (ret <= 0) { | ||
452 | dev_err(sachip->dev, "unable to allocate %u irqs: %d\n", | ||
453 | SA1111_IRQ_NR, ret); | ||
454 | if (ret == 0) | ||
455 | ret = -EINVAL; | ||
456 | return ret; | ||
457 | } | ||
458 | |||
459 | sachip->irq_base = ret; | ||
460 | |||
448 | /* disable all IRQs */ | 461 | /* disable all IRQs */ |
449 | sa1111_writel(0, irqbase + SA1111_INTEN0); | 462 | sa1111_writel(0, irqbase + SA1111_INTEN0); |
450 | sa1111_writel(0, irqbase + SA1111_INTEN1); | 463 | sa1111_writel(0, irqbase + SA1111_INTEN1); |
@@ -486,6 +499,11 @@ static void sa1111_setup_irq(struct sa1111 *sachip) | |||
486 | irq_set_irq_type(sachip->irq, IRQ_TYPE_EDGE_RISING); | 499 | irq_set_irq_type(sachip->irq, IRQ_TYPE_EDGE_RISING); |
487 | irq_set_handler_data(sachip->irq, sachip); | 500 | irq_set_handler_data(sachip->irq, sachip); |
488 | irq_set_chained_handler(sachip->irq, sa1111_irq_handler); | 501 | irq_set_chained_handler(sachip->irq, sa1111_irq_handler); |
502 | |||
503 | dev_info(sachip->dev, "Providing IRQ%u-%u\n", | ||
504 | sachip->irq_base, sachip->irq_base + SA1111_IRQ_NR - 1); | ||
505 | |||
506 | return 0; | ||
489 | } | 507 | } |
490 | 508 | ||
491 | /* | 509 | /* |
@@ -740,7 +758,6 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) | |||
740 | 758 | ||
741 | sachip->phys = mem->start; | 759 | sachip->phys = mem->start; |
742 | sachip->irq = irq; | 760 | sachip->irq = irq; |
743 | sachip->irq_base = pd->irq_base; | ||
744 | 761 | ||
745 | /* | 762 | /* |
746 | * Map the whole region. This also maps the | 763 | * Map the whole region. This also maps the |
@@ -771,6 +788,16 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) | |||
771 | */ | 788 | */ |
772 | sa1111_wake(sachip); | 789 | sa1111_wake(sachip); |
773 | 790 | ||
791 | /* | ||
792 | * The interrupt controller must be initialised before any | ||
793 | * other device to ensure that the interrupts are available. | ||
794 | */ | ||
795 | if (sachip->irq != NO_IRQ) { | ||
796 | ret = sa1111_setup_irq(sachip, pd->irq_base); | ||
797 | if (ret) | ||
798 | goto err_unmap; | ||
799 | } | ||
800 | |||
774 | #ifdef CONFIG_ARCH_SA1100 | 801 | #ifdef CONFIG_ARCH_SA1100 |
775 | { | 802 | { |
776 | unsigned int val; | 803 | unsigned int val; |
@@ -801,13 +828,6 @@ __sa1111_probe(struct device *me, struct resource *mem, int irq) | |||
801 | } | 828 | } |
802 | #endif | 829 | #endif |
803 | 830 | ||
804 | /* | ||
805 | * The interrupt controller must be initialised before any | ||
806 | * other device to ensure that the interrupts are available. | ||
807 | */ | ||
808 | if (sachip->irq != NO_IRQ) | ||
809 | sa1111_setup_irq(sachip); | ||
810 | |||
811 | g_sa1111 = sachip; | 831 | g_sa1111 = sachip; |
812 | 832 | ||
813 | has_devs = ~0; | 833 | has_devs = ~0; |
@@ -858,6 +878,7 @@ static void __sa1111_remove(struct sa1111 *sachip) | |||
858 | if (sachip->irq != NO_IRQ) { | 878 | if (sachip->irq != NO_IRQ) { |
859 | irq_set_chained_handler(sachip->irq, NULL); | 879 | irq_set_chained_handler(sachip->irq, NULL); |
860 | irq_set_handler_data(sachip->irq, NULL); | 880 | irq_set_handler_data(sachip->irq, NULL); |
881 | irq_free_descs(sachip->irq_base, SA1111_IRQ_NR); | ||
861 | 882 | ||
862 | release_mem_region(sachip->phys + SA1111_INTC, 512); | 883 | release_mem_region(sachip->phys + SA1111_INTC, 512); |
863 | } | 884 | } |