regmap: prevent noinc writes from clobbering cache
authorBen Wolsieffer <ben.wolsieffer@hefring.com>
Wed, 1 Nov 2023 14:29:27 +0000 (10:29 -0400)
committerMark Brown <broonie@kernel.org>
Wed, 1 Nov 2023 20:22:55 +0000 (20:22 +0000)
Currently, noinc writes are cached as if they were standard incrementing
writes, overwriting unrelated register values in the cache. Instead, we
want to cache the last value written to the register, as is done in the
accelerated noinc handler (regmap_noinc_readwrite).

Fixes: cdf6b11daa77 ("regmap: Add regmap_noinc_write API")
Signed-off-by: Ben Wolsieffer <ben.wolsieffer@hefring.com>
Link: https://lore.kernel.org/r/20231101142926.2722603-2-ben.wolsieffer@hefring.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/base/regmap/regmap.c

index 884cb51c8f67291fc25724c05ec03aa6f56f02ac..784eb9ba56fe241a1a55a0fbfd1bbc59df61b1d9 100644 (file)
@@ -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;
                        }
                }