Merge remote-tracking branch 'regmap/topic/core' into regmap-next
authorMark Brown <broonie@kernel.org>
Fri, 4 Sep 2015 16:22:08 +0000 (17:22 +0100)
committerMark Brown <broonie@kernel.org>
Fri, 4 Sep 2015 16:22:08 +0000 (17:22 +0100)
drivers/base/regmap/internal.h
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-i2c.c
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap.c
include/linux/regmap.h

index b2b2849..fc554e3 100644 (file)
@@ -139,11 +139,17 @@ struct regmap {
        struct reg_default *patch;
        int patch_regs;
 
-       /* if set, converts bulk rw to single rw */
-       bool use_single_rw;
+       /* if set, converts bulk read to single read */
+       bool use_single_read;
+       /* if set, converts bulk read to single read */
+       bool use_single_write;
        /* if set, the device supports multi write mode */
        bool can_multi_write;
 
+       /* if set, raw reads/writes are limited to this size */
+       size_t max_raw_read;
+       size_t max_raw_write;
+
        struct rb_root range_tree;
        void *selector_work_buf;        /* Scratch buffer used for selector */
 };
index b9862d7..6f8a13e 100644 (file)
@@ -729,7 +729,7 @@ int regcache_sync_block(struct regmap *map, void *block,
                        unsigned int block_base, unsigned int start,
                        unsigned int end)
 {
-       if (regmap_can_raw_write(map) && !map->use_single_rw)
+       if (regmap_can_raw_write(map) && !map->use_single_write)
                return regcache_sync_block_raw(map, block, cache_present,
                                               block_base, start, end);
        else
index 4b76e33..ddb9b0e 100644 (file)
@@ -209,11 +209,60 @@ static struct regmap_bus regmap_i2c = {
        .val_format_endian_default = REGMAP_ENDIAN_BIG,
 };
 
+static int regmap_i2c_smbus_i2c_write(void *context, const void *data,
+                                     size_t count)
+{
+       struct device *dev = context;
+       struct i2c_client *i2c = to_i2c_client(dev);
+
+       if (count < 1)
+               return -EINVAL;
+       if (count >= I2C_SMBUS_BLOCK_MAX)
+               return -E2BIG;
+
+       --count;
+       return i2c_smbus_write_i2c_block_data(i2c, ((u8 *)data)[0], count,
+                                             ((u8 *)data + 1));
+}
+
+static int regmap_i2c_smbus_i2c_read(void *context, const void *reg,
+                                    size_t reg_size, void *val,
+                                    size_t val_size)
+{
+       struct device *dev = context;
+       struct i2c_client *i2c = to_i2c_client(dev);
+       int ret;
+
+       if (reg_size != 1 || val_size < 1)
+               return -EINVAL;
+       if (val_size >= I2C_SMBUS_BLOCK_MAX)
+               return -E2BIG;
+
+       ret = i2c_smbus_read_i2c_block_data(i2c, ((u8 *)reg)[0], val_size, val);
+       if (ret == val_size)
+               return 0;
+       else if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+
+static struct regmap_bus regmap_i2c_smbus_i2c_block = {
+       .write = regmap_i2c_smbus_i2c_write,
+       .read = regmap_i2c_smbus_i2c_read,
+       .max_raw_read = I2C_SMBUS_BLOCK_MAX,
+       .max_raw_write = I2C_SMBUS_BLOCK_MAX,
+};
+
 static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
                                        const struct regmap_config *config)
 {
        if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
                return &regmap_i2c;
+       else if (config->reg_bits == 8 &&
+                i2c_check_functionality(i2c->adapter,
+                                        I2C_FUNC_SMBUS_I2C_BLOCK))
+               return &regmap_i2c_smbus_i2c_block;
        else if (config->val_bits == 16 && config->reg_bits == 8 &&
                 i2c_check_functionality(i2c->adapter,
                                         I2C_FUNC_SMBUS_WORD_DATA))
index 2597600..38d1f72 100644 (file)
@@ -209,7 +209,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
         * Read in the statuses, using a single bulk read if possible
         * in order to reduce the I/O overheads.
         */
-       if (!map->use_single_rw && map->reg_stride == 1 &&
+       if (!map->use_single_read && map->reg_stride == 1 &&
            data->irq_reg_stride == 1) {
                u8 *buf8 = data->status_reg_buf;
                u16 *buf16 = data->status_reg_buf;
@@ -398,7 +398,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
        else
                d->irq_reg_stride = 1;
 
-       if (!map->use_single_rw && map->reg_stride == 1 &&
+       if (!map->use_single_read && map->reg_stride == 1 &&
            d->irq_reg_stride == 1) {
                d->status_reg_buf = kmalloc(map->format.val_bytes *
                                            chip->num_regs, GFP_KERNEL);
index c0aeda5..93d2e23 100644 (file)
@@ -93,6 +93,9 @@ bool regmap_writeable(struct regmap *map, unsigned int reg)
 
 bool regmap_readable(struct regmap *map, unsigned int reg)
 {
+       if (!map->reg_read)
+               return false;
+
        if (map->max_register && reg > map->max_register)
                return false;
 
@@ -573,8 +576,13 @@ struct regmap *regmap_init(struct device *dev,
                map->reg_stride = config->reg_stride;
        else
                map->reg_stride = 1;
-       map->use_single_rw = config->use_single_rw;
-       map->can_multi_write = config->can_multi_write;
+       map->use_single_read = config->use_single_rw || !bus || !bus->read;
+       map->use_single_write = config->use_single_rw || !bus || !bus->write;
+       map->can_multi_write = config->can_multi_write && bus && bus->write;
+       if (bus) {
+               map->max_raw_read = bus->max_raw_read;
+               map->max_raw_write = bus->max_raw_write;
+       }
        map->dev = dev;
        map->bus = bus;
        map->bus_context = bus_context;
@@ -763,7 +771,7 @@ struct regmap *regmap_init(struct device *dev,
                if ((reg_endian != REGMAP_ENDIAN_BIG) ||
                    (val_endian != REGMAP_ENDIAN_BIG))
                        goto err_map;
-               map->use_single_rw = true;
+               map->use_single_write = true;
        }
 
        if (!map->format.format_write &&
@@ -1382,10 +1390,33 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
  */
 bool regmap_can_raw_write(struct regmap *map)
 {
-       return map->bus && map->format.format_val && map->format.format_reg;
+       return map->bus && map->bus->write && map->format.format_val &&
+               map->format.format_reg;
 }
 EXPORT_SYMBOL_GPL(regmap_can_raw_write);
 
+/**
+ * regmap_get_raw_read_max - Get the maximum size we can read
+ *
+ * @map: Map to check.
+ */
+size_t regmap_get_raw_read_max(struct regmap *map)
+{
+       return map->max_raw_read;
+}
+EXPORT_SYMBOL_GPL(regmap_get_raw_read_max);
+
+/**
+ * regmap_get_raw_write_max - Get the maximum size we can read
+ *
+ * @map: Map to check.
+ */
+size_t regmap_get_raw_write_max(struct regmap *map)
+{
+       return map->max_raw_write;
+}
+EXPORT_SYMBOL_GPL(regmap_get_raw_write_max);
+
 static int _regmap_bus_formatted_write(void *context, unsigned int reg,
                                       unsigned int val)
 {
@@ -1555,6 +1586,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
                return -EINVAL;
        if (val_len % map->format.val_bytes)
                return -EINVAL;
+       if (map->max_raw_write && map->max_raw_write > val_len)
+               return -E2BIG;
 
        map->lock(map->lock_arg);
 
@@ -1669,6 +1702,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
 {
        int ret = 0, i;
        size_t val_bytes = map->format.val_bytes;
+       size_t total_size = val_bytes * val_count;
 
        if (map->bus && !map->format.parse_inplace)
                return -EINVAL;
@@ -1677,9 +1711,15 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
 
        /*
         * Some devices don't support bulk write, for
-        * them we have a series of single write operations.
+        * them we have a series of single write operations in the first two if
+        * blocks.
+        *
+        * The first if block is used for memory mapped io. It does not allow
+        * val_bytes of 3 for example.
+        * The second one is used for busses which do not have this limitation
+        * and can write arbitrary value lengths.
         */
-       if (!map->bus || map->use_single_rw) {
+       if (!map->bus) {
                map->lock(map->lock_arg);
                for (i = 0; i < val_count; i++) {
                        unsigned int ival;
@@ -1711,6 +1751,38 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
                }
 out:
                map->unlock(map->lock_arg);
+       } else if (map->use_single_write ||
+                  (map->max_raw_write && map->max_raw_write < total_size)) {
+               int chunk_stride = map->reg_stride;
+               size_t chunk_size = val_bytes;
+               size_t chunk_count = val_count;
+
+               if (!map->use_single_write) {
+                       chunk_size = map->max_raw_write;
+                       if (chunk_size % val_bytes)
+                               chunk_size -= chunk_size % val_bytes;
+                       chunk_count = total_size / chunk_size;
+                       chunk_stride *= chunk_size / val_bytes;
+               }
+
+               map->lock(map->lock_arg);
+               /* Write as many bytes as possible with chunk_size */
+               for (i = 0; i < chunk_count; i++) {
+                       ret = _regmap_raw_write(map,
+                                               reg + (i * chunk_stride),
+                                               val + (i * chunk_size),
+                                               chunk_size);
+                       if (ret)
+                               break;
+               }
+
+               /* Write remaining bytes */
+               if (!ret && chunk_size * i < total_size) {
+                       ret = _regmap_raw_write(map, reg + (i * chunk_stride),
+                                               val + (i * chunk_size),
+                                               total_size - i * chunk_size);
+               }
+               map->unlock(map->lock_arg);
        } else {
                void *wval;
 
@@ -1740,7 +1812,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write);
  *
  * the (register,newvalue) pairs in regs have not been formatted, but
  * they are all in the same page and have been changed to being page
- * relative. The page register has been written if that was neccessary.
+ * relative. The page register has been written if that was necessary.
  */
 static int _regmap_raw_multi_reg_write(struct regmap *map,
                                       const struct reg_default *regs,
@@ -2050,7 +2122,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
 
        /*
         * Some buses or devices flag reads by setting the high bits in the
-        * register addresss; since it's always the high bits for all
+        * register address; since it's always the high bits for all
         * current formats we can do this here rather than in
         * formatting.  This may break if we get interesting formats.
         */
@@ -2097,8 +2169,6 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
        int ret;
        void *context = _regmap_map_get_context(map);
 
-       WARN_ON(!map->reg_read);
-
        if (!map->cache_bypass) {
                ret = regcache_read(map, reg, val);
                if (ret == 0)
@@ -2179,6 +2249,8 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
                return -EINVAL;
        if (reg % map->reg_stride)
                return -EINVAL;
+       if (val_count == 0)
+               return -EINVAL;
 
        map->lock(map->lock_arg);
 
@@ -2188,6 +2260,10 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
                        ret = -ENOTSUPP;
                        goto out;
                }
+               if (map->max_raw_read && map->max_raw_read < val_len) {
+                       ret = -E2BIG;
+                       goto out;
+               }
 
                /* Physical block read if there's no cache involved */
                ret = _regmap_raw_read(map, reg, val, val_len);
@@ -2297,20 +2373,51 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
                 * Some devices does not support bulk read, for
                 * them we have a series of single read operations.
                 */
-               if (map->use_single_rw) {
-                       for (i = 0; i < val_count; i++) {
-                               ret = regmap_raw_read(map,
-                                               reg + (i * map->reg_stride),
-                                               val + (i * val_bytes),
-                                               val_bytes);
-                               if (ret != 0)
-                                       return ret;
-                       }
-               } else {
+               size_t total_size = val_bytes * val_count;
+
+               if (!map->use_single_read &&
+                   (!map->max_raw_read || map->max_raw_read > total_size)) {
                        ret = regmap_raw_read(map, reg, val,
                                              val_bytes * val_count);
                        if (ret != 0)
                                return ret;
+               } else {
+                       /*
+                        * Some devices do not support bulk read or do not
+                        * support large bulk reads, for them we have a series
+                        * of read operations.
+                        */
+                       int chunk_stride = map->reg_stride;
+                       size_t chunk_size = val_bytes;
+                       size_t chunk_count = val_count;
+
+                       if (!map->use_single_read) {
+                               chunk_size = map->max_raw_read;
+                               if (chunk_size % val_bytes)
+                                       chunk_size -= chunk_size % val_bytes;
+                               chunk_count = total_size / chunk_size;
+                               chunk_stride *= chunk_size / val_bytes;
+                       }
+
+                       /* Read bytes that fit into a multiple of chunk_size */
+                       for (i = 0; i < chunk_count; i++) {
+                               ret = regmap_raw_read(map,
+                                                     reg + (i * chunk_stride),
+                                                     val + (i * chunk_size),
+                                                     chunk_size);
+                               if (ret != 0)
+                                       return ret;
+                       }
+
+                       /* Read remaining bytes */
+                       if (chunk_size * i < total_size) {
+                               ret = regmap_raw_read(map,
+                                                     reg + (i * chunk_stride),
+                                                     val + (i * chunk_size),
+                                                     total_size - i * chunk_size);
+                               if (ret != 0)
+                                       return ret;
+                       }
                }
 
                for (i = 0; i < val_count * val_bytes; i += val_bytes)
@@ -2322,7 +2429,34 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
                                          &ival);
                        if (ret != 0)
                                return ret;
-                       map->format.format_val(val + (i * val_bytes), ival, 0);
+
+                       if (map->format.format_val) {
+                               map->format.format_val(val + (i * val_bytes), ival, 0);
+                       } else {
+                               /* Devices providing read and write
+                                * operations can use the bulk I/O
+                                * functions if they define a val_bytes,
+                                * we assume that the values are native
+                                * endian.
+                                */
+                               u32 *u32 = val;
+                               u16 *u16 = val;
+                               u8 *u8 = val;
+
+                               switch (map->format.val_bytes) {
+                               case 4:
+                                       u32[i] = ival;
+                                       break;
+                               case 2:
+                                       u16[i] = ival;
+                                       break;
+                               case 1:
+                                       u8[i] = ival;
+                                       break;
+                               default:
+                                       return -EINVAL;
+                               }
+                       }
                }
        }
 
index 59c55ea..6724d0e 100644 (file)
@@ -296,8 +296,12 @@ typedef void (*regmap_hw_free_context)(void *context);
  *                if not implemented  on a given device.
  * @async_write: Write operation which completes asynchronously, optional and
  *               must serialise with respect to non-async I/O.
+ * @reg_write: Write a single register value to the given register address. This
+ *             write operation has to complete when returning from the function.
  * @read: Read operation.  Data is returned in the buffer used to transmit
  *         data.
+ * @reg_read: Read a single register value from a given register address.
+ * @free_context: Free context.
  * @async_alloc: Allocate a regmap_async() structure.
  * @read_flag_mask: Mask to be set in the top byte of the register when doing
  *                  a read.
@@ -307,7 +311,8 @@ typedef void (*regmap_hw_free_context)(void *context);
  * @val_format_endian_default: Default endianness for formatted register
  *     values. Used when the regmap_config specifies DEFAULT. If this is
  *     DEFAULT, BIG is assumed.
- * @async_size: Size of struct used for async work.
+ * @max_raw_read: Max raw read size that can be used on the bus.
+ * @max_raw_write: Max raw write size that can be used on the bus.
  */
 struct regmap_bus {
        bool fast_io;
@@ -322,6 +327,8 @@ struct regmap_bus {
        u8 read_flag_mask;
        enum regmap_endian reg_format_endian_default;
        enum regmap_endian val_format_endian_default;
+       size_t max_raw_read;
+       size_t max_raw_write;
 };
 
 struct regmap *regmap_init(struct device *dev,
@@ -437,6 +444,8 @@ int regmap_get_max_register(struct regmap *map);
 int regmap_get_reg_stride(struct regmap *map);
 int regmap_async_complete(struct regmap *map);
 bool regmap_can_raw_write(struct regmap *map);
+size_t regmap_get_raw_read_max(struct regmap *map);
+size_t regmap_get_raw_write_max(struct regmap *map);
 
 int regcache_sync(struct regmap *map);
 int regcache_sync_region(struct regmap *map, unsigned int min,