Linux I2C framework(1)_概述
作者:wowo 发布于:2016-2-14 22:01
分类:通信类协议
1. 前言
I2C协议是嵌入式系统中广泛使用的一类通信协议,主要用于CPU和各种外设之间的低速数据通信。Linux kernel使用I2C framework抽象、管理相应的资源,并以各种形式,向各类使用者提供API。另外,作为总线(bus)的一种,I2C framework的实现体现了linux设备模型的精髓,值得研究与学习。这就是攥写“Linux I2C framework”系列文章的缘由和目的。
按照分析各类framework的老规矩,蜗蜗会从4个角度分4篇文章介绍I2C framework: 1)Linux I2C framework的整体介绍,包括基础知识、软件框架、API汇整等。就是本文。
2)从Provider的角度,介绍怎么借助I2C framework管理I2C相关的SOC资源。换句话说,就是怎么编写一个I2C driver。具体可参考“Linux I2C framework(2)_I2C provider”。
3)从Consumer的角度,介绍I2C framework为使用者提供了哪些功能、哪些API,以及怎样利用I2C framework编写程序。具体可参考“Linux I2C framework(3)_I2C consumer”。
4)从内部实现的角度,分析I2C framework的实现逻辑。具体可参考“Linux I2C framework(4)_I2C core”。
2. I2C的总线拓扑
I2C是总线的一种,其硬件拓扑如下图所示:
图片1 I2C H/W topology
关于I2C的硬件拓扑,相信驱动工程师都很熟悉,这里就不过多描述了,但有一点要强调: 我们都知道,I2C协议是主从式的,包括master(主设备)和slave(从设备),而Linux kernel的I2C framework只抽象了I2C master有关的功能,换句话说,linux kernel有这样的一个假设:
所有运行linux kernel的设备,在I2C总线里面,都是I2C master(至于I2C slave,抱歉,kernel不管!)。
正是基于这样的假设,linux I2C framework才成为当前的样子,具体可参考本文后续的描述。
linux kernel I2C framework使用如下的软件拓扑抽象I2C硬件(我们可以一起领会一下其中的“设备模型”思想):
图片2 I2C S/W topology 1)platform bus(/sys/bus/platform)是驱动工程师常见的bus,用于挂载和CPU通过系统总线连接的各类外设。在I2C framework中,I2C控制器直接从属于platform bus,我们在linux kernel中常说的I2C driver,都是指I2C controller driver,都是以platform driver的形式存在,当然,对应的控制器是platform device。
2)与此同时,kernel抽象出I2C bus(/sys/bus/i2c),用于挂载和I2C controller通过I2C总线连接的各个I2C slave device。
3)比较特殊的地方是,I2C core使用一个虚拟实体----I2C adapter,抽象I2C controller有关的功能(主要是数据的收发),I2C adapter也挂载在I2C bus上。
4)I2C adapter和I2C slave device都挂载在I2C bus上,就可以方便的进行Master(I2C adapter)和Slave之间的匹配操作,并通过I2C core提供的统一接口,访问I2C salve device,进行数据的收发。
5)以上各实体在sysfs中的位置,已经在“图片2”中通过红色字体标注,大家可自行理解。
3. 软件框架
基于第2章所述的总线拓扑,Linux kernel抽象出如下的软件框架:
图片3 I2C framework software architecture 1)I2C framework的最终目标,是提供一种“访问I2C slave devices”的方法。由于这些slave devices由I2C controller控制,因而主要由I2C controller驱动实现这一目标。
2)经过I2C framework的抽象,consumer可以不用关心I2C总线的技术细节,只需要通过简单的API,就可以与slave devices进行数据交互。正常情况下,consumer是位于内核态的其它driver(如HDMI driver、touch screen driver等等)。与此同时,I2C framework也通过字符设备向用户空间提供类似的接口,用户空间程序可以通过该接口访问slave devices。
3)在I2C framework内部,有I2C core、I2C busses、I2C algos和I2C muxes四个模块。
4)I2C core使用I2C adapter和I2C algorithm两个子模块抽象I2C controller的功能,使用I2C client和I2C driver抽象I2C slave device的功能(对应设备模型中的device和device driver)。另外,基于I2C协议,通过smbus模块实现SMBus(System Management Bus,系统管理总线)的功能。
5)I2C busses是各个I2C controller drivers的集合,位于drivers/i2c/busses/目录下,驱动工程师常说的“I2C driver”就是指它们。
6)I2C algos包含了一些通用的I2C algorithm,所谓的algorithm,是指I2C协议包的生成方法,进而组合成I2C的read/write指令,一般情况下,都是由硬件实现,不需要特别关注该目录。
7)I2C muxes用于实现I2C bus的多路复用功能,属于奇葩的冷门功能,暂不过多介绍。
4. I2C有关的软件流程总结
TODO(会在后续文章完成之后再回来补充)。
原创文章,转发请注明出处。蜗窝科技,www.wowotech.net。
评论:
x
2019-01-09 17:49
咨询一下各位大神,Linux kernel 4.1.15,两个进程A和B同时访问同一个SPI总线,会导致这两个进程退出吗?同一个SPI总线 但是有主和从
是不是有可能A访问主SPI,B访问从SPI,然后B再请求主的,A再请求从的 两边都没释放,导致的进程僵死了?
2019-01-10 19:26
@x:这和SPI driver的实现有关,当然,一个好的driver不会出现这种问题。
2016-03-28 19:31
I2C slave device driver和I2C client driver在内核代码中有不同的含义,图片3中使用的术语似乎和内核不一致
2016-03-28 21:58
@hello_world:kernel中有“I2C slave device driver”这个概念吗?这篇文章中我有意回避了I2C client这个概念,因为觉得它不直观,不好理解。从本质上来说,I2C client应该是I2C slave device在本地的一个“映像”(这让我想起了bluez中device的概念)。
2016-03-29 09:01
@wowo:对的i2c client driver其实是驱动I2C 总线上的slave设备的,因此其实i2c slave driver更顺一些,但是,内核代码其实都是用i2c client的概念。因此,我觉得图片3应该表述这一部分的内容的:即i2c client driver模块应该和i2c slave HW block之间有虚线,表示这两个模块之间的关系。BTW,我觉的图片3应该可以有更好的表达。
即便是有了I2C slave device的支持(类似USB 的gadget driver),实际上仍然用struct i2c_client来抽象这个slave设备。
最后:我们觉得我们还是锁定一个内核版本好了,我建议是4.4.y的内核版本,大家都围绕这个版本讨论。
2016-03-28 19:19
探讨一个问题啊,我说的也不一定对。
我感觉I2C algos和I2C buses模块的关系不是平行关系,毫无疑问,I2C buses模块(I2C controller driver)模块是和底层硬件相关的,所有和具体的I2C controller的交互都是通过I2C busses模块进行,I2C algos是和硬件无关的(也不能这么说,应该说是和硬件操作序列有关)。I2C algos对底层硬件的操作都是通过I2C busses中的adapter的callback完成的,或者说,adapter提供了最底层的通信机制,不同的algos可以利用它实现具体的I2C的数据传输服务。
2016-03-28 21:52
@hello_world:这个还真不一定,我觉得kernel的设计初衷,是尽可能的复用I2C algos,也就是说,将adapter和algos分离。当然,现状是,adapter和algos基本上一一对应了,因而algos似乎变成adapter的一个属性(从属关系)了。
2016-03-29 09:04
@wowo:的确,algos像是adapter的一个lib,不过反正在嵌入式的场景中,每一个adapter都有自己独特的algos,我们没有必要争论它们之间的关系,algos,就让它随风飘散吧,^_^
2016-03-28 18:54
所有运行linux kernel的设备,在I2C总线里面,都是I2C master(至于I2C slave,抱歉,kernel不管!)。
------------------------------------------
为什么不管呢?其实只要有需求,就应该提供支持的。在4.4.6的内核中,已经增加了对I2C slave的支持,同时也复用了当前的I2C framework的代码。
另外,I2C物理拓扑(图片1)以及关于I2C和设备模型那部分(图片2),基本上四着眼于嵌入式平台,其实可以更通用一些。另外,图片2中的CPU block的出现容易误导的,或者建议增加更多的文字描述,对于I2C和设备模型之间的关系可以多写一些。
2016-03-28 21:47
@hello_world:4.4.6是3/16才发布啊,我还没看呢!已经支持I2C slave了吗?看来kernel还是妥协了。其实我觉得,一个跑linux kernel的设备,当做I2C slave的可能性不大,还真不需要管它。
通用一些具体指什么意思呢?加入slave?还是其它?
2016-03-29 08:50
@wowo:具体是哪一个版本加上的我没有查证,不过这不重要,重要的是开源社区增加i2c slave的支持也是很纠结的(就像你说的,其实大部分的运行linux的设备应该都是I2C master),在log中有这样的描述:最终,我们还是增加了slave的支持......
增加slave的支持是指其他的模块可以调用i2c core提供的i2c_slave_register/i2c_slave_unregister来注册一个或者注销一个i2c的slave设备。一旦注册了slave设备,底层的adapter要切换到slave mode。完成这些操作之后,该i2c slave设备可以响应来自对端i2c master设备的各种命令和数据了。
2016-03-04 22:05
确实i2c是一个比较清晰的framework,记得第一个接触的驱动就是i2c slave,清晰的记得当时的迷茫,对各种数据结构的不解,现在看来感觉清楚了不少。
2016-03-05 17:55
@electrlife:是啊,I2C相对比较简单,不用当做理解设备模型的一个例子,也挺不错的。
Jordon Wu
2016-02-19 15:05
@wowo,
请教下,对于I2C,可以在userspace的application里处理中断吗?谢谢
2016-02-19 15:34
@Jordon Wu:我不太明白您的意思,对I2C来说,它负责数据接收,中断是在Kernel处理的。
我们讲的在用户空间访问,只是应用程序通过I2C Framework提供的字符设备接口,访问I2C slave device(数据收发)而已,应该不需要关心中断。
2016-02-19 16:52
@wowo:@wowo,
是的,是在应用程序中通过字符设备接口open/read/write数据到slave device,这样做发数据没问题,但是收数据需要while循环去读或者poll去查询是否有数据可读。我想知道有没有办法把kernel的有数据可接受这个中断暴露给userspace的应用程序?这样应用程序只在这个中断来了之后才去度slave device的数据。
云
2016-02-19 17:06
@jordonwu:我大概理解的你的想法。
1.首先中断只能在kenerl空间处理,这个是必须的。如果想实现此类模型,一个途径是应用程序调用read/write,在kernel空间中用诸如wait_even_xx()陷入睡眠,当有中断来临时,在ISR中wake_up_xx()来唤醒之前陷入睡眠的进程。
2.i2c的bus驱动已经实现了上述模型,你可以参考drivers/i2c/busess/下的各种driver。也就是说,在应用程序中字节设备接口的read/write/ioctl都是同步的。
2016-02-19 17:13
@jordonwu:建议不这样做,poll已经够用了,如果poll解决不了,估计是应用层的设计有待商榷。
云
2016-02-15 10:26
Linux下的i2c framework还是比较直观的。。不像usb mmc那样“荡气回肠” ;)
这篇比较概括浅显,期待后续
情人节还在发文章,wowo你可以啊,不担心跪键盘?哈哈
2016-02-15 13:09
@云:是的,I2C Framework还是比较清晰易懂的。
哈哈,感情好的话哪天都是节,不怕不怕~~~
发表评论:
昵称
邮件地址 (选填)
个人主页 (选填)