hwmon: (peci) Use devm_delayed_work_autocancel() to simplify code
[linux-block.git] / drivers / hwmon / aquacomputer_d5next.c
CommitLineData
0e35f63f
AS
1// SPDX-License-Identifier: GPL-2.0+
2/*
2fd3eec1 3 * hwmon driver for Aquacomputer devices (D5 Next, Farbwerk 360)
0e35f63f 4 *
2fd3eec1
AS
5 * Aquacomputer devices send HID reports (with ID 0x01) every second to report
6 * sensor values.
0e35f63f
AS
7 *
8 * Copyright 2021 Aleksa Savic <savicaleksa83@gmail.com>
9 */
10
0e35f63f
AS
11#include <linux/debugfs.h>
12#include <linux/hid.h>
13#include <linux/hwmon.h>
14#include <linux/jiffies.h>
15#include <linux/module.h>
16#include <linux/seq_file.h>
2fd3eec1 17#include <asm/unaligned.h>
0e35f63f 18
2fd3eec1
AS
19#define USB_VENDOR_ID_AQUACOMPUTER 0x0c70
20#define USB_PRODUCT_ID_D5NEXT 0xf00e
21#define USB_PRODUCT_ID_FARBWERK360 0xf010
0e35f63f 22
2fd3eec1 23enum kinds { d5next, farbwerk360 };
0e35f63f 24
2fd3eec1
AS
25static const char *const aqc_device_names[] = {
26 [d5next] = "d5next",
27 [farbwerk360] = "farbwerk360"
28};
0e35f63f 29
2fd3eec1
AS
30#define DRIVER_NAME "aquacomputer_d5next"
31
32#define STATUS_REPORT_ID 0x01
33#define STATUS_UPDATE_INTERVAL (2 * HZ) /* In seconds */
34#define SERIAL_FIRST_PART 3
35#define SERIAL_SECOND_PART 5
36#define FIRMWARE_VERSION 13
37
38/* Register offsets for the D5 Next pump */
0e35f63f
AS
39#define D5NEXT_POWER_CYCLES 24
40
41#define D5NEXT_COOLANT_TEMP 87
42
43#define D5NEXT_PUMP_SPEED 116
44#define D5NEXT_FAN_SPEED 103
45
46#define D5NEXT_PUMP_POWER 114
47#define D5NEXT_FAN_POWER 101
48
49#define D5NEXT_PUMP_VOLTAGE 110
50#define D5NEXT_FAN_VOLTAGE 97
51#define D5NEXT_5V_VOLTAGE 57
52
53#define D5NEXT_PUMP_CURRENT 112
54#define D5NEXT_FAN_CURRENT 99
55
2fd3eec1
AS
56/* Register offsets for the Farbwerk 360 RGB controller */
57#define FARBWERK360_NUM_SENSORS 4
58#define FARBWERK360_SENSOR_START 0x32
59#define FARBWERK360_SENSOR_SIZE 0x02
60#define FARBWERK360_SENSOR_DISCONNECTED 0x7FFF
0e35f63f 61
2fd3eec1
AS
62/* Labels for D5 Next */
63#define L_D5NEXT_COOLANT_TEMP "Coolant temp"
0e35f63f 64
2fd3eec1
AS
65static const char *const label_d5next_speeds[] = {
66 "Pump speed",
67 "Fan speed"
68};
0e35f63f 69
2fd3eec1
AS
70static const char *const label_d5next_power[] = {
71 "Pump power",
72 "Fan power"
0e35f63f
AS
73};
74
2fd3eec1
AS
75static const char *const label_d5next_voltages[] = {
76 "Pump voltage",
77 "Fan voltage",
78 "+5V voltage"
0e35f63f
AS
79};
80
2fd3eec1
AS
81static const char *const label_d5next_current[] = {
82 "Pump current",
83 "Fan current"
0e35f63f
AS
84};
85
2fd3eec1
AS
86/* Labels for Farbwerk 360 temperature sensors */
87static const char *const label_temp_sensors[] = {
88 "Sensor 1",
89 "Sensor 2",
90 "Sensor 3",
91 "Sensor 4"
0e35f63f
AS
92};
93
2fd3eec1 94struct aqc_data {
0e35f63f
AS
95 struct hid_device *hdev;
96 struct device *hwmon_dev;
97 struct dentry *debugfs;
2fd3eec1
AS
98 enum kinds kind;
99 const char *name;
100
101 /* General info, same across all devices */
102 u32 serial_number[2];
103 u16 firmware_version;
104
105 /* D5 Next specific - how many times the device was powered on */
106 u32 power_cycles;
107
108 /* Sensor values */
109 s32 temp_input[4];
0e35f63f
AS
110 u16 speed_input[2];
111 u32 power_input[2];
112 u16 voltage_input[3];
113 u16 current_input[2];
2fd3eec1 114
0e35f63f
AS
115 unsigned long updated;
116};
117
2fd3eec1
AS
118static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
119 int channel)
0e35f63f 120{
2fd3eec1
AS
121 const struct aqc_data *priv = data;
122
123 switch (type) {
124 case hwmon_temp:
125 switch (priv->kind) {
126 case d5next:
127 if (channel == 0)
128 return 0444;
129 break;
130 case farbwerk360:
131 return 0444;
132 default:
133 break;
134 }
135 break;
136 case hwmon_fan:
137 case hwmon_power:
138 case hwmon_in:
139 case hwmon_curr:
140 switch (priv->kind) {
141 case d5next:
142 return 0444;
143 default:
144 break;
145 }
146 break;
147 default:
148 break;
149 }
150
151 return 0;
0e35f63f
AS
152}
153
2fd3eec1
AS
154static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
155 int channel, long *val)
0e35f63f 156{
2fd3eec1 157 struct aqc_data *priv = dev_get_drvdata(dev);
0e35f63f 158
2fd3eec1 159 if (time_after(jiffies, priv->updated + STATUS_UPDATE_INTERVAL))
0e35f63f
AS
160 return -ENODATA;
161
162 switch (type) {
163 case hwmon_temp:
2fd3eec1
AS
164 if (priv->temp_input[channel] == -ENODATA)
165 return -ENODATA;
166
167 *val = priv->temp_input[channel];
0e35f63f
AS
168 break;
169 case hwmon_fan:
170 *val = priv->speed_input[channel];
171 break;
172 case hwmon_power:
173 *val = priv->power_input[channel];
174 break;
175 case hwmon_in:
176 *val = priv->voltage_input[channel];
177 break;
178 case hwmon_curr:
179 *val = priv->current_input[channel];
180 break;
181 default:
182 return -EOPNOTSUPP;
183 }
184
185 return 0;
186}
187
2fd3eec1
AS
188static int aqc_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
189 int channel, const char **str)
0e35f63f 190{
2fd3eec1
AS
191 struct aqc_data *priv = dev_get_drvdata(dev);
192
0e35f63f
AS
193 switch (type) {
194 case hwmon_temp:
2fd3eec1
AS
195 switch (priv->kind) {
196 case d5next:
197 *str = L_D5NEXT_COOLANT_TEMP;
198 break;
199 case farbwerk360:
200 *str = label_temp_sensors[channel];
201 break;
202 default:
203 break;
204 }
0e35f63f
AS
205 break;
206 case hwmon_fan:
2fd3eec1
AS
207 switch (priv->kind) {
208 case d5next:
209 *str = label_d5next_speeds[channel];
210 break;
211 default:
212 break;
213 }
0e35f63f
AS
214 break;
215 case hwmon_power:
2fd3eec1
AS
216 switch (priv->kind) {
217 case d5next:
218 *str = label_d5next_power[channel];
219 break;
220 default:
221 break;
222 }
0e35f63f
AS
223 break;
224 case hwmon_in:
2fd3eec1
AS
225 switch (priv->kind) {
226 case d5next:
227 *str = label_d5next_voltages[channel];
228 break;
229 default:
230 break;
231 }
0e35f63f
AS
232 break;
233 case hwmon_curr:
2fd3eec1
AS
234 switch (priv->kind) {
235 case d5next:
236 *str = label_d5next_current[channel];
237 break;
238 default:
239 break;
240 }
0e35f63f
AS
241 break;
242 default:
243 return -EOPNOTSUPP;
244 }
245
246 return 0;
247}
248
2fd3eec1
AS
249static const struct hwmon_ops aqc_hwmon_ops = {
250 .is_visible = aqc_is_visible,
251 .read = aqc_read,
252 .read_string = aqc_read_string,
0e35f63f
AS
253};
254
2fd3eec1
AS
255static const struct hwmon_channel_info *aqc_info[] = {
256 HWMON_CHANNEL_INFO(temp,
257 HWMON_T_INPUT | HWMON_T_LABEL,
258 HWMON_T_INPUT | HWMON_T_LABEL,
259 HWMON_T_INPUT | HWMON_T_LABEL,
260 HWMON_T_INPUT | HWMON_T_LABEL),
261 HWMON_CHANNEL_INFO(fan,
262 HWMON_F_INPUT | HWMON_F_LABEL,
263 HWMON_F_INPUT | HWMON_F_LABEL),
264 HWMON_CHANNEL_INFO(power,
265 HWMON_P_INPUT | HWMON_P_LABEL,
266 HWMON_P_INPUT | HWMON_P_LABEL),
267 HWMON_CHANNEL_INFO(in,
268 HWMON_I_INPUT | HWMON_I_LABEL,
269 HWMON_I_INPUT | HWMON_I_LABEL,
0e35f63f 270 HWMON_I_INPUT | HWMON_I_LABEL),
2fd3eec1
AS
271 HWMON_CHANNEL_INFO(curr,
272 HWMON_C_INPUT | HWMON_C_LABEL,
273 HWMON_C_INPUT | HWMON_C_LABEL),
0e35f63f
AS
274 NULL
275};
276
2fd3eec1
AS
277static const struct hwmon_chip_info aqc_chip_info = {
278 .ops = &aqc_hwmon_ops,
279 .info = aqc_info,
0e35f63f
AS
280};
281
2fd3eec1
AS
282static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data,
283 int size)
0e35f63f 284{
2fd3eec1
AS
285 int i, sensor_value;
286 struct aqc_data *priv;
0e35f63f 287
2fd3eec1 288 if (report->id != STATUS_REPORT_ID)
0e35f63f
AS
289 return 0;
290
291 priv = hid_get_drvdata(hdev);
292
293 /* Info provided with every report */
2fd3eec1
AS
294 priv->serial_number[0] = get_unaligned_be16(data + SERIAL_FIRST_PART);
295 priv->serial_number[1] = get_unaligned_be16(data + SERIAL_SECOND_PART);
296 priv->firmware_version = get_unaligned_be16(data + FIRMWARE_VERSION);
0e35f63f
AS
297
298 /* Sensor readings */
2fd3eec1
AS
299 switch (priv->kind) {
300 case d5next:
301 priv->power_cycles = get_unaligned_be32(data + D5NEXT_POWER_CYCLES);
0e35f63f 302
2fd3eec1 303 priv->temp_input[0] = get_unaligned_be16(data + D5NEXT_COOLANT_TEMP) * 10;
0e35f63f 304
2fd3eec1
AS
305 priv->speed_input[0] = get_unaligned_be16(data + D5NEXT_PUMP_SPEED);
306 priv->speed_input[1] = get_unaligned_be16(data + D5NEXT_FAN_SPEED);
0e35f63f 307
2fd3eec1
AS
308 priv->power_input[0] = get_unaligned_be16(data + D5NEXT_PUMP_POWER) * 10000;
309 priv->power_input[1] = get_unaligned_be16(data + D5NEXT_FAN_POWER) * 10000;
0e35f63f 310
2fd3eec1
AS
311 priv->voltage_input[0] = get_unaligned_be16(data + D5NEXT_PUMP_VOLTAGE) * 10;
312 priv->voltage_input[1] = get_unaligned_be16(data + D5NEXT_FAN_VOLTAGE) * 10;
313 priv->voltage_input[2] = get_unaligned_be16(data + D5NEXT_5V_VOLTAGE) * 10;
0e35f63f 314
2fd3eec1
AS
315 priv->current_input[0] = get_unaligned_be16(data + D5NEXT_PUMP_CURRENT);
316 priv->current_input[1] = get_unaligned_be16(data + D5NEXT_FAN_CURRENT);
317 break;
318 case farbwerk360:
319 /* Temperature sensor readings */
320 for (i = 0; i < FARBWERK360_NUM_SENSORS; i++) {
321 sensor_value = get_unaligned_be16(data + FARBWERK360_SENSOR_START +
322 i * FARBWERK360_SENSOR_SIZE);
323 if (sensor_value == FARBWERK360_SENSOR_DISCONNECTED)
324 priv->temp_input[i] = -ENODATA;
325 else
326 priv->temp_input[i] = sensor_value * 10;
327 }
328 break;
329 default:
330 break;
331 }
0e35f63f
AS
332
333 priv->updated = jiffies;
334
335 return 0;
336}
337
338#ifdef CONFIG_DEBUG_FS
339
340static int serial_number_show(struct seq_file *seqf, void *unused)
341{
2fd3eec1 342 struct aqc_data *priv = seqf->private;
0e35f63f
AS
343
344 seq_printf(seqf, "%05u-%05u\n", priv->serial_number[0], priv->serial_number[1]);
345
346 return 0;
347}
348DEFINE_SHOW_ATTRIBUTE(serial_number);
349
350static int firmware_version_show(struct seq_file *seqf, void *unused)
351{
2fd3eec1 352 struct aqc_data *priv = seqf->private;
0e35f63f
AS
353
354 seq_printf(seqf, "%u\n", priv->firmware_version);
355
356 return 0;
357}
358DEFINE_SHOW_ATTRIBUTE(firmware_version);
359
360static int power_cycles_show(struct seq_file *seqf, void *unused)
361{
2fd3eec1 362 struct aqc_data *priv = seqf->private;
0e35f63f
AS
363
364 seq_printf(seqf, "%u\n", priv->power_cycles);
365
366 return 0;
367}
368DEFINE_SHOW_ATTRIBUTE(power_cycles);
369
2fd3eec1 370static void aqc_debugfs_init(struct aqc_data *priv)
0e35f63f 371{
2fd3eec1 372 char name[64];
0e35f63f 373
2fd3eec1
AS
374 scnprintf(name, sizeof(name), "%s_%s-%s", "aquacomputer", priv->name,
375 dev_name(&priv->hdev->dev));
0e35f63f
AS
376
377 priv->debugfs = debugfs_create_dir(name, NULL);
378 debugfs_create_file("serial_number", 0444, priv->debugfs, priv, &serial_number_fops);
379 debugfs_create_file("firmware_version", 0444, priv->debugfs, priv, &firmware_version_fops);
2fd3eec1
AS
380
381 if (priv->kind == d5next)
382 debugfs_create_file("power_cycles", 0444, priv->debugfs, priv, &power_cycles_fops);
0e35f63f
AS
383}
384
385#else
386
2fd3eec1 387static void aqc_debugfs_init(struct aqc_data *priv)
0e35f63f
AS
388{
389}
390
391#endif
392
2fd3eec1 393static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
0e35f63f 394{
2fd3eec1 395 struct aqc_data *priv;
0e35f63f
AS
396 int ret;
397
398 priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
399 if (!priv)
400 return -ENOMEM;
401
402 priv->hdev = hdev;
403 hid_set_drvdata(hdev, priv);
404
2fd3eec1 405 priv->updated = jiffies - STATUS_UPDATE_INTERVAL;
0e35f63f
AS
406
407 ret = hid_parse(hdev);
408 if (ret)
409 return ret;
410
411 ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
412 if (ret)
413 return ret;
414
415 ret = hid_hw_open(hdev);
416 if (ret)
417 goto fail_and_stop;
418
2fd3eec1
AS
419 switch (hdev->product) {
420 case USB_PRODUCT_ID_D5NEXT:
421 priv->kind = d5next;
422 break;
423 case USB_PRODUCT_ID_FARBWERK360:
424 priv->kind = farbwerk360;
425 break;
426 default:
427 break;
428 }
429
430 priv->name = aqc_device_names[priv->kind];
431
432 priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, priv->name, priv,
433 &aqc_chip_info, NULL);
0e35f63f
AS
434
435 if (IS_ERR(priv->hwmon_dev)) {
436 ret = PTR_ERR(priv->hwmon_dev);
437 goto fail_and_close;
438 }
439
2fd3eec1 440 aqc_debugfs_init(priv);
0e35f63f
AS
441
442 return 0;
443
444fail_and_close:
445 hid_hw_close(hdev);
446fail_and_stop:
447 hid_hw_stop(hdev);
448 return ret;
449}
450
2fd3eec1 451static void aqc_remove(struct hid_device *hdev)
0e35f63f 452{
2fd3eec1 453 struct aqc_data *priv = hid_get_drvdata(hdev);
0e35f63f
AS
454
455 debugfs_remove_recursive(priv->debugfs);
456 hwmon_device_unregister(priv->hwmon_dev);
457
458 hid_hw_close(hdev);
459 hid_hw_stop(hdev);
460}
461
2fd3eec1
AS
462static const struct hid_device_id aqc_table[] = {
463 { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_D5NEXT) },
464 { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_FARBWERK360) },
465 { }
0e35f63f
AS
466};
467
2fd3eec1 468MODULE_DEVICE_TABLE(hid, aqc_table);
0e35f63f 469
2fd3eec1 470static struct hid_driver aqc_driver = {
0e35f63f 471 .name = DRIVER_NAME,
2fd3eec1
AS
472 .id_table = aqc_table,
473 .probe = aqc_probe,
474 .remove = aqc_remove,
475 .raw_event = aqc_raw_event,
0e35f63f
AS
476};
477
2fd3eec1 478static int __init aqc_init(void)
0e35f63f 479{
2fd3eec1 480 return hid_register_driver(&aqc_driver);
0e35f63f
AS
481}
482
2fd3eec1 483static void __exit aqc_exit(void)
0e35f63f 484{
2fd3eec1 485 hid_unregister_driver(&aqc_driver);
0e35f63f
AS
486}
487
488/* Request to initialize after the HID bus to ensure it's not being loaded before */
2fd3eec1
AS
489late_initcall(aqc_init);
490module_exit(aqc_exit);
0e35f63f
AS
491
492MODULE_LICENSE("GPL");
493MODULE_AUTHOR("Aleksa Savic <savicaleksa83@gmail.com>");
2fd3eec1 494MODULE_DESCRIPTION("Hwmon driver for Aquacomputer devices");