cros_ec_i2c.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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_command_xfer(struct cros_ec_device *ec_dev,
  29. struct cros_ec_msg *msg)
  30. {
  31. struct i2c_client *client = ec_dev->priv;
  32. int ret = -ENOMEM;
  33. int i;
  34. int packet_len;
  35. u8 *out_buf = NULL;
  36. u8 *in_buf = NULL;
  37. u8 sum;
  38. struct i2c_msg i2c_msg[2];
  39. i2c_msg[0].addr = client->addr;
  40. i2c_msg[0].flags = 0;
  41. i2c_msg[1].addr = client->addr;
  42. i2c_msg[1].flags = I2C_M_RD;
  43. /*
  44. * allocate larger packet (one byte for checksum, one byte for
  45. * length, and one for result code)
  46. */
  47. packet_len = msg->in_len + 3;
  48. in_buf = kzalloc(packet_len, GFP_KERNEL);
  49. if (!in_buf)
  50. goto done;
  51. i2c_msg[1].len = packet_len;
  52. i2c_msg[1].buf = (char *)in_buf;
  53. /*
  54. * allocate larger packet (one byte for checksum, one for
  55. * command code, one for length, and one for command version)
  56. */
  57. packet_len = msg->out_len + 4;
  58. out_buf = kzalloc(packet_len, GFP_KERNEL);
  59. if (!out_buf)
  60. goto done;
  61. i2c_msg[0].len = packet_len;
  62. i2c_msg[0].buf = (char *)out_buf;
  63. out_buf[0] = EC_CMD_VERSION0 + msg->version;
  64. out_buf[1] = msg->cmd;
  65. out_buf[2] = msg->out_len;
  66. /* copy message payload and compute checksum */
  67. sum = out_buf[0] + out_buf[1] + out_buf[2];
  68. for (i = 0; i < msg->out_len; i++) {
  69. out_buf[3 + i] = msg->out_buf[i];
  70. sum += out_buf[3 + i];
  71. }
  72. out_buf[3 + msg->out_len] = sum;
  73. /* send command to EC and read answer */
  74. ret = i2c_transfer(client->adapter, i2c_msg, 2);
  75. if (ret < 0) {
  76. dev_err(ec_dev->dev, "i2c transfer failed: %d\n", ret);
  77. goto done;
  78. } else if (ret != 2) {
  79. dev_err(ec_dev->dev, "failed to get response: %d\n", ret);
  80. ret = -EIO;
  81. goto done;
  82. }
  83. /* check response error code */
  84. if (i2c_msg[1].buf[0]) {
  85. dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n",
  86. msg->cmd, i2c_msg[1].buf[0]);
  87. ret = -EINVAL;
  88. goto done;
  89. }
  90. /* copy response packet payload and compute checksum */
  91. sum = in_buf[0] + in_buf[1];
  92. for (i = 0; i < msg->in_len; i++) {
  93. msg->in_buf[i] = in_buf[2 + i];
  94. sum += in_buf[2 + i];
  95. }
  96. dev_dbg(ec_dev->dev, "packet: %*ph, sum = %02x\n",
  97. i2c_msg[1].len, in_buf, sum);
  98. if (sum != in_buf[2 + msg->in_len]) {
  99. dev_err(ec_dev->dev, "bad packet checksum\n");
  100. ret = -EBADMSG;
  101. goto done;
  102. }
  103. ret = 0;
  104. done:
  105. kfree(in_buf);
  106. kfree(out_buf);
  107. return ret;
  108. }
  109. static int cros_ec_probe_i2c(struct i2c_client *client,
  110. const struct i2c_device_id *dev_id)
  111. {
  112. struct device *dev = &client->dev;
  113. struct cros_ec_device *ec_dev = NULL;
  114. int err;
  115. ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
  116. if (!ec_dev)
  117. return -ENOMEM;
  118. i2c_set_clientdata(client, ec_dev);
  119. ec_dev->name = "I2C";
  120. ec_dev->dev = dev;
  121. ec_dev->priv = client;
  122. ec_dev->irq = client->irq;
  123. ec_dev->command_xfer = cros_ec_command_xfer;
  124. ec_dev->ec_name = client->name;
  125. ec_dev->phys_name = client->adapter->name;
  126. ec_dev->parent = &client->dev;
  127. err = cros_ec_register(ec_dev);
  128. if (err) {
  129. dev_err(dev, "cannot register EC\n");
  130. return err;
  131. }
  132. return 0;
  133. }
  134. static int cros_ec_remove_i2c(struct i2c_client *client)
  135. {
  136. struct cros_ec_device *ec_dev = i2c_get_clientdata(client);
  137. cros_ec_remove(ec_dev);
  138. return 0;
  139. }
  140. #ifdef CONFIG_PM_SLEEP
  141. static int cros_ec_i2c_suspend(struct device *dev)
  142. {
  143. struct cros_ec_device *ec_dev = to_ec_dev(dev);
  144. return cros_ec_suspend(ec_dev);
  145. }
  146. static int cros_ec_i2c_resume(struct device *dev)
  147. {
  148. struct cros_ec_device *ec_dev = to_ec_dev(dev);
  149. return cros_ec_resume(ec_dev);
  150. }
  151. #endif
  152. static SIMPLE_DEV_PM_OPS(cros_ec_i2c_pm_ops, cros_ec_i2c_suspend,
  153. cros_ec_i2c_resume);
  154. static const struct i2c_device_id cros_ec_i2c_id[] = {
  155. { "cros-ec-i2c", 0 },
  156. { }
  157. };
  158. MODULE_DEVICE_TABLE(i2c, cros_ec_i2c_id);
  159. static struct i2c_driver cros_ec_driver = {
  160. .driver = {
  161. .name = "cros-ec-i2c",
  162. .owner = THIS_MODULE,
  163. .pm = &cros_ec_i2c_pm_ops,
  164. },
  165. .probe = cros_ec_probe_i2c,
  166. .remove = cros_ec_remove_i2c,
  167. .id_table = cros_ec_i2c_id,
  168. };
  169. module_i2c_driver(cros_ec_driver);
  170. MODULE_LICENSE("GPL");
  171. MODULE_DESCRIPTION("ChromeOS EC multi function device");