ARM: tegra11: power: Set safe cold voltage in DFLL mode
Alex Frid [Thu, 31 Jan 2013 22:52:01 +0000 (14:52 -0800)]
Used regulator API to set CPU voltage at cold temperature minimum
limit if DFLL is selected as fast G CPU clock source, and

- CPU is switching to LP cluster
- on entry to system suspend

This is done since in both cases: suspend and LP cluster operations,
CPU rail is off while temperature may go down, and on exit from each
state CPU will be running on DFLL clock for some time before CL-DVFS
regulation starts.

Change-Id: I02e06a2e92f348a147693ad2b811d7bedb4e70e2
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/196289
(cherry picked from commit fea89035708cc9f21f995194cb1586672e9c0e05)
Reviewed-on: http://git-master/r/199167
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

arch/arm/mach-tegra/dvfs.c
arch/arm/mach-tegra/dvfs.h
arch/arm/mach-tegra/tegra11_clocks.c
arch/arm/mach-tegra/tegra_cl_dvfs.c

index 6f101a1..9fe9f57 100644 (file)
@@ -172,6 +172,22 @@ void tegra_dvfs_rail_pause(struct dvfs_rail *rail, ktime_t delta, bool on)
                dvfs_rail_stats_pause(rail, delta, on);
 }
 
+static int dvfs_rail_set_voltage_reg(struct dvfs_rail *rail, int millivolts)
+{
+       int ret;
+
+       rail->updating = true;
+       rail->reg_max_millivolts = rail->reg_max_millivolts ==
+               rail->max_millivolts ?
+               rail->max_millivolts + 1 : rail->max_millivolts;
+       ret = regulator_set_voltage(rail->reg,
+               millivolts * 1000,
+               rail->reg_max_millivolts * 1000);
+       rail->updating = false;
+
+       return ret;
+}
+
 /* Sets the voltage on a dvfs rail to a specific value, and updates any
  * rails that depend on this rail. */
 static int dvfs_rail_set_voltage(struct dvfs_rail *rail, int millivolts)
@@ -230,16 +246,7 @@ static int dvfs_rail_set_voltage(struct dvfs_rail *rail, int millivolts)
                                goto out;
                }
 
-               if (!rail->disabled) {
-                       rail->updating = true;
-                       rail->reg_max_millivolts = rail->reg_max_millivolts ==
-                               rail->max_millivolts ?
-                               rail->max_millivolts + 1 : rail->max_millivolts;
-                       ret = regulator_set_voltage(rail->reg,
-                               rail->new_millivolts * 1000,
-                               rail->reg_max_millivolts * 1000);
-                       rail->updating = false;
-               }
+               ret = dvfs_rail_set_voltage_reg(rail, rail->new_millivolts);
                if (ret) {
                        pr_err("Failed to set dvfs regulator %s\n", rail->reg_id);
                        goto out;
@@ -888,6 +895,24 @@ static void tegra_dvfs_rail_register_pll_mode_cdev(struct dvfs_rail *rail)
 #define tegra_dvfs_rail_register_pll_mode_cdev(rail)
 #endif
 
+/* Directly set cold temperature limit in dfll mode */
+int tegra_dvfs_rail_dfll_mode_set_cold(struct dvfs_rail *rail)
+{
+       int ret = 0;
+
+#ifdef CONFIG_THERMAL
+       if (!rail || !rail->dfll_mode_cdev || !rail->min_millivolts_cold)
+               return ret;
+
+       mutex_lock(&dvfs_lock);
+       if (rail->dfll_mode)
+               ret = dvfs_rail_set_voltage_reg(
+                       rail, rail->min_millivolts_cold);
+       mutex_unlock(&dvfs_lock);
+#endif
+       return ret;
+}
+
 /*
  * Iterate through all the dvfs regulators, finding the regulator exported
  * by the regulator api for each one.  Must be called in late init, after
index e060249..a4d82ca 100644 (file)
@@ -214,6 +214,7 @@ int tegra_dvfs_dfll_mode_clear(struct dvfs *d, unsigned long rate);
 struct tegra_cooling_device *tegra_dvfs_get_cpu_dfll_cdev(void);
 struct tegra_cooling_device *tegra_dvfs_get_cpu_pll_cdev(void);
 struct tegra_cooling_device *tegra_dvfs_get_core_cdev(void);
+int tegra_dvfs_rail_dfll_mode_set_cold(struct dvfs_rail *rail);
 
 #ifndef CONFIG_ARCH_TEGRA_2x_SOC
 int tegra_dvfs_rail_disable_prepare(struct dvfs_rail *rail);
index 4d64d51..868db81 100644 (file)
@@ -1403,6 +1403,10 @@ static int tegra11_cpu_cmplx_clk_set_parent(struct clk *c, struct clk *p)
                if (ret)
                        goto abort;
 
+               ret = tegra_dvfs_rail_dfll_mode_set_cold(tegra_cpu_rail);
+               if (ret)
+                       goto abort;
+
                p_source = rate <= p->u.cpu.backup_rate ?
                        p->u.cpu.backup : p->u.cpu.main;
                ret = clk_set_rate(p_source, rate);
index 7a69f8d..69e1158 100644 (file)
@@ -909,6 +909,7 @@ static void tegra_cl_dvfs_init_cdev(struct work_struct *work)
  */
 static int tegra_cl_dvfs_suspend_cl(struct device *dev)
 {
+       int ret;
        unsigned long flags;
        struct tegra_cl_dvfs *cld = dev_get_drvdata(dev);
 
@@ -917,7 +918,10 @@ static int tegra_cl_dvfs_suspend_cl(struct device *dev)
                tegra_cl_dvfs_unlock(cld);
        cld->cl_suspended = true;
        clk_unlock_restore(cld->dfll_clk, &flags);
-       return 0;
+
+       /* Enforce safe cold limit via direct regulator api */
+       ret = tegra_dvfs_rail_dfll_mode_set_cold(cld->safe_dvfs->dvfs_rail);
+       return ret;
 }
 
 static int tegra_cl_dvfs_resume_cl(struct device *dev)