regmap: Add bulk read/write callbacks into regmap_config
authorMarek Vasut <marex@denx.de>
Sat, 30 Apr 2022 02:51:44 +0000 (04:51 +0200)
committerMark Brown <broonie@kernel.org>
Thu, 5 May 2022 12:22:34 +0000 (13:22 +0100)
Currently the regmap_config structure only allows the user to implement
single element register read/write using .reg_read/.reg_write callbacks.
The regmap_bus already implements bulk counterparts of both, and is being
misused as a workaround for the missing bulk read/write callbacks in
regmap_config by a couple of drivers. To stop this misuse, add the bulk
read/write callbacks to regmap_config and call them from the regmap core
code.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Jagan Teki <jagan@amarulasolutions.com>
Cc: Mark Brown <broonie@kernel.org>
Cc: Maxime Ripard <maxime@cerno.tech>
Cc: Robert Foss <robert.foss@linaro.org>
Cc: Sam Ravnborg <sam@ravnborg.org>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
To: dri-devel@lists.freedesktop.org
Link: https://lore.kernel.org/r/20220430025145.640305-1-marex@denx.de
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/base/regmap/internal.h
drivers/base/regmap/regmap.c
include/linux/regmap.h

index b4df36c..da8996e 100644 (file)
@@ -110,6 +110,10 @@ struct regmap {
        int (*reg_write)(void *context, unsigned int reg, unsigned int val);
        int (*reg_update_bits)(void *context, unsigned int reg,
                               unsigned int mask, unsigned int val);
+       /* Bulk read/write */
+       int (*read)(void *context, const void *reg_buf, size_t reg_size,
+                   void *val_buf, size_t val_size);
+       int (*write)(void *context, const void *data, size_t count);
 
        bool defer_caching;
 
index 5e12f7c..879a87a 100644 (file)
@@ -838,12 +838,15 @@ struct regmap *__regmap_init(struct device *dev,
                map->reg_stride_order = ilog2(map->reg_stride);
        else
                map->reg_stride_order = -1;
-       map->use_single_read = config->use_single_read || !bus || !bus->read;
-       map->use_single_write = config->use_single_write || !bus || !bus->write;
-       map->can_multi_write = config->can_multi_write && bus && bus->write;
+       map->use_single_read = config->use_single_read || !(config->read || (bus && bus->read));
+       map->use_single_write = config->use_single_write || !(config->write || (bus && bus->write));
+       map->can_multi_write = config->can_multi_write && (config->write || (bus && bus->write));
        if (bus) {
                map->max_raw_read = bus->max_raw_read;
                map->max_raw_write = bus->max_raw_write;
+       } else if (config->max_raw_read && config->max_raw_write) {
+               map->max_raw_read = config->max_raw_read;
+               map->max_raw_write = config->max_raw_write;
        }
        map->dev = dev;
        map->bus = bus;
@@ -877,7 +880,16 @@ struct regmap *__regmap_init(struct device *dev,
                map->read_flag_mask = bus->read_flag_mask;
        }
 
-       if (!bus) {
+       if (config && config->read && config->write) {
+               map->reg_read  = _regmap_bus_read;
+
+               /* Bulk read/write */
+               map->read = config->read;
+               map->write = config->write;
+
+               reg_endian = REGMAP_ENDIAN_NATIVE;
+               val_endian = REGMAP_ENDIAN_NATIVE;
+       } else if (!bus) {
                map->reg_read  = config->reg_read;
                map->reg_write = config->reg_write;
                map->reg_update_bits = config->reg_update_bits;
@@ -894,10 +906,13 @@ struct regmap *__regmap_init(struct device *dev,
        } else {
                map->reg_read  = _regmap_bus_read;
                map->reg_update_bits = bus->reg_update_bits;
-       }
+               /* Bulk read/write */
+               map->read = bus->read;
+               map->write = bus->write;
 
-       reg_endian = regmap_get_reg_endian(bus, config);
-       val_endian = regmap_get_val_endian(dev, bus, config);
+               reg_endian = regmap_get_reg_endian(bus, config);
+               val_endian = regmap_get_val_endian(dev, bus, config);
+       }
 
        switch (config->reg_bits + map->reg_shift) {
        case 2:
@@ -1671,8 +1686,6 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
        size_t len;
        int i;
 
-       WARN_ON(!map->bus);
-
        /* Check for unwritable or noinc registers in range
         * before we start
         */
@@ -1754,7 +1767,7 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
                val = work_val;
        }
 
-       if (map->async && map->bus->async_write) {
+       if (map->async && map->bus && map->bus->async_write) {
                struct regmap_async *async;
 
                trace_regmap_async_write_start(map, reg, val_len);
@@ -1822,10 +1835,10 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
         * write.
         */
        if (val == work_val)
-               ret = map->bus->write(map->bus_context, map->work_buf,
-                                     map->format.reg_bytes +
-                                     map->format.pad_bytes +
-                                     val_len);
+               ret = map->write(map->bus_context, map->work_buf,
+                                map->format.reg_bytes +
+                                map->format.pad_bytes +
+                                val_len);
        else if (map->bus->gather_write)
                ret = map->bus->gather_write(map->bus_context, map->work_buf,
                                             map->format.reg_bytes +
@@ -1844,7 +1857,7 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
                memcpy(buf, map->work_buf, map->format.reg_bytes);
                memcpy(buf + map->format.reg_bytes + map->format.pad_bytes,
                       val, val_len);
-               ret = map->bus->write(map->bus_context, buf, len);
+               ret = map->write(map->bus_context, buf, len);
 
                kfree(buf);
        } else if (ret != 0 && !map->cache_bypass && map->format.parse_val) {
@@ -1901,7 +1914,7 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg,
        struct regmap_range_node *range;
        struct regmap *map = context;
 
-       WARN_ON(!map->bus || !map->format.format_write);
+       WARN_ON(!map->format.format_write);
 
        range = _regmap_range_lookup(map, reg);
        if (range) {
@@ -1916,8 +1929,7 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg,
 
        trace_regmap_hw_write_start(map, reg, 1);
 
-       ret = map->bus->write(map->bus_context, map->work_buf,
-                             map->format.buf_size);
+       ret = map->write(map->bus_context, map->work_buf, map->format.buf_size);
 
        trace_regmap_hw_write_done(map, reg, 1);
 
@@ -1937,7 +1949,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg,
 {
        struct regmap *map = context;
 
-       WARN_ON(!map->bus || !map->format.format_val);
+       WARN_ON(!map->format.format_val);
 
        map->format.format_val(map->work_buf + map->format.reg_bytes
                               + map->format.pad_bytes, val, 0);
@@ -1951,7 +1963,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg,
 
 static inline void *_regmap_map_get_context(struct regmap *map)
 {
-       return (map->bus) ? map : map->bus_context;
+       return (map->bus || (!map->bus && map->read)) ? map : map->bus_context;
 }
 
 int _regmap_write(struct regmap *map, unsigned int reg,
@@ -2363,7 +2375,7 @@ static int _regmap_raw_multi_reg_write(struct regmap *map,
        u8 = buf;
        *u8 |= map->write_flag_mask;
 
-       ret = map->bus->write(map->bus_context, buf, len);
+       ret = map->write(map->bus_context, buf, len);
 
        kfree(buf);
 
@@ -2669,9 +2681,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
        struct regmap_range_node *range;
        int ret;
 
-       WARN_ON(!map->bus);
-
-       if (!map->bus || !map->bus->read)
+       if (!map->read)
                return -EINVAL;
 
        range = _regmap_range_lookup(map, reg);
@@ -2689,9 +2699,9 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
                                      map->read_flag_mask);
        trace_regmap_hw_read_start(map, reg, val_len / map->format.val_bytes);
 
-       ret = map->bus->read(map->bus_context, map->work_buf,
-                            map->format.reg_bytes + map->format.pad_bytes,
-                            val, val_len);
+       ret = map->read(map->bus_context, map->work_buf,
+                       map->format.reg_bytes + map->format.pad_bytes,
+                       val, val_len);
 
        trace_regmap_hw_read_done(map, reg, val_len / map->format.val_bytes);
 
@@ -2802,8 +2812,6 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
        unsigned int v;
        int ret, i;
 
-       if (!map->bus)
-               return -EINVAL;
        if (val_len % map->format.val_bytes)
                return -EINVAL;
        if (!IS_ALIGNED(reg, map->reg_stride))
@@ -2818,7 +2826,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
                size_t chunk_count, chunk_bytes;
                size_t chunk_regs = val_count;
 
-               if (!map->bus->read) {
+               if (!map->read) {
                        ret = -ENOTSUPP;
                        goto out;
                }
@@ -2878,7 +2886,7 @@ EXPORT_SYMBOL_GPL(regmap_raw_read);
  * @val: Pointer to data buffer
  * @val_len: Length of output buffer in bytes.
  *
- * The regmap API usually assumes that bulk bus read operations will read a
+ * The regmap API usually assumes that bulk read operations will read a
  * range of registers. Some devices have certain registers for which a read
  * operation read will read from an internal FIFO.
  *
@@ -2896,10 +2904,6 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg,
        size_t read_len;
        int ret;
 
-       if (!map->bus)
-               return -EINVAL;
-       if (!map->bus->read)
-               return -ENOTSUPP;
        if (val_len % map->format.val_bytes)
                return -EINVAL;
        if (!IS_ALIGNED(reg, map->reg_stride))
@@ -3013,7 +3017,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
        if (val_count == 0)
                return -EINVAL;
 
-       if (map->bus && map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) {
+       if (map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) {
                ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
                if (ret != 0)
                        return ret;
index de81a94..8952fa3 100644 (file)
@@ -299,6 +299,12 @@ typedef void (*regmap_unlock)(void *);
  *                  if the function require special handling with lock and reg
  *                  handling and the operation cannot be represented as a simple
  *                  update_bits operation on a bus such as SPI, I2C, etc.
+ * @read: Optional callback that if filled will be used to perform all the
+ *        bulk reads from the registers. Data is returned in the buffer used
+ *        to transmit data.
+ * @write: Same as above for writing.
+ * @max_raw_read: Max raw read size that can be used on the device.
+ * @max_raw_write: Max raw write size that can be used on the device.
  * @fast_io:     Register IO is fast. Use a spinlock instead of a mutex
  *               to perform locking. This field is ignored if custom lock/unlock
  *               functions are used (see fields lock/unlock of struct regmap_config).
@@ -385,6 +391,12 @@ struct regmap_config {
        int (*reg_write)(void *context, unsigned int reg, unsigned int val);
        int (*reg_update_bits)(void *context, unsigned int reg,
                               unsigned int mask, unsigned int val);
+       /* Bulk read/write */
+       int (*read)(void *context, const void *reg_buf, size_t reg_size,
+                   void *val_buf, size_t val_size);
+       int (*write)(void *context, const void *data, size_t count);
+       size_t max_raw_read;
+       size_t max_raw_write;
 
        bool fast_io;