diff options
Diffstat (limited to 'arch/arm/mach-pxa/pxa3xx.c')
-rw-r--r-- | arch/arm/mach-pxa/pxa3xx.c | 99 |
1 files changed, 82 insertions, 17 deletions
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index 5cbf057a1b32..e47e67c11afe 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/irq.h> | 21 | #include <linux/irq.h> |
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <linux/sysdev.h> | ||
23 | 24 | ||
24 | #include <asm/hardware.h> | 25 | #include <asm/hardware.h> |
25 | #include <asm/arch/pxa3xx-regs.h> | 26 | #include <asm/arch/pxa3xx-regs.h> |
@@ -39,6 +40,7 @@ | |||
39 | #define RO_CLK 60000000 | 40 | #define RO_CLK 60000000 |
40 | 41 | ||
41 | #define ACCR_D0CS (1 << 26) | 42 | #define ACCR_D0CS (1 << 26) |
43 | #define ACCR_PCCE (1 << 11) | ||
42 | 44 | ||
43 | /* crystal frequency to static memory controller multiplier (SMCFS) */ | 45 | /* crystal frequency to static memory controller multiplier (SMCFS) */ |
44 | static unsigned char smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, }; | 46 | static unsigned char smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, }; |
@@ -203,7 +205,6 @@ static struct clk pxa3xx_clks[] = { | |||
203 | }; | 205 | }; |
204 | 206 | ||
205 | #ifdef CONFIG_PM | 207 | #ifdef CONFIG_PM |
206 | #define SLEEP_SAVE_SIZE 4 | ||
207 | 208 | ||
208 | #define ISRAM_START 0x5c000000 | 209 | #define ISRAM_START 0x5c000000 |
209 | #define ISRAM_SIZE SZ_256K | 210 | #define ISRAM_SIZE SZ_256K |
@@ -211,25 +212,29 @@ static struct clk pxa3xx_clks[] = { | |||
211 | static void __iomem *sram; | 212 | static void __iomem *sram; |
212 | static unsigned long wakeup_src; | 213 | static unsigned long wakeup_src; |
213 | 214 | ||
214 | static void pxa3xx_cpu_pm_save(unsigned long *sleep_save) | 215 | #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x |
215 | { | 216 | #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] |
216 | pr_debug("PM: CKENA=%08x CKENB=%08x\n", CKENA, CKENB); | ||
217 | 217 | ||
218 | if (CKENA & (1 << CKEN_USBH)) { | 218 | enum { SLEEP_SAVE_START = 0, |
219 | printk(KERN_ERR "PM: USB host clock not stopped?\n"); | 219 | SLEEP_SAVE_CKENA, |
220 | CKENA &= ~(1 << CKEN_USBH); | 220 | SLEEP_SAVE_CKENB, |
221 | } | 221 | SLEEP_SAVE_ACCR, |
222 | // CKENA |= 1 << (CKEN_ISC & 31); | ||
223 | 222 | ||
224 | /* | 223 | SLEEP_SAVE_SIZE, |
225 | * Low power modes require the HSIO2 clock to be enabled. | 224 | }; |
226 | */ | 225 | |
227 | CKENB |= 1 << (CKEN_HSIO2 & 31); | 226 | static void pxa3xx_cpu_pm_save(unsigned long *sleep_save) |
227 | { | ||
228 | SAVE(CKENA); | ||
229 | SAVE(CKENB); | ||
230 | SAVE(ACCR); | ||
228 | } | 231 | } |
229 | 232 | ||
230 | static void pxa3xx_cpu_pm_restore(unsigned long *sleep_save) | 233 | static void pxa3xx_cpu_pm_restore(unsigned long *sleep_save) |
231 | { | 234 | { |
232 | CKENB &= ~(1 << (CKEN_HSIO2 & 31)); | 235 | RESTORE(ACCR); |
236 | RESTORE(CKENA); | ||
237 | RESTORE(CKENB); | ||
233 | } | 238 | } |
234 | 239 | ||
235 | /* | 240 | /* |
@@ -265,6 +270,46 @@ static void pxa3xx_cpu_standby(unsigned int pwrmode) | |||
265 | printk("PM: AD2D0SR=%08x ASCR=%08x\n", AD2D0SR, ASCR); | 270 | printk("PM: AD2D0SR=%08x ASCR=%08x\n", AD2D0SR, ASCR); |
266 | } | 271 | } |
267 | 272 | ||
273 | /* | ||
274 | * NOTE: currently, the OBM (OEM Boot Module) binary comes along with | ||
275 | * PXA3xx development kits assumes that the resuming process continues | ||
276 | * with the address stored within the first 4 bytes of SDRAM. The PSPR | ||
277 | * register is used privately by BootROM and OBM, and _must_ be set to | ||
278 | * 0x5c014000 for the moment. | ||
279 | */ | ||
280 | static void pxa3xx_cpu_pm_suspend(void) | ||
281 | { | ||
282 | volatile unsigned long *p = (volatile void *)0xc0000000; | ||
283 | unsigned long saved_data = *p; | ||
284 | |||
285 | extern void pxa3xx_cpu_suspend(void); | ||
286 | extern void pxa3xx_cpu_resume(void); | ||
287 | |||
288 | /* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */ | ||
289 | CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM); | ||
290 | CKENB |= 1 << (CKEN_HSIO2 & 0x1f); | ||
291 | |||
292 | /* clear and setup wakeup source */ | ||
293 | AD3SR = ~0; | ||
294 | AD3ER = wakeup_src; | ||
295 | ASCR = ASCR; | ||
296 | ARSR = ARSR; | ||
297 | |||
298 | PCFR |= (1u << 13); /* L1_DIS */ | ||
299 | PCFR &= ~((1u << 12) | (1u << 1)); /* L0_EN | SL_ROD */ | ||
300 | |||
301 | PSPR = 0x5c014000; | ||
302 | |||
303 | /* overwrite with the resume address */ | ||
304 | *p = virt_to_phys(pxa3xx_cpu_resume); | ||
305 | |||
306 | pxa3xx_cpu_suspend(); | ||
307 | |||
308 | *p = saved_data; | ||
309 | |||
310 | AD3ER = 0; | ||
311 | } | ||
312 | |||
268 | static void pxa3xx_cpu_pm_enter(suspend_state_t state) | 313 | static void pxa3xx_cpu_pm_enter(suspend_state_t state) |
269 | { | 314 | { |
270 | /* | 315 | /* |
@@ -279,6 +324,7 @@ static void pxa3xx_cpu_pm_enter(suspend_state_t state) | |||
279 | break; | 324 | break; |
280 | 325 | ||
281 | case PM_SUSPEND_MEM: | 326 | case PM_SUSPEND_MEM: |
327 | pxa3xx_cpu_pm_suspend(); | ||
282 | break; | 328 | break; |
283 | } | 329 | } |
284 | } | 330 | } |
@@ -452,9 +498,21 @@ static struct platform_device *devices[] __initdata = { | |||
452 | &pxa3xx_device_ssp4, | 498 | &pxa3xx_device_ssp4, |
453 | }; | 499 | }; |
454 | 500 | ||
501 | static struct sys_device pxa3xx_sysdev[] = { | ||
502 | { | ||
503 | .id = 0, | ||
504 | .cls = &pxa_irq_sysclass, | ||
505 | }, { | ||
506 | .id = 1, | ||
507 | .cls = &pxa_irq_sysclass, | ||
508 | }, { | ||
509 | .cls = &pxa_gpio_sysclass, | ||
510 | }, | ||
511 | }; | ||
512 | |||
455 | static int __init pxa3xx_init(void) | 513 | static int __init pxa3xx_init(void) |
456 | { | 514 | { |
457 | int ret = 0; | 515 | int i, ret = 0; |
458 | 516 | ||
459 | if (cpu_is_pxa3xx()) { | 517 | if (cpu_is_pxa3xx()) { |
460 | clks_register(pxa3xx_clks, ARRAY_SIZE(pxa3xx_clks)); | 518 | clks_register(pxa3xx_clks, ARRAY_SIZE(pxa3xx_clks)); |
@@ -464,9 +522,16 @@ static int __init pxa3xx_init(void) | |||
464 | 522 | ||
465 | pxa3xx_init_pm(); | 523 | pxa3xx_init_pm(); |
466 | 524 | ||
467 | return platform_add_devices(devices, ARRAY_SIZE(devices)); | 525 | for (i = 0; i < ARRAY_SIZE(pxa3xx_sysdev); i++) { |
526 | ret = sysdev_register(&pxa3xx_sysdev[i]); | ||
527 | if (ret) | ||
528 | pr_err("failed to register sysdev[%d]\n", i); | ||
529 | } | ||
530 | |||
531 | ret = platform_add_devices(devices, ARRAY_SIZE(devices)); | ||
468 | } | 532 | } |
469 | return 0; | 533 | |
534 | return ret; | ||
470 | } | 535 | } |
471 | 536 | ||
472 | subsys_initcall(pxa3xx_init); | 537 | subsys_initcall(pxa3xx_init); |