I2C子系统驱动架构 - 驱动框架

文章系列

I2C子系统驱动架构 - 简介

I2C子系统驱动架构 - 驱动框架

I2C子系统驱动架构 - 具体实现

基于linux内核4.6.3版本介绍

I2C驱动框架

I2C驱动框架图如下所示,用户空间上的节点是用于上层开发工程师来操作i2c设备,内核空间的驱动架构分2层,Bus层的驱动代码是芯片厂商已经写好的,对于驱动开发人员来说,主要是设计device层的代码,不过要理解i2c驱动框架对于整个框架机制还是要熟练的

I2C子系统驱动架构 - 驱动框架_第1张图片

上图中的设备节点/dev/i2c-*只是简单列举了例子中i2c_dev.c驱动中的设备节点,实际i2c设备驱动节点的例子不一定是上图所示。不管怎样,整个i2c驱动框架还是符合设备驱动模型device-bus-driver,上图中的Device层的含义是相对于i2c Bus层来理解的,每一层都有自己的注册方法,系统启动后先要把Bus层注册,一个adapter对应一个bus,然后再把挂在总线上的所有device进行注册,然后i2c driver进行注册找到匹配的device,这样一个i2c设备就完成了。

i2c驱动的代码都在目录drivers/i2c/下,有三个目录algos busses muxes,其中busses目录是每个i2c模块或者说总线的代码目录,drivers/i2c/下的文件i2c-boardinfo.c i2c-core.c i2c-core.h i2c-dev.c i2c-mux.c i2c-smbus.c i2c-stub.c都是i2c驱动架构文件,其中 i2c-core.c 是主要文件

I2C总线介绍

I2C总线设备的注册是通过platform总线来注册初始化的,在系统初始化的时候platform总线会完成i2c bus也就是i2c adapter的device的注册,然后driver的注册根据各个SoC的i2c模块来进行注册,注册代码在文件drivers/i2/busses/i2c-*.c中,注册后就会进行匹配,匹配成功就完成adapter的注册,adapter除了可以被i2c_client使用,也可以被其他使用了i2c总线的设备来使用,比如在v4l2中就有v4l2_subdev是使用的i2c adapter作为subdev

结构体介绍

i2c_adapter和i2c_algorithm 都是操作i2c bus的结构体,前者定义一个i2c模块,后者定义操作模块的方法

struct i2c_adapter {
    struct module *owner;
    unsigned int class;       /* classes to allow probing for */
    const struct i2c_algorithm *algo; /* the algorithm to access the bus */
    void *algo_data;

    /* data fields that are valid for all devices   */
    struct rt_mutex bus_lock;

    int timeout;            /* in jiffies */
    int retries;
    struct device dev;      /* the adapter device */

    int nr;
    char name[48];
    struct completion dev_released;

    struct mutex userspace_clients_lock;
    struct list_head userspace_clients;

    struct i2c_bus_recovery_info *bus_recovery_info;
    const struct i2c_adapter_quirks *quirks;
};
struct i2c_algorithm {
    /* If an adapter algorithm can't do I2C-level access, set master_xfer
       to NULL. If an adapter algorithm can do SMBus access, set
       smbus_xfer. If set to NULL, the SMBus protocol is simulated
       using common I2C messages */
    /* master_xfer should return the number of messages successfully
       processed, or a negative value on error */
    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);

    /* To determine what the adapter supports */
    u32 (*functionality) (struct i2c_adapter *);

#if IS_ENABLED(CONFIG_I2C_SLAVE)
    int (*reg_slave)(struct i2c_client *client);
    int (*unreg_slave)(struct i2c_client *client);
#endif
};

函数介绍

i2c_add_adapter和i2c_add_numbered_adapter用来注册i2c bus设备,并把挂载在总线上的设备进行注册
i2c_del_adapter用来卸载i2c bus设备

extern int i2c_add_adapter(struct i2c_adapter *);
extern void i2c_del_adapter(struct i2c_adapter *);
extern int i2c_add_numbered_adapter(struct i2c_adapter *);

I2C设备驱动介绍

结构体介绍

i2c_client 等同于驱动模型中的device

struct i2c_client {
    unsigned short flags;       /* div., see below      */
    unsigned short addr;        /* chip address - NOTE: 7bit    */
                    /* addresses are stored in the  */
                    /* _LOWER_ 7 bits       */
    char name[I2C_NAME_SIZE];
    struct i2c_adapter *adapter;    /* the adapter we sit on    */
    struct device dev;      /* the device structure     */
    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
};

i2c_driver 等同于驱动模型中的driver

struct i2c_driver {
    unsigned int class;

    /* Notifies the driver that a new bus has appeared. You should avoid
     * using this, it will be removed in a near future.
     */
    int (*attach_adapter)(struct i2c_adapter *) __deprecated;

    /* Standard driver model interfaces */
    int (*probe)(struct i2c_client *, const struct i2c_device_id *);
    int (*remove)(struct i2c_client *);

    /* driver model interfaces that don't relate to enumeration  */
    void (*shutdown)(struct i2c_client *);

    /* Alert callback, for example for the SMBus alert protocol.
     * The format and meaning of the data value depends on the protocol.
     * For the SMBus alert protocol, there is a single bit of data passed
     * as the alert response's low bit ("event flag").
     */
    void (*alert)(struct i2c_client *, unsigned int data);

    /* a ioctl like command that can be used to perform specific functions
     * with the device.
     */
    int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);

    struct device_driver driver;
    const struct i2c_device_id *id_table;

    /* Device detection callback for automatic device creation */
    int (*detect)(struct i2c_client *, struct i2c_board_info *);
    const unsigned short *address_list;
    struct list_head clients;
};

函数介绍

i2c_new_device和i2c_unregister_device等同于驱动模型中的device注册与卸载函数

extern struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);

extern struct i2c_client *
i2c_new_probed_device(struct i2c_adapter *adap,
              struct i2c_board_info *info,
              unsigned short const *addr_list,
              int (*probe)(struct i2c_adapter *, unsigned short addr));

extern struct i2c_client *

extern void i2c_unregister_device(struct i2c_client *);

i2c_register_driver和i2c_del_driver等同于驱动模型中的driver注册与卸载函数

extern int i2c_register_driver(struct module *, struct i2c_driver *);

extern void i2c_del_driver(struct i2c_driver *);

你可能感兴趣的:(Linux驱动)