xref: /linux/drivers/acpi/wakeup.c (revision 9090589d87506c578ea1523ffd7ae7fd9424fb28)
195b482a8SLen Brown /*
295b482a8SLen Brown  * wakeup.c - support wakeup devices
395b482a8SLen Brown  * Copyright (C) 2004 Li Shaohua <shaohua.li@intel.com>
495b482a8SLen Brown  */
595b482a8SLen Brown 
695b482a8SLen Brown #include <linux/init.h>
795b482a8SLen Brown #include <linux/acpi.h>
895b482a8SLen Brown #include <acpi/acpi_drivers.h>
995b482a8SLen Brown #include <linux/kernel.h>
1095b482a8SLen Brown #include <linux/types.h>
11e60cc7a6SBjorn Helgaas 
12e60cc7a6SBjorn Helgaas #include "internal.h"
1395b482a8SLen Brown #include "sleep.h"
1495b482a8SLen Brown 
15*9090589dSShaohua Li /*
16*9090589dSShaohua Li  * We didn't lock acpi_device_lock in the file, because it invokes oops in
17*9090589dSShaohua Li  * suspend/resume and isn't really required as this is called in S-state. At
18*9090589dSShaohua Li  * that time, there is no device hotplug
19*9090589dSShaohua Li  **/
2095b482a8SLen Brown #define _COMPONENT		ACPI_SYSTEM_COMPONENT
2195b482a8SLen Brown ACPI_MODULE_NAME("wakeup_devices")
2295b482a8SLen Brown 
2395b482a8SLen Brown /**
2495b482a8SLen Brown  * acpi_enable_wakeup_device_prep - prepare wakeup devices
2595b482a8SLen Brown  *	@sleep_state:	ACPI state
2695b482a8SLen Brown  * Enable all wakup devices power if the devices' wakeup level
2795b482a8SLen Brown  * is higher than requested sleep level
2895b482a8SLen Brown  */
2995b482a8SLen Brown 
3095b482a8SLen Brown void acpi_enable_wakeup_device_prep(u8 sleep_state)
3195b482a8SLen Brown {
3295b482a8SLen Brown 	struct list_head *node, *next;
3395b482a8SLen Brown 
3495b482a8SLen Brown 	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
3595b482a8SLen Brown 		struct acpi_device *dev = container_of(node,
3695b482a8SLen Brown 						       struct acpi_device,
3795b482a8SLen Brown 						       wakeup_list);
3895b482a8SLen Brown 
3995b482a8SLen Brown 		if (!dev->wakeup.flags.valid ||
4095b482a8SLen Brown 		    !dev->wakeup.state.enabled ||
4195b482a8SLen Brown 		    (sleep_state > (u32) dev->wakeup.sleep_state))
4295b482a8SLen Brown 			continue;
4395b482a8SLen Brown 
4495b482a8SLen Brown 		acpi_enable_wakeup_device_power(dev, sleep_state);
4595b482a8SLen Brown 	}
4695b482a8SLen Brown }
4795b482a8SLen Brown 
4895b482a8SLen Brown /**
4995b482a8SLen Brown  * acpi_enable_wakeup_device - enable wakeup devices
5095b482a8SLen Brown  *	@sleep_state:	ACPI state
5195b482a8SLen Brown  * Enable all wakup devices's GPE
5295b482a8SLen Brown  */
5395b482a8SLen Brown void acpi_enable_wakeup_device(u8 sleep_state)
5495b482a8SLen Brown {
5595b482a8SLen Brown 	struct list_head *node, *next;
5695b482a8SLen Brown 
5795b482a8SLen Brown 	/*
5895b482a8SLen Brown 	 * Caution: this routine must be invoked when interrupt is disabled
5995b482a8SLen Brown 	 * Refer ACPI2.0: P212
6095b482a8SLen Brown 	 */
6195b482a8SLen Brown 	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
6295b482a8SLen Brown 		struct acpi_device *dev =
6395b482a8SLen Brown 			container_of(node, struct acpi_device, wakeup_list);
6495b482a8SLen Brown 
6595b482a8SLen Brown 		if (!dev->wakeup.flags.valid)
6695b482a8SLen Brown 			continue;
6795b482a8SLen Brown 
6895b482a8SLen Brown 		/* If users want to disable run-wake GPE,
6995b482a8SLen Brown 		 * we only disable it for wake and leave it for runtime
7095b482a8SLen Brown 		 */
7195b482a8SLen Brown 		if ((!dev->wakeup.state.enabled && !dev->wakeup.flags.prepared)
7295b482a8SLen Brown 		    || sleep_state > (u32) dev->wakeup.sleep_state) {
7395b482a8SLen Brown 			if (dev->wakeup.flags.run_wake) {
7495b482a8SLen Brown 				/* set_gpe_type will disable GPE, leave it like that */
7595b482a8SLen Brown 				acpi_set_gpe_type(dev->wakeup.gpe_device,
7695b482a8SLen Brown 						  dev->wakeup.gpe_number,
7795b482a8SLen Brown 						  ACPI_GPE_TYPE_RUNTIME);
7895b482a8SLen Brown 			}
7995b482a8SLen Brown 			continue;
8095b482a8SLen Brown 		}
8195b482a8SLen Brown 		if (!dev->wakeup.flags.run_wake)
8295b482a8SLen Brown 			acpi_enable_gpe(dev->wakeup.gpe_device,
8395b482a8SLen Brown 					dev->wakeup.gpe_number);
8495b482a8SLen Brown 	}
8595b482a8SLen Brown }
8695b482a8SLen Brown 
8795b482a8SLen Brown /**
8895b482a8SLen Brown  * acpi_disable_wakeup_device - disable devices' wakeup capability
8995b482a8SLen Brown  *	@sleep_state:	ACPI state
9095b482a8SLen Brown  * Disable all wakup devices's GPE and wakeup capability
9195b482a8SLen Brown  */
9295b482a8SLen Brown void acpi_disable_wakeup_device(u8 sleep_state)
9395b482a8SLen Brown {
9495b482a8SLen Brown 	struct list_head *node, *next;
9595b482a8SLen Brown 
9695b482a8SLen Brown 	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
9795b482a8SLen Brown 		struct acpi_device *dev =
9895b482a8SLen Brown 			container_of(node, struct acpi_device, wakeup_list);
9995b482a8SLen Brown 
10095b482a8SLen Brown 		if (!dev->wakeup.flags.valid)
10195b482a8SLen Brown 			continue;
10295b482a8SLen Brown 
10395b482a8SLen Brown 		if ((!dev->wakeup.state.enabled && !dev->wakeup.flags.prepared)
10495b482a8SLen Brown 		    || sleep_state > (u32) dev->wakeup.sleep_state) {
10595b482a8SLen Brown 			if (dev->wakeup.flags.run_wake) {
10695b482a8SLen Brown 				acpi_set_gpe_type(dev->wakeup.gpe_device,
10795b482a8SLen Brown 						  dev->wakeup.gpe_number,
10895b482a8SLen Brown 						  ACPI_GPE_TYPE_WAKE_RUN);
10995b482a8SLen Brown 				/* Re-enable it, since set_gpe_type will disable it */
11095b482a8SLen Brown 				acpi_enable_gpe(dev->wakeup.gpe_device,
11195b482a8SLen Brown 						dev->wakeup.gpe_number);
11295b482a8SLen Brown 			}
11395b482a8SLen Brown 			continue;
11495b482a8SLen Brown 		}
11595b482a8SLen Brown 
11695b482a8SLen Brown 		acpi_disable_wakeup_device_power(dev);
11795b482a8SLen Brown 		/* Never disable run-wake GPE */
11895b482a8SLen Brown 		if (!dev->wakeup.flags.run_wake) {
11995b482a8SLen Brown 			acpi_disable_gpe(dev->wakeup.gpe_device,
12095b482a8SLen Brown 					 dev->wakeup.gpe_number);
12195b482a8SLen Brown 			acpi_clear_gpe(dev->wakeup.gpe_device,
12295b482a8SLen Brown 				       dev->wakeup.gpe_number, ACPI_NOT_ISR);
12395b482a8SLen Brown 		}
12495b482a8SLen Brown 	}
12595b482a8SLen Brown }
12695b482a8SLen Brown 
127201b8c65SBjorn Helgaas int __init acpi_wakeup_device_init(void)
12895b482a8SLen Brown {
12995b482a8SLen Brown 	struct list_head *node, *next;
13095b482a8SLen Brown 
131*9090589dSShaohua Li 	mutex_lock(&acpi_device_lock);
13295b482a8SLen Brown 	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
13395b482a8SLen Brown 		struct acpi_device *dev = container_of(node,
13495b482a8SLen Brown 						       struct acpi_device,
13595b482a8SLen Brown 						       wakeup_list);
13695b482a8SLen Brown 		/* In case user doesn't load button driver */
13795b482a8SLen Brown 		if (!dev->wakeup.flags.run_wake || dev->wakeup.state.enabled)
13895b482a8SLen Brown 			continue;
13995b482a8SLen Brown 		acpi_set_gpe_type(dev->wakeup.gpe_device,
14095b482a8SLen Brown 				  dev->wakeup.gpe_number,
14195b482a8SLen Brown 				  ACPI_GPE_TYPE_WAKE_RUN);
14295b482a8SLen Brown 		acpi_enable_gpe(dev->wakeup.gpe_device,
14395b482a8SLen Brown 				dev->wakeup.gpe_number);
14495b482a8SLen Brown 		dev->wakeup.state.enabled = 1;
14595b482a8SLen Brown 	}
146*9090589dSShaohua Li 	mutex_unlock(&acpi_device_lock);
14795b482a8SLen Brown 	return 0;
14895b482a8SLen Brown }
149