2 * cpufreq driver for the SuperH processors.
4 * Copyright (C) 2002 - 2012 Paul Mundt
5 * Copyright (C) 2002 M. R. Brown
7 * Clock framework bits from arch/avr32/mach-at32ap/cpufreq.c
9 * Copyright (C) 2004-2007 Atmel Corporation
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
15 #define pr_fmt(fmt) "cpufreq: " fmt
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>
31 static DEFINE_PER_CPU(struct clk
, sh_cpuclk
);
33 struct cpufreq_target
{
34 struct cpufreq_policy
*policy
;
38 static unsigned int sh_cpufreq_get(unsigned int cpu
)
40 return (clk_get_rate(&per_cpu(sh_cpuclk
, cpu
)) + 500) / 1000;
43 static long __sh_cpufreq_target(void *arg
)
45 struct cpufreq_target
*target
= arg
;
46 struct cpufreq_policy
*policy
= target
->policy
;
47 int cpu
= policy
->cpu
;
48 struct clk
*cpuclk
= &per_cpu(sh_cpuclk
, cpu
);
49 struct cpufreq_freqs freqs
;
53 if (smp_processor_id() != cpu
)
56 dev
= get_cpu_device(cpu
);
58 /* Convert target_freq from kHz to Hz */
59 freq
= clk_round_rate(cpuclk
, target
->freq
* 1000);
61 if (freq
< (policy
->min
* 1000) || freq
> (policy
->max
* 1000))
64 dev_dbg(dev
, "requested frequency %u Hz\n", target
->freq
* 1000);
66 freqs
.old
= sh_cpufreq_get(cpu
);
67 freqs
.new = (freq
+ 500) / 1000;
70 cpufreq_freq_transition_begin(target
->policy
, &freqs
);
71 clk_set_rate(cpuclk
, freq
);
72 cpufreq_freq_transition_end(target
->policy
, &freqs
, 0);
74 dev_dbg(dev
, "set frequency %lu Hz\n", freq
);
79 * Here we notify other drivers of the proposed change and the final change.
81 static int sh_cpufreq_target(struct cpufreq_policy
*policy
,
82 unsigned int target_freq
,
83 unsigned int relation
)
85 struct cpufreq_target data
= { .policy
= policy
, .freq
= target_freq
};
87 return work_on_cpu(policy
->cpu
, __sh_cpufreq_target
, &data
);
90 static int sh_cpufreq_verify(struct cpufreq_policy_data
*policy
)
92 struct clk
*cpuclk
= &per_cpu(sh_cpuclk
, policy
->cpu
);
93 struct cpufreq_frequency_table
*freq_table
;
95 freq_table
= cpuclk
->nr_freqs
? cpuclk
->freq_table
: NULL
;
97 return cpufreq_frequency_table_verify(policy
, freq_table
);
99 cpufreq_verify_within_cpu_limits(policy
);
101 policy
->min
= (clk_round_rate(cpuclk
, 1) + 500) / 1000;
102 policy
->max
= (clk_round_rate(cpuclk
, ~0UL) + 500) / 1000;
104 cpufreq_verify_within_cpu_limits(policy
);
108 static int sh_cpufreq_cpu_init(struct cpufreq_policy
*policy
)
110 unsigned int cpu
= policy
->cpu
;
111 struct clk
*cpuclk
= &per_cpu(sh_cpuclk
, cpu
);
112 struct cpufreq_frequency_table
*freq_table
;
115 dev
= get_cpu_device(cpu
);
117 cpuclk
= clk_get(dev
, "cpu_clk");
118 if (IS_ERR(cpuclk
)) {
119 dev_err(dev
, "couldn't get CPU clk\n");
120 return PTR_ERR(cpuclk
);
123 freq_table
= cpuclk
->nr_freqs
? cpuclk
->freq_table
: NULL
;
125 policy
->freq_table
= freq_table
;
127 dev_notice(dev
, "no frequency table found, falling back "
128 "to rate rounding.\n");
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;
139 static int sh_cpufreq_cpu_exit(struct cpufreq_policy
*policy
)
141 unsigned int cpu
= policy
->cpu
;
142 struct clk
*cpuclk
= &per_cpu(sh_cpuclk
, cpu
);
149 static void sh_cpufreq_cpu_ready(struct cpufreq_policy
*policy
)
151 struct device
*dev
= get_cpu_device(policy
->cpu
);
153 dev_info(dev
, "CPU Frequencies - Minimum %u.%03u MHz, "
154 "Maximum %u.%03u MHz.\n",
155 policy
->min
/ 1000, policy
->min
% 1000,
156 policy
->max
/ 1000, policy
->max
% 1000);
159 static struct cpufreq_driver sh_cpufreq_driver
= {
161 .flags
= CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING
,
162 .get
= sh_cpufreq_get
,
163 .target
= sh_cpufreq_target
,
164 .verify
= sh_cpufreq_verify
,
165 .init
= sh_cpufreq_cpu_init
,
166 .exit
= sh_cpufreq_cpu_exit
,
167 .ready
= sh_cpufreq_cpu_ready
,
168 .attr
= cpufreq_generic_attr
,
171 static int __init
sh_cpufreq_module_init(void)
173 pr_notice("SuperH CPU frequency driver.\n");
174 return cpufreq_register_driver(&sh_cpufreq_driver
);
177 static void __exit
sh_cpufreq_module_exit(void)
179 cpufreq_unregister_driver(&sh_cpufreq_driver
);
182 module_init(sh_cpufreq_module_init
);
183 module_exit(sh_cpufreq_module_exit
);
185 MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
186 MODULE_DESCRIPTION("cpufreq driver for SuperH");
187 MODULE_LICENSE("GPL");