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_device *adev = to_acpi_device(dev->parent);
97 struct acpi_fan *fan = dev_get_drvdata(dev);
98 struct acpi_fan_fps *fps;
99 struct acpi_fan_fst fst;
100 int ret;
101
102 ret = acpi_fan_get_fst(adev, &fst);
103 if (ret < 0)
104 return ret;
105
106 switch (type) {
107 case hwmon_fan:
108 switch (attr) {
109 case hwmon_fan_input:
110 if (fst.speed == FAN_SPEED_UNAVAILABLE)
111 return -ENODEV;
112
113 if (fst.speed > LONG_MAX)
114 return -EOVERFLOW;
115
116 *val = fst.speed;
117 return 0;
118 case hwmon_fan_target:
119 fps = acpi_fan_get_current_fps(fan, fst.control);
120 if (!fps)
121 return -EIO;
122
123 if (fps->speed > LONG_MAX)
124 return -EOVERFLOW;
125
126 *val = fps->speed;
127 return 0;
128 default:
129 return -EOPNOTSUPP;
130 }
131 case hwmon_power:
132 switch (attr) {
133 case hwmon_power_input:
134 fps = acpi_fan_get_current_fps(fan, fst.control);
135 if (!fps)
136 return -EIO;
137
138 if (fps->power == FAN_POWER_UNAVAILABLE)
139 return -ENODEV;
140
141 if (fps->power > LONG_MAX / MICROWATT_PER_MILLIWATT)
142 return -EOVERFLOW;
143
144 *val = fps->power * MICROWATT_PER_MILLIWATT;
145 return 0;
146 default:
147 return -EOPNOTSUPP;
148 }
149 default:
150 return -EOPNOTSUPP;
151 }
152 }
153
154 static const struct hwmon_ops acpi_fan_hwmon_ops = {
155 .is_visible = acpi_fan_hwmon_is_visible,
156 .read = acpi_fan_hwmon_read,
157 };
158
159 static const struct hwmon_channel_info * const acpi_fan_hwmon_info[] = {
160 HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_TARGET),
161 HWMON_CHANNEL_INFO(power, HWMON_P_INPUT),
162 NULL
163 };
164
165 static const struct hwmon_chip_info acpi_fan_hwmon_chip_info = {
166 .ops = &acpi_fan_hwmon_ops,
167 .info = acpi_fan_hwmon_info,
168 };
169
devm_acpi_fan_create_hwmon(struct acpi_device * device)170 int devm_acpi_fan_create_hwmon(struct acpi_device *device)
171 {
172 struct acpi_fan *fan = acpi_driver_data(device);
173 struct device *hdev;
174
175 hdev = devm_hwmon_device_register_with_info(&device->dev, "acpi_fan", fan,
176 &acpi_fan_hwmon_chip_info, NULL);
177 return PTR_ERR_OR_ZERO(hdev);
178 }
179