]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'regmap/for-next'
authorThierry Reding <treding@nvidia.com>
Thu, 24 Oct 2013 12:58:58 +0000 (14:58 +0200)
committerThierry Reding <treding@nvidia.com>
Thu, 24 Oct 2013 12:58:58 +0000 (14:58 +0200)
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap-spi.c
drivers/base/regmap/regmap.c
include/linux/regmap.h

index a36112af494ce34464d989e8037fa96e1a2a2c98..d4dd77134814bac1a8ba2bc91a817c1cc2002454 100644 (file)
@@ -307,6 +307,8 @@ int regcache_sync(struct regmap *map)
        if (!map->cache_dirty)
                goto out;
 
+       map->async = true;
+
        /* Apply any patch first */
        map->cache_bypass = 1;
        for (i = 0; i < map->patch_regs; i++) {
@@ -332,11 +334,15 @@ int regcache_sync(struct regmap *map)
                map->cache_dirty = false;
 
 out:
-       trace_regcache_sync(map->dev, name, "stop");
        /* Restore the bypass state */
+       map->async = false;
        map->cache_bypass = bypass;
        map->unlock(map->lock_arg);
 
+       regmap_async_complete(map);
+
+       trace_regcache_sync(map->dev, name, "stop");
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(regcache_sync);
@@ -375,17 +381,23 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
        if (!map->cache_dirty)
                goto out;
 
+       map->async = true;
+
        if (map->cache_ops->sync)
                ret = map->cache_ops->sync(map, min, max);
        else
                ret = regcache_default_sync(map, min, max);
 
 out:
-       trace_regcache_sync(map->dev, name, "stop region");
        /* Restore the bypass state */
        map->cache_bypass = bypass;
+       map->async = false;
        map->unlock(map->lock_arg);
 
+       regmap_async_complete(map);
+
+       trace_regcache_sync(map->dev, name, "stop region");
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(regcache_sync_region);
index d10456ffd811f5acc7da0dcd23979b1408d736a9..763c60d3d2774aaabedaa8fbdba40f9abf53faff 100644 (file)
@@ -105,6 +105,22 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
                                        "Failed to sync wakes in %x: %d\n",
                                        reg, ret);
                }
+
+               if (!d->chip->init_ack_masked)
+                       continue;
+               /*
+                * Ack all the masked interrupts uncondictionly,
+                * OR if there is masked interrupt which hasn't been Acked,
+                * it'll be ignored in irq handler, then may introduce irq storm
+                */
+               if (d->mask_buf[i] && d->chip->ack_base) {
+                       reg = d->chip->ack_base +
+                               (i * map->reg_stride * d->irq_reg_stride);
+                       ret = regmap_write(map, reg, d->mask_buf[i]);
+                       if (ret != 0)
+                               dev_err(d->map->dev, "Failed to ack 0x%x: %d\n",
+                                       reg, ret);
+               }
        }
 
        if (d->chip->runtime_pm)
