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 controlling CPU frequency. It allows you to change
17 * the CPU clock speed on the fly.
20 #include <linux/module.h>
21 #include <linux/cpufreq.h>
22 #include <linux/clk.h>
23 #include <linux/err.h>
24 #include <linux/slab.h>
25 #include <mach/hardware.h>
26 #include <mach/clock.h>
28 #define CLK32_FREQ 32768
29 #define NANOSECOND (1000 * 1000 * 1000)
31 struct cpu_op
*(*get_cpu_op
)(int *op
);
33 static int cpu_freq_khz_min
;
34 static int cpu_freq_khz_max
;
36 static struct clk
*cpu_clk
;
37 static struct cpufreq_frequency_table
*imx_freq_table
;
40 static struct cpu_op
*cpu_op_tbl
;
42 static int set_cpu_freq(int freq
)
47 org_cpu_rate
= clk_get_rate(cpu_clk
);
48 if (org_cpu_rate
== freq
)
51 ret
= clk_set_rate(cpu_clk
, freq
);
53 printk(KERN_DEBUG
"cannot set CPU clock rate\n");
60 static int mxc_verify_speed(struct cpufreq_policy
*policy
)
65 return cpufreq_frequency_table_verify(policy
, imx_freq_table
);
68 static unsigned int mxc_get_speed(unsigned int cpu
)
73 return clk_get_rate(cpu_clk
) / 1000;
76 static int mxc_set_target(struct cpufreq_policy
*policy
,
77 unsigned int target_freq
, unsigned int relation
)
79 struct cpufreq_freqs freqs
;
84 cpufreq_frequency_table_target(policy
, imx_freq_table
,
85 target_freq
, relation
, &index
);
86 freq_Hz
= imx_freq_table
[index
].frequency
* 1000;
88 freqs
.old
= clk_get_rate(cpu_clk
) / 1000;
89 freqs
.new = freq_Hz
/ 1000;
92 cpufreq_notify_transition(&freqs
, CPUFREQ_PRECHANGE
);
94 ret
= set_cpu_freq(freq_Hz
);
96 cpufreq_notify_transition(&freqs
, CPUFREQ_POSTCHANGE
);
101 static int mxc_cpufreq_init(struct cpufreq_policy
*policy
)
106 printk(KERN_INFO
"i.MXC CPU frequency driver\n");
108 if (policy
->cpu
!= 0)
114 cpu_clk
= clk_get(NULL
, "cpu_clk");
115 if (IS_ERR(cpu_clk
)) {
116 printk(KERN_ERR
"%s: failed to get cpu clock\n", __func__
);
117 return PTR_ERR(cpu_clk
);
120 cpu_op_tbl
= get_cpu_op(&cpu_op_nr
);
122 cpu_freq_khz_min
= cpu_op_tbl
[0].cpu_rate
/ 1000;
123 cpu_freq_khz_max
= cpu_op_tbl
[0].cpu_rate
/ 1000;
125 imx_freq_table
= kmalloc(
126 sizeof(struct cpufreq_frequency_table
) * (cpu_op_nr
+ 1),
128 if (!imx_freq_table
) {
133 for (i
= 0; i
< cpu_op_nr
; i
++) {
134 imx_freq_table
[i
].index
= i
;
135 imx_freq_table
[i
].frequency
= cpu_op_tbl
[i
].cpu_rate
/ 1000;
137 if ((cpu_op_tbl
[i
].cpu_rate
/ 1000) < cpu_freq_khz_min
)
138 cpu_freq_khz_min
= cpu_op_tbl
[i
].cpu_rate
/ 1000;
140 if ((cpu_op_tbl
[i
].cpu_rate
/ 1000) > cpu_freq_khz_max
)
141 cpu_freq_khz_max
= cpu_op_tbl
[i
].cpu_rate
/ 1000;
144 imx_freq_table
[i
].index
= i
;
145 imx_freq_table
[i
].frequency
= CPUFREQ_TABLE_END
;
147 policy
->cur
= clk_get_rate(cpu_clk
) / 1000;
148 policy
->min
= policy
->cpuinfo
.min_freq
= cpu_freq_khz_min
;
149 policy
->max
= policy
->cpuinfo
.max_freq
= cpu_freq_khz_max
;
151 /* Manual states, that PLL stabilizes in two CLK32 periods */
152 policy
->cpuinfo
.transition_latency
= 2 * NANOSECOND
/ CLK32_FREQ
;
154 ret
= cpufreq_frequency_table_cpuinfo(policy
, imx_freq_table
);
157 printk(KERN_ERR
"%s: failed to register i.MXC CPUfreq with error code %d\n",
162 cpufreq_frequency_table_get_attr(imx_freq_table
, policy
->cpu
);
165 kfree(imx_freq_table
);
171 static int mxc_cpufreq_exit(struct cpufreq_policy
*policy
)
173 cpufreq_frequency_table_put_attr(policy
->cpu
);
175 set_cpu_freq(cpu_freq_khz_max
* 1000);
177 kfree(imx_freq_table
);
181 static struct cpufreq_driver mxc_driver
= {
182 .flags
= CPUFREQ_STICKY
,
183 .verify
= mxc_verify_speed
,
184 .target
= mxc_set_target
,
185 .get
= mxc_get_speed
,
186 .init
= mxc_cpufreq_init
,
187 .exit
= mxc_cpufreq_exit
,
191 static int __devinit
mxc_cpufreq_driver_init(void)
193 return cpufreq_register_driver(&mxc_driver
);
196 static void mxc_cpufreq_driver_exit(void)
198 cpufreq_unregister_driver(&mxc_driver
);
201 module_init(mxc_cpufreq_driver_init
);
202 module_exit(mxc_cpufreq_driver_exit
);
204 MODULE_AUTHOR("Freescale Semiconductor Inc. Yong Shen <yong.shen@linaro.org>");
205 MODULE_DESCRIPTION("CPUfreq driver for i.MX");
206 MODULE_LICENSE("GPL");