mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/3] hwmon: (asus-ec-sensors) more MAXIMUS IX EXTREME sensors
@ 2026-10-26  8:57 Remy Demangeot via B4 Relay
  2026-10-26  8:57 ` [PATCH 1/3] hwmon: (asus-ec-sensors) add EXT_Sensor temperatures for MAXIMUS IX EXTREME Remy Demangeot via B4 Relay
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Remy Demangeot via B4 Relay @ 2026-10-26  8:57 UTC (permalink / raw)
  To: Eugene Shalygin, Guenter Roeck; +Cc: linux-hwmon, linux-kernel, Remy Demangeot

This series adds the remaining sensors of the MAXIMUS IX EXTREME EC
that HWiNFO reads. It applies on top of "hwmon: (asus-ec-sensors) add
MAXIMUS IX EXTREME", which Guenter applied:
https://lore.kernel.org/r/20261015-b4-m9e-extreme-v1-1-621da921e320@demangeot.net

Guenter asked why I assumed these might not be acceptable. No
particular reason: two of them need access patterns the driver does
not have yet (a selector register written before the read, and a
second EC on its own I/O ports), so I preferred to ask before touching
the read path.

 1/3: EXT_Sensor1-3, plain reads at bank 0, 0x60-0x62.
 2/3: EXT_FAN1-3 speeds, read after writing the fan number to the
      selector register 0x43, which is restored afterwards.
 3/3: the four water temperatures, on a second EC at I/O ports
      0x68/0x6c, bank 1.

Notes:
 - After 3/3, enum ec_sensors has 32 entries, which fills the
   unsigned long sensor mask on 32-bit builds. Any further sensor
   will need a wider mask (u64 and BIT_ULL()). I can send that as a
   preparatory patch if you prefer.
 - asus_ec2_wait() polls with udelay(10). checkpatch suggests
   usleep_range(), but the EC normally answers within a few
   microseconds, so I kept udelay(). Happy to change it.

A related question, independent of this series. The EC also holds the
fan curves of the extension card fans: after selecting a fan through
0x43, registers 0x4a-0x4f hold a 3-point curve (temperature in degrees
Celsius, duty 0-255) that the BIOS writes at boot. Writing these
registers changes the fan speed immediately, and writing the same duty
at the three points gives a fixed speed. My out-of-tree driver uses
this to expose pwmN and pwmN_enable (1: fixed duty through a flat
curve, 2: BIOS curve, saved at probe and restored at unload and
shutdown, and re-applied after resume), so that these fans can be
driven from userspace like the Super I/O ones.

Would write support like this be acceptable in asus-ec-sensors, or is
it better kept out of tree or in a separate driver? I understand the
driver is read-only by design, so "no" is a fine answer.

Tested on the MAXIMUS IX EXTREME (BIOS 1501): readings match HWiNFO
8.54 and the out-of-tree driver on the same machine.

---
Remy Demangeot (3):
      hwmon: (asus-ec-sensors) add EXT_Sensor temperatures for MAXIMUS IX EXTREME
      hwmon: (asus-ec-sensors) add fan extension card fans for MAXIMUS IX EXTREME
      hwmon: (asus-ec-sensors) add water temperatures for MAXIMUS IX EXTREME

 drivers/hwmon/asus-ec-sensors.c | 219 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 205 insertions(+), 14 deletions(-)
---
base-commit: e1b3c2630d5b8bc755fe4ba86d20d08c734eb504
change-id: 20261026-b4-m9e-ext-sensors-390e83e8879d

Best regards,
-- 
Remy Demangeot <remy@demangeot.net>



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/3] hwmon: (asus-ec-sensors) add EXT_Sensor temperatures for MAXIMUS IX EXTREME
  2026-10-26  8:57 [PATCH 0/3] hwmon: (asus-ec-sensors) more MAXIMUS IX EXTREME sensors Remy Demangeot via B4 Relay
@ 2026-10-26  8:57 ` Remy Demangeot via B4 Relay
  2026-10-26 19:33   ` Guenter Roeck
  2026-10-26  8:57 ` [PATCH 2/3] hwmon: (asus-ec-sensors) add fan extension card fans " Remy Demangeot via B4 Relay
  2026-10-26  8:57 ` [PATCH 3/3] hwmon: (asus-ec-sensors) add water temperatures " Remy Demangeot via B4 Relay
  2 siblings, 1 reply; 8+ messages in thread
From: Remy Demangeot via B4 Relay @ 2026-10-26  8:57 UTC (permalink / raw)
  To: Eugene Shalygin, Guenter Roeck; +Cc: linux-hwmon, linux-kernel, Remy Demangeot

From: Remy Demangeot <remy@demangeot.net>

The MAXIMUS IX EXTREME supports three additional thermistor inputs,
EXT_Sensor1-3, located on the optional ASUS fan extension card. The
EC reports them at bank 0, registers 0x60-0x62, as signed degrees
Celsius, with -60 when no probe is connected (already handled as a
blank value).

Add them to the Intel 200-series family as Extra_1-Extra_3 and enable
them for the board.

Readings match HWiNFO 8.54 on the same machine, and moving a probe
from one header to another moves the reading accordingly.

Signed-off-by: Remy Demangeot <remy@demangeot.net>
---
 drivers/hwmon/asus-ec-sensors.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c
index 3c97ae09cc19acad54696bff9e65d6bc4f3ce835..8966053b58173592a19afbab42ccbe8e6e6d7042 100644
--- a/drivers/hwmon/asus-ec-sensors.c
+++ b/drivers/hwmon/asus-ec-sensors.c
@@ -359,6 +359,12 @@ static const struct ec_sensor_info sensors_family_intel_200[] = {
 	[ec_sensor_temp_t_sensor] =
 		EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d),
 	[ec_sensor_temp_vrm] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e),
+	[ec_sensor_temp_sensor_extra_1] =
+		EC_SENSOR("Extra_1", hwmon_temp, 1, 0x00, 0x60),
+	[ec_sensor_temp_sensor_extra_2] =
+		EC_SENSOR("Extra_2", hwmon_temp, 1, 0x00, 0x61),
+	[ec_sensor_temp_sensor_extra_3] =
+		EC_SENSOR("Extra_3", hwmon_temp, 1, 0x00, 0x62),
 	[ec_sensor_fan_cpu_opt] =
 		EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xbc),
 };
@@ -523,7 +529,8 @@ static const struct ec_board_info board_info_maximus_vi_hero = {
 
 static const struct ec_board_info board_info_maximus_ix_extreme = {
 	.sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_T_SENSOR |
-		SENSOR_TEMP_VRM,
+		SENSOR_TEMP_VRM | SENSOR_TEMP_SENSOR_EXTRA_1 |
+		SENSOR_TEMP_SENSOR_EXTRA_2 | SENSOR_TEMP_SENSOR_EXTRA_3,
 	.mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_LPCB_SIO1_MUT0,
 	.family = family_intel_200_series,
 };

-- 
2.47.3



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 2/3] hwmon: (asus-ec-sensors) add fan extension card fans for MAXIMUS IX EXTREME
  2026-10-26  8:57 [PATCH 0/3] hwmon: (asus-ec-sensors) more MAXIMUS IX EXTREME sensors Remy Demangeot via B4 Relay
  2026-10-26  8:57 ` [PATCH 1/3] hwmon: (asus-ec-sensors) add EXT_Sensor temperatures for MAXIMUS IX EXTREME Remy Demangeot via B4 Relay
