For the following cases of the SoCs using regmap-mmio: Index CPU mode Device mode Need Bytes Swap ? -------------------------------------------------- 1 LE LE No 2 LE BE Yes 3 BE BE No 4 BE LE Yes
And possiblly one Device will be used in all the endianness modes above with the same device driver, then for the 1 and 3 cases the REGMAP_ENDIAN_NATIVE is okey, but for the 2 and 4 cases, the REGMAP_ENDIAN_SWAP is needed. For the DT node, just one property like 'endian-swap' will be okey for cases 2 and 4. ---- Certainly, for the 2 case, we can just use REGMAP_ENDIAN_BIG instead of REGMAP_ENDIAN_SWAP, and then we should add one DT node property like 'big-endian'. While for the 4 case, we can just use REGMAP_ENDIAN_LITTLE instead of REGMAP_ENDIAN_SWAP, and then we should add one DT node property like 'little-endian'. Another question is that the REGMAP_ENDIAN_LITTLE hasn't support by regmap core yet. And using the REGMAP_ENDIAN_BIG and REGMAP_ENDIAN_LITTLE will make the driver a bit more complex, and also the usage of it. Thus using the REGMAP_ENDIAN_SWAP and one DT node property like 'endian-swap' will make the driver more easy to develop and to use for all the above possible cases. Signed-off-by: Xiubo Li <li.xi...@freescale.com> --- drivers/base/regmap/regmap.c | 56 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/regmap.h | 1 + 2 files changed, 57 insertions(+) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 6a19515..71e0a0d 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -192,6 +192,14 @@ static void regmap_format_16_be(void *buf, unsigned int val, unsigned int shift) b[0] = cpu_to_be16(val << shift); } +static void regmap_format_16_swap(void *buf, unsigned int val, + unsigned int shift) +{ + __u16 *b = buf; + + b[0] = __swab16(val << shift); +} + static void regmap_format_16_native(void *buf, unsigned int val, unsigned int shift) { @@ -216,6 +224,14 @@ static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift) b[0] = cpu_to_be32(val << shift); } +static void regmap_format_32_swap(void *buf, unsigned int val, + unsigned int shift) +{ + __u32 *b = buf; + + b[0] = __swab32(val << shift); +} + static void regmap_format_32_native(void *buf, unsigned int val, unsigned int shift) { @@ -240,6 +256,13 @@ static unsigned int regmap_parse_16_be(const void *buf) return be16_to_cpu(b[0]); } +static unsigned int regmap_parse_16_swap(const void *buf) +{ + const __u16 *b = buf; + + return __swab16(b[0]); +} + static void regmap_parse_16_be_inplace(void *buf) { __be16 *b = buf; @@ -247,6 +270,13 @@ static void regmap_parse_16_be_inplace(void *buf) b[0] = be16_to_cpu(b[0]); } +static void regmap_parse_16_swap_inplace(void *buf) +{ + __u16 *b = buf; + + b[0] = __swab16(b[0]); +} + static unsigned int regmap_parse_16_native(const void *buf) { return *(u16 *)buf; @@ -269,6 +299,13 @@ static unsigned int regmap_parse_32_be(const void *buf) return be32_to_cpu(b[0]); } +static unsigned int regmap_parse_32_swap(const void *buf) +{ + const __u32 *b = buf; + + return __swab32((b[0])); +} + static void regmap_parse_32_be_inplace(void *buf) { __be32 *b = buf; @@ -276,6 +313,13 @@ static void regmap_parse_32_be_inplace(void *buf) b[0] = be32_to_cpu(b[0]); } +static void regmap_parse_32_swap_inplace(void *buf) +{ + __u32 *b = buf; + + b[0] = __swab32(b[0]); +} + static unsigned int regmap_parse_32_native(const void *buf) { return *(u32 *)buf; @@ -585,6 +629,12 @@ struct regmap *regmap_init(struct device *dev, map->format.parse_val = regmap_parse_16_be; map->format.parse_inplace = regmap_parse_16_be_inplace; break; + case REGMAP_ENDIAN_SWAP: + map->format.format_val = regmap_format_16_swap; + map->format.parse_val = regmap_parse_16_swap; + map->format.parse_inplace = + regmap_parse_16_swap_inplace; + break; case REGMAP_ENDIAN_NATIVE: map->format.format_val = regmap_format_16_native; map->format.parse_val = regmap_parse_16_native; @@ -606,6 +656,12 @@ struct regmap *regmap_init(struct device *dev, map->format.parse_val = regmap_parse_32_be; map->format.parse_inplace = regmap_parse_32_be_inplace; break; + case REGMAP_ENDIAN_SWAP: + map->format.format_val = regmap_format_32_swap; + map->format.parse_val = regmap_parse_32_swap; + map->format.parse_inplace = + regmap_parse_32_swap_inplace; + break; case REGMAP_ENDIAN_NATIVE: map->format.format_val = regmap_format_32_native; map->format.parse_val = regmap_parse_32_native; diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 4149f1a..a2e68f3 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -56,6 +56,7 @@ enum regmap_endian { REGMAP_ENDIAN_DEFAULT = 0, REGMAP_ENDIAN_BIG, REGMAP_ENDIAN_LITTLE, + REGMAP_ENDIAN_SWAP, REGMAP_ENDIAN_NATIVE, }; -- 1.8.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/