一、I2C驱动框架

I2c_driver、i2c_client与i2c_adapter
I2c_driver与i2c_client是一对多的关系,一个i2c_driver上可以支持多个同等类型的i2c_client。调用i2c_add_driver函数将I2c_driver注册到I2C总线上,调用i2c_register_board_info函数将i2c_client注册到全局链表__i2c_board_list。当调用i2c_add_adapter注册适配器时,遍历__i2c_board_list链表,i2c_register_adapter()->i2c_scan_static_board_info()->i2c_new_device()会构建i2c_client结构。当调用i2c_add_driver时,会先注册i2c_driver到I2C总线上,然后调用I2C BUS注册的match函数进行匹配,如果匹配成功,则先调用I2C BUS中注册的probe函数,在调用i2c_driver中实现的probe函数,完成相应的工作。
二、I2C驱动
- I2C总线驱动由I2C_adapter和I2C_algorithm表示
I2C_adapter结构体代表I2C总线控制器
struct i2c_adapter {
struct module *owner;
unsigned int class; /*classes to allow probing for */
const struct i2c_algorithm*algo; /* 总线上数据传输的算法*/
void *algo_data; /* algorithm 数据 */
int timeout; /* injiffies */
int retries; /* 重试次数 */
struct device dev; /* the adapter device */
int nr;
char name[48]; /* 适配器名字 */
struct completion dev_released; /* 用于同步 */
};
I2c_algorithm对应一套通信方法
struct i2c_algorithm {
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, intnum);
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
unsigned short flags, charread_write,
u8 command, int size, unioni2c_smbus_data *data);
u32 (*functionality) (structi2c_adapter *);
};
Functionality 函数用于返回algorithm所支持的通信协议,比如I2C_FUNC_I2C,I2C_FUNC_10BIT_ADDR等。
Master_xfer 函数实现总线上数据传输,与具体的适配器有关
master_xfer函数实现模板
static int i2c_adapter_xxx_xfer(structi2c_adapter *adap, struct i2c_msg *msgs, int num)
{
......
for (i = 0; i < num; i++) {
i2c_adapter_xxx_start(); /*产生起始位*/
if (msgs[i]->flags & I2C_M_RD) { /*读取*/
i2c_adapter_xxx_setaddr((msg->addr << 1) | 1); /*发送从设备地址*/
i2c_adapter_xxx_wait_ack(); /*获得从设备的ACK*/
i2c_adapter_xxx_readbytes(msgs[i]->buf,msgs[i]->len); /*读取len长度的数据到buf中*/
} else {
i2c_adapter_xxx_setaddr(msg->addr << 1);
i2c_adapter_xxx_wait_ack();
i2c_adapter_xxx_writebytes(msgs[i]->buf, msgs[i]->len);
}
}
i2c_adapter_xxx_stop(); /*产生停止位*/
}
上面调用的函数用于完成适配器的底层硬件操作,与I2C适配器和CPU的具体硬件直接相关,
需要由工程师根据芯片的数据手册来实现。在内核源码中,针对不同的I2C适配器都有master_xfer的实现,
风格与模板不尽相同,但是可以用该模板作为参考来看源代码,受益匪浅。
i2c_driver代表I2C从设备驱动
struct i2c_driver {
unsignedint class;
int(*attach_adapter)(struct i2c_adapter *) __deprecated; /*依附i2c适配器函数指针*/
int(*detach_adapter)(struct i2c_adapter *) __deprecated;/*脱离i2c适配器函数指针*/
int (*probe)(struct i2c_client*, const struct i2c_device_id *);
int (*remove)(struct i2c_client*);
int(*suspend)(struct i2c_client *, pm_message_t mesg);
int(*resume)(struct i2c_client *);
void(*alert)(struct i2c_client *, unsigned int data);
int(*command)(struct i2c_client *client, unsigned int cmd, void *arg);
struct device_driver driver;
const struct i2c_device_id*id_table; /* 该驱动所支持的设备ID表 */
/*Device detection callback for automatic device creation */
int(*detect)(struct i2c_client *, struct i2c_board_info *);
constunsigned short *address_list;
structlist_head clients;
};
id_tabel用于i2c_driver和i2c_client的匹配

本文详细探讨了Linux内核对于I2C总线驱动的实现,包括I2C_adapter和I2C_algorithm两个核心概念。

1775

被折叠的 条评论
为什么被折叠?



