aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-03-24 19:41:48 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-03-24 19:41:48 -0400
commit18020a0d8cccad0d3642219d6aef789420c04c1f (patch)
tree73fba2c01ae2e5638c7bf0e271daf4bfa5418fa0 /drivers
parentc27b9a2e6c29eac2fe770bd1071007c9f8c43de5 (diff)
parent0f5ed04cb365ce0117b0588c4d9ed89f2623650b (diff)
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
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/scan.c38
-rw-r--r--drivers/i2c/busses/i2c-scmi.c32
2 files changed, 62 insertions, 8 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index fb7fc24fe727..189cbc2585fa 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -8,6 +8,7 @@
8#include <linux/acpi.h> 8#include <linux/acpi.h>
9#include <linux/signal.h> 9#include <linux/signal.h>
10#include <linux/kthread.h> 10#include <linux/kthread.h>
11#include <linux/dmi.h>
11 12
12#include <acpi/acpi_drivers.h> 13#include <acpi/acpi_drivers.h>
13 14
@@ -1032,6 +1033,41 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id)
1032 list_add_tail(&id->list, &device->pnp.ids); 1033 list_add_tail(&id->list, &device->pnp.ids);
1033} 1034}
1034 1035
1036/*
1037 * Old IBM workstations have a DSDT bug wherein the SMBus object
1038 * lacks the SMBUS01 HID and the methods do not have the necessary "_"
1039 * prefix. Work around this.
1040 */
1041static int acpi_ibm_smbus_match(struct acpi_device *device)
1042{
1043 acpi_handle h_dummy;
1044 struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
1045 int result;
1046
1047 if (!dmi_name_in_vendors("IBM"))
1048 return -ENODEV;
1049
1050 /* Look for SMBS object */
1051 result = acpi_get_name(device->handle, ACPI_SINGLE_NAME, &path);
1052 if (result)
1053 return result;
1054
1055 if (strcmp("SMBS", path.pointer)) {
1056 result = -ENODEV;
1057 goto out;
1058 }
1059
1060 /* Does it have the necessary (but misnamed) methods? */
1061 result = -ENODEV;
1062 if (ACPI_SUCCESS(acpi_get_handle(device->handle, "SBI", &h_dummy)) &&
1063 ACPI_SUCCESS(acpi_get_handle(device->handle, "SBR", &h_dummy)) &&
1064 ACPI_SUCCESS(acpi_get_handle(device->handle, "SBW", &h_dummy)))
1065 result = 0;
1066out:
1067 kfree(path.pointer);
1068 return result;
1069}
1070
1035static void acpi_device_set_id(struct acpi_device *device) 1071static void acpi_device_set_id(struct acpi_device *device)
1036{ 1072{
1037 acpi_status status; 1073 acpi_status status;
@@ -1082,6 +1118,8 @@ static void acpi_device_set_id(struct acpi_device *device)
1082 acpi_add_id(device, ACPI_BAY_HID); 1118 acpi_add_id(device, ACPI_BAY_HID);
1083 else if (ACPI_SUCCESS(acpi_dock_match(device))) 1119 else if (ACPI_SUCCESS(acpi_dock_match(device)))
1084 acpi_add_id(device, ACPI_DOCK_HID); 1120 acpi_add_id(device, ACPI_DOCK_HID);
1121 else if (!acpi_ibm_smbus_match(device))
1122 acpi_add_id(device, ACPI_SMBUS_IBM_HID);
1085 1123
1086 break; 1124 break;
1087 case ACPI_BUS_TYPE_POWER: 1125 case ACPI_BUS_TYPE_POWER:
diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c
index 365e0becaf12..388cbdc96db7 100644
--- a/drivers/i2c/busses/i2c-scmi.c
+++ b/drivers/i2c/busses/i2c-scmi.c
@@ -33,6 +33,7 @@ struct acpi_smbus_cmi {
33 u8 cap_info:1; 33 u8 cap_info:1;
34 u8 cap_read:1; 34 u8 cap_read:1;
35 u8 cap_write:1; 35 u8 cap_write:1;
36 struct smbus_methods_t *methods;
36}; 37};
37 38
38static const struct smbus_methods_t smbus_methods = { 39static const struct smbus_methods_t smbus_methods = {
@@ -41,10 +42,19 @@ static const struct smbus_methods_t smbus_methods = {
41 .mt_sbw = "_SBW", 42 .mt_sbw = "_SBW",
42}; 43};
43 44
45/* Some IBM BIOSes omit the leading underscore */
46static const struct smbus_methods_t ibm_smbus_methods = {
47 .mt_info = "SBI_",
48 .mt_sbr = "SBR_",
49 .mt_sbw = "SBW_",
50};
51
44static const struct acpi_device_id acpi_smbus_cmi_ids[] = { 52static const struct acpi_device_id acpi_smbus_cmi_ids[] = {
45 {"SMBUS01", 0}, 53 {"SMBUS01", (kernel_ulong_t)&smbus_methods},
54 {ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods},
46 {"", 0} 55 {"", 0}
47}; 56};
57MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids);
48 58
49#define ACPI_SMBUS_STATUS_OK 0x00 59#define ACPI_SMBUS_STATUS_OK 0x00
50#define ACPI_SMBUS_STATUS_FAIL 0x07 60#define ACPI_SMBUS_STATUS_FAIL 0x07
@@ -150,11 +160,11 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
150 160
151 if (read_write == I2C_SMBUS_READ) { 161 if (read_write == I2C_SMBUS_READ) {
152 protocol |= ACPI_SMBUS_PRTCL_READ; 162 protocol |= ACPI_SMBUS_PRTCL_READ;
153 method = smbus_methods.mt_sbr; 163 method = smbus_cmi->methods->mt_sbr;
154 input.count = 3; 164 input.count = 3;
155 } else { 165 } else {
156 protocol |= ACPI_SMBUS_PRTCL_WRITE; 166 protocol |= ACPI_SMBUS_PRTCL_WRITE;
157 method = smbus_methods.mt_sbw; 167 method = smbus_cmi->methods->mt_sbw;
158 input.count = 5; 168 input.count = 5;
159 } 169 }
160 170
@@ -290,13 +300,13 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
290 union acpi_object *obj; 300 union acpi_object *obj;
291 acpi_status status; 301 acpi_status status;
292 302
293 if (!strcmp(name, smbus_methods.mt_info)) { 303 if (!strcmp(name, smbus_cmi->methods->mt_info)) {
294 status = acpi_evaluate_object(smbus_cmi->handle, 304 status = acpi_evaluate_object(smbus_cmi->handle,
295 smbus_methods.mt_info, 305 smbus_cmi->methods->mt_info,
296 NULL, &buffer); 306 NULL, &buffer);
297 if (ACPI_FAILURE(status)) { 307 if (ACPI_FAILURE(status)) {
298 ACPI_ERROR((AE_INFO, "Evaluating %s: %i", 308 ACPI_ERROR((AE_INFO, "Evaluating %s: %i",
299 smbus_methods.mt_info, status)); 309 smbus_cmi->methods->mt_info, status));
300 return -EIO; 310 return -EIO;
301 } 311 }
302 312
@@ -319,9 +329,9 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
319 329
320 kfree(buffer.pointer); 330 kfree(buffer.pointer);
321 smbus_cmi->cap_info = 1; 331 smbus_cmi->cap_info = 1;
322 } else if (!strcmp(name, smbus_methods.mt_sbr)) 332 } else if (!strcmp(name, smbus_cmi->methods->mt_sbr))
323 smbus_cmi->cap_read = 1; 333 smbus_cmi->cap_read = 1;
324 else if (!strcmp(name, smbus_methods.mt_sbw)) 334 else if (!strcmp(name, smbus_cmi->methods->mt_sbw))
325 smbus_cmi->cap_write = 1; 335 smbus_cmi->cap_write = 1;
326 else 336 else
327 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported CMI method: %s\n", 337 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,
349static int acpi_smbus_cmi_add(struct acpi_device *device) 359static int acpi_smbus_cmi_add(struct acpi_device *device)
350{ 360{
351 struct acpi_smbus_cmi *smbus_cmi; 361 struct acpi_smbus_cmi *smbus_cmi;
362 const struct acpi_device_id *id;
352 363
353 smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL); 364 smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
354 if (!smbus_cmi) 365 if (!smbus_cmi)
@@ -362,6 +373,11 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
362 smbus_cmi->cap_read = 0; 373 smbus_cmi->cap_read = 0;
363 smbus_cmi->cap_write = 0; 374 smbus_cmi->cap_write = 0;
364 375
376 for (id = acpi_smbus_cmi_ids; id->id[0]; id++)
377 if (!strcmp(id->id, acpi_device_hid(device)))
378 smbus_cmi->methods =
379 (struct smbus_methods_t *) id->driver_data;
380
365 acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1, 381 acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
366 acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL); 382 acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);
367 383