From 3fcad983e7df504ecb1d0db79e3fe2e3abc44850 Mon Sep 17 00:00:00 2001
From: Thara Gopinath <thara@ti.com>
Date: Fri, 29 Oct 2010 20:43:24 +0530
Subject: [PATCH 08/20] OMAP: Introduce API to register a device with a voltagedomain

This patch adds an API in the voltage layer that
can be used  during omap_device_build to register the built
device with the voltage domain. This API is to be typically called
only once per device during the device registeration. This approach
makes it easy during dvfs to scale all the devices associated with
a voltage domain and then scale the voltage domain.

Signed-off-by: Thara Gopinath <thara@ti.com>
---
 arch/arm/mach-omap2/voltage.c             |   50 +++++++++++++++++++++++++++++
 arch/arm/plat-omap/include/plat/voltage.h |    7 +++-
 arch/arm/plat-omap/omap_device.c          |   12 +++++++
 3 files changed, 68 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 76c98c6..7381fa6 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -134,6 +134,11 @@ struct omap_vdd_user_list {
 	u32 volt;
 };
 
+struct omap_vdd_dev_list {
+	struct device *dev;
+	struct list_head node;
+};
+
 /**
  * omap_vdd_info - Per Voltage Domain info
  *
@@ -153,6 +158,7 @@ struct omap_vdd_user_list {
  * @user_list		: the list head maintaining the various users.
  * @scaling_mutex	: the dvfs muutex.
  *			  of this vdd with the voltage requested by each user.
+ * @dev_list		: list of devices bwlonging to this voltage domain.
  * @curr_volt		: current voltage for this vdd.
  * @ocp_mod		: The prm module for accessing the prm irqstatus reg.
  * @prm_irqst_reg	: prm irqstatus register.
@@ -170,6 +176,7 @@ struct omap_vdd_info {
 	spinlock_t user_lock;
 	struct plist_head user_list;
 	struct mutex scaling_mutex;
+	struct list_head dev_list;
 	u32 curr_volt;
 	u16 ocp_mod;
 	u8 prm_irqst_reg;
@@ -1093,6 +1100,8 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
 	plist_head_init(&vdd->user_list, &vdd->user_lock);
 	/* Init the DVFS mutex */
 	mutex_init(&vdd->scaling_mutex);
+	/* Init the device list */
+	INIT_LIST_HEAD(&vdd->dev_list);
 
 	/* VC parameters */
 	vdd->vc_reg.prm_mod = OMAP4430_PRM_DEVICE_INST;
@@ -1269,6 +1278,40 @@ int omap_voltage_add_request(struct voltagedomain *voltdm, struct device *dev,
 	return 0;
 }
 
+int omap_voltage_add_dev(struct voltagedomain *voltdm, struct device *dev)
+{
+	struct omap_vdd_info *vdd;
+	struct omap_vdd_dev_list *temp_dev;
+
+	if (!voltdm || IS_ERR(voltdm)) {
+		pr_warning("%s: VDD specified does not exist!\n", __func__);
+		return -EINVAL;
+	}
+
+	vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
+
+	list_for_each_entry(temp_dev, &vdd->dev_list, node) {
+		if (temp_dev->dev == dev) {
+			dev_warn(dev, "%s: Device already added to vdee_%s\n",
+				__func__, voltdm->name);
+			return -EINVAL;
+		}
+	}
+
+	temp_dev = kzalloc(sizeof(struct omap_vdd_dev_list), GFP_KERNEL);
+	if (!temp_dev) {
+		dev_err(dev, "%s: Unable to creat a new device for vdd_%s\n",
+			__func__, voltdm->name);
+		return -ENOMEM;
+	}
+
+	temp_dev->dev = dev;
+
+	list_add(&temp_dev->node, &vdd->dev_list);
+
+	return 0;
+}
+
 /**
  * omap_vp_enable() - API to enable a particular VP
  * @voltdm:	pointer to the VDD whose VP is to be enabled.
@@ -1649,6 +1692,8 @@ int __init omap_voltage_late_init(void)
  */
 static int __init omap_voltage_early_init(void)
 {
+	int i;
+
 	if (cpu_is_omap34xx()) {
 		vdd_info = omap3_vdd_info;
 		nr_scalable_vdd = OMAP3_NR_SCALABLE_VDD;
@@ -1661,8 +1706,13 @@ static int __init omap_voltage_early_init(void)
 		vdd_data_configure = omap4_vdd_data_configure;
 	} else {
 		pr_warning("%s: voltage driver support not added\n", __func__);
+		return -EINVAL;
 	}
 
+	/* Init the device list */
+	for (i = 0; i < nr_scalable_vdd; i++)
+		INIT_LIST_HEAD(&(vdd_info[i].dev_list));
+
 	return 0;
 }
 core_initcall(omap_voltage_early_init);
diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
index bd07eca..adbc6af 100644
--- a/arch/arm/plat-omap/include/plat/voltage.h
+++ b/arch/arm/plat-omap/include/plat/voltage.h
@@ -134,7 +134,7 @@ void omap_change_voltscale_method(struct voltagedomain *voltdm,
 int omap_voltage_late_init(void);
 int omap_voltage_add_request(struct voltagedomain *voltdm, struct device *dev,
 		unsigned long *volt);
-
+int omap_voltage_add_dev(struct voltagedomain *voltdm, struct device *dev);
 #else
 static inline int omap_voltage_register_pmic(struct voltagedomain *voltdm,
 		struct omap_volt_pmic_info *pmic_info) {}
@@ -149,6 +149,11 @@ static inline int omap_voltage_add_request(struct voltagedomain *voltdm,
 {
 	return -EINVAL;
 }
+static inline int omap_voltage_add_dev(struct voltagedomain *voltdm,
+		struct device *dev)
+{
+	return -EINVAL;
+}
 #endif
 
 #endif
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index 57adb27..2c95e61 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -86,6 +86,7 @@
 
 #include <plat/omap_device.h>
 #include <plat/omap_hwmod.h>
+#include <plat/voltage.h>
 
 /* These parameters are passed to _omap_device_{de,}activate() */
 #define USE_WAKEUP_LAT			0
@@ -481,6 +482,17 @@ struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
 	for (i = 0; i < oh_cnt; i++) {
 		hwmods[i]->od = od;
 		_add_optional_clock_alias(od, hwmods[i]);
+		if (hwmods[i]->vdd_name) {
+			struct omap_hwmod *oh = hwmods[i];
+			struct voltagedomain *voltdm;
+
+			if (is_early_device)
+				continue;
+
+			voltdm = omap_voltage_domain_lookup(oh->vdd_name);
+			if (!omap_voltage_add_dev(voltdm, &od->pdev.dev))
+				oh->voltdm = voltdm;
+		}
 	}
 
 	if (ret)
-- 
1.6.6.1

