cros_hps_i2c.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Driver for the ChromeOS human presence sensor (HPS), attached via I2C.
  4. *
  5. * The driver exposes HPS as a character device, although currently no read or
  6. * write operations are supported. Instead, the driver only controls the power
  7. * state of the sensor, keeping it on only while userspace holds an open file
  8. * descriptor to the HPS device.
  9. *
  10. * Copyright 2022 Google LLC.
  11. */
  12. #include <linux/acpi.h>
  13. #include <linux/fs.h>
  14. #include <linux/gpio/consumer.h>
  15. #include <linux/i2c.h>
  16. #include <linux/miscdevice.h>
  17. #include <linux/module.h>
  18. #include <linux/pm_runtime.h>
  19. #define HPS_ACPI_ID "GOOG0020"
  20. struct hps_drvdata {
  21. struct i2c_client *client;
  22. struct miscdevice misc_device;
  23. struct gpio_desc *enable_gpio;
  24. };
  25. static void hps_set_power(struct hps_drvdata *hps, bool state)
  26. {
  27. gpiod_set_value_cansleep(hps->enable_gpio, state);
  28. }
  29. static int hps_open(struct inode *inode, struct file *file)
  30. {
  31. struct hps_drvdata *hps = container_of(file->private_data,
  32. struct hps_drvdata, misc_device);
  33. struct device *dev = &hps->client->dev;
  34. return pm_runtime_resume_and_get(dev);
  35. }
  36. static int hps_release(struct inode *inode, struct file *file)
  37. {
  38. struct hps_drvdata *hps = container_of(file->private_data,
  39. struct hps_drvdata, misc_device);
  40. struct device *dev = &hps->client->dev;
  41. return pm_runtime_put(dev);
  42. }
  43. static const struct file_operations hps_fops = {
  44. .owner = THIS_MODULE,
  45. .open = hps_open,
  46. .release = hps_release,
  47. };
  48. static int hps_i2c_probe(struct i2c_client *client)
  49. {
  50. struct hps_drvdata *hps;
  51. int ret;
  52. hps = devm_kzalloc(&client->dev, sizeof(*hps), GFP_KERNEL);
  53. if (!hps)
  54. return -ENOMEM;
  55. hps->misc_device.parent = &client->dev;
  56. hps->misc_device.minor = MISC_DYNAMIC_MINOR;
  57. hps->misc_device.name = "cros-hps";
  58. hps->misc_device.fops = &hps_fops;
  59. i2c_set_clientdata(client, hps);
  60. hps->client = client;
  61. /*
  62. * HPS is powered on from firmware before entering the kernel, so we
  63. * acquire the line with GPIOD_OUT_HIGH here to preserve the existing
  64. * state. The peripheral is powered off after successful probe below.
  65. */
  66. hps->enable_gpio = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_HIGH);
  67. if (IS_ERR(hps->enable_gpio)) {
  68. ret = PTR_ERR(hps->enable_gpio);
  69. dev_err(&client->dev, "failed to get enable gpio: %d\n", ret);
  70. return ret;
  71. }
  72. ret = misc_register(&hps->misc_device);
  73. if (ret) {
  74. dev_err(&client->dev, "failed to initialize misc device: %d\n", ret);
  75. return ret;
  76. }
  77. hps_set_power(hps, false);
  78. pm_runtime_enable(&client->dev);
  79. return 0;
  80. }
  81. static void hps_i2c_remove(struct i2c_client *client)
  82. {
  83. struct hps_drvdata *hps = i2c_get_clientdata(client);
  84. pm_runtime_disable(&client->dev);
  85. misc_deregister(&hps->misc_device);
  86. /*
  87. * Re-enable HPS, in order to return it to its default state
  88. * (i.e. powered on).
  89. */
  90. hps_set_power(hps, true);
  91. }
  92. static int hps_suspend(struct device *dev)
  93. {
  94. struct i2c_client *client = to_i2c_client(dev);
  95. struct hps_drvdata *hps = i2c_get_clientdata(client);
  96. hps_set_power(hps, false);
  97. return 0;
  98. }
  99. static int hps_resume(struct device *dev)
  100. {
  101. struct i2c_client *client = to_i2c_client(dev);
  102. struct hps_drvdata *hps = i2c_get_clientdata(client);
  103. hps_set_power(hps, true);
  104. return 0;
  105. }
  106. static DEFINE_RUNTIME_DEV_PM_OPS(hps_pm_ops, hps_suspend, hps_resume, NULL);
  107. static const struct i2c_device_id hps_i2c_id[] = {
  108. { "cros-hps", 0 },
  109. { }
  110. };
  111. MODULE_DEVICE_TABLE(i2c, hps_i2c_id);
  112. #ifdef CONFIG_ACPI
  113. static const struct acpi_device_id hps_acpi_id[] = {
  114. { HPS_ACPI_ID, 0 },
  115. { }
  116. };
  117. MODULE_DEVICE_TABLE(acpi, hps_acpi_id);
  118. #endif /* CONFIG_ACPI */
  119. static struct i2c_driver hps_i2c_driver = {
  120. .probe = hps_i2c_probe,
  121. .remove = hps_i2c_remove,
  122. .id_table = hps_i2c_id,
  123. .driver = {
  124. .name = "cros-hps",
  125. .pm = pm_ptr(&hps_pm_ops),
  126. .acpi_match_table = ACPI_PTR(hps_acpi_id),
  127. },
  128. };
  129. module_i2c_driver(hps_i2c_driver);
  130. MODULE_ALIAS("acpi:" HPS_ACPI_ID);
  131. MODULE_AUTHOR("Sami Kyöstilä <skyostil@chromium.org>");
  132. MODULE_DESCRIPTION("Driver for ChromeOS HPS");
  133. MODULE_LICENSE("GPL");