嵌入式LINUX驱动学习之15 i2c总线源码分析

一、i2c设备的注册

1.1、struct i2c_board_info结构体及头文件

//头文件位置 : include/linux/i2c.h 
//结构体定义
struct i2c_board_info {
    
    
        char            type[I2C_NAME_SIZE];  //i2c_client.name
        unsigned short  flags;                //i2c_client.flags
        unsigned short  addr;                 //i2c_client.addr
        void            *platform_data;       //i2c_client.dev.platform_data
        //........省略更多............
};
//struct i2c_board_info结构体对象可以用下面的宏进行定义
#define I2C_BOARD_INFO(dev_type, dev_addr) \
        .type = dev_type, .addr = (dev_addr)
//使用:
struct i2c_board_info i2c_obj_info[] = {
    
    
    {
    
    
        I2C_BOARD_INFO("i2c设备匹配名称“,i2c设备物理地址)
    }
}

1.2、i2c_register_board_info()函数头文件

使用方法见: i2c代码举例(三轴加速度传感器MMA8653)方式一

//头文件位置 : include/linux/i2c.h 
//函数原型:
int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned n)/*      
    参数说明:
        busum  : i2x设备所属总线;
        info   :定义的struct i2c_board_info结构体对象取首地址,用于描述i2c设备,可以是数组;
        n      :struct i2c_board_info对象个数,即i2c设备数量

1.2.1、i2c_register_board_info()函数实现

//源码位置:drivers/i2c/i2c-boardinfo.c 
int __init i2c_register_board_info(int busnum,\
        struct i2c_board_info const *info, unsigned len)
{
    
    
        int status;
        down_write(&__i2c_board_lock);//获取信号量写锁操作
        /* 动态分配总线号 */
        if (busnum >= __i2c_first_dynamic_bus_num)
                __i2c_first_dynamic_bus_num = busnum + 1;
        /* 注册info中的i2c设备 */
        for (status = 0; len; len--, info++) {
    
    
                struct i2c_devinfo      *devinfo;
                devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
                /*当内核空间分配内存失败时执行的操作*/
                if (!devinfo) {
    
    
                        pr_debug("i2c-core: can't register boardinfo!\n");
                        status = -ENOMEM;
                        break;
                }

                devinfo->busnum = busnum;
                devinfo->board_info = *info;
                list_add_tail(&devinfo->list, &__i2c_board_list);//将devinfo节点加入到__i2c_board_list链表中;
        }
        up_write(&__i2c_board_lock);//释放信号量写锁
        return status;//返回0 或错误号 -ENOMEM;
}

1.2.2 i2c_register_board_info的配套函数arch_initcall()

//头文件位置 : include/linux/init.h
#define __define_initcall(level,fn,id) \
        static initcall_t __initcall_##fn##id __used \
        __attribute__((__section__(".initcall" level ".init"))) = fn
#define arch_initcall(fn)               __define_initcall("3",fn,3)

1.3 i2c_new_device() 和 i2c_get_adapter();

使用方法见: i2c代码举例(三轴加速度传感器MMA8653)方式二

1.3.1 i2c_new_device() 通过模块的方式添加一个i2c设备

/*
    头文件:include/linux/i2c.h
    源码位置:drivers/i2c/i2c-core.c
    函数原型:
*/
struct i2c_client * i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
    /*参数说明:
           adap : struct i2c_apater结构体对象地址
           info : struct i2c_board_info 结构体对象地址
       功能:向i2c总线添加一个i2c从设备
       返回值 :成功:i2c从设备信息,保存在struct i2c_client结构体中
             
    */

1.3.2 i2c_get_adapter() 从内核I2C总线中获取总线适配器

/*
    头文件:include/linux/i2c.h
    源码位置:drivers/i2c/i2c-core.c
    函数原型:
*/
struct i2c_adapter *i2c_get_adapter(int nr)
    /*参数说明:
           nr : I2C总线编号 
      功能:
          根据I2C总线编号,获取I2C总线适配器
    */

1.4 i2c_new_probed_device()从地址列表中查找匹配的地址

和i2c_new_device()二选一使用即可

/*
    头文件:include/linux/i2c.h
    源码位置:drivers/i2c/i2c-core.c
    函数原型:
*/
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));
     /*参数说明:
           addr_list : i2c从设备可能的地址
           probe     :  当配置了对应的函数时,匹配成功,执行对应的函数,
                        如果匹配成功不需要执行对应函数,可以用NULL
      功能:
          根据I2C总线编号,获取I2C总线适配器
    */                  

二、i2c驱动软件信息

2.1结构体及函数

//头文件位置 : include/linux/i2c.h
struct i2c_driver {
    
    
    int (*probe)(struct i2c_client *, const struct i2c_device_id *);/*当软件驱动和硬件驱动匹配成功时,执行的函数*/
    int (*remove)(struct i2c_client *); /*当硬件驱动卸载或当前驱动卸载时执行的函数*/
    struct device_driver driver; /*主要使用const char *name;成员,用于和硬件驱动匹配*/
    //...........省略更多........................
}
int i2c_register_driver(struct module *owner, struct i2c_driver *driver); //注册软件驱动
i2c_add_driver(driver);//宏定义如下:
/*
#define i2c_add_driver(driver) \
        i2c_register_driver(THIS_MODULE, driver)
*/
void i2c_del_driver(struct i2c_driver *driver); //移除软件驱动
/*
    参数说明:
        owner : 一般用THIS_MODULE;
        driver: struct i2c_driver结构体对象取地址;
*/

三、i2c设备控制命令

//源码位置 : include/linux/i2c.h
/*
//Documentation/i2c/smbus-protocol
S     (1 bit) : Start bit
P     (1 bit) : Stop bit
Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
A, NA (1 bit) : Accept and reverse accept bit.
Addr  (7 bits): I2C 7 bit address. Note that this can be expanded as usual to
                get a 10 bit I2C address.
Comm  (8 bits): Command byte, a data byte which often selects a register on
                the device.
Data  (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh
                for 16 bit data.
Count (8 bits): A data byte containing the length of a block operation.

[..]: Data sent by I2C device, as opposed to data sent by the host adapter.

*/
 s32 i2c_smbus_read_byte(const struct i2c_client *client);
     //S Addr Rd [A] [Data] NA P

s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value);
   //S Addr Wr [A] Data [A] P

s32 i2c_smbus_read_byte_data(const struct i2c_client *client,u8 command);
    //S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P

s32 i2c_smbus_write_byte_data(const struct i2c_client *client,u8 command, u8 value);
    //S Addr Wr [A] Comm [A] Data [A] P

s32 i2c_smbus_read_word_data(const struct i2c_client *client,u8 command);
    //S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P

s32 i2c_smbus_write_word_data(const struct i2c_client *client,u8 command, u16 value);
    //S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P

s32 i2c_smbus_read_block_data(const struct i2c_client *client,u8 command, u8 *values);
    //S Addr Wr [A] Comm [A] S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P

s32 i2c_smbus_write_block_data(const struct i2c_client *client,u8 command, u8 length, const u8 *values);
    //S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P

//...........省略更多,可以根据时芯片序图找函数,查找方式:
//...........先根据芯片时序图,到Documentation/i2c/smbus-protocol文档中找对应时序图的函数, 
//...........再根据找到的函数,到include/i2c.h中打函数的原型...................

猜你喜欢

转载自blog.csdn.net/weixin_47273317/article/details/108373643