summaryrefslogtreecommitdiff
path: root/arch/arm/mach-msm/cpufreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-msm/cpufreq.c')
-rw-r--r--arch/arm/mach-msm/cpufreq.c126
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