在没有dts配置I2C硬件信息的情况下,要怎么去适配I2C设备和对应的驱动匹配,让驱动探测到设备,并且让probe函数跑起来
硬件信息:
CPU:海光平台Hygon3490
I2C芯片:at24c eep芯片, 从设备地址:0x57【可以跳电阻改地址】
I2C总线:I2C1
在内核没有设备树(DTS)的情况下,要加载 `at24` 驱动并指定硬件资源,主要有两种标准方法。根据硬件信息的情况(硬件连接在 `I2C1`,设备地址 `0x57`),我推荐使用 方法一。
首先不能忘记把对应驱动编译进内核或者模块:
#以下宏定义二选一即可,在对应defconfig文件配置 #eep驱动编译进内核 CONFIG_EEPROM_AT24=y #或者编译成模块,即ko CONFIG_EEPROM_AT24=m方法一:使用 `i2c_board_info` (推荐)
这是在没有设备树的传统内核中最标准的方法。其核心思想是在板级初始化代码中,通过 `i2c_board_info` 结构体静态描述设备信息。
1. 定义 `i2c_board_info` 结构体
你需要在板级初始化文件(通常是 `arch/xxx/mach-xxx/board-xxx.c` 或类似文件)中添加如下代码。这个结构体告诉内核:“在名为 `24c256` 的设备,其从设备地址是 `0x57`”。
#include <linux/i2c.h> #include <linux/platform_data/at24.h> /* 如果驱动需要额外的平台数据,可以在这里定义 */ static struct at24_platform_data eeprom_pdata = { .byte_len = 256 * 1024 / 8, /* 根据你的 EEPROM 型号设置,例如 24c256 */ .page_size = 64, /* 根据你的 EEPROM 型号设置 */ .flags = AT24_FLAG_ADDR16, /* 根据你的 EEPROM 型号设置,例如 16-bit 地址 */ }; static struct i2c_board_info __initdata my_i2c_board_info[] = { { I2C_BOARD_INFO("24c256", 0x57), /* 驱动名称与设备地址 */ .platform_data = &eeprom_pdata, /* 可选,如果需要 */ }, };2. 注册设备到 I2C 总线
在同一个文件的板级初始化函数中(例如 `xxx_init(void)`),调用 `i2c_register_board_info()` 函数,将上述设备信息注册到特定的 I2C 总线(这里是 `I2C1`)上。
/* * 第一个参数是总线号,对于 I2C1,通常是 1。 * 具体编号需参考你的硬件手册或内核中 I2C 控制器的注册顺序。 */ i2c_register_board_info(1, my_i2c_board_info, ARRAY_SIZE(my_i2c_board_info));3. 重新编译内核并烧写
完成上述修改后,需要重新编译内核,并将新生成的内核镜像烧写或者更新到海光平台上。重启后,当 `at24` 驱动加载时,它应该就能正确匹配到这个设备并执行 `probe` 函数了。
或者如果没有板级配置文件或者不知道使用哪个板级配置文件也可以直接改到驱动里面去,参考如下:
.flags = I2C_DRV_ACPI_WAIVE_D0_PROBE, }; static struct i2c_client *at24_device_client; static int __init at24_init(void) { - if (!at24_io_limit) { - pr_err("at24: at24_io_limit must not be 0!\n"); - return -EINVAL; - } + struct i2c_adapter *adap; + struct i2c_board_info info = { + .type = "24c64", /* 匹配 at24_ids[] 中的 name */ + .addr = 0x57, /* 根据实际硬件修改:24c64 常见 0x50~0x57 */ + .flags = 0, + }; + int ret; + at24_io_limit = rounddown_pow_of_two(at24_io_limit); - return i2c_add_driver(&at24_driver); + /* 1. 注册驱动 */ + ret = i2c_add_driver(&at24_driver); + if (ret) { + pr_err("at24: driver registration failed (%d)\n", ret); + return ret; + } + /* 2. 获取 I2C adapter(总线号 1,用 i2cdetect -l 确认你的总线号) */ + adap = i2c_get_adapter(1); + if (!adap) { + pr_err("at24: i2c adapter 1 not found\n"); + i2c_del_driver(&at24_driver); + return -ENODEV; + } + /* 3. 强行在总线上创建设备 */ + at24_device_client = i2c_new_client_device(adap, &info); + i2c_put_adapter(adap); + + if (IS_ERR(at24_device_client)) { + ret = PTR_ERR(at24_device_client); + pr_err("at24: failed to create i2c client (%d)\n", ret); + at24_device_client = NULL; + i2c_del_driver(&at24_driver); + return ret; + } + pr_info("at24: go to probe 24c64 at 0x%02x on i2c-%d\n",info.addr, adap->nr); + return 0; } module_init(at24_init); static void __exit at24_exit(void) { + if (at24_device_client) { + i2c_unregister_device(at24_device_client); + at24_device_client = NULL; + } i2c_del_driver(&at24_driver); } module_exit(at24_exit);方法二:通过 `/sys` 文件系统动态创建 (调试/临时)
此方法适用于调试或临时测试,不需要修改和编译内核。
1. 加载驱动
首先,确保 `at24` 驱动模块已加载。
insmod at24.ko # 或者如果已经编译进内核,则此步可跳过2. 动态创建设备
使用 `echo` 命令向 `/sys/bus/i2c/devices/i2c-1/new_device` 文件写入设备信息,格式为 `设备名称 设备地址`。
echo "24c256 0x57" > /sys/bus/i2c/devices/i2c-1/new_device
执行后,内核会尝试在 `I2C1` 总线上创建一个地址为 `0x57` 的 `24c256` 设备,并尝试与 `at24` 驱动进行匹配。
方法三:使用设备树覆盖层 (Device Tree Overlay)
如果你的海光平台使用设备树,但你想在不修改基础 DTS 的情况下添加设备,可以使用设备树覆盖层 (DT Overlay)。
创建一个 `.dts` 文件(例如 `eeprom-overlay.dts`),内容如下:```dts
/dts-v1/; /plugin/; / { fragment@1 { target = <&i2c1>; /* 假设 I2C1 在基础 DTS 中的标签是 &i2c1 */ __overlay__ { #address-cells = <1>; #size-cells = <0>; eeprom@57 { compatible = "atmel,24c256"; /* 需要与驱动匹配 */ reg = <0x57>; }; }; }; };然后编译并加载这个 overlay:
dtc -@ -I dts -O dtb -o eeprom-overlay.dtbo eeprom-overlay.dts # 加载 overlay (具体命令可能因平台而异)关于at24驱动加载函数
`at24_init` 函数使用 `i2c_add_driver(&at24_driver)` 来注册驱动。这个操作本身只是告诉内核:“我这里有 `at24` 这个驱动”。驱动与设备的匹配(即 `probe` 函数的调用)发生在内核遍历 I2C 设备列表时。因此,关键在于“如何将这个设备信息放入内核的 I2C 设备列表”中,这正是上面三种方法要解决的问题。
重要检查与注意事项
1. 确认 I2C 总线编号:务必确认 `I2C1` 在内核中对应的总线编号是 `1`。可以通过 `i2cdetect -l` 命令查看系统中所有 I2C 总线及其编号。
2. 确保驱动兼容:`at24` 驱动是一个通用驱动,它通过 `compatible` 或 `i2c_device_id` 来匹配设备。请确保 `I2C_BOARD_INFO` 中的名称(如 `"24c256"`)存在于 `at24` 驱动的 `i2c_device_id` 列表中。通常,`at24` 驱动支持 `"24c256"`、`"atmel,24c256"` 等多种名称。
3. 验证设备地址:`0x57` 是标准的 7 位 I2C 设备地址,不包含读写位。
4. 检查 `at24_io_limit`:你的 `at24_init` 函数中检查了 `at24_io_limit`,如果它为 0 则加载失败。请确保在加载驱动前,通过模块参数或其他方式正确设置了该值。
总结一下:
最可靠的方法是修改板级文件,使用 `i2c_register_board_info` 进行静态注册。如果只是想快速验证,可以使用 `/sys` 文件系统接口。选择哪种方法,取决于你的需求是永久性的解决方案还是临时性的调试。