cros_ec_sensorhub.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Sensor HUB driver that discovers sensors behind a ChromeOS Embedded
  4. * Controller.
  5. *
  6. * Copyright 2019 Google LLC
  7. */
  8. #include <linux/init.h>
  9. #include <linux/device.h>
  10. #include <linux/delay.h>
  11. #include <linux/mod_devicetable.h>
  12. #include <linux/module.h>
  13. #include <linux/platform_data/cros_ec_commands.h>
  14. #include <linux/platform_data/cros_ec_proto.h>
  15. #include <linux/platform_data/cros_ec_sensorhub.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/slab.h>
  18. #include <linux/types.h>
  19. #define DRV_NAME "cros-ec-sensorhub"
  20. #define CROS_EC_CMD_INFO_RETRIES 50
  21. static void cros_ec_sensorhub_free_sensor(void *arg)
  22. {
  23. struct platform_device *pdev = arg;
  24. platform_device_unregister(pdev);
  25. }
  26. static int cros_ec_sensorhub_allocate_sensor(struct device *parent,
  27. char *sensor_name,
  28. int sensor_num)
  29. {
  30. struct cros_ec_sensor_platform sensor_platforms = {
  31. .sensor_num = sensor_num,
  32. };
  33. struct platform_device *pdev;
  34. pdev = platform_device_register_data(parent, sensor_name,
  35. PLATFORM_DEVID_AUTO,
  36. &sensor_platforms,
  37. sizeof(sensor_platforms));
  38. if (IS_ERR(pdev))
  39. return PTR_ERR(pdev);
  40. return devm_add_action_or_reset(parent,
  41. cros_ec_sensorhub_free_sensor,
  42. pdev);
  43. }
  44. static int cros_ec_sensorhub_register(struct device *dev,
  45. struct cros_ec_sensorhub *sensorhub)
  46. {
  47. int sensor_type[MOTIONSENSE_TYPE_MAX] = { 0 };
  48. struct cros_ec_command *msg = sensorhub->msg;
  49. struct cros_ec_dev *ec = sensorhub->ec;
  50. int ret, i, retries;
  51. char *name;
  52. msg->version = 1;
  53. msg->insize = sizeof(struct ec_response_motion_sense);
  54. msg->outsize = sizeof(struct ec_params_motion_sense);
  55. for (i = 0; i < sensorhub->sensor_num; i++) {
  56. sensorhub->params->cmd = MOTIONSENSE_CMD_INFO;
  57. sensorhub->params->info.sensor_num = i;
  58. retries = CROS_EC_CMD_INFO_RETRIES;
  59. do {
  60. ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
  61. if (ret == -EBUSY) {
  62. /* The EC is still busy initializing sensors. */
  63. usleep_range(5000, 6000);
  64. retries--;
  65. }
  66. } while (ret == -EBUSY && retries);
  67. if (ret < 0) {
  68. dev_err(dev, "no info for EC sensor %d : %d/%d\n",
  69. i, ret, msg->result);
  70. continue;
  71. }
  72. if (retries < CROS_EC_CMD_INFO_RETRIES) {
  73. dev_warn(dev, "%d retries needed to bring up sensor %d\n",
  74. CROS_EC_CMD_INFO_RETRIES - retries, i);
  75. }
  76. switch (sensorhub->resp->info.type) {
  77. case MOTIONSENSE_TYPE_ACCEL:
  78. name = "cros-ec-accel";
  79. break;
  80. case MOTIONSENSE_TYPE_BARO:
  81. name = "cros-ec-baro";
  82. break;
  83. case MOTIONSENSE_TYPE_GYRO:
  84. name = "cros-ec-gyro";
  85. break;
  86. case MOTIONSENSE_TYPE_MAG:
  87. name = "cros-ec-mag";
  88. break;
  89. case MOTIONSENSE_TYPE_PROX:
  90. name = "cros-ec-prox";
  91. break;
  92. case MOTIONSENSE_TYPE_LIGHT:
  93. name = "cros-ec-light";
  94. break;
  95. case MOTIONSENSE_TYPE_ACTIVITY:
  96. name = "cros-ec-activity";
  97. break;
  98. default:
  99. dev_warn(dev, "unknown type %d\n",
  100. sensorhub->resp->info.type);
  101. continue;
  102. }
  103. ret = cros_ec_sensorhub_allocate_sensor(dev, name, i);
  104. if (ret)
  105. return ret;
  106. sensor_type[sensorhub->resp->info.type]++;
  107. }
  108. if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2)
  109. ec->has_kb_wake_angle = true;
  110. if (cros_ec_check_features(ec,
  111. EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS)) {
  112. ret = cros_ec_sensorhub_allocate_sensor(dev,
  113. "cros-ec-lid-angle",
  114. 0);
  115. if (ret)
  116. return ret;
  117. }
  118. return 0;
  119. }
  120. static int cros_ec_sensorhub_probe(struct platform_device *pdev)
  121. {
  122. struct device *dev = &pdev->dev;
  123. struct cros_ec_dev *ec = dev_get_drvdata(dev->parent);
  124. struct cros_ec_sensorhub *data;
  125. struct cros_ec_command *msg;
  126. int ret, i, sensor_num;
  127. msg = devm_kzalloc(dev, sizeof(struct cros_ec_command) +
  128. max((u16)sizeof(struct ec_params_motion_sense),
  129. ec->ec_dev->max_response), GFP_KERNEL);
  130. if (!msg)
  131. return -ENOMEM;
  132. msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;
  133. data = devm_kzalloc(dev, sizeof(struct cros_ec_sensorhub), GFP_KERNEL);
  134. if (!data)
  135. return -ENOMEM;
  136. mutex_init(&data->cmd_lock);
  137. data->dev = dev;
  138. data->ec = ec;
  139. data->msg = msg;
  140. data->params = (struct ec_params_motion_sense *)msg->data;
  141. data->resp = (struct ec_response_motion_sense *)msg->data;
  142. dev_set_drvdata(dev, data);
  143. /* Check whether this EC is a sensor hub. */
  144. if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE)) {
  145. sensor_num = cros_ec_get_sensor_count(ec);
  146. if (sensor_num < 0) {
  147. dev_err(dev,
  148. "Unable to retrieve sensor information (err:%d)\n",
  149. sensor_num);
  150. return sensor_num;
  151. }
  152. if (sensor_num == 0) {
  153. dev_err(dev, "Zero sensors reported.\n");
  154. return -EINVAL;
  155. }
  156. data->sensor_num = sensor_num;
  157. /*
  158. * Prepare the ring handler before enumering the
  159. * sensors.
  160. */
  161. if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) {
  162. ret = cros_ec_sensorhub_ring_allocate(data);
  163. if (ret)
  164. return ret;
  165. }
  166. /* Enumerate the sensors.*/
  167. ret = cros_ec_sensorhub_register(dev, data);
  168. if (ret)
  169. return ret;
  170. /*
  171. * When the EC does not have a FIFO, the sensors will query
  172. * their data themselves via sysfs or a software trigger.
  173. */
  174. if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) {
  175. ret = cros_ec_sensorhub_ring_add(data);
  176. if (ret)
  177. return ret;
  178. /*
  179. * The msg and its data is not under the control of the
  180. * ring handler.
  181. */
  182. return devm_add_action_or_reset(dev,
  183. cros_ec_sensorhub_ring_remove,
  184. data);
  185. }
  186. } else {
  187. /*
  188. * If the device has sensors but does not claim to
  189. * be a sensor hub, we are in legacy mode.
  190. */
  191. data->sensor_num = 2;
  192. for (i = 0; i < data->sensor_num; i++) {
  193. ret = cros_ec_sensorhub_allocate_sensor(dev,
  194. "cros-ec-accel-legacy", i);
  195. if (ret)
  196. return ret;
  197. }
  198. }
  199. return 0;
  200. }
  201. #ifdef CONFIG_PM_SLEEP
  202. /*
  203. * When the EC is suspending, we must stop sending interrupt,
  204. * we may use the same interrupt line for waking up the device.
  205. * Tell the EC to stop sending non-interrupt event on the iio ring.
  206. */
  207. static int cros_ec_sensorhub_suspend(struct device *dev)
  208. {
  209. struct cros_ec_sensorhub *sensorhub = dev_get_drvdata(dev);
  210. struct cros_ec_dev *ec = sensorhub->ec;
  211. if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO))
  212. return cros_ec_sensorhub_ring_fifo_enable(sensorhub, false);
  213. return 0;
  214. }
  215. static int cros_ec_sensorhub_resume(struct device *dev)
  216. {
  217. struct cros_ec_sensorhub *sensorhub = dev_get_drvdata(dev);
  218. struct cros_ec_dev *ec = sensorhub->ec;
  219. if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO))
  220. return cros_ec_sensorhub_ring_fifo_enable(sensorhub, true);
  221. return 0;
  222. }
  223. #endif
  224. static SIMPLE_DEV_PM_OPS(cros_ec_sensorhub_pm_ops,
  225. cros_ec_sensorhub_suspend,
  226. cros_ec_sensorhub_resume);
  227. static const struct platform_device_id cros_ec_sensorhub_id[] = {
  228. { DRV_NAME, 0 },
  229. {}
  230. };
  231. MODULE_DEVICE_TABLE(platform, cros_ec_sensorhub_id);
  232. static struct platform_driver cros_ec_sensorhub_driver = {
  233. .driver = {
  234. .name = DRV_NAME,
  235. .pm = &cros_ec_sensorhub_pm_ops,
  236. },
  237. .probe = cros_ec_sensorhub_probe,
  238. .id_table = cros_ec_sensorhub_id,
  239. };
  240. module_platform_driver(cros_ec_sensorhub_driver);
  241. MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>");
  242. MODULE_DESCRIPTION("ChromeOS EC MEMS Sensor Hub Driver");
  243. MODULE_LICENSE("GPL");