mirror of
https://github.com/lm-sensors/lm-sensors
synced 2025-09-01 14:55:27 +00:00
backport from kernel 2.5.69. untested.
git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@1763 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
@@ -49,28 +49,12 @@
|
|||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "sensors_compat.h"
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
|
|
||||||
#ifdef I2C_FUNC_SMBUS_BLOCK_DATA_PEC
|
#ifdef I2C_FUNC_SMBUS_BLOCK_DATA_PEC
|
||||||
#define HAVE_PEC
|
#define HAVE_PEC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PCI_DEVICE_ID_INTEL_82801CA_SMBUS
|
|
||||||
#define PCI_DEVICE_ID_INTEL_82801CA_SMBUS 0x2483
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PCI_DEVICE_ID_INTEL_82801DB_SMBUS
|
|
||||||
#define PCI_DEVICE_ID_INTEL_82801DB_SMBUS 0x24C3
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int supported[] = {PCI_DEVICE_ID_INTEL_82801AA_3,
|
|
||||||
PCI_DEVICE_ID_INTEL_82801AB_3,
|
|
||||||
PCI_DEVICE_ID_INTEL_82801BA_2,
|
|
||||||
PCI_DEVICE_ID_INTEL_82801CA_SMBUS,
|
|
||||||
PCI_DEVICE_ID_INTEL_82801DB_SMBUS,
|
|
||||||
0 };
|
|
||||||
|
|
||||||
/* I801 SMBus address offsets */
|
/* I801 SMBus address offsets */
|
||||||
#define SMBHSTSTS (0 + i801_smba)
|
#define SMBHSTSTS (0 + i801_smba)
|
||||||
#define SMBHSTCNT (2 + i801_smba)
|
#define SMBHSTCNT (2 + i801_smba)
|
||||||
@@ -120,59 +104,29 @@ MODULE_PARM_DESC(force_addr,
|
|||||||
"Forcibly enable the I801 at the given address. "
|
"Forcibly enable the I801 at the given address. "
|
||||||
"EXTREMELY DANGEROUS!");
|
"EXTREMELY DANGEROUS!");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void i801_do_pause(unsigned int amount);
|
static void i801_do_pause(unsigned int amount);
|
||||||
static int i801_transaction(void);
|
static int i801_transaction(void);
|
||||||
static int i801_block_transaction(union i2c_smbus_data *data,
|
static int i801_block_transaction(union i2c_smbus_data *data,
|
||||||
char read_write, int command);
|
char read_write, int command);
|
||||||
|
|
||||||
|
static unsigned short i801_smba;
|
||||||
|
static struct pci_dev *I801_dev;
|
||||||
|
static int isich4;
|
||||||
|
|
||||||
|
static int i801_setup(struct pci_dev *dev)
|
||||||
|
|
||||||
static unsigned short i801_smba = 0;
|
|
||||||
static struct pci_dev *I801_dev = NULL;
|
|
||||||
static int isich4 = 0;
|
|
||||||
|
|
||||||
/* Detect whether a I801 can be found, and initialize it, where necessary.
|
|
||||||
Note the differences between kernels with the old PCI BIOS interface and
|
|
||||||
newer kernels with the real PCI interface. In compat.h some things are
|
|
||||||
defined to make the transition easier. */
|
|
||||||
int i801_setup(void)
|
|
||||||
{
|
{
|
||||||
int error_return = 0;
|
int error_return = 0;
|
||||||
int *num = supported;
|
|
||||||
unsigned char temp;
|
unsigned char temp;
|
||||||
|
|
||||||
/* First check whether we can access PCI at all */
|
|
||||||
if (pci_present() == 0) {
|
|
||||||
printk(KERN_WARNING "i2c-i801.o: Error: No PCI-bus found!\n");
|
|
||||||
error_return = -ENODEV;
|
|
||||||
goto END;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Look for each chip */
|
|
||||||
/* Note: we keep on searching until we have found 'function 3' */
|
/* Note: we keep on searching until we have found 'function 3' */
|
||||||
I801_dev = NULL;
|
if(PCI_FUNC(dev->devfn) != 3)
|
||||||
do {
|
return -ENODEV;
|
||||||
if((I801_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
|
|
||||||
*num, I801_dev))) {
|
|
||||||
if(PCI_FUNC(I801_dev->devfn) != 3)
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
num++;
|
|
||||||
} while (*num != 0);
|
|
||||||
|
|
||||||
if (I801_dev == NULL) {
|
I801_dev = dev;
|
||||||
printk
|
if (dev->device == PCI_DEVICE_ID_INTEL_82801DB_3)
|
||||||
(KERN_WARNING "i2c-i801.o: Error: Can't detect I801, function 3!\n");
|
isich4 = 1;
|
||||||
error_return = -ENODEV;
|
else
|
||||||
goto END;
|
isich4 = 0;
|
||||||
}
|
|
||||||
isich4 = *num == PCI_DEVICE_ID_INTEL_82801DB_SMBUS;
|
|
||||||
|
|
||||||
/* Determine the address of the SMBus areas */
|
/* Determine the address of the SMBus areas */
|
||||||
if (force_addr) {
|
if (force_addr) {
|
||||||
@@ -181,92 +135,78 @@ int i801_setup(void)
|
|||||||
pci_read_config_word(I801_dev, SMBBA, &i801_smba);
|
pci_read_config_word(I801_dev, SMBBA, &i801_smba);
|
||||||
i801_smba &= 0xfff0;
|
i801_smba &= 0xfff0;
|
||||||
if(i801_smba == 0) {
|
if(i801_smba == 0) {
|
||||||
printk(KERN_ERR "i2c-i801.o: SMB base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
|
dev_err(dev, "SMB base address uninitialized"
|
||||||
|
"- upgrade BIOS or use force_addr=0xaddr\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_region(i801_smba, (isich4 ? 16 : 8))) {
|
if (!request_region(i801_smba, (isich4 ? 16 : 8), "i801-smbus")) {
|
||||||
printk
|
dev_err(dev, "I801_smb region 0x%x already in use!\n",
|
||||||
(KERN_ERR "i2c-i801.o: I801_smb region 0x%x already in use!\n",
|
|
||||||
i801_smba);
|
i801_smba);
|
||||||
error_return = -ENODEV;
|
error_return = -EBUSY;
|
||||||
goto END;
|
goto END;
|
||||||
}
|
}
|
||||||
|
|
||||||
pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
|
pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
|
||||||
temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */
|
temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */
|
||||||
pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
|
pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
|
||||||
|
|
||||||
/* If force_addr is set, we program the new address here. Just to make
|
/* If force_addr is set, we program the new address here. Just to make
|
||||||
sure, we disable the device first. */
|
sure, we disable the device first. */
|
||||||
if (force_addr) {
|
if (force_addr) {
|
||||||
pci_write_config_byte(I801_dev, SMBHSTCFG, temp & 0xfe);
|
pci_write_config_byte(I801_dev, SMBHSTCFG, temp & 0xfe);
|
||||||
pci_write_config_word(I801_dev, SMBBA, i801_smba);
|
pci_write_config_word(I801_dev, SMBBA, i801_smba);
|
||||||
pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 0x01);
|
pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 0x01);
|
||||||
printk
|
dev_warn(dev, "WARNING: I801 SMBus interface set to "
|
||||||
(KERN_WARNING "i2c-i801.o: WARNING: I801 SMBus interface set to new "
|
"new address %04x!\n", i801_smba);
|
||||||
"address %04x!\n", i801_smba);
|
|
||||||
} else if ((temp & 1) == 0) {
|
} else if ((temp & 1) == 0) {
|
||||||
pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 1);
|
pci_write_config_byte(I801_dev, SMBHSTCFG, temp | 1);
|
||||||
printk(KERN_WARNING "i2c-i801.o: enabling SMBus device\n");
|
dev_warn(dev, "enabling SMBus device\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
request_region(i801_smba, (isich4 ? 16 : 8), "i801-smbus");
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
if (temp & 0x02)
|
if (temp & 0x02)
|
||||||
printk
|
dev_dbg(dev, "I801 using Interrupt SMI# for SMBus.\n");
|
||||||
(KERN_DEBUG "i2c-i801.o: I801 using Interrupt SMI# for SMBus.\n");
|
|
||||||
else
|
else
|
||||||
printk
|
dev_dbg(dev, "I801 using PCI Interrupt for SMBus.\n");
|
||||||
(KERN_DEBUG "i2c-i801.o: I801 using PCI Interrupt for SMBus.\n");
|
|
||||||
|
|
||||||
pci_read_config_byte(I801_dev, SMBREV, &temp);
|
pci_read_config_byte(I801_dev, SMBREV, &temp);
|
||||||
printk(KERN_DEBUG "i2c-i801.o: SMBREV = 0x%X\n", temp);
|
dev_dbg(dev, "SMBREV = 0x%X\n", temp);
|
||||||
printk(KERN_DEBUG "i2c-i801.o: I801_smba = 0x%X\n", i801_smba);
|
dev_dbg(dev, "I801_smba = 0x%X\n", i801_smba);
|
||||||
#endif /* DEBUG */
|
|
||||||
|
|
||||||
END:
|
END:
|
||||||
return error_return;
|
return error_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void i801_do_pause(unsigned int amount)
|
static void i801_do_pause(unsigned int amount)
|
||||||
{
|
{
|
||||||
current->state = TASK_INTERRUPTIBLE;
|
current->state = TASK_INTERRUPTIBLE;
|
||||||
schedule_timeout(amount);
|
schedule_timeout(amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
int i801_transaction(void)
|
static int i801_transaction(void)
|
||||||
{
|
{
|
||||||
int temp;
|
int temp;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int timeout = 0;
|
int timeout = 0;
|
||||||
|
|
||||||
#ifdef DEBUG
|
dev_dbg(I801_dev, "Transaction (pre): CNT=%02x, CMD=%02x,"
|
||||||
printk
|
"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
|
||||||
(KERN_DEBUG "i2c-i801.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
|
inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
|
||||||
"DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
|
inb_p(SMBHSTDAT1));
|
||||||
inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Make sure the SMBus host is ready to start transmitting */
|
/* Make sure the SMBus host is ready to start transmitting */
|
||||||
/* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
|
/* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
|
||||||
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
|
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
|
||||||
#ifdef DEBUG
|
dev_dbg(I801_dev, "SMBus busy (%02x). Resetting... \n",
|
||||||
printk(KERN_DEBUG "i2c-i801.o: SMBus busy (%02x). Resetting... \n",
|
|
||||||
temp);
|
temp);
|
||||||
#endif
|
|
||||||
outb_p(temp, SMBHSTSTS);
|
outb_p(temp, SMBHSTSTS);
|
||||||
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
|
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
|
||||||
#ifdef DEBUG
|
dev_dbg(I801_dev, "Failed! (%02x)\n", temp);
|
||||||
printk(KERN_DEBUG "i2c-i801.o: Failed! (%02x)\n", temp);
|
|
||||||
#endif
|
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
#ifdef DEBUG
|
dev_dbg(I801_dev, "Successfull!\n");
|
||||||
printk(KERN_DEBUG "i2c-i801.o: Successfull!\n");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,55 +220,43 @@ int i801_transaction(void)
|
|||||||
|
|
||||||
/* If the SMBus is still busy, we give up */
|
/* If the SMBus is still busy, we give up */
|
||||||
if (timeout >= MAX_TIMEOUT) {
|
if (timeout >= MAX_TIMEOUT) {
|
||||||
#ifdef DEBUG
|
dev_dbg(I801_dev, "SMBus Timeout!\n");
|
||||||
printk(KERN_DEBUG "i2c-i801.o: SMBus Timeout!\n");
|
|
||||||
result = -1;
|
result = -1;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (temp & 0x10) {
|
if (temp & 0x10) {
|
||||||
result = -1;
|
result = -1;
|
||||||
#ifdef DEBUG
|
dev_dbg(I801_dev, "Error: Failed bus transaction\n");
|
||||||
printk(KERN_DEBUG "i2c-i801.o: Error: Failed bus transaction\n");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (temp & 0x08) {
|
if (temp & 0x08) {
|
||||||
result = -1;
|
result = -1;
|
||||||
printk
|
dev_err(I801_dev, "Bus collision! SMBus may be locked "
|
||||||
(KERN_ERR "i2c-i801.o: Bus collision! SMBus may be locked until next hard\n"
|
"until next hard reset. (sorry!)\n");
|
||||||
"reset. (sorry!)\n");
|
|
||||||
/* Clock stops and slave is stuck in mid-transmission */
|
/* Clock stops and slave is stuck in mid-transmission */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (temp & 0x04) {
|
if (temp & 0x04) {
|
||||||
result = -1;
|
result = -1;
|
||||||
#ifdef DEBUG
|
dev_dbg(I801_dev, "Error: no response!\n");
|
||||||
printk(KERN_DEBUG "i2c-i801.o: Error: no response!\n");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00)
|
if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00)
|
||||||
outb_p(inb(SMBHSTSTS), SMBHSTSTS);
|
outb_p(inb(SMBHSTSTS), SMBHSTSTS);
|
||||||
|
|
||||||
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
|
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
|
||||||
#ifdef DEBUG
|
dev_dbg(I801_dev, "Failed reset at end of transaction"
|
||||||
printk
|
"(%02x)\n", temp);
|
||||||
(KERN_DEBUG "i2c-i801.o: Failed reset at end of transaction (%02x)\n",
|
|
||||||
temp);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
dev_dbg(I801_dev, "Transaction (post): CNT=%02x, CMD=%02x, "
|
||||||
printk
|
"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
|
||||||
(KERN_DEBUG "i2c-i801.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, "
|
inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
|
||||||
"DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
|
inb_p(SMBHSTDAT1));
|
||||||
inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
|
|
||||||
#endif
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All-inclusive block transaction function */
|
/* All-inclusive block transaction function */
|
||||||
int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
||||||
int command)
|
int command)
|
||||||
{
|
{
|
||||||
int i, len;
|
int i, len;
|
||||||
@@ -345,8 +273,8 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
|||||||
pci_write_config_byte(I801_dev, SMBHSTCFG,
|
pci_write_config_byte(I801_dev, SMBHSTCFG,
|
||||||
hostc | SMBHSTCFG_I2C_EN);
|
hostc | SMBHSTCFG_I2C_EN);
|
||||||
} else {
|
} else {
|
||||||
printk("i2c-i801.o: "
|
dev_err(I801_dev,
|
||||||
"I2C_SMBUS_I2C_BLOCK_READ not supported!\n");
|
"I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -372,19 +300,12 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
|||||||
smbcmd = I801_BLOCK_LAST;
|
smbcmd = I801_BLOCK_LAST;
|
||||||
else
|
else
|
||||||
smbcmd = I801_BLOCK_DATA;
|
smbcmd = I801_BLOCK_DATA;
|
||||||
#if 0 /* now using HW PEC */
|
|
||||||
if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC)
|
|
||||||
smbcmd |= I801_PEC_EN;
|
|
||||||
#endif
|
|
||||||
outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
|
outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
|
||||||
|
|
||||||
#ifdef DEBUG
|
dev_dbg(I801_dev, "Block (pre %d): CNT=%02x, CMD=%02x, "
|
||||||
printk
|
"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
|
||||||
(KERN_DEBUG "i2c-i801.o: Block (pre %d): CNT=%02x, CMD=%02x, ADD=%02x, "
|
inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
|
||||||
"DAT0=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT),
|
inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
|
||||||
inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
|
|
||||||
inb_p(SMBBLKDAT));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Make sure the SMBus host is ready to start transmitting */
|
/* Make sure the SMBus host is ready to start transmitting */
|
||||||
temp = inb_p(SMBHSTSTS);
|
temp = inb_p(SMBHSTSTS);
|
||||||
@@ -398,34 +319,24 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
|||||||
errmask=0x1e;
|
errmask=0x1e;
|
||||||
}
|
}
|
||||||
if (temp & errmask) {
|
if (temp & errmask) {
|
||||||
#ifdef DEBUG
|
dev_dbg(I801_dev, "SMBus busy (%02x). "
|
||||||
printk
|
"Resetting... \n", temp);
|
||||||
(KERN_DEBUG "i2c-i801.o: SMBus busy (%02x). Resetting... \n",
|
|
||||||
temp);
|
|
||||||
#endif
|
|
||||||
outb_p(temp, SMBHSTSTS);
|
outb_p(temp, SMBHSTSTS);
|
||||||
if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
|
if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
|
||||||
printk
|
dev_err(I801_dev,
|
||||||
(KERN_ERR "i2c-i801.o: Reset failed! (%02x)\n",
|
"Reset failed! (%02x)\n", temp);
|
||||||
temp);
|
|
||||||
result = -1;
|
result = -1;
|
||||||
goto END;
|
goto END;
|
||||||
}
|
}
|
||||||
if (i != 1) {
|
if (i != 1) {
|
||||||
result = -1; /* if die in middle of block transaction, fail */
|
/* if die in middle of block transaction, fail */
|
||||||
|
result = -1;
|
||||||
goto END;
|
goto END;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == 1) {
|
if (i == 1)
|
||||||
#if 0 /* #ifdef HAVE_PEC (now using HW PEC) */
|
|
||||||
if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) {
|
|
||||||
if(read_write == I2C_SMBUS_WRITE)
|
|
||||||
outb_p(data->block[len + 1], SMBPEC);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
|
outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
|
||||||
}
|
|
||||||
|
|
||||||
/* We will always wait for a fraction of a second! */
|
/* We will always wait for a fraction of a second! */
|
||||||
timeout = 0;
|
timeout = 0;
|
||||||
@@ -439,25 +350,19 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
|||||||
/* If the SMBus is still busy, we give up */
|
/* If the SMBus is still busy, we give up */
|
||||||
if (timeout >= MAX_TIMEOUT) {
|
if (timeout >= MAX_TIMEOUT) {
|
||||||
result = -1;
|
result = -1;
|
||||||
#ifdef DEBUG
|
dev_dbg(I801_dev, "SMBus Timeout!\n");
|
||||||
printk(KERN_DEBUG "i2c-i801.o: SMBus Timeout!\n");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (temp & 0x10) {
|
if (temp & 0x10) {
|
||||||
result = -1;
|
result = -1;
|
||||||
#ifdef DEBUG
|
dev_dbg(I801_dev,
|
||||||
printk
|
"Error: Failed bus transaction\n");
|
||||||
(KERN_DEBUG "i2c-i801.o: Error: Failed bus transaction\n");
|
|
||||||
#endif
|
|
||||||
} else if (temp & 0x08) {
|
} else if (temp & 0x08) {
|
||||||
result = -1;
|
result = -1;
|
||||||
printk(KERN_ERR "i2c-i801.o: Bus collision!\n");
|
dev_err(I801_dev, "Bus collision!\n");
|
||||||
} else if (temp & 0x04) {
|
} else if (temp & 0x04) {
|
||||||
result = -1;
|
result = -1;
|
||||||
#ifdef DEBUG
|
dev_dbg(I801_dev, "Error: no response!\n");
|
||||||
printk(KERN_DEBUG "i2c-i801.o: Error: no response!\n");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == 1 && read_write == I2C_SMBUS_READ) {
|
if (i == 1 && read_write == I2C_SMBUS_READ) {
|
||||||
@@ -477,18 +382,15 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
|||||||
if ((temp & 0x9e) != 0x00)
|
if ((temp & 0x9e) != 0x00)
|
||||||
outb_p(temp, SMBHSTSTS); /* signals SMBBLKDAT ready */
|
outb_p(temp, SMBHSTSTS); /* signals SMBBLKDAT ready */
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
if ((temp = (0x1e & inb_p(SMBHSTSTS))) != 0x00) {
|
if ((temp = (0x1e & inb_p(SMBHSTSTS))) != 0x00) {
|
||||||
printk
|
dev_dbg(I801_dev,
|
||||||
(KERN_DEBUG "i2c-i801.o: Bad status (%02x) at end of transaction\n",
|
"Bad status (%02x) at end of transaction\n",
|
||||||
temp);
|
temp);
|
||||||
}
|
}
|
||||||
printk
|
dev_dbg(I801_dev, "Block (post %d): CNT=%02x, CMD=%02x, "
|
||||||
(KERN_DEBUG "i2c-i801.o: Block (post %d): CNT=%02x, CMD=%02x, ADD=%02x, "
|
"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
|
||||||
"DAT0=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT),
|
inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
|
||||||
inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
|
inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
|
||||||
inb_p(SMBBLKDAT));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
goto END;
|
goto END;
|
||||||
@@ -505,13 +407,8 @@ int i801_block_transaction(union i2c_smbus_data *data, char read_write,
|
|||||||
&& (timeout++ < MAX_TIMEOUT));
|
&& (timeout++ < MAX_TIMEOUT));
|
||||||
|
|
||||||
if (timeout >= MAX_TIMEOUT) {
|
if (timeout >= MAX_TIMEOUT) {
|
||||||
printk(KERN_DEBUG "i2c-i801.o: PEC Timeout!\n");
|
dev_dbg(I801_dev, "PEC Timeout!\n");
|
||||||
}
|
}
|
||||||
#if 0 /* now using HW PEC */
|
|
||||||
if(read_write == I2C_SMBUS_READ) {
|
|
||||||
data->block[len + 1] = inb_p(SMBPEC);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
outb_p(temp, SMBHSTSTS);
|
outb_p(temp, SMBHSTSTS);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -525,9 +422,9 @@ END:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Return -1 on error. */
|
/* Return -1 on error. */
|
||||||
s32 i801_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
|
static s32 i801_access(struct i2c_adapter * adap, u16 addr,
|
||||||
char read_write, u8 command, int size,
|
unsigned short flags, char read_write, u8 command,
|
||||||
union i2c_smbus_data * data)
|
int size, union i2c_smbus_data * data)
|
||||||
{
|
{
|
||||||
int hwpec = 0;
|
int hwpec = 0;
|
||||||
int block = 0;
|
int block = 0;
|
||||||
@@ -583,7 +480,7 @@ s32 i801_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
|
|||||||
break;
|
break;
|
||||||
case I2C_SMBUS_PROC_CALL:
|
case I2C_SMBUS_PROC_CALL:
|
||||||
default:
|
default:
|
||||||
printk(KERN_ERR "i2c-i801.o: Unsupported transaction %d\n", size);
|
dev_err(I801_dev, "Unsupported transaction %d\n", size);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -629,7 +526,7 @@ s32 i801_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
u32 i801_func(struct i2c_adapter *adapter)
|
static u32 i801_func(struct i2c_adapter *adapter)
|
||||||
{
|
{
|
||||||
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
|
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
|
||||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
|
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
|
||||||
@@ -651,29 +548,57 @@ static struct i2c_algorithm smbus_algorithm = {
|
|||||||
|
|
||||||
static struct i2c_adapter i801_adapter = {
|
static struct i2c_adapter i801_adapter = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = "unset",
|
|
||||||
.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_I801,
|
.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_I801,
|
||||||
.algo = &smbus_algorithm,
|
.algo = &smbus_algorithm,
|
||||||
|
.name = "unset",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static struct pci_device_id i801_ids[] __devinitdata = {
|
static struct pci_device_id i801_ids[] __devinitdata = {
|
||||||
|
{
|
||||||
|
.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,
|
||||||
|
},
|
||||||
{ 0, }
|
{ 0, }
|
||||||
};
|
};
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (i801_setup()) {
|
if (i801_setup(dev)) {
|
||||||
printk
|
dev_warn(dev,
|
||||||
(KERN_WARNING "i2c-i801.o: I801 not detected, module not inserted.\n");
|
"I801 not detected, module not inserted.\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(i801_adapter.name, "SMBus I801 adapter at %04x",
|
snprintf(i801_adapter.name, 32,
|
||||||
i801_smba);
|
"SMBus I801 adapter at %04x", i801_smba);
|
||||||
i2c_add_adapter(&i801_adapter);
|
return i2c_add_adapter(&i801_adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __devexit i801_remove(struct pci_dev *dev)
|
static void __devexit i801_remove(struct pci_dev *dev)
|
||||||
@@ -690,22 +615,21 @@ static struct pci_driver i801_driver = {
|
|||||||
|
|
||||||
static int __init i2c_i801_init(void)
|
static int __init i2c_i801_init(void)
|
||||||
{
|
{
|
||||||
printk(KERN_INFO "i2c-i801.o version %s (%s)\n", LM_VERSION, LM_DATE);
|
printk(KERN_INFO "i2c-i801 version %s (%s)\n", LM_VERSION, LM_DATE);
|
||||||
return pci_module_init(&i801_driver);
|
return pci_module_init(&i801_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void __exit i2c_i801_exit(void)
|
static void __exit i2c_i801_exit(void)
|
||||||
{
|
{
|
||||||
pci_unregister_driver(&i801_driver);
|
pci_unregister_driver(&i801_driver);
|
||||||
release_region(i801_smba, (isich4 ? 16 : 8));
|
release_region(i801_smba, (isich4 ? 16 : 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
|
||||||
|
"Philip Edelbrock <phil@netroedge.com>, "
|
||||||
MODULE_AUTHOR
|
"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
|
||||||
("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker <mdsxyz123@yahoo.com>");
|
|
||||||
MODULE_DESCRIPTION("I801 SMBus driver");
|
MODULE_DESCRIPTION("I801 SMBus driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
module_init(i2c_i801_init);
|
module_init(i2c_i801_init);
|
||||||
module_exit(i2c_i801_exit);
|
module_exit(i2c_i801_exit);
|
||||||
|
Reference in New Issue
Block a user