]> Pileus Git - ~andy/linux/commitdiff
mfd: Emulate active low IRQs as well as active high IRQs for wm831x
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Fri, 18 May 2012 16:02:02 +0000 (17:02 +0100)
committerSamuel Ortiz <sameo@linux.intel.com>
Sun, 20 May 2012 15:27:14 +0000 (17:27 +0200)
As with the existing emulation this should not be used in production
systems but is useful for test purposes.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
drivers/mfd/wm831x-irq.c
include/linux/mfd/wm831x/core.h

index ecc9d6d62fad3245f416d39b5bcbff0eef06085b..804e56ec99eb284f4c32e1f44f8b7a143d4f340c 100644 (file)
@@ -413,22 +413,25 @@ static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
         * do the update here as we can be called with the bus lock
         * held.
         */
+       wm831x->gpio_level_low[irq] = false;
+       wm831x->gpio_level_high[irq] = false;
        switch (type) {
        case IRQ_TYPE_EDGE_BOTH:
                wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_INT_MODE;
-               wm831x->gpio_level[irq] = false;
                break;
        case IRQ_TYPE_EDGE_RISING:
                wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_POL;
-               wm831x->gpio_level[irq] = false;
                break;
        case IRQ_TYPE_EDGE_FALLING:
                wm831x->gpio_update[irq] = 0x10000;
-               wm831x->gpio_level[irq] = false;
                break;
        case IRQ_TYPE_LEVEL_HIGH:
                wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_POL;
-               wm831x->gpio_level[irq] = true;
+               wm831x->gpio_level_high[irq] = true;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               wm831x->gpio_update[irq] = 0x10000;
+               wm831x->gpio_level_low[irq] = true;
                break;
        default:
                return -EINVAL;
@@ -517,7 +520,7 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
                 * status.  This is sucky but improves interoperability.
                 */
                if (primary == WM831X_GP_INT &&
-                   wm831x->gpio_level[i - WM831X_IRQ_GPIO_1]) {
+                   wm831x->gpio_level_high[i - WM831X_IRQ_GPIO_1]) {
                        ret = wm831x_reg_read(wm831x, WM831X_GPIO_LEVEL);
                        while (ret & 1 << (i - WM831X_IRQ_GPIO_1)) {
                                handle_nested_irq(irq_find_mapping(wm831x->irq_domain,
@@ -526,6 +529,17 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
                                                      WM831X_GPIO_LEVEL);
                        }
                }
+
+               if (primary == WM831X_GP_INT &&
+                   wm831x->gpio_level_low[i - WM831X_IRQ_GPIO_1]) {
+                       ret = wm831x_reg_read(wm831x, WM831X_GPIO_LEVEL);
+                       while (!(ret & 1 << (i - WM831X_IRQ_GPIO_1))) {
+                               handle_nested_irq(irq_find_mapping(wm831x->irq_domain,
+                                                                  i));
+                               ret = wm831x_reg_read(wm831x,
+                                                     WM831X_GPIO_LEVEL);
+                       }
+               }
        }
 
 out:
index 736191cc7e0077be084db7bcef1520f94a65bbd1..4a3b83a776148eb2ace611436b38ab42e931450e 100644 (file)
@@ -384,7 +384,8 @@ struct wm831x {
 
        /* Used by the interrupt controller code to post writes */
        int gpio_update[WM831X_NUM_GPIO_REGS];
-       bool gpio_level[WM831X_NUM_GPIO_REGS];
+       bool gpio_level_high[WM831X_NUM_GPIO_REGS];
+       bool gpio_level_low[WM831X_NUM_GPIO_REGS];
 
        struct mutex auxadc_lock;
        struct list_head auxadc_pending;