📄 i2c-ali15x3.c
字号:
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 -1; } } 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 = -1; dev_err(&adap->dev, "SMBus Timeout!\n"); } if (temp & ALI15X3_STS_TERM) { result = -1; dev_dbg(&adap->dev, "Error: Failed bus transaction\n"); } /* Unfortunately the ALI SMB controller maps "no response" and "bus collision" into a single bit. No reponse is the usual case so don't do a printk. This means that bus collisions go unreported. */ if (temp & ALI15X3_STS_COLL) { result = -1; 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 = -1; 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 -1 on error. */static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr, unsigned short 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); } switch (size) { case I2C_SMBUS_PROC_CALL: dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); return -1; case I2C_SMBUS_QUICK: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); size = ALI15X3_QUICK; break; case I2C_SMBUS_BYTE: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); if (read_write == I2C_SMBUS_WRITE) outb_p(command, SMBHSTCMD); size = ALI15X3_BYTE; break; case I2C_SMBUS_BYTE_DATA: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); outb_p(command, SMBHSTCMD); if (read_write == I2C_SMBUS_WRITE) outb_p(data->byte, SMBHSTDAT0); size = ALI15X3_BYTE_DATA; break; case I2C_SMBUS_WORD_DATA: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); outb_p(command, SMBHSTCMD); if (read_write == I2C_SMBUS_WRITE) { outb_p(data->word & 0xff, SMBHSTDAT0); outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1); } size = ALI15X3_WORD_DATA; break; case I2C_SMBUS_BLOCK_DATA: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); outb_p(command, SMBHSTCMD); if (read_write == I2C_SMBUS_WRITE) { len = data->block[0]; if (len < 0) { len = 0; data->block[0] = len; } if (len > 32) { len = 32; data->block[0] = len; } outb_p(len, SMBHSTDAT0); /* Reset SMBBLKDAT */ outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); for (i = 1; i <= len; i++) outb_p(data->block[i], SMBBLKDAT); } size = ALI15X3_BLOCK_DATA; break; } outb_p(size, SMBHSTCNT); /* output command */ if (ali15x3_transaction(adap)) /* Error in transaction */ return -1; if ((read_write == I2C_SMBUS_WRITE) || (size == ALI15X3_QUICK)) return 0; switch (size) { case ALI15X3_BYTE: /* Result put in SMBHSTDAT0 */ data->byte = inb_p(SMBHSTDAT0); break; case ALI15X3_BYTE_DATA: data->byte = inb_p(SMBHSTDAT0); break; case ALI15X3_WORD_DATA: data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); break; case ALI15X3_BLOCK_DATA: len = inb_p(SMBHSTDAT0); if (len > 32) len = 32; data->block[0] = len; /* Reset SMBBLKDAT */ outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); for (i = 1; i <= data->block[0]; i++) { data->block[i] = inb_p(SMBBLKDAT); dev_dbg(&adap->dev, "Blk: len=%d, i=%d, data=%02x\n", len, i, data->block[i]); } break; } return 0;}static u32 ali15x3_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;}static struct i2c_algorithm smbus_algorithm = { .name = "Non-I2C SMBus adapter", .id = I2C_ALGO_SMBUS, .smbus_xfer = ali15x3_access, .functionality = ali15x3_func,};static struct i2c_adapter ali15x3_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, .name = "unset",};static struct pci_device_id ali15x3_ids[] = { { .vendor = PCI_VENDOR_ID_AL, .device = PCI_DEVICE_ID_AL_M7101, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, { 0, }};static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id){ if (ali15x3_setup(dev)) { dev_err(&dev->dev, "ALI15X3 not detected, module not inserted.\n"); return -ENODEV; } /* set up the driverfs linkage to our parent device */ ali15x3_adapter.dev.parent = &dev->dev; snprintf(ali15x3_adapter.name, I2C_NAME_SIZE, "SMBus ALI15X3 adapter at %04x", ali15x3_smba); return i2c_add_adapter(&ali15x3_adapter);}static void __devexit ali15x3_remove(struct pci_dev *dev){ i2c_del_adapter(&ali15x3_adapter); release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);}static struct pci_driver ali15x3_driver = { .name = "ali15x3 smbus", .id_table = ali15x3_ids, .probe = ali15x3_probe, .remove = __devexit_p(ali15x3_remove),};static int __init i2c_ali15x3_init(void){ return pci_module_init(&ali15x3_driver);}static void __exit i2c_ali15x3_exit(void){ pci_unregister_driver(&ali15x3_driver);}MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, " "Philip Edelbrock <phil@netroedge.com>, " "and Mark D. Studebaker <mdsxyz123@yahoo.com>");MODULE_DESCRIPTION("ALI15X3 SMBus driver");MODULE_LICENSE("GPL");module_init(i2c_ali15x3_init);module_exit(i2c_ali15x3_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -