xref: /linux/drivers/hwmon/gigabyte_waterforce.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
142ac68e3SAleksa Savic // SPDX-License-Identifier: GPL-2.0+
242ac68e3SAleksa Savic /*
342ac68e3SAleksa Savic  * hwmon driver for Gigabyte AORUS Waterforce AIO CPU coolers: X240, X280 and X360.
442ac68e3SAleksa Savic  *
542ac68e3SAleksa Savic  * Copyright 2023 Aleksa Savic <savicaleksa83@gmail.com>
642ac68e3SAleksa Savic  */
742ac68e3SAleksa Savic 
842ac68e3SAleksa Savic #include <linux/debugfs.h>
942ac68e3SAleksa Savic #include <linux/hid.h>
1042ac68e3SAleksa Savic #include <linux/hwmon.h>
1142ac68e3SAleksa Savic #include <linux/jiffies.h>
1242ac68e3SAleksa Savic #include <linux/module.h>
1342ac68e3SAleksa Savic #include <linux/spinlock.h>
1442ac68e3SAleksa Savic #include <asm/unaligned.h>
1542ac68e3SAleksa Savic 
1642ac68e3SAleksa Savic #define DRIVER_NAME	"gigabyte_waterforce"
1742ac68e3SAleksa Savic 
1842ac68e3SAleksa Savic #define USB_VENDOR_ID_GIGABYTE		0x1044
1942ac68e3SAleksa Savic #define USB_PRODUCT_ID_WATERFORCE	0x7a4d	/* Gigabyte AORUS WATERFORCE X240, X280 and X360 */
2042ac68e3SAleksa Savic 
2142ac68e3SAleksa Savic #define STATUS_VALIDITY		(2 * 1000)	/* ms */
2242ac68e3SAleksa Savic #define MAX_REPORT_LENGTH	6144
2342ac68e3SAleksa Savic 
2442ac68e3SAleksa Savic #define WATERFORCE_TEMP_SENSOR	0xD
2542ac68e3SAleksa Savic #define WATERFORCE_FAN_SPEED	0x02
2642ac68e3SAleksa Savic #define WATERFORCE_PUMP_SPEED	0x05
2742ac68e3SAleksa Savic #define WATERFORCE_FAN_DUTY	0x08
2842ac68e3SAleksa Savic #define WATERFORCE_PUMP_DUTY	0x09
2942ac68e3SAleksa Savic 
3042ac68e3SAleksa Savic /* Control commands, inner offsets and lengths */
3142ac68e3SAleksa Savic static const u8 get_status_cmd[] = { 0x99, 0xDA };
3242ac68e3SAleksa Savic 
3342ac68e3SAleksa Savic #define FIRMWARE_VER_START_OFFSET_1	2
3442ac68e3SAleksa Savic #define FIRMWARE_VER_START_OFFSET_2	3
3542ac68e3SAleksa Savic static const u8 get_firmware_ver_cmd[] = { 0x99, 0xD6 };
3642ac68e3SAleksa Savic 
3742ac68e3SAleksa Savic /* Command lengths */
3842ac68e3SAleksa Savic #define GET_STATUS_CMD_LENGTH		2
3942ac68e3SAleksa Savic #define GET_FIRMWARE_VER_CMD_LENGTH	2
4042ac68e3SAleksa Savic 
4142ac68e3SAleksa Savic static const char *const waterforce_temp_label[] = {
4242ac68e3SAleksa Savic 	"Coolant temp"
4342ac68e3SAleksa Savic };
4442ac68e3SAleksa Savic 
4542ac68e3SAleksa Savic static const char *const waterforce_speed_label[] = {
4642ac68e3SAleksa Savic 	"Fan speed",
4742ac68e3SAleksa Savic 	"Pump speed"
4842ac68e3SAleksa Savic };
4942ac68e3SAleksa Savic 
5042ac68e3SAleksa Savic struct waterforce_data {
5142ac68e3SAleksa Savic 	struct hid_device *hdev;
5242ac68e3SAleksa Savic 	struct device *hwmon_dev;
5342ac68e3SAleksa Savic 	struct dentry *debugfs;
5442ac68e3SAleksa Savic 	/* For locking access to buffer */
5542ac68e3SAleksa Savic 	struct mutex buffer_lock;
5642ac68e3SAleksa Savic 	/* For queueing multiple readers */
5742ac68e3SAleksa Savic 	struct mutex status_report_request_mutex;
5842ac68e3SAleksa Savic 	/* For reinitializing the completion below */
5942ac68e3SAleksa Savic 	spinlock_t status_report_request_lock;
6042ac68e3SAleksa Savic 	struct completion status_report_received;
6142ac68e3SAleksa Savic 	struct completion fw_version_processed;
6242ac68e3SAleksa Savic 
6342ac68e3SAleksa Savic 	/* Sensor data */
6442ac68e3SAleksa Savic 	s32 temp_input[1];
6542ac68e3SAleksa Savic 	u16 speed_input[2];	/* Fan and pump speed in RPM */
6642ac68e3SAleksa Savic 	u8 duty_input[2];	/* Fan and pump duty in 0-100% */
6742ac68e3SAleksa Savic 
6842ac68e3SAleksa Savic 	u8 *buffer;
6942ac68e3SAleksa Savic 	int firmware_version;
7042ac68e3SAleksa Savic 	unsigned long updated;	/* jiffies */
7142ac68e3SAleksa Savic };
7242ac68e3SAleksa Savic 
waterforce_is_visible(const void * data,enum hwmon_sensor_types type,u32 attr,int channel)7342ac68e3SAleksa Savic static umode_t waterforce_is_visible(const void *data,
7442ac68e3SAleksa Savic 				     enum hwmon_sensor_types type, u32 attr, int channel)
7542ac68e3SAleksa Savic {
7642ac68e3SAleksa Savic 	switch (type) {
7742ac68e3SAleksa Savic 	case hwmon_temp:
7842ac68e3SAleksa Savic 		switch (attr) {
7942ac68e3SAleksa Savic 		case hwmon_temp_label:
8042ac68e3SAleksa Savic 		case hwmon_temp_input:
8142ac68e3SAleksa Savic 			return 0444;
8242ac68e3SAleksa Savic 		default:
8342ac68e3SAleksa Savic 			break;
8442ac68e3SAleksa Savic 		}
8542ac68e3SAleksa Savic 		break;
8642ac68e3SAleksa Savic 	case hwmon_fan:
8742ac68e3SAleksa Savic 		switch (attr) {
8842ac68e3SAleksa Savic 		case hwmon_fan_label:
8942ac68e3SAleksa Savic 		case hwmon_fan_input:
9042ac68e3SAleksa Savic 			return 0444;
9142ac68e3SAleksa Savic 		default:
9242ac68e3SAleksa Savic 			break;
9342ac68e3SAleksa Savic 		}
9442ac68e3SAleksa Savic 		break;
9542ac68e3SAleksa Savic 	case hwmon_pwm:
9642ac68e3SAleksa Savic 		switch (attr) {
9742ac68e3SAleksa Savic 		case hwmon_pwm_input:
9842ac68e3SAleksa Savic 			return 0444;
9942ac68e3SAleksa Savic 		default:
10042ac68e3SAleksa Savic 			break;
10142ac68e3SAleksa Savic 		}
10242ac68e3SAleksa Savic 		break;
10342ac68e3SAleksa Savic 	default:
10442ac68e3SAleksa Savic 		break;
10542ac68e3SAleksa Savic 	}
10642ac68e3SAleksa Savic 
10742ac68e3SAleksa Savic 	return 0;
10842ac68e3SAleksa Savic }
10942ac68e3SAleksa Savic 
11042ac68e3SAleksa Savic /* Writes the command to the device with the rest of the report filled with zeroes */
waterforce_write_expanded(struct waterforce_data * priv,const u8 * cmd,int cmd_length)11142ac68e3SAleksa Savic static int waterforce_write_expanded(struct waterforce_data *priv, const u8 *cmd, int cmd_length)
11242ac68e3SAleksa Savic {
11342ac68e3SAleksa Savic 	int ret;
11442ac68e3SAleksa Savic 
11542ac68e3SAleksa Savic 	mutex_lock(&priv->buffer_lock);
11642ac68e3SAleksa Savic 
11742ac68e3SAleksa Savic 	memcpy_and_pad(priv->buffer, MAX_REPORT_LENGTH, cmd, cmd_length, 0x00);
11842ac68e3SAleksa Savic 	ret = hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH);
11942ac68e3SAleksa Savic 
12042ac68e3SAleksa Savic 	mutex_unlock(&priv->buffer_lock);
12142ac68e3SAleksa Savic 	return ret;
12242ac68e3SAleksa Savic }
12342ac68e3SAleksa Savic 
waterforce_get_status(struct waterforce_data * priv)12442ac68e3SAleksa Savic static int waterforce_get_status(struct waterforce_data *priv)
12542ac68e3SAleksa Savic {
12642ac68e3SAleksa Savic 	int ret = mutex_lock_interruptible(&priv->status_report_request_mutex);
12742ac68e3SAleksa Savic 
12842ac68e3SAleksa Savic 	if (ret < 0)
12942ac68e3SAleksa Savic 		return ret;
13042ac68e3SAleksa Savic 
13142ac68e3SAleksa Savic 	if (!time_after(jiffies, priv->updated + msecs_to_jiffies(STATUS_VALIDITY))) {
13242ac68e3SAleksa Savic 		/* Data is up to date */
13342ac68e3SAleksa Savic 		goto unlock_and_return;
13442ac68e3SAleksa Savic 	}
13542ac68e3SAleksa Savic 
13642ac68e3SAleksa Savic 	/*
13742ac68e3SAleksa Savic 	 * Disable raw event parsing for a moment to safely reinitialize the
13842ac68e3SAleksa Savic 	 * completion. Reinit is done because hidraw could have triggered
13942ac68e3SAleksa Savic 	 * the raw event parsing and marked the priv->status_report_received
14042ac68e3SAleksa Savic 	 * completion as done.
14142ac68e3SAleksa Savic 	 */
14242ac68e3SAleksa Savic 	spin_lock_bh(&priv->status_report_request_lock);
14342ac68e3SAleksa Savic 	reinit_completion(&priv->status_report_received);
14442ac68e3SAleksa Savic 	spin_unlock_bh(&priv->status_report_request_lock);
14542ac68e3SAleksa Savic 
14642ac68e3SAleksa Savic 	/* Send command for getting status */
14742ac68e3SAleksa Savic 	ret = waterforce_write_expanded(priv, get_status_cmd, GET_STATUS_CMD_LENGTH);
14842ac68e3SAleksa Savic 	if (ret < 0)
149*97aab852SHarshit Mogalapalli 		goto unlock_and_return;
15042ac68e3SAleksa Savic 
15142ac68e3SAleksa Savic 	ret = wait_for_completion_interruptible_timeout(&priv->status_report_received,
15242ac68e3SAleksa Savic 							msecs_to_jiffies(STATUS_VALIDITY));
15342ac68e3SAleksa Savic 	if (ret == 0)
15442ac68e3SAleksa Savic 		ret = -ETIMEDOUT;
15542ac68e3SAleksa Savic 
15642ac68e3SAleksa Savic unlock_and_return:
15742ac68e3SAleksa Savic 	mutex_unlock(&priv->status_report_request_mutex);
15842ac68e3SAleksa Savic 	if (ret < 0)
15942ac68e3SAleksa Savic 		return ret;
16042ac68e3SAleksa Savic 
16142ac68e3SAleksa Savic 	return 0;
16242ac68e3SAleksa Savic }
16342ac68e3SAleksa Savic 
waterforce_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)16442ac68e3SAleksa Savic static int waterforce_read(struct device *dev, enum hwmon_sensor_types type,
16542ac68e3SAleksa Savic 			   u32 attr, int channel, long *val)
16642ac68e3SAleksa Savic {
16742ac68e3SAleksa Savic 	struct waterforce_data *priv = dev_get_drvdata(dev);
16842ac68e3SAleksa Savic 	int ret = waterforce_get_status(priv);
16942ac68e3SAleksa Savic 
17042ac68e3SAleksa Savic 	if (ret < 0)
17142ac68e3SAleksa Savic 		return ret;
17242ac68e3SAleksa Savic 
17342ac68e3SAleksa Savic 	switch (type) {
17442ac68e3SAleksa Savic 	case hwmon_temp:
17542ac68e3SAleksa Savic 		*val = priv->temp_input[channel];
17642ac68e3SAleksa Savic 		break;
17742ac68e3SAleksa Savic 	case hwmon_fan:
17842ac68e3SAleksa Savic 		*val = priv->speed_input[channel];
17942ac68e3SAleksa Savic 		break;
18042ac68e3SAleksa Savic 	case hwmon_pwm:
18142ac68e3SAleksa Savic 		switch (attr) {
18242ac68e3SAleksa Savic 		case hwmon_pwm_input:
18342ac68e3SAleksa Savic 			*val = DIV_ROUND_CLOSEST(priv->duty_input[channel] * 255, 100);
18442ac68e3SAleksa Savic 			break;
18542ac68e3SAleksa Savic 		default:
18642ac68e3SAleksa Savic 			return -EOPNOTSUPP;
18742ac68e3SAleksa Savic 		}
18842ac68e3SAleksa Savic 		break;
18942ac68e3SAleksa Savic 	default:
19042ac68e3SAleksa Savic 		return -EOPNOTSUPP;	/* unreachable */
19142ac68e3SAleksa Savic 	}
19242ac68e3SAleksa Savic 
19342ac68e3SAleksa Savic 	return 0;
19442ac68e3SAleksa Savic }
19542ac68e3SAleksa Savic 
waterforce_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** str)19642ac68e3SAleksa Savic static int waterforce_read_string(struct device *dev, enum hwmon_sensor_types type,
19742ac68e3SAleksa Savic 				  u32 attr, int channel, const char **str)
19842ac68e3SAleksa Savic {
19942ac68e3SAleksa Savic 	switch (type) {
20042ac68e3SAleksa Savic 	case hwmon_temp:
20142ac68e3SAleksa Savic 		*str = waterforce_temp_label[channel];
20242ac68e3SAleksa Savic 		break;
20342ac68e3SAleksa Savic 	case hwmon_fan:
20442ac68e3SAleksa Savic 		*str = waterforce_speed_label[channel];
20542ac68e3SAleksa Savic 		break;
20642ac68e3SAleksa Savic 	default:
20742ac68e3SAleksa Savic 		return -EOPNOTSUPP;	/* unreachable */
20842ac68e3SAleksa Savic 	}
20942ac68e3SAleksa Savic 
21042ac68e3SAleksa Savic 	return 0;
21142ac68e3SAleksa Savic }
21242ac68e3SAleksa Savic 
waterforce_get_fw_ver(struct hid_device * hdev)21342ac68e3SAleksa Savic static int waterforce_get_fw_ver(struct hid_device *hdev)
21442ac68e3SAleksa Savic {
21542ac68e3SAleksa Savic 	struct waterforce_data *priv = hid_get_drvdata(hdev);
21642ac68e3SAleksa Savic 	int ret;
21742ac68e3SAleksa Savic 
21842ac68e3SAleksa Savic 	ret = waterforce_write_expanded(priv, get_firmware_ver_cmd, GET_FIRMWARE_VER_CMD_LENGTH);
21942ac68e3SAleksa Savic 	if (ret < 0)
22042ac68e3SAleksa Savic 		return ret;
22142ac68e3SAleksa Savic 
22242ac68e3SAleksa Savic 	ret = wait_for_completion_interruptible_timeout(&priv->fw_version_processed,
22342ac68e3SAleksa Savic 							msecs_to_jiffies(STATUS_VALIDITY));
22442ac68e3SAleksa Savic 	if (ret == 0)
22542ac68e3SAleksa Savic 		return -ETIMEDOUT;
22642ac68e3SAleksa Savic 	else if (ret < 0)
22742ac68e3SAleksa Savic 		return ret;
22842ac68e3SAleksa Savic 
22942ac68e3SAleksa Savic 	return 0;
23042ac68e3SAleksa Savic }
23142ac68e3SAleksa Savic 
23242ac68e3SAleksa Savic static const struct hwmon_ops waterforce_hwmon_ops = {
23342ac68e3SAleksa Savic 	.is_visible = waterforce_is_visible,
23442ac68e3SAleksa Savic 	.read = waterforce_read,
23542ac68e3SAleksa Savic 	.read_string = waterforce_read_string
23642ac68e3SAleksa Savic };
23742ac68e3SAleksa Savic 
23842ac68e3SAleksa Savic static const struct hwmon_channel_info *waterforce_info[] = {
23942ac68e3SAleksa Savic 	HWMON_CHANNEL_INFO(temp,
24042ac68e3SAleksa Savic 			   HWMON_T_INPUT | HWMON_T_LABEL),
24142ac68e3SAleksa Savic 	HWMON_CHANNEL_INFO(fan,
24242ac68e3SAleksa Savic 			   HWMON_F_INPUT | HWMON_F_LABEL,
24342ac68e3SAleksa Savic 			   HWMON_F_INPUT | HWMON_F_LABEL),
24442ac68e3SAleksa Savic 	HWMON_CHANNEL_INFO(pwm,
24542ac68e3SAleksa Savic 			   HWMON_PWM_INPUT,
24642ac68e3SAleksa Savic 			   HWMON_PWM_INPUT),
24742ac68e3SAleksa Savic 	NULL
24842ac68e3SAleksa Savic };
24942ac68e3SAleksa Savic 
25042ac68e3SAleksa Savic static const struct hwmon_chip_info waterforce_chip_info = {
25142ac68e3SAleksa Savic 	.ops = &waterforce_hwmon_ops,
25242ac68e3SAleksa Savic 	.info = waterforce_info,
25342ac68e3SAleksa Savic };
25442ac68e3SAleksa Savic 
waterforce_raw_event(struct hid_device * hdev,struct hid_report * report,u8 * data,int size)25542ac68e3SAleksa Savic static int waterforce_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data,
25642ac68e3SAleksa Savic 				int size)
25742ac68e3SAleksa Savic {
25842ac68e3SAleksa Savic 	struct waterforce_data *priv = hid_get_drvdata(hdev);
25942ac68e3SAleksa Savic 
26042ac68e3SAleksa Savic 	if (data[0] == get_firmware_ver_cmd[0] && data[1] == get_firmware_ver_cmd[1]) {
26142ac68e3SAleksa Savic 		/* Received a firmware version report */
26242ac68e3SAleksa Savic 		priv->firmware_version =
26342ac68e3SAleksa Savic 		    data[FIRMWARE_VER_START_OFFSET_1] * 10 + data[FIRMWARE_VER_START_OFFSET_2];
26442ac68e3SAleksa Savic 
26542ac68e3SAleksa Savic 		if (!completion_done(&priv->fw_version_processed))
26642ac68e3SAleksa Savic 			complete_all(&priv->fw_version_processed);
26742ac68e3SAleksa Savic 		return 0;
26842ac68e3SAleksa Savic 	}
26942ac68e3SAleksa Savic 
27042ac68e3SAleksa Savic 	if (data[0] != get_status_cmd[0] || data[1] != get_status_cmd[1])
27142ac68e3SAleksa Savic 		return 0;
27242ac68e3SAleksa Savic 
27342ac68e3SAleksa Savic 	priv->temp_input[0] = data[WATERFORCE_TEMP_SENSOR] * 1000;
27442ac68e3SAleksa Savic 	priv->speed_input[0] = get_unaligned_le16(data + WATERFORCE_FAN_SPEED);
27542ac68e3SAleksa Savic 	priv->speed_input[1] = get_unaligned_le16(data + WATERFORCE_PUMP_SPEED);
27642ac68e3SAleksa Savic 	priv->duty_input[0] = data[WATERFORCE_FAN_DUTY];
27742ac68e3SAleksa Savic 	priv->duty_input[1] = data[WATERFORCE_PUMP_DUTY];
27842ac68e3SAleksa Savic 
27941c71105SAleksa Savic 	spin_lock(&priv->status_report_request_lock);
28042ac68e3SAleksa Savic 	if (!completion_done(&priv->status_report_received))
28142ac68e3SAleksa Savic 		complete_all(&priv->status_report_received);
28241c71105SAleksa Savic 	spin_unlock(&priv->status_report_request_lock);
28342ac68e3SAleksa Savic 
28442ac68e3SAleksa Savic 	priv->updated = jiffies;
28542ac68e3SAleksa Savic 
28642ac68e3SAleksa Savic 	return 0;
28742ac68e3SAleksa Savic }
28842ac68e3SAleksa Savic 
firmware_version_show(struct seq_file * seqf,void * unused)28942ac68e3SAleksa Savic static int firmware_version_show(struct seq_file *seqf, void *unused)
29042ac68e3SAleksa Savic {
29142ac68e3SAleksa Savic 	struct waterforce_data *priv = seqf->private;
29242ac68e3SAleksa Savic 
29342ac68e3SAleksa Savic 	seq_printf(seqf, "%u\n", priv->firmware_version);
29442ac68e3SAleksa Savic 
29542ac68e3SAleksa Savic 	return 0;
29642ac68e3SAleksa Savic }
29742ac68e3SAleksa Savic DEFINE_SHOW_ATTRIBUTE(firmware_version);
29842ac68e3SAleksa Savic 
waterforce_debugfs_init(struct waterforce_data * priv)29942ac68e3SAleksa Savic static void waterforce_debugfs_init(struct waterforce_data *priv)
30042ac68e3SAleksa Savic {
30142ac68e3SAleksa Savic 	char name[64];
30242ac68e3SAleksa Savic 
30342ac68e3SAleksa Savic 	if (!priv->firmware_version)
30442ac68e3SAleksa Savic 		return;	/* There's nothing to show in debugfs */
30542ac68e3SAleksa Savic 
30642ac68e3SAleksa Savic 	scnprintf(name, sizeof(name), "%s-%s", DRIVER_NAME, dev_name(&priv->hdev->dev));
30742ac68e3SAleksa Savic 
30842ac68e3SAleksa Savic 	priv->debugfs = debugfs_create_dir(name, NULL);
30942ac68e3SAleksa Savic 	debugfs_create_file("firmware_version", 0444, priv->debugfs, priv, &firmware_version_fops);
31042ac68e3SAleksa Savic }
31142ac68e3SAleksa Savic 
waterforce_probe(struct hid_device * hdev,const struct hid_device_id * id)31242ac68e3SAleksa Savic static int waterforce_probe(struct hid_device *hdev, const struct hid_device_id *id)
31342ac68e3SAleksa Savic {
31442ac68e3SAleksa Savic 	struct waterforce_data *priv;
31542ac68e3SAleksa Savic 	int ret;
31642ac68e3SAleksa Savic 
31742ac68e3SAleksa Savic 	priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
31842ac68e3SAleksa Savic 	if (!priv)
31942ac68e3SAleksa Savic 		return -ENOMEM;
32042ac68e3SAleksa Savic 
32142ac68e3SAleksa Savic 	priv->hdev = hdev;
32242ac68e3SAleksa Savic 	hid_set_drvdata(hdev, priv);
32342ac68e3SAleksa Savic 
32442ac68e3SAleksa Savic 	/*
32542ac68e3SAleksa Savic 	 * Initialize priv->updated to STATUS_VALIDITY seconds in the past, making
32642ac68e3SAleksa Savic 	 * the initial empty data invalid for waterforce_read() without the need for
32742ac68e3SAleksa Savic 	 * a special case there.
32842ac68e3SAleksa Savic 	 */
32942ac68e3SAleksa Savic 	priv->updated = jiffies - msecs_to_jiffies(STATUS_VALIDITY);
33042ac68e3SAleksa Savic 
33142ac68e3SAleksa Savic 	ret = hid_parse(hdev);
33242ac68e3SAleksa Savic 	if (ret) {
33342ac68e3SAleksa Savic 		hid_err(hdev, "hid parse failed with %d\n", ret);
33442ac68e3SAleksa Savic 		return ret;
33542ac68e3SAleksa Savic 	}
33642ac68e3SAleksa Savic 
33742ac68e3SAleksa Savic 	/*
33842ac68e3SAleksa Savic 	 * Enable hidraw so existing user-space tools can continue to work.
33942ac68e3SAleksa Savic 	 */
34042ac68e3SAleksa Savic 	ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
34142ac68e3SAleksa Savic 	if (ret) {
34242ac68e3SAleksa Savic 		hid_err(hdev, "hid hw start failed with %d\n", ret);
34342ac68e3SAleksa Savic 		return ret;
34442ac68e3SAleksa Savic 	}
34542ac68e3SAleksa Savic 
34642ac68e3SAleksa Savic 	ret = hid_hw_open(hdev);
34742ac68e3SAleksa Savic 	if (ret) {
34842ac68e3SAleksa Savic 		hid_err(hdev, "hid hw open failed with %d\n", ret);
34942ac68e3SAleksa Savic 		goto fail_and_stop;
35042ac68e3SAleksa Savic 	}
35142ac68e3SAleksa Savic 
35242ac68e3SAleksa Savic 	priv->buffer = devm_kzalloc(&hdev->dev, MAX_REPORT_LENGTH, GFP_KERNEL);
35342ac68e3SAleksa Savic 	if (!priv->buffer) {
35442ac68e3SAleksa Savic 		ret = -ENOMEM;
35542ac68e3SAleksa Savic 		goto fail_and_close;
35642ac68e3SAleksa Savic 	}
35742ac68e3SAleksa Savic 
35842ac68e3SAleksa Savic 	mutex_init(&priv->status_report_request_mutex);
35942ac68e3SAleksa Savic 	mutex_init(&priv->buffer_lock);
36042ac68e3SAleksa Savic 	spin_lock_init(&priv->status_report_request_lock);
36142ac68e3SAleksa Savic 	init_completion(&priv->status_report_received);
36242ac68e3SAleksa Savic 	init_completion(&priv->fw_version_processed);
36342ac68e3SAleksa Savic 
36442ac68e3SAleksa Savic 	hid_device_io_start(hdev);
36542ac68e3SAleksa Savic 	ret = waterforce_get_fw_ver(hdev);
36642ac68e3SAleksa Savic 	if (ret < 0)
36742ac68e3SAleksa Savic 		hid_warn(hdev, "fw version request failed with %d\n", ret);
36842ac68e3SAleksa Savic 
36942ac68e3SAleksa Savic 	priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "waterforce",
37042ac68e3SAleksa Savic 							  priv, &waterforce_chip_info, NULL);
37142ac68e3SAleksa Savic 	if (IS_ERR(priv->hwmon_dev)) {
37242ac68e3SAleksa Savic 		ret = PTR_ERR(priv->hwmon_dev);
37342ac68e3SAleksa Savic 		hid_err(hdev, "hwmon registration failed with %d\n", ret);
37442ac68e3SAleksa Savic 		goto fail_and_close;
37542ac68e3SAleksa Savic 	}
37642ac68e3SAleksa Savic 
37742ac68e3SAleksa Savic 	waterforce_debugfs_init(priv);
37842ac68e3SAleksa Savic 
37942ac68e3SAleksa Savic 	return 0;
38042ac68e3SAleksa Savic 
38142ac68e3SAleksa Savic fail_and_close:
38242ac68e3SAleksa Savic 	hid_hw_close(hdev);
38342ac68e3SAleksa Savic fail_and_stop:
38442ac68e3SAleksa Savic 	hid_hw_stop(hdev);
38542ac68e3SAleksa Savic 	return ret;
38642ac68e3SAleksa Savic }
38742ac68e3SAleksa Savic 
waterforce_remove(struct hid_device * hdev)38842ac68e3SAleksa Savic static void waterforce_remove(struct hid_device *hdev)
38942ac68e3SAleksa Savic {
39042ac68e3SAleksa Savic 	struct waterforce_data *priv = hid_get_drvdata(hdev);
39142ac68e3SAleksa Savic 
39242ac68e3SAleksa Savic 	debugfs_remove_recursive(priv->debugfs);
39342ac68e3SAleksa Savic 	hwmon_device_unregister(priv->hwmon_dev);
39442ac68e3SAleksa Savic 
39542ac68e3SAleksa Savic 	hid_hw_close(hdev);
39642ac68e3SAleksa Savic 	hid_hw_stop(hdev);
39742ac68e3SAleksa Savic }
39842ac68e3SAleksa Savic 
39942ac68e3SAleksa Savic static const struct hid_device_id waterforce_table[] = {
40042ac68e3SAleksa Savic 	{ HID_USB_DEVICE(USB_VENDOR_ID_GIGABYTE, USB_PRODUCT_ID_WATERFORCE) },
40142ac68e3SAleksa Savic 	{ }
40242ac68e3SAleksa Savic };
40342ac68e3SAleksa Savic 
40442ac68e3SAleksa Savic MODULE_DEVICE_TABLE(hid, waterforce_table);
40542ac68e3SAleksa Savic 
40642ac68e3SAleksa Savic static struct hid_driver waterforce_driver = {
40742ac68e3SAleksa Savic 	.name = "waterforce",
40842ac68e3SAleksa Savic 	.id_table = waterforce_table,
40942ac68e3SAleksa Savic 	.probe = waterforce_probe,
41042ac68e3SAleksa Savic 	.remove = waterforce_remove,
41142ac68e3SAleksa Savic 	.raw_event = waterforce_raw_event,
41242ac68e3SAleksa Savic };
41342ac68e3SAleksa Savic 
waterforce_init(void)41442ac68e3SAleksa Savic static int __init waterforce_init(void)
41542ac68e3SAleksa Savic {
41642ac68e3SAleksa Savic 	return hid_register_driver(&waterforce_driver);
41742ac68e3SAleksa Savic }
41842ac68e3SAleksa Savic 
waterforce_exit(void)41942ac68e3SAleksa Savic static void __exit waterforce_exit(void)
42042ac68e3SAleksa Savic {
42142ac68e3SAleksa Savic 	hid_unregister_driver(&waterforce_driver);
42242ac68e3SAleksa Savic }
42342ac68e3SAleksa Savic 
42442ac68e3SAleksa Savic /* When compiled into the kernel, initialize after the HID bus */
42542ac68e3SAleksa Savic late_initcall(waterforce_init);
42642ac68e3SAleksa Savic module_exit(waterforce_exit);
42742ac68e3SAleksa Savic 
42842ac68e3SAleksa Savic MODULE_LICENSE("GPL");
42942ac68e3SAleksa Savic MODULE_AUTHOR("Aleksa Savic <savicaleksa83@gmail.com>");
43042ac68e3SAleksa Savic MODULE_DESCRIPTION("Hwmon driver for Gigabyte AORUS Waterforce AIO coolers");
431