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