i2c_add_driver关键流程

文章目录

    • [1. 背景](#1. 背景)
    • [2. 核心函数说明](#2. 核心函数说明)
    • [3. 执行流程详解](#3. 执行流程详解)
    • [4. 设备何时存在?两种典型场景](#4. 设备何时存在?两种典型场景)
      • [场景 A:设备先于驱动注册(常见于 Device Tree)](#场景 A:设备先于驱动注册(常见于 Device Tree))
      • [场景 B:驱动先于设备注册](#场景 B:驱动先于设备注册)
    • [5. 数据结构关系简图](#5. 数据结构关系简图)
    • [6. 总结:`i2c_add_driver()` 后的关键流程](#6. 总结:i2c_add_driver() 后的关键流程)

1. 背景

嵌入式开发中,存在很多的外设,如 i2c 设备,对于最常用的嵌入式OS --Linux,内核采用的驱动-总线-设备模型。最近刚好遇到一个i2c外设,设备树提前配置对应i2c的子设备信息,在设备启动后自动加载driver,自动触发匹配机制后,执行对应driver的probe流程。此处进行简单记录。

2. 核心函数说明

  • i2c_add_driver(struct i2c_driver *driver)
    其本质是一个宏,实际调用:
c 复制代码
i2c_register_driver(THIS_MODULE, driver);
  • i2c_register_driver(struct module *owner, struct i2c_driver *driver)

是真正的注册函数(定义在 drivers/i2c/i2c-core-base.c)。

3. 执行流程详解

  1. 步骤 1:注册 I2C 驱动到 I2C 总线
c 复制代码
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
  • i2c_driver 的内嵌 device_driver 结构挂载到 I2C 总线(i2c_bus_type)上。
  • 设置模块所有者(用于引用计数)。
  1. 步骤 2:调用 driver_register()
    这是 Linux 设备驱动模型的核心函数:
c 复制代码
ret = driver_register(&driver->driver);

该函数会:

  • 将驱动添加到总线的驱动链表中;
  • 遍历总线上所有已注册的设备,尝试与当前驱动匹配。
    🔍 注意:I2C 设备可能在驱动注册之前或之后被添加。无论哪种情况,只要两者都存在,就会触发匹配。
  1. 步骤 3:总线匹配(match)
    I2C 总线的.match回调是 i2c_device_match()(在 i2c-core-base.c 中):

它按优先级依次尝试匹配:

1.) ACPI 匹配(如果启用)

比较设备的 _HID 或 _CID 与驱动的 acpi_match_table

2.) OF(Device Tree)匹配

比较设备的 compatible 字符串与驱动的 of_match_table

这是嵌入式系统中最常见的匹配方式。

3.)I2C 地址 + 名称匹配

如果设备是通过 i2c_board_info 静态注册的(旧式方法),则比较:
i2c_client.name i2c_driver.id_table[i].name

同时检查 I2C 地址是否在 id_table 允许范围内(或通配)

✅ 只要满足任一匹配条件,就认为"驱动支持该设备"。

  1. 步骤 4:调用 probe() 函数
    匹配成功后,总线层调用驱动的 .probe 回调:

    ret = driver_probe_device(&driver->driver, &client->dev);

这最终会执行:

复制代码
status = drv->probe(client, i2c_match_id(drv->id_table, client));

其中:

  • client:匹配成功的 struct i2c_client(代表一个 I2C 从设备)
  • 第二个参数是匹配到的 i2c_device_id(来自 id_table

📌 关键点probe() 是驱动初始化硬件、申请资源、注册子系统(如 input、hwmon、regulator 等)的地方。

4. 设备何时存在?两种典型场景

场景 A:设备先于驱动注册(常见于 Device Tree)

  1. 内核启动时解析 DT,为每个 I2C 节点创建 i2c_client 并注册到 I2C 总线。
  2. 后续模块加载(或 built-in 驱动初始化)调用 i2c_add_driver()
  3. 驱动注册时,立即匹配已存在的 client,调用 probe()

场景 B:驱动先于设备注册

  1. 驱动先注册,但总线上尚无匹配设备 → probe() 暂不执行。
  2. 后续通过以下方式添加设备:
    • 用户空间:echo <name> <addr> > /sys/bus/i2c/devices/i2c-<bus>/new_device
    • 内核空间:i2c_new_client_device(adapter, info)
  3. 设备注册时,I2C 核心会反向匹配已注册的驱动 ,若匹配成功,立即调用 probe()

✅ 无论先后顺序,只要驱动和设备都存在且匹配,probe() 就会被调用一次。

5. 数据结构关系简图

复制代码
i2c_bus_type
│
├── drivers: [your_i2c_driver] ──┐
│                               │
└── devices: [i2c_client_1] ←───┘ (匹配成功 → probe)
             [i2c_client_2]
  • i2c_driver:描述驱动能力(支持哪些设备)
  • i2c_client:描述一个具体的 I2C 从设备(地址、名称、所属 adapter)

6. 总结:i2c_add_driver() 后的关键流程

步骤 动作
1 i2c_driver 注册到 i2c_bus_type
2 遍历总线上所有 i2c_client 设备
3 通过 ACPI / OF / id_table 进行匹配
4 对每个匹配成功的设备,调用 driver->probe(client, id)
5 probe() 成功 → 设备驱动绑定完成;失败 → 绑定终止

⚠️ 注意:probe() 必须可重入、线程安全,且不能睡眠过久(在某些上下文中)。

理解这一流程,对调试 I2C 驱动不加载、设备未识别等问题至关重要。

相关推荐
fengyue01102 小时前
C++使用epoll实现高并发tcp服务
linux·服务器·网络·c++
谷雨不太卷2 小时前
Linux_文件指令
linux·运维·服务器
0vvv02 小时前
Vimer
linux·靶机
MediaTea2 小时前
Python:实例 __dict__ 详解
java·linux·前端·数据库·python
jerryinwuhan2 小时前
linux_shell_2
linux
Hncj20222 小时前
项目02--JsonRpc
linux·c++·ubuntu·rpc
JobDocLS3 小时前
Linux系统相关知识
linux·运维·服务器
QT 小鲜肉3 小时前
【Linux命令大全】001.文件管理之gitview命令(实操篇)
linux·运维·服务器·chrome·笔记
DeeplyMind3 小时前
Linux MMU Notifier 机制与应用系列目录
linux·驱动开发·mmu notifier