




已阅读5页,还剩26页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
内核中I2C体系结构1.总体框架21.1 I2C体系结构总体框图:21.2 组成部分:21.3 重要文件:31.4 重要函数接口与结构体3结构体:3函数:3各结构体的作用与它们之间的关系31.5 i2c子系统的初始化函数的执行先后顺序42.I2C核心42.1 i2c_init()函数42.1.1 i2c总线的注册52.1.2 i2c驱动注册62.1.3 i2c_init()函数总结63.总线驱动73.1 I2C platform_device初始化-smdk2440_machine_init()73.1.1 s3c_i2c_set_platdata 83.1.2 i2c_register_board_info93.1.3 platform_add_devices103.2 I2C platform_drive适配器驱动初始化-i2c_adap_s3c_init()103.3 platform_bus总线113.4总线设备和总线驱动初始化总结:113.5 probe函数adapter_device 和 client_device的注册12总结164,设备驱动174.1 i2c_dev_init()174.1.1 register_chardev174.1.2 i2c_add_drive 注册i2c_driver (i2cdev_driver)18总结i2c_dev_init() :205,i2c子系统通信方法205.1 open设备/dev/i2c-0205.2 write215.3 i2cdev_ioctl275.2.1 I2C_SLAVE / I2C_SLAVE_FORCE275.2.2 I2C_RDWR276,I2C子系统总结:29附录:30说明:内核版本: 2.6.32 I2C设备:E2PROM (at24c02)/* 跳过此内容不影响整体框架学习*/(标号) 上下文相互提到1.总体框架1.1 I2C体系结构总体框图:从i2c驱动架构图中可以看出,linux内核对i2c架构抽象了一个叫核心层core的中间件,它分离了设备驱动device driver和硬件控制的实现细节(如操作i2c的寄存器),core层不但为上面的设备驱动提供封装后的内核注册函数,而且还为小面的硬件事件提供注册接口(也就是i2c总线注册接口),可以说core层起到了承上启下的作用。1.2 组成部分:Linux的I2C体系结构分为3个组成部分:I2C设备驱动:提供策略,定义描述具体设备的i2c_client和可能的私有数据结构。是对I2C硬件体系结构中设备端的实现,设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。主要数据结构:i2c_driver, i2c_clientI2C框架层:i2c.h和i2c-core.c为其主体框架代码,提供了核心数据结构的定义、i2c适配器驱动和设备驱动的注册、注销管理等;i2c-dev.c用于创建i2c适配器的/dev/i2c-%d设备节点,提供i2c设备的用户空间访问方法等。I2C总线驱动:提供硬件操作能力。i2c/busses/目录下,如i2c-msm.c。描述i2c_adapter数据结构及其具体总线通信,适配器可由CPU控制,甚至可以直接集成在CPU内部。I2C控制驱动(总线驱动)在芯片(S3C2410)生产出来的时候生产厂商就已经写好了,且永远不变(1类芯片对应1种控制器驱动,控制器驱动就是去操作各种寄存器的值,实现标准I2C时序)1.3 重要文件:i2c-core.c实现I2C核心功能 以及/proc/bus/i2c*接口。 i2c-dev.c通用设备驱动。创建i2c适配器的/dev/i2c-%d设备节点(MAJOR=89,MINOR=0-255)每一个I2C适配器都被分配一个client。Busses包含I2C总线的驱动,如S3C2410,S3C2440的控制器驱动i2c-s3c2410.cAlgos实现I2C总线适配器的algorithm.1.4 重要函数接口与结构体结构体:Struct i2c_adapter/描述一个i2c控制器Struct i2c_driver/描述一个i2c设备驱动Struct i2c_client/描述一个i2c设备(e2prom)Struct i2c_msg/描述一个i2c消息结构体struct i2c_algorithm/描述一个i2c算法struct bus_type i2c_bus_type/用于管理的i2c_bus总线struct s3c24xx_i2c i2c/i2c_adapters的algo_data类似私有信息。封装适配器的所有信息。函数:i2c_add_driver/加载i2c设备驱动结构体到链表里i2c_add_adapter/加载i2c适配器结构体到适配器链表i2c_master_send/发送数据函数i2c_transfer/转接到底层的函数static int s3c24xx_i2c_probe(struct platform_device *pdev)/发现合适设备时会被bus driver调用各结构体的作用与它们之间的关系i2c_adapter与i2c_algorithmi2c_adapter对应物理上的适配器,用于产生I2C标准时序,产生方法由i2c_algorithm实现。i2c_driver和i2c_clienti2c_client = adapter+devinfo (_i2c_board_list链表上一个信息结构体)每个i2c设备都需要一个i2c_client来描述注册i2c_driver后程序调用其attach_adapter():将adapter加入到i2c_dev_list,并创建设备节点i2c-%d,应用层打开时i2c-%d,在此取出adapter。一个i2c_driver上可以支持多个同等类型的i2c_client.i2c_adapter和i2c_clienti2c_client依附于i2c_adapter,一个适配器上可以连接多个i2c设备,所以i2c_adapter中包含依附于它的i2c_client的链表。1.5 i2c子系统的初始化函数的执行先后顺序1. /dricer/i2c/i2c-core.c中的函数:i2c_init() postcore_initca级别2. /arch/arm/mach-s3c2440/mach-smdk2440.c中的函数:smdk2440_machine_init() arch_initcall级别3. driver/i2c/buses/i2c-s3c2410.c中的函数:i2c_adap_s3c_init() bsys_initcall级别 4./driver/i2c/i2c-dev.c中的函数:i2c_dev_init() module_init级别后续将根据这个顺序进行分析2.I2C核心2.1 i2c_init()函数:i2c_init() = 1,注册i2c总线2,注册类i2c_adapter_class3,注册空i2c driver 2.1.1 i2c总线的注册i2c_bus_type总线提供match和probe方法:注册i2c设备或i2c驱动时,调用match匹配client device和client driver,匹配成功调用probe。(1)i2c_device_match 如果该驱动不是一个new-style形式的且driver没有定义匹配的id_table都会匹配失败.I2c_match_id()函数的作用:匹配板文件中定义的ID和i2c_driver所支持的ID表(P338 宋宝华驱动)(2)i2c_device_probe通过传递进来的dev找到包含此dev的i2c_driver驱动,然后再去调用i2c_driver的probe方法。所以在i2c总线中,驱动和设备匹配成功,就调用驱动中的probe函数。2.1.2 i2c驱动注册dummy_driver仅仅是注册了一个空的设备驱动。2.1.3 i2c_init()函数总结该过程主要完成了sysfs总线结构,最终形成如下结构:/sys/bus/i2c/|- devices|- drivers| |- dummy| |- bind| |- uevent| - unbind|- drivers_autoprobe|- drivers_probe- uevent和/sys/class/i2c-adapter/3.总线驱动3.1 I2C platform_device初始化-smdk2440_machine_init()smdk2440_machine_init() =1.构建platform_device型设备s3c_device_i2c0。2.将板上i2c设备信息注册到i2c设备链_i2c_board_list上。此处就为at24c02的相关参数。3.添加platform总线/* static struct i2c_board_info tq2440_i2c_devs _initdata = I2C_BOARD_INFO(24c02, 0x50), .platform_data = &at24c02, , ; static struct at24_platform_data at24c02 = .byte_len = SZ_2K / 8, .page_size = 8, ; 将这两句添加到smdk2440_machine_init()上面(因为此处用到)或添加到at24c04所在处(试试)*/( i2c_register_board_info(0, tq2440_i2c_devs, ARRAY_SIZE(tq2440_i2c_devs); )需要注意的是,此处的i2c_register_board_info()函数是后来添加的,原生内核此处并未调用此函数。经过分析,也许需要调用此函数,之后会实际论证。3.1.1 s3c_i2c_set_platdata 构建platform_device s3c_device_i2c01,定义s3c_device_i2c02,s3c_i2c_set_platdata :将default_i2c_data0保存到s3c_device_i2c0的dev.platform_data(标号D)3,生成表1:Struct platform_device s3c_device_i2c0Name: s3c2410-i2cResource:s3c_i2c_resourceStruct device devVoid *platform_data(default_i2c_data0).flags= 0,.slave_addr= 0x10,.frequency= 100*1000,.sda_delay= 100,表1slave_addr要改成0x50?If(!pd)为真(pd=null),则将default_i2c_data0赋值给pd。通过2,3 实现将default_i2c_data0的值保存到s3c_device_i2c0的dev.platform_data下在s3c24xx_i2c_probe函数中,对s3c2440的i2c相关控制寄存器的初始化操作会将platform_data参数填入到相关寄存器。3.1.2 i2c_register_board_info i2c_register_board_info =1,生成表22,将表2挂到_i2c_board_list链表(标号C)初始化client时从链表取下struct i2c_devinfostruct list_headlist_i2c_board_listintbusnum0struct i2c_board_infoboard_info(tq2440_i2c_devs) I2C_BOARD_INFO(24c02, 0x50), .type =24c02.addr= 0x50.platform_data = &at24c02,.byte_len= SZ_2K / 8.page_size = 8, 表 23.1.3 platform_add_devices将之前创建的platform_device型设备s3c_device_i2c0添加到platform_bus总线。3.2 I2C platform_drive适配器驱动初始化-i2c_adap_s3c_init()platform_driver_register 向platform总线注册s3c2410_i2c_driver(platform_driver类型)配对成功调用Probe注册i2c_adapter 和 i2c_client。(后面详细分析)3.3 platform_bus总线有设备或驱动注册时,调用platform_match函数(根据名字来配对)。如下:到此处,之前已注册的platform_device型s3c_devicei2c0 和现在的platfor_drver型s3c24xx_i2c_drive配对成功。3.4总线设备和总线驱动初始化总结:Platform device初始化:smdk2440_machine_init()构建一个包含初始化数据的 s3c_device_i2c0,并注册到总线Platform driver初始化:i2c_adap_s3c_init()定义s3c2410_i2c_drive,并注册到总线,匹配device,调用probe。图13.5 probe函数adapter_device 和 client_device的注册该函数的主体工作是使能硬件并申请I2C适配器使用的I/O地址,中断号等,在这些工作都完成无误后,通过I2C核心提供的i2c_add_adapter()函数添加适配器。当处理器包含多个I2C控制器时,我们通过板文件定义的platform数据中的bus_num进行区分。(摘自 宋宝华驱动。)/*probe函数的功能如下:1.创建struct s3c24xx_i2c *i2c。i2c相关数据的初始化来源于s3c2_device_i2c0.dev.platdata(标号D)。2.i2c-adap.algo = &s3c24xx_i2c_algorithm;初始化algo方法。3.init_waitqueue_head(&i2c-wait); 初始化一个等待队列4.初始化i2c控制器,s3c24xx_i2c_init (i2c);对s3c24xx的i2c控制寄存器进行,比如配置s3c2440i/o功能,设置从机地址,以及设置i2c时钟频率等相关操作。5.申请中断。request_irq(i2c-irq, s3c24xx_i2c_irq, IRQF_DISABLED, dev_name(&pdev-dev), i2c);6. 注册i2c adapteri2c_add_numbered_adapter(&i2c-adap)*/s3c24xx_i2c_probe在probe函数会调用函数i2c_add_number_adapter(),通过此函数来实现adapter device和client device的注册。struct s3c24xx_i2c i2c/作为i2c_adapters的algo_data。封装适配器的所有信息然后调用i2c_add_number_adapter()s3c24xx_i2c *i2c值tx_setup50clkclk_get(&pdev-dev, i2c);dev&pdev-dev 注:struct platform_device *pdevioarearequest_mem_region(res-start,(res-end-res-start)+1, pdev-name); / request IOregsioremap(res-start, (res-end-res-start)+1);adapternames3c2410-i2cownerTHIS_MODULEalgo&s3c24xx_i2c_algorithmretries2classI2C_CLASS_HWMON | I2C_CLASS_SPDalgo_datai2c(即这个表格)nrpdata-bus_numdevparent&pdev-devnamei2c-%dclass&i2c_adapter_classrelease&i2c_adapter_dev_release表3/*i2c_add_number_adapter()函数如下:int i2c_add_numbered_adapter(struct i2c_adapter *adap)if (status = 0)status = i2c_register_adapter(adap);return status;最重要的就是 i2c_register_adapter()通过以下函数将名为i2c-0的adapter设备注册到i2c_bus_type型的i2c总线上,其中通过指定了本次注册的设备类型为i2c_adapter_class(因为还有client设备同时需要注册到这条i2c总线上)。在后面注册适配器驱动时(标号E)会在i2c_adapter_class这个类中找适配器设备,也就是这个adaper.最后device_register()将adapter注册到i2c总线上。*/在函数i2c_register_adapter中注册adapter后紧接着注册client。判断if是否成立,此处成立。_i2c_first_dynamic_bus_num的判断分析待续执行i2c_scan_static_board_info(adap);从_i2c_board_list链表上获取一个devinfo信息结构体,(标号C)。i2c_new_device:利用_i2c_board_list链表上一个devinfo信息结构体和刚注册的adapter创建一个clientclient(从设备at24c02)数据adapteradap(表3)nameInfo-typedevplatform_datainfo-platform_data表2(tq2440_i2c_devs)parent&client-adapter-devbus&i2c_bus_typeflagsinfo-flagsaddrinfo-addrirqinfo-irq表4/*i2c_attach_client()填充client成员且向总线注册client。*/此i2c总线同时包含了adapter和client,即i2c主机(s3c2440的i2c控制器)、i2c从设备at24c02。到这一步内核实现了adapter device和client device的注册,接着要通过函数bus_for_each_drv()来扫描i2c总线,检测刚注册到i2c总线的adapter是否有对应的驱动。不过目前肯定失败,因为到目前为止还未注册adapter driver。总结至此,执行完i2c_add_numbered_adapter函数后,i2c总线上已有adapter device和client device,但是i2c总线此时还未有adapter driver和client driver。总线挂载如图:4,设备驱动i2c adapter的驱动通过i2cdev_driver这个通用驱动的attach方法来实现注册。在/dev目录下生成i2c设备文件等操作4.1 i2c_dev_init()1,创建字符设备2,创建i2c_dev_class类(标号B )3,注册驱动4.1.1 register_chardevi2cdev_fops如下:4.1.2 i2c_add_drive 注册i2c_driver (i2cdev_driver)i2c_add_driver = 1,注册i2cdev_driver (如果未初始化driver-detect 将 adapter加入到i2c_dev_list)2,创建设备文件 “i2c-%d ”/*class_for_each_device()在新的驱动加入内核时调用该函数,在类i2c_adapter_class中找一个适配器设备与新驱动匹配。(标号E)class_for_each_device并不执行匹配的操作,只是简单的取出所有的驱动或是适配器。真正的匹配是在函数i2c_detect和attach_adapter中进行的。由于此处驱动并未初始化driver-detect,所以i2c_detect函数未执行有效操作就会退出。接着通过传统方式执行driver-attach_adapter方法。*/绕了一大圈,其实就是注册 i2c_driver类型的i2cdev_driver到i2c bus 上,然后调用驱动本身的attach_adapter:将adapter加入到i2c_dev_list,和创建设备文件/*i2cdev_attach_adapter =1,将adapter加入到i2c_dev_list。应用层打开i2c-0设备文件时,在此取出adapter。(标号A) 2,调用device_create()函数,通过之前class_create的类信息(标号B )在/dev下自动创建设备文件。到此i2c部分的初始化就完成了,可以通过read write来操作设备了。*/总结i2c_dev_init() :1通过register_chrdev(I2C_MAJOR, i2c, &i2cdev_fops);创建主设备号=I2C_MAJOR, 操作函数集=i2cdev_fops 的字符设备2,然后通过 i2c_add_driver(&i2cdev_driver); 注册i2驱动i2cdev_driver,创建主设备号=I2C_MAJOR,次设备号为nr的设备文件,i2c-%d。这样以后就可以通过操作i2c-%d节点来操作设备文件i2c,(其实是操作i2cdev_fops)5,i2c子系统通信方法5.1 open设备/dev/i2c-0open通过系统调用最后调用到fops的i2cdev_open函数i2cdev_open =1,根据/dev/i2c-%d的设备号找到i2c_dev_list链表中的i2c_dev (标号A) 取出对应的adapter.2,将adapter保存到临时变量client中,存入file-private_data供ioctl() write() open()等操作使用。5.2 writei2cdev_write =1,取出fileprivate_data中的client(内有adapter)2,将用户输入的数据buf 传导tmp中3, i2c_master_send(client,tmp,count);将tmp数据发给client i2c_transfer(adap, &msg, 1);adap-algo-master_xfer =s3c24xx_i2c_xfers3c24xx_i2c_doxfer(i2c, msgs, num);s3c24xx_i2c_message_start(i2c, msgs);(中断)s3c24xx_i2c_irq()。i2s_s3c_irq_nextbyte(i2c, status)根据status进行操作i2c_master_send = 1,取出client2,填充msg3, i2c_transfer(adap, &msg, 1);/*i2c_transfer = adap-algo-master_xfer根据 probe函数中i2c-adap.algo = &s3c24xx_i2c_algorithm;此处调用 s3c24xx_i2c_algorithm-master_xfer 即 s3c24xx_i2c_xfer0 s3c24xx_i2c_xfer =s3c24xx_i2c_doxfer(i2c, msgs, num);s3c24xx_i2c_doxfer =1,查询adapter是否为“忙”3c24xx_i2c_set_master(i2c) (400ms后放弃)2,标记i2c状态STATE_START3,打开中断s3c24xx_i2c_enable_irq(i2c)4,发送(msg-addr & 0x7f) state 改为 STATE_WRITE2,retry_write1,将i2c-state 改为 STATE_WRITE2,将msg中Buf的数据写到s3c2440的IICDS寄存器发送,流程图:图2s3c24xx_i2c_stop1,将状态改为STATE_STOP2,扫尾工作s3c24xx_i2c_master_complete(i2c, ret);3,关闭中断*/至此 write函数的发送数据流程就分析完了,读类似。根据write() read()的实现方法可以发现,write() read()每次都固定只能发送一则msg,发送完毕时发送stop信号。5.3 i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) i2cdev_ioctl 可以执行不同的cmd,本文当着重分析I2C_SLAV / I2C_SLAVE_FORCE和 I2C_RDWR 其他命令需要时再加入5.2.1 I2C_SLAVE / I2C_SLAVE_FORCE将参数(我们输入的地址)赋值给client-addr5.2.2 I2C_RDWR此处的arg是应用层 rdwrdata(struct i2c_rdwr_ioctl_data)的地址i2cdev_ioctl_rdrw(client, arg);i2cdev_ioctl_rdrw(client, arg);图3 打包过程 所以由图2和图3可知,i2cdev_ioctl 可以发送多个msg 中间使用start/restart信号,而不是stop。6,I2C子系统总结:I2C子系统的结构符合内核总的驱动模型。主要包含4大部件1.i2c bus2.adapter device3.client device4.adapter driver其中i2c bus是用于管理的,并非是通信总线。i2c bus上挂着adapter(主机) device、client(从机) device、adapter driver。为了统一操作,adapter device、client device、adapter driver并非直接通过
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 航空航天产业股权并购与航天器研发协议
- 《哈姆莱特(节选)》课件 统编版高中语文必修下册
- 教师招聘之《幼儿教师招聘》考前冲刺练习题及参考答案详解
- 教师招聘之《小学教师招聘》练习题含完整答案详解【历年真题】
- 绿色信贷对中国银行盈利能力的影响研究
- 教师招聘之《小学教师招聘》全真模拟模拟题及完整答案详解(有一套)
- 内蒙古呼伦贝尔农垦牙克石莫拐免渡河农牧场有限公司招聘笔试题库附答案详解(完整版)
- 2025卫生院医保业务流程
- 2024年呼伦贝尔农垦集团有限公司人员招聘笔试备考及答案详解(新)
- 2025年教师招聘之《幼儿教师招聘》综合提升练习题附参考答案详解(黄金题型)
- Rexroth (博世力士乐)VFC 3610系列变频器使用说明书
- ×××学校“学校学生资助管理机构成立文件”
- 动词过去式和过去分词的变化规则练习及答案
- 第四章 土壤污染调查与风险评价
- GB/T 9877-2008液压传动旋转轴唇形密封圈设计规范
- GB/T 12670-2008聚丙烯(PP)树脂
- 共享服务中心(HRSSC)课件
- 工程结构检测鉴定与加固第1章工程结构检测鉴定与加固概论课件
- 高中心理健康课程《人际关系-寝室篇》课件
- 数字色彩课件
- 一年级上册科学课件-第一单元 走近科学 复习课件-鄂教版(共23张PPT)
评论
0/150
提交评论