spmi: Add spmi_resource for non spmi-dev-container cases

The devnode array is currently being used for non
spmi-dev-container devices as a special case where the number of
devnodes is 1. This obfuscates the code and also removes the
ability to store the dev-container's device resource information,
since in that special case the devnode array is dedicated for the
child devices.

Add a new spmi_resource entry used for typical spmi_devices, and
treat the devnode array as the special case for
spmi-dev-container.

Also add a new API spmi_get_primary_dev_name() to return the name
of the device assigned with the 'label' binding if it exists.

Change-Id: Ibe7b12285e37bb0529024558550a96d71393bc10
Signed-off-by: Michael Bohan <mbohan@codeaurora.org>
diff --git a/drivers/of/of_spmi.c b/drivers/of/of_spmi.c
index d0ae95a..0c23db5 100644
--- a/drivers/of/of_spmi.c
+++ b/drivers/of/of_spmi.c
@@ -43,27 +43,12 @@
 }
 
 /*
- * Allocate dev_node array for spmi_device
- */
-static inline int of_spmi_alloc_device_store(struct of_spmi_dev_info *d_info,
-					     uint32_t num_dev_node)
-{
-	d_info->b_info.num_dev_node = num_dev_node;
-	d_info->b_info.dev_node = kzalloc(sizeof(struct spmi_resource) *
-						num_dev_node, GFP_KERNEL);
-	if (!d_info->b_info.dev_node)
-		return -ENOMEM;
-
-	return 0;
-}
-
-/*
  * Calculate the number of resources to allocate
  *
  * The caller is responsible for initializing the of_spmi_res_info structure.
  */
-static void of_spmi_sum_node_resources(struct of_spmi_res_info *r_info,
-				       bool has_reg)
+static void of_spmi_sum_resources(struct of_spmi_res_info *r_info,
+				  bool has_reg)
 {
 	struct of_irq oirq;
 	uint64_t size;
@@ -92,9 +77,75 @@
 }
 
 /*
- * free spmi_resource for the spmi_device
+ * Allocate dev_node array for spmi_device - used with spmi-dev-container
  */
