ImageVerifierCode 换一换
格式:DOC , 页数:11 ,大小:478KB ,
资源ID:3560619      下载积分:8 金币
快捷注册下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

开通VIP
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.zixin.com.cn/docdown/3560619.html】到电脑端继续下载(重复下载【60天内】不扣币)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

开通VIP折扣优惠下载文档

            查看会员权益                  [ 下载后找不到文档?]

填表反馈(24小时):  下载求助     关注领币    退款申请

开具发票请登录PC端进行申请

   平台协调中心        【在线客服】        免费申请共赢上传

权利声明

1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。

注意事项

本文(Linux-I2C总线分析(主要是probe的方式).doc)为本站上传会员【精****】主动上传,咨信网仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知咨信网(发送邮件至1219186828@qq.com、拔打电话4009-655-100或【 微信客服】、【 QQ客服】),核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载【60天内】不扣币。 服务填表

Linux-I2C总线分析(主要是probe的方式).doc

1、 Linux I2C 总线浅析 ㈠ Overview 内核空间层次! i2c adapter 是一个struct, 用来抽象一个物理i2c bus ,而且还和linux 设备驱动架构柔和在一起.. 如果只说硬件的话,就是在CPU内部集成的一个I2C控制器(提供给用户的就是那几个register),硬件上并没的所谓的adapter,client这些东东,,adapter和client都是linux驱动软件抽象出来的东西 资料帖子: struct i2c_algorithm { /* If an adapter algorit

2、hm can't do I2C-level access, set master_xfer to NULL. If an adapter algorithm can do SMBus access, set smbus_xfer. If set to NULL, the SMBus protocol is simulated using common I2C messages */ /* master_xfer should return the number of messages successfully processed, or a nega

3、tive value on error */ int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data); /* To determine what the a

4、dapter supports */ u32 (*functionality) (struct i2c_adapter *); }; /* * i2c_adapter is the structure used to identify a physical i2c bus along * with the access algorithms necessary to access it. */ struct i2c_adapter { struct module *owner; unsigned int id; unsigned int class;

5、 /* classes to allow probing for */ const struct i2c_algorithm *algo; /* the algorithm to access the bus */ void *algo_data; /* data fields that are valid for all devices */ u8 level; /* nesting level for lockdep */ struct mutex bus_lock; int timeout; /* in jiffies */ int retr

6、ies; struct device dev; /* the adapter device */ int nr; char name[48]; struct completion dev_released; }; Linux的I2C体系结构分为3个组成部分: 1·I2C核心: I2C核心提供了I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法(即“algorithm”)上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。这部分是与平台无关的。 2·I2C总线驱动: I2C总线驱动是对I2C硬件体系结构中适配器端的实现。I2C总线驱动

7、主要包含了I2C适配器数据结构i2c_adapter、I2C适配器的algorithm数据结构i2c_algorithm和控制I2C适配器产生通信信号的函数。经由I2C总线驱动的代码,我们可以控制I2C适配器以主控方式产生开始位、停止位、读写周期,以及以从设备方式被读写、产生ACK等。不同的CPU平台对应着不同的I2C总线驱动。 总线驱动的职责,是为系统中每个I2C总线增加相应的读写方法。但是总线驱动本身并不会进行任何的通讯,它只是存在在那里,等待设备驱动调用其函数。 这部分在MTK 6516中是由MTK已经帮我们实现了的,不需要我们更改。 3· I2C设备驱动: I2C设备驱动是对

8、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设备的工作方式。 设备驱动则是与挂在I

9、2C总线上的具体的设备通讯的驱动。通过I2C总线驱动提供的函数,设备驱动可以忽略不同总线控制器的差异,不考虑其实现细节地与硬件设备通讯。 这部分在MTK 6516中是由具体的设备实现的。(比如camera) struct i2c_client: 代表一个挂载到i2c总线上的i2c从设备,该设备所需要的数据结构,其中包括该i2c从设备所依附的i2c主设备 struct i2c_adapter *adapter 该i2c从设备的驱动程序struct i2c_driver *driver 作为i2c从设备所通用的成员变量,比如addr, name等 该i2c从设备驱动所特有的数据,依附于d

