mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-31 16:38:12 +00:00
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_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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue