作者:嵌入式Jerry
視頻教程請關注 B 站:“嵌入式Jerry”
一、寫在前面
在上一階段我們已經深入理解了字符設備驅動與設備模型之間的結合方式、sysfs 的創建方式以及平臺驅動模型的實際運用。今天我們邁入總線驅動模型的世界,聚焦于 I2C 總線驅動模型,并選取一個典型、真實且廣泛使用的驅動設備 —— at24 EEPROM,進行完整分析。
本篇內容將從 I2C 總線模型的架構出發,講清楚:
- 驅動如何注冊到 I2C 總線上?
- I2C client 是如何匹配的?
- at24 是如何成為標準驅動代表的?
- 如何配置設備樹節點?
- 如何驗證實際讀寫?
并配套提供真實代碼與調試示例。
二、I2C 總線驅動模型架構簡介
在 Linux 內核中,I2C 總線驅動模型是基于總線-設備-驅動的三層結構之上實現的:
I2C 總線(i2c_adapter) ←→ I2C 設備(i2c_client) ←→ I2C 驅動(i2c_driver)
i2c_adapter
:抽象了一個物理 I2C 控制器(主機控制器)i2c_client
:抽象了掛在某條 adapter 上的 I2C 外設i2c_driver
:抽象了對某種類型 I2C 設備的驅動代碼
這和設備模型中的 bus_type
、device
、device_driver
是一致的,i2c-core
就是 bus_type
的實現,負責完成 match 和 probe。
三、典型案例介紹:at24 EEPROM
我們選擇 i2c 子系統中的一個經典外設:at24 系列 EEPROM。它們遵循 I2C 協議,容量常見為 16Kbit/32Kbit/64Kbit,支持頁寫和順序讀。
在 Linux 內核中,驅動文件為:
drivers/misc/eeprom/at24.c
其本質是一個標準 i2c_driver
驅動。
四、設備樹配置
在 NXP i.MX8MP 平臺中,at24 EEPROM 可以通過設備樹添加,典型配置如下:
&i2c3 {status = "okay";clock-frequency = <400000>;eeprom@50 {compatible = "atmel,24c16";reg = <0x50>;pagesize = <16>;};
};
解釋:
compatible
:用于匹配驅動reg
:I2C 地址(7 位)pagesize
:頁寫大小(單位:字節)
五、驅動入口分析
at24.c
中的核心驅動結構如下:
static const struct of_device_id at24_of_match[] = {{ .compatible = "atmel,24c16", .data = (void *)AT24_DEVICE_MAGIC },{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, at24_of_match);static struct i2c_driver at24_driver = {.driver = {.name = "at24",.of_match_table = of_match_ptr(at24_of_match),},.probe_new = at24_probe,.remove = at24_remove,.id_table = at24_ids,
};
module_i2c_driver(at24_driver);
🔍 核心點解析:
- 使用
of_match_table
進行設備樹匹配; - 使用
module_i2c_driver
宏注冊; - probe 函數負責初始化工作,注冊字符設備。
六、字符設備注冊邏輯
at24 實現為字符設備,允許用戶從 /dev
直接讀寫 EEPROM 數據。
ret = devm_device_add_groups(&client->dev, at24_groups);
cdev_init(&at24->cdev, &at24_fops);
ret = cdev_add(&at24->cdev, at24->devt, 1);
device_create(...);
最終會創建出:
/dev/eeprom
/sys/class/eeprom/eeprom0
文件操作如下:
static const struct file_operations at24_fops = {.owner = THIS_MODULE,.llseek = no_llseek,.read = at24_read,.write = at24_write,.open = at24_open,
};
七、匹配過程剖析
整個驅動匹配過程:
at24
驅動通過of_match_table
注冊支持"atmel,24c16"
i2c-core
掃描設備樹時發現此節點- 創建
i2c_client
,并匹配i2c_driver
- 調用
at24_probe()
,完成驅動綁定
八、調試驗證操作
加載驅動后會創建字符設備:
ls /dev/eeprom
我們可以直接寫入:
echo "hello" > /dev/eeprom
再讀取:
hexdump -C /dev/eeprom
若權限不足,可添加 udev 規則或通過 root 權限訪問。
九、at24 驅動完整結構總覽
+-----------------------------+
| I2C Adapter |
| (控制器,如i.MX8MP) |
+-------------+-------------+|v
+-------------+-------------+
| I2C Client | ←─────────────── 由設備樹注冊
| i2c_client @ 0x50 |
+-------------+-------------+|v
+-------------+-------------+
| I2C Driver | ←─────────────── drivers/misc/eeprom/at24.c
| i2c_driver: at24 |
+-------------+-------------+|v
+-------------+-------------+
| Character Device | ←─────────────── /dev/eeprom
| file_operations: fops |
+---------------------------+
🔟 總結與思考
通過 at24 EEPROM 的驅動分析,我們掌握了 I2C 總線驅動模型的完整機制:
關鍵組成 | 說明 |
---|---|
i2c_adapter | 控制器抽象,如 i2c3 |
i2c_client | 掛載在 adapter 上的設備 |
i2c_driver | 與 client 匹配的驅動 |
device tree | 提供匹配入口 |
字符設備 | 提供用戶訪問接口 |
相比 platform 模型,I2C 總線驅動具有自動枚舉能力,更適合標準器件(如 EEPROM、音頻 codec、傳感器等)。
? 今日任務鞏固
- I2C 總線模型中,
client
與driver
如何匹配? - at24 驅動中,字符設備注冊在哪個函數中?
- 如何通過設備樹指定 I2C 地址與頁大小?
- EEPROM 驅動是否需要實現
read/write
? - 與 platform_driver 模型的區別有哪些?
📢 后續預告
在下一篇(Day 30 下篇)中,我們將圍繞 lm48100q 音頻 codec 展開,深入講解 音頻子系統 + I2C 驅動模型 的高級應用與集成技巧,敬請期待!
本文由 嵌入式Jerry 原創發布,轉載請注明出處
視頻教程請關注 B 站:“嵌入式Jerry”