aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);