分类: 嵌入式
2013-09-24 21:06:42
原文地址:linux下I2C驱动分析2-(2) 作者:zjh_larm
用法总结
上面我们总结了i2c_algorithm的master_xfer成员函数的实现,我们正是调用该函数来实现i2c设备的访问的。一般我们在设备驱动中找到设备所接的适配器以后,同时也找到了该适配器的通信方法,然后我们会根据芯片的datasheet组织i2c消息,然后调用i2c核心提供的函数i2c_transfer来访问芯片。下面我们来跟踪下i2c_transfer函数,其实就是对i2c_algorithm->master_xfer的封装。
int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
{
int ret;
if (adap->algo->master_xfer) {
#ifdef DEBUG
for (ret = 0; ret < num; ret++) {
dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
"len=%d\n", ret, msgs[ret].flags & I2C_M_RD ?
'R' : 'W', msgs[ret].addr, msgs[ret].len);
}
#endif
mutex_lock(&adap->bus_lock);
//可以看到就是直接调用master_xfer函数。
ret = adap->algo->master_xfer(adap,msgs,num);
mutex_unlock(&adap->bus_lock);
return ret;
} else {
dev_dbg(&adap->dev, "I2C level transfers not supported\n");
return -ENOSYS;
}
}
下面再来讨论下前面一章中i2c_probe函数中调用的i2c_check_functionality函数的实现。
I2c_probe函数中有这样一段:
/* Stop here if we can't use SMBUS_QUICK */
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
if (address_data->probe[0] == I2C_CLIENT_END
&& address_data->normal_i2c[0] == I2C_CLIENT_END)
return 0;
dev_warn(&adapter->dev, "SMBus Quick command not supported, "
"can't probe for chips\n");
return -1;
}
追踪i2c_check_functionality:
static inline int i2c_check_functionality(struct i2c_adapter *adap, u32 func)
{
return (func & i2c_get_functionality(adap)) == func;
}
static inline u32 i2c_get_functionality(struct i2c_adapter *adap)
{
return adap->algo->functionality(adap);
}
可见还是调用了algothm的functionlity函数。
我们来看看该驱动中这个函数的实现:
static struct i2c_algorithm mxc_i2c_algorithm = {
.master_xfer = mxc_i2c_xfer,
.functionality = mxc_i2c_func
};
static u32 mxc_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
可见就是要该适配器支持I2C_FUNC_SMBUS_QUICK的功能。