2005-04-17 02:20:36 +04:00
/*
* wakeup . c - support wakeup devices
* Copyright ( C ) 2004 Li Shaohua < shaohua . li @ intel . com >
*/
# include <linux/init.h>
# include <linux/acpi.h>
# include <acpi/acpi_drivers.h>
# include <linux/kernel.h>
# include <linux/types.h>
# include "sleep.h"
# define _COMPONENT ACPI_SYSTEM_COMPONENT
2005-08-05 08:44:28 +04:00
ACPI_MODULE_NAME ( " wakeup_devices " )
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
extern struct list_head acpi_wakeup_device_list ;
2005-04-17 02:20:36 +04:00
extern spinlock_t acpi_device_lock ;
/**
* acpi_enable_wakeup_device_prep - prepare wakeup devices
* @ sleep_state : ACPI state
* Enable all wakup devices power if the devices ' wakeup level
* is higher than requested sleep level
*/
2005-08-05 08:44:28 +04:00
void acpi_enable_wakeup_device_prep ( u8 sleep_state )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct list_head * node , * next ;
2005-04-17 02:20:36 +04:00
spin_lock ( & acpi_device_lock ) ;
list_for_each_safe ( node , next , & acpi_wakeup_device_list ) {
2005-08-05 08:44:28 +04:00
struct acpi_device * dev = container_of ( node ,
struct acpi_device ,
wakeup_list ) ;
if ( ! dev - > wakeup . flags . valid | |
! dev - > wakeup . state . enabled | |
( sleep_state > ( u32 ) dev - > wakeup . sleep_state ) )
2005-04-17 02:20:36 +04:00
continue ;
spin_unlock ( & acpi_device_lock ) ;
2008-07-07 05:33:34 +04:00
acpi_enable_wakeup_device_power ( dev , sleep_state ) ;
2005-04-17 02:20:36 +04:00
spin_lock ( & acpi_device_lock ) ;
}
spin_unlock ( & acpi_device_lock ) ;
}
/**
* acpi_enable_wakeup_device - enable wakeup devices
* @ sleep_state : ACPI state
* Enable all wakup devices ' s GPE
*/
2005-08-05 08:44:28 +04:00
void acpi_enable_wakeup_device ( u8 sleep_state )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct list_head * node , * next ;
2005-04-17 02:20:36 +04:00
/*
* Caution : this routine must be invoked when interrupt is disabled
* Refer ACPI2 .0 : P212
*/
spin_lock ( & acpi_device_lock ) ;
list_for_each_safe ( node , next , & acpi_wakeup_device_list ) {
2007-09-26 19:47:30 +04:00
struct acpi_device * dev =
container_of ( node , struct acpi_device , wakeup_list ) ;
2008-07-07 05:34:48 +04:00
2007-09-26 19:47:30 +04:00
if ( ! dev - > wakeup . flags . valid )
continue ;
2008-07-07 05:34:48 +04:00
2005-04-17 02:20:36 +04:00
/* If users want to disable run-wake GPE,
* we only disable it for wake and leave it for runtime
*/
2008-07-07 05:34:48 +04:00
if ( ( ! dev - > wakeup . state . enabled & & ! dev - > wakeup . flags . prepared )
| | sleep_state > ( u32 ) dev - > wakeup . sleep_state ) {
2007-09-26 19:47:30 +04:00
if ( dev - > wakeup . flags . run_wake ) {
spin_unlock ( & acpi_device_lock ) ;
/* set_gpe_type will disable GPE, leave it like that */
acpi_set_gpe_type ( dev - > wakeup . gpe_device ,
dev - > wakeup . gpe_number ,
ACPI_GPE_TYPE_RUNTIME ) ;
spin_lock ( & acpi_device_lock ) ;
}
2005-04-17 02:20:36 +04:00
continue ;
}
spin_unlock ( & acpi_device_lock ) ;
if ( ! dev - > wakeup . flags . run_wake )
2005-08-05 08:44:28 +04:00
acpi_enable_gpe ( dev - > wakeup . gpe_device ,
2008-10-25 21:48:46 +04:00
dev - > wakeup . gpe_number ) ;
2005-04-17 02:20:36 +04:00
spin_lock ( & acpi_device_lock ) ;
}
spin_unlock ( & acpi_device_lock ) ;
}
/**
* acpi_disable_wakeup_device - disable devices ' wakeup capability
* @ sleep_state : ACPI state
* Disable all wakup devices ' s GPE and wakeup capability
*/
2005-08-05 08:44:28 +04:00
void acpi_disable_wakeup_device ( u8 sleep_state )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct list_head * node , * next ;
2005-04-17 02:20:36 +04:00
spin_lock ( & acpi_device_lock ) ;
list_for_each_safe ( node , next , & acpi_wakeup_device_list ) {
2007-09-26 19:47:30 +04:00
struct acpi_device * dev =
container_of ( node , struct acpi_device , wakeup_list ) ;
2005-04-17 02:20:36 +04:00
2007-09-26 19:47:30 +04:00
if ( ! dev - > wakeup . flags . valid )
2005-04-17 02:20:36 +04:00
continue ;
2008-07-07 05:34:48 +04:00
if ( ( ! dev - > wakeup . state . enabled & & ! dev - > wakeup . flags . prepared )
| | sleep_state > ( u32 ) dev - > wakeup . sleep_state ) {
2007-09-26 19:47:30 +04:00
if ( dev - > wakeup . flags . run_wake ) {
spin_unlock ( & acpi_device_lock ) ;
acpi_set_gpe_type ( dev - > wakeup . gpe_device ,
dev - > wakeup . gpe_number ,
ACPI_GPE_TYPE_WAKE_RUN ) ;
/* Re-enable it, since set_gpe_type will disable it */
acpi_enable_gpe ( dev - > wakeup . gpe_device ,
2008-10-25 21:48:46 +04:00
dev - > wakeup . gpe_number ) ;
2007-09-26 19:47:30 +04:00
spin_lock ( & acpi_device_lock ) ;
}
2005-04-17 02:20:36 +04:00
continue ;
2007-09-26 19:47:30 +04:00
}
2005-04-17 02:20:36 +04:00
spin_unlock ( & acpi_device_lock ) ;
acpi_disable_wakeup_device_power ( dev ) ;
/* Never disable run-wake GPE */
if ( ! dev - > wakeup . flags . run_wake ) {
2005-08-05 08:44:28 +04:00
acpi_disable_gpe ( dev - > wakeup . gpe_device ,
2008-10-25 21:48:46 +04:00
dev - > wakeup . gpe_number ) ;
2005-08-05 08:44:28 +04:00
acpi_clear_gpe ( dev - > wakeup . gpe_device ,
dev - > wakeup . gpe_number , ACPI_NOT_ISR ) ;
2005-04-17 02:20:36 +04:00
}
spin_lock ( & acpi_device_lock ) ;
}
spin_unlock ( & acpi_device_lock ) ;
}
static int __init acpi_wakeup_device_init ( void )
{
2005-08-05 08:44:28 +04:00
struct list_head * node , * next ;
2005-04-17 02:20:36 +04:00
if ( acpi_disabled )
return 0 ;
spin_lock ( & acpi_device_lock ) ;
list_for_each_safe ( node , next , & acpi_wakeup_device_list ) {
2005-08-05 08:44:28 +04:00
struct acpi_device * dev = container_of ( node ,
struct acpi_device ,
wakeup_list ) ;
2005-04-17 02:20:36 +04:00
/* In case user doesn't load button driver */
2007-09-26 19:47:30 +04:00
if ( ! dev - > wakeup . flags . run_wake | | dev - > wakeup . state . enabled )
continue ;
spin_unlock ( & acpi_device_lock ) ;
acpi_set_gpe_type ( dev - > wakeup . gpe_device ,
dev - > wakeup . gpe_number ,
ACPI_GPE_TYPE_WAKE_RUN ) ;
acpi_enable_gpe ( dev - > wakeup . gpe_device ,
2008-10-25 21:48:46 +04:00
dev - > wakeup . gpe_number ) ;
2007-09-26 19:47:30 +04:00
dev - > wakeup . state . enabled = 1 ;
spin_lock ( & acpi_device_lock ) ;
2005-04-17 02:20:36 +04:00
}
spin_unlock ( & acpi_device_lock ) ;
return 0 ;
}
late_initcall ( acpi_wakeup_device_init ) ;