Skip to content

Instantly share code, notes, and snippets.

@bylaws
Created September 28, 2025 14:27
Show Gist options
  • Select an option

  • Save bylaws/3fed4c9148a677b9b9615073a0ad8ee2 to your computer and use it in GitHub Desktop.

Select an option

Save bylaws/3fed4c9148a677b9b9615073a0ad8ee2 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import sys
import time
from smbus2 import SMBus, i2c_msg
# Constants based on the ASL code
I2C_ADDR = 0x28 # From I2cSerialBusV2 (0x0028)
def ec_read(bus, register):
"""
Simulates the ECRD ASL method to read a byte from an EC register.
Args:
bus (SMBus): An initialized smbus2 SMBus object.
register (int): The register address to read from.
Returns:
int: The value read from the register, or None on error.
"""
try:
# Based on the ECRD method in the ASL:
# WLEN = 0x04
# ECW0 = 0x02 (Command for reading)
# ECW1 = Arg0 (The register to read)
# ECW2 = Zero
# ECW3 = One
# ECWB = IC7W = ECWB
#
# This sequence prepares a buffer to tell the EC which register we want to read.
# The command 0x02 seems to indicate a "prepare for read" operation.
write_data = [0x02, register, 0x00, 0x01]
# This corresponds to the `IC7W` operation, writing the command buffer.
# We use a write transaction for this.
msg_write = i2c_msg.write(I2C_ADDR, write_data)
bus.i2c_rdwr(msg_write)
# The ASL code has a Sleep(0x0A) -> 10ms delay.
time.sleep(0.01)
# Based on the ECRD method:
# ECRB = IC7R
# This corresponds to reading the result back from the EC.
# The ASL `IC7R` field is 8 bytes, so we read 8 bytes.
# The actual data is in ECR0, which is at offset 2 of the ECRB buffer.
read_buf = i2c_msg.read(I2C_ADDR, 8)
bus.i2c_rdwr(read_buf)
# Convert the read buffer to a list of integers
read_data = list(read_buf)
# The return value is ECR0, which is at the 3rd byte (index 2) of the read buffer (ECRB).
# RSTA = ECRB[0] -> Status
# RLEN = ECRB[1] -> Length
# ECR0 = ECRB[2] -> Data
status = read_data[0]
return read_data[0]
except IOError as e:
print(f"I/O error during read: {e}")
return None
def ec_write(bus, register, value):
"""
Simulates the ECWR ASL method to write a byte to an EC register.
Args:
bus (SMBus): An initialized smbus2 SMBus object.
register (int): The register address to write to.
value (int): The byte value to write.
"""
try:
# Based on the ECWR method in the ASL:
# WLEN = 0x05
# ECW0 = 0x03 (Command for writing)
# ECW1 = Arg0 (The register to write to)
# ECW2 = Zero
# ECW3 = One
# ECW4 = Arg1 (The value to write)
# I7WW = ECWB
#
# This sequence prepares a buffer with the command, register, and value.
write_data = [0x03, register, 0x00, 0x01, value]
# This corresponds to the `I7WW` operation.
# We use a single write transaction to send the command and data.
msg_write = i2c_msg.write(I2C_ADDR, write_data)
bus.i2c_rdwr(msg_write)
# The ASL code has a Sleep(0x0A) -> 10ms delay.
time.sleep(0.01)
print(f"Successfully wrote {hex(value)} to register {hex(register)}")
except IOError as e:
print(f"I/O error during write: {e}")
def main():
"""Main function to parse arguments and execute commands."""
try:
i2c_bus_num = int(sys.argv[1])
command = sys.argv[2].lower()
register = int(sys.argv[3], 16) # Accept hex input for register
except:
pass
try:
bus = SMBus(i2c_bus_num)
except FileNotFoundError:
print(f"Error: I2C bus {i2c_bus_num} not found.")
print("Please ensure the i2c-dev module is loaded and you have permission.")
sys.exit(1)
if command == "read":
if len(sys.argv) != 4:
print("Usage: {} <i2c_bus> read <register>".format(sys.argv[0]))
sys.exit(1)
value = ec_read(bus, register)
if value is not None:
print(f"Value at register {hex(register)}: {hex(value)} ({value})")
elif command == "dump":
for i in range(0xff):
value = ec_read(bus, i)
if value is not None:
print(f"Value at register {hex(i)}: {hex(value)} ({value})")
elif command == "write":
if len(sys.argv) != 5:
print("Usage: {} <i2c_bus> write <register> <value>".format(sys.argv[0]))
sys.exit(1)
try:
value = int(sys.argv[4], 16) # Accept hex input for value
except ValueError:
print("Invalid value. Must be an integer (e.g., 0x1a).")
sys.exit(1)
print(f"Attempting to write {hex(value)} to register {hex(register)} on I2C bus {i2c_bus_num}...")
ec_write(bus, register, value)
elif command == "maxfans":
ec_write(bus, 0x31, 0x0)
ec_write(bus, 0x2F, 0x40)
elif command == "autofans":
ec_write(bus, 0x31, 0x0)
ec_write(bus, 0x2F, 0x80)
else:
print(f"Unknown command: {command}")
sys.exit(1)
bus.close()
if __name__ == "__main__":
main()
diff --git a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi
index e19daf0f41f1..b5b109a0a7bd 100644
--- a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi
+++ b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dtsi
@@ -992,6 +992,12 @@ eusb6_repeater: redriver@4f {
};
};
+&i2c6 {
+ clock-frequency = <400000>;
+
+ status = "okay";
+};
+
&i2c7 {
clock-frequency = <400000>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment