blob: fab8f2694f03284bf23f3dd256cd1a811ae6727f [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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
159 spin_lock(&acpi_device_lock);
160 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
Len Brown4be44fc2005-08-05 00:44:28 -0400161 struct acpi_device *dev = container_of(node,
162 struct acpi_device,
163 wakeup_list);
164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 /* In case user doesn't load button driver */
166 if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
167 spin_unlock(&acpi_device_lock);
Len Brown4be44fc2005-08-05 00:44:28 -0400168 acpi_set_gpe_type(dev->wakeup.gpe_device,
169 dev->wakeup.gpe_number,
170 ACPI_GPE_TYPE_WAKE_RUN);
171 acpi_enable_gpe(dev->wakeup.gpe_device,
172 dev->wakeup.gpe_number, ACPI_NOT_ISR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 dev->wakeup.state.enabled = 1;
174 spin_lock(&acpi_device_lock);
175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 }
177 spin_unlock(&acpi_device_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
179 return 0;
180}
181
182late_initcall(acpi_wakeup_device_init);
183#endif
184
185/*
Satoru Takeuchib7b09b12006-11-02 19:08:57 +0900186 * Disable all wakeup GPEs before entering requested sleep state.
187 * @sleep_state: ACPI state
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 * Since acpi_enter_sleep_state() will disable all
189 * RUNTIME GPEs, we simply mark all GPES that
Satoru Takeuchib7b09b12006-11-02 19:08:57 +0900190 * are not enabled for wakeup from requested state as RUNTIME.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 */
Alexey Starikovskiy729b4d42005-12-01 04:29:00 -0500192void acpi_gpe_sleep_prepare(u32 sleep_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193{
Len Brown4be44fc2005-08-05 00:44:28 -0400194 struct list_head *node, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
Len Brown4be44fc2005-08-05 00:44:28 -0400197 struct acpi_device *dev = container_of(node,
198 struct acpi_device,
199 wakeup_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
Alexey Starikovskiy729b4d42005-12-01 04:29:00 -0500201 /* The GPE can wakeup system from this state, don't touch it */
202 if ((u32) dev->wakeup.sleep_state >= sleep_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 continue;
204 /* acpi_set_gpe_type will automatically disable GPE */
205 acpi_set_gpe_type(dev->wakeup.gpe_device,
Len Brown4be44fc2005-08-05 00:44:28 -0400206 dev->wakeup.gpe_number,
207 ACPI_GPE_TYPE_RUNTIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 }
209}