summaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2012-05-24 10:47:26 -0600
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-06-03 13:11:43 +0100
commit141eba2e006dd8145bed2e49fae3de5af65ab9b0 (patch)
treed8891499689971466ac978719c45c33d408fd5c5 /drivers/base
parentf8f5701bdaf9134b1f90e5044a82c66324d2073f (diff)
regmap: allow busses to request formatting with specific endianness
Add a field to struct regmap_bus that allows bus drivers to request that register addresses and values be formatted with a specific endianness. The default endianness is unchanged from current operation: Big. Implement native endian formatting/parsing for 16- and 32-bit values. This will be enough to support regmap-mmio.c. Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/regmap/regmap.c101
1 files changed, 90 insertions, 11 deletions
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 0bcda488f11..1cf721421be 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -119,13 +119,19 @@ static void regmap_format_8(void *buf, unsigned int val, unsigned int shift)
b[0] = val << shift;
}
-static void regmap_format_16(void *buf, unsigned int val, unsigned int shift)
+static void regmap_format_16_be(void *buf, unsigned int val, unsigned int shift)
{
__be16 *b = buf;
b[0] = cpu_to_be16(val << shift);
}
+static void regmap_format_16_native(void *buf, unsigned int val,
+ unsigned int shift)
+{
+ *(u16 *)buf = val << shift;
+}
+
static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
{
u8 *b = buf;
@@ -137,13 +143,19 @@ static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
b[2] = val;
}
-static void regmap_format_32(void *buf, unsigned int val, unsigned int shift)
+static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift)
{
__be32 *b = buf;
b[0] = cpu_to_be32(val << shift);
}
+static void regmap_format_32_native(void *buf, unsigned int val,
+ unsigned int shift)
+{
+ *(u32 *)buf = val << shift;
+}
+
static unsigned int regmap_parse_8(void *buf)
{
u8 *b = buf;
@@ -151,7 +163,7 @@ static unsigned int regmap_parse_8(void *buf)
return b[0];
}
-static unsigned int regmap_parse_16(void *buf)
+static unsigned int regmap_parse_16_be(void *buf)
{
__be16 *b = buf;
@@ -160,6 +172,11 @@ static unsigned int regmap_parse_16(void *buf)
return b[0];
}
+static unsigned int regmap_parse_16_native(void *buf)
+{
+ return *(u16 *)buf;
+}
+
static unsigned int regmap_parse_24(void *buf)
{
u8 *b = buf;
@@ -170,7 +187,7 @@ static unsigned int regmap_parse_24(void *buf)
return ret;
}
-static unsigned int regmap_parse_32(void *buf)
+static unsigned int regmap_parse_32_be(void *buf)
{
__be32 *b = buf;
@@ -179,6 +196,11 @@ static unsigned int regmap_parse_32(void *buf)
return b[0];
}
+static unsigned int regmap_parse_32_native(void *buf)
+{
+ return *(u32 *)buf;
+}
+
static void regmap_lock_mutex(struct regmap *map)
{
mutex_lock(&map->mutex);
@@ -227,6 +249,7 @@ struct regmap *regmap_init(struct device *dev,
{
struct regmap *map, **m;
int ret = -EINVAL;
+ enum regmap_endian reg_endian, val_endian;
if (!bus || !config)
goto err;
@@ -275,6 +298,18 @@ struct regmap *regmap_init(struct device *dev,
map->read_flag_mask = bus->read_flag_mask;
}
+ reg_endian = config->reg_format_endian;
+ if (reg_endian == REGMAP_ENDIAN_DEFAULT)
+ reg_endian = bus->reg_format_endian_default;
+ if (reg_endian == REGMAP_ENDIAN_DEFAULT)
+ reg_endian = REGMAP_ENDIAN_BIG;
+
+ val_endian = config->val_format_endian;
+ if (val_endian == REGMAP_ENDIAN_DEFAULT)
+ val_endian = bus->val_format_endian_default;
+ if (val_endian == REGMAP_ENDIAN_DEFAULT)
+ val_endian = REGMAP_ENDIAN_BIG;
+
switch (config->reg_bits + map->reg_shift) {
case 2:
switch (config->val_bits) {
@@ -321,11 +356,29 @@ struct regmap *regmap_init(struct device *dev,
break;
case 16:
- map->format.format_reg = regmap_format_16;
+ switch (reg_endian) {
+ case REGMAP_ENDIAN_BIG:
+ map->format.format_reg = regmap_format_16_be;
+ break;
+ case REGMAP_ENDIAN_NATIVE:
+ map->format.format_reg = regmap_format_16_native;
+ break;
+ default:
+ goto err_map;
+ }
break;
case 32:
- map->format.format_reg = regmap_format_32;
+ switch (reg_endian) {
+ case REGMAP_ENDIAN_BIG:
+ map->format.format_reg = regmap_format_32_be;
+ break;
+ case REGMAP_ENDIAN_NATIVE:
+ map->format.format_reg = regmap_format_32_native;
+ break;
+ default:
+ goto err_map;
+ }
break;
default:
@@ -338,21 +391,47 @@ struct regmap *regmap_init(struct device *dev,
map->format.parse_val = regmap_parse_8;
break;
case 16:
- map->format.format_val = regmap_format_16;
- map->format.parse_val = regmap_parse_16;
+ switch (val_endian) {
+ case REGMAP_ENDIAN_BIG:
+ map->format.format_val = regmap_format_16_be;
+ map->format.parse_val = regmap_parse_16_be;
+ break;
+ case REGMAP_ENDIAN_NATIVE:
+ map->format.format_val = regmap_format_16_native;
+ map->format.parse_val = regmap_parse_16_native;
+ break;
+ default:
+ goto err_map;
+ }
break;
case 24:
+ if (val_endian != REGMAP_ENDIAN_BIG)
+ goto err_map;
map->format.format_val = regmap_format_24;
map->format.parse_val = regmap_parse_24;
break;
case 32:
- map->format.format_val = regmap_format_32;
- map->format.parse_val = regmap_parse_32;
+ switch (val_endian) {
+ case REGMAP_ENDIAN_BIG:
+ map->format.format_val = regmap_format_32_be;
+ map->format.parse_val = regmap_parse_32_be;
+ break;
+ case REGMAP_ENDIAN_NATIVE:
+ map->format.format_val = regmap_format_32_native;
+ map->format.parse_val = regmap_parse_32_native;
+ break;
+ default:
+ goto err_map;
+ }
break;
}
- if (map->format.format_write)
+ if (map->format.format_write) {
+ if ((reg_endian != REGMAP_ENDIAN_BIG) ||
+ (val_endian != REGMAP_ENDIAN_BIG))
+ goto err_map;
map->use_single_rw = true;
+ }
if (!map->format.format_write &&
!(map->format.format_reg && map->format.format_val))