[PATCHv2 3/3] regmap: add DT endianness binding support.

From: Xiubo Li
Date: Wed Apr 02 2014 - 06:53:47 EST


For many drivers which will support rich endianness of CPU<-->Dev
need define DT properties by itself without the binding support.

The value endianness using regmap-mmio, for example:
Index CPU Device Endianess flag for DT property
------------------------------------------------------------
1 LE LE -
2 LE BE 'big-endian'
3 BE BE -
4 BE LE 'little-endian'

============

Here add DT endianness binding support will define two string
properties of the register and value endiannesses:

'reg-endian' and 'val-endian'.

And the value of them will be:
'LE' : REGMAP_ENDIAN_LITTLE
'BE' : REGMAP_ENDIAN_BIG
'NT' : REGMAP_ENDIAN_NATIVE
Absent : REGMAP_ENDIAN_DEFAULT

The value endianness using regmap-mmio, for example:
Index CPU Device Endianess flag for DT property
------------------------------------------------------------
1 LE LE 'NT' or absent
2 LE BE 'BE'
3 BE BE 'NT' or absent
4 BE LE 'LE'

Please see the following documetation for detail usage:
Documentation/devicetree/bindings/regmap/regmap-endianness.txt

Signed-off-by: Xiubo Li <Li.Xiubo@xxxxxxxxxxxxx>
---
drivers/base/regmap/regmap.c | 91 ++++++++++++++++++++++++++++++++++++++------
1 file changed, 80 insertions(+), 11 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 8e8cea1..36a96cc 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -15,6 +15,7 @@
#include <linux/export.h>
#include <linux/mutex.h>
#include <linux/err.h>
+#include <linux/of.h>
#include <linux/rbtree.h>
#include <linux/sched.h>

@@ -423,6 +424,78 @@ static void regmap_range_exit(struct regmap *map)
}

/**
+ * of_regmap_endian_get_by_name() - Parse and lookup the endianness referenced
+ * by a device node
+ * @np: pointer to clock consumer node
+ * @name: name of consumer's endianness input
+ *
+ * This function parses the device endianness property, and uses them to
+ * determine the endianness of the registers and values.
+ */
+static int of_regmap_endian_get_by_name(struct device_node *np,
+ const char *endian_name,
+ enum regmap_endian *out_endian)
+{
+ const char *endianness;
+ int ret;
+
+ if (!out_endian)
+ return -EINVAL;
+
+ /* Set the default endianness */
+ *out_endian = REGMAP_ENDIAN_DEFAULT;
+
+ /* Absent or being to use the flag from config of the drivers */
+ if (!of_find_property(np, endian_name, NULL))
+ return 0;
+
+ ret = of_property_read_string(np, endian_name, &endianness);
+ if (ret)
+ return ret;
+
+ if (!strcmp("LE", endianness))
+ *out_endian = REGMAP_ENDIAN_LITTLE;
+ else if (!strcmp("BE", endianness))
+ *out_endian = REGMAP_ENDIAN_BIG;
+ else if (!strcmp("NT", endianness))
+ *out_endian = REGMAP_ENDIAN_NATIVE;
+
+ return 0;
+}
+
+static int of_regmap_get_endian(struct device *dev,
+ const struct regmap_bus *bus,
+ const struct regmap_config *config,
+ const char *endian_name,
+ enum regmap_endian *out_endian)
+{
+ int ret;
+
+ if (!out_endian)
+ return -EINVAL;
+
+ if (dev) {
+ ret = of_regmap_endian_get_by_name(dev->of_node, endian_name,
+ out_endian);
+ if (ret)
+ return ret;
+ }
+
+ /* To be compatible with the none DT or the old drivers */
+ if (*out_endian != REGMAP_ENDIAN_DEFAULT)
+ return 0;
+
+ /* Parsing the endianness from driver's config or bus */
+ *out_endian = config->reg_format_endian;
+ if (*out_endian == REGMAP_ENDIAN_DEFAULT)
+ *out_endian = bus->reg_format_endian_default;
+ if (*out_endian == REGMAP_ENDIAN_DEFAULT)
+ *out_endian = REGMAP_ENDIAN_BIG;
+
+ return 0;
+}
+
+/**
* regmap_init(): Initialise register map
*
* @dev: Device that will be interacted with
@@ -518,17 +591,13 @@ struct regmap *regmap_init(struct device *dev,
map->reg_read = _regmap_bus_read;
}

- 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;
+ ret = of_regmap_get_endian(dev, bus, config, "reg_endian", &reg_endian);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = of_regmap_get_endian(dev, bus, config, "val_endian", &val_endian);
+ if (ret)
+ return ERR_PTR(ret);

switch (config->reg_bits + map->reg_shift) {
case 2:
--
1.8.4


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/