Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / drivers / i2c / busses / i2c-i801.c
index 4689bd0..7be1d0a 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
-    i801.c - Part of lm_sensors, Linux kernel modules for hardware
+    i2c-i801.c - Part of lm_sensors, Linux kernel modules for hardware
               monitoring
     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
     Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
               monitoring
     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
     Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
     82801EB            24D3   (HW PEC supported, 32 byte buffer not supported)
     6300ESB            25A4
     ICH6               266A
     82801EB            24D3   (HW PEC supported, 32 byte buffer not supported)
     6300ESB            25A4
     ICH6               266A
+    ICH7               27DA
+    ESB2               269B
+    ICH8               283E
     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.
     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.
+    See the file Documentation/i2c/busses/i2c-i801 for details.
     I2C Block Read and Process Call are not supported.
 */
 
 /* Note: we assume there can only be one I801, with one SMBus interface */
 
     I2C Block Read and Process Call are not supported.
 */
 
 /* Note: we assume there can only be one I801, with one SMBus interface */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/i2c.h>
 #include <asm/io.h>
 
 #include <linux/i2c.h>
 #include <asm/io.h>
 
-#ifdef I2C_FUNC_SMBUS_BLOCK_DATA_PEC
-#define HAVE_PEC
-#endif
-
 /* I801 SMBus address offsets */
 #define SMBHSTSTS      (0 + i801_smba)
 #define SMBHSTCNT      (2 + i801_smba)
 /* I801 SMBus address offsets */
 #define SMBHSTSTS      (0 + i801_smba)
 #define SMBHSTCNT      (2 + i801_smba)
@@ -68,9 +66,8 @@
 #define SMBAUXCTL      (13 + i801_smba)        /* ICH4 only */
 
 /* PCI Address Constants */
 #define SMBAUXCTL      (13 + i801_smba)        /* ICH4 only */
 
 /* PCI Address Constants */
-#define SMBBA          0x020
+#define SMBBAR         4
 #define SMBHSTCFG      0x040
 #define SMBHSTCFG      0x040
-#define SMBREV         0x008
 
 /* Host configuration bits for SMBHSTCFG */
 #define SMBHSTCFG_HST_EN       1
 
 /* Host configuration bits for SMBHSTCFG */
 #define SMBHSTCFG_HST_EN       1
 #define I801_START             0x40
 #define I801_PEC_EN            0x80    /* ICH4 only */
 
 #define I801_START             0x40
 #define I801_PEC_EN            0x80    /* ICH4 only */
 
-/* insmod parameters */
-
-/* If force_addr is set to anything different from 0, we forcibly enable
-   the I801 at the given address. VERY DANGEROUS! */
-static int force_addr = 0;
-MODULE_PARM(force_addr, "i");
-MODULE_PARM_DESC(force_addr,
-                "Forcibly enable the I801 at the given address. "
-                "EXTREMELY DANGEROUS!");
 
 static int i801_transaction(void);
 
 static int i801_transaction(void);
-static int i801_block_transaction(union i2c_smbus_data *data,
-                                 char read_write, int command);
+static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
+                                 int command, int hwpec);
 
 
-static unsigned short i801_smba;
+static unsigned long i801_smba;
+static struct pci_driver i801_driver;
 static struct pci_dev *I801_dev;
 static int isich4;
 
 static struct pci_dev *I801_dev;
 static int isich4;
 