-static void of_spmi_free_device_resources(struct of_spmi_dev_info *d_info)
+static inline int of_spmi_alloc_devnode_store(struct of_spmi_dev_info *d_info,
+					      uint32_t num_dev_node)
+{
+	d_info->b_info.num_dev_node = num_dev_node;
+	d_info->b_info.dev_node = kzalloc(sizeof(struct spmi_resource) *
+						num_dev_node, GFP_KERNEL);
+	if (!d_info->b_info.dev_node)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/*
+ * Allocate enough memory to handle the resources associated with the
+ * primary node.
+ */
+static int of_spmi_allocate_node_resources(struct of_spmi_dev_info *d_info,
+					   struct of_spmi_res_info *r_info)
+{
+	uint32_t num_irq = r_info->num_irq, num_reg = r_info->num_reg;
+	struct resource *res = NULL;
+
+	if (num_irq || num_reg) {
+		res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
+		if (!res)
+			return -ENOMEM;
+	}
+	d_info->b_info.res.num_resources = num_reg + num_irq;
+	d_info->b_info.res.resource = res;
+
+	return 0;
+}
+
+/*
+ * Allocate enough memory to handle the resources associated with the
+ * spmi-dev-container nodes.
+ */
+static int of_spmi_allocate_devnode_resources(struct of_spmi_dev_info *d_info,
+					      struct of_spmi_res_info *r_info,
+					      uint32_t idx)
+{
+	uint32_t num_irq = r_info->num_irq, num_reg = r_info->num_reg;
+	struct resource *res = NULL;
+
+	if (num_irq || num_reg) {
+		res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
+		if (!res)
+			return -ENOMEM;
+	}
+	d_info->b_info.dev_node[idx].num_resources = num_reg + num_irq;
+	d_info->b_info.dev_node[idx].resource = res;
+
+	return 0;
+}
+
+/*
+ * free node resources - used with primary node
+ */
+static void of_spmi_free_node_resources(struct of_spmi_dev_info *d_info)
+{
+	kfree(d_info->b_info.res.resource);
+}
+
+/*
+ * free devnode resources - used with spmi-dev-container
+ */
+static void of_spmi_free_devnode_resources(struct of_spmi_dev_info *d_info)
 {
 	int i;
 
@@ -104,26 +155,17 @@
 	kfree(d_info->b_info.dev_node);
 }
 
-/*
- * Gather node resources and populate
- */
-static void of_spmi_populate_node_resources(struct of_spmi_dev_info *d_info,
-					    struct of_spmi_res_info *r_info,
-					    int idx)
+static void of_spmi_populate_resources(struct of_spmi_dev_info *d_info,
+				       struct of_spmi_res_info *r_info,
+				       struct resource *res)
 
 {
 	uint32_t num_irq = r_info->num_irq, num_reg = r_info->num_reg;
 	int i;
-	struct resource *res;
 	const  __be32 *addrp;
 	uint64_t size;
 	uint32_t flags;
 
-	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++) {
 			/* Addresses are always 16 bits */
@@ -141,26 +183,36 @@
 }
 
 /*
- * Allocate enough memory to handle the resources associated with the
- * device_node. The number of device nodes included in this allocation
- * depends on whether the spmi-dev-container flag is specified or not.
+ * Gather primary node resources and populate.
  */
-static int of_spmi_allocate_node_resources(struct of_spmi_dev_info *d_info,
-					   struct of_spmi_res_info *r_info,
-					   uint32_t idx)
+static void of_spmi_populate_node_resources(struct of_spmi_dev_info *d_info,
+					    struct of_spmi_res_info *r_info)
+
 {
-	uint32_t num_irq = r_info->num_irq, num_reg = r_info->num_reg;
-	struct resource *res = NULL;
+	struct resource *res;
 
-	if (num_irq || num_reg) {
-		res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
-		if (!res)
-			return -ENOMEM;
-	}
-	d_info->b_info.dev_node[idx].num_resources = num_reg + num_irq;
-	d_info->b_info.dev_node[idx].resource = res;
+	res = d_info->b_info.res.resource;
+	d_info->b_info.res.of_node = r_info->node;
+	of_property_read_string(r_info->node, "label",
+				&d_info->b_info.res.label);
+	of_spmi_populate_resources(d_info, r_info, res);
+}
 
-	return 0;
+/*
+ * Gather node devnode resources and populate - used with spmi-dev-container.
+ */
+static void of_spmi_populate_devnode_resources(struct of_spmi_dev_info *d_info,
+					       struct of_spmi_res_info *r_info,
+					       int idx)
+
+{
+	struct resource *res;
+
+	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);
+	of_spmi_populate_resources(d_info, r_info, res);
 }
 
 /*
@@ -220,10 +272,10 @@
 		num_dev_node++;
 	}
 
-	rc = of_spmi_alloc_device_store(d_info, num_dev_node);
+	rc = of_spmi_alloc_devnode_store(d_info, num_dev_node);
 	if (rc) {
-		dev_err(&ctrl->dev, "%s: unable to allocate"
-				" device resources\n", __func__);
+		dev_err(&ctrl->dev, "%s: unable to allocate devnode resources\n",
+								__func__);
 		return;
 	}
 
@@ -232,23 +284,36 @@
 		if (!of_device_is_available(node))
 			continue;
 		of_spmi_init_resource(&r_info, node);
-		of_spmi_sum_node_resources(&r_info, 1);
-		rc = of_spmi_allocate_node_resources(d_info, &r_info, i);
+		of_spmi_sum_resources(&r_info, true);
+		rc = of_spmi_allocate_devnode_resources(d_info, &r_info, i);
 		if (rc) {
 			dev_err(&ctrl->dev, "%s: unable to allocate"
 					" resources\n", __func__);
-			of_spmi_free_device_resources(d_info);
+			of_spmi_free_devnode_resources(d_info);
 			return;
 		}
-		of_spmi_populate_node_resources(d_info, &r_info, i);
+		of_spmi_populate_devnode_resources(d_info, &r_info, i);
 		i++;
 	}
 
+	of_spmi_init_resource(&r_info, container);
+	of_spmi_sum_resources(&r_info, true);
+
+	rc = of_spmi_allocate_node_resources(d_info, &r_info);
+	if (rc) {
+		dev_err(&ctrl->dev, "%s: unable to allocate resources\n",
+								  __func__);
+		of_spmi_free_node_resources(d_info);
+	}
+
+	of_spmi_populate_node_resources(d_info, &r_info);
+
+
 	rc = of_spmi_create_device(d_info, container);
 	if (rc) {
 		dev_err(&ctrl->dev, "%s: unable to create device for"
 				" node %s\n", __func__, container->full_name);
-		of_spmi_free_device_resources(d_info);
+		of_spmi_free_devnode_resources(d_info);
 		return;
 	}
 }
@@ -259,7 +324,7 @@
  * point all share the same slave_id.
  */
 static void of_spmi_walk_slave_container(struct of_spmi_dev_info *d_info,
-					struct device_node *container)
+					 struct device_node *container)
 {
 	struct spmi_controller *ctrl = d_info->ctrl;
 	struct device_node *node;
@@ -280,24 +345,17 @@
 			continue;
 		}
 
