diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap2plus-cpufreq.c')
-rw-r--r-- | arch/arm/mach-omap2/omap2plus-cpufreq.c | 94 |
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); } |