asus_rog_ryujin.c 16 KB

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