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