当前位置:   article > 正文

Linux i2c总线(1) - 概述_i2c设备中断引脚

i2c设备中断引脚

0. I2C子系统总体框架

1. 概念

        I2C总线因为它极简单的硬件连接和通讯方式,在现在的很多设备上它是一种不可或缺的通讯总线。当用单片机直接操作I2C时,其实很简单,只要正确把握IIC的操作时序就可以了,但是在linux系统中,I2C子系统结构是稍微有一点复杂度的,因为它涉及到很多linux内核相关的知识。

        这里的I2C Bus并不是通讯上的总线,而是linux系统为了管理设备和驱动而虚拟出来的(注意这里的虚拟和平台总线的虚拟,意思上有区别),I2C Bus被用来挂载I2C适配器(adapter)和I2C设备(client)。

        平台总线和IIC总线在Linux下都是被虚拟成总线模块,但是两者有很大区别,平台总线是纯虚拟的总线,不是通讯上的物理总线;而IIC总线是通讯上的物理总线,是有具体的控制器的(即dapter)。

        I2C适配器是SoC中内置i2c控制器的软件抽象,可以理解为他所代表的是一个I2C主机。

2. 两种实现方法

        I2C子系统提供的两种驱动实现方法(源码中I2C相关的驱动均位于:drivers/i2c目录下)

        第一种叫i2c-dev,对应drivers/i2c/i2c-dev.c,这种方法只是封装了主机(I2C master,一般是SoC中内置的I2C 控制器)的I2C 基本操作,并且向应用层提供相应的操作接口,应用层代码需要自己去实现对slave 的控制和操作,所以这种I2C 驱动相当于只是提供给应用层可以访问slave 硬件设备的接口,本身并未对硬件做任何操作,应用需要实现对硬件的操作,因此写应用的人必须对硬件非常了解,所以这种I2C 驱动又叫做“应用层驱动”,这种方式并不主流,它的优势是把差异化都放在应用中,这样在设备比较难缠(尤其是slave是非标准I2C时)时不用动驱动,而只需要修改应用就可以实现对各种设备的驱动。

        第二种I2C 驱动是所有的代码都放在驱动层实现,直接向应用层提供最终结果。应用层甚至不需要知道这里面有I2C存在,譬如电容式触摸屏驱动,直接向应用层提供/dev/input/event1 的操作接口,应用层编程的人根本不知道event1 中涉及到了I2C。

3. 相关的结构体

(1)struct i2c_adapter(I2C适配器)

        struct i2c_adapter是用来描述一个I2C适配器,在SoC中的指的就是内部外设I2C控制器,当向I2C核心层注册一个I2C适配器时就需要提供这样的一个结构体变量。

  1. struct i2c_adapter {
  2. struct module *owner; //所有者
  3. unsigned int id;
  4. unsigned int class; //该适配器支持的从机设备的类型
  5. const struct i2c_algorithm *algo; //该适配器与从机设备的通信算法
  6. int timeout; //超时时间
  7. struct device dev; //该适配器设备对应的device
  8. int nr; //适配器的编号
  9. char name[48]; //适配器的名字
  10. struct list_head userspace_clients; //用来挂接与适配器匹配成功的从机设备i2c_client的一个链表头
  11. };

(2)struct i2c_algorithm(I2C算法)

        struct i2c_algorithm结构体代表的是适配器的通信算法,在构建i2c_adapter结构体变量的时候会去填充这个元素。

  1. struct i2c_algorithm {
  2. int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
  3. int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data);
  4. u32 (*functionality) (struct i2c_adapter *);
  5. };

        注意:smbus协议是从I2C协议的基础上发展而来的,他们之间有很大的相似度,SMBus与I2C总线之间在时序特性上存在一些差别。

(3)struct i2c_client(I2C设备)

  1. struct i2c_client { //用来描述一个i2c 从机设备
  2. unsigned short flags; //描述i2c 从机设备特性的标志位
  3. unsigned short addr; //i2c 从机设备的地址
  4. ······
  5. char name[I2C_NAME_SIZE]; //i2c 从机设备的名字
  6. struct i2c_adapter *adapter; //指向与从机设备匹配成功的适配器
  7. struct i2c_driver *driver; //指向与从机设备匹配成功的设备驱动
  8. struct device dev; //该从机设备对应的device
  9. int irq; //从机设备的中断引脚
  10. struct list_head detected; //作为一个链表节点挂接到与他匹配成功的i2c_driver相应的链表头上
  11. };

(4)struct device_driver(I2C设备驱动)

  1. struct i2c_driver { //代表一个i2c设备驱动
  2. unsigned int class; //i2c设备驱动所支持的i2c设备的类型
  3. int (*attach_adapter)(struct i2c_adapter *); //用来匹配适配器的函数 adapter
  4. int (*detach_adapter)(struct i2c_adapter *);
  5. ······
  6. int (*probe)(struct i2c_client *, const struct i2c_device_id *); //设备驱动层的probe函数
  7. int (*remove)(struct i2c_client *); //设备驱动层卸载函数
  8. struct device_driver driver; //该i2c设备驱动所对应的device_driver
  9. const struct i2c_device_id *id_table; //设备驱动层用来匹配设备的id_table
  10. const unsigned short *address_list; //该设备驱动支持的所有次设备的地址数组
  11. struct list_head clients; //用来挂接与该i2c_driver匹配成功的i2c_client (从机设备)的一个链表头
  12. };
  1. struct i2c_board_info { //这个结构体是用来描述板子上的一个i2c从机设备的信息
  2. char type[I2C_NAME_SIZE]; //i2c从机设备的名字,用来初始化i2c_client.name
  3. unsigned short flags; //用来初始化i2c_client.flags
  4. unsigned short addr; //用来初始化 i2c_client.addr
  5. void *platform_data; //用来初始化 i2c_client.dev.platform_data
  6. struct dev_archdata *archdata; //用来初始化i2c_client.dev.archdata
  7. #ifdef CONFIG_OF
  8. struct device_node *of_node;
  9. #endif
  10. int irq; //用来初始化i2c_client.irq
  11. };
  12. struct i2c_devinfo {
  13. struct list_head list; //作为一个链表节点挂接到__i2c_board_list 链表上去
  14. int busnum; //适配器的编号
  15. struct i2c_board_info board_info; //内置的i2c_board_info 结构体
  16. };

4. 关键文件(drivers\i2c)

(1)i2c-core.c: i2c核心层

(2)busses目录:这个文件中是已经编写好的各种向i2c核心层注册的适配器

(3)algos目录:这个目录里面是一些I2C通信算法

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号