0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/errno.h>
0011 #include <linux/err.h>
0012 #include <linux/time.h>
0013 #include <linux/delay.h>
0014 #include <linux/suspend.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/io.h>
0017 #include <linux/irq.h>
0018 #include <asm/mach-types.h>
0019 #include <asm/outercache.h>
0020
0021 #include <linux/soc/mmp/cputype.h>
0022 #include "addr-map.h"
0023 #include "pm-pxa910.h"
0024 #include "regs-icu.h"
0025 #include "irqs.h"
0026
0027 int pxa910_set_wake(struct irq_data *data, unsigned int on)
0028 {
0029 uint32_t awucrm = 0, apcr = 0;
0030 int irq = data->irq;
0031
0032
0033 switch (irq) {
0034
0035 case IRQ_PXA910_AP_GPIO:
0036 awucrm = MPMU_AWUCRM_WAKEUP(2);
0037 apcr |= MPMU_APCR_SLPWP2;
0038 break;
0039
0040 case IRQ_PXA910_KEYPAD:
0041 awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_KEYPRESS;
0042 apcr |= MPMU_APCR_SLPWP3;
0043 break;
0044 case IRQ_PXA910_ROTARY:
0045 awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_NEWROTARY;
0046 apcr |= MPMU_APCR_SLPWP3;
0047 break;
0048 case IRQ_PXA910_TRACKBALL:
0049 awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_TRACKBALL;
0050 apcr |= MPMU_APCR_SLPWP3;
0051 break;
0052
0053 case IRQ_PXA910_AP1_TIMER1:
0054 awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_1;
0055 apcr |= MPMU_APCR_SLPWP4;
0056 break;
0057 case IRQ_PXA910_AP1_TIMER2:
0058 awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_2;
0059 apcr |= MPMU_APCR_SLPWP4;
0060 break;
0061 case IRQ_PXA910_AP1_TIMER3:
0062 awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_3;
0063 apcr |= MPMU_APCR_SLPWP4;
0064 break;
0065 case IRQ_PXA910_AP2_TIMER1:
0066 awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_1;
0067 apcr |= MPMU_APCR_SLPWP4;
0068 break;
0069 case IRQ_PXA910_AP2_TIMER2:
0070 awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_2;
0071 apcr |= MPMU_APCR_SLPWP4;
0072 break;
0073 case IRQ_PXA910_AP2_TIMER3:
0074 awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_3;
0075 apcr |= MPMU_APCR_SLPWP4;
0076 break;
0077 case IRQ_PXA910_RTC_ALARM:
0078 awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_RTC_ALARM;
0079 apcr |= MPMU_APCR_SLPWP4;
0080 break;
0081
0082 case IRQ_PXA910_USB1:
0083 case IRQ_PXA910_USB2:
0084 awucrm = MPMU_AWUCRM_WAKEUP(5);
0085 apcr |= MPMU_APCR_SLPWP5;
0086 break;
0087
0088 case IRQ_PXA910_MMC:
0089 awucrm = MPMU_AWUCRM_WAKEUP(6)
0090 | MPMU_AWUCRM_SDH1
0091 | MPMU_AWUCRM_SDH2;
0092 apcr |= MPMU_APCR_SLPWP6;
0093 break;
0094
0095 case IRQ_PXA910_PMIC_INT:
0096 awucrm = MPMU_AWUCRM_WAKEUP(7);
0097 apcr |= MPMU_APCR_SLPWP7;
0098 break;
0099 default:
0100 if (irq >= IRQ_GPIO_START && irq < IRQ_BOARD_START) {
0101 awucrm = MPMU_AWUCRM_WAKEUP(2);
0102 apcr |= MPMU_APCR_SLPWP2;
0103 } else {
0104
0105 printk(KERN_ERR "Error: no defined wake up source irq: %d\n",
0106 irq);
0107 }
0108 }
0109
0110 if (on) {
0111 if (awucrm) {
0112 awucrm |= __raw_readl(MPMU_AWUCRM);
0113 __raw_writel(awucrm, MPMU_AWUCRM);
0114 }
0115 if (apcr) {
0116 apcr = ~apcr & __raw_readl(MPMU_APCR);
0117 __raw_writel(apcr, MPMU_APCR);
0118 }
0119 } else {
0120 if (awucrm) {
0121 awucrm = ~awucrm & __raw_readl(MPMU_AWUCRM);
0122 __raw_writel(awucrm, MPMU_AWUCRM);
0123 }
0124 if (apcr) {
0125 apcr |= __raw_readl(MPMU_APCR);
0126 __raw_writel(apcr, MPMU_APCR);
0127 }
0128 }
0129 return 0;
0130 }
0131
0132 void pxa910_pm_enter_lowpower_mode(int state)
0133 {
0134 uint32_t idle_cfg, apcr;
0135
0136 idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
0137 apcr = __raw_readl(MPMU_APCR);
0138
0139 apcr &= ~(MPMU_APCR_DDRCORSD | MPMU_APCR_APBSD | MPMU_APCR_AXISD
0140 | MPMU_APCR_VCTCXOSD | MPMU_APCR_STBYEN);
0141 idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_IDLE
0142 | APMU_MOH_IDLE_CFG_MOH_PWRDWN);
0143
0144 switch (state) {
0145 case POWER_MODE_UDR:
0146
0147 apcr |= MPMU_APCR_STBYEN | MPMU_APCR_APBSD;
0148 fallthrough;
0149 case POWER_MODE_SYS_SLEEP:
0150 apcr |= MPMU_APCR_SLPEN;
0151 apcr |= MPMU_APCR_VCTCXOSD;
0152 fallthrough;
0153 case POWER_MODE_APPS_SLEEP:
0154 apcr |= MPMU_APCR_DDRCORSD;
0155 fallthrough;
0156 case POWER_MODE_APPS_IDLE:
0157 apcr |= MPMU_APCR_AXISD;
0158 fallthrough;
0159 case POWER_MODE_CORE_EXTIDLE:
0160 idle_cfg |= APMU_MOH_IDLE_CFG_MOH_IDLE;
0161 idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN;
0162 idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWR_SW(3)
0163 | APMU_MOH_IDLE_CFG_MOH_L2_PWR_SW(3);
0164 fallthrough;
0165 case POWER_MODE_CORE_INTIDLE:
0166 break;
0167 }
0168
0169
0170 idle_cfg |= APMU_MOH_IDLE_CFG_MOH_DIS_MC_SW_REQ;
0171 idle_cfg |= APMU_MOH_IDLE_CFG_MOH_MC_WAKE_EN;
0172 __raw_writel(0x0, APMU_MC_HW_SLP_TYPE);
0173
0174
0175 apcr |= MPMU_APCR_DSPSD | MPMU_APCR_DTCMSD | MPMU_APCR_BBSD
0176 | MPMU_APCR_MSASLPEN;
0177
0178
0179 apcr |= MPMU_APCR_SLPEN;
0180
0181
0182 __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
0183 __raw_writel(apcr, MPMU_APCR);
0184
0185 }
0186
0187 static int pxa910_pm_enter(suspend_state_t state)
0188 {
0189 unsigned int idle_cfg, reg = 0;
0190
0191
0192 reg = __raw_readl(ICU_INT_CONF(IRQ_PXA910_PMIC_INT));
0193 if ((reg & 0x3) == 0)
0194 return -EAGAIN;
0195
0196 idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
0197 idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN
0198 | APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN;
0199 __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
0200
0201
0202 outer_disable();
0203
0204 while (!(readl(CIU_REG(0x8)) & (1 << 16)))
0205 udelay(1);
0206
0207 cpu_do_idle();
0208
0209
0210 outer_resume();
0211
0212 while (!(readl(CIU_REG(0x8)) & (1 << 16)))
0213 udelay(1);
0214
0215 idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
0216 idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_PWRDWN
0217 | APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN);
0218 __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
0219
0220 return 0;
0221 }
0222
0223
0224
0225
0226 static int pxa910_pm_prepare(void)
0227 {
0228 pxa910_pm_enter_lowpower_mode(POWER_MODE_UDR);
0229 return 0;
0230 }
0231
0232
0233
0234
0235 static void pxa910_pm_finish(void)
0236 {
0237 pxa910_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE);
0238 }
0239
0240 static int pxa910_pm_valid(suspend_state_t state)
0241 {
0242 return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM));
0243 }
0244
0245 static const struct platform_suspend_ops pxa910_pm_ops = {
0246 .valid = pxa910_pm_valid,
0247 .prepare = pxa910_pm_prepare,
0248 .enter = pxa910_pm_enter,
0249 .finish = pxa910_pm_finish,
0250 };
0251
0252 static int __init pxa910_pm_init(void)
0253 {
0254 uint32_t awucrm = 0;
0255
0256 if (!cpu_is_pxa910())
0257 return -EIO;
0258
0259 suspend_set_ops(&pxa910_pm_ops);
0260
0261
0262 __raw_writel(__raw_readl(APMU_SQU_CLK_GATE_CTRL) | (1 << 30),
0263 APMU_SQU_CLK_GATE_CTRL);
0264 __raw_writel(__raw_readl(MPMU_FCCR) | (1 << 28), MPMU_FCCR);
0265
0266 awucrm |= MPMU_AWUCRM_AP_ASYNC_INT | MPMU_AWUCRM_AP_FULL_IDLE;
0267 __raw_writel(awucrm, MPMU_AWUCRM);
0268
0269 return 0;
0270 }
0271
0272 late_initcall(pxa910_pm_init);