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); |
