cros_ec_acpi_gpe.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /*
  2. * ChromeOS EC multi-function device
  3. *
  4. * Copyright (C) 2017 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/acpi.h>
  20. #define ACPI_LID_DEVICE "LID0"
  21. static int ec_wake_gpe = -EINVAL;
  22. /*
  23. * This handler indicates to ACPI core that this GPE should stay enabled for
  24. * lid to work in suspend to idle path.
  25. */
  26. static u32 cros_ec_gpe_handler(acpi_handle gpe_device, u32 gpe_number,
  27. void *data)
  28. {
  29. return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
  30. }
  31. /*
  32. * Get ACPI GPE for LID0 device.
  33. */
  34. static int cros_ec_get_ec_wake_gpe(struct device *dev)
  35. {
  36. struct acpi_device *cros_acpi_dev;
  37. struct acpi_device *adev;
  38. acpi_handle handle;
  39. acpi_status status;
  40. int ret;
  41. cros_acpi_dev = ACPI_COMPANION(dev);
  42. if (!cros_acpi_dev || !cros_acpi_dev->parent ||
  43. !cros_acpi_dev->parent->handle)
  44. return -EINVAL;
  45. status = acpi_get_handle(cros_acpi_dev->parent->handle, ACPI_LID_DEVICE,
  46. &handle);
  47. if (ACPI_FAILURE(status))
  48. return -EINVAL;
  49. ret = acpi_bus_get_device(handle, &adev);
  50. if (ret)
  51. return ret;
  52. return adev->wakeup.gpe_number;
  53. }
  54. int cros_ec_acpi_install_gpe_handler(struct device *dev)
  55. {
  56. acpi_status status;
  57. ec_wake_gpe = cros_ec_get_ec_wake_gpe(dev);
  58. if (ec_wake_gpe < 0)
  59. return ec_wake_gpe;
  60. status = acpi_install_gpe_handler(NULL, ec_wake_gpe,
  61. ACPI_GPE_EDGE_TRIGGERED,
  62. &cros_ec_gpe_handler, NULL);
  63. if (ACPI_FAILURE(status))
  64. return -ENODEV;
  65. dev_info(dev, "Initialized, GPE = 0x%x\n", ec_wake_gpe);
  66. return 0;
  67. }
  68. void cros_ec_acpi_remove_gpe_handler(void)
  69. {
  70. acpi_status status;
  71. if (ec_wake_gpe < 0)
  72. return;
  73. status = acpi_remove_gpe_handler(NULL, ec_wake_gpe,
  74. &cros_ec_gpe_handler);
  75. if (ACPI_FAILURE(status))
  76. pr_err("failed to remove gpe handler\n");
  77. }
  78. void cros_ec_acpi_clear_gpe(void)
  79. {
  80. if (ec_wake_gpe < 0)
  81. return;
  82. acpi_clear_gpe(NULL, ec_wake_gpe);
  83. }