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 <asm/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");