mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-31 04:01:48 -04:00
Merge branch 'acpi-pm'
* acpi-pm: PM / core: Drop run_wake flag from struct dev_pm_info PCI / PM: Simplify device wakeup settings code PCI / PM: Drop pme_interrupt flag from struct pci_dev ACPI / PM: Consolidate device wakeup settings code ACPI / PM: Drop run_wake from struct acpi_device_wakeup_flags ACPI / sleep: EC-based wakeup from suspend-to-idle on recent systems platform: x86: intel-hid: Wake up the system from suspend-to-idle platform: x86: intel-vbtn: Wake up the system from suspend-to-idle ACPI / PM: Ignore spurious SCI wakeups from suspend-to-idle platform/x86: Add driver for ACPI INT0002 Virtual GPIO device PCI / PM: Restore PME Enable if skipping wakeup setup PM / sleep: Print timing information if debug is enabled ACPI / PM: Clean up device wakeup enable/disable code ACPI / PM: Change log level of wakeup-related message USB / PCI / PM: Allow the PCI core to do the resume cleanup ACPI / PM: Run wakeup notify handlers synchronously Conflicts: drivers/base/power/main.c
This commit is contained in:
commit
8f8e5c3e27
35 changed files with 669 additions and 301 deletions
|
|
@ -782,7 +782,7 @@ static int acpi_battery_update(struct acpi_battery *battery, bool resume)
|
|||
if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) ||
|
||||
(test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
|
||||
(battery->capacity_now <= battery->alarm)))
|
||||
pm_wakeup_event(&battery->device->dev, 0);
|
||||
acpi_pm_wakeup_event(&battery->device->dev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state)
|
|||
}
|
||||
|
||||
if (state)
|
||||
pm_wakeup_event(&device->dev, 0);
|
||||
acpi_pm_wakeup_event(&device->dev);
|
||||
|
||||
ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device);
|
||||
if (ret == NOTIFY_DONE)
|
||||
|
|
@ -402,7 +402,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
|
|||
} else {
|
||||
int keycode;
|
||||
|
||||
pm_wakeup_event(&device->dev, 0);
|
||||
acpi_pm_wakeup_event(&device->dev);
|
||||
if (button->suspended)
|
||||
break;
|
||||
|
||||
|
|
@ -534,6 +534,7 @@ static int acpi_button_add(struct acpi_device *device)
|
|||
lid_device = device;
|
||||
}
|
||||
|
||||
device_init_wakeup(&device->dev, true);
|
||||
printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device));
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/pm_qos.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
|
@ -385,6 +386,12 @@ EXPORT_SYMBOL(acpi_bus_power_manageable);
|
|||
#ifdef CONFIG_PM
|
||||
static DEFINE_MUTEX(acpi_pm_notifier_lock);
|
||||
|
||||
void acpi_pm_wakeup_event(struct device *dev)
|
||||
{
|
||||
pm_wakeup_dev_event(dev, 0, acpi_s2idle_wakeup());
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_pm_wakeup_event);
|
||||
|
||||
static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
|
||||
{
|
||||
struct acpi_device *adev;
|
||||
|
|
@ -399,9 +406,9 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
|
|||
mutex_lock(&acpi_pm_notifier_lock);
|
||||
|
||||
if (adev->wakeup.flags.notifier_present) {
|
||||
__pm_wakeup_event(adev->wakeup.ws, 0);
|
||||
if (adev->wakeup.context.work.func)
|
||||
queue_pm_work(&adev->wakeup.context.work);
|
||||
pm_wakeup_ws_event(adev->wakeup.ws, 0, acpi_s2idle_wakeup());
|
||||
if (adev->wakeup.context.func)
|
||||
adev->wakeup.context.func(&adev->wakeup.context);
|
||||
}
|
||||
|
||||
mutex_unlock(&acpi_pm_notifier_lock);
|
||||
|
|
@ -413,7 +420,7 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
|
|||
* acpi_add_pm_notifier - Register PM notify handler for given ACPI device.
|
||||
* @adev: ACPI device to add the notify handler for.
|
||||
* @dev: Device to generate a wakeup event for while handling the notification.
|
||||
* @work_func: Work function to execute when handling the notification.
|
||||
* @func: Work function to execute when handling the notification.
|
||||
*
|
||||
* NOTE: @adev need not be a run-wake or wakeup device to be a valid source of
|
||||
* PM wakeup events. For example, wakeup events may be generated for bridges
|
||||
|
|
@ -421,11 +428,11 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
|
|||
* bridge itself doesn't have a wakeup GPE associated with it.
|
||||
*/
|
||||
acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
|
||||
void (*work_func)(struct work_struct *work))
|
||||
void (*func)(struct acpi_device_wakeup_context *context))
|
||||
{
|
||||
acpi_status status = AE_ALREADY_EXISTS;
|
||||
|
||||
if (!dev && !work_func)
|
||||
if (!dev && !func)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
mutex_lock(&acpi_pm_notifier_lock);
|
||||
|
|
@ -435,8 +442,7 @@ acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
|
|||
|
||||
adev->wakeup.ws = wakeup_source_register(dev_name(&adev->dev));
|
||||
adev->wakeup.context.dev = dev;
|
||||
if (work_func)
|
||||
INIT_WORK(&adev->wakeup.context.work, work_func);
|
||||
adev->wakeup.context.func = func;
|
||||
|
||||
status = acpi_install_notify_handler(adev->handle, ACPI_SYSTEM_NOTIFY,
|
||||
acpi_pm_notify_handler, NULL);
|
||||
|
|
@ -469,10 +475,7 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev)
|
|||
if (ACPI_FAILURE(status))
|
||||
goto out;
|
||||
|
||||
if (adev->wakeup.context.work.func) {
|
||||
cancel_work_sync(&adev->wakeup.context.work);
|
||||
adev->wakeup.context.work.func = NULL;
|
||||
}
|
||||
adev->wakeup.context.func = NULL;
|
||||
adev->wakeup.context.dev = NULL;
|
||||
wakeup_source_unregister(adev->wakeup.ws);
|
||||
|
||||
|
|
@ -493,6 +496,13 @@ bool acpi_bus_can_wakeup(acpi_handle handle)
|
|||
}
|
||||
EXPORT_SYMBOL(acpi_bus_can_wakeup);
|
||||
|
||||
bool acpi_pm_device_can_wakeup(struct device *dev)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
|
||||
return adev ? acpi_device_can_wakeup(adev) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_dev_pm_get_state - Get preferred power state of ACPI device.
|
||||
* @dev: Device whose preferred target power state to return.
|
||||
|
|
@ -658,16 +668,15 @@ EXPORT_SYMBOL(acpi_pm_device_sleep_state);
|
|||
|
||||
/**
|
||||
* acpi_pm_notify_work_func - ACPI devices wakeup notification work function.
|
||||
* @work: Work item to handle.
|
||||
* @context: Device wakeup context.
|
||||
*/
|
||||
static void acpi_pm_notify_work_func(struct work_struct *work)
|
||||
static void acpi_pm_notify_work_func(struct acpi_device_wakeup_context *context)
|
||||
{
|
||||
struct device *dev;
|
||||
struct device *dev = context->dev;
|
||||
|
||||
dev = container_of(work, struct acpi_device_wakeup_context, work)->dev;
|
||||
if (dev) {
|
||||
pm_wakeup_event(dev, 0);
|
||||
pm_runtime_resume(dev);
|
||||
pm_request_resume(dev);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -693,80 +702,53 @@ static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state,
|
|||
acpi_status res;
|
||||
int error;
|
||||
|
||||
if (adev->wakeup.flags.enabled)
|
||||
return 0;
|
||||
|
||||
error = acpi_enable_wakeup_device_power(adev, target_state);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (adev->wakeup.flags.enabled)
|
||||
return 0;
|
||||
|
||||
res = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
|
||||
if (ACPI_SUCCESS(res)) {
|
||||
adev->wakeup.flags.enabled = 1;
|
||||
} else {
|
||||
if (ACPI_FAILURE(res)) {
|
||||
acpi_disable_wakeup_device_power(adev);
|
||||
return -EIO;
|
||||
}
|
||||
} else {
|
||||
if (adev->wakeup.flags.enabled) {
|
||||
acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
|
||||
adev->wakeup.flags.enabled = 0;
|
||||
}
|
||||
adev->wakeup.flags.enabled = 1;
|
||||
} else if (adev->wakeup.flags.enabled) {
|
||||
acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
|
||||
acpi_disable_wakeup_device_power(adev);
|
||||
adev->wakeup.flags.enabled = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_pm_device_run_wake - Enable/disable remote wakeup for given device.
|
||||
* @dev: Device to enable/disable the platform to wake up.
|
||||
* acpi_pm_set_device_wakeup - Enable/disable remote wakeup for given device.
|
||||
* @dev: Device to enable/disable to generate wakeup events.
|
||||
* @enable: Whether to enable or disable the wakeup functionality.
|
||||
*/
|
||||
int acpi_pm_device_run_wake(struct device *phys_dev, bool enable)
|
||||
{
|
||||
struct acpi_device *adev;
|
||||
|
||||
if (!device_run_wake(phys_dev))
|
||||
return -EINVAL;
|
||||
|
||||
adev = ACPI_COMPANION(phys_dev);
|
||||
if (!adev) {
|
||||
dev_dbg(phys_dev, "ACPI companion missing in %s!\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return acpi_device_wakeup(adev, ACPI_STATE_S0, enable);
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_pm_device_run_wake);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/**
|
||||
* acpi_pm_device_sleep_wake - Enable or disable device to wake up the system.
|
||||
* @dev: Device to enable/desible to wake up the system from sleep states.
|
||||
* @enable: Whether to enable or disable @dev to wake up the system.
|
||||
*/
|
||||
int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
|
||||
int acpi_pm_set_device_wakeup(struct device *dev, bool enable)
|
||||
{
|
||||
struct acpi_device *adev;
|
||||
int error;
|
||||
|
||||
if (!device_can_wakeup(dev))
|
||||
return -EINVAL;
|
||||
|
||||
adev = ACPI_COMPANION(dev);
|
||||
if (!adev) {
|
||||
dev_dbg(dev, "ACPI companion missing in %s!\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!acpi_device_can_wakeup(adev))
|
||||
return -EINVAL;
|
||||
|
||||
error = acpi_device_wakeup(adev, acpi_target_system_state(), enable);
|
||||
if (!error)
|
||||
dev_info(dev, "System wakeup %s by ACPI\n",
|
||||
enable ? "enabled" : "disabled");
|
||||
dev_dbg(dev, "Wakeup %s by ACPI\n", enable ? "enabled" : "disabled");
|
||||
|
||||
return error;
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
EXPORT_SYMBOL(acpi_pm_set_device_wakeup);
|
||||
|
||||
/**
|
||||
* acpi_dev_pm_low_power - Put ACPI device into a low-power state.
|
||||
|
|
|
|||
|
|
@ -1835,7 +1835,7 @@ static int acpi_ec_suspend(struct device *dev)
|
|||
struct acpi_ec *ec =
|
||||
acpi_driver_data(to_acpi_device(dev));
|
||||
|
||||
if (ec_freeze_events)
|
||||
if (acpi_sleep_no_ec_events() && ec_freeze_events)
|
||||
acpi_ec_disable_event(ec);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -198,8 +198,12 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);
|
|||
Suspend/Resume
|
||||
-------------------------------------------------------------------------- */
|
||||
#ifdef CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT
|
||||
extern bool acpi_s2idle_wakeup(void);
|
||||
extern bool acpi_sleep_no_ec_events(void);
|
||||
extern int acpi_sleep_init(void);
|
||||
#else
|
||||
static inline bool acpi_s2idle_wakeup(void) { return false; }
|
||||
static inline bool acpi_sleep_no_ec_events(void) { return true; }
|
||||
static inline int acpi_sleep_init(void) { return -ENXIO; }
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -608,8 +608,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
|
|||
pcie_no_aspm();
|
||||
|
||||
pci_acpi_add_bus_pm_notifier(device);
|
||||
if (device->wakeup.flags.run_wake)
|
||||
device_set_run_wake(root->bus->bridge, true);
|
||||
device_set_wakeup_capable(root->bus->bridge, device->wakeup.flags.valid);
|
||||
|
||||
if (hotadd) {
|
||||
pcibios_resource_survey_bus(root->bus);
|
||||
|
|
@ -649,7 +648,7 @@ static void acpi_pci_root_remove(struct acpi_device *device)
|
|||
pci_stop_root_bus(root->bus);
|
||||
|
||||
pci_ioapic_remove(root);
|
||||
device_set_run_wake(root->bus->bridge, false);
|
||||
device_set_wakeup_capable(root->bus->bridge, false);
|
||||
pci_acpi_remove_bus_pm_notifier(device);
|
||||
|
||||
pci_remove_root_bus(root->bus);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
|
|||
|
||||
if (!dev->physical_node_count) {
|
||||
seq_printf(seq, "%c%-8s\n",
|
||||
dev->wakeup.flags.run_wake ? '*' : ' ',
|
||||
dev->wakeup.flags.valid ? '*' : ' ',
|
||||
device_may_wakeup(&dev->dev) ?
|
||||
"enabled" : "disabled");
|
||||
} else {
|
||||
|
|
@ -58,7 +58,7 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
|
|||
seq_printf(seq, "\t\t");
|
||||
|
||||
seq_printf(seq, "%c%-8s %s:%s\n",
|
||||
dev->wakeup.flags.run_wake ? '*' : ' ',
|
||||
dev->wakeup.flags.valid ? '*' : ' ',
|
||||
(device_may_wakeup(&dev->dev) ||
|
||||
device_may_wakeup(ldev)) ?
|
||||
"enabled" : "disabled",
|
||||
|
|
|
|||
|
|
@ -835,7 +835,7 @@ static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
|
|||
return err;
|
||||
}
|
||||
|
||||
static void acpi_wakeup_gpe_init(struct acpi_device *device)
|
||||
static bool acpi_wakeup_gpe_init(struct acpi_device *device)
|
||||
{
|
||||
static const struct acpi_device_id button_device_ids[] = {
|
||||
{"PNP0C0C", 0},
|
||||
|
|
@ -845,13 +845,11 @@ static void acpi_wakeup_gpe_init(struct acpi_device *device)
|
|||
};
|
||||
struct acpi_device_wakeup *wakeup = &device->wakeup;
|
||||
acpi_status status;
|
||||
acpi_event_status event_status;
|
||||
|
||||
wakeup->flags.notifier_present = 0;
|
||||
|
||||
/* Power button, Lid switch always enable wakeup */
|
||||
if (!acpi_match_device_ids(device, button_device_ids)) {
|
||||
wakeup->flags.run_wake = 1;
|
||||
if (!acpi_match_device_ids(device, &button_device_ids[1])) {
|
||||
/* Do not use Lid/sleep button for S5 wakeup */
|
||||
if (wakeup->sleep_state == ACPI_STATE_S5)
|
||||
|
|
@ -859,17 +857,12 @@ static void acpi_wakeup_gpe_init(struct acpi_device *device)
|
|||
}
|
||||
acpi_mark_gpe_for_wake(wakeup->gpe_device, wakeup->gpe_number);
|
||||
device_set_wakeup_capable(&device->dev, true);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
acpi_setup_gpe_for_wake(device->handle, wakeup->gpe_device,
|
||||
wakeup->gpe_number);
|
||||
status = acpi_get_gpe_status(wakeup->gpe_device, wakeup->gpe_number,
|
||||
&event_status);
|
||||
if (ACPI_FAILURE(status))
|
||||
return;
|
||||
|
||||
wakeup->flags.run_wake = !!(event_status & ACPI_EVENT_FLAG_HAS_HANDLER);
|
||||
status = acpi_setup_gpe_for_wake(device->handle, wakeup->gpe_device,
|
||||
wakeup->gpe_number);
|
||||
return ACPI_SUCCESS(status);
|
||||
}
|
||||
|
||||
static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
|
||||
|
|
@ -887,10 +880,10 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
|
|||
return;
|
||||
}
|
||||
|
||||
device->wakeup.flags.valid = 1;
|
||||
device->wakeup.flags.valid = acpi_wakeup_gpe_init(device);
|
||||
device->wakeup.prepare_count = 0;
|
||||
acpi_wakeup_gpe_init(device);
|
||||
/* Call _PSW/_DSW object to disable its ability to wake the sleeping
|
||||
/*
|
||||
* Call _PSW/_DSW object to disable its ability to wake the sleeping
|
||||
* system for the ACPI device with the _PRW object.
|
||||
* The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
|
||||
* So it is necessary to call _DSW object first. Only when it is not
|
||||
|
|
|
|||
|
|
@ -650,38 +650,165 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = {
|
|||
.recover = acpi_pm_finish,
|
||||
};
|
||||
|
||||
static bool s2idle_in_progress;
|
||||
static bool s2idle_wakeup;
|
||||
|
||||
/*
|
||||
* On platforms supporting the Low Power S0 Idle interface there is an ACPI
|
||||
* device object with the PNP0D80 compatible device ID (System Power Management
|
||||
* Controller) and a specific _DSM method under it. That method, if present,
|
||||
* can be used to indicate to the platform that the OS is transitioning into a
|
||||
* low-power state in which certain types of activity are not desirable or that
|
||||
* it is leaving such a state, which allows the platform to adjust its operation
|
||||
* mode accordingly.
|
||||
*/
|
||||
static const struct acpi_device_id lps0_device_ids[] = {
|
||||
{"PNP0D80", },
|
||||
{"", },
|
||||
};
|
||||
|
||||
#define ACPI_LPS0_DSM_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66"
|
||||
|
||||
#define ACPI_LPS0_SCREEN_OFF 3
|
||||
#define ACPI_LPS0_SCREEN_ON 4
|
||||
#define ACPI_LPS0_ENTRY 5
|
||||
#define ACPI_LPS0_EXIT 6
|
||||
|
||||
#define ACPI_S2IDLE_FUNC_MASK ((1 << ACPI_LPS0_ENTRY) | (1 << ACPI_LPS0_EXIT))
|
||||
|
||||
static acpi_handle lps0_device_handle;
|
||||
static guid_t lps0_dsm_guid;
|
||||
static char lps0_dsm_func_mask;
|
||||
|
||||
static void acpi_sleep_run_lps0_dsm(unsigned int func)
|
||||
{
|
||||
union acpi_object *out_obj;
|
||||
|
||||
if (!(lps0_dsm_func_mask & (1 << func)))
|
||||
return;
|
||||
|
||||
out_obj = acpi_evaluate_dsm(lps0_device_handle, &lps0_dsm_guid, 1, func, NULL);
|
||||
ACPI_FREE(out_obj);
|
||||
|
||||
acpi_handle_debug(lps0_device_handle, "_DSM function %u evaluation %s\n",
|
||||
func, out_obj ? "successful" : "failed");
|
||||
}
|
||||
|
||||
static int lps0_device_attach(struct acpi_device *adev,
|
||||
const struct acpi_device_id *not_used)
|
||||
{
|
||||
union acpi_object *out_obj;
|
||||
|
||||
if (lps0_device_handle)
|
||||
return 0;
|
||||
|
||||
if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
|
||||
return 0;
|
||||
|
||||
guid_parse(ACPI_LPS0_DSM_UUID, &lps0_dsm_guid);
|
||||
/* Check if the _DSM is present and as expected. */
|
||||
out_obj = acpi_evaluate_dsm(adev->handle, &lps0_dsm_guid, 1, 0, NULL);
|
||||
if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) {
|
||||
char bitmask = *(char *)out_obj->buffer.pointer;
|
||||
|
||||
if ((bitmask & ACPI_S2IDLE_FUNC_MASK) == ACPI_S2IDLE_FUNC_MASK) {
|
||||
lps0_dsm_func_mask = bitmask;
|
||||
lps0_device_handle = adev->handle;
|
||||
}
|
||||
|
||||
acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n",
|
||||
bitmask);
|
||||
} else {
|
||||
acpi_handle_debug(adev->handle,
|
||||
"_DSM function 0 evaluation failed\n");
|
||||
}
|
||||
ACPI_FREE(out_obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct acpi_scan_handler lps0_handler = {
|
||||
.ids = lps0_device_ids,
|
||||
.attach = lps0_device_attach,
|
||||
};
|
||||
|
||||
static int acpi_freeze_begin(void)
|
||||
{
|
||||
acpi_scan_lock_acquire();
|
||||
s2idle_in_progress = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_freeze_prepare(void)
|
||||
{
|
||||
acpi_enable_wakeup_devices(ACPI_STATE_S0);
|
||||
acpi_enable_all_wakeup_gpes();
|
||||
acpi_os_wait_events_complete();
|
||||
if (lps0_device_handle) {
|
||||
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF);
|
||||
acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY);
|
||||
} else {
|
||||
/*
|
||||
* The configuration of GPEs is changed here to avoid spurious
|
||||
* wakeups, but that should not be necessary if this is a
|
||||
* "low-power S0" platform and the low-power S0 _DSM is present.
|
||||
*/
|
||||
acpi_enable_all_wakeup_gpes();
|
||||
acpi_os_wait_events_complete();
|
||||
}
|
||||
if (acpi_sci_irq_valid())
|
||||
enable_irq_wake(acpi_sci_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acpi_freeze_wake(void)
|
||||
{
|
||||
/*
|
||||
* If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means
|
||||
* that the SCI has triggered while suspended, so cancel the wakeup in
|
||||
* case it has not been a wakeup event (the GPEs will be checked later).
|
||||
*/
|
||||
if (acpi_sci_irq_valid() &&
|
||||
!irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) {
|
||||
pm_system_cancel_wakeup();
|
||||
s2idle_wakeup = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void acpi_freeze_sync(void)
|
||||
{
|
||||
/*
|
||||
* Process all pending events in case there are any wakeup ones.
|
||||
*
|
||||
* The EC driver uses the system workqueue, so that one needs to be
|
||||
* flushed too.
|
||||
*/
|
||||
acpi_os_wait_events_complete();
|
||||
flush_scheduled_work();
|
||||
s2idle_wakeup = false;
|
||||
}
|
||||
|
||||
static void acpi_freeze_restore(void)
|
||||
{
|
||||
acpi_disable_wakeup_devices(ACPI_STATE_S0);
|
||||
if (acpi_sci_irq_valid())
|
||||
disable_irq_wake(acpi_sci_irq);
|
||||
acpi_enable_all_runtime_gpes();
|
||||
|
||||
if (lps0_device_handle) {
|
||||
acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT);
|
||||
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON);
|
||||
} else {
|
||||
acpi_enable_all_runtime_gpes();
|
||||
}
|
||||
}
|
||||
|
||||
static void acpi_freeze_end(void)
|
||||
{
|
||||
s2idle_in_progress = false;
|
||||
acpi_scan_lock_release();
|
||||
}
|
||||
|
||||
static const struct platform_freeze_ops acpi_freeze_ops = {
|
||||
.begin = acpi_freeze_begin,
|
||||
.prepare = acpi_freeze_prepare,
|
||||
.wake = acpi_freeze_wake,
|
||||
.sync = acpi_freeze_sync,
|
||||
.restore = acpi_freeze_restore,
|
||||
.end = acpi_freeze_end,
|
||||
};
|
||||
|
|
@ -696,13 +823,28 @@ static void acpi_sleep_suspend_setup(void)
|
|||
|
||||
suspend_set_ops(old_suspend_ordering ?
|
||||
&acpi_suspend_ops_old : &acpi_suspend_ops);
|
||||
|
||||
acpi_scan_add_handler(&lps0_handler);
|
||||
freeze_set_ops(&acpi_freeze_ops);
|
||||
}
|
||||
|
||||
#else /* !CONFIG_SUSPEND */
|
||||
#define s2idle_in_progress (false)
|
||||
#define s2idle_wakeup (false)
|
||||
#define lps0_device_handle (NULL)
|
||||
static inline void acpi_sleep_suspend_setup(void) {}
|
||||
#endif /* !CONFIG_SUSPEND */
|
||||
|
||||
bool acpi_s2idle_wakeup(void)
|
||||
{
|
||||
return s2idle_wakeup;
|
||||
}
|
||||
|
||||
bool acpi_sleep_no_ec_events(void)
|
||||
{
|
||||
return !s2idle_in_progress || !lps0_device_handle;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static u32 saved_bm_rld;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue