IIC子系统和input子系统一样,适用于所有挂载在IIC下与SOC进行通行的。即适用于所有的IIC设备。
常见的有Cream mpu6050 等等的一些设备。
我们说input子系统里面要完成的事情都是把设备的信息传递给用户。就是input。
那对于我们IIC来说它肯定也是有一类的作用,所以才会划分出一类出来。所以IIC子系统它的功能是什么?它要做什么?
相对于IIC来说,我们之前就接触过IIC总线协议,IIC总线协议里面做的事情就是让主机和从机进行通信。

这是一些IIC传输过程的内容。
那我们IIC子系统一个也是要完成这样的一个通信。就是我们的soc作为主机,可以发送从机地址然后和从机通信,并且通信过程遵从IIC总线协议。
——————————————————————————————————————————————————
一、
我们看一下IIC子系统的框架是怎么完成这个步骤。

这个框架总共分为五层,但是驱动的框架是三层。
第一层应用层,用于数据交互。
第二层:IIC drivers从设备驱动层:这一层主要创建一个iic drivers的结构体并且注册到 iic bus的drv的链表里面。
然后再数据交互的时候会把数据放到I2C msg的结构体里面。
第三层:core 核心层:这一层做的事情就是把 drv 和 dev的链表进行匹配。
第四层:IIC adaptor 控制器层:这一层主要是接收到上层传送的数据,并发送到IIC控制器里面。
这个层做了:
1)创建一个IIC client的信息结构体,并注册到dev的链表进行匹配。(由IIC adapter 适配器,由设备树提供信息)
2)创建一个IIC adapter 适配器,也是一个结构体,里面有一个aloglitm 的一个算法 算法里面有master_Xop()
就是用来控制IIC通信,让它遵从IIC总线协议>
3)这一层还会有平台总线。等下我们会详细讲解,为什么这里有平台总线,并且它的作用是什么?
第五层:硬件设备层,这一层就是用iic总线(就是俩跟线)连接了很多从设备。
我们思考一些:这个和input子系统的框架有什么不同?
| |
| |
首先:
对我们来说,我们要编写的部分不同,输入子系统是要编写设备层,把设备添加进去。
而我们的iic子系统要不要添加设备呢??这肯定不用啊,因为我们的iic挂载的设备在板子做好的的时候就已经决定了
有那些设备还有地址,这些都是固定的,都是用物理上的俩根线给你串好了,你怎么添加?
所以我们编写的是drv层,目的就是找到我们要操作的从机,并且对它进行收发数据的通信。
所以这俩个东西做的事情是不一样的。
————————————————————————————————————————————————————
二、
数据传输过程。
我们的目的就是数据的传送和收发。
不是是SOC和IIC设备的的数据传送和通信,这个是裸机开发的时候讲的。
我们现在要做的事情就是我们的应用层,怎么和SOC连接的那两根线连接。
以我要发送一个从机地址为例讲数据的传输过程。

1)首先我们的数据会传送到IIC_msg这个结构体里面。
2)然后这个结构体其实是IIC_transfer接口里面的。
3)IIC_transfer接口就会借助IIC_client把数据发送到IIC_adapter这个结构体里面
这里面进行了很多一步。
首先IIC_adapter创建了IIC_client所以我可以借助IIC_client把数据发送到IIC_adapter这个结构体里面(以小博大的方法)
然后我IIC_transfer接口怎么借助到IIC_client的呢?
因为我IIC_client 和IIC_driver进行了匹配,所以IIC_driver可以拿到IIC_client
而匹配成功之后又会调用probe方法,里面也有client,然后我就把client给到IIC_transfer接口。
这就实现了:IIC_transfer接口就会借助IIC_client把数据发送到IIC_adapter这个结构体里面
4)数据包发送到IIC_adapter之后又会通过算法等达到控制sSDA和SCL的目的。
——————————————————————————————————————————————————————————
三、
前面说到了,在我们的iic_adpat层会有一个平台总线。

