diff mbox

[RFC,4/7] OMAP: Voltage layer changes to support DVFS.

Message ID 1278065909-32148-5-git-send-email-thara@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Thara Gopinath July 2, 2010, 10:18 a.m. UTC
None
diff mbox

Patch

diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index a2f30a4..1e6712e 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -137,6 +137,8 @@  struct omap_vdd_info{
 	struct omap_volt_domain volt_domain;
 	spinlock_t user_lock;
 	struct plist_head user_list;
+	struct device **dev_list;
+	int dev_count;
 	int volt_data_count;
 	unsigned long nominal_volt;
 	u8 cmdval_reg;
@@ -387,6 +389,10 @@  static void __init omap3_vdd_data_configure(struct omap_vdd_info *vdd)
 	spin_lock_init(&vdd->user_lock);
 	plist_head_init(&vdd->user_list, &vdd->user_lock);
 
+	/* Get the devices associated with this VDD */
+	vdd->dev_list = opp_init_voltage_params(&vdd->volt_domain,
+			&vdd->dev_count);
+
 	if (!strcmp(vdd->volt_domain.name, "mpu")) {
 		if (cpu_is_omap3630()) {
 			vdd->vp_reg.vlimitto_vddmin =
@@ -1073,7 +1079,8 @@  void omap_voltageprocessor_disable(struct omap_volt_domain *volt_domain)
 }
 
 /**
- * omap_voltage_scale : API to scale voltage of a particular voltage domain.
+ * omap_voltage_scale_vdd : API to scale voltage of a particular
+ *			    voltage domain.
  * @volt_domain: pointer to the VDD which is to be scaled.
  * @target_vsel : The target voltage of the voltage domain
  * @current_vsel : the current voltage of the voltage domain.
@@ -1081,7 +1088,7 @@  void omap_voltageprocessor_disable(struct omap_volt_domain *volt_domain)
  * This API should be called by the kernel to do the voltage scaling
  * for a particular voltage domain during dvfs or any other situation.
  */
-int omap_voltage_scale(struct omap_volt_domain *volt_domain,
+int omap_voltage_scale_vdd(struct omap_volt_domain *volt_domain,
 					unsigned long target_volt)
 {
 	struct omap_vdd_info *vdd;
@@ -1290,6 +1297,84 @@  struct omap_volt_domain *omap_volt_domain_get(char *name)
 }
 
 /**
+ * omap_voltage_scale : API to scale the devices associated with a
+ *			voltage domain vdd voltage.
+ * @volt_domain : the voltage domain to be scaled
+ * @volt : the new voltage for the voltage domain
+ *
+ * This API runs through the list of devices associated with the
+ * voltage domain and scales the device rates to those corresponding
+ * to the new voltage of the voltage domain. This API also scales
+ * the voltage domain voltage to the new value. Returns 0 on success
+ * else the error value.
+ */
+int omap_voltage_scale(struct omap_volt_domain *volt_domain,
+		unsigned long volt)
+{
+	unsigned long curr_volt;
+	int is_volt_scaled = 0, i;
+	struct omap_vdd_info *vdd;
+
+	if (!volt_domain || IS_ERR(volt_domain)) {
+		pr_warning("%s: VDD specified does not exist!\n", __func__);
+		return -EINVAL;
+	}
+
+	vdd = container_of(volt_domain, struct omap_vdd_info, volt_domain);
+	curr_volt = get_curr_voltage(volt_domain);
+
+	if (curr_volt == volt) {
+		is_volt_scaled = 1;
+	} else if (curr_volt < volt) {
+		omap_voltage_scale_vdd(volt_domain, volt);
+		is_volt_scaled = 1;
+	}
+
+	for (i = 0; i < vdd->dev_count; i++) {
+		struct device_opp *dev_opp;
+		struct omap_opp *opp;
+		unsigned long freq;
+
+		dev_opp = opp_find_dev_opp(vdd->dev_list[i]);
+		if (IS_ERR(dev_opp)) {
+			dev_err(vdd->dev_list[i], "%s: Unable to find device"
+				"opp table\n", __func__);
+			continue;
+		}
+		if (!dev_opp->set_rate) {
+			dev_err(vdd->dev_list[i], "%s: No set_rate API"
+				"for scaling opp\n", __func__);
+			continue;
+		}
+
+		opp = opp_find_voltage(vdd->dev_list[i], volt);
+		if (IS_ERR(opp)) {
+			dev_err(vdd->dev_list[i], "%s: Unable to find OPP for"
+				"volt%ld\n", __func__, volt);
+			continue;
+		}
+
+		freq = opp_get_freq(opp);
+
+		if (dev_opp->get_rate) {
+			if (freq == dev_opp->get_rate(vdd->dev_list[i])) {
+				dev_err(vdd->dev_list[i], "%s: Already at the"
+					"requested rate %ld\n",
+					__func__, freq);
+				continue;
+			}
+		}
+
+		dev_opp->set_rate(vdd->dev_list[i], freq);
+	}
+
+	if (!is_volt_scaled)
+		omap_voltage_scale_vdd(volt_domain, volt);
+
+	return 0;
+}
+
+/**
  * omap_voltage_init : Volatage init API which does VP and VC init.
  */
 static int __init omap_voltage_init(void)
diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
index bc1e4d3..072ee76 100644
--- a/arch/arm/plat-omap/include/plat/voltage.h
+++ b/arch/arm/plat-omap/include/plat/voltage.h
@@ -120,8 +120,10 @@  unsigned long omap_voltageprocessor_get_curr_volt(
 		struct omap_volt_domain *volt_domain);
 void omap_voltageprocessor_enable(struct omap_volt_domain *volt_domain);
 void omap_voltageprocessor_disable(struct omap_volt_domain *volt_domain);
-int omap_voltage_scale(struct omap_volt_domain *volt_domain,
+int omap_voltage_scale_vdd(struct omap_volt_domain *volt_domain,
 		unsigned long target_volt);
+int omap_voltage_scale(struct omap_volt_domain *volt_domain,
+		unsigned long volt);
 void omap_reset_voltage(struct omap_volt_domain *volt_domain);
 int omap_get_voltage_table(struct omap_volt_domain *volt_domain,
 					struct omap_volt_data **volt_data);