@ 2026-10-26  8:57 ` Remy Demangeot via B4 Relay
  2026-10-26 19:33   ` Guenter Roeck
  2026-10-26  8:57 ` [PATCH 3/3] hwmon: (asus-ec-sensors) add water temperatures " Remy Demangeot via B4 Relay
  2 siblings, 1 reply; 8+ messages in thread
From: Remy Demangeot via B4 Relay @ 2026-10-26  8:57 UTC (permalink / raw)
  To: Eugene Shalygin, Guenter Roeck; +Cc: linux-hwmon, linux-kernel, Remy Demangeot

From: Remy Demangeot <remy@demangeot.net>

On the MAXIMUS IX EXTREME, the speeds of the three fans on the
optional ASUS fan extension card (EXT_FAN1-3) are not at fixed EC
addresses. Bank 0 register 0x43 selects which fan a group of registers
describes: after writing 0x0a, 0x0b or 0x0c to it, registers 0x57:0x58
hold the RPM of EXT_FAN1, EXT_FAN2 or EXT_FAN3 (big-endian).

Allow a sensor definition to carry a selector value, using the unused
byte of sensor_address. When reading such a register, the driver
writes the selector first and restores the previous selector value
once the bank has been read. Sensors without a selector are read as
before.

Readings match HWiNFO 8.54 on the same machine, and follow the fan
speed when the fan duty is changed.

Signed-off-by: Remy Demangeot <remy@demangeot.net>
---
 drivers/hwmon/asus-ec-sensors.c | 75 ++++++++++++++++++++++++++++++++++++-----
 1 file changed, 66 insertions(+), 9 deletions(-)

diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c
index 8966053b58173592a19afbab42ccbe8e6e6d7042..11dd7f587530d640b6ccc9b7952dc9da47e11c19 100644
--- a/drivers/hwmon/asus-ec-sensors.c
+++ b/drivers/hwmon/asus-ec-sensors.c
@@ -40,6 +40,11 @@ static char *mutex_path_override;
 
 /* Writing to this EC register switches EC bank */
 #define ASUS_EC_BANK_REGISTER	0xff
+/*
+ * On some boards, writing to this bank 0 register selects which device a
+ * group of registers reports (e.g. one of the fans of the fan extension card).
+ */
+#define ASUS_EC_SELECT_REGISTER	0x43
 #define SENSOR_LABEL_LEN	16
 
 /*
@@ -73,7 +78,8 @@ typedef union {
 		u8 index;
 		u8 bank;
 		u8 size;
-		u8 dummy;
+		/* value to write to ASUS_EC_SELECT_REGISTER first, 0 if none */
+		u8 select;
 	} components;
 } sensor_address;
 
@@ -81,6 +87,11 @@ typedef union {
 		.value = (size << 16) + (bank << 8) + index                    \
 	}
 
+#define MAKE_SENSOR_ADDRESS_SELECT(size, bank, index, select) {               \
+		.value = ((u32)(select) << 24) + ((size) << 16) +            \
+			 ((bank) << 8) + (index)                               \
+	}
+
 static u32 hwmon_attributes[hwmon_max] = {
 	[hwmon_chip] = HWMON_C_REGISTER_TZ,
 	[hwmon_temp] = HWMON_T_INPUT | HWMON_T_LABEL,
@@ -100,6 +111,12 @@ struct ec_sensor_info {
 		.addr = MAKE_SENSOR_ADDRESS(size, bank, index),                \
 	}
 
+/* A sensor read after writing @select to ASUS_EC_SELECT_REGISTER */
+#define EC_SENSOR_SELECT(sensor_label, sensor_type, size, bank, index, select) {\
+		.label = sensor_label, .type = sensor_type,                    \
+		.addr = MAKE_SENSOR_ADDRESS_SELECT(size, bank, index, select), \
+	}
+
 enum ec_sensors {
 	/* chipset temperature [℃] */
 	ec_sensor_temp_chipset,
@@ -155,6 +172,10 @@ enum ec_sensors {
 	ec_sensor_temp_sensor_extra_2,
 	/* "Extra_3" temperature sensor reading [℃] */
 	ec_sensor_temp_sensor_extra_3,
+	/* fan extension card fans [RPM] */
+	ec_sensor_fan_ext_1,
+	ec_sensor_fan_ext_2,
+	ec_sensor_fan_ext_3,
 };
 
 #define SENSOR_TEMP_CHIPSET BIT(ec_sensor_temp_chipset)
@@ -184,6 +205,9 @@ enum ec_sensors {
 #define SENSOR_TEMP_SENSOR_EXTRA_1 BIT(ec_sensor_temp_sensor_extra_1)
 #define SENSOR_TEMP_SENSOR_EXTRA_2 BIT(ec_sensor_temp_sensor_extra_2)
 #define SENSOR_TEMP_SENSOR_EXTRA_3 BIT(ec_sensor_temp_sensor_extra_3)
+#define SENSOR_FAN_EXT_1 BIT(ec_sensor_fan_ext_1)
+#define SENSOR_FAN_EXT_2 BIT(ec_sensor_fan_ext_2)
+#define SENSOR_FAN_EXT_3 BIT(ec_sensor_fan_ext_3)
 
 /*
  * The values for temperature sensor readings without physical sensors connected.
@@ -367,6 +391,12 @@ static const struct ec_sensor_info sensors_family_intel_200[] = {
 		EC_SENSOR("Extra_3", hwmon_temp, 1, 0x00, 0x62),
 	[ec_sensor_fan_cpu_opt] =
 		EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xbc),
+	[ec_sensor_fan_ext_1] =
+		EC_SENSOR_SELECT("EXT_FAN1", hwmon_fan, 2, 0x00, 0x57, 0x0a),
+	[ec_sensor_fan_ext_2] =
+		EC_SENSOR_SELECT("EXT_FAN2", hwmon_fan, 2, 0x00, 0x57, 0x0b),
+	[ec_sensor_fan_ext_3] =
+		EC_SENSOR_SELECT("EXT_FAN3", hwmon_fan, 2, 0x00, 0x57, 0x0c),
 };
 
 static const struct ec_sensor_info sensors_family_intel_300[] = {
@@ -530,7 +560,8 @@ static const struct ec_board_info board_info_maximus_vi_hero = {
 static const struct ec_board_info board_info_maximus_ix_extreme = {
 	.sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_T_SENSOR |
 		SENSOR_TEMP_VRM | SENSOR_TEMP_SENSOR_EXTRA_1 |
-		SENSOR_TEMP_SENSOR_EXTRA_2 | SENSOR_TEMP_SENSOR_EXTRA_3,
+		SENSOR_TEMP_SENSOR_EXTRA_2 | SENSOR_TEMP_SENSOR_EXTRA_3 |
+		SENSOR_FAN_EXT_1 | SENSOR_FAN_EXT_2 | SENSOR_FAN_EXT_3,
 	.mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_LPCB_SIO1_MUT0,
 	.family = family_intel_200_series,
 };
@@ -1074,8 +1105,11 @@ struct ec_sensors_data {
 	const struct ec_board_info *board_info;
 	const struct ec_sensor_info *sensors_info;
 	struct ec_sensor *sensors;
-	/* EC registers to read from */
-	u16 *registers;
+	/*
+	 * EC registers to read from: (select << 16) + (bank << 8) + index,
+	 * see register_select()
+	 */
+	u32 *registers;
 	u8 *read_buffer;
 	/* sorted list of unique register banks */
 	u8 banks[ASUS_EC_MAX_BANK + 1];
@@ -1093,16 +1127,21 @@ struct ec_sensors_data {
 	u8 nr_banks;
 };
 
-static u8 register_bank(u16 reg)
+static u8 register_bank(u32 reg)
 {
-	return reg >> 8;
+	return (reg >> 8) & 0xff;
 }
 
-static u8 register_index(u16 reg)
+static u8 register_index(u32 reg)
 {
 	return reg & 0x00ff;
 }
 
+static u8 register_select(u32 reg)
+{
+	return (reg >> 16) & 0xff;
+}
+
 static bool is_sensor_data_signed(const struct ec_sensor_info *si)
 {
 	/*
@@ -1185,6 +1224,7 @@ static void fill_ec_registers(struct ec_sensors_data *ec)
 		si = get_sensor_info(ec, i);
 		for (j = 0; j < si->addr.components.size; ++j, ++register_idx) {
 			ec->registers[register_idx] =
+				(si->addr.components.select << 16) +
 				(si->addr.components.bank << 8) +
 				si->addr.components.index + j;
 		}
@@ -1239,7 +1279,8 @@ static int asus_ec_block_read(const struct device *dev,
 			      struct ec_sensors_data *ec)
 {
 	int ireg, ibank, status;
-	u8 bank, reg_bank, prev_bank;
+	u8 bank, reg_bank, prev_bank, select, prev_select;
+	bool select_saved;
 
 	bank = 0;
 	status = asus_ec_bank_switch(bank, &prev_bank);
@@ -1264,14 +1305,30 @@ static int asus_ec_block_read(const struct device *dev,
 				break;
 			}
 		}
+		select_saved = false;
 		for (ireg = 0; ireg < ec->nr_registers; ireg++) {
 			reg_bank = register_bank(ec->registers[ireg]);
 			if (reg_bank != bank) {
 				continue;
 			}
+			select = register_select(ec->registers[ireg]);
+			if (select) {
+				if (!select_saved) {
+					if (ec_read(ASUS_EC_SELECT_REGISTER,
+						    &prev_select))
+						continue;
+					select_saved = true;
+				}
+				if (ec_write(ASUS_EC_SELECT_REGISTER, select))
+					continue;
+			}
 			ec_read(register_index(ec->registers[ireg]),
 				ec->read_buffer + ireg);
 		}
+		/* restore the selector while still in its bank */
+		if (select_saved &&
+		    ec_write(ASUS_EC_SELECT_REGISTER, prev_select))
+			dev_warn(dev, "EC selector restore failed");
 	}
 
 	status = asus_ec_bank_switch(prev_bank, NULL);
@@ -1556,7 +1613,7 @@ static int asus_ec_probe(struct platform_device *pdev)
 
 	setup_sensor_data(ec_data);
 	ec_data->registers = devm_kcalloc(dev, ec_data->nr_registers,
-					  sizeof(u16), GFP_KERNEL);
+					  sizeof(*ec_data->registers), GFP_KERNEL);
 	ec_data->read_buffer = devm_kcalloc(dev, ec_data->nr_registers,
 					    sizeof(u8), GFP_KERNEL);
 

-- 
2.47.3



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 3/3] hwmon: (asus-ec-sensors) add water temperatures for MAXIMUS IX EXTREME
  2026-10-26  8:57 [PATCH 0/3] hwmon: (asus-ec-sensors) more MAXIMUS IX EXTREME sensors Remy Demangeot via B4 Relay
  2026-10-26  8:57 ` [PATCH 1/3] hwmon: (asus-ec-sensors) add EXT_Sensor temperatures for MAXIMUS IX EXTREME Remy Demangeot via B4 Relay
  2026-10-26  8:57 ` [PATCH 2/3] hwmon: (asus-ec-sensors) add fan extension card fans " Remy Demangeot via B4 Relay
@ 2026-10-26  8:57 ` Remy Demangeot via B4 Relay
  2026-10-26 19:34   ` Guenter Roeck
  2026-10-27  9:23   ` Eugene Shalygin
  2 siblings, 2 replies; 8+ messages in thread
