Blame view

drivers/acpi/battery.c 37.8 KB
c942fddf8   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  /*
aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
3
   *  battery.c - ACPI Battery Driver (Revision: 2.0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
   *
aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
5
6
   *  Copyright (C) 2007 Alexey Starikovskiy <astarikovskiy@suse.de>
   *  Copyright (C) 2004-2007 Vladimir Lebedev <vladimir.p.lebedev@intel.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
   *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
   *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
   */
fa93854f7   Ognjen Galic   battery: Add the ...
10
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
53dd200a2   Dmitry Rozhkov   ACPI / battery: r...
11
12
13
14
  #include <linux/async.h>
  #include <linux/delay.h>
  #include <linux/dmi.h>
  #include <linux/jiffies.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/kernel.h>
fa93854f7   Ognjen Galic   battery: Add the ...
16
  #include <linux/list.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #include <linux/module.h>
fa93854f7   Ognjen Galic   battery: Add the ...
18
  #include <linux/mutex.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
19
  #include <linux/slab.h>
25be58215   Kyle McMartin   ACPI battery: fri...
20
  #include <linux/suspend.h>
53dd200a2   Dmitry Rozhkov   ACPI / battery: r...
21
  #include <linux/types.h>
4000e6261   Kamil Iskra   ACPI / battery: C...
22
  #include <asm/unaligned.h>
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
23

8b48463f8   Lv Zheng   ACPI: Clean up in...
24
  #include <linux/acpi.h>
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
25
  #include <linux/power_supply.h>
fa93854f7   Ognjen Galic   battery: Add the ...
26
  #include <acpi/battery.h>
f03be3525   Alexander Mezin   ACPI / battery: m...
27

a192a9580   Len Brown   ACPI: Move defini...
28
  #define PREFIX "ACPI: "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
cc99f0ad5   Hans de Goede   ACPI / battery: D...
30
31
  #define ACPI_BATTERY_CAPACITY_VALID(capacity) \
  	((capacity) != 0 && (capacity) != ACPI_BATTERY_VALUE_UNKNOWN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  #define ACPI_BATTERY_DEVICE_NAME	"Battery"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34

ae6f61870   Lan Tianyu   ACPI / Battery: A...
35
36
  /* Battery power unit: 0 means mW, 1 means mA */
  #define ACPI_BATTERY_POWER_UNIT_MA	1
1ac5aaa67   Zhang Rui   ACPI / battery: i...
37
38
39
  #define ACPI_BATTERY_STATE_DISCHARGING	0x1
  #define ACPI_BATTERY_STATE_CHARGING	0x2
  #define ACPI_BATTERY_STATE_CRITICAL	0x4
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  #define _COMPONENT		ACPI_BATTERY_COMPONENT
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
41

f52fd66d2   Len Brown   ACPI: clean up AC...
42
  ACPI_MODULE_NAME("battery");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43

f52fd66d2   Len Brown   ACPI: clean up AC...
44
  MODULE_AUTHOR("Paul Diefenbaugh");
aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
45
  MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
7cda93e00   Len Brown   ACPI: delete extr...
46
  MODULE_DESCRIPTION("ACPI Battery Driver");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  MODULE_LICENSE("GPL");
eca21d916   Luis Henriques   ACPI / battery: e...
48
  static async_cookie_t async_cookie;
bc39fbcf9   Hans de Goede   ACPI / battery: F...
49
  static bool battery_driver_registered;
a90b40385   Lan Tianyu   ACPI / Battery: A...
50
  static int battery_bix_broken_package;
f43691c61   Alexander Mezin   ACPI / battery: a...
51
  static int battery_notification_delay_ms;
1b799c5cf   Hans de Goede   ACPI / battery: I...
52
  static int battery_ac_is_broken;
ec625a37c   Carlo Caione   ACPI / battery: A...
53
  static int battery_check_pmic = 1;
f1d4661ab   Alexey Starikovskiy   ACPI: Battery: si...
54
55
56
  static unsigned int cache_time = 1000;
  module_param(cache_time, uint, 0644);
  MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
57

1ba90e3a8   Thomas Renninger   ACPI: autoload mo...
58
59
60
61
  static const struct acpi_device_id battery_device_ids[] = {
  	{"PNP0C0A", 0},
  	{"", 0},
  };
1ba90e3a8   Thomas Renninger   ACPI: autoload mo...
62

aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
63
  MODULE_DEVICE_TABLE(acpi, battery_device_ids);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64

dccfae6d4   Hans de Goede   ACPI / battery: A...
65
66
67
68
  /* Lists of PMIC ACPI HIDs with an (often better) native battery driver */
  static const char * const acpi_battery_blacklist[] = {
  	"INT33F4", /* X-Powers AXP288 PMIC */
  };
7b3bcc4a1   Alexey Starikovskiy   ACPI: Battery: Ad...
69
70
  enum {
  	ACPI_BATTERY_ALARM_PRESENT,
c67fcd670   Alexey Starikovskiy   ACPI: Battery: Ad...
71
  	ACPI_BATTERY_XINFO_PRESENT,
557d58687   Zhang Rui   ACPI battery: sup...
72
  	ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY,
4000e6261   Kamil Iskra   ACPI / battery: C...
73
74
75
76
77
78
79
80
81
82
83
84
  	/* On Lenovo Thinkpad models from 2010 and 2011, the power unit
  	   switches between mWh and mAh depending on whether the system
  	   is running on battery or not.  When mAh is the unit, most
  	   reported values are incorrect and need to be adjusted by
  	   10000/design_voltage.  Verified on x201, t410, t410s, and x220.
  	   Pre-2010 and 2012 models appear to always report in mWh and
  	   are thus unaffected (tested with t42, t61, t500, x200, x300,
  	   and x230).  Also, in mid-2012 Lenovo issued a BIOS update for
  	   the 2011 models that fixes the issue (tested on x220 with a
  	   post-1.29 BIOS), but as of Nov. 2012, no such update is
  	   available for the 2010 models.  */
  	ACPI_BATTERY_QUIRK_THINKPAD_MAH,
a20136a67   Laszlo Toth   ACPI: battery: do...
85
86
87
88
  	/* for batteries reporting current capacity with design capacity
  	 * on a full charge, but showing degradation in full charge cap.
  	 */
  	ACPI_BATTERY_QUIRK_DEGRADED_FULL_CHARGE,
7b3bcc4a1   Alexey Starikovskiy   ACPI: Battery: Ad...
89
  };
78490d821   Alexey Starikovskiy   ACPI: battery: sy...
90

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  struct acpi_battery {
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
92
  	struct mutex lock;
69d94ec6d   Sergey Senozhatsky   Battery: sysfs_re...
93
  	struct mutex sysfs_lock;
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
94
95
  	struct power_supply *bat;
  	struct power_supply_desc bat_desc;
f1d4661ab   Alexey Starikovskiy   ACPI: Battery: si...
96
  	struct acpi_device *device;
25be58215   Kyle McMartin   ACPI battery: fri...
97
  	struct notifier_block pm_nb;
fa93854f7   Ognjen Galic   battery: Add the ...
98
  	struct list_head list;
f1d4661ab   Alexey Starikovskiy   ACPI: Battery: si...
99
  	unsigned long update_time;
016d5baad   Lan Tianyu   ACPI / battery: F...
100
  	int revision;
7faa144a5   Alexey Starikovskiy   ACPI: battery: ad...
101
  	int rate_now;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
102
103
  	int capacity_now;
  	int voltage_now;
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
104
  	int design_capacity;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
105
  	int full_charge_capacity;
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
106
107
108
109
  	int technology;
  	int design_voltage;
  	int design_capacity_warning;
  	int design_capacity_low;
c67fcd670   Alexey Starikovskiy   ACPI: Battery: Ad...
110
111
112
113
114
115
  	int cycle_count;
  	int measurement_accuracy;
  	int max_sampling_time;
  	int min_sampling_time;
  	int max_averaging_interval;
  	int min_averaging_interval;
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
116
117
  	int capacity_granularity_1;
  	int capacity_granularity_2;
f1d4661ab   Alexey Starikovskiy   ACPI: Battery: si...
118
  	int alarm;
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
119
120
121
122
  	char model_number[32];
  	char serial_number[32];
  	char type[32];
  	char oem_info[32];
f1d4661ab   Alexey Starikovskiy   ACPI: Battery: si...
123
124
  	int state;
  	int power_unit;
7b3bcc4a1   Alexey Starikovskiy   ACPI: Battery: Ad...
125
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  };
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
127
  #define to_acpi_battery(x) power_supply_get_drvdata(x)
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
128

efd941f10   Andy Shevchenko   ACPI: suppress co...
129
  static inline int acpi_battery_present(struct acpi_battery *battery)
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
130
  {
78490d821   Alexey Starikovskiy   ACPI: battery: sy...
131
132
  	return battery->device->status.battery_present;
  }
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
133

d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
134
135
136
137
138
139
140
141
  static int acpi_battery_technology(struct acpi_battery *battery)
  {
  	if (!strcasecmp("NiCd", battery->type))
  		return POWER_SUPPLY_TECHNOLOGY_NiCd;
  	if (!strcasecmp("NiMH", battery->type))
  		return POWER_SUPPLY_TECHNOLOGY_NiMH;
  	if (!strcasecmp("LION", battery->type))
  		return POWER_SUPPLY_TECHNOLOGY_LION;
ad40e68bf   Andrey Borzenkov   ACPI: battery: fi...
142
  	if (!strncasecmp("LI-ION", battery->type, 6))
0bde7eee9   Alexey Starikovskiy   ACPI: battery: Su...
143
  		return POWER_SUPPLY_TECHNOLOGY_LION;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
144
145
146
147
  	if (!strcasecmp("LiP", battery->type))
  		return POWER_SUPPLY_TECHNOLOGY_LIPO;
  	return POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
  }
9104476e4   Alexey Starikovskiy   ACPI: Battery: re...
148
  static int acpi_battery_get_state(struct acpi_battery *battery);
b19073a0b   Alexey Starikovskiy   ACPI: battery: Up...
149

56f382a08   Richard Hughes   battery: don't as...
150
151
  static int acpi_battery_is_charged(struct acpi_battery *battery)
  {
1ac5aaa67   Zhang Rui   ACPI / battery: i...
152
  	/* charging, discharging or critical low */
56f382a08   Richard Hughes   battery: don't as...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  	if (battery->state != 0)
  		return 0;
  
  	/* battery not reporting charge */
  	if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
  	    battery->capacity_now == 0)
  		return 0;
  
  	/* good batteries update full_charge as the batteries degrade */
  	if (battery->full_charge_capacity == battery->capacity_now)
  		return 1;
  
  	/* fallback to using design values for broken batteries */
  	if (battery->design_capacity == battery->capacity_now)
  		return 1;
  
  	/* we don't do any sort of metric based on percentages */
  	return 0;
  }
