3.16.60-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Charles Keepax ckeepax@opensource.cirrus.com
commit 9ae27a8d1f3ebff09191fb8cb1341414547293b2 upstream.
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 [bwh: Backported to 3.16: - 64-bit I/O is not supported - Adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2240,39 +2240,30 @@ int regmap_bulk_read(struct regmap *map, for (i = 0; i < val_count * val_bytes; i += val_bytes) map->format.parse_inplace(val + i); } else { + u32 *u32 = val; + u16 *u16 = val; + u8 *u8 = val; + for (i = 0; i < val_count; i++) { unsigned int ival; + ret = regmap_read(map, reg + (i * map->reg_stride), &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. - */ - u32 *u32 = val; - u16 *u16 = val; - u8 *u8 = val; - - switch (map->format.val_bytes) { - case 4: - u32[i] = ival; - break; - case 2: - u16[i] = ival; - break; - case 1: - u8[i] = ival; - break; - default: - return -EINVAL; - } + switch (map->format.val_bytes) { + case 4: + u32[i] = ival; + break; + case 2: + u16[i] = ival; + break; + case 1: + u8[i] = ival; + break; + default: + return -EINVAL; } } }