diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/boot/dts/exynos5420.dtsi | 5 | ||||
-rw-r--r-- | arch/arm/mach-exynos/exynos.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-exynos/pm_domains.c | 61 |
3 files changed, 66 insertions, 6 deletions
diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index e38532271ef9..15957227ffda 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi | |||
@@ -167,7 +167,7 @@ | |||
167 | compatible = "samsung,exynos5420-audss-clock"; | 167 | compatible = "samsung,exynos5420-audss-clock"; |
168 | reg = <0x03810000 0x0C>; | 168 | reg = <0x03810000 0x0C>; |
169 | #clock-cells = <1>; | 169 | #clock-cells = <1>; |
170 | clocks = <&clock CLK_FIN_PLL>, <&clock CLK_FOUT_EPLL>, | 170 | clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MAU_EPLL>, |
171 | <&clock CLK_SCLK_MAUDIO0>, <&clock CLK_SCLK_MAUPCM0>; | 171 | <&clock CLK_SCLK_MAUDIO0>, <&clock CLK_SCLK_MAUPCM0>; |
172 | clock-names = "pll_ref", "pll_in", "sclk_audio", "sclk_pcm_in"; | 172 | clock-names = "pll_ref", "pll_in", "sclk_audio", "sclk_pcm_in"; |
173 | }; | 173 | }; |
@@ -260,6 +260,9 @@ | |||
260 | mfc_pd: power-domain@10044060 { | 260 | mfc_pd: power-domain@10044060 { |
261 | compatible = "samsung,exynos4210-pd"; | 261 | compatible = "samsung,exynos4210-pd"; |
262 | reg = <0x10044060 0x20>; | 262 | reg = <0x10044060 0x20>; |
263 | clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_SW_ACLK333>, | ||
264 | <&clock CLK_MOUT_USER_ACLK333>; | ||
265 | clock-names = "oscclk", "pclk0", "clk0"; | ||
263 | }; | 266 | }; |
264 | 267 | ||
265 | disp_pd: power-domain@100440C0 { | 268 | disp_pd: power-domain@100440C0 { |
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 95cad252eb1b..46d893fcbe85 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c | |||
@@ -173,10 +173,8 @@ static struct platform_device exynos_cpuidle = { | |||
173 | 173 | ||
174 | void __init exynos_cpuidle_init(void) | 174 | void __init exynos_cpuidle_init(void) |
175 | { | 175 | { |
176 | if (soc_is_exynos5440()) | 176 | if (soc_is_exynos4210() || soc_is_exynos5250()) |
177 | return; | 177 | platform_device_register(&exynos_cpuidle); |
178 | |||
179 | platform_device_register(&exynos_cpuidle); | ||
180 | } | 178 | } |
181 | 179 | ||
182 | void __init exynos_cpufreq_init(void) | 180 | void __init exynos_cpufreq_init(void) |
diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c index fe6570ebbdde..797cb134bfff 100644 --- a/arch/arm/mach-exynos/pm_domains.c +++ b/arch/arm/mach-exynos/pm_domains.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/pm_domain.h> | 19 | #include <linux/pm_domain.h> |
20 | #include <linux/clk.h> | ||
20 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
21 | #include <linux/of_address.h> | 22 | #include <linux/of_address.h> |
22 | #include <linux/of_platform.h> | 23 | #include <linux/of_platform.h> |
@@ -24,6 +25,8 @@ | |||
24 | 25 | ||
25 | #include "regs-pmu.h" | 26 | #include "regs-pmu.h" |
26 | 27 | ||
28 | #define MAX_CLK_PER_DOMAIN 4 | ||
29 | |||
27 | /* | 30 | /* |
28 | * Exynos specific wrapper around the generic power domain | 31 | * Exynos specific wrapper around the generic power domain |
29 | */ | 32 | */ |
@@ -32,6 +35,9 @@ struct exynos_pm_domain { | |||
32 | char const *name; | 35 | char const *name; |
33 | bool is_off; | 36 | bool is_off; |
34 | struct generic_pm_domain pd; | 37 | struct generic_pm_domain pd; |
38 | struct clk *oscclk; | ||
39 | struct clk *clk[MAX_CLK_PER_DOMAIN]; | ||
40 | struct clk *pclk[MAX_CLK_PER_DOMAIN]; | ||
35 | }; | 41 | }; |
36 | 42 | ||
37 | static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) | 43 | static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) |
@@ -44,6 +50,19 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) | |||
44 | pd = container_of(domain, struct exynos_pm_domain, pd); | 50 | pd = container_of(domain, struct exynos_pm_domain, pd); |
45 | base = pd->base; | 51 | base = pd->base; |
46 | 52 | ||
53 | /* Set oscclk before powering off a domain*/ | ||
54 | if (!power_on) { | ||
55 | int i; | ||
56 | |||
57 | for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { | ||
58 | if (IS_ERR(pd->clk[i])) | ||
59 | break; | ||
60 | if (clk_set_parent(pd->clk[i], pd->oscclk)) | ||
61 | pr_err("%s: error setting oscclk as parent to clock %d\n", | ||
62 | pd->name, i); | ||
63 | } | ||
64 | } | ||
65 | |||
47 | pwr = power_on ? S5P_INT_LOCAL_PWR_EN : 0; | 66 | pwr = power_on ? S5P_INT_LOCAL_PWR_EN : 0; |
48 | __raw_writel(pwr, base); | 67 | __raw_writel(pwr, base); |
49 | 68 | ||
@@ -60,6 +79,20 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) | |||
60 | cpu_relax(); | 79 | cpu_relax(); |
61 | usleep_range(80, 100); | 80 | usleep_range(80, 100); |
62 | } | 81 | } |
82 | |||
83 | /* Restore clocks after powering on a domain*/ | ||
84 | if (power_on) { | ||
85 | int i; | ||
86 | |||
87 | for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { | ||
88 | if (IS_ERR(pd->clk[i])) | ||
89 | break; | ||
90 | if (clk_set_parent(pd->clk[i], pd->pclk[i])) | ||
91 | pr_err("%s: error setting parent to clock%d\n", | ||
92 | pd->name, i); | ||
93 | } | ||
94 | } | ||
95 | |||
63 | return 0; | 96 | return 0; |
64 | } | 97 | } |
65 | 98 | ||
@@ -152,9 +185,11 @@ static __init int exynos4_pm_init_power_domain(void) | |||
152 | 185 | ||
153 | for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { | 186 | for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { |
154 | struct exynos_pm_domain *pd; | 187 | struct exynos_pm_domain *pd; |
155 | int on; | 188 | int on, i; |
189 | struct device *dev; | ||
156 | 190 | ||
157 | pdev = of_find_device_by_node(np); | 191 | pdev = of_find_device_by_node(np); |
192 | dev = &pdev->dev; | ||
158 | 193 | ||
159 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); | 194 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); |
160 | if (!pd) { | 195 | if (!pd) { |
@@ -170,6 +205,30 @@ static __init int exynos4_pm_init_power_domain(void) | |||
170 | pd->pd.power_on = exynos_pd_power_on; | 205 | pd->pd.power_on = exynos_pd_power_on; |
171 | pd->pd.of_node = np; | 206 | pd->pd.of_node = np; |
172 | 207 | ||
208 | pd->oscclk = clk_get(dev, "oscclk"); | ||
209 | if (IS_ERR(pd->oscclk)) | ||
210 | goto no_clk; | ||
211 | |||
212 | for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { | ||
213 | char clk_name[8]; | ||
214 | |||
215 | snprintf(clk_name, sizeof(clk_name), "clk%d", i); | ||
216 | pd->clk[i] = clk_get(dev, clk_name); | ||
217 | if (IS_ERR(pd->clk[i])) | ||
218 | break; | ||
219 | snprintf(clk_name, sizeof(clk_name), "pclk%d", i); | ||
220 | pd->pclk[i] = clk_get(dev, clk_name); | ||
221 | if (IS_ERR(pd->pclk[i])) { | ||
222 | clk_put(pd->clk[i]); | ||
223 | pd->clk[i] = ERR_PTR(-EINVAL); | ||
224 | break; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | if (IS_ERR(pd->clk[0])) | ||
229 | clk_put(pd->oscclk); | ||
230 | |||
231 | no_clk: | ||
173 | platform_set_drvdata(pdev, pd); | 232 | platform_set_drvdata(pdev, pd); |
174 | 233 | ||
175 | on = __raw_readl(pd->base + 0x4) & S5P_INT_LOCAL_PWR_EN; | 234 | on = __raw_readl(pd->base + 0x4) & S5P_INT_LOCAL_PWR_EN; |