/* Other settings */ #define MAX_TIMEOUT 200/* times 1/100 sec */ #define ALI15X3_SMB_IOSIZE 32
/* this is what the Award 1004 BIOS sets them to on a ASUS P5A MB. Wedon'tusethesehere.Ifthebasesaren'tsettosomevaluewe tellusertoupgradeBIOSandwefail.
*/ #define ALI15X3_SMB_DEFAULTBASE 0xE800
/* ALI15X3 status register bits */ #define ALI15X3_STS_IDLE 0x04 #define ALI15X3_STS_BUSY 0x08 #define ALI15X3_STS_DONE 0x10 #define ALI15X3_STS_DEV 0x20 /* device error */ #define ALI15X3_STS_COLL 0x40 /* collision or no response */ #define ALI15X3_STS_TERM 0x80 /* terminated by abort */ #define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */
/* If force_addr is set to anything different from 0, we forcibly enable
the device at the given address. */ static u16 force_addr;
module_param_hw(force_addr, ushort, ioport, 0);
MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller");
/* Make sure the SMBus host is ready to start transmitting */ /* Check the busy bit first */ if (temp & ALI15X3_STS_BUSY) { /* Ifthehostcontrollerisstillbusy,itmayhavetimedoutinthe previoustransaction,resultingina"SMBusTimeout"Dev. I'vetriedthefollowingtoresetastuckbusybit. 1.ResetthecontrollerwithanABORTcommand. (thisdoesn'tseemtoclearthecontrollerifanexternal deviceishung) 2.ResetthecontrollerandtheotherSMBusdeviceswitha T_OUTcommand.(thisclearsthehostbusybitifan externaldeviceishung,butitcomesbackuponanewaccess toadevice) 3.DisableandreenablethecontrollerinSMBHSTCFG Worstcase,nothingseemstoworkexceptpowerreset.
*/ /* Abort - reset the host controller */ /* TryresettingentireSMBbus,includingotherdevices- Thismaynotworkeither-itclearstheBUSYbitbut thentheBUSYbitmaycomebackonwhenyoutryandusethechipagain. Ifthat'sthecaseyouarestuck.
*/
dev_info(&adap->dev, "Resetting entire SMB Bus to " "clear busy condition (%02x)\n", temp);
outb_p(ALI15X3_T_OUT, SMBHSTCNT);
temp = inb_p(SMBHSTSTS);
}
/* now check the error bits and the busy bit */ if (temp & (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) { /* do a clear-on-write */
outb_p(0xFF, SMBHSTSTS); if ((temp = inb_p(SMBHSTSTS)) &
(ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) { /* this is probably going to be correctable only by a power reset
as one of the bits now appears to be stuck */ /* This may be a bus or device with electrical problems. */
dev_err(&adap->dev, "SMBus reset failed! (0x%02x) - " "controller or device on bus is probably hung\n",
temp); return -EBUSY;
}
} else { /* check and clear done bit */ if (temp & ALI15X3_STS_DONE) {
outb_p(temp, SMBHSTSTS);
}
}
/* start the transaction by writing anything to the start register */
outb_p(0xFF, SMBHSTSTART);
/* We will always wait for a fraction of a second! */
timeout = 0; do {
msleep(1);
temp = inb_p(SMBHSTSTS);
} while ((!(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)))
&& (timeout++ < MAX_TIMEOUT));
/* If the SMBus is still busy, we give up */ if (timeout > MAX_TIMEOUT)
result = -ETIMEDOUT;
if (temp & ALI15X3_STS_TERM) {
result = -EIO;
dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
}
/* UnfortunatelytheALISMBcontrollermaps"noresponse"and"bus collision"intoasinglebit.Noresponseistheusualcasesodon't doaprintk. Thismeansthatbuscollisionsgounreported.
*/ if (temp & ALI15X3_STS_COLL) {
result = -ENXIO;
dev_dbg(&adap->dev, "Error: no response or bus collision ADD=%02x\n",
inb_p(SMBHSTADD));
}
/* haven't ever seen this */ if (temp & ALI15X3_STS_DEV) {
result = -EIO;
dev_err(&adap->dev, "Error: device error\n");
}
dev_dbg(&adap->dev, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, " "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); return result;
}
/* Return negative errno on error. */ static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr, unsignedshort flags, char read_write, u8 command, int size, union i2c_smbus_data * data)
{ int i, len; int temp; int timeout;
/* clear all the bits (clear-on-write) */
outb_p(0xFF, SMBHSTSTS); /* make sure SMBus is idle */
temp = inb_p(SMBHSTSTS); for (timeout = 0;
(timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE);
timeout++) {
msleep(1);
temp = inb_p(SMBHSTSTS);
} if (timeout >= MAX_TIMEOUT) {
dev_err(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp);
}
staticint ali15x3_probe(struct pci_dev *dev, conststruct pci_device_id *id)
{ int ret;
if (ali15x3_setup(dev)) {
dev_err(&dev->dev, "ALI15X3 not detected, module not inserted.\n"); return -ENODEV;
}
/* set up the sysfs linkage to our parent device */
ali15x3_adapter.dev.parent = &dev->dev;
snprintf(ali15x3_adapter.name, sizeof(ali15x3_adapter.name), "SMBus ALI15X3 adapter at %04x", ali15x3_smba);
ret = i2c_add_adapter(&ali15x3_adapter); if (ret) goto release_region;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.