【Linux基础系列之】i2c架构简析

[I2C总线的信号状态]

1、  空闲状态:SDA和SCL都是高电平;

2、  开始条件(S):SCL为高电平时,SDA由高电平向低电平跳变,开始传输数据;

3、  结束条件(P):SCL为高电平时,SDA由低电平向高电平跳变,结束传输数据;

4、  数据有效:在SCL的高电平期间,SDA保持稳定,数据有效。SDA的改变只能发生在SCL的低电平期间;

5、  ACK信号:数据传输的过程中,接收器件每接收一个字节数据要产生一个ACK信号,向发送器件发出特定的低电平脉冲,表示已经收到数据。





先看下源码目录:drivers/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算法;


代码中涉及到4个结构体:2c_driver、i2c_client、i2c_adapter和i2c_algorithm


•  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结构体也非常关键。
代码清单 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 的链表;

struct i2c_client {
	unsigned short flags;		/* div., see below		*/
	unsigned short addr;		/* chip address - NOTE: 7bit	*/ 7 bit模式,去读写时地址要右移一位;
					/* addresses are stored in the	*/
					/* _LOWER_ 7 bits		*/
	char name[I2C_NAME_SIZE];
	struct i2c_adapter *adapter;	/* the adapter we sit on	*/
	struct i2c_driver *driver;	/* and our access routines	*/
	struct device dev;		/* the device structure		*/
	int irq;			/* irq issued by device		*/
	struct list_head detected;
};

driver/i2c/i2c-core.c:

static int __init i2c_init(void)
{
    ....
    retval = bus_register(&i2c_bus_type);//bus_type    
    ....
    retval = i2c_add_driver(&dummy_driver);
}

static struct i2c_driver dummy_driver = {
    .driver.name    = "dummy",
    .probe        = dummy_probe,
    .remove        = dummy_remove,
    .id_table    = dummy_id,
};


i2c_add_driver() --> i2c_register_driver --> driver_register -> bus_add_driver() --> driver_attach --> bus_for_each_dev --> while遍历device列表 执行__driver_attach()

__driver_attach执行;

调用总线上match函数判断设备和驱动是否匹配,若匹配则返真,找到对应的设备,继续执行后面的程序,若没有找到,则返回假,函数执行结束。

driver端:

设备驱动init 函数里面i2c_add_driver > i2c_register_driver注册驱动并去匹配相应的设备并调用驱动注册的probe函数;

i2c_check_functionality:查看adapte的2c_algorithm支持类型,对应定义在/i2c/busses/i2c-xx.c里面;对应的传输函数也在i2c_algorithm结构体里面;

static const struct i2c_algorithm xxx_i2c_algo = {
	.master_xfer = xxx_i2c_master_xfer,
	.functionality = xxx_i2c_func,
};

i2c/busses/i2c-xx.c:

注册在platform上的一个虚拟设备,并通过probe函数初始化一个i2c_adapter,通过函数i2c_add_numbered_adapter注册这个adapeter,这样适配器的algorithm也就对应好了;

i2c_add_numbered_adapter -> i2c_register_adapter


Master_xfer函数实现模板:

    static int i2c_adapter_xxx_xfer(structi2c_adapter *adap, struct i2c_msg *msgs, int num)  
    {  
       ......  
       for (i = 0; i < num; i++) {  
           i2c_adapter_xxx_start();         /*产生起始位*/  
           if (msgs[i]->flags & I2C_M_RD) {    /*读取*/  
               i2c_adapter_xxx_setaddr((msg->addr << 1) | 1);  /*发送从设备地址*/  
               i2c_adapter_xxx_wait_ack();   /*获得从设备的ACK*/  
    i2c_adapter_xxx_readbytes(msgs[i]->buf,msgs[i]->len);  /*读取len长度的数据到buf中*/  
           } else {  
               i2c_adapter_xxx_setaddr(msg->addr << 1);  
               i2c_adapter_xxx_wait_ack();  
               i2c_adapter_xxx_writebytes(msgs[i]->buf, msgs[i]->len);  
           }  
        }  
       i2c_adapter_xxx_stop(); /*产生停止位*/  
    }  

框架图:



总结:

 

执行顺序:

(1)    i2c-core.c 完成i2c bus的注册;

(2)    bus/i2c-xxx.c 通过probe函数注册adapter,并添加相应的algorithm;

(3)    register adapter device的同时会添加boardinfo i2c设备device type为i2c_client_type;

(4)    i2c-dev.c:添加adapter 字符设备,创建设备文件提供上层相应的操作接口;

(5)    相应i2c驱动,通过add_i2c_driver,匹配bus上相应设备,走入相应的probe;









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值