xref: /linux/drivers/hwmon/gigabyte_waterforce.c (revision a06c3fad49a50d5d5eb078f93e70f4d3eca5d5a5)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * hwmon driver for Gigabyte AORUS Waterforce AIO CPU coolers: X240, X280 and X360.
4  *
5  * Copyright 2023 Aleksa Savic <savicaleksa83@gmail.com>
6  */
7 
8 #include <linux/debugfs.h>
9 #include <linux/hid.h>
10 #include <linux/hwmon.h>
11 #include <linux/jiffies.h>
12 #include <linux/module.h>
13 #include <linux/spinlock.h>
14 #include <asm/unaligned.h>
15 
16 #define DRIVER_NAME	"gigabyte_waterforce"
17 
18 #define USB_VENDOR_ID_GIGABYTE		0x1044
19 #define USB_PRODUCT_ID_WATERFORCE	0x7a4d	/* Gigabyte AORUS WATERFORCE X240, X280 and X360 */
20 
21 #define STATUS_VALIDITY		(2 * 1000)	/* ms */
22 #define MAX_REPORT_LENGTH	6144
23 
24 #define WATERFORCE_TEMP_SENSOR	0xD
25 #define WATERFORCE_FAN_SPEED	0x02
26 #define WATERFORCE_PUMP_SPEED	0x05
27 #define WATERFORCE_FAN_DUTY	0x08
28 #define WATERFORCE_PUMP_DUTY	0x09
29 
30 /* Control commands, inner offsets and lengths */
31 static const u8 get_status_cmd[] = { 0x99, 0xDA };
32 
33 #define FIRMWARE_VER_START_OFFSET_1	2
34 #define FIRMWARE_VER_START_OFFSET_2	3
35 static const u8 get_firmware_ver_cmd[] = { 0x99, 0xD6 };
36 
37 /* Command lengths */
38 #define GET_STATUS_CMD_LENGTH		2
39 #define GET_FIRMWARE_VER_CMD_LENGTH	2
40 
41 static const char *const waterforce_temp_label[] = {
42 	"Coolant temp"
43 };
44 
45 static const char *const waterforce_speed_label[] = {
46 	"Fan speed",
47 	"Pump speed"
48 };
49 
50 struct waterforce_data {
51 	struct hid_device *hdev;
52 	struct device *hwmon_dev;
53 	struct dentry *debugfs;
54 	/* For locking access to buffer */
55 	struct mutex buffer_lock;
56 	/* For queueing multiple readers */
57 	struct mutex status_report_request_mutex;
58 	/* For reinitializing the completion below */
59 	spinlock_t status_report_request_lock;
60 	struct completion status_report_received;
61 	struct completion fw_version_processed;
62 
63 	/* Sensor data */
64 	s32 temp_input[1];
65 	u16 speed_input[2];	/* Fan and pump speed in RPM */
66 	u8 duty_input[2];	/* Fan and pump duty in 0-100% */
67 
68 	u8 *buffer;
69 	int firmware_version;
70 	unsigned long updated;	/* jiffies */
71 };
72 
73 static umode_t waterforce_is_visible(const void *data,
74 				     enum hwmon_sensor_types type, u32 attr, int channel)
75 {
76 	switch (type) {
77 	case hwmon_temp:
78 		switch (attr) {
79 		case hwmon_temp_label:
80 		case hwmon_temp_input:
81 			return 0444;
82 		default:
83 			break;
84 		}
85 		break;
86 	case hwmon_fan:
87 		switch (attr) {
88 		case hwmon_fan_label:
89 		case hwmon_fan_input:
90 			return 0444;
91 		default:
92 			break;
93 		}
94 		break;
95 	case hwmon_pwm:
96 		switch (attr) {
97 		case hwmon_pwm_input:
98 			return 0444;
99 		default:
100 			break;
101 		}
102 		break;
103 	default:
104 		break;
105 	}
106 
107 	return 0;
108 }
109 
110 /* Writes the command to the device with the rest of the report filled with zeroes */
111 static int waterforce_write_expanded(struct waterforce_data *priv, const u8 *cmd, int cmd_length)
112 {
113 	int ret;
114 
115 	mutex_lock(&priv->buffer_lock);
116 
117 	memcpy_and_pad(priv->buffer, MAX_REPORT_LENGTH, cmd, cmd_length, 0x00);
118 	ret = hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH);
119 
120 	mutex_unlock(&priv->buffer_lock);
121 	return ret;
122 }
123 
124 static int waterforce_get_status(struct waterforce_data *priv)
125 {
126 	int ret = mutex_lock_interruptible(&priv->status_report_request_mutex);
127 
128 	if (ret < 0)
129 		return ret;
130 
131 	if (!time_after(jiffies, priv->updated + msecs_to_jiffies(STATUS_VALIDITY))) {
132 		/* Data is up to date */
133 		goto unlock_and_return;
134 	}
135 
136 	/*
137 	 * Disable raw event parsing for a moment to safely reinitialize the
138 	 * completion. Reinit is done because hidraw could have triggered
139 	 * the raw event parsing and marked the priv->status_report_received
140 	 * completion as done.
141 	 */
142 	spin_lock_bh(&priv->status_report_request_lock);
143 	reinit_completion(&priv->status_report_received);
144 	spin_unlock_bh(&priv->status_report_request_lock);
145 
146 	/* Send command for getting status */
147 	ret = waterforce_write_expanded(priv, get_status_cmd, GET_STATUS_CMD_LENGTH);
148 	if (ret < 0)
149 		goto unlock_and_return;
150 
151 	ret = wait_for_completion_interruptible_timeout(&priv->status_report_received,
152 							msecs_to_jiffies(STATUS_VALIDITY));
153 	if (ret == 0)
154 		ret = -ETIMEDOUT;
155 
156 unlock_and_return:
157 	mutex_unlock(&priv->status_report_request_mutex);
158 	if (ret < 0)
159 		return ret;
160 
161 	return 0;
162 }
163 
164 static int waterforce_read(struct device *dev, enum hwmon_sensor_types type,
165 			   u32 attr, int channel, long *val)
166 {
167 	struct waterforce_data *priv = dev_get_drvdata(dev);
168 	int ret = waterforce_get_status(priv);
169 
170 	if (ret < 0)
171 		return ret;
172 
173 	switch (type) {
174 	case hwmon_temp:
175 		*val = priv->temp_input[channel];
176 		break;
177 	case hwmon_fan:
178 		*val = priv->speed_input[channel];
179 		break;
180 	case hwmon_pwm:
181 		switch (attr) {
182 		case hwmon_pwm_input:
183 			*val = DIV_ROUND_CLOSEST(priv->duty_input[channel] * 255, 100);
184 			break;
185 		default:
186 			return -EOPNOTSUPP;
187 		}
188 		break;
189 	default:
190 		return -EOPNOTSUPP;	/* unreachable */
191 	}
192 
193 	return 0;
194 }
195 
196 static int waterforce_read_string(struct device *dev, enum hwmon_sensor_types type,
197 				  u32 attr, int channel, const char **str)
198 {
199 	switch (type) {
200 	case hwmon_temp:
201 		*str = waterforce_temp_label[channel];
202 		break;
203 	case hwmon_fan:
204 		*str = waterforce_speed_label[channel];
205 		break;
206 	default:
207 		return -EOPNOTSUPP;	/* unreachable */
208 	}
209 
210 	return 0;
211 }
212 
213 static int waterforce_get_fw_ver(struct hid_device *hdev)
214 {
215 	struct waterforce_data *priv = hid_get_drvdata(hdev);
216 	int ret;
217 
218 	ret = waterforce_write_expanded(priv, get_firmware_ver_cmd, GET_FIRMWARE_VER_CMD_LENGTH);
219 	if (ret < 0)
220 		return ret;
221 
222 	ret = wait_for_completion_interruptible_timeout(&priv->fw_version_processed,
223 							msecs_to_jiffies(STATUS_VALIDITY));
224 	if (ret == 0)
225 		return -ETIMEDOUT;
226 	else if (ret < 0)
227 		return ret;
228 
229 	return 0;
230 }
231 
232 static const struct hwmon_ops waterforce_hwmon_ops = {
233 	.is_visible = waterforce_is_visible,
234 	.read = waterforce_read,
235 	.read_string = waterforce_read_string
236 };
237 
238 static const struct hwmon_channel_info *waterforce_info[] = {
239 	HWMON_CHANNEL_INFO(temp,
240 			   HWMON_T_INPUT | HWMON_T_LABEL),
241 	HWMON_CHANNEL_INFO(fan,
242 			   HWMON_F_INPUT | HWMON_F_LABEL,
243 			   HWMON_F_INPUT | HWMON_F_LABEL),
244 	HWMON_CHANNEL_INFO(pwm,
245 			   HWMON_PWM_INPUT,
246 			   HWMON_PWM_INPUT),
247 	NULL
248 };
249 
250 static const struct hwmon_chip_info waterforce_chip_info = {
251 	.ops = &waterforce_hwmon_ops,
252 	.info = waterforce_info,
253 };
254 
255 static int waterforce_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data,
256 				int size)
257 {
258 	struct waterforce_data *priv = hid_get_drvdata(hdev);
259 
260 	if (data[0] == get_firmware_ver_cmd[0] && data[1] == get_firmware_ver_cmd[1]) {
261 		/* Received a firmware version report */
262 		priv->firmware_version =
263 		    data[FIRMWARE_VER_START_OFFSET_1] * 10 + data[FIRMWARE_VER_START_OFFSET_2];
264 
265 		if (!completion_done(&priv->fw_version_processed))
266 			complete_all(&priv->fw_version_processed);
267 		return 0;
268 	}
269 
270 	if (data[0] != get_status_cmd[0] || data[1] != get_status_cmd[1])
271 		return 0;
272 
273 	priv->temp_input[0] = data[WATERFORCE_TEMP_SENSOR] * 1000;
274 	priv->speed_input[0] = get_unaligned_le16(data + WATERFORCE_FAN_SPEED);
275 	priv->speed_input[1] = get_unaligned_le16(data + WATERFORCE_PUMP_SPEED);
276 	priv->duty_input[0] = data[WATERFORCE_FAN_DUTY];
277 	priv->duty_input[1] = data[WATERFORCE_PUMP_DUTY];
278 
279 	spin_lock(&priv->status_report_request_lock);
280 	if (!completion_done(&priv->status_report_received))
281 		complete_all(&priv->status_report_received);
282 	spin_unlock(&priv->status_report_request_lock);
283 
284 	priv->updated = jiffies;
285 
286 	return 0;
287 }
288 
289 static int firmware_version_show(struct seq_file *seqf, void *unused)
290 {
291 	struct waterforce_data *priv = seqf->private;
292 
293 	seq_printf(seqf, "%u\n", priv->firmware_version);
294 
295 	return 0;
296 }
297 DEFINE_SHOW_ATTRIBUTE(firmware_version);
298 
299 static void waterforce_debugfs_init(struct waterforce_data *priv)
300 {
301 	char name[64];
302 
303 	if (!priv->firmware_version)
304 		return;	/* There's nothing to show in debugfs */
305 
306 	scnprintf(name, sizeof(name), "%s-%s", DRIVER_NAME, dev_name(&priv->hdev->dev));
307 
308 	priv->debugfs = debugfs_create_dir(name, NULL);
309 	debugfs_create_file("firmware_version", 0444, priv->debugfs, priv, &firmware_version_fops);
310 }
311 
312 static int waterforce_probe(struct hid_device *hdev, const struct hid_device_id *id)
313 {
314 	struct waterforce_data *priv;
315 	int ret;
316 
317 	priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
318 	if (!priv)
319 		return -ENOMEM;
320 
321 	priv->hdev = hdev;
322 	hid_set_drvdata(hdev, priv);
323 
324 	/*
325 	 * Initialize priv->updated to STATUS_VALIDITY seconds in the past, making
326 	 * the initial empty data invalid for waterforce_read() without the need for
327 	 * a special case there.
328 	 */
329 	priv->updated = jiffies - msecs_to_jiffies(STATUS_VALIDITY);
330 
331 	ret = hid_parse(hdev);
332 	if (ret) {
333 		hid_err(hdev, "hid parse failed with %d\n", ret);
334 		return ret;
335 	}
336 
337 	/*
338 	 * Enable hidraw so existing user-space tools can continue to work.
339 	 */
340 	ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
341 	if (ret) {
342 		hid_err(hdev, "hid hw start failed with %d\n", ret);
343 		return ret;
344 	}
345 
346 	ret = hid_hw_open(hdev);
347 	if (ret) {
348 		hid_err(hdev, "hid hw open failed with %d\n", ret);
349 		goto fail_and_stop;
350 	}
351 
352 	priv->buffer = devm_kzalloc(&hdev->dev, MAX_REPORT_LENGTH, GFP_KERNEL);
353 	if (!priv->buffer) {
354 		ret = -ENOMEM;
355 		goto fail_and_close;
356 	}
357 
358 	mutex_init(&priv->status_report_request_mutex);
359 	mutex_init(&priv->buffer_lock);
360 	spin_lock_init(&priv->status_report_request_lock);
361 	init_completion(&priv->status_report_received);
362 	init_completion(&priv->fw_version_processed);
363 
364 	hid_device_io_start(hdev);
365 	ret = waterforce_get_fw_ver(hdev);
366 	if (ret < 0)
367 		hid_warn(hdev, "fw version request failed with %d\n", ret);
368 
369 	priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "waterforce",
370 							  priv, &waterforce_chip_info, NULL);
371 	if (IS_ERR(priv->hwmon_dev)) {
372 		ret = PTR_ERR(priv->hwmon_dev);
373 		hid_err(hdev, "hwmon registration failed with %d\n", ret);
374 		goto fail_and_close;
375 	}
376 
377 	waterforce_debugfs_init(priv);
378 
379 	return 0;
380 
381 fail_and_close:
382 	hid_hw_close(hdev);
383 fail_and_stop:
384 	hid_hw_stop(hdev);
385 	return ret;
386 }
387 
388 static void waterforce_remove(struct hid_device *hdev)
389 {
390 	struct waterforce_data *priv = hid_get_drvdata(hdev);
391 
392 	debugfs_remove_recursive(priv->debugfs);
393 	hwmon_device_unregister(priv->hwmon_dev);
394 
395 	hid_hw_close(hdev);
396 	hid_hw_stop(hdev);
397 }
398 
399 static const struct hid_device_id waterforce_table[] = {
400 	{ HID_USB_DEVICE(USB_VENDOR_ID_GIGABYTE, USB_PRODUCT_ID_WATERFORCE) },
401 	{ }
402 };
403 
404 MODULE_DEVICE_TABLE(hid, waterforce_table);
405 
406 static struct hid_driver waterforce_driver = {
407 	.name = "waterforce",
408 	.id_table = waterforce_table,
409 	.probe = waterforce_probe,
410 	.remove = waterforce_remove,
411 	.raw_event = waterforce_raw_event,
412 };
413 
414 static int __init waterforce_init(void)
415 {
416 	return hid_register_driver(&waterforce_driver);
417 }
418 
419 static void __exit waterforce_exit(void)
420 {
421 	hid_unregister_driver(&waterforce_driver);
422 }
423 
424 /* When compiled into the kernel, initialize after the HID bus */
425 late_initcall(waterforce_init);
426 module_exit(waterforce_exit);
427 
428 MODULE_LICENSE("GPL");
429 MODULE_AUTHOR("Aleksa Savic <savicaleksa83@gmail.com>");
430 MODULE_DESCRIPTION("Hwmon driver for Gigabyte AORUS Waterforce AIO coolers");
431