a20136a67   Laszlo Toth   ACPI: battery: do...
172
173
  static bool acpi_battery_is_degraded(struct acpi_battery *battery)
  {
cc99f0ad5   Hans de Goede   ACPI / battery: D...
174
175
  	return ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity) &&
  		ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity) &&
a20136a67   Laszlo Toth   ACPI: battery: do...
176
177
  		battery->full_charge_capacity < battery->design_capacity;
  }
19fffc845   Hans de Goede   ACPI / battery: A...
178
179
180
181
182
183
184
  static int acpi_battery_handle_discharging(struct acpi_battery *battery)
  {
  	/*
  	 * Some devices wrongly report discharging if the battery's charge level
  	 * was above the device's start charging threshold atm the AC adapter
  	 * was plugged in and the device thus did not start a new charge cycle.
  	 */
1b799c5cf   Hans de Goede   ACPI / battery: I...
185
186
  	if ((battery_ac_is_broken || power_supply_is_system_supplied()) &&
  	    battery->rate_now == 0)
19fffc845   Hans de Goede   ACPI / battery: A...
187
188
189
190
  		return POWER_SUPPLY_STATUS_NOT_CHARGING;
  
  	return POWER_SUPPLY_STATUS_DISCHARGING;
  }
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
191
192
193
194
  static int acpi_battery_get_property(struct power_supply *psy,
  				     enum power_supply_property psp,
  				     union power_supply_propval *val)
  {
5b74d1d16   Hans de Goede   ACPI / battery: U...
195
  	int full_capacity = ACPI_BATTERY_VALUE_UNKNOWN, ret = 0;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
196
  	struct acpi_battery *battery = to_acpi_battery(psy);
9104476e4   Alexey Starikovskiy   ACPI: Battery: re...
197
198
199
200
  	if (acpi_battery_present(battery)) {
  		/* run battery update only if it is present */
  		acpi_battery_get_state(battery);
  	} else if (psp != POWER_SUPPLY_PROP_PRESENT)
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
201
202
203
  		return -ENODEV;
  	switch (psp) {
  	case POWER_SUPPLY_PROP_STATUS:
82bf43b29   Daniel Drake   Revert "ACPI / ba...
204
  		if (battery->state & ACPI_BATTERY_STATE_DISCHARGING)
19fffc845   Hans de Goede   ACPI / battery: A...
205
  			val->intval = acpi_battery_handle_discharging(battery);
82bf43b29   Daniel Drake   Revert "ACPI / ba...
206
  		else if (battery->state & ACPI_BATTERY_STATE_CHARGING)
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
207
  			val->intval = POWER_SUPPLY_STATUS_CHARGING;
56f382a08   Richard Hughes   battery: don't as...
208
  		else if (acpi_battery_is_charged(battery))
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
209
  			val->intval = POWER_SUPPLY_STATUS_FULL;
4c41d3ad6   Roland Dreier   ACPI: Always retu...
210
211
  		else
  			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
212
213
214
215
216
217
218
  		break;
  	case POWER_SUPPLY_PROP_PRESENT:
  		val->intval = acpi_battery_present(battery);
  		break;
  	case POWER_SUPPLY_PROP_TECHNOLOGY:
  		val->intval = acpi_battery_technology(battery);
  		break;
c67fcd670   Alexey Starikovskiy   ACPI: Battery: Ad...
219
220
221
  	case POWER_SUPPLY_PROP_CYCLE_COUNT:
  		val->intval = battery->cycle_count;
  		break;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
222
  	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
a1b4bd694   Rafael J. Wysocki   ACPI / Battery: R...
223
224
225
226
  		if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
  			ret = -ENODEV;
  		else
  			val->intval = battery->design_voltage * 1000;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
227
228
  		break;
  	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
a1b4bd694   Rafael J. Wysocki   ACPI / Battery: R...
229
230
231
232
  		if (battery->voltage_now == ACPI_BATTERY_VALUE_UNKNOWN)
  			ret = -ENODEV;
  		else
  			val->intval = battery->voltage_now * 1000;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
233
234
  		break;
  	case POWER_SUPPLY_PROP_CURRENT_NOW:
7faa144a5   Alexey Starikovskiy   ACPI: battery: ad...
235
  	case POWER_SUPPLY_PROP_POWER_NOW:
a1b4bd694   Rafael J. Wysocki   ACPI / Battery: R...
236
237
238
239
  		if (battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN)
  			ret = -ENODEV;
  		else
  			val->intval = battery->rate_now * 1000;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
240
241
242
  		break;
  	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
  	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
cc99f0ad5   Hans de Goede   ACPI / battery: D...
243
  		if (!ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity))
a1b4bd694   Rafael J. Wysocki   ACPI / Battery: R...
244
245
246
  			ret = -ENODEV;
  		else
  			val->intval = battery->design_capacity * 1000;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
247
248
249
  		break;
  	case POWER_SUPPLY_PROP_CHARGE_FULL:
  	case POWER_SUPPLY_PROP_ENERGY_FULL:
cc99f0ad5   Hans de Goede   ACPI / battery: D...
250
  		if (!ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity))
a1b4bd694   Rafael J. Wysocki   ACPI / Battery: R...
251
252
253
  			ret = -ENODEV;
  		else
  			val->intval = battery->full_charge_capacity * 1000;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
254
255
256
  		break;
  	case POWER_SUPPLY_PROP_CHARGE_NOW:
  	case POWER_SUPPLY_PROP_ENERGY_NOW:
a1b4bd694   Rafael J. Wysocki   ACPI / Battery: R...
257
258
259
260
  		if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN)
  			ret = -ENODEV;
  		else
  			val->intval = battery->capacity_now * 1000;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
261
  		break;
a58e11502   srinivas pandruvada   ACPI Battery: Add...
262
  	case POWER_SUPPLY_PROP_CAPACITY:
5b74d1d16   Hans de Goede   ACPI / battery: U...
263
264
265
266
  		if (ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity))
  			full_capacity = battery->full_charge_capacity;
  		else if (ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity))
  			full_capacity = battery->design_capacity;
cc99f0ad5   Hans de Goede   ACPI / battery: D...
267
  		if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
5b74d1d16   Hans de Goede   ACPI / battery: U...
268
  		    full_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
cc99f0ad5   Hans de Goede   ACPI / battery: D...
269
270
  			ret = -ENODEV;
  		else
a58e11502   srinivas pandruvada   ACPI Battery: Add...
271
  			val->intval = battery->capacity_now * 100/
5b74d1d16   Hans de Goede   ACPI / battery: U...
272
  					full_capacity;
a58e11502   srinivas pandruvada   ACPI Battery: Add...
273
  		break;
1ac5aaa67   Zhang Rui   ACPI / battery: i...
274
275
276
277
278
279
280
281
282
283
284
  	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
  		if (battery->state & ACPI_BATTERY_STATE_CRITICAL)
  			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
  		else if (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
  			(battery->capacity_now <= battery->alarm))
  			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
  		else if (acpi_battery_is_charged(battery))
  			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
  		else
  			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
  		break;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
285
286
287
288
289
290
  	case POWER_SUPPLY_PROP_MODEL_NAME:
  		val->strval = battery->model_number;
  		break;
  	case POWER_SUPPLY_PROP_MANUFACTURER:
  		val->strval = battery->oem_info;
  		break;
7c2670bbb   maximilian attems   ACPI: battery: ad...
291
292
293
  	case POWER_SUPPLY_PROP_SERIAL_NUMBER:
  		val->strval = battery->serial_number;
  		break;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
294
  	default:
a1b4bd694   Rafael J. Wysocki   ACPI / Battery: R...
295
  		ret = -EINVAL;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
296
  	}
