I2C系统驱动程序模型

文章详细介绍了Linux内核中的I2C驱动程序模型,包括I2C驱动的层次结构,如I2CCore、i2c_driver和i2c_client。i2c_driver通过of_match_table和id_table与i2c_client匹配,成功后调用probe函数。同时,文章列举了创建i2c_client的四种方法,包括通过设备树、i2c_register_board_info函数,以及i2c_new_device和i2c_new_probed_device函数。此外,还提到了用户空间生成i2C客户端的机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

I2C系统驱动程序模型



参考资料:

  • Linux内核文档:
    • Documentation\i2c\instantiating-devices.rst
    • Documentation\i2c\writing-clients.rst
  • Linux内核驱动程序示例:
    • drivers/eeprom/at24.c

一、 I2C驱动程序的层次

在这里插入图片描述
I2C Core就是I2C核心层,它的作用:

  • 提供统一的访问函数,比如i2c_transfer、i2c_smbus_xfer等
  • 实现I2C总线-设备-驱动模型,管理:I2C设备(i2c_client)、I2C设备驱动(i2c_driver)、I2C控制器(i2c_adapter)

二、 I2C总线-设备-驱动模型

在这里插入图片描述

2.1 i2c_driver

i2c_driver表明能支持哪些设备:

  • 使用of_match_table来判断
    • 设备树中,某个I2C控制器节点下可以创建I2C设备的节点
      • 如果I2C设备节点的compatible属性跟of_match_table的某项兼容,则匹配成功
    • i2c_client.name跟某个of_match_table[i].compatible值相同,则匹配成功
  • 使用id_table来判断
    • i2c_client.name跟某个id_table[i].name值相同,则匹配成功

i2c_driver跟i2c_client匹配成功后,就调用i2c_driver.probe函数。

2.2 i2c_client

i2c_client表示一个I2C设备,创建i2c_client的方法有4种:

  • 方法1

    • 通过I2C bus number来创建

      int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len);
      
    • 通过设备树来创建

    	i2c1: i2c@400a0000 {
    		/* ... master properties skipped ... */
    		clock-frequency = <100000>;
    
    		flash@50 {
    			compatible = "atmel,24c256";
    			reg = <0x50>;
    		};
    
    		pca9532: gpio@60 {
    			compatible = "nxp,pca9532";
    			gpio-controller;
    			#gpio-cells = <2>;
    			reg = <0x60>;
    		};
    	};
    
  • 方法2
    有时候无法知道该设备挂载哪个I2C bus下,无法知道它对应的I2C bus number。
    但是可以通过其他方法知道对应的i2c_adapter结构体。
    可以使用下面两个函数来创建i2c_client:

    • i2c_new_device

        static struct i2c_board_info sfe4001_hwmon_info = {
      	I2C_BOARD_INFO("max6647", 0x4e),
        };
      
        int sfe4001_init(struct efx_nic *efx)
        {
      	(...)
      	efx->board_info.hwmon_client =
      		i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info);
      
      	(...)
        }
      
    • i2c_new_probed_device

        static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
      
        static int usb_hcd_nxp_probe(struct platform_device *pdev)
        {
      	(...)
      	struct i2c_adapter *i2c_adap;
      	struct i2c_board_info i2c_info;
      
      	(...)
      	i2c_adap = i2c_get_adapter(2);
      	memset(&i2c_info, 0, sizeof(struct i2c_board_info));
      	strscpy(i2c_info.type, "isp1301_nxp", sizeof(i2c_info.type));
      	isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
      						   normal_i2c, NULL);
      	i2c_put_adapter(i2c_adap);
      	(...)
        }
      
    • 差别:

      • i2c_new_device:会创建i2c_client,即使该设备并不存在

      • i2c_new_probed_device:

        • 它成功的话,会创建i2c_client,并且表示这个设备肯定存在

        • I2C设备的地址可能发生变化,比如AT24C02的引脚A2A1A0电平不一样时,设备地址就不一样

        • 可以罗列出可能的地址

        • i2c_new_probed_device使用这些地址判断设备是否存在

  • 方法3(不推荐):由i2c_driver.detect函数来判断是否有对应的I2C设备并生成i2c_client

  • 方法4:通过用户空间(user-space)生成
    调试时、或者不方便通过代码明确地生成i2c_client时,可以通过用户空间来生成。

  // 创建一个i2c_client, .name = "eeprom", .addr=0x50, .adapter是i2c-3
  # echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-3/new_device
  
  // 删除一个i2c_client
  # echo 0x50 > /sys/bus/i2c/devices/i2c-3/delete_device

致谢

以上笔记源自韦东山老师的视频课程,感谢韦老师,韦老师是嵌入式培训界一股清流,为嵌入式linux开发点起的星星之火,也愿韦老师桃李满园。聚是一团火,散是满天星!

在这样一个速食的时代,坚持做自己,慢下来,潜心琢磨,心怀敬畏,领悟知识,才能向下扎到根,向上捅破天,背着世界往前行!
仅此向嵌入行业里的每一个认真做技术的从业者致敬!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值