aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Kconfig4
-rw-r--r--arch/arm/mach-exynos4/Makefile1
-rw-r--r--arch/arm/mach-s3c64xx/Makefile4
-rw-r--r--arch/arm/mach-s5pv210/Makefile1
-rw-r--r--drivers/cpufreq/Kconfig5
-rw-r--r--drivers/cpufreq/Kconfig.arm32
-rw-r--r--drivers/cpufreq/Makefile8
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c2
-rw-r--r--drivers/cpufreq/exynos4210-cpufreq.c (renamed from arch/arm/mach-exynos4/cpufreq.c)9
-rw-r--r--drivers/cpufreq/s3c64xx-cpufreq.c (renamed from arch/arm/mach-s3c64xx/cpufreq.c)11
-rw-r--r--drivers/cpufreq/s5pv210-cpufreq.c (renamed from arch/arm/mach-s5pv210/cpufreq.c)210
11 files changed, 241 insertions, 46 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1478c6171b00..83a7aa2ca57a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1895,10 +1895,6 @@ config CPU_FREQ_PXA
1895 default y 1895 default y
1896 select CPU_FREQ_DEFAULT_GOV_USERSPACE 1896 select CPU_FREQ_DEFAULT_GOV_USERSPACE
1897 1897
1898config CPU_FREQ_S3C64XX
1899 bool "CPUfreq support for Samsung S3C64XX CPUs"
1900 depends on CPU_FREQ && CPU_S3C6410
1901
1902config CPU_FREQ_S3C 1898config CPU_FREQ_S3C
1903 bool 1899 bool
1904 help 1900 help
diff --git a/arch/arm/mach-exynos4/Makefile b/arch/arm/mach-exynos4/Makefile
index 60fe5ecf3599..1366995d8c2c 100644
--- a/arch/arm/mach-exynos4/Makefile
+++ b/arch/arm/mach-exynos4/Makefile
@@ -15,7 +15,6 @@ obj- :=
15obj-$(CONFIG_CPU_EXYNOS4210) += cpu.o init.o clock.o irq-combiner.o 15obj-$(CONFIG_CPU_EXYNOS4210) += cpu.o init.o clock.o irq-combiner.o
16obj-$(CONFIG_CPU_EXYNOS4210) += setup-i2c0.o irq-eint.o dma.o 16obj-$(CONFIG_CPU_EXYNOS4210) += setup-i2c0.o irq-eint.o dma.o
17obj-$(CONFIG_PM) += pm.o sleep.o 17obj-$(CONFIG_PM) += pm.o sleep.o
18obj-$(CONFIG_CPU_FREQ) += cpufreq.o
19obj-$(CONFIG_CPU_IDLE) += cpuidle.o 18obj-$(CONFIG_CPU_IDLE) += cpuidle.o
20 19
21obj-$(CONFIG_SMP) += platsmp.o headsmp.o 20obj-$(CONFIG_SMP) += platsmp.o headsmp.o
diff --git a/arch/arm/mach-s3c64xx/Makefile b/arch/arm/mach-s3c64xx/Makefile
index 4657363f0674..f5a7144a052f 100644
--- a/arch/arm/mach-s3c64xx/Makefile
+++ b/arch/arm/mach-s3c64xx/Makefile
@@ -23,10 +23,6 @@ obj-$(CONFIG_CPU_S3C6410) += s3c6410.o
23obj-y += irq.o 23obj-y += irq.o
24obj-y += irq-eint.o 24obj-y += irq-eint.o
25 25
26# CPU frequency scaling
27
28obj-$(CONFIG_CPU_FREQ_S3C64XX) += cpufreq.o
29
30# DMA support 26# DMA support
31 27
32obj-$(CONFIG_S3C64XX_DMA) += dma.o 28obj-$(CONFIG_S3C64XX_DMA) += dma.o
diff --git a/arch/arm/mach-s5pv210/Makefile b/arch/arm/mach-s5pv210/Makefile
index 50907aca006c..599a3c0e8f6c 100644
--- a/arch/arm/mach-s5pv210/Makefile
+++ b/arch/arm/mach-s5pv210/Makefile
@@ -15,7 +15,6 @@ obj- :=
15obj-$(CONFIG_CPU_S5PV210) += cpu.o init.o clock.o dma.o 15obj-$(CONFIG_CPU_S5PV210) += cpu.o init.o clock.o dma.o
16obj-$(CONFIG_CPU_S5PV210) += setup-i2c0.o 16obj-$(CONFIG_CPU_S5PV210) += setup-i2c0.o
17obj-$(CONFIG_S5PV210_PM) += pm.o sleep.o 17obj-$(CONFIG_S5PV210_PM) += pm.o sleep.o
18obj-$(CONFIG_CPU_FREQ) += cpufreq.o
19 18
20# machine support 19# machine support
21 20
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 9fb84853d8e3..e898215b88af 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -184,5 +184,10 @@ depends on X86
184source "drivers/cpufreq/Kconfig.x86" 184source "drivers/cpufreq/Kconfig.x86"
185endmenu 185endmenu
186 186
187menu "ARM CPU frequency scaling drivers"
188depends on ARM
189source "drivers/cpufreq/Kconfig.arm"
190endmenu
191
187endif 192endif
188endmenu 193endmenu
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
new file mode 100644
index 000000000000..72a0044c1baa
--- /dev/null
+++ b/drivers/cpufreq/Kconfig.arm
@@ -0,0 +1,32 @@
1#
2# ARM CPU Frequency scaling drivers
3#
4
5config ARM_S3C64XX_CPUFREQ
6 bool "Samsung S3C64XX"
7 depends on CPU_S3C6410
8 default y
9 help
10 This adds the CPUFreq driver for Samsung S3C6410 SoC.
11
12 If in doubt, say N.
13
14config ARM_S5PV210_CPUFREQ
15 bool "Samsung S5PV210 and S5PC110"
16 depends on CPU_S5PV210
17 default y
18 help
19 This adds the CPUFreq driver for Samsung S5PV210 and
20 S5PC110 SoCs.
21
22 If in doubt, say N.
23
24config ARM_EXYNOS4210_CPUFREQ
25 bool "Samsung EXYNOS4210"
26 depends on CPU_EXYNOS4210
27 default y
28 help
29 This adds the CPUFreq driver for Samsung EXYNOS4210
30 SoC (S5PV310 or S5PC210).
31
32 If in doubt, say N.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index e2fc2d21fa61..ab75e573c69f 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o
13# CPUfreq cross-arch helpers 13# CPUfreq cross-arch helpers
14obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o 14obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o
15 15
16##################################################################################d 16##################################################################################
17# x86 drivers. 17# x86 drivers.
18# Link order matters. K8 is preferred to ACPI because of firmware bugs in early 18# Link order matters. K8 is preferred to ACPI because of firmware bugs in early
19# K8 systems. ACPI is preferred to all other hardware-specific drivers. 19# K8 systems. ACPI is preferred to all other hardware-specific drivers.
@@ -37,7 +37,9 @@ obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
37obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o 37obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
38obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o 38obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
39 39
40##################################################################################d 40##################################################################################
41
42# ARM SoC drivers 41# ARM SoC drivers
43obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o 42obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o
43obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o
44obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o
45obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 596d5dd32f41..56c6c6b4eb4d 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -655,7 +655,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
655 acpi_processor_notify_smm(THIS_MODULE); 655 acpi_processor_notify_smm(THIS_MODULE);
656 656
657 /* Check for APERF/MPERF support in hardware */ 657 /* Check for APERF/MPERF support in hardware */
658 if (cpu_has(c, X86_FEATURE_APERFMPERF)) 658 if (boot_cpu_has(X86_FEATURE_APERFMPERF))
659 acpi_cpufreq_driver.getavg = cpufreq_get_measured_perf; 659 acpi_cpufreq_driver.getavg = cpufreq_get_measured_perf;
660 660
661 pr_debug("CPU%u - ACPI performance management activated.\n", cpu); 661 pr_debug("CPU%u - ACPI performance management activated.\n", cpu);
diff --git a/arch/arm/mach-exynos4/cpufreq.c b/drivers/cpufreq/exynos4210-cpufreq.c
index a1bd258f0c4d..b7c3a84c4cfa 100644
--- a/arch/arm/mach-exynos4/cpufreq.c
+++ b/drivers/cpufreq/exynos4210-cpufreq.c
@@ -1,5 +1,4 @@
1/* linux/arch/arm/mach-exynos4/cpufreq.c 1/*
2 *
3 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. 2 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com 3 * http://www.samsung.com
5 * 4 *
@@ -192,17 +191,17 @@ static unsigned int exynos4_apll_pms_table[CPUFREQ_LEVEL_END] = {
192 ((200 << 16) | (6 << 8) | 4), 191 ((200 << 16) | (6 << 8) | 4),
193}; 192};
194 193
195int exynos4_verify_speed(struct cpufreq_policy *policy) 194static int exynos4_verify_speed(struct cpufreq_policy *policy)
196{ 195{
197 return cpufreq_frequency_table_verify(policy, exynos4_freq_table); 196 return cpufreq_frequency_table_verify(policy, exynos4_freq_table);
198} 197}
199 198
200unsigned int exynos4_getspeed(unsigned int cpu) 199static unsigned int exynos4_getspeed(unsigned int cpu)
201{ 200{
202 return clk_get_rate(cpu_clk) / 1000; 201 return clk_get_rate(cpu_clk) / 1000;
203} 202}
204 203
205void exynos4_set_clkdiv(unsigned int div_index) 204static void exynos4_set_clkdiv(unsigned int div_index)
206{ 205{
207 unsigned int tmp; 206 unsigned int tmp;
208 207
diff --git a/arch/arm/mach-s3c64xx/cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c
index 4375b97588b8..b8d1d205e1ef 100644
--- a/arch/arm/mach-s3c64xx/cpufreq.c
+++ b/drivers/cpufreq/s3c64xx-cpufreq.c
@@ -1,5 +1,4 @@
1/* linux/arch/arm/plat-s3c64xx/cpufreq.c 1/*
2 *
3 * Copyright 2009 Wolfson Microelectronics plc 2 * Copyright 2009 Wolfson Microelectronics plc
4 * 3 *
5 * S3C64xx CPUfreq Support 4 * S3C64xx CPUfreq Support
@@ -32,11 +31,14 @@ static struct s3c64xx_dvfs s3c64xx_dvfs_table[] = {
32 [1] = { 1050000, 1150000 }, 31 [1] = { 1050000, 1150000 },
33 [2] = { 1100000, 1150000 }, 32 [2] = { 1100000, 1150000 },
34 [3] = { 1200000, 1350000 }, 33 [3] = { 1200000, 1350000 },
34 [4] = { 1300000, 1350000 },
35}; 35};
36 36
37static struct cpufreq_frequency_table s3c64xx_freq_table[] = { 37static struct cpufreq_frequency_table s3c64xx_freq_table[] = {
38 { 0, 66000 }, 38 { 0, 66000 },
39 { 0, 100000 },
39 { 0, 133000 }, 40 { 0, 133000 },
41 { 1, 200000 },
40 { 1, 222000 }, 42 { 1, 222000 },
41 { 1, 266000 }, 43 { 1, 266000 },
42 { 2, 333000 }, 44 { 2, 333000 },
@@ -44,6 +46,7 @@ static struct cpufreq_frequency_table s3c64xx_freq_table[] = {
44 { 2, 532000 }, 46 { 2, 532000 },
45 { 2, 533000 }, 47 { 2, 533000 },
46 { 3, 667000 }, 48 { 3, 667000 },
49 { 4, 800000 },
47 { 0, CPUFREQ_TABLE_END }, 50 { 0, CPUFREQ_TABLE_END },
48}; 51};
49#endif 52#endif
@@ -111,6 +114,8 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
111 goto err; 114 goto err;
112 } 115 }
113 116
117 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
118
114#ifdef CONFIG_REGULATOR 119#ifdef CONFIG_REGULATOR
115 if (vddarm && freqs.new < freqs.old) { 120 if (vddarm && freqs.new < freqs.old) {
116 ret = regulator_set_voltage(vddarm, 121 ret = regulator_set_voltage(vddarm,
@@ -124,8 +129,6 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
124 } 129 }
125#endif 130#endif
126 131
127 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
128
129 pr_debug("cpufreq: Set actual frequency %lukHz\n", 132 pr_debug("cpufreq: Set actual frequency %lukHz\n",
130 clk_get_rate(armclk) / 1000); 133 clk_get_rate(armclk) / 1000);
131 134
diff --git a/arch/arm/mach-s5pv210/cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c
index 153af8b359ec..a484aaea9809 100644
--- a/arch/arm/mach-s5pv210/cpufreq.c
+++ b/drivers/cpufreq/s5pv210-cpufreq.c
@@ -1,5 +1,4 @@
1/* linux/arch/arm/mach-s5pv210/cpufreq.c 1/*
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd. 2 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com 3 * http://www.samsung.com
5 * 4 *
@@ -17,6 +16,9 @@
17#include <linux/clk.h> 16#include <linux/clk.h>
18#include <linux/io.h> 17#include <linux/io.h>
19#include <linux/cpufreq.h> 18#include <linux/cpufreq.h>
19#include <linux/reboot.h>
20#include <linux/regulator/consumer.h>
21#include <linux/suspend.h>
20 22
21#include <mach/map.h> 23#include <mach/map.h>
22#include <mach/regs-clock.h> 24#include <mach/regs-clock.h>
@@ -25,11 +27,27 @@ static struct clk *cpu_clk;
25static struct clk *dmc0_clk; 27static struct clk *dmc0_clk;
26static struct clk *dmc1_clk; 28static struct clk *dmc1_clk;
27static struct cpufreq_freqs freqs; 29static struct cpufreq_freqs freqs;
30static DEFINE_MUTEX(set_freq_lock);
28 31
29/* APLL M,P,S values for 1G/800Mhz */ 32/* APLL M,P,S values for 1G/800Mhz */
30#define APLL_VAL_1000 ((1 << 31) | (125 << 16) | (3 << 8) | 1) 33#define APLL_VAL_1000 ((1 << 31) | (125 << 16) | (3 << 8) | 1)
31#define APLL_VAL_800 ((1 << 31) | (100 << 16) | (3 << 8) | 1) 34#define APLL_VAL_800 ((1 << 31) | (100 << 16) | (3 << 8) | 1)
32 35
36/* Use 800MHz when entering sleep mode */
37#define SLEEP_FREQ (800 * 1000)
38
39/*
40 * relation has an additional symantics other than the standard of cpufreq
41 * DISALBE_FURTHER_CPUFREQ: disable further access to target
42 * ENABLE_FURTUER_CPUFREQ: enable access to target
43 */
44enum cpufreq_access {
45 DISABLE_FURTHER_CPUFREQ = 0x10,
46 ENABLE_FURTHER_CPUFREQ = 0x20,
47};
48
49static bool no_cpufreq_access;
50
33/* 51/*
34 * DRAM configurations to calculate refresh counter for changing 52 * DRAM configurations to calculate refresh counter for changing
35 * frequency of memory. 53 * frequency of memory.
@@ -66,6 +84,40 @@ static struct cpufreq_frequency_table s5pv210_freq_table[] = {
66 {0, CPUFREQ_TABLE_END}, 84 {0, CPUFREQ_TABLE_END},
67}; 85};
68 86
87static struct regulator *arm_regulator;
88static struct regulator *int_regulator;
89
90struct s5pv210_dvs_conf {
91 int arm_volt; /* uV */
92 int int_volt; /* uV */
93};
94
95static const int arm_volt_max = 1350000;
96static const int int_volt_max = 1250000;
97
98static struct s5pv210_dvs_conf dvs_conf[] = {
99 [L0] = {
100 .arm_volt = 1250000,
101 .int_volt = 1100000,
102 },
103 [L1] = {
104 .arm_volt = 1200000,
105 .int_volt = 1100000,
106 },
107 [L2] = {
108 .arm_volt = 1050000,
109 .int_volt = 1100000,
110 },
111 [L3] = {
112 .arm_volt = 950000,
113 .int_volt = 1100000,
114 },
115 [L4] = {
116 .arm_volt = 950000,
117 .int_volt = 1000000,
118 },
119};
120
69static u32 clkdiv_val[5][11] = { 121static u32 clkdiv_val[5][11] = {
70 /* 122 /*
71 * Clock divider value for following 123 * Clock divider value for following
@@ -122,7 +174,7 @@ static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq)
122 __raw_writel(tmp1, reg); 174 __raw_writel(tmp1, reg);
123} 175}
124 176
125int s5pv210_verify_speed(struct cpufreq_policy *policy) 177static int s5pv210_verify_speed(struct cpufreq_policy *policy)
126{ 178{
127 if (policy->cpu) 179 if (policy->cpu)
128 return -EINVAL; 180 return -EINVAL;
@@ -130,7 +182,7 @@ int s5pv210_verify_speed(struct cpufreq_policy *policy)
130 return cpufreq_frequency_table_verify(policy, s5pv210_freq_table); 182 return cpufreq_frequency_table_verify(policy, s5pv210_freq_table);
131} 183}
132 184
133unsigned int s5pv210_getspeed(unsigned int cpu) 185static unsigned int s5pv210_getspeed(unsigned int cpu)
134{ 186{
135 if (cpu) 187 if (cpu)
136 return 0; 188 return 0;
@@ -146,30 +198,66 @@ static int s5pv210_target(struct cpufreq_policy *policy,
146 unsigned int index, priv_index; 198 unsigned int index, priv_index;
147 unsigned int pll_changing = 0; 199 unsigned int pll_changing = 0;
148 unsigned int bus_speed_changing = 0; 200 unsigned int bus_speed_changing = 0;
201 int arm_volt, int_volt;
202 int ret = 0;
203
204 mutex_lock(&set_freq_lock);
205
206 if (relation & ENABLE_FURTHER_CPUFREQ)
207 no_cpufreq_access = false;
208
209 if (no_cpufreq_access) {
210#ifdef CONFIG_PM_VERBOSE
211 pr_err("%s:%d denied access to %s as it is disabled"
212 "temporarily\n", __FILE__, __LINE__, __func__);
213#endif
214 ret = -EINVAL;
215 goto exit;
216 }
217
218 if (relation & DISABLE_FURTHER_CPUFREQ)
219 no_cpufreq_access = true;
220
221 relation &= ~(ENABLE_FURTHER_CPUFREQ | DISABLE_FURTHER_CPUFREQ);
149 222
150 freqs.old = s5pv210_getspeed(0); 223 freqs.old = s5pv210_getspeed(0);
151 224
152 if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, 225 if (cpufreq_frequency_table_target(policy, s5pv210_freq_table,
153 target_freq, relation, &index)) 226 target_freq, relation, &index)) {
154 return -EINVAL; 227 ret = -EINVAL;
228 goto exit;
229 }
155 230
156 freqs.new = s5pv210_freq_table[index].frequency; 231 freqs.new = s5pv210_freq_table[index].frequency;
157 freqs.cpu = 0; 232 freqs.cpu = 0;
158 233
159 if (freqs.new == freqs.old) 234 if (freqs.new == freqs.old)
160 return 0; 235 goto exit;
161 236
162 /* Finding current running level index */ 237 /* Finding current running level index */
163 if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, 238 if (cpufreq_frequency_table_target(policy, s5pv210_freq_table,
164 freqs.old, relation, &priv_index)) 239 freqs.old, relation, &priv_index)) {
165 return -EINVAL; 240 ret = -EINVAL;
241 goto exit;
242 }
166 243
167 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 244 arm_volt = dvs_conf[index].arm_volt;
245 int_volt = dvs_conf[index].int_volt;
168 246
169 if (freqs.new > freqs.old) { 247 if (freqs.new > freqs.old) {
170 /* Voltage up: will be implemented */ 248 ret = regulator_set_voltage(arm_regulator,
249 arm_volt, arm_volt_max);
250 if (ret)
251 goto exit;
252
253 ret = regulator_set_voltage(int_regulator,
254 int_volt, int_volt_max);
255 if (ret)
256 goto exit;
171 } 257 }
172 258
259 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
260
173 /* Check if there need to change PLL */ 261 /* Check if there need to change PLL */
174 if ((index == L0) || (priv_index == L0)) 262 if ((index == L0) || (priv_index == L0))
175 pll_changing = 1; 263 pll_changing = 1;
@@ -380,15 +468,21 @@ static int s5pv210_target(struct cpufreq_policy *policy,
380 } 468 }
381 } 469 }
382 470
471 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
472
383 if (freqs.new < freqs.old) { 473 if (freqs.new < freqs.old) {
384 /* Voltage down: will be implemented */ 474 regulator_set_voltage(int_regulator,
385 } 475 int_volt, int_volt_max);
386 476
387 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 477 regulator_set_voltage(arm_regulator,
478 arm_volt, arm_volt_max);
479 }
388 480
389 printk(KERN_DEBUG "Perf changed[L%d]\n", index); 481 printk(KERN_DEBUG "Perf changed[L%d]\n", index);
390 482
391 return 0; 483exit:
484 mutex_unlock(&set_freq_lock);
485 return ret;
392} 486}
393 487
394#ifdef CONFIG_PM 488#ifdef CONFIG_PM
@@ -416,6 +510,7 @@ static int check_mem_type(void __iomem *dmc_reg)
416static int __init s5pv210_cpu_init(struct cpufreq_policy *policy) 510static int __init s5pv210_cpu_init(struct cpufreq_policy *policy)
417{ 511{
418 unsigned long mem_type; 512 unsigned long mem_type;
513 int ret;
419 514
420 cpu_clk = clk_get(NULL, "armclk"); 515 cpu_clk = clk_get(NULL, "armclk");
421 if (IS_ERR(cpu_clk)) 516 if (IS_ERR(cpu_clk))
@@ -423,19 +518,20 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy)
423 518
424 dmc0_clk = clk_get(NULL, "sclk_dmc0"); 519 dmc0_clk = clk_get(NULL, "sclk_dmc0");
425 if (IS_ERR(dmc0_clk)) { 520 if (IS_ERR(dmc0_clk)) {
426 clk_put(cpu_clk); 521 ret = PTR_ERR(dmc0_clk);
427 return PTR_ERR(dmc0_clk); 522 goto out_dmc0;
428 } 523 }
429 524
430 dmc1_clk = clk_get(NULL, "hclk_msys"); 525 dmc1_clk = clk_get(NULL, "hclk_msys");
431 if (IS_ERR(dmc1_clk)) { 526 if (IS_ERR(dmc1_clk)) {
432 clk_put(dmc0_clk); 527 ret = PTR_ERR(dmc1_clk);
433 clk_put(cpu_clk); 528 goto out_dmc1;
434 return PTR_ERR(dmc1_clk);
435 } 529 }
436 530
437 if (policy->cpu != 0) 531 if (policy->cpu != 0) {
438 return -EINVAL; 532 ret = -EINVAL;
533 goto out_dmc1;
534 }
439 535
440 /* 536 /*
441 * check_mem_type : This driver only support LPDDR & LPDDR2. 537 * check_mem_type : This driver only support LPDDR & LPDDR2.
@@ -445,7 +541,8 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy)
445 541
446 if ((mem_type != LPDDR) && (mem_type != LPDDR2)) { 542 if ((mem_type != LPDDR) && (mem_type != LPDDR2)) {
447 printk(KERN_ERR "CPUFreq doesn't support this memory type\n"); 543 printk(KERN_ERR "CPUFreq doesn't support this memory type\n");
448 return -EINVAL; 544 ret = -EINVAL;
545 goto out_dmc1;
449 } 546 }
450 547
451 /* Find current refresh counter and frequency each DMC */ 548 /* Find current refresh counter and frequency each DMC */
@@ -462,6 +559,49 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy)
462 policy->cpuinfo.transition_latency = 40000; 559 policy->cpuinfo.transition_latency = 40000;
463 560
464 return cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table); 561 return cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table);
562
563out_dmc1:
564 clk_put(dmc0_clk);
565out_dmc0:
566 clk_put(cpu_clk);
567 return ret;
568}
569
570static int s5pv210_cpufreq_notifier_event(struct notifier_block *this,
571 unsigned long event, void *ptr)
572{
573 int ret;
574
575 switch (event) {
576 case PM_SUSPEND_PREPARE:
577 ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ,
578 DISABLE_FURTHER_CPUFREQ);
579 if (ret < 0)
580 return NOTIFY_BAD;
581
582 return NOTIFY_OK;
583 case PM_POST_RESTORE:
584 case PM_POST_SUSPEND:
585 cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ,
586 ENABLE_FURTHER_CPUFREQ);
587
588 return NOTIFY_OK;
589 }
590
591 return NOTIFY_DONE;
592}
593
594static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this,
595 unsigned long event, void *ptr)
596{
597 int ret;
598
599 ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ,
600 DISABLE_FURTHER_CPUFREQ);
601 if (ret < 0)
602 return NOTIFY_BAD;
603
604 return NOTIFY_DONE;
465} 605}
466 606
467static struct cpufreq_driver s5pv210_driver = { 607static struct cpufreq_driver s5pv210_driver = {
@@ -477,8 +617,32 @@ static struct cpufreq_driver s5pv210_driver = {
477#endif 617#endif
478}; 618};
479 619
620static struct notifier_block s5pv210_cpufreq_notifier = {
621 .notifier_call = s5pv210_cpufreq_notifier_event,
622};
623
624static struct notifier_block s5pv210_cpufreq_reboot_notifier = {
625 .notifier_call = s5pv210_cpufreq_reboot_notifier_event,
626};
627
480static int __init s5pv210_cpufreq_init(void) 628static int __init s5pv210_cpufreq_init(void)
481{ 629{
630 arm_regulator = regulator_get(NULL, "vddarm");
631 if (IS_ERR(arm_regulator)) {
632 pr_err("failed to get regulator vddarm");
633 return PTR_ERR(arm_regulator);
634 }
635
636 int_regulator = regulator_get(NULL, "vddint");
637 if (IS_ERR(int_regulator)) {
638 pr_err("failed to get regulator vddint");
639 regulator_put(arm_regulator);
640 return PTR_ERR(int_regulator);
641 }
642
643 register_pm_notifier(&s5pv210_cpufreq_notifier);
644 register_reboot_notifier(&s5pv210_cpufreq_reboot_notifier);
645
482 return cpufreq_register_driver(&s5pv210_driver); 646 return cpufreq_register_driver(&s5pv210_driver);
483} 647}
484 648