a1b4bd694   Rafael J. Wysocki   ACPI / Battery: R...
297
  	return ret;
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
298
299
300
301
302
303
  }
  
  static enum power_supply_property charge_battery_props[] = {
  	POWER_SUPPLY_PROP_STATUS,
  	POWER_SUPPLY_PROP_PRESENT,
  	POWER_SUPPLY_PROP_TECHNOLOGY,
c67fcd670   Alexey Starikovskiy   ACPI: Battery: Ad...
304
  	POWER_SUPPLY_PROP_CYCLE_COUNT,
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
305
306
307
308
309
310
  	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
  	POWER_SUPPLY_PROP_VOLTAGE_NOW,
  	POWER_SUPPLY_PROP_CURRENT_NOW,
  	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
  	POWER_SUPPLY_PROP_CHARGE_FULL,
  	POWER_SUPPLY_PROP_CHARGE_NOW,
a58e11502   srinivas pandruvada   ACPI Battery: Add...
311
  	POWER_SUPPLY_PROP_CAPACITY,
1ac5aaa67   Zhang Rui   ACPI / battery: i...
312
  	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
313
314
  	POWER_SUPPLY_PROP_MODEL_NAME,
  	POWER_SUPPLY_PROP_MANUFACTURER,
7c2670bbb   maximilian attems   ACPI: battery: ad...
315
  	POWER_SUPPLY_PROP_SERIAL_NUMBER,
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
316
  };
ff3154d1d   Hans de Goede   ACPI / battery: D...
317
318
319
320
321
322
323
324
325
326
327
328
329
  static enum power_supply_property charge_battery_full_cap_broken_props[] = {
  	POWER_SUPPLY_PROP_STATUS,
  	POWER_SUPPLY_PROP_PRESENT,
  	POWER_SUPPLY_PROP_TECHNOLOGY,
  	POWER_SUPPLY_PROP_CYCLE_COUNT,
  	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
  	POWER_SUPPLY_PROP_VOLTAGE_NOW,
  	POWER_SUPPLY_PROP_CURRENT_NOW,
  	POWER_SUPPLY_PROP_CHARGE_NOW,
  	POWER_SUPPLY_PROP_MODEL_NAME,
  	POWER_SUPPLY_PROP_MANUFACTURER,
  	POWER_SUPPLY_PROP_SERIAL_NUMBER,
  };
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
330
331
332
333
  static enum power_supply_property energy_battery_props[] = {
  	POWER_SUPPLY_PROP_STATUS,
  	POWER_SUPPLY_PROP_PRESENT,
  	POWER_SUPPLY_PROP_TECHNOLOGY,
c67fcd670   Alexey Starikovskiy   ACPI: Battery: Ad...
334
  	POWER_SUPPLY_PROP_CYCLE_COUNT,
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
335
336
  	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
  	POWER_SUPPLY_PROP_VOLTAGE_NOW,
7faa144a5   Alexey Starikovskiy   ACPI: battery: ad...
337
  	POWER_SUPPLY_PROP_POWER_NOW,
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
338
339
340
  	POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
  	POWER_SUPPLY_PROP_ENERGY_FULL,
  	POWER_SUPPLY_PROP_ENERGY_NOW,
a58e11502   srinivas pandruvada   ACPI Battery: Add...
341
  	POWER_SUPPLY_PROP_CAPACITY,
1ac5aaa67   Zhang Rui   ACPI / battery: i...
342
  	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
343
344
  	POWER_SUPPLY_PROP_MODEL_NAME,
  	POWER_SUPPLY_PROP_MANUFACTURER,
7c2670bbb   maximilian attems   ACPI: battery: ad...
345
  	POWER_SUPPLY_PROP_SERIAL_NUMBER,
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
346
  };
b41901a2c   Hans de Goede   ACPI / battery: D...
347
348
349
350
351
352
353
354
355
356
357
358
359
  static enum power_supply_property energy_battery_full_cap_broken_props[] = {
  	POWER_SUPPLY_PROP_STATUS,
  	POWER_SUPPLY_PROP_PRESENT,
  	POWER_SUPPLY_PROP_TECHNOLOGY,
  	POWER_SUPPLY_PROP_CYCLE_COUNT,
  	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
  	POWER_SUPPLY_PROP_VOLTAGE_NOW,
  	POWER_SUPPLY_PROP_POWER_NOW,
  	POWER_SUPPLY_PROP_ENERGY_NOW,
  	POWER_SUPPLY_PROP_MODEL_NAME,
  	POWER_SUPPLY_PROP_MANUFACTURER,
  	POWER_SUPPLY_PROP_SERIAL_NUMBER,
  };
78490d821   Alexey Starikovskiy   ACPI: battery: sy...
360
361
362
  /* --------------------------------------------------------------------------
                                 Battery Management
     -------------------------------------------------------------------------- */
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
363
364
365
366
  struct acpi_offsets {
  	size_t offset;		/* offset inside struct acpi_sbs_battery */
  	u8 mode;		/* int or string? */
  };
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
367

a46587845   Mathias Krause   ACPI / battery: c...
368
  static const struct acpi_offsets state_offsets[] = {
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
369
  	{offsetof(struct acpi_battery, state), 0},
7faa144a5   Alexey Starikovskiy   ACPI: battery: ad...
370
  	{offsetof(struct acpi_battery, rate_now), 0},
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
371
372
  	{offsetof(struct acpi_battery, capacity_now), 0},
  	{offsetof(struct acpi_battery, voltage_now), 0},
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
373
  };
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
374

a46587845   Mathias Krause   ACPI / battery: c...
375
  static const struct acpi_offsets info_offsets[] = {
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
376
377
  	{offsetof(struct acpi_battery, power_unit), 0},
  	{offsetof(struct acpi_battery, design_capacity), 0},
d73809657   Alexey Starikovskiy   ACPI: Battery: Ad...
378
  	{offsetof(struct acpi_battery, full_charge_capacity), 0},
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
379
380
381
382
383
384
385
386
387
388
389
  	{offsetof(struct acpi_battery, technology), 0},
  	{offsetof(struct acpi_battery, design_voltage), 0},
  	{offsetof(struct acpi_battery, design_capacity_warning), 0},
  	{offsetof(struct acpi_battery, design_capacity_low), 0},
  	{offsetof(struct acpi_battery, capacity_granularity_1), 0},
  	{offsetof(struct acpi_battery, capacity_granularity_2), 0},
  	{offsetof(struct acpi_battery, model_number), 1},
  	{offsetof(struct acpi_battery, serial_number), 1},
  	{offsetof(struct acpi_battery, type), 1},
  	{offsetof(struct acpi_battery, oem_info), 1},
  };
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
390

a46587845   Mathias Krause   ACPI / battery: c...
391
  static const struct acpi_offsets extended_info_offsets[] = {
016d5baad   Lan Tianyu   ACPI / battery: F...
392
  	{offsetof(struct acpi_battery, revision), 0},
c67fcd670   Alexey Starikovskiy   ACPI: Battery: Ad...
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
  	{offsetof(struct acpi_battery, power_unit), 0},
  	{offsetof(struct acpi_battery, design_capacity), 0},
  	{offsetof(struct acpi_battery, full_charge_capacity), 0},
  	{offsetof(struct acpi_battery, technology), 0},
  	{offsetof(struct acpi_battery, design_voltage), 0},
  	{offsetof(struct acpi_battery, design_capacity_warning), 0},
  	{offsetof(struct acpi_battery, design_capacity_low), 0},
  	{offsetof(struct acpi_battery, cycle_count), 0},
  	{offsetof(struct acpi_battery, measurement_accuracy), 0},
  	{offsetof(struct acpi_battery, max_sampling_time), 0},
  	{offsetof(struct acpi_battery, min_sampling_time), 0},
  	{offsetof(struct acpi_battery, max_averaging_interval), 0},
  	{offsetof(struct acpi_battery, min_averaging_interval), 0},
  	{offsetof(struct acpi_battery, capacity_granularity_1), 0},
  	{offsetof(struct acpi_battery, capacity_granularity_2), 0},
  	{offsetof(struct acpi_battery, model_number), 1},
  	{offsetof(struct acpi_battery, serial_number), 1},
  	{offsetof(struct acpi_battery, type), 1},
  	{offsetof(struct acpi_battery, oem_info), 1},
  };
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
413
414
  static int extract_package(struct acpi_battery *battery,
  			   union acpi_object *package,
a46587845   Mathias Krause   ACPI / battery: c...
415
  			   const struct acpi_offsets *offsets, int num)
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
416
  {
106449e87   Alexey Starikovskiy   ACPI: Battery: Al...
417
  	int i;
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
418
419
420
421
422
423
424
425
  	union acpi_object *element;
  	if (package->type != ACPI_TYPE_PACKAGE)
  		return -EFAULT;
  	for (i = 0; i < num; ++i) {
  		if (package->package.count <= i)
  			return -EFAULT;
  		element = &package->package.elements[i];
  		if (offsets[i].mode) {
106449e87   Alexey Starikovskiy   ACPI: Battery: Al...
426
427
428
429
430
431
  			u8 *ptr = (u8 *)battery + offsets[i].offset;
  			if (element->type == ACPI_TYPE_STRING ||
  			    element->type == ACPI_TYPE_BUFFER)
  				strncpy(ptr, element->string.pointer, 32);
  			else if (element->type == ACPI_TYPE_INTEGER) {
  				strncpy(ptr, (u8 *)&element->integer.value,
439913fff   Lin Ming   ACPI: replace acp...
432
433
  					sizeof(u64));
  				ptr[sizeof(u64)] = 0;
b8a1bdb14   Alexey Starikovskiy   ACPI: battery: Do...
434
435
  			} else
  				*ptr = 0; /* don't have value */
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
436
  		} else {
b8a1bdb14   Alexey Starikovskiy   ACPI: battery: Do...
437
438
439
  			int *x = (int *)((u8 *)battery + offsets[i].offset);
  			*x = (element->type == ACPI_TYPE_INTEGER) ?
  				element->integer.value : -1;
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
440
  		}
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
441
  	}
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
442
443
444
445
446
  	return 0;
  }
  
  static int acpi_battery_get_status(struct acpi_battery *battery)
  {
aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
447
  	if (acpi_bus_get_status(battery->device)) {
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
448
449
450
  		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA"));
  		return -ENODEV;
  	}
aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
451
  	return 0;
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
452
  }
