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.
/* 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/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)
/* 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");
+static u16 force_addr;
+module_param(force_addr, ushort, 0);
MODULE_PARM_DESC(force_addr,
"Forcibly enable the I801 at the given address. "
"EXTREMELY DANGEROUS!");
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 struct pci_driver i801_driver;
static struct pci_dev *I801_dev;
static int isich4;
pci_read_config_word(I801_dev, SMBBA, &i801_smba);
i801_smba &= 0xfff0;
if(i801_smba == 0) {
- dev_err(&dev->dev, "SMB base address uninitialized"
+ 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")) {
+ if (!request_region(i801_smba, (isich4 ? 16 : 8), i801_driver.name)) {
dev_err(&dev->dev, "I801_smb region 0x%x already in use!\n",
i801_smba);
error_return = -EBUSY;
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));
/* 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) {
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, "
/* 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;
}
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,
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 {
}
outb_p(temp, SMBHSTSTS);
}
-#endif
result = 0;
END:
if (command == I2C_SMBUS_I2C_BLOCK_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;
-#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:
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);
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)
- 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();
}
-#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;
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 = {
- .name = "Non-I2C SMBus adapter",
- .id = I2C_ALGO_SMBUS,
.smbus_xfer = i801_access,
.functionality = i801_func,
};
.owner = THIS_MODULE,
.class = I2C_CLASS_HWMON,
.algo = &smbus_algorithm,
- .name = "unset",
};
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, }
};
+MODULE_DEVICE_TABLE (pci, i801_ids);
+
static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
}
static struct pci_driver i801_driver = {
- .name = "i801 smbus",
+ .name = "i801_smbus",
.id_table = i801_ids,
.probe = i801_probe,
.remove = __devexit_p(i801_remove),
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)