Skip to content

Commit 9faf613

Browse files
Matthew Garrettrafaeljw
authored andcommitted
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 <[email protected]> Signed-off-by: Andreas Noever <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 3031cdd commit 9faf613

File tree

1 file changed

+43
-8
lines changed

1 file changed

+43
-8
lines changed

drivers/acpi/sbs.c

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <linux/jiffies.h>
3636
#include <linux/delay.h>
3737
#include <linux/power_supply.h>
38+
#include <linux/dmi.h>
3839

3940
#include "sbshc.h"
4041
#include "battery.h"
@@ -61,6 +62,8 @@ static unsigned int cache_time = 1000;
6162
module_param(cache_time, uint, 0644);
6263
MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
6364

65+
static bool sbs_manager_broken;
66+
6467
#define MAX_SBS_BAT 4
6568
#define ACPI_SBS_BLOCK_MAX 32
6669

@@ -494,16 +497,21 @@ static int acpi_battery_read(struct acpi_battery *battery)
494497
ACPI_SBS_MANAGER, 0x01, (u8 *)&state, 2);
495498
} else if (battery->id == 0)
496499
battery->present = 1;
500+
497501
if (result || !battery->present)
498502
return result;
499503

500504
if (saved_present != battery->present) {
501505
battery->update_time = 0;
502506
result = acpi_battery_get_info(battery);
503-
if (result)
507+
if (result) {
508+
battery->present = 0;
504509
return result;
510+
}
505511
}
506512
result = acpi_battery_get_state(battery);
513+
if (result)
514+
battery->present = 0;
507515
return result;
508516
}
509517

@@ -535,6 +543,7 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
535543
result = power_supply_register(&sbs->device->dev, &battery->bat);
536544
if (result)
537545
goto end;
546+
538547
result = device_create_file(battery->bat.dev, &alarm_attr);
539548
if (result)
540549
goto end;
@@ -613,12 +622,31 @@ static void acpi_sbs_callback(void *context)
613622
}
614623
}
615624

625+
static int disable_sbs_manager(const struct dmi_system_id *d)
626+
{
627+
sbs_manager_broken = true;
628+
return 0;
629+
}
630+
631+
static 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+
616642
static int acpi_sbs_add(struct acpi_device *device)
617643
{
618644
struct acpi_sbs *sbs;
619645
int result = 0;
620646
int id;
621647

648+
dmi_check_system(acpi_sbs_dmi_table);
649+
622650
sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
623651
if (!sbs) {
624652
result = -ENOMEM;
@@ -637,14 +665,21 @@ static int acpi_sbs_add(struct acpi_device *device)
637665
if (result && result != -ENODEV)
638666
goto end;
639667

640-
result = acpi_manager_get_info(sbs);
641-
if (!result) {
642-
sbs->manager_present = 1;
643-
for (id = 0; id < MAX_SBS_BAT; ++id)
644-
if ((sbs->batteries_supported & (1 << id)))
645-
acpi_battery_add(sbs, id);
646-
} else
668+
result = 0;
669+
670+
if (!sbs_manager_broken) {
671+
result = acpi_manager_get_info(sbs);
672+
if (!result) {
673+
sbs->manager_present = 0;
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)
647681
acpi_battery_add(sbs, 0);
682+
648683
acpi_smbus_register_callback(sbs->hc, acpi_sbs_callback, sbs);
649684
end:
650685
if (result)

0 commit comments

Comments
 (0)