diff options
Diffstat (limited to 'drivers/acpi/battery.c')
-rw-r--r-- | drivers/acpi/battery.c | 80 |
1 files changed, 76 insertions, 4 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index e48fc98e71c4..130f513e08c9 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c | |||
@@ -32,8 +32,10 @@ | |||
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 | #include <linux/dmi.h> |
35 | #include <linux/delay.h> | ||
35 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
36 | #include <linux/suspend.h> | 37 | #include <linux/suspend.h> |
38 | #include <linux/delay.h> | ||
37 | #include <asm/unaligned.h> | 39 | #include <asm/unaligned.h> |
38 | 40 | ||
39 | #ifdef CONFIG_ACPI_PROCFS_POWER | 41 | #ifdef CONFIG_ACPI_PROCFS_POWER |
@@ -70,6 +72,7 @@ MODULE_DESCRIPTION("ACPI Battery Driver"); | |||
70 | MODULE_LICENSE("GPL"); | 72 | MODULE_LICENSE("GPL"); |
71 | 73 | ||
72 | static int battery_bix_broken_package; | 74 | static int battery_bix_broken_package; |
75 | static int battery_notification_delay_ms; | ||
73 | static unsigned int cache_time = 1000; | 76 | static unsigned int cache_time = 1000; |
74 | module_param(cache_time, uint, 0644); | 77 | module_param(cache_time, uint, 0644); |
75 | MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); | 78 | MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); |
@@ -532,6 +535,20 @@ static int acpi_battery_get_state(struct acpi_battery *battery) | |||
532 | " invalid.\n"); | 535 | " invalid.\n"); |
533 | } | 536 | } |
534 | 537 | ||
538 | /* | ||
539 | * When fully charged, some batteries wrongly report | ||
540 | * capacity_now = design_capacity instead of = full_charge_capacity | ||
541 | */ | ||
542 | if (battery->capacity_now > battery->full_charge_capacity | ||
543 | && battery->full_charge_capacity != ACPI_BATTERY_VALUE_UNKNOWN) { | ||
544 | battery->capacity_now = battery->full_charge_capacity; | ||
545 | if (battery->capacity_now != battery->design_capacity) | ||
546 | printk_once(KERN_WARNING FW_BUG | ||
547 | "battery: reported current charge level (%d) " | ||
548 | "is higher than reported maximum charge level (%d).\n", | ||
549 | battery->capacity_now, battery->full_charge_capacity); | ||
550 | } | ||
551 | |||
535 | if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags) | 552 | if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags) |
536 | && battery->capacity_now >= 0 && battery->capacity_now <= 100) | 553 | && battery->capacity_now >= 0 && battery->capacity_now <= 100) |
537 | battery->capacity_now = (battery->capacity_now * | 554 | battery->capacity_now = (battery->capacity_now * |
@@ -930,7 +947,10 @@ static ssize_t acpi_battery_write_alarm(struct file *file, | |||
930 | goto end; | 947 | goto end; |
931 | } | 948 | } |
932 | alarm_string[count] = '\0'; | 949 | alarm_string[count] = '\0'; |
933 | battery->alarm = simple_strtol(alarm_string, NULL, 0); | 950 | if (kstrtoint(alarm_string, 0, &battery->alarm)) { |
951 | result = -EINVAL; | ||
952 | goto end; | ||
953 | } | ||
934 | result = acpi_battery_set_alarm(battery); | 954 | result = acpi_battery_set_alarm(battery); |
935 | end: | 955 | end: |
936 | if (!result) | 956 | if (!result) |
@@ -1062,6 +1082,14 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) | |||
1062 | if (!battery) | 1082 | if (!battery) |
1063 | return; | 1083 | return; |
1064 | old = battery->bat.dev; | 1084 | old = battery->bat.dev; |
1085 | /* | ||
1086 | * On Acer Aspire V5-573G notifications are sometimes triggered too | ||
1087 | * early. For example, when AC is unplugged and notification is | ||
1088 | * triggered, battery state is still reported as "Full", and changes to | ||
1089 | * "Discharging" only after short delay, without any notification. | ||
1090 | */ | ||
1091 | if (battery_notification_delay_ms > 0) | ||
1092 | msleep(battery_notification_delay_ms); | ||
1065 | if (event == ACPI_BATTERY_NOTIFY_INFO) | 1093 | if (event == ACPI_BATTERY_NOTIFY_INFO) |
1066 | acpi_battery_refresh(battery); | 1094 | acpi_battery_refresh(battery); |
1067 | acpi_battery_update(battery, false); | 1095 | acpi_battery_update(battery, false); |
@@ -1106,17 +1134,60 @@ static int battery_notify(struct notifier_block *nb, | |||
1106 | return 0; | 1134 | return 0; |
1107 | } | 1135 | } |
1108 | 1136 | ||
1137 | static int battery_bix_broken_package_quirk(const struct dmi_system_id *d) | ||
1138 | { | ||
1139 | battery_bix_broken_package = 1; | ||
1140 | return 0; | ||
1141 | } | ||
1142 | |||
1143 | static int battery_notification_delay_quirk(const struct dmi_system_id *d) | ||
1144 | { | ||
1145 | battery_notification_delay_ms = 1000; | ||
1146 | return 0; | ||
1147 | } | ||
1148 | |||
1109 | static struct dmi_system_id bat_dmi_table[] = { | 1149 | static struct dmi_system_id bat_dmi_table[] = { |
1110 | { | 1150 | { |
1151 | .callback = battery_bix_broken_package_quirk, | ||
1111 | .ident = "NEC LZ750/LS", | 1152 | .ident = "NEC LZ750/LS", |
1112 | .matches = { | 1153 | .matches = { |
1113 | DMI_MATCH(DMI_SYS_VENDOR, "NEC"), | 1154 | DMI_MATCH(DMI_SYS_VENDOR, "NEC"), |
1114 | DMI_MATCH(DMI_PRODUCT_NAME, "PC-LZ750LS"), | 1155 | DMI_MATCH(DMI_PRODUCT_NAME, "PC-LZ750LS"), |
1115 | }, | 1156 | }, |
1116 | }, | 1157 | }, |
1158 | { | ||
1159 | .callback = battery_notification_delay_quirk, | ||
1160 | .ident = "Acer Aspire V5-573G", | ||
1161 | .matches = { | ||
1162 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | ||
1163 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-573G"), | ||
1164 | }, | ||
1165 | }, | ||
1117 | {}, | 1166 | {}, |
1118 | }; | 1167 | }; |
1119 | 1168 | ||
1169 | /* | ||
1170 | * Some machines'(E,G Lenovo Z480) ECs are not stable | ||
1171 | * during boot up and this causes battery driver fails to be | ||
1172 | * probed due to failure of getting battery information | ||
1173 | * from EC sometimes. After several retries, the operation | ||
1174 | * may work. So add retry code here and 20ms sleep between | ||
1175 | * every retries. | ||
1176 | */ | ||
1177 | static int acpi_battery_update_retry(struct acpi_battery *battery) | ||
1178 | { | ||
1179 | int retry, ret; | ||
1180 | |||
1181 | for (retry = 5; retry; retry--) { | ||
1182 | ret = acpi_battery_update(battery, false); | ||
1183 | if (!ret) | ||
1184 | break; | ||
1185 | |||
1186 | msleep(20); | ||
1187 | } | ||
1188 | return ret; | ||
1189 | } | ||
1190 | |||
1120 | static int acpi_battery_add(struct acpi_device *device) | 1191 | static int acpi_battery_add(struct acpi_device *device) |
1121 | { | 1192 | { |
1122 | int result = 0; | 1193 | int result = 0; |
@@ -1135,9 +1206,11 @@ static int acpi_battery_add(struct acpi_device *device) | |||
1135 | mutex_init(&battery->sysfs_lock); | 1206 | mutex_init(&battery->sysfs_lock); |
1136 | if (acpi_has_method(battery->device->handle, "_BIX")) | 1207 | if (acpi_has_method(battery->device->handle, "_BIX")) |
1137 | set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); | 1208 | set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); |
1138 | result = acpi_battery_update(battery, false); | 1209 | |
1210 | result = acpi_battery_update_retry(battery); | ||
1139 | if (result) | 1211 | if (result) |
1140 | goto fail; | 1212 | goto fail; |
1213 | |||
1141 | #ifdef CONFIG_ACPI_PROCFS_POWER | 1214 | #ifdef CONFIG_ACPI_PROCFS_POWER |
1142 | result = acpi_battery_add_fs(device); | 1215 | result = acpi_battery_add_fs(device); |
1143 | #endif | 1216 | #endif |
@@ -1227,8 +1300,7 @@ static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie) | |||
1227 | if (acpi_disabled) | 1300 | if (acpi_disabled) |
1228 | return; | 1301 | return; |
1229 | 1302 | ||
1230 | if (dmi_check_system(bat_dmi_table)) | 1303 | dmi_check_system(bat_dmi_table); |
1231 | battery_bix_broken_package = 1; | ||
1232 | 1304 | ||
1233 | #ifdef CONFIG_ACPI_PROCFS_POWER | 1305 | #ifdef CONFIG_ACPI_PROCFS_POWER |
1234 | acpi_battery_dir = acpi_lock_battery_dir(); | 1306 | acpi_battery_dir = acpi_lock_battery_dir(); |