Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * linux/drivers/parisc/power.c
0003  * HP PARISC soft power switch support driver
0004  *
0005  * Copyright (c) 2001-2007 Helge Deller <deller@gmx.de>
0006  * All rights reserved.
0007  *
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  * 1. Redistributions of source code must retain the above copyright
0013  *    notice, this list of conditions, and the following disclaimer,
0014  *    without modification.
0015  * 2. The name of the author may not be used to endorse or promote products
0016  *    derived from this software without specific prior written permission.
0017  *
0018  * Alternatively, this software may be distributed under the terms of the
0019  * GNU General Public License ("GPL").
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
0022  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
0025  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0026  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0027  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0028  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0030  *
0031  *
0032  *  HINT:
0033  *  Support of the soft power switch button may be enabled or disabled at
0034  *  runtime through the "/proc/sys/kernel/power" procfs entry.
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 /* how often should the power button be polled ? */
0055 #define POWERSWITCH_POLL_PER_SEC 2
0056 
0057 /* how long does the power button needs to be down until we react ? */
0058 #define POWERSWITCH_DOWN_SEC 2
0059 
0060 /* assembly code to access special registers */
0061 /* taken from PCXL ERS page 82 */
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)       /* move value of gr to dr[dr] */
0068 #define MFCPU_C(dr, gr)     MFCPU_X(dr, gr,  0, 0x30)   /* for dr0 and dr8 only ! */
0069 #define MFCPU_T(dr, gr)     MFCPU_X(dr,  0, gr, 0xa0)   /* all dr except dr0 and dr8 */
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 /* local shutdown counter */
0080 static int shutdown_timer __read_mostly;
0081 
0082 /* check, give feedback and start shutdown after one second */
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     /* wait until the button was pressed for 1 second */
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         /* send kill signal */
0097         if (kill_cad_pid(SIGINT, 1)) {
0098             /* just in case killing init process failed */
0099             machine_power_off();
0100         }
0101     }
0102 }
0103 
0104 
0105 /* main power switch task struct */
0106 static struct task_struct *power_task;
0107 
0108 /* filename in /proc which can be used to enable/disable the power switch */
0109 #define SYSCTL_FILENAME "sys/kernel/power"
0110 
0111 /* soft power switch enabled/disabled */
0112 int pwrsw_enabled __read_mostly = 1;
0113 
0114 /* main kernel thread worker. It polls the button state */
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              * Non-Gecko-style machines:
0131              * Check the power switch status which is read from the
0132              * real I/O location at soft_power_reg.
0133              * Bit 31 ("the lowest bit) is the status of the power switch.
0134              * This bit is "1" if the button is NOT pressed.
0135              */
0136             button_not_pressed = (gsc_readl(soft_power_reg) & 0x1);
0137         } else {
0138             /*
0139              * On gecko style machines (e.g. 712/xx and 715/xx) 
0140              * the power switch status is stored in Bit 0 ("the highest bit")
0141              * of CPU diagnose register 25.
0142              * Warning: Some machines never reset the DIAG flag, even if
0143              * the button has been released again.
0144              */
0145             button_not_pressed = (__getDIAG(25) & 0x80000000);
0146         }
0147 
0148         if (likely(button_not_pressed)) {
0149             if (unlikely(shutdown_timer && /* avoid writing if not necessary */
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  * powerfail interruption handler (irq IRQ_FROM_REGION(CPU_IRQ_REGION)+2) 
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 /* parisc_panic_event() is called by the panic handler.
0179  * As soon as a panic occurs, our tasklets above will not be
0180  * executed any longer. This function then re-enables the 
0181  * soft-power switch and allows the user to switch off the system
0182  */
0183 static int parisc_panic_event(struct notifier_block *this,
0184         unsigned long event, void *ptr)
0185 {
0186     /* re-enable the soft-power switch */
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     /* enable the soft power switch if possible */
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     /* Register a call for panic conditions. */
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");