Linux i2c总线(1) - 概述

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适配器时就需要提供这样的一个结构体变量。

struct i2c_adapter {
    struct module *owner;             //所有者
    unsigned int id;
    unsigned int class;               //该适配器支持的从机设备的类型
    const struct i2c_algorithm *algo; //该适配器与从机设备的通信算法
    int timeout;              //超时时间
    struct device dev;        //该适配器设备对应的device

    int nr;                   //适配器的编号
    char name[48];            //适配器的名字
    struct list_head userspace_clients;  //用来挂接与适配器匹配成功的从机设备i2c_client的一个链表头
};

(2)struct i2c_algorithm(I2C算法)

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

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

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

(3)struct i2c_client(I2C设备)

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

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

struct i2c_driver {      //代表一个i2c设备驱动
    unsigned int class;      //i2c设备驱动所支持的i2c设备的类型

    int (*attach_adapter)(struct i2c_adapter *);   //用来匹配适配器的函数 adapter
    int (*detach_adapter)(struct i2c_adapter *);
    ······
    int (*probe)(struct i2c_client *, const struct i2c_device_id *); //设备驱动层的probe函数
    int (*remove)(struct i2c_client *);                              //设备驱动层卸载函数
    struct device_driver driver;            //该i2c设备驱动所对应的device_driver
    const struct i2c_device_id *id_table;  //设备驱动层用来匹配设备的id_table
    const unsigned short *address_list;    //该设备驱动支持的所有次设备的地址数组
    struct list_head clients;              //用来挂接与该i2c_driver匹配成功的i2c_client (从机设备)的一个链表头
};
struct i2c_board_info {                 //这个结构体是用来描述板子上的一个i2c从机设备的信息
    char        type[I2C_NAME_SIZE];    //i2c从机设备的名字,用来初始化i2c_client.name
    unsigned short    flags;            //用来初始化i2c_client.flags
    unsigned short    addr;             //用来初始化 i2c_client.addr
    void        *platform_data;         //用来初始化 i2c_client.dev.platform_data
    struct dev_archdata    *archdata;   //用来初始化i2c_client.dev.archdata
#ifdef CONFIG_OF
    struct device_node *of_node;
#endif
    int        irq;                     //用来初始化i2c_client.irq
};

struct i2c_devinfo {
    struct list_head    list;            //作为一个链表节点挂接到__i2c_board_list 链表上去
    int            busnum;               //适配器的编号
    struct i2c_board_info    board_info; //内置的i2c_board_info 结构体
};

4. 关键文件(drivers\i2c)

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

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

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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值