diff options
author | Manuel Lauss <mano@roarinelk.homelinux.net> | 2008-12-21 03:26:18 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2009-01-11 04:57:26 -0500 |
commit | 197b0d31eb3e82f598bf13da6ee777d906c611f3 (patch) | |
tree | 663ecf85c0096a695f425bb602012ea7ca9e57de /arch/mips | |
parent | 785e3268e2951d4c0c21417c8e5d8004b2ab2480 (diff) |
MIPS: Alchemy: pb1200: update CPLD cascade irq handler.
Tested on Db1200.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/alchemy/devboards/pb1200/irqmap.c | 87 |
1 files changed, 30 insertions, 57 deletions
diff --git a/arch/mips/alchemy/devboards/pb1200/irqmap.c b/arch/mips/alchemy/devboards/pb1200/irqmap.c index 1f92fec24a3..fe47498da28 100644 --- a/arch/mips/alchemy/devboards/pb1200/irqmap.c +++ b/arch/mips/alchemy/devboards/pb1200/irqmap.c | |||
@@ -47,77 +47,50 @@ struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { | |||
47 | /* | 47 | /* |
48 | * Support for External interrupts on the Pb1200 Development platform. | 48 | * Support for External interrupts on the Pb1200 Development platform. |
49 | */ | 49 | */ |
50 | static volatile int pb1200_cascade_en; | ||
51 | 50 | ||
52 | irqreturn_t pb1200_cascade_handler(int irq, void *dev_id) | 51 | static void pb1200_cascade_handler(unsigned int irq, struct irq_desc *d) |
53 | { | 52 | { |
54 | unsigned short bisr = bcsr->int_status; | 53 | unsigned short bisr = bcsr->int_status; |
55 | int extirq_nr = 0; | ||
56 | |||
57 | /* Clear all the edge interrupts. This has no effect on level. */ | ||
58 | bcsr->int_status = bisr; | ||
59 | for ( ; bisr; bisr &= bisr - 1) { | ||
60 | extirq_nr = PB1200_INT_BEGIN + __ffs(bisr); | ||
61 | /* Ack and dispatch IRQ */ | ||
62 | do_IRQ(extirq_nr); | ||
63 | } | ||
64 | |||
65 | return IRQ_RETVAL(1); | ||
66 | } | ||
67 | 54 | ||
68 | inline void pb1200_enable_irq(unsigned int irq_nr) | 55 | for ( ; bisr; bisr &= bisr - 1) |
69 | { | 56 | generic_handle_irq(PB1200_INT_BEGIN + __ffs(bisr)); |
70 | bcsr->intset_mask = 1 << (irq_nr - PB1200_INT_BEGIN); | ||
71 | bcsr->intset = 1 << (irq_nr - PB1200_INT_BEGIN); | ||
72 | } | 57 | } |
73 | 58 | ||
74 | inline void pb1200_disable_irq(unsigned int irq_nr) | 59 | /* NOTE: both the enable and mask bits must be cleared, otherwise the |
60 | * CPLD generates tons of spurious interrupts (at least on the DB1200). | ||
61 | */ | ||
62 | static void pb1200_mask_irq(unsigned int irq_nr) | ||
75 | { | 63 | { |
76 | bcsr->intclr_mask = 1 << (irq_nr - PB1200_INT_BEGIN); | 64 | bcsr->intclr_mask = 1 << (irq_nr - PB1200_INT_BEGIN); |
77 | bcsr->intclr = 1 << (irq_nr - PB1200_INT_BEGIN); | 65 | bcsr->intclr = 1 << (irq_nr - PB1200_INT_BEGIN); |
66 | au_sync(); | ||
78 | } | 67 | } |
79 | 68 | ||
80 | static unsigned int pb1200_setup_cascade(void) | 69 | static void pb1200_maskack_irq(unsigned int irq_nr) |
81 | { | ||
82 | return request_irq(AU1000_GPIO_7, &pb1200_cascade_handler, | ||
83 | 0, "Pb1200 Cascade", &pb1200_cascade_handler); | ||
84 | } | ||
85 | |||
86 | static unsigned int pb1200_startup_irq(unsigned int irq) | ||
87 | { | 70 | { |
88 | if (++pb1200_cascade_en == 1) { | 71 | bcsr->intclr_mask = 1 << (irq_nr - PB1200_INT_BEGIN); |
89 | int res; | 72 | bcsr->intclr = 1 << (irq_nr - PB1200_INT_BEGIN); |
90 | 73 | bcsr->int_status = 1 << (irq_nr - PB1200_INT_BEGIN); /* ack */ | |
91 | res = pb1200_setup_cascade(); | 74 | au_sync(); |
92 | if (res) | ||
93 | return res; | ||
94 | } | ||
95 | |||
96 | pb1200_enable_irq(irq); | ||
97 | |||
98 | return 0; | ||
99 | } | 75 | } |
100 | 76 | ||
101 | static void pb1200_shutdown_irq(unsigned int irq) | 77 | static void pb1200_unmask_irq(unsigned int irq_nr) |
102 | { | 78 | { |
103 | pb1200_disable_irq(irq); | 79 | bcsr->intset = 1 << (irq_nr - PB1200_INT_BEGIN); |
104 | if (--pb1200_cascade_en == 0) | 80 | bcsr->intset_mask = 1 << (irq_nr - PB1200_INT_BEGIN); |
105 | free_irq(AU1000_GPIO_7, &pb1200_cascade_handler); | 81 | au_sync(); |
106 | } | 82 | } |
107 | 83 | ||
108 | static struct irq_chip external_irq_type = { | 84 | static struct irq_chip pb1200_cpld_irq_type = { |
109 | #ifdef CONFIG_MIPS_PB1200 | 85 | #ifdef CONFIG_MIPS_PB1200 |
110 | .name = "Pb1200 Ext", | 86 | .name = "Pb1200 Ext", |
111 | #endif | 87 | #endif |
112 | #ifdef CONFIG_MIPS_DB1200 | 88 | #ifdef CONFIG_MIPS_DB1200 |
113 | .name = "Db1200 Ext", | 89 | .name = "Db1200 Ext", |
114 | #endif | 90 | #endif |
115 | .startup = pb1200_startup_irq, | 91 | .mask = pb1200_mask_irq, |
116 | .shutdown = pb1200_shutdown_irq, | 92 | .mask_ack = pb1200_maskack_irq, |
117 | .ack = pb1200_disable_irq, | 93 | .unmask = pb1200_unmask_irq, |
118 | .mask = pb1200_disable_irq, | ||
119 | .mask_ack = pb1200_disable_irq, | ||
120 | .unmask = pb1200_enable_irq, | ||
121 | }; | 94 | }; |
122 | 95 | ||
123 | void __init board_init_irq(void) | 96 | void __init board_init_irq(void) |
@@ -147,15 +120,15 @@ void __init board_init_irq(void) | |||
147 | panic("Game over. Your score is 0."); | 120 | panic("Game over. Your score is 0."); |
148 | } | 121 | } |
149 | #endif | 122 | #endif |
123 | /* mask & disable & ack all */ | ||
124 | bcsr->intclr_mask = 0xffff; | ||
125 | bcsr->intclr = 0xffff; | ||
126 | bcsr->int_status = 0xffff; | ||
127 | au_sync(); | ||
150 | 128 | ||
151 | for (irq = PB1200_INT_BEGIN; irq <= PB1200_INT_END; irq++) { | 129 | for (irq = PB1200_INT_BEGIN; irq <= PB1200_INT_END; irq++) |
152 | set_irq_chip_and_handler(irq, &external_irq_type, | 130 | set_irq_chip_and_handler_name(irq, &pb1200_cpld_irq_type, |
153 | handle_level_irq); | 131 | handle_level_irq, "level"); |
154 | pb1200_disable_irq(irq); | ||
155 | } | ||
156 | 132 | ||
157 | /* | 133 | set_irq_chained_handler(AU1000_GPIO_7, pb1200_cascade_handler); |
158 | * GPIO_7 can not be hooked here, so it is hooked upon first | ||
159 | * request of any source attached to the cascade. | ||
160 | */ | ||
161 | } | 134 | } |