blob: 4134ed43d026537e1886b288081ae33a09b046e6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * wakeup.c - support wakeup devices
3 * Copyright (C) 2004 Li Shaohua <shaohua.li@intel.com>
4 */
5
6#include <linux/init.h>
7#include <linux/acpi.h>
8#include <acpi/acpi_drivers.h>
9#include <linux/kernel.h>
10#include <linux/types.h>
11#include <acpi/acevents.h>
12#include "sleep.h"
13
14#define _COMPONENT ACPI_SYSTEM_COMPONENT
Len Brown4be44fc2005-08-05 00:44:28 -040015ACPI_MODULE_NAME("wakeup_devices")
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
Len Brown4be44fc2005-08-05 00:44:28 -040017extern struct list_head acpi_wakeup_device_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -070018extern spinlock_t acpi_device_lock;
19
20#ifdef CONFIG_ACPI_SLEEP
21/**
22 * acpi_enable_wakeup_device_prep - prepare wakeup devices
23 * @sleep_state: ACPI state
24 * Enable all wakup devices power if the devices' wakeup level
25 * is higher than requested sleep level
26 */
27
Len Brown4be44fc2005-08-05 00:44:28 -040028void acpi_enable_wakeup_device_prep(u8 sleep_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -070029{
Len Brown4be44fc2005-08-05 00:44:28 -040030 struct list_head *node, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32 ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device_prep");
33
34 spin_lock(&acpi_device_lock);
35 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
Len Brown4be44fc2005-08-05 00:44:28 -040036 struct acpi_device *dev = container_of(node,
37 struct acpi_device,
38 wakeup_list);
39
40 if (!dev->wakeup.flags.valid ||
41 !dev->wakeup.state.enabled ||
42 (sleep_state > (u32) dev->wakeup.sleep_state))
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 continue;
44
45 spin_unlock(&acpi_device_lock);
46 acpi_enable_wakeup_device_power(dev);
47 spin_lock(&acpi_device_lock);
48 }
49 spin_unlock(&acpi_device_lock);
50}
51
52/**
53 * acpi_enable_wakeup_device - enable wakeup devices
54 * @sleep_state: ACPI state
55 * Enable all wakup devices's GPE
56 */
Len Brown4be44fc2005-08-05 00:44:28 -040057void acpi_enable_wakeup_device(u8 sleep_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -070058{
Len Brown4be44fc2005-08-05 00:44:28 -040059 struct list_head *node, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
61 /*
62 * Caution: this routine must be invoked when interrupt is disabled
63 * Refer ACPI2.0: P212
64 */
65 ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device");
66 spin_lock(&acpi_device_lock);
67 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
Len Brown4be44fc2005-08-05 00:44:28 -040068 struct acpi_device *dev = container_of(node,
69 struct acpi_device,
70 wakeup_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
72 /* If users want to disable run-wake GPE,
73 * we only disable it for wake and leave it for runtime
74 */
75 if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
76 spin_unlock(&acpi_device_lock);
Len Brown4be44fc2005-08-05 00:44:28 -040077 acpi_set_gpe_type(dev->wakeup.gpe_device,
78 dev->wakeup.gpe_number,
79 ACPI_GPE_TYPE_RUNTIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 /* Re-enable it, since set_gpe_type will disable it */
Len Brown4be44fc2005-08-05 00:44:28 -040081 acpi_enable_gpe(dev->wakeup.gpe_device,
82 dev->wakeup.gpe_number, ACPI_ISR);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 spin_lock(&acpi_device_lock);
84 continue;
85 }
86
87 if (!dev->wakeup.flags.valid ||
Len Brown4be44fc2005-08-05 00:44:28 -040088 !dev->wakeup.state.enabled ||
89 (sleep_state > (u32) dev->wakeup.sleep_state))
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 continue;
91
92 spin_unlock(&acpi_device_lock);
93 /* run-wake GPE has been enabled */
94 if (!dev->wakeup.flags.run_wake)
Len Brown4be44fc2005-08-05 00:44:28 -040095 acpi_enable_gpe(dev->wakeup.gpe_device,
96 dev->wakeup.gpe_number, ACPI_ISR);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 dev->wakeup.state.active = 1;
98 spin_lock(&acpi_device_lock);
99 }
100 spin_unlock(&acpi_device_lock);
101}
102
103/**
104 * acpi_disable_wakeup_device - disable devices' wakeup capability
105 * @sleep_state: ACPI state
106 * Disable all wakup devices's GPE and wakeup capability
107 */
Len Brown4be44fc2005-08-05 00:44:28 -0400108void acpi_disable_wakeup_device(u8 sleep_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109{
Len Brown4be44fc2005-08-05 00:44:28 -0400110 struct list_head *node, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
112 ACPI_FUNCTION_TRACE("acpi_disable_wakeup_device");
113
114 spin_lock(&acpi_device_lock);
115 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
Len Brown4be44fc2005-08-05 00:44:28 -0400116 struct acpi_device *dev = container_of(node,
117 struct acpi_device,
118 wakeup_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
120 if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
121 spin_unlock(&acpi_device_lock);
Len Brown4be44fc2005-08-05 00:44:28 -0400122 acpi_set_gpe_type(dev->wakeup.gpe_device,
123 dev->wakeup.gpe_number,
124 ACPI_GPE_TYPE_WAKE_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 /* Re-enable it, since set_gpe_type will disable it */
Len Brown4be44fc2005-08-05 00:44:28 -0400126 acpi_enable_gpe(dev->wakeup.gpe_device,
127 dev->wakeup.gpe_number, ACPI_NOT_ISR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 spin_lock(&acpi_device_lock);
129 continue;
130 }
131
Len Brown4be44fc2005-08-05 00:44:28 -0400132 if (!dev->wakeup.flags.valid ||
133 !dev->wakeup.state.active ||
134 (sleep_state > (u32) dev->wakeup.sleep_state))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 continue;
136
137 spin_unlock(&acpi_device_lock);
138 acpi_disable_wakeup_device_power(dev);
139 /* Never disable run-wake GPE */
140 if (!dev->wakeup.flags.run_wake) {
Len Brown4be44fc2005-08-05 00:44:28 -0400141 acpi_disable_gpe(dev->wakeup.gpe_device,
142 dev->wakeup.gpe_number, ACPI_NOT_ISR);
143 acpi_clear_gpe(dev->wakeup.gpe_device,
144 dev->wakeup.gpe_number, ACPI_NOT_ISR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 }
146 dev->wakeup.state.active = 0;
147 spin_lock(&acpi_device_lock);
148 }
149 spin_unlock(&acpi_device_lock);
150}
151
152static int __init acpi_wakeup_device_init(void)
153{
Len Brown4be44fc2005-08-05 00:44:28 -0400154 struct list_head *node, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156 if (acpi_disabled)
157 return 0;
158 printk("ACPI wakeup devices: \n");
159
160 spin_lock(&acpi_device_lock);
161 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
Len Brown4be44fc2005-08-05 00:44:28 -0400162 struct acpi_device *dev = container_of(node,
163 struct acpi_device,
164 wakeup_list);
165
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 /* In case user doesn't load button driver */
167 if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
168 spin_unlock(&acpi_device_lock);
Len Brown4be44fc2005-08-05 00:44:28 -0400169 acpi_set_gpe_type(dev->wakeup.gpe_device,
170 dev->wakeup.gpe_number,
171 ACPI_GPE_TYPE_WAKE_RUN);
172 acpi_enable_gpe(dev->wakeup.gpe_device,
173 dev->wakeup.gpe_number, ACPI_NOT_ISR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 dev->wakeup.state.enabled = 1;
175 spin_lock(&acpi_device_lock);
176 }
177 printk("%4s ", dev->pnp.bus_id);
178 }
179 spin_unlock(&acpi_device_lock);
180 printk("\n");
181
182 return 0;
183}
184
185late_initcall(acpi_wakeup_device_init);
186#endif
187
188/*
189 * Disable all wakeup GPEs before power off.
190 *
191 * Since acpi_enter_sleep_state() will disable all
192 * RUNTIME GPEs, we simply mark all GPES that
193 * are not enabled for wakeup from S5 as RUNTIME.
194 */
195void acpi_wakeup_gpe_poweroff_prepare(void)
196{
Len Brown4be44fc2005-08-05 00:44:28 -0400197 struct list_head *node, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
199 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
Len Brown4be44fc2005-08-05 00:44:28 -0400200 struct acpi_device *dev = container_of(node,
201 struct acpi_device,
202 wakeup_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
204 /* The GPE can wakeup system from S5, don't touch it */
Len Brown4be44fc2005-08-05 00:44:28 -0400205 if ((u32) dev->wakeup.sleep_state == ACPI_STATE_S5)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 continue;
207 /* acpi_set_gpe_type will automatically disable GPE */
208 acpi_set_gpe_type(dev->wakeup.gpe_device,
Len Brown4be44fc2005-08-05 00:44:28 -0400209 dev->wakeup.gpe_number,
210 ACPI_GPE_TYPE_RUNTIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 }
212}