mfd: Convert 88pm860x to use regmap api
[linux-2.6.git] / drivers / mfd / wm831x-irq.c
index d3015df..f4747a4 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
+#include <linux/irq.h>
 #include <linux/mfd/core.h>
 #include <linux/interrupt.h>
 
 #include <linux/mfd/wm831x/core.h>
 #include <linux/mfd/wm831x/pdata.h>
+#include <linux/mfd/wm831x/gpio.h>
 #include <linux/mfd/wm831x/irq.h>
 
 #include <linux/delay.h>
 
-/*
- * Since generic IRQs don't currently support interrupt controllers on
- * interrupt driven buses we don't use genirq but instead provide an
- * interface that looks very much like the standard ones.  This leads
- * to some bodges, including storing interrupt handler information in
- * the static irq_data table we use to look up the data for individual
- * interrupts, but hopefully won't last too long.
- */
-
 struct wm831x_irq_data {
        int primary;
        int reg;
        int mask;
-       irq_handler_t handler;
-       void *handler_data;
 };
 
 static struct wm831x_irq_data wm831x_irqs[] = {
@@ -339,110 +330,135 @@ static inline int irq_data_to_mask_reg(struct wm831x_irq_data *irq_data)
        return WM831X_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg;
 }
 
-static void __wm831x_enable_irq(struct wm831x *wm831x, int irq)
+static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x,
+                                                       int irq)
 {
-       struct wm831x_irq_data *irq_data = &wm831x_irqs[irq];
-
-       wm831x->irq_masks[irq_data->reg - 1] &= ~irq_data->mask;
-       wm831x_reg_write(wm831x, irq_data_to_mask_reg(irq_data),
-                        wm831x->irq_masks[irq_data->reg - 1]);
+       return &wm831x_irqs[irq - wm831x->irq_base];
 }
 
-void wm831x_enable_irq(struct wm831x *wm831x, int irq)
+static void wm831x_irq_lock(struct irq_data *data)
 {
+       struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+
        mutex_lock(&wm831x->irq_lock);
-       __wm831x_enable_irq(wm831x, irq);
-       mutex_unlock(&wm831x->irq_lock);
 }
-EXPORT_SYMBOL_GPL(wm831x_enable_irq);
 
-static void __wm831x_disable_irq(struct wm831x *wm831x, int irq)
+static void wm831x_irq_sync_unlock(struct irq_data *data)
 {
-       struct wm831x_irq_data *irq_data = &wm831x_irqs[irq];
+       struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(wm831x->gpio_update); i++) {
+               if (wm831x->gpio_update[i]) {
+                       wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + i,
+                                       WM831X_GPN_INT_MODE | WM831X_GPN_POL,
+                                       wm831x->gpio_update[i]);
+                       wm831x->gpio_update[i] = 0;
+               }
+       }
 
-       wm831x->irq_masks[irq_data->reg - 1] |= irq_data->mask;
-       wm831x_reg_write(wm831x, irq_data_to_mask_reg(irq_data),
-                        wm831x->irq_masks[irq_data->reg - 1]);
-}
+       for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) {
+               /* If there's been a change in the mask write it back
+                * to the hardware. */
+               if (wm831x->irq_masks_cur[i] != wm831x->irq_masks_cache[i]) {
+                       dev_dbg(wm831x->dev, "IRQ mask sync: %x = %x\n",
+                               WM831X_INTERRUPT_STATUS_1_MASK + i,
+                               wm831x->irq_masks_cur[i]);
+
+                       wm831x->irq_masks_cache[i] = wm831x->irq_masks_cur[i];
+                       wm831x_reg_write(wm831x,
+                                        WM831X_INTERRUPT_STATUS_1_MASK + i,
+                                        wm831x->irq_masks_cur[i]);
+               }
+       }
 
-void wm831x_disable_irq(struct wm831x *wm831x, int irq)
-{
-       mutex_lock(&wm831x->irq_lock);
-       __wm831x_disable_irq(wm831x, irq);
        mutex_unlock(&wm831x->irq_lock);
 }
-EXPORT_SYMBOL_GPL(wm831x_disable_irq);
 
-int wm831x_request_irq(struct wm831x *wm831x,
-                      unsigned int irq, irq_handler_t handler,
-                      unsigned long flags, const char *name,
-                      void *dev)
+static void wm831x_irq_enable(struct irq_data *data)
 {
-       int ret = 0;
-
-       if (irq < 0 || irq >= WM831X_NUM_IRQS)
-               return -EINVAL;
-
-       mutex_lock(&wm831x->irq_lock);
-
-       if (wm831x_irqs[irq].handler) {
-               dev_err(wm831x->dev, "Already have handler for IRQ %d\n", irq);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       wm831x_irqs[irq].handler = handler;
-       wm831x_irqs[irq].handler_data = dev;
-
-       __wm831x_enable_irq(wm831x, irq);
+       struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+       struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
+                                                            data->irq);
 
-out:
-       mutex_unlock(&wm831x->irq_lock);
-
-       return ret;
+       wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
 }
