Linux I2C设备驱动学习

一、I2C 简介

1、I2C简介:
a)优点:I2C总线仅用两根信号线(SCL、SDA)就实现了设备之间的数据交互,极大简化了对硬件资源和PCB板布线空间的占用;
b)用途:EEPROM、实时钟、小型LCD等设备与CPU的接口中;

2、I2C驱动体系:
                     I2C框架    (通用、适应性强)
                       ^
                        |    
       |------------------------------|
 ---------   --------------     -------------
I2C核心、I2C总线驱动、I2C设备驱动   


二、I2C 体系结构

1、I2C核心:(I2c-core.c)
提供:I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法(“algorithm”)上层的与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。

2、I2C总线驱动:
a)定义:对I2C硬件体系结构中适配器端的实现,适配器可由CPU控制,甚至可以直接集成在CPU内部;
b)内容:I2C适配器数据结构i2c_adapter、I2C适配器的algorithm数据结构i2c_algorithm和控制I2C适配器产生通信信号的函数;
c)功能:控制I2C适配器以主控方式产生开始位、停止位、读写周期,以及以从设备方式被读写、产生ACK;

3、I2C设备驱动:    
a)定义:对I2C硬件体系结构中设备端的实现,设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据;
b)内容:数据结构i2c_driver和i2c_client,我们需要根据具体设备实现其中的成员函数;

4、设备文件:
所有的I2C设备都在sysfs文件系统中,存于/sys/bus/i2c/目录,以适配器地址和芯片地址的形式列出;

# busybox ls /sys/bus/i2c/devices/
0-0051  1-0040  1-0042  1-0046  1-0060  i2c-0   i2c-1   i2c-2   i2c-3
# busybox ls /sys/bus/i2c/drivers/               
DLP Projector  dummy          rk610_hdmi     rtc_hym8563
RK610_CODEC    rk610_ctl      rk610_tvout
#

5、I2C源码:
有关I2C源码位于/drivers/i2c/中;
a)i2c-core.c
功能:实现了I2C核心的功能以及/proc/bus/i2c*接口;
b)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 设备的工作方式。
c)chips文件夹
这个目录中包含了一些特定的I2C设备驱动,如Dallas公司的DS1337实时钟芯片、EPSON公司的RTC8564实时钟芯片和I2C接口的EEPROM驱动等。
d)busses文件夹
这个文件中包含了一些I2C总线的驱动,如S3C2410的I2C控制器驱动为i2c-s3c2410.c。
e)algos文件夹
实现了一些I2C总线适配器的algorithm。


6、内核中的i2c.h这个头文件对i2c_driver、i2c_client、i2c_adapter和i2c_algorithm这4个数据结构进行了定义。理解这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,/*smbus传输函数指针*/
 unsigned short flags, char read_write,
 u8 command, int size, union i2c_smbus_data * data);
 int (*slave_send)(struct i2c_adapter *,char*,int);/*当I2C适配器为slave时,发送函数*/
 int (*slave_recv)(struct i2c_adapter *,char*,int); /*当I2C适配器为slave时,接收函数*/
 int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long);/*类似 ioctl*/
 u32 (*functionality) (struct i2c_adapter *);/*返回适配器支持的功能*/
};
说明:SMBus大部分基于I2C总线规范,SMBus不需增加额外引脚。与I2C总线相比,SMBus增加了一些新的功能特性,在访问时序也有一定的差异。

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; 3 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; /* 用于同步 */
};

7、分析i2c_driver、i2c_client、i2c_adapter和i2c_algorithm这4个数据结构的作用及其盘根错节的关系。
a)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消息)为单位。
struct i2c_msg {
 _ _u16 addr;/* 设备地址*/
 _ _u16 flags;/* 标志 */
 _ _u16 len;/* 消息长度*/
 _ _u8 *buf;/* 消息数据*/
};

b)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()函数被调用的时候。

c)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所示。

8、如何编写I2C驱动
一方面,适配器驱动可能是Linux内核本身还不包含的;另一方面,挂接在适配器上的具体设备驱动可能也是Linux内核还不包含的。即便上述设备驱动都存在于Linux内核中,其基于的平台也可能与我们的电路板不一样。因此,工程师要实现的主要工作如下。
a)提供I2C适配器的硬件驱动,探测、初始化I2C适配器(如申请I2C的I/O地址和中断号)、驱动CPU控制的I2C适配器从硬件上产生各种信号以及处理I2C中断等。
b)提供I2C适配器的algorithm,用具体适配器的xxx_xfer()函数填充i2c_algorithm的master_xfer指针,并把i2c_algorithm指针赋值给i2c_adapter的algo指针。
c)实现I2C设备驱动与i2c_driver接口,用具体设备yyy的yyy_attach_adapter()函数指针、yyy_detach_client()函数指针和 yyy_command()函数指针的赋值给i2c_driver的attach_ adapter、detach_adapter和detach_client指针。
d)实现I2C设备驱动的文件操作接口,即实现具体设备yyy的yyy_read()、yyy_write()和yyy_ioctl()函数等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值