-		rc = of_spmi_alloc_device_store(d_info, 1);
-		if (rc) {
-			dev_err(&ctrl->dev, "%s: unable to allocate"
-					" device resources\n", __func__);
-			goto slave_err;
-		}
-
 		of_spmi_init_resource(&r_info, node);
-		of_spmi_sum_node_resources(&r_info, 1);
+		of_spmi_sum_resources(&r_info, true);
 
-		rc = of_spmi_allocate_node_resources(d_info, &r_info, 0);
+		rc = of_spmi_allocate_node_resources(d_info, &r_info);
 		if (rc) {
 			dev_err(&ctrl->dev, "%s: unable to allocate"
 						" resources\n", __func__);
 			goto slave_err;
 		}
 
-		of_spmi_populate_node_resources(d_info, &r_info, 0);
+		of_spmi_populate_node_resources(d_info, &r_info);
 
 		rc = of_spmi_create_device(d_info, node);
 		if (rc) {
@@ -309,7 +367,7 @@
 	return;
 
 slave_err:
-	of_spmi_free_device_resources(d_info);
+	of_spmi_free_node_resources(d_info);
 }
 
 int of_spmi_register_devices(struct spmi_controller *ctrl)
@@ -374,31 +432,23 @@
 			if (!of_device_is_available(node))
 				continue;
 
-			rc = of_spmi_alloc_device_store(&d_info, 1);
-			if (rc) {
-				dev_err(&ctrl->dev, "%s: unable to allocate"
-					" device resources\n", __func__);
-				continue;
-			}
-
 			of_spmi_init_resource(&r_info, node);
-			of_spmi_sum_node_resources(&r_info, 0);
-			rc = of_spmi_allocate_node_resources(&d_info,
-								&r_info, 0);
+			of_spmi_sum_resources(&r_info, false);
+			rc = of_spmi_allocate_node_resources(&d_info, &r_info);
 			if (rc) {
 				dev_err(&ctrl->dev, "%s: unable to allocate"
 						" resources\n", __func__);
-				of_spmi_free_device_resources(&d_info);
+				of_spmi_free_node_resources(&d_info);
 				continue;
 			}
 
-			of_spmi_populate_node_resources(&d_info, &r_info, 0);
+			of_spmi_populate_node_resources(&d_info, &r_info);
 
 			rc = of_spmi_create_device(&d_info, node);
 			if (rc) {
 				dev_err(&ctrl->dev, "%s: unable to create"
 						" device\n", __func__);
-				of_spmi_free_device_resources(&d_info);
+				of_spmi_free_node_resources(&d_info);
 				continue;
 			}
 		}
@@ -408,4 +458,4 @@
 }
 EXPORT_SYMBOL(of_spmi_register_devices);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spmi/spmi-resources.c b/drivers/spmi/spmi-resources.c
index 390e9ec..97f15ae 100644
--- a/drivers/spmi/spmi-resources.c
+++ b/drivers/spmi/spmi-resources.c
@@ -41,7 +41,7 @@
 
 	/* if a node is not specified, default to the first node */
 	if (!node)