-EXPORT_SYMBOL_GPL(wm831x_request_irq);
 
-void wm831x_free_irq(struct wm831x *wm831x, unsigned int irq, void *data)
+static void wm831x_irq_disable(struct irq_data *data)
 {
-       if (irq < 0 || irq >= WM831X_NUM_IRQS)
-               return;
+       struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+       struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
+                                                            data->irq);
 
-       mutex_lock(&wm831x->irq_lock);
-
-       wm831x_irqs[irq].handler = NULL;
-       wm831x_irqs[irq].handler_data = NULL;
+       wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
+}
 
-       __wm831x_disable_irq(wm831x, irq);
+static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
+{
+       struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+       int irq;
 
-       mutex_unlock(&wm831x->irq_lock);
-}
-EXPORT_SYMBOL_GPL(wm831x_free_irq);
+       irq = data->irq - wm831x->irq_base;
 
+       if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) {
+               /* Ignore internal-only IRQs */
+               if (irq >= 0 && irq < WM831X_NUM_IRQS)
+                       return 0;
+               else
+                       return -EINVAL;
+       }
 
-static void wm831x_handle_irq(struct wm831x *wm831x, int irq, int status)
-{
-       struct wm831x_irq_data *irq_data = &wm831x_irqs[irq];
+       /* Rebase the IRQ into the GPIO range so we've got a sensible array
+        * index.
+        */
+       irq -= WM831X_IRQ_GPIO_1;
 
-       if (irq_data->handler) {
-               irq_data->handler(irq, irq_data->handler_data);
-               wm831x_reg_write(wm831x, irq_data_to_status_reg(irq_data),
-                                irq_data->mask);
-       } else {
-               dev_err(wm831x->dev, "Unhandled IRQ %d, masking\n", irq);
-               __wm831x_disable_irq(wm831x, irq);
+       /* We set the high bit to flag that we need an update; don't
+        * do the update here as we can be called with the bus lock
+        * held.
+        */
+       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;
        }
+
+       return 0;
 }
 
-/* Main interrupt handling occurs in a workqueue since we need
- * interrupts enabled to interact with the chip. */
-static void wm831x_irq_worker(struct work_struct *work)
+static struct irq_chip wm831x_irq_chip = {
+       .name                   = "wm831x",
+       .irq_bus_lock           = wm831x_irq_lock,
+       .irq_bus_sync_unlock    = wm831x_irq_sync_unlock,
+       .irq_disable            = wm831x_irq_disable,
+       .irq_enable             = wm831x_irq_enable,
+       .irq_set_type           = wm831x_irq_set_type,
+};
+
+/* The processing of the primary interrupt occurs in a thread so that
+ * we can interact with the device over I2C or SPI. */
+static irqreturn_t wm831x_irq_thread(int irq, void *data)
 {
-       struct wm831x *wm831x = container_of(work, struct wm831x, irq_work);
+       struct wm831x *wm831x = data;
        unsigned int i;
-       int primary;
-       int status_regs[5];
-       int read[5] = { 0 };
+       int primary, status_addr, ret;
+       int status_regs[WM831X_NUM_IRQ_REGS] = { 0 };
+       int read[WM831X_NUM_IRQ_REGS] = { 0 };
        int *status;
 
        primary = wm831x_reg_read(wm831x, WM831X_SYSTEM_INTERRUPTS);
@@ -452,7 +468,17 @@ static void wm831x_irq_worker(struct work_struct *work)
                goto out;
        }
 
