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