RK3568摄像头ov8858设备树 compatible → driver probe 完整匹配流程

📅 2026/7/29 9:43:02
RK3568摄像头ov8858设备树 compatible → driver probe 完整匹配流程
以 RK3568 上的 I2C 控制器rockchip,rk3568-i2c和 OV8858 摄像头ovti,ov8858为例追踪两条不同类型的匹配路径。一、整体架构两条路径of_platform_populate()│┌───────────────┴───────────────┐▼ ▼① I2C 控制器 ② OV8858 传感器(platform_device) (i2c_client)│ │compatible rockchip,rk3568-i2c compatible ovti,ov8858│ │在 platform bus 上 在 i2c bus 上匹配 platform_driver 匹配 i2c_driver│ │rk3x_i2c_probe() ov8858_probe()关键区别I2C 控制器是由 platform device直接挂在 platform bus 上而 OV8858 是 I2C_client_device挂在 I2C bus 上由 I2C 控制器在 probe 时通过 of_i2c_register_devices() 动态创建。二、路径 ①I2C 控制器匹配platform_driver设备树:// arch/arm64/boot/dts/rockchip/rk3568.dtsi驱动代码// drivers/i2c/busses/i2c-rk3x.c// 注册时机arch_initcall 或 module_platform_driver()module_platform_driver(rk3x_i2c_driver);MODULE_DEVICE_TABLE(of, rk3x_i2c_match)负责模块自动加载告诉系统这个模块支持哪些设备树兼容设备完整调用链━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━阶段 A: 设备树节点展开为 platform_device━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━start_kernel()└─→ rest_init()└─→ kernel_init()└──→ kernel_init_freeable()└─→ do_basic_setup()└─→ driver_init() // drivers/base/init.c│ ├── devices_init() // 创建 /sys/devices│ ├── buses_init() // 创建 /sys/bus│ │ └── bus_register(platform_bus_type) // ★ platform bus│ └── of_core_init()│└─→ do_initcalls()│// 在某级 initcall 中调用 of_platform_default_populate()└─→ of_platform_default_populate_init() // arch_initcall_sync└─→ of_platform_default_populate(NULL, NULL, NULL)└─→ of_platform_populate(root, ...) // ★ 入口// drivers/base/init.c阶段 B: of_platform_populate() → 递归遍历设备树// drivers/of/platform.c阶段 B1: of_platform_bus_create() → 递归创建设备阶段 B2: of_platform_device_create_pdata() → 创建 platform_device走到这里I2C 控制器对应的 platform_device 已经被创建并注册到了 platform bus 上。 此时 device_node np-OF_POPULATED 标志被置位。阶段 C: platform_device 和 platform_driver 如何 match进入到drivers/base/platform.c看看platform_device_add具体实现进入到drivers/base/core.c看看核心部分match成功后会有下面这一系列的连锁反应最后soc侧的i2c控制器以及它的子设备链表都会成功注册平台总线以及klist_devices总线一句话串起来I2C 控制器 platform_device→ platform_match(rockchip,rk3568-i2c) ✓→ rk3x_i2c_probe()→ i2c_add_adapter()→ of_i2c_register_devices() ← 遍历子节点→ for_each (子节点 camera36)→ i2c_new_client_device() ← 创建 i2c_client→ device_add(client-dev)→ bus_probe_device()→ i2c_device_match(ovti,ov8858) ✓→ ov8858_probe() ← 子设备 probe父设备的 probe 成功是子设备被创建的触发器。子设备通过 device_add() 重新进入 match 循环开启新一轮匹配。这就是设备树层级结构被逐层展开的机制。核心进入 // drivers/base/platform.c中static int platform_match这个函数的核心作用判断一个 platform_device 和一个 platform_driver 是否匹配。四条匹配路径按优先级从高到低依次尝试。---第 0 条driver_override —— 强制绑定优先级最高if (pdev-driver_override)return !strcmp(pdev-driver_override, drv-name);作用用户态通过 sysfs 强制指定这个设备只能用某个驱动绕过所有自动匹配逻辑。使用方式# 强制 fdd40000.i2c 只匹配名为 rk3x-i2c 的驱动echo rk3x-i2c /sys/bus/platform/devices/fdd40000.i2c/driver_override代码路径路径drivers/base/platform.c// sysfs 写入口static ssize_t driver_override_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count){struct platform_device *pdev to_platform_device(dev);// 把用户写入的字符串存到 pdev-driver_override// 下次 match 时优先使用}---第 1 条OF设备树匹配if (of_driver_match_device(dev, drv))return 1;路径drivers/of/device.cint of_driver_match_device(struct device *dev, const struct device_driver *drv){// 拿到 driver 的 of_match_tablereturn of_match_device(drv-of_match_table, dev);// │// │ drv-of_match_table rk3x_i2c_match[]// │ dev-of_node /i2cfdd40000 的 device_node// │// └── drivers/of/device.c// │// └── __of_match_node(matches, dev-of_node)// │// │ drivers/of/base.c// │// │ for (每个 match entry) {// │ compatible match-compatible; // rockchip,rk3568-i2c// │ if (__of_device_is_compatible(node, compatible, ...))// │ return match; ★ 匹配成功// │ }// │// └── ★ 比较的是// device_node 的 compatible 属性值// vs// of_match_table 中每个 entry 的 .compatible 字符串}实际比较过程device_node 的 compatible 属性/i2cfdd40000 {compatible rockchip,rk3568-i2c, rockchip,rk3399-i2c;// ↑ [0] ↑ [1]}driver 的 of_match_tablestatic const struct of_device_id rk3x_i2c_match[] {{ .compatible rockchip,rk3568-i2c, .data rk3568_soc_data }, ← 匹配{ .compatible rockchip,rk3399-i2c, .data rk3399_soc_data },{ }};比较过程第 1 轮device_node.compatible[0] (rockchip,rk3568-i2c) vs match[0].compatible (rockchip,rk3568-i2c)→ ★ 完全一致 → 返回该 entry其中携带了 .data rk3568_soc_data如果第一兼容项不匹配继续device_node.compatible[1] (rockchip,rk3399-i2c) vs match[0].compatible → 不匹配device_node.compatible[0] vs match[1].compatible → 不匹配device_node.compatible[1] (rockchip,rk3399-i2c) vs match[1].compatible (rockchip,rk3399-i2c) → 匹配关键of_match_device 返回的 of_device_id 指针会被保存到 dev-of_matchprobe 函数里可以通过 of_device_get_match_data() 拿到 .data 字段用来区分不同 SoC 的差异参数。---第 2 条ACPI 匹配if (acpi_driver_match_device(dev, drv))return 1;路径drivers/acpi/scan.c或 drivers/acpi/bus.cRK3568 是 ARM64 平台用设备树不用 ACPI这条永远跳过去。x86 服务器/PC 上才会走这里。---第 3 条ID table 匹配if (pdrv-id_table)return platform_match_id(pdrv-id_table, pdev) ! NULL;路径drivers/base/platform.cstatic const struct platform_device_id *platform_match_id(const struct platform_device_id *id,struct platform_device *pdev){while (id-name[0]) {if (!strcmp(pdev-name, id-name))return id; // 名字匹配id;}return NULL;}这是非设备树场景的传统匹配方式// driver 侧static const struct platform_device_id my_id_table[] {{ my-device, 0 },{ my-device-v2, 1 },{ }};// 比较的是 pdev-name vs id-name// pdev-name 可以是 my-device来自 board 文件硬编码---第 4 条名字 fallbackreturn (strcmp(pdev-name, drv-name) 0);最原始的方式device 的名字和 driver 的名字一模一样就算匹配。// driver 侧static struct platform_driver my_driver {.driver {.name my-device, // ← 这个名字},};// device 侧static struct platform_device my_device {.name my-device, // ← 和这个名字};// strcmp(my-device, my-device) 0 → 匹配---完整决策树│├── pdev-driver_override 非空│ → YES: 用户强制指定只比较 driver_override drv-name│ → NO: 继续│├── dev-of_node 存在 且 of_match_table 中有匹配的 compatible│ → YES: ★ 返回 1匹配成功设备树路径│ → NO: 继续│├── ACPI 表中有匹配│ → YES: 返回 1│ → NO: 继续│├── drv-id_table 中有和 pdev-name 匹配的│ → YES: 返回 1│ → NO: 继续│└── pdev-name drv-name→ YES: 返回 1→ NO: 返回 0匹配失败对于 RK356899% 的 match 都走第 1 条——OF 路径。 其他路径要么不启用ACPI要么是历史遗留的 fallback。三、OV8858 传感器匹配i2c_driver设备树驱动kernel\drivers\media\i2c\ov8858.cdrivers/i2c/i2c-core-base.cOV8858 在这个函数里实际走的路径i2c_device_match(devov8858_client, drvov8858_i2c_driver)of_driver_match_device(dev, drv)→ dev-of_node.compatible ovti,ov8858→ drv-of_match_table[0].compatible ovti,ov8858→ ★ 匹配成功返回 1③ 函数直接 return 1后面的 ACPI、id_table 不再执行整个函数对 OV8858 来说只有一行有效代码of_driver_match_device(dev, drv) 返回 1。 其余分支都是给没有设备树的平台用的。至此ov8858驱动实现匹配