@@ -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)
@@ -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);