* 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
#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)
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 */
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;
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;
&& 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,
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);
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) ?
case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS:
case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS:
case PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS:
+ priv->features |= FEATURE_BLOCK_PROC;
priv->features |= FEATURE_I2C_BLOCK_READ;
priv->features |= FEATURE_IRQ;
priv->features |= FEATURE_SMBUS_PEC;
priv->features |= FEATURE_IDF;
/* fall through */
default:
+ priv->features |= FEATURE_BLOCK_PROC;
priv->features |= FEATURE_I2C_BLOCK_READ;
priv->features |= FEATURE_IRQ;
/* fall through */