[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1396250797-17758-3-git-send-email-Li.Xiubo@freescale.com>
Date: Mon, 31 Mar 2014 15:26:37 +0800
From: Xiubo Li <Li.Xiubo@...escale.com>
To: <broonie@...nel.org>
CC: <gregkh@...uxfoundation.org>, <linux-doc@...r.kernel.org>,
<linux-kernel@...r.kernel.org>, Xiubo Li <Li.Xiubo@...escale.com>
Subject: [PATCH 2/2] regmap: add DT endianness binding support.
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 'little-endian'
3 BE BE -
4 BE LE 'big-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 'LE'
3 BE BE 'NT' or absent
4 BE LE 'BE'
Please see the following documetation for detail usage:
Documentation/devicetree/bindings/regmap/regmap-endianness.txt
Signed-off-by: Xiubo Li <Li.Xiubo@...escale.com>
---
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", ®_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@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists