diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/algos/i2c-algo-bit.c | 52 | ||||
-rw-r--r-- | drivers/i2c/busses/Kconfig | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-gpio.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-piix4.c | 6 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pxa.c | 2 |
5 files changed, 37 insertions, 26 deletions
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 8a5f582..7f0a0a6 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -357,13 +357,29 @@ static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) return wrcount; } +static int acknak(struct i2c_adapter *i2c_adap, int is_ack) +{ + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + /* assert: sda is high */ + if (is_ack) /* send ack */ + setsda(adap, 0); + udelay((adap->udelay + 1) / 2); + if (sclhi(adap) < 0) { /* timeout */ + dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n"); + return -ETIMEDOUT; + } + scllo(adap); + return 0; +} + static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { int inval; int rdcount=0; /* counts bytes read */ - struct i2c_algo_bit_data *adap = i2c_adap->algo_data; unsigned char *temp = msg->buf; int count = msg->len; + const unsigned flags = msg->flags; while (count > 0) { inval = i2c_inb(i2c_adap); @@ -377,28 +393,12 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) temp++; count--; - if (msg->flags & I2C_M_NO_RD_ACK) { - bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x\n", - inval); - continue; - } - - /* assert: sda is high */ - if (count) /* send ack */ - setsda(adap, 0); - udelay((adap->udelay + 1) / 2); - bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x %s\n", inval, - count ? "A" : "NA"); - if (sclhi(adap)<0) { /* timeout */ - dev_err(&i2c_adap->dev, "readbytes: timeout at ack\n"); - return -ETIMEDOUT; - }; - scllo(adap); - /* Some SMBus transactions require that we receive the transaction length as the first read byte. */ - if (rdcount == 1 && (msg->flags & I2C_M_RECV_LEN)) { + if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) { if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) { + if (!(flags & I2C_M_NO_RD_ACK)) + acknak(i2c_adap, 0); dev_err(&i2c_adap->dev, "readbytes: invalid " "block length (%d)\n", inval); return -EREMOTEIO; @@ -409,6 +409,18 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) count += inval; msg->len += inval; } + + bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n", + inval, + (flags & I2C_M_NO_RD_ACK) + ? "(no ack/nak)" + : (count ? "A" : "NA")); + + if (!(flags & I2C_M_NO_RD_ACK)) { + inval = acknak(i2c_adap, count); + if (inval < 0) + return inval; + } } return rdcount; } diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 1842f52..9f3a4cd 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -208,6 +208,7 @@ config I2C_PIIX4 ATI IXP400 ATI SB600 ATI SB700 + ATI SB800 Serverworks OSB4 Serverworks CSB5 Serverworks CSB6 diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 025f194..44e1cd2 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -147,7 +147,7 @@ static int __init i2c_gpio_probe(struct platform_device *pdev) * The reason to do so is to avoid sysfs names that only make * sense when there are multiple adapters. */ - adap->nr = pdev->id >= 0 ? pdev->id : 0; + adap->nr = (pdev->id != -1) ? pdev->id : 0; ret = i2c_bit_add_numbered_bus(adap); if (ret) goto err_add_bus; diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index debc76c..167e413 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -23,7 +23,7 @@ Supports: Intel PIIX4, 440MX Serverworks OSB4, CSB5, CSB6, HT-1000 - ATI IXP200, IXP300, IXP400, SB600, SB700 + ATI IXP200, IXP300, IXP400, SB600, SB700, SB800 SMSC Victory66 Note: we assume there can only be one device, with one SMBus interface. @@ -397,9 +397,7 @@ static struct pci_device_id piix4_ids[] = { .driver_data = 0 }, { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS), .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SMBUS), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SMBUS), + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS), .driver_data = 0 }, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4), .driver_data = 0 }, diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 9d6b790..bb5466b 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -926,7 +926,7 @@ static int i2c_pxa_probe(struct platform_device *dev) * The reason to do so is to avoid sysfs names that only make * sense when there are multiple adapters. */ - i2c->adap.nr = dev->id >= 0 ? dev->id : 0; + i2c->adap.nr = dev->id != -1 ? dev->id : 0; ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { |