1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/config.h>
14#include <linux/init.h>
15#include <linux/suspend.h>
16#include <linux/errno.h>
17#include <linux/time.h>
18
19#include <asm/hardware.h>
20#include <asm/memory.h>
21#include <asm/system.h>
22#include <asm/arch/lubbock.h>
23
24
25
26
27
28#undef DEBUG
29
30extern void pxa_cpu_suspend(void);
31extern void pxa_cpu_resume(void);
32
33#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
34#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
35
36#define RESTORE_GPLEVEL(n) do { \
37 GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
38 GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
39} while (0)
40
41
42
43
44
45
46enum { SLEEP_SAVE_START = 0,
47
48 SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER,
49 SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3,
50
51 SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2,
52 SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2,
53 SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2,
54 SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2,
55 SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR2_L,
56 SLEEP_SAVE_GAFR0_U, SLEEP_SAVE_GAFR1_U, SLEEP_SAVE_GAFR2_U,
57
58 SLEEP_SAVE_ICMR,
59 SLEEP_SAVE_CKEN,
60
61 SLEEP_SAVE_CKSUM,
62
63 SLEEP_SAVE_SIZE
64};
65
66
67static int pxa_pm_enter(u32 state)
68{
69 unsigned long sleep_save[SLEEP_SAVE_SIZE];
70 unsigned long checksum = 0;
71 unsigned long delta;
72 int i;
73
74 if (state != PM_SUSPEND_MEM)
75 return -EINVAL;
76
77
78 delta = xtime.tv_sec - RCNR;
79
80
81 SAVE(OSCR);
82 SAVE(OSMR0);
83 SAVE(OSMR1);
84 SAVE(OSMR2);
85 SAVE(OSMR3);
86 SAVE(OIER);
87
88 SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2);
89 SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
90 SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
91 SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
92 SAVE(GAFR0_L); SAVE(GAFR0_U);
93 SAVE(GAFR1_L); SAVE(GAFR1_U);
94 SAVE(GAFR2_L); SAVE(GAFR2_U);
95
96 SAVE(ICMR);
97 ICMR = 0;
98
99 SAVE(CKEN);
100 CKEN = 0;
101
102
103
104
105 GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2;
106
107
108 RCSR = RCSR_SMR;
109
110
111 PSPR = virt_to_phys(pxa_cpu_resume);
112
113
114 for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
115 checksum += sleep_save[i];
116 sleep_save[SLEEP_SAVE_CKSUM] = checksum;
117
118
119 pxa_cpu_suspend();
120
121
122 checksum = 0;
123 for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
124 checksum += sleep_save[i];
125
126
127 if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) {
128#ifdef CONFIG_ARCH_LUBBOCK
129 LUB_HEXLED = 0xbadbadc5;
130#endif
131 while (1);
132 }
133
134
135 PSPR = 0;
136
137
138 RESTORE(GAFR0_L); RESTORE(GAFR0_U);
139 RESTORE(GAFR1_L); RESTORE(GAFR1_U);
140 RESTORE(GAFR2_L); RESTORE(GAFR2_U);
141 RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2);
142 RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
143 RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
144 RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
145
146 PSSR = PSSR_RDH | PSSR_PH;
147
148 RESTORE(OSMR0);
149 RESTORE(OSMR1);
150 RESTORE(OSMR2);
151 RESTORE(OSMR3);
152 RESTORE(OSCR);
153 RESTORE(OIER);
154
155 RESTORE(CKEN);
156
157 ICLR = 0;
158 ICCR = 1;
159 RESTORE(ICMR);
160
161
162 xtime.tv_sec = RCNR + delta;
163
164#ifdef DEBUG
165 printk(KERN_DEBUG "*** made it back from resume\n");
166#endif
167
168 return 0;
169}
170
171unsigned long sleep_phys_sp(void *sp)
172{
173 return virt_to_phys(sp);
174}
175
176
177
178
179static int pxa_pm_prepare(u32 state)
180{
181 return 0;
182}
183
184
185
186
187static int pxa_pm_finish(u32 state)
188{
189 return 0;
190}
191
192
193
194
195static struct pm_ops pxa_pm_ops = {
196 .pm_disk_mode = PM_DISK_FIRMWARE,
197 .prepare = pxa_pm_prepare,
198 .enter = pxa_pm_enter,
199 .finish = pxa_pm_finish,
200};
201
202static int __init pxa_pm_init(void)
203{
204 pm_set_ops(&pxa_pm_ops);
205 return 0;
206}
207
208late_initcall(pxa_pm_init);
209