Skip to content

Commit 74fe7b5

Browse files
Crestez Dan Leonardbroonie
authored andcommitted
regmap: Add regmap_noinc_read API
The regmap API usually assumes that bulk read operations will read a range of registers but some I2C/SPI devices have certain registers for which a such a read operation will return data from an internal FIFO instead. Add an explicit API to support bulk read without range semantics. Some linux drivers use regmap_bulk_read or regmap_raw_read for such registers, for example mpu6050 or bmi150 from IIO. This only happens to work because when caching is disabled a single regmap read op will map to a single bus read op (as desired). This breaks if caching is enabled and reg+1 happens to be a cacheable register. Without regmap support refactoring a driver to enable regmap caching requires separate I2C and SPI paths. This is exactly what regmap is supposed to help avoid. Suggested-by: Jonathan Cameron <[email protected]> Signed-off-by: Crestez Dan Leonard <[email protected]> Signed-off-by: Stefan Popa <[email protected]> Signed-off-by: Mark Brown <[email protected]>
1 parent ce397d2 commit 74fe7b5

File tree

3 files changed

+100
-1
lines changed

3 files changed

+100
-1
lines changed

drivers/base/regmap/internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,12 @@ struct regmap {
9494
bool (*readable_reg)(struct device *dev, unsigned int reg);
9595
bool (*volatile_reg)(struct device *dev, unsigned int reg);
9696
bool (*precious_reg)(struct device *dev, unsigned int reg);
97+
bool (*readable_noinc_reg)(struct device *dev, unsigned int reg);
9798
const struct regmap_access_table *wr_table;
9899
const struct regmap_access_table *rd_table;
99100
const struct regmap_access_table *volatile_table;
100101
const struct regmap_access_table *precious_table;
102+
const struct regmap_access_table *rd_noinc_table;
101103

102104
int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
103105
int (*reg_write)(void *context, unsigned int reg, unsigned int val);
@@ -181,6 +183,7 @@ bool regmap_writeable(struct regmap *map, unsigned int reg);
181183
bool regmap_readable(struct regmap *map, unsigned int reg);
182184
bool regmap_volatile(struct regmap *map, unsigned int reg);
183185
bool regmap_precious(struct regmap *map, unsigned int reg);
186+
bool regmap_readable_noinc(struct regmap *map, unsigned int reg);
184187

185188
int _regmap_write(struct regmap *map, unsigned int reg,
186189
unsigned int val);

drivers/base/regmap/regmap.c

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,17 @@ bool regmap_precious(struct regmap *map, unsigned int reg)
168168
return false;
169169
}
170170