10、ev->driver_data下 struct i2c_adapter: 代表主芯片所支持的一个i2c主设备。 struct i2c_algorithm *algo: 是该i2c主设备传输数据的一种算法,或者说是在i2c总线上完成主从设备间数据通信的一种能力。 Linux的i2c子系统新、旧架构并存。主要分为旧架构(Legacy)也有人称之为adapter方式,和新的架构new-style的方式。 这俩者的区别主要在于设备注册和驱动注册的不同。对于Legacy的设备注册是在驱动运行的时候动态的创建,而新式的new-style则是采用静态定义的方式。 注:MTK在A

11、ndroid2.1版上用的是Legacy的架构,而在Android2.2版上用的是new-style的架构。(在这里我就只说明Android2.2的new-style的实现方法) 要完成I2C设备的驱动,我们可以分三步走: 第一步:完成适配器的注册(总线); 第二步:完成I2C client的设备注册(设备); 第三步:完成I2C client驱动的注册(驱动); 我们分别给予介绍:(I2C-mt6516.c) ⑴就总线而言,其本质只需要我们填充俩个结构体就可以了: i2c_adapter;i2c_algorithm; i2c_add_adapter(i2c->adap

12、); 往总线上添加对应的适配器; struct i2c_adapter {    struct module *owner;    unsigned int id;    unsigned int class;    /* classes to allow probing for */   const struct i2c_algorithm *algo; /* the algorithm to access the bus */   void *algo_data;    /* --- administration stuff. */   int (*c

13、lient_register)(struct i2c_client *);    int (*client_unregister)(struct i2c_client *);      /* data fields that are valid for all devices */   u8 level;    /* nesting level for lockdep */   struct mutex bus_lock;    struct mutex clist_lock;      int timeout;   /* in jiffies */   i

14、nt retries;    struct device dev;  /* the adapter device */     int nr; /*该成员描述了总线号*/   struct list_head clients; /* i2c_client结构链表,该结构包含device,driver和  adapter结构*/   char name[48];    struct completion dev_released;   };  static struct i2c_algorithm mt6516_i2c_algorithm = {

15、master_xfer = mt6516_i2c_transfer, .smbus_xfer = NULL, .functionality = mt6516_i2c_functionality, }; 2、设备注册 第一步: 记得以前的i2c设备驱动,设备部分喜欢驱动运行的时候动态创建,新式的驱动倾向于向传统的linux下设备驱动看齐,采用静态定义的方式来注册设备,使用接口为: int __init i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigne

