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