Skip to content

Commit 77792b1

Browse files
ringlejbroonie
authored andcommitted
regmap: Allow installing custom reg_update_bits function
This commit allows installing a custom reg_update_bits function for cases where the hardware provides a mechanism to set or clear register bits without a read/modify/write cycle. Such is the case with the Microchip ENCX24J600. If a custom reg_update_bits function is provided, it will only be used against volatile registers. Signed-off-by: Jon Ringle <[email protected]> Signed-off-by: Mark Brown <[email protected]>
1 parent 6ff33f3 commit 77792b1

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)