⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c-i801.c

📁 i2c 在linux下的驱动设计
💻 C
📖 第 1 页 / 共 2 页
字号:
			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 + -