regmap: Add bulk read/write callbacks into regmap_config
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>
This commit is contained in:
parent
3123109284
commit
d77e745613
3 changed files with 56 additions and 36 deletions
|
@ -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,
|
||||||
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,
|
||||||
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,
|
||||||
} 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,
|
||||||
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,
|
||||||
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,
|
||||||
* 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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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);
|
||||||
* @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,
|
||||||
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,
|
||||||
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 *);
|
||||||
* 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 {
|
||||||
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;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue