2022-12-18 12:46:48

by Leonard Anderweit

[permalink] [raw]
Subject: [PATCH 0/6] hwmon: (aquacomputer_d5next) Add Aquacomputer Aquaero sensors

Add support for the Aquacomputer Aquaero 5/6 fan controllers. These fan
controllers support 4 fans, 8 physical temperature sensors, 8 virtual
temperature sensors and 2 flow sensors.

The first 5 patches prepare support for Aquacomputer Aquaero without
changing the functionality. Patch 6 adds support for Aquaero sensors.
Fan control is planned for a future patch.

Leonard Anderweit (6):
hwmon: (aquacomputer_d5next) Rename AQC_TEMP_SENSOR_SIZE to
AQC_SENSOR_SIZE
hwmon: (aquacomputer_d5next) Restructure flow sensor reading
hwmon: (aquacomputer_d5next) Add structure for fan layout
hwmon: (aquacomputer_d5next) Device dependent serial number and
firmware offsets
hwmon: (aquacomputer_d5next) Make fan sensor offsets u16
hwmon: (aquacomputer_d5next) Support sensors for Aquacomputer Aquaero

Documentation/hwmon/aquacomputer_d5next.rst | 5 +
drivers/hwmon/aquacomputer_d5next.c | 193 ++++++++++++++++----
2 files changed, 165 insertions(+), 33 deletions(-)

--
2.38.1


2022-12-18 12:50:33

by Leonard Anderweit

[permalink] [raw]
Subject: [PATCH 3/6] hwmon: (aquacomputer_d5next) Add structure for fan layout

Introduce structure for per device fan sensor offsets. This allows
reading fan sensors in aqc_raw_event() from devices which use a
different sensor layout in their status HID report. Currently only one
version is implemented as all supported devices use the same structure.

Signed-off-by: Leonard Anderweit <[email protected]>
---
drivers/hwmon/aquacomputer_d5next.c | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c
index 388bf1e33e0d..1ea866fcd3ec 100644
--- a/drivers/hwmon/aquacomputer_d5next.c
+++ b/drivers/hwmon/aquacomputer_d5next.c
@@ -282,6 +282,21 @@ static const char *const label_highflownext_voltage[] = {
"+5V USB voltage"
};

+struct aqc_fan_structure_offsets {
+ u8 voltage;
+ u8 curr;
+ u8 power;
+ u8 speed;
+};
+
+/* Fan structure offsets for all devices except Aquaero */
+static struct aqc_fan_structure_offsets aqc_general_fan_structure = {
+ .voltage = AQC_FAN_VOLTAGE_OFFSET,
+ .curr = AQC_FAN_CURRENT_OFFSET,
+ .power = AQC_FAN_POWER_OFFSET,
+ .speed = AQC_FAN_SPEED_OFFSET
+};
+
struct aqc_data {
struct hid_device *hdev;
struct device *hwmon_dev;
@@ -308,6 +323,7 @@ struct aqc_data {
int num_flow_sensors;
u8 flow_sensors_start_offset;
u8 flow_pulses_ctrl_offset;
+ struct aqc_fan_structure_offsets *fan_structure;

/* General info, same across all devices */
u32 serial_number[2];
@@ -822,15 +838,17 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
/* Fan speed and related readings */
for (i = 0; i < priv->num_fans; i++) {
priv->speed_input[i] =
- get_unaligned_be16(data + priv->fan_sensor_offsets[i] + AQC_FAN_SPEED_OFFSET);
+ get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
+ priv->fan_structure->speed);
priv->power_input[i] =
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
- AQC_FAN_POWER_OFFSET) * 10000;
+ priv->fan_structure->power) * 10000;
priv->voltage_input[i] =
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
- AQC_FAN_VOLTAGE_OFFSET) * 10;
+ priv->fan_structure->voltage) * 10;
priv->current_input[i] =
- get_unaligned_be16(data + priv->fan_sensor_offsets[i] + AQC_FAN_CURRENT_OFFSET);
+ get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
+ priv->fan_structure->curr);
}

/* Flow sensor readings */
@@ -1078,6 +1096,8 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
break;
}

