Path: blob/master/drivers/hwmon/acpi_power_meter.c
15109 views
/*1* A hwmon driver for ACPI 4.0 power meters2* Copyright (C) 2009 IBM3*4* Author: Darrick J. Wong <[email protected]>5*6* This program is free software; you can redistribute it and/or modify7* it under the terms of the GNU General Public License as published by8* the Free Software Foundation; either version 2 of the License, or9* (at your option) any later version.10*11* This program is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14* GNU General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program; if not, write to the Free Software18* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA19*/2021#include <linux/module.h>22#include <linux/hwmon.h>23#include <linux/hwmon-sysfs.h>24#include <linux/jiffies.h>25#include <linux/mutex.h>26#include <linux/dmi.h>27#include <linux/slab.h>28#include <linux/kdev_t.h>29#include <linux/sched.h>30#include <linux/time.h>31#include <acpi/acpi_drivers.h>32#include <acpi/acpi_bus.h>3334#define ACPI_POWER_METER_NAME "power_meter"35ACPI_MODULE_NAME(ACPI_POWER_METER_NAME);36#define ACPI_POWER_METER_DEVICE_NAME "Power Meter"37#define ACPI_POWER_METER_CLASS "pwr_meter_resource"3839#define NUM_SENSORS 174041#define POWER_METER_CAN_MEASURE (1 << 0)42#define POWER_METER_CAN_TRIP (1 << 1)43#define POWER_METER_CAN_CAP (1 << 2)44#define POWER_METER_CAN_NOTIFY (1 << 3)45#define POWER_METER_IS_BATTERY (1 << 8)46#define UNKNOWN_HYSTERESIS 0xFFFFFFFF4748#define METER_NOTIFY_CONFIG 0x8049#define METER_NOTIFY_TRIP 0x8150#define METER_NOTIFY_CAP 0x8251#define METER_NOTIFY_CAPPING 0x8352#define METER_NOTIFY_INTERVAL 0x845354#define POWER_AVERAGE_NAME "power1_average"55#define POWER_CAP_NAME "power1_cap"56#define POWER_AVG_INTERVAL_NAME "power1_average_interval"57#define POWER_ALARM_NAME "power1_alarm"5859static int cap_in_hardware;60static int force_cap_on;6162static int can_cap_in_hardware(void)63{64return force_cap_on || cap_in_hardware;65}6667static const struct acpi_device_id power_meter_ids[] = {68{"ACPI000D", 0},69{"", 0},70};71MODULE_DEVICE_TABLE(acpi, power_meter_ids);7273struct acpi_power_meter_capabilities {74u64 flags;75u64 units;76u64 type;77u64 accuracy;78u64 sampling_time;79u64 min_avg_interval;80u64 max_avg_interval;81u64 hysteresis;82u64 configurable_cap;83u64 min_cap;84u64 max_cap;85};8687struct acpi_power_meter_resource {88struct acpi_device *acpi_dev;89acpi_bus_id name;90struct mutex lock;91struct device *hwmon_dev;92struct acpi_power_meter_capabilities caps;93acpi_string model_number;94acpi_string serial_number;95acpi_string oem_info;96u64 power;97u64 cap;98u64 avg_interval;99int sensors_valid;100unsigned long sensors_last_updated;101struct sensor_device_attribute sensors[NUM_SENSORS];102int num_sensors;103int trip[2];104int num_domain_devices;105struct acpi_device **domain_devices;106struct kobject *holders_dir;107};108109struct ro_sensor_template {110char *label;111ssize_t (*show)(struct device *dev,112struct device_attribute *devattr,113char *buf);114int index;115};116117struct rw_sensor_template {118char *label;119ssize_t (*show)(struct device *dev,120struct device_attribute *devattr,121char *buf);122ssize_t (*set)(struct device *dev,123struct device_attribute *devattr,124const char *buf, size_t count);125int index;126};127128/* Averaging interval */129static int update_avg_interval(struct acpi_power_meter_resource *resource)130{131unsigned long long data;132acpi_status status;133134status = acpi_evaluate_integer(resource->acpi_dev->handle, "_GAI",135NULL, &data);136if (ACPI_FAILURE(status)) {137ACPI_EXCEPTION((AE_INFO, status, "Evaluating _GAI"));138return -ENODEV;139}140141resource->avg_interval = data;142return 0;143}144145static ssize_t show_avg_interval(struct device *dev,146struct device_attribute *devattr,147char *buf)148{149struct acpi_device *acpi_dev = to_acpi_device(dev);150struct acpi_power_meter_resource *resource = acpi_dev->driver_data;151152mutex_lock(&resource->lock);153update_avg_interval(resource);154mutex_unlock(&resource->lock);155156return sprintf(buf, "%llu\n", resource->avg_interval);157}158159static ssize_t set_avg_interval(struct device *dev,160struct device_attribute *devattr,161const char *buf, size_t count)162{163struct acpi_device *acpi_dev = to_acpi_device(dev);164struct acpi_power_meter_resource *resource = acpi_dev->driver_data;165union acpi_object arg0 = { ACPI_TYPE_INTEGER };166struct acpi_object_list args = { 1, &arg0 };167int res;168unsigned long temp;169unsigned long long data;170acpi_status status;171172res = strict_strtoul(buf, 10, &temp);173if (res)174return res;175176if (temp > resource->caps.max_avg_interval ||177temp < resource->caps.min_avg_interval)178return -EINVAL;179arg0.integer.value = temp;180181mutex_lock(&resource->lock);182status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PAI",183&args, &data);184if (!ACPI_FAILURE(status))185resource->avg_interval = temp;186mutex_unlock(&resource->lock);187188if (ACPI_FAILURE(status)) {189ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PAI"));190return -EINVAL;191}192193/* _PAI returns 0 on success, nonzero otherwise */194if (data)195return -EINVAL;196197return count;198}199200/* Cap functions */201static int update_cap(struct acpi_power_meter_resource *resource)202{203unsigned long long data;204acpi_status status;205206status = acpi_evaluate_integer(resource->acpi_dev->handle, "_GHL",207NULL, &data);208if (ACPI_FAILURE(status)) {209ACPI_EXCEPTION((AE_INFO, status, "Evaluating _GHL"));210return -ENODEV;211}212213resource->cap = data;214return 0;215}216217static ssize_t show_cap(struct device *dev,218struct device_attribute *devattr,219char *buf)220{221struct acpi_device *acpi_dev = to_acpi_device(dev);222struct acpi_power_meter_resource *resource = acpi_dev->driver_data;223224mutex_lock(&resource->lock);225update_cap(resource);226mutex_unlock(&resource->lock);227228return sprintf(buf, "%llu\n", resource->cap * 1000);229}230231static ssize_t set_cap(struct device *dev, struct device_attribute *devattr,232const char *buf, size_t count)233{234struct acpi_device *acpi_dev = to_acpi_device(dev);235struct acpi_power_meter_resource *resource = acpi_dev->driver_data;236union acpi_object arg0 = { ACPI_TYPE_INTEGER };237struct acpi_object_list args = { 1, &arg0 };238int res;239unsigned long temp;240unsigned long long data;241acpi_status status;242243res = strict_strtoul(buf, 10, &temp);244if (res)245return res;246247temp /= 1000;248if (temp > resource->caps.max_cap || temp < resource->caps.min_cap)249return -EINVAL;250arg0.integer.value = temp;251252mutex_lock(&resource->lock);253status = acpi_evaluate_integer(resource->acpi_dev->handle, "_SHL",254&args, &data);255if (!ACPI_FAILURE(status))256resource->cap = temp;257mutex_unlock(&resource->lock);258259if (ACPI_FAILURE(status)) {260ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SHL"));261return -EINVAL;262}263264/* _SHL returns 0 on success, nonzero otherwise */265if (data)266return -EINVAL;267268return count;269}270271/* Power meter trip points */272static int set_acpi_trip(struct acpi_power_meter_resource *resource)273{274union acpi_object arg_objs[] = {275{ACPI_TYPE_INTEGER},276{ACPI_TYPE_INTEGER}277};278struct acpi_object_list args = { 2, arg_objs };279unsigned long long data;280acpi_status status;281282/* Both trip levels must be set */283if (resource->trip[0] < 0 || resource->trip[1] < 0)284return 0;285286/* This driver stores min, max; ACPI wants max, min. */287arg_objs[0].integer.value = resource->trip[1];288arg_objs[1].integer.value = resource->trip[0];289290status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PTP",291&args, &data);292if (ACPI_FAILURE(status)) {293ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTP"));294return -EINVAL;295}296297/* _PTP returns 0 on success, nonzero otherwise */298if (data)299return -EINVAL;300301return 0;302}303304static ssize_t set_trip(struct device *dev, struct device_attribute *devattr,305const char *buf, size_t count)306{307struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);308struct acpi_device *acpi_dev = to_acpi_device(dev);309struct acpi_power_meter_resource *resource = acpi_dev->driver_data;310int res;311unsigned long temp;312313res = strict_strtoul(buf, 10, &temp);314if (res)315return res;316317temp /= 1000;318if (temp < 0)319return -EINVAL;320321mutex_lock(&resource->lock);322resource->trip[attr->index - 7] = temp;323res = set_acpi_trip(resource);324mutex_unlock(&resource->lock);325326if (res)327return res;328329return count;330}331332/* Power meter */333static int update_meter(struct acpi_power_meter_resource *resource)334{335unsigned long long data;336acpi_status status;337unsigned long local_jiffies = jiffies;338339if (time_before(local_jiffies, resource->sensors_last_updated +340msecs_to_jiffies(resource->caps.sampling_time)) &&341resource->sensors_valid)342return 0;343344status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PMM",345NULL, &data);346if (ACPI_FAILURE(status)) {347ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMM"));348return -ENODEV;349}350351resource->power = data;352resource->sensors_valid = 1;353resource->sensors_last_updated = jiffies;354return 0;355}356357static ssize_t show_power(struct device *dev,358struct device_attribute *devattr,359char *buf)360{361struct acpi_device *acpi_dev = to_acpi_device(dev);362struct acpi_power_meter_resource *resource = acpi_dev->driver_data;363364mutex_lock(&resource->lock);365update_meter(resource);366mutex_unlock(&resource->lock);367368return sprintf(buf, "%llu\n", resource->power * 1000);369}370371/* Miscellaneous */372static ssize_t show_str(struct device *dev,373struct device_attribute *devattr,374char *buf)375{376struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);377struct acpi_device *acpi_dev = to_acpi_device(dev);378struct acpi_power_meter_resource *resource = acpi_dev->driver_data;379acpi_string val;380381switch (attr->index) {382case 0:383val = resource->model_number;384break;385case 1:386val = resource->serial_number;387break;388case 2:389val = resource->oem_info;390break;391default:392BUG();393}394395return sprintf(buf, "%s\n", val);396}397398static ssize_t show_val(struct device *dev,399struct device_attribute *devattr,400char *buf)401{402struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);403struct acpi_device *acpi_dev = to_acpi_device(dev);404struct acpi_power_meter_resource *resource = acpi_dev->driver_data;405u64 val = 0;406407switch (attr->index) {408case 0:409val = resource->caps.min_avg_interval;410break;411case 1:412val = resource->caps.max_avg_interval;413break;414case 2:415val = resource->caps.min_cap * 1000;416break;417case 3:418val = resource->caps.max_cap * 1000;419break;420case 4:421if (resource->caps.hysteresis == UNKNOWN_HYSTERESIS)422return sprintf(buf, "unknown\n");423424val = resource->caps.hysteresis * 1000;425break;426case 5:427if (resource->caps.flags & POWER_METER_IS_BATTERY)428val = 1;429else430val = 0;431break;432case 6:433if (resource->power > resource->cap)434val = 1;435else436val = 0;437break;438case 7:439case 8:440if (resource->trip[attr->index - 7] < 0)441return sprintf(buf, "unknown\n");442443val = resource->trip[attr->index - 7] * 1000;444break;445default:446BUG();447}448449return sprintf(buf, "%llu\n", val);450}451452static ssize_t show_accuracy(struct device *dev,453struct device_attribute *devattr,454char *buf)455{456struct acpi_device *acpi_dev = to_acpi_device(dev);457struct acpi_power_meter_resource *resource = acpi_dev->driver_data;458unsigned int acc = resource->caps.accuracy;459460return sprintf(buf, "%u.%u%%\n", acc / 1000, acc % 1000);461}462463static ssize_t show_name(struct device *dev,464struct device_attribute *devattr,465char *buf)466{467return sprintf(buf, "%s\n", ACPI_POWER_METER_NAME);468}469470/* Sensor descriptions. If you add a sensor, update NUM_SENSORS above! */471static struct ro_sensor_template meter_ro_attrs[] = {472{POWER_AVERAGE_NAME, show_power, 0},473{"power1_accuracy", show_accuracy, 0},474{"power1_average_interval_min", show_val, 0},475{"power1_average_interval_max", show_val, 1},476{"power1_is_battery", show_val, 5},477{NULL, NULL, 0},478};479480static struct rw_sensor_template meter_rw_attrs[] = {481{POWER_AVG_INTERVAL_NAME, show_avg_interval, set_avg_interval, 0},482{NULL, NULL, NULL, 0},483};484485static struct ro_sensor_template misc_cap_attrs[] = {486{"power1_cap_min", show_val, 2},487{"power1_cap_max", show_val, 3},488{"power1_cap_hyst", show_val, 4},489{POWER_ALARM_NAME, show_val, 6},490{NULL, NULL, 0},491};492493static struct ro_sensor_template ro_cap_attrs[] = {494{POWER_CAP_NAME, show_cap, 0},495{NULL, NULL, 0},496};497498static struct rw_sensor_template rw_cap_attrs[] = {499{POWER_CAP_NAME, show_cap, set_cap, 0},500{NULL, NULL, NULL, 0},501};502503static struct rw_sensor_template trip_attrs[] = {504{"power1_average_min", show_val, set_trip, 7},505{"power1_average_max", show_val, set_trip, 8},506{NULL, NULL, NULL, 0},507};508509static struct ro_sensor_template misc_attrs[] = {510{"name", show_name, 0},511{"power1_model_number", show_str, 0},512{"power1_oem_info", show_str, 2},513{"power1_serial_number", show_str, 1},514{NULL, NULL, 0},515};516517/* Read power domain data */518static void remove_domain_devices(struct acpi_power_meter_resource *resource)519{520int i;521522if (!resource->num_domain_devices)523return;524525for (i = 0; i < resource->num_domain_devices; i++) {526struct acpi_device *obj = resource->domain_devices[i];527if (!obj)528continue;529530sysfs_remove_link(resource->holders_dir,531kobject_name(&obj->dev.kobj));532put_device(&obj->dev);533}534535kfree(resource->domain_devices);536kobject_put(resource->holders_dir);537resource->num_domain_devices = 0;538}539540static int read_domain_devices(struct acpi_power_meter_resource *resource)541{542int res = 0;543int i;544struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };545union acpi_object *pss;546acpi_status status;547548status = acpi_evaluate_object(resource->acpi_dev->handle, "_PMD", NULL,549&buffer);550if (ACPI_FAILURE(status)) {551ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMD"));552return -ENODEV;553}554555pss = buffer.pointer;556if (!pss ||557pss->type != ACPI_TYPE_PACKAGE) {558dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME559"Invalid _PMD data\n");560res = -EFAULT;561goto end;562}563564if (!pss->package.count)565goto end;566567resource->domain_devices = kzalloc(sizeof(struct acpi_device *) *568pss->package.count, GFP_KERNEL);569if (!resource->domain_devices) {570res = -ENOMEM;571goto end;572}573574resource->holders_dir = kobject_create_and_add("measures",575&resource->acpi_dev->dev.kobj);576if (!resource->holders_dir) {577res = -ENOMEM;578goto exit_free;579}580581resource->num_domain_devices = pss->package.count;582583for (i = 0; i < pss->package.count; i++) {584struct acpi_device *obj;585union acpi_object *element = &(pss->package.elements[i]);586587/* Refuse non-references */588if (element->type != ACPI_TYPE_LOCAL_REFERENCE)589continue;590591/* Create a symlink to domain objects */592resource->domain_devices[i] = NULL;593status = acpi_bus_get_device(element->reference.handle,594&resource->domain_devices[i]);595if (ACPI_FAILURE(status))596continue;597598obj = resource->domain_devices[i];599get_device(&obj->dev);600601res = sysfs_create_link(resource->holders_dir, &obj->dev.kobj,602kobject_name(&obj->dev.kobj));603if (res) {604put_device(&obj->dev);605resource->domain_devices[i] = NULL;606}607}608609res = 0;610goto end;611612exit_free:613kfree(resource->domain_devices);614end:615kfree(buffer.pointer);616return res;617}618619/* Registration and deregistration */620static int register_ro_attrs(struct acpi_power_meter_resource *resource,621struct ro_sensor_template *ro)622{623struct device *dev = &resource->acpi_dev->dev;624struct sensor_device_attribute *sensors =625&resource->sensors[resource->num_sensors];626int res = 0;627628while (ro->label) {629sensors->dev_attr.attr.name = ro->label;630sensors->dev_attr.attr.mode = S_IRUGO;631sensors->dev_attr.show = ro->show;632sensors->index = ro->index;633634res = device_create_file(dev, &sensors->dev_attr);635if (res) {636sensors->dev_attr.attr.name = NULL;637goto error;638}639sensors++;640resource->num_sensors++;641ro++;642}643644error:645return res;646}647648static int register_rw_attrs(struct acpi_power_meter_resource *resource,649struct rw_sensor_template *rw)650{651struct device *dev = &resource->acpi_dev->dev;652struct sensor_device_attribute *sensors =653&resource->sensors[resource->num_sensors];654int res = 0;655656while (rw->label) {657sensors->dev_attr.attr.name = rw->label;658sensors->dev_attr.attr.mode = S_IRUGO | S_IWUSR;659sensors->dev_attr.show = rw->show;660sensors->dev_attr.store = rw->set;661sensors->index = rw->index;662663res = device_create_file(dev, &sensors->dev_attr);664if (res) {665sensors->dev_attr.attr.name = NULL;666goto error;667}668sensors++;669resource->num_sensors++;670rw++;671}672673error:674return res;675}676677static void remove_attrs(struct acpi_power_meter_resource *resource)678{679int i;680681for (i = 0; i < resource->num_sensors; i++) {682if (!resource->sensors[i].dev_attr.attr.name)683continue;684device_remove_file(&resource->acpi_dev->dev,685&resource->sensors[i].dev_attr);686}687688remove_domain_devices(resource);689690resource->num_sensors = 0;691}692693static int setup_attrs(struct acpi_power_meter_resource *resource)694{695int res = 0;696697res = read_domain_devices(resource);698if (res)699return res;700701if (resource->caps.flags & POWER_METER_CAN_MEASURE) {702res = register_ro_attrs(resource, meter_ro_attrs);703if (res)704goto error;705res = register_rw_attrs(resource, meter_rw_attrs);706if (res)707goto error;708}709710if (resource->caps.flags & POWER_METER_CAN_CAP) {711if (!can_cap_in_hardware()) {712dev_err(&resource->acpi_dev->dev,713"Ignoring unsafe software power cap!\n");714goto skip_unsafe_cap;715}716717if (resource->caps.configurable_cap) {718res = register_rw_attrs(resource, rw_cap_attrs);719if (res)720goto error;721} else {722res = register_ro_attrs(resource, ro_cap_attrs);723if (res)724goto error;725}726res = register_ro_attrs(resource, misc_cap_attrs);727if (res)728goto error;729}730skip_unsafe_cap:731732if (resource->caps.flags & POWER_METER_CAN_TRIP) {733res = register_rw_attrs(resource, trip_attrs);734if (res)735goto error;736}737738res = register_ro_attrs(resource, misc_attrs);739if (res)740goto error;741742return res;743error:744remove_attrs(resource);745return res;746}747748static void free_capabilities(struct acpi_power_meter_resource *resource)749{750acpi_string *str;751int i;752753str = &resource->model_number;754for (i = 0; i < 3; i++, str++)755kfree(*str);756}757758static int read_capabilities(struct acpi_power_meter_resource *resource)759{760int res = 0;761int i;762struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };763struct acpi_buffer state = { 0, NULL };764struct acpi_buffer format = { sizeof("NNNNNNNNNNN"), "NNNNNNNNNNN" };765union acpi_object *pss;766acpi_string *str;767acpi_status status;768769status = acpi_evaluate_object(resource->acpi_dev->handle, "_PMC", NULL,770&buffer);771if (ACPI_FAILURE(status)) {772ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PMC"));773return -ENODEV;774}775776pss = buffer.pointer;777if (!pss ||778pss->type != ACPI_TYPE_PACKAGE ||779pss->package.count != 14) {780dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME781"Invalid _PMC data\n");782res = -EFAULT;783goto end;784}785786/* Grab all the integer data at once */787state.length = sizeof(struct acpi_power_meter_capabilities);788state.pointer = &resource->caps;789790status = acpi_extract_package(pss, &format, &state);791if (ACPI_FAILURE(status)) {792ACPI_EXCEPTION((AE_INFO, status, "Invalid data"));793res = -EFAULT;794goto end;795}796797if (resource->caps.units) {798dev_err(&resource->acpi_dev->dev, ACPI_POWER_METER_NAME799"Unknown units %llu.\n",800resource->caps.units);801res = -EINVAL;802goto end;803}804805/* Grab the string data */806str = &resource->model_number;807808for (i = 11; i < 14; i++) {809union acpi_object *element = &(pss->package.elements[i]);810811if (element->type != ACPI_TYPE_STRING) {812res = -EINVAL;813goto error;814}815816*str = kzalloc(sizeof(u8) * (element->string.length + 1),817GFP_KERNEL);818if (!*str) {819res = -ENOMEM;820goto error;821}822823strncpy(*str, element->string.pointer, element->string.length);824str++;825}826827dev_info(&resource->acpi_dev->dev, "Found ACPI power meter.\n");828goto end;829error:830str = &resource->model_number;831for (i = 0; i < 3; i++, str++)832kfree(*str);833end:834kfree(buffer.pointer);835return res;836}837838/* Handle ACPI event notifications */839static void acpi_power_meter_notify(struct acpi_device *device, u32 event)840{841struct acpi_power_meter_resource *resource;842int res;843844if (!device || !acpi_driver_data(device))845return;846847resource = acpi_driver_data(device);848849mutex_lock(&resource->lock);850switch (event) {851case METER_NOTIFY_CONFIG:852free_capabilities(resource);853res = read_capabilities(resource);854if (res)855break;856857remove_attrs(resource);858setup_attrs(resource);859break;860case METER_NOTIFY_TRIP:861sysfs_notify(&device->dev.kobj, NULL, POWER_AVERAGE_NAME);862update_meter(resource);863break;864case METER_NOTIFY_CAP:865sysfs_notify(&device->dev.kobj, NULL, POWER_CAP_NAME);866update_cap(resource);867break;868case METER_NOTIFY_INTERVAL:869sysfs_notify(&device->dev.kobj, NULL, POWER_AVG_INTERVAL_NAME);870update_avg_interval(resource);871break;872case METER_NOTIFY_CAPPING:873sysfs_notify(&device->dev.kobj, NULL, POWER_ALARM_NAME);874dev_info(&device->dev, "Capping in progress.\n");875break;876default:877BUG();878}879mutex_unlock(&resource->lock);880881acpi_bus_generate_netlink_event(ACPI_POWER_METER_CLASS,882dev_name(&device->dev), event, 0);883}884885static int acpi_power_meter_add(struct acpi_device *device)886{887int res;888struct acpi_power_meter_resource *resource;889890if (!device)891return -EINVAL;892893resource = kzalloc(sizeof(struct acpi_power_meter_resource),894GFP_KERNEL);895if (!resource)896return -ENOMEM;897898resource->sensors_valid = 0;899resource->acpi_dev = device;900mutex_init(&resource->lock);901strcpy(acpi_device_name(device), ACPI_POWER_METER_DEVICE_NAME);902strcpy(acpi_device_class(device), ACPI_POWER_METER_CLASS);903device->driver_data = resource;904905free_capabilities(resource);906res = read_capabilities(resource);907if (res)908goto exit_free;909910resource->trip[0] = resource->trip[1] = -1;911912res = setup_attrs(resource);913if (res)914goto exit_free;915916resource->hwmon_dev = hwmon_device_register(&device->dev);917if (IS_ERR(resource->hwmon_dev)) {918res = PTR_ERR(resource->hwmon_dev);919goto exit_remove;920}921922res = 0;923goto exit;924925exit_remove:926remove_attrs(resource);927exit_free:928kfree(resource);929exit:930return res;931}932933static int acpi_power_meter_remove(struct acpi_device *device, int type)934{935struct acpi_power_meter_resource *resource;936937if (!device || !acpi_driver_data(device))938return -EINVAL;939940resource = acpi_driver_data(device);941hwmon_device_unregister(resource->hwmon_dev);942943free_capabilities(resource);944remove_attrs(resource);945946kfree(resource);947return 0;948}949950static int acpi_power_meter_resume(struct acpi_device *device)951{952struct acpi_power_meter_resource *resource;953954if (!device || !acpi_driver_data(device))955return -EINVAL;956957resource = acpi_driver_data(device);958free_capabilities(resource);959read_capabilities(resource);960961return 0;962}963964static struct acpi_driver acpi_power_meter_driver = {965.name = "power_meter",966.class = ACPI_POWER_METER_CLASS,967.ids = power_meter_ids,968.ops = {969.add = acpi_power_meter_add,970.remove = acpi_power_meter_remove,971.resume = acpi_power_meter_resume,972.notify = acpi_power_meter_notify,973},974};975976/* Module init/exit routines */977static int __init enable_cap_knobs(const struct dmi_system_id *d)978{979cap_in_hardware = 1;980return 0;981}982983static struct dmi_system_id __initdata pm_dmi_table[] = {984{985enable_cap_knobs, "IBM Active Energy Manager",986{987DMI_MATCH(DMI_SYS_VENDOR, "IBM")988},989},990{}991};992993static int __init acpi_power_meter_init(void)994{995int result;996997if (acpi_disabled)998return -ENODEV;9991000dmi_check_system(pm_dmi_table);10011002result = acpi_bus_register_driver(&acpi_power_meter_driver);1003if (result < 0)1004return -ENODEV;10051006return 0;1007}10081009static void __exit acpi_power_meter_exit(void)1010{1011acpi_bus_unregister_driver(&acpi_power_meter_driver);1012}10131014MODULE_AUTHOR("Darrick J. Wong <[email protected]>");1015MODULE_DESCRIPTION("ACPI 4.0 power meter driver");1016MODULE_LICENSE("GPL");10171018module_param(force_cap_on, bool, 0644);1019MODULE_PARM_DESC(force_cap_on, "Enable power cap even it is unsafe to do so.");10201021module_init(acpi_power_meter_init);1022module_exit(acpi_power_meter_exit);102310241025