Add SMBUS 2.0 Block Write-Block Read Process Call command support. Signed-off-by: Alexander Sverdlin <alexander.sverdlin@xxxxxxxxx> --- drivers/i2c/busses/i2c-i801.c | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 941c223..b02e798 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -76,7 +76,7 @@ * Software PEC no * Hardware PEC yes * Block buffer yes - * Block process call transaction no + * Block process call transaction yes * I2C block read transaction yes (doesn't use the block buffer) * Slave mode no * SMBus Host Notify yes @@ -175,6 +175,7 @@ #define I801_PROC_CALL 0x10 /* unimplemented */ #define I801_BLOCK_DATA 0x14 #define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ +#define I801_BLOCK_PROC_CALL 0x1C /* I801 Host Control register bits */ #define SMBHSTCNT_INTREN BIT(0) @@ -514,10 +515,23 @@ static int i801_transaction(struct i801_priv *priv, int xact) static int i801_block_transaction_by_block(struct i801_priv *priv, union i2c_smbus_data *data, - char read_write, int hwpec) + char read_write, int command, + int hwpec) { int i, len; int status; + int xact = hwpec ? SMBHSTCNT_PEC_EN : 0; + + switch (command) { + case I2C_SMBUS_BLOCK_PROC_CALL: + xact |= I801_BLOCK_PROC_CALL; + break; + case I2C_SMBUS_BLOCK_DATA: + xact |= I801_BLOCK_DATA; + break; + default: + return -EOPNOTSUPP; + } inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */ @@ -529,12 +543,12 @@ static int i801_block_transaction_by_block(struct i801_priv *priv, outb_p(data->block[i+1], SMBBLKDAT(priv)); } - status = i801_transaction(priv, I801_BLOCK_DATA | - (hwpec ? SMBHSTCNT_PEC_EN : 0)); + status = i801_transaction(priv, xact); if (status) return status; - if (read_write == I2C_SMBUS_READ) { + if (read_write == I2C_SMBUS_READ || + command == I2C_SMBUS_BLOCK_PROC_CALL) { len = inb_p(SMBHSTDAT0(priv)); if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) return -EPROTO; @@ -672,6 +686,9 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, int result; const struct i2c_adapter *adap = &priv->adapter; + if (command == I2C_SMBUS_BLOCK_PROC_CALL) + return -EOPNOTSUPP; + result = i801_check_pre(priv); if (result < 0) return result; @@ -803,7 +820,8 @@ static int i801_block_transaction(struct i801_priv *priv, && command != I2C_SMBUS_I2C_BLOCK_DATA && i801_set_block_buffer_mode(priv) == 0) result = i801_block_transaction_by_block(priv, data, - read_write, hwpec); + read_write, + command, hwpec); else result = i801_block_transaction_byte_by_byte(priv, data, read_write, @@ -895,6 +913,15 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, outb_p(command, SMBHSTCMD(priv)); block = 1; break; + case I2C_SMBUS_BLOCK_PROC_CALL: + /* + * Bit 0 of the slave address register always indicate a write + * command. + */ + outb_p((addr & 0x7f) << 1, SMBHSTADD(priv)); + outb_p(command, SMBHSTCMD(priv)); + block = 1; + break; default: dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n", size); @@ -955,6 +982,8 @@ static u32 i801_func(struct i2c_adapter *adapter) I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | + ((priv->features & FEATURE_BLOCK_PROC) ? + I2C_FUNC_SMBUS_BLOCK_PROC_CALL : 0) | ((priv->features & FEATURE_I2C_BLOCK_READ) ? I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) | ((priv->features & FEATURE_HOST_NOTIFY) ? @@ -1522,6 +1551,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) case PCI_DEVICE_ID_INTEL_DNV_SMBUS: case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS: case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS: + priv->features |= FEATURE_BLOCK_PROC; priv->features |= FEATURE_I2C_BLOCK_READ; priv->features |= FEATURE_IRQ; priv->features |= FEATURE_SMBUS_PEC; @@ -1541,6 +1571,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) priv->features |= FEATURE_IDF; /* fall through */ default: + priv->features |= FEATURE_BLOCK_PROC; priv->features |= FEATURE_I2C_BLOCK_READ; priv->features |= FEATURE_IRQ; /* fall through */ -- 2.4.6