Linux I2C总线框架 学习笔记

本文详细介绍了Linux内核中I2C框架的组成部分及其工作原理,包括核心(Core)、总线驱动(BusDriver)和设备驱动(DeviceDriver)。通过分析adapter结构体、client结构体和driver结构体,帮助读者理解如何编写I2C驱动。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值