pm-pxa910.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * PXA910 Power Management Routines
  3. *
  4. * This software program is licensed subject to the GNU General Public License
  5. * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
  6. *
  7. * (C) Copyright 2009 Marvell International Ltd.
  8. * All Rights Reserved
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/errno.h>
  12. #include <linux/err.h>
  13. #include <linux/time.h>
  14. #include <linux/delay.h>
  15. #include <linux/suspend.h>
  16. #include <linux/interrupt.h>
  17. #include <linux/io.h>
  18. #include <linux/irq.h>
  19. #include <asm/mach-types.h>
  20. #include <asm/outercache.h>
  21. #include <mach/hardware.h>
  22. #include <mach/cputype.h>
  23. #include <mach/addr-map.h>
  24. #include <mach/pm-pxa910.h>
  25. #include <mach/regs-icu.h>
  26. #include <mach/irqs.h>
  27. int pxa910_set_wake(struct irq_data *data, unsigned int on)
  28. {
  29. uint32_t awucrm = 0, apcr = 0;
  30. int irq = data->irq;
  31. /* setting wakeup sources */
  32. switch (irq) {
  33. /* wakeup line 2 */
  34. case IRQ_PXA910_AP_GPIO:
  35. awucrm = MPMU_AWUCRM_WAKEUP(2);
  36. apcr |= MPMU_APCR_SLPWP2;
  37. break;
  38. /* wakeup line 3 */
  39. case IRQ_PXA910_KEYPAD:
  40. awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_KEYPRESS;
  41. apcr |= MPMU_APCR_SLPWP3;
  42. break;
  43. case IRQ_PXA910_ROTARY:
  44. awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_NEWROTARY;
  45. apcr |= MPMU_APCR_SLPWP3;
  46. break;
  47. case IRQ_PXA910_TRACKBALL:
  48. awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_TRACKBALL;
  49. apcr |= MPMU_APCR_SLPWP3;
  50. break;
  51. /* wakeup line 4 */
  52. case IRQ_PXA910_AP1_TIMER1:
  53. awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_1;
  54. apcr |= MPMU_APCR_SLPWP4;
  55. break;
  56. case IRQ_PXA910_AP1_TIMER2:
  57. awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_2;
  58. apcr |= MPMU_APCR_SLPWP4;
  59. break;
  60. case IRQ_PXA910_AP1_TIMER3:
  61. awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_3;
  62. apcr |= MPMU_APCR_SLPWP4;
  63. break;
  64. case IRQ_PXA910_AP2_TIMER1:
  65. awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_1;
  66. apcr |= MPMU_APCR_SLPWP4;
  67. break;
  68. case IRQ_PXA910_AP2_TIMER2:
  69. awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_2;
  70. apcr |= MPMU_APCR_SLPWP4;
  71. break;
  72. case IRQ_PXA910_AP2_TIMER3:
  73. awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_3;
  74. apcr |= MPMU_APCR_SLPWP4;
  75. break;
  76. case IRQ_PXA910_RTC_ALARM:
  77. awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_RTC_ALARM;
  78. apcr |= MPMU_APCR_SLPWP4;
  79. break;
  80. /* wakeup line 5 */
  81. case IRQ_PXA910_USB1:
  82. case IRQ_PXA910_USB2:
  83. awucrm = MPMU_AWUCRM_WAKEUP(5);
  84. apcr |= MPMU_APCR_SLPWP5;
  85. break;
  86. /* wakeup line 6 */
  87. case IRQ_PXA910_MMC:
  88. awucrm = MPMU_AWUCRM_WAKEUP(6)
  89. | MPMU_AWUCRM_SDH1
  90. | MPMU_AWUCRM_SDH2;
  91. apcr |= MPMU_APCR_SLPWP6;
  92. break;
  93. /* wakeup line 7 */
  94. case IRQ_PXA910_PMIC_INT:
  95. awucrm = MPMU_AWUCRM_WAKEUP(7);
  96. apcr |= MPMU_APCR_SLPWP7;
  97. break;
  98. default:
  99. if (irq >= IRQ_GPIO_START && irq < IRQ_BOARD_START) {
  100. awucrm = MPMU_AWUCRM_WAKEUP(2);
  101. apcr |= MPMU_APCR_SLPWP2;
  102. } else {
  103. /* FIXME: This should return a proper error code ! */
  104. printk(KERN_ERR "Error: no defined wake up source irq: %d\n",
  105. irq);
  106. }
  107. }
  108. if (on) {
  109. if (awucrm) {
  110. awucrm |= __raw_readl(MPMU_AWUCRM);
  111. __raw_writel(awucrm, MPMU_AWUCRM);
  112. }
  113. if (apcr) {
  114. apcr = ~apcr & __raw_readl(MPMU_APCR);
  115. __raw_writel(apcr, MPMU_APCR);
  116. }
  117. } else {
  118. if (awucrm) {
  119. awucrm = ~awucrm & __raw_readl(MPMU_AWUCRM);
  120. __raw_writel(awucrm, MPMU_AWUCRM);
  121. }
  122. if (apcr) {
  123. apcr |= __raw_readl(MPMU_APCR);
  124. __raw_writel(apcr, MPMU_APCR);
  125. }
  126. }
  127. return 0;
  128. }
  129. void pxa910_pm_enter_lowpower_mode(int state)
  130. {
  131. uint32_t idle_cfg, apcr;
  132. idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
  133. apcr = __raw_readl(MPMU_APCR);
  134. apcr &= ~(MPMU_APCR_DDRCORSD | MPMU_APCR_APBSD | MPMU_APCR_AXISD
  135. | MPMU_APCR_VCTCXOSD | MPMU_APCR_STBYEN);
  136. idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_IDLE
  137. | APMU_MOH_IDLE_CFG_MOH_PWRDWN);
  138. switch (state) {
  139. case POWER_MODE_UDR:
  140. /* only shutdown APB in UDR */
  141. apcr |= MPMU_APCR_STBYEN | MPMU_APCR_APBSD;
  142. /* fall through */
  143. case POWER_MODE_SYS_SLEEP:
  144. apcr |= MPMU_APCR_SLPEN; /* set the SLPEN bit */
  145. apcr |= MPMU_APCR_VCTCXOSD; /* set VCTCXOSD */
  146. /* fall through */
  147. case POWER_MODE_APPS_SLEEP:
  148. apcr |= MPMU_APCR_DDRCORSD; /* set DDRCORSD */
  149. /* fall through */
  150. case POWER_MODE_APPS_IDLE:
  151. apcr |= MPMU_APCR_AXISD; /* set AXISDD bit */
  152. /* fall through */
  153. case POWER_MODE_CORE_EXTIDLE:
  154. idle_cfg |= APMU_MOH_IDLE_CFG_MOH_IDLE;
  155. idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN;
  156. idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWR_SW(3)
  157. | APMU_MOH_IDLE_CFG_MOH_L2_PWR_SW(3);
  158. /* fall through */
  159. case POWER_MODE_CORE_INTIDLE:
  160. break;
  161. }
  162. /* program the memory controller hardware sleep type and auto wakeup */
  163. idle_cfg |= APMU_MOH_IDLE_CFG_MOH_DIS_MC_SW_REQ;
  164. idle_cfg |= APMU_MOH_IDLE_CFG_MOH_MC_WAKE_EN;
  165. __raw_writel(0x0, APMU_MC_HW_SLP_TYPE); /* auto refresh */
  166. /* set DSPSD, DTCMSD, BBSD, MSASLPEN */
  167. apcr |= MPMU_APCR_DSPSD | MPMU_APCR_DTCMSD | MPMU_APCR_BBSD
  168. | MPMU_APCR_MSASLPEN;
  169. /*always set SLEPEN bit mainly for MSA*/
  170. apcr |= MPMU_APCR_SLPEN;
  171. /* finally write the registers back */
  172. __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
  173. __raw_writel(apcr, MPMU_APCR);
  174. }
  175. static int pxa910_pm_enter(suspend_state_t state)
  176. {
  177. unsigned int idle_cfg, reg = 0;
  178. /*pmic thread not completed,exit;otherwise system can't be waked up*/
  179. reg = __raw_readl(ICU_INT_CONF(IRQ_PXA910_PMIC_INT));
  180. if ((reg & 0x3) == 0)
  181. return -EAGAIN;
  182. idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
  183. idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN
  184. | APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN;
  185. __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
  186. /* disable L2 */
  187. outer_disable();
  188. /* wait for l2 idle */
  189. while (!(readl(CIU_REG(0x8)) & (1 << 16)))
  190. udelay(1);
  191. cpu_do_idle();
  192. /* enable L2 */
  193. outer_resume();
  194. /* wait for l2 idle */
  195. while (!(readl(CIU_REG(0x8)) & (1 << 16)))
  196. udelay(1);
  197. idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
  198. idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_PWRDWN
  199. | APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN);
  200. __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
  201. return 0;
  202. }
  203. /*
  204. * Called after processes are frozen, but before we shut down devices.
  205. */
  206. static int pxa910_pm_prepare(void)
  207. {
  208. pxa910_pm_enter_lowpower_mode(POWER_MODE_UDR);
  209. return 0;
  210. }
  211. /*
  212. * Called after devices are re-setup, but before processes are thawed.
  213. */
  214. static void pxa910_pm_finish(void)
  215. {
  216. pxa910_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE);
  217. }
  218. static int pxa910_pm_valid(suspend_state_t state)
  219. {
  220. return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM));
  221. }
  222. static const struct platform_suspend_ops pxa910_pm_ops = {
  223. .valid = pxa910_pm_valid,
  224. .prepare = pxa910_pm_prepare,
  225. .enter = pxa910_pm_enter,
  226. .finish = pxa910_pm_finish,
  227. };
  228. static int __init pxa910_pm_init(void)
  229. {
  230. uint32_t awucrm = 0;
  231. if (!cpu_is_pxa910())
  232. return -EIO;
  233. suspend_set_ops(&pxa910_pm_ops);
  234. /* Set the following bits for MMP3 playback with VCTXO on */
  235. __raw_writel(__raw_readl(APMU_SQU_CLK_GATE_CTRL) | (1 << 30),
  236. APMU_SQU_CLK_GATE_CTRL);
  237. __raw_writel(__raw_readl(MPMU_FCCR) | (1 << 28), MPMU_FCCR);
  238. awucrm |= MPMU_AWUCRM_AP_ASYNC_INT | MPMU_AWUCRM_AP_FULL_IDLE;
  239. __raw_writel(awucrm, MPMU_AWUCRM);
  240. return 0;
  241. }
  242. late_initcall(pxa910_pm_init);