2d09af4a8   Dave Lambley   ACPI / battery: I...
453
454
455
456
  
  static int extract_battery_info(const int use_bix,
  			 struct acpi_battery *battery,
  			 const struct acpi_buffer *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  {
aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
458
  	int result = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459

2d09af4a8   Dave Lambley   ACPI / battery: I...
460
461
  	if (use_bix && battery_bix_broken_package)
  		result = extract_package(battery, buffer->pointer,
a90b40385   Lan Tianyu   ACPI / Battery: A...
462
463
  				extended_info_offsets + 1,
  				ARRAY_SIZE(extended_info_offsets) - 1);
2d09af4a8   Dave Lambley   ACPI / battery: I...
464
465
  	else if (use_bix)
  		result = extract_package(battery, buffer->pointer,
c67fcd670   Alexey Starikovskiy   ACPI: Battery: Ad...
466
467
468
  				extended_info_offsets,
  				ARRAY_SIZE(extended_info_offsets));
  	else
2d09af4a8   Dave Lambley   ACPI / battery: I...
469
  		result = extract_package(battery, buffer->pointer,
c67fcd670   Alexey Starikovskiy   ACPI: Battery: Ad...
470
  				info_offsets, ARRAY_SIZE(info_offsets));
557d58687   Zhang Rui   ACPI battery: sup...
471
472
  	if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
  		battery->full_charge_capacity = battery->design_capacity;
4000e6261   Kamil Iskra   ACPI / battery: C...
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
  	if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
  	    battery->power_unit && battery->design_voltage) {
  		battery->design_capacity = battery->design_capacity *
  		    10000 / battery->design_voltage;
  		battery->full_charge_capacity = battery->full_charge_capacity *
  		    10000 / battery->design_voltage;
  		battery->design_capacity_warning =
  		    battery->design_capacity_warning *
  		    10000 / battery->design_voltage;
  		/* Curiously, design_capacity_low, unlike the rest of them,
  		   is correct.  */
  		/* capacity_granularity_* equal 1 on the systems tested, so
  		   it's impossible to tell if they would need an adjustment
  		   or not if their values were higher.  */
  	}
a20136a67   Laszlo Toth   ACPI: battery: do...
488
489
490
  	if (test_bit(ACPI_BATTERY_QUIRK_DEGRADED_FULL_CHARGE, &battery->flags) &&
  	    battery->capacity_now > battery->full_charge_capacity)
  		battery->capacity_now = battery->full_charge_capacity;
d550d98d3   Patrick Mochel   ACPI: delete trac...
491
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
  }
2d09af4a8   Dave Lambley   ACPI / battery: I...
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  static int acpi_battery_get_info(struct acpi_battery *battery)
  {
  	const int xinfo = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
  	int use_bix;
  	int result = -ENODEV;
  
  	if (!acpi_battery_present(battery))
  		return 0;
  
  
  	for (use_bix = xinfo ? 1 : 0; use_bix >= 0; use_bix--) {
  		struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
  		acpi_status status = AE_ERROR;
  
  		mutex_lock(&battery->lock);
  		status = acpi_evaluate_object(battery->device->handle,
  					      use_bix ? "_BIX":"_BIF",
  					      NULL, &buffer);
  		mutex_unlock(&battery->lock);
  
  		if (ACPI_FAILURE(status)) {
  			ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s",
  					use_bix ? "_BIX":"_BIF"));
  		} else {
  			result = extract_battery_info(use_bix,
  						      battery,
  						      &buffer);
  
  			kfree(buffer.pointer);
  			break;
  		}
  	}
  
  	if (!result && !use_bix && xinfo)
  		pr_warn(FW_BUG "The _BIX method is broken, using _BIF.
  ");
  
  	return result;
  }
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
532
  static int acpi_battery_get_state(struct acpi_battery *battery)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
534
535
536
  	int result = 0;
  	acpi_status status = 0;
  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537

b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
538
539
  	if (!acpi_battery_present(battery))
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540

f1d4661ab   Alexey Starikovskiy   ACPI: Battery: si...
541
542
543
544
  	if (battery->update_time &&
  	    time_before(jiffies, battery->update_time +
  			msecs_to_jiffies(cache_time)))
  		return 0;
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
545
  	mutex_lock(&battery->lock);
f1d4661ab   Alexey Starikovskiy   ACPI: Battery: si...
546
  	status = acpi_evaluate_object(battery->device->handle, "_BST",
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
547
548
  				      NULL, &buffer);
  	mutex_unlock(&battery->lock);
5b31d8958   Len Brown   Revert "ACPI: Bat...
549

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  	if (ACPI_FAILURE(status)) {
a6fc67202   Thomas Renninger   ACPI: Enable ACPI...
551
  		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
d550d98d3   Patrick Mochel   ACPI: delete trac...
552
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  	}
aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
554

038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
555
556
  	result = extract_package(battery, buffer.pointer,
  				 state_offsets, ARRAY_SIZE(state_offsets));
f1d4661ab   Alexey Starikovskiy   ACPI: Battery: si...
557
  	battery->update_time = jiffies;
78490d821   Alexey Starikovskiy   ACPI: battery: sy...
558
  	kfree(buffer.pointer);
bc76f90b8   Hector Martin   ACPI battery: wor...
559

55003b210   Lan Tianyu   ACPI / Battery: C...
560
561
562
563
564
565
566
  	/* For buggy DSDTs that report negative 16-bit values for either
  	 * charging or discharging current and/or report 0 as 65536
  	 * due to bad math.
  	 */
  	if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA &&
  		battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN &&
  		(s16)(battery->rate_now) < 0) {
bc76f90b8   Hector Martin   ACPI battery: wor...
567
  		battery->rate_now = abs((s16)battery->rate_now);
dd1fca9e6   Dmitry Rozhkov   ACPI / battery: u...
568
569
  		pr_warn_once(FW_BUG "battery: (dis)charge rate invalid.
  ");
55003b210   Lan Tianyu   ACPI / Battery: C...
570
  	}
bc76f90b8   Hector Martin   ACPI battery: wor...
571

557d58687   Zhang Rui   ACPI battery: sup...
572
573
574
575
  	if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)
  	    && battery->capacity_now >= 0 && battery->capacity_now <= 100)
  		battery->capacity_now = (battery->capacity_now *
  				battery->full_charge_capacity) / 100;
4000e6261   Kamil Iskra   ACPI / battery: C...
576
577
578
579
580
  	if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
  	    battery->power_unit && battery->design_voltage) {
  		battery->capacity_now = battery->capacity_now *
  		    10000 / battery->design_voltage;
  	}
a20136a67   Laszlo Toth   ACPI: battery: do...
581
582
583
  	if (test_bit(ACPI_BATTERY_QUIRK_DEGRADED_FULL_CHARGE, &battery->flags) &&
  	    battery->capacity_now > battery->full_charge_capacity)
  		battery->capacity_now = battery->full_charge_capacity;
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
584
585
  	return result;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586

aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
587
  static int acpi_battery_set_alarm(struct acpi_battery *battery)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
589
  	acpi_status status = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590

c67fcd670   Alexey Starikovskiy   ACPI: Battery: Ad...
591
  	if (!acpi_battery_present(battery) ||
7b3bcc4a1   Alexey Starikovskiy   ACPI: Battery: Ad...
592
  	    !test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags))
d550d98d3   Patrick Mochel   ACPI: delete trac...
593
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594

038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
595
  	mutex_lock(&battery->lock);
0db982026   Jiang Liu   ACPI: introduce h...
596
597
  	status = acpi_execute_simple_method(battery->device->handle, "_BTP",
  					    battery->alarm);
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
598
  	mutex_unlock(&battery->lock);
aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
599

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
  	if (ACPI_FAILURE(status))
d550d98d3   Patrick Mochel   ACPI: delete trac...
601
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602

aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
603
604
  	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d
  ", battery->alarm));
d550d98d3   Patrick Mochel   ACPI: delete trac...
605
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
  }
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
607
  static int acpi_battery_init_alarm(struct acpi_battery *battery)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
  {
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
609
  	/* See if alarms are supported, and if so, set default */
952c63e95   Jiang Liu   ACPI: introduce h...
610
  	if (!acpi_has_method(battery->device->handle, "_BTP")) {
7b3bcc4a1   Alexey Starikovskiy   ACPI: Battery: Ad...
611
  		clear_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags);
f1d4661ab   Alexey Starikovskiy   ACPI: Battery: si...
612
  		return 0;
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
613
  	}
7b3bcc4a1   Alexey Starikovskiy   ACPI: Battery: Ad...
614
  	set_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags);