From: Remy Demangeot via B4 Relay @ 2026-10-26  8:57 UTC (permalink / raw)
  To: Eugene Shalygin, Guenter Roeck; +Cc: linux-hwmon, linux-kernel, Remy Demangeot

From: Remy Demangeot <remy@demangeot.net>

The MAXIMUS IX EXTREME has a second EC (firmware ID "RGE2-Z270-0109"),
not handled by the ACPI EC driver, at I/O ports 0x68 (data) and 0x6c
(command/status). It uses the standard EC protocol (0x80 read, 0x81
write) and the same bank register (0xff). Its bank 1 holds the water
temperatures: WATER_IN 0x0d, WATER_OUT 0x0b, WATER_IN2 0x13 and
WATER_OUT2 0x11, as signed degrees Celsius with -60 for an absent
probe. Water_In and Water_Out are at the same offsets as on the AMD
400-series boards.

Describe registers of the second EC by setting ASUS_EC2_BANK_FLAG in
the sensor bank. Banks are sorted, so such registers are read last;
the second EC bank is saved and restored like the first one, under the
same hardware access mutex. The I/O ports are only requested for
boards using these sensors.

Add Water_In 2 and Water_Out 2 sensors and enable the four water
temperatures for the board. Readings match HWiNFO 8.54 on the same
machine.

