blob: b35fca4780977f00710e95e372c0bd0f1a08fa12 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +04002 * battery.c - ACPI Battery Driver (Revision: 2.0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +04004 * Copyright (C) 2007 Alexey Starikovskiy <astarikovskiy@suse.de>
5 * Copyright (C) 2004-2007 Vladimir Lebedev <vladimir.p.lebedev@intel.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
7 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
8 *
9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or (at
14 * your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22 */
23
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/init.h>
27#include <linux/types.h>
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +040028#include <linux/jiffies.h>
Arjan van de Ven0f66af52009-01-10 14:19:05 -050029#include <linux/async.h>
Hector Martinbc76f902009-08-06 15:57:48 -070030#include <linux/dmi.h>
Alexander Mezinf43691c2014-06-04 02:01:23 +070031#include <linux/delay.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Kyle McMartin25be5822011-03-22 16:19:50 -040033#include <linux/suspend.h>
Kamil Iskra4000e622012-11-16 22:28:58 +010034#include <asm/unaligned.h>
Alexey Starikovskiyd7380962007-09-26 19:43:04 +040035
Lan Tianyu3a670cc2014-05-04 11:07:25 +080036#ifdef CONFIG_ACPI_PROCFS_POWER
37#include <linux/proc_fs.h>
38#include <linux/seq_file.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080039#include <linux/uaccess.h>
Lan Tianyu3a670cc2014-05-04 11:07:25 +080040#endif
41
Lv Zheng8b484632013-12-03 08:49:16 +080042#include <linux/acpi.h>
Alexey Starikovskiyd7380962007-09-26 19:43:04 +040043#include <linux/power_supply.h>
44
Alexander Mezinf03be352014-03-12 00:58:46 +070045#include "battery.h"
46
Len Browna192a952009-07-28 16:45:54 -040047#define PREFIX "ACPI: "
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
50
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#define ACPI_BATTERY_DEVICE_NAME "Battery"
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
Lan Tianyuae6f6182011-06-30 11:32:40 +080053/* Battery power unit: 0 means mW, 1 means mA */
54#define ACPI_BATTERY_POWER_UNIT_MA 1
55
Zhang Rui1ac5aaa2014-05-28 15:23:36 +080056#define ACPI_BATTERY_STATE_DISCHARGING 0x1
57#define ACPI_BATTERY_STATE_CHARGING 0x2
58#define ACPI_BATTERY_STATE_CRITICAL 0x4
59
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#define _COMPONENT ACPI_BATTERY_COMPONENT
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +030061
Len Brownf52fd662007-02-12 22:42:12 -050062ACPI_MODULE_NAME("battery");
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Len Brownf52fd662007-02-12 22:42:12 -050064MODULE_AUTHOR("Paul Diefenbaugh");
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +040065MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
Len Brown7cda93e2007-02-12 23:50:02 -050066MODULE_DESCRIPTION("ACPI Battery Driver");
Linus Torvalds1da177e2005-04-16 15:20:36 -070067MODULE_LICENSE("GPL");
68
Luis Henriqueseca21d912015-05-11 22:49:05 +010069static async_cookie_t async_cookie;
Hans de Goedebc39fbc2017-04-19 14:02:09 +020070static bool battery_driver_registered;
Lan Tianyua90b4032014-01-06 22:50:37 +080071static int battery_bix_broken_package;
Alexander Mezinf43691c2014-06-04 02:01:23 +070072static int battery_notification_delay_ms;
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +040073static unsigned int cache_time = 1000;
74module_param(cache_time, uint, 0644);
75MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +030076
Lan Tianyu3a670cc2014-05-04 11:07:25 +080077#ifdef CONFIG_ACPI_PROCFS_POWER
78extern struct proc_dir_entry *acpi_lock_battery_dir(void);
79extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
80
81enum acpi_battery_files {
82 info_tag = 0,
83 state_tag,
84 alarm_tag,
85 ACPI_BATTERY_NUMFILES,
86};
87
88#endif
89
Alexey Starikovskiyd7380962007-09-26 19:43:04 +040090static const struct acpi_device_id battery_device_ids[] = {
91 {"PNP0C0A", 0},
92 {"", 0},
93};
94
95MODULE_DEVICE_TABLE(acpi, battery_device_ids);
96
Alexey Starikovskiy7b3bcc42009-10-15 14:31:24 +040097enum {
98 ACPI_BATTERY_ALARM_PRESENT,
Alexey Starikovskiyc67fcd62009-10-15 14:31:44 +040099 ACPI_BATTERY_XINFO_PRESENT,
Zhang Rui557d5862010-10-22 10:02:06 +0800100 ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY,
Kamil Iskra4000e622012-11-16 22:28:58 +0100101 /* On Lenovo Thinkpad models from 2010 and 2011, the power unit
102 switches between mWh and mAh depending on whether the system
103 is running on battery or not. When mAh is the unit, most
104 reported values are incorrect and need to be adjusted by
105 10000/design_voltage. Verified on x201, t410, t410s, and x220.
106 Pre-2010 and 2012 models appear to always report in mWh and
107 are thus unaffected (tested with t42, t61, t500, x200, x300,
108 and x230). Also, in mid-2012 Lenovo issued a BIOS update for
109 the 2011 models that fixes the issue (tested on x220 with a
110 post-1.29 BIOS), but as of Nov. 2012, no such update is
111 available for the 2010 models. */
112 ACPI_BATTERY_QUIRK_THINKPAD_MAH,
Alexey Starikovskiy7b3bcc42009-10-15 14:31:24 +0400113};
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400114
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400115struct acpi_battery {
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400116 struct mutex lock;
Sergey Senozhatsky69d94ec2011-08-06 01:34:08 +0300117 struct mutex sysfs_lock;
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100118 struct power_supply *bat;
119 struct power_supply_desc bat_desc;
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400120 struct acpi_device *device;
Kyle McMartin25be5822011-03-22 16:19:50 -0400121 struct notifier_block pm_nb;
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400122 unsigned long update_time;
Lan Tianyu016d5ba2013-07-30 14:00:42 +0200123 int revision;
Alexey Starikovskiy7faa1442009-03-27 22:23:52 -0400124 int rate_now;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400125 int capacity_now;
126 int voltage_now;
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400127 int design_capacity;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400128 int full_charge_capacity;
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400129 int technology;
130 int design_voltage;
131 int design_capacity_warning;
132 int design_capacity_low;
Alexey Starikovskiyc67fcd62009-10-15 14:31:44 +0400133 int cycle_count;
134 int measurement_accuracy;
135 int max_sampling_time;
136 int min_sampling_time;
137 int max_averaging_interval;
138 int min_averaging_interval;
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400139 int capacity_granularity_1;
140 int capacity_granularity_2;
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400141 int alarm;
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400142 char model_number[32];
143 char serial_number[32];
144 char type[32];
145 char oem_info[32];
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400146 int state;
147 int power_unit;
Alexey Starikovskiy7b3bcc42009-10-15 14:31:24 +0400148 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149};
150
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100151#define to_acpi_battery(x) power_supply_get_drvdata(x)
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400152
Andy Shevchenkoefd941f2013-03-11 09:17:06 +0000153static inline int acpi_battery_present(struct acpi_battery *battery)
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400154{
155 return battery->device->status.battery_present;
156}
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400157
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400158static int acpi_battery_technology(struct acpi_battery *battery)
159{
160 if (!strcasecmp("NiCd", battery->type))
161 return POWER_SUPPLY_TECHNOLOGY_NiCd;
162 if (!strcasecmp("NiMH", battery->type))
163 return POWER_SUPPLY_TECHNOLOGY_NiMH;
164 if (!strcasecmp("LION", battery->type))
165 return POWER_SUPPLY_TECHNOLOGY_LION;
Andrey Borzenkovad40e682007-11-10 20:02:49 +0300166 if (!strncasecmp("LI-ION", battery->type, 6))
Alexey Starikovskiy0bde7ee2007-10-28 15:33:10 +0300167 return POWER_SUPPLY_TECHNOLOGY_LION;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400168 if (!strcasecmp("LiP", battery->type))
169 return POWER_SUPPLY_TECHNOLOGY_LIPO;
170 return POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
171}
172
Alexey Starikovskiy91044762007-11-13 12:23:06 +0300173static int acpi_battery_get_state(struct acpi_battery *battery);
Alexey Starikovskiyb19073a2007-10-25 17:10:47 -0400174
Richard Hughes56f382a2009-01-25 15:05:50 +0000175static int acpi_battery_is_charged(struct acpi_battery *battery)
176{
Zhang Rui1ac5aaa2014-05-28 15:23:36 +0800177 /* charging, discharging or critical low */
Richard Hughes56f382a2009-01-25 15:05:50 +0000178 if (battery->state != 0)
179 return 0;
180
181 /* battery not reporting charge */
182 if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
183 battery->capacity_now == 0)
184 return 0;
185
186 /* good batteries update full_charge as the batteries degrade */
187 if (battery->full_charge_capacity == battery->capacity_now)
188 return 1;
189
190 /* fallback to using design values for broken batteries */
191 if (battery->design_capacity == battery->capacity_now)
192 return 1;
193
194 /* we don't do any sort of metric based on percentages */
195 return 0;
196}
197
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400198static int acpi_battery_get_property(struct power_supply *psy,
199 enum power_supply_property psp,
200 union power_supply_propval *val)
201{
Rafael J. Wysockia1b4bd62010-10-23 19:35:15 +0200202 int ret = 0;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400203 struct acpi_battery *battery = to_acpi_battery(psy);
204
Alexey Starikovskiy91044762007-11-13 12:23:06 +0300205 if (acpi_battery_present(battery)) {
206 /* run battery update only if it is present */
207 acpi_battery_get_state(battery);
208 } else if (psp != POWER_SUPPLY_PROP_PRESENT)
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400209 return -ENODEV;
210 switch (psp) {
211 case POWER_SUPPLY_PROP_STATUS:
Zhang Rui1ac5aaa2014-05-28 15:23:36 +0800212 if (battery->state & ACPI_BATTERY_STATE_DISCHARGING)
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400213 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
Zhang Rui1ac5aaa2014-05-28 15:23:36 +0800214 else if (battery->state & ACPI_BATTERY_STATE_CHARGING)
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400215 val->intval = POWER_SUPPLY_STATUS_CHARGING;
Richard Hughes56f382a2009-01-25 15:05:50 +0000216 else if (acpi_battery_is_charged(battery))
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400217 val->intval = POWER_SUPPLY_STATUS_FULL;
Roland Dreier4c41d3a2007-11-07 15:09:09 -0800218 else
219 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400220 break;
221 case POWER_SUPPLY_PROP_PRESENT:
222 val->intval = acpi_battery_present(battery);
223 break;
224 case POWER_SUPPLY_PROP_TECHNOLOGY:
225 val->intval = acpi_battery_technology(battery);
226 break;
Alexey Starikovskiyc67fcd62009-10-15 14:31:44 +0400227 case POWER_SUPPLY_PROP_CYCLE_COUNT:
228 val->intval = battery->cycle_count;
229 break;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400230 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Rafael J. Wysockia1b4bd62010-10-23 19:35:15 +0200231 if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
232 ret = -ENODEV;
233 else
234 val->intval = battery->design_voltage * 1000;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400235 break;
236 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Rafael J. Wysockia1b4bd62010-10-23 19:35:15 +0200237 if (battery->voltage_now == ACPI_BATTERY_VALUE_UNKNOWN)
238 ret = -ENODEV;
239 else
240 val->intval = battery->voltage_now * 1000;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400241 break;
242 case POWER_SUPPLY_PROP_CURRENT_NOW:
Alexey Starikovskiy7faa1442009-03-27 22:23:52 -0400243 case POWER_SUPPLY_PROP_POWER_NOW:
Rafael J. Wysockia1b4bd62010-10-23 19:35:15 +0200244 if (battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN)
245 ret = -ENODEV;
246 else
247 val->intval = battery->rate_now * 1000;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400248 break;
249 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
250 case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
Rafael J. Wysockia1b4bd62010-10-23 19:35:15 +0200251 if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
252 ret = -ENODEV;
253 else
254 val->intval = battery->design_capacity * 1000;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400255 break;
256 case POWER_SUPPLY_PROP_CHARGE_FULL:
257 case POWER_SUPPLY_PROP_ENERGY_FULL:
Rafael J. Wysockia1b4bd62010-10-23 19:35:15 +0200258 if (battery->full_charge_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
259 ret = -ENODEV;
260 else
261 val->intval = battery->full_charge_capacity * 1000;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400262 break;
263 case POWER_SUPPLY_PROP_CHARGE_NOW:
264 case POWER_SUPPLY_PROP_ENERGY_NOW:
Rafael J. Wysockia1b4bd62010-10-23 19:35:15 +0200265 if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN)
266 ret = -ENODEV;
267 else
268 val->intval = battery->capacity_now * 1000;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400269 break;
srinivas pandruvadaa58e1152012-04-05 17:38:54 -0700270 case POWER_SUPPLY_PROP_CAPACITY:
271 if (battery->capacity_now && battery->full_charge_capacity)
272 val->intval = battery->capacity_now * 100/
273 battery->full_charge_capacity;
274 else
275 val->intval = 0;
276 break;
Zhang Rui1ac5aaa2014-05-28 15:23:36 +0800277 case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
278 if (battery->state & ACPI_BATTERY_STATE_CRITICAL)
279 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
280 else if (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
281 (battery->capacity_now <= battery->alarm))
282 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
283 else if (acpi_battery_is_charged(battery))
284 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
285 else
286 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
287 break;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400288 case POWER_SUPPLY_PROP_MODEL_NAME:
289 val->strval = battery->model_number;
290 break;
291 case POWER_SUPPLY_PROP_MANUFACTURER:
292 val->strval = battery->oem_info;
293 break;
maximilian attems7c2670b2008-01-22 18:46:50 +0100294 case POWER_SUPPLY_PROP_SERIAL_NUMBER:
295 val->strval = battery->serial_number;
296 break;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400297 default:
Rafael J. Wysockia1b4bd62010-10-23 19:35:15 +0200298 ret = -EINVAL;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400299 }
Rafael J. Wysockia1b4bd62010-10-23 19:35:15 +0200300 return ret;
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400301}
302
303static enum power_supply_property charge_battery_props[] = {
304 POWER_SUPPLY_PROP_STATUS,
305 POWER_SUPPLY_PROP_PRESENT,
306 POWER_SUPPLY_PROP_TECHNOLOGY,
Alexey Starikovskiyc67fcd62009-10-15 14:31:44 +0400307 POWER_SUPPLY_PROP_CYCLE_COUNT,
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400308 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
309 POWER_SUPPLY_PROP_VOLTAGE_NOW,
310 POWER_SUPPLY_PROP_CURRENT_NOW,
311 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
312 POWER_SUPPLY_PROP_CHARGE_FULL,
313 POWER_SUPPLY_PROP_CHARGE_NOW,
srinivas pandruvadaa58e1152012-04-05 17:38:54 -0700314 POWER_SUPPLY_PROP_CAPACITY,
Zhang Rui1ac5aaa2014-05-28 15:23:36 +0800315 POWER_SUPPLY_PROP_CAPACITY_LEVEL,
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400316 POWER_SUPPLY_PROP_MODEL_NAME,
317 POWER_SUPPLY_PROP_MANUFACTURER,
maximilian attems7c2670b2008-01-22 18:46:50 +0100318 POWER_SUPPLY_PROP_SERIAL_NUMBER,
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400319};
320
321static enum power_supply_property energy_battery_props[] = {
322 POWER_SUPPLY_PROP_STATUS,
323 POWER_SUPPLY_PROP_PRESENT,
324 POWER_SUPPLY_PROP_TECHNOLOGY,
Alexey Starikovskiyc67fcd62009-10-15 14:31:44 +0400325 POWER_SUPPLY_PROP_CYCLE_COUNT,
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400326 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
327 POWER_SUPPLY_PROP_VOLTAGE_NOW,
Alexey Starikovskiy7faa1442009-03-27 22:23:52 -0400328 POWER_SUPPLY_PROP_POWER_NOW,
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400329 POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
330 POWER_SUPPLY_PROP_ENERGY_FULL,
331 POWER_SUPPLY_PROP_ENERGY_NOW,
srinivas pandruvadaa58e1152012-04-05 17:38:54 -0700332 POWER_SUPPLY_PROP_CAPACITY,
Zhang Rui1ac5aaa2014-05-28 15:23:36 +0800333 POWER_SUPPLY_PROP_CAPACITY_LEVEL,
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400334 POWER_SUPPLY_PROP_MODEL_NAME,
335 POWER_SUPPLY_PROP_MANUFACTURER,
maximilian attems7c2670b2008-01-22 18:46:50 +0100336 POWER_SUPPLY_PROP_SERIAL_NUMBER,
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400337};
338
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339/* --------------------------------------------------------------------------
340 Battery Management
341 -------------------------------------------------------------------------- */
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400342struct acpi_offsets {
343 size_t offset; /* offset inside struct acpi_sbs_battery */
344 u8 mode; /* int or string? */
345};
346
Mathias Krausea4658782015-06-13 14:26:53 +0200347static const struct acpi_offsets state_offsets[] = {
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400348 {offsetof(struct acpi_battery, state), 0},
Alexey Starikovskiy7faa1442009-03-27 22:23:52 -0400349 {offsetof(struct acpi_battery, rate_now), 0},
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400350 {offsetof(struct acpi_battery, capacity_now), 0},
351 {offsetof(struct acpi_battery, voltage_now), 0},
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400352};
353
Mathias Krausea4658782015-06-13 14:26:53 +0200354static const struct acpi_offsets info_offsets[] = {
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400355 {offsetof(struct acpi_battery, power_unit), 0},
356 {offsetof(struct acpi_battery, design_capacity), 0},
Alexey Starikovskiyd7380962007-09-26 19:43:04 +0400357 {offsetof(struct acpi_battery, full_charge_capacity), 0},
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400358 {offsetof(struct acpi_battery, technology), 0},
359 {offsetof(struct acpi_battery, design_voltage), 0},
360 {offsetof(struct acpi_battery, design_capacity_warning), 0},
361 {offsetof(struct acpi_battery, design_capacity_low), 0},
362 {offsetof(struct acpi_battery, capacity_granularity_1), 0},
363 {offsetof(struct acpi_battery, capacity_granularity_2), 0},
364 {offsetof(struct acpi_battery, model_number), 1},
365 {offsetof(struct acpi_battery, serial_number), 1},
366 {offsetof(struct acpi_battery, type), 1},
367 {offsetof(struct acpi_battery, oem_info), 1},
368};
369
Mathias Krausea4658782015-06-13 14:26:53 +0200370static const struct acpi_offsets extended_info_offsets[] = {
Lan Tianyu016d5ba2013-07-30 14:00:42 +0200371 {offsetof(struct acpi_battery, revision), 0},
Alexey Starikovskiyc67fcd62009-10-15 14:31:44 +0400372 {offsetof(struct acpi_battery, power_unit), 0},
373 {offsetof(struct acpi_battery, design_capacity), 0},
374 {offsetof(struct acpi_battery, full_charge_capacity), 0},
375 {offsetof(struct acpi_battery, technology), 0},
376 {offsetof(struct acpi_battery, design_voltage), 0},
377 {offsetof(struct acpi_battery, design_capacity_warning), 0},
378 {offsetof(struct acpi_battery, design_capacity_low), 0},
379 {offsetof(struct acpi_battery, cycle_count), 0},
380 {offsetof(struct acpi_battery, measurement_accuracy), 0},
381 {offsetof(struct acpi_battery, max_sampling_time), 0},
382 {offsetof(struct acpi_battery, min_sampling_time), 0},
383 {offsetof(struct acpi_battery, max_averaging_interval), 0},
384 {offsetof(struct acpi_battery, min_averaging_interval), 0},
385 {offsetof(struct acpi_battery, capacity_granularity_1), 0},
386 {offsetof(struct acpi_battery, capacity_granularity_2), 0},
387 {offsetof(struct acpi_battery, model_number), 1},
388 {offsetof(struct acpi_battery, serial_number), 1},
389 {offsetof(struct acpi_battery, type), 1},
390 {offsetof(struct acpi_battery, oem_info), 1},
391};
392
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400393static int extract_package(struct acpi_battery *battery,
394 union acpi_object *package,
Mathias Krausea4658782015-06-13 14:26:53 +0200395 const struct acpi_offsets *offsets, int num)
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300396{
Alexey Starikovskiy106449e2007-10-29 23:29:40 +0300397 int i;
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400398 union acpi_object *element;
399 if (package->type != ACPI_TYPE_PACKAGE)
400 return -EFAULT;
401 for (i = 0; i < num; ++i) {
402 if (package->package.count <= i)
403 return -EFAULT;
404 element = &package->package.elements[i];
405 if (offsets[i].mode) {
Alexey Starikovskiy106449e2007-10-29 23:29:40 +0300406 u8 *ptr = (u8 *)battery + offsets[i].offset;
407 if (element->type == ACPI_TYPE_STRING ||
408 element->type == ACPI_TYPE_BUFFER)
409 strncpy(ptr, element->string.pointer, 32);
410 else if (element->type == ACPI_TYPE_INTEGER) {
411 strncpy(ptr, (u8 *)&element->integer.value,
Lin Ming439913f2010-01-28 10:53:19 +0800412 sizeof(u64));
413 ptr[sizeof(u64)] = 0;
Alexey Starikovskiyb8a1bdb2008-03-17 22:37:42 -0400414 } else
415 *ptr = 0; /* don't have value */
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400416 } else {
Alexey Starikovskiyb8a1bdb2008-03-17 22:37:42 -0400417 int *x = (int *)((u8 *)battery + offsets[i].offset);
418 *x = (element->type == ACPI_TYPE_INTEGER) ?
419 element->integer.value : -1;
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300420 }
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300421 }
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300422 return 0;
423}
424
425static int acpi_battery_get_status(struct acpi_battery *battery)
426{
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +0400427 if (acpi_bus_get_status(battery->device)) {
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300428 ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA"));
429 return -ENODEV;
430 }
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +0400431 return 0;
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300432}
433
Dave Lambley2d09af42016-11-04 01:05:40 +0000434
435static int extract_battery_info(const int use_bix,
436 struct acpi_battery *battery,
437 const struct acpi_buffer *buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438{
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +0400439 int result = -EFAULT;
Alexey Starikovskiyc67fcd62009-10-15 14:31:44 +0400440
Dave Lambley2d09af42016-11-04 01:05:40 +0000441 if (use_bix && battery_bix_broken_package)
442 result = extract_package(battery, buffer->pointer,
Lan Tianyua90b4032014-01-06 22:50:37 +0800443 extended_info_offsets + 1,
444 ARRAY_SIZE(extended_info_offsets) - 1);
Dave Lambley2d09af42016-11-04 01:05:40 +0000445 else if (use_bix)
446 result = extract_package(battery, buffer->pointer,
Alexey Starikovskiyc67fcd62009-10-15 14:31:44 +0400447 extended_info_offsets,
448 ARRAY_SIZE(extended_info_offsets));
449 else
Dave Lambley2d09af42016-11-04 01:05:40 +0000450 result = extract_package(battery, buffer->pointer,
Alexey Starikovskiyc67fcd62009-10-15 14:31:44 +0400451 info_offsets, ARRAY_SIZE(info_offsets));
Zhang Rui557d5862010-10-22 10:02:06 +0800452 if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
453 battery->full_charge_capacity = battery->design_capacity;
Kamil Iskra4000e622012-11-16 22:28:58 +0100454 if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
455 battery->power_unit && battery->design_voltage) {
456 battery->design_capacity = battery->design_capacity *
457 10000 / battery->design_voltage;
458 battery->full_charge_capacity = battery->full_charge_capacity *
459 10000 / battery->design_voltage;
460 battery->design_capacity_warning =
461 battery->design_capacity_warning *
462 10000 / battery->design_voltage;
463 /* Curiously, design_capacity_low, unlike the rest of them,
464 is correct. */
465 /* capacity_granularity_* equal 1 on the systems tested, so
466 it's impossible to tell if they would need an adjustment
467 or not if their values were higher. */
468 }
Patrick Mocheld550d982006-06-27 00:41:40 -0400469 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470}
471
Dave Lambley2d09af42016-11-04 01:05:40 +0000472static int acpi_battery_get_info(struct acpi_battery *battery)
473{
474 const int xinfo = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
475 int use_bix;
476 int result = -ENODEV;
477
478 if (!acpi_battery_present(battery))
479 return 0;
480
481
482 for (use_bix = xinfo ? 1 : 0; use_bix >= 0; use_bix--) {
483 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
484 acpi_status status = AE_ERROR;
485
486 mutex_lock(&battery->lock);
487 status = acpi_evaluate_object(battery->device->handle,
488 use_bix ? "_BIX":"_BIF",
489 NULL, &buffer);
490 mutex_unlock(&battery->lock);
491
492 if (ACPI_FAILURE(status)) {
493 ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s",
494 use_bix ? "_BIX":"_BIF"));
495 } else {
496 result = extract_battery_info(use_bix,
497 battery,
498 &buffer);
499
500 kfree(buffer.pointer);
501 break;
502 }
503 }
504
505 if (!result && !use_bix && xinfo)
506 pr_warn(FW_BUG "The _BIX method is broken, using _BIF.\n");
507
508 return result;
509}
510
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300511static int acpi_battery_get_state(struct acpi_battery *battery)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
Len Brown4be44fc2005-08-05 00:44:28 -0400513 int result = 0;
514 acpi_status status = 0;
515 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300517 if (!acpi_battery_present(battery))
518 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400520 if (battery->update_time &&
521 time_before(jiffies, battery->update_time +
522 msecs_to_jiffies(cache_time)))
523 return 0;
524
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400525 mutex_lock(&battery->lock);
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400526 status = acpi_evaluate_object(battery->device->handle, "_BST",
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400527 NULL, &buffer);
528 mutex_unlock(&battery->lock);
Len Brown5b31d892007-08-15 00:19:26 -0400529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 if (ACPI_FAILURE(status)) {
Thomas Renningera6fc6722006-06-26 23:58:43 -0400531 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
Patrick Mocheld550d982006-06-27 00:41:40 -0400532 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 }
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +0400534
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400535 result = extract_package(battery, buffer.pointer,
536 state_offsets, ARRAY_SIZE(state_offsets));
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400537 battery->update_time = jiffies;
Alexey Starikovskiy78490d82007-05-11 13:18:55 -0400538 kfree(buffer.pointer);
Hector Martinbc76f902009-08-06 15:57:48 -0700539
Lan Tianyu55003b22011-06-30 11:33:12 +0800540 /* For buggy DSDTs that report negative 16-bit values for either
541 * charging or discharging current and/or report 0 as 65536
542 * due to bad math.
543 */
544 if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA &&
545 battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN &&
546 (s16)(battery->rate_now) < 0) {
Hector Martinbc76f902009-08-06 15:57:48 -0700547 battery->rate_now = abs((s16)battery->rate_now);
Martin Kepplinger92375162015-03-13 00:48:17 +0100548 printk_once(KERN_WARNING FW_BUG
549 "battery: (dis)charge rate invalid.\n");
Lan Tianyu55003b22011-06-30 11:33:12 +0800550 }
Hector Martinbc76f902009-08-06 15:57:48 -0700551
Zhang Rui557d5862010-10-22 10:02:06 +0800552 if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)
553 && battery->capacity_now >= 0 && battery->capacity_now <= 100)
554 battery->capacity_now = (battery->capacity_now *
555 battery->full_charge_capacity) / 100;
Kamil Iskra4000e622012-11-16 22:28:58 +0100556 if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
557 battery->power_unit && battery->design_voltage) {
558 battery->capacity_now = battery->capacity_now *
559 10000 / battery->design_voltage;
560 }
Patrick Mocheld550d982006-06-27 00:41:40 -0400561 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562}
563
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +0400564static int acpi_battery_set_alarm(struct acpi_battery *battery)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565{
Len Brown4be44fc2005-08-05 00:44:28 -0400566 acpi_status status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Alexey Starikovskiyc67fcd62009-10-15 14:31:44 +0400568 if (!acpi_battery_present(battery) ||
Alexey Starikovskiy7b3bcc42009-10-15 14:31:24 +0400569 !test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags))
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300570 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400572 mutex_lock(&battery->lock);
Jiang Liu0db98202013-06-29 00:24:39 +0800573 status = acpi_execute_simple_method(battery->device->handle, "_BTP",
574 battery->alarm);
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +0400575 mutex_unlock(&battery->lock);
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +0400576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 if (ACPI_FAILURE(status))
Patrick Mocheld550d982006-06-27 00:41:40 -0400578 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +0400580 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", battery->alarm));
Patrick Mocheld550d982006-06-27 00:41:40 -0400581 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582}
583
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300584static int acpi_battery_init_alarm(struct acpi_battery *battery)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300586 /* See if alarms are supported, and if so, set default */
Jiang Liu952c63e2013-06-29 00:24:38 +0800587 if (!acpi_has_method(battery->device->handle, "_BTP")) {
Alexey Starikovskiy7b3bcc42009-10-15 14:31:24 +0400588 clear_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags);
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400589 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 }
Alexey Starikovskiy7b3bcc42009-10-15 14:31:24 +0400591 set_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags);
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +0400592 if (!battery->alarm)
593 battery->alarm = battery->design_capacity_warning;
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +0400594 return acpi_battery_set_alarm(battery);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595}
596
Andrey Borzenkov508df922007-10-28 12:50:09 +0300597static ssize_t acpi_battery_alarm_show(struct device *dev,
598 struct device_attribute *attr,
599 char *buf)
600{
601 struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
602 return sprintf(buf, "%d\n", battery->alarm * 1000);
603}
604
605static ssize_t acpi_battery_alarm_store(struct device *dev,
606 struct device_attribute *attr,
607 const char *buf, size_t count)
608{
609 unsigned long x;
610 struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
Luis G.F47a08c82014-01-21 15:40:43 +0100611 if (sscanf(buf, "%lu\n", &x) == 1)
Andrey Borzenkov508df922007-10-28 12:50:09 +0300612 battery->alarm = x/1000;
613 if (acpi_battery_present(battery))
614 acpi_battery_set_alarm(battery);
615 return count;
616}
617
618static struct device_attribute alarm_attr = {
Parag Warudkar01e8ef12008-10-18 20:28:50 -0700619 .attr = {.name = "alarm", .mode = 0644},
Andrey Borzenkov508df922007-10-28 12:50:09 +0300620 .show = acpi_battery_alarm_show,
621 .store = acpi_battery_alarm_store,
622};
623
624static int sysfs_add_battery(struct acpi_battery *battery)
625{
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100626 struct power_supply_config psy_cfg = { .drv_data = battery, };
Andrey Borzenkov508df922007-10-28 12:50:09 +0300627
Lan Tianyuae6f6182011-06-30 11:32:40 +0800628 if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) {
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100629 battery->bat_desc.properties = charge_battery_props;
630 battery->bat_desc.num_properties =
Andrey Borzenkov508df922007-10-28 12:50:09 +0300631 ARRAY_SIZE(charge_battery_props);
632 } else {
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100633 battery->bat_desc.properties = energy_battery_props;
634 battery->bat_desc.num_properties =
Andrey Borzenkov508df922007-10-28 12:50:09 +0300635 ARRAY_SIZE(energy_battery_props);
636 }
637
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100638 battery->bat_desc.name = acpi_device_bid(battery->device);
639 battery->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
640 battery->bat_desc.get_property = acpi_battery_get_property;
Andrey Borzenkov508df922007-10-28 12:50:09 +0300641
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100642 battery->bat = power_supply_register_no_ws(&battery->device->dev,
643 &battery->bat_desc, &psy_cfg);
Zhang Ruie0d1f092014-05-28 15:23:38 +0800644
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100645 if (IS_ERR(battery->bat)) {
646 int result = PTR_ERR(battery->bat);
647
648 battery->bat = NULL;
Andrey Borzenkov508df922007-10-28 12:50:09 +0300649 return result;
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100650 }
651 return device_create_file(&battery->bat->dev, &alarm_attr);
Andrey Borzenkov508df922007-10-28 12:50:09 +0300652}
653
654static void sysfs_remove_battery(struct acpi_battery *battery)
655{
Sergey Senozhatsky69d94ec2011-08-06 01:34:08 +0300656 mutex_lock(&battery->sysfs_lock);
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100657 if (!battery->bat) {
Sergey Senozhatsky69d94ec2011-08-06 01:34:08 +0300658 mutex_unlock(&battery->sysfs_lock);
Andrey Borzenkov508df922007-10-28 12:50:09 +0300659 return;
Lan Tianyu9c921c222011-06-30 11:34:12 +0800660 }
661
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100662 device_remove_file(&battery->bat->dev, &alarm_attr);
663 power_supply_unregister(battery->bat);
664 battery->bat = NULL;
Sergey Senozhatsky69d94ec2011-08-06 01:34:08 +0300665 mutex_unlock(&battery->sysfs_lock);
Hector Martinbc76f902009-08-06 15:57:48 -0700666}
667
Kamil Iskra4000e622012-11-16 22:28:58 +0100668static void find_battery(const struct dmi_header *dm, void *private)
669{
670 struct acpi_battery *battery = (struct acpi_battery *)private;
671 /* Note: the hardcoded offsets below have been extracted from
672 the source code of dmidecode. */
673 if (dm->type == DMI_ENTRY_PORTABLE_BATTERY && dm->length >= 8) {
674 const u8 *dmi_data = (const u8 *)(dm + 1);
675 int dmi_capacity = get_unaligned((const u16 *)(dmi_data + 6));
676 if (dm->length >= 18)
677 dmi_capacity *= dmi_data[17];
678 if (battery->design_capacity * battery->design_voltage / 1000
679 != dmi_capacity &&
680 battery->design_capacity * 10 == dmi_capacity)
681 set_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH,
682 &battery->flags);
683 }
684}
685
Zhang Rui557d5862010-10-22 10:02:06 +0800686/*
687 * According to the ACPI spec, some kinds of primary batteries can
688 * report percentage battery remaining capacity directly to OS.
689 * In this case, it reports the Last Full Charged Capacity == 100
690 * and BatteryPresentRate == 0xFFFFFFFF.
691 *
692 * Now we found some battery reports percentage remaining capacity
693 * even if it's rechargeable.
694 * https://bugzilla.kernel.org/show_bug.cgi?id=15979
695 *
696 * Handle this correctly so that they won't break userspace.
697 */
Lan Tianyu7b786222011-06-30 11:33:27 +0800698static void acpi_battery_quirks(struct acpi_battery *battery)
Zhang Rui557d5862010-10-22 10:02:06 +0800699{
700 if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
Nicholas Mazzuca0f4c6542013-05-08 23:11:15 +0000701 return;
Zhang Rui557d5862010-10-22 10:02:06 +0800702
Nicholas Mazzuca0f4c6542013-05-08 23:11:15 +0000703 if (battery->full_charge_capacity == 100 &&
704 battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN &&
705 battery->capacity_now >= 0 && battery->capacity_now <= 100) {
Zhang Rui557d5862010-10-22 10:02:06 +0800706 set_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags);
707 battery->full_charge_capacity = battery->design_capacity;
708 battery->capacity_now = (battery->capacity_now *
709 battery->full_charge_capacity) / 100;
710 }
Kamil Iskra4000e622012-11-16 22:28:58 +0100711
712 if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags))
Nicholas Mazzuca0f4c6542013-05-08 23:11:15 +0000713 return;
Kamil Iskra4000e622012-11-16 22:28:58 +0100714
715 if (battery->power_unit && dmi_name_in_vendors("LENOVO")) {
716 const char *s;
717 s = dmi_get_system_info(DMI_PRODUCT_VERSION);
Rasmus Villemoesffd8a732014-09-16 22:51:24 +0200718 if (s && !strncasecmp(s, "ThinkPad", 8)) {
Kamil Iskra4000e622012-11-16 22:28:58 +0100719 dmi_walk(find_battery, battery);
720 if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH,
721 &battery->flags) &&
722 battery->design_voltage) {
723 battery->design_capacity =
724 battery->design_capacity *
725 10000 / battery->design_voltage;
726 battery->full_charge_capacity =
727 battery->full_charge_capacity *
728 10000 / battery->design_voltage;
729 battery->design_capacity_warning =
730 battery->design_capacity_warning *
731 10000 / battery->design_voltage;
732 battery->capacity_now = battery->capacity_now *
733 10000 / battery->design_voltage;
734 }
735 }
736 }
Zhang Rui557d5862010-10-22 10:02:06 +0800737}
738
Lan Tianyu9e50bc12014-05-04 14:07:06 +0800739static int acpi_battery_update(struct acpi_battery *battery, bool resume)
Vladimir Lebedev4bd35cd2007-02-10 01:43:48 -0500740{
Alexey Starikovskiy50b17852008-12-23 02:44:54 +0300741 int result, old_present = acpi_battery_present(battery);
Alexey Starikovskiy97749cd2008-01-01 14:27:24 -0500742 result = acpi_battery_get_status(battery);
Andrey Borzenkov508df922007-10-28 12:50:09 +0300743 if (result)
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300744 return result;
Andrey Borzenkov508df922007-10-28 12:50:09 +0300745 if (!acpi_battery_present(battery)) {
746 sysfs_remove_battery(battery);
Alexey Starikovskiy97749cd2008-01-01 14:27:24 -0500747 battery->update_time = 0;
Andrey Borzenkov508df922007-10-28 12:50:09 +0300748 return 0;
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +0300749 }
Lan Tianyu9e50bc12014-05-04 14:07:06 +0800750
751 if (resume)
752 return 0;
753
Alexey Starikovskiy50b17852008-12-23 02:44:54 +0300754 if (!battery->update_time ||
755 old_present != acpi_battery_present(battery)) {
Alexey Starikovskiy97749cd2008-01-01 14:27:24 -0500756 result = acpi_battery_get_info(battery);
757 if (result)
758 return result;
759 acpi_battery_init_alarm(battery);
760 }
Carlos Garnacho12c78ca2016-08-10 17:24:15 +0200761
762 result = acpi_battery_get_state(battery);
763 if (result)
764 return result;
765 acpi_battery_quirks(battery);
766
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100767 if (!battery->bat) {
Stefan Hajnoczieb03cb02011-07-12 09:03:29 +0100768 result = sysfs_add_battery(battery);
769 if (result)
770 return result;
771 }
Zhang Ruie0d1f092014-05-28 15:23:38 +0800772
773 /*
774 * Wakeup the system if battery is critical low
775 * or lower than the alarm level
776 */
777 if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) ||
778 (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
779 (battery->capacity_now <= battery->alarm)))
780 pm_wakeup_event(&battery->device->dev, 0);
781
Zhang Rui557d5862010-10-22 10:02:06 +0800782 return result;
Vladimir Lebedev4bd35cd2007-02-10 01:43:48 -0500783}
784
Rafael J. Wysockida8aeb92011-01-06 23:42:27 +0100785static void acpi_battery_refresh(struct acpi_battery *battery)
786{
Andy Whitcroftc5971452012-05-03 14:48:26 +0100787 int power_unit;
788
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100789 if (!battery->bat)
Rafael J. Wysockida8aeb92011-01-06 23:42:27 +0100790 return;
791
Andy Whitcroftc5971452012-05-03 14:48:26 +0100792 power_unit = battery->power_unit;
793
Rafael J. Wysockida8aeb92011-01-06 23:42:27 +0100794 acpi_battery_get_info(battery);
Andy Whitcroftc5971452012-05-03 14:48:26 +0100795
796 if (power_unit == battery->power_unit)
797 return;
798
799 /* The battery has changed its reporting units. */
Rafael J. Wysockida8aeb92011-01-06 23:42:27 +0100800 sysfs_remove_battery(battery);
801 sysfs_add_battery(battery);
802}
803
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804/* --------------------------------------------------------------------------
Lan Tianyu3a670cc2014-05-04 11:07:25 +0800805 FS Interface (/proc)
806 -------------------------------------------------------------------------- */
807
808#ifdef CONFIG_ACPI_PROCFS_POWER
809static struct proc_dir_entry *acpi_battery_dir;
810
Mathias Krause27059b92015-06-13 14:26:54 +0200811static const char *acpi_battery_units(const struct acpi_battery *battery)
812{
813 return (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) ?
814 "mA" : "mW";
815}
816
Lan Tianyu3a670cc2014-05-04 11:07:25 +0800817static int acpi_battery_print_info(struct seq_file *seq, int result)
818{
819 struct acpi_battery *battery = seq->private;
820
821 if (result)
822 goto end;
823
824 seq_printf(seq, "present: %s\n",
825 acpi_battery_present(battery) ? "yes" : "no");
826 if (!acpi_battery_present(battery))
827 goto end;
828 if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
829 seq_printf(seq, "design capacity: unknown\n");
830 else
831 seq_printf(seq, "design capacity: %d %sh\n",
832 battery->design_capacity,
833 acpi_battery_units(battery));
834
835 if (battery->full_charge_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
836 seq_printf(seq, "last full capacity: unknown\n");
837 else
838 seq_printf(seq, "last full capacity: %d %sh\n",
839 battery->full_charge_capacity,
840 acpi_battery_units(battery));
841
842 seq_printf(seq, "battery technology: %srechargeable\n",
843 (!battery->technology)?"non-":"");
844
845 if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
846 seq_printf(seq, "design voltage: unknown\n");
847 else
848 seq_printf(seq, "design voltage: %d mV\n",
849 battery->design_voltage);
850 seq_printf(seq, "design capacity warning: %d %sh\n",
851 battery->design_capacity_warning,
852 acpi_battery_units(battery));
853 seq_printf(seq, "design capacity low: %d %sh\n",
854 battery->design_capacity_low,
855 acpi_battery_units(battery));
856 seq_printf(seq, "cycle count: %i\n", battery->cycle_count);
857 seq_printf(seq, "capacity granularity 1: %d %sh\n",
858 battery->capacity_granularity_1,
859 acpi_battery_units(battery));
860 seq_printf(seq, "capacity granularity 2: %d %sh\n",
861 battery->capacity_granularity_2,
862 acpi_battery_units(battery));
863 seq_printf(seq, "model number: %s\n", battery->model_number);
864 seq_printf(seq, "serial number: %s\n", battery->serial_number);
865 seq_printf(seq, "battery type: %s\n", battery->type);
866 seq_printf(seq, "OEM info: %s\n", battery->oem_info);
867 end:
868 if (result)
869 seq_printf(seq, "ERROR: Unable to read battery info\n");
870 return result;
871}
872
873static int acpi_battery_print_state(struct seq_file *seq, int result)
874{
875 struct acpi_battery *battery = seq->private;
876
877 if (result)
878 goto end;
879
880 seq_printf(seq, "present: %s\n",
881 acpi_battery_present(battery) ? "yes" : "no");
882 if (!acpi_battery_present(battery))
883 goto end;
884
885 seq_printf(seq, "capacity state: %s\n",
886 (battery->state & 0x04) ? "critical" : "ok");
887 if ((battery->state & 0x01) && (battery->state & 0x02))
888 seq_printf(seq,
889 "charging state: charging/discharging\n");
890 else if (battery->state & 0x01)
891 seq_printf(seq, "charging state: discharging\n");
892 else if (battery->state & 0x02)
893 seq_printf(seq, "charging state: charging\n");
894 else
895 seq_printf(seq, "charging state: charged\n");
896
897 if (battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN)
898 seq_printf(seq, "present rate: unknown\n");
899 else
900 seq_printf(seq, "present rate: %d %s\n",
901 battery->rate_now, acpi_battery_units(battery));
902
903 if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN)
904 seq_printf(seq, "remaining capacity: unknown\n");
905 else
906 seq_printf(seq, "remaining capacity: %d %sh\n",
907 battery->capacity_now, acpi_battery_units(battery));
908 if (battery->voltage_now == ACPI_BATTERY_VALUE_UNKNOWN)
909 seq_printf(seq, "present voltage: unknown\n");
910 else
911 seq_printf(seq, "present voltage: %d mV\n",
912 battery->voltage_now);
913 end:
914 if (result)
915 seq_printf(seq, "ERROR: Unable to read battery state\n");
916
917 return result;
918}
919
920static int acpi_battery_print_alarm(struct seq_file *seq, int result)
921{
922 struct acpi_battery *battery = seq->private;
923
924 if (result)
925 goto end;
926
927 if (!acpi_battery_present(battery)) {
928 seq_printf(seq, "present: no\n");
929 goto end;
930 }
931 seq_printf(seq, "alarm: ");
932 if (!battery->alarm)
933 seq_printf(seq, "unsupported\n");
934 else
935 seq_printf(seq, "%u %sh\n", battery->alarm,
936 acpi_battery_units(battery));
937 end:
938 if (result)
939 seq_printf(seq, "ERROR: Unable to read battery alarm\n");
940 return result;
941}
942
943static ssize_t acpi_battery_write_alarm(struct file *file,
944 const char __user * buffer,
945 size_t count, loff_t * ppos)
946{
947 int result = 0;
948 char alarm_string[12] = { '\0' };
949 struct seq_file *m = file->private_data;
950 struct acpi_battery *battery = m->private;
951
952 if (!battery || (count > sizeof(alarm_string) - 1))
953 return -EINVAL;
954 if (!acpi_battery_present(battery)) {
955 result = -ENODEV;
956 goto end;
957 }
958 if (copy_from_user(alarm_string, buffer, count)) {
959 result = -EFAULT;
960 goto end;
961 }
962 alarm_string[count] = '\0';
Christoph Jaeger3d915892014-06-13 21:49:58 +0200963 if (kstrtoint(alarm_string, 0, &battery->alarm)) {
964 result = -EINVAL;
965 goto end;
966 }
Lan Tianyu3a670cc2014-05-04 11:07:25 +0800967 result = acpi_battery_set_alarm(battery);
968 end:
969 if (!result)
970 return count;
971 return result;
972}
973
974typedef int(*print_func)(struct seq_file *seq, int result);
975
976static print_func acpi_print_funcs[ACPI_BATTERY_NUMFILES] = {
977 acpi_battery_print_info,
978 acpi_battery_print_state,
979 acpi_battery_print_alarm,
980};
981
982static int acpi_battery_read(int fid, struct seq_file *seq)
983{
984 struct acpi_battery *battery = seq->private;
Lan Tianyu9e50bc12014-05-04 14:07:06 +0800985 int result = acpi_battery_update(battery, false);
Lan Tianyu3a670cc2014-05-04 11:07:25 +0800986 return acpi_print_funcs[fid](seq, result);
987}
988
989#define DECLARE_FILE_FUNCTIONS(_name) \
990static int acpi_battery_read_##_name(struct seq_file *seq, void *offset) \
991{ \
992 return acpi_battery_read(_name##_tag, seq); \
993} \
994static int acpi_battery_##_name##_open_fs(struct inode *inode, struct file *file) \
995{ \
996 return single_open(file, acpi_battery_read_##_name, PDE_DATA(inode)); \
997}
998
999DECLARE_FILE_FUNCTIONS(info);
1000DECLARE_FILE_FUNCTIONS(state);
1001DECLARE_FILE_FUNCTIONS(alarm);
1002
1003#undef DECLARE_FILE_FUNCTIONS
1004
1005#define FILE_DESCRIPTION_RO(_name) \
1006 { \
1007 .name = __stringify(_name), \
1008 .mode = S_IRUGO, \
1009 .ops = { \
1010 .open = acpi_battery_##_name##_open_fs, \
1011 .read = seq_read, \
1012 .llseek = seq_lseek, \
1013 .release = single_release, \
1014 .owner = THIS_MODULE, \
1015 }, \
1016 }
1017
1018#define FILE_DESCRIPTION_RW(_name) \
1019 { \
1020 .name = __stringify(_name), \
1021 .mode = S_IFREG | S_IRUGO | S_IWUSR, \
1022 .ops = { \
1023 .open = acpi_battery_##_name##_open_fs, \
1024 .read = seq_read, \
1025 .llseek = seq_lseek, \
1026 .write = acpi_battery_write_##_name, \
1027 .release = single_release, \
1028 .owner = THIS_MODULE, \
1029 }, \
1030 }
1031
1032static const struct battery_file {
1033 struct file_operations ops;
1034 umode_t mode;
1035 const char *name;
1036} acpi_battery_file[] = {
1037 FILE_DESCRIPTION_RO(info),
1038 FILE_DESCRIPTION_RO(state),
1039 FILE_DESCRIPTION_RW(alarm),
1040};
1041
1042#undef FILE_DESCRIPTION_RO
1043#undef FILE_DESCRIPTION_RW
1044
1045static int acpi_battery_add_fs(struct acpi_device *device)
1046{
1047 struct proc_dir_entry *entry = NULL;
1048 int i;
1049
1050 printk(KERN_WARNING PREFIX "Deprecated procfs I/F for battery is loaded,"
1051 " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n");
1052 if (!acpi_device_dir(device)) {
1053 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
1054 acpi_battery_dir);
1055 if (!acpi_device_dir(device))
1056 return -ENODEV;
1057 }
1058
1059 for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
1060 entry = proc_create_data(acpi_battery_file[i].name,
1061 acpi_battery_file[i].mode,
1062 acpi_device_dir(device),
1063 &acpi_battery_file[i].ops,
1064 acpi_driver_data(device));
1065 if (!entry)
1066 return -ENODEV;
1067 }
1068 return 0;
1069}
1070
1071static void acpi_battery_remove_fs(struct acpi_device *device)
1072{
1073 int i;
1074 if (!acpi_device_dir(device))
1075 return;
1076 for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i)
1077 remove_proc_entry(acpi_battery_file[i].name,
1078 acpi_device_dir(device));
1079
1080 remove_proc_entry(acpi_device_bid(device), acpi_battery_dir);
1081 acpi_device_dir(device) = NULL;
1082}
1083
1084#endif
1085
1086/* --------------------------------------------------------------------------
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 Driver Interface
1088 -------------------------------------------------------------------------- */
1089
Bjorn Helgaasd9406692009-04-30 09:35:47 -06001090static void acpi_battery_notify(struct acpi_device *device, u32 event)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091{
Bjorn Helgaasd9406692009-04-30 09:35:47 -06001092 struct acpi_battery *battery = acpi_driver_data(device);
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +01001093 struct power_supply *old;
Bjorn Helgaasd9406692009-04-30 09:35:47 -06001094
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 if (!battery)
Patrick Mocheld550d982006-06-27 00:41:40 -04001096 return;
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +01001097 old = battery->bat;
Alexander Mezinf43691c2014-06-04 02:01:23 +07001098 /*
1099 * On Acer Aspire V5-573G notifications are sometimes triggered too
1100 * early. For example, when AC is unplugged and notification is
1101 * triggered, battery state is still reported as "Full", and changes to
1102 * "Discharging" only after short delay, without any notification.
1103 */
1104 if (battery_notification_delay_ms > 0)
1105 msleep(battery_notification_delay_ms);
Rafael J. Wysockida8aeb92011-01-06 23:42:27 +01001106 if (event == ACPI_BATTERY_NOTIFY_INFO)
1107 acpi_battery_refresh(battery);
Lan Tianyu9e50bc12014-05-04 14:07:06 +08001108 acpi_battery_update(battery, false);
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +04001109 acpi_bus_generate_netlink_event(device->pnp.device_class,
Kay Sievers07944692008-10-30 01:18:59 +01001110 dev_name(&device->dev), event,
Vladimir Lebedev9ea7d572007-02-20 15:48:06 +03001111 acpi_battery_present(battery));
Alexander Mezin411e0f72014-03-12 00:58:47 +07001112 acpi_notifier_call_chain(device, event, acpi_battery_present(battery));
Justin P. Mattock2345baf2009-12-13 14:42:36 -08001113 /* acpi_battery_update could remove power_supply object */
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +01001114 if (old && battery->bat)
1115 power_supply_changed(battery->bat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116}
1117
Kyle McMartin25be5822011-03-22 16:19:50 -04001118static int battery_notify(struct notifier_block *nb,
1119 unsigned long mode, void *_unused)
1120{
1121 struct acpi_battery *battery = container_of(nb, struct acpi_battery,
1122 pm_nb);
Lan Tianyu9e50bc12014-05-04 14:07:06 +08001123 int result;
1124
Kyle McMartin25be5822011-03-22 16:19:50 -04001125 switch (mode) {
Lan Tianyud5a59112011-06-30 11:33:40 +08001126 case PM_POST_HIBERNATION:
Kyle McMartin25be5822011-03-22 16:19:50 -04001127 case PM_POST_SUSPEND:
Lan Tianyu9e50bc12014-05-04 14:07:06 +08001128 if (!acpi_battery_present(battery))
1129 return 0;
1130
Krzysztof Kozlowski31f7dc72015-04-14 22:24:13 +09001131 if (!battery->bat) {
Lan Tianyu9e50bc12014-05-04 14:07:06 +08001132 result = acpi_battery_get_info(battery);
1133 if (result)
1134 return result;
1135
1136 result = sysfs_add_battery(battery);
1137 if (result)
1138 return result;
1139 } else
1140 acpi_battery_refresh(battery);
1141
1142 acpi_battery_init_alarm(battery);
1143 acpi_battery_get_state(battery);
Kyle McMartin25be5822011-03-22 16:19:50 -04001144 break;
1145 }
1146
1147 return 0;
1148}
1149
Mathias Krause048d16d2015-06-13 14:26:55 +02001150static int __init
1151battery_bix_broken_package_quirk(const struct dmi_system_id *d)
Alexander Mezin3f5dc082014-06-04 02:01:22 +07001152{
1153 battery_bix_broken_package = 1;
1154 return 0;
1155}
1156
Mathias Krause048d16d2015-06-13 14:26:55 +02001157static int __init
1158battery_notification_delay_quirk(const struct dmi_system_id *d)
Alexander Mezinf43691c2014-06-04 02:01:23 +07001159{
1160 battery_notification_delay_ms = 1000;
1161 return 0;
1162}
1163
Mathias Krause048d16d2015-06-13 14:26:55 +02001164static const struct dmi_system_id bat_dmi_table[] __initconst = {
Lan Tianyua90b4032014-01-06 22:50:37 +08001165 {
Alexander Mezin3f5dc082014-06-04 02:01:22 +07001166 .callback = battery_bix_broken_package_quirk,
Lan Tianyua90b4032014-01-06 22:50:37 +08001167 .ident = "NEC LZ750/LS",
1168 .matches = {
1169 DMI_MATCH(DMI_SYS_VENDOR, "NEC"),
1170 DMI_MATCH(DMI_PRODUCT_NAME, "PC-LZ750LS"),
1171 },
1172 },
Alexander Mezinf43691c2014-06-04 02:01:23 +07001173 {
1174 .callback = battery_notification_delay_quirk,
1175 .ident = "Acer Aspire V5-573G",
1176 .matches = {
1177 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
1178 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-573G"),
1179 },
1180 },
Lan Tianyua90b4032014-01-06 22:50:37 +08001181 {},
1182};
1183
Lan Tianyu75646e72014-07-07 15:47:12 +08001184/*
1185 * Some machines'(E,G Lenovo Z480) ECs are not stable
1186 * during boot up and this causes battery driver fails to be
1187 * probed due to failure of getting battery information
1188 * from EC sometimes. After several retries, the operation
1189 * may work. So add retry code here and 20ms sleep between
1190 * every retries.
1191 */
1192static int acpi_battery_update_retry(struct acpi_battery *battery)
1193{
1194 int retry, ret;
1195
1196 for (retry = 5; retry; retry--) {
1197 ret = acpi_battery_update(battery, false);
1198 if (!ret)
1199 break;
1200
1201 msleep(20);
1202 }
1203 return ret;
1204}
1205
Len Brown4be44fc2005-08-05 00:44:28 -04001206static int acpi_battery_add(struct acpi_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207{
Len Brown4be44fc2005-08-05 00:44:28 -04001208 int result = 0;
Len Brown4be44fc2005-08-05 00:44:28 -04001209 struct acpi_battery *battery = NULL;
Jiang Liu952c63e2013-06-29 00:24:38 +08001210
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 if (!device)
Patrick Mocheld550d982006-06-27 00:41:40 -04001212 return -EINVAL;
Lan Tianyu40e7fcb2014-11-23 21:22:54 +08001213
1214 if (device->dep_unmet)
1215 return -EPROBE_DEFER;
1216
Burman Yan36bcbec2006-12-19 12:56:11 -08001217 battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 if (!battery)
Patrick Mocheld550d982006-06-27 00:41:40 -04001219 return -ENOMEM;
Patrick Mochel145def82006-05-19 16:54:39 -04001220 battery->device = device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
1222 strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
Pavel Machekdb89b4f2008-09-22 14:37:34 -07001223 device->driver_data = battery;
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +04001224 mutex_init(&battery->lock);
Sergey Senozhatsky69d94ec2011-08-06 01:34:08 +03001225 mutex_init(&battery->sysfs_lock);
Jiang Liu952c63e2013-06-29 00:24:38 +08001226 if (acpi_has_method(battery->device->handle, "_BIX"))
Alexey Starikovskiyc67fcd62009-10-15 14:31:44 +04001227 set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
Lan Tianyu75646e72014-07-07 15:47:12 +08001228
1229 result = acpi_battery_update_retry(battery);
Stefan Hajnoczieb03cb02011-07-12 09:03:29 +01001230 if (result)
1231 goto fail;
Lan Tianyu75646e72014-07-07 15:47:12 +08001232
Lan Tianyu3a670cc2014-05-04 11:07:25 +08001233#ifdef CONFIG_ACPI_PROCFS_POWER
1234 result = acpi_battery_add_fs(device);
1235#endif
1236 if (result) {
1237#ifdef CONFIG_ACPI_PROCFS_POWER
1238 acpi_battery_remove_fs(device);
1239#endif
1240 goto fail;
1241 }
Kyle McMartin25be5822011-03-22 16:19:50 -04001242
Stefan Hajnoczie80bba42011-07-12 09:03:28 +01001243 printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n",
1244 ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
1245 device->status.battery_present ? "present" : "absent");
1246
Kyle McMartin25be5822011-03-22 16:19:50 -04001247 battery->pm_nb.notifier_call = battery_notify;
1248 register_pm_notifier(&battery->pm_nb);
1249
Zhang Ruie0d1f092014-05-28 15:23:38 +08001250 device_init_wakeup(&device->dev, 1);
1251
Patrick Mocheld550d982006-06-27 00:41:40 -04001252 return result;
Stefan Hajnoczie80bba42011-07-12 09:03:28 +01001253
1254fail:
1255 sysfs_remove_battery(battery);
1256 mutex_destroy(&battery->lock);
Sergey Senozhatsky69d94ec2011-08-06 01:34:08 +03001257 mutex_destroy(&battery->sysfs_lock);
Stefan Hajnoczie80bba42011-07-12 09:03:28 +01001258 kfree(battery);
1259 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260}
1261
Rafael J. Wysocki51fac832013-01-24 00:24:48 +01001262static int acpi_battery_remove(struct acpi_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263{
Len Brown4be44fc2005-08-05 00:44:28 -04001264 struct acpi_battery *battery = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 if (!device || !acpi_driver_data(device))
Patrick Mocheld550d982006-06-27 00:41:40 -04001267 return -EINVAL;
Zhang Ruie0d1f092014-05-28 15:23:38 +08001268 device_init_wakeup(&device->dev, 0);
Jan Engelhardt50dd0962006-10-01 00:28:50 +02001269 battery = acpi_driver_data(device);
Kyle McMartin25be5822011-03-22 16:19:50 -04001270 unregister_pm_notifier(&battery->pm_nb);
Lan Tianyu3a670cc2014-05-04 11:07:25 +08001271#ifdef CONFIG_ACPI_PROCFS_POWER
1272 acpi_battery_remove_fs(device);
1273#endif
Andrey Borzenkov508df922007-10-28 12:50:09 +03001274 sysfs_remove_battery(battery);
Alexey Starikovskiy038fdea2007-09-26 19:42:46 +04001275 mutex_destroy(&battery->lock);
Sergey Senozhatsky69d94ec2011-08-06 01:34:08 +03001276 mutex_destroy(&battery->sysfs_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 kfree(battery);
Patrick Mocheld550d982006-06-27 00:41:40 -04001278 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279}
1280
Rafael J. Wysocki90692402012-08-09 23:00:02 +02001281#ifdef CONFIG_PM_SLEEP
Jiri Kosina34c44152006-10-10 14:20:41 -07001282/* this is needed to learn about changes made in suspended state */
Rafael J. Wysockia6f50dc2012-06-27 23:26:43 +02001283static int acpi_battery_resume(struct device *dev)
Jiri Kosina34c44152006-10-10 14:20:41 -07001284{
1285 struct acpi_battery *battery;
Rafael J. Wysockia6f50dc2012-06-27 23:26:43 +02001286
1287 if (!dev)
Jiri Kosina34c44152006-10-10 14:20:41 -07001288 return -EINVAL;
Rafael J. Wysockia6f50dc2012-06-27 23:26:43 +02001289
1290 battery = acpi_driver_data(to_acpi_device(dev));
1291 if (!battery)
1292 return -EINVAL;
1293
Alexey Starikovskiyf1d46612007-09-26 19:42:52 +04001294 battery->update_time = 0;
Lan Tianyu9e50bc12014-05-04 14:07:06 +08001295 acpi_battery_update(battery, true);
Vladimir Lebedevb6ce4082007-02-20 15:48:06 +03001296 return 0;
Jiri Kosina34c44152006-10-10 14:20:41 -07001297}
Shuah Khan7f6895c2014-02-12 20:19:06 -07001298#else
1299#define acpi_battery_resume NULL
Rafael J. Wysocki90692402012-08-09 23:00:02 +02001300#endif
Jiri Kosina34c44152006-10-10 14:20:41 -07001301
Rafael J. Wysockia6f50dc2012-06-27 23:26:43 +02001302static SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume);
1303
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +04001304static struct acpi_driver acpi_battery_driver = {
1305 .name = "battery",
1306 .class = ACPI_BATTERY_CLASS,
1307 .ids = battery_device_ids,
Bjorn Helgaasd9406692009-04-30 09:35:47 -06001308 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +04001309 .ops = {
1310 .add = acpi_battery_add,
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +04001311 .remove = acpi_battery_remove,
Bjorn Helgaasd9406692009-04-30 09:35:47 -06001312 .notify = acpi_battery_notify,
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +04001313 },
Rafael J. Wysockia6f50dc2012-06-27 23:26:43 +02001314 .drv.pm = &acpi_battery_pm,
Alexey Starikovskiyaa650bb2007-09-26 19:42:58 +04001315};
1316
Linus Torvaldsb0cbc862009-04-11 12:45:20 -07001317static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318{
Luis Henriques479faaf2015-05-11 22:48:46 +01001319 int result;
1320
Alexander Mezin3f5dc082014-06-04 02:01:22 +07001321 dmi_check_system(bat_dmi_table);
Luis Henriques479faaf2015-05-11 22:48:46 +01001322
Lan Tianyu3a670cc2014-05-04 11:07:25 +08001323#ifdef CONFIG_ACPI_PROCFS_POWER
1324 acpi_battery_dir = acpi_lock_battery_dir();
1325 if (!acpi_battery_dir)
1326 return;
1327#endif
Luis Henriques479faaf2015-05-11 22:48:46 +01001328 result = acpi_bus_register_driver(&acpi_battery_driver);
Lan Tianyu3a670cc2014-05-04 11:07:25 +08001329#ifdef CONFIG_ACPI_PROCFS_POWER
Luis Henriques479faaf2015-05-11 22:48:46 +01001330 if (result < 0)
Lan Tianyu3a670cc2014-05-04 11:07:25 +08001331 acpi_unlock_battery_dir(acpi_battery_dir);
1332#endif
Hans de Goedebc39fbc2017-04-19 14:02:09 +02001333 battery_driver_registered = (result == 0);
Arjan van de Ven0f66af52009-01-10 14:19:05 -05001334}
1335
1336static int __init acpi_battery_init(void)
1337{
Luis Henriquese234b072015-05-11 22:48:38 +01001338 if (acpi_disabled)
1339 return -ENODEV;
1340
Luis Henriqueseca21d912015-05-11 22:49:05 +01001341 async_cookie = async_schedule(acpi_battery_init_async, NULL);
Patrick Mocheld550d982006-06-27 00:41:40 -04001342 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343}
1344
Len Brown4be44fc2005-08-05 00:44:28 -04001345static void __exit acpi_battery_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346{
Chris Wilson5dfa0c72016-05-19 09:11:52 +01001347 async_synchronize_cookie(async_cookie + 1);
Hans de Goedebc39fbc2017-04-19 14:02:09 +02001348 if (battery_driver_registered)
1349 acpi_bus_unregister_driver(&acpi_battery_driver);
Lan Tianyu3a670cc2014-05-04 11:07:25 +08001350#ifdef CONFIG_ACPI_PROCFS_POWER
Hans de Goedebc39fbc2017-04-19 14:02:09 +02001351 if (acpi_battery_dir)
1352 acpi_unlock_battery_dir(acpi_battery_dir);
Lan Tianyu3a670cc2014-05-04 11:07:25 +08001353#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354}
1355
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356module_init(acpi_battery_init);
1357module_exit(acpi_battery_exit);