-		node = &dev->dev_node[0];
+		node = &dev->res;
 
 	for (i = 0; i < node->num_resources; i++) {
 		struct resource *r = &node->resource[i];
@@ -71,7 +71,7 @@
 
 	/* if a node is not specified, default to the first node */
 	if (!node)
-		node = &dev->dev_node[0];
+		node = &dev->res;
 
 	for (i = 0; i < node->num_resources; i++) {
 		struct resource *r = &node->resource[i];
@@ -121,12 +121,15 @@
 EXPORT_SYMBOL_GPL(spmi_get_irq_byname);
 
 /*
- * spmi_get_devnode_byname - get a device node resource
+ * spmi_get_container_dev_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.
+ * Only useable in spmi-dev-container configurations. Given a name,
+ * find the associated spmi_resource that matches the name.
+ *
+ * Return NULL if the spmi_device is not a dev-container,
+ * or if the lookup fails.
  */
 struct spmi_resource *spmi_get_dev_container_byname(struct spmi_device *dev,
 						    const char *label)
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 0342b97..914df95 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -238,6 +238,7 @@
 	spmidev->dev.platform_data = (void *)info->platform_data;
 	spmidev->num_dev_node = info->num_dev_node;
 	spmidev->dev_node = info->dev_node;
+	spmidev->res = info->res;
 
 	rc = spmi_add_device(spmidev);
 	if (rc < 0) {
diff --git a/include/linux/spmi.h b/include/linux/spmi.h
index 299d3de..f94b5c5 100644
--- a/include/linux/spmi.h
+++ b/include/linux/spmi.h
@@ -116,7 +116,8 @@
  *  @dev: Driver model representation of the device.
  *  @name: Name of driver to use with this device.
  *  @ctrl: SPMI controller managing the bus hosting this device.
- *  @dev_node: array of SPMI resources - one entry per device_node.
+ *  @res: SPMI resource for the primary node
+ *  @dev_node: array of SPMI resources when used with spmi-dev-container.
  *  @num_dev_node: number of device_node structures.
  *  @sid: Slave Identifier.
  */
@@ -124,6 +125,7 @@
 	struct device		dev;
 	const char		*name;
 	struct spmi_controller	*ctrl;
+	struct spmi_resource	res;
 	struct spmi_resource	*dev_node;
 	u32			num_dev_node;
 	u8			sid;
@@ -132,10 +134,12 @@
 
 /**
  * struct spmi_boardinfo: Declare board info for SPMI device bringup.
+ * @name: Name of driver to use with this device.
  * @slave_id: slave identifier.
  * @spmi_device: device to be registered with the SPMI framework.
  * @of_node: pointer to the OpenFirmware device node.
- * @dev_node: one spmi_resource for each device_node.
+ * @res: SPMI resource for the primary node
+ * @dev_node: array of SPMI resources when used with spmi-dev-container.
  * @num_dev_node: number of device_node structures.
  * @platform_data: goes to spmi_device.dev.platform_data
  */
@@ -143,6 +147,7 @@
 	char			name[SPMI_NAME_SIZE];
 	uint8_t			slave_id;
 	struct device_node	*of_node;
+	struct spmi_resource	res;
 	struct spmi_resource	*dev_node;
 	u32			num_dev_node;
 	const void		*platform_data;
@@ -452,6 +457,22 @@
 extern int spmi_get_irq_byname(struct spmi_device *dev,
 			       struct spmi_resource *node, const char *name);
 
+/**
+ * spmi_get_node_name - return device name for spmi node
+ * @dev: spmi device handle
+ *
+ * Get the primary node name of a spmi_device coresponding with
+ * with the 'label' binding.
+ *
+ * Returns NULL if no primary dev name has been assigned to this spmi_device.
+ */
+static inline const char *spmi_get_primary_dev_name(struct spmi_device *dev)
+{
+	if (dev->res.label)
+		return dev->res.label;
+	return NULL;
+}
+
 struct spmi_resource *spmi_get_dev_container_byname(struct spmi_device *dev,
 						    const char *label);
 #endif