index 4c506bd940f372b8bbe3b630a9599ca52ea745bf..37f12ae7aadaeadc60005b2bced37ac05bc7210d 100644 (file)
@@ -73,7 +73,8 @@ static int regmap_spi_async_write(void *context,
 
        spi_message_init(&async->m);
        spi_message_add_tail(&async->t[0], &async->m);
-       spi_message_add_tail(&async->t[1], &async->m);
+       if (val)
+               spi_message_add_tail(&async->t[1], &async->m);
 
        async->m.complete = regmap_spi_complete;
        async->m.context = async;
index ccdac61ac5e2b2b6de72819d8911fd01ad1ecf60..9c021d9cace0fcc74080ccec7b5a2b3933c65f2a 100644 (file)
@@ -1159,18 +1159,23 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
                /* If the caller supplied the value we can use it safely. */
                memcpy(async->work_buf, map->work_buf, map->format.pad_bytes +
                       map->format.reg_bytes + map->format.val_bytes);
-               if (val == work_val)
-                       val = async->work_buf + map->format.pad_bytes +
-                               map->format.reg_bytes;
 
                spin_lock_irqsave(&map->async_lock, flags);
                list_add_tail(&async->list, &map->async_list);
                spin_unlock_irqrestore(&map->async_lock, flags);
 
-               ret = map->bus->async_write(map->bus_context, async->work_buf,
-                                           map->format.reg_bytes +
-                                           map->format.pad_bytes,
-                                           val, val_len, async);
+               if (val != work_val)
+                       ret = map->bus->async_write(map->bus_context,
+                                                   async->work_buf,
+                                                   map->format.reg_bytes +
+                                                   map->format.pad_bytes,
+                                                   val, val_len, async);
+               else
+                       ret = map->bus->async_write(map->bus_context,
+                                                   async->work_buf,
+                                                   map->format.reg_bytes +
+                                                   map->format.pad_bytes +
+                                                   val_len, NULL, 0, async);
 
                if (ret != 0) {
                        dev_err(map->dev, "Failed to schedule write: %d\n",
@@ -1539,10 +1544,10 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
         */
        if (map->use_single_rw) {
                for (i = 0; i < val_count; i++) {
-                       ret = regmap_raw_write(map,
-                                              reg + (i * map->reg_stride),
-                                              val + (i * val_bytes),
-                                              val_bytes);
+                       ret = _regmap_raw_write(map,
+                                               reg + (i * map->reg_stride),
+                                               val + (i * val_bytes),
+                                               val_bytes);
                        if (ret != 0)
                                return ret;
                }
@@ -1559,6 +1564,47 @@ out:
 }
 EXPORT_SYMBOL_GPL(regmap_bulk_write);
 
+/*
+ * regmap_multi_reg_write(): Write multiple registers to the device
+ *
+ * where the set of register are supplied in any order
+ *
+ * @map: Register map to write to
+ * @regs: Array of structures containing register,value to be written
+ * @num_regs: Number of registers to write
+ *
+ * This function is intended to be used for writing a large block of data
+ * atomically to the device in single transfer for those I2C client devices
+ * that implement this alternative block write mode.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int regmap_multi_reg_write(struct regmap *map, struct reg_default *regs,
+                               int num_regs)
+{
+       int ret = 0, i;
+
+       for (i = 0; i < num_regs; i++) {
+               int reg = regs[i].reg;
+               if (reg % map->reg_stride)
+                       return -EINVAL;
+       }
+
+       map->lock(map->lock_arg);
+
+       for (i = 0; i < num_regs; i++) {
+               ret = _regmap_write(map, regs[i].reg, regs[i].def);
+               if (ret != 0)
+                       goto out;
+       }
+out:
+       map->unlock(map->lock_arg);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
+
 /**
  * regmap_raw_write_async(): Write raw values to one or more registers
  *                           asynchronously
@@ -2132,6 +2178,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
        bypass = map->cache_bypass;
 
        map->cache_bypass = true;
+       map->async = true;
 
        /* Write out first; it's useful to apply even if we fail later. */
        for (i = 0; i < num_regs; i++) {
@@ -2155,10 +2202,13 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
        }
 
 out:
+       map->async = false;
        map->cache_bypass = bypass;
 
        map->unlock(map->lock_arg);
 
+       regmap_async_complete(map);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(regmap_register_patch);
index dc90b8c134a12a9d5b87755a3e27fcfa7b01e0c8..f12dca97b9d52a1cf6933566bc6eec381efeecb3 100644 (file)
@@ -70,6 +70,8 @@ struct regmap_range {
        unsigned int range_max;
 };
 
+#define regmap_reg_range(low, high) { .range_min = low, .range_max = high, }
+
 /*
  * A table of ranges including some yes ranges and some no ranges.
  * If a register belongs to a no_range, the corresponding check function
@@ -379,6 +381,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
                     const void *val, size_t val_len);
 int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
                        size_t val_count);
+int regmap_multi_reg_write(struct regmap *map, struct reg_default *regs,
+                       int num_regs);
 int regmap_raw_write_async(struct regmap *map, unsigned int reg,
                           const void *val, size_t val_len);
 int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);