Linux I2C驱动-框架与数据类型导读

1.驱动框架

Linux内核也将 I2C 驱动框架分为三部分,符合 Linux 的驱动分离与分层的思想:

  1. I2C 总线驱动,I2C 总线驱动就是 SOC I2C 控制器驱动,也叫做 I2C 适配器驱动。
  2. I2C设备驱动,I2C 设备驱动就是针对具体的 I2C 设备而编写的驱动。
  3. I2C 核心,提供了IIC总线驱动与IIC设备驱动的注册、注销方法和与具体IIC控制器无关的代码,该部分用来管理IIC总线驱动与IIC设备驱动。

https://i-blog.csdnimg.cn/blog_migrate/807931bceca10693621d433887a55a8a.png

2.数据结构

(1)i2c_bus_type:

I2C总线对应着/bus下的一条总线,这个i2c总线结构体管理着i2c设备与I2C驱动的匹配,删除等操作,I2C总线会调用i2c_device_match函数看I2C设备和I2C驱动是否匹配,如果匹配就调用i2c_device_probe函数,进而调用I2C驱动的probe函数。

注意:i2c_device_match会管理I2C设备和I2C总线匹配规则,这将和如何编写I2C驱动程序息息相关。

(2)i2c_adapter:

描述一个适配器(IIC控制器),用于向IIC核心注册。设备数据结构i2c_client中的一个对象指向i2c_adapter,这样就可以通过其中的方法(i2c_adapter内部的i2c_algorithm对象)以及i2c物理控制器来和一个i2c总线的物理设备进行交互。

3)i2c_algorithm:

描述一个适配器的通信方法,用于产生I 2 C访问周期需要的信号,该类的对象algo是i2c_adapter的一个域,其中的master_xfer()注册的函数最终被设备驱动端的i2c_transfer()回调。在构建i2c_adapter数据结构时要填充这个数据结构,否则i2c_adapter什么也做不了。

(4)i2c_client:

描述一个挂接在硬件i2c总线上的设备的设备信息,即i2c设备的设备对象,与i2c_driver对象匹配成功后通过detected和i2c_driver相连。一般通过i2c_new_device()创建。

(5)i2c_driver:

描述一个挂接在硬件i2c总线上的设备的驱动方法,即i2c设备的驱动对象,通过i2c_bus_type和设备信息i2c_client匹配,匹配成功后通过clients和i2c_client对象相连。

(6)i2c_msg:

描述一个在设备端和主机端之间进行流动的数据,在设备驱动中打包并通过i2c_transfer()发送。

2.1 I2C总线驱动中数据结构:i2c_adapter 和 i2c_algorithm

        I2C 总线驱动重点是 I2C 适配器(也就是 SOC 的 I2C 接口控制器)驱动,这里要用到两个重要的数据结构:i2c_adapter 和 i2c_algorithm,Linux 内核将 SOC 的 I2C 适配器(控制器)抽象成 i2c_adapter,i2c_adapter 结构体定义在 include/linux/i2c.h 文件中,结构体内容如下:

498 struct i2c_adapter {

499 struct module *owner; //所有者

500 unsigned int class; /*适配器支持的从设备类型 */

501 const struct i2c_algorithm *algo; /* 适配器的通信方法,也就是上面的i2c_algorithm */

502 void *algo_data;

503

504 /* data fields that are valid for all devices */

505 struct rt_mutex bus_lock;

506

507 int timeout; /* 超时时间 */

508 int retries;

509 struct device dev; /* 表明这是一个设备,挂载在I2C总线上 */

510

511 int nr; //适配器(总线)的编号

512 char name[48]; //适配器name

513 struct completion dev_released;

514

515 struct mutex userspace_clients_lock;

516 struct list_head userspace_clients;

517

518 struct i2c_bus_recovery_info *bus_recovery_info;

519 const struct i2c_adapter_quirks *quirks;

520 };

        第 501 行,i2c_algorithm 类型的指针变量 algo,对于一个 I2C 适配器,肯定要对外提供读写 API 函数,设备驱动程序可以使用这些 API 函数来完成读写操作。i2c_algorithm 就是 I2C 适配器与 IIC 设备进行通信的方法。

        i2c_algorithm 结构体定义在 include/linux/i2c.h 文件中,内容如下(删除条件编译):

391 struct i2c_algorithm {

......

398 int (*master_xfer)(struct i2c_adapter *adap,

struct i2c_msg *msgs,

399               int num);

400 int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,

401       unsigned short flags, char read_write,

402       u8 command, int size, union i2c_smbus_data *data);

403

404 /* To determine what the adapter supports */

405 u32 (*functionality) (struct i2c_adapter *);

......

411 };

        第 398 行,master_xfer 就是 I2C 适配器的传输函数,可以通过此函数来完成与 IIC 设备之间的通信。

        第 400 行,smbus_xfer 就是 SMBUS 总线的传输函数。

        综上所述,I2C 总线驱动,或者说 I2C 适配器驱动的主要工作就是初始化 i2c_adapter 结构体变量,然后设置 i2c_algorithm 中的 master_xfer 函数。完成以后通过 i2c_add_numbered_adapter或 i2c_add_adapter 这两个函数向系统注册设置好的 i2c_adapter.

2.2  I2C设备驱动中数据结构:i2c_client 和 i2c_driver

        I2C 设备驱动重点关注两个数据结构:i2c_client 和 i2c_driver,根据总线、设备和驱动模型,i2c_client 就是描述设备信息的,i2c_driver 描述驱动内容,类似于 platform_driver。