-static int i801_setup(struct pci_dev *dev)
-{
-       int error_return = 0;
-       unsigned char temp;
-
-       /* Note: we keep on searching until we have found 'function 3' */
-       if(PCI_FUNC(dev->devfn) != 3)
-               return -ENODEV;
-
-       I801_dev = dev;
-       if ((dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) ||
-           (dev->device == PCI_DEVICE_ID_INTEL_82801EB_3) ||
-           (dev->device == PCI_DEVICE_ID_INTEL_ESB_4))
-               isich4 = 1;
-       else
-               isich4 = 0;
-
-       /* Determine the address of the SMBus areas */
-       if (force_addr) {
-               i801_smba = force_addr & 0xfff0;
-       } else {
-               pci_read_config_word(I801_dev, SMBBA, &i801_smba);
-               i801_smba &= 0xfff0;
-               if(i801_smba == 0) {
-                       dev_err(&dev->dev, "SMB base address uninitialized"
-                               "- upgrade BIOS or use force_addr=0xaddr\n");
-                       return -ENODEV;
-               }
-       }
-
-       if (!request_region(i801_smba, (isich4 ? 16 : 8), "i801-smbus")) {
-               dev_err(&dev->dev, "I801_smb region 0x%x already in use!\n",
-                       i801_smba);
-               error_return = -EBUSY;
-               goto END;
-       }
-
-       pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
-       temp &= ~SMBHSTCFG_I2C_EN;      /* SMBus timing */
-       pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
-
-       /* If force_addr is set, we program the new address here. Just to make
-          sure, we disable the device first. */
-       if (force_addr) {
-               pci_write_config_byte(I801_dev, SMBHSTCFG, temp & 0xfe);
-               pci_write_config_word(I801_dev, SMBBA, i801_smba);
-               pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 0x01);
-               dev_warn(&dev->dev, "WARNING: I801 SMBus interface set to "
-                       "new address %04x!\n", i801_smba);
-       } else if ((temp & 1) == 0) {
-               pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 1);
-               dev_warn(&dev->dev, "enabling SMBus device\n");
-       }
-
-       if (temp & 0x02)
-               dev_dbg(&dev->dev, "I801 using Interrupt SMI# for SMBus.\n");
-       else
-               dev_dbg(&dev->dev, "I801 using PCI Interrupt for SMBus.\n");
-
-       pci_read_config_byte(I801_dev, SMBREV, &temp);
-       dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp);
-       dev_dbg(&dev->dev, "I801_smba = 0x%X\n", i801_smba);
-
-END:
-       return error_return;
-}
-
 static int i801_transaction(void)
 {
        int temp;
        int result = 0;
        int timeout = 0;
 
 static int i801_transaction(void)
 {
        int temp;
        int result = 0;
        int timeout = 0;
 
-       dev_dbg(&I801_dev->dev, "Transaction (pre): CNT=%02x, CMD=%02x,"
+       dev_dbg(&I801_dev->dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
                "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
                inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
                inb_p(SMBHSTDAT1));
                "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
                inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
                inb_p(SMBHSTDAT1));
@@ -193,7 +115,7 @@ static int i801_transaction(void)
        /* Make sure the SMBus host is ready to start transmitting */
        /* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
        if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
        /* Make sure the SMBus host is ready to start transmitting */
        /* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
        if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
-               dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting... \n",
+               dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting...\n",
                        temp);
                outb_p(temp, SMBHSTSTS);
                if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
                        temp);
                outb_p(temp, SMBHSTSTS);
                if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
@@ -239,7 +161,7 @@ static int i801_transaction(void)
                outb_p(inb(SMBHSTSTS), SMBHSTSTS);
 
        if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
                outb_p(inb(SMBHSTSTS), SMBHSTSTS);
 
        if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
-               dev_dbg(&I801_dev->dev, "Failed reset at end of transaction"
+               dev_dbg(&I801_dev->dev, "Failed reset at end of transaction "
                        "(%02x)\n", temp);
        }
        dev_dbg(&I801_dev->dev, "Transaction (post): CNT=%02x, CMD=%02x, "
                        "(%02x)\n", temp);
        }
        dev_dbg(&I801_dev->dev, "Transaction (post): CNT=%02x, CMD=%02x, "
@@ -251,7 +173,7 @@ static int i801_transaction(void)
 
 /* All-inclusive block transaction function */
 static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
 
 /* All-inclusive block transaction function */
 static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
-                                 int command)
+                                 int command, int hwpec)
 {
        int i, len;
        int smbcmd;
 {
        int i, len;
        int smbcmd;
@@ -314,7 +236,7 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
                }
                if (temp & errmask) {
                        dev_dbg(&I801_dev->dev, "SMBus busy (%02x). "
                }
                if (temp & errmask) {
                        dev_dbg(&I801_dev->dev, "SMBus busy (%02x). "
-                               "Resetting... \n", temp);
+                               "Resetting...\n", temp);
                        outb_p(temp, SMBHSTSTS);
                        if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
                                dev_err(&I801_dev->dev,
                        outb_p(temp, SMBHSTSTS);
                        if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
                                dev_err(&I801_dev->dev,
@@ -335,8 +257,8 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
                /* We will always wait for a fraction of a second! */
                timeout = 0;
                do {
                /* We will always wait for a fraction of a second! */
                timeout = 0;
                do {
-                       temp = inb_p(SMBHSTSTS);
                        msleep(1);
                        msleep(1);
+                       temp = inb_p(SMBHSTSTS);
                }
                    while ((!(temp & 0x80))
                           && (timeout++ < MAX_TIMEOUT));
                }
                    while ((!(temp & 0x80))
                           && (timeout++ < MAX_TIMEOUT));
@@ -390,13 +312,12 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
                        goto END;
        }
 
                        goto END;
        }
 
-#ifdef HAVE_PEC
-       if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) {
+       if (hwpec) {
                /* wait for INTR bit as advised by Intel */
                timeout = 0;
                do {
                /* wait for INTR bit as advised by Intel */
                timeout = 0;
                do {
-                       temp = inb_p(SMBHSTSTS);
                        msleep(1);
                        msleep(1);
+                       temp = inb_p(SMBHSTSTS);
                } while ((!(temp & 0x02))
                           && (timeout++ < MAX_TIMEOUT));
 
                } while ((!(temp & 0x02))
                           && (timeout++ < MAX_TIMEOUT));
 
@@ -405,7 +326,6 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
                }
                outb_p(temp, SMBHSTSTS); 
        }
                }
                outb_p(temp, SMBHSTSTS); 
        }
