]> Git Repo - J-linux.git/blob - drivers/hwmon/asus_rog_ryujin.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / hwmon / asus_rog_ryujin.c
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 <[email protected]>
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 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 <[email protected]>");
609 MODULE_DESCRIPTION("Hwmon driver for Asus ROG Ryujin II 360 AIO cooler");
This page took 0.05853 seconds and 4 git commands to generate.