[PATCH 1/1] of_propery_map: compact interface for Device-Tree

From: Gilad Avidov
Date: Thu Oct 30 2014 - 19:00:31 EST


Compact API for populating variables with values
from Device-Tree properties.

Change-Id: Ib0f17d32941605b0c431a1815cfcf5e8b76fb07c
Signed-off-by: Gilad Avidov <gavidov@xxxxxxxxxxxxxx>
---
Documentation/devicetree/of_property_map.txt | 76 ++++++++++++++++++++++
drivers/of/Makefile | 2 +-
drivers/of/of_property_map.c | 88 ++++++++++++++++++++++++++
include/linux/of_property_map.h | 74 ++++++++++++++++++++++
4 files changed, 239 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/of_property_map.txt
create mode 100644 drivers/of/of_property_map.c
create mode 100644 include/linux/of_property_map.h

diff --git a/Documentation/devicetree/of_property_map.txt b/Documentation/devicetree/of_property_map.txt
new file mode 100644
index 0000000..307bf57
--- /dev/null
+++ b/Documentation/devicetree/of_property_map.txt
@@ -0,0 +1,76 @@
+* of_property_map:
+
+of_property_map is a compact API for reading Device-Tree nodes.
+The following snippet demonstrates reading the aliased-ID and four other
+properties of the Device-Tree node defined at the bottom.
+
+Example:
+
+struct of_prop_map map[] = {
+ {"i2c", &dev->id, OF_REQ, OF_ID, -1},
+ {"qcom,clk-freq-out", &dev->clk_freq_out, OF_REQ, OF_U32, 0},
+ {"qcom,clk-freq-in", &dev->clk_freq_in, OF_REQ, OF_U32, 0},
+ {"qcom,disable-dma", &dev->disable_dma, OF_OPT, OF_BOOL, 0},
+ {"qcom,master-id", &dev->mstr_id, OF_SGST, OF_U32, 0},
+ {NULL, NULL, 0, 0, 0},
+};
+
+ret = of_prop_populate(dev, dev->of_node, map);
+
+
+An equivalent code snippet using the traditional of_property_read_XXXX() API.
+Note that the equivalent is longer and more difficult to follow and debug.
+
+Example:
+
+/* optional property */
+dev->disable_dma = of_property_read_bool(node, "qcom,disable-dma");
+
+ret = of_property_read_u32(dev->node, "qcom,clk-freq-out", &dev->clk_freq_out);
+if (ret) {
+ dev_err(dev, "error: missing 'qcom,clk-freq-out' DT property\n");
+ if (!err)
+ err = ret;
+}
+
+ret = of_property_read_u32(dev->node, "qcom,clk-freq-in", &dev->clk_freq_in);
+if (ret) {
+ dev_err(dev, "error: missing 'qcom,clk-freq-in' DT property\n");
+ if (!err)
+ err = ret;
+}
+
+/* suggested property */
+ret = of_property_read_u32(dev->node, "qcom,master-id", &dev->mstr_id);
+if (ret && !err)
+ err = ret;
+
+
+ret = of_alias_get_id(dev->node, "i2c");
+if (ret < 0) {
+ dev_err(dev, "error: missing '"i2c"' DT property\n");
+ if (!err)
+ err = ret;
+} else {
+ dev->id = ret;
+}
+
+
+The Device-Tree node and alias which are read by the above code snippets.
+
+Example:
+
+ aliases {
+ i2c0 = &i2c_0; /* I2C0 controller device */
+ };
+
+ i2c_0: i2c@78b6000 { /* BLSP1 QUP2 */
+ compatible = "qcom,i2c-msm-v2";
+ reg-names = "qup_phys_addr", "bam_phys_addr";
+ reg = <0x78b6000 0x600>,
+ <0x7884000 0x23000>;
+ qcom,clk-freq-out = <100000>;
+ qcom,clk-freq-in = <19200000>;
+ qcom,disable-dma;
+ qcom,master-id = <86>;
+ };
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index ca9209c..c60eeb0 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -1,4 +1,4 @@
-obj-y = base.o device.o platform.o
+obj-y = base.o device.o platform.o of_property_map.o
obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
obj-$(CONFIG_OF_FLATTREE) += fdt.o
obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
diff --git a/drivers/of/of_property_map.c b/drivers/of/of_property_map.c
new file mode 100644
index 0000000..8145f1c
--- /dev/null
+++ b/drivers/of/of_property_map.c
@@ -0,0 +1,88 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/of.h>
+#include <linux/device.h>
+#include <linux/of_property_map.h>
+
+int of_prop_populate(struct device *dev, struct device_node *np,
+ struct of_prop_map *itr)
+{
+ int ret, err = 0;
+
+ for (; itr->propname; ++itr) {
+ switch (itr->type) {
+ case OF_BOOL:
+ *((bool *) itr->var_ptr) =
+ of_property_read_bool(np, itr->propname);
+ ret = 0;
+ break;
+ case OF_U8:
+ ret = of_property_read_u8(np, itr->propname,
+ (u8 *) itr->var_ptr);
+ break;
+ case OF_U16:
+ ret = of_property_read_u16(np, itr->propname,
+ (u16 *) itr->var_ptr);
+ break;
+ case OF_U32:
+ ret = of_property_read_u32(np, itr->propname,
+ (u32 *) itr->var_ptr);
+ break;
+ case OF_U64:
+ ret = of_property_read_u64(np, itr->propname,
+ (u64 *) itr->var_ptr);
+ break;
+ case OF_STR:
+ ret = of_property_read_string(np, itr->propname,
+ itr->var_ptr);
+ break;
+ case OF_ID:
+ ret = of_alias_get_id(np, itr->propname);
+ if (ret >= 0) {
+ *((int *) itr->var_ptr) = ret;
+ ret = 0;
+ }
+ break;
+ default:
+ dev_err(dev, "error: %d is unknown DT property type\n",
+ itr->type);
+ ret = -EINVAL;
+ }
+
+ dev_dbg(dev, "of_property: name:%s val:%d ret:%d\n",
+ itr->propname, *((int *)itr->var_ptr), ret);
+
+ if (ret) {
+ /* on error set value to default */
+ *((long long int *)itr->var_ptr) = itr->default_val;
+
+ if (itr->criticality < OF_OPT) {
+ dev_err(dev,
+ "error: missing '%s' DT property\n",
+ itr->propname);
+
+ /*
+ * Do not stop on errors. Keep running to
+ * dump messages for all missing properties.
+ * On error return the first one found.
+ */
+ if (itr->criticality == OF_REQ && !err)
+ err = ret;
+ }
+ }
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(of_prop_populate);
diff --git a/include/linux/of_property_map.h b/include/linux/of_property_map.h
new file mode 100644
index 0000000..0c61673
--- /dev/null
+++ b/include/linux/of_property_map.h
@@ -0,0 +1,74 @@
+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+/*
+ * Higher level and compact interface for reading Device-Tree nodes. Uses
+ * a direct visual mapping table of the node's property name to the
+ * driver's/module's fields.
+ *
+ * Usage exapmle:
+ * struct of_prop_map map[] = {
+ * {"i2c", &dev->id, OF_REQ, OF_ID, -1},
+ * {"qcom,clk-freq-out", &dev->clk_freq_out, OF_REQ, OF_U32, 0},
+ * {"qcom,clk-freq-in", &dev->clk_freq_in, OF_REQ, OF_U32, 0},
+ * {"qcom,bam-disable", &dev->disable_dma, OF_OPT, OF_BOOL, 0},
+ * {"qcom,master-id", &dev->mstr_id, OF_SGST, OF_U32, 0},
+ * {NULL, NULL, 0, 0, 0},
+ * };
+ *
+ * ret = of_prop_populate(dev, dev->of_node, map);
+ */
+
+#ifndef _OF_PROPERTY_MAP_H
+#define _OF_PROPERTY_MAP_H
+
+enum of_prop_criticality {
+ OF_REQ, /* Required : fail if missing */
+ OF_SGST, /* Suggested: warn if missing */
+ OF_OPT, /* Optional : don't warn if missing */
+};
+
+enum of_prop_type {
+ OF_BOOL, /* of_property_read_bool() */
+ OF_U8, /* of_property_read_u8() */
+ OF_U16, /* of_property_read_u16() */
+ OF_U32, /* of_property_read_u32() */
+ OF_U64, /* of_property_read_u64() */
+ OF_STR, /* of_property_read_string() */
+ OF_ID, /* of_alias_get_id() */
+};
+
+/*
+ * of_prop_map: mapping Device-Tree property name to the dev's variable
+ *
+ * @propname property name in Device-Tree
+ * @var_ptr pointer to the device's variable to store the value in.
+ * @default_val if propname is not found then *var_ptr = default_val
+ */
+struct of_prop_map {
+ const char *propname;
+ void *var_ptr;
+ enum of_prop_criticality criticality;
+ enum of_prop_type type;
+ long long int default_val;
+};
+
+/*
+ * of_prop_populate: read Device-Tree properites and populate the mapped fields
+ *
+ * @node the Device-Tree node corresponding to dev
+ * @itr pointer to a NULL terminated property mapping
+ */
+int of_prop_populate(struct device *dev, struct device_node *node,
+ struct of_prop_map *itr);
+
+#endif /*_OF_PROPERTY_MAP_H*/
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

--
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/