ACPI: clean up white space in a few places for consistency
[sfrench/cifs-2.6.git] / drivers / hwmon / aquacomputer_d5next.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * hwmon driver for Aquacomputer devices (D5 Next, Farbwerk 360)
4  *
5  * Aquacomputer devices send HID reports (with ID 0x01) every second to report
6  * sensor values.
7  *
8  * Copyright 2021 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/jiffies.h>
15 #include <linux/module.h>
16 #include <linux/seq_file.h>
17 #include <asm/unaligned.h>
18
19 #define USB_VENDOR_ID_AQUACOMPUTER      0x0c70
20 #define USB_PRODUCT_ID_D5NEXT           0xf00e
21 #define USB_PRODUCT_ID_FARBWERK360      0xf010
22
23 enum kinds { d5next, farbwerk360 };
24
25 static const char *const aqc_device_names[] = {
26         [d5next] = "d5next",
27         [farbwerk360] = "farbwerk360"
28 };
29
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 */
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
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
61
62 /* Labels for D5 Next */
63 #define L_D5NEXT_COOLANT_TEMP           "Coolant temp"
64
65 static const char *const label_d5next_speeds[] = {
66         "Pump speed",
67         "Fan speed"
68 };
69
70 static const char *const label_d5next_power[] = {
71         "Pump power",
72         "Fan power"
73 };
74
75 static const char *const label_d5next_voltages[] = {
76         "Pump voltage",
77         "Fan voltage",
78         "+5V voltage"
79 };
80
81 static const char *const label_d5next_current[] = {
82         "Pump current",
83         "Fan current"
84 };
85
86 /* Labels for Farbwerk 360 temperature sensors */
87 static const char *const label_temp_sensors[] = {
88         "Sensor 1",
89         "Sensor 2",
90         "Sensor 3",
91         "Sensor 4"
92 };
93
94 struct aqc_data {
95         struct hid_device *hdev;
96         struct device *hwmon_dev;
97         struct dentry *debugfs;
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];
110         u16 speed_input[2];
111         u32 power_input[2];
112         u16 voltage_input[3];
113         u16 current_input[2];
114
115         unsigned long updated;
116 };
117
118 static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
119                               int channel)
120 {
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;
152 }
153
154 static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
155                     int channel, long *val)
156 {
157         struct aqc_data *priv = dev_get_drvdata(dev);
158
159         if (time_after(jiffies, priv->updated + STATUS_UPDATE_INTERVAL))
160                 return -ENODATA;
161
162         switch (type) {
163         case hwmon_temp:
164                 if (priv->temp_input[channel] == -ENODATA)
165                         return -ENODATA;
166
167                 *val = priv->temp_input[channel];
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
188 static int aqc_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
189                            int channel, const char **str)
190 {
191         struct aqc_data *priv = dev_get_drvdata(dev);
192
193         switch (type) {
194         case hwmon_temp:
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                 }
205                 break;
206         case hwmon_fan:
207                 switch (priv->kind) {
208                 case d5next:
209                         *str = label_d5next_speeds[channel];
210                         break;
211                 default:
212                         break;
213                 }
214                 break;
215         case hwmon_power:
216                 switch (priv->kind) {
217                 case d5next:
218                         *str = label_d5next_power[channel];
219                         break;
220                 default:
221                         break;
222                 }
223                 break;
224         case hwmon_in:
225                 switch (priv->kind) {
226                 case d5next:
227                         *str = label_d5next_voltages[channel];
228                         break;
229                 default:
230                         break;
231                 }
232                 break;
233         case hwmon_curr:
234                 switch (priv->kind) {
235                 case d5next:
236                         *str = label_d5next_current[channel];
237                         break;
238                 default:
239                         break;
240                 }
241                 break;
242         default:
243                 return -EOPNOTSUPP;
244         }
245
246         return 0;
247 }
248
249 static const struct hwmon_ops aqc_hwmon_ops = {
250         .is_visible = aqc_is_visible,
251         .read = aqc_read,
252         .read_string = aqc_read_string,
253 };
254
255 static 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,
270                            HWMON_I_INPUT | HWMON_I_LABEL),
271         HWMON_CHANNEL_INFO(curr,
272                            HWMON_C_INPUT | HWMON_C_LABEL,
273                            HWMON_C_INPUT | HWMON_C_LABEL),
274         NULL
275 };
276
277 static const struct hwmon_chip_info aqc_chip_info = {
278         .ops = &aqc_hwmon_ops,
279         .info = aqc_info,
280 };
281
282 static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data,
283                          int size)
284 {
285         int i, sensor_value;
286         struct aqc_data *priv;
287
288         if (report->id != STATUS_REPORT_ID)
289                 return 0;
290
291         priv = hid_get_drvdata(hdev);
292
293         /* Info provided with every report */
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);
297
298         /* Sensor readings */
299         switch (priv->kind) {
300         case d5next:
301                 priv->power_cycles = get_unaligned_be32(data + D5NEXT_POWER_CYCLES);
302
303                 priv->temp_input[0] = get_unaligned_be16(data + D5NEXT_COOLANT_TEMP) * 10;
304
305                 priv->speed_input[0] = get_unaligned_be16(data + D5NEXT_PUMP_SPEED);
306                 priv->speed_input[1] = get_unaligned_be16(data + D5NEXT_FAN_SPEED);
307
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;
310
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;
314
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         }
332
333         priv->updated = jiffies;
334
335         return 0;
336 }
337
338 #ifdef CONFIG_DEBUG_FS
339
340 static int serial_number_show(struct seq_file *seqf, void *unused)
341 {
342         struct aqc_data *priv = seqf->private;
343
344         seq_printf(seqf, "%05u-%05u\n", priv->serial_number[0], priv->serial_number[1]);
345
346         return 0;
347 }
348 DEFINE_SHOW_ATTRIBUTE(serial_number);
349
350 static int firmware_version_show(struct seq_file *seqf, void *unused)
351 {
352         struct aqc_data *priv = seqf->private;
353
354         seq_printf(seqf, "%u\n", priv->firmware_version);
355
356         return 0;
357 }
358 DEFINE_SHOW_ATTRIBUTE(firmware_version);
359
360 static int power_cycles_show(struct seq_file *seqf, void *unused)
361 {
362         struct aqc_data *priv = seqf->private;
363
364         seq_printf(seqf, "%u\n", priv->power_cycles);
365
366         return 0;
367 }
368 DEFINE_SHOW_ATTRIBUTE(power_cycles);
369
370 static void aqc_debugfs_init(struct aqc_data *priv)
371 {
372         char name[64];
373
374         scnprintf(name, sizeof(name), "%s_%s-%s", "aquacomputer", priv->name,
375                   dev_name(&priv->hdev->dev));
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);
380
381         if (priv->kind == d5next)
382                 debugfs_create_file("power_cycles", 0444, priv->debugfs, priv, &power_cycles_fops);
383 }
384
385 #else
386
387 static void aqc_debugfs_init(struct aqc_data *priv)
388 {
389 }
390
391 #endif
392
393 static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
394 {
395         struct aqc_data *priv;
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
405         priv->updated = jiffies - STATUS_UPDATE_INTERVAL;
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
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);
434
435         if (IS_ERR(priv->hwmon_dev)) {
436                 ret = PTR_ERR(priv->hwmon_dev);
437                 goto fail_and_close;
438         }
439
440         aqc_debugfs_init(priv);
441
442         return 0;
443
444 fail_and_close:
445         hid_hw_close(hdev);
446 fail_and_stop:
447         hid_hw_stop(hdev);
448         return ret;
449 }
450
451 static void aqc_remove(struct hid_device *hdev)
452 {
453         struct aqc_data *priv = hid_get_drvdata(hdev);
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
462 static 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         { }
466 };
467
468 MODULE_DEVICE_TABLE(hid, aqc_table);
469
470 static struct hid_driver aqc_driver = {
471         .name = DRIVER_NAME,
472         .id_table = aqc_table,
473         .probe = aqc_probe,
474         .remove = aqc_remove,
475         .raw_event = aqc_raw_event,
476 };
477
478 static int __init aqc_init(void)
479 {
480         return hid_register_driver(&aqc_driver);
481 }
482
483 static void __exit aqc_exit(void)
484 {
485         hid_unregister_driver(&aqc_driver);
486 }
487
488 /* Request to initialize after the HID bus to ensure it's not being loaded before */
489 late_initcall(aqc_init);
490 module_exit(aqc_exit);
491
492 MODULE_LICENSE("GPL");
493 MODULE_AUTHOR("Aleksa Savic <savicaleksa83@gmail.com>");
494 MODULE_DESCRIPTION("Hwmon driver for Aquacomputer devices");