i2c-ibm_iic: Remove deprecated OCP style part
[pandora-kernel.git] / drivers / i2c / busses / i2c-piix4.c
index 9bbe96c..85d69f3 100644 (file)
 #include <linux/ioport.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
-#include <linux/apm_bios.h>
 #include <linux/dmi.h>
 #include <asm/io.h>
 
 
-struct sd {
-       const unsigned short mfr;
-       const unsigned short dev;
-       const unsigned char fn;
-       const char *name;
-};
-
 /* PIIX4 SMBus address offsets */
 #define SMBHSTSTS      (0 + piix4_smba)
 #define SMBHSLVSTS     (1 + piix4_smba)
@@ -102,13 +94,32 @@ MODULE_PARM_DESC(force_addr,
                 "Forcibly enable the PIIX4 at the given address. "
                 "EXTREMELY DANGEROUS!");
 
-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;
 
-static struct dmi_system_id __devinitdata piix4_dmi_table[] = {
+static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = {
+       {
+               .ident = "Sapphire AM2RD790",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "SAPPHIRE Inc."),
+                       DMI_MATCH(DMI_BOARD_NAME, "PC-AM2RD790"),
+               },
+       },
+       {
+               .ident = "DFI Lanparty UT 790FX",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "DFI Inc."),
+                       DMI_MATCH(DMI_BOARD_NAME, "LP UT 790FX"),
+               },
+       },
+       { }
+};
+
+/* The IBM entry is in a separate table because we only check it
+   on Intel-based systems */
+static struct dmi_system_id __devinitdata piix4_dmi_ibm[] = {
        {
                .ident = "IBM",
                .matches = { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), },
@@ -121,10 +132,20 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
 {
        unsigned char temp;
 
-       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;
+
+       /* On some motherboards, it was reported that accessing the SMBus
+          caused severe hardware problems */
+       if (dmi_check_system(piix4_dmi_blacklist)) {
+               dev_err(&PIIX4_dev->dev,
+                       "Accessing the SMBus on this system is unsafe!\n");
+               return -EPERM;
+       }
 
        /* Don't access SMBus on IBM systems which get corrupted eeproms */
-       if (dmi_check_system(piix4_dmi_table) &&
+       if (dmi_check_system(piix4_dmi_ibm) &&
                        PIIX4_dev->vendor == PCI_VENDOR_ID_INTEL) {
                dev_err(&PIIX4_dev->dev, "IBM system detected; this module "
                        "may corrupt your serial eeprom! Refusing to load "
@@ -140,7 +161,7 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
                pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba);
                piix4_smba &= 0xfff0;
                if(piix4_smba == 0) {
-                       dev_err(&PIIX4_dev->dev, "SMB base address "
+                       dev_err(&PIIX4_dev->dev, "SMBus base address "
                                "uninitialized - upgrade BIOS or use "
                                "force_addr=0xaddr\n");
                        return -ENODEV;
@@ -148,9 +169,9 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
        }
 
        if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
-               dev_err(&PIIX4_dev->dev, "SMB region 0x%x already in use!\n",
+               dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n",
                        piix4_smba);
-               return -ENODEV;
+               return -EBUSY;
        }
 
        pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp);
@@ -196,13 +217,13 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
                        "(or code out of date)!\n");
 
        pci_read_config_byte(PIIX4_dev, SMBREV, &temp);
-       dev_dbg(&PIIX4_dev->dev, "SMBREV = 0x%X\n", temp);
-       dev_dbg(&PIIX4_dev->dev, "SMBA = 0x%X\n", piix4_smba);
+       dev_info(&PIIX4_dev->dev,
+                "SMBus Host Controller at 0x%x, revision %d\n",
+                piix4_smba, temp);
 
        return 0;
 }
 
-/* Another internally used function */
 static int piix4_transaction(void)
 {
        int temp;
@@ -221,9 +242,9 @@ static int piix4_transaction(void)
                outb_p(temp, SMBHSTSTS);
                if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
                        dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp);
-                       return -1;
+                       return -EBUSY;
                } else {
-                       dev_dbg(&piix4_adapter.dev, "Successfull!\n");
+                       dev_dbg(&piix4_adapter.dev, "Successful!\n");
                }
        }
 
