aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Milburn <dmilburn@redhat.com>2008-05-11 20:37:05 +0200
committerJean Delvare <khali@hyperion.delvare>2008-05-11 20:37:05 +0200
commitb1c1759cd192fe1d27989f986c7f6b2939905e0c (patch)
treebd8cc93f5ba349c39fb7cdcfbbdae627d8ece515
parentf5fff3602a67ff8c98fccdbf15959780be542802 (diff)
i2c-piix4: Increase the intitial delay for the ServerWorks CSB5
Per the PIIX4 errata, there maybe a delay between setting the start bit in the Smbus Host Controller Register and the transaction actually starting. If the driver doesn't delay long enough, it may appear that the transaction is complete when actually it hasn't started, this may lead to bus collisions. While 1 ms appears to be enough for most chips, the ServerWorks CSB5 wants 2 ms. Signed-off-by: David Milburn <dmilburn@redhat.com> Signed-off-by: Jean Delvare <khali@linux-fr.org>
-rw-r--r--drivers/i2c/busses/i2c-piix4.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index fdc9ad805e3..7217410f425 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -104,6 +104,7 @@ MODULE_PARM_DESC(force_addr,
static int piix4_transaction(void);
static unsigned short piix4_smba;
+static int srvrworks_csb5_delay;
static struct pci_driver piix4_driver;
static struct i2c_adapter piix4_adapter;
@@ -122,6 +123,10 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
dev_info(&PIIX4_dev->dev, "Found %s device\n", pci_name(PIIX4_dev));
+ if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
+ (PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5))
+ srvrworks_csb5_delay = 1;
+
/* Don't access SMBus on IBM systems which get corrupted eeproms */
if (dmi_check_system(piix4_dmi_table) &&
PIIX4_dev->vendor == PCI_VENDOR_ID_INTEL) {
@@ -230,10 +235,14 @@ static int piix4_transaction(void)
outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT);
/* We will always wait for a fraction of a second! (See PIIX4 docs errata) */
- do {
+ if (srvrworks_csb5_delay) /* Extra delay for SERVERWORKS_CSB5 */
+ msleep(2);
+ else
+ msleep(1);
+
+ while ((timeout++ < MAX_TIMEOUT) &&
+ ((temp = inb_p(SMBHSTSTS)) & 0x01))
msleep(1);
- temp = inb_p(SMBHSTSTS);
- } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
/* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) {