pm.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:4k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * SA1100 Power Management Routines
  3.  *
  4.  * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
  5.  *
  6.  * This program is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU General Public License.
  8.  *
  9.  * History:
  10.  *
  11.  * 2001-02-06: Cliff Brake         Initial code
  12.  *
  13.  * 2001-02-25: Sukjae Cho <sjcho@east.isi.edu> &
  14.  *  Chester Kuo <chester@linux.org.tw>
  15.  *  Save more value for the resume function! Support
  16.  *  Bitsy/Assabet/Freebird board
  17.  *
  18.  * 2001-08-29: Nicolas Pitre <nico@cam.org>
  19.  *  Cleaned up, pushed platform dependent stuff
  20.  *  in the platform specific files.
  21.  *
  22.  * 2002-05-27: Nicolas Pitre Killed sleep.h and the kmalloced save array.
  23.  *  Storage is local on the stack now.
  24.  */
  25. #include <linux/config.h>
  26. #include <linux/init.h>
  27. #include <linux/pm.h>
  28. #include <linux/sched.h>
  29. #include <linux/interrupt.h>
  30. #include <linux/sysctl.h>
  31. #include <linux/errno.h>
  32. #include <asm/hardware.h>
  33. #include <asm/memory.h>
  34. #include <asm/system.h>
  35. #include <asm/leds.h>
  36. /*
  37.  * Debug macros
  38.  */
  39. #undef DEBUG
  40. extern void sa1100_cpu_suspend(void);
  41. extern void sa1100_cpu_resume(void);
  42. #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
  43. #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
  44. /*
  45.  * List of global SA11x0 peripheral registers to preserve.
  46.  * More ones like CP and general purpose register values are preserved
  47.  * with the stack location in sleep.S.
  48.  */
  49. enum { SLEEP_SAVE_START = 0,
  50. SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER,
  51. SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3,
  52. SLEEP_SAVE_GPDR, SLEEP_SAVE_GRER, SLEEP_SAVE_GFER, SLEEP_SAVE_GAFR,
  53. SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR,
  54. SLEEP_SAVE_ICMR,
  55. SLEEP_SAVE_Ser1SDCR0,
  56. SLEEP_SAVE_SIZE
  57. };
  58. int pm_do_suspend(void)
  59. {
  60. unsigned long sleep_save[SLEEP_SAVE_SIZE];
  61. cli();
  62. leds_event(led_stop);
  63. /* preserve current time */
  64. RCNR = xtime.tv_sec;
  65. /* save vital registers */
  66. SAVE(OSCR);
  67. SAVE(OSMR0);
  68. SAVE(OSMR1);
  69. SAVE(OSMR2);
  70. SAVE(OSMR3);
  71. SAVE(OIER);
  72. SAVE(GPDR);
  73. SAVE(GRER);
  74. SAVE(GFER);
  75. SAVE(GAFR);
  76. SAVE(PPDR);
  77. SAVE(PPSR);
  78. SAVE(PPAR);
  79. SAVE(PSDR);
  80. SAVE(Ser1SDCR0);
  81. SAVE(ICMR);
  82. /* ... maybe a global variable initialized by arch code to set this? */
  83. GRER = PWER;
  84. GFER = 0;
  85. GEDR = GEDR;
  86. /* Clear previous reset status */
  87. RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR;
  88. /* set resume return address */
  89. PSPR = virt_to_phys(sa1100_cpu_resume);
  90. /* go zzz */
  91. sa1100_cpu_suspend();
  92. /* ensure not to come back here if it wasn't intended */
  93. PSPR = 0;
  94. #ifdef DEBUG
  95. printk(KERN_DEBUG "*** made it back from resumen");
  96. #endif
  97. /* restore registers */
  98. RESTORE(GPDR);
  99. RESTORE(GRER);
  100. RESTORE(GFER);
  101. RESTORE(GAFR);
  102. /* clear any edge detect bit */
  103. GEDR = GEDR;
  104. RESTORE(PPDR);
  105. RESTORE(PPSR);
  106. RESTORE(PPAR);
  107. RESTORE(PSDR);
  108. RESTORE(Ser1SDCR0);
  109. PSSR = PSSR_PH;
  110. RESTORE(OSMR0);
  111. RESTORE(OSMR1);
  112. RESTORE(OSMR2);
  113. RESTORE(OSMR3);
  114. RESTORE(OSCR);
  115. RESTORE(OIER);
  116. ICLR = 0;
  117. ICCR = 1;
  118. RESTORE(ICMR);
  119. /* restore current time */
  120. xtime.tv_sec = RCNR;
  121. leds_event(led_start);
  122. sti();
  123. /*
  124.  * Restore the CPU frequency settings.
  125.  */
  126. #ifdef CONFIG_CPU_FREQ
  127. cpufreq_restore();
  128. #endif
  129. return 0;
  130. }
  131. unsigned long sleep_phys_sp(void *sp)
  132. {
  133. return virt_to_phys(sp);
  134. }
  135. #ifdef CONFIG_SYSCTL
  136. /*
  137.  * ARGH!  ACPI people defined CTL_ACPI in linux/acpi.h rather than
  138.  * linux/sysctl.h.
  139.  *
  140.  * This means our interface here won't survive long - it needs a new
  141.  * interface.  Quick hack to get this working - use sysctl id 9999.
  142.  */
  143. #warning ACPI broke the kernel, this interface needs to be fixed up.
  144. #define CTL_ACPI 9999
  145. #define ACPI_S1_SLP_TYP 19
  146. /*
  147.  * Send us to sleep.
  148.  */
  149. static int sysctl_pm_do_suspend(void)
  150. {
  151. int retval;
  152. retval = pm_send_all(PM_SUSPEND, (void *)3);
  153. if (retval == 0) {
  154. retval = pm_do_suspend();
  155. pm_send_all(PM_RESUME, (void *)0);
  156. }
  157. return retval;
  158. }
  159. static struct ctl_table pm_table[] =
  160. {
  161. {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_do_suspend},
  162. {0}
  163. };
  164. static struct ctl_table pm_dir_table[] =
  165. {
  166. {CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
  167. {0}
  168. };
  169. /*
  170.  * Initialize power interface
  171.  */
  172. static int __init pm_init(void)
  173. {
  174. register_sysctl_table(pm_dir_table, 1);
  175. return 0;
  176. }
  177. __initcall(pm_init);
  178. #endif