^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * drivers/acpi/power.c - ACPI Power Resources management.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2001 - 2015 Intel Corp.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author: Andy Grover <andrew.grover@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author: Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * ACPI power-managed devices may be controlled in two ways:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * 1. via "Device Specific (D-State) Control"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * 2. via "Power Resource Control".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * The code below deals with ACPI Power Resources control.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * An ACPI "power resource object" represents a software controllable power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * plane, clock plane, or other resource depended on by a device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * A device may rely on multiple power resources, and a power resource
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * may be shared by multiple devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/sysfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include "sleep.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include "internal.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define _COMPONENT ACPI_POWER_COMPONENT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) ACPI_MODULE_NAME("power");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define ACPI_POWER_CLASS "power_resource"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define ACPI_POWER_DEVICE_NAME "Power Resource"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define ACPI_POWER_RESOURCE_STATE_OFF 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define ACPI_POWER_RESOURCE_STATE_ON 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct acpi_power_dependent_device {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct list_head node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct acpi_power_resource {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct acpi_device device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct list_head list_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) u32 system_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) u32 order;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) unsigned int ref_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) bool wakeup_enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct mutex resource_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct list_head dependents;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct acpi_power_resource_entry {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct list_head node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct acpi_power_resource *resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static LIST_HEAD(acpi_power_resource_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static DEFINE_MUTEX(power_resource_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /* --------------------------------------------------------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) Power Resource Management
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) -------------------------------------------------------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static inline
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct acpi_power_resource *to_power_resource(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return container_of(device, struct acpi_power_resource, device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static struct acpi_power_resource *acpi_power_get_context(acpi_handle handle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct acpi_device *device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (acpi_bus_get_device(handle, &device))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return to_power_resource(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static int acpi_power_resources_list_add(acpi_handle handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct list_head *list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct acpi_power_resource *resource = acpi_power_get_context(handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct acpi_power_resource_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (!resource || !list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) entry = kzalloc(sizeof(*entry), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (!entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) entry->resource = resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (!list_empty(list)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct acpi_power_resource_entry *e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) list_for_each_entry(e, list, node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (e->resource->order > resource->order) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) list_add_tail(&entry->node, &e->node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) list_add_tail(&entry->node, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) void acpi_power_resources_list_free(struct list_head *list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct acpi_power_resource_entry *entry, *e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) list_for_each_entry_safe(entry, e, list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) list_del(&entry->node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) kfree(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static bool acpi_power_resource_is_dup(union acpi_object *package,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) unsigned int start, unsigned int i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) acpi_handle rhandle, dup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) unsigned int j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /* The caller is expected to check the package element types */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) rhandle = package->package.elements[i].reference.handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) for (j = start; j < i; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) dup = package->package.elements[j].reference.handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (dup == rhandle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) struct list_head *list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) for (i = start; i < package->package.count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) union acpi_object *element = &package->package.elements[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) acpi_handle rhandle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) err = -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) rhandle = element->reference.handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (!rhandle) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /* Some ACPI tables contain duplicate power resource references */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (acpi_power_resource_is_dup(package, start, i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) err = acpi_add_power_resource(rhandle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) err = acpi_power_resources_list_add(rhandle, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) acpi_power_resources_list_free(list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) static int acpi_power_get_state(acpi_handle handle, int *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) acpi_status status = AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) unsigned long long sta = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) char node_name[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) struct acpi_buffer buffer = { sizeof(node_name), node_name };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (!handle || !state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) *state = (sta & 0x01)?ACPI_POWER_RESOURCE_STATE_ON:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) ACPI_POWER_RESOURCE_STATE_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) node_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) *state ? "on" : "off"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) static int acpi_power_get_list_state(struct list_head *list, int *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) struct acpi_power_resource_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) int cur_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (!list || !state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) /* The state of the list is 'on' IFF all resources are 'on'. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) cur_state = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) list_for_each_entry(entry, list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) struct acpi_power_resource *resource = entry->resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) acpi_handle handle = resource->device.handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) mutex_lock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) result = acpi_power_get_state(handle, &cur_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) mutex_unlock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (cur_state != ACPI_POWER_RESOURCE_STATE_ON)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) cur_state ? "on" : "off"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) *state = cur_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) acpi_power_resource_add_dependent(struct acpi_power_resource *resource,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) struct acpi_power_dependent_device *dep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) mutex_lock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) list_for_each_entry(dep, &resource->dependents, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) /* Only add it once */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) if (dep->dev == dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) dep = kzalloc(sizeof(*dep), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (!dep) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) dep->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) list_add_tail(&dep->node, &resource->dependents);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) dev_dbg(dev, "added power dependency to [%s]\n", resource->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) mutex_unlock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) acpi_power_resource_remove_dependent(struct acpi_power_resource *resource,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) struct acpi_power_dependent_device *dep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) mutex_lock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) list_for_each_entry(dep, &resource->dependents, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if (dep->dev == dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) list_del(&dep->node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) kfree(dep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) dev_dbg(dev, "removed power dependency to [%s]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) resource->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) mutex_unlock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) * acpi_device_power_add_dependent - Add dependent device of this ACPI device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) * @adev: ACPI device pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) * @dev: Dependent device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) * If @adev has non-empty _PR0 the @dev is added as dependent device to all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) * power resources returned by it. This means that whenever these power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) * resources are turned _ON the dependent devices get runtime resumed. This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) * is needed for devices such as PCI to allow its driver to re-initialize
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) * it after it went to D0uninitialized.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) * If @adev does not have _PR0 this does nothing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) * Returns %0 in case of success and negative errno otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) int acpi_device_power_add_dependent(struct acpi_device *adev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) struct acpi_power_resource_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) struct list_head *resources;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (!adev->flags.power_manageable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) resources = &adev->power.states[ACPI_STATE_D0].resources;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) list_for_each_entry(entry, resources, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) ret = acpi_power_resource_add_dependent(entry->resource, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) list_for_each_entry(entry, resources, node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) acpi_power_resource_remove_dependent(entry->resource, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) * acpi_device_power_remove_dependent - Remove dependent device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) * @adev: ACPI device pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) * @dev: Dependent device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) * Does the opposite of acpi_device_power_add_dependent() and removes the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) * dependent device if it is found. Can be called to @adev that does not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) * have _PR0 as well.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) void acpi_device_power_remove_dependent(struct acpi_device *adev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) struct acpi_power_resource_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) struct list_head *resources;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if (!adev->flags.power_manageable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) resources = &adev->power.states[ACPI_STATE_D0].resources;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) list_for_each_entry_reverse(entry, resources, node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) acpi_power_resource_remove_dependent(entry->resource, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) static int __acpi_power_on(struct acpi_power_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) struct acpi_power_dependent_device *dep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) acpi_status status = AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) status = acpi_evaluate_object(resource->device.handle, "_ON", NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) resource->name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) * If there are other dependents on this power resource we need to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) * resume them now so that their drivers can re-initialize the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) * hardware properly after it went back to D0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (list_empty(&resource->dependents) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) list_is_singular(&resource->dependents))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) list_for_each_entry(dep, &resource->dependents, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) dev_dbg(dep->dev, "runtime resuming because [%s] turned on\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) resource->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) pm_request_resume(dep->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) static int acpi_power_on_unlocked(struct acpi_power_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (resource->ref_count++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) ACPI_DEBUG_PRINT((ACPI_DB_INFO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) "Power resource [%s] already on\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) resource->name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) result = __acpi_power_on(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) resource->ref_count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) static int acpi_power_on(struct acpi_power_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) mutex_lock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) result = acpi_power_on_unlocked(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) mutex_unlock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) static int __acpi_power_off(struct acpi_power_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) status = acpi_evaluate_object(resource->device.handle, "_OFF",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned off\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) resource->name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) static int acpi_power_off_unlocked(struct acpi_power_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) if (!resource->ref_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) ACPI_DEBUG_PRINT((ACPI_DB_INFO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) "Power resource [%s] already off\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) resource->name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) if (--resource->ref_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) ACPI_DEBUG_PRINT((ACPI_DB_INFO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) "Power resource [%s] still in use\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) resource->name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) result = __acpi_power_off(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) resource->ref_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) static int acpi_power_off(struct acpi_power_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) mutex_lock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) result = acpi_power_off_unlocked(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) mutex_unlock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) static int acpi_power_off_list(struct list_head *list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) struct acpi_power_resource_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) list_for_each_entry_reverse(entry, list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) result = acpi_power_off(entry->resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) list_for_each_entry_continue(entry, list, node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) acpi_power_on(entry->resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) static int acpi_power_on_list(struct list_head *list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) struct acpi_power_resource_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) list_for_each_entry(entry, list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) result = acpi_power_on(entry->resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) list_for_each_entry_continue_reverse(entry, list, node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) acpi_power_off(entry->resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) static struct attribute *attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) static const struct attribute_group attr_groups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) [ACPI_STATE_D0] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) .name = "power_resources_D0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) .attrs = attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) [ACPI_STATE_D1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) .name = "power_resources_D1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) .attrs = attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) [ACPI_STATE_D2] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) .name = "power_resources_D2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) .attrs = attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) [ACPI_STATE_D3_HOT] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) .name = "power_resources_D3hot",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) .attrs = attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) static const struct attribute_group wakeup_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) .name = "power_resources_wakeup",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) .attrs = attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) static void acpi_power_hide_list(struct acpi_device *adev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) struct list_head *resources,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) const struct attribute_group *attr_group)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) struct acpi_power_resource_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) if (list_empty(resources))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) list_for_each_entry_reverse(entry, resources, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) struct acpi_device *res_dev = &entry->resource->device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) sysfs_remove_link_from_group(&adev->dev.kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) attr_group->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) dev_name(&res_dev->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) sysfs_remove_group(&adev->dev.kobj, attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) static void acpi_power_expose_list(struct acpi_device *adev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) struct list_head *resources,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) const struct attribute_group *attr_group)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) struct acpi_power_resource_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) if (list_empty(resources))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) ret = sysfs_create_group(&adev->dev.kobj, attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) list_for_each_entry(entry, resources, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) struct acpi_device *res_dev = &entry->resource->device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) ret = sysfs_add_link_to_group(&adev->dev.kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) attr_group->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) &res_dev->dev.kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) dev_name(&res_dev->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) acpi_power_hide_list(adev, resources, attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) static void acpi_power_expose_hide(struct acpi_device *adev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) struct list_head *resources,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) const struct attribute_group *attr_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) bool expose)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) if (expose)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) acpi_power_expose_list(adev, resources, attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) acpi_power_hide_list(adev, resources, attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) int state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) if (adev->wakeup.flags.valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) acpi_power_expose_hide(adev, &adev->wakeup.resources,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) &wakeup_attr_group, add);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) if (!adev->power.flags.power_resources)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) acpi_power_expose_hide(adev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) &adev->power.states[state].resources,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) &attr_groups[state], add);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) struct acpi_power_resource_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) int system_level = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) list_for_each_entry(entry, list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) struct acpi_power_resource *resource = entry->resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) acpi_handle handle = resource->device.handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) int state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) mutex_lock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) result = acpi_power_get_state(handle, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) mutex_unlock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) if (state == ACPI_POWER_RESOURCE_STATE_ON) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) resource->ref_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) resource->wakeup_enabled = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) if (system_level > resource->system_level)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) system_level = resource->system_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) mutex_unlock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) *system_level_p = system_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) /* --------------------------------------------------------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) Device Power Management
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) -------------------------------------------------------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) * ACPI 3.0) _PSW (Power State Wake)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) * @dev: Device to handle.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) * @enable: 0 - disable, 1 - enable the wake capabilities of the device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) * @sleep_state: Target sleep state of the system.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) * @dev_state: Target power state of the device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) * Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) * State Wake) for the device, if present. On failure reset the device's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) * wakeup.flags.valid flag.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) * RETURN VALUE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) * 0 if either _DSW or _PSW has been successfully executed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) * 0 if neither _DSW nor _PSW has been found
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) * -ENODEV if the execution of either _DSW or _PSW has failed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) int acpi_device_sleep_wake(struct acpi_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) int enable, int sleep_state, int dev_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) union acpi_object in_arg[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) struct acpi_object_list arg_list = { 3, in_arg };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) acpi_status status = AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) * Try to execute _DSW first.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) * Three arguments are needed for the _DSW object:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) * Argument 0: enable/disable the wake capabilities
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) * Argument 1: target system state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) * Argument 2: target device state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) * When _DSW object is called to disable the wake capabilities, maybe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) * the first argument is filled. The values of the other two arguments
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) * are meaningless.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) in_arg[0].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) in_arg[0].integer.value = enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) in_arg[1].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) in_arg[1].integer.value = sleep_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) in_arg[2].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) in_arg[2].integer.value = dev_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) status = acpi_evaluate_object(dev->handle, "_DSW", &arg_list, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) if (ACPI_SUCCESS(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) } else if (status != AE_NOT_FOUND) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) printk(KERN_ERR PREFIX "_DSW execution failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) dev->wakeup.flags.valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) /* Execute _PSW */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) status = acpi_execute_simple_method(dev->handle, "_PSW", enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) printk(KERN_ERR PREFIX "_PSW execution failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) dev->wakeup.flags.valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) * Prepare a wakeup device, two steps (Ref ACPI 2.0:P229):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) * 1. Power on the power resources required for the wakeup device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) * 2. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) * State Wake) for the device, if present
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) struct acpi_power_resource_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) if (!dev || !dev->wakeup.flags.valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) mutex_lock(&acpi_device_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) if (dev->wakeup.prepare_count++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) list_for_each_entry(entry, &dev->wakeup.resources, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) struct acpi_power_resource *resource = entry->resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) mutex_lock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) if (!resource->wakeup_enabled) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) err = acpi_power_on_unlocked(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) resource->wakeup_enabled = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) mutex_unlock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) dev_err(&dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) "Cannot turn wakeup power resources on\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) dev->wakeup.flags.valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) * Passing 3 as the third argument below means the device may be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) * put into arbitrary power state afterward.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) dev->wakeup.prepare_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) mutex_unlock(&acpi_device_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) * Shutdown a wakeup device, counterpart of above method
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) * 1. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) * State Wake) for the device, if present
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) * 2. Shutdown down the power resources
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) int acpi_disable_wakeup_device_power(struct acpi_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) struct acpi_power_resource_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) if (!dev || !dev->wakeup.flags.valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) mutex_lock(&acpi_device_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) if (--dev->wakeup.prepare_count > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) * Executing the code below even if prepare_count is already zero when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) * the function is called may be useful, for example for initialisation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) if (dev->wakeup.prepare_count < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) dev->wakeup.prepare_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) err = acpi_device_sleep_wake(dev, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) list_for_each_entry(entry, &dev->wakeup.resources, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) struct acpi_power_resource *resource = entry->resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) mutex_lock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) if (resource->wakeup_enabled) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) err = acpi_power_off_unlocked(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) resource->wakeup_enabled = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) mutex_unlock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) dev_err(&dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) "Cannot turn wakeup power resources off\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) dev->wakeup.flags.valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) mutex_unlock(&acpi_device_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) int list_state = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) if (!device || !state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) * We know a device's inferred power state when all the resources
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) * required for a given D-state are 'on'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) struct list_head *list = &device->power.states[i].resources;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) if (list_empty(list))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) result = acpi_power_get_list_state(list, &list_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) if (list_state == ACPI_POWER_RESOURCE_STATE_ON) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) *state = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) *state = device->power.states[ACPI_STATE_D3_COLD].flags.valid ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) ACPI_STATE_D3_COLD : ACPI_STATE_D3_HOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) int acpi_power_on_resources(struct acpi_device *device, int state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3_HOT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) return acpi_power_on_list(&device->power.states[state].resources);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) int acpi_power_transition(struct acpi_device *device, int state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) if (device->power.state == state || !device->flags.power_manageable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) if ((device->power.state < ACPI_STATE_D0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) || (device->power.state > ACPI_STATE_D3_COLD))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) * First we reference all power resources required in the target list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) * (e.g. so the device doesn't lose power while transitioning). Then,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) * we dereference all power resources used in the current list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) if (state < ACPI_STATE_D3_COLD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) result = acpi_power_on_list(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) &device->power.states[state].resources);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) if (!result && device->power.state < ACPI_STATE_D3_COLD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) acpi_power_off_list(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) &device->power.states[device->power.state].resources);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) /* We shouldn't change the state unless the above operations succeed. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) device->power.state = result ? ACPI_STATE_UNKNOWN : state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) static void acpi_release_power_resource(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) struct acpi_device *device = to_acpi_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) struct acpi_power_resource *resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) resource = container_of(device, struct acpi_power_resource, device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) mutex_lock(&power_resource_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) list_del(&resource->list_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) mutex_unlock(&power_resource_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) acpi_free_pnp_ids(&device->pnp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) kfree(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) static ssize_t resource_in_use_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) struct acpi_power_resource *resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) resource = to_power_resource(to_acpi_device(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) return sprintf(buf, "%u\n", !!resource->ref_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) static DEVICE_ATTR_RO(resource_in_use);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) static void acpi_power_sysfs_remove(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) device_remove_file(&device->dev, &dev_attr_resource_in_use);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) static void acpi_power_add_resource_to_list(struct acpi_power_resource *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) mutex_lock(&power_resource_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) if (!list_empty(&acpi_power_resource_list)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) struct acpi_power_resource *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) list_for_each_entry(r, &acpi_power_resource_list, list_node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) if (r->order > resource->order) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) list_add_tail(&resource->list_node, &r->list_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) list_add_tail(&resource->list_node, &acpi_power_resource_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) mutex_unlock(&power_resource_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) int acpi_add_power_resource(acpi_handle handle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) struct acpi_power_resource *resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) struct acpi_device *device = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) union acpi_object acpi_object;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) int state, result = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) acpi_bus_get_device(handle, &device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) if (device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) resource = kzalloc(sizeof(*resource), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) if (!resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) device = &resource->device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) ACPI_STA_DEFAULT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) mutex_init(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) INIT_LIST_HEAD(&resource->list_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) INIT_LIST_HEAD(&resource->dependents);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) resource->name = device->pnp.bus_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) device->power.state = ACPI_STATE_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) /* Evalute the object to get the system level and resource order. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) resource->system_level = acpi_object.power_resource.system_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) resource->order = acpi_object.power_resource.resource_order;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) result = acpi_power_get_state(handle, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) acpi_device_bid(device), state ? "on" : "off");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) device->flags.match_driver = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) result = acpi_device_add(device, acpi_release_power_resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) if (!device_create_file(&device->dev, &dev_attr_resource_in_use))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) device->remove = acpi_power_sysfs_remove;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) acpi_power_add_resource_to_list(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) acpi_device_add_finalize(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) acpi_release_power_resource(&device->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) #ifdef CONFIG_ACPI_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) void acpi_resume_power_resources(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) struct acpi_power_resource *resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) mutex_lock(&power_resource_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) list_for_each_entry(resource, &acpi_power_resource_list, list_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) int result, state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) mutex_lock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) result = acpi_power_get_state(resource->device.handle, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) if (result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) mutex_unlock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) if (state == ACPI_POWER_RESOURCE_STATE_OFF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) && resource->ref_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) dev_info(&resource->device.dev, "Turning ON\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) __acpi_power_on(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) mutex_unlock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) mutex_unlock(&power_resource_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) void acpi_turn_off_unused_power_resources(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) struct acpi_power_resource *resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) mutex_lock(&power_resource_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) list_for_each_entry_reverse(resource, &acpi_power_resource_list, list_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) int result, state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) mutex_lock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) result = acpi_power_get_state(resource->device.handle, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) if (result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) mutex_unlock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) if (state == ACPI_POWER_RESOURCE_STATE_ON
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) && !resource->ref_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) dev_info(&resource->device.dev, "Turning OFF\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) __acpi_power_off(resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) mutex_unlock(&resource->resource_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) mutex_unlock(&power_resource_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) #endif