2 * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
6 * The code contained herein is licensed under the GNU General Public
7 * License. You may obtain a copy of the GNU General Public License
8 * Version 2 or later at the following locations:
10 * http://www.opensource.org/licenses/gpl-license.html
11 * http://www.gnu.org/copyleft/gpl.html
15 * A driver for the Freescale Semiconductor i.MXC CPUfreq module.
16 * The CPUFREQ driver is for controling CPU frequency. It allows you to change
17 * the CPU clock speed on the fly.
20 #include <linux/cpufreq.h>
21 #include <linux/clk.h>
22 #include <linux/err.h>
23 #include <linux/slab.h>
24 #include <mach/hardware.h>
25 #include <mach/clock.h>
27 #define CLK32_FREQ 32768
28 #define NANOSECOND (1000 * 1000 * 1000)
30 struct cpu_op
*(*get_cpu_op
)(int *op
);
32 static int cpu_freq_khz_min
;
33 static int cpu_freq_khz_max
;
35 static struct clk
*cpu_clk
;
36 static struct cpufreq_frequency_table
*imx_freq_table
;
39 static struct cpu_op
*cpu_op_tbl
;
41 static int set_cpu_freq(int freq
)
46 org_cpu_rate
= clk_get_rate(cpu_clk
);
47 if (org_cpu_rate
== freq
)
50 ret
= clk_set_rate(cpu_clk
, freq
);
52 printk(KERN_DEBUG
"cannot set CPU clock rate\n");
59 static int mxc_verify_speed(struct cpufreq_policy
*policy
)
64 return cpufreq_frequency_table_verify(policy
, imx_freq_table
);
67 static unsigned int mxc_get_speed(unsigned int cpu
)
72 return clk_get_rate(cpu_clk
) / 1000;
75 static int mxc_set_target(struct cpufreq_policy
*policy
,
76 unsigned int target_freq
, unsigned int relation
)
78 struct cpufreq_freqs freqs
;
83 cpufreq_frequency_table_target(policy
, imx_freq_table
,
84 target_freq
, relation
, &index
);
85 freq_Hz
= imx_freq_table
[index
].frequency
* 1000;
87 freqs
.old
= clk_get_rate(cpu_clk
) / 1000;
88 freqs
.new = freq_Hz
/ 1000;
91 cpufreq_notify_transition(&freqs
, CPUFREQ_PRECHANGE
);
93 ret
= set_cpu_freq(freq_Hz
);
95 cpufreq_notify_transition(&freqs
, CPUFREQ_POSTCHANGE
);
100 static int __init
mxc_cpufreq_init(struct cpufreq_policy
*policy
)
105 printk(KERN_INFO
"i.MXC CPU frequency driver\n");
107 if (policy
->cpu
!= 0)
113 cpu_clk
= clk_get(NULL
, "cpu_clk");
114 if (IS_ERR(cpu_clk
)) {
115 printk(KERN_ERR
"%s: failed to get cpu clock\n", __func__
);
116 return PTR_ERR(cpu_clk
);
119 cpu_op_tbl
= get_cpu_op(&cpu_op_nr
);
121 cpu_freq_khz_min
= cpu_op_tbl
[0].cpu_rate
/ 1000;
122 cpu_freq_khz_max
= cpu_op_tbl
[0].cpu_rate
/ 1000;
124 imx_freq_table
= kmalloc(
125 sizeof(struct cpufreq_frequency_table
) * (cpu_op_nr
+ 1),
127 if (!imx_freq_table
) {
132 for (i
= 0; i
< cpu_op_nr
; i
++) {
133 imx_freq_table
[i
].index
= i
;
134 imx_freq_table
[i
].frequency
= cpu_op_tbl
[i
].cpu_rate
/ 1000;
136 if ((cpu_op_tbl
[i
].cpu_rate
/ 1000) < cpu_freq_khz_min
)
137 cpu_freq_khz_min
= cpu_op_tbl
[i
].cpu_rate
/ 1000;
139 if ((cpu_op_tbl
[i
].cpu_rate
/ 1000) > cpu_freq_khz_max
)
140 cpu_freq_khz_max
= cpu_op_tbl
[i
].cpu_rate
/ 1000;
143 imx_freq_table
[i
].index
= i
;
144 imx_freq_table
[i
].frequency
= CPUFREQ_TABLE_END
;
146 policy
->cur
= clk_get_rate(cpu_clk
) / 1000;
147 policy
->min
= policy
->cpuinfo
.min_freq
= cpu_freq_khz_min
;
148 policy
->max
= policy
->cpuinfo
.max_freq
= cpu_freq_khz_max
;
150 /* Manual states, that PLL stabilizes in two CLK32 periods */
151 policy
->cpuinfo
.transition_latency
= 2 * NANOSECOND
/ CLK32_FREQ
;
153 ret
= cpufreq_frequency_table_cpuinfo(policy
, imx_freq_table
);
156 printk(KERN_ERR
"%s: failed to register i.MXC CPUfreq \
157 with error code %d\n", __func__
, ret
);
161 cpufreq_frequency_table_get_attr(imx_freq_table
, policy
->cpu
);
164 kfree(imx_freq_table
);
170 static int mxc_cpufreq_exit(struct cpufreq_policy
*policy
)
172 cpufreq_frequency_table_put_attr(policy
->cpu
);
174 set_cpu_freq(cpu_freq_khz_max
* 1000);
176 kfree(imx_freq_table
);
180 static struct cpufreq_driver mxc_driver
= {
181 .flags
= CPUFREQ_STICKY
,
182 .verify
= mxc_verify_speed
,
183 .target
= mxc_set_target
,
184 .get
= mxc_get_speed
,
185 .init
= mxc_cpufreq_init
,
186 .exit
= mxc_cpufreq_exit
,
190 static int __devinit
mxc_cpufreq_driver_init(void)
192 return cpufreq_register_driver(&mxc_driver
);
195 static void mxc_cpufreq_driver_exit(void)
197 cpufreq_unregister_driver(&mxc_driver
);
200 module_init(mxc_cpufreq_driver_init
);
201 module_exit(mxc_cpufreq_driver_exit
);
203 MODULE_AUTHOR("Freescale Semiconductor Inc. Yong Shen <yong.shen@linaro.org>");
204 MODULE_DESCRIPTION("CPUfreq driver for i.MX");
205 MODULE_LICENSE("GPL");