0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/slab.h>
0010 #include <linux/kernel.h>
0011 #include <linux/stddef.h>
0012 #include <linux/i2c.h>
0013 #include <linux/acpi.h>
0014
0015 #define ACPI_SMBUS_HC_CLASS "smbus"
0016 #define ACPI_SMBUS_HC_DEVICE_NAME "cmi"
0017
0018
0019 #define ACPI_SMBUS_MS_HID "SMB0001"
0020
0021 struct smbus_methods_t {
0022 char *mt_info;
0023 char *mt_sbr;
0024 char *mt_sbw;
0025 };
0026
0027 struct acpi_smbus_cmi {
0028 acpi_handle handle;
0029 struct i2c_adapter adapter;
0030 u8 cap_info:1;
0031 u8 cap_read:1;
0032 u8 cap_write:1;
0033 struct smbus_methods_t *methods;
0034 };
0035
0036 static const struct smbus_methods_t smbus_methods = {
0037 .mt_info = "_SBI",
0038 .mt_sbr = "_SBR",
0039 .mt_sbw = "_SBW",
0040 };
0041
0042
0043 static const struct smbus_methods_t ibm_smbus_methods = {
0044 .mt_info = "SBI_",
0045 .mt_sbr = "SBR_",
0046 .mt_sbw = "SBW_",
0047 };
0048
0049 static const struct acpi_device_id acpi_smbus_cmi_ids[] = {
0050 {"SMBUS01", (kernel_ulong_t)&smbus_methods},
0051 {ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods},
0052 {ACPI_SMBUS_MS_HID, (kernel_ulong_t)&smbus_methods},
0053 {"", 0}
0054 };
0055 MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids);
0056
0057 #define ACPI_SMBUS_STATUS_OK 0x00
0058 #define ACPI_SMBUS_STATUS_FAIL 0x07
0059 #define ACPI_SMBUS_STATUS_DNAK 0x10
0060 #define ACPI_SMBUS_STATUS_DERR 0x11
0061 #define ACPI_SMBUS_STATUS_CMD_DENY 0x12
0062 #define ACPI_SMBUS_STATUS_UNKNOWN 0x13
0063 #define ACPI_SMBUS_STATUS_ACC_DENY 0x17
0064 #define ACPI_SMBUS_STATUS_TIMEOUT 0x18
0065 #define ACPI_SMBUS_STATUS_NOTSUP 0x19
0066 #define ACPI_SMBUS_STATUS_BUSY 0x1a
0067 #define ACPI_SMBUS_STATUS_PEC 0x1f
0068
0069 #define ACPI_SMBUS_PRTCL_WRITE 0x00
0070 #define ACPI_SMBUS_PRTCL_READ 0x01
0071 #define ACPI_SMBUS_PRTCL_QUICK 0x02
0072 #define ACPI_SMBUS_PRTCL_BYTE 0x04
0073 #define ACPI_SMBUS_PRTCL_BYTE_DATA 0x06
0074 #define ACPI_SMBUS_PRTCL_WORD_DATA 0x08
0075 #define ACPI_SMBUS_PRTCL_BLOCK_DATA 0x0a
0076
0077
0078 static int
0079 acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
0080 char read_write, u8 command, int size,
0081 union i2c_smbus_data *data)
0082 {
0083 int result = 0;
0084 struct acpi_smbus_cmi *smbus_cmi = adap->algo_data;
0085 unsigned char protocol;
0086 acpi_status status = 0;
0087 struct acpi_object_list input;
0088 union acpi_object mt_params[5];
0089 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
0090 union acpi_object *obj;
0091 union acpi_object *pkg;
0092 char *method;
0093 int len = 0;
0094
0095 dev_dbg(&adap->dev, "access size: %d %s\n", size,
0096 (read_write) ? "READ" : "WRITE");
0097 switch (size) {
0098 case I2C_SMBUS_QUICK:
0099 protocol = ACPI_SMBUS_PRTCL_QUICK;
0100 command = 0;
0101 if (read_write == I2C_SMBUS_WRITE) {
0102 mt_params[3].type = ACPI_TYPE_INTEGER;
0103 mt_params[3].integer.value = 0;
0104 mt_params[4].type = ACPI_TYPE_INTEGER;
0105 mt_params[4].integer.value = 0;
0106 }
0107 break;
0108
0109 case I2C_SMBUS_BYTE:
0110 protocol = ACPI_SMBUS_PRTCL_BYTE;
0111 if (read_write == I2C_SMBUS_WRITE) {
0112 mt_params[3].type = ACPI_TYPE_INTEGER;
0113 mt_params[3].integer.value = 0;
0114 mt_params[4].type = ACPI_TYPE_INTEGER;
0115 mt_params[4].integer.value = 0;
0116 } else {
0117 command = 0;
0118 }
0119 break;
0120
0121 case I2C_SMBUS_BYTE_DATA:
0122 protocol = ACPI_SMBUS_PRTCL_BYTE_DATA;
0123 if (read_write == I2C_SMBUS_WRITE) {
0124 mt_params[3].type = ACPI_TYPE_INTEGER;
0125 mt_params[3].integer.value = 1;
0126 mt_params[4].type = ACPI_TYPE_INTEGER;
0127 mt_params[4].integer.value = data->byte;
0128 }
0129 break;
0130
0131 case I2C_SMBUS_WORD_DATA:
0132 protocol = ACPI_SMBUS_PRTCL_WORD_DATA;
0133 if (read_write == I2C_SMBUS_WRITE) {
0134 mt_params[3].type = ACPI_TYPE_INTEGER;
0135 mt_params[3].integer.value = 2;
0136 mt_params[4].type = ACPI_TYPE_INTEGER;
0137 mt_params[4].integer.value = data->word;
0138 }
0139 break;
0140
0141 case I2C_SMBUS_BLOCK_DATA:
0142 protocol = ACPI_SMBUS_PRTCL_BLOCK_DATA;
0143 if (read_write == I2C_SMBUS_WRITE) {
0144 len = data->block[0];
0145 if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
0146 return -EINVAL;
0147 mt_params[3].type = ACPI_TYPE_INTEGER;
0148 mt_params[3].integer.value = len;
0149 mt_params[4].type = ACPI_TYPE_BUFFER;
0150 mt_params[4].buffer.length = len;
0151 mt_params[4].buffer.pointer = data->block + 1;
0152 }
0153 break;
0154
0155 default:
0156 dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
0157 return -EOPNOTSUPP;
0158 }
0159
0160 if (read_write == I2C_SMBUS_READ) {
0161 protocol |= ACPI_SMBUS_PRTCL_READ;
0162 method = smbus_cmi->methods->mt_sbr;
0163 input.count = 3;
0164 } else {
0165 protocol |= ACPI_SMBUS_PRTCL_WRITE;
0166 method = smbus_cmi->methods->mt_sbw;
0167 input.count = 5;
0168 }
0169
0170 input.pointer = mt_params;
0171 mt_params[0].type = ACPI_TYPE_INTEGER;
0172 mt_params[0].integer.value = protocol;
0173 mt_params[1].type = ACPI_TYPE_INTEGER;
0174 mt_params[1].integer.value = addr;
0175 mt_params[2].type = ACPI_TYPE_INTEGER;
0176 mt_params[2].integer.value = command;
0177
0178 status = acpi_evaluate_object(smbus_cmi->handle, method, &input,
0179 &buffer);
0180 if (ACPI_FAILURE(status)) {
0181 acpi_handle_err(smbus_cmi->handle,
0182 "Failed to evaluate %s: %i\n", method, status);
0183 return -EIO;
0184 }
0185
0186 pkg = buffer.pointer;
0187 if (pkg && pkg->type == ACPI_TYPE_PACKAGE)
0188 obj = pkg->package.elements;
0189 else {
0190 acpi_handle_err(smbus_cmi->handle, "Invalid argument type\n");
0191 result = -EIO;
0192 goto out;
0193 }
0194 if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
0195 acpi_handle_err(smbus_cmi->handle, "Invalid argument type\n");
0196 result = -EIO;
0197 goto out;
0198 }
0199
0200 result = obj->integer.value;
0201 acpi_handle_debug(smbus_cmi->handle, "%s return status: %i\n", method,
0202 result);
0203
0204 switch (result) {
0205 case ACPI_SMBUS_STATUS_OK:
0206 result = 0;
0207 break;
0208 case ACPI_SMBUS_STATUS_BUSY:
0209 result = -EBUSY;
0210 goto out;
0211 case ACPI_SMBUS_STATUS_TIMEOUT:
0212 result = -ETIMEDOUT;
0213 goto out;
0214 case ACPI_SMBUS_STATUS_DNAK:
0215 result = -ENXIO;
0216 goto out;
0217 default:
0218 result = -EIO;
0219 goto out;
0220 }
0221
0222 if (read_write == I2C_SMBUS_WRITE || size == I2C_SMBUS_QUICK)
0223 goto out;
0224
0225 obj = pkg->package.elements + 1;
0226 if (obj->type != ACPI_TYPE_INTEGER) {
0227 acpi_handle_err(smbus_cmi->handle, "Invalid argument type\n");
0228 result = -EIO;
0229 goto out;
0230 }
0231
0232 len = obj->integer.value;
0233 obj = pkg->package.elements + 2;
0234 switch (size) {
0235 case I2C_SMBUS_BYTE:
0236 case I2C_SMBUS_BYTE_DATA:
0237 case I2C_SMBUS_WORD_DATA:
0238 if (obj->type != ACPI_TYPE_INTEGER) {
0239 acpi_handle_err(smbus_cmi->handle,
0240 "Invalid argument type\n");
0241 result = -EIO;
0242 goto out;
0243 }
0244 if (len == 2)
0245 data->word = obj->integer.value;
0246 else
0247 data->byte = obj->integer.value;
0248 break;
0249 case I2C_SMBUS_BLOCK_DATA:
0250 if (obj->type != ACPI_TYPE_BUFFER) {
0251 acpi_handle_err(smbus_cmi->handle,
0252 "Invalid argument type\n");
0253 result = -EIO;
0254 goto out;
0255 }
0256 if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
0257 return -EPROTO;
0258 data->block[0] = len;
0259 memcpy(data->block + 1, obj->buffer.pointer, len);
0260 break;
0261 }
0262
0263 out:
0264 kfree(buffer.pointer);
0265 dev_dbg(&adap->dev, "Transaction status: %i\n", result);
0266 return result;
0267 }
0268
0269 static u32 acpi_smbus_cmi_func(struct i2c_adapter *adapter)
0270 {
0271 struct acpi_smbus_cmi *smbus_cmi = adapter->algo_data;
0272 u32 ret;
0273
0274 ret = smbus_cmi->cap_read | smbus_cmi->cap_write ?
0275 I2C_FUNC_SMBUS_QUICK : 0;
0276
0277 ret |= smbus_cmi->cap_read ?
0278 (I2C_FUNC_SMBUS_READ_BYTE |
0279 I2C_FUNC_SMBUS_READ_BYTE_DATA |
0280 I2C_FUNC_SMBUS_READ_WORD_DATA |
0281 I2C_FUNC_SMBUS_READ_BLOCK_DATA) : 0;
0282
0283 ret |= smbus_cmi->cap_write ?
0284 (I2C_FUNC_SMBUS_WRITE_BYTE |
0285 I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
0286 I2C_FUNC_SMBUS_WRITE_WORD_DATA |
0287 I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) : 0;
0288
0289 return ret;
0290 }
0291
0292 static const struct i2c_algorithm acpi_smbus_cmi_algorithm = {
0293 .smbus_xfer = acpi_smbus_cmi_access,
0294 .functionality = acpi_smbus_cmi_func,
0295 };
0296
0297
0298 static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
0299 const char *name)
0300 {
0301 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
0302 struct acpi_handle *handle = smbus_cmi->handle;
0303 union acpi_object *obj;
0304 acpi_status status;
0305
0306 if (!strcmp(name, smbus_cmi->methods->mt_info)) {
0307 status = acpi_evaluate_object(smbus_cmi->handle,
0308 smbus_cmi->methods->mt_info,
0309 NULL, &buffer);
0310 if (ACPI_FAILURE(status)) {
0311 acpi_handle_err(handle, "Failed to evaluate %s: %i\n",
0312 smbus_cmi->methods->mt_info, status);
0313 return -EIO;
0314 }
0315
0316 obj = buffer.pointer;
0317 if (obj && obj->type == ACPI_TYPE_PACKAGE)
0318 obj = obj->package.elements;
0319 else {
0320 acpi_handle_err(handle, "Invalid argument type\n");
0321 kfree(buffer.pointer);
0322 return -EIO;
0323 }
0324
0325 if (obj->type != ACPI_TYPE_INTEGER) {
0326 acpi_handle_err(handle, "Invalid argument type\n");
0327 kfree(buffer.pointer);
0328 return -EIO;
0329 } else
0330 acpi_handle_debug(handle, "SMBus CMI Version %x\n",
0331 (int)obj->integer.value);
0332
0333 kfree(buffer.pointer);
0334 smbus_cmi->cap_info = 1;
0335 } else if (!strcmp(name, smbus_cmi->methods->mt_sbr))
0336 smbus_cmi->cap_read = 1;
0337 else if (!strcmp(name, smbus_cmi->methods->mt_sbw))
0338 smbus_cmi->cap_write = 1;
0339 else
0340 acpi_handle_debug(handle, "Unsupported CMI method: %s\n", name);
0341
0342 return 0;
0343 }
0344
0345 static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
0346 void *context, void **return_value)
0347 {
0348 char node_name[5];
0349 struct acpi_buffer buffer = { sizeof(node_name), node_name };
0350 struct acpi_smbus_cmi *smbus_cmi = context;
0351 acpi_status status;
0352
0353 status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
0354
0355 if (ACPI_SUCCESS(status))
0356 acpi_smbus_cmi_add_cap(smbus_cmi, node_name);
0357
0358 return AE_OK;
0359 }
0360
0361 static int acpi_smbus_cmi_add(struct acpi_device *device)
0362 {
0363 struct acpi_smbus_cmi *smbus_cmi;
0364 const struct acpi_device_id *id;
0365 int ret;
0366
0367 smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
0368 if (!smbus_cmi)
0369 return -ENOMEM;
0370
0371 smbus_cmi->handle = device->handle;
0372 strcpy(acpi_device_name(device), ACPI_SMBUS_HC_DEVICE_NAME);
0373 strcpy(acpi_device_class(device), ACPI_SMBUS_HC_CLASS);
0374 device->driver_data = smbus_cmi;
0375 smbus_cmi->cap_info = 0;
0376 smbus_cmi->cap_read = 0;
0377 smbus_cmi->cap_write = 0;
0378
0379 for (id = acpi_smbus_cmi_ids; id->id[0]; id++)
0380 if (!strcmp(id->id, acpi_device_hid(device)))
0381 smbus_cmi->methods =
0382 (struct smbus_methods_t *) id->driver_data;
0383
0384 acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
0385 acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);
0386
0387 if (smbus_cmi->cap_info == 0) {
0388 ret = -ENODEV;
0389 goto err;
0390 }
0391
0392 snprintf(smbus_cmi->adapter.name, sizeof(smbus_cmi->adapter.name),
0393 "SMBus CMI adapter %s",
0394 acpi_device_name(device));
0395 smbus_cmi->adapter.owner = THIS_MODULE;
0396 smbus_cmi->adapter.algo = &acpi_smbus_cmi_algorithm;
0397 smbus_cmi->adapter.algo_data = smbus_cmi;
0398 smbus_cmi->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
0399 smbus_cmi->adapter.dev.parent = &device->dev;
0400
0401 ret = i2c_add_adapter(&smbus_cmi->adapter);
0402 if (ret) {
0403 dev_err(&device->dev, "Couldn't register adapter!\n");
0404 goto err;
0405 }
0406
0407 return 0;
0408
0409 err:
0410 kfree(smbus_cmi);
0411 device->driver_data = NULL;
0412 return ret;
0413 }
0414
0415 static int acpi_smbus_cmi_remove(struct acpi_device *device)
0416 {
0417 struct acpi_smbus_cmi *smbus_cmi = acpi_driver_data(device);
0418
0419 i2c_del_adapter(&smbus_cmi->adapter);
0420 kfree(smbus_cmi);
0421 device->driver_data = NULL;
0422
0423 return 0;
0424 }
0425
0426 static struct acpi_driver acpi_smbus_cmi_driver = {
0427 .name = ACPI_SMBUS_HC_DEVICE_NAME,
0428 .class = ACPI_SMBUS_HC_CLASS,
0429 .ids = acpi_smbus_cmi_ids,
0430 .ops = {
0431 .add = acpi_smbus_cmi_add,
0432 .remove = acpi_smbus_cmi_remove,
0433 },
0434 };
0435 module_acpi_driver(acpi_smbus_cmi_driver);
0436
0437 MODULE_LICENSE("GPL");
0438 MODULE_AUTHOR("Crane Cai <crane.cai@amd.com>");
0439 MODULE_DESCRIPTION("ACPI SMBus CMI driver");