驱动篇:Linux 的 I2C设备驱动(一)(摘录)
发布日期:2021-06-29 11:34:53 浏览次数:2 分类:技术文章

本文共 5871 字,大约阅读时间需要 19 分钟。

驱动篇:Linux 的 I2C设备驱动(一)

I 2 C 总线仅仅使用 SCL、SDA 这两根信号线就实现了设备之间的数据交互,极大地简化了对硬件资源和 PCB 板布线空间的占用。因此,I 2 C 总线被非常广泛地应用在EEPROM、实时钟、小型 LCD 等设备与 CPU 的接口中。在 Linux 系统中,I 2 C 驱动由 3 部分组成,即 I 2 C 核心、I 2 C 总线驱动和 I 2 C 设备驱动。这 3 部分相互协作,形成了非常通用、可适应性很强的 I 2 C 框架。

1.I 2 C 体系结构
(1)I 2 C 核心
I 2 C 核心提供了 I 2 C 总线驱动和设备驱动的注册、注销方法,I 2 C 通信方法(即“algorithm”)上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等
2)I 2 C 总线驱动
I 2 C 总线驱动是对 I 2 C 硬件体系结构中适配器端的实现,适配器可由 CPU 控制,甚至可以直接集成在 CPU 内部。I 2 C 总线驱动主要包含了 I 2 C 适配器数据结构 i2c_adapter、I 2 C 适配器的algorithm数据结构 i2c_algorithm 和控制 I 2 C 适配器产生通信信号的函数。经由 I 2 C 总线驱动的代码,我们可以控制 I 2 C 适配器以主控方式产生开始位、停止位、读写周期,以及以从设备方式被读写、产生 ACK 等。
(3)I 2 C 设备驱动
I 2 C 设备驱动是对 I 2 C 硬件体系结构中设备端的实现,设备一般挂接在受 CPU 控制的 I 2 C 适配器上,通过 I 2 C 适配器与CPU 交换数据。
在这里插入图片描述
I 2 C 设备驱动主要包含了数据结构 i2c_driver 和 i2c_client, 我们需要根据具体设备实现其中的成员函数。
在 Linux 2.6 内核中, 所有的 I 2 C 设备都在 sysfs 文件系统中显示, 存于/sys/bus/i2c/目录,以适配器地址和芯片地址的形式列出

使用下面的命令显示$ tree /sys/bus/i2c/

在 Linux 内核源代码中的 drivers 目录下包含一个 i2c 目录,而在 i2c 目录下又包含如下文件和文件夹。

(1)i2c-core.c。

这个文件实现了 I 2 C 核心的功能以及/proc/bus/i2c*接口。
(2)i2c-dev.c。
实现了 I 2 C 适配器设备文件的功能,每一个 I 2 C 适配器都被分配一个设备。通过适配器访问设备时的主设备号都为 89,次设备号为 0~255。应用程序通过“i2c-%d”(i2c-0, i2c-1,…, i2c-10,…)文件名并使用文件操作接口 open()、write()、read()、ioctl()和 close()等来访问这个设备。i2c-dev.c 并没有针对特定的设备而设计,只是提供了通用的 read()、 write()和 ioctl()等接口,应用层可以借用这些接口访问挂接在适配器上的 I 2 C 设备的存储空间或寄存器,并控制 I 2 C 设备的工作方式。
(3)chips 文件夹。
这个目录中包含了一些特定的 I 2 C 设备驱动,如 Dallas 公司的 DS1337 实时钟芯片、EPSON 公司的 RTC8564 实时钟芯片和 I 2 C 接口的 EEPROM 驱动等。
(4)busses 文件夹。
这个文件中包含了一些 I 2 C 总线的驱动,如 S3C2410 的 I 2 C 控制器驱动为i2c-s3c2410.c。
(5)algos 文件夹。
实现了一些 I 2 C 总线适配器的 algorithm。

内核中的 i2c.h 这 个 头 文 件 对 i2c_driver 、 i2c_client 、 i2c_adapter 和i2c_algorithm 这 4 个数据结构进行了定义

i2c_adapter 结构体

struct i2c_adapter {
struct module *owner;/*所属模块*/unsigned int id; /*algorithm 的类型,定义于 i2c-id.h,以 I2C_ALGO_开始*/unsigned int class;struct i2c_algorithm *algo;/*总线通信方法结构体指针*/void *algo_data;/* algorithm 数据 */int (*client_register)(struct i2c_client *); /*client 注册时调用*/int (*client_unregister)(struct i2c_client *); /*client 注销时调用*/struct semaphore bus_lock;/*控制并发访问的自旋锁*/ struct semaphore clist_lock; int timeout; int retries;/*重试次数*/ struct device dev;/* 适配器设备 */ struct class_device class_dev; /* 类设备 */ int nr; struct list_head clients; /* client 链表头*/ struct list_head list; char name[I2C_NAME_SIZE]; /*适配器名称*/ struct completion dev_released;/*用于同步*/ struct completion class_dev_released;};

i2c_algorithm 结构体

struct i2c_algorithm {
int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs,int num); /*i2c 传输函数指针*/int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,unsigned short flags, char read_write,u8 command, int size, union i2c_smbus_data * data);/*smbus传输函数指针, SMBus 大部分基于 I 2 C 总线规范,SMBus 不需增加额外引脚。与 I 2 C 总线相比,SMBus 增加了一些新的功能特性,在访问时序也有一定的差异*/int (*slave_send)(struct i2c_adapter *,char*,int);/*当 I 2 C 适配器为 slave时,发送函数*/int (*slave_recv)(struct i2c_adapter *,char*,int); /*当 I 2 C 适配器为 slave时,接收函数*/int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long);/*类似 ioctl*/ u32 (*functionality) (struct i2c_adapter *);/*返回适配器支持的功能*/ };

