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 */
31static const u8 get_status_cmd[] = { 0x99, 0xDA };
32
33#define FIRMWARE_VER_START_OFFSET_1	2
34#define FIRMWARE_VER_START_OFFSET_2	3
35static 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
41static const char *const waterforce_temp_label[] = {
42	"Coolant temp"
43};
44
45static const char *const waterforce_speed_label[] = {
46	"Fan speed",
47	"Pump speed"
48};
49
50struct 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
73static 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 */
111static 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
124static 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
156unlock_and_return:
157	mutex_unlock(&priv->status_report_request_mutex);
158	if (ret < 0)
159		return ret;
160
161	return 0;
162}
163
164static 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
196static 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
213static 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
232static 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
238static 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
250static const struct hwmon_chip_info waterforce_chip_info = {
251	.ops = &waterforce_hwmon_ops,
252	.info = waterforce_info,
253};
254
255static 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
289static 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}
297DEFINE_SHOW_ATTRIBUTE(firmware_version);
298
299static 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
312static 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
381fail_and_close:
382	hid_hw_close(hdev);
383fail_and_stop:
384	hid_hw_stop(hdev);
385	return ret;
386}
387
388static 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
399static const struct hid_device_id waterforce_table[] = {
400	{ HID_USB_DEVICE(USB_VENDOR_ID_GIGABYTE, USB_PRODUCT_ID_WATERFORCE) },
401	{ }
402};
403
404MODULE_DEVICE_TABLE(hid, waterforce_table);
405
406static 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
414static int __init waterforce_init(void)
415{
416	return hid_register_driver(&waterforce_driver);
417}
418
419static 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 */
425late_initcall(waterforce_init);
426module_exit(waterforce_exit);
427
428MODULE_LICENSE("GPL");
429MODULE_AUTHOR("Aleksa Savic <savicaleksa83@gmail.com>");
430MODULE_DESCRIPTION("Hwmon driver for Gigabyte AORUS Waterforce AIO coolers");
431