Commit 18020a0d authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging

* '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
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/dmi.h>
#include <acpi/acpi_drivers.h> #include <acpi/acpi_drivers.h>
...@@ -1032,6 +1033,41 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id) ...@@ -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); 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) static void acpi_device_set_id(struct acpi_device *device)
{ {
acpi_status status; acpi_status status;
...@@ -1082,6 +1118,8 @@ static void acpi_device_set_id(struct acpi_device *device) ...@@ -1082,6 +1118,8 @@ static void acpi_device_set_id(struct acpi_device *device)
acpi_add_id(device, ACPI_BAY_HID); acpi_add_id(device, ACPI_BAY_HID);
else if (ACPI_SUCCESS(acpi_dock_match(device))) else if (ACPI_SUCCESS(acpi_dock_match(device)))
acpi_add_id(device, ACPI_DOCK_HID); acpi_add_id(device, ACPI_DOCK_HID);
else if (!acpi_ibm_smbus_match(device))
acpi_add_id(device, ACPI_SMBUS_IBM_HID);
break; break;
case ACPI_BUS_TYPE_POWER: case ACPI_BUS_TYPE_POWER:
......
...@@ -33,6 +33,7 @@ struct acpi_smbus_cmi { ...@@ -33,6 +33,7 @@ struct acpi_smbus_cmi {
u8 cap_info:1; u8 cap_info:1;
u8 cap_read:1; u8 cap_read:1;
u8 cap_write:1; u8 cap_write:1;
struct smbus_methods_t *methods;
}; };
static const struct smbus_methods_t smbus_methods = { static const struct smbus_methods_t smbus_methods = {
...@@ -41,10 +42,19 @@ static const struct smbus_methods_t smbus_methods = { ...@@ -41,10 +42,19 @@ static const struct smbus_methods_t smbus_methods = {
.mt_sbw = "_SBW", .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[] = { 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} {"", 0}
}; };
MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids);
#define ACPI_SMBUS_STATUS_OK 0x00 #define ACPI_SMBUS_STATUS_OK 0x00
#define ACPI_SMBUS_STATUS_FAIL 0x07 #define ACPI_SMBUS_STATUS_FAIL 0x07
...@@ -150,11 +160,11 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, ...@@ -150,11 +160,11 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
if (read_write == I2C_SMBUS_READ) { if (read_write == I2C_SMBUS_READ) {
protocol |= ACPI_SMBUS_PRTCL_READ; protocol |= ACPI_SMBUS_PRTCL_READ;
method = smbus_methods.mt_sbr; method = smbus_cmi->methods->mt_sbr;
input.count = 3; input.count = 3;
} else { } else {
protocol |= ACPI_SMBUS_PRTCL_WRITE; protocol |= ACPI_SMBUS_PRTCL_WRITE;
method = smbus_methods.mt_sbw; method = smbus_cmi->methods->mt_sbw;
input.count = 5; input.count = 5;
} }
...@@ -290,13 +300,13 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi, ...@@ -290,13 +300,13 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
union acpi_object *obj; union acpi_object *obj;
acpi_status status; 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, status = acpi_evaluate_object(smbus_cmi->handle,
smbus_methods.mt_info, smbus_cmi->methods->mt_info,
NULL, &buffer); NULL, &buffer);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO, "Evaluating %s: %i", ACPI_ERROR((AE_INFO, "Evaluating %s: %i",
smbus_methods.mt_info, status)); smbus_cmi->methods->mt_info, status));
return -EIO; return -EIO;
} }
...@@ -319,9 +329,9 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi, ...@@ -319,9 +329,9 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
kfree(buffer.pointer); kfree(buffer.pointer);
smbus_cmi->cap_info = 1; 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; 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; smbus_cmi->cap_write = 1;
else else
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported CMI method: %s\n", 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, ...@@ -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) static int acpi_smbus_cmi_add(struct acpi_device *device)
{ {
struct acpi_smbus_cmi *smbus_cmi; struct acpi_smbus_cmi *smbus_cmi;
const struct acpi_device_id *id;
smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL); smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
if (!smbus_cmi) if (!smbus_cmi)
...@@ -362,6 +373,11 @@ static int acpi_smbus_cmi_add(struct acpi_device *device) ...@@ -362,6 +373,11 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
smbus_cmi->cap_read = 0; smbus_cmi->cap_read = 0;
smbus_cmi->cap_write = 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_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL); acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);
......
...@@ -65,6 +65,8 @@ ...@@ -65,6 +65,8 @@
#define ACPI_VIDEO_HID "LNXVIDEO" #define ACPI_VIDEO_HID "LNXVIDEO"
#define ACPI_BAY_HID "LNXIOBAY" #define ACPI_BAY_HID "LNXIOBAY"
#define ACPI_DOCK_HID "LNXDOCK" #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 * For fixed hardware buttons, we fabricate acpi_devices with HID
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment