| From: Charles Keepax <ckeepax@opensource.cirrus.com> |
| Date: Mon, 12 Feb 2018 18:15:46 +0000 |
| Subject: regmap: Don't use format_val in regmap_bulk_read |
| |
| 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; |
| } |
| } |
| } |