Commit eedd8a85 authored by Mark Brown's avatar Mark Brown

regmap: Custom bulk operations for regmaps

Merge series from Marek Vasut:

This patch adds an API for custom bulk operations on a simple regmap,
the number of single use bus implementations shows there's a need for
this.
parents d6409475 d77e7456
...@@ -110,6 +110,10 @@ struct regmap { ...@@ -110,6 +110,10 @@ struct regmap {
int (*reg_write)(void *context, unsigned int reg, unsigned int val); int (*reg_write)(void *context, unsigned int reg, unsigned int val);
int (*reg_update_bits)(void *context, unsigned int reg, int (*reg_update_bits)(void *context, unsigned int reg,
unsigned int mask, unsigned int val); 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; bool defer_caching;
......
...@@ -838,12 +838,15 @@ struct regmap *__regmap_init(struct device *dev, ...@@ -838,12 +838,15 @@ struct regmap *__regmap_init(struct device *dev,
map->reg_stride_order = ilog2(map->reg_stride); map->reg_stride_order = ilog2(map->reg_stride);
else else
map->reg_stride_order = -1; map->reg_stride_order = -1;
map->use_single_read = config->use_single_read || !bus || !bus->read; map->use_single_read = config->use_single_read || !(config->read || (bus && bus->read));
map->use_single_write = config->use_single_write || !bus || !bus->write; map->use_single_write = config->use_single_write || !(config->write || (bus && bus->write));
map->can_multi_write = config->can_multi_write && bus && bus->write; map->can_multi_write = config->can_multi_write && (config->write || (bus && bus->write));
if (bus) { if (bus) {
map->max_raw_read = bus->max_raw_read; map->max_raw_read = bus->max_raw_read;
map->max_raw_write = bus->max_raw_write; 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->dev = dev;
map->bus = bus; map->bus = bus;
...@@ -877,7 +880,16 @@ struct regmap *__regmap_init(struct device *dev, ...@@ -877,7 +880,16 @@ struct regmap *__regmap_init(struct device *dev,
map->read_flag_mask = bus->read_flag_mask; 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_read = config->reg_read;
map->reg_write = config->reg_write; map->reg_write = config->reg_write;
map->reg_update_bits = config->reg_update_bits; map->reg_update_bits = config->reg_update_bits;
...@@ -894,10 +906,13 @@ struct regmap *__regmap_init(struct device *dev, ...@@ -894,10 +906,13 @@ struct regmap *__regmap_init(struct device *dev,
} else { } else {
map->reg_read = _regmap_bus_read; map->reg_read = _regmap_bus_read;
map->reg_update_bits = bus->reg_update_bits; 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); reg_endian = regmap_get_reg_endian(bus, config);
val_endian = regmap_get_val_endian(dev, bus, config); val_endian = regmap_get_val_endian(dev, bus, config);
}
switch (config->reg_bits + map->reg_shift) { switch (config->reg_bits + map->reg_shift) {
case 2: case 2:
...@@ -1671,8 +1686,6 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg, ...@@ -1671,8 +1686,6 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
size_t len; size_t len;
int i; int i;
WARN_ON(!map->bus);
/* Check for unwritable or noinc registers in range /* Check for unwritable or noinc registers in range
* before we start * before we start
*/ */
...@@ -1754,7 +1767,7 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg, ...@@ -1754,7 +1767,7 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
val = work_val; val = work_val;
} }
if (map->async && map->bus->async_write) { if (map->async && map->bus && map->bus->async_write) {
struct regmap_async *async; struct regmap_async *async;
trace_regmap_async_write_start(map, reg, val_len); 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, ...@@ -1822,10 +1835,10 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
* write. * write.
*/ */
if (val == work_val) if (val == work_val)
ret = map->bus->write(map->bus_context, map->work_buf, ret = map->write(map->bus_context, map->work_buf,
map->format.reg_bytes + map->format.reg_bytes +
map->format.pad_bytes + map->format.pad_bytes +
val_len); val_len);
else if (map->bus->gather_write) else if (map->bus->gather_write)
ret = map->bus->gather_write(map->bus_context, map->work_buf, ret = map->bus->gather_write(map->bus_context, map->work_buf,
map->format.reg_bytes + map->format.reg_bytes +
...@@ -1844,7 +1857,7 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg, ...@@ -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->work_buf, map->format.reg_bytes);
memcpy(buf + map->format.reg_bytes + map->format.pad_bytes, memcpy(buf + map->format.reg_bytes + map->format.pad_bytes,
val, val_len); val, val_len);
ret = map->bus->write(map->bus_context, buf, len); ret = map->write(map->bus_context, buf, len);
kfree(buf); kfree(buf);
} else if (ret != 0 && !map->cache_bypass && map->format.parse_val) { } 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, ...@@ -1901,7 +1914,7 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg,
struct regmap_range_node *range; struct regmap_range_node *range;
struct regmap *map = context; struct regmap *map = context;
WARN_ON(!map->bus || !map->format.format_write); WARN_ON(!map->format.format_write);
range = _regmap_range_lookup(map, reg); range = _regmap_range_lookup(map, reg);
if (range) { if (range) {
...@@ -1916,8 +1929,7 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg, ...@@ -1916,8 +1929,7 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg,
trace_regmap_hw_write_start(map, reg, 1); trace_regmap_hw_write_start(map, reg, 1);
ret = map->bus->write(map->bus_context, map->work_buf, ret = map->write(map->bus_context, map->work_buf, map->format.buf_size);
map->format.buf_size);
trace_regmap_hw_write_done(map, reg, 1); trace_regmap_hw_write_done(map, reg, 1);
...@@ -1937,7 +1949,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg, ...@@ -1937,7 +1949,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg,
{ {
struct regmap *map = context; 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.format_val(map->work_buf + map->format.reg_bytes
+ map->format.pad_bytes, val, 0); + map->format.pad_bytes, val, 0);
...@@ -1951,7 +1963,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg, ...@@ -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) 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, int _regmap_write(struct regmap *map, unsigned int reg,
...@@ -2363,7 +2375,7 @@ static int _regmap_raw_multi_reg_write(struct regmap *map, ...@@ -2363,7 +2375,7 @@ static int _regmap_raw_multi_reg_write(struct regmap *map,
u8 = buf; u8 = buf;
*u8 |= map->write_flag_mask; *u8 |= map->write_flag_mask;
ret = map->bus->write(map->bus_context, buf, len); ret = map->write(map->bus_context, buf, len);
kfree(buf); kfree(buf);
...@@ -2669,9 +2681,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, ...@@ -2669,9 +2681,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
struct regmap_range_node *range; struct regmap_range_node *range;
int ret; int ret;
WARN_ON(!map->bus); if (!map->read)
if (!map->bus || !map->bus->read)
return -EINVAL; return -EINVAL;
range = _regmap_range_lookup(map, reg); range = _regmap_range_lookup(map, reg);
...@@ -2689,9 +2699,9 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, ...@@ -2689,9 +2699,9 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
map->read_flag_mask); map->read_flag_mask);
trace_regmap_hw_read_start(map, reg, val_len / map->format.val_bytes); trace_regmap_hw_read_start(map, reg, val_len / map->format.val_bytes);
ret = map->bus->read(map->bus_context, map->work_buf, ret = map->read(map->bus_context, map->work_buf,
map->format.reg_bytes + map->format.pad_bytes, map->format.reg_bytes + map->format.pad_bytes,
val, val_len); val, val_len);
trace_regmap_hw_read_done(map, reg, val_len / map->format.val_bytes); 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, ...@@ -2802,8 +2812,6 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
unsigned int v; unsigned int v;
int ret, i; int ret, i;
if (!map->bus)
return -EINVAL;
if (val_len % map->format.val_bytes) if (val_len % map->format.val_bytes)
return -EINVAL; return -EINVAL;
if (!IS_ALIGNED(reg, map->reg_stride)) if (!IS_ALIGNED(reg, map->reg_stride))
...@@ -2818,7 +2826,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, ...@@ -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_count, chunk_bytes;
size_t chunk_regs = val_count; size_t chunk_regs = val_count;
if (!map->bus->read) { if (!map->read) {
ret = -ENOTSUPP; ret = -ENOTSUPP;
goto out; goto out;
} }
...@@ -2878,7 +2886,7 @@ EXPORT_SYMBOL_GPL(regmap_raw_read); ...@@ -2878,7 +2886,7 @@ EXPORT_SYMBOL_GPL(regmap_raw_read);
* @val: Pointer to data buffer * @val: Pointer to data buffer
* @val_len: Length of output buffer in bytes. * @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 * range of registers. Some devices have certain registers for which a read
* operation read will read from an internal FIFO. * operation read will read from an internal FIFO.
* *
...@@ -2896,10 +2904,6 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg, ...@@ -2896,10 +2904,6 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg,
size_t read_len; size_t read_len;
int ret; int ret;
if (!map->bus)
return -EINVAL;
if (!map->bus->read)
return -ENOTSUPP;
if (val_len % map->format.val_bytes) if (val_len % map->format.val_bytes)
return -EINVAL; return -EINVAL;
if (!IS_ALIGNED(reg, map->reg_stride)) if (!IS_ALIGNED(reg, map->reg_stride))
...@@ -3013,7 +3017,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, ...@@ -3013,7 +3017,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
if (val_count == 0) if (val_count == 0)
return -EINVAL; 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); ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
if (ret != 0) if (ret != 0)
return ret; return ret;
......
...@@ -299,6 +299,12 @@ typedef void (*regmap_unlock)(void *); ...@@ -299,6 +299,12 @@ typedef void (*regmap_unlock)(void *);
* if the function require special handling with lock and reg * if the function require special handling with lock and reg
* handling and the operation cannot be represented as a simple * handling and the operation cannot be represented as a simple
* update_bits operation on a bus such as SPI, I2C, etc. * 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 * @fast_io: Register IO is fast. Use a spinlock instead of a mutex
* to perform locking. This field is ignored if custom lock/unlock * to perform locking. This field is ignored if custom lock/unlock
* functions are used (see fields lock/unlock of struct regmap_config). * functions are used (see fields lock/unlock of struct regmap_config).
...@@ -385,6 +391,12 @@ struct regmap_config { ...@@ -385,6 +391,12 @@ struct regmap_config {
int (*reg_write)(void *context, unsigned int reg, unsigned int val); int (*reg_write)(void *context, unsigned int reg, unsigned int val);
int (*reg_update_bits)(void *context, unsigned int reg, int (*reg_update_bits)(void *context, unsigned int reg,
unsigned int mask, unsigned int val); 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; bool fast_io;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment