Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 18020a0d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
  i2c-scmi: Provide module aliases for automatic loading
  i2c-scmi: Support IBM SMBus CMI devices
  acpi: Support IBM SMBus CMI devices
parents c27b9a2e 0f5ed04c
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include <linux/acpi.h>
#include <linux/signal.h>
#include <linux/kthread.h>
#include <linux/dmi.h>

#include <acpi/acpi_drivers.h>

@@ -1032,6 +1033,41 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id)
	list_add_tail(&id->list, &device->pnp.ids);
}

/*
 * Old IBM workstations have a DSDT bug wherein the SMBus object
 * lacks the SMBUS01 HID and the methods do not have the necessary "_"
 * prefix.  Work around this.
 */
static int acpi_ibm_smbus_match(struct acpi_device *device)
{
	acpi_handle h_dummy;
	struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
	int result;

	if (!dmi_name_in_vendors("IBM"))
		return -ENODEV;

	/* Look for SMBS object */
	result = acpi_get_name(device->handle, ACPI_SINGLE_NAME, &path);
	if (result)
		return result;

	if (strcmp("SMBS", path.pointer)) {
		result = -ENODEV;
		goto out;
	}

	/* Does it have the necessary (but misnamed) methods? */
	result = -ENODEV;
	if (ACPI_SUCCESS(acpi_get_handle(device->handle, "SBI", &h_dummy)) &&
	    ACPI_SUCCESS(acpi_get_handle(device->handle, "SBR", &h_dummy)) &&
	    ACPI_SUCCESS(acpi_get_handle(device->handle, "SBW", &h_dummy)))
		result = 0;
out:
	kfree(path.pointer);
	return result;
}

static void acpi_device_set_id(struct acpi_device *device)
{
	acpi_status status;
@@ -1082,6 +1118,8 @@ static void acpi_device_set_id(struct acpi_device *device)
			acpi_add_id(device, ACPI_BAY_HID);
		else if (ACPI_SUCCESS(acpi_dock_match(device)))
			acpi_add_id(device, ACPI_DOCK_HID);
		else if (!acpi_ibm_smbus_match(device))
			acpi_add_id(device, ACPI_SMBUS_IBM_HID);

		break;
	case ACPI_BUS_TYPE_POWER:
+24 −8
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ struct acpi_smbus_cmi {
	u8 cap_info:1;
	u8 cap_read:1;
	u8 cap_write:1;
	struct smbus_methods_t *methods;
};

static const struct smbus_methods_t smbus_methods = {
@@ -41,10 +42,19 @@ static const struct smbus_methods_t smbus_methods = {
	.mt_sbw  = "_SBW",
};

/* Some IBM BIOSes omit the leading underscore */
static const struct smbus_methods_t ibm_smbus_methods = {
	.mt_info = "SBI_",
	.mt_sbr  = "SBR_",
	.mt_sbw  = "SBW_",
};

static const struct acpi_device_id acpi_smbus_cmi_ids[] = {
	{"SMBUS01", 0},
	{"SMBUS01", (kernel_ulong_t)&smbus_methods},
	{ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods},
	{"", 0}
};
MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids);

#define ACPI_SMBUS_STATUS_OK			0x00
#define ACPI_SMBUS_STATUS_FAIL			0x07
@@ -150,11 +160,11 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,

	if (read_write == I2C_SMBUS_READ) {
		protocol |= ACPI_SMBUS_PRTCL_READ;
		method = smbus_methods.mt_sbr;
		method = smbus_cmi->methods->mt_sbr;
		input.count = 3;
	} else {
		protocol |= ACPI_SMBUS_PRTCL_WRITE;
		method = smbus_methods.mt_sbw;
		method = smbus_cmi->methods->mt_sbw;
		input.count = 5;
	}

@@ -290,13 +300,13 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
	union acpi_object *obj;
	acpi_status status;

	if (!strcmp(name, smbus_methods.mt_info)) {
	if (!strcmp(name, smbus_cmi->methods->mt_info)) {
		status = acpi_evaluate_object(smbus_cmi->handle,
					smbus_methods.mt_info,
					smbus_cmi->methods->mt_info,
					NULL, &buffer);
		if (ACPI_FAILURE(status)) {
			ACPI_ERROR((AE_INFO, "Evaluating %s: %i",
				   smbus_methods.mt_info, status));
				   smbus_cmi->methods->mt_info, status));
			return -EIO;
		}

@@ -319,9 +329,9 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,

		kfree(buffer.pointer);
		smbus_cmi->cap_info = 1;
	} else if (!strcmp(name, smbus_methods.mt_sbr))
	} else if (!strcmp(name, smbus_cmi->methods->mt_sbr))
		smbus_cmi->cap_read = 1;
	else if (!strcmp(name, smbus_methods.mt_sbw))
	else if (!strcmp(name, smbus_cmi->methods->mt_sbw))
		smbus_cmi->cap_write = 1;
	else
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported CMI method: %s\n",
@@ -349,6 +359,7 @@ static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
static int acpi_smbus_cmi_add(struct acpi_device *device)
{
	struct acpi_smbus_cmi *smbus_cmi;
	const struct acpi_device_id *id;

	smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
	if (!smbus_cmi)
@@ -362,6 +373,11 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
	smbus_cmi->cap_read = 0;
	smbus_cmi->cap_write = 0;

	for (id = acpi_smbus_cmi_ids; id->id[0]; id++)
		if (!strcmp(id->id, acpi_device_hid(device)))
			smbus_cmi->methods =
				(struct smbus_methods_t *) id->driver_data;

	acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
			    acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);

+2 −0
Original line number Diff line number Diff line
@@ -65,6 +65,8 @@
#define ACPI_VIDEO_HID			"LNXVIDEO"
#define ACPI_BAY_HID			"LNXIOBAY"
#define ACPI_DOCK_HID			"LNXDOCK"
/* Quirk for broken IBM BIOSes */
#define ACPI_SMBUS_IBM_HID		"SMBUSIBM"

/*
 * For fixed hardware buttons, we fabricate acpi_devices with HID