Commit 6ff9d46c authored by Heiner Kallweit's avatar Heiner Kallweit Committed by Andi Shyti
Browse files

i2c: i801: Split i801_block_transaction



i2c and smbus block transaction handling have little in common,
therefore split this function to improve code readability.

Signed-off-by: default avatarHeiner Kallweit <hkallweit1@gmail.com>
Reviewed-by: default avatarAndi Shyti <andi.shyti@kernel.org>
Signed-off-by: default avatarAndi Shyti <andi.shyti@kernel.org>
parent 03f9863b
Loading
Loading
Loading
Loading
+50 −62
Original line number Diff line number Diff line
@@ -802,77 +802,65 @@ static int i801_simple_transaction(struct i801_priv *priv, union i2c_smbus_data
	return 0;
}

/* Block transaction function */
static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
static int i801_smbus_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
					u8 addr, u8 hstcmd, char read_write, int command)
{
	int result = 0;
	unsigned char hostc;

	if (read_write == I2C_SMBUS_READ && command == I2C_SMBUS_BLOCK_DATA)
		data->block[0] = I2C_SMBUS_BLOCK_MAX;
	else if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
		return -EPROTO;

	switch (command) {
	case I2C_SMBUS_BLOCK_DATA:
	if (command == I2C_SMBUS_BLOCK_PROC_CALL)
		/* Needs to be flagged as write transaction */
		i801_set_hstadd(priv, addr, I2C_SMBUS_WRITE);
	else
		i801_set_hstadd(priv, addr, read_write);
	outb_p(hstcmd, SMBHSTCMD(priv));
		break;
	case I2C_SMBUS_I2C_BLOCK_DATA:

	if (priv->features & FEATURE_BLOCK_BUFFER)
		return i801_block_transaction_by_block(priv, data, read_write, command);
	else
		return i801_block_transaction_byte_by_byte(priv, data, read_write, command);
}

static int i801_i2c_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
				      u8 addr, u8 hstcmd, char read_write, int command)
{
	int result;
	u8 hostc;

	if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
		return -EPROTO;
	/*
		 * NB: page 240 of ICH5 datasheet shows that the R/#W
		 * bit should be cleared here, even when reading.
		 * However if SPD Write Disable is set (Lynx Point and later),
	 * NB: page 240 of ICH5 datasheet shows that the R/#W bit should be cleared here,
	 * even when reading. However if SPD Write Disable is set (Lynx Point and later),
	 * the read will fail if we don't set the R/#W bit.
	 */
	i801_set_hstadd(priv, addr,
				priv->original_hstcfg & SMBHSTCFG_SPD_WD ?
				read_write : I2C_SMBUS_WRITE);
		if (read_write == I2C_SMBUS_READ) {
			/* NB: page 240 of ICH5 datasheet also shows
			 * that DATA1 is the cmd field when reading
			 */
			priv->original_hstcfg & SMBHSTCFG_SPD_WD ? read_write : I2C_SMBUS_WRITE);

	/* NB: page 240 of ICH5 datasheet shows that DATA1 is the cmd field when reading */
	if (read_write == I2C_SMBUS_READ)
		outb_p(hstcmd, SMBHSTDAT1(priv));
		} else
	else
		outb_p(hstcmd, SMBHSTCMD(priv));

	if (read_write == I2C_SMBUS_WRITE) {
		/* set I2C_EN bit in configuration register */
		pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
			pci_write_config_byte(priv->pci_dev, SMBHSTCFG,
					      hostc | SMBHSTCFG_I2C_EN);
		pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc | SMBHSTCFG_I2C_EN);
	} else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) {
			dev_err(&priv->pci_dev->dev,
				"I2C block read is unsupported!\n");
		pci_err(priv->pci_dev, "I2C block read is unsupported!\n");
		return -EOPNOTSUPP;
	}
		break;
	case I2C_SMBUS_BLOCK_PROC_CALL:
		/* Needs to be flagged as write transaction */
		i801_set_hstadd(priv, addr, I2C_SMBUS_WRITE);
		outb_p(hstcmd, SMBHSTCMD(priv));
		break;
	}

	/* Experience has shown that the block buffer can only be used for
	   SMBus (not I2C) block transactions, even though the datasheet
	   doesn't mention this limitation. */
	if ((priv->features & FEATURE_BLOCK_BUFFER) &&
	    command != I2C_SMBUS_I2C_BLOCK_DATA)
		result = i801_block_transaction_by_block(priv, data,
							 read_write,
							 command);
	else
		result = i801_block_transaction_byte_by_byte(priv, data,
							     read_write,
							     command);
	/* Block buffer isn't supported for I2C block transactions */
	result = i801_block_transaction_byte_by_byte(priv, data, read_write, command);

	if (command == I2C_SMBUS_I2C_BLOCK_DATA
	 && read_write == I2C_SMBUS_WRITE) {
	/* restore saved configuration register value */
	if (read_write == I2C_SMBUS_WRITE)
		pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc);
	}

	return result;
}

@@ -903,10 +891,10 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
		outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC),
		       SMBAUXCTL(priv));

	if (size == I2C_SMBUS_BLOCK_DATA ||
	    size == I2C_SMBUS_I2C_BLOCK_DATA ||
	    size == I2C_SMBUS_BLOCK_PROC_CALL)
		ret = i801_block_transaction(priv, data, addr, command, read_write, size);
	if (size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_BLOCK_PROC_CALL)
		ret = i801_smbus_block_transaction(priv, data, addr, command, read_write, size);
	else if (size == I2C_SMBUS_I2C_BLOCK_DATA)
		ret = i801_i2c_block_transaction(priv, data, addr, command, read_write, size);
	else
		ret = i801_simple_transaction(priv, data, addr, command, read_write, size);