disable vdd_gpu when early suspend
author陈亮 <cl@rock-chips.com>
Tue, 24 Jun 2014 06:11:32 +0000 (23:11 -0700)
committer陈亮 <cl@rock-chips.com>
Tue, 24 Jun 2014 06:20:56 +0000 (23:20 -0700)
Signed-off-by: 陈亮 <cl@rock-chips.com>
arch/arm/boot/dts/rk3288-p977_8846.dts
arch/arm/boot/dts/rk3288-tb.dts
arch/arm/mach-rockchip/dvfs.c
drivers/cpufreq/rockchip-cpufreq.c

index 26a26576d8c09c019db1dbb0822b51222ba98719..7a7c6b1678ffb2bb895c1a3350fd4e6e21f6de38 100755 (executable)
                        regulator-name = "vdd_gpu";
                        regulator-min-microvolt = <712500>;
                        regulator-max-microvolt = <1500000>;
-                       regulator-always-on;
-                       regulator-boot-on;
+                       //regulator-always-on;
+                       //regulator-boot-on;
                        regulator-initial-mode = <0x2>;
                        regulator-initial-state = <3>;
                        regulator-state-mem {
index 53799123cc604f631bb88da348196687e661ef67..1ff6ae730612dcf5fed358d6e5825d9dcaa77b0e 100755 (executable)
 
                rk808_dcdc2_reg: regulator@1 {
                        regulator-name= "vdd_gpu";
-                       regulator-always-on;
-                       regulator-boot-on;
+                       //regulator-always-on;
+                       //regulator-boot-on;
                };
 
                rk808_dcdc3_reg: regulator@2 {
index eaa3136a156342baed316bee58cbdbbc087a9363..d6c70be7a862c9aecf9d4330ed3950a3d0589ff9 100644 (file)
@@ -21,6 +21,9 @@
 #include <linux/opp.h>
 #include <linux/rockchip/dvfs.h>
 #include <linux/rockchip/common.h>
+#include <linux/fb.h>
+#include <linux/reboot.h>
+#include "../../../drivers/clk/rockchip/clk-pd.h"
 
 extern int rockchip_tsadc_get_temp(int chn);
 
@@ -32,6 +35,108 @@ static struct dvfs_node *clk_cpu_dvfs_node;
 static unsigned int target_temp = 80;
 static int temp_limit_enable = 1;
 
+static int pd_gpu_off, early_suspend;
+static DEFINE_MUTEX(switch_vdd_gpu_mutex);
+struct regulator *vdd_gpu_regulator;
+
+static int vdd_gpu_reboot_notifier_event(struct notifier_block *this,
+       unsigned long event, void *ptr)
+{
+       int ret;
+
+       DVFS_DBG("%s: enable vdd_gpu\n", __func__);
+       mutex_lock(&switch_vdd_gpu_mutex);
+       if (!regulator_is_enabled(vdd_gpu_regulator))
+               ret = regulator_enable(vdd_gpu_regulator);
+       mutex_unlock(&switch_vdd_gpu_mutex);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block vdd_gpu_reboot_notifier = {
+       .notifier_call = vdd_gpu_reboot_notifier_event,
+};
+
+static int clk_pd_gpu_notifier_call(struct notifier_block *nb,
+       unsigned long event, void *ptr)
+{
+       int ret;
+
+       mutex_lock(&switch_vdd_gpu_mutex);
+       switch (event) {
+       case RK_CLK_PD_PREPARE:
+               pd_gpu_off = 0;
+               if (early_suspend) {
+                       if (!regulator_is_enabled(vdd_gpu_regulator))
+                               ret = regulator_enable(vdd_gpu_regulator);
+               }
+               break;
+       case RK_CLK_PD_UNPREPARE:
+               pd_gpu_off = 1;
+               if (early_suspend) {
+                       if (regulator_is_enabled(vdd_gpu_regulator))
+                               ret = regulator_disable(vdd_gpu_regulator);
+               }
+               break;
+       default:
+               break;
+       }
+       mutex_unlock(&switch_vdd_gpu_mutex);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block clk_pd_gpu_notifier = {
+       .notifier_call = clk_pd_gpu_notifier_call,
+};
+
+
+static int early_suspend_notifier_call(struct notifier_block *self,
+                               unsigned long action, void *data)
+{
+       struct fb_event *event = data;
+       int blank_mode = *((int *)event->data);
+       int ret;
+
+       mutex_lock(&switch_vdd_gpu_mutex);
+       if (action == FB_EARLY_EVENT_BLANK) {
+               switch (blank_mode) {
+               case FB_BLANK_UNBLANK:
+                       early_suspend = 0;
+                       if (pd_gpu_off) {
+                               if (!regulator_is_enabled(vdd_gpu_regulator))
+                                       ret = regulator_enable(
+                                       vdd_gpu_regulator);
+                       }
+                       break;
+               default:
+                       break;
+               }
+       } else if (action == FB_EVENT_BLANK) {
+               switch (blank_mode) {
+               case FB_BLANK_POWERDOWN:
+                       early_suspend = 1;
+                       if (pd_gpu_off) {
+                               if (regulator_is_enabled(vdd_gpu_regulator))
+                                       ret = regulator_disable(
+                                       vdd_gpu_regulator);
+                       }
+
+                       break;
+               default:
+                       break;
+               }
+       }
+       mutex_unlock(&switch_vdd_gpu_mutex);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block early_suspend_notifier = {
+               .notifier_call = early_suspend_notifier_call,
+};
+
+
 static void dvfs_volt_up_delay(struct vd_node *vd, int new_volt, int old_volt)
 {
        int u_time;
@@ -1395,6 +1500,17 @@ static int __init dvfs_init(void)
                queue_delayed_work_on(0, dvfs_wq, &dvfs_temp_limit_work, 0*HZ);
        }
 
+       vdd_gpu_regulator = dvfs_get_regulator("vdd_gpu");
+       if (!IS_ERR_OR_NULL(vdd_gpu_regulator)) {
+               struct clk *clk = clk_get(NULL, "pd_gpu");
+
+               if (clk)
+                       rk_clk_pd_notifier_register(clk, &clk_pd_gpu_notifier);
+
+               fb_register_client(&early_suspend_notifier);
+               register_reboot_notifier(&vdd_gpu_reboot_notifier);
+       }
+
        return ret;
 }
 
index b4af52f96c1f5bb3d8cbdf1f96d2b2f96c4fc3ab..559d92c273bd2dd97d4558283fcc4236dc886f3e 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/cpu.h>
 #include <asm/unistd.h>
 #include <asm/uaccess.h>
+#include <asm/system_misc.h>
 #include "../../../drivers/clk/rockchip/clk-pd.h"
 
 extern void dvfs_disable_temp_limit(void);
@@ -174,11 +175,26 @@ static int cpufreq_scale_rate_for_dvfs(struct clk *clk, unsigned long rate)
 static int cpufreq_init_cpu0(struct cpufreq_policy *policy)
 {
        unsigned int i;
+       int ret;
+       struct regulator *vdd_gpu_regulator;
+
        gpu_is_mali400 = cpu_is_rk3188();
 
        clk_gpu_dvfs_node = clk_get_dvfs_node("clk_gpu");
        if (clk_gpu_dvfs_node){
                clk_enable_dvfs(clk_gpu_dvfs_node);
+               vdd_gpu_regulator = dvfs_get_regulator("vdd_gpu");
+               if (!IS_ERR_OR_NULL(vdd_gpu_regulator)) {
+                       if (!regulator_is_enabled(vdd_gpu_regulator)) {
+                               ret = regulator_enable(vdd_gpu_regulator);
+                               arm_pm_restart('h', NULL);
+                       }
+                       /* make sure vdd_gpu_regulator is in use,
+                       so it will not be disable by regulator_init_complete*/
+                       ret = regulator_enable(vdd_gpu_regulator);
+                       if (ret != 0)
+                               arm_pm_restart('h', NULL);
+               }
                if (gpu_is_mali400)
                        dvfs_clk_enable_limit(clk_gpu_dvfs_node, 133000000, 600000000); 
        }