fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / i2c / busses / i2c-nforce2.c
index 2d80eb2..ad37c10 100644 (file)
     nForce3 250Gb MCP          00E4
     nForce4 MCP                        0052
     nForce4 MCP-04             0034
+    nForce4 MCP51              0264
+    nForce4 MCP55              0368
 
     This driver supports the 2 SMBuses that are included in the MCP of the
-    nForce2/3/4 chipsets.
+    nForce2/3/4/5xx chipsets.
 */
 
 /* Note: we assume there can only be one nForce2, with two SMBus interfaces */
@@ -50,8 +52,8 @@
 #include <asm/io.h>
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR ("Hans-Frieder Vogt <hfvogt@arcor.de>");
-MODULE_DESCRIPTION("nForce2 SMBus driver");
+MODULE_AUTHOR ("Hans-Frieder Vogt <hfvogt@gmx.net>");
+MODULE_DESCRIPTION("nForce2/3/4/5xx SMBus driver");
 
 
 struct nforce2_smbus {
@@ -64,6 +66,7 @@ struct nforce2_smbus {
 
 /*
  * nVidia nForce2 SMBus control register definitions
+ * (Newer incarnations use standard BARs 4 and 5 instead)
  */
 #define NFORCE_PCI_SMB1        0x50
 #define NFORCE_PCI_SMB2        0x54
@@ -77,9 +80,6 @@ struct nforce2_smbus {
 #define NVIDIA_SMB_ADDR                (smbus->base + 0x02)    /* address */
 #define NVIDIA_SMB_CMD         (smbus->base + 0x03)    /* command */
 #define NVIDIA_SMB_DATA                (smbus->base + 0x04)    /* 32 data registers */
-#define NVIDIA_SMB_BCNT                (smbus->base + 0x24)    /* number of data bytes */
-#define NVIDIA_SMB_ALRM_A      (smbus->base + 0x25)    /* alarm address */
-#define NVIDIA_SMB_ALRM_D      (smbus->base + 0x26)    /* 2 bytes alarm data */
 
 #define NVIDIA_SMB_STS_DONE    0x80
 #define NVIDIA_SMB_STS_ALRM    0x40
@@ -92,40 +92,17 @@ struct nforce2_smbus {
 #define NVIDIA_SMB_PRTCL_BYTE                  0x04
 #define NVIDIA_SMB_PRTCL_BYTE_DATA             0x06
 #define NVIDIA_SMB_PRTCL_WORD_DATA             0x08
-#define NVIDIA_SMB_PRTCL_BLOCK_DATA            0x0a
-#define NVIDIA_SMB_PRTCL_PROC_CALL             0x0c
-#define NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL       0x0d
-#define NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA                0x4a
 #define NVIDIA_SMB_PRTCL_PEC                   0x80
 
 static struct pci_driver nforce2_driver;
 
-static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
-                      unsigned short flags, char read_write,
-                      u8 command, int size, union i2c_smbus_data *data);
-static u32 nforce2_func(struct i2c_adapter *adapter);
-
-
-static struct i2c_algorithm smbus_algorithm = {
-       .smbus_xfer = nforce2_access,
-       .functionality = nforce2_func,
-};
-
-static struct i2c_adapter nforce2_adapter = {
-       .owner          = THIS_MODULE,
-       .class          = I2C_CLASS_HWMON,
-       .algo           = &smbus_algorithm,
-};
-
-/* Return -1 on error. See smbus.h for more information */
+/* Return -1 on error */
 static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
                unsigned short flags, char read_write,
                u8 command, int size, union i2c_smbus_data * data)
 {
        struct nforce2_smbus *smbus = adap->algo_data;
        unsigned char protocol, pec, temp;
-       unsigned char len = 0; /* to keep the compiler quiet */
-       int i;
 
        protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :
                NVIDIA_SMB_PRTCL_WRITE;
@@ -160,35 +137,6 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
                        protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec;
                        break;
 
-               case I2C_SMBUS_BLOCK_DATA:
-                       outb_p(command, NVIDIA_SMB_CMD);
-                       if (read_write == I2C_SMBUS_WRITE) {
-                               len = min_t(u8, data->block[0], 32);
-                               outb_p(len, NVIDIA_SMB_BCNT);
-                               for (i = 0; i < len; i++)
-                                       outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
-                       }
-                       protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;
-                       break;
-
-               case I2C_SMBUS_I2C_BLOCK_DATA:
-                       len = min_t(u8, data->block[0], 32);
-                       outb_p(command, NVIDIA_SMB_CMD);
-                       outb_p(len, NVIDIA_SMB_BCNT);
-                       if (read_write == I2C_SMBUS_WRITE)
-                               for (i = 0; i < len; i++)
-                                       outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
-                       protocol |= NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA;
-                       break;
-
-               case I2C_SMBUS_PROC_CALL:
-                       dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
-                       return -1;
-
-               case I2C_SMBUS_BLOCK_PROC_CALL:
-                       dev_err(&adap->dev, "I2C_SMBUS_BLOCK_PROC_CALL not supported!\n");
-                       return -1;
-
                default:
                        dev_err(&adap->dev, "Unsupported transaction %d\n", size);
                        return -1;
@@ -224,19 +172,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
                        break;
 
                case I2C_SMBUS_WORD_DATA:
-               /* case I2C_SMBUS_PROC_CALL: not supported */
                        data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8);
                        break;
-
-               case I2C_SMBUS_BLOCK_DATA:
-               /* case I2C_SMBUS_BLOCK_PROC_CALL: not supported */
-                       len = inb_p(NVIDIA_SMB_BCNT);
-                       len = min_t(u8, len, 32);
-               case I2C_SMBUS_I2C_BLOCK_DATA:
-                       for (i = 0; i < len; i++)
-                               data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
-                       data->block[0] = len;
-                       break;
        }
 
        return 0;
@@ -247,10 +184,14 @@ static u32 nforce2_func(struct i2c_adapter *adapter)
 {
        /* other functionality might be possible, but is not tested */
        return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-           I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA /* |
-           I2C_FUNC_SMBUS_BLOCK_DATA */;
+           I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA;
 }
 
+static struct i2c_algorithm smbus_algorithm = {
+       .smbus_xfer     = nforce2_access,
+       .functionality  = nforce2_func,
+};
+
 
 static struct pci_device_id nforce2_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },
