11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2ec2cd81cSRafael J. Wysocki /* 3ec2cd81cSRafael J. Wysocki * drivers/acpi/device_pm.c - ACPI device power management routines. 4ec2cd81cSRafael J. Wysocki * 5ec2cd81cSRafael J. Wysocki * Copyright (C) 2012, Intel Corp. 6ec2cd81cSRafael J. Wysocki * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> 7ec2cd81cSRafael J. Wysocki * 8ec2cd81cSRafael J. Wysocki * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9ec2cd81cSRafael J. Wysocki * 10ec2cd81cSRafael J. Wysocki * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 11ec2cd81cSRafael J. Wysocki */ 12ec2cd81cSRafael J. Wysocki 137b199811SRafael J. Wysocki #include <linux/acpi.h> 1486b3832cSRafael J. Wysocki #include <linux/export.h> 15ec2cd81cSRafael J. Wysocki #include <linux/mutex.h> 1686b3832cSRafael J. Wysocki #include <linux/pm_qos.h> 17989561deSTomeu Vizoso #include <linux/pm_domain.h> 18cd7bd02dSRafael J. Wysocki #include <linux/pm_runtime.h> 1933e4f80eSRafael J. Wysocki #include <linux/suspend.h> 20ec2cd81cSRafael J. Wysocki 219ce4e607SRafael J. Wysocki #include "internal.h" 229ce4e607SRafael J. Wysocki 239ce4e607SRafael J. Wysocki #define _COMPONENT ACPI_POWER_COMPONENT 249ce4e607SRafael J. Wysocki ACPI_MODULE_NAME("device_pm"); 25ec2cd81cSRafael J. Wysocki 2686b3832cSRafael J. Wysocki /** 279ce4e607SRafael J. Wysocki * acpi_power_state_string - String representation of ACPI device power state. 289ce4e607SRafael J. Wysocki * @state: ACPI device power state to return the string representation of. 299ce4e607SRafael J. Wysocki */ 309ce4e607SRafael J. Wysocki const char *acpi_power_state_string(int state) 319ce4e607SRafael J. Wysocki { 329ce4e607SRafael J. Wysocki switch (state) { 339ce4e607SRafael J. Wysocki case ACPI_STATE_D0: 349ce4e607SRafael J. Wysocki return "D0"; 359ce4e607SRafael J. Wysocki case ACPI_STATE_D1: 369ce4e607SRafael J. Wysocki return "D1"; 379ce4e607SRafael J. Wysocki case ACPI_STATE_D2: 389ce4e607SRafael J. Wysocki return "D2"; 399ce4e607SRafael J. Wysocki case ACPI_STATE_D3_HOT: 409ce4e607SRafael J. Wysocki return "D3hot"; 419ce4e607SRafael J. Wysocki case ACPI_STATE_D3_COLD: 42898fee4fSRafael J. Wysocki return "D3cold"; 439ce4e607SRafael J. Wysocki default: 449ce4e607SRafael J. Wysocki return "(unknown)"; 459ce4e607SRafael J. Wysocki } 469ce4e607SRafael J. Wysocki } 479ce4e607SRafael J. Wysocki 48f850a48aSRafael J. Wysocki static int acpi_dev_pm_explicit_get(struct acpi_device *device, int *state) 49f850a48aSRafael J. Wysocki { 50f850a48aSRafael J. Wysocki unsigned long long psc; 51f850a48aSRafael J. Wysocki acpi_status status; 52f850a48aSRafael J. Wysocki 53f850a48aSRafael J. Wysocki status = acpi_evaluate_integer(device->handle, "_PSC", NULL, &psc); 54f850a48aSRafael J. Wysocki if (ACPI_FAILURE(status)) 55f850a48aSRafael J. Wysocki return -ENODEV; 56f850a48aSRafael J. Wysocki 57f850a48aSRafael J. Wysocki *state = psc; 58f850a48aSRafael J. Wysocki return 0; 59f850a48aSRafael J. Wysocki } 60f850a48aSRafael J. Wysocki 619ce4e607SRafael J. Wysocki /** 629ce4e607SRafael J. Wysocki * acpi_device_get_power - Get power state of an ACPI device. 639ce4e607SRafael J. Wysocki * @device: Device to get the power state of. 649ce4e607SRafael J. Wysocki * @state: Place to store the power state of the device. 659ce4e607SRafael J. Wysocki * 669ce4e607SRafael J. Wysocki * This function does not update the device's power.state field, but it may 679ce4e607SRafael J. Wysocki * update its parent's power.state field (when the parent's power state is 689ce4e607SRafael J. Wysocki * unknown and the device's power state turns out to be D0). 699ed411c0SRafael J. Wysocki * 709ed411c0SRafael J. Wysocki * Also, it does not update power resource reference counters to ensure that 719ed411c0SRafael J. Wysocki * the power state returned by it will be persistent and it may return a power 729ed411c0SRafael J. Wysocki * state shallower than previously set by acpi_device_set_power() for @device 739ed411c0SRafael J. Wysocki * (if that power state depends on any power resources). 749ce4e607SRafael J. Wysocki */ 759ce4e607SRafael J. Wysocki int acpi_device_get_power(struct acpi_device *device, int *state) 769ce4e607SRafael J. Wysocki { 779ce4e607SRafael J. Wysocki int result = ACPI_STATE_UNKNOWN; 78f850a48aSRafael J. Wysocki int error; 799ce4e607SRafael J. Wysocki 809ce4e607SRafael J. Wysocki if (!device || !state) 819ce4e607SRafael J. Wysocki return -EINVAL; 829ce4e607SRafael J. Wysocki 839ce4e607SRafael J. Wysocki if (!device->flags.power_manageable) { 849ce4e607SRafael J. Wysocki /* TBD: Non-recursive algorithm for walking up hierarchy. */ 859ce4e607SRafael J. Wysocki *state = device->parent ? 869ce4e607SRafael J. Wysocki device->parent->power.state : ACPI_STATE_D0; 879ce4e607SRafael J. Wysocki goto out; 889ce4e607SRafael J. Wysocki } 899ce4e607SRafael J. Wysocki 909ce4e607SRafael J. Wysocki /* 9175eb2d13SRafael J. Wysocki * Get the device's power state from power resources settings and _PSC, 9275eb2d13SRafael J. Wysocki * if available. 939ce4e607SRafael J. Wysocki */ 9475eb2d13SRafael J. Wysocki if (device->power.flags.power_resources) { 95f850a48aSRafael J. Wysocki error = acpi_power_get_inferred_state(device, &result); 969ce4e607SRafael J. Wysocki if (error) 979ce4e607SRafael J. Wysocki return error; 9875eb2d13SRafael J. Wysocki } 9975eb2d13SRafael J. Wysocki if (device->power.flags.explicit_get) { 100f850a48aSRafael J. Wysocki int psc; 10175eb2d13SRafael J. Wysocki 102f850a48aSRafael J. Wysocki error = acpi_dev_pm_explicit_get(device, &psc); 103f850a48aSRafael J. Wysocki if (error) 104f850a48aSRafael J. Wysocki return error; 10575eb2d13SRafael J. Wysocki 10675eb2d13SRafael J. Wysocki /* 10775eb2d13SRafael J. Wysocki * The power resources settings may indicate a power state 10820dacb71SRafael J. Wysocki * shallower than the actual power state of the device, because 10920dacb71SRafael J. Wysocki * the same power resources may be referenced by other devices. 11075eb2d13SRafael J. Wysocki * 11120dacb71SRafael J. Wysocki * For systems predating ACPI 4.0 we assume that D3hot is the 11220dacb71SRafael J. Wysocki * deepest state that can be supported. 11375eb2d13SRafael J. Wysocki */ 11475eb2d13SRafael J. Wysocki if (psc > result && psc < ACPI_STATE_D3_COLD) 11575eb2d13SRafael J. Wysocki result = psc; 11675eb2d13SRafael J. Wysocki else if (result == ACPI_STATE_UNKNOWN) 11720dacb71SRafael J. Wysocki result = psc > ACPI_STATE_D2 ? ACPI_STATE_D3_HOT : psc; 1189ce4e607SRafael J. Wysocki } 1199ce4e607SRafael J. Wysocki 1209ce4e607SRafael J. Wysocki /* 1219ce4e607SRafael J. Wysocki * If we were unsure about the device parent's power state up to this 1229ce4e607SRafael J. Wysocki * point, the fact that the device is in D0 implies that the parent has 123644f17adSMika Westerberg * to be in D0 too, except if ignore_parent is set. 1249ce4e607SRafael J. Wysocki */ 125644f17adSMika Westerberg if (!device->power.flags.ignore_parent && device->parent 126644f17adSMika Westerberg && device->parent->power.state == ACPI_STATE_UNKNOWN 1279ce4e607SRafael J. Wysocki && result == ACPI_STATE_D0) 1289ce4e607SRafael J. Wysocki device->parent->power.state = ACPI_STATE_D0; 1299ce4e607SRafael J. Wysocki 1309ce4e607SRafael J. Wysocki *state = result; 1319ce4e607SRafael J. Wysocki 1329ce4e607SRafael J. Wysocki out: 1339ce4e607SRafael J. Wysocki ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n", 1349ce4e607SRafael J. Wysocki device->pnp.bus_id, acpi_power_state_string(*state))); 1359ce4e607SRafael J. Wysocki 1369ce4e607SRafael J. Wysocki return 0; 1379ce4e607SRafael J. Wysocki } 1389ce4e607SRafael J. Wysocki 1399c0f45e3SRafael J. Wysocki static int acpi_dev_pm_explicit_set(struct acpi_device *adev, int state) 1409c0f45e3SRafael J. Wysocki { 1419c0f45e3SRafael J. Wysocki if (adev->power.states[state].flags.explicit_set) { 1429c0f45e3SRafael J. Wysocki char method[5] = { '_', 'P', 'S', '0' + state, '\0' }; 1439c0f45e3SRafael J. Wysocki acpi_status status; 1449c0f45e3SRafael J. Wysocki 1459c0f45e3SRafael J. Wysocki status = acpi_evaluate_object(adev->handle, method, NULL, NULL); 1469c0f45e3SRafael J. Wysocki if (ACPI_FAILURE(status)) 1479c0f45e3SRafael J. Wysocki return -ENODEV; 1489c0f45e3SRafael J. Wysocki } 1499c0f45e3SRafael J. Wysocki return 0; 1509c0f45e3SRafael J. Wysocki } 1519c0f45e3SRafael J. Wysocki 1529ce4e607SRafael J. Wysocki /** 1539ce4e607SRafael J. Wysocki * acpi_device_set_power - Set power state of an ACPI device. 1549ce4e607SRafael J. Wysocki * @device: Device to set the power state of. 1559ce4e607SRafael J. Wysocki * @state: New power state to set. 1569ce4e607SRafael J. Wysocki * 1579ce4e607SRafael J. Wysocki * Callers must ensure that the device is power manageable before using this 1589ce4e607SRafael J. Wysocki * function. 1599ce4e607SRafael J. Wysocki */ 1609ce4e607SRafael J. Wysocki int acpi_device_set_power(struct acpi_device *device, int state) 1619ce4e607SRafael J. Wysocki { 16220dacb71SRafael J. Wysocki int target_state = state; 1639ce4e607SRafael J. Wysocki int result = 0; 1649ce4e607SRafael J. Wysocki 1652c7d132aSRafael J. Wysocki if (!device || !device->flags.power_manageable 1662c7d132aSRafael J. Wysocki || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD)) 1679ce4e607SRafael J. Wysocki return -EINVAL; 1689ce4e607SRafael J. Wysocki 169ee8193eeSRafael J. Wysocki acpi_handle_debug(device->handle, "Power state change: %s -> %s\n", 170ee8193eeSRafael J. Wysocki acpi_power_state_string(device->power.state), 171ee8193eeSRafael J. Wysocki acpi_power_state_string(state)); 172ee8193eeSRafael J. Wysocki 1739ce4e607SRafael J. Wysocki /* Make sure this is a valid target state */ 1749ce4e607SRafael J. Wysocki 175f850a48aSRafael J. Wysocki /* There is a special case for D0 addressed below. */ 176f850a48aSRafael J. Wysocki if (state > ACPI_STATE_D0 && state == device->power.state) { 177b69137a7SRafael J. Wysocki ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already in %s\n", 178b69137a7SRafael J. Wysocki device->pnp.bus_id, 1799ce4e607SRafael J. Wysocki acpi_power_state_string(state))); 1809ce4e607SRafael J. Wysocki return 0; 1819ce4e607SRafael J. Wysocki } 1829ce4e607SRafael J. Wysocki 18320dacb71SRafael J. Wysocki if (state == ACPI_STATE_D3_COLD) { 18420dacb71SRafael J. Wysocki /* 18520dacb71SRafael J. Wysocki * For transitions to D3cold we need to execute _PS3 and then 18620dacb71SRafael J. Wysocki * possibly drop references to the power resources in use. 18720dacb71SRafael J. Wysocki */ 18820dacb71SRafael J. Wysocki state = ACPI_STATE_D3_HOT; 18920dacb71SRafael J. Wysocki /* If _PR3 is not available, use D3hot as the target state. */ 19020dacb71SRafael J. Wysocki if (!device->power.states[ACPI_STATE_D3_COLD].flags.valid) 19120dacb71SRafael J. Wysocki target_state = state; 19220dacb71SRafael J. Wysocki } else if (!device->power.states[state].flags.valid) { 193b69137a7SRafael J. Wysocki dev_warn(&device->dev, "Power state %s not supported\n", 1949ce4e607SRafael J. Wysocki acpi_power_state_string(state)); 1959ce4e607SRafael J. Wysocki return -ENODEV; 1969ce4e607SRafael J. Wysocki } 19720dacb71SRafael J. Wysocki 198644f17adSMika Westerberg if (!device->power.flags.ignore_parent && 199644f17adSMika Westerberg device->parent && (state < device->parent->power.state)) { 200b69137a7SRafael J. Wysocki dev_warn(&device->dev, 201593298e6SAaron Lu "Cannot transition to power state %s for parent in %s\n", 202593298e6SAaron Lu acpi_power_state_string(state), 203593298e6SAaron Lu acpi_power_state_string(device->parent->power.state)); 2049ce4e607SRafael J. Wysocki return -ENODEV; 2059ce4e607SRafael J. Wysocki } 2069ce4e607SRafael J. Wysocki 207e78adb75SRafael J. Wysocki /* 208e78adb75SRafael J. Wysocki * Transition Power 209e78adb75SRafael J. Wysocki * ---------------- 21020dacb71SRafael J. Wysocki * In accordance with ACPI 6, _PSx is executed before manipulating power 21120dacb71SRafael J. Wysocki * resources, unless the target state is D0, in which case _PS0 is 21220dacb71SRafael J. Wysocki * supposed to be executed after turning the power resources on. 213e78adb75SRafael J. Wysocki */ 21420dacb71SRafael J. Wysocki if (state > ACPI_STATE_D0) { 21520dacb71SRafael J. Wysocki /* 21620dacb71SRafael J. Wysocki * According to ACPI 6, devices cannot go from lower-power 21720dacb71SRafael J. Wysocki * (deeper) states to higher-power (shallower) states. 21820dacb71SRafael J. Wysocki */ 21920dacb71SRafael J. Wysocki if (state < device->power.state) { 22020dacb71SRafael J. Wysocki dev_warn(&device->dev, "Cannot transition from %s to %s\n", 22120dacb71SRafael J. Wysocki acpi_power_state_string(device->power.state), 22220dacb71SRafael J. Wysocki acpi_power_state_string(state)); 22320dacb71SRafael J. Wysocki return -ENODEV; 2249ce4e607SRafael J. Wysocki } 22520dacb71SRafael J. Wysocki 22621ba2379SRafael J. Wysocki /* 22721ba2379SRafael J. Wysocki * If the device goes from D3hot to D3cold, _PS3 has been 22821ba2379SRafael J. Wysocki * evaluated for it already, so skip it in that case. 22921ba2379SRafael J. Wysocki */ 23021ba2379SRafael J. Wysocki if (device->power.state < ACPI_STATE_D3_HOT) { 231e78adb75SRafael J. Wysocki result = acpi_dev_pm_explicit_set(device, state); 232e78adb75SRafael J. Wysocki if (result) 233e78adb75SRafael J. Wysocki goto end; 23421ba2379SRafael J. Wysocki } 2359ce4e607SRafael J. Wysocki 23620dacb71SRafael J. Wysocki if (device->power.flags.power_resources) 23720dacb71SRafael J. Wysocki result = acpi_power_transition(device, target_state); 23820dacb71SRafael J. Wysocki } else { 23942787ed7SRafael J. Wysocki int cur_state = device->power.state; 24042787ed7SRafael J. Wysocki 24120dacb71SRafael J. Wysocki if (device->power.flags.power_resources) { 24220dacb71SRafael J. Wysocki result = acpi_power_transition(device, ACPI_STATE_D0); 24320dacb71SRafael J. Wysocki if (result) 24420dacb71SRafael J. Wysocki goto end; 24520dacb71SRafael J. Wysocki } 246f850a48aSRafael J. Wysocki 24742787ed7SRafael J. Wysocki if (cur_state == ACPI_STATE_D0) { 248f850a48aSRafael J. Wysocki int psc; 249f850a48aSRafael J. Wysocki 250f850a48aSRafael J. Wysocki /* Nothing to do here if _PSC is not present. */ 251f850a48aSRafael J. Wysocki if (!device->power.flags.explicit_get) 252f850a48aSRafael J. Wysocki return 0; 253f850a48aSRafael J. Wysocki 254f850a48aSRafael J. Wysocki /* 255f850a48aSRafael J. Wysocki * The power state of the device was set to D0 last 256f850a48aSRafael J. Wysocki * time, but that might have happened before a 257f850a48aSRafael J. Wysocki * system-wide transition involving the platform 258f850a48aSRafael J. Wysocki * firmware, so it may be necessary to evaluate _PS0 259f850a48aSRafael J. Wysocki * for the device here. However, use extra care here 260f850a48aSRafael J. Wysocki * and evaluate _PSC to check the device's current power 261f850a48aSRafael J. Wysocki * state, and only invoke _PS0 if the evaluation of _PSC 262f850a48aSRafael J. Wysocki * is successful and it returns a power state different 263f850a48aSRafael J. Wysocki * from D0. 264f850a48aSRafael J. Wysocki */ 265f850a48aSRafael J. Wysocki result = acpi_dev_pm_explicit_get(device, &psc); 266f850a48aSRafael J. Wysocki if (result || psc == ACPI_STATE_D0) 267f850a48aSRafael J. Wysocki return 0; 268f850a48aSRafael J. Wysocki } 269f850a48aSRafael J. Wysocki 27020dacb71SRafael J. Wysocki result = acpi_dev_pm_explicit_set(device, ACPI_STATE_D0); 271e5656271SRafael J. Wysocki } 2729ce4e607SRafael J. Wysocki 2739ce4e607SRafael J. Wysocki end: 274e78adb75SRafael J. Wysocki if (result) { 275b69137a7SRafael J. Wysocki dev_warn(&device->dev, "Failed to change power state to %s\n", 276*a9b760b0SKai-Heng Feng acpi_power_state_string(target_state)); 277e78adb75SRafael J. Wysocki } else { 27871b65445SMika Westerberg device->power.state = target_state; 2799ce4e607SRafael J. Wysocki ACPI_DEBUG_PRINT((ACPI_DB_INFO, 2809ce4e607SRafael J. Wysocki "Device [%s] transitioned to %s\n", 2819ce4e607SRafael J. Wysocki device->pnp.bus_id, 282*a9b760b0SKai-Heng Feng acpi_power_state_string(target_state))); 2839ce4e607SRafael J. Wysocki } 2849ce4e607SRafael J. Wysocki 2859ce4e607SRafael J. Wysocki return result; 2869ce4e607SRafael J. Wysocki } 2879ce4e607SRafael J. Wysocki EXPORT_SYMBOL(acpi_device_set_power); 2889ce4e607SRafael J. Wysocki 2899ce4e607SRafael J. Wysocki int acpi_bus_set_power(acpi_handle handle, int state) 2909ce4e607SRafael J. Wysocki { 2919ce4e607SRafael J. Wysocki struct acpi_device *device; 2929ce4e607SRafael J. Wysocki int result; 2939ce4e607SRafael J. Wysocki 2949ce4e607SRafael J. Wysocki result = acpi_bus_get_device(handle, &device); 2959ce4e607SRafael J. Wysocki if (result) 2969ce4e607SRafael J. Wysocki return result; 2979ce4e607SRafael J. Wysocki 2989ce4e607SRafael J. Wysocki return acpi_device_set_power(device, state); 2999ce4e607SRafael J. Wysocki } 3009ce4e607SRafael J. Wysocki EXPORT_SYMBOL(acpi_bus_set_power); 3019ce4e607SRafael J. Wysocki 3029ce4e607SRafael J. Wysocki int acpi_bus_init_power(struct acpi_device *device) 3039ce4e607SRafael J. Wysocki { 3049ce4e607SRafael J. Wysocki int state; 3059ce4e607SRafael J. Wysocki int result; 3069ce4e607SRafael J. Wysocki 3079ce4e607SRafael J. Wysocki if (!device) 3089ce4e607SRafael J. Wysocki return -EINVAL; 3099ce4e607SRafael J. Wysocki 3109ce4e607SRafael J. Wysocki device->power.state = ACPI_STATE_UNKNOWN; 311cde1f95fSSakari Ailus if (!acpi_device_is_present(device)) { 312cde1f95fSSakari Ailus device->flags.initialized = false; 3131b1f3e16SRafael J. Wysocki return -ENXIO; 314cde1f95fSSakari Ailus } 3159ce4e607SRafael J. Wysocki 3169ce4e607SRafael J. Wysocki result = acpi_device_get_power(device, &state); 3179ce4e607SRafael J. Wysocki if (result) 3189ce4e607SRafael J. Wysocki return result; 3199ce4e607SRafael J. Wysocki 320a2367807SRafael J. Wysocki if (state < ACPI_STATE_D3_COLD && device->power.flags.power_resources) { 32120dacb71SRafael J. Wysocki /* Reference count the power resources. */ 3229ce4e607SRafael J. Wysocki result = acpi_power_on_resources(device, state); 323a2367807SRafael J. Wysocki if (result) 3249ce4e607SRafael J. Wysocki return result; 325a2367807SRafael J. Wysocki 32620dacb71SRafael J. Wysocki if (state == ACPI_STATE_D0) { 32720dacb71SRafael J. Wysocki /* 32820dacb71SRafael J. Wysocki * If _PSC is not present and the state inferred from 32920dacb71SRafael J. Wysocki * power resources appears to be D0, it still may be 33020dacb71SRafael J. Wysocki * necessary to execute _PS0 at this point, because 33120dacb71SRafael J. Wysocki * another device using the same power resources may 33220dacb71SRafael J. Wysocki * have been put into D0 previously and that's why we 33320dacb71SRafael J. Wysocki * see D0 here. 33420dacb71SRafael J. Wysocki */ 3359c0f45e3SRafael J. Wysocki result = acpi_dev_pm_explicit_set(device, state); 3369c0f45e3SRafael J. Wysocki if (result) 3379c0f45e3SRafael J. Wysocki return result; 33820dacb71SRafael J. Wysocki } 339b3785492SRafael J. Wysocki } else if (state == ACPI_STATE_UNKNOWN) { 3407cd8407dSRafael J. Wysocki /* 3417cd8407dSRafael J. Wysocki * No power resources and missing _PSC? Cross fingers and make 3427cd8407dSRafael J. Wysocki * it D0 in hope that this is what the BIOS put the device into. 3437cd8407dSRafael J. Wysocki * [We tried to force D0 here by executing _PS0, but that broke 3447cd8407dSRafael J. Wysocki * Toshiba P870-303 in a nasty way.] 3457cd8407dSRafael J. Wysocki */ 346b3785492SRafael J. Wysocki state = ACPI_STATE_D0; 347a2367807SRafael J. Wysocki } 348a2367807SRafael J. Wysocki device->power.state = state; 349a2367807SRafael J. Wysocki return 0; 3509ce4e607SRafael J. Wysocki } 3519ce4e607SRafael J. Wysocki 352b9e95fc6SRafael J. Wysocki /** 353b9e95fc6SRafael J. Wysocki * acpi_device_fix_up_power - Force device with missing _PSC into D0. 354b9e95fc6SRafael J. Wysocki * @device: Device object whose power state is to be fixed up. 355b9e95fc6SRafael J. Wysocki * 356b9e95fc6SRafael J. Wysocki * Devices without power resources and _PSC, but having _PS0 and _PS3 defined, 357b9e95fc6SRafael J. Wysocki * are assumed to be put into D0 by the BIOS. However, in some cases that may 358b9e95fc6SRafael J. Wysocki * not be the case and this function should be used then. 359b9e95fc6SRafael J. Wysocki */ 360b9e95fc6SRafael J. Wysocki int acpi_device_fix_up_power(struct acpi_device *device) 361b9e95fc6SRafael J. Wysocki { 362b9e95fc6SRafael J. Wysocki int ret = 0; 363b9e95fc6SRafael J. Wysocki 364b9e95fc6SRafael J. Wysocki if (!device->power.flags.power_resources 365b9e95fc6SRafael J. Wysocki && !device->power.flags.explicit_get 366b9e95fc6SRafael J. Wysocki && device->power.state == ACPI_STATE_D0) 367b9e95fc6SRafael J. Wysocki ret = acpi_dev_pm_explicit_set(device, ACPI_STATE_D0); 368b9e95fc6SRafael J. Wysocki 369b9e95fc6SRafael J. Wysocki return ret; 370b9e95fc6SRafael J. Wysocki } 37178a898d0SUlf Hansson EXPORT_SYMBOL_GPL(acpi_device_fix_up_power); 372b9e95fc6SRafael J. Wysocki 373202317a5SRafael J. Wysocki int acpi_device_update_power(struct acpi_device *device, int *state_p) 3749ce4e607SRafael J. Wysocki { 3759ce4e607SRafael J. Wysocki int state; 3769ce4e607SRafael J. Wysocki int result; 3779ce4e607SRafael J. Wysocki 378202317a5SRafael J. Wysocki if (device->power.state == ACPI_STATE_UNKNOWN) { 379202317a5SRafael J. Wysocki result = acpi_bus_init_power(device); 380202317a5SRafael J. Wysocki if (!result && state_p) 381202317a5SRafael J. Wysocki *state_p = device->power.state; 382202317a5SRafael J. Wysocki 3839ce4e607SRafael J. Wysocki return result; 384202317a5SRafael J. Wysocki } 3859ce4e607SRafael J. Wysocki 3869ce4e607SRafael J. Wysocki result = acpi_device_get_power(device, &state); 3879ce4e607SRafael J. Wysocki if (result) 3889ce4e607SRafael J. Wysocki return result; 3899ce4e607SRafael J. Wysocki 39091bdad0bSRafael J. Wysocki if (state == ACPI_STATE_UNKNOWN) { 391511d5c42SRafael J. Wysocki state = ACPI_STATE_D0; 3929ce4e607SRafael J. Wysocki result = acpi_device_set_power(device, state); 39391bdad0bSRafael J. Wysocki if (result) 39491bdad0bSRafael J. Wysocki return result; 39591bdad0bSRafael J. Wysocki } else { 39691bdad0bSRafael J. Wysocki if (device->power.flags.power_resources) { 39791bdad0bSRafael J. Wysocki /* 39891bdad0bSRafael J. Wysocki * We don't need to really switch the state, bu we need 39991bdad0bSRafael J. Wysocki * to update the power resources' reference counters. 40091bdad0bSRafael J. Wysocki */ 40191bdad0bSRafael J. Wysocki result = acpi_power_transition(device, state); 40291bdad0bSRafael J. Wysocki if (result) 40391bdad0bSRafael J. Wysocki return result; 40491bdad0bSRafael J. Wysocki } 40591bdad0bSRafael J. Wysocki device->power.state = state; 40691bdad0bSRafael J. Wysocki } 40791bdad0bSRafael J. Wysocki if (state_p) 4089ce4e607SRafael J. Wysocki *state_p = state; 4099ce4e607SRafael J. Wysocki 41091bdad0bSRafael J. Wysocki return 0; 4119ce4e607SRafael J. Wysocki } 4122bb3a2bfSAaron Lu EXPORT_SYMBOL_GPL(acpi_device_update_power); 413202317a5SRafael J. Wysocki 414202317a5SRafael J. Wysocki int acpi_bus_update_power(acpi_handle handle, int *state_p) 415202317a5SRafael J. Wysocki { 416202317a5SRafael J. Wysocki struct acpi_device *device; 417202317a5SRafael J. Wysocki int result; 418202317a5SRafael J. Wysocki 419202317a5SRafael J. Wysocki result = acpi_bus_get_device(handle, &device); 420202317a5SRafael J. Wysocki return result ? result : acpi_device_update_power(device, state_p); 421202317a5SRafael J. Wysocki } 4229ce4e607SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_bus_update_power); 4239ce4e607SRafael J. Wysocki 4249ce4e607SRafael J. Wysocki bool acpi_bus_power_manageable(acpi_handle handle) 4259ce4e607SRafael J. Wysocki { 4269ce4e607SRafael J. Wysocki struct acpi_device *device; 4279ce4e607SRafael J. Wysocki int result; 4289ce4e607SRafael J. Wysocki 4299ce4e607SRafael J. Wysocki result = acpi_bus_get_device(handle, &device); 4309ce4e607SRafael J. Wysocki return result ? false : device->flags.power_manageable; 4319ce4e607SRafael J. Wysocki } 4329ce4e607SRafael J. Wysocki EXPORT_SYMBOL(acpi_bus_power_manageable); 4339ce4e607SRafael J. Wysocki 434ec4602a9SRafael J. Wysocki #ifdef CONFIG_PM 435ec4602a9SRafael J. Wysocki static DEFINE_MUTEX(acpi_pm_notifier_lock); 436ff165679SVille Syrjälä static DEFINE_MUTEX(acpi_pm_notifier_install_lock); 437ec4602a9SRafael J. Wysocki 43833e4f80eSRafael J. Wysocki void acpi_pm_wakeup_event(struct device *dev) 43933e4f80eSRafael J. Wysocki { 44033e4f80eSRafael J. Wysocki pm_wakeup_dev_event(dev, 0, acpi_s2idle_wakeup()); 44133e4f80eSRafael J. Wysocki } 44233e4f80eSRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_pm_wakeup_event); 44333e4f80eSRafael J. Wysocki 444c072530fSRafael J. Wysocki static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) 445c072530fSRafael J. Wysocki { 446c072530fSRafael J. Wysocki struct acpi_device *adev; 447c072530fSRafael J. Wysocki 448c072530fSRafael J. Wysocki if (val != ACPI_NOTIFY_DEVICE_WAKE) 449c072530fSRafael J. Wysocki return; 450c072530fSRafael J. Wysocki 451020a6375SRafael J. Wysocki acpi_handle_debug(handle, "Wake notify\n"); 452020a6375SRafael J. Wysocki 453c072530fSRafael J. Wysocki adev = acpi_bus_get_acpi_device(handle); 454c072530fSRafael J. Wysocki if (!adev) 455c072530fSRafael J. Wysocki return; 456c072530fSRafael J. Wysocki 457c072530fSRafael J. Wysocki mutex_lock(&acpi_pm_notifier_lock); 458c072530fSRafael J. Wysocki 459c072530fSRafael J. Wysocki if (adev->wakeup.flags.notifier_present) { 46033e4f80eSRafael J. Wysocki pm_wakeup_ws_event(adev->wakeup.ws, 0, acpi_s2idle_wakeup()); 461020a6375SRafael J. Wysocki if (adev->wakeup.context.func) { 462d75f773cSSakari Ailus acpi_handle_debug(handle, "Running %pS for %s\n", 463020a6375SRafael J. Wysocki adev->wakeup.context.func, 464020a6375SRafael J. Wysocki dev_name(adev->wakeup.context.dev)); 46564fd1c70SRafael J. Wysocki adev->wakeup.context.func(&adev->wakeup.context); 466c072530fSRafael J. Wysocki } 467020a6375SRafael J. Wysocki } 468c072530fSRafael J. Wysocki 469c072530fSRafael J. Wysocki mutex_unlock(&acpi_pm_notifier_lock); 470c072530fSRafael J. Wysocki 471c072530fSRafael J. Wysocki acpi_bus_put_acpi_device(adev); 472c072530fSRafael J. Wysocki } 473c072530fSRafael J. Wysocki 474ec4602a9SRafael J. Wysocki /** 475c072530fSRafael J. Wysocki * acpi_add_pm_notifier - Register PM notify handler for given ACPI device. 476c072530fSRafael J. Wysocki * @adev: ACPI device to add the notify handler for. 477c072530fSRafael J. Wysocki * @dev: Device to generate a wakeup event for while handling the notification. 47864fd1c70SRafael J. Wysocki * @func: Work function to execute when handling the notification. 479ec4602a9SRafael J. Wysocki * 480ec4602a9SRafael J. Wysocki * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of 481ec4602a9SRafael J. Wysocki * PM wakeup events. For example, wakeup events may be generated for bridges 482ec4602a9SRafael J. Wysocki * if one of the devices below the bridge is signaling wakeup, even if the 483ec4602a9SRafael J. Wysocki * bridge itself doesn't have a wakeup GPE associated with it. 484ec4602a9SRafael J. Wysocki */ 485c072530fSRafael J. Wysocki acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, 48664fd1c70SRafael J. Wysocki void (*func)(struct acpi_device_wakeup_context *context)) 487ec4602a9SRafael J. Wysocki { 488ec4602a9SRafael J. Wysocki acpi_status status = AE_ALREADY_EXISTS; 489ec4602a9SRafael J. Wysocki 49064fd1c70SRafael J. Wysocki if (!dev && !func) 491c072530fSRafael J. Wysocki return AE_BAD_PARAMETER; 492c072530fSRafael J. Wysocki 493ff165679SVille Syrjälä mutex_lock(&acpi_pm_notifier_install_lock); 494ec4602a9SRafael J. Wysocki 495ec4602a9SRafael J. Wysocki if (adev->wakeup.flags.notifier_present) 496ec4602a9SRafael J. Wysocki goto out; 497ec4602a9SRafael J. Wysocki 498c072530fSRafael J. Wysocki status = acpi_install_notify_handler(adev->handle, ACPI_SYSTEM_NOTIFY, 499c072530fSRafael J. Wysocki acpi_pm_notify_handler, NULL); 500ec4602a9SRafael J. Wysocki if (ACPI_FAILURE(status)) 501ec4602a9SRafael J. Wysocki goto out; 502ec4602a9SRafael J. Wysocki 503ff165679SVille Syrjälä mutex_lock(&acpi_pm_notifier_lock); 504c8377adfSTri Vo adev->wakeup.ws = wakeup_source_register(&adev->dev, 505c8377adfSTri Vo dev_name(&adev->dev)); 506ff165679SVille Syrjälä adev->wakeup.context.dev = dev; 507ff165679SVille Syrjälä adev->wakeup.context.func = func; 508ec4602a9SRafael J. Wysocki adev->wakeup.flags.notifier_present = true; 509ff165679SVille Syrjälä mutex_unlock(&acpi_pm_notifier_lock); 510ec4602a9SRafael J. Wysocki 511ec4602a9SRafael J. Wysocki out: 512ff165679SVille Syrjälä mutex_unlock(&acpi_pm_notifier_install_lock); 513ec4602a9SRafael J. Wysocki return status; 514ec4602a9SRafael J. Wysocki } 515ec4602a9SRafael J. Wysocki 516ec4602a9SRafael J. Wysocki /** 517ec4602a9SRafael J. Wysocki * acpi_remove_pm_notifier - Unregister PM notifier from given ACPI device. 518ec4602a9SRafael J. Wysocki * @adev: ACPI device to remove the notifier from. 519ec4602a9SRafael J. Wysocki */ 520c072530fSRafael J. Wysocki acpi_status acpi_remove_pm_notifier(struct acpi_device *adev) 521ec4602a9SRafael J. Wysocki { 522ec4602a9SRafael J. Wysocki acpi_status status = AE_BAD_PARAMETER; 523ec4602a9SRafael J. Wysocki 524ff165679SVille Syrjälä mutex_lock(&acpi_pm_notifier_install_lock); 525ec4602a9SRafael J. Wysocki 526ec4602a9SRafael J. Wysocki if (!adev->wakeup.flags.notifier_present) 527ec4602a9SRafael J. Wysocki goto out; 528ec4602a9SRafael J. Wysocki 529ec4602a9SRafael J. Wysocki status = acpi_remove_notify_handler(adev->handle, 530ec4602a9SRafael J. Wysocki ACPI_SYSTEM_NOTIFY, 531c072530fSRafael J. Wysocki acpi_pm_notify_handler); 532ec4602a9SRafael J. Wysocki if (ACPI_FAILURE(status)) 533ec4602a9SRafael J. Wysocki goto out; 534ec4602a9SRafael J. Wysocki 535ff165679SVille Syrjälä mutex_lock(&acpi_pm_notifier_lock); 53664fd1c70SRafael J. Wysocki adev->wakeup.context.func = NULL; 537c072530fSRafael J. Wysocki adev->wakeup.context.dev = NULL; 538c072530fSRafael J. Wysocki wakeup_source_unregister(adev->wakeup.ws); 539ec4602a9SRafael J. Wysocki adev->wakeup.flags.notifier_present = false; 540ff165679SVille Syrjälä mutex_unlock(&acpi_pm_notifier_lock); 541ec4602a9SRafael J. Wysocki 542ec4602a9SRafael J. Wysocki out: 543ff165679SVille Syrjälä mutex_unlock(&acpi_pm_notifier_install_lock); 544ec4602a9SRafael J. Wysocki return status; 545ec4602a9SRafael J. Wysocki } 546ec4602a9SRafael J. Wysocki 5479ce4e607SRafael J. Wysocki bool acpi_bus_can_wakeup(acpi_handle handle) 5489ce4e607SRafael J. Wysocki { 5499ce4e607SRafael J. Wysocki struct acpi_device *device; 5509ce4e607SRafael J. Wysocki int result; 5519ce4e607SRafael J. Wysocki 5529ce4e607SRafael J. Wysocki result = acpi_bus_get_device(handle, &device); 5539ce4e607SRafael J. Wysocki return result ? false : device->wakeup.flags.valid; 5549ce4e607SRafael J. Wysocki } 5559ce4e607SRafael J. Wysocki EXPORT_SYMBOL(acpi_bus_can_wakeup); 5569ce4e607SRafael J. Wysocki 5578370c2dcSRafael J. Wysocki bool acpi_pm_device_can_wakeup(struct device *dev) 5588370c2dcSRafael J. Wysocki { 5598370c2dcSRafael J. Wysocki struct acpi_device *adev = ACPI_COMPANION(dev); 5608370c2dcSRafael J. Wysocki 5618370c2dcSRafael J. Wysocki return adev ? acpi_device_can_wakeup(adev) : false; 5628370c2dcSRafael J. Wysocki } 5638370c2dcSRafael J. Wysocki 5649ce4e607SRafael J. Wysocki /** 565b25c77efSRafael J. Wysocki * acpi_dev_pm_get_state - Get preferred power state of ACPI device. 56686b3832cSRafael J. Wysocki * @dev: Device whose preferred target power state to return. 56786b3832cSRafael J. Wysocki * @adev: ACPI device node corresponding to @dev. 56886b3832cSRafael J. Wysocki * @target_state: System state to match the resultant device state. 569fa1675b5SRafael J. Wysocki * @d_min_p: Location to store the highest power state available to the device. 570fa1675b5SRafael J. Wysocki * @d_max_p: Location to store the lowest power state available to the device. 57186b3832cSRafael J. Wysocki * 572fa1675b5SRafael J. Wysocki * Find the lowest power (highest number) and highest power (lowest number) ACPI 573fa1675b5SRafael J. Wysocki * device power states that the device can be in while the system is in the 574fa1675b5SRafael J. Wysocki * state represented by @target_state. Store the integer numbers representing 575fa1675b5SRafael J. Wysocki * those stats in the memory locations pointed to by @d_max_p and @d_min_p, 576fa1675b5SRafael J. Wysocki * respectively. 57786b3832cSRafael J. Wysocki * 57886b3832cSRafael J. Wysocki * Callers must ensure that @dev and @adev are valid pointers and that @adev 57986b3832cSRafael J. Wysocki * actually corresponds to @dev before using this function. 580fa1675b5SRafael J. Wysocki * 581fa1675b5SRafael J. Wysocki * Returns 0 on success or -ENODATA when one of the ACPI methods fails or 582fa1675b5SRafael J. Wysocki * returns a value that doesn't make sense. The memory locations pointed to by 583fa1675b5SRafael J. Wysocki * @d_max_p and @d_min_p are only modified on success. 58486b3832cSRafael J. Wysocki */ 585b25c77efSRafael J. Wysocki static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev, 586fa1675b5SRafael J. Wysocki u32 target_state, int *d_min_p, int *d_max_p) 58786b3832cSRafael J. Wysocki { 588fa1675b5SRafael J. Wysocki char method[] = { '_', 'S', '0' + target_state, 'D', '\0' }; 589fa1675b5SRafael J. Wysocki acpi_handle handle = adev->handle; 590fa1675b5SRafael J. Wysocki unsigned long long ret; 591fa1675b5SRafael J. Wysocki int d_min, d_max; 59286b3832cSRafael J. Wysocki bool wakeup = false; 593bf8c6184SDaniel Drake bool has_sxd = false; 594fa1675b5SRafael J. Wysocki acpi_status status; 59586b3832cSRafael J. Wysocki 59686b3832cSRafael J. Wysocki /* 597fa1675b5SRafael J. Wysocki * If the system state is S0, the lowest power state the device can be 598fa1675b5SRafael J. Wysocki * in is D3cold, unless the device has _S0W and is supposed to signal 599fa1675b5SRafael J. Wysocki * wakeup, in which case the return value of _S0W has to be used as the 600fa1675b5SRafael J. Wysocki * lowest power state available to the device. 60186b3832cSRafael J. Wysocki */ 60286b3832cSRafael J. Wysocki d_min = ACPI_STATE_D0; 6034c164ae7SRafael J. Wysocki d_max = ACPI_STATE_D3_COLD; 60486b3832cSRafael J. Wysocki 60586b3832cSRafael J. Wysocki /* 60686b3832cSRafael J. Wysocki * If present, _SxD methods return the minimum D-state (highest power 60786b3832cSRafael J. Wysocki * state) we can use for the corresponding S-states. Otherwise, the 60886b3832cSRafael J. Wysocki * minimum D-state is D0 (ACPI 3.x). 60986b3832cSRafael J. Wysocki */ 61086b3832cSRafael J. Wysocki if (target_state > ACPI_STATE_S0) { 611fa1675b5SRafael J. Wysocki /* 612fa1675b5SRafael J. Wysocki * We rely on acpi_evaluate_integer() not clobbering the integer 613fa1675b5SRafael J. Wysocki * provided if AE_NOT_FOUND is returned. 614fa1675b5SRafael J. Wysocki */ 615fa1675b5SRafael J. Wysocki ret = d_min; 616fa1675b5SRafael J. Wysocki status = acpi_evaluate_integer(handle, method, NULL, &ret); 617fa1675b5SRafael J. Wysocki if ((ACPI_FAILURE(status) && status != AE_NOT_FOUND) 618fa1675b5SRafael J. Wysocki || ret > ACPI_STATE_D3_COLD) 619fa1675b5SRafael J. Wysocki return -ENODATA; 620fa1675b5SRafael J. Wysocki 621fa1675b5SRafael J. Wysocki /* 622fa1675b5SRafael J. Wysocki * We need to handle legacy systems where D3hot and D3cold are 623fa1675b5SRafael J. Wysocki * the same and 3 is returned in both cases, so fall back to 624fa1675b5SRafael J. Wysocki * D3cold if D3hot is not a valid state. 625fa1675b5SRafael J. Wysocki */ 626fa1675b5SRafael J. Wysocki if (!adev->power.states[ret].flags.valid) { 627fa1675b5SRafael J. Wysocki if (ret == ACPI_STATE_D3_HOT) 628fa1675b5SRafael J. Wysocki ret = ACPI_STATE_D3_COLD; 629fa1675b5SRafael J. Wysocki else 630fa1675b5SRafael J. Wysocki return -ENODATA; 631fa1675b5SRafael J. Wysocki } 632bf8c6184SDaniel Drake 633bf8c6184SDaniel Drake if (status == AE_OK) 634bf8c6184SDaniel Drake has_sxd = true; 635bf8c6184SDaniel Drake 636fa1675b5SRafael J. Wysocki d_min = ret; 63786b3832cSRafael J. Wysocki wakeup = device_may_wakeup(dev) && adev->wakeup.flags.valid 63886b3832cSRafael J. Wysocki && adev->wakeup.sleep_state >= target_state; 63920f97cafSRafael J. Wysocki } else { 64086b3832cSRafael J. Wysocki wakeup = adev->wakeup.flags.valid; 64186b3832cSRafael J. Wysocki } 64286b3832cSRafael J. Wysocki 64386b3832cSRafael J. Wysocki /* 64486b3832cSRafael J. Wysocki * If _PRW says we can wake up the system from the target sleep state, 64586b3832cSRafael J. Wysocki * the D-state returned by _SxD is sufficient for that (we assume a 64686b3832cSRafael J. Wysocki * wakeup-aware driver if wake is set). Still, if _SxW exists 64786b3832cSRafael J. Wysocki * (ACPI 3.x), it should return the maximum (lowest power) D-state that 64886b3832cSRafael J. Wysocki * can wake the system. _S0W may be valid, too. 64986b3832cSRafael J. Wysocki */ 65086b3832cSRafael J. Wysocki if (wakeup) { 651fa1675b5SRafael J. Wysocki method[3] = 'W'; 652fa1675b5SRafael J. Wysocki status = acpi_evaluate_integer(handle, method, NULL, &ret); 653fa1675b5SRafael J. Wysocki if (status == AE_NOT_FOUND) { 654bf8c6184SDaniel Drake /* No _SxW. In this case, the ACPI spec says that we 655bf8c6184SDaniel Drake * must not go into any power state deeper than the 656bf8c6184SDaniel Drake * value returned from _SxD. 657bf8c6184SDaniel Drake */ 658bf8c6184SDaniel Drake if (has_sxd && target_state > ACPI_STATE_S0) 65986b3832cSRafael J. Wysocki d_max = d_min; 660fa1675b5SRafael J. Wysocki } else if (ACPI_SUCCESS(status) && ret <= ACPI_STATE_D3_COLD) { 661fa1675b5SRafael J. Wysocki /* Fall back to D3cold if ret is not a valid state. */ 662fa1675b5SRafael J. Wysocki if (!adev->power.states[ret].flags.valid) 663fa1675b5SRafael J. Wysocki ret = ACPI_STATE_D3_COLD; 664fa1675b5SRafael J. Wysocki 665fa1675b5SRafael J. Wysocki d_max = ret > d_min ? ret : d_min; 666fa1675b5SRafael J. Wysocki } else { 667fa1675b5SRafael J. Wysocki return -ENODATA; 66886b3832cSRafael J. Wysocki } 66986b3832cSRafael J. Wysocki } 67086b3832cSRafael J. Wysocki 67186b3832cSRafael J. Wysocki if (d_min_p) 67286b3832cSRafael J. Wysocki *d_min_p = d_min; 673fa1675b5SRafael J. Wysocki 674fa1675b5SRafael J. Wysocki if (d_max_p) 675fa1675b5SRafael J. Wysocki *d_max_p = d_max; 676fa1675b5SRafael J. Wysocki 677fa1675b5SRafael J. Wysocki return 0; 67886b3832cSRafael J. Wysocki } 679cd7bd02dSRafael J. Wysocki 680a6ae7594SRafael J. Wysocki /** 681a6ae7594SRafael J. Wysocki * acpi_pm_device_sleep_state - Get preferred power state of ACPI device. 682a6ae7594SRafael J. Wysocki * @dev: Device whose preferred target power state to return. 683a6ae7594SRafael J. Wysocki * @d_min_p: Location to store the upper limit of the allowed states range. 684a6ae7594SRafael J. Wysocki * @d_max_in: Deepest low-power state to take into consideration. 685a6ae7594SRafael J. Wysocki * Return value: Preferred power state of the device on success, -ENODEV 686fa1675b5SRafael J. Wysocki * if there's no 'struct acpi_device' for @dev, -EINVAL if @d_max_in is 687fa1675b5SRafael J. Wysocki * incorrect, or -ENODATA on ACPI method failure. 688a6ae7594SRafael J. Wysocki * 689a6ae7594SRafael J. Wysocki * The caller must ensure that @dev is valid before using this function. 690a6ae7594SRafael J. Wysocki */ 691a6ae7594SRafael J. Wysocki int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) 692a6ae7594SRafael J. Wysocki { 693a6ae7594SRafael J. Wysocki struct acpi_device *adev; 6949b5c7a5aSRafael J. Wysocki int ret, d_min, d_max; 695fa1675b5SRafael J. Wysocki 696fa1675b5SRafael J. Wysocki if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3_COLD) 697fa1675b5SRafael J. Wysocki return -EINVAL; 698fa1675b5SRafael J. Wysocki 69920dacb71SRafael J. Wysocki if (d_max_in > ACPI_STATE_D2) { 700fa1675b5SRafael J. Wysocki enum pm_qos_flags_status stat; 701fa1675b5SRafael J. Wysocki 702fa1675b5SRafael J. Wysocki stat = dev_pm_qos_flags(dev, PM_QOS_FLAG_NO_POWER_OFF); 703fa1675b5SRafael J. Wysocki if (stat == PM_QOS_FLAGS_ALL) 70420dacb71SRafael J. Wysocki d_max_in = ACPI_STATE_D2; 705fa1675b5SRafael J. Wysocki } 706a6ae7594SRafael J. Wysocki 70717653a3eSRafael J. Wysocki adev = ACPI_COMPANION(dev); 70817653a3eSRafael J. Wysocki if (!adev) { 70917653a3eSRafael J. Wysocki dev_dbg(dev, "ACPI companion missing in %s!\n", __func__); 710a6ae7594SRafael J. Wysocki return -ENODEV; 711a6ae7594SRafael J. Wysocki } 712a6ae7594SRafael J. Wysocki 713fa1675b5SRafael J. Wysocki ret = acpi_dev_pm_get_state(dev, adev, acpi_target_system_state(), 7149b5c7a5aSRafael J. Wysocki &d_min, &d_max); 715fa1675b5SRafael J. Wysocki if (ret) 716fa1675b5SRafael J. Wysocki return ret; 717fa1675b5SRafael J. Wysocki 7189b5c7a5aSRafael J. Wysocki if (d_max_in < d_min) 719fa1675b5SRafael J. Wysocki return -EINVAL; 720fa1675b5SRafael J. Wysocki 721fa1675b5SRafael J. Wysocki if (d_max > d_max_in) { 7229b5c7a5aSRafael J. Wysocki for (d_max = d_max_in; d_max > d_min; d_max--) { 723fa1675b5SRafael J. Wysocki if (adev->power.states[d_max].flags.valid) 724fa1675b5SRafael J. Wysocki break; 725fa1675b5SRafael J. Wysocki } 726fa1675b5SRafael J. Wysocki } 7279b5c7a5aSRafael J. Wysocki 7289b5c7a5aSRafael J. Wysocki if (d_min_p) 7299b5c7a5aSRafael J. Wysocki *d_min_p = d_min; 7309b5c7a5aSRafael J. Wysocki 731fa1675b5SRafael J. Wysocki return d_max; 732a6ae7594SRafael J. Wysocki } 733a6ae7594SRafael J. Wysocki EXPORT_SYMBOL(acpi_pm_device_sleep_state); 734a6ae7594SRafael J. Wysocki 735cd7bd02dSRafael J. Wysocki /** 736c072530fSRafael J. Wysocki * acpi_pm_notify_work_func - ACPI devices wakeup notification work function. 73764fd1c70SRafael J. Wysocki * @context: Device wakeup context. 738e5cc8ef3SRafael J. Wysocki */ 73964fd1c70SRafael J. Wysocki static void acpi_pm_notify_work_func(struct acpi_device_wakeup_context *context) 740e5cc8ef3SRafael J. Wysocki { 74164fd1c70SRafael J. Wysocki struct device *dev = context->dev; 742e5cc8ef3SRafael J. Wysocki 743c072530fSRafael J. Wysocki if (dev) { 744e5cc8ef3SRafael J. Wysocki pm_wakeup_event(dev, 0); 74564fd1c70SRafael J. Wysocki pm_request_resume(dev); 746e5cc8ef3SRafael J. Wysocki } 747e5cc8ef3SRafael J. Wysocki } 748e5cc8ef3SRafael J. Wysocki 74999d8845eSRafael J. Wysocki static DEFINE_MUTEX(acpi_wakeup_lock); 75099d8845eSRafael J. Wysocki 7511ba51a7cSRafael J. Wysocki static int __acpi_device_wakeup_enable(struct acpi_device *adev, 7521ba51a7cSRafael J. Wysocki u32 target_state, int max_count) 7531ba51a7cSRafael J. Wysocki { 7541ba51a7cSRafael J. Wysocki struct acpi_device_wakeup *wakeup = &adev->wakeup; 7551ba51a7cSRafael J. Wysocki acpi_status status; 7561ba51a7cSRafael J. Wysocki int error = 0; 7571ba51a7cSRafael J. Wysocki 7581ba51a7cSRafael J. Wysocki mutex_lock(&acpi_wakeup_lock); 7591ba51a7cSRafael J. Wysocki 7601ba51a7cSRafael J. Wysocki if (wakeup->enable_count >= max_count) 7611ba51a7cSRafael J. Wysocki goto out; 7621ba51a7cSRafael J. Wysocki 7631ba51a7cSRafael J. Wysocki if (wakeup->enable_count > 0) 7641ba51a7cSRafael J. Wysocki goto inc; 7651ba51a7cSRafael J. Wysocki 7661ba51a7cSRafael J. Wysocki error = acpi_enable_wakeup_device_power(adev, target_state); 7671ba51a7cSRafael J. Wysocki if (error) 7681ba51a7cSRafael J. Wysocki goto out; 7691ba51a7cSRafael J. Wysocki 7701ba51a7cSRafael J. Wysocki status = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number); 7711ba51a7cSRafael J. Wysocki if (ACPI_FAILURE(status)) { 7721ba51a7cSRafael J. Wysocki acpi_disable_wakeup_device_power(adev); 7731ba51a7cSRafael J. Wysocki error = -EIO; 7741ba51a7cSRafael J. Wysocki goto out; 7751ba51a7cSRafael J. Wysocki } 7761ba51a7cSRafael J. Wysocki 777fbc9418fSRafael J. Wysocki acpi_handle_debug(adev->handle, "GPE%2X enabled for wakeup\n", 778fbc9418fSRafael J. Wysocki (unsigned int)wakeup->gpe_number); 779fbc9418fSRafael J. Wysocki 7801ba51a7cSRafael J. Wysocki inc: 7811ba51a7cSRafael J. Wysocki wakeup->enable_count++; 7821ba51a7cSRafael J. Wysocki 7831ba51a7cSRafael J. Wysocki out: 7841ba51a7cSRafael J. Wysocki mutex_unlock(&acpi_wakeup_lock); 7851ba51a7cSRafael J. Wysocki return error; 7861ba51a7cSRafael J. Wysocki } 7871ba51a7cSRafael J. Wysocki 788e5cc8ef3SRafael J. Wysocki /** 78999d8845eSRafael J. Wysocki * acpi_device_wakeup_enable - Enable wakeup functionality for device. 79099d8845eSRafael J. Wysocki * @adev: ACPI device to enable wakeup functionality for. 791f35cec25SRafael J. Wysocki * @target_state: State the system is transitioning into. 792cd7bd02dSRafael J. Wysocki * 79399d8845eSRafael J. Wysocki * Enable the GPE associated with @adev so that it can generate wakeup signals 79499d8845eSRafael J. Wysocki * for the device in response to external (remote) events and enable wakeup 79599d8845eSRafael J. Wysocki * power for it. 796dee8370cSRafael J. Wysocki * 797dee8370cSRafael J. Wysocki * Callers must ensure that @adev is a valid ACPI device node before executing 798dee8370cSRafael J. Wysocki * this function. 799dee8370cSRafael J. Wysocki */ 80099d8845eSRafael J. Wysocki static int acpi_device_wakeup_enable(struct acpi_device *adev, u32 target_state) 801dee8370cSRafael J. Wysocki { 8021ba51a7cSRafael J. Wysocki return __acpi_device_wakeup_enable(adev, target_state, 1); 80399d8845eSRafael J. Wysocki } 80499d8845eSRafael J. Wysocki 80599d8845eSRafael J. Wysocki /** 80699d8845eSRafael J. Wysocki * acpi_device_wakeup_disable - Disable wakeup functionality for device. 80799d8845eSRafael J. Wysocki * @adev: ACPI device to disable wakeup functionality for. 80899d8845eSRafael J. Wysocki * 80999d8845eSRafael J. Wysocki * Disable the GPE associated with @adev and disable wakeup power for it. 81099d8845eSRafael J. Wysocki * 81199d8845eSRafael J. Wysocki * Callers must ensure that @adev is a valid ACPI device node before executing 81299d8845eSRafael J. Wysocki * this function. 81399d8845eSRafael J. Wysocki */ 81499d8845eSRafael J. Wysocki static void acpi_device_wakeup_disable(struct acpi_device *adev) 81599d8845eSRafael J. Wysocki { 81699d8845eSRafael J. Wysocki struct acpi_device_wakeup *wakeup = &adev->wakeup; 81799d8845eSRafael J. Wysocki 81899d8845eSRafael J. Wysocki mutex_lock(&acpi_wakeup_lock); 81999d8845eSRafael J. Wysocki 82099d8845eSRafael J. Wysocki if (!wakeup->enable_count) 82199d8845eSRafael J. Wysocki goto out; 82299d8845eSRafael J. Wysocki 823dee8370cSRafael J. Wysocki acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number); 824dee8370cSRafael J. Wysocki acpi_disable_wakeup_device_power(adev); 82599d8845eSRafael J. Wysocki 82699d8845eSRafael J. Wysocki wakeup->enable_count--; 82799d8845eSRafael J. Wysocki 82899d8845eSRafael J. Wysocki out: 82999d8845eSRafael J. Wysocki mutex_unlock(&acpi_wakeup_lock); 830dee8370cSRafael J. Wysocki } 831dee8370cSRafael J. Wysocki 8321ba51a7cSRafael J. Wysocki static int __acpi_pm_set_device_wakeup(struct device *dev, bool enable, 8331ba51a7cSRafael J. Wysocki int max_count) 834a6ae7594SRafael J. Wysocki { 835a6ae7594SRafael J. Wysocki struct acpi_device *adev; 836a6ae7594SRafael J. Wysocki int error; 837a6ae7594SRafael J. Wysocki 83817653a3eSRafael J. Wysocki adev = ACPI_COMPANION(dev); 83917653a3eSRafael J. Wysocki if (!adev) { 84017653a3eSRafael J. Wysocki dev_dbg(dev, "ACPI companion missing in %s!\n", __func__); 841a6ae7594SRafael J. Wysocki return -ENODEV; 842a6ae7594SRafael J. Wysocki } 843a6ae7594SRafael J. Wysocki 8444d183d04SRafael J. Wysocki if (!acpi_device_can_wakeup(adev)) 8454d183d04SRafael J. Wysocki return -EINVAL; 8464d183d04SRafael J. Wysocki 84799d8845eSRafael J. Wysocki if (!enable) { 84899d8845eSRafael J. Wysocki acpi_device_wakeup_disable(adev); 84999d8845eSRafael J. Wysocki dev_dbg(dev, "Wakeup disabled by ACPI\n"); 85099d8845eSRafael J. Wysocki return 0; 85199d8845eSRafael J. Wysocki } 85299d8845eSRafael J. Wysocki 8531ba51a7cSRafael J. Wysocki error = __acpi_device_wakeup_enable(adev, acpi_target_system_state(), 8541ba51a7cSRafael J. Wysocki max_count); 855a6ae7594SRafael J. Wysocki if (!error) 85699d8845eSRafael J. Wysocki dev_dbg(dev, "Wakeup enabled by ACPI\n"); 857a6ae7594SRafael J. Wysocki 858a6ae7594SRafael J. Wysocki return error; 859a6ae7594SRafael J. Wysocki } 8601ba51a7cSRafael J. Wysocki 8611ba51a7cSRafael J. Wysocki /** 8621ba51a7cSRafael J. Wysocki * acpi_pm_set_device_wakeup - Enable/disable remote wakeup for given device. 8631ba51a7cSRafael J. Wysocki * @dev: Device to enable/disable to generate wakeup events. 8641ba51a7cSRafael J. Wysocki * @enable: Whether to enable or disable the wakeup functionality. 8651ba51a7cSRafael J. Wysocki */ 8661ba51a7cSRafael J. Wysocki int acpi_pm_set_device_wakeup(struct device *dev, bool enable) 8671ba51a7cSRafael J. Wysocki { 8681ba51a7cSRafael J. Wysocki return __acpi_pm_set_device_wakeup(dev, enable, 1); 8691ba51a7cSRafael J. Wysocki } 8701ba51a7cSRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_pm_set_device_wakeup); 8711ba51a7cSRafael J. Wysocki 8721ba51a7cSRafael J. Wysocki /** 8731ba51a7cSRafael J. Wysocki * acpi_pm_set_bridge_wakeup - Enable/disable remote wakeup for given bridge. 8741ba51a7cSRafael J. Wysocki * @dev: Bridge device to enable/disable to generate wakeup events. 8751ba51a7cSRafael J. Wysocki * @enable: Whether to enable or disable the wakeup functionality. 8761ba51a7cSRafael J. Wysocki */ 8771ba51a7cSRafael J. Wysocki int acpi_pm_set_bridge_wakeup(struct device *dev, bool enable) 8781ba51a7cSRafael J. Wysocki { 8791ba51a7cSRafael J. Wysocki return __acpi_pm_set_device_wakeup(dev, enable, INT_MAX); 8801ba51a7cSRafael J. Wysocki } 8811ba51a7cSRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_pm_set_bridge_wakeup); 882e5cc8ef3SRafael J. Wysocki 883e5cc8ef3SRafael J. Wysocki /** 884e5cc8ef3SRafael J. Wysocki * acpi_dev_pm_low_power - Put ACPI device into a low-power state. 885e5cc8ef3SRafael J. Wysocki * @dev: Device to put into a low-power state. 886e5cc8ef3SRafael J. Wysocki * @adev: ACPI device node corresponding to @dev. 887e5cc8ef3SRafael J. Wysocki * @system_state: System state to choose the device state for. 888e5cc8ef3SRafael J. Wysocki */ 889e5cc8ef3SRafael J. Wysocki static int acpi_dev_pm_low_power(struct device *dev, struct acpi_device *adev, 890e5cc8ef3SRafael J. Wysocki u32 system_state) 891e5cc8ef3SRafael J. Wysocki { 892fa1675b5SRafael J. Wysocki int ret, state; 893e5cc8ef3SRafael J. Wysocki 894e5cc8ef3SRafael J. Wysocki if (!acpi_device_power_manageable(adev)) 895e5cc8ef3SRafael J. Wysocki return 0; 896e5cc8ef3SRafael J. Wysocki 897fa1675b5SRafael J. Wysocki ret = acpi_dev_pm_get_state(dev, adev, system_state, NULL, &state); 898fa1675b5SRafael J. Wysocki return ret ? ret : acpi_device_set_power(adev, state); 899e5cc8ef3SRafael J. Wysocki } 900e5cc8ef3SRafael J. Wysocki 901e5cc8ef3SRafael J. Wysocki /** 902e5cc8ef3SRafael J. Wysocki * acpi_dev_pm_full_power - Put ACPI device into the full-power state. 903e5cc8ef3SRafael J. Wysocki * @adev: ACPI device node to put into the full-power state. 904e5cc8ef3SRafael J. Wysocki */ 905e5cc8ef3SRafael J. Wysocki static int acpi_dev_pm_full_power(struct acpi_device *adev) 906e5cc8ef3SRafael J. Wysocki { 907e5cc8ef3SRafael J. Wysocki return acpi_device_power_manageable(adev) ? 908e5cc8ef3SRafael J. Wysocki acpi_device_set_power(adev, ACPI_STATE_D0) : 0; 909e5cc8ef3SRafael J. Wysocki } 910e5cc8ef3SRafael J. Wysocki 911e5cc8ef3SRafael J. Wysocki /** 912cbe25ce3SRafael J. Wysocki * acpi_dev_suspend - Put device into a low-power state using ACPI. 913e5cc8ef3SRafael J. Wysocki * @dev: Device to put into a low-power state. 914cbe25ce3SRafael J. Wysocki * @wakeup: Whether or not to enable wakeup for the device. 915e5cc8ef3SRafael J. Wysocki * 916cbe25ce3SRafael J. Wysocki * Put the given device into a low-power state using the standard ACPI 917e5cc8ef3SRafael J. Wysocki * mechanism. Set up remote wakeup if desired, choose the state to put the 918e5cc8ef3SRafael J. Wysocki * device into (this checks if remote wakeup is expected to work too), and set 919e5cc8ef3SRafael J. Wysocki * the power state of the device. 920e5cc8ef3SRafael J. Wysocki */ 921cbe25ce3SRafael J. Wysocki int acpi_dev_suspend(struct device *dev, bool wakeup) 922e5cc8ef3SRafael J. Wysocki { 92379c0373fSRafael J. Wysocki struct acpi_device *adev = ACPI_COMPANION(dev); 924cbe25ce3SRafael J. Wysocki u32 target_state = acpi_target_system_state(); 925e5cc8ef3SRafael J. Wysocki int error; 926e5cc8ef3SRafael J. Wysocki 927e5cc8ef3SRafael J. Wysocki if (!adev) 928e5cc8ef3SRafael J. Wysocki return 0; 929e5cc8ef3SRafael J. Wysocki 930cbe25ce3SRafael J. Wysocki if (wakeup && acpi_device_can_wakeup(adev)) { 931cbe25ce3SRafael J. Wysocki error = acpi_device_wakeup_enable(adev, target_state); 93299d8845eSRafael J. Wysocki if (error) 933e5cc8ef3SRafael J. Wysocki return -EAGAIN; 934cbe25ce3SRafael J. Wysocki } else { 935cbe25ce3SRafael J. Wysocki wakeup = false; 93699d8845eSRafael J. Wysocki } 937e5cc8ef3SRafael J. Wysocki 938cbe25ce3SRafael J. Wysocki error = acpi_dev_pm_low_power(dev, adev, target_state); 939cbe25ce3SRafael J. Wysocki if (error && wakeup) 94099d8845eSRafael J. Wysocki acpi_device_wakeup_disable(adev); 941e5cc8ef3SRafael J. Wysocki 942e5cc8ef3SRafael J. Wysocki return error; 943e5cc8ef3SRafael J. Wysocki } 944cbe25ce3SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_dev_suspend); 945e5cc8ef3SRafael J. Wysocki 946e5cc8ef3SRafael J. Wysocki /** 94763705c40SRafael J. Wysocki * acpi_dev_resume - Put device into the full-power state using ACPI. 948e5cc8ef3SRafael J. Wysocki * @dev: Device to put into the full-power state. 949e5cc8ef3SRafael J. Wysocki * 950e5cc8ef3SRafael J. Wysocki * Put the given device into the full-power state using the standard ACPI 95163705c40SRafael J. Wysocki * mechanism. Set the power state of the device to ACPI D0 and disable wakeup. 952e5cc8ef3SRafael J. Wysocki */ 95363705c40SRafael J. Wysocki int acpi_dev_resume(struct device *dev) 954e5cc8ef3SRafael J. Wysocki { 95579c0373fSRafael J. Wysocki struct acpi_device *adev = ACPI_COMPANION(dev); 956e5cc8ef3SRafael J. Wysocki int error; 957e5cc8ef3SRafael J. Wysocki 958e5cc8ef3SRafael J. Wysocki if (!adev) 959e5cc8ef3SRafael J. Wysocki return 0; 960e5cc8ef3SRafael J. Wysocki 961e5cc8ef3SRafael J. Wysocki error = acpi_dev_pm_full_power(adev); 96299d8845eSRafael J. Wysocki acpi_device_wakeup_disable(adev); 963e5cc8ef3SRafael J. Wysocki return error; 964e5cc8ef3SRafael J. Wysocki } 96563705c40SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_dev_resume); 966e5cc8ef3SRafael J. Wysocki 967e5cc8ef3SRafael J. Wysocki /** 968e5cc8ef3SRafael J. Wysocki * acpi_subsys_runtime_suspend - Suspend device using ACPI. 969e5cc8ef3SRafael J. Wysocki * @dev: Device to suspend. 970e5cc8ef3SRafael J. Wysocki * 971e5cc8ef3SRafael J. Wysocki * Carry out the generic runtime suspend procedure for @dev and use ACPI to put 972e5cc8ef3SRafael J. Wysocki * it into a runtime low-power state. 973e5cc8ef3SRafael J. Wysocki */ 974e5cc8ef3SRafael J. Wysocki int acpi_subsys_runtime_suspend(struct device *dev) 975e5cc8ef3SRafael J. Wysocki { 976e5cc8ef3SRafael J. Wysocki int ret = pm_generic_runtime_suspend(dev); 977cbe25ce3SRafael J. Wysocki return ret ? ret : acpi_dev_suspend(dev, true); 978e5cc8ef3SRafael J. Wysocki } 979e5cc8ef3SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_subsys_runtime_suspend); 980e5cc8ef3SRafael J. Wysocki 981e5cc8ef3SRafael J. Wysocki /** 982e5cc8ef3SRafael J. Wysocki * acpi_subsys_runtime_resume - Resume device using ACPI. 983e5cc8ef3SRafael J. Wysocki * @dev: Device to Resume. 984e5cc8ef3SRafael J. Wysocki * 985e5cc8ef3SRafael J. Wysocki * Use ACPI to put the given device into the full-power state and carry out the 986e5cc8ef3SRafael J. Wysocki * generic runtime resume procedure for it. 987e5cc8ef3SRafael J. Wysocki */ 988e5cc8ef3SRafael J. Wysocki int acpi_subsys_runtime_resume(struct device *dev) 989e5cc8ef3SRafael J. Wysocki { 99063705c40SRafael J. Wysocki int ret = acpi_dev_resume(dev); 991e5cc8ef3SRafael J. Wysocki return ret ? ret : pm_generic_runtime_resume(dev); 992e5cc8ef3SRafael J. Wysocki } 993e5cc8ef3SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_subsys_runtime_resume); 994e5cc8ef3SRafael J. Wysocki 995e5cc8ef3SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 996c2ebf788SUlf Hansson static bool acpi_dev_needs_resume(struct device *dev, struct acpi_device *adev) 997c2ebf788SUlf Hansson { 998c2ebf788SUlf Hansson u32 sys_target = acpi_target_system_state(); 999c2ebf788SUlf Hansson int ret, state; 1000c2ebf788SUlf Hansson 10019a51c6b1SRafael J. Wysocki if (!pm_runtime_suspended(dev) || !adev || (adev->wakeup.flags.valid && 10029a51c6b1SRafael J. Wysocki device_may_wakeup(dev) != !!adev->wakeup.prepare_count)) 1003c2ebf788SUlf Hansson return true; 1004c2ebf788SUlf Hansson 1005c2ebf788SUlf Hansson if (sys_target == ACPI_STATE_S0) 1006c2ebf788SUlf Hansson return false; 1007c2ebf788SUlf Hansson 1008c2ebf788SUlf Hansson if (adev->power.flags.dsw_present) 1009c2ebf788SUlf Hansson return true; 1010c2ebf788SUlf Hansson 1011c2ebf788SUlf Hansson ret = acpi_dev_pm_get_state(dev, adev, sys_target, NULL, &state); 1012c2ebf788SUlf Hansson if (ret) 1013c2ebf788SUlf Hansson return true; 1014c2ebf788SUlf Hansson 1015c2ebf788SUlf Hansson return state != adev->power.state; 1016c2ebf788SUlf Hansson } 1017c2ebf788SUlf Hansson 1018e5cc8ef3SRafael J. Wysocki /** 1019e5cc8ef3SRafael J. Wysocki * acpi_subsys_prepare - Prepare device for system transition to a sleep state. 1020e5cc8ef3SRafael J. Wysocki * @dev: Device to prepare. 1021e5cc8ef3SRafael J. Wysocki */ 1022e5cc8ef3SRafael J. Wysocki int acpi_subsys_prepare(struct device *dev) 1023e5cc8ef3SRafael J. Wysocki { 1024f25c0ae2SRafael J. Wysocki struct acpi_device *adev = ACPI_COMPANION(dev); 102592858c47SRafael J. Wysocki 102608810a41SRafael J. Wysocki if (dev->driver && dev->driver->pm && dev->driver->pm->prepare) { 102708810a41SRafael J. Wysocki int ret = dev->driver->pm->prepare(dev); 102808810a41SRafael J. Wysocki 1029f25c0ae2SRafael J. Wysocki if (ret < 0) 1030f25c0ae2SRafael J. Wysocki return ret; 1031f25c0ae2SRafael J. Wysocki 103208810a41SRafael J. Wysocki if (!ret && dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_PREPARE)) 1033f25c0ae2SRafael J. Wysocki return 0; 103408810a41SRafael J. Wysocki } 1035f25c0ae2SRafael J. Wysocki 1036c2ebf788SUlf Hansson return !acpi_dev_needs_resume(dev, adev); 1037e5cc8ef3SRafael J. Wysocki } 1038e5cc8ef3SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_subsys_prepare); 1039e5cc8ef3SRafael J. Wysocki 1040e5cc8ef3SRafael J. Wysocki /** 1041e4da817dSUlf Hansson * acpi_subsys_complete - Finalize device's resume during system resume. 1042e4da817dSUlf Hansson * @dev: Device to handle. 1043e4da817dSUlf Hansson */ 1044e4da817dSUlf Hansson void acpi_subsys_complete(struct device *dev) 1045e4da817dSUlf Hansson { 1046e4da817dSUlf Hansson pm_generic_complete(dev); 1047e4da817dSUlf Hansson /* 1048e4da817dSUlf Hansson * If the device had been runtime-suspended before the system went into 1049e4da817dSUlf Hansson * the sleep state it is going out of and it has never been resumed till 1050e4da817dSUlf Hansson * now, resume it in case the firmware powered it up. 1051e4da817dSUlf Hansson */ 1052db68daffSRafael J. Wysocki if (pm_runtime_suspended(dev) && pm_resume_via_firmware()) 1053e4da817dSUlf Hansson pm_request_resume(dev); 1054e4da817dSUlf Hansson } 1055e4da817dSUlf Hansson EXPORT_SYMBOL_GPL(acpi_subsys_complete); 1056e4da817dSUlf Hansson 1057e4da817dSUlf Hansson /** 105892858c47SRafael J. Wysocki * acpi_subsys_suspend - Run the device driver's suspend callback. 105992858c47SRafael J. Wysocki * @dev: Device to handle. 106092858c47SRafael J. Wysocki * 106105087360SRafael J. Wysocki * Follow PCI and resume devices from runtime suspend before running their 106205087360SRafael J. Wysocki * system suspend callbacks, unless the driver can cope with runtime-suspended 106305087360SRafael J. Wysocki * devices during system suspend and there are no ACPI-specific reasons for 106405087360SRafael J. Wysocki * resuming them. 106592858c47SRafael J. Wysocki */ 106692858c47SRafael J. Wysocki int acpi_subsys_suspend(struct device *dev) 106792858c47SRafael J. Wysocki { 106805087360SRafael J. Wysocki if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) || 106905087360SRafael J. Wysocki acpi_dev_needs_resume(dev, ACPI_COMPANION(dev))) 107092858c47SRafael J. Wysocki pm_runtime_resume(dev); 107105087360SRafael J. Wysocki 107292858c47SRafael J. Wysocki return pm_generic_suspend(dev); 107392858c47SRafael J. Wysocki } 10744cf563c5SHeikki Krogerus EXPORT_SYMBOL_GPL(acpi_subsys_suspend); 107592858c47SRafael J. Wysocki 107692858c47SRafael J. Wysocki /** 1077e5cc8ef3SRafael J. Wysocki * acpi_subsys_suspend_late - Suspend device using ACPI. 1078e5cc8ef3SRafael J. Wysocki * @dev: Device to suspend. 1079e5cc8ef3SRafael J. Wysocki * 1080e5cc8ef3SRafael J. Wysocki * Carry out the generic late suspend procedure for @dev and use ACPI to put 1081e5cc8ef3SRafael J. Wysocki * it into a low-power state during system transition into a sleep state. 1082e5cc8ef3SRafael J. Wysocki */ 1083e5cc8ef3SRafael J. Wysocki int acpi_subsys_suspend_late(struct device *dev) 1084e5cc8ef3SRafael J. Wysocki { 108505087360SRafael J. Wysocki int ret; 108605087360SRafael J. Wysocki 108705087360SRafael J. Wysocki if (dev_pm_smart_suspend_and_suspended(dev)) 108805087360SRafael J. Wysocki return 0; 108905087360SRafael J. Wysocki 109005087360SRafael J. Wysocki ret = pm_generic_suspend_late(dev); 1091cbe25ce3SRafael J. Wysocki return ret ? ret : acpi_dev_suspend(dev, device_may_wakeup(dev)); 1092e5cc8ef3SRafael J. Wysocki } 1093e5cc8ef3SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late); 1094e5cc8ef3SRafael J. Wysocki 1095e5cc8ef3SRafael J. Wysocki /** 109605087360SRafael J. Wysocki * acpi_subsys_suspend_noirq - Run the device driver's "noirq" suspend callback. 109705087360SRafael J. Wysocki * @dev: Device to suspend. 109805087360SRafael J. Wysocki */ 109905087360SRafael J. Wysocki int acpi_subsys_suspend_noirq(struct device *dev) 110005087360SRafael J. Wysocki { 1101db68daffSRafael J. Wysocki int ret; 110205087360SRafael J. Wysocki 1103db68daffSRafael J. Wysocki if (dev_pm_smart_suspend_and_suspended(dev)) { 1104db68daffSRafael J. Wysocki dev->power.may_skip_resume = true; 1105db68daffSRafael J. Wysocki return 0; 1106db68daffSRafael J. Wysocki } 1107db68daffSRafael J. Wysocki 1108db68daffSRafael J. Wysocki ret = pm_generic_suspend_noirq(dev); 1109db68daffSRafael J. Wysocki if (ret) 1110db68daffSRafael J. Wysocki return ret; 1111db68daffSRafael J. Wysocki 1112db68daffSRafael J. Wysocki /* 1113db68daffSRafael J. Wysocki * If the target system sleep state is suspend-to-idle, it is sufficient 1114db68daffSRafael J. Wysocki * to check whether or not the device's wakeup settings are good for 1115db68daffSRafael J. Wysocki * runtime PM. Otherwise, the pm_resume_via_firmware() check will cause 1116db68daffSRafael J. Wysocki * acpi_subsys_complete() to take care of fixing up the device's state 1117db68daffSRafael J. Wysocki * anyway, if need be. 1118db68daffSRafael J. Wysocki */ 1119db68daffSRafael J. Wysocki dev->power.may_skip_resume = device_may_wakeup(dev) || 1120db68daffSRafael J. Wysocki !device_can_wakeup(dev); 1121db68daffSRafael J. Wysocki 1122db68daffSRafael J. Wysocki return 0; 112305087360SRafael J. Wysocki } 112405087360SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_subsys_suspend_noirq); 112505087360SRafael J. Wysocki 112605087360SRafael J. Wysocki /** 112705087360SRafael J. Wysocki * acpi_subsys_resume_noirq - Run the device driver's "noirq" resume callback. 112805087360SRafael J. Wysocki * @dev: Device to handle. 112905087360SRafael J. Wysocki */ 11303cd7957eSRafael J. Wysocki static int acpi_subsys_resume_noirq(struct device *dev) 113105087360SRafael J. Wysocki { 1132db68daffSRafael J. Wysocki if (dev_pm_may_skip_resume(dev)) 1133db68daffSRafael J. Wysocki return 0; 1134db68daffSRafael J. Wysocki 113505087360SRafael J. Wysocki /* 113605087360SRafael J. Wysocki * Devices with DPM_FLAG_SMART_SUSPEND may be left in runtime suspend 113705087360SRafael J. Wysocki * during system suspend, so update their runtime PM status to "active" 113805087360SRafael J. Wysocki * as they will be put into D0 going forward. 113905087360SRafael J. Wysocki */ 114005087360SRafael J. Wysocki if (dev_pm_smart_suspend_and_suspended(dev)) 114105087360SRafael J. Wysocki pm_runtime_set_active(dev); 114205087360SRafael J. Wysocki 114305087360SRafael J. Wysocki return pm_generic_resume_noirq(dev); 114405087360SRafael J. Wysocki } 114505087360SRafael J. Wysocki 114605087360SRafael J. Wysocki /** 1147e5cc8ef3SRafael J. Wysocki * acpi_subsys_resume_early - Resume device using ACPI. 1148e5cc8ef3SRafael J. Wysocki * @dev: Device to Resume. 1149e5cc8ef3SRafael J. Wysocki * 1150e5cc8ef3SRafael J. Wysocki * Use ACPI to put the given device into the full-power state and carry out the 1151e5cc8ef3SRafael J. Wysocki * generic early resume procedure for it during system transition into the 1152e5cc8ef3SRafael J. Wysocki * working state. 1153e5cc8ef3SRafael J. Wysocki */ 11543cd7957eSRafael J. Wysocki static int acpi_subsys_resume_early(struct device *dev) 1155e5cc8ef3SRafael J. Wysocki { 115663705c40SRafael J. Wysocki int ret = acpi_dev_resume(dev); 1157e5cc8ef3SRafael J. Wysocki return ret ? ret : pm_generic_resume_early(dev); 1158e5cc8ef3SRafael J. Wysocki } 115992858c47SRafael J. Wysocki 116092858c47SRafael J. Wysocki /** 116192858c47SRafael J. Wysocki * acpi_subsys_freeze - Run the device driver's freeze callback. 116292858c47SRafael J. Wysocki * @dev: Device to handle. 116392858c47SRafael J. Wysocki */ 116492858c47SRafael J. Wysocki int acpi_subsys_freeze(struct device *dev) 116592858c47SRafael J. Wysocki { 116692858c47SRafael J. Wysocki /* 1167501debd4SRafael J. Wysocki * Resume all runtime-suspended devices before creating a snapshot 1168501debd4SRafael J. Wysocki * image of system memory, because the restore kernel generally cannot 1169501debd4SRafael J. Wysocki * be expected to always handle them consistently and they need to be 1170501debd4SRafael J. Wysocki * put into the runtime-active metastate during system resume anyway, 1171501debd4SRafael J. Wysocki * so it is better to ensure that the state saved in the image will be 1172501debd4SRafael J. Wysocki * always consistent with that. 117392858c47SRafael J. Wysocki */ 117492858c47SRafael J. Wysocki pm_runtime_resume(dev); 117505087360SRafael J. Wysocki 117692858c47SRafael J. Wysocki return pm_generic_freeze(dev); 117792858c47SRafael J. Wysocki } 11784cf563c5SHeikki Krogerus EXPORT_SYMBOL_GPL(acpi_subsys_freeze); 117992858c47SRafael J. Wysocki 118005087360SRafael J. Wysocki /** 11813cd7957eSRafael J. Wysocki * acpi_subsys_restore_early - Restore device using ACPI. 11823cd7957eSRafael J. Wysocki * @dev: Device to restore. 118305087360SRafael J. Wysocki */ 11843cd7957eSRafael J. Wysocki int acpi_subsys_restore_early(struct device *dev) 118505087360SRafael J. Wysocki { 11863cd7957eSRafael J. Wysocki int ret = acpi_dev_resume(dev); 11873cd7957eSRafael J. Wysocki return ret ? ret : pm_generic_restore_early(dev); 118805087360SRafael J. Wysocki } 11893cd7957eSRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_subsys_restore_early); 1190c95b7595SRafael J. Wysocki 1191c95b7595SRafael J. Wysocki /** 1192c95b7595SRafael J. Wysocki * acpi_subsys_poweroff - Run the device driver's poweroff callback. 1193c95b7595SRafael J. Wysocki * @dev: Device to handle. 1194c95b7595SRafael J. Wysocki * 1195c95b7595SRafael J. Wysocki * Follow PCI and resume devices from runtime suspend before running their 1196c95b7595SRafael J. Wysocki * system poweroff callbacks, unless the driver can cope with runtime-suspended 1197c95b7595SRafael J. Wysocki * devices during system suspend and there are no ACPI-specific reasons for 1198c95b7595SRafael J. Wysocki * resuming them. 1199c95b7595SRafael J. Wysocki */ 1200c95b7595SRafael J. Wysocki int acpi_subsys_poweroff(struct device *dev) 1201c95b7595SRafael J. Wysocki { 1202c95b7595SRafael J. Wysocki if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) || 1203c95b7595SRafael J. Wysocki acpi_dev_needs_resume(dev, ACPI_COMPANION(dev))) 1204c95b7595SRafael J. Wysocki pm_runtime_resume(dev); 1205c95b7595SRafael J. Wysocki 1206c95b7595SRafael J. Wysocki return pm_generic_poweroff(dev); 1207c95b7595SRafael J. Wysocki } 1208c95b7595SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_subsys_poweroff); 1209c95b7595SRafael J. Wysocki 1210c95b7595SRafael J. Wysocki /** 1211c95b7595SRafael J. Wysocki * acpi_subsys_poweroff_late - Run the device driver's poweroff callback. 1212c95b7595SRafael J. Wysocki * @dev: Device to handle. 1213c95b7595SRafael J. Wysocki * 1214c95b7595SRafael J. Wysocki * Carry out the generic late poweroff procedure for @dev and use ACPI to put 1215c95b7595SRafael J. Wysocki * it into a low-power state during system transition into a sleep state. 1216c95b7595SRafael J. Wysocki */ 1217c95b7595SRafael J. Wysocki static int acpi_subsys_poweroff_late(struct device *dev) 1218c95b7595SRafael J. Wysocki { 1219c95b7595SRafael J. Wysocki int ret; 122005087360SRafael J. Wysocki 122105087360SRafael J. Wysocki if (dev_pm_smart_suspend_and_suspended(dev)) 122205087360SRafael J. Wysocki return 0; 122305087360SRafael J. Wysocki 1224c95b7595SRafael J. Wysocki ret = pm_generic_poweroff_late(dev); 1225c95b7595SRafael J. Wysocki if (ret) 1226c95b7595SRafael J. Wysocki return ret; 1227c95b7595SRafael J. Wysocki 1228c95b7595SRafael J. Wysocki return acpi_dev_suspend(dev, device_may_wakeup(dev)); 122905087360SRafael J. Wysocki } 123005087360SRafael J. Wysocki 123105087360SRafael J. Wysocki /** 1232c95b7595SRafael J. Wysocki * acpi_subsys_poweroff_noirq - Run the driver's "noirq" poweroff callback. 1233c95b7595SRafael J. Wysocki * @dev: Device to suspend. 123405087360SRafael J. Wysocki */ 1235c95b7595SRafael J. Wysocki static int acpi_subsys_poweroff_noirq(struct device *dev) 123605087360SRafael J. Wysocki { 123705087360SRafael J. Wysocki if (dev_pm_smart_suspend_and_suspended(dev)) 123805087360SRafael J. Wysocki return 0; 123905087360SRafael J. Wysocki 1240c95b7595SRafael J. Wysocki return pm_generic_poweroff_noirq(dev); 124105087360SRafael J. Wysocki } 1242e5cc8ef3SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 1243e5cc8ef3SRafael J. Wysocki 1244e5cc8ef3SRafael J. Wysocki static struct dev_pm_domain acpi_general_pm_domain = { 1245e5cc8ef3SRafael J. Wysocki .ops = { 1246e5cc8ef3SRafael J. Wysocki .runtime_suspend = acpi_subsys_runtime_suspend, 1247e5cc8ef3SRafael J. Wysocki .runtime_resume = acpi_subsys_runtime_resume, 1248e5cc8ef3SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 1249e5cc8ef3SRafael J. Wysocki .prepare = acpi_subsys_prepare, 1250e4da817dSUlf Hansson .complete = acpi_subsys_complete, 125192858c47SRafael J. Wysocki .suspend = acpi_subsys_suspend, 1252e5cc8ef3SRafael J. Wysocki .suspend_late = acpi_subsys_suspend_late, 125305087360SRafael J. Wysocki .suspend_noirq = acpi_subsys_suspend_noirq, 125405087360SRafael J. Wysocki .resume_noirq = acpi_subsys_resume_noirq, 1255e5cc8ef3SRafael J. Wysocki .resume_early = acpi_subsys_resume_early, 125692858c47SRafael J. Wysocki .freeze = acpi_subsys_freeze, 1257c95b7595SRafael J. Wysocki .poweroff = acpi_subsys_poweroff, 1258c95b7595SRafael J. Wysocki .poweroff_late = acpi_subsys_poweroff_late, 1259c95b7595SRafael J. Wysocki .poweroff_noirq = acpi_subsys_poweroff_noirq, 12603cd7957eSRafael J. Wysocki .restore_early = acpi_subsys_restore_early, 1261e5cc8ef3SRafael J. Wysocki #endif 1262e5cc8ef3SRafael J. Wysocki }, 1263e5cc8ef3SRafael J. Wysocki }; 1264e5cc8ef3SRafael J. Wysocki 1265e5cc8ef3SRafael J. Wysocki /** 126691d66cd2SUlf Hansson * acpi_dev_pm_detach - Remove ACPI power management from the device. 126791d66cd2SUlf Hansson * @dev: Device to take care of. 126891d66cd2SUlf Hansson * @power_off: Whether or not to try to remove power from the device. 126991d66cd2SUlf Hansson * 127091d66cd2SUlf Hansson * Remove the device from the general ACPI PM domain and remove its wakeup 127191d66cd2SUlf Hansson * notifier. If @power_off is set, additionally remove power from the device if 127291d66cd2SUlf Hansson * possible. 127391d66cd2SUlf Hansson * 127491d66cd2SUlf Hansson * Callers must ensure proper synchronization of this function with power 127591d66cd2SUlf Hansson * management callbacks. 127691d66cd2SUlf Hansson */ 127791d66cd2SUlf Hansson static void acpi_dev_pm_detach(struct device *dev, bool power_off) 127891d66cd2SUlf Hansson { 127991d66cd2SUlf Hansson struct acpi_device *adev = ACPI_COMPANION(dev); 128091d66cd2SUlf Hansson 128191d66cd2SUlf Hansson if (adev && dev->pm_domain == &acpi_general_pm_domain) { 1282989561deSTomeu Vizoso dev_pm_domain_set(dev, NULL); 128391d66cd2SUlf Hansson acpi_remove_pm_notifier(adev); 128491d66cd2SUlf Hansson if (power_off) { 128591d66cd2SUlf Hansson /* 128691d66cd2SUlf Hansson * If the device's PM QoS resume latency limit or flags 128791d66cd2SUlf Hansson * have been exposed to user space, they have to be 128891d66cd2SUlf Hansson * hidden at this point, so that they don't affect the 128991d66cd2SUlf Hansson * choice of the low-power state to put the device into. 129091d66cd2SUlf Hansson */ 129191d66cd2SUlf Hansson dev_pm_qos_hide_latency_limit(dev); 129291d66cd2SUlf Hansson dev_pm_qos_hide_flags(dev); 129399d8845eSRafael J. Wysocki acpi_device_wakeup_disable(adev); 129491d66cd2SUlf Hansson acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0); 129591d66cd2SUlf Hansson } 129691d66cd2SUlf Hansson } 129791d66cd2SUlf Hansson } 129891d66cd2SUlf Hansson 129991d66cd2SUlf Hansson /** 1300e5cc8ef3SRafael J. Wysocki * acpi_dev_pm_attach - Prepare device for ACPI power management. 1301e5cc8ef3SRafael J. Wysocki * @dev: Device to prepare. 1302b88ce2a4SRafael J. Wysocki * @power_on: Whether or not to power on the device. 1303e5cc8ef3SRafael J. Wysocki * 1304e5cc8ef3SRafael J. Wysocki * If @dev has a valid ACPI handle that has a valid struct acpi_device object 1305e5cc8ef3SRafael J. Wysocki * attached to it, install a wakeup notification handler for the device and 1306b88ce2a4SRafael J. Wysocki * add it to the general ACPI PM domain. If @power_on is set, the device will 1307b88ce2a4SRafael J. Wysocki * be put into the ACPI D0 state before the function returns. 1308e5cc8ef3SRafael J. Wysocki * 1309e5cc8ef3SRafael J. Wysocki * This assumes that the @dev's bus type uses generic power management callbacks 1310e5cc8ef3SRafael J. Wysocki * (or doesn't use any power management callbacks at all). 1311e5cc8ef3SRafael J. Wysocki * 1312e5cc8ef3SRafael J. Wysocki * Callers must ensure proper synchronization of this function with power 1313e5cc8ef3SRafael J. Wysocki * management callbacks. 1314e5cc8ef3SRafael J. Wysocki */ 1315b88ce2a4SRafael J. Wysocki int acpi_dev_pm_attach(struct device *dev, bool power_on) 1316e5cc8ef3SRafael J. Wysocki { 1317b9ea0baeSRafael J. Wysocki /* 1318b9ea0baeSRafael J. Wysocki * Skip devices whose ACPI companions match the device IDs below, 1319b9ea0baeSRafael J. Wysocki * because they require special power management handling incompatible 1320b9ea0baeSRafael J. Wysocki * with the generic ACPI PM domain. 1321b9ea0baeSRafael J. Wysocki */ 1322b9ea0baeSRafael J. Wysocki static const struct acpi_device_id special_pm_ids[] = { 1323b9ea0baeSRafael J. Wysocki {"PNP0C0B", }, /* Generic ACPI fan */ 1324b9ea0baeSRafael J. Wysocki {"INT3404", }, /* Fan */ 1325b62c770fSGayatri Kammela {"INTC1044", }, /* Fan for Tiger Lake generation */ 1326b9ea0baeSRafael J. Wysocki {} 1327b9ea0baeSRafael J. Wysocki }; 132879c0373fSRafael J. Wysocki struct acpi_device *adev = ACPI_COMPANION(dev); 1329e5cc8ef3SRafael J. Wysocki 1330b9ea0baeSRafael J. Wysocki if (!adev || !acpi_match_device_ids(adev, special_pm_ids)) 1331919b7308SUlf Hansson return 0; 1332e5cc8ef3SRafael J. Wysocki 1333712e960fSMika Westerberg /* 1334712e960fSMika Westerberg * Only attach the power domain to the first device if the 1335712e960fSMika Westerberg * companion is shared by multiple. This is to prevent doing power 1336712e960fSMika Westerberg * management twice. 1337712e960fSMika Westerberg */ 1338712e960fSMika Westerberg if (!acpi_device_is_first_physical_node(adev, dev)) 1339919b7308SUlf Hansson return 0; 1340712e960fSMika Westerberg 1341c072530fSRafael J. Wysocki acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func); 1342989561deSTomeu Vizoso dev_pm_domain_set(dev, &acpi_general_pm_domain); 1343b88ce2a4SRafael J. Wysocki if (power_on) { 1344b88ce2a4SRafael J. Wysocki acpi_dev_pm_full_power(adev); 134599d8845eSRafael J. Wysocki acpi_device_wakeup_disable(adev); 1346b88ce2a4SRafael J. Wysocki } 134786f1e15fSUlf Hansson 134886f1e15fSUlf Hansson dev->pm_domain->detach = acpi_dev_pm_detach; 1349919b7308SUlf Hansson return 1; 1350e5cc8ef3SRafael J. Wysocki } 1351e5cc8ef3SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); 1352ec4602a9SRafael J. Wysocki #endif /* CONFIG_PM */ 1353