diff --git a/kernel/busses/i2c-i801.c b/kernel/busses/i2c-i801.c index 604ac5b6..a66fbba7 100644 --- a/kernel/busses/i2c-i801.c +++ b/kernel/busses/i2c-i801.c @@ -29,12 +29,13 @@ 82801DB 24C3 (HW PEC supported, 32 byte buffer not supported) 82801EB 24D3 (HW PEC supported, 32 byte buffer not supported) 6300ESB 25A4 ("") - ICH6 266A + ICH6 266A ("") This driver supports several versions of Intel's I/O Controller Hubs (ICH). For SMBus support, they are similar to the PIIX4 and are part of Intel's '810' and other chipsets. See the doc/busses/i2c-i801 file for details. - I2C Block Read and Process Call are not supported. + I2C Block Read supported for ICH5 and higher. + Block Process Call are not supported. */ /* Note: we assume there can only be one I801, with one SMBus interface */ @@ -95,11 +96,11 @@ #define I801_WORD_DATA 0x0C #define I801_PROC_CALL 0x10 /* later chips only, unimplemented */ #define I801_BLOCK_DATA 0x14 -#define I801_I2C_BLOCK_DATA 0x18 /* unimplemented */ +#define I801_I2C_BLOCK_DATA 0x18 /* ich4 and later */ #define I801_BLOCK_LAST 0x34 #define I801_I2C_BLOCK_LAST 0x38 /* unimplemented */ #define I801_START 0x40 -#define I801_PEC_EN 0x80 /* ICH4 only */ +#define I801_PEC_EN 0x80 /* ich4 and later */ /* insmod parameters */ @@ -117,7 +118,8 @@ static int i801_block_transaction(union i2c_smbus_data *data, static unsigned short i801_smba; static struct pci_dev *I801_dev; -static int isich4; +static int isich4; /* is PEC supported? */ +static int isich5; /* is i2c block read supported? */ static int i801_setup(struct pci_dev *dev) { @@ -136,6 +138,7 @@ static int i801_setup(struct pci_dev *dev) isich4 = 1; else isich4 = 0; + isich5 = isich4 && dev->device != PCI_DEVICE_ID_INTEL_82801DB_3; /* Determine the address of the SMBus areas */ if (force_addr) { @@ -275,7 +278,7 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); pci_write_config_byte(I801_dev, SMBHSTCFG, hostc | SMBHSTCFG_I2C_EN); - } else { + } else if (!isich5) { dev_err(I801_dev, "I2C_SMBUS_I2C_BLOCK_READ unsupported!\n"); return -1; @@ -301,6 +304,9 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, for (i = 1; i <= len; i++) { if (i == len && read_write == I2C_SMBUS_READ) smbcmd = I801_BLOCK_LAST; + else if (command == I2C_SMBUS_I2C_BLOCK_DATA && + read_write == I2C_SMBUS_READ) + smbcmd = I801_I2C_BLOCK_DATA; else smbcmd = I801_BLOCK_DATA; outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT); @@ -369,12 +375,17 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, } if (i == 1 && read_write == I2C_SMBUS_READ) { - len = inb_p(SMBHSTDAT0); - if (len < 1) - len = 1; - if (len > 32) - len = 32; - data->block[0] = len; + if (command != I2C_SMBUS_I2C_BLOCK_DATA) { + len = inb_p(SMBHSTDAT0); + if (len < 1) + len = 1; + if (len > 32) + len = 32; + data->block[0] = len; + } else { + /* if slave returns < 32 bytes transaction will fail */ + data->block[0] = 32; + } } /* Retrieve/store value in SMBBLKDAT */ @@ -417,7 +428,8 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, #endif result = 0; END: - if (command == I2C_SMBUS_I2C_BLOCK_DATA) { + if (command == I2C_SMBUS_I2C_BLOCK_DATA && + read_write == I2C_SMBUS_WRITE) { /* restore saved configuration register value */ pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); } @@ -552,6 +564,8 @@ static u32 i801_func(struct i2c_adapter *adapter) I2C_FUNC_SMBUS_HWPEC_CALC : 0) #endif + | (isich5 ? I2C_FUNC_SMBUS_READ_I2C_BLOCK + : 0) ; }