xref: /linux/drivers/acpi/wakeup.c (revision 201b8c655f7a48563f6a0b66f9e388460a1ea611)
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 
1595b482a8SLen Brown #define _COMPONENT		ACPI_SYSTEM_COMPONENT
1695b482a8SLen Brown ACPI_MODULE_NAME("wakeup_devices")
1795b482a8SLen Brown 
1895b482a8SLen Brown extern struct list_head acpi_wakeup_device_list;
1995b482a8SLen Brown extern spinlock_t acpi_device_lock;
2095b482a8SLen Brown 
2195b482a8SLen Brown /**
2295b482a8SLen Brown  * acpi_enable_wakeup_device_prep - prepare wakeup devices
2395b482a8SLen Brown  *	@sleep_state:	ACPI state
2495b482a8SLen Brown  * Enable all wakup devices power if the devices' wakeup level
2595b482a8SLen Brown  * is higher than requested sleep level
2695b482a8SLen Brown  */
2795b482a8SLen Brown 
2895b482a8SLen Brown void acpi_enable_wakeup_device_prep(u8 sleep_state)
2995b482a8SLen Brown {
3095b482a8SLen Brown 	struct list_head *node, *next;
3195b482a8SLen Brown 
3295b482a8SLen Brown 	spin_lock(&acpi_device_lock);
3395b482a8SLen Brown 	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
3495b482a8SLen Brown 		struct acpi_device *dev = container_of(node,
3595b482a8SLen Brown 						       struct acpi_device,
3695b482a8SLen Brown 						       wakeup_list);
3795b482a8SLen Brown 
3895b482a8SLen Brown 		if (!dev->wakeup.flags.valid ||
3995b482a8SLen Brown 		    !dev->wakeup.state.enabled ||
4095b482a8SLen Brown 		    (sleep_state > (u32) dev->wakeup.sleep_state))
4195b482a8SLen Brown 			continue;
4295b482a8SLen Brown 
4395b482a8SLen Brown 		spin_unlock(&acpi_device_lock);
4495b482a8SLen Brown 		acpi_enable_wakeup_device_power(dev, sleep_state);
4595b482a8SLen Brown 		spin_lock(&acpi_device_lock);
4695b482a8SLen Brown 	}
4795b482a8SLen Brown 	spin_unlock(&acpi_device_lock);
4895b482a8SLen Brown }
4995b482a8SLen Brown 
5095b482a8SLen Brown /**
5195b482a8SLen Brown  * acpi_enable_wakeup_device - enable wakeup devices
5295b482a8SLen Brown  *	@sleep_state:	ACPI state
5395b482a8SLen Brown  * Enable all wakup devices's GPE
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 	spin_lock(&acpi_device_lock);
6495b482a8SLen Brown 	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
6595b482a8SLen Brown 		struct acpi_device *dev =
6695b482a8SLen Brown 			container_of(node, struct acpi_device, wakeup_list);
6795b482a8SLen Brown 
6895b482a8SLen Brown 		if (!dev->wakeup.flags.valid)
6995b482a8SLen Brown 			continue;
7095b482a8SLen Brown 
7195b482a8SLen Brown 		/* If users want to disable run-wake GPE,
7295b482a8SLen Brown 		 * we only disable it for wake and leave it for runtime
7395b482a8SLen Brown 		 */
7495b482a8SLen Brown 		if ((!dev->wakeup.state.enabled && !dev->wakeup.flags.prepared)
7595b482a8SLen Brown 		    || sleep_state > (u32) dev->wakeup.sleep_state) {
7695b482a8SLen Brown 			if (dev->wakeup.flags.run_wake) {
7795b482a8SLen Brown 				spin_unlock(&acpi_device_lock);
7895b482a8SLen Brown 				/* set_gpe_type will disable GPE, leave it like that */
7995b482a8SLen Brown 				acpi_set_gpe_type(dev->wakeup.gpe_device,
8095b482a8SLen Brown 						  dev->wakeup.gpe_number,
8195b482a8SLen Brown 						  ACPI_GPE_TYPE_RUNTIME);
8295b482a8SLen Brown 				spin_lock(&acpi_device_lock);
8395b482a8SLen Brown 			}
8495b482a8SLen Brown 			continue;
8595b482a8SLen Brown 		}
8695b482a8SLen Brown 		spin_unlock(&acpi_device_lock);
8795b482a8SLen Brown 		if (!dev->wakeup.flags.run_wake)
8895b482a8SLen Brown 			acpi_enable_gpe(dev->wakeup.gpe_device,
8995b482a8SLen Brown 					dev->wakeup.gpe_number);
9095b482a8SLen Brown 		spin_lock(&acpi_device_lock);
9195b482a8SLen Brown 	}
9295b482a8SLen Brown 	spin_unlock(&acpi_device_lock);
9395b482a8SLen Brown }
9495b482a8SLen Brown 
9595b482a8SLen Brown /**
9695b482a8SLen Brown  * acpi_disable_wakeup_device - disable devices' wakeup capability
9795b482a8SLen Brown  *	@sleep_state:	ACPI state
9895b482a8SLen Brown  * Disable all wakup devices's GPE and wakeup capability
9995b482a8SLen Brown  */
10095b482a8SLen Brown void acpi_disable_wakeup_device(u8 sleep_state)
10195b482a8SLen Brown {
10295b482a8SLen Brown 	struct list_head *node, *next;
10395b482a8SLen Brown 
10495b482a8SLen Brown 	spin_lock(&acpi_device_lock);
10595b482a8SLen Brown 	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
10695b482a8SLen Brown 		struct acpi_device *dev =
10795b482a8SLen Brown 			container_of(node, struct acpi_device, wakeup_list);
10895b482a8SLen Brown 
10995b482a8SLen Brown 		if (!dev->wakeup.flags.valid)
11095b482a8SLen Brown 			continue;
11195b482a8SLen Brown 
11295b482a8SLen Brown 		if ((!dev->wakeup.state.enabled && !dev->wakeup.flags.prepared)
11395b482a8SLen Brown 		    || sleep_state > (u32) dev->wakeup.sleep_state) {
11495b482a8SLen Brown 			if (dev->wakeup.flags.run_wake) {
11595b482a8SLen Brown 				spin_unlock(&acpi_device_lock);
11695b482a8SLen Brown 				acpi_set_gpe_type(dev->wakeup.gpe_device,
11795b482a8SLen Brown 						  dev->wakeup.gpe_number,
11895b482a8SLen Brown 						  ACPI_GPE_TYPE_WAKE_RUN);
11995b482a8SLen Brown 				/* Re-enable it, since set_gpe_type will disable it */
12095b482a8SLen Brown 				acpi_enable_gpe(dev->wakeup.gpe_device,
12195b482a8SLen Brown 						dev->wakeup.gpe_number);
12295b482a8SLen Brown 				spin_lock(&acpi_device_lock);
12395b482a8SLen Brown 			}
12495b482a8SLen Brown 			continue;
12595b482a8SLen Brown 		}
12695b482a8SLen Brown 
12795b482a8SLen Brown 		spin_unlock(&acpi_device_lock);
12895b482a8SLen Brown 		acpi_disable_wakeup_device_power(dev);
12995b482a8SLen Brown 		/* Never disable run-wake GPE */
13095b482a8SLen Brown 		if (!dev->wakeup.flags.run_wake) {
13195b482a8SLen Brown 			acpi_disable_gpe(dev->wakeup.gpe_device,
13295b482a8SLen Brown 					 dev->wakeup.gpe_number);
13395b482a8SLen Brown 			acpi_clear_gpe(dev->wakeup.gpe_device,
13495b482a8SLen Brown 				       dev->wakeup.gpe_number, ACPI_NOT_ISR);
13595b482a8SLen Brown 		}
13695b482a8SLen Brown 		spin_lock(&acpi_device_lock);
13795b482a8SLen Brown 	}
13895b482a8SLen Brown 	spin_unlock(&acpi_device_lock);
13995b482a8SLen Brown }
14095b482a8SLen Brown 
141*201b8c65SBjorn Helgaas int __init acpi_wakeup_device_init(void)
14295b482a8SLen Brown {
14395b482a8SLen Brown 	struct list_head *node, *next;
14495b482a8SLen Brown 
14595b482a8SLen Brown 	spin_lock(&acpi_device_lock);
14695b482a8SLen Brown 	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
14795b482a8SLen Brown 		struct acpi_device *dev = container_of(node,
14895b482a8SLen Brown 						       struct acpi_device,
14995b482a8SLen Brown 						       wakeup_list);
15095b482a8SLen Brown 		/* In case user doesn't load button driver */
15195b482a8SLen Brown 		if (!dev->wakeup.flags.run_wake || dev->wakeup.state.enabled)
15295b482a8SLen Brown 			continue;
15395b482a8SLen Brown 		spin_unlock(&acpi_device_lock);
15495b482a8SLen Brown 		acpi_set_gpe_type(dev->wakeup.gpe_device,
15595b482a8SLen Brown 				  dev->wakeup.gpe_number,
15695b482a8SLen Brown 				  ACPI_GPE_TYPE_WAKE_RUN);
15795b482a8SLen Brown 		acpi_enable_gpe(dev->wakeup.gpe_device,
15895b482a8SLen Brown 				dev->wakeup.gpe_number);
15995b482a8SLen Brown 		dev->wakeup.state.enabled = 1;
16095b482a8SLen Brown 		spin_lock(&acpi_device_lock);
16195b482a8SLen Brown 	}
16295b482a8SLen Brown 	spin_unlock(&acpi_device_lock);
16395b482a8SLen Brown 	return 0;
16495b482a8SLen Brown }
165