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"); 495