f1d4661ab   Alexey Starikovskiy   ACPI: Battery: si...
615
616
  	if (!battery->alarm)
  		battery->alarm = battery->design_capacity_warning;
aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
617
  	return acpi_battery_set_alarm(battery);
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
618
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619

508df92d1   Andrey Borzenkov   ACPI: battery: re...
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
  static ssize_t acpi_battery_alarm_show(struct device *dev,
  					struct device_attribute *attr,
  					char *buf)
  {
  	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
  	return sprintf(buf, "%d
  ", battery->alarm * 1000);
  }
  
  static ssize_t acpi_battery_alarm_store(struct device *dev,
  					struct device_attribute *attr,
  					const char *buf, size_t count)
  {
  	unsigned long x;
  	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
47a08c85f   Luis G.F   ACPI / battery: F...
635
636
  	if (sscanf(buf, "%lu
  ", &x) == 1)
508df92d1   Andrey Borzenkov   ACPI: battery: re...
637
638
639
640
641
  		battery->alarm = x/1000;
  	if (acpi_battery_present(battery))
  		acpi_battery_set_alarm(battery);
  	return count;
  }
82d2b6105   Bhumika Goyal   ACPI: make device...
642
  static const struct device_attribute alarm_attr = {
01e8ef11b   Parag Warudkar   x86: sysfs: kill ...
643
  	.attr = {.name = "alarm", .mode = 0644},
508df92d1   Andrey Borzenkov   ACPI: battery: re...
644
645
646
  	.show = acpi_battery_alarm_show,
  	.store = acpi_battery_alarm_store,
  };
fa93854f7   Ognjen Galic   battery: Add the ...
647
648
649
650
651
652
653
654
655
656
657
658
  /*
   * The Battery Hooking API
   *
   * This API is used inside other drivers that need to expose
   * platform-specific behaviour within the generic driver in a
   * generic way.
   *
   */
  
  static LIST_HEAD(acpi_battery_list);
  static LIST_HEAD(battery_hook_list);
  static DEFINE_MUTEX(hook_mutex);
514bcc5df   Colin Ian King   ACPI: battery: ma...
659
  static void __battery_hook_unregister(struct acpi_battery_hook *hook, int lock)
fa93854f7   Ognjen Galic   battery: Add the ...
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
  {
  	struct acpi_battery *battery;
  	/*
  	 * In order to remove a hook, we first need to
  	 * de-register all the batteries that are registered.
  	 */
  	if (lock)
  		mutex_lock(&hook_mutex);
  	list_for_each_entry(battery, &acpi_battery_list, list) {
  		hook->remove_battery(battery->bat);
  	}
  	list_del(&hook->list);
  	if (lock)
  		mutex_unlock(&hook_mutex);
  	pr_info("extension unregistered: %s
  ", hook->name);
  }
  
  void battery_hook_unregister(struct acpi_battery_hook *hook)
  {
  	__battery_hook_unregister(hook, 1);
  }
  EXPORT_SYMBOL_GPL(battery_hook_unregister);
  
  void battery_hook_register(struct acpi_battery_hook *hook)
  {
  	struct acpi_battery *battery;
  
  	mutex_lock(&hook_mutex);
  	INIT_LIST_HEAD(&hook->list);
  	list_add(&hook->list, &battery_hook_list);
  	/*
  	 * Now that the driver is registered, we need
  	 * to notify the hook that a battery is available
  	 * for each battery, so that the driver may add
  	 * its attributes.
  	 */
  	list_for_each_entry(battery, &acpi_battery_list, list) {
  		if (hook->add_battery(battery->bat)) {
  			/*
  			 * If a add-battery returns non-zero,
  			 * the registration of the extension has failed,
  			 * and we will not add it to the list of loaded
  			 * hooks.
  			 */
  			pr_err("extension failed to load: %s", hook->name);
  			__battery_hook_unregister(hook, 0);
673b42716   Jouke Witteveen   ACPI / battery: S...
707
  			goto end;
fa93854f7   Ognjen Galic   battery: Add the ...
708
709
710
711
  		}
  	}
  	pr_info("new extension: %s
  ", hook->name);
673b42716   Jouke Witteveen   ACPI / battery: S...
712
  end:
fa93854f7   Ognjen Galic   battery: Add the ...
713
714
715
716
717
718
719
720
  	mutex_unlock(&hook_mutex);
  }
  EXPORT_SYMBOL_GPL(battery_hook_register);
  
  /*
   * This function gets called right after the battery sysfs
   * attributes have been added, so that the drivers that
   * define custom sysfs attributes can add their own.
7a4ea10c0   Rafael J. Wysocki   Revert "ACPI: bat...
721
  */
fa93854f7   Ognjen Galic   battery: Add the ...
722
723
  static void battery_hook_add_battery(struct acpi_battery *battery)
  {
673b42716   Jouke Witteveen   ACPI / battery: S...
724
  	struct acpi_battery_hook *hook_node, *tmp;
fa93854f7   Ognjen Galic   battery: Add the ...
725
726
727
728
729
730
731
732
733
734
735
  
  	mutex_lock(&hook_mutex);
  	INIT_LIST_HEAD(&battery->list);
  	list_add(&battery->list, &acpi_battery_list);
  	/*
  	 * Since we added a new battery to the list, we need to
  	 * iterate over the hooks and call add_battery for each
  	 * hook that was registered. This usually happens
  	 * when a battery gets hotplugged or initialized
  	 * during the battery module initialization.
  	 */
673b42716   Jouke Witteveen   ACPI / battery: S...
736
  	list_for_each_entry_safe(hook_node, tmp, &battery_hook_list, list) {
fa93854f7   Ognjen Galic   battery: Add the ...
737
738
739
740
741
  		if (hook_node->add_battery(battery->bat)) {
  			/*
  			 * The notification of the extensions has failed, to
  			 * prevent further errors we will unload the extension.
  			 */
fa93854f7   Ognjen Galic   battery: Add the ...
742
743
  			pr_err("error in extension, unloading: %s",
  					hook_node->name);
673b42716   Jouke Witteveen   ACPI / battery: S...
744
  			__battery_hook_unregister(hook_node, 0);
fa93854f7   Ognjen Galic   battery: Add the ...
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
  		}
  	}
  	mutex_unlock(&hook_mutex);
  }
  
  static void battery_hook_remove_battery(struct acpi_battery *battery)
  {
  	struct acpi_battery_hook *hook;
  
  	mutex_lock(&hook_mutex);
  	/*
  	 * Before removing the hook, we need to remove all
  	 * custom attributes from the battery.
  	 */
  	list_for_each_entry(hook, &battery_hook_list, list) {
  		hook->remove_battery(battery->bat);
  	}
  	/* Then, just remove the battery from the list */
  	list_del(&battery->list);
  	mutex_unlock(&hook_mutex);
  }
  
  static void __exit battery_hook_exit(void)
  {
  	struct acpi_battery_hook *hook;
  	struct acpi_battery_hook *ptr;
  	/*
  	 * At this point, the acpi_bus_unregister_driver()
  	 * has called remove for all batteries. We just
  	 * need to remove the hooks.
  	 */
  	list_for_each_entry_safe(hook, ptr, &battery_hook_list, list) {
  		__battery_hook_unregister(hook, 1);
  	}
  	mutex_destroy(&hook_mutex);
  }
508df92d1   Andrey Borzenkov   ACPI: battery: re...
781
782
  static int sysfs_add_battery(struct acpi_battery *battery)
  {
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
783
  	struct power_supply_config psy_cfg = { .drv_data = battery, };
ff3154d1d   Hans de Goede   ACPI / battery: D...
784
785
786
787
788
  	bool full_cap_broken = false;
  
  	if (!ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity) &&
  	    !ACPI_BATTERY_CAPACITY_VALID(battery->design_capacity))
  		full_cap_broken = true;
508df92d1   Andrey Borzenkov   ACPI: battery: re...
789

ae6f61870   Lan Tianyu   ACPI / Battery: A...
790
  	if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) {
ff3154d1d   Hans de Goede   ACPI / battery: D...
791
792
793
794
795
796
797
798
799
800
  		if (full_cap_broken) {
  			battery->bat_desc.properties =
  			    charge_battery_full_cap_broken_props;
  			battery->bat_desc.num_properties =
  			    ARRAY_SIZE(charge_battery_full_cap_broken_props);
  		} else {
  			battery->bat_desc.properties = charge_battery_props;
  			battery->bat_desc.num_properties =
  			    ARRAY_SIZE(charge_battery_props);
  		}
508df92d1   Andrey Borzenkov   ACPI: battery: re...
801
  	} else {
ff3154d1d   Hans de Goede   ACPI / battery: D...
802
803
804
805
806
807
808
809
810
811
  		if (full_cap_broken) {
  			battery->bat_desc.properties =
  			    energy_battery_full_cap_broken_props;
  			battery->bat_desc.num_properties =
  			    ARRAY_SIZE(energy_battery_full_cap_broken_props);
  		} else {
  			battery->bat_desc.properties = energy_battery_props;
  			battery->bat_desc.num_properties =
  			    ARRAY_SIZE(energy_battery_props);
  		}
508df92d1   Andrey Borzenkov   ACPI: battery: re...
812
  	}
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
813
814
815
  	battery->bat_desc.name = acpi_device_bid(battery->device);
  	battery->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
  	battery->bat_desc.get_property = acpi_battery_get_property;
508df92d1   Andrey Borzenkov   ACPI: battery: re...
816

297d716f6   Krzysztof Kozlowski   power_supply: Cha...
817
818
  	battery->bat = power_supply_register_no_ws(&battery->device->dev,
  				&battery->bat_desc, &psy_cfg);
e0d1f09e3   Zhang Rui   ACPI / battery: w...
819

297d716f6   Krzysztof Kozlowski   power_supply: Cha...
820
821
822
823
  	if (IS_ERR(battery->bat)) {
  		int result = PTR_ERR(battery->bat);
  
  		battery->bat = NULL;
508df92d1   Andrey Borzenkov   ACPI: battery: re...
824
  		return result;
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
825
  	}
fa93854f7   Ognjen Galic   battery: Add the ...
826
  	battery_hook_add_battery(battery);
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
827
  	return device_create_file(&battery->bat->dev, &alarm_attr);
508df92d1   Andrey Borzenkov   ACPI: battery: re...
828
829
830
831
  }
  
  static void sysfs_remove_battery(struct acpi_battery *battery)
  {
69d94ec6d   Sergey Senozhatsky   Battery: sysfs_re...
832
  	mutex_lock(&battery->sysfs_lock);
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
833
  	if (!battery->bat) {
69d94ec6d   Sergey Senozhatsky   Battery: sysfs_re...
834
  		mutex_unlock(&battery->sysfs_lock);
508df92d1   Andrey Borzenkov   ACPI: battery: re...
835
  		return;
9c921c22a   Lan Tianyu   ACPI / Battery: R...
836
  	}
fa93854f7   Ognjen Galic   battery: Add the ...
837
  	battery_hook_remove_battery(battery);
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
838
839
840
  	device_remove_file(&battery->bat->dev, &alarm_attr);
  	power_supply_unregister(battery->bat);
  	battery->bat = NULL;
69d94ec6d   Sergey Senozhatsky   Battery: sysfs_re...
841
  	mutex_unlock(&battery->sysfs_lock);
bc76f90b8   Hector Martin   ACPI battery: wor...
842
  }
4000e6261   Kamil Iskra   ACPI / battery: C...
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
  static void find_battery(const struct dmi_header *dm, void *private)
  {
  	struct acpi_battery *battery = (struct acpi_battery *)private;
  	/* Note: the hardcoded offsets below have been extracted from
  	   the source code of dmidecode.  */
  	if (dm->type == DMI_ENTRY_PORTABLE_BATTERY && dm->length >= 8) {
  		const u8 *dmi_data = (const u8 *)(dm + 1);
  		int dmi_capacity = get_unaligned((const u16 *)(dmi_data + 6));
  		if (dm->length >= 18)
  			dmi_capacity *= dmi_data[17];
  		if (battery->design_capacity * battery->design_voltage / 1000
  		    != dmi_capacity &&
  		    battery->design_capacity * 10 == dmi_capacity)
  			set_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH,
  				&battery->flags);
  	}
  }
557d58687   Zhang Rui   ACPI battery: sup...
860
861
862
863
864
865
866
867
868
869
870
871
  /*
   * According to the ACPI spec, some kinds of primary batteries can
   * report percentage battery remaining capacity directly to OS.
   * In this case, it reports the Last Full Charged Capacity == 100
   * and BatteryPresentRate == 0xFFFFFFFF.
   *
   * Now we found some battery reports percentage remaining capacity
   * even if it's rechargeable.
   * https://bugzilla.kernel.org/show_bug.cgi?id=15979
   *
   * Handle this correctly so that they won't break userspace.
   */
7b78622d0   Lan Tianyu   ACPI / Battery: R...
872
  static void acpi_battery_quirks(struct acpi_battery *battery)
557d58687   Zhang Rui   ACPI battery: sup...
873
874
  {
  	if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
0f4c65478   Nicholas Mazzuca   ACPI / battery: M...
875
  		return;
557d58687   Zhang Rui   ACPI battery: sup...
876

0f4c65478   Nicholas Mazzuca   ACPI / battery: M...
877
878
879
  	if (battery->full_charge_capacity == 100 &&
  		battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN &&
  		battery->capacity_now >= 0 && battery->capacity_now <= 100) {
557d58687   Zhang Rui   ACPI battery: sup...
880
881
882
883
884
  		set_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags);
  		battery->full_charge_capacity = battery->design_capacity;
  		battery->capacity_now = (battery->capacity_now *
  				battery->full_charge_capacity) / 100;
  	}
4000e6261   Kamil Iskra   ACPI / battery: C...
885
886
  
  	if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags))
