Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | /* * SA1100 Power Management Routines * * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License. * * History: * * 2001-02-06: Cliff Brake Initial code * * 2001-02-25: Sukjae Cho <sjcho@east.isi.edu> & * Chester Kuo <chester@linux.org.tw> * Save more value for the resume function! Support * Bitsy/Assabet/Freebird board * * 2001-08-29: Nicolas Pitre <nico@fluxnic.net> * Cleaned up, pushed platform dependent stuff * in the platform specific files. * * 2002-05-27: Nicolas Pitre Killed sleep.h and the kmalloced save array. * Storage is local on the stack now. */ #include <linux/init.h> #include <linux/suspend.h> #include <linux/errno.h> #include <linux/time.h> #include <mach/hardware.h> #include <asm/memory.h> #include <asm/system.h> #include <asm/mach/time.h> extern void sa1100_cpu_suspend(void); extern void sa1100_cpu_resume(void); #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] /* * List of global SA11x0 peripheral registers to preserve. * More ones like CP and general purpose register values are preserved * on the stack and then the stack pointer is stored last in sleep.S. */ enum { SLEEP_SAVE_GPDR, SLEEP_SAVE_GAFR, SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR, SLEEP_SAVE_Ser1SDCR0, SLEEP_SAVE_COUNT }; static int sa11x0_pm_enter(suspend_state_t state) { unsigned long gpio, sleep_save[SLEEP_SAVE_COUNT]; gpio = GPLR; /* save vital registers */ SAVE(GPDR); SAVE(GAFR); SAVE(PPDR); SAVE(PPSR); SAVE(PPAR); SAVE(PSDR); SAVE(Ser1SDCR0); /* Clear previous reset status */ RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR; /* set resume return address */ PSPR = virt_to_phys(sa1100_cpu_resume); /* go zzz */ sa1100_cpu_suspend(); cpu_init(); /* * Ensure not to come back here if it wasn't intended */ PSPR = 0; /* * Ensure interrupt sources are disabled; we will re-init * the interrupt subsystem via the device manager. */ ICLR = 0; ICCR = 1; ICMR = 0; /* restore registers */ RESTORE(GPDR); RESTORE(GAFR); RESTORE(PPDR); RESTORE(PPSR); RESTORE(PPAR); RESTORE(PSDR); RESTORE(Ser1SDCR0); GPSR = gpio; GPCR = ~gpio; /* * Clear the peripheral sleep-hold bit. */ PSSR = PSSR_PH; return 0; } unsigned long sleep_phys_sp(void *sp) { return virt_to_phys(sp); } static struct platform_suspend_ops sa11x0_pm_ops = { .enter = sa11x0_pm_enter, .valid = suspend_valid_only_mem, }; static int __init sa11x0_pm_init(void) { suspend_set_ops(&sa11x0_pm_ops); return 0; } late_initcall(sa11x0_pm_init); |