2005-04-16 15:20:36 -07: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 <acpi/acevents.h>
# include "sleep.h"
# define _COMPONENT ACPI_SYSTEM_COMPONENT
2005-08-05 00:44:28 -04:00
ACPI_MODULE_NAME ( " wakeup_devices " )
2005-04-16 15:20:36 -07:00
2005-08-05 00:44:28 -04:00
extern struct list_head acpi_wakeup_device_list ;
2005-04-16 15:20:36 -07:00
extern spinlock_t acpi_device_lock ;
# ifdef CONFIG_ACPI_SLEEP
/**
* 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 00:44:28 -04:00
void acpi_enable_wakeup_device_prep ( u8 sleep_state )
2005-04-16 15:20:36 -07:00
{
2005-08-05 00:44:28 -04:00
struct list_head * node , * next ;
2005-04-16 15:20:36 -07:00
ACPI_FUNCTION_TRACE ( " acpi_enable_wakeup_device_prep " ) ;
spin_lock ( & acpi_device_lock ) ;
list_for_each_safe ( node , next , & acpi_wakeup_device_list ) {
2005-08-05 00: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-16 15:20:36 -07:00
continue ;
spin_unlock ( & acpi_device_lock ) ;
acpi_enable_wakeup_device_power ( dev ) ;
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 00:44:28 -04:00
void acpi_enable_wakeup_device ( u8 sleep_state )
2005-04-16 15:20:36 -07:00
{
2005-08-05 00:44:28 -04:00
struct list_head * node , * next ;
2005-04-16 15:20:36 -07:00
/*
* Caution : this routine must be invoked when interrupt is disabled
* Refer ACPI2 .0 : P212
*/
ACPI_FUNCTION_TRACE ( " acpi_enable_wakeup_device " ) ;
spin_lock ( & acpi_device_lock ) ;
list_for_each_safe ( node , next , & acpi_wakeup_device_list ) {
2005-08-05 00:44:28 -04:00
struct acpi_device * dev = container_of ( node ,
struct acpi_device ,
wakeup_list ) ;
2005-04-16 15:20:36 -07:00
/* If users want to disable run-wake GPE,
* we only disable it for wake and leave it for runtime
*/
if ( dev - > wakeup . flags . run_wake & & ! dev - > wakeup . state . enabled ) {
spin_unlock ( & acpi_device_lock ) ;
2005-08-05 00:44:28 -04:00
acpi_set_gpe_type ( dev - > wakeup . gpe_device ,
dev - > wakeup . gpe_number ,
ACPI_GPE_TYPE_RUNTIME ) ;
2005-04-16 15:20:36 -07:00
/* Re-enable it, since set_gpe_type will disable it */
2005-08-05 00:44:28 -04:00
acpi_enable_gpe ( dev - > wakeup . gpe_device ,
dev - > wakeup . gpe_number , ACPI_ISR ) ;
2005-04-16 15:20:36 -07:00
spin_lock ( & acpi_device_lock ) ;
continue ;
}
if ( ! dev - > wakeup . flags . valid | |
2005-08-05 00:44:28 -04:00
! dev - > wakeup . state . enabled | |
( sleep_state > ( u32 ) dev - > wakeup . sleep_state ) )
2005-04-16 15:20:36 -07:00
continue ;
spin_unlock ( & acpi_device_lock ) ;
/* run-wake GPE has been enabled */
if ( ! dev - > wakeup . flags . run_wake )
2005-08-05 00:44:28 -04:00
acpi_enable_gpe ( dev - > wakeup . gpe_device ,
dev - > wakeup . gpe_number , ACPI_ISR ) ;
2005-04-16 15:20:36 -07:00
dev - > wakeup . state . active = 1 ;
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 00:44:28 -04:00
void acpi_disable_wakeup_device ( u8 sleep_state )
2005-04-16 15:20:36 -07:00
{
2005-08-05 00:44:28 -04:00
struct list_head * node , * next ;
2005-04-16 15:20:36 -07:00
ACPI_FUNCTION_TRACE ( " acpi_disable_wakeup_device " ) ;
spin_lock ( & acpi_device_lock ) ;
list_for_each_safe ( node , next , & acpi_wakeup_device_list ) {
2005-08-05 00:44:28 -04:00
struct acpi_device * dev = container_of ( node ,
struct acpi_device ,
wakeup_list ) ;
2005-04-16 15:20:36 -07:00
if ( dev - > wakeup . flags . run_wake & & ! dev - > wakeup . state . enabled ) {
spin_unlock ( & acpi_device_lock ) ;
2005-08-05 00:44:28 -04:00
acpi_set_gpe_type ( dev - > wakeup . gpe_device ,
dev - > wakeup . gpe_number ,
ACPI_GPE_TYPE_WAKE_RUN ) ;
2005-04-16 15:20:36 -07:00
/* Re-enable it, since set_gpe_type will disable it */
2005-08-05 00:44:28 -04:00
acpi_enable_gpe ( dev - > wakeup . gpe_device ,
dev - > wakeup . gpe_number , ACPI_NOT_ISR ) ;
2005-04-16 15:20:36 -07:00
spin_lock ( & acpi_device_lock ) ;
continue ;
}
2005-08-05 00:44:28 -04:00
if ( ! dev - > wakeup . flags . valid | |
! dev - > wakeup . state . active | |
( sleep_state > ( u32 ) dev - > wakeup . sleep_state ) )
2005-04-16 15:20:36 -07:00
continue ;
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 00:44:28 -04:00
acpi_disable_gpe ( dev - > wakeup . gpe_device ,
dev - > wakeup . gpe_number , ACPI_NOT_ISR ) ;
acpi_clear_gpe ( dev - > wakeup . gpe_device ,
dev - > wakeup . gpe_number , ACPI_NOT_ISR ) ;
2005-04-16 15:20:36 -07:00
}
dev - > wakeup . state . active = 0 ;
spin_lock ( & acpi_device_lock ) ;
}
spin_unlock ( & acpi_device_lock ) ;
}
static int __init acpi_wakeup_device_init ( void )
{
2005-08-05 00:44:28 -04:00
struct list_head * node , * next ;
2005-04-16 15:20:36 -07:00
if ( acpi_disabled )
return 0 ;
printk ( " ACPI wakeup devices: \n " ) ;
spin_lock ( & acpi_device_lock ) ;
list_for_each_safe ( node , next , & acpi_wakeup_device_list ) {
2005-08-05 00:44:28 -04:00
struct acpi_device * dev = container_of ( node ,
struct acpi_device ,
wakeup_list ) ;
2005-04-16 15:20:36 -07:00
/* In case user doesn't load button driver */
if ( dev - > wakeup . flags . run_wake & & ! dev - > wakeup . state . enabled ) {
spin_unlock ( & acpi_device_lock ) ;
2005-08-05 00:44:28 -04:00
acpi_set_gpe_type ( dev - > wakeup . gpe_device ,
dev - > wakeup . gpe_number ,
ACPI_GPE_TYPE_WAKE_RUN ) ;
acpi_enable_gpe ( dev - > wakeup . gpe_device ,
dev - > wakeup . gpe_number , ACPI_NOT_ISR ) ;
2005-04-16 15:20:36 -07:00
dev - > wakeup . state . enabled = 1 ;
spin_lock ( & acpi_device_lock ) ;
}
printk ( " %4s " , dev - > pnp . bus_id ) ;
}
spin_unlock ( & acpi_device_lock ) ;
printk ( " \n " ) ;
return 0 ;
}
late_initcall ( acpi_wakeup_device_init ) ;
# endif
/*
* Disable all wakeup GPEs before power off .
*
* Since acpi_enter_sleep_state ( ) will disable all
* RUNTIME GPEs , we simply mark all GPES that
* are not enabled for wakeup from S5 as RUNTIME .
*/
void acpi_wakeup_gpe_poweroff_prepare ( void )
{
2005-08-05 00:44:28 -04:00
struct list_head * node , * next ;
2005-04-16 15:20:36 -07:00
list_for_each_safe ( node , next , & acpi_wakeup_device_list ) {
2005-08-05 00:44:28 -04:00
struct acpi_device * dev = container_of ( node ,
struct acpi_device ,
wakeup_list ) ;
2005-04-16 15:20:36 -07:00
/* The GPE can wakeup system from S5, don't touch it */
2005-08-05 00:44:28 -04:00
if ( ( u32 ) dev - > wakeup . sleep_state = = ACPI_STATE_S5 )
2005-04-16 15:20:36 -07:00
continue ;
/* acpi_set_gpe_type will automatically disable GPE */
acpi_set_gpe_type ( dev - > wakeup . gpe_device ,
2005-08-05 00:44:28 -04:00
dev - > wakeup . gpe_number ,
ACPI_GPE_TYPE_RUNTIME ) ;
2005-04-16 15:20:36 -07:00
}
}