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 static unsigned int sh_cpufreq_get(unsigned int cpu
)
35 return (clk_get_rate(&per_cpu(sh_cpuclk
, cpu
)) + 500) / 1000;
39 * Here we notify other drivers of the proposed change and the final change.
41 static int sh_cpufreq_target(struct cpufreq_policy
*policy
,
42 unsigned int target_freq
,
43 unsigned int relation
)
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
;
52 cpus_allowed
= current
->cpus_allowed
;
53 set_cpus_allowed_ptr(current
, cpumask_of(cpu
));
55 BUG_ON(smp_processor_id() != cpu
);
57 dev
= get_cpu_device(cpu
);
59 /* Convert target_freq from kHz to Hz */
60 freq
= clk_round_rate(cpuclk
, target_freq
* 1000);
62 if (freq
< (policy
->min
* 1000) || freq
> (policy
->max
* 1000))
65 dev_dbg(dev
, "requested frequency %u Hz\n", target_freq
* 1000);
67 freqs
.old
= sh_cpufreq_get(cpu
);
68 freqs
.new = (freq
+ 500) / 1000;
71 cpufreq_freq_transition_begin(policy
, &freqs
);
72 set_cpus_allowed_ptr(current
, &cpus_allowed
);
73 clk_set_rate(cpuclk
, freq
);
74 cpufreq_freq_transition_end(policy
, &freqs
, 0);
76 dev_dbg(dev
, "set frequency %lu Hz\n", freq
);
81 static int sh_cpufreq_verify(struct cpufreq_policy
*policy
)
83 struct clk
*cpuclk
= &per_cpu(sh_cpuclk
, policy
->cpu
);
84 struct cpufreq_frequency_table
*freq_table
;
86 freq_table
= cpuclk
->nr_freqs
? cpuclk
->freq_table
: NULL
;
88 return cpufreq_frequency_table_verify(policy
, freq_table
);
90 cpufreq_verify_within_cpu_limits(policy
);
92 policy
->min
= (clk_round_rate(cpuclk
, 1) + 500) / 1000;
93 policy
->max
= (clk_round_rate(cpuclk
, ~0UL) + 500) / 1000;
95 cpufreq_verify_within_cpu_limits(policy
);
99 static int sh_cpufreq_cpu_init(struct cpufreq_policy
*policy
)
101 unsigned int cpu
= policy
->cpu
;
102 struct clk
*cpuclk
= &per_cpu(sh_cpuclk
, cpu
);
103 struct cpufreq_frequency_table
*freq_table
;
106 dev
= get_cpu_device(cpu
);
108 cpuclk
= clk_get(dev
, "cpu_clk");
109 if (IS_ERR(cpuclk
)) {
110 dev_err(dev
, "couldn't get CPU clk\n");
111 return PTR_ERR(cpuclk
);
114 freq_table
= cpuclk
->nr_freqs
? cpuclk
->freq_table
: NULL
;
118 result
= cpufreq_table_validate_and_show(policy
, freq_table
);
122 dev_notice(dev
, "no frequency table found, falling back "
123 "to rate rounding.\n");
125 policy
->min
= policy
->cpuinfo
.min_freq
=
126 (clk_round_rate(cpuclk
, 1) + 500) / 1000;
127 policy
->max
= policy
->cpuinfo
.max_freq
=
128 (clk_round_rate(cpuclk
, ~0UL) + 500) / 1000;
131 policy
->cpuinfo
.transition_latency
= CPUFREQ_ETERNAL
;
133 dev_info(dev
, "CPU Frequencies - Minimum %u.%03u MHz, "
134 "Maximum %u.%03u MHz.\n",
135 policy
->min
/ 1000, policy
->min
% 1000,
136 policy
->max
/ 1000, policy
->max
% 1000);
141 static int sh_cpufreq_cpu_exit(struct cpufreq_policy
*policy
)
143 unsigned int cpu
= policy
->cpu
;
144 struct clk
*cpuclk
= &per_cpu(sh_cpuclk
, cpu
);
151 static struct cpufreq_driver sh_cpufreq_driver
= {
153 .get
= sh_cpufreq_get
,
154 .target
= sh_cpufreq_target
,
155 .verify
= sh_cpufreq_verify
,
156 .init
= sh_cpufreq_cpu_init
,
157 .exit
= sh_cpufreq_cpu_exit
,
158 .attr
= cpufreq_generic_attr
,
161 static int __init
sh_cpufreq_module_init(void)
163 pr_notice("SuperH CPU frequency driver.\n");
164 return cpufreq_register_driver(&sh_cpufreq_driver
);
167 static void __exit
sh_cpufreq_module_exit(void)
169 cpufreq_unregister_driver(&sh_cpufreq_driver
);
172 module_init(sh_cpufreq_module_init
);
173 module_exit(sh_cpufreq_module_exit
);
175 MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
176 MODULE_DESCRIPTION("cpufreq driver for SuperH");
177 MODULE_LICENSE("GPL");