summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/mfd/wm831x-irq.c22
-rw-r--r--include/linux/mfd/wm831x/core.h1
2 files changed, 22 insertions, 1 deletions
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c
index a10937cfff4..f4747a4a9a9 100644
--- a/drivers/mfd/wm831x-irq.c
+++ b/drivers/mfd/wm831x-irq.c
@@ -420,12 +420,19 @@ static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
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;
break;
default:
return -EINVAL;
@@ -449,7 +456,7 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
{
struct wm831x *wm831x = data;
unsigned int i;
- int primary, status_addr;
+ int primary, status_addr, ret;
int status_regs[WM831X_NUM_IRQ_REGS] = { 0 };
int read[WM831X_NUM_IRQ_REGS] = { 0 };
int *status;
@@ -507,6 +514,19 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
if (*status & wm831x_irqs[i].mask)
handle_nested_irq(wm831x->irq_base + i);
+
+ /* Simulate an edge triggered IRQ by polling the input
+ * status. This is sucky but improves interoperability.
+ */
+ if (primary == WM831X_GP_INT &&
+ wm831x->gpio_level[i - WM831X_IRQ_GPIO_1]) {
+ ret = wm831x_reg_read(wm831x, WM831X_GPIO_LEVEL);
+ while (ret & 1 << (i - WM831X_IRQ_GPIO_1)) {
+ handle_nested_irq(wm831x->irq_base + i);
+ ret = wm831x_reg_read(wm831x,
+ WM831X_GPIO_LEVEL);
+ }
+ }
}
out:
diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h
index fb3e84f92e9..272f7fb5f8b 100644
--- a/include/linux/mfd/wm831x/core.h
+++ b/include/linux/mfd/wm831x/core.h
@@ -385,6 +385,7 @@ 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];
struct mutex auxadc_lock;
struct list_head auxadc_pending;