总结
iic_client和iic_driver 加入iic总线的思想和paltform总线的玩法一样
 把iic设备和驱动注册到iic总线中 构造出字符设备驱动和设备节点供app进行操作
 但是iic硬件设备是挂在iic控制器下面的 所以iic控制器也会有自己的驱动和设备树节点 厂家一般都会帮做好
 我们写的iic_driver驱动程序 控制iic硬件的时候 使用iic总线提供的api 来控制iic硬件设备
 
 详细介绍分两部分 一个是iic设备驱动程序 一个是iic控制器驱动介绍
iic控制器驱动
芯片的iic控制器抽象成 一个iic_adapter (一般这个控制器的驱动和设备节点芯片厂商都帮创建好了)
 iic_algotithm 也构建好了
linux 上电注册iic总线 drivers/i2c/i2c-core-base.c
static int __init i2c_init(void)
	bus_register(&i2c_bus_type); //很熟悉的总线注册
IIC总线匹配规则 也就是看总线上的.match函数
 - of_driver_match_device:设备树匹配方式
  - 比较 I2C 设备节点的 compatible 属性和 of_device_id 中的 compatible 属性
- acpi_driver_match_device : ACPI 匹配方式
- i2c_match_id:i2c总线传统匹配方式
  - 比较 I2C设备名字和 i2c驱动的id_table->name 字段是否相等
 
构造iic_适配器设备树节点
下面用IIC1控制器来举例子
i2c1: i2c@21a0000 {
				#address-cells = <1>;
				#size-cells = <0>;
				compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";
				reg = <0x21a0000 0x4000>;  //reg属性记录了IIC寄存器组的地址
				interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
				clocks = <&clks IMX6UL_CLK_I2C1>;
				status = "disabled";
			};  
 
适配器的驱动与之匹配
这个就是厂商写的适配器驱动 但只是在和设备树匹配后
 应该是存了个什么东西给 适配器万能驱动调用
plantform_driver.probe
	struct resource *res;
	void __iomem *base;
	of_device_id *of_id = of_match_device(i2c_imx_dt_ids,&pdev->dev);
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);//获取resource资源,放到设备树就是reg = <0x21a0000 0x4000>;
	base = devm_ioremap_resource(&pdev->dev, res);//对resource物理地址和虚拟地址映射,此时base记录了虚拟地址
	phy_addr = (dma_addr_t)res->start;//这里记录物理地址,直接从resource->start拿取
	i2c_imx = devm_kzalloc(&pdev->dev, sizeof(*i2c_imx), GFP_KERNEL);//分配内存
	i2c_imx->adapter.algo		= &i2c_imx_algo;//初始化运算器,用于直接操作硬件的代码
	ret = i2c_add_numbered_adapter(&i2c_imx->adapter);//在linux注册一个i2c_adap
	
static const struct i2c_algorithm i2c_imx_algo = {  //运算器结构体
	.master_xfer	= i2c_imx_xfer,//产生IIC通讯时序,负责数据收发
	.functionality	= i2c_imx_func,//查询iic通信协议类型,iic通讯协议有一大类
};
	
	
.master_xfer
	result = i2c_imx_start(i2c_imx);//发送IIC的启动信号
	...
	for (i = 0; i < num; i++) {  //在for循环里面发送数据
		if (i == num - 1)
			is_lastmsg = true;
	result = i2c_imx_bus_busy(i2c_imx, 1);//判断当前iic总线是否忙
	if (msgs[i].flags & I2C_M_RD) //不忙判断当前信息需要读还是写
			result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg);//这里真正控制IIC的寄存器进行发送读取
		else {
			if (i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD)
				result = i2c_imx_dma_write(i2c_imx, &msgs[i]);
			else
				result = i2c_imx_write(i2c_imx, &msgs[i]);
		}	
 
IIC核心函数和万能驱动!!! i2c-dev.c
iic设备驱动程序
struct i2c_client
 struct device dev; 继承了 struct device 符合linux驱动设备模型
 linux根据IIC设备节点自动生成i2c_client节点
struct i2c_client {
	unsigned short flags;		/* div., see below		*/
	unsigned short addr;		/* 7位地址	*/
	char name[I2C_NAME_SIZE];
	struct i2c_adapter *adapter;	/* the adapter we sit on	*/
	struct device dev;		/* 继承了 struct device 符合linux驱动设备模型		*/
	int init_irq;			/* irq set at initialization	*/
	int irq;			/* irq issued by device		*/
	struct list_head detected;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
	i2c_slave_cb_t slave_cb;	/* callback for slave mode	*/
#endif
};
struct i2c_driver {
	unsigned int class;
	/* Standard driver model interfaces */
	int (*probe)(struct i2c_client *, const struct i2c_device_id *);
	int (*remove)(struct i2c_client *);
	...
	struct device_driver driver;
	const struct i2c_device_id *id_table;
	...
}
                


















