1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * hwmon driver for NZXT Kraken X53/X63/X73 and Z53/Z63/Z73 all in one coolers. |
4 | * X53 and Z53 in code refer to all models in their respective series (shortened |
5 | * for brevity). |
6 | * |
7 | * Copyright 2021 Jonas Malaco <jonas@protocubo.io> |
8 | * Copyright 2022 Aleksa Savic <savicaleksa83@gmail.com> |
9 | */ |
10 | |
11 | #include <linux/debugfs.h> |
12 | #include <linux/hid.h> |
13 | #include <linux/hwmon.h> |
14 | #include <linux/hwmon-sysfs.h> |
15 | #include <linux/jiffies.h> |
16 | #include <linux/module.h> |
17 | #include <linux/mutex.h> |
18 | #include <linux/spinlock.h> |
19 | #include <linux/wait.h> |
20 | #include <asm/unaligned.h> |
21 | |
22 | #define USB_VENDOR_ID_NZXT 0x1e71 |
23 | #define USB_PRODUCT_ID_X53 0x2007 |
24 | #define USB_PRODUCT_ID_X53_SECOND 0x2014 |
25 | #define USB_PRODUCT_ID_Z53 0x3008 |
26 | |
27 | enum kinds { X53, Z53 } __packed; |
28 | enum pwm_enable { off, manual, curve } __packed; |
29 | |
30 | static const char *const kraken3_device_names[] = { |
31 | [X53] = "x53" , |
32 | [Z53] = "z53" , |
33 | }; |
34 | |
35 | #define DRIVER_NAME "nzxt_kraken3" |
36 | #define STATUS_REPORT_ID 0x75 |
37 | #define FIRMWARE_REPORT_ID 0x11 |
38 | #define STATUS_VALIDITY 2000 /* In ms, equivalent to period of four status reports */ |
39 | #define CUSTOM_CURVE_POINTS 40 /* For temps from 20C to 59C (critical temp) */ |
40 | #define PUMP_DUTY_MIN 20 /* In percent */ |
41 | |
42 | /* Sensor report offsets for Kraken X53 and Z53 */ |
43 | #define TEMP_SENSOR_START_OFFSET 15 |
44 | #define TEMP_SENSOR_END_OFFSET 16 |
45 | #define PUMP_SPEED_OFFSET 17 |
46 | #define PUMP_DUTY_OFFSET 19 |
47 | |
48 | /* Firmware version report offset for Kraken X53 and Z53 */ |
49 | #define FIRMWARE_VERSION_OFFSET 17 |
50 | |
51 | /* Sensor report offsets for Kraken Z53 */ |
52 | #define Z53_FAN_SPEED_OFFSET 23 |
53 | #define Z53_FAN_DUTY_OFFSET 25 |
54 | |
55 | /* Report offsets for control commands for Kraken X53 and Z53 */ |
56 | #define SET_DUTY_ID_OFFSET 1 |
57 | |
58 | /* Control commands and their lengths for Kraken X53 and Z53 */ |
59 | |
60 | /* Last byte sets the report interval at 0.5s */ |
61 | static const u8 set_interval_cmd[] = { 0x70, 0x02, 0x01, 0xB8, 1 }; |
62 | static const u8 finish_init_cmd[] = { 0x70, 0x01 }; |
63 | static const u8 __maybe_unused get_fw_version_cmd[] = { 0x10, 0x01 }; |
64 | static const u8 [] = { 0x72, 0x00, 0x00, 0x00 }; |
65 | static const u8 z53_get_status_cmd[] = { 0x74, 0x01 }; |
66 | |
67 | #define SET_INTERVAL_CMD_LENGTH 5 |
68 | #define FINISH_INIT_CMD_LENGTH 2 |
69 | #define GET_FW_VERSION_CMD_LENGTH 2 |
70 | #define MAX_REPORT_LENGTH 64 |
71 | #define MIN_REPORT_LENGTH 20 |
72 | #define 4 |
73 | /* 4 byte header and 40 duty offsets */ |
74 | #define SET_CURVE_DUTY_CMD_LENGTH (4 + 40) |
75 | #define Z53_GET_STATUS_CMD_LENGTH 2 |
76 | |
77 | static const char *const kraken3_temp_label[] = { |
78 | "Coolant temp" , |
79 | }; |
80 | |
81 | static const char *const kraken3_fan_label[] = { |
82 | "Pump speed" , |
83 | "Fan speed" |
84 | }; |
85 | |
86 | struct kraken3_channel_info { |
87 | enum pwm_enable mode; |
88 | |
89 | /* Both values are PWM */ |
90 | u16 reported_duty; |
91 | u16 fixed_duty; /* Manually set fixed duty */ |
92 | |
93 | u8 pwm_points[CUSTOM_CURVE_POINTS]; |
94 | }; |
95 | |
96 | struct kraken3_data { |
97 | struct hid_device *hdev; |
98 | struct device *hwmon_dev; |
99 | struct dentry *debugfs; |
100 | struct mutex buffer_lock; /* For locking access to buffer */ |
101 | struct mutex z53_status_request_lock; |
102 | struct completion fw_version_processed; |
103 | /* |
104 | * For X53 devices, tracks whether an initial (one) sensor report was received to |
105 | * make fancontrol not bail outright. For Z53 devices, whether a status report |
106 | * was processed after requesting one. |
107 | */ |
108 | struct completion status_report_processed; |
109 | /* For locking the above completion */ |
110 | spinlock_t status_completion_lock; |
111 | |
112 | u8 *buffer; |
113 | struct kraken3_channel_info channel_info[2]; /* Pump and fan */ |
114 | bool is_device_faulty; |
115 | |
116 | /* Sensor values */ |
117 | s32 temp_input[1]; |
118 | u16 fan_input[2]; |
119 | |
120 | enum kinds kind; |
121 | u8 firmware_version[3]; |
122 | |
123 | unsigned long updated; /* jiffies */ |
124 | }; |
125 | |
126 | static umode_t kraken3_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, |
127 | int channel) |
128 | { |
129 | const struct kraken3_data *priv = data; |
130 | |
131 | switch (type) { |
132 | case hwmon_temp: |
133 | if (channel < 1) |
134 | return 0444; |
135 | break; |
136 | case hwmon_fan: |
137 | switch (priv->kind) { |
138 | case X53: |
139 | /* Just the pump */ |
140 | if (channel < 1) |
141 | return 0444; |
142 | break; |
143 | case Z53: |
144 | /* Pump and fan */ |
145 | if (channel < 2) |
146 | return 0444; |
147 | break; |
148 | default: |
149 | break; |
150 | } |
151 | break; |
152 | case hwmon_pwm: |
153 | switch (attr) { |
154 | case hwmon_pwm_enable: |
155 | case hwmon_pwm_input: |
156 | switch (priv->kind) { |
157 | case X53: |
158 | /* Just the pump */ |
159 | if (channel < 1) |
160 | return 0644; |
161 | break; |
162 | case Z53: |
163 | /* Pump and fan */ |
164 | if (channel < 2) |
165 | return 0644; |
166 | break; |
167 | default: |
168 | break; |
169 | } |
170 | break; |
171 | default: |
172 | break; |
173 | } |
174 | break; |
175 | default: |
176 | break; |
177 | } |
178 | |
179 | return 0; |
180 | } |
181 | |
182 | /* |
183 | * Writes the command to the device with the rest of the report (up to 64 bytes) filled |
184 | * with zeroes. |
185 | */ |
186 | static int kraken3_write_expanded(struct kraken3_data *priv, const u8 *cmd, int cmd_length) |
187 | { |
188 | int ret; |
189 | |
190 | mutex_lock(&priv->buffer_lock); |
191 | |
192 | memcpy_and_pad(dest: priv->buffer, MAX_REPORT_LENGTH, src: cmd, count: cmd_length, pad: 0x00); |
193 | ret = hid_hw_output_report(hdev: priv->hdev, buf: priv->buffer, MAX_REPORT_LENGTH); |
194 | |
195 | mutex_unlock(lock: &priv->buffer_lock); |
196 | return ret; |
197 | } |
198 | |
199 | static int kraken3_percent_to_pwm(long val) |
200 | { |
201 | return DIV_ROUND_CLOSEST(val * 255, 100); |
202 | } |
203 | |
204 | static int kraken3_pwm_to_percent(long val, int channel) |
205 | { |
206 | int percent_value; |
207 | |
208 | if (val < 0 || val > 255) |
209 | return -EINVAL; |
210 | |
211 | percent_value = DIV_ROUND_CLOSEST(val * 100, 255); |
212 | |
213 | /* Bring up pump duty to min value if needed */ |
214 | if (channel == 0 && percent_value < PUMP_DUTY_MIN) |
215 | percent_value = PUMP_DUTY_MIN; |
216 | |
217 | return percent_value; |
218 | } |
219 | |
220 | static int kraken3_read_x53(struct kraken3_data *priv) |
221 | { |
222 | int ret; |
223 | |
224 | if (completion_done(x: &priv->status_report_processed)) |
225 | /* |
226 | * We're here because data is stale. This means that sensor reports haven't |
227 | * been received for some time in kraken3_raw_event(). On X-series sensor data |
228 | * can't be manually requested, so return an error. |
229 | */ |
230 | return -ENODATA; |
231 | |
232 | /* |
233 | * Data needs to be read, but a sensor report wasn't yet received. It's usually |
234 | * fancontrol that requests data this early and it exits if it reads an error code. |
235 | * So, wait for the first report to be parsed (but up to STATUS_VALIDITY). |
236 | * This does not concern the Z series devices, because they send a sensor report |
237 | * only when requested. |
238 | */ |
239 | ret = wait_for_completion_interruptible_timeout(x: &priv->status_report_processed, |
240 | timeout: msecs_to_jiffies(STATUS_VALIDITY)); |
241 | if (ret == 0) |
242 | return -ETIMEDOUT; |
243 | else if (ret < 0) |
244 | return ret; |
245 | |
246 | /* The first sensor report was parsed on time and reading can continue */ |
247 | return 0; |
248 | } |
249 | |
250 | static int kraken3_read_z53(struct kraken3_data *priv) |
251 | { |
252 | int ret = mutex_lock_interruptible(&priv->z53_status_request_lock); |
253 | |
254 | if (ret < 0) |
255 | return ret; |
256 | |
257 | if (!time_after(jiffies, priv->updated + msecs_to_jiffies(STATUS_VALIDITY))) { |
258 | /* Data is up to date */ |
259 | goto unlock_and_return; |
260 | } |
261 | |
262 | /* |
263 | * Disable interrupts for a moment to safely reinit the completion, |
264 | * as hidraw calls could have allowed one or more readers to complete. |
265 | */ |
266 | spin_lock_bh(lock: &priv->status_completion_lock); |
267 | reinit_completion(x: &priv->status_report_processed); |
268 | spin_unlock_bh(lock: &priv->status_completion_lock); |
269 | |
270 | /* Send command for getting status */ |
271 | ret = kraken3_write_expanded(priv, cmd: z53_get_status_cmd, Z53_GET_STATUS_CMD_LENGTH); |
272 | if (ret < 0) |
273 | goto unlock_and_return; |
274 | |
275 | /* Wait for completion from kraken3_raw_event() */ |
276 | ret = wait_for_completion_interruptible_timeout(x: &priv->status_report_processed, |
277 | timeout: msecs_to_jiffies(STATUS_VALIDITY)); |
278 | if (ret == 0) |
279 | ret = -ETIMEDOUT; |
280 | |
281 | unlock_and_return: |
282 | mutex_unlock(lock: &priv->z53_status_request_lock); |
283 | if (ret < 0) |
284 | return ret; |
285 | |
286 | return 0; |
287 | } |
288 | |
289 | static int kraken3_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, |
290 | long *val) |
291 | { |
292 | struct kraken3_data *priv = dev_get_drvdata(dev); |
293 | int ret; |
294 | |
295 | if (time_after(jiffies, priv->updated + msecs_to_jiffies(STATUS_VALIDITY))) { |
296 | if (priv->kind == X53) |
297 | ret = kraken3_read_x53(priv); |
298 | else |
299 | ret = kraken3_read_z53(priv); |
300 | |
301 | if (ret < 0) |
302 | return ret; |
303 | |
304 | if (priv->is_device_faulty) |
305 | return -ENODATA; |
306 | } |
307 | |
308 | switch (type) { |
309 | case hwmon_temp: |
310 | *val = priv->temp_input[channel]; |
311 | break; |
312 | case hwmon_fan: |
313 | *val = priv->fan_input[channel]; |
314 | break; |
315 | case hwmon_pwm: |
316 | switch (attr) { |
317 | case hwmon_pwm_enable: |
318 | *val = priv->channel_info[channel].mode; |
319 | break; |
320 | case hwmon_pwm_input: |
321 | *val = priv->channel_info[channel].reported_duty; |
322 | break; |
323 | default: |
324 | return -EOPNOTSUPP; |
325 | } |
326 | break; |
327 | default: |
328 | return -EOPNOTSUPP; |
329 | } |
330 | |
331 | return 0; |
332 | } |
333 | |
334 | static int kraken3_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr, |
335 | int channel, const char **str) |
336 | { |
337 | switch (type) { |
338 | case hwmon_temp: |
339 | *str = kraken3_temp_label[channel]; |
340 | break; |
341 | case hwmon_fan: |
342 | *str = kraken3_fan_label[channel]; |
343 | break; |
344 | default: |
345 | return -EOPNOTSUPP; |
346 | } |
347 | |
348 | return 0; |
349 | } |
350 | |
351 | /* Writes custom curve to device */ |
352 | static int kraken3_write_curve(struct kraken3_data *priv, u8 *curve_array, int channel) |
353 | { |
354 | u8 fixed_duty_cmd[SET_CURVE_DUTY_CMD_LENGTH]; |
355 | int ret; |
356 | |
357 | /* Copy command header */ |
358 | memcpy(fixed_duty_cmd, set_pump_duty_cmd_header, SET_CURVE_DUTY_CMD_HEADER_LENGTH); |
359 | |
360 | /* Set the correct ID for writing pump/fan duty (0x01 or 0x02, respectively) */ |
361 | fixed_duty_cmd[SET_DUTY_ID_OFFSET] = channel + 1; |
362 | |
363 | /* Copy curve to command */ |
364 | memcpy(fixed_duty_cmd + SET_CURVE_DUTY_CMD_HEADER_LENGTH, curve_array, CUSTOM_CURVE_POINTS); |
365 | |
366 | ret = kraken3_write_expanded(priv, cmd: fixed_duty_cmd, SET_CURVE_DUTY_CMD_LENGTH); |
367 | return ret; |
368 | } |
369 | |
370 | static int kraken3_write_fixed_duty(struct kraken3_data *priv, long val, int channel) |
371 | { |
372 | u8 fixed_curve_points[CUSTOM_CURVE_POINTS]; |
373 | int ret, percent_val, i; |
374 | |
375 | percent_val = kraken3_pwm_to_percent(val, channel); |
376 | if (percent_val < 0) |
377 | return percent_val; |
378 | |
379 | /* |
380 | * The devices can only control the duty through a curve. |
381 | * Since we're setting a fixed duty here, fill the whole curve |
382 | * (ranging from 20C to 59C) with the same duty, except for |
383 | * the last point, the critical temperature, where it's maxed |
384 | * out for safety. |
385 | */ |
386 | |
387 | /* Fill the custom curve with the fixed value we're setting */ |
388 | for (i = 0; i < CUSTOM_CURVE_POINTS - 1; i++) |
389 | fixed_curve_points[i] = percent_val; |
390 | |
391 | /* Force duty to 100% at critical temp */ |
392 | fixed_curve_points[CUSTOM_CURVE_POINTS - 1] = 100; |
393 | |
394 | /* Write the fixed duty curve to the device */ |
395 | ret = kraken3_write_curve(priv, curve_array: fixed_curve_points, channel); |
396 | return ret; |
397 | } |
398 | |
399 | static int kraken3_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, |
400 | long val) |
401 | { |
402 | struct kraken3_data *priv = dev_get_drvdata(dev); |
403 | int ret; |
404 | |
405 | switch (type) { |
406 | case hwmon_pwm: |
407 | switch (attr) { |
408 | case hwmon_pwm_input: |
409 | /* Remember the last set fixed duty for channel */ |
410 | priv->channel_info[channel].fixed_duty = val; |
411 | |
412 | if (priv->channel_info[channel].mode == manual) { |
413 | ret = kraken3_write_fixed_duty(priv, val, channel); |
414 | if (ret < 0) |
415 | return ret; |
416 | |
417 | /* |
418 | * Lock onto this value and report it until next interrupt status |
419 | * report is received, so userspace tools can continue to work. |
420 | */ |
421 | priv->channel_info[channel].reported_duty = val; |
422 | } |
423 | break; |
424 | case hwmon_pwm_enable: |
425 | if (val < 0 || val > 2) |
426 | return -EINVAL; |
427 | |
428 | switch (val) { |
429 | case 0: |
430 | /* Set channel to 100%, direct duty value */ |
431 | ret = kraken3_write_fixed_duty(priv, val: 255, channel); |
432 | if (ret < 0) |
433 | return ret; |
434 | |
435 | /* We don't control anything anymore */ |
436 | priv->channel_info[channel].mode = off; |
437 | break; |
438 | case 1: |
439 | /* Apply the last known direct duty value */ |
440 | ret = |
441 | kraken3_write_fixed_duty(priv, |
442 | val: priv->channel_info[channel].fixed_duty, |
443 | channel); |
444 | if (ret < 0) |
445 | return ret; |
446 | |
447 | priv->channel_info[channel].mode = manual; |
448 | break; |
449 | case 2: |
450 | /* Apply the curve and note as enabled */ |
451 | ret = |
452 | kraken3_write_curve(priv, |
453 | curve_array: priv->channel_info[channel].pwm_points, |
454 | channel); |
455 | if (ret < 0) |
456 | return ret; |
457 | |
458 | priv->channel_info[channel].mode = curve; |
459 | break; |
460 | default: |
461 | break; |
462 | } |
463 | break; |
464 | default: |
465 | return -EOPNOTSUPP; |
466 | } |
467 | break; |
468 | default: |
469 | return -EOPNOTSUPP; |
470 | } |
471 | |
472 | return 0; |
473 | } |
474 | |
475 | static ssize_t kraken3_fan_curve_pwm_store(struct device *dev, struct device_attribute *attr, |
476 | const char *buf, size_t count) |
477 | { |
478 | struct sensor_device_attribute_2 *dev_attr = to_sensor_dev_attr_2(attr); |
479 | struct kraken3_data *priv = dev_get_drvdata(dev); |
480 | long val; |
481 | int ret; |
482 | |
483 | if (kstrtol(s: buf, base: 10, res: &val) < 0) |
484 | return -EINVAL; |
485 | |
486 | val = kraken3_pwm_to_percent(val, channel: dev_attr->nr); |
487 | if (val < 0) |
488 | return val; |
489 | |
490 | priv->channel_info[dev_attr->nr].pwm_points[dev_attr->index] = val; |
491 | |
492 | if (priv->channel_info[dev_attr->nr].mode == curve) { |
493 | /* Apply the curve */ |
494 | ret = |
495 | kraken3_write_curve(priv, |
496 | curve_array: priv->channel_info[dev_attr->nr].pwm_points, channel: dev_attr->nr); |
497 | if (ret < 0) |
498 | return ret; |
499 | } |
500 | |
501 | return count; |
502 | } |
503 | |
504 | static umode_t kraken3_curve_props_are_visible(struct kobject *kobj, struct attribute *attr, |
505 | int index) |
506 | { |
507 | struct device *dev = kobj_to_dev(kobj); |
508 | struct kraken3_data *priv = dev_get_drvdata(dev); |
509 | |
510 | /* Only Z53 has the fan curve */ |
511 | if (index >= CUSTOM_CURVE_POINTS && priv->kind != Z53) |
512 | return 0; |
513 | |
514 | return attr->mode; |
515 | } |
516 | |
517 | /* Custom pump curve from 20C to 59C (critical temp) */ |
518 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point1_pwm, kraken3_fan_curve_pwm, 0, 0); |
519 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point2_pwm, kraken3_fan_curve_pwm, 0, 1); |
520 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point3_pwm, kraken3_fan_curve_pwm, 0, 2); |
521 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point4_pwm, kraken3_fan_curve_pwm, 0, 3); |
522 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point5_pwm, kraken3_fan_curve_pwm, 0, 4); |
523 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point6_pwm, kraken3_fan_curve_pwm, 0, 5); |
524 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point7_pwm, kraken3_fan_curve_pwm, 0, 6); |
525 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point8_pwm, kraken3_fan_curve_pwm, 0, 7); |
526 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point9_pwm, kraken3_fan_curve_pwm, 0, 8); |
527 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point10_pwm, kraken3_fan_curve_pwm, 0, 9); |
528 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point11_pwm, kraken3_fan_curve_pwm, 0, 10); |
529 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point12_pwm, kraken3_fan_curve_pwm, 0, 11); |
530 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point13_pwm, kraken3_fan_curve_pwm, 0, 12); |
531 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point14_pwm, kraken3_fan_curve_pwm, 0, 13); |
532 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point15_pwm, kraken3_fan_curve_pwm, 0, 14); |
533 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point16_pwm, kraken3_fan_curve_pwm, 0, 15); |
534 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point17_pwm, kraken3_fan_curve_pwm, 0, 16); |
535 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point18_pwm, kraken3_fan_curve_pwm, 0, 17); |
536 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point19_pwm, kraken3_fan_curve_pwm, 0, 18); |
537 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point20_pwm, kraken3_fan_curve_pwm, 0, 19); |
538 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point21_pwm, kraken3_fan_curve_pwm, 0, 20); |
539 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point22_pwm, kraken3_fan_curve_pwm, 0, 21); |
540 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point23_pwm, kraken3_fan_curve_pwm, 0, 22); |
541 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point24_pwm, kraken3_fan_curve_pwm, 0, 23); |
542 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point25_pwm, kraken3_fan_curve_pwm, 0, 24); |
543 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point26_pwm, kraken3_fan_curve_pwm, 0, 25); |
544 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point27_pwm, kraken3_fan_curve_pwm, 0, 26); |
545 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point28_pwm, kraken3_fan_curve_pwm, 0, 27); |
546 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point29_pwm, kraken3_fan_curve_pwm, 0, 28); |
547 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point30_pwm, kraken3_fan_curve_pwm, 0, 29); |
548 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point31_pwm, kraken3_fan_curve_pwm, 0, 30); |
549 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point32_pwm, kraken3_fan_curve_pwm, 0, 31); |
550 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point33_pwm, kraken3_fan_curve_pwm, 0, 32); |
551 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point34_pwm, kraken3_fan_curve_pwm, 0, 33); |
552 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point35_pwm, kraken3_fan_curve_pwm, 0, 34); |
553 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point36_pwm, kraken3_fan_curve_pwm, 0, 35); |
554 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point37_pwm, kraken3_fan_curve_pwm, 0, 36); |
555 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point38_pwm, kraken3_fan_curve_pwm, 0, 37); |
556 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point39_pwm, kraken3_fan_curve_pwm, 0, 38); |
557 | static SENSOR_DEVICE_ATTR_2_WO(temp1_auto_point40_pwm, kraken3_fan_curve_pwm, 0, 39); |
558 | |
559 | /* Custom fan curve from 20C to 59C (critical temp) */ |
560 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point1_pwm, kraken3_fan_curve_pwm, 1, 0); |
561 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point2_pwm, kraken3_fan_curve_pwm, 1, 1); |
562 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point3_pwm, kraken3_fan_curve_pwm, 1, 2); |
563 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point4_pwm, kraken3_fan_curve_pwm, 1, 3); |
564 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point5_pwm, kraken3_fan_curve_pwm, 1, 4); |
565 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point6_pwm, kraken3_fan_curve_pwm, 1, 5); |
566 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point7_pwm, kraken3_fan_curve_pwm, 1, 6); |
567 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point8_pwm, kraken3_fan_curve_pwm, 1, 7); |
568 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point9_pwm, kraken3_fan_curve_pwm, 1, 8); |
569 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point10_pwm, kraken3_fan_curve_pwm, 1, 9); |
570 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point11_pwm, kraken3_fan_curve_pwm, 1, 10); |
571 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point12_pwm, kraken3_fan_curve_pwm, 1, 11); |
572 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point13_pwm, kraken3_fan_curve_pwm, 1, 12); |
573 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point14_pwm, kraken3_fan_curve_pwm, 1, 13); |
574 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point15_pwm, kraken3_fan_curve_pwm, 1, 14); |
575 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point16_pwm, kraken3_fan_curve_pwm, 1, 15); |
576 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point17_pwm, kraken3_fan_curve_pwm, 1, 16); |
577 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point18_pwm, kraken3_fan_curve_pwm, 1, 17); |
578 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point19_pwm, kraken3_fan_curve_pwm, 1, 18); |
579 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point20_pwm, kraken3_fan_curve_pwm, 1, 19); |
580 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point21_pwm, kraken3_fan_curve_pwm, 1, 20); |
581 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point22_pwm, kraken3_fan_curve_pwm, 1, 21); |
582 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point23_pwm, kraken3_fan_curve_pwm, 1, 22); |
583 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point24_pwm, kraken3_fan_curve_pwm, 1, 23); |
584 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point25_pwm, kraken3_fan_curve_pwm, 1, 24); |
585 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point26_pwm, kraken3_fan_curve_pwm, 1, 25); |
586 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point27_pwm, kraken3_fan_curve_pwm, 1, 26); |
587 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point28_pwm, kraken3_fan_curve_pwm, 1, 27); |
588 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point29_pwm, kraken3_fan_curve_pwm, 1, 28); |
589 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point30_pwm, kraken3_fan_curve_pwm, 1, 29); |
590 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point31_pwm, kraken3_fan_curve_pwm, 1, 30); |
591 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point32_pwm, kraken3_fan_curve_pwm, 1, 31); |
592 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point33_pwm, kraken3_fan_curve_pwm, 1, 32); |
593 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point34_pwm, kraken3_fan_curve_pwm, 1, 33); |
594 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point35_pwm, kraken3_fan_curve_pwm, 1, 34); |
595 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point36_pwm, kraken3_fan_curve_pwm, 1, 35); |
596 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point37_pwm, kraken3_fan_curve_pwm, 1, 36); |
597 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point38_pwm, kraken3_fan_curve_pwm, 1, 37); |
598 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point39_pwm, kraken3_fan_curve_pwm, 1, 38); |
599 | static SENSOR_DEVICE_ATTR_2_WO(temp2_auto_point40_pwm, kraken3_fan_curve_pwm, 1, 39); |
600 | |
601 | static struct attribute *kraken3_curve_attrs[] = { |
602 | /* Pump control curve */ |
603 | &sensor_dev_attr_temp1_auto_point1_pwm.dev_attr.attr, |
604 | &sensor_dev_attr_temp1_auto_point2_pwm.dev_attr.attr, |
605 | &sensor_dev_attr_temp1_auto_point3_pwm.dev_attr.attr, |
606 | &sensor_dev_attr_temp1_auto_point4_pwm.dev_attr.attr, |
607 | &sensor_dev_attr_temp1_auto_point5_pwm.dev_attr.attr, |
608 | &sensor_dev_attr_temp1_auto_point6_pwm.dev_attr.attr, |
609 | &sensor_dev_attr_temp1_auto_point7_pwm.dev_attr.attr, |
610 | &sensor_dev_attr_temp1_auto_point8_pwm.dev_attr.attr, |
611 | &sensor_dev_attr_temp1_auto_point9_pwm.dev_attr.attr, |
612 | &sensor_dev_attr_temp1_auto_point10_pwm.dev_attr.attr, |
613 | &sensor_dev_attr_temp1_auto_point11_pwm.dev_attr.attr, |
614 | &sensor_dev_attr_temp1_auto_point12_pwm.dev_attr.attr, |
615 | &sensor_dev_attr_temp1_auto_point13_pwm.dev_attr.attr, |
616 | &sensor_dev_attr_temp1_auto_point14_pwm.dev_attr.attr, |
617 | &sensor_dev_attr_temp1_auto_point15_pwm.dev_attr.attr, |
618 | &sensor_dev_attr_temp1_auto_point16_pwm.dev_attr.attr, |
619 | &sensor_dev_attr_temp1_auto_point17_pwm.dev_attr.attr, |
620 | &sensor_dev_attr_temp1_auto_point18_pwm.dev_attr.attr, |
621 | &sensor_dev_attr_temp1_auto_point19_pwm.dev_attr.attr, |
622 | &sensor_dev_attr_temp1_auto_point20_pwm.dev_attr.attr, |
623 | &sensor_dev_attr_temp1_auto_point21_pwm.dev_attr.attr, |
624 | &sensor_dev_attr_temp1_auto_point22_pwm.dev_attr.attr, |
625 | &sensor_dev_attr_temp1_auto_point23_pwm.dev_attr.attr, |
626 | &sensor_dev_attr_temp1_auto_point24_pwm.dev_attr.attr, |
627 | &sensor_dev_attr_temp1_auto_point25_pwm.dev_attr.attr, |
628 | &sensor_dev_attr_temp1_auto_point26_pwm.dev_attr.attr, |
629 | &sensor_dev_attr_temp1_auto_point27_pwm.dev_attr.attr, |
630 | &sensor_dev_attr_temp1_auto_point28_pwm.dev_attr.attr, |
631 | &sensor_dev_attr_temp1_auto_point29_pwm.dev_attr.attr, |
632 | &sensor_dev_attr_temp1_auto_point30_pwm.dev_attr.attr, |
633 | &sensor_dev_attr_temp1_auto_point31_pwm.dev_attr.attr, |
634 | &sensor_dev_attr_temp1_auto_point32_pwm.dev_attr.attr, |
635 | &sensor_dev_attr_temp1_auto_point33_pwm.dev_attr.attr, |
636 | &sensor_dev_attr_temp1_auto_point34_pwm.dev_attr.attr, |
637 | &sensor_dev_attr_temp1_auto_point35_pwm.dev_attr.attr, |
638 | &sensor_dev_attr_temp1_auto_point36_pwm.dev_attr.attr, |
639 | &sensor_dev_attr_temp1_auto_point37_pwm.dev_attr.attr, |
640 | &sensor_dev_attr_temp1_auto_point38_pwm.dev_attr.attr, |
641 | &sensor_dev_attr_temp1_auto_point39_pwm.dev_attr.attr, |
642 | &sensor_dev_attr_temp1_auto_point40_pwm.dev_attr.attr, |
643 | /* Fan control curve (Z53 only) */ |
644 | &sensor_dev_attr_temp2_auto_point1_pwm.dev_attr.attr, |
645 | &sensor_dev_attr_temp2_auto_point2_pwm.dev_attr.attr, |
646 | &sensor_dev_attr_temp2_auto_point3_pwm.dev_attr.attr, |
647 | &sensor_dev_attr_temp2_auto_point4_pwm.dev_attr.attr, |
648 | &sensor_dev_attr_temp2_auto_point5_pwm.dev_attr.attr, |
649 | &sensor_dev_attr_temp2_auto_point6_pwm.dev_attr.attr, |
650 | &sensor_dev_attr_temp2_auto_point7_pwm.dev_attr.attr, |
651 | &sensor_dev_attr_temp2_auto_point8_pwm.dev_attr.attr, |
652 | &sensor_dev_attr_temp2_auto_point9_pwm.dev_attr.attr, |
653 | &sensor_dev_attr_temp2_auto_point10_pwm.dev_attr.attr, |
654 | &sensor_dev_attr_temp2_auto_point11_pwm.dev_attr.attr, |
655 | &sensor_dev_attr_temp2_auto_point12_pwm.dev_attr.attr, |
656 | &sensor_dev_attr_temp2_auto_point13_pwm.dev_attr.attr, |
657 | &sensor_dev_attr_temp2_auto_point14_pwm.dev_attr.attr, |
658 | &sensor_dev_attr_temp2_auto_point15_pwm.dev_attr.attr, |
659 | &sensor_dev_attr_temp2_auto_point16_pwm.dev_attr.attr, |
660 | &sensor_dev_attr_temp2_auto_point17_pwm.dev_attr.attr, |
661 | &sensor_dev_attr_temp2_auto_point18_pwm.dev_attr.attr, |
662 | &sensor_dev_attr_temp2_auto_point19_pwm.dev_attr.attr, |
663 | &sensor_dev_attr_temp2_auto_point20_pwm.dev_attr.attr, |
664 | &sensor_dev_attr_temp2_auto_point21_pwm.dev_attr.attr, |
665 | &sensor_dev_attr_temp2_auto_point22_pwm.dev_attr.attr, |
666 | &sensor_dev_attr_temp2_auto_point23_pwm.dev_attr.attr, |
667 | &sensor_dev_attr_temp2_auto_point24_pwm.dev_attr.attr, |
668 | &sensor_dev_attr_temp2_auto_point25_pwm.dev_attr.attr, |
669 | &sensor_dev_attr_temp2_auto_point26_pwm.dev_attr.attr, |
670 | &sensor_dev_attr_temp2_auto_point27_pwm.dev_attr.attr, |
671 | &sensor_dev_attr_temp2_auto_point28_pwm.dev_attr.attr, |
672 | &sensor_dev_attr_temp2_auto_point29_pwm.dev_attr.attr, |
673 | &sensor_dev_attr_temp2_auto_point30_pwm.dev_attr.attr, |
674 | &sensor_dev_attr_temp2_auto_point31_pwm.dev_attr.attr, |
675 | &sensor_dev_attr_temp2_auto_point32_pwm.dev_attr.attr, |
676 | &sensor_dev_attr_temp2_auto_point33_pwm.dev_attr.attr, |
677 | &sensor_dev_attr_temp2_auto_point34_pwm.dev_attr.attr, |
678 | &sensor_dev_attr_temp2_auto_point35_pwm.dev_attr.attr, |
679 | &sensor_dev_attr_temp2_auto_point36_pwm.dev_attr.attr, |
680 | &sensor_dev_attr_temp2_auto_point37_pwm.dev_attr.attr, |
681 | &sensor_dev_attr_temp2_auto_point38_pwm.dev_attr.attr, |
682 | &sensor_dev_attr_temp2_auto_point39_pwm.dev_attr.attr, |
683 | &sensor_dev_attr_temp2_auto_point40_pwm.dev_attr.attr, |
684 | NULL |
685 | }; |
686 | |
687 | static const struct attribute_group kraken3_curves_group = { |
688 | .attrs = kraken3_curve_attrs, |
689 | .is_visible = kraken3_curve_props_are_visible |
690 | }; |
691 | |
692 | static const struct attribute_group *kraken3_groups[] = { |
693 | &kraken3_curves_group, |
694 | NULL |
695 | }; |
696 | |
697 | static const struct hwmon_ops kraken3_hwmon_ops = { |
698 | .is_visible = kraken3_is_visible, |
699 | .read = kraken3_read, |
700 | .read_string = kraken3_read_string, |
701 | .write = kraken3_write |
702 | }; |
703 | |
704 | static const struct hwmon_channel_info *kraken3_info[] = { |
705 | HWMON_CHANNEL_INFO(temp, |
706 | HWMON_T_INPUT | HWMON_T_LABEL), |
707 | HWMON_CHANNEL_INFO(fan, |
708 | HWMON_F_INPUT | HWMON_F_LABEL, |
709 | HWMON_F_INPUT | HWMON_F_LABEL, |
710 | HWMON_F_INPUT | HWMON_F_LABEL, |
711 | HWMON_F_INPUT | HWMON_F_LABEL), |
712 | HWMON_CHANNEL_INFO(pwm, |
713 | HWMON_PWM_INPUT | HWMON_PWM_ENABLE, |
714 | HWMON_PWM_INPUT | HWMON_PWM_ENABLE), |
715 | NULL |
716 | }; |
717 | |
718 | static const struct hwmon_chip_info kraken3_chip_info = { |
719 | .ops = &kraken3_hwmon_ops, |
720 | .info = kraken3_info, |
721 | }; |
722 | |
723 | static int kraken3_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) |
724 | { |
725 | struct kraken3_data *priv = hid_get_drvdata(hdev); |
726 | int i; |
727 | |
728 | if (size < MIN_REPORT_LENGTH) |
729 | return 0; |
730 | |
731 | if (report->id == FIRMWARE_REPORT_ID) { |
732 | /* Read firmware version */ |
733 | for (i = 0; i < 3; i++) |
734 | priv->firmware_version[i] = data[FIRMWARE_VERSION_OFFSET + i]; |
735 | |
736 | if (!completion_done(x: &priv->fw_version_processed)) |
737 | complete_all(&priv->fw_version_processed); |
738 | |
739 | return 0; |
740 | } |
741 | |
742 | if (report->id != STATUS_REPORT_ID) |
743 | return 0; |
744 | |
745 | if (data[TEMP_SENSOR_START_OFFSET] == 0xff && data[TEMP_SENSOR_END_OFFSET] == 0xff) { |
746 | hid_err_once(hdev, |
747 | "firmware or device is possibly damaged (is SATA power connected?), not parsing reports\n" ); |
748 | |
749 | /* |
750 | * Mark first X-series device report as received, |
751 | * as well as all for Z-series, if faulty. |
752 | */ |
753 | spin_lock(lock: &priv->status_completion_lock); |
754 | if (priv->kind != X53 || !completion_done(x: &priv->status_report_processed)) { |
755 | priv->is_device_faulty = true; |
756 | complete_all(&priv->status_report_processed); |
757 | } |
758 | spin_unlock(lock: &priv->status_completion_lock); |
759 | |
760 | return 0; |
761 | } |
762 | |
763 | /* Received normal data */ |
764 | priv->is_device_faulty = false; |
765 | |
766 | /* Temperature and fan sensor readings */ |
767 | priv->temp_input[0] = |
768 | data[TEMP_SENSOR_START_OFFSET] * 1000 + data[TEMP_SENSOR_END_OFFSET] * 100; |
769 | |
770 | priv->fan_input[0] = get_unaligned_le16(p: data + PUMP_SPEED_OFFSET); |
771 | priv->channel_info[0].reported_duty = kraken3_percent_to_pwm(val: data[PUMP_DUTY_OFFSET]); |
772 | |
773 | spin_lock(lock: &priv->status_completion_lock); |
774 | if (priv->kind == X53 && !completion_done(x: &priv->status_report_processed)) { |
775 | /* Mark first X-series device report as received */ |
776 | complete_all(&priv->status_report_processed); |
777 | } else if (priv->kind == Z53) { |
778 | /* Additional readings for Z53 */ |
779 | priv->fan_input[1] = get_unaligned_le16(p: data + Z53_FAN_SPEED_OFFSET); |
780 | priv->channel_info[1].reported_duty = |
781 | kraken3_percent_to_pwm(val: data[Z53_FAN_DUTY_OFFSET]); |
782 | |
783 | if (!completion_done(x: &priv->status_report_processed)) |
784 | complete_all(&priv->status_report_processed); |
785 | } |
786 | spin_unlock(lock: &priv->status_completion_lock); |
787 | |
788 | priv->updated = jiffies; |
789 | |
790 | return 0; |
791 | } |
792 | |
793 | static int kraken3_init_device(struct hid_device *hdev) |
794 | { |
795 | struct kraken3_data *priv = hid_get_drvdata(hdev); |
796 | int ret; |
797 | |
798 | /* Set the polling interval */ |
799 | ret = kraken3_write_expanded(priv, cmd: set_interval_cmd, SET_INTERVAL_CMD_LENGTH); |
800 | if (ret < 0) |
801 | return ret; |
802 | |
803 | /* Finalize the init process */ |
804 | ret = kraken3_write_expanded(priv, cmd: finish_init_cmd, FINISH_INIT_CMD_LENGTH); |
805 | if (ret < 0) |
806 | return ret; |
807 | |
808 | return 0; |
809 | } |
810 | |
811 | static int kraken3_get_fw_ver(struct hid_device *hdev) |
812 | { |
813 | struct kraken3_data *priv = hid_get_drvdata(hdev); |
814 | int ret; |
815 | |
816 | ret = kraken3_write_expanded(priv, cmd: get_fw_version_cmd, GET_FW_VERSION_CMD_LENGTH); |
817 | if (ret < 0) |
818 | return ret; |
819 | |
820 | ret = wait_for_completion_interruptible_timeout(x: &priv->fw_version_processed, |
821 | timeout: msecs_to_jiffies(STATUS_VALIDITY)); |
822 | if (ret == 0) |
823 | return -ETIMEDOUT; |
824 | else if (ret < 0) |
825 | return ret; |
826 | |
827 | return 0; |
828 | } |
829 | |
830 | static int __maybe_unused kraken3_reset_resume(struct hid_device *hdev) |
831 | { |
832 | int ret; |
833 | |
834 | ret = kraken3_init_device(hdev); |
835 | if (ret) |
836 | hid_err(hdev, "req init (reset_resume) failed with %d\n" , ret); |
837 | |
838 | return ret; |
839 | } |
840 | |
841 | static int firmware_version_show(struct seq_file *seqf, void *unused) |
842 | { |
843 | struct kraken3_data *priv = seqf->private; |
844 | |
845 | seq_printf(m: seqf, fmt: "%u.%u.%u\n" , priv->firmware_version[0], priv->firmware_version[1], |
846 | priv->firmware_version[2]); |
847 | |
848 | return 0; |
849 | } |
850 | DEFINE_SHOW_ATTRIBUTE(firmware_version); |
851 | |
852 | static void kraken3_debugfs_init(struct kraken3_data *priv) |
853 | { |
854 | char name[64]; |
855 | |
856 | if (!priv->firmware_version[0]) |
857 | return; /* Nothing to display in debugfs */ |
858 | |
859 | scnprintf(buf: name, size: sizeof(name), fmt: "%s_%s-%s" , DRIVER_NAME, kraken3_device_names[priv->kind], |
860 | dev_name(dev: &priv->hdev->dev)); |
861 | |
862 | priv->debugfs = debugfs_create_dir(name, NULL); |
863 | debugfs_create_file(name: "firmware_version" , mode: 0444, parent: priv->debugfs, data: priv, fops: &firmware_version_fops); |
864 | } |
865 | |
866 | static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id) |
867 | { |
868 | struct kraken3_data *priv; |
869 | int ret; |
870 | |
871 | priv = devm_kzalloc(dev: &hdev->dev, size: sizeof(*priv), GFP_KERNEL); |
872 | if (!priv) |
873 | return -ENOMEM; |
874 | |
875 | priv->hdev = hdev; |
876 | hid_set_drvdata(hdev, data: priv); |
877 | |
878 | /* |
879 | * Initialize ->updated to STATUS_VALIDITY seconds in the past, making |
880 | * the initial empty data invalid for kraken3_read without the need for |
881 | * a special case there. |
882 | */ |
883 | priv->updated = jiffies - msecs_to_jiffies(STATUS_VALIDITY); |
884 | |
885 | ret = hid_parse(hdev); |
886 | if (ret) { |
887 | hid_err(hdev, "hid parse failed with %d\n" , ret); |
888 | return ret; |
889 | } |
890 | |
891 | /* Enable hidraw so existing user-space tools can continue to work */ |
892 | ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); |
893 | if (ret) { |
894 | hid_err(hdev, "hid hw start failed with %d\n" , ret); |
895 | return ret; |
896 | } |
897 | |
898 | ret = hid_hw_open(hdev); |
899 | if (ret) { |
900 | hid_err(hdev, "hid hw open failed with %d\n" , ret); |
901 | goto fail_and_stop; |
902 | } |
903 | |
904 | switch (hdev->product) { |
905 | case USB_PRODUCT_ID_X53: |
906 | case USB_PRODUCT_ID_X53_SECOND: |
907 | priv->kind = X53; |
908 | break; |
909 | case USB_PRODUCT_ID_Z53: |
910 | priv->kind = Z53; |
911 | break; |
912 | default: |
913 | break; |
914 | } |
915 | |
916 | priv->buffer = devm_kzalloc(dev: &hdev->dev, MAX_REPORT_LENGTH, GFP_KERNEL); |
917 | if (!priv->buffer) { |
918 | ret = -ENOMEM; |
919 | goto fail_and_close; |
920 | } |
921 | |
922 | mutex_init(&priv->buffer_lock); |
923 | mutex_init(&priv->z53_status_request_lock); |
924 | init_completion(x: &priv->fw_version_processed); |
925 | init_completion(x: &priv->status_report_processed); |
926 | spin_lock_init(&priv->status_completion_lock); |
927 | |
928 | hid_device_io_start(hid: hdev); |
929 | ret = kraken3_init_device(hdev); |
930 | if (ret < 0) { |
931 | hid_err(hdev, "device init failed with %d\n" , ret); |
932 | goto fail_and_close; |
933 | } |
934 | |
935 | ret = kraken3_get_fw_ver(hdev); |
936 | if (ret < 0) |
937 | hid_warn(hdev, "fw version request failed with %d\n" , ret); |
938 | |
939 | priv->hwmon_dev = hwmon_device_register_with_info(dev: &hdev->dev, |
940 | name: kraken3_device_names[priv->kind], drvdata: priv, |
941 | info: &kraken3_chip_info, extra_groups: kraken3_groups); |
942 | if (IS_ERR(ptr: priv->hwmon_dev)) { |
943 | ret = PTR_ERR(ptr: priv->hwmon_dev); |
944 | hid_err(hdev, "hwmon registration failed with %d\n" , ret); |
945 | goto fail_and_close; |
946 | } |
947 | |
948 | kraken3_debugfs_init(priv); |
949 | |
950 | return 0; |
951 | |
952 | fail_and_close: |
953 | hid_hw_close(hdev); |
954 | fail_and_stop: |
955 | hid_hw_stop(hdev); |
956 | return ret; |
957 | } |
958 | |
959 | static void kraken3_remove(struct hid_device *hdev) |
960 | { |
961 | struct kraken3_data *priv = hid_get_drvdata(hdev); |
962 | |
963 | debugfs_remove_recursive(dentry: priv->debugfs); |
964 | hwmon_device_unregister(dev: priv->hwmon_dev); |
965 | |
966 | hid_hw_close(hdev); |
967 | hid_hw_stop(hdev); |
968 | } |
969 | |
970 | static const struct hid_device_id kraken3_table[] = { |
971 | /* NZXT Kraken X53/X63/X73 have two possible product IDs */ |
972 | { HID_USB_DEVICE(USB_VENDOR_ID_NZXT, USB_PRODUCT_ID_X53) }, |
973 | { HID_USB_DEVICE(USB_VENDOR_ID_NZXT, USB_PRODUCT_ID_X53_SECOND) }, |
974 | { HID_USB_DEVICE(USB_VENDOR_ID_NZXT, USB_PRODUCT_ID_Z53) }, |
975 | { } |
976 | }; |
977 | |
978 | MODULE_DEVICE_TABLE(hid, kraken3_table); |
979 | |
980 | static struct hid_driver kraken3_driver = { |
981 | .name = DRIVER_NAME, |
982 | .id_table = kraken3_table, |
983 | .probe = kraken3_probe, |
984 | .remove = kraken3_remove, |
985 | .raw_event = kraken3_raw_event, |
986 | #ifdef CONFIG_PM |
987 | .reset_resume = kraken3_reset_resume, |
988 | #endif |
989 | }; |
990 | |
991 | static int __init kraken3_init(void) |
992 | { |
993 | return hid_register_driver(&kraken3_driver); |
994 | } |
995 | |
996 | static void __exit kraken3_exit(void) |
997 | { |
998 | hid_unregister_driver(&kraken3_driver); |
999 | } |
1000 | |
1001 | /* When compiled into the kernel, initialize after the HID bus */ |
1002 | late_initcall(kraken3_init); |
1003 | module_exit(kraken3_exit); |
1004 | |
1005 | MODULE_LICENSE("GPL" ); |
1006 | MODULE_AUTHOR("Jonas Malaco <jonas@protocubo.io>" ); |
1007 | MODULE_AUTHOR("Aleksa Savic <savicaleksa83@gmail.com>" ); |
1008 | MODULE_DESCRIPTION("Hwmon driver for NZXT Kraken X53/X63/X73, Z53/Z63/Z73 coolers" ); |
1009 | |