summaryrefslogtreecommitdiff
path: root/arch/arm/mach-omap2/dvfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/dvfs.c')
-rw-r--r--arch/arm/mach-omap2/dvfs.c81
1 files changed, 72 insertions, 9 deletions
diff --git a/arch/arm/mach-omap2/dvfs.c b/arch/arm/mach-omap2/dvfs.c
index d5d3e2a8fa3..44642507eb4 100644
--- a/arch/arm/mach-omap2/dvfs.c
+++ b/arch/arm/mach-omap2/dvfs.c
@@ -66,15 +66,17 @@
* needs to be scaled to. This API then internally finds out the voltage
* domain to which the device belongs to and the voltage to which the voltage
* domain needs to be put to for the device to be scaled to the new frequency
- * from he device opp table. Then this API will add requested frequency into
+ * from the device opp table. Then this API will add requested frequency into
* the corresponding target device frequency list and add voltage request to
* the corresponding vdd. Subsequently it calls voltage scale function which
* will find out the highest requested voltage for the given vdd and scales
- * the voltage to the required one. It also runs through the list of all
+ * the voltage to the required one and also adds corresponding frequency
+ * request for that voltage. It also runs through the list of all
* scalable devices belonging to this voltage domain and scale them to the
* appropriate frequencies using the set_rate pointer in the device opp
* tables.
- * 6. Handle inter VDD dependecies.
+ * 6. Handle inter VDD dependecies. This will take care of scaling domain's voltage
+ * and frequency together.
*
*
* DOC: The Core DVFS data structure:
@@ -534,8 +536,11 @@ static int _dep_scan_table(struct device *dev,
struct omap_vdd_dep_info *dep_info, unsigned long main_volt)
{
struct omap_vdd_dep_volt *dep_table = dep_info->dep_table;
- int i;
- unsigned long dep_volt = 0;
+ struct device *target_dev;
+ struct omap_vdd_dvfs_info *tdvfs_info;
+ struct opp *opp;
+ int i, ret;
+ unsigned long dep_volt = 0, new_freq = 0;
if (!dep_table) {
dev_err(dev, "%s: deptable not present for vdd%s\n",
@@ -567,12 +572,43 @@ static int _dep_scan_table(struct device *dev,
}
/* See if dep_volt is possible for the vdd*/
- i = _add_vdd_user(_voltdm_to_dvfs_info(dep_info->_dep_voltdm),
+ ret = _add_vdd_user(_voltdm_to_dvfs_info(dep_info->_dep_voltdm),
dev, dep_volt);
- if (i)
+ if (ret)
dev_err(dev, "%s: Failed to add dep to domain %s volt=%ld\n",
__func__, dep_info->name, dep_volt);
- return i;
+
+ /* And also add corresponding freq request */
+ tdvfs_info = _voltdm_to_dvfs_info(dep_info->_dep_voltdm);
+ if (!tdvfs_info) {
+ dev_warn(dev, "%s: no dvfs_info\n",
+ __func__);
+ return -ENODEV;
+ }
+ target_dev = _dvfs_info_to_dev(tdvfs_info);
+ if (!target_dev) {
+ dev_warn(dev, "%s: no target_dev\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ rcu_read_lock();
+ opp = _volt_to_opp(target_dev, dep_volt);
+ if (!IS_ERR(opp))
+ new_freq = opp_get_freq(opp);
+ rcu_read_unlock();
+
+ if (new_freq) {
+ ret = _add_freq_request(tdvfs_info, dev, target_dev, new_freq);
+ if (ret) {
+ dev_err(target_dev, "%s: freqadd(%s) failed %d[f=%ld,"
+ "v=%ld]\n", __func__, dev_name(dev),
+ i, new_freq, dep_volt);
+ return ret;
+ }
+ }
+
+ return ret;
}
/**
@@ -832,10 +868,11 @@ int omap_device_scale(struct device *req_dev, struct device *target_dev,
unsigned long rate)
{
struct opp *opp;
- unsigned long volt, freq = rate;
+ unsigned long volt, freq = rate, new_freq = 0;
struct omap_vdd_dvfs_info *tdvfs_info;
struct platform_device *p_dev;
struct omap_device *od;
+ struct device *dev;
int ret = 0;
p_dev = container_of(target_dev, struct platform_device, dev);
@@ -906,6 +943,32 @@ int omap_device_scale(struct device *req_dev, struct device *target_dev,
goto out;
}
+ dev = _dvfs_info_to_dev(tdvfs_info);
+ if (!dev) {
+ dev_warn(dev, "%s: no target_dev\n",
+ __func__);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (dev != target_dev) {
+ rcu_read_lock();
+ opp = _volt_to_opp(dev, volt);
+ if (!IS_ERR(opp))
+ new_freq = opp_get_freq(opp);
+ rcu_read_unlock();
+ if (new_freq) {
+ ret = _add_freq_request(tdvfs_info, req_dev, dev,
+ new_freq);
+ if (ret) {
+ dev_err(target_dev, "%s: freqadd(%s) failed %d"
+ "[f=%ld, v=%ld]\n", __func__,
+ dev_name(req_dev), ret, freq, volt);
+ goto out;
+ }
+ }
+ }
+
/* Do the actual scaling */
ret = _dvfs_scale(req_dev, target_dev, tdvfs_info);
if (ret) {