gigabyte-wmi.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2021 Thomas Weißschuh <[email protected]>
  4. */
  5. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  6. #include <linux/acpi.h>
  7. #include <linux/dmi.h>
  8. #include <linux/hwmon.h>
  9. #include <linux/module.h>
  10. #include <linux/wmi.h>
  11. #define GIGABYTE_WMI_GUID "DEADBEEF-2001-0000-00A0-C90629100000"
  12. #define NUM_TEMPERATURE_SENSORS 6
  13. static bool force_load;
  14. module_param(force_load, bool, 0444);
  15. MODULE_PARM_DESC(force_load, "Force loading on unknown platform");
  16. static u8 usable_sensors_mask;
  17. enum gigabyte_wmi_commandtype {
  18. GIGABYTE_WMI_BUILD_DATE_QUERY = 0x1,
  19. GIGABYTE_WMI_MAINBOARD_TYPE_QUERY = 0x2,
  20. GIGABYTE_WMI_FIRMWARE_VERSION_QUERY = 0x4,
  21. GIGABYTE_WMI_MAINBOARD_NAME_QUERY = 0x5,
  22. GIGABYTE_WMI_TEMPERATURE_QUERY = 0x125,
  23. };
  24. struct gigabyte_wmi_args {
  25. u32 arg1;
  26. };
  27. static int gigabyte_wmi_perform_query(struct wmi_device *wdev,
  28. enum gigabyte_wmi_commandtype command,
  29. struct gigabyte_wmi_args *args, struct acpi_buffer *out)
  30. {
  31. const struct acpi_buffer in = {
  32. .length = sizeof(*args),
  33. .pointer = args,
  34. };
  35. acpi_status ret = wmidev_evaluate_method(wdev, 0x0, command, &in, out);
  36. if (ACPI_FAILURE(ret))
  37. return -EIO;
  38. return 0;
  39. }
  40. static int gigabyte_wmi_query_integer(struct wmi_device *wdev,
  41. enum gigabyte_wmi_commandtype command,
  42. struct gigabyte_wmi_args *args, u64 *res)
  43. {
  44. union acpi_object *obj;
  45. struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
  46. int ret;
  47. ret = gigabyte_wmi_perform_query(wdev, command, args, &result);
  48. if (ret)
  49. return ret;
  50. obj = result.pointer;
  51. if (obj && obj->type == ACPI_TYPE_INTEGER)
  52. *res = obj->integer.value;
  53. else
  54. ret = -EIO;
  55. kfree(result.pointer);
  56. return ret;
  57. }
  58. static int gigabyte_wmi_temperature(struct wmi_device *wdev, u8 sensor, long *res)
  59. {
  60. struct gigabyte_wmi_args args = {
  61. .arg1 = sensor,
  62. };
  63. u64 temp;
  64. acpi_status ret;
  65. ret = gigabyte_wmi_query_integer(wdev, GIGABYTE_WMI_TEMPERATURE_QUERY, &args, &temp);
  66. if (ret == 0) {
  67. if (temp == 0)
  68. return -ENODEV;
  69. *res = (s8)temp * 1000; // value is a signed 8-bit integer
  70. }
  71. return ret;
  72. }
  73. static int gigabyte_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
  74. u32 attr, int channel, long *val)
  75. {
  76. struct wmi_device *wdev = dev_get_drvdata(dev);
  77. return gigabyte_wmi_temperature(wdev, channel, val);
  78. }
  79. static umode_t gigabyte_wmi_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
  80. u32 attr, int channel)
  81. {
  82. return usable_sensors_mask & BIT(channel) ? 0444 : 0;
  83. }
  84. static const struct hwmon_channel_info *gigabyte_wmi_hwmon_info[] = {
  85. HWMON_CHANNEL_INFO(temp,
  86. HWMON_T_INPUT,
  87. HWMON_T_INPUT,
  88. HWMON_T_INPUT,
  89. HWMON_T_INPUT,
  90. HWMON_T_INPUT,
  91. HWMON_T_INPUT),
  92. NULL
  93. };
  94. static const struct hwmon_ops gigabyte_wmi_hwmon_ops = {
  95. .read = gigabyte_wmi_hwmon_read,
  96. .is_visible = gigabyte_wmi_hwmon_is_visible,
  97. };
  98. static const struct hwmon_chip_info gigabyte_wmi_hwmon_chip_info = {
  99. .ops = &gigabyte_wmi_hwmon_ops,
  100. .info = gigabyte_wmi_hwmon_info,
  101. };
  102. static u8 gigabyte_wmi_detect_sensor_usability(struct wmi_device *wdev)
  103. {
  104. int i;
  105. long temp;
  106. u8 r = 0;
  107. for (i = 0; i < NUM_TEMPERATURE_SENSORS; i++) {
  108. if (!gigabyte_wmi_temperature(wdev, i, &temp))
  109. r |= BIT(i);
  110. }
  111. return r;
  112. }
  113. #define DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME(name) \
  114. { .matches = { \
  115. DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."), \
  116. DMI_EXACT_MATCH(DMI_BOARD_NAME, name), \
  117. }}
  118. static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = {
  119. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("A320M-S2H V2-CF"),
  120. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M DS3H-CF"),
  121. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M DS3H WIFI-CF"),
  122. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M S2H V2"),
  123. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE AX V2"),
  124. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE"),
  125. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE V2"),
  126. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 GAMING X V2"),
  127. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550I AORUS PRO AX"),
  128. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M AORUS PRO-P"),
  129. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M DS3H"),
  130. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B650 AORUS ELITE AX"),
  131. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B660 GAMING X DDR4"),
  132. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B660I AORUS PRO DDR4"),
  133. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z390 I AORUS PRO WIFI-CF"),
  134. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z490 AORUS ELITE AC"),
  135. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 AORUS ELITE"),
  136. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 AORUS ELITE WIFI"),
  137. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 GAMING X"),
  138. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 I AORUS PRO WIFI"),
  139. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 UD"),
  140. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570S AORUS ELITE"),
  141. DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z690M AORUS ELITE AX DDR4"),
  142. { }
  143. };
  144. static int gigabyte_wmi_probe(struct wmi_device *wdev, const void *context)
  145. {
  146. struct device *hwmon_dev;
  147. if (!dmi_check_system(gigabyte_wmi_known_working_platforms)) {
  148. if (!force_load)
  149. return -ENODEV;
  150. dev_warn(&wdev->dev, "Forcing load on unknown platform");
  151. }
  152. usable_sensors_mask = gigabyte_wmi_detect_sensor_usability(wdev);
  153. if (!usable_sensors_mask) {
  154. dev_info(&wdev->dev, "No temperature sensors usable");
  155. return -ENODEV;
  156. }
  157. hwmon_dev = devm_hwmon_device_register_with_info(&wdev->dev, "gigabyte_wmi", wdev,
  158. &gigabyte_wmi_hwmon_chip_info, NULL);
  159. return PTR_ERR_OR_ZERO(hwmon_dev);
  160. }
  161. static const struct wmi_device_id gigabyte_wmi_id_table[] = {
  162. { GIGABYTE_WMI_GUID, NULL },
  163. { }
  164. };
  165. static struct wmi_driver gigabyte_wmi_driver = {
  166. .driver = {
  167. .name = "gigabyte-wmi",
  168. },
  169. .id_table = gigabyte_wmi_id_table,
  170. .probe = gigabyte_wmi_probe,
  171. };
  172. module_wmi_driver(gigabyte_wmi_driver);
  173. MODULE_DEVICE_TABLE(wmi, gigabyte_wmi_id_table);
  174. MODULE_AUTHOR("Thomas Weißschuh <[email protected]>");
  175. MODULE_DESCRIPTION("Gigabyte WMI temperature driver");
  176. MODULE_LICENSE("GPL");