cros_ec_i2c.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * ChromeOS EC multi-function device (I2C)
  3. *
  4. * Copyright (C) 2012 Google, Inc
  5. *
  6. * This software is licensed under the terms of the GNU General Public
  7. * License version 2, as published by the Free Software Foundation, and
  8. * may be copied, distributed, and modified under those terms.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <linux/kernel.h>
  16. #include <linux/module.h>
  17. #include <linux/i2c.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/mfd/cros_ec.h>
  20. #include <linux/mfd/cros_ec_commands.h>
  21. #include <linux/platform_device.h>
  22. #include <linux/slab.h>
  23. static inline struct cros_ec_device *to_ec_dev(struct device *dev)
  24. {
  25. struct i2c_client *client = to_i2c_client(dev);
  26. return i2c_get_clientdata(client);
  27. }
  28. static int cros_ec_cmd_xfer_i2c(struct cros_ec_device *ec_dev,
  29. struct cros_ec_command *msg)
  30. {
  31. struct i2c_client *client = ec_dev->priv;
  32. int ret = -ENOMEM;
  33. int i;
  34. int len;
  35. int packet_len;
  36. u8 *out_buf = NULL;
  37. u8 *in_buf = NULL;
  38. u8 sum;
  39. struct i2c_msg i2c_msg[2];
  40. i2c_msg[0].addr = client->addr;
  41. i2c_msg[0].flags = 0;
  42. i2c_msg[1].addr = client->addr;
  43. i2c_msg[1].flags = I2C_M_RD;
  44. /*
  45. * allocate larger packet (one byte for checksum, one byte for
  46. * length, and one for result code)
  47. */
  48. packet_len = msg->insize + 3;
  49. in_buf = kzalloc(packet_len, GFP_KERNEL);
  50. if (!in_buf)
  51. goto done;
  52. i2c_msg[1].len = packet_len;
  53. i2c_msg[1].buf = (char *)in_buf;
  54. /*
  55. * allocate larger packet (one byte for checksum, one for
  56. * command code, one for length, and one for command version)
  57. */
  58. packet_len = msg->outsize + 4;
  59. out_buf = kzalloc(packet_len, GFP_KERNEL);
  60. if (!out_buf)
  61. goto done;
  62. i2c_msg[0].len = packet_len;
  63. i2c_msg[0].buf = (char *)out_buf;
  64. out_buf[0] = EC_CMD_VERSION0 + msg->version;
  65. out_buf[1] = msg->command;
  66. out_buf[2] = msg->outsize;
  67. /* copy message payload and compute checksum */
  68. sum = out_buf[0] + out_buf[1] + out_buf[2];
  69. for (i = 0; i < msg->outsize; i++) {
  70. out_buf[3 + i] = msg->outdata[i];
  71. sum += out_buf[3 + i];
  72. }
  73. out_buf[3 + msg->outsize] = sum;
  74. /* send command to EC and read answer */
  75. ret = i2c_transfer(client->adapter, i2c_msg, 2);
  76. if (ret < 0) {
  77. dev_err(ec_dev->dev, "i2c transfer failed: %d\n", ret);
  78. goto done;
  79. } else if (ret != 2) {
  80. dev_err(ec_dev->dev, "failed to get response: %d\n", ret);
  81. ret = -EIO;
  82. goto done;
  83. }
  84. /* check response error code */
  85. msg->result = i2c_msg[1].buf[0];
  86. ret = cros_ec_check_result(ec_dev, msg);
  87. if (ret)
  88. goto done;
  89. len = in_buf[1];
  90. if (len > msg->insize) {
  91. dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)",
  92. len, msg->insize);
  93. ret = -ENOSPC;
  94. goto done;
  95. }
  96. /* copy response packet payload and compute checksum */
  97. sum = in_buf[0] + in_buf[1];
  98. for (i = 0; i < len; i++) {
  99. msg->indata[i] = in_buf[2 + i];
  100. sum += in_buf[2 + i];
  101. }
  102. dev_dbg(ec_dev->dev, "packet: %*ph, sum = %02x\n",
  103. i2c_msg[1].len, in_buf, sum);
  104. if (sum != in_buf[2 + len]) {
  105. dev_err(ec_dev->dev, "bad packet checksum\n");
  106. ret = -EBADMSG;
  107. goto done;
  108. }
  109. ret = len;
  110. done:
  111. kfree(in_buf);
  112. kfree(out_buf);
  113. return ret;
  114. }
  115. static int cros_ec_i2c_probe(struct i2c_client *client,
  116. const struct i2c_device_id *dev_id)
  117. {
  118. struct device *dev = &client->dev;
  119. struct cros_ec_device *ec_dev = NULL;
  120. int err;
  121. ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
  122. if (!ec_dev)
  123. return -ENOMEM;
  124. i2c_set_clientdata(client, ec_dev);
  125. ec_dev->dev = dev;
  126. ec_dev->priv = client;
  127. ec_dev->irq = client->irq;
  128. ec_dev->cmd_xfer = cros_ec_cmd_xfer_i2c;
  129. ec_dev->ec_name = client->name;
  130. ec_dev->phys_name = client->adapter->name;
  131. ec_dev->parent = &client->dev;
  132. err = cros_ec_register(ec_dev);
  133. if (err) {
  134. dev_err(dev, "cannot register EC\n");
  135. return err;
  136. }
  137. return 0;
  138. }
  139. static int cros_ec_i2c_remove(struct i2c_client *client)
  140. {
  141. struct cros_ec_device *ec_dev = i2c_get_clientdata(client);
  142. cros_ec_remove(ec_dev);
  143. return 0;
  144. }
  145. #ifdef CONFIG_PM_SLEEP
  146. static int cros_ec_i2c_suspend(struct device *dev)
  147. {
  148. struct cros_ec_device *ec_dev = to_ec_dev(dev);
  149. return cros_ec_suspend(ec_dev);
  150. }
  151. static int cros_ec_i2c_resume(struct device *dev)
  152. {
  153. struct cros_ec_device *ec_dev = to_ec_dev(dev);
  154. return cros_ec_resume(ec_dev);
  155. }
  156. #endif
  157. static SIMPLE_DEV_PM_OPS(cros_ec_i2c_pm_ops, cros_ec_i2c_suspend,
  158. cros_ec_i2c_resume);
  159. static const struct i2c_device_id cros_ec_i2c_id[] = {
  160. { "cros-ec-i2c", 0 },
  161. { }
  162. };
  163. MODULE_DEVICE_TABLE(i2c, cros_ec_i2c_id);
  164. static struct i2c_driver cros_ec_driver = {
  165. .driver = {
  166. .name = "cros-ec-i2c",
  167. .owner = THIS_MODULE,
  168. .pm = &cros_ec_i2c_pm_ops,
  169. },
  170. .probe = cros_ec_i2c_probe,
  171. .remove = cros_ec_i2c_remove,
  172. .id_table = cros_ec_i2c_id,
  173. };
  174. module_i2c_driver(cros_ec_driver);
  175. MODULE_LICENSE("GPL");
  176. MODULE_DESCRIPTION("ChromeOS EC multi function device");