📄 iic driver.txt
字号:
要测试X1227的时钟功能,首先把AT91RM9200的I2C总线驱动模块和X1227模块在系统启动时先后加载。需要指出的是,Linux将时钟分为系统时钟和硬件时钟两种。系统时钟是指当前Linux Kernel中的时钟,而硬件时钟则是主板上由电池供电的那个主板硬件时钟,也就是本文中的X1227。
在Linux中,用于时钟查看和设置的命令主要有date、hwclock。首先设置系统时钟,比如设置为2006年8月17日12点30分:date 081712302006,然后设置硬件时钟为当前系统时钟时间,使用命令/sbin/hwclock 衧ystohc,则X1227中的时间设置为当前系统时间。然后,通常在操作系统启动时设置启动脚本/sbin/hwclock 衕ctosys,利用X1227内的时间更新系统时钟,然后直到重启或关闭系统,由系统时钟来记录时间。
结语
本文介绍了I2C总线适配器及I2C设备驱动的实现。该设计成功用于某网络测试设备的主控模块上,实现了设备的实时时钟功能,便于整个系统的监控。I2C总线在目前的嵌入式领域中应用非常广泛,如音/视频的控制,存储设备的通讯等,而Linux也已成为嵌入式系统的主流。从linux内核看,I2C的驱动程序具有清晰的层次结构,为编程者开发I2C相关驱动提供了规范的框架。
参考文献:
1. lessandro Rubini,Jonathan Corbet. Linux Device Drivers,second edition[M].O誖eilly & Associates,2002.
2. 郑旭阳、李兵兵、黄新平,模拟I2C总线多主通信研究与软件设计,单片机与嵌入式系统应用,2005,12:29_32
3. Philips Corporation, I2C bus specification version 2.1, 2000
4. Atmel Corporation, AT91RM9200 Datasheet, version E, 2005
5. Xicor Corporation, X1227 Datasheet, version1.3, 2004
在Linux内核源代码中的drivers目录下包含一个i2c目录,而在i2c目录下又包含如下文件和文件夹:
? i2c-core.c
这个文件实现了I2C核心的功能以及/proc/bus/i2c*接口。
? i2c-dev.c
实 现了I2C适配器设备文件的功能,每一个I2C适配器都被分配一个设备。通过适配器访问设备时的主设备号都为89,次设备号为0~255。应用程序通过 “i2c-%d” (i2c-0, i2c-1, ..., i2c-10, ...)文件名并使用文件操作接口open()、write()、read()、ioctl()和close()等来访问这个设备。
i2c-dev.c并没有针对特定的设备而设计,只是提供了通用的read()、write()和ioctl()等接口,应用层可以借用这些接口访问挂接在适配器上的I2C设备的存储空间或寄存器并控制I2C设备的工作方式。
? chips文件夹
这个目录中包含了一些特定的I2C设备驱动,如Dallas公司的DS1337实时钟芯片、EPSON公司的RTC8564实时钟芯片和I2C接口的EEPROM驱动等。
? busses文件夹
这个文件中包含了一些I2C总线的驱动,如S3C2410的I2C控制器驱动为i2c-s3c2410.c。
? algos文件夹
实现了一些I2C总线适配器的algorithm。
此外,内核中的i2c.h这个头文件对i2c_driver、i2c_client、i2c_adapter和i2c_algorithm这4个数据结构进行了定义。理解这4个结构体的作用十分关键,代码清单15.1、15.2、15.3、15.4分别给出了它们的定义。
代码清单15.1 i2c_adapter结构体
1 struct i2c_adapter {
2 struct module *owner;/*所属模块*/
3 unsigned int id; /*algorithm的类型,定义于i2c-id.h,以I2C_ALGO_开始*/
4 unsigned int class;
5 struct i2c_algorithm *algo;/*总线通信方法结构体指针 */
6 void *algo_data; /* algorithm数据 */
7 int (*client_register)(struct i2c_client *); /*client注册时调用*/
8 int (*client_unregister)(struct i2c_client *); /*client注销时调用*/
9 struct semaphore bus_lock; /*控制并发访问的自旋锁*/
10 struct semaphore clist_lock;
11 int timeout;
12 int retries; /*重试次数*/
13 struct device dev; /* 适配器设备 */
14 struct class_device class_dev; /* 类设备 */
15 int nr;
16 struct list_head clients; /* client链表头*/
17 struct list_head list;
18 char name[I2C_NAME_SIZE]; /*适配器名称*/
19 struct completion dev_released; /*用于同步*/
20 struct completion class_dev_released;
21};
代码清单15.2 i2c_algorithm结构体
1 struct i2c_algorithm {
2 int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs,
3 int num); /*i2c传输函数指针*/
4 int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, /*smbus传输函数指针*/
5 unsigned short flags, char read_write,
6 u8 command, int size, union i2c_smbus_data * data);
7 int (*slave_send)(struct i2c_adapter *,char*,int);/*当i2c适配器为slave时,发送函数*/
8 int (*slave_recv)(struct i2c_adapter *,char*,int); /*当i2c适配器为slave时,接收函数*/
9 int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long); /*类似ioctl*/
10 u32 (*functionality) (struct i2c_adapter *);/*返回适配器支持的功能*/
11 };
上述代码第4行对应为SMBus传输函数指针,SMBus大部分基于I2C总线规范,SMBus不需增加额外引脚。与I2C总线相比,SMBus增加了一些新的功能特性,在访问时序也有一定的差异。
代码清单15.3 i2c_driver结构体
1 struct i2c_driver {
2 int id;
3 unsigned int class;
4 int (*attach_adapter)(struct i2c_adapter *); /*依附i2c_adapter函数指针 */
5 int (*detach_adapter)(struct i2c_adapter *); /*脱离i2c_adapter函数指针*/
6 int (*detach_client)(struct i2c_client *); /*i2c client脱离函数指针*/
7 int (*command)(struct i2c_client *client,unsigned int cmd, void *arg); /*类似ioctl*/
8 struct device_driver driver; /*设备驱动结构体*/
9 struct list_head list; /*链表头*/
10 };
代码清单15.4 i2c_client结构体
1 struct i2c_client {
2 unsigned int flags; /* 标志 */
3 unsigned short addr; /* 低7位为芯片地址 */
4 struct i2c_adapter *adapter; /*依附的i2c_adapter*/
5 struct i2c_driver *driver; /*依附的i2c_driver */
6 int usage_count; /* 访问计数 */
7 struct device dev; /* 设备结构体 */
8 struct list_head list; /* 链表头 */
9 char name[I2C_NAME_SIZE]; /* 设备名称 */
10 struct completion released; /* 用于同步 */
11 };
下面分析一下i2c_driver、i2c_client、i2c_adapter和i2c_algorithm这4个数据结构的作用及其盘根错节的关系。
? i2c_adapter与i2c_algorithm
i2c_adapter 对应于物理上的一个适配器,而i2c_algorithm对应一套通信方法。一个I2C适配器需要i2c_algorithm中提供的通信函数来控制适配 器上产生特定的访问周期。缺少i2c_algorithm的i2c_adapter什么也做不了,因此i2c_adapter中包含其使用的 i2c_algorithm的指针。
i2c_algorithm中的关键函数master_xfer()用于产生I2C访问周期需要的信号,以i2c_msg(即I2C消息)为单位。i2c_msg结构体也非常关键,代码清单15.5给出了它的定义。
代码清单15.5 i2c_msg结构体
1 struct i2c_msg {
2 __u16 addr; /* 设备地址*/
3 __u16 flags; /* 标志 */
4 __u16 len; /* 消息长度*/
5 __u8 *buf; /* 消息数据*/
6 };
? i2c_driver与i2c_client
i2c_driver对应一套驱动方法,是纯粹的用于辅助作用的数据结构,它不对应于任何的物理实体。i2c_client对应于真实的物理设备,每个I2C设备都需要一个i2c_client来描述。i2c_client一般被包含在i2c字符设备的私有信息结构体中。
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()函数被调用的时候。
? i2c_adpater与i2c_client
i2c_adpater 与i2c_client的关系与I2C硬件体系中适配器和设备的关系一致,即i2c_client依附于i2c_adpater。由于一个适配器上可以连 接多个I2C设备,所以一个i2c_adpater也可以被多个i2c_client依附,i2c_adpater中包括依附于它的i2c_client 的链表。
假设I2C总线适配器xxx上有两个使用相同驱动程序的yyy I2C设备,在打开该I2C总线的设备结点后相关数据结构之间的逻辑组织关系将如图15.2所示。
文章出处:http://www.diybl.com/course/6_system/linux/Linuxjs/2008717/133288.html
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -