aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/common/sa1111.c
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2012-01-24 16:25:20 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-02-09 10:34:50 -0500
commit36d312130228504a223de44739c807b0353248c1 (patch)
treee2599b3ba8c759bb4598cd9a803a5067403a76d6 /arch/arm/common/sa1111.c
parentf03ecaa0aa3a3b74b9b9e8341cf7919516c902d5 (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.c43
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
90extern void sa1110_mb_enable(void); 91extern void sa1110_mb_enable(void);
91extern void sa1110_mb_disable(void); 92extern 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
438static void sa1111_setup_irq(struct sa1111 *sachip) 439static 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 }