regmap: Implement regmap_multi_reg_read()

regmap_multi_reg_read() is similar to regmap_bilk_read() but reads from
an array of non-sequential registers.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20240710015622.1960522-2-linux@roeck-us.net
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Guenter Roeck 2024-07-09 18:56:20 -07:00 committed by Mark Brown
parent f2661062f1
commit 3c1ff93b4d
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 70 additions and 35 deletions

View File

@ -3101,8 +3101,53 @@ int regmap_fields_read(struct regmap_field *field, unsigned int id,
}
EXPORT_SYMBOL_GPL(regmap_fields_read);
static int _regmap_bulk_read(struct regmap *map, unsigned int reg,
unsigned int *regs, void *val, size_t val_count)
{
u32 *u32 = val;
u16 *u16 = val;
u8 *u8 = val;
int ret, i;
map->lock(map->lock_arg);
for (i = 0; i < val_count; i++) {
unsigned int ival;
if (regs) {
if (!IS_ALIGNED(regs[i], map->reg_stride)) {
ret = -EINVAL;
goto out;
}
ret = _regmap_read(map, regs[i], &ival);
} else {
ret = _regmap_read(map, reg + regmap_get_offset(map, i), &ival);
}
if (ret != 0)
goto out;
switch (map->format.val_bytes) {
case 4:
u32[i] = ival;
break;
case 2:
u16[i] = ival;
break;
case 1:
u8[i] = ival;
break;
default:
ret = -EINVAL;
goto out;
}
}
out:
map->unlock(map->lock_arg);
return ret;
}
/**
* regmap_bulk_read() - Read multiple registers from the device
* regmap_bulk_read() - Read multiple sequential registers from the device
*
* @map: Register map to read from
* @reg: First register to be read from
@ -3132,47 +3177,35 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
for (i = 0; i < val_count * val_bytes; i += val_bytes)
map->format.parse_inplace(val + i);
} else {
u32 *u32 = val;
u16 *u16 = val;
u8 *u8 = val;
map->lock(map->lock_arg);
for (i = 0; i < val_count; i++) {
unsigned int ival;
ret = _regmap_read(map, reg + regmap_get_offset(map, i),
&ival);
if (ret != 0)
goto out;
switch (map->format.val_bytes) {
case 4:
u32[i] = ival;
break;
case 2:
u16[i] = ival;
break;
case 1:
u8[i] = ival;
break;
default:
ret = -EINVAL;
goto out;
}
}
out:
map->unlock(map->lock_arg);
ret = _regmap_bulk_read(map, reg, NULL, val, val_count);
}
if (!ret)
trace_regmap_bulk_read(map, reg, val, val_bytes * val_count);
return ret;
}
EXPORT_SYMBOL_GPL(regmap_bulk_read);
/**
* regmap_multi_reg_read() - Read multiple non-sequential registers from the device
*
* @map: Register map to read from
* @regs: Array of registers to read from
* @val: Pointer to store read value, in native register size for device
* @val_count: Number of registers to read
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
int regmap_multi_reg_read(struct regmap *map, unsigned int *regs, void *val,
size_t val_count)
{
if (val_count == 0)
return -EINVAL;
return _regmap_bulk_read(map, 0, regs, val, val_count);
}
EXPORT_SYMBOL_GPL(regmap_multi_reg_read);
static int _regmap_update_bits(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val,
bool *change, bool force_write)

View File

@ -1237,6 +1237,8 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg,
void *val, size_t val_len);
int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
size_t val_count);
int regmap_multi_reg_read(struct regmap *map, unsigned int *reg, void *val,
size_t val_count);
int regmap_update_bits_base(struct regmap *map, unsigned int reg,
unsigned int mask, unsigned int val,
bool *change, bool async, bool force);