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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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-doc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux