of: spmi: Add support for device naming and lookups

Since we support multiple device_nodes per spmi_device when used
with the spmi-dev-container flag, it's often unclear how a driver
should make reference to a particular device. Therefore,
introduce the spmi specific binding spmi-dev-name that specifies
the device name for the device_node.

Also introduce an API that can be used from
the driver to lookup the specific device node associated with a
particular device name.

Note that it may seem at first glance that the binding 'label' is
redundant with device_node->name. However, per the ePAPR,
device_node->name is intended to be as generic as possible,
representing the function of the device and not the precise
programming model. 'label' is used to give a platform
specific name that can be queried from device drivers.

Change-Id: I28eca35d0b625372c26a6d8ad81e7679f200d14b
Signed-off-by: Michael Bohan <mbohan@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/spmi/msm-spmi.txt b/Documentation/devicetree/bindings/spmi/msm-spmi.txt
index 5539940..9d10f07 100644
--- a/Documentation/devicetree/bindings/spmi/msm-spmi.txt
+++ b/Documentation/devicetree/bindings/spmi/msm-spmi.txt
@@ -91,7 +91,10 @@
    specified above in the 'reg' property.
  - interrupt-names : a list of strings that map in order to the list of
    interrupts specified in the 'interrupts' property.
-
+ - label: A single name that names the device. This name can be looked up
+   with spmi_get_node_byname(). This is mostly useful in spmi-dev-container
+   configurations where multiple device_nodes are associated with one spmi
+   device.
 Notes :
  - It is considered an error to include spmi-slave-dev at this level.
 
@@ -132,6 +135,7 @@
 					qcom,qpnp_gpio = <1>;
 					interrupt-parent = <&qpnp>;
 					interrupts = <0x3 0x15 0x02 0x1 0x47 0x0>;
+					label = "foo-dev";
 				};
 
 				pm8941_gpio2@0xc100 {
diff --git a/drivers/of/of_spmi.c b/drivers/of/of_spmi.c
index ea8f45c..d0ae95a 100644
--- a/drivers/of/of_spmi.c
+++ b/drivers/of/of_spmi.c
@@ -121,6 +121,8 @@
 
 	res = d_info->b_info.dev_node[idx].resource;
 	d_info->b_info.dev_node[idx].of_node = r_info->node;
+	of_property_read_string(r_info->node, "label",
+				&d_info->b_info.dev_node[idx].label);
 
 	if ((num_irq || num_reg) && (res != NULL)) {
 		for (i = 0; i < num_reg; i++, res++) {
diff --git a/drivers/spmi/spmi-resources.c b/drivers/spmi/spmi-resources.c
index 152b69d..390e9ec 100644
--- a/drivers/spmi/spmi-resources.c
+++ b/drivers/spmi/spmi-resources.c
@@ -119,3 +119,30 @@
 	return r ? r->start : -ENXIO;
 }
 EXPORT_SYMBOL_GPL(spmi_get_irq_byname);
+
+/*
+ * spmi_get_devnode_byname - get a device node resource
+ * @dev: spmi device handle
+ * @label: device name to lookup
+ *
+ * Given a name, find the associated spmi_resource that matches the name.
+ * Return NULL if the lookup fails.
+ */
+struct spmi_resource *spmi_get_dev_container_byname(struct spmi_device *dev,
+						    const char *label)
+{
+	int i;
+
+	if (!label)
+		return NULL;
+
+	for (i = 0; i < dev->num_dev_node; i++) {
+		struct spmi_resource *r = &dev->dev_node[i];
+
+		if (r && r->label && !strncmp(r->label,
+					label, SPMI_MAX_RES_NAME))
+			return r;
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(spmi_get_dev_container_byname);
diff --git a/include/linux/spmi.h b/include/linux/spmi.h
index 3ac2a34..299d3de 100644
--- a/include/linux/spmi.h
+++ b/include/linux/spmi.h
@@ -92,11 +92,19 @@
  * @num_resources: number of resources for this device node
  * @resources: array of resources for this device_node
  * @of_node: device_node of the resource in question
+ * @label: name used to reference the device from the driver
+ *
+ * Note that we explicitly add a 'label' pointer here since per
+ * the ePAPR 2.2.2, the device_node->name should be generic and not
+ * reflect precise programming model. Thus label enables a
+ * platform specific name to be assigned with the 'label' binding to
+ * allow for unique query names.
  */
 struct spmi_resource {
 	struct resource		*resource;
 	u32			num_resources;
 	struct device_node	*of_node;
+	const char		*label;
 };
 
 /**
@@ -443,4 +451,7 @@
 
 extern int spmi_get_irq_byname(struct spmi_device *dev,
 			       struct spmi_resource *node, const char *name);
+
+struct spmi_resource *spmi_get_dev_container_byname(struct spmi_device *dev,
+						    const char *label);
 #endif