gigabyte-wmi.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2021 Thomas Weißschuh <linux@weissschuh.net>
  4. */
  5. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  6. #include <linux/acpi.h>
  7. #include <linux/hwmon.h>
  8. #include <linux/module.h>
  9. #include <linux/wmi.h>
  10. #define GIGABYTE_WMI_GUID "DEADBEEF-2001-0000-00A0-C90629100000"
  11. #define NUM_TEMPERATURE_SENSORS 6
  12. static u8 usable_sensors_mask;
  13. enum gigabyte_wmi_commandtype {
  14. GIGABYTE_WMI_BUILD_DATE_QUERY = 0x1,
  15. GIGABYTE_WMI_MAINBOARD_TYPE_QUERY = 0x2,
  16. GIGABYTE_WMI_FIRMWARE_VERSION_QUERY = 0x4,
  17. GIGABYTE_WMI_MAINBOARD_NAME_QUERY = 0x5,
  18. GIGABYTE_WMI_TEMPERATURE_QUERY = 0x125,
  19. };
  20. struct gigabyte_wmi_args {
  21. u32 arg1;
  22. };
  23. static int gigabyte_wmi_perform_query(struct wmi_device *wdev,
  24. enum gigabyte_wmi_commandtype command,
  25. struct gigabyte_wmi_args *args, struct acpi_buffer *out)
  26. {
  27. const struct acpi_buffer in = {
  28. .length = sizeof(*args),
  29. .pointer = args,
  30. };
  31. acpi_status ret = wmidev_evaluate_method(wdev, 0x0, command, &in, out);
  32. if (ACPI_FAILURE(ret))
  33. return -EIO;
  34. return 0;
  35. }
  36. static int gigabyte_wmi_query_integer(struct wmi_device *wdev,
  37. enum gigabyte_wmi_commandtype command,
  38. struct gigabyte_wmi_args *args, u64 *res)
  39. {
  40. union acpi_object *obj;
  41. struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
  42. int ret;
  43. ret = gigabyte_wmi_perform_query(wdev, command, args, &result);
  44. if (ret)
  45. return ret;
  46. obj = result.pointer;
  47. if (obj && obj->type == ACPI_TYPE_INTEGER)
  48. *res = obj->integer.value;
  49. else
  50. ret = -EIO;
  51. kfree(result.pointer);
  52. return ret;
  53. }
  54. static int gigabyte_wmi_temperature(struct wmi_device *wdev, u8 sensor, long *res)
  55. {
  56. struct gigabyte_wmi_args args = {
  57. .arg1 = sensor,
  58. };
  59. u64 temp;
  60. acpi_status ret;
  61. ret = gigabyte_wmi_query_integer(wdev, GIGABYTE_WMI_TEMPERATURE_QUERY, &args, &temp);
  62. if (ret == 0) {
  63. if (temp == 0)
  64. return -ENODEV;
  65. *res = (s8)temp * 1000; // value is a signed 8-bit integer
  66. }
  67. return ret;
  68. }
  69. static int gigabyte_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
  70. u32 attr, int channel, long *val)
  71. {
  72. struct wmi_device *wdev = dev_get_drvdata(dev);
  73. return gigabyte_wmi_temperature(wdev, channel, val);
  74. }
  75. static umode_t gigabyte_wmi_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
  76. u32 attr, int channel)
  77. {
  78. return usable_sensors_mask & BIT(channel) ? 0444 : 0;
  79. }
  80. static const struct hwmon_channel_info * const gigabyte_wmi_hwmon_info[] = {
  81. HWMON_CHANNEL_INFO(temp,
  82. HWMON_T_INPUT,
  83. HWMON_T_INPUT,
  84. HWMON_T_INPUT,
  85. HWMON_T_INPUT,
  86. HWMON_T_INPUT,
  87. HWMON_T_INPUT),
  88. NULL
  89. };
  90. static const struct hwmon_ops gigabyte_wmi_hwmon_ops = {
  91. .read = gigabyte_wmi_hwmon_read,
  92. .is_visible = gigabyte_wmi_hwmon_is_visible,
  93. };
  94. static const struct hwmon_chip_info gigabyte_wmi_hwmon_chip_info = {
  95. .ops = &gigabyte_wmi_hwmon_ops,
  96. .info = gigabyte_wmi_hwmon_info,
  97. };
  98. static u8 gigabyte_wmi_detect_sensor_usability(struct wmi_device *wdev)
  99. {
  100. int i;
  101. long temp;
  102. u8 r = 0;
  103. for (i = 0; i < NUM_TEMPERATURE_SENSORS; i++) {
  104. if (!gigabyte_wmi_temperature(wdev, i, &temp))
  105. r |= BIT(i);
  106. }
  107. return r;
  108. }
  109. static int gigabyte_wmi_probe(struct wmi_device *wdev, const void *context)
  110. {
  111. struct device *hwmon_dev;
  112. usable_sensors_mask = gigabyte_wmi_detect_sensor_usability(wdev);
  113. if (!usable_sensors_mask) {
  114. dev_info(&wdev->dev, "No temperature sensors usable");
  115. return -ENODEV;
  116. }
  117. hwmon_dev = devm_hwmon_device_register_with_info(&wdev->dev, "gigabyte_wmi", wdev,
  118. &gigabyte_wmi_hwmon_chip_info, NULL);
  119. return PTR_ERR_OR_ZERO(hwmon_dev);
  120. }
  121. static const struct wmi_device_id gigabyte_wmi_id_table[] = {
  122. { GIGABYTE_WMI_GUID, NULL },
  123. { }
  124. };
  125. static struct wmi_driver gigabyte_wmi_driver = {
  126. .driver = {
  127. .name = "gigabyte-wmi",
  128. },
  129. .id_table = gigabyte_wmi_id_table,
  130. .probe = gigabyte_wmi_probe,
  131. };
  132. module_wmi_driver(gigabyte_wmi_driver);
  133. MODULE_DEVICE_TABLE(wmi, gigabyte_wmi_id_table);
  134. MODULE_AUTHOR("Thomas Weißschuh <linux@weissschuh.net>");
  135. MODULE_DESCRIPTION("Gigabyte WMI temperature driver");
  136. MODULE_LICENSE("GPL");