diff options
Diffstat (limited to 'arch/arm/plat-omap/gpio.c')
-rw-r--r-- | arch/arm/plat-omap/gpio.c | 103 |
1 files changed, 94 insertions, 9 deletions
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 418b88fbea8e..ae08eeec7aad 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c | |||
@@ -536,6 +536,49 @@ static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) | |||
536 | _clear_gpio_irqbank(bank, 1 << get_gpio_index(gpio)); | 536 | _clear_gpio_irqbank(bank, 1 << get_gpio_index(gpio)); |
537 | } | 537 | } |
538 | 538 | ||
539 | static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) | ||
540 | { | ||
541 | void __iomem *reg = bank->base; | ||
542 | int inv = 0; | ||
543 | u32 l; | ||
544 | u32 mask; | ||
545 | |||
546 | switch (bank->method) { | ||
547 | case METHOD_MPUIO: | ||
548 | reg += OMAP_MPUIO_GPIO_MASKIT; | ||
549 | mask = 0xffff; | ||
550 | inv = 1; | ||
551 | break; | ||
552 | case METHOD_GPIO_1510: | ||
553 | reg += OMAP1510_GPIO_INT_MASK; | ||
554 | mask = 0xffff; | ||
555 | inv = 1; | ||
556 | break; | ||
557 | case METHOD_GPIO_1610: | ||
558 | reg += OMAP1610_GPIO_IRQENABLE1; | ||
559 | mask = 0xffff; | ||
560 | break; | ||
561 | case METHOD_GPIO_730: | ||
562 | reg += OMAP730_GPIO_INT_MASK; | ||
563 | mask = 0xffffffff; | ||
564 | inv = 1; | ||
565 | break; | ||
566 | case METHOD_GPIO_24XX: | ||
567 | reg += OMAP24XX_GPIO_IRQENABLE1; | ||
568 | mask = 0xffffffff; | ||
569 | break; | ||
570 | default: | ||
571 | BUG(); | ||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | l = __raw_readl(reg); | ||
576 | if (inv) | ||
577 | l = ~l; | ||
578 | l &= mask; | ||
579 | return l; | ||
580 | } | ||
581 | |||
539 | static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable) | 582 | static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable) |
540 | { | 583 | { |
541 | void __iomem *reg = bank->base; | 584 | void __iomem *reg = bank->base; |
@@ -735,6 +778,8 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, | |||
735 | u32 isr; | 778 | u32 isr; |
736 | unsigned int gpio_irq; | 779 | unsigned int gpio_irq; |
737 | struct gpio_bank *bank; | 780 | struct gpio_bank *bank; |
781 | u32 retrigger = 0; | ||
782 | int unmasked = 0; | ||
738 | 783 | ||
739 | desc->chip->ack(irq); | 784 | desc->chip->ack(irq); |
740 | 785 | ||
@@ -759,18 +804,22 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, | |||
759 | #endif | 804 | #endif |
760 | while(1) { | 805 | while(1) { |
761 | u32 isr_saved, level_mask = 0; | 806 | u32 isr_saved, level_mask = 0; |
807 | u32 enabled; | ||
762 | 808 | ||
763 | isr_saved = isr = __raw_readl(isr_reg); | 809 | enabled = _get_gpio_irqbank_mask(bank); |
810 | isr_saved = isr = __raw_readl(isr_reg) & enabled; | ||
764 | 811 | ||
765 | if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO)) | 812 | if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO)) |
766 | isr &= 0x0000ffff; | 813 | isr &= 0x0000ffff; |
767 | 814 | ||
768 | if (cpu_is_omap24xx()) | 815 | if (cpu_is_omap24xx()) { |
769 | level_mask = | 816 | level_mask = |
770 | __raw_readl(bank->base + | 817 | __raw_readl(bank->base + |
771 | OMAP24XX_GPIO_LEVELDETECT0) | | 818 | OMAP24XX_GPIO_LEVELDETECT0) | |
772 | __raw_readl(bank->base + | 819 | __raw_readl(bank->base + |
773 | OMAP24XX_GPIO_LEVELDETECT1); | 820 | OMAP24XX_GPIO_LEVELDETECT1); |
821 | level_mask &= enabled; | ||
822 | } | ||
774 | 823 | ||
775 | /* clear edge sensitive interrupts before handler(s) are | 824 | /* clear edge sensitive interrupts before handler(s) are |
776 | called so that we don't miss any interrupt occurred while | 825 | called so that we don't miss any interrupt occurred while |
@@ -781,19 +830,54 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, | |||
781 | 830 | ||
782 | /* if there is only edge sensitive GPIO pin interrupts | 831 | /* if there is only edge sensitive GPIO pin interrupts |
783 | configured, we could unmask GPIO bank interrupt immediately */ | 832 | configured, we could unmask GPIO bank interrupt immediately */ |
784 | if (!level_mask) | 833 | if (!level_mask && !unmasked) { |
834 | unmasked = 1; | ||
785 | desc->chip->unmask(irq); | 835 | desc->chip->unmask(irq); |
836 | } | ||
786 | 837 | ||
838 | isr |= retrigger; | ||
839 | retrigger = 0; | ||
787 | if (!isr) | 840 | if (!isr) |
788 | break; | 841 | break; |
789 | 842 | ||
790 | gpio_irq = bank->virtual_irq_start; | 843 | gpio_irq = bank->virtual_irq_start; |
791 | for (; isr != 0; isr >>= 1, gpio_irq++) { | 844 | for (; isr != 0; isr >>= 1, gpio_irq++) { |
792 | struct irqdesc *d; | 845 | struct irqdesc *d; |
846 | int irq_mask; | ||
793 | if (!(isr & 1)) | 847 | if (!(isr & 1)) |
794 | continue; | 848 | continue; |
795 | d = irq_desc + gpio_irq; | 849 | d = irq_desc + gpio_irq; |
850 | /* Don't run the handler if it's already running | ||
851 | * or was disabled lazely. | ||
852 | */ | ||
853 | if (unlikely((d->disable_depth || d->running))) { | ||
854 | irq_mask = 1 << | ||
855 | (gpio_irq - bank->virtual_irq_start); | ||
856 | /* The unmasking will be done by | ||
857 | * enable_irq in case it is disabled or | ||
858 | * after returning from the handler if | ||
859 | * it's already running. | ||
860 | */ | ||
861 | _enable_gpio_irqbank(bank, irq_mask, 0); | ||
862 | if (!d->disable_depth) { | ||
863 | /* Level triggered interrupts | ||
864 | * won't ever be reentered | ||
865 | */ | ||
866 | BUG_ON(level_mask & irq_mask); | ||
867 | d->pending = 1; | ||
868 | } | ||
869 | continue; | ||
870 | } | ||
871 | d->running = 1; | ||
796 | desc_handle_irq(gpio_irq, d, regs); | 872 | desc_handle_irq(gpio_irq, d, regs); |
873 | d->running = 0; | ||
874 | if (unlikely(d->pending && !d->disable_depth)) { | ||
875 | irq_mask = 1 << | ||
876 | (gpio_irq - bank->virtual_irq_start); | ||
877 | d->pending = 0; | ||
878 | _enable_gpio_irqbank(bank, irq_mask, 1); | ||
879 | retrigger |= irq_mask; | ||
880 | } | ||
797 | } | 881 | } |
798 | 882 | ||
799 | if (cpu_is_omap24xx()) { | 883 | if (cpu_is_omap24xx()) { |
@@ -803,13 +887,14 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, | |||
803 | _enable_gpio_irqbank(bank, isr_saved & level_mask, 1); | 887 | _enable_gpio_irqbank(bank, isr_saved & level_mask, 1); |
804 | } | 888 | } |
805 | 889 | ||
806 | /* if bank has any level sensitive GPIO pin interrupt | ||
807 | configured, we must unmask the bank interrupt only after | ||
808 | handler(s) are executed in order to avoid spurious bank | ||
809 | interrupt */ | ||
810 | if (level_mask) | ||
811 | desc->chip->unmask(irq); | ||
812 | } | 890 | } |
891 | /* if bank has any level sensitive GPIO pin interrupt | ||
892 | configured, we must unmask the bank interrupt only after | ||
893 | handler(s) are executed in order to avoid spurious bank | ||
894 | interrupt */ | ||
895 | if (!unmasked) | ||
896 | desc->chip->unmask(irq); | ||
897 | |||
813 | } | 898 | } |
814 | 899 | ||
815 | static void gpio_ack_irq(unsigned int irq) | 900 | static void gpio_ack_irq(unsigned int irq) |