From: Aleksa Savic <savicaleksa83@gmail.com>
To: linux-hwmon@vger.kernel.org
Cc: Aleksa Savic <savicaleksa83@gmail.com>,
Jack Doan <me@jackdoan.com>, Jean Delvare <jdelvare@suse.com>,
Guenter Roeck <linux@roeck-us.net>,
Jonathan Corbet <corbet@lwn.net>,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] hwmon: (aquacomputer_d5next) Add support for Aquacomputer Poweradjust 3
Date: Tue, 31 Jan 2023 11:12:09 +0100 [thread overview]
Message-ID: <20230131101210.8095-1-savicaleksa83@gmail.com> (raw)
Extend aquacomputer_d5next driver to expose the temp sensor of the
Aquacomputer Poweradjust 3 fan controller, which communicates
through a proprietary USB HID protocol.
The Poweradjust 3 is not currently known to expose firmware version
and serial number, so don't create debugfs entries if their values
can't be retrieved.
Tested by a user on Github [1].
[1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/issues/57
Signed-off-by: Aleksa Savic <savicaleksa83@gmail.com>
---
Documentation/hwmon/aquacomputer_d5next.rst | 3 +
drivers/hwmon/aquacomputer_d5next.c | 88 +++++++++++++++++++--
2 files changed, 84 insertions(+), 7 deletions(-)
diff --git a/Documentation/hwmon/aquacomputer_d5next.rst b/Documentation/hwmon/aquacomputer_d5next.rst
index 3f7880fb8116..527bcd3edda9 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 Poweradjust 3 fan controller
Author: Aleksa Savic
@@ -53,6 +54,8 @@ 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 Poweradjust 3 controller exposes a single external temperature sensor.
+
Depending on the device, not all sysfs and debugfs entries will be available.
Writing to virtual temperature sensors is not currently supported.
diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c
index c1b885240ddf..2945b630b4a0 100644
--- a/drivers/hwmon/aquacomputer_d5next.c
+++ b/drivers/hwmon/aquacomputer_d5next.c
@@ -4,7 +4,8 @@
* Quadro, High Flow Next, Aquaero)
*
* Aquacomputer devices send HID reports (with ID 0x01) every second to report
- * sensor values.
+ * sensor values, except for devices that communicate through the
+ * legacy way (currently, Poweradjust 3).
*
* Copyright 2021 Aleksa Savic <savicaleksa83@gmail.com>
* Copyright 2022 Jack Doan <me@jackdoan.com>
@@ -28,8 +29,9 @@
#define USB_PRODUCT_ID_FARBWERK360 0xf010
#define USB_PRODUCT_ID_OCTO 0xf011
#define USB_PRODUCT_ID_HIGHFLOWNEXT 0xf012
+#define USB_PRODUCT_ID_POWERADJUST3 0xf0bd
-enum kinds { d5next, farbwerk, farbwerk360, octo, quadro, highflownext, aquaero };
+enum kinds { d5next, farbwerk, farbwerk360, octo, quadro, highflownext, aquaero, poweradjust3 };
static const char *const aqc_device_names[] = {
[d5next] = "d5next",
@@ -38,7 +40,8 @@ static const char *const aqc_device_names[] = {
[octo] = "octo",
[quadro] = "quadro",
[highflownext] = "highflownext",
- [aquaero] = "aquaero"
+ [aquaero] = "aquaero",
+ [poweradjust3] = "poweradjust3"
};
#define DRIVER_NAME "aquacomputer_d5next"
@@ -59,6 +62,9 @@ static u8 secondary_ctrl_report[] = {
0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0xC6
};
+/* Report IDs for legacy devices */
+#define POWERADJUST3_STATUS_REPORT_ID 0x03
+
/* Info, sensor sizes and offsets for most Aquacomputer devices */
#define AQC_SERIAL_START 0x3
#define AQC_FIRMWARE_VERSION 0xD
@@ -176,6 +182,13 @@ 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 Poweradjust 3 */
+#define POWERADJUST3_NUM_SENSORS 1
+#define POWERADJUST3_SENSOR_REPORT_SIZE 0x32
+
+/* Sensor report offsets for the Poweradjust 3 */
+#define POWERADJUST3_SENSOR_START 0x03
+
/* Labels for D5 Next */
static const char *const label_d5next_temp[] = {
"Coolant temp"
@@ -326,6 +339,11 @@ static const char *const label_highflownext_voltage[] = {
"+5V USB voltage"
};
+/* Labels for Poweradjust 3 */
+static const char *const label_poweradjust3_temp_sensors[] = {
+ "External sensor"
+};
+
struct aqc_fan_structure_offsets {
u8 voltage;
u8 curr;
@@ -357,6 +375,8 @@ struct aqc_data {
enum kinds kind;
const char *name;
+ int status_report_id; /* Used for legacy devices, report is stored in buffer */
+
int buffer_size;
u8 *buffer;
int checksum_start;
@@ -615,14 +635,49 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
return 0;
}
+/* Read device sensors by manually requesting the sensor report (legacy way) */
+static int aqc_legacy_read(struct aqc_data *priv)
+{
+ int ret, i, sensor_value;
+
+ mutex_lock(&priv->mutex);
+
+ memset(priv->buffer, 0x00, priv->buffer_size);
+ ret = hid_hw_raw_request(priv->hdev, priv->status_report_id, priv->buffer,
+ priv->buffer_size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+ if (ret < 0)
+ goto unlock_and_return;
+
+ /* Temperature sensor readings */
+ 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;
+ }
+
+ priv->updated = jiffies;
+
+unlock_and_return:
+ mutex_unlock(&priv->mutex);
+ return ret;
+}
+
static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
{
int ret;
struct aqc_data *priv = dev_get_drvdata(dev);
- if (time_after(jiffies, priv->updated + STATUS_UPDATE_INTERVAL))
- return -ENODATA;
+ if (time_after(jiffies, priv->updated + STATUS_UPDATE_INTERVAL)) {
+ if (priv->status_report_id != 0) {
+ /* Legacy devices require manual reads */
+ ret = aqc_legacy_read(priv);
+ if (ret < 0)
+ return -ENODATA;
+ } else {
+ return -ENODATA;
+ }
+ }
switch (type) {
case hwmon_temp:
@@ -1014,9 +1069,13 @@ static void aqc_debugfs_init(struct aqc_data *priv)
dev_name(&priv->hdev->dev));
priv->debugfs = debugfs_create_dir(name, NULL);
- debugfs_create_file("serial_number", 0444, priv->debugfs, priv, &serial_number_fops);
- debugfs_create_file("firmware_version", 0444, priv->debugfs, priv, &firmware_version_fops);
+ if (priv->serial_number_start_offset != 0)
+ debugfs_create_file("serial_number", 0444, priv->debugfs, priv,
+ &serial_number_fops);
+ if (priv->firmware_version_offset != 0)
+ debugfs_create_file("firmware_version", 0444, priv->debugfs, priv,
+ &firmware_version_fops);
if (priv->power_cycle_count_offset != 0)
debugfs_create_file("power_cycles", 0444, priv->debugfs, priv, &power_cycles_fops);
}
@@ -1214,6 +1273,17 @@ 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_POWERADJUST3:
+ priv->kind = poweradjust3;
+
+ priv->num_fans = 0;
+
+ priv->num_temp_sensors = POWERADJUST3_NUM_SENSORS;
+ priv->temp_sensor_start_offset = POWERADJUST3_SENSOR_START;
+ priv->buffer_size = POWERADJUST3_SENSOR_REPORT_SIZE;
+
+ priv->temp_label = label_poweradjust3_temp_sensors;
+ break;
default:
break;
}
@@ -1225,6 +1295,9 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->fan_structure = &aqc_aquaero_fan_structure;
break;
+ case poweradjust3:
+ priv->status_report_id = POWERADJUST3_STATUS_REPORT_ID;
+ break;
default:
priv->serial_number_start_offset = AQC_SERIAL_START;
priv->firmware_version_offset = AQC_FIRMWARE_VERSION;
@@ -1287,6 +1360,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_POWERADJUST3) },
{ }
};
--
2.39.1
next reply other threads:[~2023-01-31 10:13 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-01-31 10:12 Aleksa Savic [this message]
2023-01-31 15:07 ` [PATCH] hwmon: (aquacomputer_d5next) Add support for Aquacomputer Poweradjust 3 Guenter Roeck
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230131101210.8095-1-savicaleksa83@gmail.com \
--to=savicaleksa83@gmail.com \
--cc=corbet@lwn.net \
--cc=jdelvare@suse.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-hwmon@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=me@jackdoan.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.