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