✳驱动之ic_bus_type框架

  • DTS中的 i2c设备节点(子节点) (例如:AT24C02)被转化为i2c_client结构体,其所在的 i2c控制器节点(父节点)转化为platform_device 结构体,匹配到对应的 platform_driver 结构体,调用对应的 probe 函数,该函数中实现:①分配、设置、注册 i2c_adapter 结构体,i2c 控制器驱动实现 ;②解析字节点,分配、设置、注册 i2c_client 结构体,该结构体对应i2c_bus 总线框架,匹配到对应的 i2c_driver 驱动,调用其中的 probe 函数,实现major、file_operations、register_chrdev、class_create,入口出口等。
  • 在实现file_operations中的read、write函数时,会使用 i2c_transfer() 函数,该函数本质是调用i2c_adapter结构体中的i2c_algorithm,此结构体包含 master_xfer()函数。
  • 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    */
        const struct i2c_lock_operations *lock_ops;
        struct rt_mutex bus_lock;
        struct rt_mutex mux_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_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
    };
    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
    };
    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
    };

     

  • probe中应用输入系统框架:
  • 为了适配以前写好的应用程序,上述probe函数中 使用到了输入系统 input_dev;不再是实现 major 这些,因为以前的应用程序可能不会去open一个你创建的设备节点,现在要去适配以前的应用程序,所以用到输入系统。
  • at24c02 应用
#define IO_READ 100;
#define IO_WRITE 101;

static struct i2c_client* at24c02_client;
static int major;
static struct class* at24c02_class;
static long at24c02_ioctl(struct file* file,unsigned int cmd,unsigned long arg){
    unsigned char data;
    unsigned char address;
    unsigned int ker_buf[2];
    unsigned int* user_buf = (unsigned int *)arg;
    copy_from_user(user_buf,ker_buf,8);
    struct i2c_msg msgs[2];
    address = ker_buf[1];
    unsigned int byte_buf[2];
    switch(cmd){
        case IO_READ:{
            msgs[0].addr = at24c02_client->addr;//设备地址
            msgs[0].flags = 0;//写地址
            msgs[0].len = 1;
            msgs[0].buf = &address;
            msgs[1].addr = at24c02_client->addr;
            msgs[1].flags = I2C_M_RD;
            msgs[1].len = 1;
            msgs[1].buf = &data;
            i2c_transfer(at24c02_client->adapter,msgs,2);
            ker_buf[1] = data;
            copy_to_user(ker_buf,user_buf,8);
            break;
        }
        case IO_WRITE:{
            byte_buf[0] = address;
            byte_buf[1] = ker_buf[1];
            msgs[0].addr = at24c02_client->addr;
            msgs[0].flags = 0;
            msgs[0].len = 2;
            msgs[0].buf = byte_buf;
            i2c_transfer(at24c02_client->adapter,msgs,1);
            mdelay(20);
            break;
        }  
    }
} 
static struct of_device_id gao_at24c02[] ={
    {.compatible = "gao,at24c02"},
    { },
};
static struct file_operations at24c02_fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = at24c02_ioctl,
}
static int at24c02_probe(struct i2c_client* client,const struct i2c_device_id* id){
    at24c02_client = client;
    major = register_chrdev(0,"at24c02",&at24c02_fops);
    at24c02_class = class_create(THIS_MODULE,"at24c02_class");
    device_create(at24c02_class,NULL,MKDEV(major,0),NULL,"myat24c02");
    return 0;
}
static int at24c02_remove(struct i2c_client* client){
    device_destroy(at24c02_class,MKDEV(major,0));
    class_destroy(at24c02_class);
    unregister_chrdev(major,"at24c02");
    return 0;
}
static struct i2c_device_id at24c02_id[] ={
    {.name = "xxx",.driver_data = NULL},
    { },
};
static struct i2c_driver at24c02_driver = {
    .driver = {
        .name = "myat24c02",
        .of_match_table = gao_at24c02,
    },
    .probe = at24c02_probe,
    .remove = at24c02_remove,
    .id_table = at24c02_id,//即使不用也得提供。调试程序时发现的bug(韦东山驱动开发P128、129)
};
static int __init at24c02_init(void){
    return err;
    err = i2c_add_driver(&at24c02_driver);
}
static void __exit at24c02_exit(void){
    i2c_del_driver(&at24c02_driver);
}
module_init(at24c02_init);
module_exit(at24c02_exit);
MODULE_LICENSE("GPL");

 

posted @ 2022-11-09 21:06  QianFa01  阅读(76)  评论(0)    收藏  举报