diff options
Diffstat (limited to 'drivers/acpi/ac.c')
-rw-r--r-- | drivers/acpi/ac.c | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 00d2efd674df..4f4e741d34b2 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/types.h> | 30 | #include <linux/types.h> |
31 | #include <linux/dmi.h> | ||
32 | #include <linux/delay.h> | ||
31 | #ifdef CONFIG_ACPI_PROCFS_POWER | 33 | #ifdef CONFIG_ACPI_PROCFS_POWER |
32 | #include <linux/proc_fs.h> | 34 | #include <linux/proc_fs.h> |
33 | #include <linux/seq_file.h> | 35 | #include <linux/seq_file.h> |
@@ -74,6 +76,8 @@ static int acpi_ac_resume(struct device *dev); | |||
74 | #endif | 76 | #endif |
75 | static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume); | 77 | static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume); |
76 | 78 | ||
79 | static int ac_sleep_before_get_state_ms; | ||
80 | |||
77 | static struct acpi_driver acpi_ac_driver = { | 81 | static struct acpi_driver acpi_ac_driver = { |
78 | .name = "ac", | 82 | .name = "ac", |
79 | .class = ACPI_AC_CLASS, | 83 | .class = ACPI_AC_CLASS, |
@@ -252,6 +256,16 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event) | |||
252 | case ACPI_AC_NOTIFY_STATUS: | 256 | case ACPI_AC_NOTIFY_STATUS: |
253 | case ACPI_NOTIFY_BUS_CHECK: | 257 | case ACPI_NOTIFY_BUS_CHECK: |
254 | case ACPI_NOTIFY_DEVICE_CHECK: | 258 | case ACPI_NOTIFY_DEVICE_CHECK: |
259 | /* | ||
260 | * A buggy BIOS may notify AC first and then sleep for | ||
261 | * a specific time before doing actual operations in the | ||
262 | * EC event handler (_Qxx). This will cause the AC state | ||
263 | * reported by the ACPI event to be incorrect, so wait for a | ||
264 | * specific time for the EC event handler to make progress. | ||
265 | */ | ||
266 | if (ac_sleep_before_get_state_ms > 0) | ||
267 | msleep(ac_sleep_before_get_state_ms); | ||
268 | |||
255 | acpi_ac_get_state(ac); | 269 | acpi_ac_get_state(ac); |
256 | acpi_bus_generate_proc_event(device, event, (u32) ac->state); | 270 | acpi_bus_generate_proc_event(device, event, (u32) ac->state); |
257 | acpi_bus_generate_netlink_event(device->pnp.device_class, | 271 | acpi_bus_generate_netlink_event(device->pnp.device_class, |
@@ -264,6 +278,24 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event) | |||
264 | return; | 278 | return; |
265 | } | 279 | } |
266 | 280 | ||
281 | static int thinkpad_e530_quirk(const struct dmi_system_id *d) | ||
282 | { | ||
283 | ac_sleep_before_get_state_ms = 1000; | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static struct dmi_system_id ac_dmi_table[] = { | ||
288 | { | ||
289 | .callback = thinkpad_e530_quirk, | ||
290 | .ident = "thinkpad e530", | ||
291 | .matches = { | ||
292 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), | ||
293 | DMI_MATCH(DMI_PRODUCT_NAME, "32597CG"), | ||
294 | }, | ||
295 | }, | ||
296 | {}, | ||
297 | }; | ||
298 | |||
267 | static int acpi_ac_add(struct acpi_device *device) | 299 | static int acpi_ac_add(struct acpi_device *device) |
268 | { | 300 | { |
269 | int result = 0; | 301 | int result = 0; |
@@ -312,6 +344,7 @@ static int acpi_ac_add(struct acpi_device *device) | |||
312 | kfree(ac); | 344 | kfree(ac); |
313 | } | 345 | } |
314 | 346 | ||
347 | dmi_check_system(ac_dmi_table); | ||
315 | return result; | 348 | return result; |
316 | } | 349 | } |
317 | 350 | ||