千家信息网

怎么进行Linux的I2C驱动框架分析

发表于:2025-01-23 作者:千家信息网编辑
千家信息网最后更新 2025年01月23日,本篇文章为大家展示了怎么进行Linux的I2C驱动框架分析,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。1.基本概念总线总线代表着同类设备需要共同遵守的工作时
千家信息网最后更新 2025年01月23日怎么进行Linux的I2C驱动框架分析

本篇文章为大家展示了怎么进行Linux的I2C驱动框架分析,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

1.基本概念

总线

总线代表着同类设备需要共同遵守的工作时序,不同的总线对于物理电平的要求是不一样的,对于每个比特的电平维持宽度也是不一样,而总线上传递的命令也会有自己的格式约束。如I2C总线、USB总线、PCI总线等等。以I2C总线为例,在同一组I2C总线上连接着不同的I2C设备。

设备

设备代表真实的、具体的物理器件,在软件上用器件的独特的参数属性来代表该器件。如I2C总线上连接的I2C从设备都有一个标识自己的设备地址,由这个设备地址来确定主设备发过来的命令是否该由它来响应。

驱动

简单的说驱动代表着操作设备的方式和流程。

Linux总线设备框架的工作原理

如果想要弄清楚I2C驱动框架,必须深刻的理解Linux的总线设备框架。之所以会形成这样的框架,很重要的原因是为了代码的复用性。因为驱动和设备的关系是一对多的,对于相同类型的不同的设备,可共用同一套驱动程序接口。为了提高驱动的可移植性,Linux抽象出一套管理资源的函数。设备是存在的硬件,在设备里包含自己的属性,也包含需要用到的资源。

总线的作用就是在软件层面上对设备和驱动进行管理,设备要让系统感知到自己的存在,所以需要向总线去注册设备,驱动同样也要向总线去注册。对于总线,有I2C总线,Platform总线等等。但是Platform是虚拟总线。

对于总线上设备与驱动的匹配,由总线负责,设备在注册的时候,总线会遍历注册在总线上的驱动,如果名字相同,则匹配上了,此时调用驱动程序的probe函数。同样的驱动在注册的时候,也会遍历总线上的设备,如果匹配上(名字一样),则也会调用驱动程序的probe函数。

2.I2C传输协议


对于I2C来说,有如下的特点:

1.一条串行数据线(SDA),一条串行时钟线(SCL)

2.每个接到总线上的器件都可以使用软件根据它的唯一地址来识别。

3.串行的8位双向数据传输,位速率在标志模式下可达100kbit/s,在快速模式下可达400kbit/s。在高速模式下可达3.4Mbit/s。

下面来看一下具体的硬件连接

以上是TFS上的摄像头I2C的连接方式,只有两根线即可实现数据的传输。在传输过程中,需要注意以下三种类型的信号:

(1)开始信号(S):SCL为高电平时,SDA由高向低电平跳变,开始传输数据

(2)结束信号(P):SCL为高电平时,SDA由低向高电平跳变,结束传输数据

(3)响应信号(ACK):接收器在接收到8位数据后,在第9个时钟周期,拉低SDA的电平

以上就是I2C的硬件层与协议层的基本概述,这部分可以作为基本认知。

3.Linux下I2C驱动程序的体系结构


对于Linux下的I2C驱动,其体系结构的组成主要分为三个部分

(1)I2C核心:I2C核心提供了I2C总线驱动和设备驱动的注册,注销方法,I2C通信方法("algorithm")上层的,与具体适配器无关的代码以及探测设备,检测设备地址的上层代码等。

(2)I2C总线驱动:I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可由CPU控制,甚至可以直接集成在CPU内部。

(3)I2C设备驱动:I2C设备驱动(也称为客户驱动)是对I2C硬件体系结构中设备端的实现,设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。

比较重要的文件

\kernel\drivers\i2c\i2c-core.c

这个文件实现了 I2C 核心的功能以及/proc/bus/i2c*接口。同时对I2C底层的收发函数进行封装。会调用i2c_transfer ,里面实现了adap->algo->master_xfer(adap, msgs, num)

kernel\drivers\i2c\i2c-dev.c

该函数注册了一个设备文件的功能,也就是注册了一个字符设备驱动程序,可以通过/dev/i2c-0(i2c-0, i2c-1,…, i2c-10,…)找到具体的I2C适配器,这个I2C设备的主设备号为89,次设备号0~255。通过访问这个接口,可以通过open()、 write()、 read()、 ioctl()和 close()等来访问这个设备。

kernel\drivers\i2c\busses\i2c-v12-jz.c

该函数对君正的x1000底层的I2C操作控制函数,通过设置寄存器来进行I2C的控制。其最底层的收发函数都在该文件里定义。重要的是i2c_jz_algorithm,其中algorithm实现了对底层寄存器的操作。

比较重要的结构体

i2c_driver、 i2c_client、 i2c_adapter 和 i2c_algorithm这四个结构体十分的关键

i2c_driver

对应一套驱动方法,是纯粹的用于辅助作用的数据结构,它不对应于任何的物理实体。

i2c_client

对应于真实的物理设备,每个 I2C 设备都需要一个 i2c_client 来描述。i2c_client 一般被包含在 I2C 字符设备的私有信息结构体中。

i2c_adpater

用来匹配i2c_driver与i2c_client。即 i2c_client 依附于 i2c_adpater。由于一个适配器上可以连接多个 I2C 设备, 所以一个 i2c_adpater 也可以被多个 i2c_client 依附, i2c_adpater 中包括依附于它的 i2c_client 的链表 。

i2c_algorithm