这是因为:我们的IIC控制器有非常多一个,每一个IIC设备都有控制器,然后控制器也是属于硬件的啊,它是属于SOC内部,但是CPU外部,所以它也要驱动,但是这个驱动只用一个IIC_S3C4210.C这个 当pdrv 驱动文件,然后那些很多的设备当成设备。
这样就引入了平台总线,要平台升级的时候,只需要在平台总线添加新的设备就好。
————————————————————————————————————————————————————————————
四,添加IIC设备树
我们以添加一个mpu6050为例。
要添加mpu6050我们肯定要知道,在设备树上要填写那些信息
所以我们用一个iic的设备树模板来对照
模板:
控制器对应的设备树:arch/arm/boot/dts/exynos4.dtsi
i2c_0: i2c@13860000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,s3c2440-i2c";
reg = <0x13860000 0x100>;
interrupts = <0 58 0>;
clocks = <&clock 317>;
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c0_bus>;
status = "disabled";
};
I2C 0代表是第几组i2c设备。
i2c@13860000 :代表基地址。
compatible = “samsung,s3c2440-i2c”; :名字,可用于做匹配
status = “disabled”;:状态,如果要使用这个IIC设备就要改成"okay";
reg = <0x13860000 0x100>;基地址
interrupts = <0 58 0>;;中断号。
查看芯片手册可以看到:
I2c子系统中涉及到的设备树文件:我们有板子有9组iic的线,每组可以挂IIC很多设备
i2c控制器地址
0x1386_0000,
0x1387_0000,
0x1388_0000,
0x1389_0000,
0x138A_0000,
0x138B_0000, ------ MPU6050
0x138C_0000,
0x138D_0000,
0x138E_0000
MPU6050: 从设备地址是0x68
soc GPB_3--- I2C_SCL5
GPB_3--- I2C_SDA5
GPX3_3--- GYRO_INT
在内核中默认就有了i2c0--13860000.i2
根据这些信息就可以写好我们的设备树信息
i2c@138B0000 {/*i2c adapter5信息*/
#address-cells = <1>;
#size-cells = <0>;
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <20000>;
pinctrl-0 = <&i2c5_bus>;
pinctrl-names = "default";
status = "okay";
//第五组IIC设备下面的的mpu6050设备
mpu6050@68 { /*i2c client信息*/
compatible = "invensense,mpu6050";
reg = <0x68>;
};
};
————————————————————————————————————————————————
驱动编写步骤:
我们编写是要编写:driver的部分。
直接编写i2c driver
1,构建i2c driver,并注册到i2c总线
2,实现probe:
|
申请设备号,实现fops
创建设备文件
通过i2c的接口去初始化i2c从设备
然后我们有几个常用的结构体对象:
struct i2c_driver:
struct i2c_driver {//表示是一个从设备的驱动对象
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int (*remove)(struct i2c_client *);
struct device_driver driver; //继承了父类
|
const struct of_device_id *of_match_table;
const struct i2c_device_id *id_table;//用于做比对,非设备树的情况
}
注册和注销
int i2c_add_driver( struct i2c_driver *driver);
void i2c_del_driver(struct i2c_driver *);
struct i2c_client:
struct i2c_client {//描述一个从设备的信息,不需要在代码中创建,因为是由i2c adapter帮我们创建
unsigned short addr; //从设备地址,来自于设备树中<reg>
char name[I2C_NAME_SIZE]; //用于和i2c driver进行匹配,来自于设备树中compatible
struct i2c_adapter *adapter;//指向当前从设备所存在的i2c adapter
struct device dev; // 继承了父类
};
创建i2c client的函数
struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
struct i2c_adapter :
struct i2c_adapter {//描述一个i2c控制器,也不是我们要构建,原厂的代码会帮我们构建
const struct i2c_algorithm *algo; //算法
|
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,int num);
struct device dev; //继承了父类,也会被加入到i2c bus
int nr; //编号
}
注册和注销:
int i2c_add_adapter(struct i2c_adapter * adapter);
void i2c_del_adapter(struct i2c_adapter * adap);
struct i2c_msg
struct i2c_msg {//描述一个从设备要发送的数据的数据包
__u16 addr; //从设备地址,发送给那个从设备
__u16 flags; //读1还是写0
__u16 len; //发送数据的长度
__u8 *buf; //指向数据的指针
};
//写从设备
int i2c_master_send(const struct i2c_client * client,const char * buf,int count)
//读从设备
int i2c_master_recv(const struct i2c_client * client,char * buf,int count)
以上两个函数都调用了:
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int

575

被折叠的 条评论
为什么被折叠?



