0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 #include <linux/module.h>
0038 #include <linux/init.h>
0039 #include <linux/kernel.h>
0040 #include <linux/notifier.h>
0041 #include <linux/panic_notifier.h>
0042 #include <linux/reboot.h>
0043 #include <linux/sched/signal.h>
0044 #include <linux/kthread.h>
0045 #include <linux/pm.h>
0046
0047 #include <asm/pdc.h>
0048 #include <asm/io.h>
0049 #include <asm/led.h>
0050
0051 #define DRIVER_NAME "powersw"
0052 #define KTHREAD_NAME "kpowerswd"
0053
0054
0055 #define POWERSWITCH_POLL_PER_SEC 2
0056
0057
0058 #define POWERSWITCH_DOWN_SEC 2
0059
0060
0061
0062 #define DIAG_CODE(code) (0x14000000 + ((code)<<5))
0063
0064 #define MFCPU_X(rDiagReg, t_ch, t_th, code) \
0065 (DIAG_CODE(code) + ((rDiagReg)<<21) + ((t_ch)<<16) + ((t_th)<<0) )
0066
0067 #define MTCPU(dr, gr) MFCPU_X(dr, gr, 0, 0x12)
0068 #define MFCPU_C(dr, gr) MFCPU_X(dr, gr, 0, 0x30)
0069 #define MFCPU_T(dr, gr) MFCPU_X(dr, 0, gr, 0xa0)
0070
0071 #define __getDIAG(dr) ( { \
0072 register unsigned long __res asm("r28");\
0073 __asm__ __volatile__ ( \
0074 ".word %1" : "=&r" (__res) : "i" (MFCPU_T(dr,28) ) \
0075 ); \
0076 __res; \
0077 } )
0078
0079
0080 static int shutdown_timer __read_mostly;
0081
0082
0083 static void process_shutdown(void)
0084 {
0085 if (shutdown_timer == 0)
0086 printk(KERN_ALERT KTHREAD_NAME ": Shutdown requested...\n");
0087
0088 shutdown_timer++;
0089
0090
0091 if (shutdown_timer == (POWERSWITCH_DOWN_SEC*POWERSWITCH_POLL_PER_SEC)) {
0092 static const char msg[] = "Shutting down...";
0093 printk(KERN_INFO KTHREAD_NAME ": %s\n", msg);
0094 lcd_print(msg);
0095
0096
0097 if (kill_cad_pid(SIGINT, 1)) {
0098
0099 machine_power_off();
0100 }
0101 }
0102 }
0103
0104
0105
0106 static struct task_struct *power_task;
0107
0108
0109 #define SYSCTL_FILENAME "sys/kernel/power"
0110
0111
0112 int pwrsw_enabled __read_mostly = 1;
0113
0114
0115 static int kpowerswd(void *param)
0116 {
0117 __set_current_state(TASK_RUNNING);
0118
0119 do {
0120 int button_not_pressed;
0121 unsigned long soft_power_reg = (unsigned long) param;
0122
0123 schedule_timeout_interruptible(pwrsw_enabled ? HZ : HZ/POWERSWITCH_POLL_PER_SEC);
0124
0125 if (unlikely(!pwrsw_enabled))
0126 continue;
0127
0128 if (soft_power_reg) {
0129
0130
0131
0132
0133
0134
0135
0136 button_not_pressed = (gsc_readl(soft_power_reg) & 0x1);
0137 } else {
0138
0139
0140
0141
0142
0143
0144
0145 button_not_pressed = (__getDIAG(25) & 0x80000000);
0146 }
0147
0148 if (likely(button_not_pressed)) {
0149 if (unlikely(shutdown_timer &&
0150 shutdown_timer < (POWERSWITCH_DOWN_SEC*POWERSWITCH_POLL_PER_SEC))) {
0151 shutdown_timer = 0;
0152 printk(KERN_INFO KTHREAD_NAME ": Shutdown request aborted.\n");
0153 }
0154 } else
0155 process_shutdown();
0156
0157
0158 } while (!kthread_should_stop());
0159
0160 return 0;
0161 }
0162
0163
0164
0165
0166
0167 #if 0
0168 static void powerfail_interrupt(int code, void *x)
0169 {
0170 printk(KERN_CRIT "POWERFAIL INTERRUPTION !\n");
0171 poweroff();
0172 }
0173 #endif
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183 static int parisc_panic_event(struct notifier_block *this,
0184 unsigned long event, void *ptr)
0185 {
0186
0187 pdc_soft_power_button(0);
0188 return NOTIFY_DONE;
0189 }
0190
0191 static struct notifier_block parisc_panic_block = {
0192 .notifier_call = parisc_panic_event,
0193 .priority = INT_MAX,
0194 };
0195
0196
0197 static int __init power_init(void)
0198 {
0199 unsigned long ret;
0200 unsigned long soft_power_reg;
0201
0202 #if 0
0203 request_irq( IRQ_FROM_REGION(CPU_IRQ_REGION)+2, &powerfail_interrupt,
0204 0, "powerfail", NULL);
0205 #endif
0206
0207
0208 ret = pdc_soft_power_info(&soft_power_reg);
0209 if (ret == PDC_OK)
0210 ret = pdc_soft_power_button(1);
0211 if (ret != PDC_OK)
0212 soft_power_reg = -1UL;
0213
0214 switch (soft_power_reg) {
0215 case 0: printk(KERN_INFO DRIVER_NAME ": Gecko-style soft power switch enabled.\n");
0216 break;
0217
0218 case -1UL: printk(KERN_INFO DRIVER_NAME ": Soft power switch support not available.\n");
0219 return -ENODEV;
0220
0221 default: printk(KERN_INFO DRIVER_NAME ": Soft power switch at 0x%08lx enabled.\n",
0222 soft_power_reg);
0223 }
0224
0225 power_task = kthread_run(kpowerswd, (void*)soft_power_reg, KTHREAD_NAME);
0226 if (IS_ERR(power_task)) {
0227 printk(KERN_ERR DRIVER_NAME ": thread creation failed. Driver not loaded.\n");
0228 pdc_soft_power_button(0);
0229 return -EIO;
0230 }
0231
0232
0233 atomic_notifier_chain_register(&panic_notifier_list,
0234 &parisc_panic_block);
0235
0236 return 0;
0237 }
0238
0239 static void __exit power_exit(void)
0240 {
0241 kthread_stop(power_task);
0242
0243 atomic_notifier_chain_unregister(&panic_notifier_list,
0244 &parisc_panic_block);
0245
0246 pdc_soft_power_button(0);
0247 }
0248
0249 arch_initcall(power_init);
0250 module_exit(power_exit);
0251
0252
0253 MODULE_AUTHOR("Helge Deller <deller@gmx.de>");
0254 MODULE_DESCRIPTION("Soft power switch driver");
0255 MODULE_LICENSE("Dual BSD/GPL");