aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap2plus-cpufreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/omap2plus-cpufreq.c')
-rw-r--r--arch/arm/mach-omap2/omap2plus-cpufreq.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c
index 7c5a6f9..6c1261c 100644
--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c
+++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c
@@ -27,6 +27,7 @@
#include <linux/io.h>
#include <linux/opp.h>
#include <linux/cpu.h>
+#include <linux/earlysuspend.h>
#include <linux/platform_device.h>
#include <asm/system.h>
@@ -59,8 +60,10 @@ static struct device *mpu_dev;
static DEFINE_MUTEX(omap_cpufreq_lock);
static unsigned int max_thermal;
+static unsigned int max_capped;
static unsigned int max_freq;
static unsigned int current_target_freq;
+static unsigned int screen_off_max_freq;
static bool omap_cpufreq_ready;
static bool omap_cpufreq_suspended;
@@ -91,6 +94,9 @@ static int omap_cpufreq_scale(unsigned int target_freq, unsigned int cur_freq)
if (freqs.new > max_thermal)
freqs.new = max_thermal;
+ if (max_capped && freqs.new > max_capped)
+ freqs.new = max_capped;
+
if ((freqs.old == freqs.new) && (cur_freq = freqs.new))
return 0;
@@ -256,6 +262,46 @@ static int omap_target(struct cpufreq_policy *policy,
return ret;
}
+static void omap_cpu_early_suspend(struct early_suspend *h)
+{
+ unsigned int cur;
+
+ mutex_lock(&omap_cpufreq_lock);
+
+ if (screen_off_max_freq) {
+ max_capped = screen_off_max_freq;
+
+ cur = omap_getspeed(0);
+ if (cur > max_capped)
+ omap_cpufreq_scale(max_capped, cur);
+ }
+
+ mutex_unlock(&omap_cpufreq_lock);
+}
+
+static void omap_cpu_late_resume(struct early_suspend *h)
+{
+ unsigned int cur;
+
+ mutex_lock(&omap_cpufreq_lock);
+
+ if (max_capped) {
+ max_capped = 0;
+
+ cur = omap_getspeed(0);
+ if (cur != current_target_freq)
+ omap_cpufreq_scale(current_target_freq, cur);
+ }
+
+ mutex_unlock(&omap_cpufreq_lock);
+}
+
+static struct early_suspend omap_cpu_early_suspend_handler = {
+ .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN,
+ .suspend = omap_cpu_early_suspend,
+ .resume = omap_cpu_late_resume,
+};
+
static inline void freq_table_free(void)
{
if (atomic_dec_and_test(&freq_table_users))
@@ -332,8 +378,52 @@ static int omap_cpu_exit(struct cpufreq_policy *policy)
return 0;
}
+static ssize_t show_screen_off_freq(struct cpufreq_policy *policy, char *buf)
+{
+ return sprintf(buf, "%u\n", screen_off_max_freq);
+}
+
+static ssize_t store_screen_off_freq(struct cpufreq_policy *policy,
+ const char *buf, size_t count)
+{
+ unsigned int freq = 0;
+ int ret;
+ int index;
+
+ if (!freq_table)
+ return -EINVAL;
+
+ ret = sscanf(buf, "%u", &freq);
+ if (ret != 1)
+ return -EINVAL;
+
+ mutex_lock(&omap_cpufreq_lock);
+
+ ret = cpufreq_frequency_table_target(policy, freq_table, freq,
+ CPUFREQ_RELATION_H, &index);
+ if (ret)
+ goto out;
+
+ screen_off_max_freq = freq_table[index].frequency;
+
+ ret = count;
+
+out:
+ mutex_unlock(&omap_cpufreq_lock);
+ return ret;
+}
+
+struct freq_attr omap_cpufreq_attr_screen_off_freq = {
+ .attr = { .name = "screen_off_max_freq",
+ .mode = 0644,
+ },
+ .show = show_screen_off_freq,
+ .store = store_screen_off_freq,
+};
+
static struct freq_attr *omap_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
+ &omap_cpufreq_attr_screen_off_freq,
NULL,
};
@@ -407,6 +497,8 @@ static int __init omap_cpufreq_init(void)
return -EINVAL;
}
+ register_early_suspend(&omap_cpu_early_suspend_handler);
+
ret = cpufreq_register_driver(&omap_driver);
omap_cpufreq_ready = !ret;
@@ -429,6 +521,8 @@ static int __init omap_cpufreq_init(void)
static void __exit omap_cpufreq_exit(void)
{
cpufreq_unregister_driver(&omap_driver);
+
+ unregister_early_suspend(&omap_cpu_early_suspend_handler);
platform_driver_unregister(&omap_cpufreq_platform_driver);
platform_device_unregister(&omap_cpufreq_device);
}