2 * Copyright (C) 2012 Freescale Semiconductor, Inc.
4 * Copyright (C) 2014 Linaro.
5 * Viresh Kumar <viresh.kumar@linaro.org>
7 * The OPP code in function cpu0_set_target() is reused from
8 * drivers/cpufreq/omap-cpufreq.c
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
15 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17 #include <linux/clk.h>
18 #include <linux/cpu.h>
19 #include <linux/cpu_cooling.h>
20 #include <linux/cpufreq.h>
21 #include <linux/cpumask.h>
22 #include <linux/err.h>
23 #include <linux/module.h>
25 #include <linux/pm_opp.h>
26 #include <linux/platform_device.h>
27 #include <linux/regulator/consumer.h>
28 #include <linux/slab.h>
29 #include <linux/thermal.h>
31 static unsigned int transition_latency
;
32 static unsigned int voltage_tolerance
; /* in percentage */
34 static struct device
*cpu_dev
;
35 static struct clk
*cpu_clk
;
36 static struct regulator
*cpu_reg
;
37 static struct cpufreq_frequency_table
*freq_table
;
38 static struct thermal_cooling_device
*cdev
;
40 static int cpu0_set_target(struct cpufreq_policy
*policy
, unsigned int index
)
42 struct dev_pm_opp
*opp
;
43 unsigned long volt
= 0, volt_old
= 0, tol
= 0;
44 unsigned int old_freq
, new_freq
;
45 long freq_Hz
, freq_exact
;
48 freq_Hz
= clk_round_rate(cpu_clk
, freq_table
[index
].frequency
* 1000);
50 freq_Hz
= freq_table
[index
].frequency
* 1000;
53 new_freq
= freq_Hz
/ 1000;
54 old_freq
= clk_get_rate(cpu_clk
) / 1000;
56 if (!IS_ERR(cpu_reg
)) {
58 opp
= dev_pm_opp_find_freq_ceil(cpu_dev
, &freq_Hz
);
61 pr_err("failed to find OPP for %ld\n", freq_Hz
);
64 volt
= dev_pm_opp_get_voltage(opp
);
66 tol
= volt
* voltage_tolerance
/ 100;
67 volt_old
= regulator_get_voltage(cpu_reg
);
70 pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
71 old_freq
/ 1000, volt_old
? volt_old
/ 1000 : -1,
72 new_freq
/ 1000, volt
? volt
/ 1000 : -1);
74 /* scaling up? scale voltage before frequency */
75 if (!IS_ERR(cpu_reg
) && new_freq
> old_freq
) {
76 ret
= regulator_set_voltage_tol(cpu_reg
, volt
, tol
);
78 pr_err("failed to scale voltage up: %d\n", ret
);
83 ret
= clk_set_rate(cpu_clk
, freq_exact
);
85 pr_err("failed to set clock rate: %d\n", ret
);
87 regulator_set_voltage_tol(cpu_reg
, volt_old
, tol
);
91 /* scaling down? scale voltage after frequency */
92 if (!IS_ERR(cpu_reg
) && new_freq
< old_freq
) {
93 ret
= regulator_set_voltage_tol(cpu_reg
, volt
, tol
);
95 pr_err("failed to scale voltage down: %d\n", ret
);
96 clk_set_rate(cpu_clk
, old_freq
* 1000);
103 static int cpu0_cpufreq_init(struct cpufreq_policy
*policy
)
105 policy
->clk
= cpu_clk
;
106 return cpufreq_generic_init(policy
, freq_table
, transition_latency
);
109 static struct cpufreq_driver cpu0_cpufreq_driver
= {
110 .flags
= CPUFREQ_STICKY
| CPUFREQ_NEED_INITIAL_FREQ_CHECK
,
111 .verify
= cpufreq_generic_frequency_table_verify
,
112 .target_index
= cpu0_set_target
,
113 .get
= cpufreq_generic_get
,
114 .init
= cpu0_cpufreq_init
,
115 .name
= "generic_cpu0",
116 .attr
= cpufreq_generic_attr
,
119 static int cpu0_cpufreq_probe(struct platform_device
*pdev
)
121 struct device_node
*np
;
124 cpu_dev
= get_cpu_device(0);
126 pr_err("failed to get cpu0 device\n");
130 np
= of_node_get(cpu_dev
->of_node
);
132 pr_err("failed to find cpu0 node\n");
136 cpu_reg
= regulator_get_optional(cpu_dev
, "cpu0");
137 if (IS_ERR(cpu_reg
)) {
139 * If cpu0 regulator supply node is present, but regulator is
140 * not yet registered, we should try defering probe.
142 if (PTR_ERR(cpu_reg
) == -EPROBE_DEFER
) {
143 dev_dbg(cpu_dev
, "cpu0 regulator not ready, retry\n");
147 pr_warn("failed to get cpu0 regulator: %ld\n",
151 cpu_clk
= clk_get(cpu_dev
, NULL
);
152 if (IS_ERR(cpu_clk
)) {
153 ret
= PTR_ERR(cpu_clk
);
156 * If cpu's clk node is present, but clock is not yet
157 * registered, we should try defering probe.
159 if (ret
== -EPROBE_DEFER
)
160 dev_dbg(cpu_dev
, "cpu0 clock not ready, retry\n");
162 dev_err(cpu_dev
, "failed to get cpu0 clock: %d\n", ret
);
167 /* OPPs might be populated at runtime, don't check for error here */
168 of_init_opp_table(cpu_dev
);
170 ret
= dev_pm_opp_init_cpufreq_table(cpu_dev
, &freq_table
);
172 pr_err("failed to init cpufreq table: %d\n", ret
);
176 of_property_read_u32(np
, "voltage-tolerance", &voltage_tolerance
);
178 if (of_property_read_u32(np
, "clock-latency", &transition_latency
))
179 transition_latency
= CPUFREQ_ETERNAL
;
181 if (!IS_ERR(cpu_reg
)) {
182 struct dev_pm_opp
*opp
;
183 unsigned long min_uV
, max_uV
;
187 * OPP is maintained in order of increasing frequency, and
188 * freq_table initialised from OPP is therefore sorted in the
191 for (i
= 0; freq_table
[i
].frequency
!= CPUFREQ_TABLE_END
; i
++)
194 opp
= dev_pm_opp_find_freq_exact(cpu_dev
,
195 freq_table
[0].frequency
* 1000, true);
196 min_uV
= dev_pm_opp_get_voltage(opp
);
197 opp
= dev_pm_opp_find_freq_exact(cpu_dev
,
198 freq_table
[i
-1].frequency
* 1000, true);
199 max_uV
= dev_pm_opp_get_voltage(opp
);
201 ret
= regulator_set_voltage_time(cpu_reg
, min_uV
, max_uV
);
203 transition_latency
+= ret
* 1000;
206 ret
= cpufreq_register_driver(&cpu0_cpufreq_driver
);
208 pr_err("failed register driver: %d\n", ret
);
213 * For now, just loading the cooling device;
214 * thermal DT code takes care of matching them.
216 if (of_find_property(np
, "#cooling-cells", NULL
)) {
217 cdev
= of_cpufreq_cooling_register(np
, cpu_present_mask
);
219 pr_err("running cpufreq without cooling device: %ld\n",
227 dev_pm_opp_free_cpufreq_table(cpu_dev
, &freq_table
);
231 if (!IS_ERR(cpu_reg
))
232 regulator_put(cpu_reg
);
238 static int cpu0_cpufreq_remove(struct platform_device
*pdev
)
240 cpufreq_cooling_unregister(cdev
);
241 cpufreq_unregister_driver(&cpu0_cpufreq_driver
);
242 dev_pm_opp_free_cpufreq_table(cpu_dev
, &freq_table
);
247 static struct platform_driver cpu0_cpufreq_platdrv
= {
249 .name
= "cpufreq-cpu0",
250 .owner
= THIS_MODULE
,
252 .probe
= cpu0_cpufreq_probe
,
253 .remove
= cpu0_cpufreq_remove
,
255 module_platform_driver(cpu0_cpufreq_platdrv
);
257 MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
258 MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
259 MODULE_DESCRIPTION("Generic CPU0 cpufreq driver");
260 MODULE_LICENSE("GPL");