]> pilppa.org Git - familiar-h63xx-build.git/blob - org.handhelds.familiar/packages/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/simpad-apm.patch
OE tree imported from monotone branch org.openembedded.oz354fam083 at revision 8b12e3...
[familiar-h63xx-build.git] / org.handhelds.familiar / packages / linux / opensimpad-2.4.27-vrs1-pxa1-jpm1 / simpad-apm.patch
1
2 #
3 # Patch managed by http://www.holgerschurig.de/patcher.html
4 #
5
6 --- /dev/null
7 +++ linux-2.4.27/arch/arm/mach-sa1100/pm-common.c
8 @@ -0,0 +1,268 @@
9 +/*
10 + * SA1100 Power Management Routines
11 + *
12 + * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
13 + *
14 + * This program is free software; you can redistribute it and/or
15 + * modify it under the terms of the GNU General Public License.
16 + *
17 + * History:
18 + *
19 + * 2001-02-06: Cliff Brake         Initial code
20 + *
21 + * 2001-02-25: Sukjae Cho <sjcho@east.isi.edu> &
22 + *             Chester Kuo <chester@linux.org.tw>
23 + *                     Save more value for the resume function! Support
24 + *                     Bitsy/Assabet/Freebird board
25 + *
26 + * 2001-08-29: Nicolas Pitre <nico@cam.org>
27 + *                     Cleaned up, pushed platform dependent stuff
28 + *                     in the platform specific files.
29 + *
30 + * 2002-05-27: Nicolas Pitre   Killed sleep.h and the kmalloced save array.
31 + *                             Storage is local on the stack now.
32 + */
33 +#include <linux/config.h>
34 +#include <linux/module.h>
35 +#include <linux/init.h>
36 +#include <linux/pm.h>
37 +#include <linux/slab.h>
38 +#include <linux/sched.h>
39 +#include <linux/interrupt.h>
40 +#include <linux/sysctl.h>
41 +#include <linux/errno.h>
42 +#include <linux/cpufreq.h>
43 +
44 +#include <asm/hardware.h>
45 +#include <asm/memory.h>
46 +#include <asm/system.h>
47 +#include <asm/leds.h>
48 +#include <asm/uaccess.h>
49 +
50 +
51 +#ifdef CONFIG_IPAQ_HANDHELD
52 +#include <asm/arch-sa1100/h3600_asic.h>
53 +#endif
54 +
55 +#define __KERNEL_SYSCALLS__
56 +#include <linux/unistd.h>
57 +
58 +/*
59 + * Debug macros
60 + */
61 +#undef DEBUG
62 +
63 +\f
64 +
65 +static char pm_helper_path[128] = "/sbin/pm_helper";
66 +extern int exec_usermodehelper(char *path, char **argv, char **envp);
67 +int debug_pm = 0;
68 +static int pm_helper_veto = 0;
69 +
70 +static int
71 +run_sbin_pm_helper( pm_request_t action )
72 +{
73 +       int i;
74 +       char *argv[3], *envp[8];
75 +
76 +       if (!pm_helper_path[0])
77 +               return 2;
78 +
79 +       if ( action != PM_SUSPEND && action != PM_RESUME )
80 +               return 1;
81 +
82 +       /* Be root */
83 +       current->uid = current->gid = 0;
84 +
85 +       i = 0;
86 +       argv[i++] = pm_helper_path;
87 +       argv[i++] = (action == PM_RESUME ? "resume" : "suspend");
88 +       argv[i] = 0;
89 +
90 +       i = 0;
91 +       /* minimal command environment */
92 +       envp[i++] = "HOME=/";
93 +       envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
94 +       envp[i] = 0;
95 +
96 +       /* other stuff we want to pass to /sbin/pm_helper */
97 +       return exec_usermodehelper (argv [0], argv, envp);
98 +}
99 +
100 +/*
101 + * If pm_suggest_suspend_hook is non-NULL, it is called by pm_suggest_suspend.
102 + */
103 +int (*pm_suggest_suspend_hook)(int state);
104 +EXPORT_SYMBOL(pm_suggest_suspend_hook);
105 +
106 +/*
107 + * If pm_use_sbin_pm_helper is nonzero, then run_sbin_pm_helper is called before suspend and after resume
108 + */
109 +int pm_use_sbin_pm_helper = 1;
110 +EXPORT_SYMBOL(pm_use_sbin_pm_helper);
111 +
112 +/*
113 + * If sysctl_pm_do_suspend_hook is non-NULL, it is called by sysctl_pm_do_suspend.
114 + * If it returns a true value, then pm_suspend is not called. 
115 + * Use this to hook in apmd, for now.
116 + */
117 +int (*pm_sysctl_suspend_hook)(int state);
118 +EXPORT_SYMBOL(pm_sysctl_suspend_hook);
119 +
120 +int pm_suspend(void);
121 +
122 +int pm_suggest_suspend(void)
123 +{
124 +       int retval;
125 +
126 +       if (pm_suggest_suspend_hook) {
127 +               if (pm_suggest_suspend_hook(PM_SUSPEND))
128 +                       return 0;
129 +       }
130 +       
131 +       if (pm_use_sbin_pm_helper) {
132 +               pid_t pid;
133 +               int res;
134 +               int status = 0;
135 +               unsigned int old_fs;
136 +               
137 +               pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_SUSPEND, 0 );
138 +               if ( pid < 0 )
139 +                       return pid;
140 +
141 +               if (debug_pm)
142 +                       printk(KERN_CRIT "%s:%d got pid=%d\n", __FUNCTION__, __LINE__, pid);    
143 +                       
144 +               old_fs = get_fs ();
145 +               set_fs (get_ds ());
146 +               res = waitpid(pid, &status, __WCLONE);
147 +               set_fs (old_fs);
148 +       
149 +               if ( pid != res ) {
150 +                       if (debug_pm)
151 +                               printk(KERN_CRIT ": waitpid returned %d (exit_code=%d); not suspending\n", res, status );
152 +                       
153 +                       return -1;
154 +               }
155 +                       
156 +               /*if ( WIFEXITED(status) && ( WIFEXITSTATUS(status) != 0 )) {*/
157 +               if (( status & 0xff7f ) != 0 ) {
158 +                       if (pm_helper_veto) {
159 +                               if (debug_pm)
160 +                                       printk(KERN_CRIT "%s: SUSPEND WAS CANCELLED BY pm_helper (exit status %d)\n", __FUNCTION__, status >> 8);
161 +                               return -1;
162 +                       } else {
163 +                               if (debug_pm)
164 +                                       printk(KERN_CRIT "%s: pm_helper returned %d, but going ahead anyway\n", __FUNCTION__, status >> 8);
165 +                       }
166 +               }
167 +       }
168 +
169 +       if (debug_pm)
170 +               printk(KERN_CRIT "%s: REALLY SUSPENDING NOW\n", __FUNCTION__ );
171 +
172 +       if (pm_sysctl_suspend_hook) {
173 +               if (pm_sysctl_suspend_hook(PM_SUSPEND))
174 +                       return 0;
175 +       }
176 +
177 +       retval = pm_suspend();
178 +       if (retval) {
179 +               if (debug_pm)
180 +                       printk(KERN_CRIT "pm_suspend returned %d\n", retval);
181 +               return retval;
182 +       }
183 +
184 +       if (pm_use_sbin_pm_helper) {
185 +               pid_t pid;
186 +               
187 +               if (debug_pm)
188 +                       printk(KERN_CRIT "%s: running pm_helper for wakeup\n", __FUNCTION__);
189 +
190 +               pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_RESUME, 0 );
191 +               if ( pid < 0 )
192 +                       return pid;
193 +                       
194 +               if ( pid != waitpid ( pid, NULL, __WCLONE ))
195 +                       return -1;
196 +       }
197 +
198 +       return 0;
199 +}
200 +
201 +EXPORT_SYMBOL(pm_suggest_suspend);
202 +
203 +
204 +/*
205 + * Send us to sleep.
206 + */
207 +int pm_suspend(void)
208 +{
209 +       int retval;
210 +
211 +       retval = pm_send_all(PM_SUSPEND, (void *)3);
212 +       if ( retval )
213 +               return retval;
214 +
215 +#ifdef CONFIG_IPAQ_HANDHELD
216 +       retval = h3600_power_management(PM_SUSPEND);
217 +       if (retval) {
218 +               pm_send_all(PM_RESUME, (void *)0);
219 +               return retval;
220 +       }
221 +#endif
222 +
223 +       retval = pm_do_suspend();
224 +
225 +#ifdef CONFIG_IPAQ_HANDHELD
226 +       /* Allow the power management routines to override resuming */
227 +       while ( h3600_power_management(PM_RESUME) )
228 +               retval = pm_do_suspend();
229 +#endif
230 +
231 +       pm_send_all(PM_RESUME, (void *)0);
232 +
233 +       return retval;
234 +}
235 +EXPORT_SYMBOL(pm_suspend);
236 +
237 +#ifdef CONFIG_SYSCTL
238 +/*
239 + * ARGH!  ACPI people defined CTL_ACPI in linux/acpi.h rather than
240 + * linux/sysctl.h.
241 + *
242 + * This means our interface here won't survive long - it needs a new
243 + * interface.  Quick hack to get this working - use sysctl id 9999.
244 + */
245 +#warning ACPI broke the kernel, this interface needs to be fixed up.
246 +#define CTL_ACPI 9999
247 +#define ACPI_S1_SLP_TYP 19
248 +
249 +static struct ctl_table pm_table[] =
250 +{
251 +/*     {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_suspend},*/
252 +       {2, "helper", pm_helper_path, sizeof(pm_helper_path), 0644, NULL, (proc_handler *)&proc_dostring},
253 +       {3, "debug", &debug_pm, sizeof(debug_pm), 0644, NULL, (proc_handler *)&proc_dointvec},
254 +       {4, "helper_veto", &pm_helper_veto, sizeof(pm_helper_veto), 0644, NULL, (proc_handler *)&proc_dointvec},
255 +       {0}
256 +};
257 +
258 +static struct ctl_table pm_dir_table[] =
259 +{
260 +       {CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
261 +       {0}
262 +};
263 +
264 +/*
265 + * Initialize power interface
266 + */
267 +static int __init pm_init(void)
268 +{
269 +       register_sysctl_table(pm_dir_table, 1);
270 +       return 0;
271 +}
272 +
273 +__initcall(pm_init);
274 +
275 +#endif
276 +
277 --- linux-2.4.27/arch/arm/mach-sa1100/apm.c~simpad-apm
278 +++ linux-2.4.27/arch/arm/mach-sa1100/apm.c
279 @@ -32,9 +32,7 @@
280  
281  #include <asm/system.h>
282  #include <asm/hardware.h>
283 -#if FIXME
284  #include <asm/arch-sa1100/pm.h>
285 -#endif
286  
287  #ifdef CONFIG_IPAQ_HANDHELD
288  #include <asm/arch-sa1100/h3600_hal.h>
289 @@ -92,6 +90,8 @@
290         int             magic;
291         struct apm_user *       next;
292         int             suser: 1;
293 +       int             writer: 1;
294 +       int             reader: 1;
295         int             suspend_wait: 1;
296         int             suspend_result;
297         int             suspends_pending;
298 @@ -111,7 +111,7 @@
299  /*
300   * Local variables
301   */
302 -//static int                   suspends_pending;
303 +static int                     suspends_pending;
304  //static int                   standbys_pending;
305  //static int                   ignore_normal_resume;
306  
307 @@ -129,8 +129,6 @@
308  #else
309  static int                     power_off = 1;
310  #endif
311 -static int                     exit_kapmd;
312 -static int                     kapmd_running;
313  
314  static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
315  static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
316 @@ -190,6 +188,42 @@
317         return as->events[as->event_tail];
318  }
319  
320 +static void queue_event(apm_event_t event, struct apm_user *sender)
321 +{
322 +       struct apm_user *       as;
323 +
324 +       if (user_list == NULL)
325 +               return;
326 +       for (as = user_list; as != NULL; as = as->next) {
327 +               if ((as == sender) || (!as->reader))
328 +                       continue;
329 +               as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
330 +               if (as->event_head == as->event_tail) {
331 +                       static int notified;
332 +
333 +                       if (notified++ == 0)
334 +                           printk(KERN_ERR "apm: an event queue overflowed\n");
335 +                       as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
336 +               }
337 +               as->events[as->event_head] = event;
338 +               if ((!as->suser) || (!as->writer))
339 +                       continue;
340 +               switch (event) {
341 +               case APM_SYS_SUSPEND:
342 +               case APM_USER_SUSPEND:
343 +                       as->suspends_pending++;
344 +                       suspends_pending++;
345 +                       break;
346 +
347 +               case APM_SYS_STANDBY:
348 +               case APM_USER_STANDBY:
349 +                       as->standbys_pending++;
350 +                       break;
351 +               }
352 +       }
353 +       wake_up_interruptible(&apm_waitqueue);
354 +}
355 +
356  static int check_apm_user(struct apm_user *as, const char *func)
357  {
358         if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
359 @@ -228,7 +262,6 @@
360         i = count;
361         while ((i >= sizeof(event)) && !queue_empty(as)) {
362                 event = get_queued_event(as);
363 -                printk("  do_read: event=%d\n", event);
364                 if (copy_to_user(buf, &event, sizeof(event))) {
365                         if (i < count)
366                                 break;
367 @@ -280,9 +313,17 @@
368                 return -EPERM;
369         switch (cmd) {
370          case APM_IOC_SUSPEND:
371 -#if FIXME
372 -               pm_suggest_suspend();
373 -#endif
374 +               if (as->suspends_read > 0) {
375 +                       as->suspends_read--;
376 +                       as->suspends_pending--;
377 +                       suspends_pending--;
378 +               } else {
379 +                       queue_event(APM_USER_SUSPEND, as);
380 +               }
381 +
382 +               if (suspends_pending <= 0)
383 +                       wake_up(&apm_suspend_waitqueue);
384 +               
385                 break;
386         default:
387                 return -EINVAL;
388 @@ -299,6 +340,20 @@
389                 return 0;
390         filp->private_data = NULL;
391         lock_kernel();
392 +       if (user_list == as)
393 +               user_list = as->next;
394 +       else {
395 +               struct apm_user *       as1;
396 +
397 +               for (as1 = user_list;
398 +                    (as1 != NULL) && (as1->next != as);
399 +                    as1 = as1->next)
400 +                       ;
401 +               if (as1 == NULL)
402 +                       printk(KERN_ERR "apm: filp not in user list\n");
403 +               else
404 +                       as1->next = as->next;
405 +       }
406         unlock_kernel();
407         kfree(as);
408         return 0;
409 @@ -326,6 +381,8 @@
410          * privileged operation -- cevans
411          */
412         as->suser = capable(CAP_SYS_ADMIN);
413 +       as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
414 +       as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
415         as->next = user_list;
416         user_list = as;
417         filp->private_data = as;
418 @@ -409,34 +466,6 @@
419         return p - buf;
420  }
421  
422 -#ifndef MODULE
423 -static int __init apm_setup(char *str)
424 -{
425 -       int     invert;
426 -
427 -       while ((str != NULL) && (*str != '\0')) {
428 -               if (strncmp(str, "off", 3) == 0)
429 -                       apm_disabled = 1;
430 -               if (strncmp(str, "on", 2) == 0)
431 -                       apm_disabled = 0;
432 -               invert = (strncmp(str, "no-", 3) == 0);
433 -               if (invert)
434 -                       str += 3;
435 -               if (strncmp(str, "debug", 5) == 0)
436 -                       debug = !invert;
437 -               if ((strncmp(str, "power-off", 9) == 0) ||
438 -                   (strncmp(str, "power_off", 9) == 0))
439 -                       power_off = !invert;
440 -               str = strchr(str, ',');
441 -               if (str != NULL)
442 -                       str += strspn(str, ", \t");
443 -       }
444 -       return 1;
445 -}
446 -
447 -__setup("apm=", apm_setup);
448 -#endif
449 -
450  static struct file_operations apm_bios_fops = {
451         owner:          THIS_MODULE,
452         read:           do_read,
453 @@ -454,6 +483,50 @@
454  
455  #define APM_INIT_ERROR_RETURN  return -1
456  
457 +static pid_t apmd_pid;
458 +static DECLARE_COMPLETION(apmd_exited);
459 +
460 +static int apm(void *unused)
461 +{
462 +       unsigned short  bx;
463 +       unsigned short  cx;
464 +       unsigned short  dx;
465 +       int             error;
466 +       char *          power_stat;
467 +       char *          bat_stat;
468 +       DECLARE_WAITQUEUE(wait, current);
469 +       struct apm_user au, *as;
470 +
471 +       lock_kernel();
472 +
473 +       daemonize();
474 +
475 +       strcpy(current->comm, "kapmd");
476 +
477 +       as = &au;
478 +       as->magic = APM_BIOS_MAGIC;
479 +       as->event_tail = as->event_head = 0;
480 +       as->suspends_pending = as->standbys_pending = 0;
481 +       as->suspends_read = as->standbys_read = 0;
482 +       as->suser = 1;
483 +       as->writer = 1;
484 +       as->reader = 0;
485 +
486 +       for (;;) {
487 +               interruptible_sleep_on(&apm_suspend_waitqueue);
488 +               if (signal_pending (current))
489 +                       break;
490 +
491 +               pm_suggest_suspend();
492 +
493 +               queue_event(APM_NORMAL_RESUME, as);
494 +       }
495 +
496 +       unlock_kernel();
497 +
498 +       complete_and_exit(&apmd_exited, 0);
499 +}
500 +
501  /*
502   * Just start the APM thread. We do NOT want to do APM BIOS
503   * calls from anything but the APM thread, if for no other reason
504 @@ -492,6 +563,8 @@
505  
506         misc_register(&apm_device);
507  
508 +       apmd_pid = kernel_thread(apm, NULL, 0);
509 +
510         return 0;
511  }
512  
513 @@ -499,11 +572,10 @@
514  {
515         misc_deregister(&apm_device);
516         remove_proc_entry("apm", NULL);
517 +       kill_proc (apmd_pid, SIGTERM, 1);
518 +       wait_for_completion(&apmd_exited);
519         if (power_off)
520                 pm_power_off = NULL;
521 -       exit_kapmd = 1;
522 -       while (kapmd_running)
523 -               schedule();
524         pm_active = 0;
525  }
526  
527 @@ -512,6 +584,7 @@
528  
529  MODULE_AUTHOR("Jamey Hicks, pulling bits from original by Stephen Rothwell");
530  MODULE_DESCRIPTION("A minimal emulation of APM");
531 +MODULE_LICENSE("GPL");
532  MODULE_PARM(debug, "i");
533  MODULE_PARM_DESC(debug, "Enable debug mode");
534  MODULE_PARM(power_off, "i");
535 --- /dev/null
536 +++ linux-2.4.27/include/asm-arm/arch-sa1100/pm.h
537 @@ -0,0 +1,20 @@
538 +/*
539 + *
540 + * Declarations for ARM Linux Power Management
541 + *
542 + * Copyright 2002 Compaq Computer Corporation.
543 + *
544 + * This program is free software; you can redistribute it and/or modify
545 + * it under the terms of the GNU General Public License version 2 as
546 + * published by the Free Software Foundation.
547 + *
548 + * Author: Jamey Hicks.
549 + *
550 + */
551 +
552 +
553 +extern int (*pm_suggest_suspend_hook)(int state);
554 +extern int (*pm_sysctl_suspend_hook)(int state);
555 +extern int pm_use_sbin_pm_helper; 
556 +extern int pm_suspend(void);
557 +extern int pm_suggest_suspend(void); /* triggers /sbin/pm_helper or queueing event to apmd */
558 --- linux-2.4.27/arch/arm/mach-sa1100/Makefile~simpad-apm
559 +++ linux-2.4.27/arch/arm/mach-sa1100/Makefile
560 @@ -19,7 +19,7 @@
561                 flexanet.o freebird.o frodo.o generic.o h3600.o \
562                 huw_webpanel.o irq.o sa1111.o sa1111-pcibuf.o \
563                 system3.o yopy.o usb_ctl.o usb_recv.o usb_send.o simputer.o ssp.o \
564 -               simpad.o
565 +               simpad.o pm-sa1100.o
566  
567  # These aren't present yet, and prevents a plain -ac kernel building.
568  # hwtimer.o
569 @@ -105,7 +105,7 @@
570  obj-$(CONFIG_SA1100_USB_CHAR) += usb-char.o
571  
572  # Miscelaneous functions
573 -obj-$(CONFIG_PM) += pm.o sleep.o
574 +obj-$(CONFIG_PM) += pm-sa1100.o sleep.o
575  obj-$(CONFIG_APM) += apm.o
576  
577  # SIMpad specific
578 --- /dev/null
579 +++ linux-2.4.27/arch/arm/mach-sa1100/pm-sa1100.c
580 @@ -0,0 +1,225 @@
581 +/*
582 + * SA1100 Power Management Routines
583 + *
584 + * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
585 + *
586 + * This program is free software; you can redistribute it and/or
587 + * modify it under the terms of the GNU General Public License.
588 + *
589 + * History:
590 + *
591 + * 2001-02-06: Cliff Brake         Initial code
592 + *
593 + * 2001-02-25: Sukjae Cho <sjcho@east.isi.edu> &
594 + *             Chester Kuo <chester@linux.org.tw>
595 + *                     Save more value for the resume function! Support
596 + *                     Bitsy/Assabet/Freebird board
597 + *
598 + * 2001-08-29: Nicolas Pitre <nico@cam.org>
599 + *                     Cleaned up, pushed platform dependent stuff
600 + *                     in the platform specific files.
601 + *
602 + * 2002-05-27: Nicolas Pitre   Killed sleep.h and the kmalloced save array.
603 + *                             Storage is local on the stack now.
604 + */
605 +#include <linux/config.h>
606 +#include <linux/module.h>
607 +#include <linux/init.h>
608 +#include <linux/pm.h>
609 +#include <linux/slab.h>
610 +#include <linux/sched.h>
611 +#include <linux/interrupt.h>
612 +#include <linux/sysctl.h>
613 +#include <linux/errno.h>
614 +#include <linux/cpufreq.h>
615 +
616 +#include <asm/hardware.h>
617 +#include <asm/memory.h>
618 +#include <asm/system.h>
619 +#include <asm/leds.h>
620 +
621 +
622 +#ifdef CONFIG_IPAQ_HANDHELD
623 +#include <asm/arch/h3600_asic.h>
624 +#endif
625 +
626 +#define __KERNEL_SYSCALLS__
627 +#include <linux/unistd.h>
628 +
629 +extern void sa1100_cpu_suspend(void);
630 +extern void sa1100_cpu_resume(void);
631 +extern int debug_pm;
632 +
633 +#define SAVE(x)                sleep_save[SLEEP_SAVE_##x] = x
634 +#define RESTORE(x)     x = sleep_save[SLEEP_SAVE_##x]
635 +
636 +/*
637 + * List of global SA11x0 peripheral registers to preserve.
638 + * More ones like CP and general purpose register values are preserved
639 + * with the stack location in sleep.S.
640 + */
641 +enum { SLEEP_SAVE_START = 0,
642 +
643 +       SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER,
644 +       SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3,
645 +
646 +       SLEEP_SAVE_GPDR, SLEEP_SAVE_GRER, SLEEP_SAVE_GFER, SLEEP_SAVE_GAFR,
647 +       SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR,
648 +
649 +       SLEEP_SAVE_ICMR,
650 +#ifdef CONFIG_SA1100_SIMPAD
651 +       SLEEP_SAVE_MECR, /* needed by SIMpad to get PCMCIA working after resume */
652 +#endif
653 +       SLEEP_SAVE_Ser1SDCR0,
654 +
655 +        SLEEP_SAVE_PWER,
656 +        SLEEP_SAVE_MSC1, SLEEP_SAVE_MSC2,
657 +
658 +       SLEEP_SAVE_SIZE
659 +};
660 +
661 +
662 +int pm_do_suspend(void)
663 +{
664 +       unsigned long sleep_save[SLEEP_SAVE_SIZE];
665 +
666 +       cli();
667 +
668 +       leds_event(led_stop);
669 +
670 +       /* preserve current time */
671 +       RCNR = xtime.tv_sec;
672 +
673 +       /* save vital registers */
674 +       SAVE(OSCR);
675 +       SAVE(OSMR0);
676 +       SAVE(OSMR1);
677 +       SAVE(OSMR2);
678 +       SAVE(OSMR3);
679 +       SAVE(OIER);
680 +
681 +       SAVE(GPDR);
682 +       SAVE(GRER);
683 +       SAVE(GFER);
684 +       SAVE(GAFR);
685 +
686 +       SAVE(PPDR);
687 +       SAVE(PPSR);
688 +       SAVE(PPAR);
689 +       SAVE(PSDR);
690 +
691 +       SAVE(Ser1SDCR0);
692 +
693 +       SAVE(ICMR);
694 +#ifdef CONFIG_SA1100_SIMPAD
695 +       SAVE(MECR);
696 +#endif
697 +        SAVE(PWER);
698 +        SAVE(MSC1);
699 +        SAVE(MSC2);
700 +
701 +       /* ... maybe a global variable initialized by arch code to set this? */
702 +       GRER &= PWER;
703 +       GFER &= PWER;
704 +       // Ugly, but I need the AC inserted event
705 +       // In the future, we're going to care about DCD and USB interrupts as well
706 +       if ( machine_is_h3800()) {
707 +#ifdef CONFIG_IPAQ_HANDHELD
708 +               GFER = GPIO_H3800_AC_IN;
709 +#endif
710 +       } else {
711 +               GFER = 0;
712 +               if (machine_is_jornada56x()) {
713 +                       /* jca */
714 +                       GFER = PWER;
715 +                       ICMR |= PWER;
716 +               }
717 +       }
718 +       GEDR = GEDR;
719 +
720 +       /* Clear previous reset status */
721 +       RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR;
722 +
723 +       /* set resume return address */
724 +       PSPR = virt_to_phys(sa1100_cpu_resume);
725 +
726 +       /* go zzz */
727 +       sa1100_cpu_suspend();
728 +
729 +       /* ensure not to come back here if it wasn't intended */
730 +       PSPR = 0;
731 +
732 +       if (debug_pm)
733 +               printk(KERN_CRIT "*** made it back from resume\n");
734 +
735 +#ifdef CONFIG_IPAQ_HANDHELD
736 +       if ( machine_is_ipaq()) {
737 +               ipaq_model_ops.gedr = GEDR;
738 +               ipaq_model_ops.icpr = ICPR;
739 +       }
740 +#endif
741 +
742 +       /* restore registers */
743 +       RESTORE(GPDR);
744 +       RESTORE(GRER);
745 +       RESTORE(GFER);
746 +       RESTORE(GAFR);
747 +
748 +       /* clear any edge detect bit */
749 +       GEDR = GEDR;
750 +
751 +       RESTORE(PPDR);
752 +       RESTORE(PPSR);
753 +       RESTORE(PPAR);
754 +       RESTORE(PSDR);
755 +
756 +       RESTORE(Ser1SDCR0);
757 +
758 +       PSSR = PSSR_PH;
759 +
760 +       RESTORE(OSMR0);
761 +       RESTORE(OSMR1);
762 +       RESTORE(OSMR2);
763 +       RESTORE(OSMR3);
764 +       RESTORE(OSCR);
765 +       RESTORE(OIER);
766 +
767 +#ifdef CONFIG_IPAQ_HANDHELD
768 +/* OSMR0 may have fired before we went to sleep, but after interrupts
769 +   were shut off.  Set OSMR0 to something plausible */
770 +       OSMR0 = OSCR + LATCH;
771 +#endif
772 +       ICLR = 0;
773 +       ICCR = 1;
774 +       RESTORE(ICMR);
775 +#ifdef CONFIG_SA1100_SIMPAD
776 +       RESTORE(MECR);
777 +#endif
778 +       RESTORE(PWER);
779 +       RESTORE(MSC1);
780 +       RESTORE(MSC2);
781 +       /* restore current time */
782 +       xtime.tv_sec = RCNR;
783 +
784 +       leds_event(led_start);
785 +       
786 +       sti();
787 +
788 +       if (debug_pm)
789 +               printk("interrupts are enabled\n");
790 +
791 +       /*
792 +        * Restore the CPU frequency settings.
793 +        */
794 +#ifdef CONFIG_CPU_FREQ
795 +       cpufreq_restore();
796 +#endif
797 +       return 0;
798 +}
799 +
800 +unsigned long sleep_phys_sp(void *sp)
801 +{
802 +       return virt_to_phys(sp);
803 +}
804 +
805 +#include "pm-common.c"