xref: /linux/drivers/hwmon/asus_rog_ryujin.c (revision 02892f90a9851f508e557b3c75e93fc178310d5f)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * hwmon driver for Asus ROG Ryujin II 360 AIO cooler.
4  *
5  * Copyright 2024 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 <linux/unaligned.h>
15 
16 #define DRIVER_NAME	"asus_rog_ryujin"
17 
18 #define USB_VENDOR_ID_ASUS_ROG		0x0b05
19 #define USB_PRODUCT_ID_RYUJIN_AIO	0x1988	/* ASUS ROG RYUJIN II 360 */
20 
21 #define STATUS_VALIDITY		1500	/* ms */
22 #define MAX_REPORT_LENGTH	65
23 
24 /* Cooler status report offsets */
25 #define RYUJIN_TEMP_SENSOR_1		3
26 #define RYUJIN_TEMP_SENSOR_2		4
27 #define RYUJIN_PUMP_SPEED		5
28 #define RYUJIN_INTERNAL_FAN_SPEED	7
29 
30 /* Cooler duty report offsets */
31 #define RYUJIN_PUMP_DUTY		4
32 #define RYUJIN_INTERNAL_FAN_DUTY	5
33 
34 /* Controller status (speeds) report offsets */
35 #define RYUJIN_CONTROLLER_SPEED_1	5
36 #define RYUJIN_CONTROLLER_SPEED_2	7
37 #define RYUJIN_CONTROLLER_SPEED_3	9
38 #define RYUJIN_CONTROLLER_SPEED_4	3
39 
40 /* Controller duty report offsets */
41 #define RYUJIN_CONTROLLER_DUTY		4
42 
43 /* Control commands and their inner offsets */
44 #define RYUJIN_CMD_PREFIX	0xEC
45 
46 static const u8 get_cooler_status_cmd[] = { RYUJIN_CMD_PREFIX, 0x99 };
47 static const u8 get_cooler_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0x9A };
48 static const u8 get_controller_speed_cmd[] = { RYUJIN_CMD_PREFIX, 0xA0 };
49 static const u8 get_controller_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0xA1 };
50 
51 #define RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET	3
52 #define RYUJIN_SET_COOLER_FAN_DUTY_OFFSET	4
53 static const u8 set_cooler_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0x1A, 0x00, 0x00, 0x00 };
54 
55 #define RYUJIN_SET_CONTROLLER_FAN_DUTY_OFFSET	4
56 static const u8 set_controller_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0x21, 0x00, 0x00, 0x00 };
57 
58 /* Command lengths */
59 #define GET_CMD_LENGTH	2	/* Same length for all get commands */
60 #define SET_CMD_LENGTH	5	/* Same length for all set commands */
61 
62 /* Command response headers */
63 #define RYUJIN_GET_COOLER_STATUS_CMD_RESPONSE		0x19
64 #define RYUJIN_GET_COOLER_DUTY_CMD_RESPONSE		0x1A
65 #define RYUJIN_GET_CONTROLLER_SPEED_CMD_RESPONSE	0x20
66 #define RYUJIN_GET_CONTROLLER_DUTY_CMD_RESPONSE		0x21
67 
68 static const char *const rog_ryujin_temp_label[] = {
69 	"Coolant temp"
70 };
71 
72 static const char *const rog_ryujin_speed_label[] = {
73 	"Pump speed",
74 	"Internal fan speed",
75 	"Controller fan 1 speed",
76 	"Controller fan 2 speed",
77 	"Controller fan 3 speed",
78 	"Controller fan 4 speed",
79 };
80 
81 struct rog_ryujin_data {
82 	struct hid_device *hdev;
83 	struct device *hwmon_dev;
84 	/* For reinitializing the completions below */
85 	spinlock_t status_report_request_lock;
86 	struct completion cooler_status_received;
87 	struct completion controller_status_received;
88 	struct completion cooler_duty_received;
89 	struct completion controller_duty_received;
90 	struct completion cooler_duty_set;
91 	struct completion controller_duty_set;
92 
93 	/* Sensor data */
94 	s32 temp_input[1];
95 	u16 speed_input[6];	/* Pump, internal fan and four controller fan speeds in RPM */
96 	u8 duty_input[3];	/* Pump, internal fan and controller fan duty in PWM */
97 
98 	u8 *buffer;
99 	unsigned long updated;	/* jiffies */
100 };
101 
102 static int rog_ryujin_percent_to_pwm(u16 val)
103 {
104 	return DIV_ROUND_CLOSEST(val * 255, 100);
105 }
106 
107 static int rog_ryujin_pwm_to_percent(long val)
108 {
109 	return DIV_ROUND_CLOSEST(val * 100, 255);
110 }
111 
112 static umode_t rog_ryujin_is_visible(const void *data,
113 				     enum hwmon_sensor_types type, u32 attr, int channel)
114 {
115 	switch (type) {
116 	case hwmon_temp:
117 		switch (attr) {
118 		case hwmon_temp_label:
119 		case hwmon_temp_input:
120 			return 0444;
121 		default:
122 			break;
123 		}
124 		break;
125 	case hwmon_fan:
126 		switch (attr) {
127 		case hwmon_fan_label:
128 		case hwmon_fan_input:
129 			return 0444;
130 		default:
131 			break;
132 		}
133 		break;
134 	case hwmon_pwm:
135 		switch (attr) {
136 		case hwmon_pwm_input:
137 			return 0644;
138 		default:
139 			break;
140 		}
141 		break;
142 	default:
143 		break;
144 	}
145 
146 	return 0;
147 }
148 
149 /* Writes the command to the device with the rest of the report filled with zeroes */
150 static int rog_ryujin_write_expanded(struct rog_ryujin_data *priv, const u8 *cmd, int cmd_length)
151 {
152 	memcpy_and_pad(priv->buffer, MAX_REPORT_LENGTH, cmd, cmd_length, 0x00);
153 	return hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH);
154 }
155 
156 static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, int cmd_length,
157 				  struct completion *status_completion)
158 {
159 	int ret;
160 
161 	/*
162 	 * Disable raw event parsing for a moment to safely reinitialize the
163 	 * completion. Reinit is done because hidraw could have triggered
164 	 * the raw event parsing and marked the passed in completion as done.
165 	 */
166 	spin_lock_bh(&priv->status_report_request_lock);
167 	reinit_completion(status_completion);
168 	spin_unlock_bh(&priv->status_report_request_lock);
169 
170 	/* Send command for getting data */
171 	ret = rog_ryujin_write_expanded(priv, cmd, cmd_length);
172 	if (ret < 0)
173 		return ret;
174 
175 	ret = wait_for_completion_interruptible_timeout(status_completion,
176 							msecs_to_jiffies(STATUS_VALIDITY));
177 	if (ret == 0)
178 		return -ETIMEDOUT;
179 	else if (ret < 0)
180 		return ret;
181 
182 	return 0;
183 }
184 
185 static int rog_ryujin_get_status(struct rog_ryujin_data *priv)
186 {
187 	int ret;
188 
189 	if (!time_after(jiffies, priv->updated + msecs_to_jiffies(STATUS_VALIDITY))) {
190 		/* Data is up to date */
191 		return 0;
192 	}
193 
194 	/* Retrieve cooler status */
195 	ret =
196 	    rog_ryujin_execute_cmd(priv, get_cooler_status_cmd, GET_CMD_LENGTH,
197 				   &priv->cooler_status_received);
198 	if (ret < 0)
199 		return ret;
200 
201 	/* Retrieve controller status (speeds) */
202 	ret =
203 	    rog_ryujin_execute_cmd(priv, get_controller_speed_cmd, GET_CMD_LENGTH,
204 				   &priv->controller_status_received);
205 	if (ret < 0)
206 		return ret;
207 
208 	/* Retrieve cooler duty */
209 	ret =
210 	    rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH,
211 				   &priv->cooler_duty_received);
212 	if (ret < 0)
213 		return ret;
214 
215 	/* Retrieve controller duty */
216 	ret =
217 	    rog_ryujin_execute_cmd(priv, get_controller_duty_cmd, GET_CMD_LENGTH,
218 				   &priv->controller_duty_received);
219 	if (ret < 0)
220 		return ret;
221 
222 	priv->updated = jiffies;
223 	return 0;
224 }
225 
226 static int rog_ryujin_read(struct device *dev, enum hwmon_sensor_types type,
227 			   u32 attr, int channel, long *val)
228 {
229 	struct rog_ryujin_data *priv = dev_get_drvdata(dev);
230 	int ret = rog_ryujin_get_status(priv);
231 
232 	if (ret < 0)
233 		return ret;
234 
235 	switch (type) {
236 	case hwmon_temp:
237 		*val = priv->temp_input[channel];
238 		break;
239 	case hwmon_fan:
240 		*val = priv->speed_input[channel];
241 		break;
242 	case hwmon_pwm:
243 		switch (attr) {
244 		case hwmon_pwm_input:
245 			*val = priv->duty_input[channel];
246 			break;
247 		default:
248 			return -EOPNOTSUPP;
249 		}
250 		break;
251 	default:
252 		return -EOPNOTSUPP;	/* unreachable */
253 	}
254 
255 	return 0;
256 }
257 
258 static int rog_ryujin_read_string(struct device *dev, enum hwmon_sensor_types type,
259 				  u32 attr, int channel, const char **str)
260 {
261 	switch (type) {
262 	case hwmon_temp:
263 		*str = rog_ryujin_temp_label[channel];
264 		break;
265 	case hwmon_fan:
266 		*str = rog_ryujin_speed_label[channel];
267 		break;
268 	default:
269 		return -EOPNOTSUPP;	/* unreachable */
270 	}
271 
272 	return 0;
273 }
274 
275 static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel, int val)
276 {
277 	u8 set_cmd[SET_CMD_LENGTH];
278 	int ret;
279 
280 	if (channel < 2) {
281 		/*
282 		 * Retrieve cooler duty since both pump and internal fan are set
283 		 * together, then write back with one of them modified.
284 		 */
285 		ret =
286 		    rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH,
287 					   &priv->cooler_duty_received);
288 		if (ret < 0)
289 			return ret;
290 
291 		memcpy(set_cmd, set_cooler_duty_cmd, SET_CMD_LENGTH);
292 
293 		/* Cooler duties are set as 0-100% */
294 		val = rog_ryujin_pwm_to_percent(val);
295 
296 		if (channel == 0) {
297 			/* Cooler pump duty */
298 			set_cmd[RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET] = val;
299 			set_cmd[RYUJIN_SET_COOLER_FAN_DUTY_OFFSET] =
300 			    rog_ryujin_pwm_to_percent(priv->duty_input[1]);
301 		} else if (channel == 1) {
302 			/* Cooler internal fan duty */
303 			set_cmd[RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET] =
304 			    rog_ryujin_pwm_to_percent(priv->duty_input[0]);
305 			set_cmd[RYUJIN_SET_COOLER_FAN_DUTY_OFFSET] = val;
306 		}
307 
308 		return rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set);
309 	} else {
310 		/*
311 		 * Controller fan duty (channel == 2). No need to retrieve current
312 		 * duty, so just send the command.
313 		 */
314 		memcpy(set_cmd, set_controller_duty_cmd, SET_CMD_LENGTH);
315 		set_cmd[RYUJIN_SET_CONTROLLER_FAN_DUTY_OFFSET] = val;
316 
317 		ret =
318 		    rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH,
319 					   &priv->controller_duty_set);
320 		if (ret < 0)
321 			return ret;
322 	}
323 
324 	/* Lock onto this value until next refresh cycle */
325 	priv->duty_input[channel] = val;
326 
327 	return 0;
328 }
329 
330 static int rog_ryujin_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
331 			    long val)
332 {
333 	struct rog_ryujin_data *priv = dev_get_drvdata(dev);
334 	int ret;
335 
336 	switch (type) {
337 	case hwmon_pwm:
338 		switch (attr) {
339 		case hwmon_pwm_input:
340 			if (val < 0 || val > 255)
341 				return -EINVAL;
342 
343 			ret = rog_ryujin_write_fixed_duty(priv, channel, val);
344 			if (ret < 0)
345 				return ret;
346 			break;
347 		default:
348 			return -EOPNOTSUPP;
349 		}
350 		break;
351 	default:
352 		return -EOPNOTSUPP;
353 	}
354 
355 	return 0;
356 }
357 
358 static const struct hwmon_ops rog_ryujin_hwmon_ops = {
359 	.is_visible = rog_ryujin_is_visible,
360 	.read = rog_ryujin_read,
361 	.read_string = rog_ryujin_read_string,
362 	.write = rog_ryujin_write
363 };
364 
365 static const struct hwmon_channel_info *rog_ryujin_info[] = {
366 	HWMON_CHANNEL_INFO(temp,
367 			   HWMON_T_INPUT | HWMON_T_LABEL),
368 	HWMON_CHANNEL_INFO(fan,
369 			   HWMON_F_INPUT | HWMON_F_LABEL,
370 			   HWMON_F_INPUT | HWMON_F_LABEL,
371 			   HWMON_F_INPUT | HWMON_F_LABEL,
372 			   HWMON_F_INPUT | HWMON_F_LABEL,
373 			   HWMON_F_INPUT | HWMON_F_LABEL,
374 			   HWMON_F_INPUT | HWMON_F_LABEL),
375 	HWMON_CHANNEL_INFO(pwm,
376 			   HWMON_PWM_INPUT,
377 			   HWMON_PWM_INPUT,
378 			   HWMON_PWM_INPUT),
379 	NULL
380 };
381 
382 static const struct hwmon_chip_info rog_ryujin_chip_info = {
383 	.ops = &rog_ryujin_hwmon_ops,
384 	.info = rog_ryujin_info,
385 };
386 
387 static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data,
388 				int size)
389 {
390 	struct rog_ryujin_data *priv = hid_get_drvdata(hdev);
391 
392 	if (data[0] != RYUJIN_CMD_PREFIX)
393 		return 0;
394 
395 	if (data[1] == RYUJIN_GET_COOLER_STATUS_CMD_RESPONSE) {
396 		/* Received coolant temp and speeds of pump and internal fan */
397 		priv->temp_input[0] =
398 		    data[RYUJIN_TEMP_SENSOR_1] * 1000 + data[RYUJIN_TEMP_SENSOR_2] * 100;
399 		priv->speed_input[0] = get_unaligned_le16(data + RYUJIN_PUMP_SPEED);
400 		priv->speed_input[1] = get_unaligned_le16(data + RYUJIN_INTERNAL_FAN_SPEED);
401 
402 		if (!completion_done(&priv->cooler_status_received))
403 			complete_all(&priv->cooler_status_received);
404 	} else if (data[1] == RYUJIN_GET_CONTROLLER_SPEED_CMD_RESPONSE) {
405 		/* Received speeds of four fans attached to the controller */
406 		priv->speed_input[2] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_1);
407 		priv->speed_input[3] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_2);
408 		priv->speed_input[4] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_3);
409 		priv->speed_input[5] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_4);
410 
411 		if (!completion_done(&priv->controller_status_received))
412 			complete_all(&priv->controller_status_received);
413 	} else if (data[1] == RYUJIN_GET_COOLER_DUTY_CMD_RESPONSE) {
414 		/* Received report for pump and internal fan duties (in %) */
415 		if (data[RYUJIN_PUMP_DUTY] == 0 && data[RYUJIN_INTERNAL_FAN_DUTY] == 0) {
416 			/*
417 			 * We received a report with zeroes for duty in both places.
418 			 * The device returns this as a confirmation that setting values
419 			 * is successful. If we initiated a write, mark it as complete.
420 			 */
421 			if (!completion_done(&priv->cooler_duty_set))
422 				complete_all(&priv->cooler_duty_set);
423 			else if (!completion_done(&priv->cooler_duty_received))
424 				/*
425 				 * We didn't initiate a write, but received both zeroes.
426 				 * This means that either both duties are actually zero,
427 				 * or that we received a success report caused by userspace.
428 				 * We're expecting a report, so parse it.
429 				 */
430 				goto read_cooler_duty;
431 			return 0;
432 		}
433 read_cooler_duty:
434 		priv->duty_input[0] = rog_ryujin_percent_to_pwm(data[RYUJIN_PUMP_DUTY]);
435 		priv->duty_input[1] = rog_ryujin_percent_to_pwm(data[RYUJIN_INTERNAL_FAN_DUTY]);
436 
437 		if (!completion_done(&priv->cooler_duty_received))
438 			complete_all(&priv->cooler_duty_received);
439 	} else if (data[1] == RYUJIN_GET_CONTROLLER_DUTY_CMD_RESPONSE) {
440 		/* Received report for controller duty for fans (in PWM) */
441 		if (data[RYUJIN_CONTROLLER_DUTY] == 0) {
442 			/*
443 			 * We received a report with a zero for duty. The device returns this as
444 			 * a confirmation that setting the controller duty value was successful.
445 			 * If we initiated a write, mark it as complete.
446 			 */
447 			if (!completion_done(&priv->controller_duty_set))
448 				complete_all(&priv->controller_duty_set);
449 			else if (!completion_done(&priv->controller_duty_received))
450 				/*
451 				 * We didn't initiate a write, but received a zero for duty.
452 				 * This means that either the duty is actually zero, or that
453 				 * we received a success report caused by userspace.
454 				 * We're expecting a report, so parse it.
455 				 */
456 				goto read_controller_duty;
457 			return 0;
458 		}
459 read_controller_duty:
460 		priv->duty_input[2] = data[RYUJIN_CONTROLLER_DUTY];
461 
462 		if (!completion_done(&priv->controller_duty_received))
463 			complete_all(&priv->controller_duty_received);
464 	}
465 
466 	return 0;
467 }
468 
469 static int rog_ryujin_probe(struct hid_device *hdev, const struct hid_device_id *id)
470 {
471 	struct rog_ryujin_data *priv;
472 	int ret;
473 
474 	priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
475 	if (!priv)
476 		return -ENOMEM;
477 
478 	priv->hdev = hdev;
479 	hid_set_drvdata(hdev, priv);
480 
481 	/*
482 	 * Initialize priv->updated to STATUS_VALIDITY seconds in the past, making
483 	 * the initial empty data invalid for rog_ryujin_read() without the need for
484 	 * a special case there.
485 	 */
486 	priv->updated = jiffies - msecs_to_jiffies(STATUS_VALIDITY);
487 
488 	ret = hid_parse(hdev);
489 	if (ret) {
490 		hid_err(hdev, "hid parse failed with %d\n", ret);
491 		return ret;
492 	}
493 
494 	/* Enable hidraw so existing user-space tools can continue to work */
495 	ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
496 	if (ret) {
497 		hid_err(hdev, "hid hw start failed with %d\n", ret);
498 		return ret;
499 	}
500 
501 	ret = hid_hw_open(hdev);
502 	if (ret) {
503 		hid_err(hdev, "hid hw open failed with %d\n", ret);
504 		goto fail_and_stop;
505 	}
506 
507 	priv->buffer = devm_kzalloc(&hdev->dev, MAX_REPORT_LENGTH, GFP_KERNEL);
508 	if (!priv->buffer) {
509 		ret = -ENOMEM;
510 		goto fail_and_close;
511 	}
512 
513 	spin_lock_init(&priv->status_report_request_lock);
514 	init_completion(&priv->cooler_status_received);
515 	init_completion(&priv->controller_status_received);
516 	init_completion(&priv->cooler_duty_received);
517 	init_completion(&priv->controller_duty_received);
518 	init_completion(&priv->cooler_duty_set);
519 	init_completion(&priv->controller_duty_set);
520 
521 	priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "rog_ryujin",
522 							  priv, &rog_ryujin_chip_info, NULL);
523 	if (IS_ERR(priv->hwmon_dev)) {
524 		ret = PTR_ERR(priv->hwmon_dev);
525 		hid_err(hdev, "hwmon registration failed with %d\n", ret);
526 		goto fail_and_close;
527 	}
528 
529 	return 0;
530 
531 fail_and_close:
532 	hid_hw_close(hdev);
533 fail_and_stop:
534 	hid_hw_stop(hdev);
535 	return ret;
536 }
537 
538 static void rog_ryujin_remove(struct hid_device *hdev)
539 {
540 	struct rog_ryujin_data *priv = hid_get_drvdata(hdev);
541 
542 	hwmon_device_unregister(priv->hwmon_dev);
543 
544 	hid_hw_close(hdev);
545 	hid_hw_stop(hdev);
546 }
547 
548 static const struct hid_device_id rog_ryujin_table[] = {
549 	{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS_ROG, USB_PRODUCT_ID_RYUJIN_AIO) },
550 	{ }
551 };
552 
553 MODULE_DEVICE_TABLE(hid, rog_ryujin_table);
554 
555 static struct hid_driver rog_ryujin_driver = {
556 	.name = "rog_ryujin",
557 	.id_table = rog_ryujin_table,
558 	.probe = rog_ryujin_probe,
559 	.remove = rog_ryujin_remove,
560 	.raw_event = rog_ryujin_raw_event,
561 };
562 
563 static int __init rog_ryujin_init(void)
564 {
565 	return hid_register_driver(&rog_ryujin_driver);
566 }
567 
568 static void __exit rog_ryujin_exit(void)
569 {
570 	hid_unregister_driver(&rog_ryujin_driver);
571 }
572 
573 /* When compiled into the kernel, initialize after the HID bus */
574 late_initcall(rog_ryujin_init);
575 module_exit(rog_ryujin_exit);
576 
577 MODULE_LICENSE("GPL");
578 MODULE_AUTHOR("Aleksa Savic <savicaleksa83@gmail.com>");
579 MODULE_DESCRIPTION("Hwmon driver for Asus ROG Ryujin II 360 AIO cooler");
580