[PATCH v3 1/3] hwmon: (asus_rog_ryujin) Add per-device configuration
From: Arie Miller
Date: Wed Aug 12 2026 - 06:42:50 EST
Move model-specific report offsets and capabilities into a device
information structure. This prepares the driver for coolers which use
a different report layout or do not include the external fan
controller, while preserving the existing Ryujin II 360 behavior.
Handles an issue reported by Sashiko where an id could
be missing driver_data.
Link: https://lore.kernel.org/r/5a817284-a9f4-48b2-9f0f-802c5dc6963c@xxxxxxxxxxxx
Assisted-by: Codex:gpt-5.6-sol sparse
Signed-off-by: Arie Miller <renari@xxxxxxxxxx>
---
drivers/hwmon/asus_rog_ryujin.c | 75 +++++++++++++++++++++++----------
1 file changed, 52 insertions(+), 23 deletions(-)
diff --git a/drivers/hwmon/asus_rog_ryujin.c b/drivers/hwmon/asus_rog_ryujin.c
index 10a1f5aca988..80563ce38519 100644
--- a/drivers/hwmon/asus_rog_ryujin.c
+++ b/drivers/hwmon/asus_rog_ryujin.c
@@ -18,15 +18,25 @@
#define USB_VENDOR_ID_ASUS_ROG 0x0b05
#define USB_PRODUCT_ID_RYUJIN_AIO 0x1988 /* ASUS ROG RYUJIN II 360 */
+struct rog_ryujin_device_info {
+ u8 temp_offset;
+ u8 pump_speed_offset;
+ u8 fan_speed_offset;
+ u8 duty_channel;
+ bool has_controller;
+};
+
+static const struct rog_ryujin_device_info rog_ryujin_ii_360_info = {
+ .temp_offset = 3,
+ .pump_speed_offset = 5,
+ .fan_speed_offset = 7,
+ .duty_channel = 0,
+ .has_controller = true,
+};
+
#define STATUS_VALIDITY 1500 /* ms */
#define MAX_REPORT_LENGTH 65
-/* Cooler status report offsets */
-#define RYUJIN_TEMP_SENSOR_1 3
-#define RYUJIN_TEMP_SENSOR_2 4
-#define RYUJIN_PUMP_SPEED 5
-#define RYUJIN_INTERNAL_FAN_SPEED 7
-
/* Cooler duty report offsets */
#define RYUJIN_PUMP_DUTY 4
#define RYUJIN_INTERNAL_FAN_DUTY 5
@@ -81,6 +91,7 @@ static const char *const rog_ryujin_speed_label[] = {
struct rog_ryujin_data {
struct hid_device *hdev;
struct device *hwmon_dev;
+ const struct rog_ryujin_device_info *info;
/* For reinitializing the completions below */
spinlock_t status_report_request_lock;
struct completion cooler_status_received;
@@ -112,6 +123,8 @@ static int rog_ryujin_pwm_to_percent(long val)
static umode_t rog_ryujin_is_visible(const void *data,
enum hwmon_sensor_types type, u32 attr, int channel)
{
+ const struct rog_ryujin_data *priv = data;
+
switch (type) {
case hwmon_temp:
switch (attr) {
@@ -123,6 +136,8 @@ static umode_t rog_ryujin_is_visible(const void *data,
}
break;
case hwmon_fan:
+ if (channel >= 2 && !priv->info->has_controller)
+ return 0;
switch (attr) {
case hwmon_fan_label:
case hwmon_fan_input:
@@ -132,6 +147,8 @@ static umode_t rog_ryujin_is_visible(const void *data,
}
break;
case hwmon_pwm:
+ if (channel >= 2 && !priv->info->has_controller)
+ return 0;
switch (attr) {
case hwmon_pwm_input:
return 0644;
@@ -198,12 +215,14 @@ static int rog_ryujin_get_status(struct rog_ryujin_data *priv)
if (ret < 0)
return ret;
- /* Retrieve controller status (speeds) */
- ret =
- rog_ryujin_execute_cmd(priv, get_controller_speed_cmd, GET_CMD_LENGTH,
- &priv->controller_status_received);
- if (ret < 0)
- return ret;
+ if (priv->info->has_controller) {
+ /* Retrieve controller status (speeds) */
+ ret = rog_ryujin_execute_cmd(priv, get_controller_speed_cmd,
+ GET_CMD_LENGTH,
+ &priv->controller_status_received);
+ if (ret < 0)
+ return ret;
+ }
/* Retrieve cooler duty */
ret =
@@ -212,12 +231,14 @@ static int rog_ryujin_get_status(struct rog_ryujin_data *priv)
if (ret < 0)
return ret;
- /* Retrieve controller duty */
- ret =
- rog_ryujin_execute_cmd(priv, get_controller_duty_cmd, GET_CMD_LENGTH,
- &priv->controller_duty_received);
- if (ret < 0)
- return ret;
+ if (priv->info->has_controller) {
+ /* Retrieve controller duty */
+ ret = rog_ryujin_execute_cmd(priv, get_controller_duty_cmd,
+ GET_CMD_LENGTH,
+ &priv->controller_duty_received);
+ if (ret < 0)
+ return ret;
+ }
priv->updated = jiffies;
return 0;
@@ -289,6 +310,7 @@ static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel
return ret;
memcpy(set_cmd, set_cooler_duty_cmd, SET_CMD_LENGTH);
+ set_cmd[2] = priv->info->duty_channel;
/* Cooler duties are set as 0-100% */
val = rog_ryujin_pwm_to_percent(val);
@@ -394,10 +416,12 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
if (data[1] == RYUJIN_GET_COOLER_STATUS_CMD_RESPONSE) {
/* Received coolant temp and speeds of pump and internal fan */
- priv->temp_input[0] =
- data[RYUJIN_TEMP_SENSOR_1] * 1000 + data[RYUJIN_TEMP_SENSOR_2] * 100;
- priv->speed_input[0] = get_unaligned_le16(data + RYUJIN_PUMP_SPEED);
- priv->speed_input[1] = get_unaligned_le16(data + RYUJIN_INTERNAL_FAN_SPEED);
+ priv->temp_input[0] = data[priv->info->temp_offset] * 1000 +
+ data[priv->info->temp_offset + 1] * 100;
+ priv->speed_input[0] =
+ get_unaligned_le16(data + priv->info->pump_speed_offset);
+ priv->speed_input[1] =
+ get_unaligned_le16(data + priv->info->fan_speed_offset);
if (!completion_done(&priv->cooler_status_received))
complete_all(&priv->cooler_status_received);
@@ -471,11 +495,15 @@ static int rog_ryujin_probe(struct hid_device *hdev, const struct hid_device_id
struct rog_ryujin_data *priv;
int ret;
+ if (!id->driver_data)
+ return -EINVAL;
+
priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->hdev = hdev;
+ priv->info = (const struct rog_ryujin_device_info *)id->driver_data;
hid_set_drvdata(hdev, priv);
/*
@@ -546,7 +574,8 @@ static void rog_ryujin_remove(struct hid_device *hdev)
}
static const struct hid_device_id rog_ryujin_table[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUS_ROG, USB_PRODUCT_ID_RYUJIN_AIO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUS_ROG, USB_PRODUCT_ID_RYUJIN_AIO),
+ .driver_data = (kernel_ulong_t)&rog_ryujin_ii_360_info },
{ }
};
--
2.55.0