cros_ec.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. * ChromeOS EC multi-function device
  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. * The ChromeOS EC multi function device is used to mux all the requests
  16. * to the EC device for its multiple features: keyboard controller,
  17. * battery charging and regulator control, firmware update.
  18. */
  19. #include <linux/interrupt.h>
  20. #include <linux/slab.h>
  21. #include <linux/module.h>
  22. #include <linux/mfd/core.h>
  23. #include <linux/mfd/cros_ec.h>
  24. #include <linux/mfd/cros_ec_commands.h>
  25. #include <linux/delay.h>
  26. #define EC_COMMAND_RETRIES 50
  27. int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
  28. struct cros_ec_command *msg)
  29. {
  30. uint8_t *out;
  31. int csum, i;
  32. BUG_ON(msg->outsize > EC_PROTO2_MAX_PARAM_SIZE);
  33. out = ec_dev->dout;
  34. out[0] = EC_CMD_VERSION0 + msg->version;
  35. out[1] = msg->command;
  36. out[2] = msg->outsize;
  37. csum = out[0] + out[1] + out[2];
  38. for (i = 0; i < msg->outsize; i++)
  39. csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->outdata[i];
  40. out[EC_MSG_TX_HEADER_BYTES + msg->outsize] = (uint8_t)(csum & 0xff);
  41. return EC_MSG_TX_PROTO_BYTES + msg->outsize;
  42. }
  43. EXPORT_SYMBOL(cros_ec_prepare_tx);
  44. int cros_ec_check_result(struct cros_ec_device *ec_dev,
  45. struct cros_ec_command *msg)
  46. {
  47. switch (msg->result) {
  48. case EC_RES_SUCCESS:
  49. return 0;
  50. case EC_RES_IN_PROGRESS:
  51. dev_dbg(ec_dev->dev, "command 0x%02x in progress\n",
  52. msg->command);
  53. return -EAGAIN;
  54. default:
  55. dev_dbg(ec_dev->dev, "command 0x%02x returned %d\n",
  56. msg->command, msg->result);
  57. return 0;
  58. }
  59. }
  60. EXPORT_SYMBOL(cros_ec_check_result);
  61. int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
  62. struct cros_ec_command *msg)
  63. {
  64. int ret;
  65. mutex_lock(&ec_dev->lock);
  66. ret = ec_dev->cmd_xfer(ec_dev, msg);
  67. if (msg->result == EC_RES_IN_PROGRESS) {
  68. int i;
  69. struct cros_ec_command status_msg;
  70. struct ec_response_get_comms_status status;
  71. status_msg.version = 0;
  72. status_msg.command = EC_CMD_GET_COMMS_STATUS;
  73. status_msg.outdata = NULL;
  74. status_msg.outsize = 0;
  75. status_msg.indata = (uint8_t *)&status;
  76. status_msg.insize = sizeof(status);
  77. /*
  78. * Query the EC's status until it's no longer busy or
  79. * we encounter an error.
  80. */
  81. for (i = 0; i < EC_COMMAND_RETRIES; i++) {
  82. usleep_range(10000, 11000);
  83. ret = ec_dev->cmd_xfer(ec_dev, &status_msg);
  84. if (ret < 0)
  85. break;
  86. msg->result = status_msg.result;
  87. if (status_msg.result != EC_RES_SUCCESS)
  88. break;
  89. if (!(status.flags & EC_COMMS_STATUS_PROCESSING))
  90. break;
  91. }
  92. }
  93. mutex_unlock(&ec_dev->lock);
  94. return ret;
  95. }
  96. EXPORT_SYMBOL(cros_ec_cmd_xfer);
  97. static const struct mfd_cell cros_devs[] = {
  98. {
  99. .name = "cros-ec-keyb",
  100. .id = 1,
  101. .of_compatible = "google,cros-ec-keyb",
  102. },
  103. {
  104. .name = "cros-ec-i2c-tunnel",
  105. .id = 2,
  106. .of_compatible = "google,cros-ec-i2c-tunnel",
  107. },
  108. };
  109. int cros_ec_register(struct cros_ec_device *ec_dev)
  110. {
  111. struct device *dev = ec_dev->dev;
  112. int err = 0;
  113. if (ec_dev->din_size) {
  114. ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL);
  115. if (!ec_dev->din)
  116. return -ENOMEM;
  117. }
  118. if (ec_dev->dout_size) {
  119. ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL);
  120. if (!ec_dev->dout)
  121. return -ENOMEM;
  122. }
  123. mutex_init(&ec_dev->lock);
  124. err = mfd_add_devices(dev, 0, cros_devs,
  125. ARRAY_SIZE(cros_devs),
  126. NULL, ec_dev->irq, NULL);
  127. if (err) {
  128. dev_err(dev, "failed to add mfd devices\n");
  129. return err;
  130. }
  131. dev_info(dev, "Chrome EC device registered\n");
  132. return 0;
  133. }
  134. EXPORT_SYMBOL(cros_ec_register);
  135. int cros_ec_remove(struct cros_ec_device *ec_dev)
  136. {
  137. mfd_remove_devices(ec_dev->dev);
  138. return 0;
  139. }
  140. EXPORT_SYMBOL(cros_ec_remove);
  141. #ifdef CONFIG_PM_SLEEP
  142. int cros_ec_suspend(struct cros_ec_device *ec_dev)
  143. {
  144. struct device *dev = ec_dev->dev;
  145. if (device_may_wakeup(dev))
  146. ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq);
  147. disable_irq(ec_dev->irq);
  148. ec_dev->was_wake_device = ec_dev->wake_enabled;
  149. return 0;
  150. }
  151. EXPORT_SYMBOL(cros_ec_suspend);
  152. int cros_ec_resume(struct cros_ec_device *ec_dev)
  153. {
  154. enable_irq(ec_dev->irq);
  155. if (ec_dev->wake_enabled) {
  156. disable_irq_wake(ec_dev->irq);
  157. ec_dev->wake_enabled = 0;
  158. }
  159. return 0;
  160. }
  161. EXPORT_SYMBOL(cros_ec_resume);
  162. #endif
  163. MODULE_LICENSE("GPL");
  164. MODULE_DESCRIPTION("ChromeOS EC core driver");