1 、i2c_client结构体

        i2c_client 结构体定义在 include/linux/i2c.h 文件中,内容如下:

217 struct i2c_client {

218 unsigned short flags; //I2C_CLIENT_TEN表示设备使用10bit从地址,I2C_CLIENT_PEC表示设备使用SMBus检错

219 unsigned short addr; /* 芯片地址,7 位,存在低 7 位 */

......

222 char name[I2C_NAME_SIZE]; //iic设备名字,用于匹配iic驱动

223 struct i2c_adapter *adapter; /*iic设备是挂在哪个适配器(总线)上        */

224 struct device dev; /* 设备结构体 */

225 int irq; /* 中断 */

226 struct list_head detected; //是i2c_adapter结构体或i2c_driver结构体中链表的节点

......

230 };

一个设备对应一个 i2c_client,每检测到一个 I2C 设备就会给这个 I2C 设备分配一个i2c_client。



struct i2c_board_info {

    char        type[I2C_NAME_SIZE];  //设备名,最长20个字符,最终安装到client的name上

    unsigned short    flags;  //最终安装到client.flags

    unsigned short    addr;  //设备从地址slave address,最终安装到client.addr上

    void        *platform_data;  //设备数据,最终存储到i2c_client.dev.platform_data上

    struct dev_archdata    *archdata;

    struct device_node *of_node;  //OpenFirmware设备节点指针

    struct acpi_dev_node acpi_node;

    int        irq;  //设备采用的中断号,最终存储到i2c_client.irq上

};

2 、i2c_driver结构体

        i2c_driver 类似 platform_driver,是我们编写 I2C 设备驱动重点要处理的内容,i2c_driver 结构体定义在 include/linux/i2c.h 文件中,内容如下:

161 struct i2c_driver {

162 unsigned int class;

163

164 /* Notifies the driver that a new bus has appeared. You should

165 * avoid using this, it will be removed in a near future.

166 */

167 int (*attach_adapter)(struct i2c_adapter *) __deprecated; //老的匹配函数

168

169 /* Standard driver model interfaces */

170 int (*probe)(struct i2c_client *, const struct i2c_device_id *);//当前匹配成功后执行函数,一般是申请资源,注册字符驱动

171 int (*remove)(struct i2c_client *);//当前移除设备或驱动时执行的移除函数,一般是释放资源

172

173 /* driver model interfaces that don't relate to enumeration */

174 void (*shutdown)(struct i2c_client *);

175

176 /* Alert callback, for example for the SMBus alert protocol.

177 * The format and meaning of the data value depends on the

178 * protocol.For the SMBus alert protocol, there is a single bit

179 * of data passed as the alert response's low bit ("event

180 flag"). */

181 void (*alert)(struct i2c_client *, unsigned int data);

182

183 /* a ioctl like command that can be used to perform specific

184 * functions with the device.

185 */

186 int (*command)(struct i2c_client *client, unsigned int cmd,

void *arg);

187

188 struct device_driver driver; //表明这是一个驱动,驱动模型用来挂在I2C总线上

189 const struct i2c_device_id *id_table; /设备匹配列表,非常重要,IIC设备的名字与这个列表匹配

190

191 /* Device detection callback for automatic device creation */

192 int (*detect)(struct i2c_client *, struct i2c_board_info *);

193 const unsigned short *address_list; //该驱动所支持的所有(次设备)的地址数组,用于注册驱动时自动去匹配

194 struct list_head clients; //用来挂接与该i2c_driver匹配成功的i2c_client (次设备)的一个链表头

195 };

参考文档:

【linux iic子系统】linux下i2c框架(二)_linux下应用层实现i2c协议-CSDN博客

正点原子-linux驱动开发指南

  • 24
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux系统中,i2c设备的驱动程序通常会使用i2c核心框架提供的API,以下是一般的i2c驱动代码框架: ```c #include <linux/module.h> #include <linux/i2c.h> static int my_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { // 初始化i2c设备 // 创建字符设备节点 // 设置私有数据 return 0; } static int my_i2c_remove(struct i2c_client *client) { // 删除字符设备节点 // 释放私有数据 return 0; } static const struct i2c_device_id my_i2c_id[] = { { "my_i2c_device", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, my_i2c_id); static struct i2c_driver my_i2c_driver = { .driver = { .name = "my_i2c_device", .owner = THIS_MODULE, }, .probe = my_i2c_probe, .remove = my_i2c_remove, .id_table = my_i2c_id, }; static int __init my_i2c_init(void) { return i2c_add_driver(&my_i2c_driver); } static void __exit my_i2c_exit(void) { i2c_del_driver(&my_i2c_driver); } module_init(my_i2c_init); module_exit(my_i2c_exit); MODULE_AUTHOR("author"); MODULE_DESCRIPTION("i2c driver for my i2c device"); MODULE_LICENSE("GPL"); ``` 以上代码定义了一个名为`my_i2c_device`的i2c设备驱动程序,其中包含了设备的`probe`和`remove`函数,以及设备的标识信息和驱动程序的初始化和卸载函数。在`probe`函数中,需要完成i2c设备的初始化工作,包括创建字符设备节点和设置私有数据。在`remove`函数中,需要释放相关资源,包括删除字符设备节点和释放私有数据。最后,通过`i2c_add_driver`和`i2c_del_driver`函数将驱动程序注册到i2c核心框架中。 需要注意的是,以上代码仅为框架示例,具体的驱动程序实现会因不同的i2c设备而异。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值