@@ -231,31 +252,35 @@ 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) {
                dev_err(&piix4_adapter.dev, "SMBus Timeout!\n");
-               result = -1;
+               result = -ETIMEDOUT;
        }
 
        if (temp & 0x10) {
-               result = -1;
+               result = -EIO;
                dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n");
        }
 
        if (temp & 0x08) {
-               result = -1;
+               result = -EIO;
                dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be "
                        "locked until next hard reset. (sorry!)\n");
                /* Clock stops and slave is stuck in mid-transmission */
        }
 
        if (temp & 0x04) {
-               result = -1;
+               result = -ENXIO;
                dev_dbg(&piix4_adapter.dev, "Error: no response!\n");
        }
 
@@ -273,31 +298,29 @@ static int piix4_transaction(void)
        return result;
 }
 
-/* Return -1 on error. */
+/* Return negative errno on error. */
 static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
                 unsigned short flags, char read_write,
                 u8 command, int size, union i2c_smbus_data * data)
 {
        int i, len;
+       int status;
 
        switch (size) {
-       case I2C_SMBUS_PROC_CALL:
-               dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
-               return -1;
        case I2C_SMBUS_QUICK:
-               outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+               outb_p((addr << 1) | read_write,
                       SMBHSTADD);
                size = PIIX4_QUICK;
                break;
        case I2C_SMBUS_BYTE:
-               outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+               outb_p((addr << 1) | read_write,
                       SMBHSTADD);
                if (read_write == I2C_SMBUS_WRITE)
                        outb_p(command, SMBHSTCMD);
                size = PIIX4_BYTE;
                break;
        case I2C_SMBUS_BYTE_DATA:
-               outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+               outb_p((addr << 1) | read_write,
                       SMBHSTADD);
                outb_p(command, SMBHSTCMD);
                if (read_write == I2C_SMBUS_WRITE)
@@ -305,7 +328,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
                size = PIIX4_BYTE_DATA;
                break;
        case I2C_SMBUS_WORD_DATA:
-               outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+               outb_p((addr << 1) | read_write,
                       SMBHSTADD);
                outb_p(command, SMBHSTCMD);
                if (read_write == I2C_SMBUS_WRITE) {
@@ -315,15 +338,13 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
                size = PIIX4_WORD_DATA;
                break;
        case I2C_SMBUS_BLOCK_DATA:
-               outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+               outb_p((addr << 1) | read_write,
                       SMBHSTADD);
                outb_p(command, SMBHSTCMD);
                if (read_write == I2C_SMBUS_WRITE) {
                        len = data->block[0];
-                       if (len < 0)
-                               len = 0;
-                       if (len > 32)
-                               len = 32;
+                       if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+                               return -EINVAL;
                        outb_p(len, SMBHSTDAT0);
                        i = inb_p(SMBHSTCNT);   /* Reset SMBBLKDAT */
                        for (i = 1; i <= len; i++)
@@ -331,24 +352,23 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
                }
                size = PIIX4_BLOCK_DATA;
                break;
+       default:
+               dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+               return -EOPNOTSUPP;
        }
 
        outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
 
-       if (piix4_transaction())        /* Error in transaction */
-               return -1;
+       status = piix4_transaction();
+       if (status)
+               return status;
 
        if ((read_write == I2C_SMBUS_WRITE) || (size == PIIX4_QUICK))
                return 0;
 
 
        switch (size) {
-       case PIIX4_BYTE:        /* Where is the result put? I assume here it is in
-                                  SMBHSTDAT0 but it might just as well be in the
-                                  SMBHSTCMD. No clue in the docs */
-
-               data->byte = inb_p(SMBHSTDAT0);
-               break;
+       case PIIX4_BYTE:
        case PIIX4_BYTE_DATA:
                data->byte = inb_p(SMBHSTDAT0);
                break;
@@ -357,6 +377,8 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
                break;
        case PIIX4_BLOCK_DATA:
                data->block[0] = inb_p(SMBHSTDAT0);
+               if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
+                       return -EPROTO;
                i = inb_p(SMBHSTCNT);   /* Reset SMBBLKDAT */
                for (i = 1; i <= data->block[0]; i++)
                        data->block[i] = inb_p(SMBBLKDAT);
@@ -380,7 +402,7 @@ static const struct i2c_algorithm smbus_algorithm = {
 static struct i2c_adapter piix4_adapter = {
        .owner          = THIS_MODULE,
        .id             = I2C_HW_SMBUS_PIIX4,
-       .class          = I2C_CLASS_HWMON,
+       .class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
        .algo           = &smbus_algorithm,
 };