-#endif
        result = 0;
 END:
        if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
        result = 0;
 END:
        if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
@@ -420,14 +340,13 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
                       unsigned short flags, char read_write, u8 command,
                       int size, union i2c_smbus_data * data)
 {
                       unsigned short flags, char read_write, u8 command,
                       int size, union i2c_smbus_data * data)
 {
-       int hwpec = 0;
+       int hwpec;
        int block = 0;
        int ret, xact = 0;
 
        int block = 0;
        int ret, xact = 0;
 
-#ifdef HAVE_PEC
-       if(isich4)
-               hwpec = (flags & I2C_CLIENT_PEC) != 0;
-#endif
+       hwpec = isich4 && (flags & I2C_CLIENT_PEC)
+               && size != I2C_SMBUS_QUICK
+               && size != I2C_SMBUS_I2C_BLOCK_DATA;
 
        switch (size) {
        case I2C_SMBUS_QUICK:
 
        switch (size) {
        case I2C_SMBUS_QUICK:
@@ -462,11 +381,6 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
                break;
        case I2C_SMBUS_BLOCK_DATA:
        case I2C_SMBUS_I2C_BLOCK_DATA:
                break;
        case I2C_SMBUS_BLOCK_DATA:
        case I2C_SMBUS_I2C_BLOCK_DATA:
-#ifdef HAVE_PEC
-       case I2C_SMBUS_BLOCK_DATA_PEC:
-               if(hwpec && size == I2C_SMBUS_BLOCK_DATA)
-                       size = I2C_SMBUS_BLOCK_DATA_PEC;
-#endif
                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
                       SMBHSTADD);
                outb_p(command, SMBHSTCMD);
                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
                       SMBHSTADD);
                outb_p(command, SMBHSTCMD);
@@ -478,27 +392,19 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
                return -1;
        }
 
                return -1;
        }
 
-#ifdef HAVE_PEC
-       if(isich4 && hwpec) {
-               if(size != I2C_SMBUS_QUICK &&
-                  size != I2C_SMBUS_I2C_BLOCK_DATA)
-                       outb_p(1, SMBAUXCTL);   /* enable HW PEC */
-       }
-#endif
+       outb_p(hwpec, SMBAUXCTL);       /* enable/disable hardware PEC */
+
        if(block)
        if(block)
-               ret = i801_block_transaction(data, read_write, size);
+               ret = i801_block_transaction(data, read_write, size, hwpec);
        else {
                outb_p(xact | ENABLE_INT9, SMBHSTCNT);
                ret = i801_transaction();
        }
 
        else {
                outb_p(xact | ENABLE_INT9, SMBHSTCNT);
                ret = i801_transaction();
        }
 
