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> | |
e60cc7a6 BH |
11 | |
12 | #include "internal.h" | |
1da177e4 LT |
13 | #include "sleep.h" |
14 | ||
9090589d SL |
15 | /* |
16 | * We didn't lock acpi_device_lock in the file, because it invokes oops in | |
17 | * suspend/resume and isn't really required as this is called in S-state. At | |
18 | * that time, there is no device hotplug | |
19 | **/ | |
1da177e4 | 20 | #define _COMPONENT ACPI_SYSTEM_COMPONENT |
4be44fcd | 21 | ACPI_MODULE_NAME("wakeup_devices") |
1da177e4 | 22 | |
1da177e4 LT |
23 | /** |
24 | * acpi_enable_wakeup_device_prep - prepare wakeup devices | |
25 | * @sleep_state: ACPI state | |
26 | * Enable all wakup devices power if the devices' wakeup level | |
27 | * is higher than requested sleep level | |
28 | */ | |
29 | ||
4be44fcd | 30 | void acpi_enable_wakeup_device_prep(u8 sleep_state) |
1da177e4 | 31 | { |
4be44fcd | 32 | struct list_head *node, *next; |
1da177e4 | 33 | |
1da177e4 | 34 | list_for_each_safe(node, next, &acpi_wakeup_device_list) { |
4be44fcd LB |
35 | struct acpi_device *dev = container_of(node, |
36 | struct acpi_device, | |
37 | wakeup_list); | |
38 | ||
39 | if (!dev->wakeup.flags.valid || | |
40 | !dev->wakeup.state.enabled || | |
41 | (sleep_state > (u32) dev->wakeup.sleep_state)) | |
1da177e4 LT |
42 | continue; |
43 | ||
77e76609 | 44 | acpi_enable_wakeup_device_power(dev, sleep_state); |
1da177e4 | 45 | } |
1da177e4 LT |
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 | 61 | list_for_each_safe(node, next, &acpi_wakeup_device_list) { |
9b039330 AS |
62 | struct acpi_device *dev = |
63 | container_of(node, struct acpi_device, wakeup_list); | |
eb9d0fe4 | 64 | |
9b039330 AS |
65 | if (!dev->wakeup.flags.valid) |
66 | continue; | |
eb9d0fe4 | 67 | |
1da177e4 LT |
68 | /* If users want to disable run-wake GPE, |
69 | * we only disable it for wake and leave it for runtime | |
70 | */ | |
9b83ccd2 | 71 | if ((!dev->wakeup.state.enabled && !dev->wakeup.prepare_count) |
eb9d0fe4 | 72 | || sleep_state > (u32) dev->wakeup.sleep_state) { |
9b039330 | 73 | if (dev->wakeup.flags.run_wake) { |
9b039330 AS |
74 | /* set_gpe_type will disable GPE, leave it like that */ |
75 | acpi_set_gpe_type(dev->wakeup.gpe_device, | |
76 | dev->wakeup.gpe_number, | |
77 | ACPI_GPE_TYPE_RUNTIME); | |
9b039330 | 78 | } |
1da177e4 LT |
79 | continue; |
80 | } | |
1da177e4 | 81 | if (!dev->wakeup.flags.run_wake) |
4be44fcd | 82 | acpi_enable_gpe(dev->wakeup.gpe_device, |
0b7084ac | 83 | dev->wakeup.gpe_number); |
1da177e4 | 84 | } |
1da177e4 LT |
85 | } |
86 | ||
87 | /** | |
88 | * acpi_disable_wakeup_device - disable devices' wakeup capability | |
89 | * @sleep_state: ACPI state | |
90 | * Disable all wakup devices's GPE and wakeup capability | |
91 | */ | |
4be44fcd | 92 | void acpi_disable_wakeup_device(u8 sleep_state) |
1da177e4 | 93 | { |
4be44fcd | 94 | struct list_head *node, *next; |
1da177e4 | 95 | |
1da177e4 | 96 | list_for_each_safe(node, next, &acpi_wakeup_device_list) { |
9b039330 AS |
97 | struct acpi_device *dev = |
98 | container_of(node, struct acpi_device, wakeup_list); | |
1da177e4 | 99 | |
9b039330 | 100 | if (!dev->wakeup.flags.valid) |
1da177e4 | 101 | continue; |
eb9d0fe4 | 102 | |
9b83ccd2 | 103 | if ((!dev->wakeup.state.enabled && !dev->wakeup.prepare_count) |
eb9d0fe4 | 104 | || sleep_state > (u32) dev->wakeup.sleep_state) { |
9b039330 | 105 | if (dev->wakeup.flags.run_wake) { |
9b039330 AS |
106 | acpi_set_gpe_type(dev->wakeup.gpe_device, |
107 | dev->wakeup.gpe_number, | |
108 | ACPI_GPE_TYPE_WAKE_RUN); | |
109 | /* Re-enable it, since set_gpe_type will disable it */ | |
110 | acpi_enable_gpe(dev->wakeup.gpe_device, | |
0b7084ac | 111 | dev->wakeup.gpe_number); |
9b039330 | 112 | } |
1da177e4 | 113 | continue; |
9b039330 | 114 | } |
1da177e4 | 115 | |
1da177e4 LT |
116 | acpi_disable_wakeup_device_power(dev); |
117 | /* Never disable run-wake GPE */ | |
118 | if (!dev->wakeup.flags.run_wake) { | |
4be44fcd | 119 | acpi_disable_gpe(dev->wakeup.gpe_device, |
0b7084ac | 120 | dev->wakeup.gpe_number); |
4be44fcd LB |
121 | acpi_clear_gpe(dev->wakeup.gpe_device, |
122 | dev->wakeup.gpe_number, ACPI_NOT_ISR); | |
1da177e4 | 123 | } |
1da177e4 | 124 | } |
1da177e4 LT |
125 | } |
126 | ||
201b8c65 | 127 | int __init acpi_wakeup_device_init(void) |
1da177e4 | 128 | { |
4be44fcd | 129 | struct list_head *node, *next; |
1da177e4 | 130 | |
9090589d | 131 | mutex_lock(&acpi_device_lock); |
1da177e4 | 132 | list_for_each_safe(node, next, &acpi_wakeup_device_list) { |
4be44fcd LB |
133 | struct acpi_device *dev = container_of(node, |
134 | struct acpi_device, | |
135 | wakeup_list); | |
1da177e4 | 136 | /* In case user doesn't load button driver */ |
9b039330 AS |
137 | if (!dev->wakeup.flags.run_wake || dev->wakeup.state.enabled) |
138 | continue; | |
9b039330 AS |
139 | acpi_set_gpe_type(dev->wakeup.gpe_device, |
140 | dev->wakeup.gpe_number, | |
141 | ACPI_GPE_TYPE_WAKE_RUN); | |
142 | acpi_enable_gpe(dev->wakeup.gpe_device, | |
0b7084ac | 143 | dev->wakeup.gpe_number); |
9b039330 | 144 | dev->wakeup.state.enabled = 1; |
1da177e4 | 145 | } |
9090589d | 146 | mutex_unlock(&acpi_device_lock); |
1da177e4 LT |
147 | return 0; |
148 | } |