1 // SPDX-License-Identifier: GPL-2.0+
3 * hwmon driver for Gigabyte AORUS Waterforce AIO CPU coolers: X240, X280 and X360.
5 * Copyright 2023 Aleksa Savic <savicaleksa83@gmail.com>
8 #include <linux/debugfs.h>
10 #include <linux/hwmon.h>
11 #include <linux/jiffies.h>
12 #include <linux/module.h>
13 #include <linux/spinlock.h>
14 #include <linux/unaligned.h>
16 #define DRIVER_NAME "gigabyte_waterforce"
18 #define USB_VENDOR_ID_GIGABYTE 0x1044
19 #define USB_PRODUCT_ID_WATERFORCE 0x7a4d /* Gigabyte AORUS WATERFORCE X240, X280 and X360 */
21 #define STATUS_VALIDITY (2 * 1000) /* ms */
22 #define MAX_REPORT_LENGTH 6144
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
30 /* Control commands, inner offsets and lengths */
31 static const u8 get_status_cmd
[] = { 0x99, 0xDA };
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 };
38 #define GET_STATUS_CMD_LENGTH 2
39 #define GET_FIRMWARE_VER_CMD_LENGTH 2
41 static const char *const waterforce_temp_label
[] = {
45 static const char *const waterforce_speed_label
[] = {
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
;
65 u16 speed_input
[2]; /* Fan and pump speed in RPM */
66 u8 duty_input
[2]; /* Fan and pump duty in 0-100% */
70 unsigned long updated
; /* jiffies */
73 static umode_t
waterforce_is_visible(const void *data
,
74 enum hwmon_sensor_types type
, u32 attr
, int channel
)
79 case hwmon_temp_label
:
80 case hwmon_temp_input
:
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
)
115 mutex_lock(&priv
->buffer_lock
);
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
);
120 mutex_unlock(&priv
->buffer_lock
);
124 static int waterforce_get_status(struct waterforce_data
*priv
)
126 int ret
= mutex_lock_interruptible(&priv
->status_report_request_mutex
);
131 if (!time_after(jiffies
, priv
->updated
+ msecs_to_jiffies(STATUS_VALIDITY
))) {
132 /* Data is up to date */
133 goto unlock_and_return
;
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.
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
);
146 /* Send command for getting status */
147 ret
= waterforce_write_expanded(priv
, get_status_cmd
, GET_STATUS_CMD_LENGTH
);
149 goto unlock_and_return
;
151 ret
= wait_for_completion_interruptible_timeout(&priv
->status_report_received
,
152 msecs_to_jiffies(STATUS_VALIDITY
));
157 mutex_unlock(&priv
->status_report_request_mutex
);
164 static int waterforce_read(struct device
*dev
, enum hwmon_sensor_types type
,
165 u32 attr
, int channel
, long *val
)
167 struct waterforce_data
*priv
= dev_get_drvdata(dev
);
168 int ret
= waterforce_get_status(priv
);
175 *val
= priv
->temp_input
[channel
];
178 *val
= priv
->speed_input
[channel
];
182 case hwmon_pwm_input
:
183 *val
= DIV_ROUND_CLOSEST(priv
->duty_input
[channel
] * 255, 100);
190 return -EOPNOTSUPP
; /* unreachable */
196 static int waterforce_read_string(struct device
*dev
, enum hwmon_sensor_types type
,
197 u32 attr
, int channel
, const char **str
)
201 *str
= waterforce_temp_label
[channel
];
204 *str
= waterforce_speed_label
[channel
];
207 return -EOPNOTSUPP
; /* unreachable */
213 static int waterforce_get_fw_ver(struct hid_device
*hdev
)
215 struct waterforce_data
*priv
= hid_get_drvdata(hdev
);
218 ret
= waterforce_write_expanded(priv
, get_firmware_ver_cmd
, GET_FIRMWARE_VER_CMD_LENGTH
);
222 ret
= wait_for_completion_interruptible_timeout(&priv
->fw_version_processed
,
223 msecs_to_jiffies(STATUS_VALIDITY
));
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
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
,
250 static const struct hwmon_chip_info waterforce_chip_info
= {
251 .ops
= &waterforce_hwmon_ops
,
252 .info
= waterforce_info
,
255 static int waterforce_raw_event(struct hid_device
*hdev
, struct hid_report
*report
, u8
*data
,
258 struct waterforce_data
*priv
= hid_get_drvdata(hdev
);
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
];
265 if (!completion_done(&priv
->fw_version_processed
))
266 complete_all(&priv
->fw_version_processed
);
270 if (data
[0] != get_status_cmd
[0] || data
[1] != get_status_cmd
[1])
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
];
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
);
284 priv
->updated
= jiffies
;
289 static int firmware_version_show(struct seq_file
*seqf
, void *unused
)
291 struct waterforce_data
*priv
= seqf
->private;
293 seq_printf(seqf
, "%u\n", priv
->firmware_version
);
297 DEFINE_SHOW_ATTRIBUTE(firmware_version
);
299 static void waterforce_debugfs_init(struct waterforce_data
*priv
)
303 if (!priv
->firmware_version
)
304 return; /* There's nothing to show in debugfs */
306 scnprintf(name
, sizeof(name
), "%s-%s", DRIVER_NAME
, dev_name(&priv
->hdev
->dev
));
308 priv
->debugfs
= debugfs_create_dir(name
, NULL
);
309 debugfs_create_file("firmware_version", 0444, priv
->debugfs
, priv
, &firmware_version_fops
);
312 static int waterforce_probe(struct hid_device
*hdev
, const struct hid_device_id
*id
)
314 struct waterforce_data
*priv
;
317 priv
= devm_kzalloc(&hdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
322 hid_set_drvdata(hdev
, priv
);
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.
329 priv
->updated
= jiffies
- msecs_to_jiffies(STATUS_VALIDITY
);
331 ret
= hid_parse(hdev
);
333 hid_err(hdev
, "hid parse failed with %d\n", ret
);
338 * Enable hidraw so existing user-space tools can continue to work.
340 ret
= hid_hw_start(hdev
, HID_CONNECT_HIDRAW
);
342 hid_err(hdev
, "hid hw start failed with %d\n", ret
);
346 ret
= hid_hw_open(hdev
);
348 hid_err(hdev
, "hid hw open failed with %d\n", ret
);
352 priv
->buffer
= devm_kzalloc(&hdev
->dev
, MAX_REPORT_LENGTH
, GFP_KERNEL
);
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
);
364 hid_device_io_start(hdev
);
365 ret
= waterforce_get_fw_ver(hdev
);
367 hid_warn(hdev
, "fw version request failed with %d\n", ret
);
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
);
377 waterforce_debugfs_init(priv
);
388 static void waterforce_remove(struct hid_device
*hdev
)
390 struct waterforce_data
*priv
= hid_get_drvdata(hdev
);
392 debugfs_remove_recursive(priv
->debugfs
);
393 hwmon_device_unregister(priv
->hwmon_dev
);
399 static const struct hid_device_id waterforce_table
[] = {
400 { HID_USB_DEVICE(USB_VENDOR_ID_GIGABYTE
, USB_PRODUCT_ID_WATERFORCE
) },
404 MODULE_DEVICE_TABLE(hid
, waterforce_table
);
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
,
414 static int __init
waterforce_init(void)
416 return hid_register_driver(&waterforce_driver
);
419 static void __exit
waterforce_exit(void)
421 hid_unregister_driver(&waterforce_driver
);
424 /* When compiled into the kernel, initialize after the HID bus */
425 late_initcall(waterforce_init
);
426 module_exit(waterforce_exit
);
428 MODULE_LICENSE("GPL");
429 MODULE_AUTHOR("Aleksa Savic <savicaleksa83@gmail.com>");
430 MODULE_DESCRIPTION("Hwmon driver for Gigabyte AORUS Waterforce AIO coolers");