16、d len) { int status; mutex_lock(&__i2c_board_lock); /* dynamic bus numbers will be assigned after the last static one */ if (busnum >= __i2c_first_dynamic_bus_num) __i2c_first_dynamic_bus_num = busnum + 1; for (status = 0; len; len--, info++) { struct

17、 i2c_devinfo *devinfo; devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);//申请表示i2c设备的结构体空间 if (!devinfo) { pr_debug("i2c-core: can't register boardinfo!\n"); status = -ENOMEM; break; } /* 填写i2c设备描述结构 */ devinfo->b

18、usnum = busnum; devinfo->board_info = *info; list_add_tail(&devinfo->list, &__i2c_board_list);//添加到全局链表__i2c_board_list中 } mutex_unlock(&__i2c_board_lock); return status; } 在系统初始化的过程中,我们可以通过 i2c_register_board_info,将所需要的I2C从设备加入一个名为__i2c_board_list双向循环链表,系统在成功加

19、载I2C主设备adapt后,就会对这张链表里所有I2C从设备逐一地完成 i2c_client的注册。 第二步: 系统初始化的时候,会根据板级i2c设备配置信息,创建i2c客户端设备(i2c_client),添加到i2c子系统中: static void i2c_scan_static_board_info (struct i2c_adapter *adapter) { struct i2c_devinfo *devinfo; mutex_lock(&__i2c_board_lock); list_for_each_entry(devinf

20、o, &__i2c_board_list, list) { //遍历全局链表__i2c_board_list if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info)) printk(KERN_ERR "i2c-core: can't create i2c%d-%04x\n", i2c_adapter_id(adapt

21、er), devinfo->board_info.addr); } mutex_unlock(&__i2c_board_lock); } struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) { struct i2c_client *client; int status; client = kzalloc(sizeof *client, GFP_KERNEL); if (!

22、client) return NULL; client->adapter = adap; client->dev.platform_data = info->platform_data; if (info->archdata) client->dev.archdata = *info->archdata; client->flags = info->flags; client->addr = info->addr; client->irq = info->irq; strlcpy(client->name, info->type, s

23、izeof(client->name)); /* Check for address business */ status = i2c_check_addr(adap, client->addr); if (status) goto out_err; client->dev.parent = &client->adapter->dev; client->dev.bus = &i2c_bus_type; client->dev.type = &i2c_client_type; dev_set_name(&client->dev, "%d-%04x",

24、 i2c_adapter_id(adap), client->addr); status = device_register(&client->dev); if (status) goto out_err; dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n", client->name, dev_name(&client->dev)); return client; out_err: dev_err(&adap->dev, "Failed to register

25、 i2c client %s at 0x%02x " "(%d)\n", client->name, client->addr, status); kfree(client); return NULL; } IDR机制:完成的是设备ID和结构体的关联。 __i2c_first_dynamic_bus_num:当前系统允许的动态总线的最大值。 i2c_scan_static_board_info(adap);/*完成新类型i2c设备的注册,一般只在主板初始化时*/  此函数为整个I2C子系统的核心,它会去遍历一个由I2C从设备组成的双向循环链表,并完成所有I2

26、C从设备的i2c_client的注册。 struct i2c_devinfo *devinfo;     //已经建立好了的I2C从设备链表 status = i2c_check_addr(adap, client->addr); 注: 特别要提一下的是这个“i2c_check_addr”,引用<>里的话:“i2c 设备的7 位地址是就当前i2c 总线而言的,是“相对地址”。不同的i2c 总线上的设备可以使用相同的7 位地址,但是它们所在的i2c 总线不同。所以在系统中一个i2c 设备的“绝对地址”由二元组(i2c 适配器的ID 和设备在该总线

27、上的7 位地址)表示。”,所以这个函数的作用主要是排除同一i2c总线上出现多个地址相同的设备。 3、I2C驱动注册: 第一步: static inline int i2c_add_driver(struct i2c_driver *driver) { return i2c_register_driver(THIS_MODULE, driver); } int i2c_register_driver(struct module *owner, struct i2c_driver *driver) { int res; /* Can't register u

28、ntil after driver model init */ if (unlikely(WARN_ON(!i2c_bus_type.p))) return -EAGAIN; /* add the driver to the list of i2c drivers in the driver core */ driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; /* When registration returns, the driver core * will have c

29、alled probe() for all matching-but-unbound devices. */ res = driver_register(&driver->driver); if (res) return res; pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); INIT_LIST_HEAD(&driver->clients); /* Walk the adapters that are already present */ mutex_lock

30、core_lock); bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter); mutex_unlock(&core_lock); return 0; } 设备和驱动的关联过程:首先当I2C从设备和I2C驱动如果处于同一条总线上,那么其在设备和驱动注册之后,将会促使I2C_bus_type中的match获得调用;()如下: struct bus_type i2c_bus_type = { .name = "i2c", .match = i2c_device_match, .p

31、robe = 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,

32、i2c_match_id(driver->id_table, client)); 它将函数的流程交回到了driver->probe的手中; 流程图: 过程分享: 1、设备和驱动的关联 大家知道,对于一个驱动程序有两个元素不可或缺,即设备和驱动,一般驱动都是通过设备名和驱动名的匹配建立关系的,最开始我从代码中只能发现驱动的注册,却不见设备注册的踪影,令人疑惑,跟踪发现,在i2c adapter注册时会遍历i2c_board_info这样一个结构,而这个结构在29以前或更早的内核里是不存在的,它会完成驱动与设备的匹配问题, 2、名字匹配 一个i2c驱动是可以

