xref: /linux/drivers/acpi/wakeup.c (revision e8b6f970107cfc9c00cdcdb12ec6c7e135cf379f)
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 
159090589dSShaohua Li /*
169090589dSShaohua Li  * We didn't lock acpi_device_lock in the file, because it invokes oops in
179090589dSShaohua Li  * suspend/resume and isn't really required as this is called in S-state. At
189090589dSShaohua Li  * that time, there is no device hotplug
199090589dSShaohua Li  **/
2095b482a8SLen Brown #define _COMPONENT		ACPI_SYSTEM_COMPONENT
2195b482a8SLen Brown ACPI_MODULE_NAME("wakeup_devices")
2295b482a8SLen Brown 
2395b482a8SLen Brown /**
249630bdd9SRafael J. Wysocki  * acpi_enable_wakeup_device_prep - Prepare wake-up devices.
259630bdd9SRafael J. Wysocki  * @sleep_state: ACPI system sleep state.
269630bdd9SRafael J. Wysocki  *
279630bdd9SRafael J. Wysocki  * Enable all wake-up devices' power, unless the requested system sleep state is
289630bdd9SRafael J. Wysocki  * too deep.
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 
399630bdd9SRafael J. Wysocki 		if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled
409630bdd9SRafael J. Wysocki 		    || (sleep_state > (u32) dev->wakeup.sleep_state))
4195b482a8SLen Brown 			continue;
4295b482a8SLen Brown 
4395b482a8SLen Brown 		acpi_enable_wakeup_device_power(dev, sleep_state);
4495b482a8SLen Brown 	}
4595b482a8SLen Brown }
4695b482a8SLen Brown 
4795b482a8SLen Brown /**
489630bdd9SRafael J. Wysocki  * acpi_enable_wakeup_device - Enable wake-up device GPEs.
499630bdd9SRafael J. Wysocki  * @sleep_state: ACPI system sleep state.
509630bdd9SRafael J. Wysocki  *
519630bdd9SRafael J. Wysocki  * Enable all wake-up devices' GPEs, with the assumption that
529630bdd9SRafael J. Wysocki  * acpi_disable_all_gpes() was executed before, so we don't need to disable any
539630bdd9SRafael J. Wysocki  * GPEs here.
5495b482a8SLen Brown  */
5595b482a8SLen Brown void acpi_enable_wakeup_device(u8 sleep_state)
5695b482a8SLen Brown {
5795b482a8SLen Brown 	struct list_head *node, *next;
5895b482a8SLen Brown 
5995b482a8SLen Brown 	/*
6095b482a8SLen Brown 	 * Caution: this routine must be invoked when interrupt is disabled
6195b482a8SLen Brown 	 * Refer ACPI2.0: P212
6295b482a8SLen Brown 	 */
6395b482a8SLen Brown 	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
6495b482a8SLen Brown 		struct acpi_device *dev =
6595b482a8SLen Brown 			container_of(node, struct acpi_device, wakeup_list);
6695b482a8SLen Brown 
67*e8b6f970SRafael J. Wysocki 		if (!dev->wakeup.flags.valid
68*e8b6f970SRafael J. Wysocki 		    || !(dev->wakeup.state.enabled || dev->wakeup.prepare_count)
699630bdd9SRafael J. Wysocki 		    || sleep_state > (u32) dev->wakeup.sleep_state)
7095b482a8SLen Brown 			continue;
719630bdd9SRafael J. Wysocki 
729630bdd9SRafael J. Wysocki 		/* The wake-up power should have been enabled already. */
73*e8b6f970SRafael J. Wysocki 		acpi_gpe_wakeup(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
74*e8b6f970SRafael J. Wysocki 				ACPI_GPE_ENABLE);
7595b482a8SLen Brown 	}
7695b482a8SLen Brown }
7795b482a8SLen Brown 
7895b482a8SLen Brown /**
799630bdd9SRafael J. Wysocki  * acpi_disable_wakeup_device - Disable devices' wakeup capability.
809630bdd9SRafael J. Wysocki  * @sleep_state: ACPI system sleep state.
819630bdd9SRafael J. Wysocki  *
829630bdd9SRafael J. Wysocki  * This function only affects devices with wakeup.state.enabled set, which means
839630bdd9SRafael J. Wysocki  * that it reverses the changes made by acpi_enable_wakeup_device_prep().
8495b482a8SLen Brown  */
8595b482a8SLen Brown void acpi_disable_wakeup_device(u8 sleep_state)
8695b482a8SLen Brown {
8795b482a8SLen Brown 	struct list_head *node, *next;
8895b482a8SLen Brown 
8995b482a8SLen Brown 	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
9095b482a8SLen Brown 		struct acpi_device *dev =
9195b482a8SLen Brown 			container_of(node, struct acpi_device, wakeup_list);
9295b482a8SLen Brown 
93*e8b6f970SRafael J. Wysocki 		if (!dev->wakeup.flags.valid
94*e8b6f970SRafael J. Wysocki 		    || !(dev->wakeup.state.enabled || dev->wakeup.prepare_count)
959630bdd9SRafael J. Wysocki 		    || (sleep_state > (u32) dev->wakeup.sleep_state))
9695b482a8SLen Brown 			continue;
9795b482a8SLen Brown 
98*e8b6f970SRafael J. Wysocki 		acpi_gpe_wakeup(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
99*e8b6f970SRafael J. Wysocki 				ACPI_GPE_DISABLE);
100*e8b6f970SRafael J. Wysocki 
101*e8b6f970SRafael J. Wysocki 		if (dev->wakeup.state.enabled)
10295b482a8SLen Brown 			acpi_disable_wakeup_device_power(dev);
10395b482a8SLen Brown 	}
10495b482a8SLen Brown }
10595b482a8SLen Brown 
106201b8c65SBjorn Helgaas int __init acpi_wakeup_device_init(void)
10795b482a8SLen Brown {
10895b482a8SLen Brown 	struct list_head *node, *next;
10995b482a8SLen Brown 
1109090589dSShaohua Li 	mutex_lock(&acpi_device_lock);
11195b482a8SLen Brown 	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
11295b482a8SLen Brown 		struct acpi_device *dev = container_of(node,
11395b482a8SLen Brown 						       struct acpi_device,
11495b482a8SLen Brown 						       wakeup_list);
115cb1cb178SRafael J. Wysocki 		if (dev->wakeup.flags.always_enabled)
11695b482a8SLen Brown 			dev->wakeup.state.enabled = 1;
11795b482a8SLen Brown 	}
1189090589dSShaohua Li 	mutex_unlock(&acpi_device_lock);
11995b482a8SLen Brown 	return 0;
12095b482a8SLen Brown }
121