diff options
Diffstat (limited to 'drivers/acpi/battery.c')
-rw-r--r-- | drivers/acpi/battery.c | 86 |
1 files changed, 68 insertions, 18 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 58d2c91ba62b..75f39f2c166d 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #define ACPI_BATTERY_DEVICE_NAME "Battery" | 54 | #define ACPI_BATTERY_DEVICE_NAME "Battery" |
55 | #define ACPI_BATTERY_NOTIFY_STATUS 0x80 | 55 | #define ACPI_BATTERY_NOTIFY_STATUS 0x80 |
56 | #define ACPI_BATTERY_NOTIFY_INFO 0x81 | 56 | #define ACPI_BATTERY_NOTIFY_INFO 0x81 |
57 | #define ACPI_BATTERY_NOTIFY_THRESHOLD 0x82 | ||
57 | 58 | ||
58 | #define _COMPONENT ACPI_BATTERY_COMPONENT | 59 | #define _COMPONENT ACPI_BATTERY_COMPONENT |
59 | 60 | ||
@@ -88,10 +89,15 @@ static const struct acpi_device_id battery_device_ids[] = { | |||
88 | 89 | ||
89 | MODULE_DEVICE_TABLE(acpi, battery_device_ids); | 90 | MODULE_DEVICE_TABLE(acpi, battery_device_ids); |
90 | 91 | ||
91 | /* For buggy DSDTs that report negative 16-bit values for either charging | 92 | enum { |
92 | * or discharging current and/or report 0 as 65536 due to bad math. | 93 | ACPI_BATTERY_ALARM_PRESENT, |
93 | */ | 94 | ACPI_BATTERY_XINFO_PRESENT, |
94 | #define QUIRK_SIGNED16_CURRENT 0x0001 | 95 | /* For buggy DSDTs that report negative 16-bit values for either |
96 | * charging or discharging current and/or report 0 as 65536 | ||
97 | * due to bad math. | ||
98 | */ | ||
99 | ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, | ||
100 | }; | ||
95 | 101 | ||
96 | struct acpi_battery { | 102 | struct acpi_battery { |
97 | struct mutex lock; | 103 | struct mutex lock; |
@@ -109,6 +115,12 @@ struct acpi_battery { | |||
109 | int design_voltage; | 115 | int design_voltage; |
110 | int design_capacity_warning; | 116 | int design_capacity_warning; |
111 | int design_capacity_low; | 117 | int design_capacity_low; |
118 | int cycle_count; | ||
119 | int measurement_accuracy; | ||
120 | int max_sampling_time; | ||
121 | int min_sampling_time; | ||
122 | int max_averaging_interval; | ||
123 | int min_averaging_interval; | ||
112 | int capacity_granularity_1; | 124 | int capacity_granularity_1; |
113 | int capacity_granularity_2; | 125 | int capacity_granularity_2; |
114 | int alarm; | 126 | int alarm; |
@@ -118,8 +130,7 @@ struct acpi_battery { | |||
118 | char oem_info[32]; | 130 | char oem_info[32]; |
119 | int state; | 131 | int state; |
120 | int power_unit; | 132 | int power_unit; |
121 | u8 alarm_present; | 133 | unsigned long flags; |
122 | long quirks; | ||
123 | }; | 134 | }; |
124 | 135 | ||
125 | #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); | 136 | #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); |
@@ -198,6 +209,9 @@ static int acpi_battery_get_property(struct power_supply *psy, | |||
198 | case POWER_SUPPLY_PROP_TECHNOLOGY: | 209 | case POWER_SUPPLY_PROP_TECHNOLOGY: |
199 | val->intval = acpi_battery_technology(battery); | 210 | val->intval = acpi_battery_technology(battery); |
200 | break; | 211 | break; |
212 | case POWER_SUPPLY_PROP_CYCLE_COUNT: | ||
213 | val->intval = battery->cycle_count; | ||
214 | break; | ||
201 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: | 215 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: |
202 | val->intval = battery->design_voltage * 1000; | 216 | val->intval = battery->design_voltage * 1000; |
203 | break; | 217 | break; |
@@ -239,6 +253,7 @@ static enum power_supply_property charge_battery_props[] = { | |||
239 | POWER_SUPPLY_PROP_STATUS, | 253 | POWER_SUPPLY_PROP_STATUS, |
240 | POWER_SUPPLY_PROP_PRESENT, | 254 | POWER_SUPPLY_PROP_PRESENT, |
241 | POWER_SUPPLY_PROP_TECHNOLOGY, | 255 | POWER_SUPPLY_PROP_TECHNOLOGY, |
256 | POWER_SUPPLY_PROP_CYCLE_COUNT, | ||
242 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, | 257 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, |
243 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | 258 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
244 | POWER_SUPPLY_PROP_CURRENT_NOW, | 259 | POWER_SUPPLY_PROP_CURRENT_NOW, |
@@ -254,6 +269,7 @@ static enum power_supply_property energy_battery_props[] = { | |||
254 | POWER_SUPPLY_PROP_STATUS, | 269 | POWER_SUPPLY_PROP_STATUS, |
255 | POWER_SUPPLY_PROP_PRESENT, | 270 | POWER_SUPPLY_PROP_PRESENT, |
256 | POWER_SUPPLY_PROP_TECHNOLOGY, | 271 | POWER_SUPPLY_PROP_TECHNOLOGY, |
272 | POWER_SUPPLY_PROP_CYCLE_COUNT, | ||
257 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, | 273 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, |
258 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | 274 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
259 | POWER_SUPPLY_PROP_CURRENT_NOW, | 275 | POWER_SUPPLY_PROP_CURRENT_NOW, |
@@ -305,6 +321,28 @@ static struct acpi_offsets info_offsets[] = { | |||
305 | {offsetof(struct acpi_battery, oem_info), 1}, | 321 | {offsetof(struct acpi_battery, oem_info), 1}, |
306 | }; | 322 | }; |
307 | 323 | ||
324 | static struct acpi_offsets extended_info_offsets[] = { | ||
325 | {offsetof(struct acpi_battery, power_unit), 0}, | ||
326 | {offsetof(struct acpi_battery, design_capacity), 0}, | ||
327 | {offsetof(struct acpi_battery, full_charge_capacity), 0}, | ||
328 | {offsetof(struct acpi_battery, technology), 0}, | ||
329 | {offsetof(struct acpi_battery, design_voltage), 0}, | ||
330 | {offsetof(struct acpi_battery, design_capacity_warning), 0}, | ||
331 | {offsetof(struct acpi_battery, design_capacity_low), 0}, | ||
332 | {offsetof(struct acpi_battery, cycle_count), 0}, | ||
333 | {offsetof(struct acpi_battery, measurement_accuracy), 0}, | ||
334 | {offsetof(struct acpi_battery, max_sampling_time), 0}, | ||
335 | {offsetof(struct acpi_battery, min_sampling_time), 0}, | ||
336 | {offsetof(struct acpi_battery, max_averaging_interval), 0}, | ||
337 | {offsetof(struct acpi_battery, min_averaging_interval), 0}, | ||
338 | {offsetof(struct acpi_battery, capacity_granularity_1), 0}, | ||
339 | {offsetof(struct acpi_battery, capacity_granularity_2), 0}, | ||
340 | {offsetof(struct acpi_battery, model_number), 1}, | ||
341 | {offsetof(struct acpi_battery, serial_number), 1}, | ||
342 | {offsetof(struct acpi_battery, type), 1}, | ||
343 | {offsetof(struct acpi_battery, oem_info), 1}, | ||
344 | }; | ||
345 | |||
308 | static int extract_package(struct acpi_battery *battery, | 346 | static int extract_package(struct acpi_battery *battery, |
309 | union acpi_object *package, | 347 | union acpi_object *package, |
310 | struct acpi_offsets *offsets, int num) | 348 | struct acpi_offsets *offsets, int num) |
@@ -350,22 +388,29 @@ static int acpi_battery_get_info(struct acpi_battery *battery) | |||
350 | { | 388 | { |
351 | int result = -EFAULT; | 389 | int result = -EFAULT; |
352 | acpi_status status = 0; | 390 | acpi_status status = 0; |
391 | char *name = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags)? | ||
392 | "_BIX" : "_BIF"; | ||
393 | |||
353 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 394 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
354 | 395 | ||
355 | if (!acpi_battery_present(battery)) | 396 | if (!acpi_battery_present(battery)) |
356 | return 0; | 397 | return 0; |
357 | mutex_lock(&battery->lock); | 398 | mutex_lock(&battery->lock); |
358 | status = acpi_evaluate_object(battery->device->handle, "_BIF", | 399 | status = acpi_evaluate_object(battery->device->handle, name, |
359 | NULL, &buffer); | 400 | NULL, &buffer); |
360 | mutex_unlock(&battery->lock); | 401 | mutex_unlock(&battery->lock); |
361 | 402 | ||
362 | if (ACPI_FAILURE(status)) { | 403 | if (ACPI_FAILURE(status)) { |
363 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); | 404 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s", name)); |
364 | return -ENODEV; | 405 | return -ENODEV; |
365 | } | 406 | } |
366 | 407 | if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags)) | |
367 | result = extract_package(battery, buffer.pointer, | 408 | result = extract_package(battery, buffer.pointer, |
368 | info_offsets, ARRAY_SIZE(info_offsets)); | 409 | extended_info_offsets, |
410 | ARRAY_SIZE(extended_info_offsets)); | ||
411 | else | ||
412 | result = extract_package(battery, buffer.pointer, | ||
413 | info_offsets, ARRAY_SIZE(info_offsets)); | ||
369 | kfree(buffer.pointer); | 414 | kfree(buffer.pointer); |
370 | return result; | 415 | return result; |
371 | } | 416 | } |
@@ -399,7 +444,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery) | |||
399 | battery->update_time = jiffies; | 444 | battery->update_time = jiffies; |
400 | kfree(buffer.pointer); | 445 | kfree(buffer.pointer); |
401 | 446 | ||
402 | if ((battery->quirks & QUIRK_SIGNED16_CURRENT) && | 447 | if (test_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags) && |
403 | battery->rate_now != -1) | 448 | battery->rate_now != -1) |
404 | battery->rate_now = abs((s16)battery->rate_now); | 449 | battery->rate_now = abs((s16)battery->rate_now); |
405 | 450 | ||
@@ -412,7 +457,8 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery) | |||
412 | union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER }; | 457 | union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER }; |
413 | struct acpi_object_list arg_list = { 1, &arg0 }; | 458 | struct acpi_object_list arg_list = { 1, &arg0 }; |
414 | 459 | ||
415 | if (!acpi_battery_present(battery)|| !battery->alarm_present) | 460 | if (!acpi_battery_present(battery) || |
461 | !test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags)) | ||
416 | return -ENODEV; | 462 | return -ENODEV; |
417 | 463 | ||
418 | arg0.integer.value = battery->alarm; | 464 | arg0.integer.value = battery->alarm; |
@@ -437,10 +483,10 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery) | |||
437 | /* See if alarms are supported, and if so, set default */ | 483 | /* See if alarms are supported, and if so, set default */ |
438 | status = acpi_get_handle(battery->device->handle, "_BTP", &handle); | 484 | status = acpi_get_handle(battery->device->handle, "_BTP", &handle); |
439 | if (ACPI_FAILURE(status)) { | 485 | if (ACPI_FAILURE(status)) { |
440 | battery->alarm_present = 0; | 486 | clear_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags); |
441 | return 0; | 487 | return 0; |
442 | } | 488 | } |
443 | battery->alarm_present = 1; | 489 | set_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags); |
444 | if (!battery->alarm) | 490 | if (!battery->alarm) |
445 | battery->alarm = battery->design_capacity_warning; | 491 | battery->alarm = battery->design_capacity_warning; |
446 | return acpi_battery_set_alarm(battery); | 492 | return acpi_battery_set_alarm(battery); |
@@ -510,9 +556,8 @@ static void sysfs_remove_battery(struct acpi_battery *battery) | |||
510 | 556 | ||
511 | static void acpi_battery_quirks(struct acpi_battery *battery) | 557 | static void acpi_battery_quirks(struct acpi_battery *battery) |
512 | { | 558 | { |
513 | battery->quirks = 0; | ||
514 | if (dmi_name_in_vendors("Acer") && battery->power_unit) { | 559 | if (dmi_name_in_vendors("Acer") && battery->power_unit) { |
515 | battery->quirks |= QUIRK_SIGNED16_CURRENT; | 560 | set_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags); |
516 | } | 561 | } |
517 | } | 562 | } |
518 | 563 | ||
@@ -590,6 +635,7 @@ static int acpi_battery_print_info(struct seq_file *seq, int result) | |||
590 | seq_printf(seq, "design capacity low: %d %sh\n", | 635 | seq_printf(seq, "design capacity low: %d %sh\n", |
591 | battery->design_capacity_low, | 636 | battery->design_capacity_low, |
592 | acpi_battery_units(battery)); | 637 | acpi_battery_units(battery)); |
638 | seq_printf(seq, "cycle count: %i\n", battery->cycle_count); | ||
593 | seq_printf(seq, "capacity granularity 1: %d %sh\n", | 639 | seq_printf(seq, "capacity granularity 1: %d %sh\n", |
594 | battery->capacity_granularity_1, | 640 | battery->capacity_granularity_1, |
595 | acpi_battery_units(battery)); | 641 | acpi_battery_units(battery)); |
@@ -841,6 +887,7 @@ static int acpi_battery_add(struct acpi_device *device) | |||
841 | { | 887 | { |
842 | int result = 0; | 888 | int result = 0; |
843 | struct acpi_battery *battery = NULL; | 889 | struct acpi_battery *battery = NULL; |
890 | acpi_handle handle; | ||
844 | if (!device) | 891 | if (!device) |
845 | return -EINVAL; | 892 | return -EINVAL; |
846 | battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); | 893 | battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); |
@@ -851,6 +898,9 @@ static int acpi_battery_add(struct acpi_device *device) | |||
851 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); | 898 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); |
852 | device->driver_data = battery; | 899 | device->driver_data = battery; |
853 | mutex_init(&battery->lock); | 900 | mutex_init(&battery->lock); |
901 | if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle, | ||
902 | "_BIX", &handle))) | ||
903 | set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); | ||
854 | acpi_battery_update(battery); | 904 | acpi_battery_update(battery); |
855 | #ifdef CONFIG_ACPI_PROCFS_POWER | 905 | #ifdef CONFIG_ACPI_PROCFS_POWER |
856 | result = acpi_battery_add_fs(device); | 906 | result = acpi_battery_add_fs(device); |