aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt (renamed from Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt)8
-rw-r--r--arch/arm/configs/mvebu_v7_defconfig2
-rw-r--r--arch/arm/mach-imx/imx27-dt.c2
-rw-r--r--arch/arm/mach-imx/mach-imx51.c2
-rw-r--r--arch/arm/mach-mvebu/pmsu.c2
-rw-r--r--arch/arm/mach-omap2/pm.c2
-rw-r--r--arch/arm/mach-shmobile/board-ape6evm-reference.c2
-rw-r--r--arch/arm/mach-shmobile/cpufreq.c2
-rw-r--r--arch/arm/mach-shmobile/setup-sh73a0.c4
-rw-r--r--arch/arm/mach-zynq/common.c2
-rw-r--r--drivers/cpufreq/Kconfig8
-rw-r--r--drivers/cpufreq/Kconfig.arm2
-rw-r--r--drivers/cpufreq/Makefile2
-rw-r--r--drivers/cpufreq/cpufreq-cpu0.c248
-rw-r--r--drivers/cpufreq/cpufreq-dt.c364
-rw-r--r--drivers/cpufreq/cpufreq.c8
-rw-r--r--drivers/cpufreq/exynos4210-cpufreq.c2
-rw-r--r--drivers/cpufreq/exynos4x12-cpufreq.c2
-rw-r--r--drivers/cpufreq/exynos5250-cpufreq.c2
-rw-r--r--drivers/cpufreq/highbank-cpufreq.c6
-rw-r--r--drivers/cpufreq/powernv-cpufreq.c44
-rw-r--r--drivers/cpufreq/ppc-corenet-cpufreq.c1
-rw-r--r--drivers/cpufreq/s5pv210-cpufreq.c2
-rw-r--r--include/linux/cpufreq.h3
24 files changed, 442 insertions, 280 deletions
diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt
index 366690cb86a3..e41c98ffbccb 100644
--- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
+++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt
@@ -1,8 +1,8 @@
1Generic CPU0 cpufreq driver 1Generic cpufreq driver
2 2
3It is a generic cpufreq driver for CPU0 frequency management. It 3It is a generic DT based cpufreq driver for frequency management. It supports
4supports both uniprocessor (UP) and symmetric multiprocessor (SMP) 4both uniprocessor (UP) and symmetric multiprocessor (SMP) systems which share
5systems which share clock and voltage across all CPUs. 5clock and voltage across all CPUs.
6 6
7Both required and optional properties listed below must be defined 7Both required and optional properties listed below must be defined
8under node /cpus/cpu@0. 8under node /cpus/cpu@0.
diff --git a/arch/arm/configs/mvebu_v7_defconfig b/arch/arm/configs/mvebu_v7_defconfig
index fdfda1fa9521..7309988b0f1f 100644
--- a/arch/arm/configs/mvebu_v7_defconfig
+++ b/arch/arm/configs/mvebu_v7_defconfig
@@ -32,7 +32,7 @@ CONFIG_ARM_ATAG_DTB_COMPAT=y
32CONFIG_CPU_IDLE=y 32CONFIG_CPU_IDLE=y
33CONFIG_ARM_MVEBU_V7_CPUIDLE=y 33CONFIG_ARM_MVEBU_V7_CPUIDLE=y
34CONFIG_CPU_FREQ=y 34CONFIG_CPU_FREQ=y
35CONFIG_CPUFREQ_GENERIC=y 35CONFIG_CPUFREQ_DT=y
36CONFIG_VFP=y 36CONFIG_VFP=y
37CONFIG_NET=y 37CONFIG_NET=y
38CONFIG_INET=y 38CONFIG_INET=y
diff --git a/arch/arm/mach-imx/imx27-dt.c b/arch/arm/mach-imx/imx27-dt.c
index 080e66c6a1d0..dc8f1a6f45f2 100644
--- a/arch/arm/mach-imx/imx27-dt.c
+++ b/arch/arm/mach-imx/imx27-dt.c
@@ -20,7 +20,7 @@
20 20
21static void __init imx27_dt_init(void) 21static void __init imx27_dt_init(void)
22{ 22{
23 struct platform_device_info devinfo = { .name = "cpufreq-cpu0", }; 23 struct platform_device_info devinfo = { .name = "cpufreq-dt", };
24 24
25 mxc_arch_reset_init_dt(); 25 mxc_arch_reset_init_dt();
26 26
diff --git a/arch/arm/mach-imx/mach-imx51.c b/arch/arm/mach-imx/mach-imx51.c
index c77deb3f0893..2c5fcaf8675b 100644
--- a/arch/arm/mach-imx/mach-imx51.c
+++ b/arch/arm/mach-imx/mach-imx51.c
@@ -51,7 +51,7 @@ static void __init imx51_ipu_mipi_setup(void)
51 51
52static void __init imx51_dt_init(void) 52static void __init imx51_dt_init(void)
53{ 53{
54 struct platform_device_info devinfo = { .name = "cpufreq-cpu0", }; 54 struct platform_device_info devinfo = { .name = "cpufreq-dt", };
55 55
56 mxc_arch_reset_init_dt(); 56 mxc_arch_reset_init_dt();
57 imx51_ipu_mipi_setup(); 57 imx51_ipu_mipi_setup();
diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c
index 8a70a51533fd..bbd8664d1bac 100644
--- a/arch/arm/mach-mvebu/pmsu.c
+++ b/arch/arm/mach-mvebu/pmsu.c
@@ -644,7 +644,7 @@ static int __init armada_xp_pmsu_cpufreq_init(void)
644 } 644 }
645 } 645 }
646 646
647 platform_device_register_simple("cpufreq-generic", -1, NULL, 0); 647 platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
648 return 0; 648 return 0;
649} 649}
650 650
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 828aee9ea6a8..58920bc8807b 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -282,7 +282,7 @@ static inline void omap_init_cpufreq(void)
282 if (!of_have_populated_dt()) 282 if (!of_have_populated_dt())
283 devinfo.name = "omap-cpufreq"; 283 devinfo.name = "omap-cpufreq";
284 else 284 else
285 devinfo.name = "cpufreq-cpu0"; 285 devinfo.name = "cpufreq-dt";
286 platform_device_register_full(&devinfo); 286 platform_device_register_full(&devinfo);
287} 287}
288 288
diff --git a/arch/arm/mach-shmobile/board-ape6evm-reference.c b/arch/arm/mach-shmobile/board-ape6evm-reference.c
index 2f7723e5fe91..0110751da511 100644
--- a/arch/arm/mach-shmobile/board-ape6evm-reference.c
+++ b/arch/arm/mach-shmobile/board-ape6evm-reference.c
@@ -50,7 +50,7 @@ static void __init ape6evm_add_standard_devices(void)
50 50
51 r8a73a4_add_dt_devices(); 51 r8a73a4_add_dt_devices();
52 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 52 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
53 platform_device_register_simple("cpufreq-cpu0", -1, NULL, 0); 53 platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
54} 54}
55 55
56static const char *ape6evm_boards_compat_dt[] __initdata = { 56static const char *ape6evm_boards_compat_dt[] __initdata = {
diff --git a/arch/arm/mach-shmobile/cpufreq.c b/arch/arm/mach-shmobile/cpufreq.c
index 8a24b2be46ae..57fbff024dcd 100644
--- a/arch/arm/mach-shmobile/cpufreq.c
+++ b/arch/arm/mach-shmobile/cpufreq.c
@@ -12,6 +12,6 @@
12 12
13int __init shmobile_cpufreq_init(void) 13int __init shmobile_cpufreq_init(void)
14{ 14{
15 platform_device_register_simple("cpufreq-cpu0", -1, NULL, 0); 15 platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
16 return 0; 16 return 0;
17} 17}
diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c
index 2c802ae9b241..15b990cd8c70 100644
--- a/arch/arm/mach-shmobile/setup-sh73a0.c
+++ b/arch/arm/mach-shmobile/setup-sh73a0.c
@@ -775,7 +775,7 @@ void __init sh73a0_add_early_devices(void)
775 775
776void __init sh73a0_add_standard_devices_dt(void) 776void __init sh73a0_add_standard_devices_dt(void)
777{ 777{
778 struct platform_device_info devinfo = { .name = "cpufreq-cpu0", .id = -1, }; 778 struct platform_device_info devinfo = { .name = "cpufreq-dt", .id = -1, };
779 779
780 /* clocks are setup late during boot in the case of DT */ 780 /* clocks are setup late during boot in the case of DT */
781 sh73a0_clock_init(); 781 sh73a0_clock_init();
@@ -784,7 +784,7 @@ void __init sh73a0_add_standard_devices_dt(void)
784 ARRAY_SIZE(sh73a0_devices_dt)); 784 ARRAY_SIZE(sh73a0_devices_dt));
785 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 785 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
786 786
787 /* Instantiate cpufreq-cpu0 */ 787 /* Instantiate cpufreq-dt */
788 platform_device_register_full(&devinfo); 788 platform_device_register_full(&devinfo);
789} 789}
790 790
diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c
index 31a6fa40ba37..ec03ec40e9c6 100644
--- a/arch/arm/mach-zynq/common.c
+++ b/arch/arm/mach-zynq/common.c
@@ -104,7 +104,7 @@ static int __init zynq_get_revision(void)
104 */ 104 */
105static void __init zynq_init_machine(void) 105static void __init zynq_init_machine(void)
106{ 106{
107 struct platform_device_info devinfo = { .name = "cpufreq-cpu0", }; 107 struct platform_device_info devinfo = { .name = "cpufreq-dt", };
108 struct soc_device_attribute *soc_dev_attr; 108 struct soc_device_attribute *soc_dev_attr;
109 struct soc_device *soc_dev; 109 struct soc_device *soc_dev;
110 struct device *parent = NULL; 110 struct device *parent = NULL;
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index ffe350f86bca..3489f8f5fada 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -183,14 +183,14 @@ config CPU_FREQ_GOV_CONSERVATIVE
183 183
184 If in doubt, say N. 184 If in doubt, say N.
185 185
186config GENERIC_CPUFREQ_CPU0 186config CPUFREQ_DT
187 tristate "Generic CPU0 cpufreq driver" 187 tristate "Generic DT based cpufreq driver"
188 depends on HAVE_CLK && OF 188 depends on HAVE_CLK && OF
189 # if CPU_THERMAL is on and THERMAL=m, CPU0 cannot be =y: 189 # if CPU_THERMAL is on and THERMAL=m, CPUFREQ_DT cannot be =y:
190 depends on !CPU_THERMAL || THERMAL 190 depends on !CPU_THERMAL || THERMAL
191 select PM_OPP 191 select PM_OPP
192 help 192 help
193 This adds a generic cpufreq driver for CPU0 frequency management. 193 This adds a generic DT based cpufreq driver for frequency management.
194 It supports both uniprocessor (UP) and symmetric multiprocessor (SMP) 194 It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
195 systems which share clock and voltage across all CPUs. 195 systems which share clock and voltage across all CPUs.
196 196
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 7364a538e056..48ed28b789f7 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -92,7 +92,7 @@ config ARM_EXYNOS_CPU_FREQ_BOOST_SW
92 92
93config ARM_HIGHBANK_CPUFREQ 93config ARM_HIGHBANK_CPUFREQ
94 tristate "Calxeda Highbank-based" 94 tristate "Calxeda Highbank-based"
95 depends on ARCH_HIGHBANK && GENERIC_CPUFREQ_CPU0 && REGULATOR 95 depends on ARCH_HIGHBANK && CPUFREQ_DT && REGULATOR
96 default m 96 default m
97 help 97 help
98 This adds the CPUFreq driver for Calxeda Highbank SoC 98 This adds the CPUFreq driver for Calxeda Highbank SoC
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index db6d9a2fea4d..40c53dc1937e 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
13obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o 13obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o
14obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o 14obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o
15 15
16obj-$(CONFIG_GENERIC_CPUFREQ_CPU0) += cpufreq-cpu0.o 16obj-$(CONFIG_CPUFREQ_DT) += cpufreq-dt.o
17 17
18################################################################################## 18##################################################################################
19# x86 drivers. 19# x86 drivers.
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
deleted file mode 100644
index 0d2172b07765..000000000000
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ /dev/null
@@ -1,248 +0,0 @@
1/*
2 * Copyright (C) 2012 Freescale Semiconductor, Inc.
3 *
4 * The OPP code in function cpu0_set_target() is reused from
5 * drivers/cpufreq/omap-cpufreq.c
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
14#include <linux/clk.h>
15#include <linux/cpu.h>
16#include <linux/cpu_cooling.h>
17#include <linux/cpufreq.h>
18#include <linux/cpumask.h>
19#include <linux/err.h>
20#include <linux/module.h>
21#include <linux/of.h>
22#include <linux/pm_opp.h>
23#include <linux/platform_device.h>
24#include <linux/regulator/consumer.h>
25#include <linux/slab.h>
26#include <linux/thermal.h>
27
28static unsigned int transition_latency;
29static unsigned int voltage_tolerance; /* in percentage */
30
31static struct device *cpu_dev;
32static struct clk *cpu_clk;
33static struct regulator *cpu_reg;
34static struct cpufreq_frequency_table *freq_table;
35static struct thermal_cooling_device *cdev;
36
37static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
38{
39 struct dev_pm_opp *opp;
40 unsigned long volt = 0, volt_old = 0, tol = 0;
41 unsigned int old_freq, new_freq;
42 long freq_Hz, freq_exact;
43 int ret;
44
45 freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
46 if (freq_Hz <= 0)
47 freq_Hz = freq_table[index].frequency * 1000;
48
49 freq_exact = freq_Hz;
50 new_freq = freq_Hz / 1000;
51 old_freq = clk_get_rate(cpu_clk) / 1000;
52
53 if (!IS_ERR(cpu_reg)) {
54 rcu_read_lock();
55 opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz);
56 if (IS_ERR(opp)) {
57 rcu_read_unlock();
58 pr_err("failed to find OPP for %ld\n", freq_Hz);
59 return PTR_ERR(opp);
60 }
61 volt = dev_pm_opp_get_voltage(opp);
62 rcu_read_unlock();
63 tol = volt * voltage_tolerance / 100;
64 volt_old = regulator_get_voltage(cpu_reg);
65 }
66
67 pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
68 old_freq / 1000, volt_old ? volt_old / 1000 : -1,
69 new_freq / 1000, volt ? volt / 1000 : -1);
70
71 /* scaling up? scale voltage before frequency */
72 if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
73 ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
74 if (ret) {
75 pr_err("failed to scale voltage up: %d\n", ret);
76 return ret;
77 }
78 }
79
80 ret = clk_set_rate(cpu_clk, freq_exact);
81 if (ret) {
82 pr_err("failed to set clock rate: %d\n", ret);
83 if (!IS_ERR(cpu_reg))
84 regulator_set_voltage_tol(cpu_reg, volt_old, tol);
85 return ret;
86 }
87
88 /* scaling down? scale voltage after frequency */
89 if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
90 ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
91 if (ret) {
92 pr_err("failed to scale voltage down: %d\n", ret);
93 clk_set_rate(cpu_clk, old_freq * 1000);
94 }
95 }
96
97 return ret;
98}
99
100static int cpu0_cpufreq_init(struct cpufreq_policy *policy)
101{
102 policy->clk = cpu_clk;
103 return cpufreq_generic_init(policy, freq_table, transition_latency);
104}
105
106static struct cpufreq_driver cpu0_cpufreq_driver = {
107 .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
108 .verify = cpufreq_generic_frequency_table_verify,
109 .target_index = cpu0_set_target,
110 .get = cpufreq_generic_get,
111 .init = cpu0_cpufreq_init,
112 .name = "generic_cpu0",
113 .attr = cpufreq_generic_attr,
114};
115
116static int cpu0_cpufreq_probe(struct platform_device *pdev)
117{
118 struct device_node *np;
119 int ret;
120
121 cpu_dev = get_cpu_device(0);
122 if (!cpu_dev) {
123 pr_err("failed to get cpu0 device\n");
124 return -ENODEV;
125 }
126
127 np = of_node_get(cpu_dev->of_node);
128 if (!np) {
129 pr_err("failed to find cpu0 node\n");
130 return -ENOENT;
131 }
132
133 cpu_reg = regulator_get_optional(cpu_dev, "cpu0");
134 if (IS_ERR(cpu_reg)) {
135 /*
136 * If cpu0 regulator supply node is present, but regulator is
137 * not yet registered, we should try defering probe.
138 */
139 if (PTR_ERR(cpu_reg) == -EPROBE_DEFER) {
140 dev_dbg(cpu_dev, "cpu0 regulator not ready, retry\n");
141 ret = -EPROBE_DEFER;
142 goto out_put_node;
143 }
144 pr_warn("failed to get cpu0 regulator: %ld\n",
145 PTR_ERR(cpu_reg));
146 }
147
148 cpu_clk = clk_get(cpu_dev, NULL);
149 if (IS_ERR(cpu_clk)) {
150 ret = PTR_ERR(cpu_clk);
151 pr_err("failed to get cpu0 clock: %d\n", ret);
152 goto out_put_reg;
153 }
154
155 /* OPPs might be populated at runtime, don't check for error here */
156 of_init_opp_table(cpu_dev);
157
158 ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
159 if (ret) {
160 pr_err("failed to init cpufreq table: %d\n", ret);
161 goto out_put_clk;
162 }
163
164 of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
165
166 if (of_property_read_u32(np, "clock-latency", &transition_latency))
167 transition_latency = CPUFREQ_ETERNAL;
168
169 if (!IS_ERR(cpu_reg)) {
170 struct dev_pm_opp *opp;
171 unsigned long min_uV, max_uV;
172 int i;
173
174 /*
175 * OPP is maintained in order of increasing frequency, and
176 * freq_table initialised from OPP is therefore sorted in the
177 * same order.
178 */
179 for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
180 ;
181 rcu_read_lock();
182 opp = dev_pm_opp_find_freq_exact(cpu_dev,
183 freq_table[0].frequency * 1000, true);
184 min_uV = dev_pm_opp_get_voltage(opp);
185 opp = dev_pm_opp_find_freq_exact(cpu_dev,
186 freq_table[i-1].frequency * 1000, true);
187 max_uV = dev_pm_opp_get_voltage(opp);
188 rcu_read_unlock();
189 ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV);
190 if (ret > 0)
191 transition_latency += ret * 1000;
192 }
193
194 ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
195 if (ret) {
196 pr_err("failed register driver: %d\n", ret);
197 goto out_free_table;
198 }
199
200 /*
201 * For now, just loading the cooling device;
202 * thermal DT code takes care of matching them.
203 */
204 if (of_find_property(np, "#cooling-cells", NULL)) {
205 cdev = of_cpufreq_cooling_register(np, cpu_present_mask);
206 if (IS_ERR(cdev))
207 pr_err("running cpufreq without cooling device: %ld\n",
208 PTR_ERR(cdev));
209 }
210
211 of_node_put(np);
212 return 0;
213
214out_free_table:
215 dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
216out_put_clk:
217 if (!IS_ERR(cpu_clk))
218 clk_put(cpu_clk);
219out_put_reg:
220 if (!IS_ERR(cpu_reg))
221 regulator_put(cpu_reg);
222out_put_node:
223 of_node_put(np);
224 return ret;
225}
226
227static int cpu0_cpufreq_remove(struct platform_device *pdev)
228{
229 cpufreq_cooling_unregister(cdev);
230 cpufreq_unregister_driver(&cpu0_cpufreq_driver);
231 dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
232
233 return 0;
234}
235
236static struct platform_driver cpu0_cpufreq_platdrv = {
237 .driver = {
238 .name = "cpufreq-cpu0",
239 .owner = THIS_MODULE,
240 },
241 .probe = cpu0_cpufreq_probe,
242 .remove = cpu0_cpufreq_remove,
243};
244module_platform_driver(cpu0_cpufreq_platdrv);
245
246MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
247MODULE_DESCRIPTION("Generic CPU0 cpufreq driver");
248MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
new file mode 100644
index 000000000000..6bbb8b913446
--- /dev/null
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -0,0 +1,364 @@
1/*
2 * Copyright (C) 2012 Freescale Semiconductor, Inc.
3 *
4 * Copyright (C) 2014 Linaro.
5 * Viresh Kumar <viresh.kumar@linaro.org>
6 *
7 * The OPP code in function set_target() is reused from
8 * drivers/cpufreq/omap-cpufreq.c
9 *
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.
13 */
14
15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16
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>
24#include <linux/of.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>
30
31struct private_data {
32 struct device *cpu_dev;
33 struct regulator *cpu_reg;
34 struct thermal_cooling_device *cdev;
35 unsigned int voltage_tolerance; /* in percentage */
36};
37
38static int set_target(struct cpufreq_policy *policy, unsigned int index)
39{
40 struct dev_pm_opp *opp;
41 struct cpufreq_frequency_table *freq_table = policy->freq_table;
42 struct clk *cpu_clk = policy->clk;
43 struct private_data *priv = policy->driver_data;
44 struct device *cpu_dev = priv->cpu_dev;
45 struct regulator *cpu_reg = priv->cpu_reg;
46 unsigned long volt = 0, volt_old = 0, tol = 0;
47 unsigned int old_freq, new_freq;
48 long freq_Hz, freq_exact;
49 int ret;
50
51 freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
52 if (freq_Hz <= 0)
53 freq_Hz = freq_table[index].frequency * 1000;
54
55 freq_exact = freq_Hz;
56 new_freq = freq_Hz / 1000;
57 old_freq = clk_get_rate(cpu_clk) / 1000;
58
59 if (!IS_ERR(cpu_reg)) {
60 rcu_read_lock();
61 opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz);
62 if (IS_ERR(opp)) {
63 rcu_read_unlock();
64 dev_err(cpu_dev, "failed to find OPP for %ld\n",
65 freq_Hz);
66 return PTR_ERR(opp);
67 }
68 volt = dev_pm_opp_get_voltage(opp);
69 rcu_read_unlock();
70 tol = volt * priv->voltage_tolerance / 100;
71 volt_old = regulator_get_voltage(cpu_reg);
72 }
73
74 dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
75 old_freq / 1000, volt_old ? volt_old / 1000 : -1,
76 new_freq / 1000, volt ? volt / 1000 : -1);
77
78 /* scaling up? scale voltage before frequency */
79 if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
80 ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
81 if (ret) {
82 dev_err(cpu_dev, "failed to scale voltage up: %d\n",
83 ret);
84 return ret;
85 }
86 }
87
88 ret = clk_set_rate(cpu_clk, freq_exact);
89 if (ret) {
90 dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
91 if (!IS_ERR(cpu_reg))
92 regulator_set_voltage_tol(cpu_reg, volt_old, tol);
93 return ret;
94 }
95
96 /* scaling down? scale voltage after frequency */
97 if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
98 ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
99 if (ret) {
100 dev_err(cpu_dev, "failed to scale voltage down: %d\n",
101 ret);
102 clk_set_rate(cpu_clk, old_freq * 1000);
103 }
104 }
105
106 return ret;
107}
108
109static int allocate_resources(int cpu, struct device **cdev,
110 struct regulator **creg, struct clk **cclk)
111{
112 struct device *cpu_dev;
113 struct regulator *cpu_reg;
114 struct clk *cpu_clk;
115 int ret = 0;
116 char *reg_cpu0 = "cpu0", *reg_cpu = "cpu", *reg;
117
118 cpu_dev = get_cpu_device(cpu);
119 if (!cpu_dev) {
120 pr_err("failed to get cpu%d device\n", cpu);
121 return -ENODEV;
122 }
123
124 /* Try "cpu0" for older DTs */
125 if (!cpu)
126 reg = reg_cpu0;
127 else
128 reg = reg_cpu;
129
130try_again:
131 cpu_reg = regulator_get_optional(cpu_dev, reg);
132 if (IS_ERR(cpu_reg)) {
133 /*
134 * If cpu's regulator supply node is present, but regulator is
135 * not yet registered, we should try defering probe.
136 */
137 if (PTR_ERR(cpu_reg) == -EPROBE_DEFER) {
138 dev_dbg(cpu_dev, "cpu%d regulator not ready, retry\n",
139 cpu);
140 return -EPROBE_DEFER;
141 }
142
143 /* Try with "cpu-supply" */
144 if (reg == reg_cpu0) {
145 reg = reg_cpu;
146 goto try_again;
147 }
148
149 dev_warn(cpu_dev, "failed to get cpu%d regulator: %ld\n",
150 cpu, PTR_ERR(cpu_reg));
151 }
152
153 cpu_clk = clk_get(cpu_dev, NULL);
154 if (IS_ERR(cpu_clk)) {
155 /* put regulator */
156 if (!IS_ERR(cpu_reg))
157 regulator_put(cpu_reg);
158
159 ret = PTR_ERR(cpu_clk);
160
161 /*
162 * If cpu's clk node is present, but clock is not yet
163 * registered, we should try defering probe.
164 */
165 if (ret == -EPROBE_DEFER)
166 dev_dbg(cpu_dev, "cpu%d clock not ready, retry\n", cpu);
167 else
168 dev_err(cpu_dev, "failed to get cpu%d clock: %d\n", ret,
169 cpu);
170 } else {
171 *cdev = cpu_dev;
172 *creg = cpu_reg;
173 *cclk = cpu_clk;
174 }
175
176 return ret;
177}
178
179static int cpufreq_init(struct cpufreq_policy *policy)
180{
181 struct cpufreq_frequency_table *freq_table;
182 struct thermal_cooling_device *cdev;
183 struct device_node *np;
184 struct private_data *priv;
185 struct device *cpu_dev;
186 struct regulator *cpu_reg;
187 struct clk *cpu_clk;
188 unsigned int transition_latency;
189 int ret;
190
191 ret = allocate_resources(policy->cpu, &cpu_dev, &cpu_reg, &cpu_clk);
192 if (ret) {
193 pr_err("%s: Failed to allocate resources\n: %d", __func__, ret);
194 return ret;
195 }
196
197 np = of_node_get(cpu_dev->of_node);
198 if (!np) {
199 dev_err(cpu_dev, "failed to find cpu%d node\n", policy->cpu);
200 ret = -ENOENT;
201 goto out_put_reg_clk;
202 }
203
204 /* OPPs might be populated at runtime, don't check for error here */
205 of_init_opp_table(cpu_dev);
206
207 ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
208 if (ret) {
209 dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
210 goto out_put_node;
211 }
212
213 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
214 if (!priv) {
215 ret = -ENOMEM;
216 goto out_free_table;
217 }
218
219 of_property_read_u32(np, "voltage-tolerance", &priv->voltage_tolerance);
220
221 if (of_property_read_u32(np, "clock-latency", &transition_latency))
222 transition_latency = CPUFREQ_ETERNAL;
223
224 if (!IS_ERR(cpu_reg)) {
225 struct dev_pm_opp *opp;
226 unsigned long min_uV, max_uV;
227 int i;
228
229 /*
230 * OPP is maintained in order of increasing frequency, and
231 * freq_table initialised from OPP is therefore sorted in the
232 * same order.
233 */
234 for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
235 ;
236 rcu_read_lock();
237 opp = dev_pm_opp_find_freq_exact(cpu_dev,
238 freq_table[0].frequency * 1000, true);
239 min_uV = dev_pm_opp_get_voltage(opp);
240 opp = dev_pm_opp_find_freq_exact(cpu_dev,
241 freq_table[i-1].frequency * 1000, true);
242 max_uV = dev_pm_opp_get_voltage(opp);
243 rcu_read_unlock();
244 ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV);
245 if (ret > 0)
246 transition_latency += ret * 1000;
247 }
248
249 /*
250 * For now, just loading the cooling device;
251 * thermal DT code takes care of matching them.
252 */
253 if (of_find_property(np, "#cooling-cells", NULL)) {
254 cdev = of_cpufreq_cooling_register(np, cpu_present_mask);
255 if (IS_ERR(cdev))
256 dev_err(cpu_dev,
257 "running cpufreq without cooling device: %ld\n",
258 PTR_ERR(cdev));
259 else
260 priv->cdev = cdev;
261 }
262
263 priv->cpu_dev = cpu_dev;
264 priv->cpu_reg = cpu_reg;
265 policy->driver_data = priv;
266
267 policy->clk = cpu_clk;
268 ret = cpufreq_generic_init(policy, freq_table, transition_latency);
269 if (ret)
270 goto out_cooling_unregister;
271
272 of_node_put(np);
273
274 return 0;
275
276out_cooling_unregister:
277 cpufreq_cooling_unregister(priv->cdev);
278 kfree(priv);
279out_free_table:
280 dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
281out_put_node:
282 of_node_put(np);
283out_put_reg_clk:
284 clk_put(cpu_clk);
285 if (!IS_ERR(cpu_reg))
286 regulator_put(cpu_reg);
287
288 return ret;
289}
290
291static int cpufreq_exit(struct cpufreq_policy *policy)
292{
293 struct private_data *priv = policy->driver_data;
294
295 cpufreq_cooling_unregister(priv->cdev);
296 dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
297 clk_put(policy->clk);
298 if (!IS_ERR(priv->cpu_reg))
299 regulator_put(priv->cpu_reg);
300 kfree(priv);
301
302 return 0;
303}
304
305static struct cpufreq_driver dt_cpufreq_driver = {
306 .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
307 .verify = cpufreq_generic_frequency_table_verify,
308 .target_index = set_target,
309 .get = cpufreq_generic_get,
310 .init = cpufreq_init,
311 .exit = cpufreq_exit,
312 .name = "cpufreq-dt",
313 .attr = cpufreq_generic_attr,
314};
315
316static int dt_cpufreq_probe(struct platform_device *pdev)
317{
318 struct device *cpu_dev;
319 struct regulator *cpu_reg;
320 struct clk *cpu_clk;
321 int ret;
322
323 /*
324 * All per-cluster (CPUs sharing clock/voltages) initialization is done
325 * from ->init(). In probe(), we just need to make sure that clk and
326 * regulators are available. Else defer probe and retry.
327 *
328 * FIXME: Is checking this only for CPU0 sufficient ?
329 */
330 ret = allocate_resources(0, &cpu_dev, &cpu_reg, &cpu_clk);
331 if (ret)
332 return ret;
333
334 clk_put(cpu_clk);
335 if (!IS_ERR(cpu_reg))
336 regulator_put(cpu_reg);
337
338 ret = cpufreq_register_driver(&dt_cpufreq_driver);
339 if (ret)
340 dev_err(cpu_dev, "failed register driver: %d\n", ret);
341
342 return ret;
343}
344
345static int dt_cpufreq_remove(struct platform_device *pdev)
346{
347 cpufreq_unregister_driver(&dt_cpufreq_driver);
348 return 0;
349}
350
351static struct platform_driver dt_cpufreq_platdrv = {
352 .driver = {
353 .name = "cpufreq-dt",
354 .owner = THIS_MODULE,
355 },
356 .probe = dt_cpufreq_probe,
357 .remove = dt_cpufreq_remove,
358};
359module_platform_driver(dt_cpufreq_platdrv);
360
361MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
362MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
363MODULE_DESCRIPTION("Generic cpufreq driver");
364MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 61190f6b4829..24bf76fba141 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -437,7 +437,7 @@ static struct cpufreq_governor *__find_governor(const char *str_governor)
437 struct cpufreq_governor *t; 437 struct cpufreq_governor *t;
438 438
439 list_for_each_entry(t, &cpufreq_governor_list, governor_list) 439 list_for_each_entry(t, &cpufreq_governor_list, governor_list)
440 if (!strnicmp(str_governor, t->name, CPUFREQ_NAME_LEN)) 440 if (!strncasecmp(str_governor, t->name, CPUFREQ_NAME_LEN))
441 return t; 441 return t;
442 442
443 return NULL; 443 return NULL;
@@ -455,10 +455,10 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
455 goto out; 455 goto out;
456 456
457 if (cpufreq_driver->setpolicy) { 457 if (cpufreq_driver->setpolicy) {
458 if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { 458 if (!strncasecmp(str_governor, "performance", CPUFREQ_NAME_LEN)) {
459 *policy = CPUFREQ_POLICY_PERFORMANCE; 459 *policy = CPUFREQ_POLICY_PERFORMANCE;
460 err = 0; 460 err = 0;
461 } else if (!strnicmp(str_governor, "powersave", 461 } else if (!strncasecmp(str_governor, "powersave",
462 CPUFREQ_NAME_LEN)) { 462 CPUFREQ_NAME_LEN)) {
463 *policy = CPUFREQ_POLICY_POWERSAVE; 463 *policy = CPUFREQ_POLICY_POWERSAVE;
464 err = 0; 464 err = 0;
@@ -1382,7 +1382,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
1382 if (!cpufreq_suspended) 1382 if (!cpufreq_suspended)
1383 pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n", 1383 pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
1384 __func__, new_cpu, cpu); 1384 __func__, new_cpu, cpu);
1385 } else if (cpufreq_driver->stop_cpu && cpufreq_driver->setpolicy) { 1385 } else if (cpufreq_driver->stop_cpu) {
1386 cpufreq_driver->stop_cpu(policy); 1386 cpufreq_driver->stop_cpu(policy);
1387 } 1387 }
1388 1388
diff --git a/drivers/cpufreq/exynos4210-cpufreq.c b/drivers/cpufreq/exynos4210-cpufreq.c
index 61a54310a1b9..843ec824fd91 100644
--- a/drivers/cpufreq/exynos4210-cpufreq.c
+++ b/drivers/cpufreq/exynos4210-cpufreq.c
@@ -127,7 +127,7 @@ int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
127 * dependencies on platform headers. It is necessary to enable 127 * dependencies on platform headers. It is necessary to enable
128 * Exynos multi-platform support and will be removed together with 128 * Exynos multi-platform support and will be removed together with
129 * this whole driver as soon as Exynos gets migrated to use 129 * this whole driver as soon as Exynos gets migrated to use
130 * cpufreq-cpu0 driver. 130 * cpufreq-dt driver.
131 */ 131 */
132 np = of_find_compatible_node(NULL, NULL, "samsung,exynos4210-clock"); 132 np = of_find_compatible_node(NULL, NULL, "samsung,exynos4210-clock");
133 if (!np) { 133 if (!np) {
diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c
index 351a2074cfea..9e78a850e29f 100644
--- a/drivers/cpufreq/exynos4x12-cpufreq.c
+++ b/drivers/cpufreq/exynos4x12-cpufreq.c
@@ -174,7 +174,7 @@ int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
174 * dependencies on platform headers. It is necessary to enable 174 * dependencies on platform headers. It is necessary to enable
175 * Exynos multi-platform support and will be removed together with 175 * Exynos multi-platform support and will be removed together with
176 * this whole driver as soon as Exynos gets migrated to use 176 * this whole driver as soon as Exynos gets migrated to use
177 * cpufreq-cpu0 driver. 177 * cpufreq-dt driver.
178 */ 178 */
179 np = of_find_compatible_node(NULL, NULL, "samsung,exynos4412-clock"); 179 np = of_find_compatible_node(NULL, NULL, "samsung,exynos4412-clock");
180 if (!np) { 180 if (!np) {
diff --git a/drivers/cpufreq/exynos5250-cpufreq.c b/drivers/cpufreq/exynos5250-cpufreq.c
index c91ce69dc631..3eafdc7ba787 100644
--- a/drivers/cpufreq/exynos5250-cpufreq.c
+++ b/drivers/cpufreq/exynos5250-cpufreq.c
@@ -153,7 +153,7 @@ int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
153 * dependencies on platform headers. It is necessary to enable 153 * dependencies on platform headers. It is necessary to enable
154 * Exynos multi-platform support and will be removed together with 154 * Exynos multi-platform support and will be removed together with
155 * this whole driver as soon as Exynos gets migrated to use 155 * this whole driver as soon as Exynos gets migrated to use
156 * cpufreq-cpu0 driver. 156 * cpufreq-dt driver.
157 */ 157 */
158 np = of_find_compatible_node(NULL, NULL, "samsung,exynos5250-clock"); 158 np = of_find_compatible_node(NULL, NULL, "samsung,exynos5250-clock");
159 if (!np) { 159 if (!np) {
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
index bf8902a0866d..ec399ad2f059 100644
--- a/drivers/cpufreq/highbank-cpufreq.c
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -6,7 +6,7 @@
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 * 7 *
8 * This driver provides the clk notifier callbacks that are used when 8 * This driver provides the clk notifier callbacks that are used when
9 * the cpufreq-cpu0 driver changes to frequency to alert the highbank 9 * the cpufreq-dt driver changes to frequency to alert the highbank
10 * EnergyCore Management Engine (ECME) about the need to change 10 * EnergyCore Management Engine (ECME) about the need to change
11 * voltage. The ECME interfaces with the actual voltage regulators. 11 * voltage. The ECME interfaces with the actual voltage regulators.
12 */ 12 */
@@ -60,7 +60,7 @@ static struct notifier_block hb_cpufreq_clk_nb = {
60 60
61static int hb_cpufreq_driver_init(void) 61static int hb_cpufreq_driver_init(void)
62{ 62{
63 struct platform_device_info devinfo = { .name = "cpufreq-cpu0", }; 63 struct platform_device_info devinfo = { .name = "cpufreq-dt", };
64 struct device *cpu_dev; 64 struct device *cpu_dev;
65 struct clk *cpu_clk; 65 struct clk *cpu_clk;
66 struct device_node *np; 66 struct device_node *np;
@@ -95,7 +95,7 @@ static int hb_cpufreq_driver_init(void)
95 goto out_put_node; 95 goto out_put_node;
96 } 96 }
97 97
98 /* Instantiate cpufreq-cpu0 */ 98 /* Instantiate cpufreq-dt */
99 platform_device_register_full(&devinfo); 99 platform_device_register_full(&devinfo);
100 100
101out_put_node: 101out_put_node:
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c
index 379c0837f5a9..2dfd4fdb5a52 100644
--- a/drivers/cpufreq/powernv-cpufreq.c
+++ b/drivers/cpufreq/powernv-cpufreq.c
@@ -26,6 +26,7 @@
26#include <linux/cpufreq.h> 26#include <linux/cpufreq.h>
27#include <linux/smp.h> 27#include <linux/smp.h>
28#include <linux/of.h> 28#include <linux/of.h>
29#include <linux/reboot.h>
29 30
30#include <asm/cputhreads.h> 31#include <asm/cputhreads.h>
31#include <asm/firmware.h> 32#include <asm/firmware.h>
@@ -35,6 +36,7 @@
35#define POWERNV_MAX_PSTATES 256 36#define POWERNV_MAX_PSTATES 256
36 37
37static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; 38static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
39static bool rebooting;
38 40
39/* 41/*
40 * Note: The set of pstates consists of contiguous integers, the 42 * Note: The set of pstates consists of contiguous integers, the
@@ -284,6 +286,15 @@ static void set_pstate(void *freq_data)
284} 286}
285 287
286/* 288/*
289 * get_nominal_index: Returns the index corresponding to the nominal
290 * pstate in the cpufreq table
291 */
292static inline unsigned int get_nominal_index(void)
293{
294 return powernv_pstate_info.max - powernv_pstate_info.nominal;
295}
296
297/*
287 * powernv_cpufreq_target_index: Sets the frequency corresponding to 298 * powernv_cpufreq_target_index: Sets the frequency corresponding to
288 * the cpufreq table entry indexed by new_index on the cpus in the 299 * the cpufreq table entry indexed by new_index on the cpus in the
289 * mask policy->cpus 300 * mask policy->cpus
@@ -293,6 +304,9 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy,
293{ 304{
294 struct powernv_smp_call_data freq_data; 305 struct powernv_smp_call_data freq_data;
295 306
307 if (unlikely(rebooting) && new_index != get_nominal_index())
308 return 0;
309
296 freq_data.pstate_id = powernv_freqs[new_index].driver_data; 310 freq_data.pstate_id = powernv_freqs[new_index].driver_data;
297 311
298 /* 312 /*
@@ -317,6 +331,33 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy)
317 return cpufreq_table_validate_and_show(policy, powernv_freqs); 331 return cpufreq_table_validate_and_show(policy, powernv_freqs);
318} 332}
319 333
334static int powernv_cpufreq_reboot_notifier(struct notifier_block *nb,
335 unsigned long action, void *unused)
336{
337 int cpu;
338 struct cpufreq_policy cpu_policy;
339
340 rebooting = true;
341 for_each_online_cpu(cpu) {
342 cpufreq_get_policy(&cpu_policy, cpu);
343 powernv_cpufreq_target_index(&cpu_policy, get_nominal_index());
344 }
345
346 return NOTIFY_DONE;
347}
348
349static struct notifier_block powernv_cpufreq_reboot_nb = {
350 .notifier_call = powernv_cpufreq_reboot_notifier,
351};
352
353static void powernv_cpufreq_stop_cpu(struct cpufreq_policy *policy)
354{
355 struct powernv_smp_call_data freq_data;
356
357 freq_data.pstate_id = powernv_pstate_info.min;
358 smp_call_function_single(policy->cpu, set_pstate, &freq_data, 1);
359}
360
320static struct cpufreq_driver powernv_cpufreq_driver = { 361static struct cpufreq_driver powernv_cpufreq_driver = {
321 .name = "powernv-cpufreq", 362 .name = "powernv-cpufreq",
322 .flags = CPUFREQ_CONST_LOOPS, 363 .flags = CPUFREQ_CONST_LOOPS,
@@ -324,6 +365,7 @@ static struct cpufreq_driver powernv_cpufreq_driver = {
324 .verify = cpufreq_generic_frequency_table_verify, 365 .verify = cpufreq_generic_frequency_table_verify,
325 .target_index = powernv_cpufreq_target_index, 366 .target_index = powernv_cpufreq_target_index,
326 .get = powernv_cpufreq_get, 367 .get = powernv_cpufreq_get,
368 .stop_cpu = powernv_cpufreq_stop_cpu,
327 .attr = powernv_cpu_freq_attr, 369 .attr = powernv_cpu_freq_attr,
328}; 370};
329 371
@@ -342,12 +384,14 @@ static int __init powernv_cpufreq_init(void)
342 return rc; 384 return rc;
343 } 385 }
344 386
387 register_reboot_notifier(&powernv_cpufreq_reboot_nb);
345 return cpufreq_register_driver(&powernv_cpufreq_driver); 388 return cpufreq_register_driver(&powernv_cpufreq_driver);
346} 389}
347module_init(powernv_cpufreq_init); 390module_init(powernv_cpufreq_init);
348 391
349static void __exit powernv_cpufreq_exit(void) 392static void __exit powernv_cpufreq_exit(void)
350{ 393{
394 unregister_reboot_notifier(&powernv_cpufreq_reboot_nb);
351 cpufreq_unregister_driver(&powernv_cpufreq_driver); 395 cpufreq_unregister_driver(&powernv_cpufreq_driver);
352} 396}
353module_exit(powernv_cpufreq_exit); 397module_exit(powernv_cpufreq_exit);
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c
index 3607070797af..bee5df7794d3 100644
--- a/drivers/cpufreq/ppc-corenet-cpufreq.c
+++ b/drivers/cpufreq/ppc-corenet-cpufreq.c
@@ -199,7 +199,6 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
199 } 199 }
200 200
201 data->table = table; 201 data->table = table;
202 per_cpu(cpu_data, cpu) = data;
203 202
204 /* update ->cpus if we have cluster, no harm if not */ 203 /* update ->cpus if we have cluster, no harm if not */
205 cpumask_copy(policy->cpus, per_cpu(cpu_mask, cpu)); 204 cpumask_copy(policy->cpus, per_cpu(cpu_mask, cpu));
diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c
index 3f9791f07b8e..567caa6313ff 100644
--- a/drivers/cpufreq/s5pv210-cpufreq.c
+++ b/drivers/cpufreq/s5pv210-cpufreq.c
@@ -597,7 +597,7 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev)
597 * and dependencies on platform headers. It is necessary to enable 597 * and dependencies on platform headers. It is necessary to enable
598 * S5PV210 multi-platform support and will be removed together with 598 * S5PV210 multi-platform support and will be removed together with
599 * this whole driver as soon as S5PV210 gets migrated to use 599 * this whole driver as soon as S5PV210 gets migrated to use
600 * cpufreq-cpu0 driver. 600 * cpufreq-dt driver.
601 */ 601 */
602 np = of_find_compatible_node(NULL, NULL, "samsung,s5pv210-clock"); 602 np = of_find_compatible_node(NULL, NULL, "samsung,s5pv210-clock");
603 if (!np) { 603 if (!np) {
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 7d1955afa62c..138336b6bb04 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -112,6 +112,9 @@ struct cpufreq_policy {
112 spinlock_t transition_lock; 112 spinlock_t transition_lock;
113 wait_queue_head_t transition_wait; 113 wait_queue_head_t transition_wait;
114 struct task_struct *transition_task; /* Task which is doing the transition */ 114 struct task_struct *transition_task; /* Task which is doing the transition */
115
116 /* For cpufreq driver's internal use */
117 void *driver_data;
115}; 118};
116 119
117/* Only for ACPI */ 120/* Only for ACPI */