aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ixp4xx
diff options
context:
space:
mode:
authorKevin Hilman <khilman@com.rmk.(none)>2006-11-02 19:47:20 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-11-03 14:52:50 -0500
commit984d115bbf2d731ed2264031fe49c1378d730db0 (patch)
tree60159c1d0b21f3214ce0fd530f4a39f2476e3e14 /arch/arm/mach-ixp4xx
parent8f7f9435e6df0985c877d10259393bdfaac3655f (diff)
[ARM] 3918/1: ixp4xx irq-chip rework
This is a rework of the ixp4xx irq_chip implementation. The use of two irq_chip structures and potentially switching between them is a violation of the intended use of the IRQ framework. The current implementation does not work with current in-kernel spinlock debugging or lockdep due to lock recursion problems caused by calling set_irq_chip/handler from within the chip's set_irq_type(). This patch goes back to using one irq_chip structure and handling the differences between edge/level, normal/GPIO interrupts inside the ack/mask/unmask routines themselves. Signed-off-by: Kevin Hilman <khilman@mvista.com> Signed-off-by: Deepak Saxena <dsaxena@mvista.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-ixp4xx')
-rw-r--r--arch/arm/mach-ixp4xx/common.c60
1 files changed, 22 insertions, 38 deletions
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index c7513f6eb50c..fbe288a8da65 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -86,7 +86,8 @@ enum ixp4xx_irq_type {
86 IXP4XX_IRQ_LEVEL, IXP4XX_IRQ_EDGE 86 IXP4XX_IRQ_LEVEL, IXP4XX_IRQ_EDGE
87}; 87};
88 88
89static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type); 89/* Each bit represents an IRQ: 1: edge-triggered, 0: level triggered */
90static unsigned long long ixp4xx_irq_edge = 0;
90 91
91/* 92/*
92 * IRQ -> GPIO mapping table 93 * IRQ -> GPIO mapping table
@@ -135,7 +136,11 @@ static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
135 default: 136 default:
136 return -EINVAL; 137 return -EINVAL;
137 } 138 }
138 ixp4xx_config_irq(irq, irq_type); 139
140 if (irq_type == IXP4XX_IRQ_EDGE)
141 ixp4xx_irq_edge |= (1 << irq);
142 else
143 ixp4xx_irq_edge &= ~(1 << irq);
139 144
140 if (line >= 8) { /* pins 8-15 */ 145 if (line >= 8) { /* pins 8-15 */
141 line -= 8; 146 line -= 8;
@@ -167,14 +172,6 @@ static void ixp4xx_irq_mask(unsigned int irq)
167 *IXP4XX_ICMR &= ~(1 << irq); 172 *IXP4XX_ICMR &= ~(1 << irq);
168} 173}
169 174
170static void ixp4xx_irq_unmask(unsigned int irq)
171{
172 if (cpu_is_ixp46x() && irq >= 32)
173 *IXP4XX_ICMR2 |= (1 << (irq - 32));
174 else
175 *IXP4XX_ICMR |= (1 << irq);
176}
177
178static void ixp4xx_irq_ack(unsigned int irq) 175static void ixp4xx_irq_ack(unsigned int irq)
179{ 176{
180 int line = (irq < 32) ? irq2gpio[irq] : -1; 177 int line = (irq < 32) ? irq2gpio[irq] : -1;
@@ -187,41 +184,25 @@ static void ixp4xx_irq_ack(unsigned int irq)
187 * Level triggered interrupts on GPIO lines can only be cleared when the 184 * Level triggered interrupts on GPIO lines can only be cleared when the
188 * interrupt condition disappears. 185 * interrupt condition disappears.
189 */ 186 */
190static void ixp4xx_irq_level_unmask(unsigned int irq) 187static void ixp4xx_irq_unmask(unsigned int irq)
191{ 188{
192 ixp4xx_irq_ack(irq); 189 if (!(ixp4xx_irq_edge & (1 << irq)))
193 ixp4xx_irq_unmask(irq); 190 ixp4xx_irq_ack(irq);
194}
195 191
196static struct irqchip ixp4xx_irq_level_chip = { 192 if (cpu_is_ixp46x() && irq >= 32)
197 .ack = ixp4xx_irq_mask, 193 *IXP4XX_ICMR2 |= (1 << (irq - 32));
198 .mask = ixp4xx_irq_mask, 194 else
199 .unmask = ixp4xx_irq_level_unmask, 195 *IXP4XX_ICMR |= (1 << irq);
200 .set_type = ixp4xx_set_irq_type, 196}
201};
202 197
203static struct irqchip ixp4xx_irq_edge_chip = { 198static struct irqchip ixp4xx_irq_chip = {
199 .name = "IXP4xx",
204 .ack = ixp4xx_irq_ack, 200 .ack = ixp4xx_irq_ack,
205 .mask = ixp4xx_irq_mask, 201 .mask = ixp4xx_irq_mask,
206 .unmask = ixp4xx_irq_unmask, 202 .unmask = ixp4xx_irq_unmask,
207 .set_type = ixp4xx_set_irq_type, 203 .set_type = ixp4xx_set_irq_type,
208}; 204};
209 205
210static void ixp4xx_config_irq(unsigned irq, enum ixp4xx_irq_type type)
211{
212 switch (type) {
213 case IXP4XX_IRQ_LEVEL:
214 set_irq_chip(irq, &ixp4xx_irq_level_chip);
215 set_irq_handler(irq, do_level_IRQ);
216 break;
217 case IXP4XX_IRQ_EDGE:
218 set_irq_chip(irq, &ixp4xx_irq_edge_chip);
219 set_irq_handler(irq, do_edge_IRQ);
220 break;
221 }
222 set_irq_flags(irq, IRQF_VALID);
223}
224
225void __init ixp4xx_init_irq(void) 206void __init ixp4xx_init_irq(void)
226{ 207{
227 int i = 0; 208 int i = 0;
@@ -241,8 +222,11 @@ void __init ixp4xx_init_irq(void)
241 } 222 }
242 223
243 /* Default to all level triggered */ 224 /* Default to all level triggered */
244 for(i = 0; i < NR_IRQS; i++) 225 for(i = 0; i < NR_IRQS; i++) {
245 ixp4xx_config_irq(i, IXP4XX_IRQ_LEVEL); 226 set_irq_chip(i, &ixp4xx_irq_chip);
227 set_irq_handler(i, do_level_IRQ);
228 set_irq_flags(i, IRQF_VALID);
229 }
246} 230}
247 231
248 232