aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2013-04-04 08:54:22 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-04-10 07:19:25 -0400
commit7258267e56325d41f468eb650b6c23f697201645 (patch)
tree6fc0d8924cd897ff1c51c989d3479e5a38bacfc5 /drivers
parent7a9989356b23fa2c7731632d3b575c53c1ac8bce (diff)
cpufreq: sh: move cpufreq driver to drivers/cpufreq
This patch moves cpufreq driver of SUPERH architecture to drivers/cpufreq. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Acked-by: Paul Mundt <lethal@linux-sh.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/cpufreq/Kconfig18
-rw-r--r--drivers/cpufreq/Makefile1
-rw-r--r--drivers/cpufreq/sh-cpufreq.c189
3 files changed, 208 insertions, 0 deletions
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 5030df5cd3eb..602d5dbc4345 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -258,5 +258,23 @@ depends on PPC32 || PPC64
258source "drivers/cpufreq/Kconfig.powerpc" 258source "drivers/cpufreq/Kconfig.powerpc"
259endmenu 259endmenu
260 260
261menu "SH CPU Frequency scaling"
262depends on SUPERH
263config SH_CPU_FREQ
264 tristate "SuperH CPU Frequency driver"
265 select CPU_FREQ_TABLE
266 help
267 This adds the cpufreq driver for SuperH. Any CPU that supports
268 clock rate rounding through the clock framework can use this
269 driver. While it will make the kernel slightly larger, this is
270 harmless for CPUs that don't support rate rounding. The driver
271 will also generate a notice in the boot log before disabling
272 itself if the CPU in question is not capable of rate rounding.
273
274 For details, take a look at <file:Documentation/cpu-freq>.
275
276 If unsure, say N.
277endmenu
278
261endif 279endif
262endmenu 280endmenu
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 9659cbbad25e..3930d2e6a664 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -83,3 +83,4 @@ obj-$(CONFIG_CRIS_MACH_ARTPEC3) += cris-artpec3-cpufreq.o
83obj-$(CONFIG_ETRAXFS) += cris-etraxfs-cpufreq.o 83obj-$(CONFIG_ETRAXFS) += cris-etraxfs-cpufreq.o
84obj-$(CONFIG_IA64_ACPI_CPUFREQ) += ia64-acpi-cpufreq.o 84obj-$(CONFIG_IA64_ACPI_CPUFREQ) += ia64-acpi-cpufreq.o
85obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o 85obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o
86obj-$(CONFIG_SH_CPU_FREQ) += sh-cpufreq.o
diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c
new file mode 100644
index 000000000000..73adb64651e8
--- /dev/null
+++ b/drivers/cpufreq/sh-cpufreq.c
@@ -0,0 +1,189 @@
1/*
2 * cpufreq driver for the SuperH processors.
3 *
4 * Copyright (C) 2002 - 2012 Paul Mundt
5 * Copyright (C) 2002 M. R. Brown
6 *
7 * Clock framework bits from arch/avr32/mach-at32ap/cpufreq.c
8 *
9 * Copyright (C) 2004-2007 Atmel Corporation
10 *
11 * This file is subject to the terms and conditions of the GNU General Public
12 * License. See the file "COPYING" in the main directory of this archive
13 * for more details.
14 */
15#define pr_fmt(fmt) "cpufreq: " fmt
16
17#include <linux/types.h>
18#include <linux/cpufreq.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/err.h>
23#include <linux/cpumask.h>
24#include <linux/cpu.h>
25#include <linux/smp.h>
26#include <linux/sched.h> /* set_cpus_allowed() */
27#include <linux/clk.h>
28#include <linux/percpu.h>
29#include <linux/sh_clk.h>
30
31static DEFINE_PER_CPU(struct clk, sh_cpuclk);
32
33static unsigned int sh_cpufreq_get(unsigned int cpu)
34{
35 return (clk_get_rate(&per_cpu(sh_cpuclk, cpu)) + 500) / 1000;
36}
37
38/*
39 * Here we notify other drivers of the proposed change and the final change.
40 */
41static int sh_cpufreq_target(struct cpufreq_policy *policy,
42 unsigned int target_freq,
43 unsigned int relation)
44{
45 unsigned int cpu = policy->cpu;
46 struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
47 cpumask_t cpus_allowed;
48 struct cpufreq_freqs freqs;
49 struct device *dev;
50 long freq;
51
52 cpus_allowed = current->cpus_allowed;
53 set_cpus_allowed_ptr(current, cpumask_of(cpu));
54
55 BUG_ON(smp_processor_id() != cpu);
56
57 dev = get_cpu_device(cpu);
58
59 /* Convert target_freq from kHz to Hz */
60 freq = clk_round_rate(cpuclk, target_freq * 1000);
61
62 if (freq < (policy->min * 1000) || freq > (policy->max * 1000))
63 return -EINVAL;
64
65 dev_dbg(dev, "requested frequency %u Hz\n", target_freq * 1000);
66
67 freqs.old = sh_cpufreq_get(cpu);
68 freqs.new = (freq + 500) / 1000;
69 freqs.flags = 0;
70
71 cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
72 set_cpus_allowed_ptr(current, &cpus_allowed);
73 clk_set_rate(cpuclk, freq);
74 cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
75
76 dev_dbg(dev, "set frequency %lu Hz\n", freq);
77
78 return 0;
79}
80
81static int sh_cpufreq_verify(struct cpufreq_policy *policy)
82{
83 struct clk *cpuclk = &per_cpu(sh_cpuclk, policy->cpu);
84 struct cpufreq_frequency_table *freq_table;
85
86 freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL;
87 if (freq_table)
88 return cpufreq_frequency_table_verify(policy, freq_table);
89
90 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
91 policy->cpuinfo.max_freq);
92
93 policy->min = (clk_round_rate(cpuclk, 1) + 500) / 1000;
94 policy->max = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
95
96 cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
97 policy->cpuinfo.max_freq);
98
99 return 0;
100}
101
102static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
103{
104 unsigned int cpu = policy->cpu;
105 struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
106 struct cpufreq_frequency_table *freq_table;
107 struct device *dev;
108
109 dev = get_cpu_device(cpu);
110
111 cpuclk = clk_get(dev, "cpu_clk");
112 if (IS_ERR(cpuclk)) {
113 dev_err(dev, "couldn't get CPU clk\n");
114 return PTR_ERR(cpuclk);
115 }
116
117 policy->cur = sh_cpufreq_get(cpu);
118
119 freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL;
120 if (freq_table) {
121 int result;
122
123 result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
124 if (!result)
125 cpufreq_frequency_table_get_attr(freq_table, cpu);
126 } else {
127 dev_notice(dev, "no frequency table found, falling back "
128 "to rate rounding.\n");
129
130 policy->min = policy->cpuinfo.min_freq =
131 (clk_round_rate(cpuclk, 1) + 500) / 1000;
132 policy->max = policy->cpuinfo.max_freq =
133 (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
134 }
135
136 policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
137
138 dev_info(dev, "CPU Frequencies - Minimum %u.%03u MHz, "
139 "Maximum %u.%03u MHz.\n",
140 policy->min / 1000, policy->min % 1000,
141 policy->max / 1000, policy->max % 1000);
142
143 return 0;
144}
145
146static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy)
147{
148 unsigned int cpu = policy->cpu;
149 struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
150
151 cpufreq_frequency_table_put_attr(cpu);
152 clk_put(cpuclk);
153
154 return 0;
155}
156
157static struct freq_attr *sh_freq_attr[] = {
158 &cpufreq_freq_attr_scaling_available_freqs,
159 NULL,
160};
161
162static struct cpufreq_driver sh_cpufreq_driver = {
163 .owner = THIS_MODULE,
164 .name = "sh",
165 .get = sh_cpufreq_get,
166 .target = sh_cpufreq_target,
167 .verify = sh_cpufreq_verify,
168 .init = sh_cpufreq_cpu_init,
169 .exit = sh_cpufreq_cpu_exit,
170 .attr = sh_freq_attr,
171};
172
173static int __init sh_cpufreq_module_init(void)
174{
175 pr_notice("SuperH CPU frequency driver.\n");
176 return cpufreq_register_driver(&sh_cpufreq_driver);
177}
178
179static void __exit sh_cpufreq_module_exit(void)
180{
181 cpufreq_unregister_driver(&sh_cpufreq_driver);
182}
183
184module_init(sh_cpufreq_module_init);
185module_exit(sh_cpufreq_module_exit);
186
187MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
188MODULE_DESCRIPTION("cpufreq driver for SuperH");
189MODULE_LICENSE("GPL");