Merge tag '6.7-rc-ksmbd-server-fixes' of git://git.samba.org/ksmbd
[linux-block.git] / drivers / hwmon / aquacomputer_d5next.c
index 023807859be721af075c5a786be9c49d9c79da67..4fdd2e12427b9dfa2d1c8f62914cb9657efb07ac 100644 (file)
@@ -1,11 +1,12 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
  * hwmon driver for Aquacomputer devices (D5 Next, Farbwerk, Farbwerk 360, Octo,
- * Quadro, High Flow Next, Aquaero, Aquastream Ultimate, Leakshield)
+ * Quadro, High Flow Next, Aquaero, Aquastream Ultimate, Leakshield,
+ * High Flow USB/MPS Flow family)
  *
  * Aquacomputer devices send HID reports (with ID 0x01) every second to report
  * sensor values, except for devices that communicate through the
- * legacy way (currently, Poweradjust 3).
+ * legacy way (currently, Poweradjust 3 and High Flow USB/MPS Flow family).
  *
  * Copyright 2021 Aleksa Savic <savicaleksa83@gmail.com>
  * Copyright 2022 Jack Doan <me@jackdoan.com>
 #define USB_PRODUCT_ID_AQUASTREAMXT    0xf0b6
 #define USB_PRODUCT_ID_AQUASTREAMULT   0xf00b
 #define USB_PRODUCT_ID_POWERADJUST3    0xf0bd
+#define USB_PRODUCT_ID_HIGHFLOW                0xf003
 
 enum kinds {
        d5next, farbwerk, farbwerk360, octo, quadro,
        highflownext, aquaero, poweradjust3, aquastreamult,
-       aquastreamxt, leakshield
+       aquastreamxt, leakshield, highflow
 };
 
 static const char *const aqc_device_names[] = {
@@ -53,7 +55,8 @@ static const char *const aqc_device_names[] = {
        [aquastreamxt] = "aquastreamxt",
        [aquaero] = "aquaero",
        [aquastreamult] = "aquastreamultimate",
-       [poweradjust3] = "poweradjust3"
+       [poweradjust3] = "poweradjust3",
+       [highflow] = "highflow" /* Covers MPS Flow devices */
 };
 
 #define DRIVER_NAME                    "aquacomputer_d5next"
@@ -90,6 +93,8 @@ static u8 aquaero_secondary_ctrl_report[] = {
 
 #define POWERADJUST3_STATUS_REPORT_ID  0x03
 
+#define HIGHFLOW_STATUS_REPORT_ID      0x02
+
 /* Data types for reading and writing control reports */
 #define AQC_8          0
 #define AQC_BE16       1
@@ -282,6 +287,17 @@ static u16 aquastreamxt_sensor_fan_offsets[] = { 0x13, 0x1b };
 /* Sensor report offsets for the Poweradjust 3 */
 #define POWERADJUST3_SENSOR_START      0x03
 
+/* Specs of the High Flow USB */
+#define HIGHFLOW_NUM_SENSORS           2
+#define HIGHFLOW_NUM_FLOW_SENSORS      1
+#define HIGHFLOW_SENSOR_REPORT_SIZE    0x76
+
+/* Sensor report offsets for the High Flow USB */
+#define HIGHFLOW_FIRMWARE_VERSION      0x3
+#define HIGHFLOW_SERIAL_START          0x9
+#define HIGHFLOW_FLOW_SENSOR_OFFSET    0x23
+#define HIGHFLOW_SENSOR_START          0x2b
+
 /* Labels for D5 Next */
 static const char *const label_d5next_temp[] = {
        "Coolant temp"
@@ -486,6 +502,16 @@ static const char *const label_poweradjust3_temp_sensors[] = {
        "External sensor"
 };
 
+/* Labels for Highflow */
+static const char *const label_highflow_temp[] = {
+       "External temp",
+       "Internal temp"
+};
+
+static const char *const label_highflow_speeds[] = {
+       "Flow speed [dL/h]"
+};
+
 struct aqc_fan_structure_offsets {
        u8 voltage;
        u8 curr;
@@ -819,6 +845,7 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
                                break;
                        case aquaero:
                        case quadro:
+                       case highflow:
                                /* Special case to support flow sensors */
                                if (channel < priv->num_fans + priv->num_flow_sensors)
                                        return 0444;
@@ -926,7 +953,10 @@ static int aqc_legacy_read(struct aqc_data *priv)
        for (i = 0; i < priv->num_temp_sensors; i++) {
                sensor_value = get_unaligned_le16(priv->buffer + priv->temp_sensor_start_offset +
                                                  i * AQC_SENSOR_SIZE);
-               priv->temp_input[i] = sensor_value * 10;
+               if (sensor_value == AQC_SENSOR_NA)
+                       priv->temp_input[i] = -ENODATA;
+               else
+                       priv->temp_input[i] = sensor_value * 10;
        }
 
        /* Special-case sensor readings */
@@ -962,6 +992,17 @@ static int aqc_legacy_read(struct aqc_data *priv)
                sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_FAN_VOLTAGE_OFFSET);
                priv->voltage_input[1] = DIV_ROUND_CLOSEST(sensor_value * 1000, 63);
                break;
+       case highflow:
+               /* Info provided with every report */
+               priv->serial_number[0] = get_unaligned_le16(priv->buffer +
+                                                           priv->serial_number_start_offset);
+               priv->firmware_version =
+                   get_unaligned_le16(priv->buffer + priv->firmware_version_offset);
+
+               /* Read flow speed */
+               priv->speed_input[0] = get_unaligned_le16(priv->buffer +
+                                                         priv->flow_sensors_start_offset);
+               break;
        default:
                break;
        }
@@ -1747,6 +1788,20 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
                priv->temp_label = label_poweradjust3_temp_sensors;
                break;
+       case USB_PRODUCT_ID_HIGHFLOW:
+               priv->kind = highflow;
+
+               priv->num_fans = 0;
+
+               priv->num_temp_sensors = HIGHFLOW_NUM_SENSORS;
+               priv->temp_sensor_start_offset = HIGHFLOW_SENSOR_START;
+               priv->num_flow_sensors = HIGHFLOW_NUM_FLOW_SENSORS;
+               priv->flow_sensors_start_offset = HIGHFLOW_FLOW_SENSOR_OFFSET;
+               priv->buffer_size = HIGHFLOW_SENSOR_REPORT_SIZE;
+
+               priv->temp_label = label_highflow_temp;
+               priv->speed_label = label_highflow_speeds;
+               break;
        default:
                break;
        }
@@ -1772,6 +1827,12 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
                priv->status_report_id = AQUASTREAMXT_STATUS_REPORT_ID;
                break;
+       case highflow:
+               priv->serial_number_start_offset = HIGHFLOW_SERIAL_START;
+               priv->firmware_version_offset = HIGHFLOW_FIRMWARE_VERSION;
+
+               priv->status_report_id = HIGHFLOW_STATUS_REPORT_ID;
+               break;
        default:
                priv->serial_number_start_offset = AQC_SERIAL_START;
                priv->firmware_version_offset = AQC_FIRMWARE_VERSION;
@@ -1846,6 +1907,7 @@ static const struct hid_device_id aqc_table[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMXT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMULT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_POWERADJUST3) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_HIGHFLOW) },
        { }
 };