// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/acpi/device_pm.c - ACPI device power management routines.
*
* Copyright (C) 2012, Intel Corp.
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/acpi.h>
#include <linux/export.h>
#include <linux/mutex.h>
#include <linux/pm_qos.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/suspend.h>
#include "internal.h"
#define _COMPONENT ACPI_POWER_COMPONENT
ACPI_MODULE_NAME("device_pm");
/**
* acpi_power_state_string - String representation of ACPI device power state.
* @state: ACPI device power state to return the string representation of.
*/
const char *acpi_power_state_string(int state)
{
switch (state) {
case ACPI_STATE_D0:
return "D0";
case ACPI_STATE_D1:
return "D1";
case ACPI_STATE_D2:
return "D2";
case ACPI_STATE_D3_HOT:
return "D3hot";
case ACPI_STATE_D3_COLD:
return "D3cold";
default:
return "(unknown)";
}
}
static int acpi_dev_pm_explicit_get(struct acpi_device *device, int *state)
{
unsigned long long psc;
acpi_status status;
status = acpi_evaluate_integer(device->handle, "_PSC", NULL, &psc);
if (ACPI_FAILURE(status))
return -ENODEV;
*state = psc;
return 0;
}
/**
* acpi_device_get_power - Get power state of an ACPI device.
* @device: Device to get the power state of.
* @state: Place to store the power state of the device.
*
* This function does not update the device's power.state field, but it may
* update its parent's power.state field (when the parent's power state is
* unknown and the device's power state turns out to be D0).
*
* Also, it does not update power resource reference counters to ensure that
* the power state returned by it will be persistent and it may return a power
* state shallower than previously set by acpi_device_set_power() for @device
* (if that power state depends on any power resources).
*/
int acpi_device_get_power(struct acpi_device *device, int *state)
{
int result = ACPI_STATE_UNKNOWN;
int error;
if (!device || !state)
return -EINVAL;
if (!device->flags.power_manageable) {
/* TBD: Non-recursive algorithm for walking up hierarchy. */
*state = device->parent ?
device->parent->power.state : ACPI_STATE_D0;
goto out;
}
/*
* Get the device's power state from power resources settings and _PSC,
* if available.
*/
if (device->power.flags.power_resources) {