@@ -259,33 +200,46 @@ static struct pci_device_id nforce2_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) },
        { 0 }
 };
 
-
 MODULE_DEVICE_TABLE (pci, nforce2_ids);
 
 
-static int __devinit nforce2_probe_smb (struct pci_dev *dev, int reg,
-       struct nforce2_smbus *smbus, char *name)
+static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
+       int alt_reg, struct nforce2_smbus *smbus, const char *name)
 {
-       u16 iobase;
        int error;
 
-       if (pci_read_config_word(dev, reg, &iobase) != PCIBIOS_SUCCESSFUL) {
-               dev_err(&smbus->adapter.dev, "Error reading PCI config for %s\n", name);
-               return -1;
+       smbus->base = pci_resource_start(dev, bar);
+       if (smbus->base) {
+               smbus->size = pci_resource_len(dev, bar);
+       } else {
+               /* Older incarnations of the device used non-standard BARs */
+               u16 iobase;
+
+               if (pci_read_config_word(dev, alt_reg, &iobase)
+                   != PCIBIOS_SUCCESSFUL) {
+                       dev_err(&dev->dev, "Error reading PCI config for %s\n",
+                               name);
+                       return -1;
+               }
+
+               smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK;
+               smbus->size = 64;
        }
-       smbus->dev  = dev;
-       smbus->base = iobase & 0xfffc;
-       smbus->size = 8;
+       smbus->dev = dev;
 
        if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) {
                dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n",
                        smbus->base, smbus->base+smbus->size-1, name);
                return -1;
        }
-       smbus->adapter = nforce2_adapter;
+       smbus->adapter.owner = THIS_MODULE;
+       smbus->adapter.class = I2C_CLASS_HWMON;
+       smbus->adapter.algo = &smbus_algorithm;
        smbus->adapter.algo_data = smbus;
        smbus->adapter.dev.parent = &dev->dev;
        snprintf(smbus->adapter.name, I2C_NAME_SIZE,
@@ -313,12 +267,13 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_
        pci_set_drvdata(dev, smbuses);
 
        /* SMBus adapter 1 */
-       res1 = nforce2_probe_smb (dev, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
+       res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
        if (res1 < 0) {
                dev_err(&dev->dev, "Error probing SMB1.\n");
                smbuses[0].base = 0;    /* to have a check value */
        }
-       res2 = nforce2_probe_smb (dev, NFORCE_PCI_SMB2, &smbuses[1], "SMB2");
+       /* SMBus adapter 2 */
+       res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1], "SMB2");
        if (res2 < 0) {
                dev_err(&dev->dev, "Error probing SMB2.\n");
                smbuses[1].base = 0;    /* to have a check value */