对i2c子系统的理解

来源:互联网 发布:网络通信协议 编辑:程序博客网 时间:2024/06/09 08:16
    驱动i2c控制器归根到底是对IIC控制器的寄存器进行读写,因此,理解了linux中是怎样通过层层调用来操作IIC的寄存器,便理解了整个IIC子系统的轮廓。
下面以公司使用的重力传感器(bma250)驱动为例来描述这个轮廓。
首先介绍三个比较重要的驱动文件:
bma250.c(Drivers/Gsensor/),I2c_core.c(Drivers/I2c/),I2c-sunxi.c(/Drivers/I2c/busses)。
    bma250.c与外接的传感器bma250有关(即client端),I2c_sunxi.c与主控的IIC控制器有关(即adapter端,是对IIC寄存器操作的所在文件),I2c_core.c则起到为前面两个文件进行关联的作用(实际上就是总线管理的作用,而这里是IIC总线)。区分开的一个很大的好处便是移植性强,比如bma250.c可以用于一切支持linux的硬件平台,而I2c_sunxi.c可用于A10的所有IIC外围器件,硬件变动下,I2c_core.c则基本不用改变。
     在I2c_sunxi.c的模块初始化中定义了一个平台设备,用于获取A10的IIC寄存器地址和中断向量,而在平台设备匹配成功后调用的i2c_sunxi_probe函数中,初始化了一个i2c_adapter结构体,这个结构体用于描述A10的IIC控制器,并通过i2c_add_numbered_adapter函数向IIC总线添加了添加了这个adapter。i2c_adapter结构体有个很重要的成员,即i2c_algorithm结构,该结构下又有一个很重要的成员:master_xferI2c_sunxi.c在初始化i2c_adapter时将master_xfer初始化为i2c_sunxi_xfer,而i2c_sunxi_xfer正是对A10的IIC寄存器进行操作的开始。在此函数中,通过直接操作IIC寄存器,使能了IIC中断,发出了IIC的开始信号,并通过wait_event_timeout函数让进程进入休眠,接下来通过层层中断(比如IIC开始信号发出完成后会发生中断,发送完一个字节也会发生中断)将i2c结构体中的msg数据发送出去,此处i2ci2c_adapter结构体中的algo_data成员,要发送的数据都放在这个msg结构体里。
    因此,只需要注册并调用i2c_adapter->algo->smbus_xfer,便可以让IIC控制器按要求发出或接收数据。
    I2c_core.c在完成建设IIC总线的同时,还完成了对i2c_adapter->algo->smbus_xfer的封装,即i2c_transfer,而i2c_smbus_read_i2c_block_data之类的函数又对i2c_transfer进行了封装。因而只需调用i2c_smbus_read_i2c_block_data等函数,并传入对应的i2c_adapter,便可以让控制器按要求发出或接收数据。
    在bma250.c的模块初始化中,注册了一个i2c_driver:bma250_driver,该步骤引发了bma250(client)与A10的IIC接口(adapter)的匹配。匹配中一个非常关键的因素是bma250_driver中的address_list,即bma250的IIC地址,新版本的内核隐藏了这一步的实现,变得自动化,只需要给出的address_list正确,硬件电路正确,linux的IIC总线上挂有对应的adapter,变可以匹配成功,匹配成功后,linux新建了一个client结构,并将结构里的adapter初始化为匹配成功的那个adapter,至此,总线上,bma250便与A10的IIC接口配对,bma250.c中的函数所用到的参数adapter,都是配对成功的那个adapter.
    这里说一下旧版本(2.6和2.6之前)内核client和adapter的匹配过程。在调用IIC驱动注册函数时(i2c_add_driver),引发了i2c_probe函数的调用,在该函数中,把注册在IIC总线上的adapter逐个拿出来做实验,实验过程如下:将IIC有可能的地址0~0x7F,逐个与address_list里的地址进行对比,如果相同则调用i2c_smbus_xfer,该函数实际操作了目前这个被实验中的adatper的寄存器,发出信号与bma250通讯。若bma250发出了应答信号,则匹配成功。匹配的实现算法与硬件无关,并且算法应该是比较成熟了,所以新内核将其直接拿来用,并将其隐藏起来,不再需要驱动开发者重写过匹配算法。
    到这里总结一下:I2c_core.c建设了一条IIC总线,I2c-sunxi.c向总线添加了一个adapter,而bma250.c通过向总线注册一个IIC驱动,探测总线上适合(硬件上连接)的adapter,探测成功后bma250便与A10建立联系,bma250.c通过调用I2c_core.c的函数从而调用I2c-sunxi.c里的函数,完成了IIC硬件上的实现。
     下面以bma250.c为例,简单说一下上层到下层的调用过程。向总线注册完IIC驱动后,将匹配到的adapter作为后续函数的参数。Bma250驱动通过一工作队列定时调用函数bma250_read_accel_xyz,该函数读出了bma250里的三轴数据,通过输入子系统,将数据上报给系统。整个调用路线如下:
