概述
- I2C子系统首先可以划分为三个层次
- 用户空间:运行应用程序。
- 内核空间:处理驱动逻辑,又细分为 I2C 设备驱动层、I2C 核心层、I2C 适配器驱动层。
- 硬件层:具体的I2C外设和I2C控制器。

- 每层具体做什么事
- 在用户空间中,需要学会如何使用I2C编写应用程序
- 在内核空间中,需要学会如何使用I2C编写驱动程序
- 在硬件层中,对应的是具体的外设,需要能够找到这个外设连接到了哪个I2C上、所使用的I2C接口是哪一个
 
- I2C子系统中一共有两处对硬件的抽象:设备驱动层将I2C外设抽象为i2c_client;适配器驱动层将I2C控制器抽象为i2c_adapter
用户空间
- 目的:编写应用程序与I2C外设交互
- 如何交互:用户空间的应用程序通过对"设备节点"进行读、写等操作来访问硬件。
- 访问方式 :
- 通用访问 :通过 i2c-dev驱动(一个内核驱动)提供的/dev/i2c-X接口。应用程序可以直接向I2C总线上的某个地址发送和接收原始的I2C消息。
- 特定设备访问:通过 I2C 设备驱动层创建的设备节点进行访问。
 
- 通用访问 :通过 
I2C 设备驱动层
- I2C 设备驱动层的两个主要作用
 1.编写驱动程序,使 I2C 外设能够正常工作
 2.创建对应的设备节点
上层的应用程序通过对设备节点进行读、写等操作来与I2C外设交互
- 
我们在 I2C 设备驱动层中编写具体I2C设备的驱动程序,但是不需要涉及时序相关的代码。因为在I2C子系统框架中,时序相关的代码被放到了I2C 适配器驱动层中,由芯片原厂编写 
- 
在编写具体I2C设备的驱动程序时,如果要用I2C设备发数据,直接调用I2C核心层提供的API接口即可 
I2C 设备驱动层包含以下几个关键部分:
- i2c_client:Linux内核用来抽象和表示一个具体的I2C从设备的结构体
- i2c_driver:我们编写的驱动程序。也就是让外设能够工作起来的代码
- I2C 总线子系统
/dev/i2c-X是i2c-dev驱动(一个内核驱动)提供给用户空间的通用访问接口,让用户空间的应用程序可以直接向I2C总线上的某个地址发送和接收原始的I2C消息。- 设备树节点 ,如
ap3216c@1e,是描述I2C设备硬件信息的数据。
i2c_client是内核根据这些数据在内存中创建的一个struct实例。
硬件层
- 
硬件层中的I2C外设通过SDA和SCL两根线,连接到处理器上的I2C控制器 
- 
硬件I2C中I2C控制器可以自己产生I2C通信所需要的波形 
- 
而I2C控制器作为一个硬件,需要对应的驱动程序才能让它工作起来,也就是让I2C控制器能够产生I2C通信所需要的波形 
- 
I2C适配器驱动层的作用就是编写I2C控制器的驱动程序 
i2c adapter就是I2C控制器,linux中通过结构体i2c_adapter结构体表示一个I2C控制器
I2C 适配器驱动/I2C总线驱动层
- 
I2C 适配器驱动层中的驱动程序由芯片原厂编写,他们最懂自己芯片! 
- 
I2C适配器驱动层的作用就是编写具体的 I2C 硬件控制器的驱动程序,让它能够产生I2C通信所需要的波形 
- 
因此,I2C核心层需要和I2C 适配器驱动层打交道。 
I2C 适配器驱动程序的作用:
1、提供标准化的 I2C 传输接口,供 I2C 核心层调用
2、实现 I2C 总线协议的时序控制和数据收发
3、向核心层注册I2C总线 (i2c_adapter),并实现该总线的物理传输方法 (i2c_algorithm)
4、处理 I2C 总线错误和异常情况
I2C 核心层
- 
I2C 核心层位于 I2C 设备驱动层和 I2C 适配器驱动层中间 
- 
作用就是承上启下:负责 I2C设备驱动层和 I2C 适配器驱动层之间数据的传递 
- 
I2C 核心层是linux自带的,不需要我们编写代码 
I2C 核心层的主要函数:
- i2c_master_send:向 I2C 从设备发送数据
- i2c_master_recv:从从设备接收数据
- i2c_transfer
总结
- I2C核心层从I2C设备驱动 那里拿到数据(i2c_msg),然后调用I2C适配器驱动 的接口,I2C适配器驱动再控制硬件产生波形。