Signed-off-by: Remy Demangeot <remy@demangeot.net>
---
 drivers/hwmon/asus-ec-sensors.c | 145 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 136 insertions(+), 9 deletions(-)

diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c
index 11dd7f587530d640b6ccc9b7952dc9da47e11c19..c1969169de6531c11a4c3485eafd54af97874991 100644
--- a/drivers/hwmon/asus-ec-sensors.c
+++ b/drivers/hwmon/asus-ec-sensors.c
@@ -26,7 +26,10 @@
 #include <linux/dev_printk.h>
 #include <linux/dmi.h>
 #include <linux/hwmon.h>
+#include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -45,6 +48,21 @@ static char *mutex_path_override;
  * group of registers reports (e.g. one of the fans of the fan extension card).
  */
 #define ASUS_EC_SELECT_REGISTER	0x43
+
+/*
+ * Some boards have a second EC, not handled by the ACPI EC driver, at these
+ * I/O ports. It uses the standard EC protocol and the same bank register.
+ * Its registers are described by sensors whose bank is ASUS_EC2_BANK(n).
+ */
+#define ASUS_EC2_DATA_PORT	0x68
+#define ASUS_EC2_CMD_PORT	0x6c
+#define ASUS_EC2_BANK_FLAG	0x80
+#define ASUS_EC2_BANK(bank)	(ASUS_EC2_BANK_FLAG | (bank))
+#define ASUS_EC2_STATUS_OBF	0x01
+#define ASUS_EC2_STATUS_IBF	0x02
+#define ASUS_EC2_CMD_READ	0x80
+#define ASUS_EC2_CMD_WRITE	0x81
+#define ASUS_EC2_TIMEOUT_US	20000
 #define SENSOR_LABEL_LEN	16
 
 /*
@@ -176,6 +194,10 @@ enum ec_sensors {
 	ec_sensor_fan_ext_1,
 	ec_sensor_fan_ext_2,
 	ec_sensor_fan_ext_3,
+	/* "Water_In 2" temperature sensor reading [℃] */
+	ec_sensor_temp_water_in_2,
+	/* "Water_Out 2" temperature sensor reading [℃] */
+	ec_sensor_temp_water_out_2,
 };
 
 #define SENSOR_TEMP_CHIPSET BIT(ec_sensor_temp_chipset)
