Linux I2C总线框架 学习笔记

来源:互联网 发布:cern数据 编辑:程序博客网 时间:2024/06/07 00:35

【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 操作,如设备注册、数据读写等,将按照以上各结构体中关联的函数相应进行。


0 0
原创粉丝点击