I2C子系统简介

I2C子系统简介,第1张

I2C子系统简介

I2C子系统的作用:为屏蔽不同的I2C主机控制器驱动,可以使I2C设备驱动仅关心如何 *** 作I2C设备,而不需要了解I2C主机控制器(主控芯片)的细节,从而使I2C设备驱动可以独立存在,适用于不同的硬件平台。
I2C驱动框架的主要目标是:让驱动开发者可以在内核中方便的添加自己的I2C设备的驱动程序,从而可以更容易的在linux下驱动自己的I2C接口硬件。

一、基本知识:
1、cpu一般只有一个iic_core,有几条IIC总线(比如IIC0、IIC1、IIC2),驱动内就会有几个i2c_adapter(适配器);
2、板上有多少个外围IIC设备(比如摄像头、触摸屏),驱动内就会有多少个iic_client;
3、ls -l /dev/i2c*就会看到主设备号只有一个(89),有几条IIC总线,就会有多少个次设备号;
4、IIC驱动其实包括两方面:适配器驱动(或者叫IIC总线驱动)和iic设备驱动。
5、IIC核心加上IIC驱动,构成了IIC驱动架构的所有3个部分,
I2C核心,由Linux内核维护者编写,代码目录位于kerneldriversi2c。I2C核心提供了I2C总线驱动和总线设备注册,注销,通信等接口。
I2C总线驱动(I2C适配器驱动,也就是主控芯片上的I2C模块驱动),由主控芯片厂家编写,并放入Linux内核源码中,不同厂家的芯片,都有其对应的不同的I2C适配器驱动,代码目录位于V2.1kerneldriversi2cbusses。通过写主控芯片的寄存器,控制主控芯片内部的I2C模块,输出标准I2C时序。主要提供读写I2C寄存器的接口。
I2C设备驱动(具体某个设备的I2C驱动),由驱动工程师编写,并放入Linux内核源码中,目录位置不定。通过I2C通讯,来读写具体设备的寄存器,比如某个摄像头设备。提供给应用层控制具体设备的接口,ioctl等。

适配器驱动:(芯片厂商负责的,一般不同的芯片厂商的芯片,都有不同的I2C适配器驱动,都是芯片原厂厂家写好,放入Linux内核里的kernel/drivers/i2c/busses$目录)可能是linux内核本身还不包含的,需提供I2C适配器的硬件驱动,探测并初始化I2C适配器(如申请I2C的I/O地址和中断号)、驱动CPU控制的I2C适配器从硬件上产生各种信号以及处理I2C中断等。提供I2C适配器的algorithm,具体适配器的xxx_xfer()函数填充i2c_algorithm的master_xfer指针,并把i2c_algorithm指针赋值给i2c_adapter的algo指针。驱动内的probe函数的最后,通过执行i2c_add_adapter()将适配器驱动注册进入Linux内核。
主控芯片的设备树dts文件中,有多少个i2c总线匹配上了名称,probe函数就执行多少次,每一条名字匹配上的i2c总线,分别i2c_add_adapter()一次。
设备驱动:(驱动工程师负责的,给不同的具体设备写不同的设备驱动,比如某个型号的摄像头)实现I2C设备驱动中的i2c_driver接口,具体设备yyy_probe()、yyy_remove()、yyy_suspend()、yyy_resume()函数指针和i2c_device_id设备ID表赋值给i2c_driver的probe、remove、suspend、resume和id_table指针。一开始,驱动入口处通过执行i2c_add_driver()将I2C设备驱动注册进入Linux内核。
在LINUX内核中,每个IIC驱动对应的结构体为struct i2c_driver。在xxx_probe()的最后,会使用device_create在/sys/class/ 下创建设备一个文件节点。

Linux i2c驱动架构:

I2C子系统的4个关键结构体
struct i2c_adapter:I2C适配器。在i2c适配器驱动内初始化,芯片厂商负责写好,不同的芯片平台有不同的适配器驱动。

struct i2c_algorithm:I2C算法,也叫通信方法。在i2c适配器驱动内初始化,芯片厂商负责写好,不同的芯片平台有不同的算法。 缺少i2c_algorithm的i2c_adapter什么也做不了,因此i2c_adapter中包含其使用i2c_algorithm的指针。i2c_algorithm中的关键函数master_xfer()用于(用写主控芯片寄存器的方式)产生i2c访问周期需要的start stop ack信号,以i2c_msg(即i2c消息)为单位发送和接收通信数据。

struct i2c_driver:对应一套驱动方法,其主要是驱动我们的i2c设备的,比如设备的初始化、上电时序、下电时序等等。包含很多函数指针,指向实现不同具体功能的函数。

struct i2c_client:对应真实的i2c物理设备device,每个i2c设备都需要一个i2c_client来描述。包含很多设备相关的信息。


  驱动中i2c_adapter和i2c_client的关系与i2c实际硬件中适配器(某个I2C总线)和设备(某个设备)的关系一致,即i2c_client依附于i2c_adapter,由于一个适配器上可以连接多个i2c设备,所以i2c_adapter中包含依附于它的i2c_client的链表。


各种I2C接口的设备驱动都需要通过I2C子系统的i2c-core-base.c内提供的API “i2c_transfer()”来进行读写寄存器的 *** 作。瑞芯微的os04a10.c驱动中使用i2c_master_send()来发送I2C数据,i2c_transfer()来读取I2C数据,但是i2c_master_send()最终也是调用i2c_transfer()。 i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 其中第1个参数是client(某个具体设备,比如某个摄像头)下的某个adapter(某个I2C适配器,也就是具体是主控芯片中的I2C几,比如I2C1、I2C2、I2C0)。每个设备都记录着自己是位于哪个I2C适配器(I2C总线)下面。 其中第2个参数i2c_msg,里面包含了从机I2C地址。
struct i2c_msg {
	__u16 addr;	
	__u16 flags;
	__u16 len;	
	__u8 *buf;	
};

I2C总线的i2c_client是在哪生成的? https://blog.csdn.net/qq_45544223/article/details/109673067 S:I2C总线的i2c_client的提供是内核通过i2c_add_adapter/i2c_add_numbered_adapter接口调用时自动生成的,生成的原料是mach-x210.c中的i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));生成之后就能与i2c_drivert通过i2c_driver的id_table里面的名字匹配。

读写I2C寄存器的流程是怎么样的,如下图:

在用户空间时,在/dev/i2c-x文件接口,使用文件 *** 作来写入I2C数据,I2C数据传输到内核空间中的write()函数,再传输到i2c_master_send(),最后调用i2c_transfer()将数据最终传输给i2c-adapter也就是i2c适配器驱动(就是主控芯片里的i2c模块对应的驱动),内对应的i2c_algorithm里的master_xfer()函数,该函数通过写主控芯片寄存器的方式,控制主控芯片内部的i2c模块发送标准的i2c时序(start stop ack信号),传输I2C数据给具体的i2c设备(比如摄像头)。







参考文章:
https://blog.csdn.net/wangpengqi/article/details/17711165
https://blog.csdn.net/jluyangsonghua/article/details/62424418
https://blog.csdn.net/tang_jin_chan/article/details/10211277
https://blog.csdn.net/Groupers/article/details/114859649
https://blog.csdn.net/u012830148/article/details/80309296

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5593697.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-15
下一篇 2022-12-15

发表评论

登录后才能评论

评论列表(0条)

保存