1
2
3
4
5
6
7
8
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
23enum kinds { d5next, farbwerk360 };
24
25static 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)
34#define SERIAL_FIRST_PART 3
35#define SERIAL_SECOND_PART 5
36#define FIRMWARE_VERSION 13
37
38
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
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
63#define L_D5NEXT_COOLANT_TEMP "Coolant temp"
64
65static const char *const label_d5next_speeds[] = {
66 "Pump speed",
67 "Fan speed"
68};
69
70static const char *const label_d5next_power[] = {
71 "Pump power",
72 "Fan power"
73};
74
75static const char *const label_d5next_voltages[] = {
76 "Pump voltage",
77 "Fan voltage",
78 "+5V voltage"
79};
80
81static const char *const label_d5next_current[] = {
82 "Pump current",
83 "Fan current"
84};
85
86
87static const char *const label_temp_sensors[] = {
88 "Sensor 1",
89 "Sensor 2",
90 "Sensor 3",
91 "Sensor 4"
92};
93
94struct 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
102 u32 serial_number[2];
103 u16 firmware_version;
104
105
106 u32 power_cycles;
107
108
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
118static 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
154static 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
188static 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
249static 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
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,
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
277static const struct hwmon_chip_info aqc_chip_info = {
278 .ops = &aqc_hwmon_ops,
279 .info = aqc_info,
280};
281
282static 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
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
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
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
340static 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}
348DEFINE_SHOW_ATTRIBUTE(serial_number);
349
350static 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}
358DEFINE_SHOW_ATTRIBUTE(firmware_version);
359
360static 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}
368DEFINE_SHOW_ATTRIBUTE(power_cycles);
369
370static 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
387static void aqc_debugfs_init(struct aqc_data *priv)
388{
389}
390
391#endif
392
393static 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
444fail_and_close:
445 hid_hw_close(hdev);
446fail_and_stop:
447 hid_hw_stop(hdev);
448 return ret;
449}
450
451static 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
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 { }
466};
467
468MODULE_DEVICE_TABLE(hid, aqc_table);
469
470static 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
478static int __init aqc_init(void)
479{
480 return hid_register_driver(&aqc_driver);
481}
482
483static void __exit aqc_exit(void)
484{
485 hid_unregister_driver(&aqc_driver);
486}
487
488
489late_initcall(aqc_init);
490module_exit(aqc_exit);
491
492MODULE_LICENSE("GPL");
493MODULE_AUTHOR("Aleksa Savic <savicaleksa83@gmail.com>");
494MODULE_DESCRIPTION("Hwmon driver for Aquacomputer devices");
495