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 unsigned long flags; 188 int ret; 189 190 /* 191 * Disable raw event parsing for a moment to safely reinitialize the 192 * completion. Reinit is done because hidraw could have triggered 193 * the raw event parsing and marked the passed in completion as done. 194 */ 195 spin_lock_irqsave(&priv->status_report_request_lock, flags); 196 reinit_completion(status_completion); 197 spin_unlock_irqrestore(&priv->status_report_request_lock, flags); 198 199 /* Send command for getting data */ 200 ret = rog_ryujin_write_expanded(priv, cmd, cmd_length); 201 if (ret < 0) 202 return ret; 203 204 ret = wait_for_completion_interruptible_timeout(status_completion, 205 msecs_to_jiffies(STATUS_VALIDITY)); 206 if (ret == 0) 207 return -ETIMEDOUT; 208 else if (ret < 0) 209 return ret; 210 211 return 0; 212 } 213 214 static int rog_ryujin_get_status(struct rog_ryujin_data *priv) 215 { 216 int ret; 217 218 if (!time_after(jiffies, priv->updated + msecs_to_jiffies(STATUS_VALIDITY))) { 219 /* Data is up to date */ 220 return 0; 221 } 222 223 /* Retrieve cooler status */ 224 ret = 225 rog_ryujin_execute_cmd(priv, get_cooler_status_cmd, GET_CMD_LENGTH, 226 &priv->cooler_status_received); 227 if (ret < 0) 228 return ret; 229 230 if (priv->info->has_controller) { 231 /* Retrieve controller status (speeds) */ 232 ret = rog_ryujin_execute_cmd(priv, get_controller_speed_cmd, 233 GET_CMD_LENGTH, 234 &priv->controller_status_received); 235 if (ret < 0) 236 return ret; 237 } 238 239 /* Retrieve cooler duty */ 240 ret = 241 rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH, 242 &priv->cooler_duty_received); 243 if (ret < 0) 244 return ret; 245 246 if (priv->info->has_controller) { 247 /* Retrieve controller duty */ 248 ret = rog_ryujin_execute_cmd(priv, get_controller_duty_cmd, 249 GET_CMD_LENGTH, 250 &priv->controller_duty_received); 251 if (ret < 0) 252 return ret; 253 } 254 255 priv->updated = jiffies; 256 return 0; 257 } 258 259 static int rog_ryujin_read(struct device *dev, enum hwmon_sensor_types type, 260 u32 attr, int channel, long *val) 261 { 262 struct rog_ryujin_data *priv = dev_get_drvdata(dev); 263 int ret = rog_ryujin_get_status(priv); 264 265 if (ret < 0) 266 return ret; 267 268 switch (type) { 269 case hwmon_temp: 270 *val = priv->temp_input[channel]; 271 break; 272 case hwmon_fan: 273 *val = priv->speed_input[channel]; 274 break; 275 case hwmon_pwm: 276 switch (attr) { 277 case hwmon_pwm_input: 278 *val = priv->duty_input[channel]; 279 break; 280 default: 281 return -EOPNOTSUPP; 282 } 283 break; 284 default: 285 return -EOPNOTSUPP; /* unreachable */ 286 } 287 288 return 0; 289 } 290 291 static int rog_ryujin_read_string(struct device *dev, enum hwmon_sensor_types type, 292 u32 attr, int channel, const char **str) 293 { 294 switch (type) { 295 case hwmon_temp: 296 *str = rog_ryujin_temp_label[channel]; 297 break; 298 case hwmon_fan: 299 *str = rog_ryujin_speed_label[channel]; 300 break; 301 default: 302 return -EOPNOTSUPP; /* unreachable */ 303 } 304 305 return 0; 306 } 307 308 static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel, int val) 309 { 310 u8 set_cmd[SET_CMD_LENGTH]; 311 int ret; 312 313 if (channel < 2) { 314 /* 315 * Retrieve cooler duty since both pump and internal fan are set 316 * together, then write back with one of them modified. 317 */ 318 ret = 319 rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH, 320 &priv->cooler_duty_received); 321 if (ret < 0) 322 return ret; 323 324 memcpy(set_cmd, set_cooler_duty_cmd, SET_CMD_LENGTH); 325 set_cmd[2] = priv->info->duty_channel; 326 327 /* Cooler duties are set as 0-100% */ 328 val = rog_ryujin_pwm_to_percent(val); 329 330 if (channel == 0) { 331 /* Cooler pump duty */ 332 set_cmd[RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET] = val; 333 set_cmd[RYUJIN_SET_COOLER_FAN_DUTY_OFFSET] = 334 rog_ryujin_pwm_to_percent(priv->duty_input[1]); 335 } else if (channel == 1) { 336 /* Cooler internal fan duty */ 337 set_cmd[RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET] = 338 rog_ryujin_pwm_to_percent(priv->duty_input[0]); 339 set_cmd[RYUJIN_SET_COOLER_FAN_DUTY_OFFSET] = val; 340 } 341 342 return rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set); 343 } else { 344 /* 345 * Controller fan duty (channel == 2). No need to retrieve current 346 * duty, so just send the command. 347 */ 348 memcpy(set_cmd, set_controller_duty_cmd, SET_CMD_LENGTH); 349 set_cmd[RYUJIN_SET_CONTROLLER_FAN_DUTY_OFFSET] = val; 350 351 ret = 352 rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, 353 &priv->controller_duty_set); 354 if (ret < 0) 355 return ret; 356 } 357 358 /* Lock onto this value until next refresh cycle */ 359 priv->duty_input[channel] = val; 360 361 return 0; 362 } 363 364 static int rog_ryujin_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, 365 long val) 366 { 367 struct rog_ryujin_data *priv = dev_get_drvdata(dev); 368 int ret; 369 370 switch (type) { 371 case hwmon_pwm: 372 switch (attr) { 373 case hwmon_pwm_input: 374 if (val < 0 || val > 255) 375 return -EINVAL; 376 377 ret = rog_ryujin_write_fixed_duty(priv, channel, val); 378 if (ret < 0) 379 return ret; 380 break; 381 default: 382 return -EOPNOTSUPP; 383 } 384 break; 385 default: 386 return -EOPNOTSUPP; 387 } 388 389 return 0; 390 } 391 392 static const struct hwmon_ops rog_ryujin_hwmon_ops = { 393 .is_visible = rog_ryujin_is_visible, 394 .read = rog_ryujin_read, 395 .read_string = rog_ryujin_read_string, 396 .write = rog_ryujin_write 397 }; 398 399 static const struct hwmon_channel_info *rog_ryujin_info[] = { 400 HWMON_CHANNEL_INFO(temp, 401 HWMON_T_INPUT | HWMON_T_LABEL), 402 HWMON_CHANNEL_INFO(fan, 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_F_INPUT | HWMON_F_LABEL), 409 HWMON_CHANNEL_INFO(pwm, 410 HWMON_PWM_INPUT, 411 HWMON_PWM_INPUT, 412 HWMON_PWM_INPUT), 413 NULL 414 }; 415 416 static const struct hwmon_chip_info rog_ryujin_chip_info = { 417 .ops = &rog_ryujin_hwmon_ops, 418 .info = rog_ryujin_info, 419 }; 420 421 static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, 422 int size) 423 { 424 struct rog_ryujin_data *priv = hid_get_drvdata(hdev); 425 unsigned long flags; 426 427 if (size < 2 || data[0] != RYUJIN_CMD_PREFIX) 428 return 0; 429 430 spin_lock_irqsave(&priv->status_report_request_lock, flags); 431 432 if (data[1] == RYUJIN_GET_COOLER_STATUS_CMD_RESPONSE) { 433 if (size <= priv->info->temp_offset + 1 || 434 size <= priv->info->pump_speed_offset + 1 || 435 size <= priv->info->fan_speed_offset + 1) 436 goto unlock; 437 438 /* Received coolant temp and speeds of pump and internal fan */ 439 priv->temp_input[0] = data[priv->info->temp_offset] * 1000 + 440 data[priv->info->temp_offset + 1] * 100; 441 priv->speed_input[0] = 442 get_unaligned_le16(data + priv->info->pump_speed_offset); 443 priv->speed_input[1] = 444 get_unaligned_le16(data + priv->info->fan_speed_offset); 445 446 if (!completion_done(&priv->cooler_status_received)) 447 complete_all(&priv->cooler_status_received); 448 } else if (data[1] == RYUJIN_GET_CONTROLLER_SPEED_CMD_RESPONSE) { 449 if (size <= RYUJIN_CONTROLLER_SPEED_3 + 1) 450 goto unlock; 451 452 /* Received speeds of four fans attached to the controller */ 453 priv->speed_input[2] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_1); 454 priv->speed_input[3] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_2); 455 priv->speed_input[4] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_3); 456 priv->speed_input[5] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_4); 457 458 if (!completion_done(&priv->controller_status_received)) 459 complete_all(&priv->controller_status_received); 460 } else if (data[1] == RYUJIN_GET_COOLER_DUTY_CMD_RESPONSE) { 461 if (size <= RYUJIN_INTERNAL_FAN_DUTY) 462 goto unlock; 463 464 /* Received report for pump and internal fan duties (in %) */ 465 if (data[RYUJIN_PUMP_DUTY] == 0 && data[RYUJIN_INTERNAL_FAN_DUTY] == 0) { 466 /* 467 * We received a report with zeroes for duty in both places. 468 * The device returns this as a confirmation that setting values 469 * is successful. If we initiated a write, mark it as complete. 470 */ 471 if (!completion_done(&priv->cooler_duty_set)) 472 complete_all(&priv->cooler_duty_set); 473 else if (!completion_done(&priv->cooler_duty_received)) 474 /* 475 * We didn't initiate a write, but received both zeroes. 476 * This means that either both duties are actually zero, 477 * or that we received a success report caused by userspace. 478 * We're expecting a report, so parse it. 479 */ 480 goto read_cooler_duty; 481 goto unlock; 482 } 483 read_cooler_duty: 484 priv->duty_input[0] = rog_ryujin_percent_to_pwm(data[RYUJIN_PUMP_DUTY]); 485 priv->duty_input[1] = rog_ryujin_percent_to_pwm(data[RYUJIN_INTERNAL_FAN_DUTY]); 486 487 if (!completion_done(&priv->cooler_duty_received)) 488 complete_all(&priv->cooler_duty_received); 489 } else if (data[1] == RYUJIN_GET_CONTROLLER_DUTY_CMD_RESPONSE) { 490 if (size <= RYUJIN_CONTROLLER_DUTY) 491 goto unlock; 492 493 /* Received report for controller duty for fans (in PWM) */ 494 if (data[RYUJIN_CONTROLLER_DUTY] == 0) { 495 /* 496 * We received a report with a zero for duty. The device returns this as 497 * a confirmation that setting the controller duty value was successful. 498 * If we initiated a write, mark it as complete. 499 */ 500 if (!completion_done(&priv->controller_duty_set)) 501 complete_all(&priv->controller_duty_set); 502 else if (!completion_done(&priv->controller_duty_received)) 503 /* 504 * We didn't initiate a write, but received a zero for duty. 505 * This means that either the duty is actually zero, or that 506 * we received a success report caused by userspace. 507 * We're expecting a report, so parse it. 508 */ 509 goto read_controller_duty; 510 goto unlock; 511 } 512 read_controller_duty: 513 priv->duty_input[2] = data[RYUJIN_CONTROLLER_DUTY]; 514 515 if (!completion_done(&priv->controller_duty_received)) 516 complete_all(&priv->controller_duty_received); 517 } 518 519 unlock: 520 spin_unlock_irqrestore(&priv->status_report_request_lock, flags); 521 return 0; 522 } 523 524 static int rog_ryujin_probe(struct hid_device *hdev, const struct hid_device_id *id) 525 { 526 struct rog_ryujin_data *priv; 527 int ret; 528 529 if (!id->driver_data) 530 return -EINVAL; 531 532 priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL); 533 if (!priv) 534 return -ENOMEM; 535 536 priv->hdev = hdev; 537 priv->info = (const struct rog_ryujin_device_info *)id->driver_data; 538 hid_set_drvdata(hdev, priv); 539 540 /* 541 * Initialize priv->updated to STATUS_VALIDITY seconds in the past, making 542 * the initial empty data invalid for rog_ryujin_read() without the need for 543 * a special case there. 544 */ 545 priv->updated = jiffies - msecs_to_jiffies(STATUS_VALIDITY); 546 547 ret = hid_parse(hdev); 548 if (ret) { 549 hid_err(hdev, "hid parse failed with %d\n", ret); 550 return ret; 551 } 552 553 /* Enable hidraw so existing user-space tools can continue to work */ 554 ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); 555 if (ret) { 556 hid_err(hdev, "hid hw start failed with %d\n", ret); 557 return ret; 558 } 559 560 ret = hid_hw_open(hdev); 561 if (ret) { 562 hid_err(hdev, "hid hw open failed with %d\n", ret); 563 goto fail_and_stop; 564 } 565 566 priv->buffer = devm_kzalloc(&hdev->dev, MAX_REPORT_LENGTH, GFP_KERNEL); 567 if (!priv->buffer) { 568 ret = -ENOMEM; 569 goto fail_and_close; 570 } 571 572 spin_lock_init(&priv->status_report_request_lock); 573 init_completion(&priv->cooler_status_received); 574 init_completion(&priv->controller_status_received); 575 init_completion(&priv->cooler_duty_received); 576 init_completion(&priv->controller_duty_received); 577 init_completion(&priv->cooler_duty_set); 578 init_completion(&priv->controller_duty_set); 579 580 priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "rog_ryujin", 581 priv, &rog_ryujin_chip_info, NULL); 582 if (IS_ERR(priv->hwmon_dev)) { 583 ret = PTR_ERR(priv->hwmon_dev); 584 hid_err(hdev, "hwmon registration failed with %d\n", ret); 585 goto fail_and_close; 586 } 587 588 return 0; 589 590 fail_and_close: 591 hid_hw_close(hdev); 592 fail_and_stop: 593 hid_hw_stop(hdev); 594 return ret; 595 } 596 597 static void rog_ryujin_remove(struct hid_device *hdev) 598 { 599 struct rog_ryujin_data *priv = hid_get_drvdata(hdev); 600 601 hwmon_device_unregister(priv->hwmon_dev); 602 603 hid_hw_close(hdev); 604 hid_hw_stop(hdev); 605 } 606 607 static const struct hid_device_id rog_ryujin_table[] = { 608 { HID_USB_DEVICE(USB_VENDOR_ID_ASUS_ROG, USB_PRODUCT_ID_RYUJIN_AIO), 609 .driver_data = (kernel_ulong_t)&rog_ryujin_ii_360_info }, 610 { HID_USB_DEVICE(USB_VENDOR_ID_ASUS_ROG, USB_PRODUCT_ID_RYUJIN_III_EXTREME), 611 .driver_data = (kernel_ulong_t)&rog_ryujin_iii_info }, 612 { HID_USB_DEVICE(USB_VENDOR_ID_ASUS_ROG, USB_PRODUCT_ID_RYUJIN_III_EVA), 613 .driver_data = (kernel_ulong_t)&rog_ryujin_iii_info }, 614 { HID_USB_DEVICE(USB_VENDOR_ID_ASUS_ROG, USB_PRODUCT_ID_RYUJIN_III_WHITE), 615 .driver_data = (kernel_ulong_t)&rog_ryujin_iii_info }, 616 { } 617 }; 618 619 MODULE_DEVICE_TABLE(hid, rog_ryujin_table); 620 621 static struct hid_driver rog_ryujin_driver = { 622 .name = "rog_ryujin", 623 .id_table = rog_ryujin_table, 624 .probe = rog_ryujin_probe, 625 .remove = rog_ryujin_remove, 626 .raw_event = rog_ryujin_raw_event, 627 }; 628 629 static int __init rog_ryujin_init(void) 630 { 631 return hid_register_driver(&rog_ryujin_driver); 632 } 633 634 static void __exit rog_ryujin_exit(void) 635 { 636 hid_unregister_driver(&rog_ryujin_driver); 637 } 638 639 /* When compiled into the kernel, initialize after the HID bus */ 640 late_initcall(rog_ryujin_init); 641 module_exit(rog_ryujin_exit); 642 643 MODULE_LICENSE("GPL"); 644 MODULE_AUTHOR("Aleksa Savic <savicaleksa83@gmail.com>"); 645 MODULE_DESCRIPTION("Hwmon driver for Asus ROG Ryujin AIO coolers"); 646