I2C驱动学习

I2C驱动框架类似于SPI驱动框架

依然是controller(adapter)为platform_bus上的device

然后对于client,采用I2C自定义的bus_type,负责管理和匹配i2c_driver,和i2c_client (实际情况是adapter也被注册到了i2c_bus上,详见[与spi总线的区别])

重要结构体

i2c_adapter

该结构体就代表了注册到系统总线上的i2c_controller,如下图设备树中所示的信息就记录在了这个结构体中

其中最重要的两个变量分别是

i2c_algorithm :是一个由i2c_controller的驱动在probe时实现的操作该i2c_controller发送和接收的函数结构体

nr:代表了其是系统中被注册进去的第几个i2c_adapter,在别的i2c_client的驱动使用i2c_adapter中的函数发送和接收数据的时候,就可以通过该编号找到对应的i2c_adapter

i2c_client

其中比较重要的几个参数为:

flags:负责表示其是10位地址还是7位地址

addr:记录注册到i2c总线中的i2c设备的地址

adapter:记录自己在物理上属于哪个adapter的从设备,发送和接收就找它

irq:记录该设备申请的全局虚拟中断号

i2c_msg

使用i2c_algorithm中的传输函数的时候,需要传入i2c_msg结构体,由该结构体记录要传输的方向(收还是发),提供缓冲区,传输多长等等

比如上面

addr:记录从设备地址,默认低位是0(写的地址),与上I2C_M_RD就变成了读的地址

flag:负责记录下面的宏是否启用

len:传输的数据长度

buf:指向缓冲区

imx6ull的i2c驱动源码学习

入口文件为i2c-imx.c

probe函数

第一部分

1057,获取驱动私有数据,里面包含了一些时钟分频的往寄存器中写的数据

1059行,定义了一个imx在内核i2c_adapter基础上包装好后自定义的i2c控制器的结构体,其包括了i2c_adapter在首位,所以完美兼容i2c_adapter的设计

1068行,获取设备树中写了的物理中断号对应的全局虚拟中断号

1074,1075行,映射寄存器地址到一个虚拟地址,方便后续写寄存器

1080行,申请i2c_imx(即i2c_adapter)

1084行,获取硬编码的驱动数据

第二部分

1091行,设置i2c设备的名字,这里是从设备树拷贝了

1093行,设置收发的操作函数,这里是imx的bsp工程师定义好的

i2c_imx_xfer函数会解析i2c_msg,然后写对应寄存器开始传输,传输完成后会进入中断函数再处理

同时其内部调用的发送函数会调用i2c_imx_trx_complete等待中断函数通知等待队列当前发送完成了

1094行,给adapter对应的dev设置parent,方便注册后加入sys层级结构

1095行,设置nr为设备树中的id,比如i2c1,i2c2等

1096行,继承设备树节点信息

1097行,继承获取并映射好的寄存器基地址

1106行,开启对应i2c控制器的时钟

1113行,为本i2c控制器,注册一个中断处理函数

第三部分

1121行,初始化一个等待队列

1124行,设置i2c_imx作为私有数据到i2c_adapter对应的device上挂着

1127行,把i2c_imx作为私有数据挂到pdev的device上挂着 何意味?

1129,一些电源管理方面的设置

1140,根据设备树中写的clock_frequency,直接赋值给i2c_imx中的bitrate变量

第四部分

1145,写i2c_controller的寄存器,将其设置为就绪状态

1151,保存当前状态,可选的一个恢复函数

1157,注册编号好了的adapter到内核中

1171,如果支持dma,初始化dma直接内存读取,后续传输可能会用到

对于i2c_client的注册

添加设备的两种方式

在用户态生成

可以往对应i2c设备节点下的属性文件写名字和地址来注册i2c_client

复制代码
// 在I2C BUS0下创建i2c_client
# echo ap3216c 0x1e > /sys/bus/i2c/devices/i2c-0/new_device

// 删除i2c_client
# echo 0x1e > /sys/bus/i2c/devices/i2c-0/delete_device

使用设备树生成

在某个I2C控制器的节点下,添加如下代码:

c 复制代码
ap3216c@1e {
			compatible = "lite-on,ap3216c";
			reg = <0x1e>;
		};
在什么时候被注册到i2c_bus上

在前面驱动的probe函数做好准备工作并调用i2c_add_numbered_adapter的时候

复制代码
i2c_add_numbered_adapter->
	__i2c_add_numbered_adapter->
			i2c_register_adapter->
				of_i2c_register_devices(adap)和i2c_acpi_register_devices(adap)
					内部会解析设备树上的i2c_client节点,并且注册其到i2c_bus上

与spi总线的区别

我觉得最大的区别在于,spi的master只是作为一个类设备存在,而i2c的控制器会被注册到系统中的i2c总线上

原因可能是:

spi物理设计上是单主机的模式,即master不存在作为slaver的情况

i2c则是每个设备都有作为master或者slaver的情况,所以i2c_adapter被注册到i2c_bustype上就不足为奇了

参考:韦东山linux驱动大全

相关推荐
爱编码的小八嘎2 小时前
C语言完美演绎6-12
c语言
321.。2 小时前
Linux 进程控制深度解析:从创建到替换的完整指南
linux·开发语言·c++·学习
小Tomkk2 小时前
怎么配置 Visual Studio Code 配置 C/C++
c语言·c++·vscode
算法鑫探3 小时前
C语言实战:学生成绩统计与分析
c语言·数据结构·算法·新人首发
qq_448011163 小时前
C语言的结构体
c语言
123过去3 小时前
trufflehog使用教程
linux·测试工具·安全
代码AC不AC3 小时前
【Linux】System V 通信方式
linux·消息队列·共享内存·信号量·system v
vortex53 小时前
vmware虚拟机设置启动时进入live cd
linux·网络安全
Lugas Luo3 小时前
Ascend 310B 定制 SDHCI 主机控制器源码深层次劫持与优化解析
linux·嵌入式硬件