• linux驱动之I2C


    目录

     1. I2C驱动层次结构图

     2. struct i2c_driver结构体

     3. struct i2c_client结构体

     3. 数据收发相关函数

     4. I2c应用层驱动

     

     1. I2C驱动层次结构图

     I2C主机控制器驱动(adapter):一般由SOC厂家负责设计实现,用于控制I2C主机控制器发出时序信号;

    I2C Core:为上层提供统一的API接口和对其他模块进行注册和注销管理等;

    I2C设备驱动(Client):调用I2C Core提供的统一API,根据I2C设备的访问规范,控制I2C控制器发出不同的时序信号,对I2C设备进行访问;该驱动称为内核层I2C设备驱动;

    i2c-dev:将I2C主机控制器实现为一个字符设备,应用程序可直接通过访问/dev/i2c-N来访问I2C主机控制器,从而对I2C设备发起访问; 称为应用层I2C设备驱动

    2. struct i2c_driver结构体

    该结构体用于表示i2c设备驱动; 

    1. struct i2c_driver {
    2. //我们实例化什么样的i2c设备
    3. unsigned int class;
    4. //总线添加和移除时回调函数
    5. int (*attach_adapter)(struct i2c_adapter *) __deprecated;
    6. int (*detach_adapter)(struct i2c_adapter *) __deprecated;
    7. //设备绑定和解绑回调函数
    8. int (*probe)(struct i2c_client *, const struct i2c_device_id *);
    9. int (*remove)(struct i2c_client *);
    10. //关机,挂起,恢复时回调函数
    11. void (*shutdown)(struct i2c_client *);
    12. int (*suspend)(struct i2c_client *, pm_message_t mesg);
    13. int (*resume)(struct i2c_client *);
    14. //警报回调,例如SMBus警报协议
    15. void (*alert)(struct i2c_client *, unsigned int data);
    16. //总线信号回调
    17. int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
    18. //设备驱动模型驱动
    19. struct device_driver driver;
    20. //此驱动程序支持的I2C设备列表
    21. const struct i2c_device_id *id_table;
    22. /* Device detection callback for automatic device creation */
    23. int (*detect)(struct i2c_client *, struct i2c_board_info *);
    24. const unsigned short *address_list;
    25. struct list_head clients;
    26. };

     常用的API:

    //添加i2c设备驱动

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

    #define i2c_add_driver(driver) \
        i2c_register_driver(THIS_MODULE, driver)

    //删除i2c设备驱动
    void i2c_del_driver(struct i2c_driver *);

    可用宏简写上述两API;参数为已填充好的struct i2c_driver变量;

    #define module_i2c_driver(__i2c_driver) \
        module_driver(__i2c_driver, i2c_add_driver, \
                i2c_del_driver)

     示例:

    1. static struct i2c_driver ltc4151_driver = {
    2. .driver = {
    3. .name = "ltc4151",
    4. },
    5. .probe = ltc4151_probe,
    6. .remove = ltc4151_remove,
    7. .id_table = ltc4151_id,
    8. };
    9. module_i2c_driver(ltc4151_driver);

     3. struct i2c_client结构体

    该结构体用于表示i2c从设备; 

    1. struct i2c_client {
    2. unsigned short flags;
    3. /*
    4. #define I2C_CLIENT_PEC 0x04 //用于包错误检查
    5. #define I2C_CLIENT_TEN 0x10 //十位的芯片地址
    6. #define I2C_CLIENT_WAKE 0x80 //for board_info; true iff can wake
    7. */
    8. //连接到父适配器的I2C总线上使用的地址。
    9. unsigned short addr;
    10. //指示设备的类型,通常是一个通用的芯片名称,足以隐藏第二来源和兼容版本
    11. char name[I2C_NAME_SIZE];
    12. //适配器
    13. struct i2c_adapter *adapter;
    14. //设备驱动
    15. struct i2c_driver *driver;
    16. //设备
    17. struct device dev;
    18. //指示此设备生成的IRQ
    19. int irq;
    20. struct list_head detected;
    21. };

    常用 API:

    void *i2c_get_clientdata(const struct i2c_client *dev);

    void i2c_set_clientdata(struct i2c_client *dev, void *data)

     3. 数据收发相关函数

     //作用:向I2c从设备写数据;

    //I2c设备的地址包含在client中,要写的数据为buf,写的字节数为count;

    int i2c_master_send(const struct i2c_client *client, const char *buf, int count);

    //作用:向I2c从设备读数据; 参数同上;
    int i2c_master_recv(const struct i2c_client *client, char *buf,int count);

    将几个读写操作合并在一起执行的函数; 

    /*

            adap:执行写操作的I2c主机控制器;

            msgs:消息数组;

            num:消息的数量;

    */

    int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);

     struct i2c_msg结构体如下:

    1. struct i2c_msg {
    2. __u16 addr; /* slave address (从设备地址)*/
    3. __u16 flags;//操作的标志,如下
    4. #define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
    5. #define I2C_M_RD 0x0001 /* read data, from slave to master */
    6. #define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */
    7. #define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
    8. #define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
    9. #define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
    10. #define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
    11. #define I2C_M_16BIT_REG 0x0002 /* indicate reg bit-width is 16bit */
    12. #define I2C_M_16BIT_DATA 0x0008 /* indicate data bit-width is 16bit */
    13. __u16 len; /* msg length 消息长度 */
    14. __u8 *buf; /* pointer to msg data 指向消息数据的指针 */
    15. };

     内核驱动框架

    1. //用于设备树匹配
    2. const struct of_device_id of_mpu6050_id[] = {
    3. {
    4. .compatible = "mpu6050, 0",
    5. },
    6. {},
    7. };
    8. static struct i2c_driver mpu6050_drv = {
    9. .probe = mpu6050_drv_probe,
    10. .remove= mpu6050_drv_remove,
    11. .driver = {
    12. .name = "mpu6050",//随便写,出现在/sys/bus/i2c/driver/ 下
    13. .of_match_table = of_match_ptr(of_mpu6050_id),
    14. },
    15. .id_table = mpu6050_id_table,
    16. };
    17. #if 0
    18. static int __init mpu6050_drv_init(void)
    19. {
    20. return i2c_add_driver(&mpu6050_drv);
    21. }
    22. static void __exit mpu6050_drv_exit(void)
    23. {
    24. i2c_del_driver(&mpu6050_drv);
    25. }
    26. module_init(mpu6050_drv_init);
    27. moudle_exit(mpu6050_drv_exit);
    28. #else
    29. mpdule_i2c_driver(mpu6050_drv);
    30. #endif
    31. MODULE_LICENSE("GPL");

    4. I2c应用层驱动

     内核需要配置:

    Device Drivers -->

            -*- I2C support -->

                    <*> I2C device interface

     应用层驱动主要调用所对应的Linux驱动为drivers/i2c/i2c-dev.c中; 

    应用层流程:

    1. {
    2. int ret = -1;
    3. struct i2c_msg msg[2];
    4. unsigned char buf[4] = {0};
    5. struct i2c_rdwr_ioctl_data rdwr = {0};
    6. unsigned int data;
    7. int fd = open(I2C_NAME,O_RDWR);
    8. if(0 > fd){
    9. printf("open %s failed\n",I2C_NAME);
    10. goto ERR0;
    11. }
    12. ret = ioctl(fd, I2C_SLAVE_FORCE, DEV_READ_ADDR);
    13. if(0 > ret){
    14. printf("ioctl I2C_SLAVE_FORCE 0x%x failed\n",DEV_READ_ADDR);
    15. goto ERR1;
    16. }
    17. msg[0].addr = DEV_READ_ADDR;
    18. msg[0].flags = 0;
    19. msg[0].len = 0x1;
    20. msg[0].buf = buf;
    21. msg[1].addr = DEV_READ_ADDR;
    22. msg[1].flags = 0;
    23. msg[1].flags |= I2C_M_RD;
    24. msg[1].len = 0x1;
    25. msg[1].buf = buf;
    26. rdwr.msgs = &msg[0];
    27. rdwr.nmsgs = (__u32)2;
    28. buf[0] = reg_addr & 0xff;
    29. ret = ioctl(fd, I2C_RDWR, &rdwr);
    30. if(0 > ret){
    31. printf("ioctl I2C_RDWR failed\n");
    32. goto ERR1;
    33. }
    34. data = buf[0];
    35. printf("0x%x: 0x%x\n", reg_addr, data);
    36. ERR1:
    37. close(fd);
    38. ERR0:
    39. return ret;
    40. }

  • 相关阅读:
    2022.11.28 英语背诵
    java-net-php-python-jsp社会公共常识科普网的设计与实现计算机毕业设计程序
    品达通用权限系统(Day 7~Day 8)
    从零开始学JAVA(02):基本知识、基本数据类型、运算符、转义符
    LeetCode 2416. 字符串的前缀分数和
    zookeeper快速上手
    【深度学习】可交互讲解图神经网络GNN
    Element的MessageBox自定义图标
    毅速丨哪些金属材料在3D打印中应用最多
    编译过程 & 学习 CMake 文档的前置知识
  • 原文地址:https://blog.csdn.net/qq_39048131/article/details/126810111