On Sat, May 20, 2023 at 11:54:47AM +0200, Aleksa Savic wrote: > Extend aquacomputer_d5next driver to expose various hardware sensors of the > Aquacomputer Leakshield leak prevention system, which communicates > through a proprietary USB HID protocol. Implemented by Noah Bergbauer [1]. > > Two temperature sensors are exposed, along with pressure (current, min, max > and target), reservoir volume (total and filled), pump speed and flow. Pump > speed and flow values are user provided and allow the Leakshield to > optimize its operation. Writing them to the device is subject of future > patches. > > [1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/pull/41 > > Originally-from: Noah Bergbauer <main@xxxxxxxx> > Signed-off-by: Aleksa Savic <savicaleksa83@xxxxxxxxx> Applied. Thanks, Guenter > --- > Changes in v2: > - Moved macro renaming to previous patch > --- > Documentation/hwmon/aquacomputer_d5next.rst | 9 ++ > drivers/hwmon/aquacomputer_d5next.c | 109 +++++++++++++++++++- > 2 files changed, 114 insertions(+), 4 deletions(-) > > diff --git a/Documentation/hwmon/aquacomputer_d5next.rst b/Documentation/hwmon/aquacomputer_d5next.rst > index 14b37851af0c..94dc2d93d180 100644 > --- a/Documentation/hwmon/aquacomputer_d5next.rst > +++ b/Documentation/hwmon/aquacomputer_d5next.rst > @@ -12,6 +12,7 @@ Supported devices: > * Aquacomputer Octo fan controller > * Aquacomputer Quadro fan controller > * Aquacomputer High Flow Next sensor > +* Aquacomputer Leakshield leak prevention system > * Aquacomputer Aquastream XT watercooling pump > * Aquacomputer Aquastream Ultimate watercooling pump > * Aquacomputer Poweradjust 3 fan controller > @@ -57,6 +58,11 @@ The High Flow Next exposes +5V voltages, water quality, conductivity and flow re > A temperature sensor can be connected to it, in which case it provides its reading > and an estimation of the dissipated/absorbed power in the liquid cooling loop. > > +The Leakshield exposes two temperature sensors and coolant pressure (current, min, max and > +target readings). It also exposes the estimated reservoir volume and how much of it is > +filled with coolant. Pump RPM and flow can be set to enhance on-device calculations, > +but this is not yet implemented here. > + > The Aquastream XT pump exposes temperature readings for the coolant, external sensor > and fan IC. It also exposes pump and fan speeds (in RPM), voltages, as well as pump > current. > @@ -83,6 +89,9 @@ Sysfs entries > temp[1-20]_input Physical/virtual temperature sensors (in millidegrees Celsius) > temp[1-8]_offset Temperature sensor correction offset (in millidegrees Celsius) > fan[1-8]_input Pump/fan speed (in RPM) / Flow speed (in dL/h) > +fan1_min Minimal fan speed (in RPM) > +fan1_max Maximal fan speed (in RPM) > +fan1_target Target fan speed (in RPM) > fan5_pulses Quadro flow sensor pulses > power[1-8]_input Pump/fan power (in micro Watts) > in[0-7]_input Pump/fan voltage (in milli Volts) > diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c > index 834d011e220f..a981f7086114 100644 > --- a/drivers/hwmon/aquacomputer_d5next.c > +++ b/drivers/hwmon/aquacomputer_d5next.c > @@ -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, Aquaero, Aquastream Ultimate) > + * Quadro, High Flow Next, Aquaero, Aquastream Ultimate, Leakshield) > * > * Aquacomputer devices send HID reports (with ID 0x01) every second to report > * sensor values, except for devices that communicate through the > @@ -29,6 +29,7 @@ > #define USB_PRODUCT_ID_FARBWERK360 0xf010 > #define USB_PRODUCT_ID_OCTO 0xf011 > #define USB_PRODUCT_ID_HIGHFLOWNEXT 0xf012 > +#define USB_PRODUCT_ID_LEAKSHIELD 0xf014 > #define USB_PRODUCT_ID_AQUASTREAMXT 0xf0b6 > #define USB_PRODUCT_ID_AQUASTREAMULT 0xf00b > #define USB_PRODUCT_ID_POWERADJUST3 0xf0bd > @@ -36,7 +37,7 @@ > enum kinds { > d5next, farbwerk, farbwerk360, octo, quadro, > highflownext, aquaero, poweradjust3, aquastreamult, > - aquastreamxt > + aquastreamxt, leakshield > }; > > static const char *const aqc_device_names[] = { > @@ -46,6 +47,7 @@ static const char *const aqc_device_names[] = { > [octo] = "octo", > [quadro] = "quadro", > [highflownext] = "highflownext", > + [leakshield] = "leakshield", > [aquastreamxt] = "aquastreamxt", > [aquaero] = "aquaero", > [aquastreamult] = "aquastreamultimate", > @@ -236,6 +238,21 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed > #define HIGHFLOWNEXT_5V_VOLTAGE 97 > #define HIGHFLOWNEXT_5V_VOLTAGE_USB 99 > > +/* Specs of the Leakshield */ > +#define LEAKSHIELD_NUM_SENSORS 2 > + > +/* Sensor report offsets for Leakshield */ > +#define LEAKSHIELD_PRESSURE_ADJUSTED 285 > +#define LEAKSHIELD_TEMPERATURE_1 265 > +#define LEAKSHIELD_TEMPERATURE_2 287 > +#define LEAKSHIELD_PRESSURE_MIN 291 > +#define LEAKSHIELD_PRESSURE_TARGET 293 > +#define LEAKSHIELD_PRESSURE_MAX 295 > +#define LEAKSHIELD_PUMP_RPM_IN 101 > +#define LEAKSHIELD_FLOW_IN 111 > +#define LEAKSHIELD_RESERVOIR_VOLUME 313 > +#define LEAKSHIELD_RESERVOIR_FILLED 311 > + > /* Specs of the Aquastream XT pump */ > #define AQUASTREAMXT_SERIAL_START 0x3a > #define AQUASTREAMXT_FIRMWARE_VERSION 0x32 > @@ -411,6 +428,20 @@ static const char *const label_highflownext_voltage[] = { > "+5V USB voltage" > }; > > +/* Labels for Leakshield */ > +static const char *const label_leakshield_temp_sensors[] = { > + "Temperature 1", > + "Temperature 2" > +}; > + > +static const char *const label_leakshield_fan_speed[] = { > + "Pressure [ubar]", > + "User-Provided Pump Speed", > + "User-Provided Flow [dL/h]", > + "Reservoir Volume [ml]", > + "Reservoir Filled [ml]", > +}; > + > /* Labels for Aquastream XT */ > static const char *const label_aquastreamxt_temp_sensors[] = { > "Fan IC temp", > @@ -529,7 +560,10 @@ struct aqc_data { > > /* Sensor values */ > s32 temp_input[20]; /* Max 4 physical and 16 virtual or 8 physical and 12 virtual */ > - u16 speed_input[8]; > + s32 speed_input[8]; > + u32 speed_input_min[1]; > + u32 speed_input_target[1]; > + u32 speed_input_max[1]; > u32 power_input[8]; > u16 voltage_input[8]; > u16 current_input[8]; > @@ -747,6 +781,11 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 > if (channel < 3) > return 0444; > break; > + case leakshield: > + /* Special case for Leakshield sensors */ > + if (channel < 5) > + return 0444; > + break; > case aquaero: > case quadro: > /* Special case to support flow sensors */ > @@ -764,6 +803,13 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 > if (priv->kind == quadro && channel == priv->num_fans) > return 0644; > break; > + case hwmon_fan_min: > + case hwmon_fan_max: > + case hwmon_fan_target: > + /* Special case for Leakshield pressure sensor */ > + if (priv->kind == leakshield && channel == 0) > + return 0444; > + break; > default: > break; > } > @@ -938,8 +984,20 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, > case hwmon_fan: > switch (attr) { > case hwmon_fan_input: > + if (priv->speed_input[channel] == -ENODATA) > + return -ENODATA; > + > *val = priv->speed_input[channel]; > break; > + case hwmon_fan_min: > + *val = priv->speed_input_min[channel]; > + break; > + case hwmon_fan_max: > + *val = priv->speed_input_max[channel]; > + break; > + case hwmon_fan_target: > + *val = priv->speed_input_target[channel]; > + break; > case hwmon_fan_pulses: > ret = aqc_get_ctrl_val(priv, priv->flow_pulses_ctrl_offset, > val, AQC_BE16); > @@ -1151,7 +1209,8 @@ static const struct hwmon_channel_info * const aqc_info[] = { > HWMON_T_INPUT | HWMON_T_LABEL, > HWMON_T_INPUT | HWMON_T_LABEL), > HWMON_CHANNEL_INFO(fan, > - HWMON_F_INPUT | HWMON_F_LABEL, > + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX | > + HWMON_F_TARGET, > HWMON_F_INPUT | HWMON_F_LABEL, > HWMON_F_INPUT | HWMON_F_LABEL, > HWMON_F_INPUT | HWMON_F_LABEL, > @@ -1314,6 +1373,28 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 > priv->speed_input[1] = get_unaligned_be16(data + HIGHFLOWNEXT_WATER_QUALITY); > priv->speed_input[2] = get_unaligned_be16(data + HIGHFLOWNEXT_CONDUCTIVITY); > break; > + case leakshield: > + priv->speed_input[0] = > + ((s16)get_unaligned_be16(data + LEAKSHIELD_PRESSURE_ADJUSTED)) * 100; > + priv->speed_input_min[0] = get_unaligned_be16(data + LEAKSHIELD_PRESSURE_MIN) * 100; > + priv->speed_input_target[0] = > + get_unaligned_be16(data + LEAKSHIELD_PRESSURE_TARGET) * 100; > + priv->speed_input_max[0] = get_unaligned_be16(data + LEAKSHIELD_PRESSURE_MAX) * 100; > + > + priv->speed_input[1] = get_unaligned_be16(data + LEAKSHIELD_PUMP_RPM_IN); > + if (priv->speed_input[1] == AQC_SENSOR_NA) > + priv->speed_input[1] = -ENODATA; > + > + priv->speed_input[2] = get_unaligned_be16(data + LEAKSHIELD_FLOW_IN); > + if (priv->speed_input[2] == AQC_SENSOR_NA) > + priv->speed_input[2] = -ENODATA; > + > + priv->speed_input[3] = get_unaligned_be16(data + LEAKSHIELD_RESERVOIR_VOLUME); > + priv->speed_input[4] = get_unaligned_be16(data + LEAKSHIELD_RESERVOIR_FILLED); > + > + /* Second temp sensor is not positioned after the first one, read it here */ > + priv->temp_input[1] = get_unaligned_be16(data + LEAKSHIELD_TEMPERATURE_2) * 10; > + break; > default: > break; > } > @@ -1571,6 +1652,25 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) > priv->power_label = label_highflownext_power; > priv->voltage_label = label_highflownext_voltage; > break; > + case USB_PRODUCT_ID_LEAKSHIELD: > + /* > + * Choose the right Leakshield device, because > + * the other one acts as a keyboard > + */ > + if (hdev->type != 2) { > + ret = -ENODEV; > + goto fail_and_close; > + } > + > + priv->kind = leakshield; > + > + priv->num_fans = 0; > + priv->num_temp_sensors = LEAKSHIELD_NUM_SENSORS; > + priv->temp_sensor_start_offset = LEAKSHIELD_TEMPERATURE_1; > + > + priv->temp_label = label_leakshield_temp_sensors; > + priv->speed_label = label_leakshield_fan_speed; > + break; > case USB_PRODUCT_ID_AQUASTREAMXT: > priv->kind = aquastreamxt; > > @@ -1707,6 +1807,7 @@ static const struct hid_device_id aqc_table[] = { > { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_OCTO) }, > { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_QUADRO) }, > { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_HIGHFLOWNEXT) }, > + { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_LEAKSHIELD) }, > { 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) },