@@ -208,6 +230,8 @@ enum ec_sensors {
 #define SENSOR_FAN_EXT_1 BIT(ec_sensor_fan_ext_1)
 #define SENSOR_FAN_EXT_2 BIT(ec_sensor_fan_ext_2)
 #define SENSOR_FAN_EXT_3 BIT(ec_sensor_fan_ext_3)
+#define SENSOR_TEMP_WATER_IN_2 BIT(ec_sensor_temp_water_in_2)
+#define SENSOR_TEMP_WATER_OUT_2 BIT(ec_sensor_temp_water_out_2)
 
 /*
  * The values for temperature sensor readings without physical sensors connected.
@@ -221,7 +245,8 @@ static const s32 environment_temp_sensors =
 	SENSOR_TEMP_WATER_IN | SENSOR_TEMP_WATER_OUT |
 	SENSOR_TEMP_WATER_BLOCK_IN | SENSOR_TEMP_WATER_BLOCK_OUT |
 	SENSOR_TEMP_T_SENSOR_2 | SENSOR_TEMP_SENSOR_EXTRA_1 |
-	SENSOR_TEMP_SENSOR_EXTRA_2 | SENSOR_TEMP_SENSOR_EXTRA_3;
+	SENSOR_TEMP_SENSOR_EXTRA_2 | SENSOR_TEMP_SENSOR_EXTRA_3 |
+	SENSOR_TEMP_WATER_IN_2 | SENSOR_TEMP_WATER_OUT_2;
 
 enum board_family {
 	family_unknown,
@@ -397,6 +422,14 @@ static const struct ec_sensor_info sensors_family_intel_200[] = {
 		EC_SENSOR_SELECT("EXT_FAN2", hwmon_fan, 2, 0x00, 0x57, 0x0b),
 	[ec_sensor_fan_ext_3] =
 		EC_SENSOR_SELECT("EXT_FAN3", hwmon_fan, 2, 0x00, 0x57, 0x0c),
+	[ec_sensor_temp_water_out] =
+		EC_SENSOR("Water_Out", hwmon_temp, 1, ASUS_EC2_BANK(0x01), 0x0b),
+	[ec_sensor_temp_water_in] =
+		EC_SENSOR("Water_In", hwmon_temp, 1, ASUS_EC2_BANK(0x01), 0x0d),
+	[ec_sensor_temp_water_out_2] =
+		EC_SENSOR("Water_Out 2", hwmon_temp, 1, ASUS_EC2_BANK(0x01), 0x11),
+	[ec_sensor_temp_water_in_2] =
+		EC_SENSOR("Water_In 2", hwmon_temp, 1, ASUS_EC2_BANK(0x01), 0x13),
 };
 
 static const struct ec_sensor_info sensors_family_intel_300[] = {
@@ -561,7 +594,9 @@ static const struct ec_board_info board_info_maximus_ix_extreme = {
 	.sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_T_SENSOR |
 		SENSOR_TEMP_VRM | SENSOR_TEMP_SENSOR_EXTRA_1 |
 		SENSOR_TEMP_SENSOR_EXTRA_2 | SENSOR_TEMP_SENSOR_EXTRA_3 |
-		SENSOR_FAN_EXT_1 | SENSOR_FAN_EXT_2 | SENSOR_FAN_EXT_3,
+		SENSOR_FAN_EXT_1 | SENSOR_FAN_EXT_2 | SENSOR_FAN_EXT_3 |
+		SENSOR_SET_TEMP_WATER | SENSOR_TEMP_WATER_IN_2 |
+		SENSOR_TEMP_WATER_OUT_2,
 	.mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_LPCB_SIO1_MUT0,
 	.family = family_intel_200_series,
 };
@@ -1263,15 +1298,84 @@ static int setup_lock_data(struct device *dev)
 	return 0;
 }
 
+static int asus_ec2_wait(bool want_obf)
+{
+	unsigned int t;
+	u8 status;
+
+	for (t = 0; t < ASUS_EC2_TIMEOUT_US; t += 10) {
+		status = inb(ASUS_EC2_CMD_PORT);
+		if (want_obf ? (status & ASUS_EC2_STATUS_OBF) :
+			       !(status & ASUS_EC2_STATUS_IBF))
+			return 0;
+		udelay(10);
+	}
+	return -ETIMEDOUT;
+}
+
+static int asus_ec2_read(u8 index, u8 *val)
+{
+	int status;
+
+	/* drop a stale byte left in the output buffer */
+	if (inb(ASUS_EC2_CMD_PORT) & ASUS_EC2_STATUS_OBF)
+		inb(ASUS_EC2_DATA_PORT);
+	status = asus_ec2_wait(false);
+	if (status)
+		return status;
+	outb(ASUS_EC2_CMD_READ, ASUS_EC2_CMD_PORT);
+	status = asus_ec2_wait(false);
+	if (status)
+		return status;
+	outb(index, ASUS_EC2_DATA_PORT);
+	status = asus_ec2_wait(true);
+	if (status)
+		return status;
+	*val = inb(ASUS_EC2_DATA_PORT);
+	return 0;
+}
+
+static int asus_ec2_write(u8 index, u8 val)
+{
+	int status;
+
+	status = asus_ec2_wait(false);
+	if (status)
+		return status;
+	outb(ASUS_EC2_CMD_WRITE, ASUS_EC2_CMD_PORT);
+	status = asus_ec2_wait(false);
+	if (status)
+		return status;
+	outb(index, ASUS_EC2_DATA_PORT);
+	status = asus_ec2_wait(false);
+	if (status)
+		return status;
+	outb(val, ASUS_EC2_DATA_PORT);
+	return asus_ec2_wait(false);
+}
+
+/* @bank may carry ASUS_EC2_BANK_FLAG to address the second EC */
+static int asus_ec_read_byte(u8 bank, u8 index, u8 *val)
+{
+	if (bank & ASUS_EC2_BANK_FLAG)
+		return asus_ec2_read(index, val);
+	return ec_read(index, val);
+}
+
 static int asus_ec_bank_switch(u8 bank, u8 *old)
 {
 	int status = 0;
 
 	if (old) {
-		status = ec_read(ASUS_EC_BANK_REGISTER, old);
+		status = asus_ec_read_byte(bank, ASUS_EC_BANK_REGISTER, old);
+		if (!status)
+			*old |= bank & ASUS_EC2_BANK_FLAG;
 	}
 	if (status || (old && (*old == bank)))
 		return status;
+	if (bank & ASUS_EC2_BANK_FLAG)
+		return asus_ec2_write(ASUS_EC_BANK_REGISTER,
+				      bank & ~ASUS_EC2_BANK_FLAG);
 	return ec_write(ASUS_EC_BANK_REGISTER, bank);
 }
 
