Skip to content

Commit 61d0372

Browse files
committed
Merge tag 'regmap-offload-update-bits' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
regmap: Allow buses to provide a custom update_bits() operation Some buses provide a native _update_bits() operation which for uncached registers is faster than doing a read/modify/write cycle as it is a single bus transaction. Add support for implementing this to regmap.
2 parents acb4a6b + 77792b1 commit 61d0372

File tree

3 files changed

+23
-11
lines changed

3 files changed

+23
-11
lines changed

drivers/base/regmap/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ struct regmap {
9898

9999
int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
100100
int (*reg_write)(void *context, unsigned int reg, unsigned int val);
101+
int (*reg_update_bits)(void *context, unsigned int reg,
102+
unsigned int mask, unsigned int val);
101103

102104
bool defer_caching;
103105

drivers/base/regmap/regmap.c

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,7 @@ struct regmap *__regmap_init(struct device *dev,
619619
goto skip_format_initialization;
620620
} else {
621621
map->reg_read = _regmap_bus_read;
622+
map->reg_update_bits = bus->reg_update_bits;
622623
}
623624

624625
reg_endian = regmap_get_reg_endian(bus, config);
@@ -2509,20 +2510,26 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
25092510
int ret;
25102511
unsigned int tmp, orig;
25112512

2512-
ret = _regmap_read(map, reg, &orig);
2513-
if (ret != 0)
2514-
return ret;
2513+
if (change)
2514+
*change = false;
25152515

2516-
tmp = orig & ~mask;
2517-
tmp |= val & mask;
2518-
2519-
if (force_write || (tmp != orig)) {
2520-
ret = _regmap_write(map, reg, tmp);
2521-
if (change)
2516+
if (regmap_volatile(map, reg) && map->reg_update_bits) {
2517+
ret = map->reg_update_bits(map->bus_context, reg, mask, val);
2518+
if (ret == 0 && change)
25222519
*change = true;
25232520
} else {
2524-
if (change)
2525-
*change = false;
2521+
ret = _regmap_read(map, reg, &orig);
2522+
if (ret != 0)
2523+
return ret;
2524+
2525+
tmp = orig & ~mask;
2526+
tmp |= val & mask;
2527+
2528+
if (force_write || (tmp != orig)) {
2529+
ret = _regmap_write(map, reg, tmp);
2530+
if (ret == 0 && change)
2531+
*change = true;
2532+
}
25262533
}
25272534

25282535
return ret;

include/linux/regmap.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ typedef int (*regmap_hw_reg_read)(void *context, unsigned int reg,
296296
unsigned int *val);
297297
typedef int (*regmap_hw_reg_write)(void *context, unsigned int reg,
298298
unsigned int val);
299+
typedef int (*regmap_hw_reg_update_bits)(void *context, unsigned int reg,
300+
unsigned int mask, unsigned int val);
299301
typedef struct regmap_async *(*regmap_hw_async_alloc)(void);
300302
typedef void (*regmap_hw_free_context)(void *context);
301303

@@ -335,6 +337,7 @@ struct regmap_bus {
335337
regmap_hw_gather_write gather_write;
336338
regmap_hw_async_write async_write;
337339
regmap_hw_reg_write reg_write;
340+
regmap_hw_reg_update_bits reg_update_bits;
338341
regmap_hw_read read;
339342
regmap_hw_reg_read reg_read;
340343
regmap_hw_free_context free_context;

0 commit comments

Comments
 (0)