-#ifdef HAVE_PEC
-       if(isich4 && hwpec) {
-               if(size != I2C_SMBUS_QUICK &&
-                  size != I2C_SMBUS_I2C_BLOCK_DATA)
-                       outb_p(0, SMBAUXCTL);
-       }
-#endif
+       /* Some BIOSes don't like it when PEC is enabled at reboot or resume
+          time, so we forcibly disable it after every transaction. */
+       if (hwpec)
+               outb_p(0, SMBAUXCTL);
 
        if(block)
                return ret;
 
        if(block)
                return ret;
@@ -525,17 +431,10 @@ static u32 i801_func(struct i2c_adapter *adapter)
        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_WRITE_I2C_BLOCK
        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_WRITE_I2C_BLOCK
-#ifdef HAVE_PEC
-            | (isich4 ? I2C_FUNC_SMBUS_BLOCK_DATA_PEC |
-                        I2C_FUNC_SMBUS_HWPEC_CALC
-                      : 0)
-#endif
-           ;
+            | (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0);
 }
 
 static struct i2c_algorithm smbus_algorithm = {
 }
 
 static struct i2c_algorithm smbus_algorithm = {
-       .name           = "Non-I2C SMBus adapter",
-       .id             = I2C_ALGO_SMBUS,
        .smbus_xfer     = i801_access,
        .functionality  = i801_func,
 };
        .smbus_xfer     = i801_access,
        .functionality  = i801_func,
 };
@@ -544,86 +443,105 @@ static struct i2c_adapter i801_adapter = {
        .owner          = THIS_MODULE,
        .class          = I2C_CLASS_HWMON,
        .algo           = &smbus_algorithm,
        .owner          = THIS_MODULE,
        .class          = I2C_CLASS_HWMON,
        .algo           = &smbus_algorithm,
-       .name           = "unset",
 };
 
 static struct pci_device_id i801_ids[] = {
 };
 
 static struct pci_device_id i801_ids[] = {
-       {
-               .vendor =       PCI_VENDOR_ID_INTEL,
-               .device =       PCI_DEVICE_ID_INTEL_82801AA_3,
-               .subvendor =    PCI_ANY_ID,
-               .subdevice =    PCI_ANY_ID,
-       },
-       {
-               .vendor =       PCI_VENDOR_ID_INTEL,
-               .device =       PCI_DEVICE_ID_INTEL_82801AB_3,
-               .subvendor =    PCI_ANY_ID,
-               .subdevice =    PCI_ANY_ID,
-       },
-       {
-               .vendor =       PCI_VENDOR_ID_INTEL,
-               .device =       PCI_DEVICE_ID_INTEL_82801BA_2,
-               .subvendor =    PCI_ANY_ID,
-               .subdevice =    PCI_ANY_ID,
-       },
-       {
-               .vendor =       PCI_VENDOR_ID_INTEL,
-               .device =       PCI_DEVICE_ID_INTEL_82801CA_3,
-               .subvendor =    PCI_ANY_ID,
-               .subdevice =    PCI_ANY_ID,
-       },
-       {
-               .vendor =       PCI_VENDOR_ID_INTEL,
-               .device =       PCI_DEVICE_ID_INTEL_82801DB_3,
-               .subvendor =    PCI_ANY_ID,
-               .subdevice =    PCI_ANY_ID,
-       },
-       {
-               .vendor =       PCI_VENDOR_ID_INTEL,
-               .device =       PCI_DEVICE_ID_INTEL_82801EB_3,
-               .subvendor =    PCI_ANY_ID,
-               .subdevice =    PCI_ANY_ID,
-       },
-       {
-               .vendor =       PCI_VENDOR_ID_INTEL,
-               .device =       PCI_DEVICE_ID_INTEL_ESB_4,
-               .subvendor =    PCI_ANY_ID,
-               .subdevice =    PCI_ANY_ID,
-       },
-       {
-               .vendor =       PCI_VENDOR_ID_INTEL,
-               .device =       PCI_DEVICE_ID_INTEL_ICH6_16,
-               .subvendor =    PCI_ANY_ID,
-               .subdevice =    PCI_ANY_ID,
-       },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_3) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_3) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_3) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_4) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_16) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) },
        { 0, }
 };
 
        { 0, }
 };
 
