diff options
Diffstat (limited to 'arch/arm/mach-s3c64xx/pm.c')
-rw-r--r-- | arch/arm/mach-s3c64xx/pm.c | 176 |
1 files changed, 174 insertions, 2 deletions
diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c index b375cd5c47cb..7d3e81b9dd06 100644 --- a/arch/arm/mach-s3c64xx/pm.c +++ b/arch/arm/mach-s3c64xx/pm.c | |||
@@ -17,10 +17,12 @@ | |||
17 | #include <linux/serial_core.h> | 17 | #include <linux/serial_core.h> |
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/gpio.h> | 19 | #include <linux/gpio.h> |
20 | #include <linux/pm_domain.h> | ||
20 | 21 | ||
21 | #include <mach/map.h> | 22 | #include <mach/map.h> |
22 | #include <mach/irqs.h> | 23 | #include <mach/irqs.h> |
23 | 24 | ||
25 | #include <plat/devs.h> | ||
24 | #include <plat/pm.h> | 26 | #include <plat/pm.h> |
25 | #include <plat/wakeup-mask.h> | 27 | #include <plat/wakeup-mask.h> |
26 | 28 | ||
@@ -31,6 +33,148 @@ | |||
31 | #include <mach/regs-gpio-memport.h> | 33 | #include <mach/regs-gpio-memport.h> |
32 | #include <mach/regs-modem.h> | 34 | #include <mach/regs-modem.h> |
33 | 35 | ||
36 | struct s3c64xx_pm_domain { | ||
37 | char *const name; | ||
38 | u32 ena; | ||
39 | u32 pwr_stat; | ||
40 | struct generic_pm_domain pd; | ||
41 | }; | ||
42 | |||
43 | static int s3c64xx_pd_off(struct generic_pm_domain *domain) | ||
44 | { | ||
45 | struct s3c64xx_pm_domain *pd; | ||
46 | u32 val; | ||
47 | |||
48 | pd = container_of(domain, struct s3c64xx_pm_domain, pd); | ||
49 | |||
50 | val = __raw_readl(S3C64XX_NORMAL_CFG); | ||
51 | val &= ~(pd->ena); | ||
52 | __raw_writel(val, S3C64XX_NORMAL_CFG); | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static int s3c64xx_pd_on(struct generic_pm_domain *domain) | ||
58 | { | ||
59 | struct s3c64xx_pm_domain *pd; | ||
60 | u32 val; | ||
61 | long retry = 1000000L; | ||
62 | |||
63 | pd = container_of(domain, struct s3c64xx_pm_domain, pd); | ||
64 | |||
65 | val = __raw_readl(S3C64XX_NORMAL_CFG); | ||
66 | val |= pd->ena; | ||
67 | __raw_writel(val, S3C64XX_NORMAL_CFG); | ||
68 | |||
69 | /* Not all domains provide power status readback */ | ||
70 | if (pd->pwr_stat) { | ||
71 | do { | ||
72 | cpu_relax(); | ||
73 | if (__raw_readl(S3C64XX_BLK_PWR_STAT) & pd->pwr_stat) | ||
74 | break; | ||
75 | } while (retry--); | ||
76 | |||
77 | if (!retry) { | ||
78 | pr_err("Failed to start domain %s\n", pd->name); | ||
79 | return -EBUSY; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static struct s3c64xx_pm_domain s3c64xx_pm_irom = { | ||
87 | .name = "IROM", | ||
88 | .ena = S3C64XX_NORMALCFG_IROM_ON, | ||
89 | .pd = { | ||
90 | .power_off = s3c64xx_pd_off, | ||
91 | .power_on = s3c64xx_pd_on, | ||
92 | }, | ||
93 | }; | ||
94 | |||
95 | static struct s3c64xx_pm_domain s3c64xx_pm_etm = { | ||
96 | .name = "ETM", | ||
97 | .ena = S3C64XX_NORMALCFG_DOMAIN_ETM_ON, | ||
98 | .pwr_stat = S3C64XX_BLKPWRSTAT_ETM, | ||
99 | .pd = { | ||
100 | .power_off = s3c64xx_pd_off, | ||
101 | .power_on = s3c64xx_pd_on, | ||
102 | }, | ||
103 | }; | ||
104 | |||
105 | static struct s3c64xx_pm_domain s3c64xx_pm_s = { | ||
106 | .name = "S", | ||
107 | .ena = S3C64XX_NORMALCFG_DOMAIN_S_ON, | ||
108 | .pwr_stat = S3C64XX_BLKPWRSTAT_S, | ||
109 | .pd = { | ||
110 | .power_off = s3c64xx_pd_off, | ||
111 | .power_on = s3c64xx_pd_on, | ||
112 | }, | ||
113 | }; | ||
114 | |||
115 | static struct s3c64xx_pm_domain s3c64xx_pm_f = { | ||
116 | .name = "F", | ||
117 | .ena = S3C64XX_NORMALCFG_DOMAIN_F_ON, | ||
118 | .pwr_stat = S3C64XX_BLKPWRSTAT_F, | ||
119 | .pd = { | ||
120 | .power_off = s3c64xx_pd_off, | ||
121 | .power_on = s3c64xx_pd_on, | ||
122 | }, | ||
123 | }; | ||
124 | |||
125 | static struct s3c64xx_pm_domain s3c64xx_pm_p = { | ||
126 | .name = "P", | ||
127 | .ena = S3C64XX_NORMALCFG_DOMAIN_P_ON, | ||
128 | .pwr_stat = S3C64XX_BLKPWRSTAT_P, | ||
129 | .pd = { | ||
130 | .power_off = s3c64xx_pd_off, | ||
131 | .power_on = s3c64xx_pd_on, | ||
132 | }, | ||
133 | }; | ||
134 | |||
135 | static struct s3c64xx_pm_domain s3c64xx_pm_i = { | ||
136 | .name = "I", | ||
137 | .ena = S3C64XX_NORMALCFG_DOMAIN_I_ON, | ||
138 | .pwr_stat = S3C64XX_BLKPWRSTAT_I, | ||
139 | .pd = { | ||
140 | .power_off = s3c64xx_pd_off, | ||
141 | .power_on = s3c64xx_pd_on, | ||
142 | }, | ||
143 | }; | ||
144 | |||
145 | static struct s3c64xx_pm_domain s3c64xx_pm_g = { | ||
146 | .name = "G", | ||
147 | .ena = S3C64XX_NORMALCFG_DOMAIN_G_ON, | ||
148 | .pd = { | ||
149 | .power_off = s3c64xx_pd_off, | ||
150 | .power_on = s3c64xx_pd_on, | ||
151 | }, | ||
152 | }; | ||
153 | |||
154 | static struct s3c64xx_pm_domain s3c64xx_pm_v = { | ||
155 | .name = "V", | ||
156 | .ena = S3C64XX_NORMALCFG_DOMAIN_V_ON, | ||
157 | .pwr_stat = S3C64XX_BLKPWRSTAT_V, | ||
158 | .pd = { | ||
159 | .power_off = s3c64xx_pd_off, | ||
160 | .power_on = s3c64xx_pd_on, | ||
161 | }, | ||
162 | }; | ||
163 | |||
164 | static struct s3c64xx_pm_domain *s3c64xx_always_on_pm_domains[] = { | ||
165 | &s3c64xx_pm_irom, | ||
166 | }; | ||
167 | |||
168 | static struct s3c64xx_pm_domain *s3c64xx_pm_domains[] = { | ||
169 | &s3c64xx_pm_etm, | ||
170 | &s3c64xx_pm_g, | ||
171 | &s3c64xx_pm_v, | ||
172 | &s3c64xx_pm_i, | ||
173 | &s3c64xx_pm_p, | ||
174 | &s3c64xx_pm_s, | ||
175 | &s3c64xx_pm_f, | ||
176 | }; | ||
177 | |||
34 | #ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK | 178 | #ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK |
35 | void s3c_pm_debug_smdkled(u32 set, u32 clear) | 179 | void s3c_pm_debug_smdkled(u32 set, u32 clear) |
36 | { | 180 | { |
@@ -89,6 +233,8 @@ static struct sleep_save misc_save[] = { | |||
89 | 233 | ||
90 | SAVE_ITEM(S3C64XX_SDMA_SEL), | 234 | SAVE_ITEM(S3C64XX_SDMA_SEL), |
91 | SAVE_ITEM(S3C64XX_MODEM_MIFPCON), | 235 | SAVE_ITEM(S3C64XX_MODEM_MIFPCON), |
236 | |||
237 | SAVE_ITEM(S3C64XX_NORMAL_CFG), | ||
92 | }; | 238 | }; |
93 | 239 | ||
94 | void s3c_pm_configure_extint(void) | 240 | void s3c_pm_configure_extint(void) |
@@ -179,7 +325,26 @@ static void s3c64xx_pm_prepare(void) | |||
179 | __raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT), S3C64XX_WAKEUP_STAT); | 325 | __raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT), S3C64XX_WAKEUP_STAT); |
180 | } | 326 | } |
181 | 327 | ||
182 | static int s3c64xx_pm_init(void) | 328 | int __init s3c64xx_pm_init(void) |
329 | { | ||
330 | int i; | ||
331 | |||
332 | s3c_pm_init(); | ||
333 | |||
334 | for (i = 0; i < ARRAY_SIZE(s3c64xx_always_on_pm_domains); i++) | ||
335 | pm_genpd_init(&s3c64xx_always_on_pm_domains[i]->pd, | ||
336 | &pm_domain_always_on_gov, false); | ||
337 | |||
338 | for (i = 0; i < ARRAY_SIZE(s3c64xx_pm_domains); i++) | ||
339 | pm_genpd_init(&s3c64xx_pm_domains[i]->pd, NULL, false); | ||
340 | |||
341 | if (dev_get_platdata(&s3c_device_fb.dev)) | ||
342 | pm_genpd_add_device(&s3c64xx_pm_f.pd, &s3c_device_fb.dev); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static __init int s3c64xx_pm_initcall(void) | ||
183 | { | 348 | { |
184 | pm_cpu_prep = s3c64xx_pm_prepare; | 349 | pm_cpu_prep = s3c64xx_pm_prepare; |
185 | pm_cpu_sleep = s3c64xx_cpu_suspend; | 350 | pm_cpu_sleep = s3c64xx_cpu_suspend; |
@@ -198,5 +363,12 @@ static int s3c64xx_pm_init(void) | |||
198 | 363 | ||
199 | return 0; | 364 | return 0; |
200 | } | 365 | } |
366 | arch_initcall(s3c64xx_pm_initcall); | ||
367 | |||
368 | static __init int s3c64xx_pm_late_initcall(void) | ||
369 | { | ||
370 | pm_genpd_poweroff_unused(); | ||
201 | 371 | ||
202 | arch_initcall(s3c64xx_pm_init); | 372 | return 0; |
373 | } | ||
374 | late_initcall(s3c64xx_pm_late_initcall); | ||