[<prev] [next>] [day] [month] [year] [list]
Message-ID: <458484CD-01AC-4155-8687-D628A19D6493@cisco.com>
Date: Tue, 9 Dec 2025 03:30:31 +0000
From: "Qing Chang (qinchang)" <qinchang@...co.com>
CC: "Jean Delvare (maintainer:I2C/SMBUS CONTROLLER DRIVERS FOR PC)"
<jdelvare@...e.com>, "Andi Shyti (maintainer:I2C SUBSYSTEM HOST DRIVERS)"
<andi.shyti@...nel.org>, "open list:I2C/SMBUS CONTROLLER DRIVERS FOR PC"
<linux-i2c@...r.kernel.org>, open list <linux-kernel@...r.kernel.org>
Subject: [PATCH] i2c: piix4: Add support for I2C block data transactions
>From 329a0f951071c03b75a92e6b3c5746d9ee002935 Mon Sep 17 00:00:00 2001
-
From: Qing Chang <qinchang@...co.com>
Date: Sun, 30 Nov 2025 19:30:36 -0800
Subject: [PATCH] i2c: piix4: Add support for I2C block data transactions
Add support for I2C_SMBUS_I2C_BLOCK_DATA protocol to the PIIX4 SMBus
driver. This enables I2C block read/write operations where the master
specifies the transfer length, unlike SMBus block data where the slave
provides the length.
Key changes:
- Add PIIX4_I2C_BLOCK_DATA protocol constant (0x18)
- Implement I2C block write: first data byte to SMBHSTDAT0, rest to SMBBLKDAT
- Implement I2C block read: pre-specify length, read first byte from
SMBHSTDAT0, rest from SMBBLKDAT
- Update piix4_func() to advertise I2C_FUNC_SMBUS_I2C_BLOCK support
- Add IMC notification for SB800 series chips
Signed-off-by: Qing Chang <qinchang@...co.com>
---
drivers/i2c/busses/i2c-piix4.c | 44 +++++++++++++++++++++++++++++++---
drivers/i2c/busses/i2c-piix4.h | 3 ++-
2 files changed, 43 insertions(+), 4 deletions(-)
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index ac3bb550303f..778ff169b138 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -649,6 +649,28 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
}
size = PIIX4_BLOCK_DATA;
break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ outb_p((addr << 1) | read_write,
+ SMBHSTADD);
+ outb_p(command, SMBHSTCMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if (len == 0 || len > I2C_SMBUS_BLOCK_MAX + 1)
+ return -EINVAL;
+ /* For I2C block write, first byte goes to SMBHSTDAT0 */
+ outb_p(data->block[1], SMBHSTDAT0);
+ inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
+ /* Write remaining bytes to SMBBLKDAT */
+ for (i = 2; i <= len; i++)
+ outb_p(data->block[i], SMBBLKDAT);
+ } else {
+ /* For I2C block read, length is pre-specified by caller */
+ len = data->block[0];
+ if (len == 0 || len > I2C_SMBUS_BLOCK_MAX + 1)
+ return -EINVAL;
+ }
+ size = PIIX4_I2C_BLOCK_DATA;
+ break;
default:
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
return -EOPNOTSUPP;
@@ -680,6 +702,18 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
for (i = 1; i <= data->block[0]; i++)
data->block[i] = inb_p(SMBBLKDAT);
break;
+ case PIIX4_I2C_BLOCK_DATA:
+ /* For I2C block read, the length was pre-specified */
+ len = data->block[0];
+ if (len == 0 || len > I2C_SMBUS_BLOCK_MAX + 1)
+ return -EPROTO;
+ /* First byte of data is in SMBHSTDAT0, not a count */
+ data->block[1] = inb_p(SMBHSTDAT0);
+ inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
+ /* Read remaining bytes from SMBBLKDAT */
+ for (i = 2; i <= len; i++)
+ data->block[i] = inb_p(SMBBLKDAT);
+ break;
}
return 0;
}
@@ -819,7 +853,9 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr,
* Therefore we need to request the ownership flag during those
* transactions.
*/
- if ((size == I2C_SMBUS_BLOCK_DATA) && adapdata->notify_imc) {
+ if ((size == I2C_SMBUS_BLOCK_DATA ||
+ size == I2C_SMBUS_I2C_BLOCK_DATA) &&
+ adapdata->notify_imc) {
int ret;
ret = piix4_imc_sleep();
@@ -855,7 +891,9 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr,
/* Release the semaphore */
outb_p(smbslvcnt | 0x20, SMBSLVCNT);
- if ((size == I2C_SMBUS_BLOCK_DATA) && adapdata->notify_imc)
+ if ((size == I2C_SMBUS_BLOCK_DATA ||
+ size == I2C_SMBUS_I2C_BLOCK_DATA) &&
+ adapdata->notify_imc)
piix4_imc_wakeup();
release:
@@ -867,7 +905,7 @@ static u32 piix4_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_BLOCK_DATA;
+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_I2C_BLOCK;
}
static const struct i2c_algorithm smbus_algorithm = {
diff --git a/drivers/i2c/busses/i2c-piix4.h b/drivers/i2c/busses/i2c-piix4.h
index 36bc6ce82a27..6311af3ca661 100644
--- a/drivers/i2c/busses/i2c-piix4.h
+++ b/drivers/i2c/busses/i2c-piix4.h
@@ -29,7 +29,8 @@
#define SMBSLVDAT (0x0C + piix4_smba)
/* PIIX4 constants */
-#define PIIX4_BLOCK_DATA 0x14
+#define PIIX4_BLOCK_DATA 0x14
+#define PIIX4_I2C_BLOCK_DATA 0x18
struct sb800_mmio_cfg {
void __iomem *addr;
--
2.35.6
Powered by blists - more mailing lists