diff options
author | Jon Ringle <jringle@gridpoint.com> | 2015-10-01 12:38:07 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-10-06 11:12:34 -0400 |
commit | 77792b11409c9270d98e604b4314b85ce886ac7d (patch) | |
tree | 13f3a518de69bbbccbd410b26ff24f0379c28dfd /drivers/base | |
parent | 6ff33f3902c3b1c5d0db6b1e2c70b6d76fba357f (diff) |
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 <jringle@gridpoint.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/regmap/internal.h | 2 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 29 |
2 files changed, 20 insertions, 11 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index cc557886ab23..628ad7ac078b 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h | |||
@@ -98,6 +98,8 @@ struct regmap { | |||
98 | 98 | ||
99 | int (*reg_read)(void *context, unsigned int reg, unsigned int *val); | 99 | int (*reg_read)(void *context, unsigned int reg, unsigned int *val); |
100 | int (*reg_write)(void *context, unsigned int reg, unsigned int val); | 100 | 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); | ||
101 | 103 | ||
102 | bool defer_caching; | 104 | bool defer_caching; |
103 | 105 | ||
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index afaf56200674..8cd155af3d63 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -619,6 +619,7 @@ struct regmap *__regmap_init(struct device *dev, | |||
619 | goto skip_format_initialization; | 619 | goto skip_format_initialization; |
620 | } else { | 620 | } else { |
621 | map->reg_read = _regmap_bus_read; | 621 | map->reg_read = _regmap_bus_read; |
622 | map->reg_update_bits = bus->reg_update_bits; | ||
622 | } | 623 | } |
623 | 624 | ||
624 | reg_endian = regmap_get_reg_endian(bus, config); | 625 | reg_endian = regmap_get_reg_endian(bus, config); |
@@ -2509,20 +2510,26 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, | |||
2509 | int ret; | 2510 | int ret; |
2510 | unsigned int tmp, orig; | 2511 | unsigned int tmp, orig; |
2511 | 2512 | ||
2512 | ret = _regmap_read(map, reg, &orig); | 2513 | if (change) |
2513 | if (ret != 0) | 2514 | *change = false; |
2514 | return ret; | ||
2515 | 2515 | ||
2516 | tmp = orig & ~mask; | 2516 | if (regmap_volatile(map, reg) && map->reg_update_bits) { |
2517 | tmp |= val & mask; | 2517 | ret = map->reg_update_bits(map->bus_context, reg, mask, val); |
2518 | 2518 | if (ret == 0 && change) | |
2519 | if (force_write || (tmp != orig)) { | ||
2520 | ret = _regmap_write(map, reg, tmp); | ||
2521 | if (change) | ||
2522 | *change = true; | 2519 | *change = true; |
2523 | } else { | 2520 | } else { |
2524 | if (change) | 2521 | ret = _regmap_read(map, reg, &orig); |
2525 | *change = false; | 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 | } | ||
2526 | } | 2533 | } |
2527 | 2534 | ||
2528 | return ret; | 2535 | return ret; |