pm.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183
  1. /* linux/arch/arm/plat-s3c24xx/pm.c
  2. *
  3. * Copyright (c) 2004,2006 Simtec Electronics
  4. * Ben Dooks <ben@simtec.co.uk>
  5. *
  6. * S3C24XX Power Manager (Suspend-To-RAM) support
  7. *
  8. * See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. *
  24. * Parts based on arch/arm/mach-pxa/pm.c
  25. *
  26. * Thanks to Dimitry Andric for debugging
  27. */
  28. #include <linux/init.h>
  29. #include <linux/suspend.h>
  30. #include <linux/errno.h>
  31. #include <linux/time.h>
  32. #include <linux/interrupt.h>
  33. #include <linux/crc32.h>
  34. #include <linux/ioport.h>
  35. #include <linux/delay.h>
  36. #include <linux/serial_core.h>
  37. #include <asm/cacheflush.h>
  38. #include <asm/hardware.h>
  39. #include <asm/io.h>
  40. #include <asm/arch/regs-serial.h>
  41. /*Qisda , wenny cheng , 20091224 , board id info {*/
  42. #include <../include/asm-arm/plat-s3c24xx/common-smdk.h>
  43. /*Qisda , wenny cheng , 20091224 , board id info }*/
  44. /*Qisda Qube, suspend mode gpio config 20091117*/
  45. #include <asm/arch/regs-mem.h>
  46. /*Qisda Qube, suspend mode gpio config 20091117*/
  47. #if defined (CONFIG_CPU_S3C6400)
  48. #include <asm/arch/regs-s3c6400-clock.h>
  49. #elif defined (CONFIG_CPU_S3C6410)
  50. #include <asm/arch/regs-s3c6410-clock.h>
  51. #elif defined (CONFIG_CPU_S3C2450)
  52. #include <asm/arch/regs-s3c2450-clock.h>
  53. #elif defined (CONFIG_CPU_S3C2416)
  54. #include <asm/arch/regs-s3c2416-clock.h>
  55. #else
  56. #include <asm/arch/regs-clock.h>
  57. #endif
  58. /*Qisda Qube, suspend mode gpio config 20091117*/
  59. #define S3C2410_GPIO_BANKM (32*16)
  60. #define S3C2410_GPMCON S3C2410_GPIOREG(0x100)
  61. #define S3C2410_GPMDAT S3C2410_GPIOREG(0x104)
  62. #define S3C2410_GPMUP S3C2410_GPIOREG(0x108)
  63. #define S3C2410_GPMSEL S3C2410_GPIOREG(0x10C)
  64. #define S3C2410_GPM0 S3C2410_GPIONO(S3C2410_GPIO_BANKM, 0)
  65. #define S3C2410_GPM0_INP (0x00 << 0)
  66. #define S3C2410_GPM1 S3C2410_GPIONO(S3C2410_GPIO_BANKM, 1)
  67. #define S3C2410_GPM1_INP (0x00 << 2)
  68. #define S3C2410_CLKREG(x) ((x) + S3C24XX_VA_CLKPWR)
  69. #define S3C_CLKREG(x) ((x) + S3C24XX_VA_SYSCON)
  70. #define S3C2410_LOCKTIME S3C2410_CLKREG(0x00)
  71. #define S3C24XX_LOCKTIME0 S3C_CLKREG(0x00)
  72. #define S3C24XX_LOCKTIME1 S3C_CLKREG(0x04)
  73. #define S3C2410_MPLLCON S3C2410_CLKREG(0x04)
  74. #define S3C2410_UPLLCON S3C2410_CLKREG(0x08)
  75. #define S3C2410_CLKCON S3C2410_CLKREG(0x0C)
  76. #define S3C2410_CLKSLOW S3C2410_CLKREG(0x10)
  77. #define S3C2410_CLKDIVN S3C2410_CLKREG(0x14)
  78. void pm_gpio_setting_enhancement (void);
  79. #if 0
  80. void test_message(void);
  81. #endif
  82. /*Qisda Qube, suspend mode gpio config 20091117*/
  83. #include <asm/arch/regs-gpio.h>
  84. #include <asm/arch/regs-gpioj.h>
  85. #include <asm/arch/regs-dsc.h>
  86. #include <asm/arch/regs-mem.h>
  87. #include <asm/arch/regs-irq.h>
  88. #include <asm/arch/regs-adc.h>
  89. #include <asm/mach/time.h>
  90. #include <asm/plat-s3c24xx/pm.h>
  91. #include <asm/mach/irq.h>
  92. //#include <asm/arch/irqs.h>
  93. //#include <asm/plat-s3c24xx/irq.h>
  94. /* Qisda, ShiYong Lin, 2009/08/18, Wake up source {*/
  95. #define SYSTEM_OFF_STATE 0
  96. #define SYSTEM_SLEEP_STATE 1
  97. extern unsigned int wkup_srce;
  98. /* Qisda, ShiYong Lin, 2009/11/02, Set En1 and En2 based on charging source {*/
  99. extern int charging_source;
  100. /* } Qisda, ShiYong Lin, 2009/11/02, Set En1 and En2 based on charging source */
  101. #ifdef CONFIG_PM_CPU_MODE
  102. extern unsigned char pm_cpu_mode;
  103. #endif
  104. /* } Qisda, ShiYong Lin, 2009/08/18, Wake up source */
  105. /* 2010/1/21, weichen, for handling events during suspend */
  106. #if defined (CONFIG_PM_PLATFORM_POWER_SAVING)
  107. extern unsigned int g_wakeup_event_occurs;
  108. #endif
  109. /* for external use */
  110. unsigned long s3c_pm_flags;
  111. #define PFX "s3c24xx-pm: "
  112. static struct sleep_save core_save[] = {
  113. #if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410)
  114. SAVE_ITEM(S3C_SDMA_SEL),
  115. #elif defined (CONFIG_CPU_S3C2450) || defined (CONFIG_CPU_S3C2416)
  116. SAVE_ITEM(S3C2443_LOCKCON0),
  117. SAVE_ITEM(S3C2443_LOCKCON1),
  118. SAVE_ITEM(S3C2443_OSCSET ),
  119. SAVE_ITEM(S3C2443_MPLLCON),
  120. SAVE_ITEM(S3C2443_EPLLCON),
  121. SAVE_ITEM(S3C2450_EPLLCON_K),
  122. SAVE_ITEM(S3C2443_CLKSRC ),
  123. SAVE_ITEM(S3C2443_CLKDIV0),
  124. SAVE_ITEM(S3C2443_CLKDIV1),
  125. SAVE_ITEM(S3C2443_CLKDIV2),
  126. SAVE_ITEM(S3C2443_HCLKCON),
  127. SAVE_ITEM(S3C2443_PCLKCON),
  128. SAVE_ITEM(S3C2443_SCLKCON),
  129. /*Qisda Qube, suspend mode kernel panic 20091117*/
  130. //s3c2416 dram config 0,4,8,c,10
  131. SAVE_ITEM(S3C2410_BWSCON),
  132. SAVE_ITEM(S3C2410_BANKCON0),
  133. SAVE_ITEM(S3C2410_BANKCON1),
  134. SAVE_ITEM(S3C2410_BANKCON2),
  135. SAVE_ITEM(S3C2410_BANKCON3),
  136. SAVE_ITEM(S3C2410_BANKCON4),
  137. /*Qisda Qube, suspend mode gpio config 20091117*/
  138. /*Qisda Qube, suspend mode kernel panic 20091117*/
  139. #else
  140. SAVE_ITEM(S3C2410_LOCKTIME),
  141. SAVE_ITEM(S3C2410_CLKCON),
  142. /* we restore the timings here, with the proviso that the board
  143. * brings the system up in an slower, or equal frequency setting
  144. * to the original system.
  145. *
  146. * if we cannot guarantee this, then things are going to go very
  147. * wrong here, as we modify the refresh and both pll settings.
  148. */
  149. SAVE_ITEM(S3C2410_BWSCON),
  150. SAVE_ITEM(S3C2410_BANKCON0),
  151. SAVE_ITEM(S3C2410_BANKCON1),
  152. SAVE_ITEM(S3C2410_BANKCON2),
  153. SAVE_ITEM(S3C2410_BANKCON3),
  154. SAVE_ITEM(S3C2410_BANKCON4),
  155. SAVE_ITEM(S3C2410_BANKCON5),
  156. SAVE_ITEM(S3C2410_CLKDIVN),
  157. SAVE_ITEM(S3C2410_MPLLCON),
  158. SAVE_ITEM(S3C2410_UPLLCON),
  159. SAVE_ITEM(S3C2410_CLKSLOW),
  160. SAVE_ITEM(S3C2410_REFRESH),
  161. #endif
  162. };
  163. static struct sleep_save gpio_save[] = {
  164. #if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410)
  165. SAVE_ITEM(S3C_GPACON),
  166. SAVE_ITEM(S3C_GPADAT),
  167. SAVE_ITEM(S3C_GPAPU),
  168. SAVE_ITEM(S3C_GPBCON),
  169. SAVE_ITEM(S3C_GPBDAT),
  170. SAVE_ITEM(S3C_GPBPU),
  171. SAVE_ITEM(S3C_GPCCON),
  172. SAVE_ITEM(S3C_GPCDAT),
  173. SAVE_ITEM(S3C_GPCPU),
  174. SAVE_ITEM(S3C_GPDCON),
  175. SAVE_ITEM(S3C_GPDDAT),
  176. SAVE_ITEM(S3C_GPDPU),
  177. SAVE_ITEM(S3C_GPECON),
  178. SAVE_ITEM(S3C_GPEDAT),
  179. SAVE_ITEM(S3C_GPEPU),
  180. SAVE_ITEM(S3C_GPFCON),
  181. SAVE_ITEM(S3C_GPFDAT),
  182. SAVE_ITEM(S3C_GPFPU),
  183. SAVE_ITEM(S3C_GPGCON),
  184. SAVE_ITEM(S3C_GPGDAT),
  185. SAVE_ITEM(S3C_GPGPU),
  186. SAVE_ITEM(S3C_GPH0CON),
  187. SAVE_ITEM(S3C_GPH1CON),
  188. SAVE_ITEM(S3C_GPHDAT),
  189. SAVE_ITEM(S3C_GPHPU),
  190. SAVE_ITEM(S3C_GPICON),
  191. SAVE_ITEM(S3C_GPIDAT),
  192. SAVE_ITEM(S3C_GPIPU),
  193. SAVE_ITEM(S3C_GPJCON),
  194. SAVE_ITEM(S3C_GPJDAT),
  195. SAVE_ITEM(S3C_GPJPU),
  196. SAVE_ITEM(S3C_GPK0CON),
  197. SAVE_ITEM(S3C_GPK1CON),
  198. SAVE_ITEM(S3C_GPKDAT),
  199. SAVE_ITEM(S3C_GPKPU),
  200. SAVE_ITEM(S3C_GPL0CON),
  201. SAVE_ITEM(S3C_GPL1CON),
  202. SAVE_ITEM(S3C_GPLDAT),
  203. SAVE_ITEM(S3C_GPLPU),
  204. SAVE_ITEM(S3C_GPMCON),
  205. SAVE_ITEM(S3C_GPMDAT),
  206. SAVE_ITEM(S3C_GPMPU),
  207. SAVE_ITEM(S3C_GPNCON),
  208. SAVE_ITEM(S3C_GPNDAT),
  209. SAVE_ITEM(S3C_GPNPU),
  210. SAVE_ITEM(S3C_GPOCON),
  211. SAVE_ITEM(S3C_GPODAT),
  212. SAVE_ITEM(S3C_GPOPU),
  213. SAVE_ITEM(S3C_GPPCON),
  214. SAVE_ITEM(S3C_GPPDAT),
  215. SAVE_ITEM(S3C_GPPPU),
  216. SAVE_ITEM(S3C_GPQCON),
  217. SAVE_ITEM(S3C_GPQDAT),
  218. SAVE_ITEM(S3C_GPQPU),
  219. SAVE_ITEM(S3C_PRIORITY),
  220. /* Special register*/
  221. SAVE_ITEM(S3C_SPCON),
  222. /* Memory port control */
  223. SAVE_ITEM(S3C_MEM0CONSTOP),
  224. SAVE_ITEM(S3C_MEM1CONSTOP),
  225. SAVE_ITEM(S3C_MEM0CONSLP0),
  226. SAVE_ITEM(S3C_MEM0CONSLP1),
  227. SAVE_ITEM(S3C_MEM1CONSLP),
  228. SAVE_ITEM(S3C_MEM0DRVCON),
  229. SAVE_ITEM(S3C_MEM1DRVCON),
  230. #elif defined (CONFIG_CPU_S3C2450) || defined (CONFIG_CPU_S3C2416)
  231. SAVE_ITEM(S3C2410_GPACON),
  232. SAVE_ITEM(S3C2410_GPADAT),
  233. SAVE_ITEM(S3C2410_GPBCON),
  234. SAVE_ITEM(S3C2410_GPBDAT),
  235. SAVE_ITEM(S3C2410_GPBUP),
  236. SAVE_ITEM(S3C2410_GPCCON),
  237. SAVE_ITEM(S3C2410_GPCDAT),
  238. SAVE_ITEM(S3C2410_GPCUP),
  239. SAVE_ITEM(S3C2410_GPDCON),
  240. SAVE_ITEM(S3C2410_GPDDAT),
  241. SAVE_ITEM(S3C2410_GPDUP),
  242. SAVE_ITEM(S3C2410_GPECON),
  243. SAVE_ITEM(S3C2410_GPEDAT),
  244. SAVE_ITEM(S3C2410_GPEUP),
  245. SAVE_ITEM(S3C2410_GPFCON),
  246. SAVE_ITEM(S3C2410_GPFDAT),
  247. SAVE_ITEM(S3C2410_GPFUP),
  248. SAVE_ITEM(S3C2410_GPGCON),
  249. SAVE_ITEM(S3C2410_GPGDAT),
  250. SAVE_ITEM(S3C2410_GPGUP),
  251. SAVE_ITEM(S3C2410_GPHCON),
  252. SAVE_ITEM(S3C2410_GPHDAT),
  253. SAVE_ITEM(S3C2410_GPHUP),
  254. SAVE_ITEM(S3C2440_GPJCON),
  255. SAVE_ITEM(S3C2440_GPJDAT),
  256. SAVE_ITEM(S3C2440_GPJUP),
  257. /*Qisda, Hiko: unmark these settings, 'cause mmc driver has solved the suspend/resume issue {*/
  258. //Qisda, Asaku Chen, 2009/07/22, Saving GPK data lets system not sleep?
  259. SAVE_ITEM(S3C2416_GPKDAT),
  260. SAVE_ITEM(S3C2416_GPKCON),
  261. SAVE_ITEM(S3C2416_GPKUDP),
  262. /*Qisda, Hiko: unmark these settings, 'cause mmc driver has solved the suspend/resume issue }*/
  263. SAVE_ITEM(S3C2443_GPLCON),
  264. SAVE_ITEM(S3C2443_GPLDAT),
  265. SAVE_ITEM(S3C2443_GPLUDP),
  266. SAVE_ITEM(S3C2410_MISCCR),
  267. SAVE_ITEM(S3C2410_DCLKCON),
  268. SAVE_ITEM(S3C2410_EXTINT0),
  269. SAVE_ITEM(S3C2410_EXTINT1),
  270. SAVE_ITEM(S3C2410_EXTINT2),
  271. SAVE_ITEM(S3C2410_EINFLT0),
  272. SAVE_ITEM(S3C2410_EINFLT1),
  273. SAVE_ITEM(S3C2410_EINFLT2),
  274. SAVE_ITEM(S3C2410_EINFLT3),
  275. SAVE_ITEM(S3C2450_DSC0),
  276. SAVE_ITEM(S3C2450_DSC1),
  277. SAVE_ITEM(S3C2450_DSC2),
  278. SAVE_ITEM(S3C2450_DSC3),
  279. #else
  280. SAVE_ITEM(S3C2410_GPACON),
  281. SAVE_ITEM(S3C2410_GPADAT),
  282. SAVE_ITEM(S3C2410_GPBCON),
  283. SAVE_ITEM(S3C2410_GPBDAT),
  284. SAVE_ITEM(S3C2410_GPBUP),
  285. SAVE_ITEM(S3C2410_GPCCON),
  286. SAVE_ITEM(S3C2410_GPCDAT),
  287. SAVE_ITEM(S3C2410_GPCUP),
  288. SAVE_ITEM(S3C2410_GPDCON),
  289. SAVE_ITEM(S3C2410_GPDDAT),
  290. SAVE_ITEM(S3C2410_GPDUP),
  291. SAVE_ITEM(S3C2410_GPECON),
  292. SAVE_ITEM(S3C2410_GPEDAT),
  293. SAVE_ITEM(S3C2410_GPEUP),
  294. SAVE_ITEM(S3C2410_GPFCON),
  295. SAVE_ITEM(S3C2410_GPFDAT),
  296. SAVE_ITEM(S3C2410_GPFUP),
  297. SAVE_ITEM(S3C2410_GPGCON),
  298. SAVE_ITEM(S3C2410_GPGDAT),
  299. SAVE_ITEM(S3C2410_GPGUP),
  300. SAVE_ITEM(S3C2410_GPHCON),
  301. SAVE_ITEM(S3C2410_GPHDAT),
  302. SAVE_ITEM(S3C2410_GPHUP),
  303. SAVE_ITEM(S3C2410_DCLKCON),
  304. #endif
  305. };
  306. #if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410)
  307. /* this lot should be really saved by the IRQ code */
  308. /* VICXADDRESSXX initilaization to be needed */
  309. static struct sleep_save irq_save[] = {
  310. SAVE_ITEM(S3C_VIC0INTSELECT),
  311. SAVE_ITEM(S3C_VIC1INTSELECT),
  312. SAVE_ITEM(S3C_VIC0INTENABLE),
  313. SAVE_ITEM(S3C_VIC1INTENABLE),
  314. SAVE_ITEM(S3C_VIC0SOFTINT),
  315. SAVE_ITEM(S3C_VIC1SOFTINT),
  316. };
  317. static struct sleep_save sromc_save[] = {
  318. SAVE_ITEM(S3C_SROM_BW),
  319. SAVE_ITEM(S3C_SROM_BC0),
  320. SAVE_ITEM(S3C_SROM_BC1),
  321. SAVE_ITEM(S3C_SROM_BC2),
  322. SAVE_ITEM(S3C_SROM_BC3),
  323. SAVE_ITEM(S3C_SROM_BC4),
  324. SAVE_ITEM(S3C_SROM_BC5),
  325. };
  326. #if 0
  327. #define SAVE_UART(va) \
  328. SAVE_ITEM((va) + S3C_ULCON), \
  329. SAVE_ITEM((va) + S3C_UCON), \
  330. SAVE_ITEM((va) + S3C_UFCON), \
  331. SAVE_ITEM((va) + S3C_UMCON), \
  332. SAVE_ITEM((va) + S3C_UBRDIV), \
  333. SAVE_ITEM((va) + S3C_UDIVSLOT), \
  334. SAVE_ITEM((va) + S3C_UINTMSK)
  335. static struct sleep_save uart_save[] = {
  336. SAVE_UART(S3C24XX_VA_UART0),
  337. SAVE_UART(S3C24XX_VA_UART1),
  338. SAVE_UART(S3C24XX_VA_UART2),
  339. SAVE_UART(S3C24XX_VA_UART3),
  340. };
  341. #endif
  342. #elif defined (CONFIG_CPU_S3C2450) || defined (CONFIG_CPU_S3C2416)
  343. static struct sleep_save irq_save[] = {
  344. SAVE_ITEM(S3C2410_EINTMASK),
  345. SAVE_ITEM(S3C2410_INTMSK),
  346. SAVE_ITEM(S3C2450_INTMSK),
  347. SAVE_ITEM(S3C2410_INTSUBMSK),
  348. };
  349. static struct sleep_save smc_save[] = {
  350. SAVE_ITEM(S3C_SSMC_SMBIDCYR1),
  351. SAVE_ITEM(S3C_SSMC_SMBIDCYR4),
  352. SAVE_ITEM(S3C_SSMC_SMBWSTRDR1),
  353. SAVE_ITEM(S3C_SSMC_SMBWSTRDR4),
  354. SAVE_ITEM(S3C_SSMC_SMBWSTWRR1),
  355. SAVE_ITEM(S3C_SSMC_SMBWSTWRR4),
  356. SAVE_ITEM(S3C_SSMC_SMBWSTOENR1),
  357. SAVE_ITEM(S3C_SSMC_SMBWSTOENR4),
  358. SAVE_ITEM(S3C_SSMC_SMBWSTWENR1),
  359. SAVE_ITEM(S3C_SSMC_SMBWSTWENR4),
  360. SAVE_ITEM(S3C_SSMC_SMBCR1),
  361. SAVE_ITEM(S3C_SSMC_SMBCR4),
  362. SAVE_ITEM(S3C_BANK_CFG),
  363. };
  364. #endif
  365. #ifdef CONFIG_S3C2410_PM_DEBUG
  366. #define SAVE_UART(va) \
  367. SAVE_ITEM((va) + S3C2410_ULCON), \
  368. SAVE_ITEM((va) + S3C2410_UCON), \
  369. SAVE_ITEM((va) + S3C2410_UFCON), \
  370. SAVE_ITEM((va) + S3C2410_UMCON), \
  371. SAVE_ITEM((va) + S3C2410_UBRDIV)
  372. static struct sleep_save uart_save[] = {
  373. SAVE_UART(S3C24XX_VA_UART0),
  374. SAVE_UART(S3C24XX_VA_UART1),
  375. #ifndef CONFIG_CPU_S3C2400
  376. SAVE_UART(S3C24XX_VA_UART2),
  377. #endif
  378. };
  379. /* debug
  380. *
  381. * we send the debug to printascii() to allow it to be seen if the
  382. * system never wakes up from the sleep
  383. */
  384. extern void printascii(const char *);
  385. void pm_dbg(const char *fmt, ...)
  386. {
  387. va_list va;
  388. char buff[256];
  389. va_start(va, fmt);
  390. vsprintf(buff, fmt, va);
  391. va_end(va);
  392. printascii(buff);
  393. }
  394. static void s3c2410_pm_debug_init(void)
  395. {
  396. unsigned long tmp = __raw_readl(S3C2410_CLKCON);
  397. /* re-start uart clocks */
  398. tmp |= S3C2410_CLKCON_UART0;
  399. tmp |= S3C2410_CLKCON_UART1;
  400. tmp |= S3C2410_CLKCON_UART2;
  401. __raw_writel(tmp, S3C2410_CLKCON);
  402. udelay(10);
  403. }
  404. #define DBG(fmt...) pm_dbg(fmt)
  405. #else
  406. #define DBG(fmt...)
  407. #define s3c2410_pm_debug_init() do { } while(0)
  408. static struct sleep_save uart_save[] = {};
  409. #endif
  410. #if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0
  411. /* suspend checking code...
  412. *
  413. * this next area does a set of crc checks over all the installed
  414. * memory, so the system can verify if the resume was ok.
  415. *
  416. * CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC,
  417. * increasing it will mean that the area corrupted will be less easy to spot,
  418. * and reducing the size will cause the CRC save area to grow
  419. */
  420. #define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024)
  421. static u32 crc_size; /* size needed for the crc block */
  422. static u32 *crcs; /* allocated over suspend/resume */
  423. typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg);
  424. /* s3c2410_pm_run_res
  425. *
  426. * go thorugh the given resource list, and look for system ram
  427. */
  428. static void s3c2410_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg)
  429. {
  430. while (ptr != NULL) {
  431. if (ptr->child != NULL)
  432. s3c2410_pm_run_res(ptr->child, fn, arg);
  433. if ((ptr->flags & IORESOURCE_MEM) &&
  434. strcmp(ptr->name, "System RAM") == 0) {
  435. DBG("Found system RAM at %08lx..%08lx\n",
  436. ptr->start, ptr->end);
  437. arg = (fn)(ptr, arg);
  438. }
  439. ptr = ptr->sibling;
  440. }
  441. }
  442. static void s3c2410_pm_run_sysram(run_fn_t fn, u32 *arg)
  443. {
  444. s3c2410_pm_run_res(&iomem_resource, fn, arg);
  445. }
  446. static u32 *s3c2410_pm_countram(struct resource *res, u32 *val)
  447. {
  448. u32 size = (u32)(res->end - res->start)+1;
  449. size += CHECK_CHUNKSIZE-1;
  450. size /= CHECK_CHUNKSIZE;
  451. DBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size);
  452. *val += size * sizeof(u32);
  453. return val;
  454. }
  455. /* s3c2410_pm_prepare_check
  456. *
  457. * prepare the necessary information for creating the CRCs. This
  458. * must be done before the final save, as it will require memory
  459. * allocating, and thus touching bits of the kernel we do not
  460. * know about.
  461. */
  462. static void s3c2410_pm_check_prepare(void)
  463. {
  464. crc_size = 0;
  465. s3c2410_pm_run_sysram(s3c2410_pm_countram, &crc_size);
  466. DBG("s3c2410_pm_prepare_check: %u checks needed\n", crc_size);
  467. crcs = kmalloc(crc_size+4, GFP_KERNEL);
  468. if (crcs == NULL)
  469. printk(KERN_ERR "Cannot allocated CRC save area\n");
  470. }
  471. static u32 *s3c2410_pm_makecheck(struct resource *res, u32 *val)
  472. {
  473. unsigned long addr, left;
  474. for (addr = res->start; addr < res->end;
  475. addr += CHECK_CHUNKSIZE) {
  476. left = res->end - addr;
  477. if (left > CHECK_CHUNKSIZE)
  478. left = CHECK_CHUNKSIZE;
  479. *val = crc32_le(~0, phys_to_virt(addr), left);
  480. val++;
  481. }
  482. return val;
  483. }
  484. /* s3c2410_pm_check_store
  485. *
  486. * compute the CRC values for the memory blocks before the final
  487. * sleep.
  488. */
  489. static void s3c2410_pm_check_store(void)
  490. {
  491. if (crcs != NULL)
  492. s3c2410_pm_run_sysram(s3c2410_pm_makecheck, crcs);
  493. }
  494. /* in_region
  495. *
  496. * return TRUE if the area defined by ptr..ptr+size contatins the
  497. * what..what+whatsz
  498. */
  499. static inline int in_region(void *ptr, int size, void *what, size_t whatsz)
  500. {
  501. if ((what+whatsz) < ptr)
  502. return 0;
  503. if (what > (ptr+size))
  504. return 0;
  505. return 1;
  506. }
  507. static u32 *s3c2410_pm_runcheck(struct resource *res, u32 *val)
  508. {
  509. void *save_at = phys_to_virt(s3c2410_sleep_save_phys);
  510. unsigned long addr;
  511. unsigned long left;
  512. void *ptr;
  513. u32 calc;
  514. for (addr = res->start; addr < res->end;
  515. addr += CHECK_CHUNKSIZE) {
  516. left = res->end - addr;
  517. if (left > CHECK_CHUNKSIZE)
  518. left = CHECK_CHUNKSIZE;
  519. ptr = phys_to_virt(addr);
  520. if (in_region(ptr, left, crcs, crc_size)) {
  521. DBG("skipping %08lx, has crc block in\n", addr);
  522. goto skip_check;
  523. }
  524. if (in_region(ptr, left, save_at, 32*4 )) {
  525. DBG("skipping %08lx, has save block in\n", addr);
  526. goto skip_check;
  527. }
  528. /* calculate and check the checksum */
  529. calc = crc32_le(~0, ptr, left);
  530. if (calc != *val) {
  531. printk(KERN_ERR PFX "Restore CRC error at "
  532. "%08lx (%08x vs %08x)\n", addr, calc, *val);
  533. DBG("Restore CRC error at %08lx (%08x vs %08x)\n",
  534. addr, calc, *val);
  535. }
  536. skip_check:
  537. val++;
  538. }
  539. return val;
  540. }
  541. /* s3c2410_pm_check_restore
  542. *
  543. * check the CRCs after the restore event and free the memory used
  544. * to hold them
  545. */
  546. static void s3c2410_pm_check_restore(void)
  547. {
  548. if (crcs != NULL) {
  549. s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs);
  550. kfree(crcs);
  551. crcs = NULL;
  552. }
  553. }
  554. #else
  555. #define s3c2410_pm_check_prepare() do { } while(0)
  556. #define s3c2410_pm_check_restore() do { } while(0)
  557. #define s3c2410_pm_check_store() do { } while(0)
  558. #endif
  559. /* helper functions to save and restore register state */
  560. void s3c2410_pm_do_save(struct sleep_save *ptr, int count)
  561. {
  562. for (; count > 0; count--, ptr++) {
  563. ptr->val = __raw_readl(ptr->reg);
  564. //DBG("saved %p value %08lx\n", ptr->reg, ptr->val);
  565. }
  566. }
  567. /* Qisda, ShiYong Lin, 2009/09/23, Debug message {*/
  568. #if 0
  569. void s3c2410_pm_do_print(struct sleep_save *ptr, int count)
  570. {
  571. int i = 0;
  572. for (i = 0;i< count; i++, ptr++) {
  573. printk("count = %02d, val = 0X%08x\n",i, __raw_readl(ptr->reg));
  574. }
  575. }
  576. #endif
  577. /* } Qisda, ShiYong Lin, 2009/09/23, Debug message */
  578. /* s3c2410_pm_do_restore
  579. *
  580. * restore the system from the given list of saved registers
  581. *
  582. * Note, we do not use DBG() in here, as the system may not have
  583. * restore the UARTs state yet
  584. */
  585. void s3c2410_pm_do_restore(struct sleep_save *ptr, int count)
  586. {
  587. for (; count > 0; count--, ptr++) {
  588. //printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n",
  589. //ptr->reg, ptr->val, __raw_readl(ptr->reg));
  590. __raw_writel(ptr->val, ptr->reg);
  591. }
  592. }
  593. /* s3c2410_pm_do_restore_core
  594. *
  595. * similar to s3c2410_pm_do_restore_core
  596. *
  597. * WARNING: Do not put any debug in here that may effect memory or use
  598. * peripherals, as things may be changing!
  599. */
  600. static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count)
  601. {
  602. for (; count > 0; count--, ptr++) {
  603. __raw_writel(ptr->val, ptr->reg);
  604. }
  605. }
  606. /* s3c2410_pm_show_resume_irqs
  607. *
  608. * print any IRQs asserted at resume time (ie, we woke from)
  609. */
  610. static void s3c2410_pm_show_resume_irqs(int start, unsigned long which,
  611. unsigned long mask)
  612. {
  613. int i;
  614. which &= ~mask;
  615. for (i = 0; i <= 31; i++) {
  616. if ((which) & (1L<<i)) {
  617. DBG("IRQ %d asserted at resume\n", start+i);
  618. }
  619. }
  620. }
  621. #if !defined (CONFIG_CPU_S3C6400) && !defined (CONFIG_CPU_S3C6410)
  622. /* s3c2410_pm_check_resume_pin
  623. *
  624. * check to see if the pin is configured correctly for sleep mode, and
  625. * make any necessary adjustments if it is not
  626. */
  627. static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs)
  628. {
  629. unsigned long irqstate;
  630. unsigned long pinstate;
  631. int irq = s3c2410_gpio_getirq(pin);
  632. if (irqoffs < 4)
  633. irqstate = s3c_irqwake_intmask & (1L<<irqoffs);
  634. else
  635. irqstate = s3c_irqwake_eintmask & (1L<<irqoffs);
  636. pinstate = s3c2410_gpio_getcfg(pin);
  637. if (!irqstate) {
  638. if (pinstate == S3C2410_GPIO_IRQ)
  639. DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin);
  640. } else {
  641. if (pinstate == S3C2410_GPIO_IRQ) {
  642. DBG("Disabling IRQ %d (pin %d)\n", irq, pin);
  643. s3c2410_gpio_cfgpin(pin, S3C2410_GPIO_INPUT);
  644. }
  645. }
  646. }
  647. /* s3c2410_pm_configure_extint
  648. *
  649. * configure all external interrupt pins
  650. */
  651. static void s3c2410_pm_configure_extint(void)
  652. {
  653. int pin;
  654. /* for each of the external interrupts (EINT0..EINT15) we
  655. * need to check wether it is an external interrupt source,
  656. * and then configure it as an input if it is not
  657. */
  658. for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) {
  659. s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0);
  660. }
  661. for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) {
  662. s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8);
  663. }
  664. }
  665. #else /* !defined (CONFIG_CPU_S3C6400) && !defined (CONFIG_CPU_S3C6410) */
  666. #if 0
  667. extern int s3c_irqext_type(unsigned int irq, unsigned int type);
  668. extern void s3c_irqext_unmaskack(unsigned int irqno);
  669. #endif
  670. static void s3c6400_pm_configure_extint(void)
  671. {
  672. int cnt = 0;
  673. u32 check, reg_val;
  674. /* for each of the external interrupts (EINT0..EINT15) we
  675. * need to check wether it is an external interrupt source,
  676. * and then configure it as an input if it is not
  677. */
  678. // s3c_irqext_type(IRQ_EINT10, IRQT_FALLING);
  679. s3c_gpio_cfgpin(S3C_GPN10, S3C_GPN10_EXTINT10);
  680. s3c_gpio_pullup(S3C_GPN10, 2);
  681. udelay(50);
  682. #if 0
  683. do {
  684. reg_val = readl(S3C_GPNCON);
  685. check = (reg_val & (3<<20))>> 20;
  686. if (++cnt > 10000) {
  687. printk("%s: Oops! GPNCON EXTINT Setting Fail... EINTMASK:0x%x\n",
  688. __FUNCTION__, reg_val);
  689. }
  690. } while (!(check == 2));
  691. printk("cnt is %d\n", cnt);
  692. #endif
  693. __raw_writel((__raw_readl(S3C_EINTCON0) & ~(0x7 << 20)) |
  694. (S3C_EXTINT_FALLEDGE << 20), S3C_EINTCON0);
  695. // s3c_irqext_unmaskack(IRQ_EINT10);
  696. __raw_writel(1UL << (IRQ_EINT10 - IRQ_EINT0), S3C_EINTPEND);
  697. __raw_writel(__raw_readl(S3C_EINTMASK)&~(1UL << (IRQ_EINT10 - IRQ_EINT0)), S3C_EINTMASK);
  698. __raw_writel((0x0fffffff&~(3<<9)), S3C_EINT_MASK);
  699. }
  700. #endif
  701. void (*pm_cpu_prep)(void);
  702. void (*pm_cpu_sleep)(void);
  703. #define any_allowed(mask, allow) (((mask) & (allow)) != (allow))
  704. /* s3c2410_pm_enter
  705. *
  706. * central control for sleep/resume process
  707. */
  708. #if !defined (CONFIG_CPU_S3C6400) && !defined (CONFIG_CPU_S3C6410)
  709. static int s3c2410_pm_enter(suspend_state_t state)
  710. {
  711. unsigned long regs_save[16];
  712. /* ensure the debug is initialised (if enabled) */
  713. s3c2410_pm_debug_init();
  714. DBG("s3c2410_pm_enter(%d)\n", state);
  715. if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) {
  716. printk(KERN_ERR PFX "error: no cpu sleep functions set\n");
  717. return -EINVAL;
  718. }
  719. #ifndef CONFIG_PM_CPU_MODE
  720. if (state != PM_SUSPEND_MEM) {
  721. printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
  722. return -EINVAL;
  723. }
  724. #endif
  725. /* check if we have anything to wake-up with... bad things seem
  726. * to happen if you suspend with no wakeup (system will often
  727. * require a full power-cycle)
  728. */
  729. if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) &&
  730. !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) {
  731. printk(KERN_ERR PFX "No sources enabled for wake-up!\n");
  732. printk(KERN_ERR PFX "Aborting sleep\n");
  733. return -EINVAL;
  734. }
  735. /* prepare check area if configured */
  736. s3c2410_pm_check_prepare();
  737. /* store the physical address of the register recovery block */
  738. s3c2410_sleep_save_phys = virt_to_phys(regs_save);
  739. DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys);
  740. /* save all necessary core registers not covered by the drivers */
  741. s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
  742. s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
  743. s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));
  744. #if defined(CONFIG_CPU_S3C2450) || defined(CONFIG_CPU_S3C2416)
  745. s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
  746. s3c2410_pm_do_save(smc_save, ARRAY_SIZE(smc_save));
  747. /* ensure INFORM1_REG has the resume address, check u-boot */
  748. __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2443_INFORM1);
  749. #endif
  750. /* set the irq configuration for wake */
  751. s3c2410_pm_configure_extint();
  752. DBG("sleep: irq wakeup masks: %08lx,%08lx\n",
  753. s3c_irqwake_intmask, s3c_irqwake_eintmask);
  754. __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK);
  755. __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK);
  756. /* ack any outstanding external interrupts before we go to sleep */
  757. __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
  758. __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND);
  759. __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND);
  760. /* call cpu specific preperation */
  761. pm_cpu_prep();
  762. /* flush cache back to ram */
  763. flush_cache_all();
  764. s3c2410_pm_check_store();
  765. /* send the cpu to sleep... */
  766. #if !defined(CONFIG_CPU_S3C2450) && !defined(CONFIG_CPU_S3C2416)
  767. __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */
  768. #endif
  769. /* s3c2410_cpu_save will also act as our return point from when
  770. * we resume as it saves its own register state, so use the return
  771. * code to differentiate return from save and return from sleep */
  772. if(s3c2410_cpu_save(regs_save) == 0) {
  773. flush_cache_all();
  774. pm_cpu_sleep();
  775. }
  776. /************************ CPU is now sleeping ... *****************************/
  777. /* restore the cpu state */
  778. cpu_init();
  779. /* restore the system state */
  780. s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
  781. s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));
  782. s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save));
  783. #if defined(CONFIG_CPU_S3C2450) || defined(CONFIG_CPU_S3C2416)
  784. s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
  785. s3c2410_pm_do_restore(smc_save, ARRAY_SIZE(smc_save));
  786. __raw_writel(0x0, S3C2443_PWRMODE);
  787. #endif
  788. s3c2410_pm_debug_init();
  789. /* check what irq (if any) restored the system */
  790. DBG("post sleep: IRQs 0x%08x, 0x%08x\n",
  791. __raw_readl(S3C2410_SRCPND),
  792. __raw_readl(S3C2410_EINTPEND));
  793. s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND),
  794. s3c_irqwake_intmask);
  795. s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
  796. s3c_irqwake_eintmask);
  797. DBG("post sleep, preparing to return\n");
  798. s3c2410_pm_check_restore();
  799. /* ok, let's return from sleep */
  800. DBG("S3C2410 PM Resume (post-restore)\n");
  801. DBG("Wakeup source =0x%08lx\n", readl(S3C2443_WKUPSTAT));
  802. return 0;
  803. }
  804. #else
  805. static int s3c6400_pm_enter(suspend_state_t state)
  806. {
  807. unsigned long regs_save[16];
  808. unsigned long clkcon, irqindex = 0;
  809. unsigned int tmp;
  810. /* ensure the debug is initialised (if enabled) */
  811. // s3c6400_pm_debug_init();
  812. if (state != PM_SUSPEND_MEM) {
  813. printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
  814. return -EINVAL;
  815. }
  816. /* prepare check area if configured */
  817. s3c2410_pm_check_prepare();
  818. /* store the physical address of the register recovery block */
  819. s3c2410_sleep_save_phys = virt_to_phys(regs_save);
  820. /* save all necessary core registers not covered by the drivers */
  821. s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
  822. s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
  823. s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
  824. s3c2410_pm_do_save(sromc_save, ARRAY_SIZE(sromc_save));
  825. /* ensure INF_REG0 has the resume address */
  826. __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C_INFORM0);
  827. /* set the irq configuration for wake */
  828. s3c6400_pm_configure_extint();
  829. /* call cpu specific preperation */
  830. pm_cpu_prep();
  831. /* flush cache back to ram */
  832. flush_cache_all();
  833. s3c2410_pm_check_store();
  834. __raw_writel(0xffffffff, S3C_VIC0INTENCLEAR);
  835. __raw_writel(0xffffffff, S3C_VIC1INTENCLEAR);
  836. __raw_writel(0xffffffff, S3C_VIC0SOFTINTCLEAR);
  837. __raw_writel(0xffffffff, S3C_VIC1SOFTINTCLEAR);
  838. __raw_writel(1, S3C_OSC_STABLE);
  839. __raw_writel(1, S3C_PWR_STABLE);
  840. /* Set WFI instruction to SLEEP mode */
  841. tmp = __raw_readl(S3C_PWR_CFG);
  842. tmp &= ~(0x60<<0);
  843. tmp |= (0x3<<5);
  844. __raw_writel(tmp, S3C_PWR_CFG);
  845. tmp = __raw_readl(S3C_SLEEP_CFG);
  846. tmp &= ~(0x61<<0);
  847. __raw_writel(tmp, S3C_SLEEP_CFG);
  848. __raw_writel(0x2, S3C_SLPEN);
  849. /* Clear WAKEUP_STAT register for next wakeup -jc.lee */
  850. /* If this register do not be cleared, Wakeup will be failed */
  851. tmp = __raw_readl(S3C_WAKEUP_STAT);
  852. __raw_writel(tmp, S3C_WAKEUP_STAT);
  853. /* ALL sub block "ON" before enterring sleep mode - EVT0 bug*/
  854. __raw_writel(0xffffff00, S3C_NORMAL_CFG);
  855. /* Open all clock gate to enter sleep mode - EVT0 bug*/
  856. __raw_writel(0xffffffff, S3C_HCLK_GATE);
  857. __raw_writel(0xffffffff, S3C_PCLK_GATE);
  858. __raw_writel(0xffffffff, S3C_SCLK_GATE);
  859. /* s3c2410_cpu_save will also act as our return point from when
  860. * we resume as it saves its own register state, so use the return
  861. * code to differentiate return from save and return from sleep */
  862. if (s3c2410_cpu_save(regs_save) == 0) {
  863. flush_cache_all();
  864. pm_cpu_sleep();
  865. }
  866. /* restore the cpu state */
  867. cpu_init();
  868. /* restore the system state */
  869. s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
  870. s3c2410_pm_do_restore(sromc_save, ARRAY_SIZE(sromc_save));
  871. s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));
  872. s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
  873. tmp = __raw_readl(S3C_EINTPEND);
  874. __raw_writel(tmp, S3C_EINTPEND);
  875. //s3c2410_pm_debug_init();
  876. DBG("post sleep, preparing to return\n");
  877. s3c2410_pm_check_restore();
  878. /* ok, let's return from sleep */
  879. DBG("S3C6400 PM Resume (post-restore)\n");
  880. return 0;
  881. }
  882. #endif
  883. /*
  884. * Called after processes are frozen, but before we shut down devices.
  885. */
  886. static int s3c2410_pm_prepare(suspend_state_t state)
  887. {
  888. printk("s3c2410_pm_prepare\n");
  889. return 0;
  890. }
  891. /*
  892. * Called after devices are re-setup, but before processes are thawed.
  893. */
  894. static int s3c2410_pm_finish(suspend_state_t state)
  895. {
  896. printk("s3c2410_pm_finish\n");
  897. return 0;
  898. }
  899. /*
  900. * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
  901. */
  902. static struct pm_ops s3c2410_pm_ops = {
  903. .pm_disk_mode = PM_DISK_FIRMWARE,
  904. .prepare = s3c2410_pm_prepare,
  905. #if !defined (CONFIG_CPU_S3C6400) && !defined (CONFIG_CPU_S3C6410)
  906. .enter = s3c2410_pm_enter,
  907. #else
  908. .enter = s3c6400_pm_enter,
  909. #endif
  910. .finish = s3c2410_pm_finish,
  911. };
  912. /* s3c2410_pm_init
  913. *
  914. * Attach the power management functions. This should be called
  915. * from the board specific initialisation if the board supports
  916. * it.
  917. */
  918. int __init s3c2410_pm_init(void)
  919. {
  920. printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n");
  921. pm_set_ops(&s3c2410_pm_ops);
  922. return 0;
  923. }