-       mutex_lock(&wm831x->irq_lock);
+       /* The touch interrupts are visible in the primary register as
+        * an optimisation; open code this to avoid complicating the
+        * main handling loop and so we can also skip iterating the
+        * descriptors.
+        */
+       if (primary & WM831X_TCHPD_INT)
+               handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD);
+       if (primary & WM831X_TCHDATA_INT)
+               handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA);
+       if (primary & (WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT))
+               goto out;
 
        for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) {
                int offset = wm831x_irqs[i].reg - 1;
@@ -465,90 +491,134 @@ static void wm831x_irq_worker(struct work_struct *work)
                /* Hopefully there should only be one register to read
                 * each time otherwise we ought to do a block read. */
                if (!read[offset]) {
-                       *status = wm831x_reg_read(wm831x,
-                                    irq_data_to_status_reg(&wm831x_irqs[i]));
+                       status_addr = irq_data_to_status_reg(&wm831x_irqs[i]);
+
+                       *status = wm831x_reg_read(wm831x, status_addr);
                        if (*status < 0) {
                                dev_err(wm831x->dev,
                                        "Failed to read IRQ status: %d\n",
                                        *status);
-                               goto out_lock;
+                               goto out;
                        }
 
-                       /* Mask out the disabled IRQs */
-                       *status &= ~wm831x->irq_masks[offset];
                        read[offset] = 1;
+
+                       /* Ignore any bits that we don't think are masked */
+                       *status &= ~wm831x->irq_masks_cur[offset];
+
+                       /* Acknowledge now so we don't miss
+                        * notifications while we handle.
+                        */
+                       wm831x_reg_write(wm831x, status_addr, *status);
                }
 
                if (*status & wm831x_irqs[i].mask)
-                       wm831x_handle_irq(wm831x, i, *status);
+                       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_lock:
-       mutex_unlock(&wm831x->irq_lock);
 out:
-       enable_irq(wm831x->irq);
-}
-
-
-static irqreturn_t wm831x_cpu_irq(int irq, void *data)
-{
-       struct wm831x *wm831x = data;
-
-       /* Shut the interrupt to the CPU up and schedule the actual
-        * handler; we can't check that the IRQ is asserted. */
-       disable_irq_nosync(irq);
-
-       queue_work(wm831x->irq_wq, &wm831x->irq_work);
-
        return IRQ_HANDLED;
 }
 
 int wm831x_irq_init(struct wm831x *wm831x, int irq)
 {
-       int i, ret;
+       struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+       int i, cur_irq, ret;
 
-       if (!irq) {
-               dev_warn(wm831x->dev,
-                        "No interrupt specified - functionality limited\n");
+       mutex_init(&wm831x->irq_lock);
+
+       /* Mask the individual interrupt sources */
+       for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) {
+               wm831x->irq_masks_cur[i] = 0xffff;
+               wm831x->irq_masks_cache[i] = 0xffff;
+               wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1_MASK + i,
+                                0xffff);
+       }
+
+       /* Try to dynamically allocate IRQs if no base is specified */
+       if (!pdata || !pdata->irq_base)
+               wm831x->irq_base = -1;
+       else
+               wm831x->irq_base = pdata->irq_base;
+
+       wm831x->irq_base = irq_alloc_descs(wm831x->irq_base, 0,
+                                          WM831X_NUM_IRQS, 0);
+       if (wm831x->irq_base < 0) {
+               dev_warn(wm831x->dev, "Failed to allocate IRQs: %d\n",
+                        wm831x->irq_base);
+               wm831x->irq_base = 0;
                return 0;
        }
 
+       if (pdata && pdata->irq_cmos)
+               i = 0;
+       else
+               i = WM831X_IRQ_OD;
+
+       wm831x_set_bits(wm831x, WM831X_IRQ_CONFIG,
+                       WM831X_IRQ_OD, i);
 
-       wm831x->irq_wq = create_singlethread_workqueue("wm831x-irq");
-       if (!wm831x->irq_wq) {
-               dev_err(wm831x->dev, "Failed to allocate IRQ worker\n");
-               return -ESRCH;
+       /* Try to flag /IRQ as a wake source; there are a number of
+        * unconditional wake sources in the PMIC so this isn't
+        * conditional but we don't actually care *too* much if it
+        * fails.
+        */
+       ret = enable_irq_wake(irq);
+       if (ret != 0) {
+               dev_warn(wm831x->dev, "Can't enable IRQ as wake source: %d\n",
+                        ret);
        }
 
        wm831x->irq = irq;
-       mutex_init(&wm831x->irq_lock);
-       INIT_WORK(&wm831x->irq_work, wm831x_irq_worker);
 
-       /* Mask the individual interrupt sources */
-       for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks); i++) {
-               wm831x->irq_masks[i] = 0xffff;
-               wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1_MASK + i,
-                                0xffff);
+       /* Register them with genirq */
+       for (cur_irq = wm831x->irq_base;
+            cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base;
+            cur_irq++) {
+               irq_set_chip_data(cur_irq, wm831x);
+               irq_set_chip_and_handler(cur_irq, &wm831x_irq_chip,
+                                        handle_edge_irq);
+               irq_set_nested_thread(cur_irq, 1);
+
+               /* ARM needs us to explicitly flag the IRQ as valid
+                * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+               set_irq_flags(cur_irq, IRQF_VALID);
+#else
+               irq_set_noprobe(cur_irq);
+#endif
+       }
+
+       if (irq) {
+               ret = request_threaded_irq(irq, NULL, wm831x_irq_thread,
+                                          IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                          "wm831x", wm831x);
+               if (ret != 0) {
+                       dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n",
+                               irq, ret);
+                       return ret;
+               }
+       } else {
+               dev_warn(wm831x->dev,
+                        "No interrupt specified - functionality limited\n");
        }
 
        /* Enable top level interrupts, we mask at secondary level */
        wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0);
 
-       /* We're good to go.  We set IRQF_SHARED since there's a
-        * chance the driver will interoperate with another driver but
-        * the need to disable the IRQ while handing via I2C/SPI means
-        * that this may break and performance will be impacted.  If
-        * this does happen it's a hardware design issue and the only
-        * other alternative would be polling.
-        */
-       ret = request_irq(irq, wm831x_cpu_irq, IRQF_TRIGGER_LOW | IRQF_SHARED,
-                         "wm831x", wm831x);
-       if (ret != 0) {
-               dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n",
-                       irq, ret);
-               return ret;
-       }
-
        return 0;
 }