aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-11-07 16:56:10 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2023-11-07 16:56:10 -0800
commiteaec7c9892bd565ffc7dcd32515b157011ca2323 (patch)
tree8a077b95ccc50a0b27957362c1737b0e28be1b42
parentb8dd631fcabe2656c8d3751ad4836131d51fb63b (diff)
parent984a4afdc87a1fc226fd657b1cd8255c13d3fc1a (diff)
downloadlinux-nomadik-eaec7c9892bd565ffc7dcd32515b157011ca2323.tar.gz
Merge tag 'regmap-fix-v6.7-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
Pull regmap fix from Mark Brown: "One fix here, for an interaction between noinc registers and caches. If a device uses noinc registers (which is rare) then we could corrupt registers after the noinc register in the cache" * tag 'regmap-fix-v6.7-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: regmap: prevent noinc writes from clobbering cache
-rw-r--r--drivers/base/regmap/regmap.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 234a84ecde8b1b..ea615774719941 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1620,17 +1620,19 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
}
if (!map->cache_bypass && map->format.parse_val) {
- unsigned int ival;
+ unsigned int ival, offset;
int val_bytes = map->format.val_bytes;
- for (i = 0; i < val_len / val_bytes; i++) {
- ival = map->format.parse_val(val + (i * val_bytes));
- ret = regcache_write(map,
- reg + regmap_get_offset(map, i),
- ival);
+
+ /* Cache the last written value for noinc writes */
+ i = noinc ? val_len - val_bytes : 0;
+ for (; i < val_len; i += val_bytes) {
+ ival = map->format.parse_val(val + i);
+ offset = noinc ? 0 : regmap_get_offset(map, i / val_bytes);
+ ret = regcache_write(map, reg + offset, ival);
if (ret) {
dev_err(map->dev,
"Error in caching of register: %x ret: %d\n",
- reg + regmap_get_offset(map, i), ret);
+ reg + offset, ret);
return ret;
}
}