1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * corsair-psu.c - Linux driver for Corsair power supplies with HID sensors interface
4 * Copyright (C) 2020 Wilken Gottwalt <wilken.gottwalt@posteo.net>
5 */
6
7 #include <linux/completion.h>
8 #include <linux/debugfs.h>
9 #include <linux/errno.h>
10 #include <linux/hid.h>
11 #include <linux/hwmon.h>
12 #include <linux/jiffies.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/slab.h>
16 #include <linux/types.h>
17
18 /*
19 * Corsair protocol for PSUs
20 *
21 * message size = 64 bytes (request and response, little endian)
22 * request:
23 * [length][command][param0][param1][paramX]...
24 * reply:
25 * [echo of length][echo of command][data0][data1][dataX]...
26 *
27 * - commands are byte sized opcodes
28 * - length is the sum of all bytes of the commands/params
29 * - the micro-controller of most of these PSUs support concatenation in the request and reply,
30 * but it is better to not rely on this (it is also hard to parse)
31 * - the driver uses raw events to be accessible from userspace (though this is not really
32 * supported, it is just there for convenience, may be removed in the future)
33 * - a reply always starts with the length and command in the same order the request used it
34 * - length of the reply data is specific to the command used
35 * - some of the commands work on a rail and can be switched to a specific rail (0 = 12v,
36 * 1 = 5v, 2 = 3.3v)
37 * - the format of the init command 0xFE is swapped length/command bytes
38 * - parameter bytes amount and values are specific to the command (rail setting is the only
39 * one for now that uses non-zero values)
40 * - the driver supports debugfs for values not fitting into the hwmon class
41 * - not every device class (HXi or RMi) supports all commands
42 * - if configured wrong the PSU resets or shuts down, often before actually hitting the
43 * reported critical temperature
44 * - new models like HX1500i Series 2023 have changes in the reported vendor and product
45 * strings, both are slightly longer now, report vendor and product in one string and are
46 * the same now
47 */
48
49 #define DRIVER_NAME "corsair-psu"
50
51 #define REPLY_SIZE 24 /* max length of a reply to a single command */
52 #define CMD_BUFFER_SIZE 64
53 #define CMD_TIMEOUT_MS 250
54 #define SECONDS_PER_HOUR (60 * 60)
55 #define SECONDS_PER_DAY (SECONDS_PER_HOUR * 24)
56 #define RAIL_COUNT 3 /* 3v3 + 5v + 12v */
57 #define TEMP_COUNT 2
58 #define OCP_MULTI_RAIL 0x02
59
60 #define PSU_CMD_SELECT_RAIL 0x00 /* expects length 2 */
61 #define PSU_CMD_FAN_PWM 0x3B /* the rest of the commands expect length 3 */
62 #define PSU_CMD_RAIL_VOLTS_HCRIT 0x40
63 #define PSU_CMD_RAIL_VOLTS_LCRIT 0x44
64 #define PSU_CMD_RAIL_AMPS_HCRIT 0x46
65 #define PSU_CMD_TEMP_HCRIT 0x4F
66 #define PSU_CMD_IN_VOLTS 0x88
67 #define PSU_CMD_IN_AMPS 0x89
68 #define PSU_CMD_RAIL_VOLTS 0x8B
69 #define PSU_CMD_RAIL_AMPS 0x8C
70 #define PSU_CMD_TEMP0 0x8D
71 #define PSU_CMD_TEMP1 0x8E
72 #define PSU_CMD_FAN 0x90
73 #define PSU_CMD_RAIL_WATTS 0x96
74 #define PSU_CMD_VEND_STR 0x99
75 #define PSU_CMD_PROD_STR 0x9A
76 #define PSU_CMD_TOTAL_UPTIME 0xD1
77 #define PSU_CMD_UPTIME 0xD2
78 #define PSU_CMD_OCPMODE 0xD8
79 #define PSU_CMD_TOTAL_WATTS 0xEE
80 #define PSU_CMD_FAN_PWM_ENABLE 0xF0
81 #define PSU_CMD_INIT 0xFE
82
83 #define L_IN_VOLTS "v_in"
84 #define L_OUT_VOLTS_12V "v_out +12v"
85 #define L_OUT_VOLTS_5V "v_out +5v"
86 #define L_OUT_VOLTS_3_3V "v_out +3.3v"
87 #define L_IN_AMPS "curr in"
88 #define L_AMPS_12V "curr +12v"
89 #define L_AMPS_5V "curr +5v"
90 #define L_AMPS_3_3V "curr +3.3v"
91 #define L_FAN "psu fan"
92 #define L_TEMP0 "vrm temp"
93 #define L_TEMP1 "case temp"
94 #define L_WATTS "power total"
95 #define L_WATTS_12V "power +12v"
96 #define L_WATTS_5V "power +5v"
97 #define L_WATTS_3_3V "power +3.3v"
98
99 static const char *const label_watts[] = {
100 L_WATTS,
101 L_WATTS_12V,
102 L_WATTS_5V,
103 L_WATTS_3_3V
104 };
105
106 static const char *const label_volts[] = {
107 L_IN_VOLTS,
108 L_OUT_VOLTS_12V,
109 L_OUT_VOLTS_5V,
110 L_OUT_VOLTS_3_3V
111 };
112
113 static const char *const label_amps[] = {
114 L_IN_AMPS,
115 L_AMPS_12V,
116 L_AMPS_5V,
117 L_AMPS_3_3V
118 };
119
120 struct corsairpsu_data {
121 struct hid_device *hdev;
122 struct device *hwmon_dev;
123 struct dentry *debugfs;
124 struct completion wait_completion;
125 u8 *cmd_buffer;
126 char vendor[REPLY_SIZE];
127 char product[REPLY_SIZE];
128 long temp_crit[TEMP_COUNT];
129 long in_crit[RAIL_COUNT];
130 long in_lcrit[RAIL_COUNT];
131 long curr_crit[RAIL_COUNT];
132 u8 temp_crit_support;
133 u8 in_crit_support;
134 u8 in_lcrit_support;
135 u8 curr_crit_support;
136 bool in_curr_cmd_support; /* not all commands are supported on every PSU */
137 };
138
139 /* some values are SMBus LINEAR11 data which need a conversion */
corsairpsu_linear11_to_long(const u16 val,const int scale)140 static long corsairpsu_linear11_to_long(const u16 val, const int scale)
141 {
142 const int exp = ((s16)val) >> 11;
143 const int mant = ((s16)((val & 0x7ff) << 5)) >> 5;
144 s64 result = mant * scale;
145
146 if (exp >= 0)
147 result *= (int)(1UL << exp);
148 else
149 result >>= -exp;
150
151 return clamp(result, LONG_MIN, LONG_MAX);
152 }
153
154 /* the micro-controller uses percentage values to control pwm */
corsairpsu_dutycycle_to_pwm(const long dutycycle)155 static int corsairpsu_dutycycle_to_pwm(const long dutycycle)
156 {
157 const int result = (256 << 16) / 100;
158
159 return (result * dutycycle) >> 16;
160 }
161
corsairpsu_usb_cmd(struct corsairpsu_data * priv,u8 p0,u8 p1,u8 p2,void * data)162 static int corsairpsu_usb_cmd(struct corsairpsu_data *priv, u8 p0, u8 p1, u8 p2, void *data)
163 {
164 unsigned long time;
165 int ret;
166
167 memset(priv->cmd_buffer, 0, CMD_BUFFER_SIZE);
168 priv->cmd_buffer[0] = p0;
169 priv->cmd_buffer[1] = p1;
170 priv->cmd_buffer[2] = p2;
171
172 reinit_completion(&priv->wait_completion);
173
174 ret = hid_hw_output_report(priv->hdev, priv->cmd_buffer, CMD_BUFFER_SIZE);
175 if (ret < 0)
176 return ret;
177
178 time = wait_for_completion_timeout(&priv->wait_completion,
179 msecs_to_jiffies(CMD_TIMEOUT_MS));
180 if (!time)
181 return -ETIMEDOUT;
182
183 /*
184 * at the start of the reply is an echo of the send command/length in the same order it
185 * was send, not every command is supported on every device class, if a command is not
186 * supported, the length value in the reply is okay, but the command value is set to 0
187 */
188 if (p0 != priv->cmd_buffer[0] || p1 != priv->cmd_buffer[1])
189 return -EOPNOTSUPP;
190
191 if (data)
192 memcpy(data, priv->cmd_buffer + 2, REPLY_SIZE);
193
194 return 0;
195 }
196
corsairpsu_init(struct corsairpsu_data * priv)197 static int corsairpsu_init(struct corsairpsu_data *priv)
198 {
199 /*
200 * PSU_CMD_INIT uses swapped length/command and expects 2 parameter bytes, this command
201 * actually generates a reply, but we don't need it
202 */
203 return corsairpsu_usb_cmd(priv, PSU_CMD_INIT, 3, 0, NULL);
204 }
205
corsairpsu_fwinfo(struct corsairpsu_data * priv)206 static int corsairpsu_fwinfo(struct corsairpsu_data *priv)
207 {
208 int ret;
209
210 ret = corsairpsu_usb_cmd(priv, 3, PSU_CMD_VEND_STR, 0, priv->vendor);
211 if (ret < 0)
212 return ret;
213
214 ret = corsairpsu_usb_cmd(priv, 3, PSU_CMD_PROD_STR, 0, priv->product);
215 if (ret < 0)
216 return ret;
217
218 return 0;
219 }
220
corsairpsu_request(struct corsairpsu_data * priv,u8 cmd,u8 rail,void * data)221 static int corsairpsu_request(struct corsairpsu_data *priv, u8 cmd, u8 rail, void *data)
222 {
223 int ret;
224
225 switch (cmd) {
226 case PSU_CMD_RAIL_VOLTS_HCRIT:
227 case PSU_CMD_RAIL_VOLTS_LCRIT:
228 case PSU_CMD_RAIL_AMPS_HCRIT:
229 case PSU_CMD_RAIL_VOLTS:
230 case PSU_CMD_RAIL_AMPS:
231 case PSU_CMD_RAIL_WATTS:
232 ret = corsairpsu_usb_cmd(priv, 2, PSU_CMD_SELECT_RAIL, rail, NULL);
233 if (ret < 0)
234 return ret;
235 break;
236 default:
237 break;
238 }
239
240 return corsairpsu_usb_cmd(priv, 3, cmd, 0, data);
241 }
242
corsairpsu_get_value(struct corsairpsu_data * priv,u8 cmd,u8 rail,long * val)243 static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, long *val)
244 {
245 u8 data[REPLY_SIZE];
246 long tmp;
247 int ret;
248
249 ret = corsairpsu_request(priv, cmd, rail, data);
250 if (ret < 0)
251 return ret;
252
253 /*
254 * the biggest value here comes from the uptime command and to exceed MAXINT total uptime
255 * needs to be about 68 years, the rest are u16 values and the biggest value coming out of
256 * the LINEAR11 conversion are the watts values which are about 1500 for the strongest psu
257 * supported (HX1500i)
258 */
259 tmp = ((long)data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0];
260 switch (cmd) {
261 case PSU_CMD_RAIL_VOLTS_HCRIT:
262 case PSU_CMD_RAIL_VOLTS_LCRIT:
263 case PSU_CMD_RAIL_AMPS_HCRIT:
264 case PSU_CMD_TEMP_HCRIT:
265 case PSU_CMD_IN_VOLTS:
266 case PSU_CMD_IN_AMPS:
267 case PSU_CMD_RAIL_VOLTS:
268 case PSU_CMD_RAIL_AMPS:
269 case PSU_CMD_TEMP0:
270 case PSU_CMD_TEMP1:
271 *val = corsairpsu_linear11_to_long(tmp & 0xFFFF, 1000);
272 break;
273 case PSU_CMD_FAN:
274 *val = corsairpsu_linear11_to_long(tmp & 0xFFFF, 1);
275 break;
276 case PSU_CMD_FAN_PWM_ENABLE:
277 *val = corsairpsu_linear11_to_long(tmp & 0xFFFF, 1);
278 /*
279 * 0 = automatic mode, means the micro-controller controls the fan using a plan
280 * which can be modified, but changing this plan is not supported by this
281 * driver, the matching PWM mode is automatic fan speed control = PWM 2
282 * 1 = fixed mode, fan runs at a fixed speed represented by a percentage
283 * value 0-100, this matches the PWM manual fan speed control = PWM 1
284 * technically there is no PWM no fan speed control mode, it would be a combination
285 * of 1 at 100%
286 */
287 if (*val == 0)
288 *val = 2;
289 break;
290 case PSU_CMD_FAN_PWM:
291 *val = corsairpsu_linear11_to_long(tmp & 0xFFFF, 1);
292 *val = corsairpsu_dutycycle_to_pwm(*val);
293 break;
294 case PSU_CMD_RAIL_WATTS:
295 case PSU_CMD_TOTAL_WATTS:
296 *val = corsairpsu_linear11_to_long(tmp & 0xFFFF, 1000000);
297 break;
298 case PSU_CMD_TOTAL_UPTIME:
299 case PSU_CMD_UPTIME:
300 case PSU_CMD_OCPMODE:
301 *val = tmp;
302 break;
303 default:
304 ret = -EOPNOTSUPP;
305 break;
306 }
307
308 return ret;
309 }
310
corsairpsu_get_criticals(struct corsairpsu_data * priv)311 static void corsairpsu_get_criticals(struct corsairpsu_data *priv)
312 {
313 long tmp;
314 int rail;
315
316 for (rail = 0; rail < TEMP_COUNT; ++rail) {
317 if (!corsairpsu_get_value(priv, PSU_CMD_TEMP_HCRIT, rail, &tmp)) {
318 priv->temp_crit_support |= BIT(rail);
319 priv->temp_crit[rail] = tmp;
320 }
321 }
322
323 for (rail = 0; rail < RAIL_COUNT; ++rail) {
324 if (!corsairpsu_get_value(priv, PSU_CMD_RAIL_VOLTS_HCRIT, rail, &tmp)) {
325 priv->in_crit_support |= BIT(rail);
326 priv->in_crit[rail] = tmp;
327 }
328
329 if (!corsairpsu_get_value(priv, PSU_CMD_RAIL_VOLTS_LCRIT, rail, &tmp)) {
330 priv->in_lcrit_support |= BIT(rail);
331 priv->in_lcrit[rail] = tmp;
332 }
333
334 if (!corsairpsu_get_value(priv, PSU_CMD_RAIL_AMPS_HCRIT, rail, &tmp)) {
335 priv->curr_crit_support |= BIT(rail);
336 priv->curr_crit[rail] = tmp;
337 }
338 }
339 }
340
corsairpsu_check_cmd_support(struct corsairpsu_data * priv)341 static void corsairpsu_check_cmd_support(struct corsairpsu_data *priv)
342 {
343 long tmp;
344
345 priv->in_curr_cmd_support = !corsairpsu_get_value(priv, PSU_CMD_IN_AMPS, 0, &tmp);
346 }
347
corsairpsu_hwmon_temp_is_visible(const struct corsairpsu_data * priv,u32 attr,int channel)348 static umode_t corsairpsu_hwmon_temp_is_visible(const struct corsairpsu_data *priv, u32 attr,
349 int channel)
350 {
351 umode_t res = 0444;
352
353 switch (attr) {
354 case hwmon_temp_input:
355 case hwmon_temp_label:
356 case hwmon_temp_crit:
357 if (channel > 0 && !(priv->temp_crit_support & BIT(channel - 1)))
358 res = 0;
359 break;
360 default:
361 break;
362 }
363
364 return res;
365 }
366
corsairpsu_hwmon_fan_is_visible(const struct corsairpsu_data * priv,u32 attr,int channel)367 static umode_t corsairpsu_hwmon_fan_is_visible(const struct corsairpsu_data *priv, u32 attr,
368 int channel)
369 {
370 switch (attr) {
371 case hwmon_fan_input:
372 case hwmon_fan_label:
373 return 0444;
374 default:
375 return 0;
376 }
377 }
378
corsairpsu_hwmon_pwm_is_visible(const struct corsairpsu_data * priv,u32 attr,int channel)379 static umode_t corsairpsu_hwmon_pwm_is_visible(const struct corsairpsu_data *priv, u32 attr,
380 int channel)
381 {
382 switch (attr) {
383 case hwmon_pwm_input:
384 case hwmon_pwm_enable:
385 return 0444;
386 default:
387 return 0;
388 }
389 }
390
corsairpsu_hwmon_power_is_visible(const struct corsairpsu_data * priv,u32 attr,int channel)391 static umode_t corsairpsu_hwmon_power_is_visible(const struct corsairpsu_data *priv, u32 attr,
392 int channel)
393 {
394 switch (attr) {
395 case hwmon_power_input:
396 case hwmon_power_label:
397 return 0444;
398 default:
399 return 0;
400 }
401 }
402
corsairpsu_hwmon_in_is_visible(const struct corsairpsu_data * priv,u32 attr,int channel)403 static umode_t corsairpsu_hwmon_in_is_visible(const struct corsairpsu_data *priv, u32 attr,
404 int channel)
405 {
406 umode_t res = 0444;
407
408 switch (attr) {
409 case hwmon_in_input:
410 case hwmon_in_label:
411 case hwmon_in_crit:
412 if (channel > 0 && !(priv->in_crit_support & BIT(channel - 1)))
413 res = 0;
414 break;
415 case hwmon_in_lcrit:
416 if (channel > 0 && !(priv->in_lcrit_support & BIT(channel - 1)))
417 res = 0;
418 break;
419 default:
420 break;
421 }
422
423 return res;
424 }
425
corsairpsu_hwmon_curr_is_visible(const struct corsairpsu_data * priv,u32 attr,int channel)426 static umode_t corsairpsu_hwmon_curr_is_visible(const struct corsairpsu_data *priv, u32 attr,
427 int channel)
428 {
429 umode_t res = 0444;
430
431 switch (attr) {
432 case hwmon_curr_input:
433 if (channel == 0 && !priv->in_curr_cmd_support)
434 res = 0;
435 break;
436 case hwmon_curr_label:
437 case hwmon_curr_crit:
438 if (channel > 0 && !(priv->curr_crit_support & BIT(channel - 1)))
439 res = 0;
440 break;
441 default:
442 break;
443 }
444
445 return res;
446 }
447
corsairpsu_hwmon_ops_is_visible(const void * data,enum hwmon_sensor_types type,u32 attr,int channel)448 static umode_t corsairpsu_hwmon_ops_is_visible(const void *data, enum hwmon_sensor_types type,
449 u32 attr, int channel)
450 {
451 const struct corsairpsu_data *priv = data;
452
453 switch (type) {
454 case hwmon_temp:
455 return corsairpsu_hwmon_temp_is_visible(priv, attr, channel);
456 case hwmon_fan:
457 return corsairpsu_hwmon_fan_is_visible(priv, attr, channel);
458 case hwmon_pwm:
459 return corsairpsu_hwmon_pwm_is_visible(priv, attr, channel);
460 case hwmon_power:
461 return corsairpsu_hwmon_power_is_visible(priv, attr, channel);
462 case hwmon_in:
463 return corsairpsu_hwmon_in_is_visible(priv, attr, channel);
464 case hwmon_curr:
465 return corsairpsu_hwmon_curr_is_visible(priv, attr, channel);
466 default:
467 return 0;
468 }
469 }
470
corsairpsu_hwmon_temp_read(struct corsairpsu_data * priv,u32 attr,int channel,long * val)471 static int corsairpsu_hwmon_temp_read(struct corsairpsu_data *priv, u32 attr, int channel,
472 long *val)
473 {
474 int err = -EOPNOTSUPP;
475
476 switch (attr) {
477 case hwmon_temp_input:
478 return corsairpsu_get_value(priv, channel ? PSU_CMD_TEMP1 : PSU_CMD_TEMP0,
479 channel, val);
480 case hwmon_temp_crit:
481 *val = priv->temp_crit[channel];
482 err = 0;
483 break;
484 default:
485 break;
486 }
487
488 return err;
489 }
490
corsairpsu_hwmon_pwm_read(struct corsairpsu_data * priv,u32 attr,int channel,long * val)491 static int corsairpsu_hwmon_pwm_read(struct corsairpsu_data *priv, u32 attr, int channel, long *val)
492 {
493 switch (attr) {
494 case hwmon_pwm_input:
495 return corsairpsu_get_value(priv, PSU_CMD_FAN_PWM, 0, val);
496 case hwmon_pwm_enable:
497 return corsairpsu_get_value(priv, PSU_CMD_FAN_PWM_ENABLE, 0, val);
498 default:
499 break;
500 }
501
502 return -EOPNOTSUPP;
503 }
504
corsairpsu_hwmon_power_read(struct corsairpsu_data * priv,u32 attr,int channel,long * val)505 static int corsairpsu_hwmon_power_read(struct corsairpsu_data *priv, u32 attr, int channel,
506 long *val)
507 {
508 if (attr == hwmon_power_input) {
509 switch (channel) {
510 case 0:
511 return corsairpsu_get_value(priv, PSU_CMD_TOTAL_WATTS, 0, val);
512 case 1 ... 3:
513 return corsairpsu_get_value(priv, PSU_CMD_RAIL_WATTS, channel - 1, val);
514 default:
515 break;
516 }
517 }
518
519 return -EOPNOTSUPP;
520 }
521
corsairpsu_hwmon_in_read(struct corsairpsu_data * priv,u32 attr,int channel,long * val)522 static int corsairpsu_hwmon_in_read(struct corsairpsu_data *priv, u32 attr, int channel, long *val)
523 {
524 int err = -EOPNOTSUPP;
525
526 switch (attr) {
527 case hwmon_in_input:
528 switch (channel) {
529 case 0:
530 return corsairpsu_get_value(priv, PSU_CMD_IN_VOLTS, 0, val);
531 case 1 ... 3:
532 return corsairpsu_get_value(priv, PSU_CMD_RAIL_VOLTS, channel - 1, val);
533 default:
534 break;
535 }
536 break;
537 case hwmon_in_crit:
538 *val = priv->in_crit[channel - 1];
539 err = 0;
540 break;
541 case hwmon_in_lcrit:
542 *val = priv->in_lcrit[channel - 1];
543 err = 0;
544 break;
545 }
546
547 return err;
548 }
549
corsairpsu_hwmon_curr_read(struct corsairpsu_data * priv,u32 attr,int channel,long * val)550 static int corsairpsu_hwmon_curr_read(struct corsairpsu_data *priv, u32 attr, int channel,
551 long *val)
552 {
553 int err = -EOPNOTSUPP;
554
555 switch (attr) {
556 case hwmon_curr_input:
557 switch (channel) {
558 case 0:
559 return corsairpsu_get_value(priv, PSU_CMD_IN_AMPS, 0, val);
560 case 1 ... 3:
561 return corsairpsu_get_value(priv, PSU_CMD_RAIL_AMPS, channel - 1, val);
562 default:
563 break;
564 }
565 break;
566 case hwmon_curr_crit:
567 *val = priv->curr_crit[channel - 1];
568 err = 0;
569 break;
570 default:
571 break;
572 }
573
574 return err;
575 }
576
corsairpsu_hwmon_ops_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)577 static int corsairpsu_hwmon_ops_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
578 int channel, long *val)
579 {
580 struct corsairpsu_data *priv = dev_get_drvdata(dev);
581
582 switch (type) {
583 case hwmon_temp:
584 return corsairpsu_hwmon_temp_read(priv, attr, channel, val);
585 case hwmon_fan:
586 if (attr == hwmon_fan_input)
587 return corsairpsu_get_value(priv, PSU_CMD_FAN, 0, val);
588 return -EOPNOTSUPP;
589 case hwmon_pwm:
590 return corsairpsu_hwmon_pwm_read(priv, attr, channel, val);
591 case hwmon_power:
592 return corsairpsu_hwmon_power_read(priv, attr, channel, val);
593 case hwmon_in:
594 return corsairpsu_hwmon_in_read(priv, attr, channel, val);
595 case hwmon_curr:
596 return corsairpsu_hwmon_curr_read(priv, attr, channel, val);
597 default:
598 return -EOPNOTSUPP;
599 }
600 }
601
corsairpsu_hwmon_ops_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** str)602 static int corsairpsu_hwmon_ops_read_string(struct device *dev, enum hwmon_sensor_types type,
603 u32 attr, int channel, const char **str)
604 {
605 if (type == hwmon_temp && attr == hwmon_temp_label) {
606 *str = channel ? L_TEMP1 : L_TEMP0;
607 return 0;
608 } else if (type == hwmon_fan && attr == hwmon_fan_label) {
609 *str = L_FAN;
610 return 0;
611 } else if (type == hwmon_power && attr == hwmon_power_label && channel < 4) {
612 *str = label_watts[channel];
613 return 0;
614 } else if (type == hwmon_in && attr == hwmon_in_label && channel < 4) {
615 *str = label_volts[channel];
616 return 0;
617 } else if (type == hwmon_curr && attr == hwmon_curr_label && channel < 4) {
618 *str = label_amps[channel];
619 return 0;
620 }
621
622 return -EOPNOTSUPP;
623 }
624
625 static const struct hwmon_ops corsairpsu_hwmon_ops = {
626 .is_visible = corsairpsu_hwmon_ops_is_visible,
627 .read = corsairpsu_hwmon_ops_read,
628 .read_string = corsairpsu_hwmon_ops_read_string,
629 };
630
631 static const struct hwmon_channel_info *const corsairpsu_info[] = {
632 HWMON_CHANNEL_INFO(chip,
633 HWMON_C_REGISTER_TZ),
634 HWMON_CHANNEL_INFO(temp,
635 HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT,
636 HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT),
637 HWMON_CHANNEL_INFO(fan,
638 HWMON_F_INPUT | HWMON_F_LABEL),
639 HWMON_CHANNEL_INFO(pwm,
640 HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
641 HWMON_CHANNEL_INFO(power,
642 HWMON_P_INPUT | HWMON_P_LABEL,
643 HWMON_P_INPUT | HWMON_P_LABEL,
644 HWMON_P_INPUT | HWMON_P_LABEL,
645 HWMON_P_INPUT | HWMON_P_LABEL),
646 HWMON_CHANNEL_INFO(in,
647 HWMON_I_INPUT | HWMON_I_LABEL,
648 HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_LCRIT | HWMON_I_CRIT,
649 HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_LCRIT | HWMON_I_CRIT,
650 HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_LCRIT | HWMON_I_CRIT),
651 HWMON_CHANNEL_INFO(curr,
652 HWMON_C_INPUT | HWMON_C_LABEL,
653 HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_CRIT,
654 HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_CRIT,
655 HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_CRIT),
656 NULL
657 };
658
659 static const struct hwmon_chip_info corsairpsu_chip_info = {
660 .ops = &corsairpsu_hwmon_ops,
661 .info = corsairpsu_info,
662 };
663
664 #ifdef CONFIG_DEBUG_FS
665
print_uptime(struct seq_file * seqf,u8 cmd)666 static void print_uptime(struct seq_file *seqf, u8 cmd)
667 {
668 struct corsairpsu_data *priv = seqf->private;
669 long val;
670 int ret;
671
672 guard(hwmon_lock)(priv->hwmon_dev);
673
674 ret = corsairpsu_get_value(priv, cmd, 0, &val);
675 if (ret < 0) {
676 seq_puts(seqf, "N/A\n");
677 return;
678 }
679
680 if (val > SECONDS_PER_DAY) {
681 seq_printf(seqf, "%ld day(s), %02ld:%02ld:%02ld\n", val / SECONDS_PER_DAY,
682 val % SECONDS_PER_DAY / SECONDS_PER_HOUR, val % SECONDS_PER_HOUR / 60,
683 val % 60);
684 return;
685 }
686
687 seq_printf(seqf, "%02ld:%02ld:%02ld\n", val % SECONDS_PER_DAY / SECONDS_PER_HOUR,
688 val % SECONDS_PER_HOUR / 60, val % 60);
689 }
690
uptime_show(struct seq_file * seqf,void * unused)691 static int uptime_show(struct seq_file *seqf, void *unused)
692 {
693 print_uptime(seqf, PSU_CMD_UPTIME);
694
695 return 0;
696 }
697 DEFINE_SHOW_ATTRIBUTE(uptime);
698
uptime_total_show(struct seq_file * seqf,void * unused)699 static int uptime_total_show(struct seq_file *seqf, void *unused)
700 {
701 print_uptime(seqf, PSU_CMD_TOTAL_UPTIME);
702
703 return 0;
704 }
705 DEFINE_SHOW_ATTRIBUTE(uptime_total);
706
vendor_show(struct seq_file * seqf,void * unused)707 static int vendor_show(struct seq_file *seqf, void *unused)
708 {
709 struct corsairpsu_data *priv = seqf->private;
710
711 seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->vendor);
712
713 return 0;
714 }
715 DEFINE_SHOW_ATTRIBUTE(vendor);
716
product_show(struct seq_file * seqf,void * unused)717 static int product_show(struct seq_file *seqf, void *unused)
718 {
719 struct corsairpsu_data *priv = seqf->private;
720
721 seq_printf(seqf, "%.*s\n", REPLY_SIZE, priv->product);
722
723 return 0;
724 }
725 DEFINE_SHOW_ATTRIBUTE(product);
726
ocpmode_show(struct seq_file * seqf,void * unused)727 static int ocpmode_show(struct seq_file *seqf, void *unused)
728 {
729 struct corsairpsu_data *priv = seqf->private;
730 long val;
731 int ret;
732
733 guard(hwmon_lock)(priv->hwmon_dev);
734
735 /*
736 * The rail mode is switchable on the fly. The RAW interface can be used for this. But it
737 * will not be included here, because I consider it somewhat dangerous for the health of the
738 * PSU. The returned value can be a bogus one, if the PSU is in the process of switching and
739 * getting of the value itself can also fail during this. Because of this every other value
740 * than OCP_MULTI_RAIL can be considered as "single rail".
741 */
742 ret = corsairpsu_get_value(priv, PSU_CMD_OCPMODE, 0, &val);
743 if (ret < 0)
744 seq_puts(seqf, "N/A\n");
745 else
746 seq_printf(seqf, "%s\n", (val == OCP_MULTI_RAIL) ? "multi rail" : "single rail");
747
748 return 0;
749 }
750 DEFINE_SHOW_ATTRIBUTE(ocpmode);
751
corsairpsu_debugfs_init(struct corsairpsu_data * priv)752 static void corsairpsu_debugfs_init(struct corsairpsu_data *priv)
753 {
754 char name[32];
755
756 scnprintf(name, sizeof(name), "%s-%s", DRIVER_NAME, dev_name(&priv->hdev->dev));
757
758 priv->debugfs = debugfs_create_dir(name, NULL);
759 debugfs_create_file("uptime", 0444, priv->debugfs, priv, &uptime_fops);
760 debugfs_create_file("uptime_total", 0444, priv->debugfs, priv, &uptime_total_fops);
761 debugfs_create_file("vendor", 0444, priv->debugfs, priv, &vendor_fops);
762 debugfs_create_file("product", 0444, priv->debugfs, priv, &product_fops);
763 debugfs_create_file("ocpmode", 0444, priv->debugfs, priv, &ocpmode_fops);
764 }
765
766 #else
767
corsairpsu_debugfs_init(struct corsairpsu_data * priv)768 static void corsairpsu_debugfs_init(struct corsairpsu_data *priv)
769 {
770 }
771
772 #endif
773
corsairpsu_probe(struct hid_device * hdev,const struct hid_device_id * id)774 static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id *id)
775 {
776 struct corsairpsu_data *priv;
777 int ret;
778
779 priv = devm_kzalloc(&hdev->dev, sizeof(struct corsairpsu_data), GFP_KERNEL);
780 if (!priv)
781 return -ENOMEM;
782
783 priv->cmd_buffer = devm_kmalloc(&hdev->dev, CMD_BUFFER_SIZE, GFP_KERNEL);
784 if (!priv->cmd_buffer)
785 return -ENOMEM;
786
787 ret = hid_parse(hdev);
788 if (ret)
789 return ret;
790
791 ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
792 if (ret)
793 return ret;
794
795 ret = hid_hw_open(hdev);
796 if (ret)
797 goto fail_and_stop;
798
799 priv->hdev = hdev;
800 hid_set_drvdata(hdev, priv);
801 init_completion(&priv->wait_completion);
802
803 hid_device_io_start(hdev);
804
805 ret = corsairpsu_init(priv);
806 if (ret < 0) {
807 dev_err(&hdev->dev, "unable to initialize device (%d)\n", ret);
808 goto fail_and_close;
809 }
810
811 ret = corsairpsu_fwinfo(priv);
812 if (ret < 0) {
813 dev_err(&hdev->dev, "unable to query firmware (%d)\n", ret);
814 goto fail_and_close;
815 }
816
817 corsairpsu_get_criticals(priv);
818 corsairpsu_check_cmd_support(priv);
819
820 priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "corsairpsu", priv,
821 &corsairpsu_chip_info, NULL);
822
823 if (IS_ERR(priv->hwmon_dev)) {
824 ret = PTR_ERR(priv->hwmon_dev);
825 goto fail_and_close;
826 }
827
828 corsairpsu_debugfs_init(priv);
829
830 return 0;
831
832 fail_and_close:
833 hid_hw_close(hdev);
834 hid_device_io_stop(hdev);
835 fail_and_stop:
836 hid_hw_stop(hdev);
837 return ret;
838 }
839
corsairpsu_remove(struct hid_device * hdev)840 static void corsairpsu_remove(struct hid_device *hdev)
841 {
842 struct corsairpsu_data *priv = hid_get_drvdata(hdev);
843
844 debugfs_remove_recursive(priv->debugfs);
845 hwmon_device_unregister(priv->hwmon_dev);
846 hid_hw_close(hdev);
847 hid_hw_stop(hdev);
848 }
849
corsairpsu_raw_event(struct hid_device * hdev,struct hid_report * report,u8 * data,int size)850 static int corsairpsu_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data,
851 int size)
852 {
853 struct corsairpsu_data *priv = hid_get_drvdata(hdev);
854
855 if (completion_done(&priv->wait_completion))
856 return 0;
857
858 memcpy(priv->cmd_buffer, data, min(CMD_BUFFER_SIZE, size));
859 complete(&priv->wait_completion);
860
861 return 0;
862 }
863
864 #ifdef CONFIG_PM
corsairpsu_resume(struct hid_device * hdev)865 static int corsairpsu_resume(struct hid_device *hdev)
866 {
867 struct corsairpsu_data *priv = hid_get_drvdata(hdev);
868
869 /* some PSUs turn off the microcontroller during standby, so a reinit is required */
870 return corsairpsu_init(priv);
871 }
872 #endif
873
874 static const struct hid_device_id corsairpsu_idtable[] = {
875 { HID_USB_DEVICE(0x1b1c, 0x1c03) }, /* Corsair HX550i */
876 { HID_USB_DEVICE(0x1b1c, 0x1c04) }, /* Corsair HX650i */
877 { HID_USB_DEVICE(0x1b1c, 0x1c05) }, /* Corsair HX750i */
878 { HID_USB_DEVICE(0x1b1c, 0x1c06) }, /* Corsair HX850i */
879 { HID_USB_DEVICE(0x1b1c, 0x1c07) }, /* Corsair HX1000i Legacy */
880 { HID_USB_DEVICE(0x1b1c, 0x1c08) }, /* Corsair HX1200i Legacy */
881 { HID_USB_DEVICE(0x1b1c, 0x1c09) }, /* Corsair RM550i */
882 { HID_USB_DEVICE(0x1b1c, 0x1c0a) }, /* Corsair RM650i */
883 { HID_USB_DEVICE(0x1b1c, 0x1c0b) }, /* Corsair RM750i */
884 { HID_USB_DEVICE(0x1b1c, 0x1c0c) }, /* Corsair RM850i */
885 { HID_USB_DEVICE(0x1b1c, 0x1c0d) }, /* Corsair RM1000i */
886 { HID_USB_DEVICE(0x1b1c, 0x1c1e) }, /* Corsair HX1000i Series 2023 */
887 { HID_USB_DEVICE(0x1b1c, 0x1c1f) }, /* Corsair HX1500i Legacy, Series 2023 and 2025 */
888 { HID_USB_DEVICE(0x1b1c, 0x1c23) }, /* Corsair HX1200i Series 2023 */
889 { HID_USB_DEVICE(0x1b1c, 0x1c27) }, /* Corsair HX1200i Series 2025 */
890 { },
891 };
892 MODULE_DEVICE_TABLE(hid, corsairpsu_idtable);
893
894 static struct hid_driver corsairpsu_driver = {
895 .name = DRIVER_NAME,
896 .id_table = corsairpsu_idtable,
897 .probe = corsairpsu_probe,
898 .remove = corsairpsu_remove,
899 .raw_event = corsairpsu_raw_event,
900 #ifdef CONFIG_PM
901 .resume = corsairpsu_resume,
902 .reset_resume = corsairpsu_resume,
903 #endif
904 };
905
corsair_init(void)906 static int __init corsair_init(void)
907 {
908 return hid_register_driver(&corsairpsu_driver);
909 }
910
corsair_exit(void)911 static void __exit corsair_exit(void)
912 {
913 hid_unregister_driver(&corsairpsu_driver);
914 }
915
916 /*
917 * With module_init() the driver would load before the HID bus when
918 * built-in, so use late_initcall() instead.
919 */
920 late_initcall(corsair_init);
921 module_exit(corsair_exit);
922
923 MODULE_LICENSE("GPL");
924 MODULE_AUTHOR("Wilken Gottwalt <wilken.gottwalt@posteo.net>");
925 MODULE_DESCRIPTION("Linux driver for Corsair power supplies with HID sensors interface");
926