pm.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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. #include <mach/hardware.h>
  20. #include <mach/pm.h>
  21. #include "setup.h"
  22. struct puv3_cpu_pm_fns *puv3_cpu_pm_fns;
  23. static unsigned long *sleep_save;
  24. int puv3_pm_enter(suspend_state_t state)
  25. {
  26. unsigned long sleep_save_checksum = 0, checksum = 0;
  27. int i;
  28. /* skip registers saving for standby */
  29. if (state != PM_SUSPEND_STANDBY) {
  30. puv3_cpu_pm_fns->save(sleep_save);
  31. /* before sleeping, calculate and save a checksum */
  32. for (i = 0; i < puv3_cpu_pm_fns->save_count - 1; i++)
  33. sleep_save_checksum += sleep_save[i];
  34. }
  35. /* *** go zzz *** */
  36. puv3_cpu_pm_fns->enter(state);
  37. cpu_init();
  38. #ifdef CONFIG_INPUT_KEYBOARD
  39. puv3_ps2_init();
  40. #endif
  41. #ifdef CONFIG_PCI
  42. pci_puv3_preinit();
  43. #endif
  44. if (state != PM_SUSPEND_STANDBY) {
  45. /* after sleeping, validate the checksum */
  46. for (i = 0; i < puv3_cpu_pm_fns->save_count - 1; i++)
  47. checksum += sleep_save[i];
  48. /* if invalid, display message and wait for a hardware reset */
  49. if (checksum != sleep_save_checksum) {
  50. while (1)
  51. puv3_cpu_pm_fns->enter(state);
  52. }
  53. puv3_cpu_pm_fns->restore(sleep_save);
  54. }
  55. pr_debug("*** made it back from resume\n");
  56. return 0;
  57. }
  58. EXPORT_SYMBOL_GPL(puv3_pm_enter);
  59. unsigned long sleep_phys_sp(void *sp)
  60. {
  61. return virt_to_phys(sp);
  62. }
  63. static int puv3_pm_valid(suspend_state_t state)
  64. {
  65. if (puv3_cpu_pm_fns)
  66. return puv3_cpu_pm_fns->valid(state);
  67. return -EINVAL;
  68. }
  69. static int puv3_pm_prepare(void)
  70. {
  71. int ret = 0;
  72. if (puv3_cpu_pm_fns && puv3_cpu_pm_fns->prepare)
  73. ret = puv3_cpu_pm_fns->prepare();
  74. return ret;
  75. }
  76. static void puv3_pm_finish(void)
  77. {
  78. if (puv3_cpu_pm_fns && puv3_cpu_pm_fns->finish)
  79. puv3_cpu_pm_fns->finish();
  80. }
  81. static struct platform_suspend_ops puv3_pm_ops = {
  82. .valid = puv3_pm_valid,
  83. .enter = puv3_pm_enter,
  84. .prepare = puv3_pm_prepare,
  85. .finish = puv3_pm_finish,
  86. };
  87. static int __init puv3_pm_init(void)
  88. {
  89. if (!puv3_cpu_pm_fns) {
  90. printk(KERN_ERR "no valid puv3_cpu_pm_fns defined\n");
  91. return -EINVAL;
  92. }
  93. sleep_save = kmalloc(puv3_cpu_pm_fns->save_count
  94. * sizeof(unsigned long), GFP_KERNEL);
  95. if (!sleep_save) {
  96. printk(KERN_ERR "failed to alloc memory for pm save\n");
  97. return -ENOMEM;
  98. }
  99. suspend_set_ops(&puv3_pm_ops);
  100. return 0;
  101. }
  102. device_initcall(puv3_pm_init);