aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIshizaki Kou <kou.ishizaki@toshiba.co.jp>2007-10-02 04:21:21 -0400
committerPaul Mackerras <paulus@samba.org>2007-10-02 23:25:28 -0400
commitb41848031ac16aee8d045e86f0b7ad3ba97e961e (patch)
tree226ba643c13c95373473a4920a25b493fb2f237b
parent80755b4144b303882437ac301034f0c7330199a8 (diff)
[POWERPC] Celleb: Support for Power/Reset buttons
This supports Power/Reset buttons on Beat on Celleb. On Beat, we have an event from Beat if Power button or Reset button is pressed. This patch catches the event and convert it to a signal to INIT process by calling ctrl_alt_del() function. /sbin/inittab have no entry to turn the machine power off so we have to detect if power button is pressed or not internally in our driver. This idea is taken from PS3's event handling subsystem. Signed-off-by: Kou Ishizaki <Kou.Ishizaki@toshiba.co.jp> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/platforms/celleb/beat.c94
1 files changed, 93 insertions, 1 deletions
diff --git a/arch/powerpc/platforms/celleb/beat.c b/arch/powerpc/platforms/celleb/beat.c
index ced6f68c7b0b..93ebb7d85120 100644
--- a/arch/powerpc/platforms/celleb/beat.c
+++ b/arch/powerpc/platforms/celleb/beat.c
@@ -22,16 +22,24 @@
22#include <linux/init.h> 22#include <linux/init.h>
23#include <linux/err.h> 23#include <linux/err.h>
24#include <linux/rtc.h> 24#include <linux/rtc.h>
25#include <linux/interrupt.h>
26#include <linux/irqreturn.h>
27#include <linux/reboot.h>
25 28
26#include <asm/hvconsole.h> 29#include <asm/hvconsole.h>
27#include <asm/time.h> 30#include <asm/time.h>
31#include <asm/machdep.h>
32#include <asm/firmware.h>
28 33
29#include "beat_wrapper.h" 34#include "beat_wrapper.h"
30#include "beat.h" 35#include "beat.h"
36#include "interrupt.h"
37
38static int beat_pm_poweroff_flag;
31 39
32void beat_restart(char *cmd) 40void beat_restart(char *cmd)
33{ 41{
34 beat_shutdown_logical_partition(1); 42 beat_shutdown_logical_partition(!beat_pm_poweroff_flag);
35} 43}
36 44
37void beat_power_off(void) 45void beat_power_off(void)
@@ -170,6 +178,90 @@ void beat_kexec_cpu_down(int crash, int secondary)
170} 178}
171#endif 179#endif
172 180
181static irqreturn_t beat_power_event(int virq, void *arg)
182{
183 printk(KERN_DEBUG "Beat: power button pressed\n");
184 beat_pm_poweroff_flag = 1;
185 ctrl_alt_del();
186 return IRQ_HANDLED;
187}
188
189static irqreturn_t beat_reset_event(int virq, void *arg)
190{
191 printk(KERN_DEBUG "Beat: reset button pressed\n");
192 beat_pm_poweroff_flag = 0;
193 ctrl_alt_del();
194 return IRQ_HANDLED;
195}
196
197static struct beat_event_list {
198 const char *typecode;
199 irq_handler_t handler;
200 unsigned int virq;
201} beat_event_list[] = {
202 { "power", beat_power_event, 0 },
203 { "reset", beat_reset_event, 0 },
204};
205
206static int __init beat_register_event(void)
207{
208 u64 path[4], data[2];
209 int rc, i;
210 unsigned int virq;
211
212 for (i = 0; i < ARRAY_SIZE(beat_event_list); i++) {
213 struct beat_event_list *ev = &beat_event_list[i];
214
215 if (beat_construct_event_receive_port(data) != 0) {
216 printk(KERN_ERR "Beat: "
217 "cannot construct event receive port for %s\n",
218 ev->typecode);
219 return -EINVAL;
220 }
221
222 virq = irq_create_mapping(NULL, data[0]);
223 if (virq == NO_IRQ) {
224 printk(KERN_ERR "Beat: failed to get virtual IRQ"
225 " for event receive port for %s\n",
226 ev->typecode);
227 beat_destruct_event_receive_port(data[0]);
228 return -EIO;
229 }
230 ev->virq = virq;
231
232 rc = request_irq(virq, ev->handler, IRQF_DISABLED,
233 ev->typecode, NULL);
234 if (rc != 0) {
235 printk(KERN_ERR "Beat: failed to request virtual IRQ"
236 " for event receive port for %s\n",
237 ev->typecode);
238 beat_destruct_event_receive_port(data[0]);
239 return rc;
240 }
241
242 path[0] = 0x1000000065780000ul; /* 1,ex */
243 path[1] = 0x627574746f6e0000ul; /* button */
244 path[2] = 0;
245 strncpy((char *)&path[2], ev->typecode, 8);
246 path[3] = 0;
247 data[1] = 0;
248
249 beat_create_repository_node(path, data);
250 }
251 return 0;
252}
253
254static int __init beat_event_init(void)
255{
256 if (!firmware_has_feature(FW_FEATURE_BEAT))
257 return -EINVAL;
258
259 beat_pm_poweroff_flag = 0;
260 return beat_register_event();
261}
262
263device_initcall(beat_event_init);
264
173EXPORT_SYMBOL(beat_get_term_char); 265EXPORT_SYMBOL(beat_get_term_char);
174EXPORT_SYMBOL(beat_put_term_char); 266EXPORT_SYMBOL(beat_put_term_char);
175EXPORT_SYMBOL(beat_halt_code); 267EXPORT_SYMBOL(beat_halt_code);