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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * PXA250/210 Power Management Routines
  3.  *
  4.  * Original code for the SA11x0:
  5.  * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
  6.  *
  7.  * Modified for the PXA250 by Nicolas Pitre:
  8.  * Copyright (c) 2002 Monta Vista Software, Inc.
  9.  *
  10.  * This program is free software; you can redistribute it and/or
  11.  * modify it under the terms of the GNU General Public License.
  12.  */
  13. #include <linux/config.h>
  14. #include <linux/init.h>
  15. #include <linux/pm.h>
  16. #include <linux/slab.h>
  17. #include <linux/sched.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/sysctl.h>
  20. #include <linux/errno.h>
  21. #include <asm/hardware.h>
  22. #include <asm/memory.h>
  23. #include <asm/system.h>
  24. #include <asm/leds.h>
  25. /*
  26.  * Debug macros
  27.  */
  28. #undef DEBUG
  29. extern void pxa_cpu_suspend(void);
  30. extern void pxa_cpu_resume(void);
  31. #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
  32. #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
  33. /*
  34.  * List of global PXA peripheral registers to preserve.
  35.  * More ones like CP and general purpose register values are preserved
  36.  * with the stack pointer in sleep.S.
  37.  */
  38. enum { SLEEP_SAVE_START = 0,
  39. SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER,
  40. SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3,
  41. SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2,
  42. SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2,
  43. SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2,
  44. SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR2_L,
  45. SLEEP_SAVE_GAFR0_U, SLEEP_SAVE_GAFR1_U, SLEEP_SAVE_GAFR2_U,
  46. SLEEP_SAVE_ICMR,
  47. SLEEP_SAVE_CKEN,
  48. SLEEP_SAVE_CKSUM,
  49. SLEEP_SAVE_SIZE
  50. };
  51. int pm_do_suspend(void)
  52. {
  53. unsigned long sleep_save[SLEEP_SAVE_SIZE];
  54. unsigned long checksum = 0;
  55. int i;
  56. cli();
  57. clf();
  58. leds_event(led_stop);
  59. /* preserve current time */
  60. RCNR = xtime.tv_sec;
  61. /* save vital registers */
  62. SAVE(OSCR);
  63. SAVE(OSMR0);
  64. SAVE(OSMR1);
  65. SAVE(OSMR2);
  66. SAVE(OSMR3);
  67. SAVE(OIER);
  68. SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
  69. SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
  70. SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
  71. SAVE(GAFR0_L); SAVE(GAFR0_U);
  72. SAVE(GAFR1_L); SAVE(GAFR1_U);
  73. SAVE(GAFR2_L); SAVE(GAFR2_U);
  74. SAVE(ICMR);
  75. ICMR = 0;
  76. SAVE(CKEN);
  77. CKEN = 0;
  78. /* Note: wake up source are set up in each machine specific files */
  79. /* clear GPIO transition detect  bits */
  80. GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2;
  81. /* Clear sleep reset status */
  82. RCSR = RCSR_SMR;
  83. /* set resume return address */
  84. PSPR = virt_to_phys(pxa_cpu_resume);
  85. // before sleeping, calculate and save a checksum
  86. for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
  87. checksum += sleep_save[i];
  88. sleep_save[SLEEP_SAVE_CKSUM] = checksum;
  89. /* *** go zzz *** */
  90. pxa_cpu_suspend();
  91. /* after sleeping, validate the checksum */
  92. checksum = 0;
  93. for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
  94. checksum += sleep_save[i];
  95. /* if invalid, display message and wait for a hardware reset */
  96. if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) {
  97. #ifdef CONFIG_ARCH_LUBBOCK
  98. LUB_HEXLED = 0xbadbadc5;
  99. #endif
  100. while (1);
  101. }
  102. /* ensure not to come back here if it wasn't intended */
  103. PSPR = 0;
  104. /* restore registers */
  105. RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
  106. RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
  107. RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
  108. RESTORE(GAFR0_L); RESTORE(GAFR0_U);
  109. RESTORE(GAFR1_L); RESTORE(GAFR1_U);
  110. RESTORE(GAFR2_L); RESTORE(GAFR2_U);
  111. PSSR = PSSR_PH;
  112. RESTORE(OSMR0);
  113. RESTORE(OSMR1);
  114. RESTORE(OSMR2);
  115. RESTORE(OSMR3);
  116. RESTORE(OSCR);
  117. RESTORE(OIER);
  118. RESTORE(CKEN);
  119. ICLR = 0;
  120. ICCR = 1;
  121. RESTORE(ICMR);
  122. /* restore current time */
  123. xtime.tv_sec = RCNR;
  124. #ifdef DEBUG
  125. #error this requires more registers to be preserved/restored to work
  126. printk(KERN_DEBUG "*** made it back from resumen");
  127. #endif
  128. leds_event(led_start);
  129. sti();
  130. return 0;
  131. }
  132. unsigned long sleep_phys_sp(void *sp)
  133. {
  134. return virt_to_phys(sp);
  135. }
  136. #ifdef CONFIG_SYSCTL
  137. /*
  138.  * ARGH!  ACPI people defined CTL_ACPI in linux/acpi.h rather than
  139.  * linux/sysctl.h.
  140.  *
  141.  * This means our interface here won't survive long - it needs a new
  142.  * interface.  Quick hack to get this working - use sysctl id 9999.
  143.  */
  144. #warning ACPI broke the kernel, this interface needs to be fixed up.
  145. #define CTL_ACPI 9999
  146. #define ACPI_S1_SLP_TYP 19
  147. /*
  148.  * Send us to sleep.
  149.  */
  150. static int sysctl_pm_do_suspend(void)
  151. {
  152. int retval;
  153. retval = pm_send_all(PM_SUSPEND, (void *)3);
  154. if (retval == 0) {
  155. retval = pm_do_suspend();
  156. pm_send_all(PM_RESUME, (void *)0);
  157. }
  158. return retval;
  159. }
  160. static struct ctl_table pm_table[] =
  161. {
  162. {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_do_suspend},
  163. {0}
  164. };
  165. static struct ctl_table pm_dir_table[] =
  166. {
  167. {CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
  168. {0}
  169. };
  170. /*
  171.  * Initialize power interface
  172.  */
  173. static int __init pm_init(void)
  174. {
  175. register_sysctl_table(pm_dir_table, 1);
  176. return 0;
  177. }
  178. __initcall(pm_init);
  179. #endif