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/clk.h>
27 #include <linux/percpu.h>
28 #include <linux/sh_clk.h>
30 static DEFINE_PER_CPU(struct clk
, sh_cpuclk
);
32 struct cpufreq_target
{
33 struct cpufreq_policy
*policy
;
37 static unsigned int sh_cpufreq_get(unsigned int cpu
)
39 return (clk_get_rate(&per_cpu(sh_cpuclk
, cpu
)) + 500) / 1000;
42 static long __sh_cpufreq_target(void *arg
)
44 struct cpufreq_target
*target
= arg
;
45 struct cpufreq_policy
*policy
= target
->policy
;
46 int cpu
= policy
->cpu
;
47 struct clk
*cpuclk
= &per_cpu(sh_cpuclk
, cpu
);
48 struct cpufreq_freqs freqs
;
52 if (smp_processor_id() != cpu
)
55 dev
= get_cpu_device(cpu
);
57 /* Convert target_freq from kHz to Hz */
58 freq
= clk_round_rate(cpuclk
, target
->freq
* 1000);
60 if (freq
< (policy
->min
* 1000) || freq
> (policy
->max
* 1000))
63 dev_dbg(dev
, "requested frequency %u Hz\n", target
->freq
* 1000);
65 freqs
.old
= sh_cpufreq_get(cpu
);
66 freqs
.new = (freq
+ 500) / 1000;
69 cpufreq_freq_transition_begin(target
->policy
, &freqs
);
70 clk_set_rate(cpuclk
, freq
);
71 cpufreq_freq_transition_end(target
->policy
, &freqs
, 0);
73 dev_dbg(dev
, "set frequency %lu Hz\n", freq
);
78 * Here we notify other drivers of the proposed change and the final change.
80 static int sh_cpufreq_target(struct cpufreq_policy
*policy
,
81 unsigned int target_freq
,
82 unsigned int relation
)
84 struct cpufreq_target data
= { .policy
= policy
, .freq
= target_freq
};
86 return work_on_cpu(policy
->cpu
, __sh_cpufreq_target
, &data
);
89 static int sh_cpufreq_verify(struct cpufreq_policy_data
*policy
)
91 struct clk
*cpuclk
= &per_cpu(sh_cpuclk
, policy
->cpu
);
92 struct cpufreq_frequency_table
*freq_table
;
94 freq_table
= cpuclk
->nr_freqs
? cpuclk
->freq_table
: NULL
;
96 return cpufreq_frequency_table_verify(policy
, freq_table
);
98 cpufreq_verify_within_cpu_limits(policy
);
100 policy
->min
= (clk_round_rate(cpuclk
, 1) + 500) / 1000;
101 policy
->max
= (clk_round_rate(cpuclk
, ~0UL) + 500) / 1000;
103 cpufreq_verify_within_cpu_limits(policy
);
107 static int sh_cpufreq_cpu_init(struct cpufreq_policy
*policy
)
109 unsigned int cpu
= policy
->cpu
;
110 struct clk
*cpuclk
= &per_cpu(sh_cpuclk
, cpu
);
111 struct cpufreq_frequency_table
*freq_table
;
114 dev
= get_cpu_device(cpu
);
116 cpuclk
= clk_get(dev
, "cpu_clk");
117 if (IS_ERR(cpuclk
)) {
118 dev_err(dev
, "couldn't get CPU clk\n");
119 return PTR_ERR(cpuclk
);
122 freq_table
= cpuclk
->nr_freqs
? cpuclk
->freq_table
: NULL
;
124 policy
->freq_table
= freq_table
;
126 dev_notice(dev
, "no frequency table found, falling back "
127 "to rate rounding.\n");
129 policy
->min
= policy
->cpuinfo
.min_freq
=
130 (clk_round_rate(cpuclk
, 1) + 500) / 1000;
131 policy
->max
= policy
->cpuinfo
.max_freq
=
132 (clk_round_rate(cpuclk
, ~0UL) + 500) / 1000;
138 static void sh_cpufreq_cpu_exit(struct cpufreq_policy
*policy
)
140 unsigned int cpu
= policy
->cpu
;
141 struct clk
*cpuclk
= &per_cpu(sh_cpuclk
, cpu
);
146 static struct cpufreq_driver sh_cpufreq_driver
= {
148 .flags
= CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING
,
149 .get
= sh_cpufreq_get
,
150 .target
= sh_cpufreq_target
,
151 .verify
= sh_cpufreq_verify
,
152 .init
= sh_cpufreq_cpu_init
,
153 .exit
= sh_cpufreq_cpu_exit
,
154 .attr
= cpufreq_generic_attr
,
157 static int __init
sh_cpufreq_module_init(void)
159 pr_notice("SuperH CPU frequency driver.\n");
160 return cpufreq_register_driver(&sh_cpufreq_driver
);
163 static void __exit
sh_cpufreq_module_exit(void)
165 cpufreq_unregister_driver(&sh_cpufreq_driver
);
168 module_init(sh_cpufreq_module_init
);
169 module_exit(sh_cpufreq_module_exit
);
171 MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
172 MODULE_DESCRIPTION("cpufreq driver for SuperH");
173 MODULE_LICENSE("GPL");