+MODULE_DEVICE_TABLE (pci, i801_ids);
+
 static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
 static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
+       unsigned char temp;
+       int err;
+
+       I801_dev = dev;
+       if ((dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) ||
+           (dev->device == PCI_DEVICE_ID_INTEL_82801EB_3) ||
+           (dev->device == PCI_DEVICE_ID_INTEL_ESB_4))
+               isich4 = 1;
+       else
+               isich4 = 0;
+
+       err = pci_enable_device(dev);
+       if (err) {
+               dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n",
+                       err);
+               goto exit;
+       }
+
+       /* Determine the address of the SMBus area */
+       i801_smba = pci_resource_start(dev, SMBBAR);
+       if (!i801_smba) {
+               dev_err(&dev->dev, "SMBus base address uninitialized, "
+                       "upgrade BIOS\n");
+               err = -ENODEV;
+               goto exit;
+       }
+
+       err = pci_request_region(dev, SMBBAR, i801_driver.name);
+       if (err) {
+               dev_err(&dev->dev, "Failed to request SMBus region "
+                       "0x%lx-0x%Lx\n", i801_smba,
+                       (unsigned long long)pci_resource_end(dev, SMBBAR));
+               goto exit;
+       }
 
 
-       if (i801_setup(dev)) {
-               dev_warn(&dev->dev,
-                       "I801 not detected, module not inserted.\n");
-               return -ENODEV;
+       pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
+       temp &= ~SMBHSTCFG_I2C_EN;      /* SMBus timing */
+       if (!(temp & SMBHSTCFG_HST_EN)) {
+               dev_info(&dev->dev, "Enabling SMBus device\n");
+               temp |= SMBHSTCFG_HST_EN;
        }
        }
+       pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
+
+       if (temp & SMBHSTCFG_SMB_SMI_EN)
+               dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
+       else
+               dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
 
        /* set up the driverfs linkage to our parent device */
        i801_adapter.dev.parent = &dev->dev;
 
        snprintf(i801_adapter.name, I2C_NAME_SIZE,
 
        /* set up the driverfs linkage to our parent device */
        i801_adapter.dev.parent = &dev->dev;
 
        snprintf(i801_adapter.name, I2C_NAME_SIZE,
-               "SMBus I801 adapter at %04x", i801_smba);
-       return i2c_add_adapter(&i801_adapter);
+               "SMBus I801 adapter at %04lx", i801_smba);
+       err = i2c_add_adapter(&i801_adapter);
+       if (err) {
+               dev_err(&dev->dev, "Failed to add SMBus adapter\n");
+               goto exit_release;
+       }
+       return 0;
+
+exit_release:
+       pci_release_region(dev, SMBBAR);
+exit:
+       return err;
 }
 
 static void __devexit i801_remove(struct pci_dev *dev)
 {
        i2c_del_adapter(&i801_adapter);
 }
 
 static void __devexit i801_remove(struct pci_dev *dev)
 {
        i2c_del_adapter(&i801_adapter);
-       release_region(i801_smba, (isich4 ? 16 : 8));
+       pci_release_region(dev, SMBBAR);
+       /*
+        * do not call pci_disable_device(dev) since it can cause hard hangs on
+        * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
+        */
 }
 
 static struct pci_driver i801_driver = {
 }
 
 static struct pci_driver i801_driver = {
-       .name           = "i801 smbus",
+       .name           = "i801_smbus",
        .id_table       = i801_ids,
        .probe          = i801_probe,
        .remove         = __devexit_p(i801_remove),
        .id_table       = i801_ids,
        .probe          = i801_probe,
        .remove         = __devexit_p(i801_remove),
@@ -631,7 +549,7 @@ static struct pci_driver i801_driver = {
 
 static int __init i2c_i801_init(void)
 {
 
 static int __init i2c_i801_init(void)
 {
-       return pci_module_init(&i801_driver);
+       return pci_register_driver(&i801_driver);
 }
 
 static void __exit i2c_i801_exit(void)
 }
 
 static void __exit i2c_i801_exit(void)