i2c总线驱动详解

I2c总线应用也是很广泛的,i2c总线经常挂载eeprom、温度传感器、湿度传感器等设备。I2c总线下可以挂载多个设备,识别设备采用一个地址,这个地址在一条i2c总线是独一无二的。I2c总线驱动与spi总线驱动框架是一致的,都是采用控制器、core、设备三层驱动。下面开始讲解i2c总线驱动流程。强烈建议读者看完本篇文章。

首先看一下设备树文件,本次示例程序是一个i2c控制器下挂在eeprom设备。由于作者手上没有对应的开发板平台,所以只能分析源码。设备树文件如下:

将图中的24c02修改成eeprom,这个没有什么影响,仅仅是用来做platfrom的匹配。Eeprom设备的地址是0x50,挂在到i2c控制器1上的。

下面开始分析控制器驱动程序,控制器驱动程序采用的是platform匹配方式。

这里就是前文屡次提到的platform结构,匹配成功后就调用probe函数。Probe函数中主要是构造i2c_adapter这个适配器结构,然后注册。

930:自定义的结构,内存包含中断、内存、实质、适配器等变量;这样方便内部耦合

934:分配内存结构

938:将该id指针赋值到platfrom私有指针,方便id指针的传递

940:获取platform用户私有数据

946:获取内存地址

951:得到中断信息

953~958:给i2c_adapter赋值,其中algo_data指针作为私有指针,存储Id指针

960~976:获取时钟,使能时钟

993:注册中断,csdn_i2c_isr为中断函数,id为参数信息

1000:注册i2c_adapter适配器。

 

I2c-core核心层负责建立控制器与设备之间的桥梁,提供注册控制器函数,i2c设备注册函,以及匹配i2c设备函数。

控制器注册函数如下:

 

1517:获取当前控制器的总线号,其实就是设备树定义的i2c0、i2c1中的数字1和2。

1533:真正注册适配器的函数

i2c_register_adapter这个函数中有一个很重要的部分,那就是建立控制器与i2c设备之间的联系,部分程序如下。

1454~1457:注册安装适配器信息

1460:扫描控制器下挂载的设备,建立桥梁

__i2c_board_list这个链表是在解析所有i2c下挂在的设备,设备在哪个控制器下是通过busnum总线号,如果匹配到挂在到当前控制器下的设备,那么久执行i2c_new_device函数新建一个设备项,i2c_new_device函数分析如下。

在这个函数只需要关心i2c_bus_type和device_register。包括平台总线管理也是通过这样的方式,device_register注册函数是所有的总线注册函数之源头,都会调用这个函数。dev.of_node是用来做匹配i2c设备驱动的。

i2c_bus_type总线定义与注册如下所示:

i2c_bus_type结构中有match函数作为匹配device_register和drivere_register两个部分,匹配成功后调用probe函数,即是eeprom设备中的probe函数。

开始分析eeprom设备驱动程序,驱动入口定义函数。   

这个没什么分析的,name和id_table用做匹配。细心的读者可能看到最后的注册函数与platform注册函数封装很相似,我们继续进入到这个结构观察分析。

还是用到了宏的联合剂、回调函数特性。i2c_add_driver其实是调用i2c_register_driver。

i2c_register_driver函数中同样传递了i2c_bus_type总线结构,采用driver_register去注册drv部分驱动程序,当device_register和drivere_register两个部分匹配成功后才会调用drv部分的probe函数,同时传入该控制器的指针。

160:得到I2c控制器的指针

163:分配eeprom数据空间指针,并且指向client的私有指针

175~189:验证标志位

192:创建sys接口,给应用程序提供访问的接口

sysfs_create_bin_file函数创建sysfs接口是通过第二个参数,该参数中定义读写函数,eeprom只定义了读函数。

Read函数参数与file_operations参数基本一致,只是多了kobject和bin_attribute。

Filp:文件描述指针

Buf:内核给用户空间传递数据的buff

Off:读写数据的偏移

Count:读写读书的长度。

函数中读取eeprom中的数据可以使用i2c控制器定义的读写函数按照eeprom时序去读写。

I2c定义了通用的读写函数,但是最后跟硬件打交道右回到了i2c控制器层驱动程序的cdns_i2c_master_xfer发送函数中。I2c驱动程序流程分析完毕。

有读者问我module_init函数在哪里被调用,这里我顺便补充一下。大家都知道Bootloadr到启动内核后进入内核的第一个c函数是start_kernel,该函数做一系列的初始化,最后执行到rest_init函数。

rest_init->kernel_init->kernel_init_freeable->do_basic_setup->do_initcalls

在图中就会根据优先级别调用module_init,优先级别体现在下图中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HeroKern

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值