📄 i2c-i801.c
字号:
/* if die in middle of block transaction, fail */ result = -1; goto END; } } if (i == 1) outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT); /* We will always wait for a fraction of a second! */ timeout = 0; do { temp = inb_p(SMBHSTSTS); msleep(1); } while ((!(temp & 0x80)) && (timeout++ < MAX_TIMEOUT)); /* If the SMBus is still busy, we give up */ if (timeout >= MAX_TIMEOUT) { result = -1; dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); } if (temp & 0x10) { result = -1; dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n"); } else if (temp & 0x08) { result = -1; dev_err(&I801_dev->dev, "Bus collision!\n"); } else if (temp & 0x04) { result = -1; dev_dbg(&I801_dev->dev, "Error: no response!\n"); } if (i == 1 && read_write == I2C_SMBUS_READ) { len = inb_p(SMBHSTDAT0); if (len < 1) len = 1; if (len > 32) len = 32; data->block[0] = len; } /* Retrieve/store value in SMBBLKDAT */ if (read_write == I2C_SMBUS_READ) data->block[i] = inb_p(SMBBLKDAT); if (read_write == I2C_SMBUS_WRITE && i+1 <= len) outb_p(data->block[i+1], SMBBLKDAT); if ((temp & 0x9e) != 0x00) outb_p(temp, SMBHSTSTS); /* signals SMBBLKDAT ready */ if ((temp = (0x1e & inb_p(SMBHSTSTS))) != 0x00) { dev_dbg(&I801_dev->dev, "Bad status (%02x) at end of transaction\n", temp); } dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, " "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); if (result < 0) goto END; }#ifdef HAVE_PEC if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) { /* wait for INTR bit as advised by Intel */ timeout = 0; do { temp = inb_p(SMBHSTSTS); msleep(1); } while ((!(temp & 0x02)) && (timeout++ < MAX_TIMEOUT)); if (timeout >= MAX_TIMEOUT) { dev_dbg(&I801_dev->dev, "PEC Timeout!\n"); } outb_p(temp, SMBHSTSTS); }#endif result = 0;END: if (command == I2C_SMBUS_I2C_BLOCK_DATA) { /* restore saved configuration register value */ pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); } return result;}/* Return -1 on error. */static s32 i801_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data){ int hwpec = 0; int block = 0; int ret, xact = 0;#ifdef HAVE_PEC if(isich4) hwpec = (flags & I2C_CLIENT_PEC) != 0;#endif switch (size) { case I2C_SMBUS_QUICK: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); xact = I801_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); xact = I801_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); xact = I801_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); } xact = I801_WORD_DATA; break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_I2C_BLOCK_DATA:#ifdef HAVE_PEC case I2C_SMBUS_BLOCK_DATA_PEC: if(hwpec && size == I2C_SMBUS_BLOCK_DATA) size = I2C_SMBUS_BLOCK_DATA_PEC;#endif outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); outb_p(command, SMBHSTCMD); block = 1; break; case I2C_SMBUS_PROC_CALL: default: dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size); return -1; }#ifdef HAVE_PEC if(isich4 && hwpec) { if(size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA) outb_p(1, SMBAUXCTL); /* enable HW PEC */ }#endif if(block) ret = i801_block_transaction(data, read_write, size); else { outb_p(xact | ENABLE_INT9, SMBHSTCNT); ret = i801_transaction(); }#ifdef HAVE_PEC if(isich4 && hwpec) { if(size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA) outb_p(0, SMBAUXCTL); }#endif if(block) return ret; if(ret) return -1; if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) return 0; switch (xact & 0x7f) { case I801_BYTE: /* Result put in SMBHSTDAT0 */ case I801_BYTE_DATA: data->byte = inb_p(SMBHSTDAT0); break; case I801_WORD_DATA: data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); break; } return 0;}static u32 i801_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 | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK#ifdef HAVE_PEC | (isich4 ? I2C_FUNC_SMBUS_BLOCK_DATA_PEC | I2C_FUNC_SMBUS_HWPEC_CALC : 0)#endif ;}static struct i2c_algorithm smbus_algorithm = { .name = "Non-I2C SMBus adapter", .id = I2C_ALGO_SMBUS, .smbus_xfer = i801_access, .functionality = i801_func,};static struct i2c_adapter i801_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, .name = "unset",};static struct pci_device_id i801_ids[] = { { .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, }, { .vendor = PCI_VENDOR_ID_INTEL, .device = PCI_DEVICE_ID_INTEL_82801EB_3, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, { .vendor = PCI_VENDOR_ID_INTEL, .device = PCI_DEVICE_ID_INTEL_ESB_4, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, { .vendor = PCI_VENDOR_ID_INTEL, .device = PCI_DEVICE_ID_INTEL_ICH6_16, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, { 0, }};static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id){ if (i801_setup(dev)) { dev_warn(&dev->dev, "I801 not detected, module not inserted.\n"); return -ENODEV; } /* set up the driverfs linkage to our parent device */ i801_adapter.dev.parent = &dev->dev; snprintf(i801_adapter.name, I2C_NAME_SIZE, "SMBus I801 adapter at %04x", i801_smba); return i2c_add_adapter(&i801_adapter);}static void __devexit i801_remove(struct pci_dev *dev){ i2c_del_adapter(&i801_adapter); release_region(i801_smba, (isich4 ? 16 : 8));}static struct pci_driver i801_driver = { .name = "i801 smbus", .id_table = i801_ids, .probe = i801_probe, .remove = __devexit_p(i801_remove),};static int __init i2c_i801_init(void){ return pci_module_init(&i801_driver);}static void __exit i2c_i801_exit(void){ pci_unregister_driver(&i801_driver);}MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, " "Philip Edelbrock <phil@netroedge.com>, " "and Mark D. Studebaker <mdsxyz123@yahoo.com>");MODULE_DESCRIPTION("I801 SMBus driver");MODULE_LICENSE("GPL");module_init(i2c_i801_init);module_exit(i2c_i801_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -