diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2005-06-24 15:54:35 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2005-06-24 15:54:35 -0400 |
commit | c4982887cacf2122bc256e901598b58caf4a34be (patch) | |
tree | 12f3ddeb179f6b6f4cc956b83c726ee9208e542a /arch/arm/mach-ixp2000 | |
parent | c6b56949de86694d837750a0a89c766b9871e81c (diff) |
[PATCH] ARM: 2744/1: ixp2000 gpio irq support
Patch from Lennert Buytenhek
This patch cleans up the ixp2000 gpio irq code and implements the
set_irq_type method for gpio irqs so that users can select for which
events (falling edge/rising edge/level low/level high) on the gpio
pin they want the corresponding gpio irq to be triggered.
Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: Deepak Saxena
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-ixp2000')
-rw-r--r-- | arch/arm/mach-ixp2000/core.c | 85 |
1 files changed, 67 insertions, 18 deletions
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c index fc0555596d6d..0ee34acb8d7b 100644 --- a/arch/arm/mach-ixp2000/core.c +++ b/arch/arm/mach-ixp2000/core.c | |||
@@ -40,6 +40,8 @@ | |||
40 | #include <asm/mach/time.h> | 40 | #include <asm/mach/time.h> |
41 | #include <asm/mach/irq.h> | 41 | #include <asm/mach/irq.h> |
42 | 42 | ||
43 | #include <asm/arch/gpio.h> | ||
44 | |||
43 | static DEFINE_SPINLOCK(ixp2000_slowport_lock); | 45 | static DEFINE_SPINLOCK(ixp2000_slowport_lock); |
44 | static unsigned long ixp2000_slowport_irq_flags; | 46 | static unsigned long ixp2000_slowport_irq_flags; |
45 | 47 | ||
@@ -179,7 +181,7 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
179 | 181 | ||
180 | /* clear timer 1 */ | 182 | /* clear timer 1 */ |
181 | ixp2000_reg_write(IXP2000_T1_CLR, 1); | 183 | ixp2000_reg_write(IXP2000_T1_CLR, 1); |
182 | 184 | ||
183 | while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) { | 185 | while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) { |
184 | timer_tick(regs); | 186 | timer_tick(regs); |
185 | next_jiffy_time -= ticks_per_jiffy; | 187 | next_jiffy_time -= ticks_per_jiffy; |
@@ -238,35 +240,40 @@ void __init ixp2000_init_time(unsigned long tick_rate) | |||
238 | /************************************************************************* | 240 | /************************************************************************* |
239 | * GPIO helpers | 241 | * GPIO helpers |
240 | *************************************************************************/ | 242 | *************************************************************************/ |
241 | static unsigned long GPIO_IRQ_rising_edge; | ||
242 | static unsigned long GPIO_IRQ_falling_edge; | 243 | static unsigned long GPIO_IRQ_falling_edge; |
244 | static unsigned long GPIO_IRQ_rising_edge; | ||
243 | static unsigned long GPIO_IRQ_level_low; | 245 | static unsigned long GPIO_IRQ_level_low; |
244 | static unsigned long GPIO_IRQ_level_high; | 246 | static unsigned long GPIO_IRQ_level_high; |
245 | 247 | ||
246 | void gpio_line_config(int line, int style) | 248 | static void update_gpio_int_csrs(void) |
249 | { | ||
250 | ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge); | ||
251 | ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge); | ||
252 | ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low); | ||
253 | ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high); | ||
254 | } | ||
255 | |||
256 | void gpio_line_config(int line, int direction) | ||
247 | { | 257 | { |
248 | unsigned long flags; | 258 | unsigned long flags; |
249 | 259 | ||
250 | local_irq_save(flags); | 260 | local_irq_save(flags); |
261 | if (direction == GPIO_OUT) { | ||
262 | irq_desc[line + IRQ_IXP2000_GPIO0].valid = 0; | ||
251 | 263 | ||
252 | if(style == GPIO_OUT) { | ||
253 | /* if it's an output, it ain't an interrupt anymore */ | 264 | /* if it's an output, it ain't an interrupt anymore */ |
254 | ixp2000_reg_write(IXP2000_GPIO_PDSR, (1 << line)); | ||
255 | GPIO_IRQ_falling_edge &= ~(1 << line); | 265 | GPIO_IRQ_falling_edge &= ~(1 << line); |
256 | GPIO_IRQ_rising_edge &= ~(1 << line); | 266 | GPIO_IRQ_rising_edge &= ~(1 << line); |
257 | GPIO_IRQ_level_low &= ~(1 << line); | 267 | GPIO_IRQ_level_low &= ~(1 << line); |
258 | GPIO_IRQ_level_high &= ~(1 << line); | 268 | GPIO_IRQ_level_high &= ~(1 << line); |
259 | ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge); | 269 | update_gpio_int_csrs(); |
260 | ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge); | 270 | |
261 | ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high); | 271 | ixp2000_reg_write(IXP2000_GPIO_PDSR, 1 << line); |
262 | ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low); | 272 | } else if (direction == GPIO_IN) { |
263 | irq_desc[line+IRQ_IXP2000_GPIO0].valid = 0; | 273 | ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line); |
264 | } else if(style == GPIO_IN) { | ||
265 | ixp2000_reg_write(IXP2000_GPIO_PDCR, (1 << line)); | ||
266 | } | 274 | } |
267 | |||
268 | local_irq_restore(flags); | 275 | local_irq_restore(flags); |
269 | } | 276 | } |
270 | 277 | ||
271 | 278 | ||
272 | /************************************************************************* | 279 | /************************************************************************* |
@@ -285,9 +292,50 @@ static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, str | |||
285 | } | 292 | } |
286 | } | 293 | } |
287 | 294 | ||
295 | static int ixp2000_GPIO_irq_type(unsigned int irq, unsigned int type) | ||
296 | { | ||
297 | int line = irq - IRQ_IXP2000_GPIO0; | ||
298 | |||
299 | /* | ||
300 | * First, configure this GPIO line as an input. | ||
301 | */ | ||
302 | ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line); | ||
303 | |||
304 | /* | ||
305 | * Then, set the proper trigger type. | ||
306 | */ | ||
307 | if (type & IRQT_FALLING) | ||
308 | GPIO_IRQ_falling_edge |= 1 << line; | ||
309 | else | ||
310 | GPIO_IRQ_falling_edge &= ~(1 << line); | ||
311 | if (type & IRQT_RISING) | ||
312 | GPIO_IRQ_rising_edge |= 1 << line; | ||
313 | else | ||
314 | GPIO_IRQ_rising_edge &= ~(1 << line); | ||
315 | if (type & IRQT_LOW) | ||
316 | GPIO_IRQ_level_low |= 1 << line; | ||
317 | else | ||
318 | GPIO_IRQ_level_low &= ~(1 << line); | ||
319 | if (type & IRQT_HIGH) | ||
320 | GPIO_IRQ_level_high |= 1 << line; | ||
321 | else | ||
322 | GPIO_IRQ_level_high &= ~(1 << line); | ||
323 | update_gpio_int_csrs(); | ||
324 | |||
325 | /* | ||
326 | * Finally, mark the corresponding IRQ as valid. | ||
327 | */ | ||
328 | irq_desc[irq].valid = 1; | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
288 | static void ixp2000_GPIO_irq_mask_ack(unsigned int irq) | 333 | static void ixp2000_GPIO_irq_mask_ack(unsigned int irq) |
289 | { | 334 | { |
290 | ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0))); | 335 | ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0))); |
336 | |||
337 | ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); | ||
338 | ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); | ||
291 | ixp2000_reg_write(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0))); | 339 | ixp2000_reg_write(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0))); |
292 | } | 340 | } |
293 | 341 | ||
@@ -302,6 +350,7 @@ static void ixp2000_GPIO_irq_unmask(unsigned int irq) | |||
302 | } | 350 | } |
303 | 351 | ||
304 | static struct irqchip ixp2000_GPIO_irq_chip = { | 352 | static struct irqchip ixp2000_GPIO_irq_chip = { |
353 | .type = ixp2000_GPIO_irq_type, | ||
305 | .ack = ixp2000_GPIO_irq_mask_ack, | 354 | .ack = ixp2000_GPIO_irq_mask_ack, |
306 | .mask = ixp2000_GPIO_irq_mask, | 355 | .mask = ixp2000_GPIO_irq_mask, |
307 | .unmask = ixp2000_GPIO_irq_unmask | 356 | .unmask = ixp2000_GPIO_irq_unmask |
@@ -338,7 +387,7 @@ static void ixp2000_irq_mask(unsigned int irq) | |||
338 | 387 | ||
339 | static void ixp2000_irq_unmask(unsigned int irq) | 388 | static void ixp2000_irq_unmask(unsigned int irq) |
340 | { | 389 | { |
341 | ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << irq)); | 390 | ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << irq)); |
342 | } | 391 | } |
343 | 392 | ||
344 | static struct irqchip ixp2000_irq_chip = { | 393 | static struct irqchip ixp2000_irq_chip = { |
@@ -375,16 +424,16 @@ void __init ixp2000_init_irq(void) | |||
375 | * our mask/unmask code much simpler. | 424 | * our mask/unmask code much simpler. |
376 | */ | 425 | */ |
377 | for (irq = IRQ_IXP2000_SOFT_INT; irq <= IRQ_IXP2000_THDB3; irq++) { | 426 | for (irq = IRQ_IXP2000_SOFT_INT; irq <= IRQ_IXP2000_THDB3; irq++) { |
378 | if((1 << irq) & IXP2000_VALID_IRQ_MASK) { | 427 | if ((1 << irq) & IXP2000_VALID_IRQ_MASK) { |
379 | set_irq_chip(irq, &ixp2000_irq_chip); | 428 | set_irq_chip(irq, &ixp2000_irq_chip); |
380 | set_irq_handler(irq, do_level_IRQ); | 429 | set_irq_handler(irq, do_level_IRQ); |
381 | set_irq_flags(irq, IRQF_VALID); | 430 | set_irq_flags(irq, IRQF_VALID); |
382 | } else set_irq_flags(irq, 0); | 431 | } else set_irq_flags(irq, 0); |
383 | } | 432 | } |
384 | 433 | ||
385 | /* | 434 | /* |
386 | * GPIO IRQs are invalid until someone sets the interrupt mode | 435 | * GPIO IRQs are invalid until someone sets the interrupt mode |
387 | * by calling gpio_line_set(); | 436 | * by calling set_irq_type(). |
388 | */ | 437 | */ |
389 | for (irq = IRQ_IXP2000_GPIO0; irq <= IRQ_IXP2000_GPIO7; irq++) { | 438 | for (irq = IRQ_IXP2000_GPIO0; irq <= IRQ_IXP2000_GPIO7; irq++) { |
390 | set_irq_chip(irq, &ixp2000_GPIO_irq_chip); | 439 | set_irq_chip(irq, &ixp2000_GPIO_irq_chip); |