i2c-scmi.c 11 KB

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