ip32-reset.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*
  2. * This file is subject to the terms and conditions of the GNU General Public
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * Copyright (C) 2001 Keith M Wesolowski
  7. * Copyright (C) 2001 Paul Mundt
  8. * Copyright (C) 2003 Guido Guenther <agx@sigxcpu.org>
  9. */
  10. #include <linux/compiler.h>
  11. #include <linux/init.h>
  12. #include <linux/kernel.h>
  13. #include <linux/module.h>
  14. #include <linux/sched.h>
  15. #include <linux/notifier.h>
  16. #include <linux/delay.h>
  17. #include <linux/rtc/ds1685.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/pm.h>
  20. #include <asm/addrspace.h>
  21. #include <asm/irq.h>
  22. #include <asm/reboot.h>
  23. #include <asm/wbflush.h>
  24. #include <asm/ip32/mace.h>
  25. #include <asm/ip32/crime.h>
  26. #include <asm/ip32/ip32_ints.h>
  27. #define POWERDOWN_TIMEOUT 120
  28. /*
  29. * Blink frequency during reboot grace period and when panicked.
  30. */
  31. #define POWERDOWN_FREQ (HZ / 4)
  32. #define PANIC_FREQ (HZ / 8)
  33. extern struct platform_device ip32_rtc_device;
  34. static struct timer_list power_timer, blink_timer;
  35. static int has_panicked, shutting_down;
  36. static __noreturn void ip32_poweroff(void *data)
  37. {
  38. void (*poweroff_func)(struct platform_device *) =
  39. symbol_get(ds1685_rtc_poweroff);
  40. #ifdef CONFIG_MODULES
  41. /* If the first __symbol_get failed, our module wasn't loaded. */
  42. if (!poweroff_func) {
  43. request_module("rtc-ds1685");
  44. poweroff_func = symbol_get(ds1685_rtc_poweroff);
  45. }
  46. #endif
  47. if (!poweroff_func)
  48. pr_emerg("RTC not available for power-off. Spinning forever ...\n");
  49. else {
  50. (*poweroff_func)((struct platform_device *)data);
  51. symbol_put(ds1685_rtc_poweroff);
  52. }
  53. unreachable();
  54. }
  55. static void ip32_machine_restart(char *cmd) __noreturn;
  56. static void ip32_machine_restart(char *cmd)
  57. {
  58. msleep(20);
  59. crime->control = CRIME_CONTROL_HARD_RESET;
  60. unreachable();
  61. }
  62. static void blink_timeout(unsigned long data)
  63. {
  64. unsigned long led = mace->perif.ctrl.misc ^ MACEISA_LED_RED;
  65. mace->perif.ctrl.misc = led;
  66. mod_timer(&blink_timer, jiffies + data);
  67. }
  68. static void ip32_machine_halt(void)
  69. {
  70. ip32_poweroff(&ip32_rtc_device);
  71. }
  72. static void power_timeout(unsigned long data)
  73. {
  74. ip32_poweroff(&ip32_rtc_device);
  75. }
  76. void ip32_prepare_poweroff(void)
  77. {
  78. if (has_panicked)
  79. return;
  80. if (shutting_down || kill_cad_pid(SIGINT, 1)) {
  81. /* No init process or button pressed twice. */
  82. ip32_poweroff(&ip32_rtc_device);
  83. }
  84. shutting_down = 1;
  85. blink_timer.data = POWERDOWN_FREQ;
  86. blink_timeout(POWERDOWN_FREQ);
  87. init_timer(&power_timer);
  88. power_timer.function = power_timeout;
  89. power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ;
  90. add_timer(&power_timer);
  91. }
  92. static int panic_event(struct notifier_block *this, unsigned long event,
  93. void *ptr)
  94. {
  95. unsigned long led;
  96. if (has_panicked)
  97. return NOTIFY_DONE;
  98. has_panicked = 1;
  99. /* turn off the green LED */
  100. led = mace->perif.ctrl.misc | MACEISA_LED_GREEN;
  101. mace->perif.ctrl.misc = led;
  102. blink_timer.data = PANIC_FREQ;
  103. blink_timeout(PANIC_FREQ);
  104. return NOTIFY_DONE;
  105. }
  106. static struct notifier_block panic_block = {
  107. .notifier_call = panic_event,
  108. };
  109. static __init int ip32_reboot_setup(void)
  110. {
  111. /* turn on the green led only */
  112. unsigned long led = mace->perif.ctrl.misc;
  113. led |= MACEISA_LED_RED;
  114. led &= ~MACEISA_LED_GREEN;
  115. mace->perif.ctrl.misc = led;
  116. _machine_restart = ip32_machine_restart;
  117. _machine_halt = ip32_machine_halt;
  118. pm_power_off = ip32_machine_halt;
  119. init_timer(&blink_timer);
  120. blink_timer.function = blink_timeout;
  121. atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
  122. return 0;
  123. }
  124. subsys_initcall(ip32_reboot_setup);