hwmon: (aquacomputer_d5next) Support sensors for Aquacomputer Aquaero
authorLeonard Anderweit <leonard.anderweit@gmail.com>
Sun, 18 Dec 2022 11:31:31 +0000 (12:31 +0100)
committerGuenter Roeck <linux@roeck-us.net>
Fri, 3 Feb 2023 15:30:09 +0000 (07:30 -0800)
Add support for reading sensors of the Aquacomputer Aquaero 5/6 fan
controllers. These fan controllers supports 4 fans, 8 physical
temperature sensors, 8 virtual temperature sensors and 2 flow sensors.
Temperature and flow sensor reading implemented by Aleksa Savic [1] [2]
[3].

[1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/pull/31
[2] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/pull/51
[3] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/pull/55

Originally-from: Aleksa Savic <savicaleksa83@gmail.com>
Signed-off-by: Leonard Anderweit <leonard.anderweit@gmail.com>
Link: https://lore.kernel.org/r/20221218113131.3752-7-leonard.anderweit@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Documentation/hwmon/aquacomputer_d5next.rst
drivers/hwmon/aquacomputer_d5next.c

index 637bdbc8fcad43ca915b9fb96450bb8e1a897850..b94ff08080bfa776dc0e9f5b868592abd92949cd 100644 (file)
@@ -5,6 +5,7 @@ Kernel driver aquacomputer-d5next
 
 Supported devices:
 
+* Aquacomputer Aquaero 5/6 fan controllers
 * Aquacomputer D5 Next watercooling pump
 * Aquacomputer Farbwerk RGB controller
 * Aquacomputer Farbwerk 360 RGB controller
@@ -20,6 +21,10 @@ Description
 This driver exposes hardware sensors of listed Aquacomputer devices, which
 communicate through proprietary USB HID protocols.
 
+The Aquaero devices expose eight temperature sensors, eight virtual temperature
+sensors and two flow senors. The fans expose their speed (in RPM), power,
+voltage and current.
+
 For the D5 Next pump, available sensors are pump and fan speed, power, voltage
 and current, as well as coolant temperature and eight virtual temp sensors. Also
 available through debugfs are the serial number, firmware version and power-on
index d28d7079917ac27fb6070d1134d693c7e51d945a..0fd00cfb86c83473c72796e6c1a1a7b0a95a65bd 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
  * hwmon driver for Aquacomputer devices (D5 Next, Farbwerk, Farbwerk 360, Octo,
- * Quadro, High Flow Next)
+ * Quadro, High Flow Next, Aquaero)
  *
  * Aquacomputer devices send HID reports (with ID 0x01) every second to report
  * sensor values.
@@ -21,6 +21,7 @@
 #include <asm/unaligned.h>
 
 #define USB_VENDOR_ID_AQUACOMPUTER     0x0c70
+#define USB_PRODUCT_ID_AQUAERO         0xf001
 #define USB_PRODUCT_ID_FARBWERK                0xf00a
 #define USB_PRODUCT_ID_QUADRO          0xf00d
 #define USB_PRODUCT_ID_D5NEXT          0xf00e
@@ -28,7 +29,7 @@
 #define USB_PRODUCT_ID_OCTO            0xf011
 #define USB_PRODUCT_ID_HIGHFLOWNEXT    0xf012
 
