11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * acpi_power.c - ACPI Bus Power Management ($Revision: 39 $) 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or (at 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * your option) any later version. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * General Public License for more details. 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License along 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with this program; if not, write to the Free Software Foundation, Inc., 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ACPI power-managed devices may be controlled in two ways: 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. via "Device Specific (D-State) Control" 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. via "Power Resource Control". 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This module is used to manage devices relying on Power Resource Control. 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * An ACPI "power resource object" describes a software controllable power 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * plane, clock plane, or other resource used by a power managed device. 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A device may rely on multiple power resources, and a power resource 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * may be shared by multiple devices. 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 425a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 430090def6c37c8ea29508a435e581f2ef26fea10fLin Ming#include <linux/pm_runtime.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_bus.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_drivers.h> 469b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki#include "sleep.h" 470090def6c37c8ea29508a435e581f2ef26fea10fLin Ming#include "internal.h" 489b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki 49a192a9580bcc41692be1f36b77c3b681827f566aLen Brown#define PREFIX "ACPI: " 50a192a9580bcc41692be1f36b77c3b681827f566aLen Brown 5189595b8f2850a080d290bf778ec933ea1d99f78eBjorn Helgaas#define _COMPONENT ACPI_POWER_COMPONENT 52f52fd66d2ea794010c2d7536cf8e6abed0ac4947Len BrownACPI_MODULE_NAME("power"); 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_POWER_CLASS "power_resource" 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_POWER_DEVICE_NAME "Power Resource" 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_POWER_FILE_INFO "info" 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_POWER_FILE_STATUS "state" 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_POWER_RESOURCE_STATE_OFF 0x00 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_POWER_RESOURCE_STATE_ON 0x01 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF 60f5adfaa372c76423b6e8e4727a9701330374f364Zhao Yakui 614be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_power_add(struct acpi_device *device); 624be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_power_remove(struct acpi_device *device, int type); 63e8363f332757ac22395fb120cc33b3262f9ee26cLen Brownstatic int acpi_power_resume(struct acpi_device *device); 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65c97adf9e7bebf17a86b95e2131bf9ba76c4857c7Márton Némethstatic const struct acpi_device_id power_device_ids[] = { 661ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger {ACPI_POWER_HID, 0}, 671ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger {"", 0}, 681ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger}; 691ba90e3a87c46500623afdc3898573e4a5ebb21bThomas RenningerMODULE_DEVICE_TABLE(acpi, power_device_ids); 701ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct acpi_driver acpi_power_driver = { 72c2b6705b75d9c7aff98a4602a32230639e10891cLen Brown .name = "power", 734be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .class = ACPI_POWER_CLASS, 741ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger .ids = power_device_ids, 754be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .ops = { 764be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .add = acpi_power_add, 774be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown .remove = acpi_power_remove, 780a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov .resume = acpi_power_resume, 794be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown }, 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 820090def6c37c8ea29508a435e581f2ef26fea10fLin Ming/* 830090def6c37c8ea29508a435e581f2ef26fea10fLin Ming * A power managed device 840090def6c37c8ea29508a435e581f2ef26fea10fLin Ming * A device may rely on multiple power resources. 850090def6c37c8ea29508a435e581f2ef26fea10fLin Ming * */ 860090def6c37c8ea29508a435e581f2ef26fea10fLin Mingstruct acpi_power_managed_device { 870090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct device *dev; /* The physical device */ 880090def6c37c8ea29508a435e581f2ef26fea10fLin Ming acpi_handle *handle; 890090def6c37c8ea29508a435e581f2ef26fea10fLin Ming}; 900090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 910090def6c37c8ea29508a435e581f2ef26fea10fLin Mingstruct acpi_power_resource_device { 920090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct acpi_power_managed_device *device; 930090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct acpi_power_resource_device *next; 940090def6c37c8ea29508a435e581f2ef26fea10fLin Ming}; 950090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 964be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstruct acpi_power_resource { 97415985728895ba3127116bc4f999caf94420ed85Patrick Mochel struct acpi_device * device; 984be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_bus_id name; 994be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u32 system_level; 1004be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown u32 order; 1013e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki unsigned int ref_count; 1020a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov struct mutex resource_lock; 1030090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 1040090def6c37c8ea29508a435e581f2ef26fea10fLin Ming /* List of devices relying on this power resource */ 1050090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct acpi_power_resource_device *devices; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1084be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic struct list_head acpi_power_resource_list; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Power Resource Management 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 1154be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_power_get_context(acpi_handle handle, 1164be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_power_resource **resource) 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1184be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int result = 0; 1194be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_device *device = NULL; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!resource) 123d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_bus_get_device(handle, &device); 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 127cece92969762b8ed7930d4e23008b76b06411deeLen Brown printk(KERN_WARNING PREFIX "Getting context [%p]\n", handle); 128d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13150dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt *resource = acpi_driver_data(device); 132a815ab8b5891f3d2515316655729272f68269e3bLi Zefan if (!*resource) 133d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 135d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 138a51e145f379ae48003129610922595893e8efde0Zhao Yakuistatic int acpi_power_get_state(acpi_handle handle, int *state) 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1404be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status = AE_OK; 14127663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox unsigned long long sta = 0; 14260a4ce7f4148155d3f28eea4a213f7ee47cd57b7Lin Ming char node_name[5]; 14360a4ce7f4148155d3f28eea4a213f7ee47cd57b7Lin Ming struct acpi_buffer buffer = { sizeof(node_name), node_name }; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 146a51e145f379ae48003129610922595893e8efde0Zhao Yakui if (!handle || !state) 147d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 149a51e145f379ae48003129610922595893e8efde0Zhao Yakui status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) 151d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 153c35923bc558074d4f5e6f9706e4cb9811ae55775Alexey Starikovskiy *state = (sta & 0x01)?ACPI_POWER_RESOURCE_STATE_ON: 154c35923bc558074d4f5e6f9706e4cb9811ae55775Alexey Starikovskiy ACPI_POWER_RESOURCE_STATE_OFF; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15660a4ce7f4148155d3f28eea4a213f7ee47cd57b7Lin Ming acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); 15760a4ce7f4148155d3f28eea4a213f7ee47cd57b7Lin Ming 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n", 15960a4ce7f4148155d3f28eea4a213f7ee47cd57b7Lin Ming node_name, 160b1b57fbe9bb10d94682a975456de7a727d1dbc84Zhao Yakui *state ? "on" : "off")); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 162d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1654be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 167d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki int cur_state; 168d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki int i = 0; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!list || !state) 171d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The state of the list is 'on' IFF all resources are 'on'. */ 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1754be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown for (i = 0; i < list->count; i++) { 176d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki struct acpi_power_resource *resource; 177d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki acpi_handle handle = list->handles[i]; 178d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki int result; 179d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki 180d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki result = acpi_power_get_context(handle, &resource); 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 182d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 184d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki mutex_lock(&resource->resource_lock); 185d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki 186d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki result = acpi_power_get_state(handle, &cur_state); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 188d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki mutex_unlock(&resource->resource_lock); 189d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki 190d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki if (result) 191d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki return result; 192d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki 193d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki if (cur_state != ACPI_POWER_RESOURCE_STATE_ON) 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n", 198d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki cur_state ? "on" : "off")); 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 200d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki *state = cur_state; 201d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki 202d0515d9fec68bace144fda57a69f4268fb875209Rafael J. Wysocki return 0; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2050090def6c37c8ea29508a435e581f2ef26fea10fLin Ming/* Resume the device when all power resources in _PR0 are on */ 2060090def6c37c8ea29508a435e581f2ef26fea10fLin Mingstatic void acpi_power_on_device(struct acpi_power_managed_device *device) 2070090def6c37c8ea29508a435e581f2ef26fea10fLin Ming{ 2080090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct acpi_device *acpi_dev; 2090090def6c37c8ea29508a435e581f2ef26fea10fLin Ming acpi_handle handle = device->handle; 2100090def6c37c8ea29508a435e581f2ef26fea10fLin Ming int state; 2110090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 2120090def6c37c8ea29508a435e581f2ef26fea10fLin Ming if (acpi_bus_get_device(handle, &acpi_dev)) 2130090def6c37c8ea29508a435e581f2ef26fea10fLin Ming return; 2140090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 2150090def6c37c8ea29508a435e581f2ef26fea10fLin Ming if(acpi_power_get_inferred_state(acpi_dev, &state)) 2160090def6c37c8ea29508a435e581f2ef26fea10fLin Ming return; 2170090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 2180090def6c37c8ea29508a435e581f2ef26fea10fLin Ming if (state == ACPI_STATE_D0 && pm_runtime_suspended(device->dev)) 2190090def6c37c8ea29508a435e581f2ef26fea10fLin Ming pm_request_resume(device->dev); 2200090def6c37c8ea29508a435e581f2ef26fea10fLin Ming} 2210090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 2223e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysockistatic int __acpi_power_on(struct acpi_power_resource *resource) 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2240090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct acpi_power_resource_device *device_list = resource->devices; 2254be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status = AE_OK; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2273e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL); 2283e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (ACPI_FAILURE(status)) 2293e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki return -ENODEV; 2303e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki 2313e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki /* Update the power resource's _device_ power state */ 2323e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki resource->device->power.state = ACPI_STATE_D0; 2333e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki 2343e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n", 2353e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki resource->name)); 2363e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki 2370090def6c37c8ea29508a435e581f2ef26fea10fLin Ming while (device_list) { 2380090def6c37c8ea29508a435e581f2ef26fea10fLin Ming acpi_power_on_device(device_list->device); 2390090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 2400090def6c37c8ea29508a435e581f2ef26fea10fLin Ming device_list = device_list->next; 2410090def6c37c8ea29508a435e581f2ef26fea10fLin Ming } 2420090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 2433e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki return 0; 2443e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki} 2453e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki 2463e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysockistatic int acpi_power_on(acpi_handle handle) 2473e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki{ 2483e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki int result = 0; 2493e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki struct acpi_power_resource *resource = NULL; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_power_get_context(handle, &resource); 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 253d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2550a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov mutex_lock(&resource->resource_lock); 2560a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 2573e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (resource->ref_count++) { 2583e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki ACPI_DEBUG_PRINT((ACPI_DB_INFO, 2593e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki "Power resource [%s] already on", 2603e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki resource->name)); 2613e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki } else { 2623e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki result = __acpi_power_on(resource); 26312b3b5afed67e08aa641d30e57df20dab2e33432Rafael J. Wysocki if (result) 26412b3b5afed67e08aa641d30e57df20dab2e33432Rafael J. Wysocki resource->ref_count--; 2650a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov } 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2673e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki mutex_unlock(&resource->resource_lock); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26912b3b5afed67e08aa641d30e57df20dab2e33432Rafael J. Wysocki return result; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27236237fa0a711c309a38d7a7a9aed727e0eb76449Rafael J. Wysockistatic int acpi_power_off(acpi_handle handle) 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 274bdf43bbf2e19952d82995a50e00cb4b66afa4f0cBjorn Helgaas int result = 0; 2754be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status = AE_OK; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpi_power_resource *resource = NULL; 2770a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_power_get_context(handle, &resource); 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 280d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2820a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov mutex_lock(&resource->resource_lock); 2833e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki 2843e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (!resource->ref_count) { 2853e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki ACPI_DEBUG_PRINT((ACPI_DB_INFO, 2863e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki "Power resource [%s] already off", 2873e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki resource->name)); 2883e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki goto unlock; 2890a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov } 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2913e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (--resource->ref_count) { 2923e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki ACPI_DEBUG_PRINT((ACPI_DB_INFO, 2933e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki "Power resource [%s] still in use\n", 2943e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki resource->name)); 2953e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki goto unlock; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2985fbc19efdbedf9c9125774f66f80d6a6ccce4566Patrick Mochel status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL); 2993e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (ACPI_FAILURE(status)) { 3003e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki result = -ENODEV; 3013e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki } else { 3023e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki /* Update the power resource's _device_ power state */ 3033e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki resource->device->power.state = ACPI_STATE_D3; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3053e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki ACPI_DEBUG_PRINT((ACPI_DB_INFO, 3063e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki "Power resource [%s] turned off\n", 3073e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki resource->name)); 3083e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki } 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3103e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki unlock: 3113e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki mutex_unlock(&resource->resource_lock); 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3133e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki return result; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 316d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysockistatic void __acpi_power_off_list(struct acpi_handle_list *list, int num_res) 317d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki{ 318d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki int i; 319d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki 320d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki for (i = num_res - 1; i >= 0 ; i--) 32136237fa0a711c309a38d7a7a9aed727e0eb76449Rafael J. Wysocki acpi_power_off(list->handles[i]); 322d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki} 323d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki 324d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysockistatic void acpi_power_off_list(struct acpi_handle_list *list) 325d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki{ 326d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki __acpi_power_off_list(list, list->count); 327d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki} 328d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki 329d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysockistatic int acpi_power_on_list(struct acpi_handle_list *list) 330d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki{ 331d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki int result = 0; 332d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki int i; 333d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki 334d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki for (i = 0; i < list->count; i++) { 335d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki result = acpi_power_on(list->handles[i]); 336d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki if (result) { 337d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki __acpi_power_off_list(list, i); 338d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki break; 339d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki } 340d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki } 341d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki 342d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki return result; 343d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki} 344d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki 3450090def6c37c8ea29508a435e581f2ef26fea10fLin Mingstatic void __acpi_power_resource_unregister_device(struct device *dev, 3460090def6c37c8ea29508a435e581f2ef26fea10fLin Ming acpi_handle res_handle) 3470090def6c37c8ea29508a435e581f2ef26fea10fLin Ming{ 3480090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct acpi_power_resource *resource = NULL; 3490090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct acpi_power_resource_device *prev, *curr; 3500090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 3510090def6c37c8ea29508a435e581f2ef26fea10fLin Ming if (acpi_power_get_context(res_handle, &resource)) 3520090def6c37c8ea29508a435e581f2ef26fea10fLin Ming return; 3530090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 3540090def6c37c8ea29508a435e581f2ef26fea10fLin Ming mutex_lock(&resource->resource_lock); 3550090def6c37c8ea29508a435e581f2ef26fea10fLin Ming prev = NULL; 3560090def6c37c8ea29508a435e581f2ef26fea10fLin Ming curr = resource->devices; 3570090def6c37c8ea29508a435e581f2ef26fea10fLin Ming while (curr) { 3580090def6c37c8ea29508a435e581f2ef26fea10fLin Ming if (curr->device->dev == dev) { 3590090def6c37c8ea29508a435e581f2ef26fea10fLin Ming if (!prev) 3600090def6c37c8ea29508a435e581f2ef26fea10fLin Ming resource->devices = curr->next; 3610090def6c37c8ea29508a435e581f2ef26fea10fLin Ming else 3620090def6c37c8ea29508a435e581f2ef26fea10fLin Ming prev->next = curr->next; 3630090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 3640090def6c37c8ea29508a435e581f2ef26fea10fLin Ming kfree(curr); 3650090def6c37c8ea29508a435e581f2ef26fea10fLin Ming break; 3660090def6c37c8ea29508a435e581f2ef26fea10fLin Ming } 3670090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 3680090def6c37c8ea29508a435e581f2ef26fea10fLin Ming prev = curr; 3690090def6c37c8ea29508a435e581f2ef26fea10fLin Ming curr = curr->next; 3700090def6c37c8ea29508a435e581f2ef26fea10fLin Ming } 3710090def6c37c8ea29508a435e581f2ef26fea10fLin Ming mutex_unlock(&resource->resource_lock); 3720090def6c37c8ea29508a435e581f2ef26fea10fLin Ming} 3730090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 3740090def6c37c8ea29508a435e581f2ef26fea10fLin Ming/* Unlink dev from all power resources in _PR0 */ 3750090def6c37c8ea29508a435e581f2ef26fea10fLin Mingvoid acpi_power_resource_unregister_device(struct device *dev, acpi_handle handle) 3760090def6c37c8ea29508a435e581f2ef26fea10fLin Ming{ 3770090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct acpi_device *acpi_dev; 3780090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct acpi_handle_list *list; 3790090def6c37c8ea29508a435e581f2ef26fea10fLin Ming int i; 3800090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 3810090def6c37c8ea29508a435e581f2ef26fea10fLin Ming if (!dev || !handle) 3820090def6c37c8ea29508a435e581f2ef26fea10fLin Ming return; 3830090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 3840090def6c37c8ea29508a435e581f2ef26fea10fLin Ming if (acpi_bus_get_device(handle, &acpi_dev)) 3850090def6c37c8ea29508a435e581f2ef26fea10fLin Ming return; 3860090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 3870090def6c37c8ea29508a435e581f2ef26fea10fLin Ming list = &acpi_dev->power.states[ACPI_STATE_D0].resources; 3880090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 3890090def6c37c8ea29508a435e581f2ef26fea10fLin Ming for (i = 0; i < list->count; i++) 3900090def6c37c8ea29508a435e581f2ef26fea10fLin Ming __acpi_power_resource_unregister_device(dev, 3910090def6c37c8ea29508a435e581f2ef26fea10fLin Ming list->handles[i]); 3920090def6c37c8ea29508a435e581f2ef26fea10fLin Ming} 3930090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 3940090def6c37c8ea29508a435e581f2ef26fea10fLin Mingstatic int __acpi_power_resource_register_device( 3950090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct acpi_power_managed_device *powered_device, acpi_handle handle) 3960090def6c37c8ea29508a435e581f2ef26fea10fLin Ming{ 3970090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct acpi_power_resource *resource = NULL; 3980090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct acpi_power_resource_device *power_resource_device; 3990090def6c37c8ea29508a435e581f2ef26fea10fLin Ming int result; 4000090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4010090def6c37c8ea29508a435e581f2ef26fea10fLin Ming result = acpi_power_get_context(handle, &resource); 4020090def6c37c8ea29508a435e581f2ef26fea10fLin Ming if (result) 4030090def6c37c8ea29508a435e581f2ef26fea10fLin Ming return result; 4040090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4050090def6c37c8ea29508a435e581f2ef26fea10fLin Ming power_resource_device = kzalloc( 4060090def6c37c8ea29508a435e581f2ef26fea10fLin Ming sizeof(*power_resource_device), GFP_KERNEL); 4070090def6c37c8ea29508a435e581f2ef26fea10fLin Ming if (!power_resource_device) 4080090def6c37c8ea29508a435e581f2ef26fea10fLin Ming return -ENOMEM; 4090090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4100090def6c37c8ea29508a435e581f2ef26fea10fLin Ming power_resource_device->device = powered_device; 4110090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4120090def6c37c8ea29508a435e581f2ef26fea10fLin Ming mutex_lock(&resource->resource_lock); 4130090def6c37c8ea29508a435e581f2ef26fea10fLin Ming power_resource_device->next = resource->devices; 4140090def6c37c8ea29508a435e581f2ef26fea10fLin Ming resource->devices = power_resource_device; 4150090def6c37c8ea29508a435e581f2ef26fea10fLin Ming mutex_unlock(&resource->resource_lock); 4160090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4170090def6c37c8ea29508a435e581f2ef26fea10fLin Ming return 0; 4180090def6c37c8ea29508a435e581f2ef26fea10fLin Ming} 4190090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4200090def6c37c8ea29508a435e581f2ef26fea10fLin Ming/* Link dev to all power resources in _PR0 */ 4210090def6c37c8ea29508a435e581f2ef26fea10fLin Mingint acpi_power_resource_register_device(struct device *dev, acpi_handle handle) 4220090def6c37c8ea29508a435e581f2ef26fea10fLin Ming{ 4230090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct acpi_device *acpi_dev; 4240090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct acpi_handle_list *list; 4250090def6c37c8ea29508a435e581f2ef26fea10fLin Ming struct acpi_power_managed_device *powered_device; 4260090def6c37c8ea29508a435e581f2ef26fea10fLin Ming int i, ret; 4270090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4280090def6c37c8ea29508a435e581f2ef26fea10fLin Ming if (!dev || !handle) 4290090def6c37c8ea29508a435e581f2ef26fea10fLin Ming return -ENODEV; 4300090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4310090def6c37c8ea29508a435e581f2ef26fea10fLin Ming ret = acpi_bus_get_device(handle, &acpi_dev); 4320090def6c37c8ea29508a435e581f2ef26fea10fLin Ming if (ret) 4330090def6c37c8ea29508a435e581f2ef26fea10fLin Ming goto no_power_resource; 4340090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4350090def6c37c8ea29508a435e581f2ef26fea10fLin Ming if (!acpi_dev->power.flags.power_resources) 4360090def6c37c8ea29508a435e581f2ef26fea10fLin Ming goto no_power_resource; 4370090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4380090def6c37c8ea29508a435e581f2ef26fea10fLin Ming powered_device = kzalloc(sizeof(*powered_device), GFP_KERNEL); 4390090def6c37c8ea29508a435e581f2ef26fea10fLin Ming if (!powered_device) 4400090def6c37c8ea29508a435e581f2ef26fea10fLin Ming return -ENOMEM; 4410090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4420090def6c37c8ea29508a435e581f2ef26fea10fLin Ming powered_device->dev = dev; 4430090def6c37c8ea29508a435e581f2ef26fea10fLin Ming powered_device->handle = handle; 4440090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4450090def6c37c8ea29508a435e581f2ef26fea10fLin Ming list = &acpi_dev->power.states[ACPI_STATE_D0].resources; 4460090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4470090def6c37c8ea29508a435e581f2ef26fea10fLin Ming for (i = 0; i < list->count; i++) { 4480090def6c37c8ea29508a435e581f2ef26fea10fLin Ming ret = __acpi_power_resource_register_device(powered_device, 4490090def6c37c8ea29508a435e581f2ef26fea10fLin Ming list->handles[i]); 4500090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4510090def6c37c8ea29508a435e581f2ef26fea10fLin Ming if (ret) { 4520090def6c37c8ea29508a435e581f2ef26fea10fLin Ming acpi_power_resource_unregister_device(dev, handle); 4530090def6c37c8ea29508a435e581f2ef26fea10fLin Ming break; 4540090def6c37c8ea29508a435e581f2ef26fea10fLin Ming } 4550090def6c37c8ea29508a435e581f2ef26fea10fLin Ming } 4560090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4570090def6c37c8ea29508a435e581f2ef26fea10fLin Ming return ret; 4580090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 4590090def6c37c8ea29508a435e581f2ef26fea10fLin Mingno_power_resource: 4600090def6c37c8ea29508a435e581f2ef26fea10fLin Ming printk(KERN_WARNING PREFIX "Invalid Power Resource to register!"); 4610090def6c37c8ea29508a435e581f2ef26fea10fLin Ming return -ENODEV; 4620090def6c37c8ea29508a435e581f2ef26fea10fLin Ming} 4630090def6c37c8ea29508a435e581f2ef26fea10fLin Ming 46477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki/** 46577e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in 46677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * ACPI 3.0) _PSW (Power State Wake) 46777e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * @dev: Device to handle. 46877e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * @enable: 0 - disable, 1 - enable the wake capabilities of the device. 46977e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * @sleep_state: Target sleep state of the system. 47077e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * @dev_state: Target power state of the device. 47177e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * 47277e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power 47377e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * State Wake) for the device, if present. On failure reset the device's 47477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * wakeup.flags.valid flag. 47577e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * 47677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * RETURN VALUE: 47777e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * 0 if either _DSW or _PSW has been successfully executed 47877e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * 0 if neither _DSW nor _PSW has been found 47977e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * -ENODEV if the execution of either _DSW or _PSW has failed 48077e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki */ 48177e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysockiint acpi_device_sleep_wake(struct acpi_device *dev, 48277e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki int enable, int sleep_state, int dev_state) 48377e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki{ 48477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki union acpi_object in_arg[3]; 48577e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki struct acpi_object_list arg_list = { 3, in_arg }; 48677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki acpi_status status = AE_OK; 48777e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki 48877e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki /* 48977e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * Try to execute _DSW first. 49077e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * 49177e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * Three agruments are needed for the _DSW object: 49277e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * Argument 0: enable/disable the wake capabilities 49377e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * Argument 1: target system state 49477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * Argument 2: target device state 49577e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * When _DSW object is called to disable the wake capabilities, maybe 49677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * the first argument is filled. The values of the other two agruments 49777e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * are meaningless. 49877e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki */ 49977e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki in_arg[0].type = ACPI_TYPE_INTEGER; 50077e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki in_arg[0].integer.value = enable; 50177e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki in_arg[1].type = ACPI_TYPE_INTEGER; 50277e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki in_arg[1].integer.value = sleep_state; 50377e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki in_arg[2].type = ACPI_TYPE_INTEGER; 50477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki in_arg[2].integer.value = dev_state; 50577e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki status = acpi_evaluate_object(dev->handle, "_DSW", &arg_list, NULL); 50677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki if (ACPI_SUCCESS(status)) { 50777e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki return 0; 50877e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki } else if (status != AE_NOT_FOUND) { 50977e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki printk(KERN_ERR PREFIX "_DSW execution failed\n"); 51077e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki dev->wakeup.flags.valid = 0; 51177e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki return -ENODEV; 51277e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki } 51377e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki 51477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki /* Execute _PSW */ 51577e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki arg_list.count = 1; 51677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki in_arg[0].integer.value = enable; 51777e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL); 51877e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { 51977e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki printk(KERN_ERR PREFIX "_PSW execution failed\n"); 52077e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki dev->wakeup.flags.valid = 0; 52177e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki return -ENODEV; 52277e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki } 52377e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki 52477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki return 0; 52577e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki} 52677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prepare a wakeup device, two steps (Ref ACPI 2.0:P229): 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. Power on the power resources required for the wakeup device 53077e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * 2. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power 53177e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * State Wake) for the device, if present 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53377e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysockiint acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5359b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki int i, err = 0; 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev || !dev->wakeup.flags.valid) 53877e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki return -EINVAL; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5409b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki mutex_lock(&acpi_device_lock); 5419b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki 5429b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki if (dev->wakeup.prepare_count++) 5439b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki goto out; 5440af4b8c4fb31193dc666f4893107a18fef82baabRafael J. Wysocki 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Open power resource */ 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < dev->wakeup.resources.count; i++) { 5473e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki int ret = acpi_power_on(dev->wakeup.resources.handles[i]); 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 5496468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Transition power state\n"); 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->wakeup.flags.valid = 0; 5519b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki err = -ENODEV; 5529b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki goto err_out; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55677e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki /* 55777e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * Passing 3 as the third argument below means the device may be placed 55877e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * in arbitrary power state afterwards. 55977e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki */ 5600af4b8c4fb31193dc666f4893107a18fef82baabRafael J. Wysocki err = acpi_device_sleep_wake(dev, 1, sleep_state, 3); 5610af4b8c4fb31193dc666f4893107a18fef82baabRafael J. Wysocki 5629b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki err_out: 5639b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki if (err) 5649b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki dev->wakeup.prepare_count = 0; 5659b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki 5669b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki out: 5679b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki mutex_unlock(&acpi_device_lock); 5680af4b8c4fb31193dc666f4893107a18fef82baabRafael J. Wysocki return err; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Shutdown a wakeup device, counterpart of above method 57377e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * 1. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power 57477e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki * State Wake) for the device, if present 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. Shutdown down the power resources 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5774be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint acpi_disable_wakeup_device_power(struct acpi_device *dev) 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5799b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki int i, err = 0; 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev || !dev->wakeup.flags.valid) 58277e766099efc29d8b01db4b8244ff64fa3d3d0caRafael J. Wysocki return -EINVAL; 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5849b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki mutex_lock(&acpi_device_lock); 5859b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki 5869b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki if (--dev->wakeup.prepare_count > 0) 5879b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki goto out; 5889b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki 5890af4b8c4fb31193dc666f4893107a18fef82baabRafael J. Wysocki /* 5909b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki * Executing the code below even if prepare_count is already zero when 5919b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki * the function is called may be useful, for example for initialisation. 5920af4b8c4fb31193dc666f4893107a18fef82baabRafael J. Wysocki */ 5939b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki if (dev->wakeup.prepare_count < 0) 5949b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki dev->wakeup.prepare_count = 0; 5950af4b8c4fb31193dc666f4893107a18fef82baabRafael J. Wysocki 5969b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki err = acpi_device_sleep_wake(dev, 0, 0, 0); 5979b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki if (err) 5989b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki goto out; 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Close power resource */ 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < dev->wakeup.resources.count; i++) { 60236237fa0a711c309a38d7a7a9aed727e0eb76449Rafael J. Wysocki int ret = acpi_power_off(dev->wakeup.resources.handles[i]); 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 6046468463abd7051fcc29f3ee7c931f9bbbb26f5a4Len Brown printk(KERN_ERR PREFIX "Transition power state\n"); 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->wakeup.flags.valid = 0; 6069b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki err = -ENODEV; 6079b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki goto out; 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6119b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki out: 6129b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki mutex_unlock(&acpi_device_lock); 6139b83ccd2f14f647936dcfbf4a9a20c501007dd69Rafael J. Wysocki return err; 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Device Power Management 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62032a00d274e877eab3ea7ab196b75c9be5170d25eRafael J. Wysockiint acpi_power_get_inferred_state(struct acpi_device *device, int *state) 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6224be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int result = 0; 6234be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_handle_list *list = NULL; 6244be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int list_state = 0; 6254be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown int i = 0; 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62732a00d274e877eab3ea7ab196b75c9be5170d25eRafael J. Wysocki if (!device || !state) 628d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We know a device's inferred power state when all the resources 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * required for a given D-state are 'on'. 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6341cc0c998fdf2cb665d625fb565a0d6db5c81c639Lin Ming for (i = ACPI_STATE_D0; i < ACPI_STATE_D3_HOT; i++) { 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list = &device->power.states[i].resources; 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (list->count < 1) 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = acpi_power_get_list_state(list, &list_state); 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 641d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (list_state == ACPI_POWER_RESOURCE_STATE_ON) { 64432a00d274e877eab3ea7ab196b75c9be5170d25eRafael J. Wysocki *state = i; 645d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64932a00d274e877eab3ea7ab196b75c9be5170d25eRafael J. Wysocki *state = ACPI_STATE_D3; 650d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65330d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysockiint acpi_power_on_resources(struct acpi_device *device, int state) 65430d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysocki{ 65530d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysocki if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3) 65630d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysocki return -EINVAL; 65730d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysocki 65830d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysocki return acpi_power_on_list(&device->power.states[state].resources); 65930d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysocki} 66030d3df41b32b1ea63d3ebc52ef5644cbe41520f4Rafael J. Wysocki 6614be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint acpi_power_transition(struct acpi_device *device, int state) 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6635c7dd710f691d1b44c39e32d2f05b4286ff51f99Rafael J. Wysocki int result = 0; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6653ebc81b8937d2bc1d0d0064bed29434dfce490aaZhang Rui if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD)) 666d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 668212967c69afd348342548272aedbe4d46a9325d6Rafael J. Wysocki if (device->power.state == state) 669212967c69afd348342548272aedbe4d46a9325d6Rafael J. Wysocki return 0; 670212967c69afd348342548272aedbe4d46a9325d6Rafael J. Wysocki 6714be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown if ((device->power.state < ACPI_STATE_D0) 6723ebc81b8937d2bc1d0d0064bed29434dfce490aaZhang Rui || (device->power.state > ACPI_STATE_D3_COLD)) 673d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENODEV; 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TBD: Resources must be ordered. */ 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First we reference all power resources required in the target list 679d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki * (e.g. so the device doesn't lose power while transitioning). Then, 680d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki * we dereference all power resources used in the current list. 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6825c7dd710f691d1b44c39e32d2f05b4286ff51f99Rafael J. Wysocki if (state < ACPI_STATE_D3_COLD) 6835c7dd710f691d1b44c39e32d2f05b4286ff51f99Rafael J. Wysocki result = acpi_power_on_list( 6845c7dd710f691d1b44c39e32d2f05b4286ff51f99Rafael J. Wysocki &device->power.states[state].resources); 6855c7dd710f691d1b44c39e32d2f05b4286ff51f99Rafael J. Wysocki 6865c7dd710f691d1b44c39e32d2f05b4286ff51f99Rafael J. Wysocki if (!result && device->power.state < ACPI_STATE_D3_COLD) 687d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki acpi_power_off_list( 688d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki &device->power.states[device->power.state].resources); 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 690d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki /* We shouldn't change the state unless the above operations succeed. */ 691d2ef555b57292cd818934636ac8e3414cc2a6762Rafael J. Wysocki device->power.state = result ? ACPI_STATE_UNKNOWN : state; 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 693d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------------------------------------------------------------- 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Driver Interface 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -------------------------------------------------------------------------- */ 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7004be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_power_add(struct acpi_device *device) 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 702c35923bc558074d4f5e6f9706e4cb9811ae55775Alexey Starikovskiy int result = 0, state; 7034be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown acpi_status status = AE_OK; 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct acpi_power_resource *resource = NULL; 7054be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown union acpi_object acpi_object; 7064be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object }; 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!device) 710d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71236bcbec7ce21e2e8b3143b11a05747330abeca70Burman Yan resource = kzalloc(sizeof(struct acpi_power_resource), GFP_KERNEL); 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!resource) 714d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -ENOMEM; 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 716415985728895ba3127116bc4f999caf94420ed85Patrick Mochel resource->device = device; 7170a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov mutex_init(&resource->resource_lock); 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(resource->name, device->pnp.bus_id); 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(acpi_device_class(device), ACPI_POWER_CLASS); 721db89b4f0dbab837d0f3de2c3e9427a8d5393afa3Pavel Machek device->driver_data = resource; 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Evalute the object to get the system level and resource order. */ 7245fbc19efdbedf9c9125774f66f80d6a6ccce4566Patrick Mochel status = acpi_evaluate_object(device->handle, NULL, NULL, &buffer); 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ACPI_FAILURE(status)) { 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -ENODEV; 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->system_level = acpi_object.power_resource.system_level; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resource->order = acpi_object.power_resource.resource_order; 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 732a51e145f379ae48003129610922595893e8efde0Zhao Yakui result = acpi_power_get_state(device->handle, &state); 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto end; 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 736c35923bc558074d4f5e6f9706e4cb9811ae55775Alexey Starikovskiy switch (state) { 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_POWER_RESOURCE_STATE_ON: 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device->power.state = ACPI_STATE_D0; 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ACPI_POWER_RESOURCE_STATE_OFF: 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device->power.state = ACPI_STATE_D3; 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device->power.state = ACPI_STATE_UNKNOWN; 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device), 749c35923bc558074d4f5e6f9706e4cb9811ae55775Alexey Starikovskiy acpi_device_bid(device), state ? "on" : "off"); 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7514be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown end: 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(resource); 7544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown 755d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return result; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7584be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_power_remove(struct acpi_device *device, int type) 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7603e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki struct acpi_power_resource *resource; 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7623e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (!device) 763d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return -EINVAL; 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 76550dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt resource = acpi_driver_data(device); 7663e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (!resource) 7673e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki return -EINVAL; 7680a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(resource); 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 774e8363f332757ac22395fb120cc33b3262f9ee26cLen Brownstatic int acpi_power_resume(struct acpi_device *device) 7750a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov{ 776c35923bc558074d4f5e6f9706e4cb9811ae55775Alexey Starikovskiy int result = 0, state; 7773e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki struct acpi_power_resource *resource; 7780a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 7793e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (!device) 7800a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov return -EINVAL; 7810a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 782db89b4f0dbab837d0f3de2c3e9427a8d5393afa3Pavel Machek resource = acpi_driver_data(device); 7833e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (!resource) 7843e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki return -EINVAL; 7853e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki 7863e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki mutex_lock(&resource->resource_lock); 7870a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 788a51e145f379ae48003129610922595893e8efde0Zhao Yakui result = acpi_power_get_state(device->handle, &state); 7890a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov if (result) 7903e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki goto unlock; 7910a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 7923e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count) 7933e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki result = __acpi_power_on(resource); 7940a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 7953e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki unlock: 7960a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov mutex_unlock(&resource->resource_lock); 7973e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki 7983e384ee6c687cb397581ee8f9440fc8220cfac80Rafael J. Wysocki return result; 7990a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov} 8000a6139027f3986162233adc17285151e78b39cacKonstantin Karasyov 80144515374cba9e46d5622256b43eb06b9c349cee1Bjorn Helgaasint __init acpi_power_init(void) 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&acpi_power_resource_list); 80406af7eb043c02822072cea862fce1b7c74115e8fZhang Rui return acpi_bus_register_driver(&acpi_power_driver); 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 806