LinuxI2C总线分析主要是probe的方式1Word文档格式.docx

上传人:b****4 文档编号:18166968 上传时间:2022-12-13 格式:DOCX 页数:12 大小:166.39KB
下载 相关 举报
LinuxI2C总线分析主要是probe的方式1Word文档格式.docx_第1页
第1页 / 共12页
LinuxI2C总线分析主要是probe的方式1Word文档格式.docx_第2页
第2页 / 共12页
LinuxI2C总线分析主要是probe的方式1Word文档格式.docx_第3页
第3页 / 共12页
LinuxI2C总线分析主要是probe的方式1Word文档格式.docx_第4页
第4页 / 共12页
LinuxI2C总线分析主要是probe的方式1Word文档格式.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

LinuxI2C总线分析主要是probe的方式1Word文档格式.docx

《LinuxI2C总线分析主要是probe的方式1Word文档格式.docx》由会员分享,可在线阅读,更多相关《LinuxI2C总线分析主要是probe的方式1Word文档格式.docx(12页珍藏版)》请在冰豆网上搜索。

LinuxI2C总线分析主要是probe的方式1Word文档格式.docx

/*thealgorithmtoaccessthebus*/

void*algo_data;

/*datafieldsthatarevalidforalldevices*/

u8level;

/*nestinglevelforlockdep*/

structmutexbus_lock;

inttimeout;

/*injiffies*/

intretries;

structdevicedev;

/*theadapterdevice*/

intnr;

charname[48];

structcompletiondev_released;

Linux的I2C体系结构分为3个组成部分:

I2C核心:

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

这部分是与平台无关的。

I2C总线驱动:

I2C总线驱动是对I2C硬件体系结构中适配器端的实现。

I2C总线驱动主要包含了I2C适配器数据结构i2c_adapter、I2C适配器的algorithm数据结构i2c_algorithm和控制I2C适配器产生通信信号的函数。

经由I2C总线驱动的代码,我们可以控制I2C适配器以主控方式产生开始位、停止位、读写周期,以及以从设备方式被读写、产生ACK等。

不同的CPU平台对应着不同的I2C总线驱动。

总线驱动的职责,是为系统中每个I2C总线增加相应的读写方法。

但是总线驱动本身并不会进行任何的通讯,它只是存在在那里,等待设备驱动调用其函数。

这部分在MTK6516中是由MTK已经帮我们实现了的,不需要我们更改。

I2C设备驱动:

I2C设备驱动是对I2C硬件体系结构中设备端的实现。

设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。

I2C设备驱动主要包含了数据结构i2c_driver和i2c_client,我们需要根据具体设备实现其中的成员函数。

在Linux内核源代码中的drivers目录下的i2c_dev.c文件,实现了I2C适配器设备文件的功能,应用程序通过“i2c-%d”文件名并使用文件操作接口open()、write()、read()、ioctl()和close()等来访问这个设备。

应用层可以借用这些接口访问挂接在适配器上的I2C设备的存储空间或寄存器并控制I2C设备的工作方式。

设备驱动则是与挂在I2C总线上的具体的设备通讯的驱动。

通过I2C总线驱动提供的函数,设备驱动可以忽略不同总线控制器的差异,不考虑其实现细节地与硬件设备通讯。

这部分在MTK6516中是由具体的设备实现的。

(比如camera)

structi2c_client:

代表一个挂载到i2c总线上的i2c从设备,该设备所需要的数据结构,其中包括该i2c从设备所依附的i2c主设备structi2c_adapter*adapter该i2c从设备的驱动程序structi2c_driver*driver作为i2c从设备所通用的成员变量,比如addr,name等该i2c从设备驱动所特有的数据,依附于dev->

driver_data下

structi2c_adapter:

代表主芯片所支持的一个i2c主设备。

structi2c_algorithm*algo:

是该i2c主设备传输数据的一种算法,或者说是在i2c总线上完成主从设备间数据通信的一种能力。

Linux的i2c子系统新、旧架构并存。

主要分为旧架构(Legacy)也有人称之为adapter方式,和新的架构new-style的方式。

这俩者的区别主要在于设备注册和驱动注册的不同。

对于Legacy的设备注册是在驱动运行的时候动态的创建,而新式的new-style则是采用静态定义的方式。

注:

MTK在Android2.1版上用的是Legacy的架构,而在Android2.2版上用的是new-style的架构。

(在这里我就只说明Android2.2的new-style的实现方法)

要完成I2C设备的驱动,我们可以分三步走:

第一步:

完成适配器的注册(总线);

第二步:

完成I2Cclient的设备注册(设备);

第三步:

完成I2Cclient驱动的注册(驱动);

我们分别给予介绍:

(I2C-mt6516.c)

