[Blackfin] arch: Enable both edge triggered GPIO IRQs on BF54x and use irq_to_gpio()
authorMichael Hennerich <michael.hennerich@analog.com>
Mon, 24 Dec 2007 10:51:34 +0000 (18:51 +0800)
committerBryan Wu <bryan.wu@analog.com>
Mon, 24 Dec 2007 10:51:34 +0000 (18:51 +0800)
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Bryan Wu <bryan.wu@analog.com>
arch/blackfin/mach-common/ints-priority-sc.c

index 36ef4d1..dec42ac 100644 (file)
@@ -483,6 +483,10 @@ static void bfin_demux_gpio_irq(unsigned int intb_irq,
 static unsigned char irq2pint_lut[NR_PINTS];
 static unsigned char pint2irq_lut[NR_PINT_SYS_IRQS * NR_PINT_BITS];
 
+static unsigned int gpio_both_edge_triggered[NR_PINT_SYS_IRQS];
+static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
+
+
 struct pin_int_t {
        unsigned int mask_set;
        unsigned int mask_clear;
@@ -549,13 +553,20 @@ void init_pint_lut(void)
 
 }
 
-static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
-
 static void bfin_gpio_ack_irq(unsigned int irq)
 {
        u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+       u32 pintbit = PINT_BIT(pint_val);
+       u8 bank = PINT_2_BANK(pint_val);
+
+       if (unlikely(gpio_both_edge_triggered[bank] & pintbit)) {
+               if (pint[bank]->invert_set & pintbit)
+                       pint[bank]->invert_clear = pintbit;
+               else
+                       pint[bank]->invert_set = pintbit;
+       }
+       pint[bank]->request = pintbit;
 
-       pint[PINT_2_BANK(pint_val)]->request = PINT_BIT(pint_val);
        SSYNC();
 }
 
@@ -565,6 +576,13 @@ static void bfin_gpio_mask_ack_irq(unsigned int irq)
        u32 pintbit = PINT_BIT(pint_val);
        u8 bank = PINT_2_BANK(pint_val);
 
+       if (unlikely(gpio_both_edge_triggered[bank] & pintbit)) {
+               if (pint[bank]->invert_set & pintbit)
+                       pint[bank]->invert_clear = pintbit;
+               else
+                       pint[bank]->invert_set = pintbit;
+       }
+
        pint[bank]->request = pintbit;
        pint[bank]->mask_clear = pintbit;
        SSYNC();
@@ -593,7 +611,7 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq)
 {
        unsigned int ret;
        char buf[8];
-       u16 gpionr = irq - IRQ_PA0;
+       u16 gpionr = irq_to_gpio(irq);
        u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
 
        if (pint_val == IRQ_NOT_AVAIL) {
@@ -618,9 +636,11 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq)
 
 static void bfin_gpio_irq_shutdown(unsigned int irq)
 {
+       u16 gpionr = irq_to_gpio(irq);
+
        bfin_gpio_mask_irq(irq);
-       gpio_free(irq - IRQ_PA0);
-       gpio_enabled[gpio_bank(irq - IRQ_PA0)] &= ~gpio_bit(irq - IRQ_PA0);
+       gpio_free(gpionr);
+       gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
 }
 
 static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
@@ -628,7 +648,7 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
 
        unsigned int ret;
        char buf[8];
-       u16 gpionr = irq - IRQ_PA0;
+       u16 gpionr = irq_to_gpio(irq);
        u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
        u32 pintbit = PINT_BIT(pint_val);
        u8 bank = PINT_2_BANK(pint_val);
@@ -660,28 +680,33 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
 
        gpio_direction_input(gpionr);
 
-       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
-               pint[bank]->edge_set = pintbit;
-       } else {
-               pint[bank]->edge_clear = pintbit;
-       }
-
        if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
                pint[bank]->invert_set = pintbit;       /* low or falling edge denoted by one */
        else
-               pint[bank]->invert_set = pintbit;       /* high or rising edge denoted by zero */
+               pint[bank]->invert_clear = pintbit;     /* high or rising edge denoted by zero */
 
-       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
-               pint[bank]->invert_set = pintbit;
-       else
-               pint[bank]->invert_set = pintbit;
+       if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+           == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
 
-       SSYNC();
+               gpio_both_edge_triggered[bank] |= pintbit;
 
-       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+               if (gpio_get_value(gpionr))
+                       pint[bank]->invert_set = pintbit;
+               else
+                       pint[bank]->invert_clear = pintbit;
+       } else {
+               gpio_both_edge_triggered[bank] &= ~pintbit;
+       }
+
+       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
+               pint[bank]->edge_set = pintbit;
                set_irq_handler(irq, handle_edge_irq);
-       else
+       } else {
+               pint[bank]->edge_clear = pintbit;
                set_irq_handler(irq, handle_level_irq);
+       }
+
+       SSYNC();
 
        return 0;
 }