diff options
Diffstat (limited to 'arch/arm/mach-msm/cpufreq.c')
-rw-r--r-- | arch/arm/mach-msm/cpufreq.c | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c new file mode 100644 index 000000000000..8c20add08267 --- /dev/null +++ b/arch/arm/mach-msm/cpufreq.c @@ -0,0 +1,126 @@ +/* arch/arm/mach-msm/cpufreq.c + * + * MSM architecture cpufreq driver + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. + * Author: Mike A. Chan <mikechan@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/init.h> +#include <linux/cpufreq.h> +#include "acpuclock.h" + +#define dprintk(msg...) \ + cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "cpufreq-msm", msg) + +#ifdef CONFIG_MSM_CPU_FREQ_SCREEN +static void msm_early_suspend(struct early_suspend *handler) +{ + acpuclk_set_rate(CONFIG_MSM_CPU_FREQ_SCREEN_OFF * 1000, SETRATE_CPUFREQ); +} + +static void msm_late_resume(struct early_suspend *handler) +{ + acpuclk_set_rate(CONFIG_MSM_CPU_FREQ_SCREEN_ON * 1000, SETRATE_CPUFREQ); +} + +static struct early_suspend msm_power_suspend = { + .suspend = msm_early_suspend, + .resume = msm_late_resume, +}; + +static int __init clock_late_init(void) +{ + register_early_suspend(&msm_power_suspend); + return 0; +} + +late_initcall(clock_late_init); +#elif defined(CONFIG_CPU_FREQ_MSM) + +static int msm_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + int index; + int ret = 0; + struct cpufreq_freqs freqs; + struct cpufreq_frequency_table *table = + cpufreq_frequency_get_table(smp_processor_id()); + + if (cpufreq_frequency_table_target(policy, table, target_freq, relation, + &index)) { + pr_err("cpufreq: invalid target_freq: %d\n", target_freq); + return -EINVAL; + } + +#ifdef CONFIG_CPU_FREQ_DEBUG + dprintk("target %d r %d (%d-%d) selected %d\n", target_freq, + relation, policy->min, policy->max, table[index].frequency); +#endif + freqs.old = policy->cur; + freqs.new = table[index].frequency; + freqs.cpu = smp_processor_id(); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + ret = acpuclk_set_rate(table[index].frequency * 1000, SETRATE_CPUFREQ); + if (!ret) + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + return ret; +} + +static int msm_cpufreq_verify(struct cpufreq_policy *policy) +{ + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + return 0; +} + +static int __init msm_cpufreq_init(struct cpufreq_policy *policy) +{ + struct cpufreq_frequency_table *table = + cpufreq_frequency_get_table(smp_processor_id()); + + policy->cur = acpuclk_get_rate(); + if (cpufreq_frequency_table_cpuinfo(policy, table)) { +#ifdef CONFIG_MSM_CPU_FREQ_SET_MIN_MAX + policy->cpuinfo.min_freq = CONFIG_MSM_CPU_FREQ_MIN; + policy->cpuinfo.max_freq = CONFIG_MSM_CPU_FREQ_MAX; +#endif + } +#ifdef CONFIG_MSM_CPU_FREQ_SET_MIN_MAX + policy->min = CONFIG_MSM_CPU_FREQ_MIN; + policy->max = CONFIG_MSM_CPU_FREQ_MAX; +#endif + + policy->cpuinfo.transition_latency = + acpuclk_get_switch_time() * NSEC_PER_USEC; + return 0; +} + +static struct cpufreq_driver msm_cpufreq_driver = { + /* lps calculations are handled here. */ + .flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS, + .init = msm_cpufreq_init, + .verify = msm_cpufreq_verify, + .target = msm_cpufreq_target, + .name = "msm", +}; + +static int __init msm_cpufreq_register(void) +{ + return cpufreq_register_driver(&msm_cpufreq_driver); +} + +late_initcall(msm_cpufreq_register); +#endif |