171+
bool regmap_readable_noinc(struct regmap *map, unsigned int reg)
172+
{
173+
if (map->readable_noinc_reg)
174+
return map->readable_noinc_reg(map->dev, reg);
175+
176+
if (map->rd_noinc_table)
177+
return regmap_check_range_table(map, reg, map->rd_noinc_table);
178+
179+
return true;
180+
}
181+
171182
static bool regmap_volatile_range(struct regmap *map, unsigned int reg,
172183
size_t num)
173184
{
@@ -766,10 +777,12 @@ struct regmap *__regmap_init(struct device *dev,
766777
map->rd_table = config->rd_table;
767778
map->volatile_table = config->volatile_table;
768779
map->precious_table = config->precious_table;
780+
map->rd_noinc_table = config->rd_noinc_table;
769781
map->writeable_reg = config->writeable_reg;
770782
map->readable_reg = config->readable_reg;
771783
map->volatile_reg = config->volatile_reg;
772784
map->precious_reg = config->precious_reg;
785+
map->readable_noinc_reg = config->readable_noinc_reg;
773786
map->cache_type = config->cache_type;
774787

775788
spin_lock_init(&map->async_lock);
@@ -1285,6 +1298,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
12851298
map->readable_reg = config->readable_reg;
12861299
map->volatile_reg = config->volatile_reg;
12871300
map->precious_reg = config->precious_reg;
1301+
map->readable_noinc_reg = config->readable_noinc_reg;
12881302
map->cache_type = config->cache_type;
12891303

12901304
regmap_debugfs_init(map, config->name);
@@ -2564,7 +2578,70 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
25642578
EXPORT_SYMBOL_GPL(regmap_raw_read);
25652579

25662580
/**
2567-
* regmap_field_read() - Read a value to a single register field
2581+
* regmap_noinc_read(): Read data from a register without incrementing the
2582+
* register number
2583+
*
2584+
* @map: Register map to read from
2585+
* @reg: Register to read from
2586+
* @val: Pointer to data buffer
2587+
* @val_len: Length of output buffer in bytes.
2588+
*
2589+
* The regmap API usually assumes that bulk bus read operations will read a
2590+
* range of registers. Some devices have certain registers for which a read
2591+
* operation read will read from an internal FIFO.
2592+
*
2593+
* The target register must be volatile but registers after it can be
2594+
* completely unrelated cacheable registers.
2595+
*
2596+
* This will attempt multiple reads as required to read val_len bytes.
2597+
*
2598+
* A value of zero will be returned on success, a negative errno will be
2599+
* returned in error cases.
2600+
*/
2601+
int regmap_noinc_read(struct regmap *map, unsigned int reg,
2602+
void *val, size_t val_len)
2603+
{
2604+
size_t read_len;
2605+
int ret;
2606+
2607+
if (!map->bus)
2608+
return -EINVAL;
2609+
if (!map->bus->read)
2610+
return -ENOTSUPP;
2611+
if (val_len % map->format.val_bytes)
2612+
return -EINVAL;
2613+
if (!IS_ALIGNED(reg, map->reg_stride))
2614+
return -EINVAL;
2615+
if (val_len == 0)
2616+
return -EINVAL;
2617+
2618+
map->lock(map->lock_arg);
2619+
2620+
if (!regmap_volatile(map, reg) || !regmap_readable_noinc(map, reg)) {
2621+
ret = -EINVAL;
2622+
goto out_unlock;
2623+
}
2624+
2625+
while (val_len) {
2626+
if (map->max_raw_read && map->max_raw_read < val_len)
2627+
read_len = map->max_raw_read;
2628+
else
2629+
read_len = val_len;
2630+
ret = _regmap_raw_read(map, reg, val, read_len);
2631+
if (ret)
2632+
goto out_unlock;
2633+
val = ((u8 *)val) + read_len;
2634+
val_len -= read_len;
2635+
}
2636+
2637+
out_unlock:
2638+
map->unlock(map->lock_arg);
2639+
return ret;
2640+
}
2641+
EXPORT_SYMBOL_GPL(regmap_noinc_read);
2642+
2643+
/**
2644+
* regmap_field_read(): Read a value to a single register field
25682645
*
25692646
* @field: Register field to read from
25702647
* @val: Pointer to store read value

include/linux/regmap.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,13 @@ typedef void (*regmap_unlock)(void *);
268268
* field is NULL but precious_table (see below) is not, the
269269
* check is performed on such table (a register is precious if
270270
* it belongs to one of the ranges specified by precious_table).
271+
* @readable_noinc_reg: Optional callback returning true if the register
272+
* supports multiple read operations without incrementing
273+
* the register number. If this field is NULL but
274+
* rd_noinc_table (see below) is not, the check is
275+
* performed on such table (a register is no increment
276+
* readable if it belongs to one of the ranges specified
277+
* by rd_noinc_table).
271278
* @disable_locking: This regmap is either protected by external means or
272279
* is guaranteed not be be accessed from multiple threads.
273280
* Don't use any locking mechanisms.
@@ -295,6 +302,7 @@ typedef void (*regmap_unlock)(void *);
295302
* @rd_table: As above, for read access.
296303
* @volatile_table: As above, for volatile registers.
297304
* @precious_table: As above, for precious registers.
305+
* @rd_noinc_table: As above, for no increment readable registers.
298306
* @reg_defaults: Power on reset values for registers (for use with
299307
* register cache support).
300308
* @num_reg_defaults: Number of elements in reg_defaults.
@@ -344,6 +352,7 @@ struct regmap_config {
344352
bool (*readable_reg)(struct device *dev, unsigned int reg);
345353
bool (*volatile_reg)(struct device *dev, unsigned int reg);
346354
bool (*precious_reg)(struct device *dev, unsigned int reg);
355+
bool (*readable_noinc_reg)(struct device *dev, unsigned int reg);
347356

348357
bool disable_locking;
349358
regmap_lock lock;
@@ -360,6 +369,7 @@ struct regmap_config {
360369
const struct regmap_access_table *rd_table;
361370
const struct regmap_access_table *volatile_table;
362371
const struct regmap_access_table *precious_table;
372+
const struct regmap_access_table *rd_noinc_table;
363373
const struct reg_default *reg_defaults;
364374
unsigned int num_reg_defaults;
365375
enum regcache_type cache_type;
@@ -946,6 +956,8 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg,
946956
int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);
947957
int regmap_raw_read(struct regmap *map, unsigned int reg,
948958
void *val, size_t val_len);
959+
int regmap_noinc_read(struct regmap *map, unsigned int reg,
960+
void *val, size_t val_len);
949961
int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
950962
size_t val_count);
951963
int regmap_update_bits_base(struct regmap *map, unsigned int reg,
@@ -1196,6 +1208,13 @@ static inline int regmap_raw_read(struct regmap *map, unsigned int reg,
11961208
return -EINVAL;
11971209
}
11981210

1211+
static inline int regmap_noinc_read(struct regmap *map, unsigned int reg,
1212+
void *val, size_t val_len)
1213+
{
1214+
WARN_ONCE(1, "regmap API is disabled");
1215+
return -EINVAL;
1216+
}
1217+
11991218
static inline int regmap_bulk_read(struct regmap *map, unsigned int reg,
12001219
void *val, size_t val_count)
12011220
{

0 commit comments

Comments
 (0)