0f4c65478   Nicholas Mazzuca   ACPI / battery: M...
887
  		return;
4000e6261   Kamil Iskra   ACPI / battery: C...
888
889
890
891
  
  	if (battery->power_unit && dmi_name_in_vendors("LENOVO")) {
  		const char *s;
  		s = dmi_get_system_info(DMI_PRODUCT_VERSION);
ffd8a731d   Rasmus Villemoes   ACPI / battery: R...
892
  		if (s && !strncasecmp(s, "ThinkPad", 8)) {
4000e6261   Kamil Iskra   ACPI / battery: C...
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
  			dmi_walk(find_battery, battery);
  			if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH,
  				     &battery->flags) &&
  			    battery->design_voltage) {
  				battery->design_capacity =
  				    battery->design_capacity *
  				    10000 / battery->design_voltage;
  				battery->full_charge_capacity =
  				    battery->full_charge_capacity *
  				    10000 / battery->design_voltage;
  				battery->design_capacity_warning =
  				    battery->design_capacity_warning *
  				    10000 / battery->design_voltage;
  				battery->capacity_now = battery->capacity_now *
  				    10000 / battery->design_voltage;
  			}
  		}
  	}
a20136a67   Laszlo Toth   ACPI: battery: do...
911
912
913
914
915
916
917
918
919
  
  	if (test_bit(ACPI_BATTERY_QUIRK_DEGRADED_FULL_CHARGE, &battery->flags))
  		return;
  
  	if (acpi_battery_is_degraded(battery) &&
  	    battery->capacity_now > battery->full_charge_capacity) {
  		set_bit(ACPI_BATTERY_QUIRK_DEGRADED_FULL_CHARGE, &battery->flags);
  		battery->capacity_now = battery->full_charge_capacity;
  	}
557d58687   Zhang Rui   ACPI battery: sup...
920
  }
9e50bc14a   Lan Tianyu   ACPI / battery: A...
921
  static int acpi_battery_update(struct acpi_battery *battery, bool resume)
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
922
  {
82f2d3057   Lucas Rangit Magasweran   ACPI: battery: re...
923
  	int result = acpi_battery_get_status(battery);
508df92d1   Andrey Borzenkov   ACPI: battery: re...
924
  	if (result)
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
925
  		return result;
82f2d3057   Lucas Rangit Magasweran   ACPI: battery: re...
926

508df92d1   Andrey Borzenkov   ACPI: battery: re...
927
928
  	if (!acpi_battery_present(battery)) {
  		sysfs_remove_battery(battery);
97749cd9a   Alexey Starikovskiy   ACPI: Make sysfs ...
929
  		battery->update_time = 0;
508df92d1   Andrey Borzenkov   ACPI: battery: re...
930
  		return 0;
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
931
  	}
9e50bc14a   Lan Tianyu   ACPI / battery: A...
932
933
934
  
  	if (resume)
  		return 0;
82f2d3057   Lucas Rangit Magasweran   ACPI: battery: re...
935
  	if (!battery->update_time) {
97749cd9a   Alexey Starikovskiy   ACPI: Make sysfs ...
936
937
938
939
940
  		result = acpi_battery_get_info(battery);
  		if (result)
  			return result;
  		acpi_battery_init_alarm(battery);
  	}
12c78ca2a   Carlos Garnacho   ACPI / battery: A...
941
942
943
944
945
  
  	result = acpi_battery_get_state(battery);
  	if (result)
  		return result;
  	acpi_battery_quirks(battery);
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
946
  	if (!battery->bat) {
eb03cb02b   Stefan Hajnoczi   ACPI / Battery: p...
947
948
949
950
  		result = sysfs_add_battery(battery);
  		if (result)
  			return result;
  	}
e0d1f09e3   Zhang Rui   ACPI / battery: w...
951
952
953
954
955
956
957
  
  	/*
  	 * Wakeup the system if battery is critical low
  	 * or lower than the alarm level
  	 */
  	if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) ||
  	    (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
c6237b210   Maximilian Luz   ACPI: Fix whitesp...
958
  	     (battery->capacity_now <= battery->alarm)))
33e4f80ee   Rafael J. Wysocki   ACPI / PM: Ignore...
959
  		acpi_pm_wakeup_event(&battery->device->dev);
e0d1f09e3   Zhang Rui   ACPI / battery: w...
960

557d58687   Zhang Rui   ACPI battery: sup...
961
  	return result;
4bd35cdb1   Vladimir Lebedev   ACPI: battery: ch...
962
  }
