diff options
author | Charles Keepax <ckeepax@opensource.cirrus.com> | 2018-02-12 19:15:46 +0100 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2018-02-13 13:27:44 +0100 |
commit | 9ae27a8d1f3ebff09191fb8cb1341414547293b2 (patch) | |
tree | ee8549ff39f7b3cb11b3aaeb5c365b371e36547f /drivers/base | |
parent | Linux 4.16-rc1 (diff) | |
download | linux-9ae27a8d1f3ebff09191fb8cb1341414547293b2.tar.xz linux-9ae27a8d1f3ebff09191fb8cb1341414547293b2.zip |
regmap: Don't use format_val in regmap_bulk_read
A bulk read can be implemented either through regmap_raw_read, or
by reading each register individually using regmap_read. Both
regmap_read and regmap_bulk_read should return values in native
endian. In the individual case the current implementation calls
format_val to put the data into the output array, which can cause
endian issues. The regmap_read will have already converted the data
into native endian, if the hosts endian differs from the device then
format_val will switch the endian back again.
Rather than using format_val simply use the code that is called if
there is no format_val function. This code supports all cases except
24-bit but there don't appear to be any users of regmap_bulk_read for
24-bit. Additionally, it would have to be a big endian host for the
old code to actually function correctly anyway.
Fixes: 15b8d2c41fe5 ("regmap: Fix regmap_bulk_read in BE mode")
Reported-by: David Rhodes <david.rhodes@cirrus.com>
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/regmap/regmap.c | 55 |
1 files changed, 23 insertions, 32 deletions
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index ee302ccdfbc8..4037b3782bd3 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2709,47 +2709,38 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, for (i = 0; i < val_count * val_bytes; i += val_bytes) map->format.parse_inplace(val + i); } else { +#ifdef CONFIG_64BIT + u64 *u64 = val; +#endif + u32 *u32 = val; + u16 *u16 = val; + u8 *u8 = val; + for (i = 0; i < val_count; i++) { unsigned int ival; + ret = regmap_read(map, reg + regmap_get_offset(map, i), &ival); if (ret != 0) return ret; - if (map->format.format_val) { - map->format.format_val(val + (i * val_bytes), ival, 0); - } else { - /* Devices providing read and write - * operations can use the bulk I/O - * functions if they define a val_bytes, - * we assume that the values are native - * endian. - */ -#ifdef CONFIG_64BIT - u64 *u64 = val; -#endif - u32 *u32 = val; - u16 *u16 = val; - u8 *u8 = val; - - switch (map->format.val_bytes) { + switch (map->format.val_bytes) { #ifdef CONFIG_64BIT - case 8: - u64[i] = ival; - break; + case 8: + u64[i] = ival; + break; #endif - case 4: - u32[i] = ival; - break; - case 2: - u16[i] = ival; - break; - case 1: - u8[i] = ival; - break; - default: - return -EINVAL; - } + case 4: + u32[i] = ival; + break; + case 2: + u16[i] = ival; + break; + case 1: + u8[i] = ival; + break; + default: + return -EINVAL; } } } |