这哥们文章写得很好!所以转了
------------------------------------------
本文系本站原创,欢迎转载!
转载请注明出处:http://ericxiao.cublog.cn/
------------------------------------------
一:前言
在前面已经分析了I2C架构,今天以 ICH5 中的I2C总线适配器驱动做为I2C总线适配 器驱动的例子进行分析.相关的datasheet可以在Intel的网页上找到.因此,在这里不再介绍芯片功能.以下代码分析是基于linux kernel2.6.26.相关的代码位于linux-2.6.26.3/drivers/i2c/busses/i2c-i801.c
二:驱动入口分析
首先,ICH5 I2C适配器是一个PCI设备.首先它的驱动符合我们之前分析过的PCI架构.代码如下:
static int __init i2c_i801_init(void)
{
return pci_register_driver(& i801_driver );
}
module_init(i2c_i801_init);
i801_driver定义如下:
static 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 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) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TOLAPAI_1) },
{ PCI_DEVICE( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_ICH10_4) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) },
{ 0, }
};
我们在<<
Intel® 82801EB I/O Controller Hub 5 (ICH5) / Intel® 82801ER I/O Controller Hub 5 R (ICH5R) >>上可以查得它的vendor_id和device_id分别为0x8086和0x24D3.在linux kernel中分别定义为了PCI_VENDOR_ID_INTEL和PCI_DEVICE_ID_INTEL_82801EB_3.它在上面的列表中, 因此会匹配这个驱动.
该驱动的probe函数如下所示:
static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
unsigned char temp;
int err;
I801_dev = dev;
i801_features = 0;
switch (dev->device) {
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:
case PCI_DEVICE_ID_INTEL_TOLAPAI_1:
case PCI_DEVICE_ID_INTEL_ICH10_4:
case PCI_DEVICE_ID_INTEL_ICH10_5:
i801_features |= FEATURE_I2C_BLOCK_READ;
/* fall through */
case PCI_DEVICE_ID_INTEL_82801DB_3:
i801_features |= FEATURE_SMBUS_PEC;
i801_features |= FEATURE_BLOCK_BUFFER;
break;
}
//启用pci 设备
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 */
//IO区域的起始地址
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;
}
//请求I/O资源
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;
}
//读HOSTC寄存器
pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
i801_original_hstcfg = temp;
//去掉I2C_EN位
temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */
//如果HST_EN位为0.表示i2c 控制器被禁用
if (!(temp & SMBHSTCFG_HST_EN)) {
dev_info(&dev->dev, "Enabling SMBus device/n");
//启用i2c host
temp |= SMBHSTCFG_HST_EN;
}
//清除了SMBHSTCFG_I2C_EN设置了SMBHSTCFG_HST_EN
pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
//SMI_EN被置,表示使SMI中断
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");
/* Clear special mode bits */
//清除AUX_CTL寄存器的CRC和E32B位
if (i801_features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
SMBAUXCTL);
/* set up the sysfs linkage to our parent device */
i801_adapter.dev.parent = &dev->dev;
snprintf(i801_adapter.name, sizeof(i801_adapter.name),
"SMBus I801 adapter at %04lx", i801_smba);
//注册adapter驱动
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;
}
首先,因为device id是PCI_DEVICE_ID_INTEL_82801EB_3,所以i801_features含有所有的标志.之后就是一般PCI设备驱动的流程,启用PCI设备.以及取得设备的I/O配置区间.之后,就对设备做一些初始化设定.
下面来了解一下这里初始化过程中所涉及到的寄存器:
HOSTC寄存器,在datasheet中被定义如下:
Bit0就是启用禁用位.
bit1表示中断的类型,被置时,表示使用SMI interrupt,为0的时候表示是Pci interrupt.
Bit2的含义有点难懂,这里就涉及到了smbus和i2c.实际上smbus和i2c都很相同,仅仅是传输的格式不同罢了.当bit2为0的 话,表示使用smbus,如果为1的话,表示使用i2c.在使用I2c Read的时候,必须要将bit2置1.另外,Quick, Send/Receive Byte, Write byte/word, Read byte/word 这些指令必须要将bit2设为0.
另外,关于数据格式的差别,datasheet上已经有详细的描述.
AUX_CTL:按字面意思,它是指辅助传输功能,包括PEC和块传输等.它在datasheet中的定义如下:
如上所示,bit0表示自动CRC检验,也就是我们之前分析的PEC.bit1是否使用块传输功能.
进行一系列初始化之后,会注册adapter.这个adapter定义如下:
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,
};
三:I2C总线上的数据传输
结合我们之前的分析,所有的数据传输都会调用adapter的 master_xfer 和smbus_xfer操作.在这个驱动中, master_xfer操作为空,所以,所有的传输操作都会到smbus_xfer中.在这里对应的就是i801_access().
它的代码如下:
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;
//如果需要PEC.且i2c host 支持PEC 其中,Quick和I2c Block Data不支持PEC
hwpec = (i801_features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
&& size != I2C_SMBUS_QUICK
&& size != I2C_SMBUS_I2C_BLOCK_DATA;
switch (size) {
case I2C_SMBUS_QUICK:
//对于Quick,只需要将地址和传输标志写入XMIT_SLAVE
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
SMBHSTADD);
xact = I801_QUICK;
break;
case I2C_SMBUS_BYTE:
//对于BYTE传输,将地址写入XMIT_SLAVE.如果是写操作,还要将command写入HST_CMD
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:
//对于BYTE_DATA,写地址,写comand,写操作还要写DATA0
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:
//对于Word_Data:写地址,写command.如果是写操作还要写DaTa0 Data1
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:
//Blocal_Data:写地址,写command
outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
SMBHSTADD);
outb_p(command, SMBHSTCMD);
block = 1;
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
//i2c Block Data
/* NB: page 240 of ICH5 datasheet shows that the R/#W
* bit should be cleared here, even when reading */
outb_p((addr & 0x7f) << 1, SMBHSTADD);
if (read_write == I2C_SMBUS_READ) {
/* NB: page 240 of ICH5 datasheet also shows
* that DATA1 is the cmd field when reading */
outb_p(command, SMBHSTDAT1);
} else
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;
}
//如果启用/禁用PEC.设置/清除 AUX_CTL的CRC
if (hwpec) /* enable/disable hardware PEC */
outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_CRC, SMBAUXCTL);
else
outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL);
//等待传输完成
if(block)
ret = i801_block_transaction(data, read_write, size, hwpec);
else
ret = i801_transaction(xact | ENABLE_INT9);
/* Some BIOSes don't like it when PEC is enabled at reboot or resume
time, so we forcibly disable it after every transaction. Turn off
E32B for the same reason. */
//复位AUXCTL寄存器
if (hwpec || block)
outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
SMBAUXCTL);
if(block)
return ret;
if(ret)
return -1;
//如果是写操作,或者是Quick,不需要取read结果,直接返回即可
if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
return 0;
//如果不是带block的读操作
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;
}
这个过程的逻辑比较简单,就是将数据写入寄存器,如果需要PEC.则启用AUX_CTL中的CRC.然后,就启动传输,并等待这个传输完成.如果是Read操作,将传输数据将寄存器取出.
在这里涉及到了两个比较重要的子函数,分别分析如下:
i801_transaction()代码如下:
static int i801_transaction(int xact)
{
int temp;
int result = 0;
int timeout = 0;
dev_dbg(&I801_dev->dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
"ADD=%02x, DAT0=%02x, DAT1=%02x/n", inb_p(SMBHSTCNT),
inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
inb_p(SMBHSTDAT1));
/* Make sure the SMBus host is ready to start transmitting */
/* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
//在传输之前,HOST_STS有错误位,清除它
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting.../n",
temp);
outb_p(temp, SMBHSTSTS);
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
dev_dbg(&I801_dev->dev, "Failed! (%02x)/n", temp);
return -1;
} else {
dev_dbg(&I801_dev->dev, "Successful!/n");
}
}
/* the current contents of SMBHSTCNT can be overwritten, since PEC,
* INTREN, SMBSCMD are passed in xact */
//写入命令代码和开始传输位,开始传输
outb_p(xact | I801_START, SMBHSTCNT);
/* We will always wait for a fraction of a second! */
//等待这次操作完成
do {
msleep(1);
temp = inb_p(SMBHSTSTS);
} while ((temp & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
/* If the SMBus is still busy, we give up */
//如果超时了,取消这次传输.置HST_CNT的Kill位
if (timeout >= MAX_TIMEOUT) {
dev_dbg(&I801_dev->dev, "SMBus Timeout!/n");
result = -1;
/* try to stop the current command */
dev_dbg(&I801_dev->dev, "Terminating the current operation/n");
outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT);
msleep(1);
outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT);
}
//传输失败
if (temp & SMBHSTSTS_FAILED) {
result = -1;
dev_dbg(&I801_dev->dev, "Error: Failed bus transaction/n");
}
//总线错误
if (temp & SMBHSTSTS_BUS_ERR) {
result = -1;
dev_err(&I801_dev->dev, "Bus collision! SMBus may be locked "
"until next hard reset. (sorry!)/n");
/* Clock stops and slave is stuck in mid-transmission */
}
//设备有错误
if (temp & SMBHSTSTS_DEV_ERR) {
result = -1;
dev_dbg(&I801_dev->dev, "Error: no response!/n");
}
//传输有错误,清除HOST_STS中的错误位
if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00)
outb_p(inb(SMBHSTSTS), SMBHSTSTS);
//HOST_STS复位错误
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
dev_dbg(&I801_dev->dev, "Failed reset at end of transaction "
"(%02x)/n", temp);
}
dev_dbg(&I801_dev->dev, "Transaction (post): CNT=%02x, CMD=%02x, "
"ADD=%02x, DAT0=%02x, DAT1=%02x/n", inb_p(SMBHSTCNT),
inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
inb_p(SMBHSTDAT1));
return result;
}
代码中的注释已经很详细了,这里不再赘述.
另一个重要的子函数是i801_block_transaction().代码如下:
static int i801_block_transaction (union i2c_smbus_data *data, char read_write,
int command, int hwpec)
{
int result = 0;
unsigned char hostc;
//如果是I2C 的写操作必须要启用 I2C 功能
if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
if (read_write == I2C_SMBUS_WRITE) {
/* set I2C_EN bit in configuration register */
pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
pci_write_config_byte(I801_dev, SMBHSTCFG,
hostc | SMBHSTCFG_I2C_EN);
} else if (!(i801_features & FEATURE_I2C_BLOCK_READ)) {
dev_err(&I801_dev->dev,
"I2C block read is unsupported!/n");
return -1;
}
}
//修正有效数据长度. 存放在data->block[0]
if (read_write == I2C_SMBUS_WRITE
|| command == I2C_SMBUS_I2C_BLOCK_DATA) {
if (data->block[0] < 1)
data->block[0] = 1;
if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
data->block[0] = I2C_SMBUS_BLOCK_MAX;
}
//如果是读操作,将block有效长度置为最大值
else {
data->block[0] = 32; /* max for SMBus block reads */
}
//i2c host 支持block data传输且不为i2C的Read操作
if ((i801_features & FEATURE_BLOCK_BUFFER)
&& !(command == I2C_SMBUS_I2C_BLOCK_DATA
&& read_write == I2C_SMBUS_READ)
&& i801_set_block_buffer_mode() == 0)
result = i801_block_transaction_by_block(data, read_write,
hwpec);
else
result = i801_block_transaction_byte_by_byte(data, read_write,
command, hwpec);
//等待中断位被设
if (result == 0 && hwpec)
i801_wait_hwpec();
//如果是I2C的Write操作,要回复HOSTCr 的值
if (command == I2C_SMBUS_I2C_BLOCK_DATA
&& read_write == I2C_SMBUS_WRITE) {
/* restore saved configuration register value */
pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
}
return result;
}
实际的传输是调用i801_block_transaction_by_block()或者i801_block_transaction_byte_by_byte()来完成的.
先来看i801_block_transaction_by_block()的代码.如下示:
static int i801_block_transaction_by_block(union i2c_smbus_data *data,
char read_write, int hwpec)
{
int i, len;
inb_p(SMBHSTCNT); /* reset the data buffer index */
/* Use 32-byte buffer to process this transaction */
if (read_write == I2C_SMBUS_WRITE) {
len = data->block[0];
outb_p(len, SMBHSTDAT0);
for (i = 0; i < len; i++)
outb_p(data->block[i+1], SMBBLKDAT);
}
if ( i801_transaction (I801_BLOCK_DATA | ENABLE_INT9 |
I801_PEC_EN * hwpec))
return -1;
if (read_write == I2C_SMBUS_READ) {
len = inb_p(SMBHSTDAT0);
if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
return -1;
data->block[0] = len;
for (i = 0; i < len; i++)
data->block[i + 1] = inb_p(SMBBLKDAT);
}
return 0;
}
它先将传输的数据总数写到SMBHSTDAT0.将要传输的数据写入到Host_BLOCK_DB寄存器,然后调用i801_transaction()启用操作并等待传输完成.如果是读操作,将结果读出.
i801_block_transaction_byte_by_byte()函数与i801_block_transaction_by_block()类似,这里就不再详细分析了.
四:小结
在本节里,大概分析了一下ICH5中I2C Bus Adapter的驱动代码.了解了一般adapter的驱动架构.