Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
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> | |
1da177e4 LT |
11 | #include "sleep.h" |
12 | ||
13 | #define _COMPONENT ACPI_SYSTEM_COMPONENT | |
4be44fcd | 14 | ACPI_MODULE_NAME("wakeup_devices") |
1da177e4 | 15 | |
4be44fcd | 16 | extern struct list_head acpi_wakeup_device_list; |
1da177e4 LT |
17 | extern spinlock_t acpi_device_lock; |
18 | ||
1da177e4 LT |
19 | /** |
20 | * acpi_enable_wakeup_device_prep - prepare wakeup devices | |
21 | * @sleep_state: ACPI state | |
22 | * Enable all wakup devices power if the devices' wakeup level | |
23 | * is higher than requested sleep level | |
24 | */ | |
25 | ||
4be44fcd | 26 | void acpi_enable_wakeup_device_prep(u8 sleep_state) |
1da177e4 | 27 | { |
4be44fcd | 28 | struct list_head *node, *next; |
1da177e4 | 29 | |
1da177e4 LT |
30 | spin_lock(&acpi_device_lock); |
31 | list_for_each_safe(node, next, &acpi_wakeup_device_list) { | |
4be44fcd LB |
32 | struct acpi_device *dev = container_of(node, |
33 | struct acpi_device, | |
34 | wakeup_list); | |
35 | ||
36 | if (!dev->wakeup.flags.valid || | |
37 | !dev->wakeup.state.enabled || | |
38 | (sleep_state > (u32) dev->wakeup.sleep_state)) | |
1da177e4 LT |
39 | continue; |
40 | ||
41 | spin_unlock(&acpi_device_lock); | |
77e76609 | 42 | acpi_enable_wakeup_device_power(dev, sleep_state); |
1da177e4 LT |
43 | spin_lock(&acpi_device_lock); |
44 | } | |
45 | spin_unlock(&acpi_device_lock); | |
46 | } | |
47 | ||
48 | /** | |
49 | * acpi_enable_wakeup_device - enable wakeup devices | |
50 | * @sleep_state: ACPI state | |
51 | * Enable all wakup devices's GPE | |
52 | */ | |
4be44fcd | 53 | void acpi_enable_wakeup_device(u8 sleep_state) |
1da177e4 | 54 | { |
4be44fcd | 55 | struct list_head *node, *next; |
1da177e4 LT |
56 | |
57 | /* | |
58 | * Caution: this routine must be invoked when interrupt is disabled | |
59 | * Refer ACPI2.0: P212 | |
60 | */ | |
1da177e4 LT |
61 | spin_lock(&acpi_device_lock); |
62 | list_for_each_safe(node, next, &acpi_wakeup_device_list) { | |
9b039330 AS |
63 | struct acpi_device *dev = |
64 | container_of(node, struct acpi_device, wakeup_list); | |
eb9d0fe4 | 65 | |
9b039330 AS |
66 | if (!dev->wakeup.flags.valid) |
67 | continue; | |
eb9d0fe4 | 68 | |
1da177e4 LT |
69 | /* If users want to disable run-wake GPE, |
70 | * we only disable it for wake and leave it for runtime | |
71 | */ | |
eb9d0fe4 RW |
72 | if ((!dev->wakeup.state.enabled && !dev->wakeup.flags.prepared) |
73 | || sleep_state > (u32) dev->wakeup.sleep_state) { | |
9b039330 AS |
74 | if (dev->wakeup.flags.run_wake) { |
75 | spin_unlock(&acpi_device_lock); | |
76 | /* set_gpe_type will disable GPE, leave it like that */ | |
77 | acpi_set_gpe_type(dev->wakeup.gpe_device, | |
78 | dev->wakeup.gpe_number, | |
79 | ACPI_GPE_TYPE_RUNTIME); | |
80 | spin_lock(&acpi_device_lock); | |
81 | } | |
1da177e4 LT |
82 | continue; |
83 | } | |
1da177e4 | 84 | spin_unlock(&acpi_device_lock); |
1da177e4 | 85 | if (!dev->wakeup.flags.run_wake) |
4be44fcd | 86 | acpi_enable_gpe(dev->wakeup.gpe_device, |
0b7084ac | 87 | dev->wakeup.gpe_number); |
1da177e4 LT |
88 | spin_lock(&acpi_device_lock); |
89 | } | |
90 | spin_unlock(&acpi_device_lock); | |
91 | } | |
92 | ||
93 | /** | |
94 | * acpi_disable_wakeup_device - disable devices' wakeup capability | |
95 | * @sleep_state: ACPI state | |
96 | * Disable all wakup devices's GPE and wakeup capability | |
97 | */ | |
4be44fcd | 98 | void acpi_disable_wakeup_device(u8 sleep_state) |
1da177e4 | 99 | { |
4be44fcd | 100 | struct list_head *node, *next; |
1da177e4 | 101 | |
1da177e4 LT |
102 | spin_lock(&acpi_device_lock); |
103 | list_for_each_safe(node, next, &acpi_wakeup_device_list) { | |
9b039330 AS |
104 | struct acpi_device *dev = |
105 | container_of(node, struct acpi_device, wakeup_list); | |
1da177e4 | 106 | |
9b039330 | 107 | if (!dev->wakeup.flags.valid) |
1da177e4 | 108 | continue; |
eb9d0fe4 RW |
109 | |
110 | if ((!dev->wakeup.state.enabled && !dev->wakeup.flags.prepared) | |
111 | || sleep_state > (u32) dev->wakeup.sleep_state) { | |
9b039330 AS |
112 | if (dev->wakeup.flags.run_wake) { |
113 | spin_unlock(&acpi_device_lock); | |
114 | acpi_set_gpe_type(dev->wakeup.gpe_device, | |
115 | dev->wakeup.gpe_number, | |
116 | ACPI_GPE_TYPE_WAKE_RUN); | |
117 | /* Re-enable it, since set_gpe_type will disable it */ | |
118 | acpi_enable_gpe(dev->wakeup.gpe_device, | |
0b7084ac | 119 | dev->wakeup.gpe_number); |
9b039330 AS |
120 | spin_lock(&acpi_device_lock); |
121 | } | |
1da177e4 | 122 | continue; |
9b039330 | 123 | } |
1da177e4 LT |
124 | |
125 | spin_unlock(&acpi_device_lock); | |
126 | acpi_disable_wakeup_device_power(dev); | |
127 | /* Never disable run-wake GPE */ | |
128 | if (!dev->wakeup.flags.run_wake) { | |
4be44fcd | 129 | acpi_disable_gpe(dev->wakeup.gpe_device, |
0b7084ac | 130 | dev->wakeup.gpe_number); |
4be44fcd LB |
131 | acpi_clear_gpe(dev->wakeup.gpe_device, |
132 | dev->wakeup.gpe_number, ACPI_NOT_ISR); | |
1da177e4 | 133 | } |
1da177e4 LT |
134 | spin_lock(&acpi_device_lock); |
135 | } | |
136 | spin_unlock(&acpi_device_lock); | |
137 | } | |
138 | ||
139 | static int __init acpi_wakeup_device_init(void) | |
140 | { | |
4be44fcd | 141 | struct list_head *node, *next; |
1da177e4 LT |
142 | |
143 | if (acpi_disabled) | |
144 | return 0; | |
1da177e4 LT |
145 | |
146 | spin_lock(&acpi_device_lock); | |
147 | list_for_each_safe(node, next, &acpi_wakeup_device_list) { | |
4be44fcd LB |
148 | struct acpi_device *dev = container_of(node, |
149 | struct acpi_device, | |
150 | wakeup_list); | |
1da177e4 | 151 | /* In case user doesn't load button driver */ |
9b039330 AS |
152 | if (!dev->wakeup.flags.run_wake || dev->wakeup.state.enabled) |
153 | continue; | |
154 | spin_unlock(&acpi_device_lock); | |
155 | acpi_set_gpe_type(dev->wakeup.gpe_device, | |
156 | dev->wakeup.gpe_number, | |
157 | ACPI_GPE_TYPE_WAKE_RUN); | |
158 | acpi_enable_gpe(dev->wakeup.gpe_device, | |
0b7084ac | 159 | dev->wakeup.gpe_number); |
9b039330 AS |
160 | dev->wakeup.state.enabled = 1; |
161 | spin_lock(&acpi_device_lock); | |
1da177e4 LT |
162 | } |
163 | spin_unlock(&acpi_device_lock); | |
1da177e4 LT |
164 | return 0; |
165 | } | |
166 | ||
167 | late_initcall(acpi_wakeup_device_init); |