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

嵌入式Linux

开发平台:

Unix_Linux

  1. #include <linux/config.h>
  2. #include <linux/init.h>
  3. #include <linux/pm.h>
  4. #include <linux/sysctl.h>
  5. #ifdef CONFIG_PROC_FS
  6. #include <linux/proc_fs.h>
  7. #endif
  8. #include <asm/hardware.h>
  9. /*
  10.  * Debug macros
  11.  */
  12. #undef DEBUG_PM
  13. #ifdef DEBUG_PM
  14. #define DPRINTK(args...) printk(##args)
  15. #else
  16. #define DPRINTK(args...)
  17. #endif
  18. extern void s3c2410_cpu_suspend(void);
  19. extern void s3c2410_cpu_resume(void);
  20. #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
  21. #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
  22. static u_int pwbt_num = 0;
  23. static int pwbt_edge = 0;
  24. static int pm_rtc_on = 0;
  25. int
  26. register_wakeup_src(u_int eint_num, int edge, int rtc_on)
  27. {
  28. if (eint_num < 0 && eint_num > 23) {
  29. return -EINVAL;
  30. }
  31. pwbt_num = eint_num;
  32. pwbt_edge = edge;
  33. pm_rtc_on = rtc_on;
  34. return 0;
  35. }
  36. static void
  37. setup_wakeup_src(void)
  38. {
  39. if (pwbt_num < 4) {
  40. EXTINT0 = (pwbt_edge << (4 * pwbt_num));
  41. SRCPND |= (1 << pwbt_num);
  42. INTPND |= (1 << pwbt_num);
  43. INTMSK &= ~(1 << pwbt_num);
  44. } else {
  45. if (pwbt_num < 8) {
  46. EXTINT0 = (pwbt_edge << (4 * pwbt_num));
  47. } else if (pwbt_num < 16) {
  48. EXTINT1 = (pwbt_edge << (4 * (pwbt_num - 8)));
  49. } else {
  50. EXTINT2 = (pwbt_edge << (4 * (pwbt_num - 16)));
  51. }
  52. EINTPEND |= (1 << pwbt_num);
  53. EINTMASK &= ~(1 << pwbt_num);
  54. }
  55. if (pm_rtc_on) {
  56. /* Enable RTC */
  57. }
  58. }
  59. /*
  60.  * List of global S3C2410 peripheral registers to preserve.
  61.  * More ones like CP and general purpose register values are preserved
  62.  * with the stack location in sleep.S.
  63.  */
  64. enum { SLEEP_SAVE_START = 0,
  65. SLEEP_SAVE_INTMSK, SLEEP_SAVE_INTPND, SLEEP_SAVE_SRCPND,
  66. SLEEP_SAVE_INTSUBMSK, SLEEP_SAVE_SUBSRCPND,
  67. SLEEP_SAVE_INTMOD,
  68. SLEEP_SAVE_CLKCON,
  69. SLEEP_SAVE_UBRDIV0, SLEEP_SAVE_ULCON0, SLEEP_SAVE_UFCON0,
  70. SLEEP_SAVE_UMCON0, SLEEP_SAVE_UCON0,
  71. SLEEP_SAVE_GPACON, SLEEP_SAVE_GPADAT,
  72. SLEEP_SAVE_GPBCON, SLEEP_SAVE_GPBDAT, SLEEP_SAVE_GPBUP,
  73. SLEEP_SAVE_GPCCON, SLEEP_SAVE_GPCDAT, SLEEP_SAVE_GPCUP,
  74. SLEEP_SAVE_GPDCON, SLEEP_SAVE_GPDDAT, SLEEP_SAVE_GPDUP,
  75. SLEEP_SAVE_GPECON, SLEEP_SAVE_GPEDAT, SLEEP_SAVE_GPEUP,
  76. SLEEP_SAVE_GPFCON, SLEEP_SAVE_GPFDAT, SLEEP_SAVE_GPFUP,
  77. SLEEP_SAVE_GPGCON, SLEEP_SAVE_GPGDAT, SLEEP_SAVE_GPGUP,
  78. SLEEP_SAVE_MISCCR, SLEEP_SAVE_DCLKCON,
  79. SLEEP_SAVE_EXTINT0, SLEEP_SAVE_EXTINT1, SLEEP_SAVE_EXTINT2,
  80. SLEEP_SAVE_EINTFLT0, SLEEP_SAVE_EINTFLT1, SLEEP_SAVE_EINTFLT2, 
  81. SLEEP_SAVE_EINTFLT3, SLEEP_SAVE_EINTMASK,
  82. SLEEP_SAVE_TCFG0, SLEEP_SAVE_TCFG1, SLEEP_SAVE_TCNTB4,
  83. SLEEP_SAVE_TCON,
  84. SLEEP_SAVE_SIZE
  85. };
  86. int pm_do_suspend(void)
  87. {
  88. unsigned long sleep_save[SLEEP_SAVE_SIZE];
  89. DPRINTK("I am pm_do_suspendn");
  90. cli();
  91. /* save vital registers */
  92. SAVE(UBRDIV0);
  93. SAVE(ULCON0);
  94. SAVE(UFCON0);
  95. SAVE(UMCON0);
  96. SAVE(UCON0);
  97. SAVE(GPACON); SAVE(GPADAT);
  98. SAVE(GPBCON); SAVE(GPBDAT); SAVE(GPBUP);
  99. SAVE(GPCCON); SAVE(GPCDAT); SAVE(GPCUP);
  100. SAVE(GPDCON); SAVE(GPDDAT); SAVE(GPDUP);
  101. SAVE(GPECON); SAVE(GPEDAT); SAVE(GPEUP);
  102. SAVE(GPFCON); SAVE(GPFDAT); SAVE(GPFUP);
  103. SAVE(GPGCON); SAVE(GPGDAT); SAVE(GPGUP);
  104. SAVE(MISCCR); SAVE(DCLKCON);
  105. SAVE(EXTINT0); SAVE(EXTINT1); SAVE(EXTINT2);
  106. SAVE(EINTFLT0); SAVE(EINTFLT1); SAVE(EINTFLT2); SAVE(EINTFLT3);
  107. SAVE(EINTMASK);
  108. SAVE(INTMOD); SAVE(INTMSK); SAVE(INTSUBMSK);
  109. SAVE(TCFG0); SAVE(TCNTB4); SAVE(TCON);
  110. /* temporary.. */
  111. GPFDAT |= 0xf0;  
  112. GPGDAT &= ~(1 << 4);
  113. PMCTL1 |= (USBSPD1 | USBSPD0);
  114. PMCTL1 |= (0x3);
  115. /* Clear previous reset status */
  116. PMST = (PMST_HWR | PMST_WDR | PMST_SMR);
  117. /* set resume return address */
  118. PMSR0 = virt_to_phys(s3c2410_cpu_resume);
  119. setup_wakeup_src();
  120. /* go zzz */
  121. s3c2410_cpu_suspend();
  122. /* ensure not to come back here if it wasn't intended */
  123. PMSR0 = 0;
  124. PMCTL1 &= ~(USBSPD1 | USBSPD0);
  125. RESTORE(TCFG0);
  126. RESTORE(TCNTB4);
  127. TCON = (TCON_4_AUTO | TCON_4_UPDATE | COUNT_4_OFF);
  128. TCON = (TCON_4_AUTO | COUNT_4_ON);
  129. /* restore registers */
  130. RESTORE(GPACON); RESTORE(GPADAT);
  131. RESTORE(GPBCON); RESTORE(GPBDAT); RESTORE(GPBUP);
  132. RESTORE(GPCCON); RESTORE(GPCDAT); RESTORE(GPCUP);
  133. RESTORE(GPDCON); RESTORE(GPDDAT); RESTORE(GPDUP);
  134. RESTORE(GPECON); RESTORE(GPEDAT); RESTORE(GPEUP);
  135. RESTORE(GPFCON); RESTORE(GPFDAT); RESTORE(GPFUP);
  136. RESTORE(GPGCON); RESTORE(GPGDAT); RESTORE(GPGUP);
  137. RESTORE(MISCCR); RESTORE(DCLKCON);
  138. RESTORE(EXTINT0); RESTORE(EXTINT1); RESTORE(EXTINT2);
  139. RESTORE(EINTFLT0); RESTORE(EINTFLT1); RESTORE(EINTFLT2); RESTORE(EINTFLT3);
  140. RESTORE(EINTMASK);
  141. RESTORE(INTMOD); RESTORE(INTMSK); RESTORE(INTSUBMSK);
  142. /* Clear interrupts */
  143. EINTPEND = EINTPEND;
  144. LCDSRCPND = LCDSRCPND;
  145. LCDINTPND = LCDINTPND;
  146. SUBSRCPND = SUBSRCPND;
  147. SRCPND = SRCPND;
  148. INTPND = INTPND;
  149. /* temporary.. reset UART */
  150. RESTORE(ULCON0); RESTORE(UCON0); RESTORE(UFCON0);
  151. RESTORE(UMCON0); RESTORE(UBRDIV0);
  152. GPFCON &= ~(0xff00);
  153. GPFCON |= 0x5500;
  154. GPFUP |= 0xf0;
  155. GPFDAT &= ~(0xf0);  
  156. GPFDAT |= 0xa0;
  157. sti();
  158. DPRINTK("具矫操氛n");
  159. DPRINTK("I am still aliven");
  160. return 0;
  161. }
  162. unsigned long sleep_phys_sp(void *sp) 
  163. {
  164. return virt_to_phys(sp);
  165. }
  166. #ifdef CONFIG_SYSCTL
  167. /*
  168.  * ARGH! ACPI people defined CTL_ACPI in linux/acpi.h rather than
  169.  * linux/sysctl.h
  170.  *
  171.  * This means our interface here won't survice long - it needs a new
  172.  * interface. Quick hact to et this working - use sysctl id 9999.
  173.  */
  174. #warning ACPI broke the kernel, this interface needs to be fixed up.
  175. #define CTL_ACPI 9999
  176. #define ACPI_S1_SLP_TYP 19
  177. /*
  178.  * Send us to sleep.
  179.  */
  180. static int
  181. sysctl_pm_do_suspend(void)
  182. {
  183. int ret;
  184. ret = pm_send_all(PM_SUSPEND, (void *)3);
  185. if (ret == 0) {
  186. ret = pm_do_suspend();
  187. pm_send_all(PM_RESUME, (void *)0);
  188. }
  189. return ret;
  190. }
  191. static struct ctl_table pm_table[] =
  192. {
  193. {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_do_suspend},
  194. {0}
  195. };
  196. static struct ctl_table pm_dir_table[] =
  197. {
  198. {CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
  199. {0}
  200. };
  201. #endif
  202. #ifdef CONFIG_PROC_FS
  203. static int
  204. pminfo_proc_output(char *buf)
  205. {
  206. char *p;
  207. struct pm_dev *dev;
  208. p = buf;
  209. p += sprintf(p, "type tt id tt stat t prev_state n");
  210. p += sprintf(p, "----------------------------------------------n");
  211. dev = NULL;
  212. while ((dev = pm_find(PM_UNKNOWN_DEV, dev)) != NULL) {
  213. switch (dev->type) {
  214. case PM_SYS_DEV:
  215. p += sprintf(p, "PM_SYS_DEV t ");
  216. break;
  217. case PM_PCI_DEV:
  218. p += sprintf(p, "PM_PCI_DEV t ");
  219. break;
  220. case PM_USB_DEV:
  221. p += sprintf(p, "PM_USB_DEV t ");
  222. break;
  223. case PM_SCSI_DEV:
  224. p += sprintf(p, "PM_SCSI_DEV t ");
  225. break;
  226. case PM_ISA_DEV:
  227. p += sprintf(p, "PM_ISA_DEV t ");
  228. break;
  229. case PM_MTD_DEV:
  230. p += sprintf(p, "PM_MTD_DEV t ");
  231. break;
  232. case PM_ILLUMINATION_DEV:
  233. p += sprintf(p, "PM_ILLUMINATION_DEV t ");
  234. break;
  235. case PM_USER_DEV:
  236. p += sprintf(p, "PM_USER_DEV t ");
  237. break;
  238. case PM_DEBUG_DEV:
  239. p += sprintf(p, "PM_DEBUG_DEV t ");
  240. break;
  241. case PM_GP_DEV:
  242. p += sprintf(p, "PM_GP_DEV t ");
  243. break;
  244. default:
  245. p += sprintf(p, "PM_UNKONWN_DEV t ");
  246. break;
  247. }
  248. switch (dev->id) {
  249. case PM_SYS_KBC:
  250. p += sprintf(p, "PM_SYS_KBC t ");
  251. break;
  252. case PM_SYS_COM:
  253. p += sprintf(p, "PM_SYS_COM t ");
  254. break;
  255. case PM_SYS_IRDA:
  256. p += sprintf(p, "PM_SYS_IRDA t ");
  257. break;
  258. case PM_SYS_FDC:
  259. p += sprintf(p, "PM_SYS_FDC t ");
  260. break;
  261. case PM_SYS_VGA:
  262. p += sprintf(p, "PM_SYS_VGA t ");
  263. break;
  264. case PM_SYS_PCMCIA:
  265. p += sprintf(p, "PM_SYS_PCMCIA t ");
  266. break;
  267. case PM_USER_LCD:
  268. p += sprintf(p, "PM_USER_LCD t ");
  269. break;
  270. case PM_USER_LIGHT:
  271. p += sprintf(p, "PM_USER_LIGHT t ");
  272. break;
  273. case PM_USER_INPUT:
  274. p += sprintf(p, "PM_USER_INPUT t ");
  275. break;
  276. case PM_DEBUG_0:
  277. p += sprintf(p, "PM_DEBUG_0 t ");
  278. break;
  279. case PM_DEBUG_1:
  280. p += sprintf(p, "PM_DEBUG_1 t ");
  281. break;
  282. case PM_DEBUG_2:
  283. p += sprintf(p, "PM_DEBUG_2 t ");
  284. break;
  285. case PM_SYS_MISC:
  286. p += sprintf(p, "PM_SYS_MISC t ");
  287. break;
  288. default:
  289. p += sprintf(p, "PM_UNKONWN_DEV t ");
  290. break;
  291. }
  292. p += sprintf(p, "%d t %dn", (int)dev->state, (int)dev->prev_state);
  293. }
  294. return p - buf;
  295. }
  296. static int
  297. pminfo_read_proc(char *page, char **start, off_t off,
  298.                  int count, int *eof, void *data)
  299. {
  300. int len = pminfo_proc_output(page);
  301. if (len <= off+count) *eof = 1;
  302. *start = page + off;
  303. len -= off;
  304. if (len > count) len = count;
  305. if (len < 0) len = 0;
  306. return len;
  307. }
  308. #endif
  309. /*
  310.  * Initialize power interface
  311.  */
  312. static int __init
  313. pm_init(void)
  314. {
  315. #ifdef CONFIG_SYSCTL
  316. register_sysctl_table(pm_dir_table, 1);
  317. #endif    
  318. #ifdef CONFIG_PROC_FS
  319. create_proc_read_entry("pminfo", 0, 0, pminfo_read_proc, NULL);
  320. #endif
  321. return 0;
  322. }
  323. __initcall(pm_init);