]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'regmap/for-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 16 Aug 2012 04:01:16 +0000 (14:01 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 16 Aug 2012 04:01:16 +0000 (14:01 +1000)
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap.c
drivers/mfd/wm8994-irq.c
include/linux/regmap.h

index a89734621e517e367b15b925ccd507da04daca89..bb5e1030519709f7aa2ca12118383be1e82c5bcb 100644 (file)
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/irqdomain.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 
 #include "internal.h"
 
 struct regmap_irq_chip_data {
        struct mutex lock;
+       struct irq_chip irq_chip;
 
        struct regmap *map;
        const struct regmap_irq_chip *chip;
@@ -59,6 +61,14 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
        struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
        struct regmap *map = d->map;
        int i, ret;
+       u32 reg;
+
+       if (d->chip->runtime_pm) {
+               ret = pm_runtime_get_sync(map->dev);
+               if (ret < 0)
+                       dev_err(map->dev, "IRQ sync failed to resume: %d\n",
+                               ret);
+       }
 
        /*
         * If there's been a change in the mask write it back to the
@@ -66,15 +76,18 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
         * suppress pointless writes.
         */
        for (i = 0; i < d->chip->num_regs; i++) {
-               ret = regmap_update_bits(d->map, d->chip->mask_base +
-                                               (i * map->reg_stride *
-                                               d->irq_reg_stride),
+               reg = d->chip->mask_base +
+                       (i * map->reg_stride * d->irq_reg_stride);
+               ret = regmap_update_bits(d->map, reg,
                                         d->mask_buf_def[i], d->mask_buf[i]);
                if (ret != 0)
                        dev_err(d->map->dev, "Failed to sync masks in %x\n",
-                               d->chip->mask_base + (i * map->reg_stride));
+                               reg);
        }
 
+       if (d->chip->runtime_pm)
+               pm_runtime_put(map->dev);
+
        /* If we've changed our wakeup count propagate it to the parent */
        if (d->wake_count < 0)
                for (i = d->wake_count; i < 0; i++)
@@ -128,8 +141,7 @@ static int regmap_irq_set_wake(struct irq_data *data, unsigned int on)
        return 0;
 }
 
-static struct irq_chip regmap_irq_chip = {
-       .name                   = "regmap",
+static const struct irq_chip regmap_irq_chip = {
        .irq_bus_lock           = regmap_irq_lock,
        .irq_bus_sync_unlock    = regmap_irq_sync_unlock,
        .irq_disable            = regmap_irq_disable,
@@ -144,6 +156,16 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
        struct regmap *map = data->map;
        int ret, i;
        bool handled = false;
+       u32 reg;
+
+       if (chip->runtime_pm) {
+               ret = pm_runtime_get_sync(map->dev);
+               if (ret < 0) {
+                       dev_err(map->dev, "IRQ thread failed to resume: %d\n",
+                               ret);
+                       return IRQ_NONE;
+               }
+       }
 
        /*
         * Ignore masked IRQs and ack if we need to; we ack early so
@@ -160,20 +182,20 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                if (ret != 0) {
                        dev_err(map->dev, "Failed to read IRQ status: %d\n",
                                        ret);
+                       if (chip->runtime_pm)
+                               pm_runtime_put(map->dev);
                        return IRQ_NONE;
                }
 
                data->status_buf[i] &= ~data->mask_buf[i];
 
                if (data->status_buf[i] && chip->ack_base) {
-                       ret = regmap_write(map, chip->ack_base +
-                                               (i * map->reg_stride *
-                                               data->irq_reg_stride),
-                                          data->status_buf[i]);
+                       reg = chip->ack_base +
+                               (i * map->reg_stride * data->irq_reg_stride);
+                       ret = regmap_write(map, reg, data->status_buf[i]);
                        if (ret != 0)
                                dev_err(map->dev, "Failed to ack 0x%x: %d\n",
-                                       chip->ack_base + (i * map->reg_stride),
-                                       ret);
+                                       reg, ret);
                }
        }
 
@@ -185,6 +207,9 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                }
        }
 
+       if (chip->runtime_pm)
+               pm_runtime_put(map->dev);
+
        if (handled)
                return IRQ_HANDLED;
        else
@@ -197,7 +222,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq,
        struct regmap_irq_chip_data *data = h->host_data;
 
        irq_set_chip_data(virq, data);
-       irq_set_chip_and_handler(virq, &regmap_irq_chip, handle_edge_irq);
+       irq_set_chip_and_handler(virq, &data->irq_chip, handle_edge_irq);
        irq_set_nested_thread(virq, 1);
 
        /* ARM needs us to explicitly flag the IRQ as valid
@@ -238,6 +263,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
        struct regmap_irq_chip_data *d;
        int i;
        int ret = -ENOMEM;
+       u32 reg;
 
        for (i = 0; i < chip->num_irqs; i++) {
                if (chip->irqs[i].reg_offset % map->reg_stride)
@@ -284,6 +310,13 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                        goto err_alloc;
        }
 
+       d->irq_chip = regmap_irq_chip;
+       d->irq_chip.name = chip->name;
+       if (!chip->wake_base) {
+               d->irq_chip.irq_set_wake = NULL;
+               d->irq_chip.flags |= IRQCHIP_MASK_ON_SUSPEND |
+                                    IRQCHIP_SKIP_SET_WAKE;
+       }
        d->irq = irq;
        d->map = map;
        d->chip = chip;
@@ -303,16 +336,33 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
        /* Mask all the interrupts by default */
        for (i = 0; i < chip->num_regs; i++) {
                d->mask_buf[i] = d->mask_buf_def[i];
-               ret = regmap_write(map, chip->mask_base + (i * map->reg_stride
-                                  * d->irq_reg_stride),
-                                  d->mask_buf[i]);
+               reg = chip->mask_base +
+                       (i * map->reg_stride * d->irq_reg_stride);
+               ret = regmap_update_bits(map, reg,
+                                        d->mask_buf[i], d->mask_buf[i]);
                if (ret != 0) {
                        dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
-                               chip->mask_base + (i * map->reg_stride), ret);
+                               reg, ret);
                        goto err_alloc;
                }
        }
 
