]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | ||
efc46d13 | 11 | #include <linux/compiler.h> |
1da177e4 LT |
12 | #include <linux/init.h> |
13 | #include <linux/kernel.h> | |
15beb694 | 14 | #include <linux/module.h> |
1da177e4 | 15 | #include <linux/sched.h> |
fc69910f | 16 | #include <linux/sched/signal.h> |
1da177e4 LT |
17 | #include <linux/notifier.h> |
18 | #include <linux/delay.h> | |
15beb694 | 19 | #include <linux/rtc/ds1685.h> |
1da177e4 | 20 | #include <linux/interrupt.h> |
fcdb27ad | 21 | #include <linux/pm.h> |
1da177e4 LT |
22 | |
23 | #include <asm/addrspace.h> | |
24 | #include <asm/irq.h> | |
25 | #include <asm/reboot.h> | |
1da177e4 LT |
26 | #include <asm/wbflush.h> |
27 | #include <asm/ip32/mace.h> | |
28 | #include <asm/ip32/crime.h> | |
29 | #include <asm/ip32/ip32_ints.h> | |
30 | ||
31 | #define POWERDOWN_TIMEOUT 120 | |
32 | /* | |
f18190bd | 33 | * Blink frequency during reboot grace period and when panicked. |
1da177e4 LT |
34 | */ |
35 | #define POWERDOWN_FREQ (HZ / 4) | |
36 | #define PANIC_FREQ (HZ / 8) | |
37 | ||
15beb694 | 38 | extern struct platform_device ip32_rtc_device; |
1da177e4 | 39 | |
15beb694 JK |
40 | static struct timer_list power_timer, blink_timer; |
41 | static int has_panicked, shutting_down; | |
1da177e4 | 42 | |
15beb694 | 43 | static __noreturn void ip32_poweroff(void *data) |
1da177e4 | 44 | { |
15beb694 JK |
45 | void (*poweroff_func)(struct platform_device *) = |
46 | symbol_get(ds1685_rtc_poweroff); | |
47 | ||
48 | #ifdef CONFIG_MODULES | |
49 | /* If the first __symbol_get failed, our module wasn't loaded. */ | |
50 | if (!poweroff_func) { | |
51 | request_module("rtc-ds1685"); | |
52 | poweroff_func = symbol_get(ds1685_rtc_poweroff); | |
53 | } | |
54 | #endif | |
1da177e4 | 55 | |
15beb694 JK |
56 | if (!poweroff_func) |
57 | pr_emerg("RTC not available for power-off. Spinning forever ...\n"); | |
58 | else { | |
59 | (*poweroff_func)((struct platform_device *)data); | |
60 | symbol_put(ds1685_rtc_poweroff); | |
61 | } | |
1da177e4 | 62 | |
15beb694 | 63 | unreachable(); |
1da177e4 LT |
64 | } |
65 | ||
15beb694 JK |
66 | static void ip32_machine_restart(char *cmd) __noreturn; |
67 | static void ip32_machine_restart(char *cmd) | |
1da177e4 | 68 | { |
15beb694 JK |
69 | msleep(20); |
70 | crime->control = CRIME_CONTROL_HARD_RESET; | |
71 | unreachable(); | |
1da177e4 LT |
72 | } |
73 | ||
74 | static void blink_timeout(unsigned long data) | |
75 | { | |
76 | unsigned long led = mace->perif.ctrl.misc ^ MACEISA_LED_RED; | |
77 | mace->perif.ctrl.misc = led; | |
78 | mod_timer(&blink_timer, jiffies + data); | |
79 | } | |
80 | ||
15beb694 | 81 | static void ip32_machine_halt(void) |
1da177e4 | 82 | { |
15beb694 JK |
83 | ip32_poweroff(&ip32_rtc_device); |
84 | } | |
1da177e4 | 85 | |
15beb694 JK |
86 | static void power_timeout(unsigned long data) |
87 | { | |
88 | ip32_poweroff(&ip32_rtc_device); | |
1da177e4 LT |
89 | } |
90 | ||
15beb694 | 91 | void ip32_prepare_poweroff(void) |
1da177e4 | 92 | { |
f18190bd | 93 | if (has_panicked) |
1da177e4 LT |
94 | return; |
95 | ||
15beb694 | 96 | if (shutting_down || kill_cad_pid(SIGINT, 1)) { |
1da177e4 | 97 | /* No init process or button pressed twice. */ |
15beb694 | 98 | ip32_poweroff(&ip32_rtc_device); |
1da177e4 LT |
99 | } |
100 | ||
15beb694 | 101 | shutting_down = 1; |
1da177e4 LT |
102 | blink_timer.data = POWERDOWN_FREQ; |
103 | blink_timeout(POWERDOWN_FREQ); | |
104 | ||
105 | init_timer(&power_timer); | |
106 | power_timer.function = power_timeout; | |
107 | power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ; | |
108 | add_timer(&power_timer); | |
109 | } | |
110 | ||
1da177e4 LT |
111 | static int panic_event(struct notifier_block *this, unsigned long event, |
112 | void *ptr) | |
113 | { | |
114 | unsigned long led; | |
115 | ||
f18190bd | 116 | if (has_panicked) |
1da177e4 | 117 | return NOTIFY_DONE; |
f18190bd | 118 | has_panicked = 1; |
1da177e4 LT |
119 | |
120 | /* turn off the green LED */ | |
121 | led = mace->perif.ctrl.misc | MACEISA_LED_GREEN; | |
122 | mace->perif.ctrl.misc = led; | |
123 | ||
124 | blink_timer.data = PANIC_FREQ; | |
125 | blink_timeout(PANIC_FREQ); | |
126 | ||
127 | return NOTIFY_DONE; | |
128 | } | |
129 | ||
130 | static struct notifier_block panic_block = { | |
131 | .notifier_call = panic_event, | |
132 | }; | |
133 | ||
134 | static __init int ip32_reboot_setup(void) | |
135 | { | |
136 | /* turn on the green led only */ | |
137 | unsigned long led = mace->perif.ctrl.misc; | |
138 | led |= MACEISA_LED_RED; | |
139 | led &= ~MACEISA_LED_GREEN; | |
140 | mace->perif.ctrl.misc = led; | |
141 | ||
142 | _machine_restart = ip32_machine_restart; | |
143 | _machine_halt = ip32_machine_halt; | |
15beb694 | 144 | pm_power_off = ip32_machine_halt; |
1da177e4 LT |
145 | |
146 | init_timer(&blink_timer); | |
147 | blink_timer.function = blink_timeout; | |
e041c683 | 148 | atomic_notifier_chain_register(&panic_notifier_list, &panic_block); |
1da177e4 | 149 | |
1da177e4 LT |
150 | return 0; |
151 | } | |
152 | ||
153 | subsys_initcall(ip32_reboot_setup); |