diff options
| -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 | ||