bma250_read_accel_xyz → bma250_smbus_read_byte_block →i2c_smbus_read_i2c_block_data(进入I2c_core.c)→ i2c_smbus_xfer → adapter->algo->smbus_xfer(i2c_sunxi_xfer) → i2c_sunxi_do_xfer(引发中断)→ i2c_sunxi_handler(IIC中断函数)→i2c_sunxi_core_process→aw_twi_put_byte/aw_twi_get_byte等 →readl/ writel(此函数正是操作A10寄存器的函数)
这便是整个IIC子系统的实现轮廓。


以下总结编写IIC驱动所需做的工作:
1、通过平台设备或其他手段获取主控IIC控制器的资源(寄存器地址和中断向量号),申请中断并实现中断函数。
2、向IIC总线添加一个初始化好的i2c_adapter结构体。而初始化一个i2c_adapter结构体时最重要的一步是实现i2c_adapter中的algo成员,在algo的成员函数中通过操作寄存器,发出IIC起始信号引发后续数据的发送与接收(通过中断,里面也是通过操作寄存器实现)。
3、向IIC总线添加一个初始化好的i2c_driver结构体。初始化时比较重要的是给出IIC设备的地址。在其probe函数中完成向应用层接口的初始化,如初始化一个输入子系统,用于上报数据。
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 淘宝买的东西退货快递弄丢了怎么办 在淘宝上已付钱店家说没货了怎么办 从淘宝物流寄东西到国外被扣怎么办 不是天猫的淘宝卖家不发货怎么办 微店违规说卖假冒商品怎么办 云集微店的商品没货了怎么办 淘宝买家被检测有虚拟交易怎么办 媒体声音突然没有声音了该怎么办 华为微信运动步数为零怎么办 淘宝店铺没货了客户拍了怎么办 房子涨价了卖家反悔不卖了怎么办 买的东西很贵质量不好怎么办 在淘宝开的店账号忘了怎么办 建了个淘宝优惠券群没人购物怎么办 刚开的淘宝店没有生意怎么办 房产代理公司不给渠道结佣金怎么办 天猫超过72小时不发货怎么办 流量魔盒苹果下载怎么打不开怎么办 淘宝包邮店铺新疆地区拍怎么办 淘宝客服当顾客要优惠时怎么办 微信手机号注册的找不到了怎么办 之前注册的微信找不到了怎么办 苹果ipad的id密码忘了怎么办 淘宝和支付宝用一张银行卡怎么办 淘宝卖家填写虚假物流信息怎么办 淘宝店铺的浏览量越来越少怎么办 网上充手机话费充错了怎么办 夜神模拟器上陌陌的位置不对怎么办 如果在大庭广众之下放了个屁怎么办 淘宝分销上传宝贝被系统下架怎么办 酷狗喜欢歌单里面的歌都没了怎么办 苹果手机下载不了微信缓冲怎么办 登陆微信提示版本过低登不了怎么办 苹果手机微信版本过低登不上怎么办 微信小程序显示微信版本过低怎么办 三星手机登微信显示版本过低怎么办 微信版本低无法登录无法升级怎么办 手机淘宝五应用界面无法打开怎么办 入住淘宝主播没有微博粉丝怎么办 手机淘宝领金币怎么没有了怎么办 淘宝荬家缺货对付款买家怎么办