+       /* Wake is disabled by default */
+       if (d->wake_buf) {
+               for (i = 0; i < chip->num_regs; i++) {
+                       d->wake_buf[i] = d->mask_buf_def[i];
+                       reg = chip->wake_base +
+                               (i * map->reg_stride * d->irq_reg_stride);
+                       ret = regmap_update_bits(map, reg, d->wake_buf[i],
+                                                d->wake_buf[i]);
+                       if (ret != 0) {
+                               dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
+                                       reg, ret);
+                               goto err_alloc;
+                       }
+               }
+       }
+
        if (irq_base)
                d->domain = irq_domain_add_legacy(map->dev->of_node,
                                                  chip->num_irqs, irq_base, 0,
index c241ae2f2f10b91e8998e5b657d5f739cc0c0b7b..52069d29ff12ef197c7d8a447ab27ffb7096d85e 100644 (file)
@@ -659,13 +659,12 @@ EXPORT_SYMBOL_GPL(devm_regmap_init);
  * new cache.  This can be used to restore the cache to defaults or to
  * update the cache configuration to reflect runtime discovery of the
  * hardware.
+ *
+ * No explicit locking is done here, the user needs to ensure that
+ * this function will not race with other calls to regmap.
  */
 int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
 {
-       int ret;
-
-       map->lock(map);
-
        regcache_exit(map);
        regmap_debugfs_exit(map);
 
@@ -681,11 +680,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
        map->cache_bypass = false;
        map->cache_only = false;
 
-       ret = regcache_init(map, config);
-
-       map->unlock(map);
-
-       return ret;
+       return regcache_init(map, config);
 }
 EXPORT_SYMBOL_GPL(regmap_reinit_cache);
 
index 0aac4aff17a5f6cf4d66144883608157a720d7ed..a050e56a9bbdcf16f200dbe363391393ce4f6756 100644 (file)
@@ -135,6 +135,7 @@ static struct regmap_irq_chip wm8994_irq_chip = {
        .status_base = WM8994_INTERRUPT_STATUS_1,
        .mask_base = WM8994_INTERRUPT_STATUS_1_MASK,
        .ack_base = WM8994_INTERRUPT_STATUS_1,
+       .runtime_pm = true,
 };
 
 int wm8994_irq_init(struct wm8994 *wm8994)
index 7f7e00df3adf9991ce844a280c4c5c03a9d7bcb6..9c4c9c673f38d65439fcf5d8c0298183f4538a2d 100644 (file)
@@ -285,6 +285,7 @@ struct regmap_irq {
  * @ack_base:    Base ack address.  If zero then the chip is clear on read.
  * @wake_base:   Base address for wake enables.  If zero unsupported.
  * @irq_reg_stride:  Stride to use for chips where registers are not contiguous.
+ * @runtime_pm:  Hold a runtime PM lock on the device when accessing it.
  *
  * @num_regs:    Number of registers in each control bank.
  * @irqs:        Descriptors for individual IRQs.  Interrupt numbers are
@@ -299,6 +300,7 @@ struct regmap_irq_chip {
        unsigned int ack_base;
        unsigned int wake_base;
        unsigned int irq_reg_stride;
+       bool runtime_pm;
 
        int num_regs;