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