aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/scan.c1
-rw-r--r--drivers/acpi/sleep.c45
2 files changed, 44 insertions, 2 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 85cbfdccc97c..c8a1f3b68110 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1567,6 +1567,7 @@ static int acpi_bus_scan_fixed(void)
1567 ACPI_BUS_TYPE_POWER_BUTTON, 1567 ACPI_BUS_TYPE_POWER_BUTTON,
1568 ACPI_STA_DEFAULT, 1568 ACPI_STA_DEFAULT,
1569 &ops); 1569 &ops);
1570 device_init_wakeup(&device->dev, true);
1570 } 1571 }
1571 1572
1572 if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { 1573 if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index eb6fd233764b..a564fc3ffa1c 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -57,6 +57,7 @@ MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend.");
57MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".); 57MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".);
58 58
59static u8 sleep_states[ACPI_S_STATE_COUNT]; 59static u8 sleep_states[ACPI_S_STATE_COUNT];
60static bool pwr_btn_event_pending;
60 61
61static void acpi_sleep_tts_switch(u32 acpi_state) 62static void acpi_sleep_tts_switch(u32 acpi_state)
62{ 63{
@@ -186,6 +187,14 @@ static int acpi_pm_prepare(void)
186 return error; 187 return error;
187} 188}
188 189
190static int find_powerf_dev(struct device *dev, void *data)
191{
192 struct acpi_device *device = to_acpi_device(dev);
193 const char *hid = acpi_device_hid(device);
194
195 return !strcmp(hid, ACPI_BUTTON_HID_POWERF);
196}
197
189/** 198/**
190 * acpi_pm_finish - Instruct the platform to leave a sleep state. 199 * acpi_pm_finish - Instruct the platform to leave a sleep state.
191 * 200 *
@@ -194,6 +203,7 @@ static int acpi_pm_prepare(void)
194 */ 203 */
195static void acpi_pm_finish(void) 204static void acpi_pm_finish(void)
196{ 205{
206 struct device *pwr_btn_dev;
197 u32 acpi_state = acpi_target_sleep_state; 207 u32 acpi_state = acpi_target_sleep_state;
198 208
199 acpi_ec_unblock_transactions(); 209 acpi_ec_unblock_transactions();
@@ -211,6 +221,23 @@ static void acpi_pm_finish(void)
211 acpi_set_firmware_waking_vector((acpi_physical_address) 0); 221 acpi_set_firmware_waking_vector((acpi_physical_address) 0);
212 222
213 acpi_target_sleep_state = ACPI_STATE_S0; 223 acpi_target_sleep_state = ACPI_STATE_S0;
224
225 /* If we were woken with the fixed power button, provide a small
226 * hint to userspace in the form of a wakeup event on the fixed power
227 * button device (if it can be found).
228 *
229 * We delay the event generation til now, as the PM layer requires
230 * timekeeping to be running before we generate events. */
231 if (!pwr_btn_event_pending)
232 return;
233
234 pwr_btn_event_pending = false;
235 pwr_btn_dev = bus_find_device(&acpi_bus_type, NULL, NULL,
236 find_powerf_dev);
237 if (pwr_btn_dev) {
238 pm_wakeup_event(pwr_btn_dev, 0);
239 put_device(pwr_btn_dev);
240 }
214} 241}
215 242
216/** 243/**
@@ -300,9 +327,23 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
300 /* ACPI 3.0 specs (P62) says that it's the responsibility 327 /* ACPI 3.0 specs (P62) says that it's the responsibility
301 * of the OSPM to clear the status bit [ implying that the 328 * of the OSPM to clear the status bit [ implying that the
302 * POWER_BUTTON event should not reach userspace ] 329 * POWER_BUTTON event should not reach userspace ]
330 *
331 * However, we do generate a small hint for userspace in the form of
332 * a wakeup event. We flag this condition for now and generate the
333 * event later, as we're currently too early in resume to be able to
334 * generate wakeup events.
303 */ 335 */
304 if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) 336 if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) {
305 acpi_clear_event(ACPI_EVENT_POWER_BUTTON); 337 acpi_event_status pwr_btn_status;
338
339 acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status);
340
341 if (pwr_btn_status & ACPI_EVENT_FLAG_SET) {
342 acpi_clear_event(ACPI_EVENT_POWER_BUTTON);
343 /* Flag for later */
344 pwr_btn_event_pending = true;
345 }
346 }
306 347
307 /* 348 /*
308 * Disable and clear GPE status before interrupt is enabled. Some GPEs 349 * Disable and clear GPE status before interrupt is enabled. Some GPEs