2007-07-11 18:18:04 -07:00
/* power.c: Power management driver.
2005-04-16 15:20:36 -07:00
*
2007-07-11 18:18:04 -07:00
* Copyright ( C ) 1999 , 2007 David S . Miller ( davem @ davemloft . net )
2005-04-16 15:20:36 -07:00
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/sched.h>
# include <linux/signal.h>
# include <linux/delay.h>
# include <linux/interrupt.h>
2006-01-09 13:59:12 -08:00
# include <linux/pm.h>
2006-10-02 02:18:26 -07:00
# include <linux/syscalls.h>
2007-07-18 13:12:45 -07:00
# include <linux/reboot.h>
2008-08-07 15:33:36 -07:00
# include <linux/of_device.h>
2005-04-16 15:20:36 -07:00
# include <asm/system.h>
# include <asm/auxio.h>
2006-06-29 15:22:46 -07:00
# include <asm/prom.h>
# include <asm/io.h>
2007-05-25 00:37:12 -07:00
# include <asm/sstate.h>
2008-02-19 20:39:18 -08:00
# include <asm/reboot.h>
2005-04-16 15:20:36 -07:00
# include <linux/unistd.h>
/*
* sysctl - toggle power - off restriction for serial console
* systems in machine_power_off ( )
*/
int scons_pwroff = 1 ;
static void __iomem * power_reg ;
2007-07-11 18:18:04 -07:00
static irqreturn_t power_handler ( int irq , void * dev_id )
{
2007-07-18 13:12:45 -07:00
orderly_poweroff ( true ) ;
2005-04-16 15:20:36 -07:00
/* FIXME: Check registers for status... */
return IRQ_HANDLED ;
}
static void ( * poweroff_method ) ( void ) = machine_alt_power_off ;
void machine_power_off ( void )
{
2007-05-25 00:37:12 -07:00
sstate_poweroff ( ) ;
2007-07-20 16:59:26 -07:00
if ( strcmp ( of_console_device - > type , " serial " ) | | scons_pwroff ) {
2005-04-16 15:20:36 -07:00
if ( power_reg ) {
/* Both register bits seem to have the
* same effect , so until I figure out
* what the difference is . . .
*/
writel ( AUXIO_PCIO_CPWR_OFF | AUXIO_PCIO_SPWR_OFF , power_reg ) ;
2007-07-11 18:18:04 -07:00
} else {
2005-04-16 15:20:36 -07:00
if ( poweroff_method ! = NULL ) {
poweroff_method ( ) ;
/* not reached */
}
2007-07-11 18:18:04 -07:00
}
2005-04-16 15:20:36 -07:00
}
machine_halt ( ) ;
}
2006-01-09 13:59:12 -08:00
void ( * pm_power_off ) ( void ) = machine_power_off ;
EXPORT_SYMBOL ( pm_power_off ) ;
2006-06-22 19:12:03 -07:00
static int __init has_button_interrupt ( unsigned int irq , struct device_node * dp )
2005-04-16 15:20:36 -07:00
{
2007-07-11 18:18:04 -07:00
if ( irq = = 0xffffffff )
2005-04-16 15:20:36 -07:00
return 0 ;
2006-06-22 19:12:03 -07:00
if ( ! of_find_property ( dp , " button " , NULL ) )
2005-04-16 15:20:36 -07:00
return 0 ;
return 1 ;
}
2006-06-29 15:22:46 -07:00
static int __devinit power_probe ( struct of_device * op , const struct of_device_id * match )
2005-04-16 15:20:36 -07:00
{
2006-06-29 15:22:46 -07:00
struct resource * res = & op - > resource [ 0 ] ;
unsigned int irq = op - > irqs [ 0 ] ;
2006-06-23 01:44:10 -07:00
2006-06-29 15:22:46 -07:00
power_reg = of_ioremap ( res , 0 , 0x4 , " power " ) ;
2007-07-18 21:18:50 -07:00
printk ( KERN_INFO " %s: Control reg at %lx \n " ,
2006-06-29 15:22:46 -07:00
op - > node - > name , res - > start ) ;
2006-06-23 01:44:10 -07:00
2005-04-16 15:20:36 -07:00
poweroff_method = machine_halt ; /* able to use the standard halt */
2006-06-23 01:44:10 -07:00
2006-06-29 15:22:46 -07:00
if ( has_button_interrupt ( irq , op - > node ) ) {
2005-10-06 20:43:54 -07:00
if ( request_irq ( irq ,
2006-06-29 14:39:11 -07:00
power_handler , 0 , " power " , NULL ) < 0 )
2007-07-11 18:18:04 -07:00
printk ( KERN_ERR " power: Cannot setup IRQ handler. \n " ) ;
2005-04-16 15:20:36 -07:00
}
2006-06-29 15:22:46 -07:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2006-06-23 01:44:10 -07:00
static struct of_device_id power_match [ ] = {
{
. name = " power " ,
} ,
{ } ,
} ;
2006-06-29 15:22:46 -07:00
static struct of_platform_driver power_driver = {
2006-06-23 01:44:10 -07:00
. match_table = power_match ,
2006-06-29 15:22:46 -07:00
. probe = power_probe ,
2007-10-10 23:27:34 -07:00
. driver = {
. name = " power " ,
} ,
2006-06-23 01:44:10 -07:00
} ;
void __init power_init ( void )
{
2007-04-30 17:43:56 +10:00
of_register_driver ( & power_driver , & of_platform_bus_type ) ;
2006-06-23 01:44:10 -07:00
return ;
}