diff options
author | Herbert Valerio Riedel <hvr@gnu.org> | 2007-11-26 12:49:08 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2008-01-26 09:37:31 -0500 |
commit | 3c9a071d77e007464952a2d41b6686d98eb3f0b8 (patch) | |
tree | 7e346e17e81ed78adaeee94741c2ec68fd8fac28 /arch/arm | |
parent | 7ca722533979d47563e75a40c86c405153818b83 (diff) |
[ARM] 4670/1: ep93xx: implement IRQT_BOTHEDGE gpio irq sense type
Having a both-edge sensitive irq trigger type is required for the
generic gpio-keys input driver; alas the ep93xx does not support
both-edge gpio triggers in hardware, so this patch implements them by
switching edge polarity on each triggered interrupt. This is the same
approach as taken by the Orion SoC both-edge gpio irq support
implementation.
Signed-off-by: Herbert Valerio Riedel <hvr@gnu.org>
Acked-by: Lennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-ep93xx/core.c | 64 |
1 files changed, 53 insertions, 11 deletions
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 58957d7a5763..2788da06417c 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * Core routines for Cirrus EP93xx chips. | 3 | * Core routines for Cirrus EP93xx chips. |
4 | * | 4 | * |
5 | * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> | 5 | * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> |
6 | * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org> | ||
6 | * | 7 | * |
7 | * Thanks go to Michael Burian and Ray Lehtiniemi for their key | 8 | * Thanks go to Michael Burian and Ray Lehtiniemi for their key |
8 | * role in the ep93xx linux community. | 9 | * role in the ep93xx linux community. |
@@ -315,12 +316,29 @@ static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc) | |||
315 | desc_handle_irq(gpio_irq, irq_desc + gpio_irq); | 316 | desc_handle_irq(gpio_irq, irq_desc + gpio_irq); |
316 | } | 317 | } |
317 | 318 | ||
319 | static void ep93xx_gpio_irq_ack(unsigned int irq) | ||
320 | { | ||
321 | int line = irq_to_gpio(irq); | ||
322 | int port = line >> 3; | ||
323 | int port_mask = 1 << (line & 7); | ||
324 | |||
325 | if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQT_BOTHEDGE) { | ||
326 | gpio_int_type2[port] ^= port_mask; /* switch edge direction */ | ||
327 | update_gpio_int_params(port); | ||
328 | } | ||
329 | |||
330 | __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); | ||
331 | } | ||
332 | |||
318 | static void ep93xx_gpio_irq_mask_ack(unsigned int irq) | 333 | static void ep93xx_gpio_irq_mask_ack(unsigned int irq) |
319 | { | 334 | { |
320 | int line = irq_to_gpio(irq); | 335 | int line = irq_to_gpio(irq); |
321 | int port = line >> 3; | 336 | int port = line >> 3; |
322 | int port_mask = 1 << (line & 7); | 337 | int port_mask = 1 << (line & 7); |
323 | 338 | ||
339 | if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQT_BOTHEDGE) | ||
340 | gpio_int_type2[port] ^= port_mask; /* switch edge direction */ | ||
341 | |||
324 | gpio_int_unmasked[port] &= ~port_mask; | 342 | gpio_int_unmasked[port] &= ~port_mask; |
325 | update_gpio_int_params(port); | 343 | update_gpio_int_params(port); |
326 | 344 | ||
@@ -353,31 +371,54 @@ static void ep93xx_gpio_irq_unmask(unsigned int irq) | |||
353 | */ | 371 | */ |
354 | static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type) | 372 | static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type) |
355 | { | 373 | { |
374 | struct irq_desc *desc = irq_desc + irq; | ||
356 | const int gpio = irq_to_gpio(irq); | 375 | const int gpio = irq_to_gpio(irq); |
357 | const int port = gpio >> 3; | 376 | const int port = gpio >> 3; |
358 | const int port_mask = 1 << (gpio & 7); | 377 | const int port_mask = 1 << (gpio & 7); |
359 | 378 | ||
360 | ep93xx_gpio_set_direction(gpio, GPIO_IN); | 379 | ep93xx_gpio_set_direction(gpio, GPIO_IN); |
361 | 380 | ||
362 | if (type & IRQT_RISING) { | 381 | switch (type) { |
363 | gpio_int_enabled[port] |= port_mask; | 382 | case IRQT_RISING: |
364 | gpio_int_type1[port] |= port_mask; | 383 | gpio_int_type1[port] |= port_mask; |
365 | gpio_int_type2[port] |= port_mask; | 384 | gpio_int_type2[port] |= port_mask; |
366 | } else if (type & IRQT_FALLING) { | 385 | desc->handle_irq = handle_edge_irq; |
367 | gpio_int_enabled[port] |= port_mask; | 386 | break; |
387 | case IRQT_FALLING: | ||
368 | gpio_int_type1[port] |= port_mask; | 388 | gpio_int_type1[port] |= port_mask; |
369 | gpio_int_type2[port] &= ~port_mask; | 389 | gpio_int_type2[port] &= ~port_mask; |
370 | } else if (type & IRQT_HIGH) { | 390 | desc->handle_irq = handle_edge_irq; |
371 | gpio_int_enabled[port] |= port_mask; | 391 | break; |
392 | case IRQT_HIGH: | ||
372 | gpio_int_type1[port] &= ~port_mask; | 393 | gpio_int_type1[port] &= ~port_mask; |
373 | gpio_int_type2[port] |= port_mask; | 394 | gpio_int_type2[port] |= port_mask; |
374 | } else if (type & IRQT_LOW) { | 395 | desc->handle_irq = handle_level_irq; |
375 | gpio_int_enabled[port] |= port_mask; | 396 | break; |
397 | case IRQT_LOW: | ||
376 | gpio_int_type1[port] &= ~port_mask; | 398 | gpio_int_type1[port] &= ~port_mask; |
377 | gpio_int_type2[port] &= ~port_mask; | 399 | gpio_int_type2[port] &= ~port_mask; |
378 | } else { | 400 | desc->handle_irq = handle_level_irq; |
379 | gpio_int_enabled[port] &= ~port_mask; | 401 | break; |
402 | case IRQT_BOTHEDGE: | ||
403 | gpio_int_type1[port] |= port_mask; | ||
404 | /* set initial polarity based on current input level */ | ||
405 | if (gpio_get_value(gpio)) | ||
406 | gpio_int_type2[port] &= ~port_mask; /* falling */ | ||
407 | else | ||
408 | gpio_int_type2[port] |= port_mask; /* rising */ | ||
409 | desc->handle_irq = handle_edge_irq; | ||
410 | break; | ||
411 | default: | ||
412 | pr_err("ep93xx: failed to set irq type %d for gpio %d\n", | ||
413 | type, gpio); | ||
414 | return -EINVAL; | ||
380 | } | 415 | } |
416 | |||
417 | gpio_int_enabled[port] |= port_mask; | ||
418 | |||
419 | desc->status &= ~IRQ_TYPE_SENSE_MASK; | ||
420 | desc->status |= type & IRQ_TYPE_SENSE_MASK; | ||
421 | |||
381 | update_gpio_int_params(port); | 422 | update_gpio_int_params(port); |
382 | 423 | ||
383 | return 0; | 424 | return 0; |
@@ -385,7 +426,8 @@ static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type) | |||
385 | 426 | ||
386 | static struct irq_chip ep93xx_gpio_irq_chip = { | 427 | static struct irq_chip ep93xx_gpio_irq_chip = { |
387 | .name = "GPIO", | 428 | .name = "GPIO", |
388 | .ack = ep93xx_gpio_irq_mask_ack, | 429 | .ack = ep93xx_gpio_irq_ack, |
430 | .mask_ack = ep93xx_gpio_irq_mask_ack, | ||
389 | .mask = ep93xx_gpio_irq_mask, | 431 | .mask = ep93xx_gpio_irq_mask, |
390 | .unmask = ep93xx_gpio_irq_unmask, | 432 | .unmask = ep93xx_gpio_irq_unmask, |
391 | .set_type = ep93xx_gpio_irq_type, | 433 | .set_type = ep93xx_gpio_irq_type, |