aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorMatthew Garrett <matthew.garrett@nebula.com>2014-09-20 07:19:46 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-09-24 17:31:11 -0400
commit9faf6136ff4647452580b019f4b16f8c5082e589 (patch)
tree50fd394859468be42aece95c81845233e7cc0774 /drivers/acpi
parent3031cddea633ea5328162d3d712a582e4205dbed (diff)
ACPI / SBS: Disable smart battery manager on Apple
Touching the smart battery manager at all on Apple hardware appears to make it unhappy - unplugging the AC adapter triggers accesses that hang the controller for several minutes. Quirk it out via DMI in order to avoid this. Compensate by changing battery presence if we fail to communicate with the battery. Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com> Signed-off-by: Andreas Noever <andreas.noever@gmail.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/sbs.c51
1 files changed, 43 insertions, 8 deletions
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index b1df4eee8657..32aeceae10e3 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -35,6 +35,7 @@
35#include <linux/jiffies.h> 35#include <linux/jiffies.h>
36#include <linux/delay.h> 36#include <linux/delay.h>
37#include <linux/power_supply.h> 37#include <linux/power_supply.h>
38#include <linux/dmi.h>
38 39
39#include "sbshc.h" 40#include "sbshc.h"
40#include "battery.h" 41#include "battery.h"
@@ -61,6 +62,8 @@ static unsigned int cache_time = 1000;
61module_param(cache_time, uint, 0644); 62module_param(cache_time, uint, 0644);
62MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); 63MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
63 64
65static bool sbs_manager_broken;
66
64#define MAX_SBS_BAT 4 67#define MAX_SBS_BAT 4
65#define ACPI_SBS_BLOCK_MAX 32 68#define ACPI_SBS_BLOCK_MAX 32
66 69
@@ -494,16 +497,21 @@ static int acpi_battery_read(struct acpi_battery *battery)
494 ACPI_SBS_MANAGER, 0x01, (u8 *)&state, 2); 497 ACPI_SBS_MANAGER, 0x01, (u8 *)&state, 2);
495 } else if (battery->id == 0) 498 } else if (battery->id == 0)
496 battery->present = 1; 499 battery->present = 1;
500
497 if (result || !battery->present) 501 if (result || !battery->present)
498 return result; 502 return result;
499 503
500 if (saved_present != battery->present) { 504 if (saved_present != battery->present) {
501 battery->update_time = 0; 505 battery->update_time = 0;
502 result = acpi_battery_get_info(battery); 506 result = acpi_battery_get_info(battery);
503 if (result) 507 if (result) {
508 battery->present = 0;
504 return result; 509 return result;
510 }
505 } 511 }
506 result = acpi_battery_get_state(battery); 512 result = acpi_battery_get_state(battery);
513 if (result)
514 battery->present = 0;
507 return result; 515 return result;
508} 516}
509 517
@@ -535,6 +543,7 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
535 result = power_supply_register(&sbs->device->dev, &battery->bat); 543 result = power_supply_register(&sbs->device->dev, &battery->bat);
536 if (result) 544 if (result)
537 goto end; 545 goto end;
546
538 result = device_create_file(battery->bat.dev, &alarm_attr); 547 result = device_create_file(battery->bat.dev, &alarm_attr);
539 if (result) 548 if (result)
540 goto end; 549 goto end;
@@ -613,12 +622,31 @@ static void acpi_sbs_callback(void *context)
613 } 622 }
614} 623}
615 624
625static int disable_sbs_manager(const struct dmi_system_id *d)
626{
627 sbs_manager_broken = true;
628 return 0;
629}
630
631static struct dmi_system_id acpi_sbs_dmi_table[] = {
632 {
633 .callback = disable_sbs_manager,
634 .ident = "Apple",
635 .matches = {
636 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc.")
637 },
638 },
639 { },
640};
641
616static int acpi_sbs_add(struct acpi_device *device) 642static int acpi_sbs_add(struct acpi_device *device)
617{ 643{
618 struct acpi_sbs *sbs; 644 struct acpi_sbs *sbs;
619 int result = 0; 645 int result = 0;
620 int id; 646 int id;
621 647
648 dmi_check_system(acpi_sbs_dmi_table);
649
622 sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL); 650 sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
623 if (!sbs) { 651 if (!sbs) {
624 result = -ENOMEM; 652 result = -ENOMEM;
@@ -637,14 +665,21 @@ static int acpi_sbs_add(struct acpi_device *device)
637 if (result && result != -ENODEV) 665 if (result && result != -ENODEV)
638 goto end; 666 goto end;
639 667
640 result = acpi_manager_get_info(sbs); 668 result = 0;
641 if (!result) { 669
642 sbs->manager_present = 1; 670 if (!sbs_manager_broken) {
643 for (id = 0; id < MAX_SBS_BAT; ++id) 671 result = acpi_manager_get_info(sbs);
644 if ((sbs->batteries_supported & (1 << id))) 672 if (!result) {
645 acpi_battery_add(sbs, id); 673 sbs->manager_present = 0;
646 } else 674 for (id = 0; id < MAX_SBS_BAT; ++id)
675 if ((sbs->batteries_supported & (1 << id)))
676 acpi_battery_add(sbs, id);
677 }
678 }
679
680 if (!sbs->manager_present)
647 acpi_battery_add(sbs, 0); 681 acpi_battery_add(sbs, 0);
682
648 acpi_smbus_register_callback(sbs->hc, acpi_sbs_callback, sbs); 683 acpi_smbus_register_callback(sbs->hc, acpi_sbs_callback, sbs);
649 end: 684 end:
650 if (result) 685 if (result)