-enum kinds { d5next, farbwerk, farbwerk360, octo, quadro, highflownext };
+enum kinds { d5next, farbwerk, farbwerk360, octo, quadro, highflownext, aquaero };
 
 static const char *const aqc_device_names[] = {
        [d5next] = "d5next",
@@ -36,7 +37,8 @@ static const char *const aqc_device_names[] = {
        [farbwerk360] = "farbwerk360",
        [octo] = "octo",
        [quadro] = "quadro",
-       [highflownext] = "highflownext"
+       [highflownext] = "highflownext",
+       [aquaero] = "aquaero"
 };
 
 #define DRIVER_NAME                    "aquacomputer_d5next"
@@ -57,7 +59,7 @@ static u8 secondary_ctrl_report[] = {
        0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0xC6
 };
 
-/* Info, sensor sizes and offsets for all Aquacomputer devices */
+/* Info, sensor sizes and offsets for most Aquacomputer devices */
 #define AQC_SERIAL_START               0x3
 #define AQC_FIRMWARE_VERSION           0xD
 
@@ -69,6 +71,24 @@ static u8 secondary_ctrl_report[] = {
 #define AQC_FAN_POWER_OFFSET           0x06
 #define AQC_FAN_SPEED_OFFSET           0x08
 
+/* Specs of the Aquaero fan controllers */
+#define AQUAERO_SERIAL_START                   0x07
+#define AQUAERO_FIRMWARE_VERSION               0x0B
+#define AQUAERO_NUM_FANS                       4
+#define AQUAERO_NUM_SENSORS                    8
+#define AQUAERO_NUM_VIRTUAL_SENSORS            8
+#define AQUAERO_NUM_FLOW_SENSORS               2
+
+/* Sensor report offsets for Aquaero fan controllers */
+#define AQUAERO_SENSOR_START                   0x65
+#define AQUAERO_VIRTUAL_SENSOR_START           0x85
+#define AQUAERO_FLOW_SENSORS_START             0xF9
+#define AQUAERO_FAN_VOLTAGE_OFFSET             0x04
+#define AQUAERO_FAN_CURRENT_OFFSET             0x06
+#define AQUAERO_FAN_POWER_OFFSET               0x08
+#define AQUAERO_FAN_SPEED_OFFSET               0x00
+static u16 aquaero_sensor_fan_offsets[] = { 0x167, 0x173, 0x17f, 0x18B };
+
 /* Specs of the D5 Next pump */
 #define D5NEXT_NUM_FANS                        2
 #define D5NEXT_NUM_SENSORS             1
@@ -181,12 +201,16 @@ static const char *const label_d5next_current[] = {
        "Fan current"
 };
 
-/* Labels for Farbwerk, Farbwerk 360 and Octo and Quadro temperature sensors */
+/* Labels for Aquaero, Farbwerk, Farbwerk 360 and Octo and Quadro temperature sensors */
 static const char *const label_temp_sensors[] = {
        "Sensor 1",
        "Sensor 2",
        "Sensor 3",
-       "Sensor 4"
+       "Sensor 4",
+       "Sensor 5",
+       "Sensor 6",
+       "Sensor 7",
+       "Sensor 8"
 };
 
 static const char *const label_virtual_temp_sensors[] = {
@@ -262,6 +286,16 @@ static const char *const label_quadro_speeds[] = {
        "Flow speed [dL/h]"
 };
 
+/* Labels for Aquaero fan speeds */
+static const char *const label_aquaero_speeds[] = {
+       "Fan 1 speed",
+       "Fan 2 speed",
+       "Fan 3 speed",
+       "Fan 4 speed",
+       "Flow sensor 1 [dL/h]",
+       "Flow sensor 2 [dL/h]"
+};
+
 /* Labels for High Flow Next */
 static const char *const label_highflownext_temp_sensors[] = {
        "Coolant temp",
@@ -290,6 +324,14 @@ struct aqc_fan_structure_offsets {
        u8 speed;
 };
 
+/* Fan structure offsets for Aquaero */
+static struct aqc_fan_structure_offsets aqc_aquaero_fan_structure = {
+       .voltage = AQUAERO_FAN_VOLTAGE_OFFSET,
+       .curr = AQUAERO_FAN_CURRENT_OFFSET,
+       .power = AQUAERO_FAN_POWER_OFFSET,
+       .speed = AQUAERO_FAN_SPEED_OFFSET
+};
+
 /* Fan structure offsets for all devices except Aquaero */
 static struct aqc_fan_structure_offsets aqc_general_fan_structure = {
        .voltage = AQC_FAN_VOLTAGE_OFFSET,
@@ -496,6 +538,7 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
                                if (channel < 3)
                                        return 0444;
                                break;
+                       case aquaero:
                        case quadro:
                                /* Special case to support flow sensors */
                                if (channel < priv->num_fans + priv->num_flow_sensors)
@@ -977,6 +1020,42 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
                goto fail_and_stop;
 
        switch (hdev->product) {
+       case USB_PRODUCT_ID_AQUAERO:
+               /*
+                * Aquaero presents itself as three HID devices under the same product ID:
+                * "aquaero keyboard/mouse", "aquaero System Control" and "aquaero Device",
+                * which is the one we want to communicate with. Unlike most other Aquacomputer
+                * devices, Aquaero does not return meaningful data when explicitly requested
+                * using GET_FEATURE_REPORT.
+                *
+                * The difference between "aquaero Device" and the other two is in the collections
+                * they present. The two other devices have the type of the second element in
+                * their respective collections set to 1, while the real device has it set to 0.
+                */
+               if (hdev->collection[1].type != 0) {
+                       ret = -ENODEV;
+                       goto fail_and_close;
+               }
+
+               priv->kind = aquaero;
+
+               priv->num_fans = AQUAERO_NUM_FANS;
+               priv->fan_sensor_offsets = aquaero_sensor_fan_offsets;
+
+               priv->num_temp_sensors = AQUAERO_NUM_SENSORS;
+               priv->temp_sensor_start_offset = AQUAERO_SENSOR_START;
+               priv->num_virtual_temp_sensors = AQUAERO_NUM_VIRTUAL_SENSORS;
+               priv->virtual_temp_sensor_start_offset = AQUAERO_VIRTUAL_SENSOR_START;
+               priv->num_flow_sensors = AQUAERO_NUM_FLOW_SENSORS;
+               priv->flow_sensors_start_offset = AQUAERO_FLOW_SENSORS_START;
+
+               priv->temp_label = label_temp_sensors;
+               priv->virtual_temp_label = label_virtual_temp_sensors;
+               priv->speed_label = label_aquaero_speeds;
+               priv->power_label = label_fan_power;
+               priv->voltage_label = label_fan_voltage;
+               priv->current_label = label_fan_current;
+               break;
        case USB_PRODUCT_ID_D5NEXT:
                priv->kind = d5next;
 
@@ -1100,10 +1179,20 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
                break;
        }
 
-       priv->serial_number_start_offset = AQC_SERIAL_START;
-       priv->firmware_version_offset = AQC_FIRMWARE_VERSION;
+       switch (priv->kind) {
+       case aquaero:
+               priv->serial_number_start_offset = AQUAERO_SERIAL_START;
+               priv->firmware_version_offset = AQUAERO_FIRMWARE_VERSION;
+
+               priv->fan_structure = &aqc_aquaero_fan_structure;
+               break;
+       default:
+               priv->serial_number_start_offset = AQC_SERIAL_START;
+               priv->firmware_version_offset = AQC_FIRMWARE_VERSION;
 
-       priv->fan_structure = &aqc_general_fan_structure;
+               priv->fan_structure = &aqc_general_fan_structure;
+               break;
+       }
 
        if (priv->buffer_size != 0) {
                priv->checksum_start = 0x01;
@@ -1152,6 +1241,7 @@ static void aqc_remove(struct hid_device *hdev)
 }
 
 static const struct hid_device_id aqc_table[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUAERO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_D5NEXT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_FARBWERK) },
        { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_FARBWERK360) },