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