⑴就总线而言,其本质只需要我们填充俩个结构体就可以了:

i2c_adapter;

i2c_algorithm;

i2c_add_adapter(i2c->

adap);

往总线上添加对应的适配器;

structi2c_adapter{ 

structmodule*owner;

unsignedintid;

unsignedintclass;

/*classestoallowprobingfor*/ 

conststructi2c_algorithm*algo;

/*thealgorithmtoaccessthebus*/ 

void*algo_data;

/*---administrationstuff.*/ 

int(*client_register)(structi2c_client*);

int(*client_unregister)(structi2c_client*);

/*datafieldsthatarevalidforalldevices*/ 

u8level;

/*nestinglevelforlockdep*/ 

structmutexbus_lock;

structmutexclist_lock;

inttimeout;

/*injiffies*/ 

intretries;

structdevicedev;

/*theadapterdevice*/ 

intnr;

/*该成员描述了总线号*/ 

structlist_headclients;

/*i2c_client结构链表,该结构包含device,driver和 

adapter结构*/ 

charname[48];

structcompletiondev_released;

staticstructi2c_algorithmmt6516_i2c_algorithm={

.master_xfer=mt6516_i2c_transfer,

.smbus_xfer=NULL,

.functionality=mt6516_i2c_functionality,

2、设备注册

记得以前的i2c设备驱动,设备部分喜欢驱动运行的时候动态创建,新式的驱动倾向于向传统的linux下设备驱动看齐,采用静态定义的方式来注册设备,使用接口为:

int__initi2c_register_board_info(intbusnum,

structi2c_board_infoconst*info,unsignedlen)

{

intstatus;

mutex_lock(&

__i2c_board_lock);

/*dynamicbusnumberswillbeassignedafterthelaststaticone*/

if(busnum>

=__i2c_first_dynamic_bus_num)

__i2c_first_dynamic_bus_num=busnum+1;

for(status=0;

len;

len--,info++){

structi2c_devinfo*devinfo;

devinfo=kzalloc(sizeof(*devinfo),GFP_KERNEL);

//申请表示i2c设备的结构体空间

if(!

devinfo){

pr_debug("

i2c-core:

can'

tregisterboardinfo!

\n"

);

status=-ENOMEM;

break;

}

/*填写i2c设备描述结构*/

devinfo->

busnum=busnum;

board_info=*info;

list_add_tail(&

devinfo->

list,&

__i2c_board_list);

//添加到全局链表__i2c_board_list中

mutex_unlock(&

returnstatus;

}

在系统初始化的过程中,我们可以通过i2c_register_board_info,将所需要的I2C从设备加入一个名为__i2c_board_list双向循环链表,系统在成功加载I2C主设备adapt后,就会对这张链表里所有I2C从设备逐一地完成i2c_client的注册。

系统初始化的时候,会根据板级i2c设备配置信息,创建i2c客户端设备(i2c_client),添加到i2c子系统中:

staticvoidi2c_scan_static_board_info(structi2c_adapter*adapter)

list_for_each_entry(devinfo,&

__i2c_board_list,list){//遍历全局链表__i2c_board_list

if(devinfo->

busnum==adapter->

nr

&

&

!

i2c_new_device(adapter,

board_info))

printk(KERN_ERR"

tcreatei2c%d-%04x\n"

i2c_adapter_id(adapter),

board_info.addr);

structi2c_client*i2c_new_device(structi2c_adapter*adap,structi2c_board_infoconst*info)

structi2c_client*client;

intstatus;

client=kzalloc(sizeof*client,GFP_KERNEL);

client)

returnNULL;

client->

adapter=adap;

dev.platform_data=info->

platform_data;

if(info->

archdata)

client->

dev.archdata=*info->

archdata;

flags=info->

flags;

addr=info->

addr;

irq=info->

irq;

strlcpy(client->

name,info->

type,sizeof(client->

name));

/*Checkforaddressbusiness*/

status=i2c_check_addr(adap,client->

addr);

if(status)

gotoout_err;

dev.parent=&

client->

adapter->

dev;

dev.bus=&

i2c_bus_type;

dev.type=&

i2c_client_type;

dev_set_name(&

dev,"

%d-%04x"

i2c_adapter_id(adap),

status=device_register(&

dev);

dev_dbg(&

adap->

client[%s]registeredwithbusid%s\n"

name,dev_name(&

dev));

returnclient;

out_err:

dev_err(&

Failedtoregisteri2cclient%sat0x%02x"

"

(%d)\n"

client->

name,client->

addr,status);

kfree(client);

returnNULL;

IDR机制:

完成的是设备ID和结构体的关联。

__i2c_first_dynamic_bus_num:

当前系统允许的动态总线的最大值。

i2c_scan_static_board_info(adap);

/*完成新类型i2c设备的注册,一般只在主板初始化时*/ 

此函数为整个I2C子系统的核心,它会去遍历一个由I2C从设备组成的双向循环链表,并完成所有I2C从设备的i2c_client的注册。

structi2c_devinfo*devinfo;

//已经建立好了的I2C从设备链表

status=i2c_check_addr(adap,client->

特别要提一下的是这个“i2c_check_addr”,引用<

<

i2c源代码情景分析>

>

里的话:

“i2c设备的7位地址是就当前i2c总线而言的,是“相对地址”。

不同的i2c总线上的设备可以使用相同的7位地址,但是它们所在的i2c总线不同。

所以在系统中一个i2c设备的“绝对地址”由二元组(i2c适配器的ID和设备在该总线上的7位地址)表示。

”,所以这个函数的作用主要是排除同一i2c总线上出现多个地址相同的设备。

3、I2C驱动注册:

staticinlineinti2c_add_driver(structi2c_driver*driver)

returni2c_register_driver(THIS_MODULE,driver);

inti2c_register_driver(structmodule*owner,structi2c_driver*driver)

intres;

/*Can'

tregisteruntilafterdrivermodelinit*/

if(unlikely(WARN_ON(!

i2c_bus_type.p)))

return-EAGAIN;

/*addthedrivertothelistofi2cdriversinthedrivercore*/

driver->

driver.owner=owner;

driver.bus=&

/*Whenregistrationreturns,thedrivercore

*willhavecalledprobe()forallmatching-but-unbounddevices.

res=driver_register(&

driver->

driver);

if(res)

returnres;

driver[%s]registered\n"

driver->

driver.name);

INIT_LIST_HEAD(&

clients);

/*Walktheadaptersthatarealreadypresent*/

core_lock);

bus_for_each_dev(&

i2c_bus_type,NULL,driver,__attach_adapter);

return0;

设备和驱动的关联过程:

首先当I2C从设备和I2C驱动如果处于同一条总线上,那么其在设备和驱动注册之后,将会促使I2C_bus_type中的match获得调用;

()如下:

structbus_typei2c_bus_type={

.name="

i2c"

.match=i2c_device_match,

.probe=i2c_device_probe,

.remove=i2c_device_remove,

.shutdown=i2c_device_shutdown,

.suspend=i2c_device_suspend,

.resume=i2c_device_resume,

继续跟进i2c_device_match;

i2c_match_id(driver->

id_table,client)!

=NULL;

我们回到i2c_device_probe;

这个函数的关键是:

status=driver->

probe(client,i2c_match_id(driver->

id_table,client));

它将函数的流程交回到了driver->

probe的手中;

流程图:

过程分享:

1、设备和驱动的关联

大家知道,对于一个驱动程序有两个元素不可或缺,即设备和驱动,一般驱动都是通过设备名和驱动名的匹配建立关系的,最开始我从代码中只能发现驱动的注册,却不见设备注册的踪影,令人疑惑,跟踪发现,在i2cadapter注册时会遍历i2c_board_info这样一个结构,而这个结构在29以前或更早的内核里是不存在的,它会完成驱动与设备的匹配问题,

2、名字匹配

一个i2c驱动是可以有多个名字的,即一个驱动程序可以支持多个设备,该机制是通过structi2c_device_id实现的,驱动中建立这么一个结构体数组,i2c架构层便会扫描该数组,与设备名去匹配,匹配成功的都会进入相应probe函数。

3、进入probe

该过程困惑了我一段时间,其实要进入自己驱动的probe首先需要进入总线的probe,而进入总线probe的前提是与总线的match成功。

待解决的困惑:

1、I2C从设备名;

Legacy的相关知识:

(一)Linux的I2C驱动框架中的主要数据结构及其关系

Linux的I2C驱动框架中的主要数据结构包括:

i2c_driver、i2c_client、i2c_adapter和i2c_algorithm。

i2c_adapter对应于物理上的一个适配器,这个适配器是基于不同的平台的,一个I2C适配器需要i2c_algorithm中提供的通信函数来控制适配器,因此i2c_adapter中包含其使用的i2c_algorithm的指针。

i2c_algorithm中的关键函数master_xfer()以i2c_msg为单位产生I2C访问需要的信号。

不同的平台所对应的master_xfer()是不同的,开发人员需要根据所用平台的硬件特性实现自己的XXX_xfer()方法以填充i2c_algorithm的master_xfer指针。

i2c_driver对应一套驱动方法,不对应于任何的物理实体。

i2c_client对应于真实的物理设备,每个I2C设备都需要一个i2c_client来描述。

i2c_client依附于i2c_adpater

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1