ARM: tegra11: clock: Skip lowering voltage on EMC backup
Alex Frid [Sun, 9 Dec 2012 02:42:41 +0000 (18:42 -0800)]
If EMC backup rate is below current rate, skip lowering voltage when
switching to backup clock source, Final voltage will be set correctly
after main clock source is re-locked, and EMC clock is switched to
main source.

Bug 1188643

Change-Id: I82a4a85449dbd589c7692f6640e1bd5e08e0bc9b
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/170604
Reviewed-by: Mrutyunjay Sawant <msawant@nvidia.com>
Tested-by: Mrutyunjay Sawant <msawant@nvidia.com>

arch/arm/mach-tegra/tegra11_clocks.c

index 871a9eb..5b9e3bc 100644 (file)
@@ -4189,7 +4189,7 @@ static int tegra11_emc_clk_set_rate(struct clk *c, unsigned long rate)
 static int tegra11_clk_emc_bus_update(struct clk *bus)
 {
        struct clk *p = NULL;
-       unsigned long rate, parent_rate, backup_rate;
+       unsigned long rate, old_rate, parent_rate, backup_rate;
 
        if (detach_shared_bus)
                return 0;
@@ -4197,25 +4197,36 @@ static int tegra11_clk_emc_bus_update(struct clk *bus)
        rate = tegra11_clk_shared_bus_update(bus, NULL, NULL);
        rate = clk_round_rate_locked(bus, rate);
 
-       if (rate == clk_get_rate_locked(bus))
+       old_rate = clk_get_rate_locked(bus);
+       if (rate == old_rate)
                return 0;
 
        if (!tegra_emc_is_parent_ready(rate, &p, &parent_rate, &backup_rate)) {
                if (bus->parent == p) {
                        /* need backup to re-lock current parent */
-                       if (IS_ERR_VALUE(backup_rate) ||
-                           clk_set_rate_locked(bus, backup_rate)) {
-                               pr_err("%s: Failed to backup %s for rate %lu\n",
+                       int ret;
+                       if (IS_ERR_VALUE(backup_rate)) {
+                               pr_err("%s: No backup for %s rate %lu\n",
                                       __func__, bus->name, rate);
                                return -EINVAL;
                        }
 
-                       if (p->refcnt) {
-                               pr_err("%s: %s has other than emc child\n",
-                                      __func__, p->name);
+                       if (backup_rate < old_rate) /* skip lowering voltage */
+                               bus->auto_dvfs = false;
+                       ret = clk_set_rate_locked(bus, backup_rate);
+                       bus->auto_dvfs = true;
+                       if (ret) {
+                               pr_err("%s: Failed to backup %s for rate %lu\n",
+                                      __func__, bus->name, rate);
                                return -EINVAL;
                        }
                }
+               if (p->refcnt) {
+                       pr_err("%s: %s has other than emc child\n",
+                              __func__, p->name);
+                       return -EINVAL;
+               }
+
                if (clk_set_rate(p, parent_rate)) {
                        pr_err("%s: Failed to set %s rate %lu\n",
                               __func__, p->name, parent_rate);