da8aeb92d   Rafael J. Wysocki   ACPI / Battery: U...
963
964
  static void acpi_battery_refresh(struct acpi_battery *battery)
  {
c59714569   Andy Whitcroft   ACPI battery: onl...
965
  	int power_unit;
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
966
  	if (!battery->bat)
da8aeb92d   Rafael J. Wysocki   ACPI / Battery: U...
967
  		return;
c59714569   Andy Whitcroft   ACPI battery: onl...
968
  	power_unit = battery->power_unit;
da8aeb92d   Rafael J. Wysocki   ACPI / Battery: U...
969
  	acpi_battery_get_info(battery);
c59714569   Andy Whitcroft   ACPI battery: onl...
970
971
972
973
974
  
  	if (power_unit == battery->power_unit)
  		return;
  
  	/* The battery has changed its reporting units. */
da8aeb92d   Rafael J. Wysocki   ACPI / Battery: U...
975
976
977
  	sysfs_remove_battery(battery);
  	sysfs_add_battery(battery);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
978
  /* --------------------------------------------------------------------------
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979
980
                                   Driver Interface
     -------------------------------------------------------------------------- */
d94066910   Bjorn Helgaas   ACPI: battery: us...
981
  static void acpi_battery_notify(struct acpi_device *device, u32 event)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982
  {
d94066910   Bjorn Helgaas   ACPI: battery: us...
983
  	struct acpi_battery *battery = acpi_driver_data(device);
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
984
  	struct power_supply *old;
d94066910   Bjorn Helgaas   ACPI: battery: us...
985

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986
  	if (!battery)
d550d98d3   Patrick Mochel   ACPI: delete trac...
987
  		return;
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
988
  	old = battery->bat;
f43691c61   Alexander Mezin   ACPI / battery: a...
989
990
991
992
993
994
995
996
  	/*
  	* On Acer Aspire V5-573G notifications are sometimes triggered too
  	* early. For example, when AC is unplugged and notification is
  	* triggered, battery state is still reported as "Full", and changes to
  	* "Discharging" only after short delay, without any notification.
  	*/
  	if (battery_notification_delay_ms > 0)
  		msleep(battery_notification_delay_ms);
da8aeb92d   Rafael J. Wysocki   ACPI / Battery: U...
997
998
  	if (event == ACPI_BATTERY_NOTIFY_INFO)
  		acpi_battery_refresh(battery);
9e50bc14a   Lan Tianyu   ACPI / battery: A...
999
  	acpi_battery_update(battery, false);
f1d4661ab   Alexey Starikovskiy   ACPI: Battery: si...
1000
  	acpi_bus_generate_netlink_event(device->pnp.device_class,
0794469da   Kay Sievers   ACPI: struct devi...
1001
  					dev_name(&device->dev), event,
9ea7d5757   Vladimir Lebedev   ACPI: battery: Li...
1002
  					acpi_battery_present(battery));
411e0f77b   Alexander Mezin   ACPI / battery: c...
1003
  	acpi_notifier_call_chain(device, event, acpi_battery_present(battery));
2345baf4a   Justin P. Mattock   battery: fix typo...
1004
  	/* acpi_battery_update could remove power_supply object */
297d716f6   Krzysztof Kozlowski   power_supply: Cha...
1005
1006
  	if (old && battery->bat)
  		power_supply_changed(battery->bat);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
  }
25be58215   Kyle McMartin   ACPI battery: fri...
1008
1009
1010
1011
1012
  static int battery_notify(struct notifier_block *nb,
  			       unsigned long mode, void *_unused)
  {
  	struct acpi_battery *battery = container_of(nb, struct acpi_battery,
  						    pm_nb);
9e50bc14a   Lan Tianyu   ACPI / battery: A...
1013
  	int result;
25be58215   Kyle McMartin   ACPI battery: fri...
1014
  	switch (mode) {
d5a5911b3   Lan Tianyu   ACPI / Battery: A...
1015
  	case PM_POST_HIBERNATION:
25be58215   Kyle McMartin   ACPI battery: fri...
1016
  	case PM_POST_SUSPEND:
9e50bc14a   Lan Tianyu   ACPI / battery: A...
1017
1018
  		if (!acpi_battery_present(battery))
  			return 0;
2754435d4   Dmitry Rozhkov   ACPI / battery: g...
1019
1020
1021
  		if (battery->bat) {
  			acpi_battery_refresh(battery);
  		} else {
9e50bc14a   Lan Tianyu   ACPI / battery: A...
1022
1023
1024
1025
1026
1027
1028
  			result = acpi_battery_get_info(battery);
  			if (result)
  				return result;
  
  			result = sysfs_add_battery(battery);
  			if (result)
  				return result;
2754435d4   Dmitry Rozhkov   ACPI / battery: g...
1029
  		}
9e50bc14a   Lan Tianyu   ACPI / battery: A...
1030
1031
1032
  
  		acpi_battery_init_alarm(battery);
  		acpi_battery_get_state(battery);
25be58215   Kyle McMartin   ACPI battery: fri...
1033
1034
1035
1036
1037
  		break;
  	}
  
  	return 0;
  }
048d16da7   Mathias Krause   ACPI / battery: m...
1038
1039
  static int __init
  battery_bix_broken_package_quirk(const struct dmi_system_id *d)
3f5dc08f5   Alexander Mezin   ACPI / battery: u...
1040
1041
1042
1043
  {
  	battery_bix_broken_package = 1;
  	return 0;
  }
048d16da7   Mathias Krause   ACPI / battery: m...
1044
1045
  static int __init
  battery_notification_delay_quirk(const struct dmi_system_id *d)
f43691c61   Alexander Mezin   ACPI / battery: a...
1046
1047
1048
1049
  {
  	battery_notification_delay_ms = 1000;
  	return 0;
  }
1b799c5cf   Hans de Goede   ACPI / battery: I...
1050
1051
1052
1053
1054
1055
  static int __init
  battery_ac_is_broken_quirk(const struct dmi_system_id *d)
  {
  	battery_ac_is_broken = 1;
  	return 0;
  }
ec625a37c   Carlo Caione   ACPI / battery: A...
1056
1057
1058
1059
1060
1061
  static int __init
  battery_do_not_check_pmic_quirk(const struct dmi_system_id *d)
  {
  	battery_check_pmic = 0;
  	return 0;
  }
048d16da7   Mathias Krause   ACPI / battery: m...
1062
  static const struct dmi_system_id bat_dmi_table[] __initconst = {
a90b40385   Lan Tianyu   ACPI / Battery: A...
1063
  	{
91afa0766   Hans de Goede   ACPI / battery: R...
1064
  		/* NEC LZ750/LS */
3f5dc08f5   Alexander Mezin   ACPI / battery: u...
1065
  		.callback = battery_bix_broken_package_quirk,
a90b40385   Lan Tianyu   ACPI / Battery: A...
1066
1067
1068
1069
1070
  		.matches = {
  			DMI_MATCH(DMI_SYS_VENDOR, "NEC"),
  			DMI_MATCH(DMI_PRODUCT_NAME, "PC-LZ750LS"),
  		},
  	},
f43691c61   Alexander Mezin   ACPI / battery: a...
1071
  	{
91afa0766   Hans de Goede   ACPI / battery: R...
1072
  		/* Acer Aspire V5-573G */
f43691c61   Alexander Mezin   ACPI / battery: a...
1073
  		.callback = battery_notification_delay_quirk,
f43691c61   Alexander Mezin   ACPI / battery: a...
1074
1075
1076
1077
1078
  		.matches = {
  			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
  			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-573G"),
  		},
  	},
1b799c5cf   Hans de Goede   ACPI / battery: I...
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
  	{
  		/* Point of View mobii wintab p800w */
  		.callback = battery_ac_is_broken_quirk,
  		.matches = {
  			DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
  			DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
  			DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1013"),
  			/* Above matches are too generic, add bios-date match */
  			DMI_MATCH(DMI_BIOS_DATE, "08/22/2014"),
  		},
  	},
ec625a37c   Carlo Caione   ACPI / battery: A...
1090
  	{
8c3f6993c   Hans de Goede   ACPI / battery: C...
1091
  		/* ECS EF20EA, AXP288 PMIC but uses separate fuel-gauge */
ec625a37c   Carlo Caione   ACPI / battery: A...
1092
1093
1094
1095
1096
1097
  		.callback = battery_do_not_check_pmic_quirk,
  		.matches = {
  			DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"),
  		},
  	},
  	{
8c3f6993c   Hans de Goede   ACPI / battery: C...
1098
  		/* Lenovo Ideapad Miix 320, AXP288 PMIC, separate fuel-gauge */
ec625a37c   Carlo Caione   ACPI / battery: A...
1099
1100
  		.callback = battery_do_not_check_pmic_quirk,
  		.matches = {
8c3f6993c   Hans de Goede   ACPI / battery: C...
1101
1102
1103
  			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
  			DMI_MATCH(DMI_PRODUCT_NAME, "80XF"),
  			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"),
ec625a37c   Carlo Caione   ACPI / battery: A...
1104
1105
  		},
  	},
a90b40385   Lan Tianyu   ACPI / Battery: A...
1106
1107
  	{},
  };
75646e758   Lan Tianyu   ACPI / battery: R...
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
  /*
   * Some machines'(E,G Lenovo Z480) ECs are not stable
   * during boot up and this causes battery driver fails to be
   * probed due to failure of getting battery information
   * from EC sometimes. After several retries, the operation
   * may work. So add retry code here and 20ms sleep between
   * every retries.
   */
  static int acpi_battery_update_retry(struct acpi_battery *battery)
  {
  	int retry, ret;
  
  	for (retry = 5; retry; retry--) {
  		ret = acpi_battery_update(battery, false);
  		if (!ret)
  			break;
  
  		msleep(20);
  	}
  	return ret;
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
1129
  static int acpi_battery_add(struct acpi_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1130
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
1131
  	int result = 0;
4be44fcd3   Len Brown   [ACPI] Lindent al...
1132
  	struct acpi_battery *battery = NULL;
952c63e95   Jiang Liu   ACPI: introduce h...
1133

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134
  	if (!device)
d550d98d3   Patrick Mochel   ACPI: delete trac...
1135
  		return -EINVAL;
40e7fcb19   Lan Tianyu   ACPI: Add _DEP su...
1136
1137
1138
  
  	if (device->dep_unmet)
  		return -EPROBE_DEFER;
36bcbec7c   Burman Yan   ACPI: replace kma...
1139
  	battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
  	if (!battery)
d550d98d3   Patrick Mochel   ACPI: delete trac...
1141
  		return -ENOMEM;
145def84a   Patrick Mochel   ACPI: battery: ad...
1142
  	battery->device = device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
1144
  	strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
  	strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
db89b4f0d   Pavel Machek   ACPI: catch calls...
1145
  	device->driver_data = battery;
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
1146
  	mutex_init(&battery->lock);
69d94ec6d   Sergey Senozhatsky   Battery: sysfs_re...
1147
  	mutex_init(&battery->sysfs_lock);
952c63e95   Jiang Liu   ACPI: introduce h...
1148
  	if (acpi_has_method(battery->device->handle, "_BIX"))
c67fcd670   Alexey Starikovskiy   ACPI: Battery: Ad...
1149
  		set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
75646e758   Lan Tianyu   ACPI / battery: R...
1150
1151
  
  	result = acpi_battery_update_retry(battery);
eb03cb02b   Stefan Hajnoczi   ACPI / Battery: p...
1152
1153
  	if (result)
  		goto fail;
75646e758   Lan Tianyu   ACPI / battery: R...
1154

dd1fca9e6   Dmitry Rozhkov   ACPI / battery: u...
1155
1156
  	pr_info(PREFIX "%s Slot [%s] (battery %s)
  ",
e80bba4b5   Stefan Hajnoczi   ACPI / Battery: a...
1157
1158
  		ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
  		device->status.battery_present ? "present" : "absent");
25be58215   Kyle McMartin   ACPI battery: fri...
1159
1160
  	battery->pm_nb.notifier_call = battery_notify;
  	register_pm_notifier(&battery->pm_nb);
e0d1f09e3   Zhang Rui   ACPI / battery: w...
1161
  	device_init_wakeup(&device->dev, 1);
d550d98d3   Patrick Mochel   ACPI: delete trac...
1162
  	return result;
e80bba4b5   Stefan Hajnoczi   ACPI / Battery: a...
1163
1164
1165
1166
  
  fail:
  	sysfs_remove_battery(battery);
  	mutex_destroy(&battery->lock);
69d94ec6d   Sergey Senozhatsky   Battery: sysfs_re...
1167
  	mutex_destroy(&battery->sysfs_lock);
e80bba4b5   Stefan Hajnoczi   ACPI / Battery: a...
1168
1169
  	kfree(battery);
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
  }
51fac8388   Rafael J. Wysocki   ACPI: Remove usel...
1171
  static int acpi_battery_remove(struct acpi_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172
  {
4be44fcd3   Len Brown   [ACPI] Lindent al...
1173
  	struct acpi_battery *battery = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1174

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1175
  	if (!device || !acpi_driver_data(device))
d550d98d3   Patrick Mochel   ACPI: delete trac...
1176
  		return -EINVAL;
e0d1f09e3   Zhang Rui   ACPI / battery: w...
1177
  	device_init_wakeup(&device->dev, 0);
50dd09697   Jan Engelhardt   ACPI: Remove unne...
1178
  	battery = acpi_driver_data(device);
25be58215   Kyle McMartin   ACPI battery: fri...
1179
  	unregister_pm_notifier(&battery->pm_nb);
508df92d1   Andrey Borzenkov   ACPI: battery: re...
1180
  	sysfs_remove_battery(battery);
038fdea29   Alexey Starikovskiy   ACPI: Battery: do...
1181
  	mutex_destroy(&battery->lock);
69d94ec6d   Sergey Senozhatsky   Battery: sysfs_re...
1182
  	mutex_destroy(&battery->sysfs_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1183
  	kfree(battery);
d550d98d3   Patrick Mochel   ACPI: delete trac...
1184
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185
  }
906924048   Rafael J. Wysocki   ACPI / PM: Fix un...
1186
  #ifdef CONFIG_PM_SLEEP
34c4415ab   Jiri Kosina   ACPI: check batte...
1187
  /* this is needed to learn about changes made in suspended state */
a6f50dc8e   Rafael J. Wysocki   ACPI: Use struct ...
1188
  static int acpi_battery_resume(struct device *dev)
34c4415ab   Jiri Kosina   ACPI: check batte...
1189
1190
  {
  	struct acpi_battery *battery;
a6f50dc8e   Rafael J. Wysocki   ACPI: Use struct ...
1191
1192
  
  	if (!dev)
34c4415ab   Jiri Kosina   ACPI: check batte...
1193
  		return -EINVAL;
a6f50dc8e   Rafael J. Wysocki   ACPI: Use struct ...
1194
1195
1196
1197
  
  	battery = acpi_driver_data(to_acpi_device(dev));
  	if (!battery)
  		return -EINVAL;
f1d4661ab   Alexey Starikovskiy   ACPI: Battery: si...
1198
  	battery->update_time = 0;
9e50bc14a   Lan Tianyu   ACPI / battery: A...
1199
  	acpi_battery_update(battery, true);
b6ce4083e   Vladimir Lebedev   ACPI: Cache batte...
1200
  	return 0;
34c4415ab   Jiri Kosina   ACPI: check batte...
1201
  }
7f6895c60   Shuah Khan   ACPI / battery: f...
1202
1203
  #else
  #define acpi_battery_resume NULL
906924048   Rafael J. Wysocki   ACPI / PM: Fix un...
1204
  #endif
34c4415ab   Jiri Kosina   ACPI: check batte...
1205

a6f50dc8e   Rafael J. Wysocki   ACPI: Use struct ...
1206
  static SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume);
aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
1207
1208
1209
1210
  static struct acpi_driver acpi_battery_driver = {
  	.name = "battery",
  	.class = ACPI_BATTERY_CLASS,
  	.ids = battery_device_ids,
d94066910   Bjorn Helgaas   ACPI: battery: us...
1211
  	.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
1212
1213
  	.ops = {
  		.add = acpi_battery_add,
aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
1214
  		.remove = acpi_battery_remove,
d94066910   Bjorn Helgaas   ACPI: battery: us...
1215
  		.notify = acpi_battery_notify,
aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
1216
  		},
a6f50dc8e   Rafael J. Wysocki   ACPI: Use struct ...
1217
  	.drv.pm = &acpi_battery_pm,
aa650bbdc   Alexey Starikovskiy   ACPI: Battery: Mi...
1218
  };
b0cbc861a   Linus Torvalds   Revert "ACPI batt...
1219
  static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1220
  {
dccfae6d4   Hans de Goede   ACPI / battery: A...
1221
  	unsigned int i;
479faaf00   Luis Henriques   ACPI / battery: d...
1222
  	int result;
3f5dc08f5   Alexander Mezin   ACPI / battery: u...
1223
  	dmi_check_system(bat_dmi_table);
479faaf00   Luis Henriques   ACPI / battery: d...
1224

ec625a37c   Carlo Caione   ACPI / battery: A...
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
  	if (battery_check_pmic) {
  		for (i = 0; i < ARRAY_SIZE(acpi_battery_blacklist); i++)
  			if (acpi_dev_present(acpi_battery_blacklist[i], "1", -1)) {
  				pr_info(PREFIX ACPI_BATTERY_DEVICE_NAME
  					": found native %s PMIC, not loading
  ",
  					acpi_battery_blacklist[i]);
  				return;
  			}
  	}
479faaf00   Luis Henriques   ACPI / battery: d...
1235
  	result = acpi_bus_register_driver(&acpi_battery_driver);
bc39fbcf9   Hans de Goede   ACPI / battery: F...
1236
  	battery_driver_registered = (result == 0);
0f66af530   Arjan van de Ven   ACPI: battery: as...
1237
1238
1239
1240
  }
  
  static int __init acpi_battery_init(void)
  {
e234b074c   Luis Henriques   ACPI / battery: a...
1241
1242
  	if (acpi_disabled)
  		return -ENODEV;
eca21d916   Luis Henriques   ACPI / battery: e...
1243
  	async_cookie = async_schedule(acpi_battery_init_async, NULL);
d550d98d3   Patrick Mochel   ACPI: delete trac...
1244
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1245
  }
4be44fcd3   Len Brown   [ACPI] Lindent al...
1246
  static void __exit acpi_battery_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1247
  {
5dfa0c739   Chris Wilson   ACPI / battery: C...
1248
  	async_synchronize_cookie(async_cookie + 1);
fa93854f7   Ognjen Galic   battery: Add the ...
1249
  	if (battery_driver_registered) {
bc39fbcf9   Hans de Goede   ACPI / battery: F...
1250
  		acpi_bus_unregister_driver(&acpi_battery_driver);
fa93854f7   Ognjen Galic   battery: Add the ...
1251
1252
  		battery_hook_exit();
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1253
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1254
1255
  module_init(acpi_battery_init);
  module_exit(acpi_battery_exit);