@@ -749,6 +749,53 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
}
#endif
+/*
+ * This only applies to chips that can't do both rising and falling edge
+ * detection at once. For all other chips, this function is a noop.
+ */
+static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
+{
+ void __iomem *reg = bank->base;
+ u32 l = 0;
+
+ switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
+ case METHOD_MPUIO:
+ reg += OMAP_MPUIO_GPIO_INT_EDGE;
+ l = __raw_readl(reg);
+ if ((l >> gpio) & 1)
+ l &= ~(1 << gpio);
+ else
+ l |= 1 << gpio;
+ break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
+ case METHOD_GPIO_1510:
+ reg += OMAP1510_GPIO_INT_CONTROL;
+ l = __raw_readl(reg);
+ if ((l >> gpio) & 1)
+ l &= ~(1 << gpio);
+ else
+ l |= 1 << gpio;
+ break;
+#endif
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ case METHOD_GPIO_7XX:
+ reg += OMAP7XX_GPIO_INT_CONTROL;
+ l = __raw_readl(reg);
+ if ((l >> gpio) & 1) {
+ l &= ~(1 << gpio);
+ } else {
+ l |= 1 << gpio;
+ }
+ break;
+#endif
+ default:
+ return;
+ }
+ __raw_writel(l, reg);
+}
+
static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
{
void __iomem *reg = bank->base;
@@ -1284,9 +1331,22 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
gpio_irq = bank->virtual_irq_start;
for (; isr != 0; isr >>= 1, gpio_irq++) {
+ struct irq_desc *desc = irq_to_desc(gpio_irq);
if (!(isr & 1))
continue;
+ /*
+ * Some chips can't respond to both rising and falling at the
+ * same time. If this irq was requested with both flags, we
+ * need to flip the ICR data for the IRQ to respond to the
+ * IRQ for the opposite direction.
+ */
+ if (desc->status & IRQ_TYPE_EDGE_FALLING &&
+ desc->status & IRQ_TYPE_EDGE_RISING)
+ _toggle_gpio_edge_triggering(
+ get_irq_chip_data(gpio_irq),
+ get_gpio_index(irq_to_gpio(gpio_irq)));
+
generic_handle_irq(gpio_irq);
}
}