ARM: tegra11: dvfs: Re-arrange CL-DVFS pm callbacks
Alex Frid [Wed, 20 Feb 2013 02:41:16 +0000 (18:41 -0800)]
Moved CL-DVFS closed loop suspend/resume operations from CL-DVFS
device power management callbacks to platform syscore callbacks.
This is done to avoid I2C bus contention between CL-DVFS exit from
closed loop and drivers s/w access to power I2C during suspend and
shutdown entry. Possible remedy for such contention - abort suspend,
and restore CL-DVFS closed loop - would adversely affect suspend
residency time. On the other hand during syscore operations CL-DVFS
h/w is the only one using power I2C bus.

CL-DVFS device suspend callback is still used to force cold zone
voltage limit, regardless of entry temperature to be safe when SoC
is resumed at cold.

This partially reverts commit 37d1df541838c65677d0ae4eb529de9160336a7f,
and commit 965dbfab96b842f50574c8ec092207b465ca0401

Bug 1237641

Change-Id: I4424babe16776fa410a0b0f54f4b7e605a1e25c4
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/202644
(cherry picked from commit 4a49cb2ce0f20f9e63a8aa11e502c753d8873584)
Reviewed-on: http://git-master/r/205789
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>

arch/arm/mach-tegra/pm.c
arch/arm/mach-tegra/tegra_cl_dvfs.c

index 7c52087..8078b57 100644 (file)
@@ -1224,6 +1224,7 @@ static struct kobject *suspend_kobj;
 static int tegra_pm_enter_suspend(void)
 {
        pr_info("Entering suspend state %s\n", lp_state[current_suspend_mode]);
+       suspend_cpu_dfll_mode();
        if (current_suspend_mode == TEGRA_SUSPEND_LP0)
                tegra_lp0_cpu_mode(true);
        return 0;
@@ -1233,12 +1234,20 @@ static void tegra_pm_enter_resume(void)
 {
        if (current_suspend_mode == TEGRA_SUSPEND_LP0)
                tegra_lp0_cpu_mode(false);
+       resume_cpu_dfll_mode();
        pr_info("Exited suspend state %s\n", lp_state[current_suspend_mode]);
 }
 
+static void tegra_pm_enter_shutdown(void)
+{
+       suspend_cpu_dfll_mode();
+       pr_info("Shutting down tegra ...\n");
+}
+
 static struct syscore_ops tegra_pm_enter_syscore_ops = {
        .suspend = tegra_pm_enter_suspend,
        .resume = tegra_pm_enter_resume,
+       .shutdown = tegra_pm_enter_shutdown,
 };
 
 static __init int tegra_pm_enter_syscore_init(void)
index 9d0b559..0694125 100644 (file)
@@ -188,7 +188,6 @@ struct tegra_cl_dvfs {
        u8                              minimax_output;
        unsigned long                   dfll_rate_min;
 
-       bool                            cl_suspended;
        u8                              lut_min;
        u8                              lut_max;
        int                             thermal_idx;
@@ -897,7 +896,7 @@ static int cl_dvfs_init(struct tegra_cl_dvfs *cld)
 /*
  * Re-initialize and enable target device clock in open loop mode. Called
  * directly from SoC clock resume syscore operation. Closed loop will be
- * re-entered in cl_dvfs pm callback tegra_cl_dvfs_resume_cl() below.
+ * re-entered in platform syscore ops as well.
  */
 void tegra_cl_dvfs_resume(struct tegra_cl_dvfs *cld)
 {
@@ -987,59 +986,33 @@ static void tegra_cl_dvfs_init_cdev(struct work_struct *work)
 #ifdef CONFIG_PM_SLEEP
 /*
  * cl_dvfs controls clock/voltage to other devices, including CPU. Therefore,
- * cl_dvfs pm suspend/resume callbacks are limited to exit/entry from/to closed
- * loop mode without actually stopping/resuming output clock to target device.
+ * cl_dvfs driver pm suspend callback does not stop cl-dvfs operations. It is
+ * only used to enforce cold volatge limit, since SoC may cool down during
+ * suspend without waking up. The correct temperature zone after supend will
+ * be updated via cl_dvfs cooling device interface during resume of temperature
+ * sensor.
  */
 static int tegra_cl_dvfs_suspend_cl(struct device *dev)
 {
-       int ret;
        unsigned long flags;
        struct tegra_cl_dvfs *cld = dev_get_drvdata(dev);
 
        clk_lock_save(cld->dfll_clk, &flags);
-       if (cld->mode == TEGRA_CL_DVFS_CLOSED_LOOP)
-               tegra_cl_dvfs_unlock(cld);
-       cld->cl_suspended = true;
+       cld->thermal_idx = 0;
+       if (cld->mode == TEGRA_CL_DVFS_CLOSED_LOOP) {
+               set_cl_config(cld, &cld->last_req);
+               set_request(cld, &cld->last_req);
+       }
        clk_unlock_restore(cld->dfll_clk, &flags);
 
-       /* 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)
-{
-       unsigned long flags;
-       struct tegra_cl_dvfs *cld = dev_get_drvdata(dev);
-
-       clk_lock_save(cld->dfll_clk, &flags);
-       cld->cl_suspended = false;
-       cld->thermal_idx = 0; /* safe, as SoC may cool down during suspend */
-       if (cld->mode == TEGRA_CL_DVFS_OPEN_LOOP)
-               tegra_cl_dvfs_lock(cld);
-       clk_unlock_restore(cld->dfll_clk, &flags);
        return 0;
 }
 
 static const struct dev_pm_ops tegra_cl_dvfs_pm_ops = {
        .suspend = tegra_cl_dvfs_suspend_cl,
-       .resume = tegra_cl_dvfs_resume_cl,
 };
 #endif
 
-/* Make sure cl_dvfs is in open loop mode during shutdown */
-static void tegra_cl_dvfs_shutdown(struct platform_device *pdev)
-{
-       unsigned long flags;
-       struct tegra_cl_dvfs *cld = platform_get_drvdata(pdev);
-
-       clk_lock_save(cld->dfll_clk, &flags);
-       if (cld->mode == TEGRA_CL_DVFS_CLOSED_LOOP)
-               tegra_cl_dvfs_unlock(cld);
-       cld->cl_suspended = true;
-       clk_unlock_restore(cld->dfll_clk, &flags);
-}
-
 static int __init tegra_cl_dvfs_probe(struct platform_device *pdev)
 {
        int ret;
@@ -1130,7 +1103,6 @@ static struct platform_driver tegra_cl_dvfs_driver = {
                .pm = &tegra_cl_dvfs_pm_ops,
 #endif
        },
-       .shutdown = tegra_cl_dvfs_shutdown,
 };
 
 int __init tegra_init_cl_dvfs(void)
@@ -1196,9 +1168,6 @@ int tegra_cl_dvfs_lock(struct tegra_cl_dvfs *cld)
 {
        struct dfll_rate_req *req = &cld->last_req;
 
-       if (cld->cl_suspended)
-               return -EBUSY;
-
        switch (cld->mode) {
        case TEGRA_CL_DVFS_CLOSED_LOOP:
                return 0;