@@ -1279,8 +1383,8 @@ static int asus_ec_block_read(const struct device *dev,
 			      struct ec_sensors_data *ec)
 {
 	int ireg, ibank, status;
-	u8 bank, reg_bank, prev_bank, select, prev_select;
-	bool select_saved;
+	u8 bank, reg_bank, prev_bank, prev_bank2, select, prev_select;
+	bool select_saved, ec2_used = false;
 
 	bank = 0;
 	status = asus_ec_bank_switch(bank, &prev_bank);
@@ -1299,7 +1403,14 @@ static int asus_ec_block_read(const struct device *dev,
 	for (ibank = 0; ibank < ec->nr_banks; ibank++) {
 		if (bank != ec->banks[ibank]) {
 			bank = ec->banks[ibank];
-			if (asus_ec_bank_switch(bank, NULL)) {
+			/* first bank of the second EC: save its bank too */
+			if ((bank & ASUS_EC2_BANK_FLAG) && !ec2_used) {
+				if (asus_ec_bank_switch(bank, &prev_bank2)) {
+					dev_warn(dev, "second EC bank switch failed");
+					break;
+				}
+				ec2_used = true;
+			} else if (asus_ec_bank_switch(bank, NULL)) {
 				dev_warn(dev, "EC bank switch to %d failed",
 					 bank);
 				break;
@@ -1312,7 +1423,7 @@ static int asus_ec_block_read(const struct device *dev,
 				continue;
 			}
 			select = register_select(ec->registers[ireg]);
-			if (select) {
+			if (select && !(bank & ASUS_EC2_BANK_FLAG)) {
 				if (!select_saved) {
 					if (ec_read(ASUS_EC_SELECT_REGISTER,
 						    &prev_select))
@@ -1322,8 +1433,9 @@ static int asus_ec_block_read(const struct device *dev,
 				if (ec_write(ASUS_EC_SELECT_REGISTER, select))
 					continue;
 			}
-			ec_read(register_index(ec->registers[ireg]),
-				ec->read_buffer + ireg);
+			asus_ec_read_byte(bank,
+					  register_index(ec->registers[ireg]),
+					  ec->read_buffer + ireg);
 		}
 		/* restore the selector while still in its bank */
 		if (select_saved &&
@@ -1331,6 +1443,9 @@ static int asus_ec_block_read(const struct device *dev,
 			dev_warn(dev, "EC selector restore failed");
 	}
 
+	if (ec2_used && asus_ec_bank_switch(prev_bank2, NULL))
+		dev_warn(dev, "second EC bank restore failed");
+
 	status = asus_ec_bank_switch(prev_bank, NULL);
 	return status;
 }
@@ -1612,6 +1727,18 @@ static int asus_ec_probe(struct platform_device *pdev)
 	}
 
 	setup_sensor_data(ec_data);
+
+	/* banks are sorted: the second EC, if used, comes last */
+	if (ec_data->nr_banks &&
+	    (ec_data->banks[ec_data->nr_banks - 1] & ASUS_EC2_BANK_FLAG)) {
+		if (!devm_request_region(dev, ASUS_EC2_DATA_PORT, 1,
+					 dev_name(dev)) ||
+		    !devm_request_region(dev, ASUS_EC2_CMD_PORT, 1,
+					 dev_name(dev))) {
+			dev_err(dev, "I/O ports of the second EC are busy");
+			return -EBUSY;
+		}
+	}
 	ec_data->registers = devm_kcalloc(dev, ec_data->nr_registers,
 					  sizeof(*ec_data->registers), GFP_KERNEL);
 	ec_data->read_buffer = devm_kcalloc(dev, ec_data->nr_registers,

-- 
2.47.3



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/3] hwmon: (asus-ec-sensors) add EXT_Sensor temperatures for MAXIMUS IX EXTREME
  2026-10-26  8:57 ` [PATCH 1/3] hwmon: (asus-ec-sensors) add EXT_Sensor temperatures for MAXIMUS IX EXTREME Remy Demangeot via B4 Relay
@ 2026-10-26 19:33   ` Guenter Roeck
  0 siblings, 0 replies; 8+ messages in thread
From: Guenter Roeck @ 2026-10-26 19:33 UTC (permalink / raw)
  To: Remy Demangeot; +Cc: Eugene Shalygin, linux-hwmon, linux-kernel

On Mon, Oct 26, 2026 at 09:57:35AM +0100, Remy Demangeot wrote:
> From: Remy Demangeot <remy@demangeot.net>
> 
> The MAXIMUS IX EXTREME supports three additional thermistor inputs,
> EXT_Sensor1-3, located on the optional ASUS fan extension card. The
> EC reports them at bank 0, registers 0x60-0x62, as signed degrees
> Celsius, with -60 when no probe is connected (already handled as a
> blank value).
> 
> Add them to the Intel 200-series family as Extra_1-Extra_3 and enable
> them for the board.
> 
> Readings match HWiNFO 8.54 on the same machine, and moving a probe
> from one header to another moves the reading accordingly.
> 
> Signed-off-by: Remy Demangeot <remy@demangeot.net>

Applied.

Thanks,
Guenter

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] hwmon: (asus-ec-sensors) add fan extension card fans for MAXIMUS IX EXTREME
  2026-10-26  8:57 ` [PATCH 2/3] hwmon: (asus-ec-sensors) add fan extension card fans " Remy Demangeot via B4 Relay
@ 2026-10-26 19:33   ` Guenter Roeck
  0 siblings, 0 replies; 8+ messages in thread
From: Guenter Roeck @ 2026-10-26 19:33 UTC (permalink / raw)
  To: Remy Demangeot; +Cc: Eugene Shalygin, linux-hwmon, linux-kernel

On Mon, Oct 26, 2026 at 09:57:36AM +0100, Remy Demangeot wrote:
> From: Remy Demangeot <remy@demangeot.net>
> 
> On the MAXIMUS IX EXTREME, the speeds of the three fans on the
> optional ASUS fan extension card (EXT_FAN1-3) are not at fixed EC
> addresses. Bank 0 register 0x43 selects which fan a group of registers
> describes: after writing 0x0a, 0x0b or 0x0c to it, registers 0x57:0x58
> hold the RPM of EXT_FAN1, EXT_FAN2 or EXT_FAN3 (big-endian).
> 
> Allow a sensor definition to carry a selector value, using the unused
> byte of sensor_address. When reading such a register, the driver
> writes the selector first and restores the previous selector value
> once the bank has been read. Sensors without a selector are read as
> before.
> 
> Readings match HWiNFO 8.54 on the same machine, and follow the fan
> speed when the fan duty is changed.
> 
> Signed-off-by: Remy Demangeot <remy@demangeot.net>

Applied.

Thanks,
Guenter

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/3] hwmon: (asus-ec-sensors) add water temperatures for MAXIMUS IX EXTREME
  2026-10-26  8:57 ` [PATCH 3/3] hwmon: (asus-ec-sensors) add water temperatures " Remy Demangeot via B4 Relay
@ 2026-10-26 19:34   ` Guenter Roeck
  2026-10-27  9:23   ` Eugene Shalygin
  1 sibling, 0 replies; 8+ messages in thread
From: Guenter Roeck @ 2026-10-26 19:34 UTC (permalink / raw)
  To: Remy Demangeot; +Cc: Eugene Shalygin, linux-hwmon, linux-kernel

On Mon, Oct 26, 2026 at 09:57:37AM +0100, Remy Demangeot wrote:
> From: Remy Demangeot <remy@demangeot.net>
> 
> The MAXIMUS IX EXTREME has a second EC (firmware ID "RGE2-Z270-0109"),
> not handled by the ACPI EC driver, at I/O ports 0x68 (data) and 0x6c
> (command/status). It uses the standard EC protocol (0x80 read, 0x81
> write) and the same bank register (0xff). Its bank 1 holds the water
> temperatures: WATER_IN 0x0d, WATER_OUT 0x0b, WATER_IN2 0x13 and
> WATER_OUT2 0x11, as signed degrees Celsius with -60 for an absent
> probe. Water_In and Water_Out are at the same offsets as on the AMD
> 400-series boards.
> 
> Describe registers of the second EC by setting ASUS_EC2_BANK_FLAG in
> the sensor bank. Banks are sorted, so such registers are read last;
> the second EC bank is saved and restored like the first one, under the
> same hardware access mutex. The I/O ports are only requested for
> boards using these sensors.
> 
> Add Water_In 2 and Water_Out 2 sensors and enable the four water
> temperatures for the board. Readings match HWiNFO 8.54 on the same
> machine.
> 
> Signed-off-by: Remy Demangeot <remy@demangeot.net>

Applied.

Thanks,
Guenter

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/3] hwmon: (asus-ec-sensors) add water temperatures for MAXIMUS IX EXTREME
  2026-10-26  8:57 ` [PATCH 3/3] hwmon: (asus-ec-sensors) add water temperatures " Remy Demangeot via B4 Relay
  2026-10-26 19:34   ` Guenter Roeck
@ 2026-10-27  9:23   ` Eugene Shalygin
  1 sibling, 0 replies; 8+ messages in thread
From: Eugene Shalygin @ 2026-10-27  9:23 UTC (permalink / raw)
  To: remy; +Cc: Guenter Roeck, linux-hwmon, linux-kernel

Hi,

On Mon, 26 Oct 2026 at 09:57, Remy Demangeot via B4 Relay
<devnull+remy.demangeot.net@kernel.org> wrote:
>
> From: Remy Demangeot <remy@demangeot.net>
>
> The MAXIMUS IX EXTREME has a second EC (firmware ID "RGE2-Z270-0109"),
> not handled by the ACPI EC driver, at I/O ports 0x68 (data) and 0x6c
> (command/status). It uses the standard EC protocol (0x80 read, 0x81
> write) and the same bank register (0xff).

I'm not fond of re-implementing EC access logic in this driver. I
believe the ec.c driver needs to be changed to allow us to simply
create another acpi_ec structure to operate the second EC.

Cheers,
Eugene

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-10-27  9:23 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-26  8:57 [PATCH 0/3] hwmon: (asus-ec-sensors) more MAXIMUS IX EXTREME sensors Remy Demangeot via B4 Relay
2026-10-26  8:57 ` [PATCH 1/3] hwmon: (asus-ec-sensors) add EXT_Sensor temperatures for MAXIMUS IX EXTREME Remy Demangeot via B4 Relay
2026-10-26 19:33   ` Guenter Roeck
2026-10-26  8:57 ` [PATCH 2/3] hwmon: (asus-ec-sensors) add fan extension card fans " Remy Demangeot via B4 Relay
2026-10-26 19:33   ` Guenter Roeck
2026-10-26  8:57 ` [PATCH 3/3] hwmon: (asus-ec-sensors) add water temperatures " Remy Demangeot via B4 Relay
2026-10-26 19:34   ` Guenter Roeck
2026-10-27  9:23   ` Eugene Shalygin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®