1 /* 2 * SMBus driver for ACPI SMBus CMI 3 * 4 * Copyright (C) 2009 Crane Cai <crane.cai@amd.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation version 2. 9 */ 10 11 #include <linux/module.h> 12 #include <linux/slab.h> 13 #include <linux/kernel.h> 14 #include <linux/stddef.h> 15 #include <linux/init.h> 16 #include <linux/i2c.h> 17 #include <linux/acpi.h> 18 19 #define ACPI_SMBUS_HC_CLASS "smbus" 20 #define ACPI_SMBUS_HC_DEVICE_NAME "cmi" 21 22 ACPI_MODULE_NAME("smbus_cmi"); 23 24 struct smbus_methods_t { 25 char *mt_info; 26 char *mt_sbr; 27 char *mt_sbw; 28 }; 29 30 struct acpi_smbus_cmi { 31 acpi_handle handle; 32 struct i2c_adapter adapter; 33 u8 cap_info:1; 34 u8 cap_read:1; 35 u8 cap_write:1; 36 }; 37 38 static const struct smbus_methods_t smbus_methods = { 39 .mt_info = "_SBI", 40 .mt_sbr = "_SBR", 41 .mt_sbw = "_SBW", 42 }; 43 44 static const struct acpi_device_id acpi_smbus_cmi_ids[] = { 45 {"SMBUS01", 0}, 46 {"", 0} 47 }; 48 49 #define ACPI_SMBUS_STATUS_OK 0x00 50 #define ACPI_SMBUS_STATUS_FAIL 0x07 51 #define ACPI_SMBUS_STATUS_DNAK 0x10 52 #define ACPI_SMBUS_STATUS_DERR 0x11 53 #define ACPI_SMBUS_STATUS_CMD_DENY 0x12 54 #define ACPI_SMBUS_STATUS_UNKNOWN 0x13 55 #define ACPI_SMBUS_STATUS_ACC_DENY 0x17 56 #define ACPI_SMBUS_STATUS_TIMEOUT 0x18 57 #define ACPI_SMBUS_STATUS_NOTSUP 0x19 58 #define ACPI_SMBUS_STATUS_BUSY 0x1a 59 #define ACPI_SMBUS_STATUS_PEC 0x1f 60 61 #define ACPI_SMBUS_PRTCL_WRITE 0x00 62 #define ACPI_SMBUS_PRTCL_READ 0x01 63 #define ACPI_SMBUS_PRTCL_QUICK 0x02 64 #define ACPI_SMBUS_PRTCL_BYTE 0x04 65 #define ACPI_SMBUS_PRTCL_BYTE_DATA 0x06 66 #define ACPI_SMBUS_PRTCL_WORD_DATA 0x08 67 #define ACPI_SMBUS_PRTCL_BLOCK_DATA 0x0a 68 69 70 static int 71 acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, 72 char read_write, u8 command, int size, 73 union i2c_smbus_data *data) 74 { 75 int result = 0; 76 struct acpi_smbus_cmi *smbus_cmi = adap->algo_data; 77 unsigned char protocol; 78 acpi_status status = 0; 79 struct acpi_object_list input; 80 union acpi_object mt_params[5]; 81 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 82 union acpi_object *obj; 83 union acpi_object *pkg; 84 char *method; 85 int len = 0; 86 87 dev_dbg(&adap->dev, "access size: %d %s\n", size, 88 (read_write) ? "READ" : "WRITE"); 89 switch (size) { 90 case I2C_SMBUS_QUICK: 91 protocol = ACPI_SMBUS_PRTCL_QUICK; 92 command = 0; 93 if (read_write == I2C_SMBUS_WRITE) { 94 mt_params[3].type = ACPI_TYPE_INTEGER; 95 mt_params[3].integer.value = 0; 96 mt_params[4].type = ACPI_TYPE_INTEGER; 97 mt_params[4].integer.value = 0; 98 } 99 break; 100 101 case I2C_SMBUS_BYTE: 102 protocol = ACPI_SMBUS_PRTCL_BYTE; 103 if (read_write == I2C_SMBUS_WRITE) { 104 mt_params[3].type = ACPI_TYPE_INTEGER; 105 mt_params[3].integer.value = 0; 106 mt_params[4].type = ACPI_TYPE_INTEGER; 107 mt_params[4].integer.value = 0; 108 } else { 109 command = 0; 110 } 111 break; 112 113 case I2C_SMBUS_BYTE_DATA: 114 protocol = ACPI_SMBUS_PRTCL_BYTE_DATA; 115 if (read_write == I2C_SMBUS_WRITE) { 116 mt_params[3].type = ACPI_TYPE_INTEGER; 117 mt_params[3].integer.value = 1; 118 mt_params[4].type = ACPI_TYPE_INTEGER; 119 mt_params[4].integer.value = data->byte; 120 } 121 break; 122 123 case I2C_SMBUS_WORD_DATA: 124 protocol = ACPI_SMBUS_PRTCL_WORD_DATA; 125 if (read_write == I2C_SMBUS_WRITE) { 126 mt_params[3].type = ACPI_TYPE_INTEGER; 127 mt_params[3].integer.value = 2; 128 mt_params[4].type = ACPI_TYPE_INTEGER; 129 mt_params[4].integer.value = data->word; 130 } 131 break; 132 133 case I2C_SMBUS_BLOCK_DATA: 134 protocol = ACPI_SMBUS_PRTCL_BLOCK_DATA; 135 if (read_write == I2C_SMBUS_WRITE) { 136 len = data->block[0]; 137 if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) 138 return -EINVAL; 139 mt_params[3].type = ACPI_TYPE_INTEGER; 140 mt_params[3].integer.value = len; 141 mt_params[4].type = ACPI_TYPE_BUFFER; 142 mt_params[4].buffer.pointer = data->block + 1; 143 } 144 break; 145 146 default: 147 dev_warn(&adap->dev, "Unsupported transaction %d\n", size); 148 return -EOPNOTSUPP; 149 } 150 151 if (read_write == I2C_SMBUS_READ) { 152 protocol |= ACPI_SMBUS_PRTCL_READ; 153 method = smbus_methods.mt_sbr; 154 input.count = 3; 155 } else { 156 protocol |= ACPI_SMBUS_PRTCL_WRITE; 157 method = smbus_methods.mt_sbw; 158 input.count = 5; 159 } 160 161 input.pointer = mt_params; 162 mt_params[0].type = ACPI_TYPE_INTEGER; 163 mt_params[0].integer.value = protocol; 164 mt_params[1].type = ACPI_TYPE_INTEGER; 165 mt_params[1].integer.value = addr; 166 mt_params[2].type = ACPI_TYPE_INTEGER; 167 mt_params[2].integer.value = command; 168 169 status = acpi_evaluate_object(smbus_cmi->handle, method, &input, 170 &buffer); 171 if (ACPI_FAILURE(status)) { 172 ACPI_ERROR((AE_INFO, "Evaluating %s: %i", method, status)); 173 return -EIO; 174 } 175 176 pkg = buffer.pointer; 177 if (pkg && pkg->type == ACPI_TYPE_PACKAGE) 178 obj = pkg->package.elements; 179 else { 180 ACPI_ERROR((AE_INFO, "Invalid argument type")); 181 result = -EIO; 182 goto out; 183 } 184 if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) { 185 ACPI_ERROR((AE_INFO, "Invalid argument type")); 186 result = -EIO; 187 goto out; 188 } 189 190 result = obj->integer.value; 191 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s return status: %i\n", 192 method, result)); 193 194 switch (result) { 195 case ACPI_SMBUS_STATUS_OK: 196 result = 0; 197 break; 198 case ACPI_SMBUS_STATUS_BUSY: 199 result = -EBUSY; 200 goto out; 201 case ACPI_SMBUS_STATUS_TIMEOUT: 202 result = -ETIMEDOUT; 203 goto out; 204 case ACPI_SMBUS_STATUS_DNAK: 205 result = -ENXIO; 206 goto out; 207 default: 208 result = -EIO; 209 goto out; 210 } 211 212 if (read_write == I2C_SMBUS_WRITE || size == I2C_SMBUS_QUICK) 213 goto out; 214 215 obj = pkg->package.elements + 1; 216 if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) { 217 ACPI_ERROR((AE_INFO, "Invalid argument type")); 218 result = -EIO; 219 goto out; 220 } 221 222 len = obj->integer.value; 223 obj = pkg->package.elements + 2; 224 switch (size) { 225 case I2C_SMBUS_BYTE: 226 case I2C_SMBUS_BYTE_DATA: 227 case I2C_SMBUS_WORD_DATA: 228 if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) { 229 ACPI_ERROR((AE_INFO, "Invalid argument type")); 230 result = -EIO; 231 goto out; 232 } 233 if (len == 2) 234 data->word = obj->integer.value; 235 else 236 data->byte = obj->integer.value; 237 break; 238 case I2C_SMBUS_BLOCK_DATA: 239 if (obj == NULL || obj->type != ACPI_TYPE_BUFFER) { 240 ACPI_ERROR((AE_INFO, "Invalid argument type")); 241 result = -EIO; 242 goto out; 243 } 244 if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) 245 return -EPROTO; 246 data->block[0] = len; 247 memcpy(data->block + 1, obj->buffer.pointer, len); 248 break; 249 } 250 251 out: 252 kfree(buffer.pointer); 253 dev_dbg(&adap->dev, "Transaction status: %i\n", result); 254 return result; 255 } 256 257 static u32 acpi_smbus_cmi_func(struct i2c_adapter *adapter) 258 { 259 struct acpi_smbus_cmi *smbus_cmi = adapter->algo_data; 260 u32 ret; 261 262 ret = smbus_cmi->cap_read | smbus_cmi->cap_write ? 263 I2C_FUNC_SMBUS_QUICK : 0; 264 265 ret |= smbus_cmi->cap_read ? 266 (I2C_FUNC_SMBUS_READ_BYTE | 267 I2C_FUNC_SMBUS_READ_BYTE_DATA | 268 I2C_FUNC_SMBUS_READ_WORD_DATA | 269 I2C_FUNC_SMBUS_READ_BLOCK_DATA) : 0; 270 271 ret |= smbus_cmi->cap_write ? 272 (I2C_FUNC_SMBUS_WRITE_BYTE | 273 I2C_FUNC_SMBUS_WRITE_BYTE_DATA | 274 I2C_FUNC_SMBUS_WRITE_WORD_DATA | 275 I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) : 0; 276 277 return ret; 278 } 279 280 static const struct i2c_algorithm acpi_smbus_cmi_algorithm = { 281 .smbus_xfer = acpi_smbus_cmi_access, 282 .functionality = acpi_smbus_cmi_func, 283 }; 284 285 286 static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi, 287 const char *name) 288 { 289 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 290 union acpi_object *obj; 291 acpi_status status; 292 293 if (!strcmp(name, smbus_methods.mt_info)) { 294 status = acpi_evaluate_object(smbus_cmi->handle, 295 smbus_methods.mt_info, 296 NULL, &buffer); 297 if (ACPI_FAILURE(status)) { 298 ACPI_ERROR((AE_INFO, "Evaluating %s: %i", 299 smbus_methods.mt_info, status)); 300 return -EIO; 301 } 302 303 obj = buffer.pointer; 304 if (obj && obj->type == ACPI_TYPE_PACKAGE) 305 obj = obj->package.elements; 306 else { 307 ACPI_ERROR((AE_INFO, "Invalid argument type")); 308 kfree(buffer.pointer); 309 return -EIO; 310 } 311 312 if (obj->type != ACPI_TYPE_INTEGER) { 313 ACPI_ERROR((AE_INFO, "Invalid argument type")); 314 kfree(buffer.pointer); 315 return -EIO; 316 } else 317 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SMBus CMI Version %x" 318 "\n", (int)obj->integer.value)); 319 320 kfree(buffer.pointer); 321 smbus_cmi->cap_info = 1; 322 } else if (!strcmp(name, smbus_methods.mt_sbr)) 323 smbus_cmi->cap_read = 1; 324 else if (!strcmp(name, smbus_methods.mt_sbw)) 325 smbus_cmi->cap_write = 1; 326 else 327 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported CMI method: %s\n", 328 name)); 329 330 return 0; 331 } 332 333 static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level, 334 void *context, void **return_value) 335 { 336 char node_name[5]; 337 struct acpi_buffer buffer = { sizeof(node_name), node_name }; 338 struct acpi_smbus_cmi *smbus_cmi = context; 339 acpi_status status; 340 341 status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); 342 343 if (ACPI_SUCCESS(status)) 344 acpi_smbus_cmi_add_cap(smbus_cmi, node_name); 345 346 return AE_OK; 347 } 348 349 static int acpi_smbus_cmi_add(struct acpi_device *device) 350 { 351 struct acpi_smbus_cmi *smbus_cmi; 352 353 smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL); 354 if (!smbus_cmi) 355 return -ENOMEM; 356 357 smbus_cmi->handle = device->handle; 358 strcpy(acpi_device_name(device), ACPI_SMBUS_HC_DEVICE_NAME); 359 strcpy(acpi_device_class(device), ACPI_SMBUS_HC_CLASS); 360 device->driver_data = smbus_cmi; 361 smbus_cmi->cap_info = 0; 362 smbus_cmi->cap_read = 0; 363 smbus_cmi->cap_write = 0; 364 365 acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1, 366 acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL); 367 368 if (smbus_cmi->cap_info == 0) 369 goto err; 370 371 snprintf(smbus_cmi->adapter.name, sizeof(smbus_cmi->adapter.name), 372 "SMBus CMI adapter %s", 373 acpi_device_name(device)); 374 smbus_cmi->adapter.owner = THIS_MODULE; 375 smbus_cmi->adapter.algo = &acpi_smbus_cmi_algorithm; 376 smbus_cmi->adapter.algo_data = smbus_cmi; 377 smbus_cmi->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; 378 smbus_cmi->adapter.dev.parent = &device->dev; 379 380 if (i2c_add_adapter(&smbus_cmi->adapter)) { 381 dev_err(&device->dev, "Couldn't register adapter!\n"); 382 goto err; 383 } 384 385 return 0; 386 387 err: 388 kfree(smbus_cmi); 389 device->driver_data = NULL; 390 return -EIO; 391 } 392 393 static int acpi_smbus_cmi_remove(struct acpi_device *device, int type) 394 { 395 struct acpi_smbus_cmi *smbus_cmi = acpi_driver_data(device); 396 397 i2c_del_adapter(&smbus_cmi->adapter); 398 kfree(smbus_cmi); 399 device->driver_data = NULL; 400 401 return 0; 402 } 403 404 static struct acpi_driver acpi_smbus_cmi_driver = { 405 .name = ACPI_SMBUS_HC_DEVICE_NAME, 406 .class = ACPI_SMBUS_HC_CLASS, 407 .ids = acpi_smbus_cmi_ids, 408 .ops = { 409 .add = acpi_smbus_cmi_add, 410 .remove = acpi_smbus_cmi_remove, 411 }, 412 }; 413 414 static int __init acpi_smbus_cmi_init(void) 415 { 416 return acpi_bus_register_driver(&acpi_smbus_cmi_driver); 417 } 418 419 static void __exit acpi_smbus_cmi_exit(void) 420 { 421 acpi_bus_unregister_driver(&acpi_smbus_cmi_driver); 422 } 423 424 module_init(acpi_smbus_cmi_init); 425 module_exit(acpi_smbus_cmi_exit); 426 427 MODULE_LICENSE("GPL"); 428 MODULE_AUTHOR("Crane Cai <crane.cai@amd.com>"); 429 MODULE_DESCRIPTION("ACPI SMBus CMI driver"); 430