33、有多个名字的,即一个驱动程序可以支持多个设备,该机制是通过 struct i2c_device_id实现的,驱动中建立这么一个结构体数组,i2c架构层便会扫描该数组,与设备名去匹配,匹配成功的都会进入相应probe函数。 3、进入probe 该过程困惑了我一段时间,其实要进入自己驱动的probe首先需要进入总线的probe,而进入总线probe的前提是与总线的match成功。 待解决的困惑: 1、I2C从设备名; Legac

34、y 的相关知识: (一) 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访问需要的信号。不同的平台所对应的mas

35、ter_xfer()是不同的,开发人员需要根据所用平台的硬件特性实现自己的XXX_xfer()方法以填充i2c_algorithm的master_xfer指针。 i2c_ driver对应一套驱动方法,不对应于任何的物理实体。i2c_client对应于真实的物理设备,每个I2C设备都需要一个i2c_client来描述。i2c_client依附于i2c_adpater,这与I2C硬件体系中适配器和设备的关系一致。i2c_driver提供了i2c-client与i2c-adapter产生联系的函数。当attach a_dapter()函数探测物理设备时,如果确定存在一个client,则把该cli

36、ent使用的i2c_client数据结构的adapter指针指向对应的i2e_ adapter,driver指针指向该i2c_driver,并调用i2e_adapter的client_register()函数来注册此设备。相反的过程发生在i2c_ driver的detach_client()函数被调用的时候。 (二) Linux的I2C体系结构中三个组成部分的作用 I2C核心提供了一组不依赖于硬件平台的接口函数,I2C总线驱动和设备驱动之间依赖于I2C核心作为纽带。I2C核心提供了i2c_adapter的增加和删除函数、i2c_driver的增加和删除函数、i2c_client的

37、依附和脱离函数以及i2c传输、发送和接收函数。i2c传输函数i2c_transfer()用于进行I2C适配器和I2C设备之间的一组消息交互i2c_master_send()函数和i2c_master_recv()函数内部会调用i2c_ transfer()函数分别完成一条写消息和一条读消息. I2C总线驱动包括I2C适配器驱动加载与卸载以及I2C总线通信方法。其中I2C适配器驱动加载(与卸载)要完成初始化(释放)I2C适配器所使用的硬件资源,申请I/0地址、中断号、通过i2c_add_ adapter()添加i2c_adapter的数据结构(通过i2c_del_adapter()删除i2

38、c _adapter的数据结构)的工作。12C总线通信方法主要对特定的I2C适配器实现i2c_algorithm的master_xfer()方法来实现i2c_ msg的传输。不同的适配器对应的master_xfer()方法由其处理器的硬件特性决定。 I2C设备驱动主要用于I2C设备驱动模块加载与卸载以及提供I2C设备驱动文件操作接口。I2C设备驱动的模块加载通用的方法遵循以下流程:首先通过register_chrdev()将I2C设备注册为一个字符设备,然后利用I2C核心中的i2c_add_a_dapter()添加i2c_driver。调用i2c_add_adapter()过程中会引发i2c_driver结构体中的YYY_attach_adapter()的执行,它通过调用I2C核心的i2e_probe()实现物理设备的探测。i2c_probe()会引发yyy_detect()的调用。yyy_detect()中会初始化i2c_ client,然后调用内核的i2e_attach_client()通知I2C核心此时系统中包含了一个新的I2C设备。之后会引发I2C设备驱动中yyy_init_client()来初始化设备。卸载过程执行相反的操作。 I2C设备驱动模块加载与卸载的流程 如图2 所示。

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服