aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorSantosh Shilimkar <santosh.shilimkar@ti.com>2010-08-11 20:02:43 -0400
committerKevin Hilman <khilman@ti.com>2011-11-08 14:42:16 -0500
commit731e0cc639364646d36981d90ab0b6af12b8face (patch)
tree62e120641ceabdae531fc928dab43fb93133986a /drivers/cpufreq
parent1ea6b8f48918282bdca0b32a34095504ee65bab5 (diff)
cpufreq: OMAP: cleanup for multi-SoC support, move into drivers/cpufreq
Move OMAP cpufreq driver from arch/arm/mach-omap2 into drivers/cpufreq, along with a few cleanups: - generalize support for better handling of different SoCs in the OMAP - use OPP layer instead of OMAP clock internals for frequency table init Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com> [khilman@ti.com: move to drivers] Signed-off-by: Kevin Hilman <khilman@ti.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/Makefile1
-rw-r--r--drivers/cpufreq/omap-cpufreq.c188
2 files changed, 189 insertions, 0 deletions
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index a48bc02cd765..ce75fcbcca4f 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o
43obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o 43obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o
44obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o 44obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o
45obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o 45obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o
46obj-$(CONFIG_ARCH_OMAP2PLUS) += omap-cpufreq.o
46 47
47################################################################################## 48##################################################################################
48# PowerPC platform drivers 49# PowerPC platform drivers
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
new file mode 100644
index 000000000000..a6b2be7ea5a9
--- /dev/null
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -0,0 +1,188 @@
1/*
2 * CPU frequency scaling for OMAP
3 *
4 * Copyright (C) 2005 Nokia Corporation
5 * Written by Tony Lindgren <tony@atomide.com>
6 *
7 * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
8 *
9 * Copyright (C) 2007-2011 Texas Instruments, Inc.
10 * - OMAP3/4 support by Rajendra Nayak, Santosh Shilimkar
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 */
16#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/sched.h>
19#include <linux/cpufreq.h>
20#include <linux/delay.h>
21#include <linux/init.h>
22#include <linux/err.h>
23#include <linux/clk.h>
24#include <linux/io.h>
25#include <linux/opp.h>
26
27#include <asm/system.h>
28#include <asm/smp_plat.h>
29
30#include <plat/clock.h>
31#include <plat/omap-pm.h>
32#include <plat/common.h>
33
34#include <mach/hardware.h>
35
36#define VERY_HI_RATE 900000000
37
38static struct cpufreq_frequency_table *freq_table;
39static struct clk *mpu_clk;
40
41static int omap_verify_speed(struct cpufreq_policy *policy)
42{
43 if (freq_table)
44 return cpufreq_frequency_table_verify(policy, freq_table);
45
46 if (policy->cpu)
47 return -EINVAL;
48
49 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
50 policy->cpuinfo.max_freq);
51
52 policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000;
53 policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000;
54 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
55 policy->cpuinfo.max_freq);
56 return 0;
57}
58
59static unsigned int omap_getspeed(unsigned int cpu)
60{
61 unsigned long rate;
62
63 if (cpu)
64 return 0;
65
66 rate = clk_get_rate(mpu_clk) / 1000;
67 return rate;
68}
69
70static int omap_target(struct cpufreq_policy *policy,
71 unsigned int target_freq,
72 unsigned int relation)
73{
74 int ret = 0;
75 struct cpufreq_freqs freqs;
76
77 /* Ensure desired rate is within allowed range. Some govenors
78 * (ondemand) will just pass target_freq=0 to get the minimum. */
79 if (target_freq < policy->min)
80 target_freq = policy->min;
81 if (target_freq > policy->max)
82 target_freq = policy->max;
83
84 freqs.old = omap_getspeed(0);
85 freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
86 freqs.cpu = 0;
87
88 if (freqs.old == freqs.new)
89 return ret;
90
91 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
92
93#ifdef CONFIG_CPU_FREQ_DEBUG
94 pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new);
95#endif
96
97 ret = clk_set_rate(mpu_clk, freqs.new * 1000);
98
99 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
100
101 return ret;
102}
103
104static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
105{
106 int result = 0;
107 struct device *mpu_dev;
108
109 if (cpu_is_omap24xx())
110 mpu_clk = clk_get(NULL, "virt_prcm_set");
111 else if (cpu_is_omap34xx())
112 mpu_clk = clk_get(NULL, "dpll1_ck");
113 else if (cpu_is_omap44xx())
114 mpu_clk = clk_get(NULL, "dpll_mpu_ck");
115
116 if (IS_ERR(mpu_clk))
117 return PTR_ERR(mpu_clk);
118
119 if (policy->cpu != 0)
120 return -EINVAL;
121
122 policy->cur = policy->min = policy->max = omap_getspeed(0);
123
124 mpu_dev = omap2_get_mpuss_device();
125 if (!mpu_dev) {
126 pr_warning("%s: unable to get the mpu device\n", __func__);
127 return -EINVAL;
128 }
129 opp_init_cpufreq_table(mpu_dev, &freq_table);
130
131 if (freq_table) {
132 result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
133 if (!result)
134 cpufreq_frequency_table_get_attr(freq_table,
135 policy->cpu);
136 } else {
137 policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
138 policy->cpuinfo.max_freq = clk_round_rate(mpu_clk,
139 VERY_HI_RATE) / 1000;
140 }
141
142 policy->min = policy->cpuinfo.min_freq;
143 policy->max = policy->cpuinfo.max_freq;
144 policy->cur = omap_getspeed(0);
145
146 /* FIXME: what's the actual transition time? */
147 policy->cpuinfo.transition_latency = 300 * 1000;
148
149 return 0;
150}
151
152static int omap_cpu_exit(struct cpufreq_policy *policy)
153{
154 clk_exit_cpufreq_table(&freq_table);
155 clk_put(mpu_clk);
156 return 0;
157}
158
159static struct freq_attr *omap_cpufreq_attr[] = {
160 &cpufreq_freq_attr_scaling_available_freqs,
161 NULL,
162};
163
164static struct cpufreq_driver omap_driver = {
165 .flags = CPUFREQ_STICKY,
166 .verify = omap_verify_speed,
167 .target = omap_target,
168 .get = omap_getspeed,
169 .init = omap_cpu_init,
170 .exit = omap_cpu_exit,
171 .name = "omap",
172 .attr = omap_cpufreq_attr,
173};
174
175static int __init omap_cpufreq_init(void)
176{
177 return cpufreq_register_driver(&omap_driver);
178}
179
180static void __exit omap_cpufreq_exit(void)
181{
182 cpufreq_unregister_driver(&omap_driver);
183}
184
185MODULE_DESCRIPTION("cpufreq driver for OMAP SoCs");
186MODULE_LICENSE("GPL");
187module_init(omap_cpufreq_init);
188module_exit(omap_cpufreq_exit);