struct i2c_algorithm{
//i2c模式下,收发函数接口
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,int num);
//用于SMBUS模式下,收发函数接口
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data);
//用于检查I2C主控制器所支持访问接口,如I2C_FUNC_SMBUS_BYTE,查看是否支持smbus单字节读取和写操作
u32 (*functionality) (struct i2c_adapter *);
}

该函数主要实现其I2C底层的操作

4.GC0328摄像头I2C实例分析


对于摄像头驱动程序,首先要知道如何让摄像头能够正常工作。

第一步:摄像头上电

在这一步的工作中,可以控制相关的GPIO进行摄像头使能,控制RESET及POWERON来让摄像头正常工作。

GC0328的上电时序如下图所示:

第二步:给摄像头提供时钟

这一步也比较的关键,对于摄像头来说,其时钟就是心跳,如果要让摄像头正常的工作,则需要x1000的CIM提供24MHz的时钟给摄像头。

第三步:配置摄像头的寄存器

对于一个摄像头sensor,需要其输出指定大小及指定格式的图片,则需要配置摄像头的寄存器。而配置摄像头寄存器就是需要通过I2C来进行配置。

第四步:配置CIM

x1000内部的摄像头接口控制模块,可以将摄像头数据进行处理,可以进行帧错误检查以及数据的传输。这部分的控制需要那些CIM相关的寄存器来完成。

第五步:启动CIM

配置及初始化完成后就可以启动摄像头了,CIM负责数据传输及产生相应的中断。

以上是摄像头初始化的一个完整的过程,对于摄像头初始化部分,I2C又是如何进行初始化及设置的呢?这也是本文的重点。

根据前面的总线设备驱动的框架,有driver那么肯定会有device。这两者的匹配靠的是.id_table

对于gc0308,具体可以通过kernel/arch/mips/xburst/soc-x1000/chip-x1000/halley2/common/i2c_bus.c

可以看到向I2C总线注册的device的是gc0308

如果匹配上了,则调用driver的.probe函数。下面我们来看一下该函数具体做了什么事情。

在probe函数中,主要向v412_i2c_subdev提供了一个可操作的client,也就是相当于I2C的操作函数的接口交给V4L2视频驱动框架来进行管理。向V4L2视频驱动框架提供的函数如下:

第一个结构体是有关视频操作的接口,比如设备gc0328的输出格式,得到当前的视频输出格式等等

第二个结构体是控制camera上电与断电,以及控制白平衡,对焦的其他的参数

通过V4L2的I2C子设备控制来进行设置。下面来基本分析一下其调用过程:

当应用程序通过ioctl传递VIDIO_S_FMT,是可以设置摄像头输出的格式

然后看一下写寄存器的过程

调用了i2c_smbus_write_byte_data该函数在kernel\drivers\i2c\i2c-core.c,这样就进入了i2c总线操作函数中。

该函数会调用i2c_smbus_xfer

为什么不满足条件,可以看注册的i2c的平台设备,在kernel\drivers\i2c\busses\i2c-v12-jz.c路径下

有个i2c_algorithm的结构体

struct i2c_algorithm{
//i2c模式下,收发函数接口
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,int num);
//用于SMBUS模式下,收发函数接口
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data);
//用于检查I2C主控制器所支持访问接口,如I2C_FUNC_SMBUS_BYTE,查看是否支持smbus单字节读取和写操作
u32 (*functionality) (struct i2c_adapter *);
}

所以只会向下执行,当执行到i2c_smbus_xfer_emulated ,会调用

该函数会调用

最后调用到kernel\drivers\i2c\busses\i2c-v12-jz.c的最底层的实现

在kernel\drivers\i2c\busses\i2c-v12-jz.c函数中

这个函数指向i2c_jz_xfer

在这个函数中,实现了I2C的读写,可以根据传递的flag进行判断是读操作函数写操作

最底层操作寄存器来实现其读写函数

到这里,一个I2C完整的传输流程就完成了。

5.总结


对于I2C完整的传输协议,最重要的是弄清楚总线驱动程序的框架,因为I2C也是属于总线框架。对于I2C总线设备框架的模型,可以用下图来说明:

也就是device与driver同时向i2c总线上注册。当注册在总线上时,可以通过id_table进行匹配,匹配上之后会调用driver的.probe函数。对于一般的I2C设备,可以在probe函数中注册一个字符设备驱动,从而应用层可以通过open函数打开/dev/i2c-0等设备节点。从而对I2C设备进行读写操作。而摄像头部分,直接将控制接口传递给V4L2进行管理,这样通过视频设备驱动框架进行摄像头调节,从而达到控制的目的。

上述内容就是怎么进行Linux的I2C驱动框架分析,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注行业资讯频道。

设备 总线 驱动 函数 摄像头 摄像 框架 接口 控制 数据 结构 传输 寄存器 程序 模式 电平 适配器 驱动程序 适配 设备驱动 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 华西安全网社工库数据库 苏州梯田软件开发有限公司 有机分子拉曼数据库 互联网科技视频背景素材 浪潮服务器端口网卡不识别 吉林什么软件开发服务价格优惠 oracle 代理服务器 迷你世界怎么用手机连接服务器 数据库mysql网课推荐 软件开发者找工作app 网络安全征询意见 java 8 数据库 微软开源文件数据库 秒针嘀嗒网络技术有限公司 成都乐云互动网络技术怎么样 php打开本地数据库失败 中兴数通软件开发部 网络安全法专家解读视频 服务器远程桌面怎么连接 贵州学习软件开发服务商 数据库编程阶段 神力科莎怎么进入别人的服务器 公安局信息网络安全保卫大队 为什么要保证服务器稳定 php 二维数组的数据库 自己做一个服务器难不难 数据库应用与技术课后答案 数据库学习总结 软件开发与设计先学什么条件 对网站服务器进行安全配置
0