Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * PXA250/210 Power Management Routines
0003  *
0004  * Original code for the SA11x0:
0005  * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
0006  *
0007  * Modified for the PXA250 by Nicolas Pitre:
0008  * Copyright (c) 2002 Monta Vista Software, Inc.
0009  *
0010  * This program is free software; you can redistribute it and/or
0011  * modify it under the terms of the GNU General Public License.
0012  */
0013 #include <linux/init.h>
0014 #include <linux/module.h>
0015 #include <linux/suspend.h>
0016 #include <linux/errno.h>
0017 #include <linux/slab.h>
0018 
0019 #include "pm.h"
0020 
0021 struct pxa_cpu_pm_fns *pxa_cpu_pm_fns;
0022 static unsigned long *sleep_save;
0023 
0024 int pxa_pm_enter(suspend_state_t state)
0025 {
0026     unsigned long sleep_save_checksum = 0, checksum = 0;
0027     int i;
0028 
0029 #ifdef CONFIG_IWMMXT
0030     /* force any iWMMXt context to ram **/
0031     if (elf_hwcap & HWCAP_IWMMXT)
0032         iwmmxt_task_disable(NULL);
0033 #endif
0034 
0035     /* skip registers saving for standby */
0036     if (state != PM_SUSPEND_STANDBY && pxa_cpu_pm_fns->save) {
0037         pxa_cpu_pm_fns->save(sleep_save);
0038         /* before sleeping, calculate and save a checksum */
0039         for (i = 0; i < pxa_cpu_pm_fns->save_count - 1; i++)
0040             sleep_save_checksum += sleep_save[i];
0041     }
0042 
0043     /* *** go zzz *** */
0044     pxa_cpu_pm_fns->enter(state);
0045 
0046     if (state != PM_SUSPEND_STANDBY && pxa_cpu_pm_fns->restore) {
0047         /* after sleeping, validate the checksum */
0048         for (i = 0; i < pxa_cpu_pm_fns->save_count - 1; i++)
0049             checksum += sleep_save[i];
0050 
0051         /* if invalid, display message and wait for a hardware reset */
0052         if (checksum != sleep_save_checksum) {
0053 
0054             lubbock_set_hexled(0xbadbadc5);
0055 
0056             while (1)
0057                 pxa_cpu_pm_fns->enter(state);
0058         }
0059         pxa_cpu_pm_fns->restore(sleep_save);
0060     }
0061 
0062     pr_debug("*** made it back from resume\n");
0063 
0064     return 0;
0065 }
0066 
0067 EXPORT_SYMBOL_GPL(pxa_pm_enter);
0068 
0069 static int pxa_pm_valid(suspend_state_t state)
0070 {
0071     if (pxa_cpu_pm_fns)
0072         return pxa_cpu_pm_fns->valid(state);
0073 
0074     return -EINVAL;
0075 }
0076 
0077 int pxa_pm_prepare(void)
0078 {
0079     int ret = 0;
0080 
0081     if (pxa_cpu_pm_fns && pxa_cpu_pm_fns->prepare)
0082         ret = pxa_cpu_pm_fns->prepare();
0083 
0084     return ret;
0085 }
0086 
0087 void pxa_pm_finish(void)
0088 {
0089     if (pxa_cpu_pm_fns && pxa_cpu_pm_fns->finish)
0090         pxa_cpu_pm_fns->finish();
0091 }
0092 
0093 static const struct platform_suspend_ops pxa_pm_ops = {
0094     .valid      = pxa_pm_valid,
0095     .enter      = pxa_pm_enter,
0096     .prepare    = pxa_pm_prepare,
0097     .finish     = pxa_pm_finish,
0098 };
0099 
0100 static int __init pxa_pm_init(void)
0101 {
0102     if (!pxa_cpu_pm_fns) {
0103         printk(KERN_ERR "no valid pxa_cpu_pm_fns defined\n");
0104         return -EINVAL;
0105     }
0106 
0107     sleep_save = kmalloc_array(pxa_cpu_pm_fns->save_count,
0108                    sizeof(*sleep_save),
0109                    GFP_KERNEL);
0110     if (!sleep_save)
0111         return -ENOMEM;
0112 
0113     suspend_set_ops(&pxa_pm_ops);
0114     return 0;
0115 }
0116 
0117 device_initcall(pxa_pm_init);