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