【I2C框架结构】
Linux 内核中的 I2C 框架分为 3 部分,分别是 Core、Bus Driver、DeviceDriver 。其中 Core 部分是框架中的框架,会调用 Bus Driver 和 Device Driver 中的函数和结构体进行 I2C 注册、数据读写。我将其整理成为下面这张框图(按下 ctrl+鼠标滚轴 可放大图片):
【驱动编写的主要工作】
I2C 框架里需要我们完善的内容存在于 Bus Driver 和 Device Driver 中,我将其分为 2 部分——接口结构体、接口函数。
先来看结构体。根据设备的不同我们需要定义包含不同内容的 adapter 结构体、client结构体、driver 结构体、algorithm 结构体。一个adapter结构体可以用于注册多个 client结构体,这些 client结构体都存储在 adapter结构体的 clients链表中。adapter结构体的定义如下:
struct i2c_adapter {
struct module *owner;
unsigned int id;
unsigned int class;
const struct i2c_algorithm *algo; // i2c 时序实现算法
void *algo_data; // 私有数据,包含要收发的消息 *msg
int(*client_register)(struct i2c_client *); // 用于注册 client
int (*client_unregister)(struct i2c_client *);
/* data fields that are valid for all devices */
u8 level;
struct mutex bus_lock;
struct mutex clist_lock;
int timeout; /* in jiffies*/
int retries;
struct device dev; /* the adapter device */
int nr; // 适配器的个数
struct list_head clients; //client链表头
char name[48]; // 适配器名称
struct completion dev_released; // 用于同步
};
client结构体定义如下:
struct i2c_client {
unsigned int flags; /* 标志 */
unsigned short addr; /* 低 7 位为芯片地址 */
struct i2c_adapter *adapter; /*依附的 i2c_adapter*/
struct i2c_driver *driver; /*依附的 i2c_driver*/
struct device dev; /* 设备结构体 */
char name[I2C_NAME_SIZE]; /* 设备名称 */
struct completion released; /* 用于同步 */
};
i2c_msg结构体定义如下:
struct i2c_msg {
__u16 addr; // 设备地址
__u16 flags; // 读/写标志
__u16 len; // 消息长度
__u8 *buf; // 消息数据
};
再来看在上述的接口结构体中存在的众多接口函数,她们也需要我们根据具体情况实现。这些待实现的接口函数有 (*master_xfer)、(*probe)、(*remove) 等。如下:
struct i2c_algorithm {
int(*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
int (*smbus_xfer) (struct i2c_adapter *adap,
u16 addr,
unsigned short flags,
char read_write,
u8 command,
int size,
union i2c_smbus_data * data);
u32 (*functionality) (struct i2c_adapter *);/*返回适配器支持的功能*/
};
struct i2c_driver {
int id;
unsigned int class;
int (*attach_adapter)(struct i2c_adapter *); /* 依附i2c_adapter函数指针 */
int (*detach_adapter)(struct i2c_adapter *); /* 脱离i2c_adapter函数指针 */
int (*detach_client)(struct i2c_client *); /* i2c client脱离函数指针 */
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int (*remove)(struct i2c_client *);
/* driver model interfaces that don't relate to enumeration */
void (*shutdown)(struct i2c_client *);
int (*suspend)(struct i2c_client *, pm_message_t mesg);
int (*resume)(struct i2c_client *);
int (*command)(struct i2c_client *client,unsigned int cmd, void*arg); /* 类似ioctl */
struct device_driver driver; /* 设备驱动结构体 */
struct list_headlist; /* 链表头 */
};
以上就是需要我们在自己的驱动里主要编写的内容。按照 Linux I2C 的框架,我们将这些内容分别写到 2 个驱动模块中,即 Bus Driver 模块和 Device Driver 模块。
【I2C驱动调用流程】
驱动加载时,从模块入口函数开始执行。2 个模块的加载/卸载函数与其余各部分的关系如上文框图所示,其形式类似下方代码:
static int __init i2c_adapter_xxx_init()
{
xxx_adapter_hw_init(); // 硬件相关初始化,如申请I/O地址、中断号等
i2c_add_adapter(&xxx_adapter); // 添加实际情况需要的 xxx_adapter
…
}
static void __exit i2c_adapter_xxx_exit()
{
xxx_adapter_hw_free();
i2c_del_adapter(&xxx_adapter);
}
static struct i2c_driver device_xxx_driver= {
.driver = {
.name = “device_xxx”, // 为各设备填充 driver 结构体
}
.probe =device_xxx_probe,
.remove =device_xxx_remove,
.id_table =device_xxx_id,
};
static int __init device_xxx_init()
{
return i2c_add_driver(&device_xxx_driver); // 为设备添加 driver 结构体,有几个设备就要添加几个 driver
}
static void __exit device_xxx_exit()
{
i2c_del_driver(&device_xxx_driver);
}
之后的 I2C 操作,如设备注册、数据读写等,将按照以上各结构体中关联的函数相应进行。
本文永久更新地址://m.ajphoenix.com/linux/26991.html