chromeos_tbmc.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. // SPDX-License-Identifier: GPL-2.0+
  2. // Driver to detect Tablet Mode for ChromeOS convertible.
  3. //
  4. // Copyright (C) 2017 Google, Inc.
  5. // Author: Gwendal Grignou <gwendal@chromium.org>
  6. #include <linux/acpi.h>
  7. #include <linux/input.h>
  8. #include <linux/io.h>
  9. #include <linux/module.h>
  10. #include <linux/printk.h>
  11. #define DRV_NAME "chromeos_tbmc"
  12. #define ACPI_DRV_NAME "GOOG0006"
  13. static int chromeos_tbmc_query_switch(struct acpi_device *adev,
  14. struct input_dev *idev)
  15. {
  16. unsigned long long state;
  17. acpi_status status;
  18. status = acpi_evaluate_integer(adev->handle, "TBMC", NULL, &state);
  19. if (ACPI_FAILURE(status))
  20. return -ENODEV;
  21. /* input layer checks if event is redundant */
  22. input_report_switch(idev, SW_TABLET_MODE, state);
  23. input_sync(idev);
  24. return 0;
  25. }
  26. static __maybe_unused int chromeos_tbmc_resume(struct device *dev)
  27. {
  28. struct acpi_device *adev = to_acpi_device(dev);
  29. return chromeos_tbmc_query_switch(adev, adev->driver_data);
  30. }
  31. static void chromeos_tbmc_notify(struct acpi_device *adev, u32 event)
  32. {
  33. switch (event) {
  34. case 0x80:
  35. chromeos_tbmc_query_switch(adev, adev->driver_data);
  36. break;
  37. default:
  38. dev_err(&adev->dev, "Unexpected event: 0x%08X\n", event);
  39. }
  40. }
  41. static int chromeos_tbmc_open(struct input_dev *idev)
  42. {
  43. struct acpi_device *adev = input_get_drvdata(idev);
  44. return chromeos_tbmc_query_switch(adev, idev);
  45. }
  46. static int chromeos_tbmc_add(struct acpi_device *adev)
  47. {
  48. struct input_dev *idev;
  49. struct device *dev = &adev->dev;
  50. int ret;
  51. idev = devm_input_allocate_device(dev);
  52. if (!idev)
  53. return -ENOMEM;
  54. idev->name = "Tablet Mode Switch";
  55. idev->phys = acpi_device_hid(adev);
  56. idev->id.bustype = BUS_HOST;
  57. idev->id.version = 1;
  58. idev->id.product = 0;
  59. idev->open = chromeos_tbmc_open;
  60. input_set_drvdata(idev, adev);
  61. adev->driver_data = idev;
  62. input_set_capability(idev, EV_SW, SW_TABLET_MODE);
  63. ret = input_register_device(idev);
  64. if (ret) {
  65. dev_err(dev, "cannot register input device\n");
  66. return ret;
  67. }
  68. return 0;
  69. }
  70. static const struct acpi_device_id chromeos_tbmc_acpi_device_ids[] = {
  71. { ACPI_DRV_NAME, 0 },
  72. { }
  73. };
  74. MODULE_DEVICE_TABLE(acpi, chromeos_tbmc_acpi_device_ids);
  75. static const SIMPLE_DEV_PM_OPS(chromeos_tbmc_pm_ops, NULL,
  76. chromeos_tbmc_resume);
  77. static struct acpi_driver chromeos_tbmc_driver = {
  78. .name = DRV_NAME,
  79. .class = DRV_NAME,
  80. .ids = chromeos_tbmc_acpi_device_ids,
  81. .ops = {
  82. .add = chromeos_tbmc_add,
  83. .notify = chromeos_tbmc_notify,
  84. },
  85. .drv.pm = &chromeos_tbmc_pm_ops,
  86. };
  87. module_acpi_driver(chromeos_tbmc_driver);
  88. MODULE_LICENSE("GPL v2");
  89. MODULE_DESCRIPTION("ChromeOS ACPI tablet switch driver");