📄 i2c-i801.c
字号:
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; } if (hwpec) { /* wait for INTR bit as advised by Intel */ timeout = 0; do { msleep(1); temp = inb_p(SMBHSTSTS); } while ((!(temp & 0x02)) && (timeout++ < MAX_TIMEOUT)); if (timeout >= MAX_TIMEOUT) { dev_dbg(&I801_dev->dev, "PEC Timeout!\n"); } outb_p(temp, SMBHSTSTS); } 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; int block = 0; int ret, xact = 0; hwpec = isich4 && (flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA; 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: 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; } outb_p(hwpec, SMBAUXCTL); /* enable/disable hardware PEC */ if(block) ret = i801_block_transaction(data, read_write, size, hwpec); else { outb_p(xact | ENABLE_INT9, SMBHSTCNT); ret = i801_transaction(); } /* Some BIOSes don't like it when PEC is enabled at reboot or resume time, so we forcibly disable it after every transaction. */ if (hwpec) outb_p(0, SMBAUXCTL); 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 | (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0);}static const struct i2c_algorithm smbus_algorithm = { .smbus_xfer = i801_access, .functionality = i801_func,};static struct i2c_adapter i801_adapter = { .owner = THIS_MODULE, .id = I2C_HW_SMBUS_I801, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm,};static struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_4) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_16) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) }, { 0, }};MODULE_DEVICE_TABLE (pci, i801_ids);static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id){ unsigned char temp; int err; I801_dev = dev; switch (dev->device) { case PCI_DEVICE_ID_INTEL_82801DB_3: case PCI_DEVICE_ID_INTEL_82801EB_3: case PCI_DEVICE_ID_INTEL_ESB_4: case PCI_DEVICE_ID_INTEL_ICH6_16: case PCI_DEVICE_ID_INTEL_ICH7_17: case PCI_DEVICE_ID_INTEL_ESB2_17: case PCI_DEVICE_ID_INTEL_ICH8_5: case PCI_DEVICE_ID_INTEL_ICH9_6: isich4 = 1; break; default: isich4 = 0; } err = pci_enable_device(dev); if (err) { dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n", err); goto exit; } /* Determine the address of the SMBus area */ i801_smba = pci_resource_start(dev, SMBBAR); if (!i801_smba) { dev_err(&dev->dev, "SMBus base address uninitialized, " "upgrade BIOS\n"); err = -ENODEV; goto exit; } err = pci_request_region(dev, SMBBAR, i801_driver.name); if (err) { dev_err(&dev->dev, "Failed to request SMBus region " "0x%lx-0x%Lx\n", i801_smba, (unsigned long long)pci_resource_end(dev, SMBBAR)); goto exit; } pci_read_config_byte(I801_dev, SMBHSTCFG, &temp); i801_original_hstcfg = temp; temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */ if (!(temp & SMBHSTCFG_HST_EN)) { dev_info(&dev->dev, "Enabling SMBus device\n"); temp |= SMBHSTCFG_HST_EN; } pci_write_config_byte(I801_dev, SMBHSTCFG, temp); if (temp & SMBHSTCFG_SMB_SMI_EN) dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n"); else dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n"); /* set up the sysfs linkage to our parent device */ i801_adapter.dev.parent = &dev->dev; snprintf(i801_adapter.name, I2C_NAME_SIZE, "SMBus I801 adapter at %04lx", i801_smba); err = i2c_add_adapter(&i801_adapter); if (err) { dev_err(&dev->dev, "Failed to add SMBus adapter\n"); goto exit_release; } return 0;exit_release: pci_release_region(dev, SMBBAR);exit: return err;}static void __devexit i801_remove(struct pci_dev *dev){ i2c_del_adapter(&i801_adapter); pci_write_config_byte(I801_dev, SMBHSTCFG, i801_original_hstcfg); pci_release_region(dev, SMBBAR); /* * do not call pci_disable_device(dev) since it can cause hard hangs on * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010) */}#ifdef CONFIG_PMstatic int i801_suspend(struct pci_dev *dev, pm_message_t mesg){ pci_save_state(dev); pci_write_config_byte(dev, SMBHSTCFG, i801_original_hstcfg); pci_set_power_state(dev, pci_choose_state(dev, mesg)); return 0;}static int i801_resume(struct pci_dev *dev){ pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); return pci_enable_device(dev);}#else#define i801_suspend NULL#define i801_resume NULL#endifstatic struct pci_driver i801_driver = { .name = "i801_smbus", .id_table = i801_ids, .probe = i801_probe, .remove = __devexit_p(i801_remove), .suspend = i801_suspend, .resume = i801_resume,};static int __init i2c_i801_init(void){ return pci_register_driver(&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 + -