📄 i2c-ali1535.c
字号:
outb_p(0xFF, SMBHSTPORT); /* We will always wait for a fraction of a second! */ timeout = 0; do { msleep(1); 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 = -1; dev_err(&adap->dev, "SMBus Timeout!\n"); } if (temp & ALI1535_STS_FAIL) { 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 & ALI1535_STS_BUSERR) { 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 & ALI1535_STS_DEV) { result = -1; dev_err(&adap->dev, "Error: device error\n"); } /* check to see if the "command complete" indication is set */ if (!(temp & ALI1535_STS_DONE)) { result = -1; dev_err(&adap->dev, "Error: command never completed\n"); } dev_dbg(&adap->dev, "Transaction (post): STS=%02x, TYP=%02x, " "CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS), inb_p(SMBHSTTYP), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); /* 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); } else if (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 -1 on error. */static s32 ali1535_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; s32 result = 0; down(&i2c_ali1535_sem); /* make sure SMBus is idle */ temp = inb_p(SMBHSTSTS); for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & ALI1535_STS_IDLE); timeout++) { msleep(1); 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); switch (size) { case I2C_SMBUS_PROC_CALL: dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); result = -1; goto EXIT; case I2C_SMBUS_QUICK: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); size = ALI1535_QUICK; outb_p(size, SMBHSTTYP); /* output command */ break; case I2C_SMBUS_BYTE: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); size = ALI1535_BYTE; outb_p(size, SMBHSTTYP); /* output command */ if (read_write == I2C_SMBUS_WRITE) outb_p(command, SMBHSTCMD); break; case I2C_SMBUS_BYTE_DATA: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); size = ALI1535_BYTE_DATA; outb_p(size, SMBHSTTYP); /* output command */ outb_p(command, SMBHSTCMD); if (read_write == I2C_SMBUS_WRITE) outb_p(data->byte, SMBHSTDAT0); break; case I2C_SMBUS_WORD_DATA: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); size = ALI1535_WORD_DATA; outb_p(size, SMBHSTTYP); /* output command */ outb_p(command, SMBHSTCMD); if (read_write == I2C_SMBUS_WRITE) { outb_p(data->word & 0xff, SMBHSTDAT0); outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1); } break; case I2C_SMBUS_BLOCK_DATA: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); size = ALI1535_BLOCK_DATA; outb_p(size, SMBHSTTYP); /* output command */ 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(SMBHSTTYP) | ALI1535_BLOCK_CLR, SMBHSTTYP); for (i = 1; i <= len; i++) outb_p(data->block[i], SMBBLKDAT); } break; } if (ali1535_transaction(adap)) { /* Error in transaction */ result = -1; goto EXIT; } if ((read_write == I2C_SMBUS_WRITE) || (size == ALI1535_QUICK)) { result = 0; goto EXIT; } switch (size) { case ALI1535_BYTE: /* Result put in SMBHSTDAT0 */ data->byte = inb_p(SMBHSTDAT0); break; case ALI1535_BYTE_DATA: data->byte = inb_p(SMBHSTDAT0); break; case ALI1535_WORD_DATA: data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); break; case ALI1535_BLOCK_DATA: len = inb_p(SMBHSTDAT0); if (len > 32) len = 32; data->block[0] = len; /* Reset SMBBLKDAT */ outb_p(inb_p(SMBHSTTYP) | ALI1535_BLOCK_CLR, SMBHSTTYP); 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; }EXIT: up(&i2c_ali1535_sem); return result;}u32 ali1535_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 = ali1535_access, .functionality = ali1535_func,};static struct i2c_adapter ali1535_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, .name = "unset",};static struct pci_device_id ali1535_ids[] = { { .vendor = PCI_VENDOR_ID_AL, .device = PCI_DEVICE_ID_AL_M7101, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, { },};static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id){ if (ali1535_setup(dev)) { dev_warn(&dev->dev, "ALI1535 not detected, module not inserted.\n"); return -ENODEV; } /* set up the driverfs linkage to our parent device */ ali1535_adapter.dev.parent = &dev->dev; snprintf(ali1535_adapter.name, I2C_NAME_SIZE, "SMBus ALI1535 adapter at %04x", ali1535_smba); return i2c_add_adapter(&ali1535_adapter);}static void __devexit ali1535_remove(struct pci_dev *dev){ i2c_del_adapter(&ali1535_adapter); release_region(ali1535_smba, ALI1535_SMB_IOSIZE);}static struct pci_driver ali1535_driver = { .name = "ali1535_smbus", .id_table = ali1535_ids, .probe = ali1535_probe, .remove = __devexit_p(ali1535_remove),};static int __init i2c_ali1535_init(void){ return pci_module_init(&ali1535_driver);}static void __exit i2c_ali1535_exit(void){ pci_unregister_driver(&ali1535_driver);}MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, " "Philip Edelbrock <phil@netroedge.com>, " "Mark D. Studebaker <mdsxyz123@yahoo.com> " "and Dan Eaton <dan.eaton@rocketlogix.com>");MODULE_DESCRIPTION("ALI1535 SMBus driver");MODULE_LICENSE("GPL");module_init(i2c_ali1535_init);module_exit(i2c_ali1535_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -