1/* 2 * linux/arch/unicore32/kernel/pm.c 3 * 4 * Code specific to PKUnity SoC and UniCore ISA 5 * 6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn> 7 * Copyright (C) 2001-2010 Guan Xuetao 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13#include <linux/init.h> 14#include <linux/module.h> 15#include <linux/suspend.h> 16#include <linux/errno.h> 17#include <linux/slab.h> 18#include <linux/io.h> 19 20#include <mach/hardware.h> 21#include <mach/pm.h> 22 23#include "setup.h" 24 25struct puv3_cpu_pm_fns *puv3_cpu_pm_fns; 26static unsigned long *sleep_save; 27 28int puv3_pm_enter(suspend_state_t state) 29{ 30 unsigned long sleep_save_checksum = 0, checksum = 0; 31 int i; 32 33 /* skip registers saving for standby */ 34 if (state != PM_SUSPEND_STANDBY) { 35 puv3_cpu_pm_fns->save(sleep_save); 36 /* before sleeping, calculate and save a checksum */ 37 for (i = 0; i < puv3_cpu_pm_fns->save_count - 1; i++) 38 sleep_save_checksum += sleep_save[i]; 39 } 40 41 /* *** go zzz *** */ 42 puv3_cpu_pm_fns->enter(state); 43 cpu_init(); 44#ifdef CONFIG_INPUT_KEYBOARD 45 puv3_ps2_init(); 46#endif 47#ifdef CONFIG_PCI 48 pci_puv3_preinit(); 49#endif 50 if (state != PM_SUSPEND_STANDBY) { 51 /* after sleeping, validate the checksum */ 52 for (i = 0; i < puv3_cpu_pm_fns->save_count - 1; i++) 53 checksum += sleep_save[i]; 54 55 /* if invalid, display message and wait for a hardware reset */ 56 if (checksum != sleep_save_checksum) { 57 while (1) 58 puv3_cpu_pm_fns->enter(state); 59 } 60 puv3_cpu_pm_fns->restore(sleep_save); 61 } 62 63 pr_debug("*** made it back from resume\n"); 64 65 return 0; 66} 67EXPORT_SYMBOL_GPL(puv3_pm_enter); 68 69unsigned long sleep_phys_sp(void *sp) 70{ 71 return virt_to_phys(sp); 72} 73 74static int puv3_pm_valid(suspend_state_t state) 75{ 76 if (puv3_cpu_pm_fns) 77 return puv3_cpu_pm_fns->valid(state); 78 79 return -EINVAL; 80} 81 82static int puv3_pm_prepare(void) 83{ 84 int ret = 0; 85 86 if (puv3_cpu_pm_fns && puv3_cpu_pm_fns->prepare) 87 ret = puv3_cpu_pm_fns->prepare(); 88 89 return ret; 90} 91 92static void puv3_pm_finish(void) 93{ 94 if (puv3_cpu_pm_fns && puv3_cpu_pm_fns->finish) 95 puv3_cpu_pm_fns->finish(); 96} 97 98static struct platform_suspend_ops puv3_pm_ops = { 99 .valid = puv3_pm_valid, 100 .enter = puv3_pm_enter, 101 .prepare = puv3_pm_prepare, 102 .finish = puv3_pm_finish, 103}; 104 105static int __init puv3_pm_init(void) 106{ 107 if (!puv3_cpu_pm_fns) { 108 printk(KERN_ERR "no valid puv3_cpu_pm_fns defined\n"); 109 return -EINVAL; 110 } 111 112 sleep_save = kmalloc(puv3_cpu_pm_fns->save_count 113 * sizeof(unsigned long), GFP_KERNEL); 114 if (!sleep_save) { 115 printk(KERN_ERR "failed to alloc memory for pm save\n"); 116 return -ENOMEM; 117 } 118 119 suspend_set_ops(&puv3_pm_ops); 120 return 0; 121} 122 123device_initcall(puv3_pm_init); 124