+ priv->fan_structure = &aqc_general_fan_structure;
+
if (priv->buffer_size != 0) {
priv->checksum_start = 0x01;
priv->checksum_length = priv->buffer_size - 3;
--
2.38.1

2022-12-18 13:04:50

by Leonard Anderweit

[permalink] [raw]
Subject: [PATCH 2/6] hwmon: (aquacomputer_d5next) Restructure flow sensor reading

Read flow sensors the same way for all devices instead of in special
cases. Implemented by Aleksa Savic [1].

[1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/commit/1c10912c5fdc8287d88378bcf1ef14d596f29462

Originally-from: Aleksa Savic <[email protected]>
Signed-off-by: Leonard Anderweit <[email protected]>
---
drivers/hwmon/aquacomputer_d5next.c | 26 ++++++++++++++++++--------
1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c
index 8fd9f7fd7ec4..388bf1e33e0d 100644
--- a/drivers/hwmon/aquacomputer_d5next.c
+++ b/drivers/hwmon/aquacomputer_d5next.c
@@ -125,6 +125,7 @@ static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0
#define QUADRO_NUM_FANS 4
#define QUADRO_NUM_SENSORS 4
#define QUADRO_NUM_VIRTUAL_SENSORS 16
+#define QUADRO_NUM_FLOW_SENSORS 1
#define QUADRO_CTRL_REPORT_SIZE 0x3c1

/* Sensor report offsets for the Quadro */
@@ -141,6 +142,7 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed

/* Specs of High Flow Next flow sensor */
#define HIGHFLOWNEXT_NUM_SENSORS 2
+#define HIGHFLOWNEXT_NUM_FLOW_SENSORS 1

/* Sensor report offsets for the High Flow Next */
#define HIGHFLOWNEXT_SENSOR_START 85
@@ -303,7 +305,8 @@ struct aqc_data {
int virtual_temp_sensor_start_offset;
u16 temp_ctrl_offset;
u16 power_cycle_count_offset;
- u8 flow_sensor_offset;
+ int num_flow_sensors;
+ u8 flow_sensors_start_offset;
u8 flow_pulses_ctrl_offset;

/* General info, same across all devices */
@@ -475,8 +478,8 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
return 0444;
break;
case quadro:
- /* Special case to support flow sensor */
- if (channel < priv->num_fans + 1)
+ /* Special case to support flow sensors */
+ if (channel < priv->num_fans + priv->num_flow_sensors)
return 0444;
break;
default:
@@ -830,6 +833,13 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
get_unaligned_be16(data + priv->fan_sensor_offsets[i] + AQC_FAN_CURRENT_OFFSET);
}

+ /* Flow sensor readings */
+ for (j = 0; j < priv->num_flow_sensors; j++) {
+ priv->speed_input[i] = get_unaligned_be16(data + priv->flow_sensors_start_offset +
+ j * AQC_SENSOR_SIZE);
+ i++;
+ }
+
if (priv->power_cycle_count_offset != 0)
priv->power_cycles = get_unaligned_be32(data + priv->power_cycle_count_offset);

@@ -839,9 +849,6 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
priv->voltage_input[2] = get_unaligned_be16(data + D5NEXT_5V_VOLTAGE) * 10;
priv->voltage_input[3] = get_unaligned_be16(data + D5NEXT_12V_VOLTAGE) * 10;
break;
- case quadro:
- priv->speed_input[4] = get_unaligned_be16(data + priv->flow_sensor_offset);
- break;
case highflownext:
/* If external temp sensor is not connected, its power reading is also N/A */
if (priv->temp_input[1] == -ENODATA)
@@ -854,7 +861,6 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
priv->voltage_input[1] =
get_unaligned_be16(data + HIGHFLOWNEXT_5V_VOLTAGE_USB) * 10;

- priv->speed_input[0] = get_unaligned_be16(data + HIGHFLOWNEXT_FLOW);
priv->speed_input[1] = get_unaligned_be16(data + HIGHFLOWNEXT_WATER_QUALITY);
priv->speed_input[2] = get_unaligned_be16(data + HIGHFLOWNEXT_CONDUCTIVITY);
break;
@@ -1034,11 +1040,13 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->temp_sensor_start_offset = QUADRO_SENSOR_START;
priv->num_virtual_temp_sensors = QUADRO_NUM_VIRTUAL_SENSORS;
priv->virtual_temp_sensor_start_offset = QUADRO_VIRTUAL_SENSORS_START;
+ priv->num_flow_sensors = QUADRO_NUM_FLOW_SENSORS;
+ priv->flow_sensors_start_offset = QUADRO_FLOW_SENSOR_OFFSET;
+
priv->temp_ctrl_offset = QUADRO_TEMP_CTRL_OFFSET;

priv->buffer_size = QUADRO_CTRL_REPORT_SIZE;

- priv->flow_sensor_offset = QUADRO_FLOW_SENSOR_OFFSET;
priv->flow_pulses_ctrl_offset = QUADRO_FLOW_PULSES_CTRL_OFFSET;
priv->power_cycle_count_offset = QUADRO_POWER_CYCLES;

@@ -1056,6 +1064,8 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)

priv->num_temp_sensors = HIGHFLOWNEXT_NUM_SENSORS;
priv->temp_sensor_start_offset = HIGHFLOWNEXT_SENSOR_START;
+ priv->num_flow_sensors = HIGHFLOWNEXT_NUM_FLOW_SENSORS;
+ priv->flow_sensors_start_offset = HIGHFLOWNEXT_FLOW;

priv->power_cycle_count_offset = QUADRO_POWER_CYCLES;

--
2.38.1

2022-12-18 13:05:12

by Leonard Anderweit

[permalink] [raw]
Subject: [PATCH 5/6] hwmon: (aquacomputer_d5next) Make fan sensor offsets u16

Make fan sensor offsets u16 as u8 is insufficient for upcoming devices.

Signed-off-by: Leonard Anderweit <[email protected]>
---
drivers/hwmon/aquacomputer_d5next.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c
index cc53231067f4..d28d7079917a 100644
--- a/drivers/hwmon/aquacomputer_d5next.c
+++ b/drivers/hwmon/aquacomputer_d5next.c
@@ -83,7 +83,7 @@ static u8 secondary_ctrl_report[] = {
#define D5NEXT_5V_VOLTAGE 0x39
#define D5NEXT_12V_VOLTAGE 0x37
#define D5NEXT_VIRTUAL_SENSORS_START 0x3f
-static u8 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET };
+static u16 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET };

/* Control report offsets for the D5 Next pump */
#define D5NEXT_TEMP_CTRL_OFFSET 0x2D /* Temperature sensor offsets location */
@@ -115,7 +115,7 @@ static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; /* Pump and fan speed (fr
#define OCTO_POWER_CYCLES 0x18
#define OCTO_SENSOR_START 0x3D
#define OCTO_VIRTUAL_SENSORS_START 0x45
-static u8 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 };
+static u16 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 };

/* Control report offsets for the Octo */
#define OCTO_TEMP_CTRL_OFFSET 0xA
@@ -134,7 +134,7 @@ static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0
#define QUADRO_SENSOR_START 0x34
#define QUADRO_VIRTUAL_SENSORS_START 0x3c
#define QUADRO_FLOW_SENSOR_OFFSET 0x6e
-static u8 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 };
+static u16 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 };

/* Control report offsets for the Quadro */
#define QUADRO_TEMP_CTRL_OFFSET 0xA
@@ -313,7 +313,7 @@ struct aqc_data {
int checksum_offset;

int num_fans;
- u8 *fan_sensor_offsets;
+ u16 *fan_sensor_offsets;
u16 *fan_ctrl_offsets;
int num_temp_sensors;
int temp_sensor_start_offset;
--
2.38.1

2022-12-18 13:10:58

by Leonard Anderweit

[permalink] [raw]
Subject: [PATCH 4/6] hwmon: (aquacomputer_d5next) Device dependent serial number and firmware offsets

Add device dependent serial number and firmware offsets to support
devices with different offsets. All currently supported devices share
the same offsets. Implemented by Aleksa Savic [1].

[1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/pull/31/commits/14c3acf78b17397edb5dd356e6f5943a9996a1f9

Originally-from: Aleksa Savic <[email protected]>
Signed-off-by: Leonard Anderweit <[email protected]>
---
drivers/hwmon/aquacomputer_d5next.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c
index 1ea866fcd3ec..cc53231067f4 100644
--- a/drivers/hwmon/aquacomputer_d5next.c
+++ b/drivers/hwmon/aquacomputer_d5next.c
@@ -43,9 +43,7 @@ static const char *const aqc_device_names[] = {

#define STATUS_REPORT_ID 0x01
#define STATUS_UPDATE_INTERVAL (2 * HZ) /* In seconds */
-#define SERIAL_FIRST_PART 3
-#define SERIAL_SECOND_PART 5
-#define FIRMWARE_VERSION 13
+#define SERIAL_PART_OFFSET 2

#define CTRL_REPORT_ID 0x03

@@ -59,7 +57,10 @@ static u8 secondary_ctrl_report[] = {
0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0xC6
};

-/* Sensor sizes and offsets for all Aquacomputer devices */
+/* Info, sensor sizes and offsets for all Aquacomputer devices */
+#define AQC_SERIAL_START 0x3
+#define AQC_FIRMWARE_VERSION 0xD
+
#define AQC_SENSOR_SIZE 0x02
#define AQC_TEMP_SENSOR_DISCONNECTED 0x7FFF
#define AQC_FAN_PERCENT_OFFSET 0x00
@@ -326,7 +327,9 @@ struct aqc_data {
struct aqc_fan_structure_offsets *fan_structure;

/* General info, same across all devices */
+ u8 serial_number_start_offset;
u32 serial_number[2];
+ u8 firmware_version_offset;
u16 firmware_version;

/* How many times the device was powered on, if available */
@@ -808,9 +811,10 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
priv = hid_get_drvdata(hdev);

/* Info provided with every report */
- priv->serial_number[0] = get_unaligned_be16(data + SERIAL_FIRST_PART);
- priv->serial_number[1] = get_unaligned_be16(data + SERIAL_SECOND_PART);
- priv->firmware_version = get_unaligned_be16(data + FIRMWARE_VERSION);
+ priv->serial_number[0] = get_unaligned_be16(data + priv->serial_number_start_offset);
+ priv->serial_number[1] = get_unaligned_be16(data + priv->serial_number_start_offset +
+ SERIAL_PART_OFFSET);
+ priv->firmware_version = get_unaligned_be16(data + priv->firmware_version_offset);

/* Physical temperature sensor readings */
for (i = 0; i < priv->num_temp_sensors; i++) {
@@ -1096,6 +1100,9 @@ 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;
+
priv->fan_structure = &aqc_general_fan_structure;

if (priv->buffer_size != 0) {
--
2.38.1