/* Detect whether a ALI1535 can be found, and initialize it, where necessary. NotethedifferencesbetweenkernelswiththeoldPCIBIOSinterfaceand newerkernelswiththerealPCIinterface.Incompat.hsomethingsare
defined to make the transition easier. */ staticint ali1535_setup(struct pci_dev *dev)
{ int retval; unsignedchar temp;
/* Check the following things: -SMBI/Oaddressisinitialized -Deviceisenabled -Wecanusetheaddresses
*/
/* Make sure the SMBus host is ready to start transmitting */ /* Check the busy bit first */ if (temp & ALI1535_STS_BUSY) { /* If the host controller is still busy, it may have timed out *intheprevioustransaction,resultingina"SMBusTimeout" *printk.I'vetriedthefollowingtoresetastuckbusybit. *1.ResetthecontrollerwithanKILLcommand.(this *doesn'tseemtoclearthecontrollerifanexternal *deviceishung) *2.ResetthecontrollerandtheotherSMBusdeviceswitha *T_OUTcommand.(thisclearsthehostbusybitifan *externaldeviceishung,butitcomesbackuponanew *accesstoadevice) *3.DisableandreenablethecontrollerinSMBHSTCFG.Worst *case,nothingseemstoworkexceptpowerreset.
*/
/* Try resetting entire SMB bus, including other devices - This *maynotworkeither-itclearstheBUSYbitbutthenthe *BUSYbitmaycomebackonwhenyoutryandusethechip *again.Ifthat'sthecaseyouarestuck.
*/
dev_info(&adap->dev, "Resetting entire SMB Bus to clear busy condition (%02x)\n",
temp);
outb_p(ALI1535_T_OUT, SMBHSTTYP);
temp = inb_p(SMBHSTSTS);
}
/* now check the error bits and the busy bit */ if (temp & (ALI1535_STS_ERR | ALI1535_STS_BUSY)) { /* do a clear-on-write */
outb_p(0xFF, SMBHSTSTS);
temp = inb_p(SMBHSTSTS); if (temp & (ALI1535_STS_ERR | ALI1535_STS_BUSY)) { /* This is probably going to be correctable only by a *powerresetasoneofthebitsnowappearstobe
* 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 & ALI1535_STS_DONE)
outb_p(temp, SMBHSTSTS);
}
/* start the transaction by writing anything to the start register */
outb_p(0xFF, SMBHSTPORT);
/* We will always wait for a fraction of a second! */
timeout = 0; do {
usleep_range(1000, 2000);
temp = inb_p(SMBHSTSTS);
} while (((temp & ALI1535_STS_BUSY) && !(temp & ALI1535_STS_IDLE))
&& (timeout++ < MAX_TIMEOUT));
/* If the SMBus is still busy, we give up */ if (timeout > MAX_TIMEOUT)
result = -ETIMEDOUT;
if (temp & ALI1535_STS_FAIL) {
result = -EIO;
dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
}
/* Unfortunately the ALI SMB controller maps "no response" and "bus *collision"intoasinglebit.Noresponseistheusualcasesodon't *doaprintk.Thismeansthatbuscollisionsgounreported.
*/ if (temp & ALI1535_STS_BUSERR) {
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 & ALI1535_STS_DEV) {
result = -EIO;
dev_err(&adap->dev, "Error: device error\n");
}
/* check to see if the "command complete" indication is set */ if (!(temp & ALI1535_STS_DONE))
result = -ETIMEDOUT;
/* take consequent actions for error conditions */ if (!(temp & ALI1535_STS_DONE)) { /* issue "kill" to reset host controller */
outb_p(ALI1535_KILL, SMBHSTTYP);
outb_p(0xFF, SMBHSTSTS);
} elseif (temp & ALI1535_STS_ERR) { /* issue "timeout" to reset all devices on bus */
outb_p(ALI1535_T_OUT, SMBHSTTYP);
outb_p(0xFF, SMBHSTSTS);
}
return result;
}
/* Return negative errno on error. */ static s32 ali1535_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;
s32 result = 0;
/* make sure SMBus is idle */
temp = inb_p(SMBHSTSTS); for (timeout = 0;
(timeout < MAX_TIMEOUT) && !(temp & ALI1535_STS_IDLE);
timeout++) {
usleep_range(1000, 2000);
temp = inb_p(SMBHSTSTS);
} if (timeout >= MAX_TIMEOUT)
dev_warn(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp);
/* clear status register (clear-on-write) */
outb_p(0xFF, SMBHSTSTS);
staticint ali1535_probe(struct pci_dev *dev, conststruct pci_device_id *id)
{ int ret;
if (ali1535_setup(dev)) {
dev_warn(&dev->dev, "ALI1535 not detected, module not inserted.\n"); return -ENODEV;
}
/* set up the sysfs linkage to our parent device */
ali1535_adapter.dev.parent = &dev->dev;
snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name), "SMBus ALI1535 adapter at %04x", ali1535_offset);
ret = i2c_add_adapter(&ali1535_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.