Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 315cd67c authored by Alexander Sverdlin's avatar Alexander Sverdlin Committed by Wolfram Sang
Browse files

i2c: i801: Add Block Write-Block Read Process Call support



Add SMBUS 2.0 Block Write-Block Read Process Call command support.

Signed-off-by: default avatarAlexander Sverdlin <alexander.sverdlin@nokia.com>
Reviewed-by: default avatarJean Delvare <jdelvare@suse.de>
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
parent 79b44995
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -88,7 +88,7 @@ SMBus controller.
Process Call Support
--------------------

Not supported.
Block process call is supported on the 82801EB (ICH5) and later chips.


I2C Block Read Support
+37 −6
Original line number Diff line number Diff line
@@ -77,7 +77,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
@@ -178,6 +178,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)
@@ -518,10 +519,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 */

@@ -533,12 +547,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;
@@ -676,6 +690,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;
@@ -807,7 +824,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,
@@ -899,6 +917,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);
@@ -959,6 +986,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) ?
@@ -1654,6 +1683,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
	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;
@@ -1673,6 +1703,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 */