linux-bk/arch/arm/mach-pxa/pm.c
<<
>>
Prefs
   1/*
   2 * PXA250/210 Power Management Routines
   3 *
   4 * Original code for the SA11x0:
   5 * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
   6 *
   7 * Modified for the PXA250 by Nicolas Pitre:
   8 * Copyright (c) 2002 Monta Vista Software, Inc.
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License.
  12 */
  13#include <linux/config.h>
  14#include <linux/init.h>
  15#include <linux/suspend.h>
  16#include <linux/errno.h>
  17#include <linux/time.h>
  18
  19#include <asm/hardware.h>
  20#include <asm/memory.h>
  21#include <asm/system.h>
  22#include <asm/arch/lubbock.h>
  23
  24
  25/*
  26 * Debug macros
  27 */
  28#undef DEBUG
  29
  30extern void pxa_cpu_suspend(void);
  31extern void pxa_cpu_resume(void);
  32
  33#define SAVE(x)         sleep_save[SLEEP_SAVE_##x] = x
  34#define RESTORE(x)      x = sleep_save[SLEEP_SAVE_##x]
  35
  36#define RESTORE_GPLEVEL(n) do { \
  37        GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
  38        GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
  39} while (0)
  40
  41/*
  42 * List of global PXA peripheral registers to preserve.
  43 * More ones like CP and general purpose register values are preserved
  44 * with the stack pointer in sleep.S.
  45 */
  46enum {  SLEEP_SAVE_START = 0,
  47
  48        SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER,
  49        SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3,
  50
  51        SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2,
  52        SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2,
  53        SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2,
  54        SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2,
  55        SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR2_L,
  56        SLEEP_SAVE_GAFR0_U, SLEEP_SAVE_GAFR1_U, SLEEP_SAVE_GAFR2_U,
  57
  58        SLEEP_SAVE_ICMR,
  59        SLEEP_SAVE_CKEN,
  60
  61        SLEEP_SAVE_CKSUM,
  62
  63        SLEEP_SAVE_SIZE
  64};
  65
  66
  67static int pxa_pm_enter(u32 state)
  68{
  69        unsigned long sleep_save[SLEEP_SAVE_SIZE];
  70        unsigned long checksum = 0;
  71        unsigned long delta;
  72        int i;
  73
  74        if (state != PM_SUSPEND_MEM)
  75                return -EINVAL;
  76
  77        /* preserve current time */
  78        delta = xtime.tv_sec - RCNR;
  79
  80        /* save vital registers */
  81        SAVE(OSCR);
  82        SAVE(OSMR0);
  83        SAVE(OSMR1);
  84        SAVE(OSMR2);
  85        SAVE(OSMR3);
  86        SAVE(OIER);
  87
  88        SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2);
  89        SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
  90        SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
  91        SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
  92        SAVE(GAFR0_L); SAVE(GAFR0_U);
  93        SAVE(GAFR1_L); SAVE(GAFR1_U);
  94        SAVE(GAFR2_L); SAVE(GAFR2_U);
  95
  96        SAVE(ICMR);
  97        ICMR = 0;
  98
  99        SAVE(CKEN);
 100        CKEN = 0;
 101
 102        /* Note: wake up source are set up in each machine specific files */
 103
 104        /* clear GPIO transition detect  bits */
 105        GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2;
 106
 107        /* Clear sleep reset status */
 108        RCSR = RCSR_SMR;
 109
 110        /* set resume return address */
 111        PSPR = virt_to_phys(pxa_cpu_resume);
 112
 113        /* before sleeping, calculate and save a checksum */
 114        for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
 115                checksum += sleep_save[i];
 116        sleep_save[SLEEP_SAVE_CKSUM] = checksum;
 117
 118        /* *** go zzz *** */
 119        pxa_cpu_suspend();
 120
 121        /* after sleeping, validate the checksum */
 122        checksum = 0;
 123        for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
 124                checksum += sleep_save[i];
 125
 126        /* if invalid, display message and wait for a hardware reset */
 127        if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) {
 128#ifdef CONFIG_ARCH_LUBBOCK
 129                LUB_HEXLED = 0xbadbadc5;
 130#endif
 131                while (1);
 132        }
 133
 134        /* ensure not to come back here if it wasn't intended */
 135        PSPR = 0;
 136
 137        /* restore registers */
 138        RESTORE(GAFR0_L); RESTORE(GAFR0_U);
 139        RESTORE(GAFR1_L); RESTORE(GAFR1_U);
 140        RESTORE(GAFR2_L); RESTORE(GAFR2_U);
 141        RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2);
 142        RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
 143        RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
 144        RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
 145
 146        PSSR = PSSR_RDH | PSSR_PH;
 147
 148        RESTORE(OSMR0);
 149        RESTORE(OSMR1);
 150        RESTORE(OSMR2);
 151        RESTORE(OSMR3);
 152        RESTORE(OSCR);
 153        RESTORE(OIER);
 154
 155        RESTORE(CKEN);
 156
 157        ICLR = 0;
 158        ICCR = 1;
 159        RESTORE(ICMR);
 160
 161        /* restore current time */
 162        xtime.tv_sec = RCNR + delta;
 163
 164#ifdef DEBUG
 165        printk(KERN_DEBUG "*** made it back from resume\n");
 166#endif
 167
 168        return 0;
 169}
 170
 171unsigned long sleep_phys_sp(void *sp)
 172{
 173        return virt_to_phys(sp);
 174}
 175
 176/*
 177 * Called after processes are frozen, but before we shut down devices.
 178 */
 179static int pxa_pm_prepare(u32 state)
 180{
 181        return 0;
 182}
 183
 184/*
 185 * Called after devices are re-setup, but before processes are thawed.
 186 */
 187static int pxa_pm_finish(u32 state)
 188{
 189        return 0;
 190}
 191
 192/*
 193 * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
 194 */
 195static struct pm_ops pxa_pm_ops = {
 196        .pm_disk_mode   = PM_DISK_FIRMWARE,
 197        .prepare        = pxa_pm_prepare,
 198        .enter          = pxa_pm_enter,
 199        .finish         = pxa_pm_finish,
 200};
 201
 202static int __init pxa_pm_init(void)
 203{
 204        pm_set_ops(&pxa_pm_ops);
 205        return 0;
 206}
 207
 208late_initcall(pxa_pm_init);
 209
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.