i2c_driver 结构体

struct i2c_driver {
int id;unsigned int class;int (*attach_adapter)(struct i2c_adapter *);/*依附 i2c_adapter函数指针 */int (*detach_adapter)(struct i2c_adapter *);/*脱离 i2c_adapter函数指针*/int (*detach_client)(struct i2c_client *);/*i2c client脱离函数指针*/int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);/*类似 ioctl*/struct device_driver driver;/*设备驱动结构体*/struct list_head list;/*链表头*/ };

i2c_client 结构体

struct i2c_client {
unsigned int flags; /* 标志 */ unsigned short addr; /* 低 7 位为芯片地址 */ struct i2c_adapter *adapter; /*依附的 i2c_adapter*/ struct i2c_driver *driver; /*依附的 i2c_driver */ int usage_count; /* 访问计数 */ struct device dev; /* 设备结构体 */ struct list_head list; /* 链表头 */ char name[I2C_NAME_SIZE]; /* 设备名称 */ struct completion released; /* 用于同步 */ };

4 个数据结构的作用及其盘根错节的关系

(1)i2c_adapter 与 i2c_algorithm。
i2c_adapter 对应于物理上的一个适配器,而 i2c_algorithm 对应一套通信方法。一个 I 2 C 适配器需要 i2c_algorithm 中提供的通信函数来控制适配器上产生特定的访问周期。缺少 i2c_algorithm 的 i2c_adapter 什么也做不了,因此 i2c_adapter 中包含其使用的 i2c_algorithm 的指针。i2c_algorithm 中的关键函数 master_xfer()用于产生 I 2 C 访问周期需要的信号,以i2c_msg(即 I 2 C 消息)为单位。i2c_msg 结构体也非常关键,代码清单出了它的定义。

struct i2c_msg {
__u16 addr;/* 设备地址*/__u16 flags;/* 标志 */__u16 len;/* 消息长度*/__u8 *buf;/* 消息数据*/ };

(2)i2c_driver 与 i2c_client。

i2c_driver 对应一套驱动方法, 是纯粹的用于辅助作用的数据结构, 它不对应于任何的物理实体。i2c_client 对应于真实的物理设备,每个 I 2 C 设备都需要一个 i2c_client来描述。i2c_client 一般被包含在 I 2 C 字符设备的私有信息结构体中。
i2c_driver 与 i2c_client 发生关联的时刻在 i2c_driver 的 attach_adapter()函数被运行时。attach_adapter()会探测物理设备,当确定一个 client 存在时,把该 client 使用的i2c_client 数据结构的 adapter 指针指向对应的 i2c_adapter,driver 指针指向该 i2c_driver,并 会 调 用 i2c_adapter 的 client_register() 函 数 。 相反 的 过 程 发 生在 i2c_driver 的detach_client()函数被调用的时候。

(3)i2c_adpater 与 i2c_client

i2c_adpater 与 i2c_client 的关系与 I 2 C 硬件体系中适配器和设备的关系一致,即i2c_client 依附于 i2c_adpater。由于一个适配器上可以连接多个 I 2 C 设备,所以一个i2c_adpater 也可以被多个 i2c_client 依附,i2c_adpater 中包括依附于它的 i2c_client 的链表。
假设 I 2 C 总线适配器 xxx 上有两个使用相同驱动程序的 yyy I 2 C 设备,在打开该2 I C 总线的设备结点后相关数据结构之间的逻辑组织关系将如图 15.2 所示。从上面的分析可知,虽然 I 2 C 硬件体系结构比较简单,但是 I 2 C 体系结构在 Linux中的实现却相当复杂。当工程师拿到实际的电路板,面对复杂的 Linux I 2 C 子系统,应该如何下手写驱动呢?究竟有哪些是需要亲自做的,哪些是内核已经提供的呢?理清这个问题非常有意义,可以使我们面对具体问题时迅速地抓住重点。
在这里插入图片描述一方面,适配器驱动可能是 Linux 内核本身还不包含的;另一方面,挂接在适配器上的具体设备驱动可能也是 Linux 内核还不包含的。即便上述设备驱动都存在于Linux 内核中,其基于的平台也可能与我们的电路板不一样。因此,工程师要实现的主要工作如下。

l 提供 I 2 C 适配器的硬件驱动,探测、初始化 I 2 C 适配器(如申请 I 2 C 的 I/O 地址和中断号)、驱动 CPU 控制的 I 2 C 适配器从硬件上产生各种信号以及处理I 2 C 中断等。

l 提 供 I 2 C 适 配 器 的 algorithm , 用 具 体 适 配 器 的 xxx_xfer() 函 数 填 充i2c_algorithm 的 master_xfer 指针, 并把 i2c_algorithm 指针赋值给 i2c_adapter的 algo 指针。
l 实现 I 2 C 设备驱动与 i2c_driver 接口,用具体设备 yyy 的 yyy_attach_adapter()函数指针、yyy_detach_client()函数指针和 yyy_command()函数指针的赋值给i2c_driver 的 attach_ adapter、detach_adapter 和 detach_client 指针。
l 实现 I 2 C 设备驱动的文件操作接口,即实现具体设备 yyy 的 yyy_read()、yyy_write()和 yyy_ioctl()函数等。
上述工作中前两个属于 I 2 C 总线驱动,后两个属于 I 2 C 设备驱动,做完这些工作,系统会增加两个内核模块

转载地址:https://blog.csdn.net/zytgg123456/article/details/110132233 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:驱动篇:Linux 的 I2C设备驱动(二)(摘录)
下一篇:驱动篇:Linux 输入子系统(摘录)

发表评论

最新留言

不错!
[***.144.177.141]2024年05月01日 14时42分22秒