fan_hwmon.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * hwmon interface for the ACPI Fan driver.
  4. *
  5. * Copyright (C) 2024 Armin Wolf <W_Armin@gmx.de>
  6. */
  7. #include <linux/acpi.h>
  8. #include <linux/device.h>
  9. #include <linux/err.h>
  10. #include <linux/hwmon.h>
  11. #include <linux/limits.h>
  12. #include <linux/types.h>
  13. #include <linux/units.h>
  14. #include "fan.h"
  15. static struct acpi_fan_fps *acpi_fan_get_current_fps(struct acpi_fan *fan, u64 control)
  16. {
  17. unsigned int i;
  18. for (i = 0; i < fan->fps_count; i++) {
  19. if (fan->fps[i].control == control)
  20. return &fan->fps[i];
  21. }
  22. return NULL;
  23. }
  24. static umode_t acpi_fan_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
  25. u32 attr, int channel)
  26. {
  27. const struct acpi_fan *fan = drvdata;
  28. unsigned int i;
  29. switch (type) {
  30. case hwmon_fan:
  31. switch (attr) {
  32. case hwmon_fan_input:
  33. return 0444;
  34. case hwmon_fan_target:
  35. /* Only acpi4 fans support fan control. */
  36. if (!fan->acpi4)
  37. return 0;
  38. /*
  39. * When in fine grain control mode, not every fan control value
  40. * has an associated fan performance state.
  41. */
  42. if (fan->fif.fine_grain_ctrl)
  43. return 0;
  44. return 0444;
  45. default:
  46. return 0;
  47. }
  48. case hwmon_power:
  49. switch (attr) {
  50. case hwmon_power_input:
  51. /* Only acpi4 fans support fan control. */
  52. if (!fan->acpi4)
  53. return 0;
  54. /*
  55. * When in fine grain control mode, not every fan control value
  56. * has an associated fan performance state.
  57. */
  58. if (fan->fif.fine_grain_ctrl)
  59. return 0;
  60. /*
  61. * When all fan performance states contain no valid power data,
  62. * when the associated attribute should not be created.
  63. */
  64. for (i = 0; i < fan->fps_count; i++) {
  65. if (acpi_fan_power_valid(fan->fps[i].power))
  66. return 0444;
  67. }
  68. return 0;
  69. default:
  70. return 0;
  71. }
  72. default:
  73. return 0;
  74. }
  75. }
  76. static int acpi_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
  77. int channel, long *val)
  78. {
  79. struct acpi_fan *fan = dev_get_drvdata(dev);
  80. struct acpi_fan_fps *fps;
  81. struct acpi_fan_fst fst;
  82. int ret;
  83. ret = acpi_fan_get_fst(fan->handle, &fst);
  84. if (ret < 0)
  85. return ret;
  86. switch (type) {
  87. case hwmon_fan:
  88. switch (attr) {
  89. case hwmon_fan_input:
  90. if (!acpi_fan_speed_valid(fst.speed))
  91. return -ENODEV;
  92. if (fst.speed > LONG_MAX)
  93. return -EOVERFLOW;
  94. *val = fst.speed;
  95. return 0;
  96. case hwmon_fan_target:
  97. fps = acpi_fan_get_current_fps(fan, fst.control);
  98. if (!fps)
  99. return -EIO;
  100. if (fps->speed > LONG_MAX)
  101. return -EOVERFLOW;
  102. *val = fps->speed;
  103. return 0;
  104. default:
  105. return -EOPNOTSUPP;
  106. }
  107. case hwmon_power:
  108. switch (attr) {
  109. case hwmon_power_input:
  110. fps = acpi_fan_get_current_fps(fan, fst.control);
  111. if (!fps)
  112. return -EIO;
  113. if (!acpi_fan_power_valid(fps->power))
  114. return -ENODEV;
  115. if (fps->power > LONG_MAX / MICROWATT_PER_MILLIWATT)
  116. return -EOVERFLOW;
  117. *val = fps->power * MICROWATT_PER_MILLIWATT;
  118. return 0;
  119. default:
  120. return -EOPNOTSUPP;
  121. }
  122. default:
  123. return -EOPNOTSUPP;
  124. }
  125. }
  126. static const struct hwmon_ops acpi_fan_hwmon_ops = {
  127. .is_visible = acpi_fan_hwmon_is_visible,
  128. .read = acpi_fan_hwmon_read,
  129. };
  130. static const struct hwmon_channel_info * const acpi_fan_hwmon_info[] = {
  131. HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_TARGET),
  132. HWMON_CHANNEL_INFO(power, HWMON_P_INPUT),
  133. NULL
  134. };
  135. static const struct hwmon_chip_info acpi_fan_hwmon_chip_info = {
  136. .ops = &acpi_fan_hwmon_ops,
  137. .info = acpi_fan_hwmon_info,
  138. };
  139. void acpi_fan_notify_hwmon(struct device *dev)
  140. {
  141. struct acpi_fan *fan = dev_get_drvdata(dev);
  142. hwmon_notify_event(fan->hdev, hwmon_fan, hwmon_fan_input, 0);
  143. }
  144. int devm_acpi_fan_create_hwmon(struct device *dev)
  145. {
  146. struct acpi_fan *fan = dev_get_drvdata(dev);
  147. fan->hdev = devm_hwmon_device_register_with_info(dev, "acpi_fan", fan,
  148. &acpi_fan_hwmon_chip_info, NULL);
  149. return PTR_ERR_OR_ZERO(fan->hdev);
  150. }