diff options
-rw-r--r-- | arch/arm/Kconfig | 4 | ||||
-rw-r--r-- | arch/arm/mach-exynos4/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-s3c64xx/Makefile | 4 | ||||
-rw-r--r-- | arch/arm/mach-s5pv210/Makefile | 1 | ||||
-rw-r--r-- | drivers/cpufreq/Kconfig | 5 | ||||
-rw-r--r-- | drivers/cpufreq/Kconfig.arm | 32 | ||||
-rw-r--r-- | drivers/cpufreq/Makefile | 8 | ||||
-rw-r--r-- | drivers/cpufreq/acpi-cpufreq.c | 2 | ||||
-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 | ||
1898 | config CPU_FREQ_S3C64XX | ||
1899 | bool "CPUfreq support for Samsung S3C64XX CPUs" | ||
1900 | depends on CPU_FREQ && CPU_S3C6410 | ||
1901 | |||
1902 | config CPU_FREQ_S3C | 1898 | config 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- := | |||
15 | obj-$(CONFIG_CPU_EXYNOS4210) += cpu.o init.o clock.o irq-combiner.o | 15 | obj-$(CONFIG_CPU_EXYNOS4210) += cpu.o init.o clock.o irq-combiner.o |
16 | obj-$(CONFIG_CPU_EXYNOS4210) += setup-i2c0.o irq-eint.o dma.o | 16 | obj-$(CONFIG_CPU_EXYNOS4210) += setup-i2c0.o irq-eint.o dma.o |
17 | obj-$(CONFIG_PM) += pm.o sleep.o | 17 | obj-$(CONFIG_PM) += pm.o sleep.o |
18 | obj-$(CONFIG_CPU_FREQ) += cpufreq.o | ||
19 | obj-$(CONFIG_CPU_IDLE) += cpuidle.o | 18 | obj-$(CONFIG_CPU_IDLE) += cpuidle.o |
20 | 19 | ||
21 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o | 20 | obj-$(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 | |||
23 | obj-y += irq.o | 23 | obj-y += irq.o |
24 | obj-y += irq-eint.o | 24 | obj-y += irq-eint.o |
25 | 25 | ||
26 | # CPU frequency scaling | ||
27 | |||
28 | obj-$(CONFIG_CPU_FREQ_S3C64XX) += cpufreq.o | ||
29 | |||
30 | # DMA support | 26 | # DMA support |
31 | 27 | ||
32 | obj-$(CONFIG_S3C64XX_DMA) += dma.o | 28 | obj-$(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- := | |||
15 | obj-$(CONFIG_CPU_S5PV210) += cpu.o init.o clock.o dma.o | 15 | obj-$(CONFIG_CPU_S5PV210) += cpu.o init.o clock.o dma.o |
16 | obj-$(CONFIG_CPU_S5PV210) += setup-i2c0.o | 16 | obj-$(CONFIG_CPU_S5PV210) += setup-i2c0.o |
17 | obj-$(CONFIG_S5PV210_PM) += pm.o sleep.o | 17 | obj-$(CONFIG_S5PV210_PM) += pm.o sleep.o |
18 | obj-$(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 | |||
184 | source "drivers/cpufreq/Kconfig.x86" | 184 | source "drivers/cpufreq/Kconfig.x86" |
185 | endmenu | 185 | endmenu |
186 | 186 | ||
187 | menu "ARM CPU frequency scaling drivers" | ||
188 | depends on ARM | ||
189 | source "drivers/cpufreq/Kconfig.arm" | ||
190 | endmenu | ||
191 | |||
187 | endif | 192 | endif |
188 | endmenu | 193 | endmenu |
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 | |||
5 | config 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 | |||
14 | config 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 | |||
24 | config 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 |
14 | obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o | 14 | obj-$(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 | |||
37 | obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o | 37 | obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o |
38 | obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o | 38 | obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o |
39 | 39 | ||
40 | ##################################################################################d | 40 | ################################################################################## |
41 | |||
42 | # ARM SoC drivers | 41 | # ARM SoC drivers |
43 | obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o | 42 | obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o |
43 | obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o | ||
44 | obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o | ||
45 | obj-$(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 | ||
195 | int exynos4_verify_speed(struct cpufreq_policy *policy) | 194 | static 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 | ||
200 | unsigned int exynos4_getspeed(unsigned int cpu) | 199 | static 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 | ||
205 | void exynos4_set_clkdiv(unsigned int div_index) | 204 | static 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 | ||
37 | static struct cpufreq_frequency_table s3c64xx_freq_table[] = { | 37 | static 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; | |||
25 | static struct clk *dmc0_clk; | 27 | static struct clk *dmc0_clk; |
26 | static struct clk *dmc1_clk; | 28 | static struct clk *dmc1_clk; |
27 | static struct cpufreq_freqs freqs; | 29 | static struct cpufreq_freqs freqs; |
30 | static 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 | */ | ||
44 | enum cpufreq_access { | ||
45 | DISABLE_FURTHER_CPUFREQ = 0x10, | ||
46 | ENABLE_FURTHER_CPUFREQ = 0x20, | ||
47 | }; | ||
48 | |||
49 | static 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 | ||
87 | static struct regulator *arm_regulator; | ||
88 | static struct regulator *int_regulator; | ||
89 | |||
90 | struct s5pv210_dvs_conf { | ||
91 | int arm_volt; /* uV */ | ||
92 | int int_volt; /* uV */ | ||
93 | }; | ||
94 | |||
95 | static const int arm_volt_max = 1350000; | ||
96 | static const int int_volt_max = 1250000; | ||
97 | |||
98 | static 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 | |||
69 | static u32 clkdiv_val[5][11] = { | 121 | static 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 | ||
125 | int s5pv210_verify_speed(struct cpufreq_policy *policy) | 177 | static 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 | ||
133 | unsigned int s5pv210_getspeed(unsigned int cpu) | 185 | static 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; | 483 | exit: |
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) | |||
416 | static int __init s5pv210_cpu_init(struct cpufreq_policy *policy) | 510 | static 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 | |||
563 | out_dmc1: | ||
564 | clk_put(dmc0_clk); | ||
565 | out_dmc0: | ||
566 | clk_put(cpu_clk); | ||
567 | return ret; | ||
568 | } | ||
569 | |||
570 | static 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 | |||
594 | static 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 | ||
467 | static struct cpufreq_driver s5pv210_driver = { | 607 | static struct cpufreq_driver s5pv210_driver = { |
@@ -477,8 +617,32 @@ static struct cpufreq_driver s5pv210_driver = { | |||
477 | #endif | 617 | #endif |
478 | }; | 618 | }; |
479 | 619 | ||
620 | static struct notifier_block s5pv210_cpufreq_notifier = { | ||
621 | .notifier_call = s5pv210_cpufreq_notifier_event, | ||
622 | }; | ||
623 | |||
624 | static struct notifier_block s5pv210_cpufreq_reboot_notifier = { | ||
625 | .notifier_call = s5pv210_cpufreq_reboot_notifier_event, | ||
626 | }; | ||
627 | |||
480 | static int __init s5pv210_cpufreq_init(void) | 628 | static 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 | ||