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