Commit 939558f2 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branch 'acpi-apple'

* acpi-apple:
  ACPI / SBS: Fix check in acpi_ac_get_present()
  ACPI: Support _OSI("Darwin") correctly
  ACPI / SBS: Disable smart battery manager on Apple
  ACPI / SBS: Don't assume the existence of an SBS charger
parents 65e8627a 5159e39b
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -152,6 +152,16 @@ static u32 acpi_osi_handler(acpi_string interface, u32 supported)
			osi_linux.dmi ? " via DMI" : "");
	}

	if (!strcmp("Darwin", interface)) {
		/*
		 * Apple firmware will behave poorly if it receives positive
		 * answers to "Darwin" and any other OS. Respond positively
		 * to Darwin and then disable all other vendor strings.
		 */
		acpi_update_interfaces(ACPI_DISABLE_ALL_VENDOR_STRINGS);
		supported = ACPI_UINT32_MAX;
	}

	return supported;
}

+14 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include <linux/pci-aspm.h>
#include <linux/acpi.h>
#include <linux/slab.h>
#include <linux/dmi.h>
#include <acpi/apei.h>	/* for acpi_hest_init() */

#include "internal.h"
@@ -429,6 +430,19 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,
	struct acpi_device *device = root->device;
	acpi_handle handle = device->handle;

	/*
	 * Apple always return failure on _OSC calls when _OSI("Darwin") has
	 * been called successfully. We know the feature set supported by the
	 * platform, so avoid calling _OSC at all
	 */

	if (dmi_match(DMI_SYS_VENDOR, "Apple Inc.")) {
		root->osc_control_set = ~OSC_PCI_EXPRESS_PME_CONTROL;
		decode_osc_control(root, "OS assumes control of",
				   root->osc_control_set);
		return;
	}

	/*
	 * All supported architectures that use ACPI have support for
	 * PCI domains, so we indicate this in _OSC support capabilities.
+65 −15
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include <linux/jiffies.h>
#include <linux/delay.h>
#include <linux/power_supply.h>
#include <linux/dmi.h>

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

static bool sbs_manager_broken;

#define MAX_SBS_BAT			4
#define ACPI_SBS_BLOCK_MAX		32

@@ -109,6 +112,7 @@ struct acpi_sbs {
	u8 batteries_supported:4;
	u8 manager_present:1;
	u8 charger_present:1;
	u8 charger_exists:1;
};

#define to_acpi_sbs(x) container_of(x, struct acpi_sbs, charger)
@@ -429,9 +433,19 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs)

	result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_CHARGER,
				 0x13, (u8 *) & status);
	if (!result)
		sbs->charger_present = (status >> 15) & 0x1;

	if (result)
		return result;

	/*
	 * The spec requires that bit 4 always be 1. If it's not set, assume
	 * that the implementation doesn't support an SBS charger
	 */
	if (!((status >> 4) & 0x1))
		return -ENODEV;

	sbs->charger_present = (status >> 15) & 0x1;
	return 0;
}

static ssize_t acpi_battery_alarm_show(struct device *dev,
@@ -483,16 +497,21 @@ static int acpi_battery_read(struct acpi_battery *battery)
				  ACPI_SBS_MANAGER, 0x01, (u8 *)&state, 2);
	} else if (battery->id == 0)
		battery->present = 1;

	if (result || !battery->present)
		return result;

	if (saved_present != battery->present) {
		battery->update_time = 0;
		result = acpi_battery_get_info(battery);
		if (result)
		if (result) {
			battery->present = 0;
			return result;
		}
	}
	result = acpi_battery_get_state(battery);
	if (result)
		battery->present = 0;
	return result;
}

@@ -524,6 +543,7 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
	result = power_supply_register(&sbs->device->dev, &battery->bat);
	if (result)
		goto end;

	result = device_create_file(battery->bat.dev, &alarm_attr);
	if (result)
		goto end;
@@ -554,6 +574,7 @@ static int acpi_charger_add(struct acpi_sbs *sbs)
	if (result)
		goto end;

	sbs->charger_exists = 1;
	sbs->charger.name = "sbs-charger";
	sbs->charger.type = POWER_SUPPLY_TYPE_MAINS;
	sbs->charger.properties = sbs_ac_props;
@@ -580,9 +601,12 @@ static void acpi_sbs_callback(void *context)
	struct acpi_battery *bat;
	u8 saved_charger_state = sbs->charger_present;
	u8 saved_battery_state;

	if (sbs->charger_exists) {
		acpi_ac_get_present(sbs);
		if (sbs->charger_present != saved_charger_state)
			kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE);
	}

	if (sbs->manager_present) {
		for (id = 0; id < MAX_SBS_BAT; ++id) {
@@ -598,12 +622,31 @@ static void acpi_sbs_callback(void *context)
	}
}

static int disable_sbs_manager(const struct dmi_system_id *d)
{
	sbs_manager_broken = true;
	return 0;
}

static struct dmi_system_id acpi_sbs_dmi_table[] = {
	{
		.callback = disable_sbs_manager,
		.ident = "Apple",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc.")
		},
	},
	{ },
};

static int acpi_sbs_add(struct acpi_device *device)
{
	struct acpi_sbs *sbs;
	int result = 0;
	int id;

	dmi_check_system(acpi_sbs_dmi_table);

	sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
	if (!sbs) {
		result = -ENOMEM;
@@ -619,17 +662,24 @@ static int acpi_sbs_add(struct acpi_device *device)
	device->driver_data = sbs;

	result = acpi_charger_add(sbs);
	if (result)
	if (result && result != -ENODEV)
		goto end;

	result = 0;

	if (!sbs_manager_broken) {
		result = acpi_manager_get_info(sbs);
		if (!result) {
		sbs->manager_present = 1;
			sbs->manager_present = 0;
			for (id = 0; id < MAX_SBS_BAT; ++id)
				if ((sbs->batteries_supported & (1 << id)))
					acpi_battery_add(sbs, id);
	} else
		}
	}

	if (!sbs->manager_present)
		acpi_battery_add(sbs, 0);

	acpi_smbus_register_callback(sbs->hc, acpi_sbs_callback, sbs);
      end:
	if (result)