aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/battery.c
diff options
context:
space:
mode:
authorHector Martin <hector@marcansoft.com>2009-08-06 18:57:48 -0400
committerLen Brown <len.brown@intel.com>2009-08-29 21:39:54 -0400
commitbc76f90b8a5cf4aceedf210d08d5e8292f820cec (patch)
tree70f5a96bd5b901a4e275dc57ae3ca1d37663338b /drivers/acpi/battery.c
parent326ba5010a5429a5a528b268b36a5900d4ab0eba (diff)
ACPI battery: work around negative s16 battery current on Acer
Acer Aspire 8930G laptops (and possibly others) report the battery current as a 16-bit signed negative when it is charging. It also reports it as 0x10000 when the current is 0. This patch adds a quirk for this which takes the absolute value of the reported current cast to an s16. This is a DSDT bug present in the latest BIOS revision (the EC register is 16 bits signed and the DSDT attempts to take the 16-bit two's complement of this, which works for discharge but not charge. It also breaks zero values because a 32-bit register is used and the high bits aren't thrown away). I've enabled this for all Acer systems which report in mA units. This should be safe since it won't break compliant systems unless they report a current above 32A, which is insane. The patch also detects the valid 32-bit value -1, which indicates unknown status, and does not attempt the fix in that case (note that this does not conflict with 16-bit -1, which is 65535 as read normally and gets translated to 1mA). Signed-off-by: Hector Martin <hector@marcansoft.com> Acked-by: Alexey Starikovskiy <astarikovskiy@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/battery.c')
-rw-r--r--drivers/acpi/battery.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 58b4517ce712..d7a786d5c4a5 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -31,6 +31,7 @@
31#include <linux/types.h> 31#include <linux/types.h>
32#include <linux/jiffies.h> 32#include <linux/jiffies.h>
33#include <linux/async.h> 33#include <linux/async.h>
34#include <linux/dmi.h>
34 35
35#ifdef CONFIG_ACPI_PROCFS_POWER 36#ifdef CONFIG_ACPI_PROCFS_POWER
36#include <linux/proc_fs.h> 37#include <linux/proc_fs.h>
@@ -85,6 +86,10 @@ static const struct acpi_device_id battery_device_ids[] = {
85 86
86MODULE_DEVICE_TABLE(acpi, battery_device_ids); 87MODULE_DEVICE_TABLE(acpi, battery_device_ids);
87 88
89/* For buggy DSDTs that report negative 16-bit values for either charging
90 * or discharging current and/or report 0 as 65536 due to bad math.
91 */
92#define QUIRK_SIGNED16_CURRENT 0x0001
88 93
89struct acpi_battery { 94struct acpi_battery {
90 struct mutex lock; 95 struct mutex lock;
@@ -112,6 +117,7 @@ struct acpi_battery {
112 int state; 117 int state;
113 int power_unit; 118 int power_unit;
114 u8 alarm_present; 119 u8 alarm_present;
120 long quirks;
115}; 121};
116 122
117#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); 123#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
@@ -390,6 +396,11 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
390 state_offsets, ARRAY_SIZE(state_offsets)); 396 state_offsets, ARRAY_SIZE(state_offsets));
391 battery->update_time = jiffies; 397 battery->update_time = jiffies;
392 kfree(buffer.pointer); 398 kfree(buffer.pointer);
399
400 if ((battery->quirks & QUIRK_SIGNED16_CURRENT) &&
401 battery->rate_now != -1)
402 battery->rate_now = abs((s16)battery->rate_now);
403
393 return result; 404 return result;
394} 405}
395 406
@@ -495,6 +506,14 @@ static void sysfs_remove_battery(struct acpi_battery *battery)
495} 506}
496#endif 507#endif
497 508
509static void acpi_battery_quirks(struct acpi_battery *battery)
510{
511 battery->quirks = 0;
512 if (dmi_name_in_vendors("Acer") && battery->power_unit) {
513 battery->quirks |= QUIRK_SIGNED16_CURRENT;
514 }
515}
516
498static int acpi_battery_update(struct acpi_battery *battery) 517static int acpi_battery_update(struct acpi_battery *battery)
499{ 518{
500 int result, old_present = acpi_battery_present(battery); 519 int result, old_present = acpi_battery_present(battery);
@@ -513,6 +532,7 @@ static int acpi_battery_update(struct acpi_battery *battery)
513 result = acpi_battery_get_info(battery); 532 result = acpi_battery_get_info(battery);
514 if (result) 533 if (result)
515 return result; 534 return result;
535 acpi_battery_quirks(battery);
516 acpi_battery_init_alarm(battery); 536 acpi_battery_init_alarm(battery);
517 } 537 }
518#ifdef CONFIG_ACPI_SYSFS_POWER 538#ifdef CONFIG_ACPI_SYSFS_POWER