linux下I2c框架分析之通信(五)
平台:君正x1000
内核:Linux3.5
在linux的i2c框架中,设备和主机的通信数据都是经过适配器处理的,所以通信的协议的实现也是依靠适配器驱动实现的。
在通信结构i2c_algorithm中主要实现两个成员.master_xfer和.functionality ,i2c通信协议的实现主要是master_xfer完成,functionality主要是返回支出的功能。
/* \drivers\i2c\busses\i2c-v12-jz.c */
static const struct i2c_algorithm i2c_jz_algorithm = {
.master_xfer = i2c_jz_xfer,
.functionality = i2c_jz_functionality,
};
static int i2c_jz_probe(struct platform_device *dev)
{
int ret = 0;
struct i2c_jz *i2c;
struct resource *res;
unsigned int reg_tmp;
i2c = kzalloc(sizeof(struct i2c_jz), GFP_KERNEL);
i2c->adap.owner = THIS_MODULE;
i2c->adap.algo = &i2c_jz_algorithm; //适配器指向这个通信结构
i2c->adap.retries = 5;
i2c->adap.timeout = 5;
i2c->adap.algo_data = i2c;
i2c->adap.dev.parent = &dev->dev;
i2c->adap.nr = dev->id;
sprintf(i2c->adap.name, "i2c%u", dev->id);
}
因为在i2c协议中,cpu作为主控,是主动读写终端设备的数据,终端总是作为被动方,下面咱们看看适配器是怎么访问终端设备的。
终极接口
此接口对设备可读可写,无论你在驱动程序中见到的任何封装的读写函数都会调用到此接口。
/* \drivers\i2c\i2c-core.c */
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
/* 上面适配器驱动中已经实现此函数 */
if (adap->algo->master_xfer)
ret = __i2c_transfer(adap, msgs, num);
}
/* \drivers\i2c\i2c-core.c */
int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
for (ret = 0, try = 0; try <= adap->retries; try++) {
ret = adap->algo->master_xfer(adap, msgs, num);
}
}
这样就把数据传进去了,是不是很奇怪,到底怎么读怎么写呢,接下来再看一个结构
struct i2c_msg {
__u16 addr; /* slave address */
__u16 flags; /* 可以是以下宏定义的组合 */
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_RD 0x0001 /* read data, from slave to master */
#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
了解了这个结构,咱们看看适配器是怎么解析消息的。此时咱们就要研究刚才 i2c_algorithm中的.master_xfer = i2c_jz_xfer的实现了。
static int i2c_jz_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int count)
{
/* 进行读写判断 */
if (msg->flags & I2C_M_RD) {
ret = xfer_read(i2c, msg->buf, msg->len, end_type);
} else {
ret = xfer_write(i2c, msg->buf, msg->len, end_type);
}
}
最关键的就是这两个函数,其对适配器寄存器的设置需配合cpu数据手册暂且不做研究。