Hello Linux-i2c community, We would like to upstream a minor enhancement for i2c-i801.c. This patch adds I2C_FUNC_SMBUS_PROC_CALL functionality to i2c-i801.c. diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c =================================================================== --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -783,6 +783,14 @@ outb_p(command, SMBHSTCMD(priv)); block = 1; break; + case I2C_SMBUS_PROC_CALL: + outb_p(((addr & 0x7f) << 1)| (I2C_SMBUS_WRITE & 0x01), + SMBHSTADD(priv)); + outb_p(command, SMBHSTCMD(priv)); + outb_p(data->word & 0xff, SMBHSTDAT0(priv)); + outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv)); + xact = I801_PROC_CALL; + break; default: dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n", size); @@ -799,9 +807,21 @@ if (block) ret = i801_block_transaction(priv, data, read_write, size, hwpec); - else + else { + unsigned char hostc = 0; + + if (xact == I801_PROC_CALL) { + /* clear I2C_EN bit in configuration register for proc calls */ + pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc); + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, + (hostc & (~SMBHSTCFG_I2C_EN))); + } ret = i801_transaction(priv, xact); - + if (xact == I801_PROC_CALL) { + /* restore saved configuration register value */ + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc); + } + } /* Some BIOSes don't like it when PEC is enabled at reboot or resume time, so we forcibly disable it after every transaction. Turn off E32B for the same reason. */ @@ -813,7 +833,14 @@ goto out; if (ret) goto out; - if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) + + /* i2c-dev.h has defined i2c_smbus_proc_call to pass I2C_SMBUS_WRITE + to the nderlying driver. However, process call is only defined for + read transactions. Process call writes will be using + i2c_smbus_write_i2c_block_data driver api. + */ + if (((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) && + (xact != I801_PROC_CALL)) goto out; switch (xact & 0x7f) { @@ -821,6 +848,7 @@ case I801_BYTE_DATA: data->byte = inb_p(SMBHSTDAT0(priv)); break; + case I801_PROC_CALL: case I801_WORD_DATA: data->word = inb_p(SMBHSTDAT0(priv)) + (inb_p(SMBHSTDAT1(priv)) << 8); @@ -840,6 +868,7 @@ 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_WRITE_I2C_BLOCK | + I2C_FUNC_SMBUS_PROC_CALL | ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | ((priv->features & FEATURE_I2C_BLOCK_READ) ? I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0); Thanks & Best Regards, Ng Sock Chan (Angela) 吴姝臻 Software Engineer (HPN)