Linux I2C Sysfs¶
概述¶
I2C 拓撲可能很複雜,因為存在 I2C MUX(I2C 多路複用器)。Linux 核心將 MUX 通道抽象為邏輯 I2C 匯流排號。然而,在將 I2C 匯流排物理號和 MUX 拓撲對映到邏輯 I2C 匯流排號方面存在知識空白。本文件旨在填補這一空白,以便讀者(例如硬體工程師和新軟體開發人員)通過了解物理 I2C 拓撲並在 Linux shell 中導航 I2C sysfs,來學習核心中邏輯 I2C 匯流排的概念。這些知識對於使用 i2c-tools 進行開發和除錯是必要且有用的。
目標讀者¶
需要在執行 Linux 的系統上使用 Linux shell 與 I2C 子系統互動的人員。
先決條件¶
熟悉常見的 Linux shell 檔案系統命令和操作。
熟悉 I2C、I2C MUX 和 I2C 拓撲的基本知識。
I2C Sysfs 的位置¶
通常,Linux Sysfs 檔案系統掛載在 /sys 目錄下,因此您可以在 /sys/bus/i2c/devices 下找到 I2C Sysfs,您可以直接 cd 到該目錄。該目錄下有一個符號連結列表。以 i2c- 開頭的連結是 I2C 匯流排,它們可以是物理的或邏輯的。其他以數字開頭並以數字結尾的連結是 I2C 裝置,其中第一個數字是 I2C 匯流排號,第二個數字是 I2C 地址。
例如 Google Pixel 3 手機
blueline:/sys/bus/i2c/devices $ ls
0-0008 0-0061 1-0028 3-0043 4-0036 4-0041 i2c-1 i2c-3
0-000c 0-0066 2-0049 4-000b 4-0040 i2c-0 i2c-2 i2c-4
i2c-2 是一個匯流排號為 2 的 I2C 匯流排,2-0049 是匯流排 2 地址 0x49 上綁定了核心驅動的 I2C 裝置。
術語¶
首先,讓我們定義一些術語,以避免在後續章節中造成混淆。
(物理)I2C 匯流排控制器¶
執行 Linux 核心的硬體系統可能包含多個物理 I2C 匯流排控制器。這些控制器是硬體和物理的,系統可以在記憶體空間中定義多個暫存器來操作這些控制器。Linux 核心在源目錄 drivers/i2c/busses 下有 I2C 匯流排驅動程式,用於將核心 I2C API 轉換為針對不同系統的暫存器操作。此術語不限於 Linux 核心。
I2C 匯流排物理號¶
對於每個物理 I2C 匯流排控制器,系統供應商可能會為每個控制器分配一個物理號。例如,第一個具有最低暫存器地址的 I2C 匯流排控制器可能被稱為 I2C-0。
邏輯 I2C 匯流排¶
您在 Linux I2C Sysfs 中看到的每個 I2C 匯流排號都是一個邏輯 I2C 匯流排,並分配了一個編號。這類似於軟體程式碼通常是基於虛擬記憶體空間而不是物理記憶體空間編寫的事實。
每個邏輯 I2C 匯流排可以是物理 I2C 匯流排控制器的抽象,或者是 I2C MUX 後面的一個通道的抽象。如果它是 MUX 通道的抽象,那麼每當我們透過這樣的邏輯匯流排訪問 I2C 裝置時,核心將為您將 I2C MUX 切換到正確的通道,作為抽象的一部分。
物理 I2C 匯流排¶
如果邏輯 I2C 匯流排是物理 I2C 匯流排控制器的直接抽象,我們稱之為物理 I2C 匯流排。
注意事項¶
對於只瞭解板卡物理 I2C 設計的人來說,這可能會讓人感到困惑。實際上,可以在裝置樹原始檔 (DTS) 的 aliases 部分中,將 I2C 匯流排物理號重新命名為邏輯 I2C 匯流排級別的不同號碼。有關 DTS 檔案示例,請參閱 arch/arm/boot/dts/nuvoton-npcm730-gsj.dts。
最佳實踐:(致核心軟體開發人員) 最好保持 I2C 匯流排物理號與其對應的邏輯 I2C 匯流排號相同,而不是重新命名或對映它們,這樣可以減少其他使用者的困惑。這些物理 I2C 匯流排可以作為 I2C MUX 扇出的良好起點。對於以下示例,我們將假定物理 I2C 匯流排的編號與其 I2C 匯流排物理號相同。
邏輯 I2C 匯流排漫遊¶
在接下來的內容中,我們將以一個更復雜的 I2C 拓撲為例。這是一個 I2C 拓撲的簡要圖。如果您初看此圖不理解,請不要害怕繼續閱讀本文件,並在閱讀完成後回顧它。
i2c-7 (physical I2C bus controller 7)
`-- 7-0071 (4-channel I2C MUX at 0x71)
|-- i2c-60 (channel-0)
|-- i2c-73 (channel-1)
| |-- 73-0040 (I2C sensor device with hwmon directory)
| |-- 73-0070 (I2C MUX at 0x70, exists in DTS, but failed to probe)
| `-- 73-0072 (8-channel I2C MUX at 0x72)
| |-- i2c-78 (channel-0)
| |-- ... (channel-1...6, i2c-79...i2c-84)
| `-- i2c-85 (channel-7)
|-- i2c-86 (channel-2)
`-- i2c-203 (channel-3)
區分物理和邏輯 I2C 匯流排¶
區分物理 I2C 匯流排和邏輯 I2C 匯流排的一種簡單方法是使用命令 ls -l 或 readlink 讀取 I2C 匯流排目錄下名為 device 的符號連結。
另一個可以檢查的符號連結是 mux_device。此連結僅存在於從另一個 I2C 匯流排扇出的邏輯 I2C 匯流排目錄中。讀取此連結還將告訴您是哪個 I2C MUX 裝置建立了此邏輯 I2C 匯流排。
如果符號連結指向以 .i2c 結尾的目錄,則它應該是物理 I2C 匯流排,直接抽象了一個物理 I2C 匯流排控制器。例如
$ readlink /sys/bus/i2c/devices/i2c-7/device
../../f0087000.i2c
$ ls /sys/bus/i2c/devices/i2c-7/mux_device
ls: /sys/bus/i2c/devices/i2c-7/mux_device: No such file or directory
在這種情況下,i2c-7 是一個物理 I2C 匯流排,因此它在其目錄下沒有符號連結 mux_device。如果核心軟體開發人員遵循不重新命名物理 I2C 匯流排的常見做法,這也意味著它是系統的物理 I2C 匯流排控制器 7。
另一方面,如果符號連結指向另一個 I2C 匯流排,則當前目錄表示的 I2C 匯流排必須是邏輯匯流排。連結指向的 I2C 匯流排是父匯流排,可以是物理 I2C 匯流排,也可以是邏輯匯流排。在這種情況下,當前目錄表示的 I2C 匯流排抽象了父匯流排下的一個 I2C MUX 通道。
例如
$ readlink /sys/bus/i2c/devices/i2c-73/device
../../i2c-7
$ readlink /sys/bus/i2c/devices/i2c-73/mux_device
../7-0071
i2c-73 是由 i2c-7 下的 I2C MUX(I2C 地址為 0x71)扇出的邏輯匯流排。每當我們透過匯流排 73 訪問 I2C 裝置時,核心都會作為抽象的一部分,為您將地址為 0x71 的 I2C MUX 切換到正確的通道。
找出邏輯 I2C 匯流排號¶
在本節中,我們將介紹如何根據物理硬體 I2C 拓撲知識,找出表示特定 I2C MUX 通道的邏輯 I2C 匯流排號。
在這個例子中,我們有一個系統,它有一個物理 I2C 匯流排 7,並且在 DTS 中沒有重新命名。該總線上地址 0x71 處有一個 4 通道 MUX。在 0x71 MUX 的通道 1 後面,還有另一個地址 0x72 的 8 通道 MUX。讓我們導航 Sysfs,找出 0x72 MUX 的通道 3 的邏輯 I2C 匯流排號。
首先,讓我們進入 i2c-7 目錄
~$ cd /sys/bus/i2c/devices/i2c-7
/sys/bus/i2c/devices/i2c-7$ ls
7-0071 i2c-60 name subsystem
delete_device i2c-73 new_device uevent
device i2c-86 of_node
i2c-203 i2c-dev power
在那裡,我們看到 0x71 MUX 為 7-0071。進入其內部
/sys/bus/i2c/devices/i2c-7$ cd 7-0071/
/sys/bus/i2c/devices/i2c-7/7-0071$ ls -l
channel-0 channel-3 modalias power
channel-1 driver name subsystem
channel-2 idle_state of_node uevent
使用 readlink 或 ls -l 讀取連結 channel-1
/sys/bus/i2c/devices/i2c-7/7-0071$ readlink channel-1
../i2c-73
我們發現 i2c-7 上 0x71 MUX 的通道 1 被分配的邏輯 I2C 匯流排號是 73。讓我們透過以下兩種方式之一繼續前往目錄 i2c-73
# cd to i2c-73 under I2C Sysfs root
/sys/bus/i2c/devices/i2c-7/7-0071$ cd /sys/bus/i2c/devices/i2c-73
/sys/bus/i2c/devices/i2c-73$
# cd the channel symbolic link
/sys/bus/i2c/devices/i2c-7/7-0071$ cd channel-1
/sys/bus/i2c/devices/i2c-7/7-0071/channel-1$
# cd the link content
/sys/bus/i2c/devices/i2c-7/7-0071$ cd ../i2c-73
/sys/bus/i2c/devices/i2c-7/i2c-73$
無論哪種方式,您都會進入 i2c-73 目錄。與上面類似,我們現在可以找到 0x72 MUX 以及其通道被分配了哪些邏輯 I2C 匯流排號
/sys/bus/i2c/devices/i2c-73$ ls
73-0040 device i2c-83 new_device
73-004e i2c-78 i2c-84 of_node
73-0050 i2c-79 i2c-85 power
73-0070 i2c-80 i2c-dev subsystem
73-0072 i2c-81 mux_device uevent
delete_device i2c-82 name
/sys/bus/i2c/devices/i2c-73$ cd 73-0072
/sys/bus/i2c/devices/i2c-73/73-0072$ ls
channel-0 channel-4 driver of_node
channel-1 channel-5 idle_state power
channel-2 channel-6 modalias subsystem
channel-3 channel-7 name uevent
/sys/bus/i2c/devices/i2c-73/73-0072$ readlink channel-3
../i2c-81
在那裡,我們發現 0x72 MUX 的通道 3 的邏輯 I2C 匯流排號是 81。我們稍後可以使用這個數字切換到它自己的 I2C Sysfs 目錄或發出 i2c-tools 命令。
提示:一旦您理解了帶 MUX 的 I2C 拓撲,如果您的系統上可用,I2C Tools 中的命令 i2cdetect -l 可以輕鬆地為您提供 I2C 拓撲的概覽。例如
$ i2cdetect -l | grep -e '\-73' -e _7 | sort -V
i2c-7 i2c npcm_i2c_7 I2C adapter
i2c-73 i2c i2c-7-mux (chan_id 1) I2C adapter
i2c-78 i2c i2c-73-mux (chan_id 0) I2C adapter
i2c-79 i2c i2c-73-mux (chan_id 1) I2C adapter
i2c-80 i2c i2c-73-mux (chan_id 2) I2C adapter
i2c-81 i2c i2c-73-mux (chan_id 3) I2C adapter
i2c-82 i2c i2c-73-mux (chan_id 4) I2C adapter
i2c-83 i2c i2c-73-mux (chan_id 5) I2C adapter
i2c-84 i2c i2c-73-mux (chan_id 6) I2C adapter
i2c-85 i2c i2c-73-mux (chan_id 7) I2C adapter
固定的邏輯 I2C 匯流排號¶
如果在 DTS 中未指定,當 I2C MUX 驅動程式被應用並且 MUX 裝置成功探測後,核心將根據當前最大的邏輯匯流排號遞增地為 MUX 通道分配邏輯匯流排號。例如,如果系統最高的邏輯匯流排號是 i2c-15,並且成功應用了一個 4 通道 MUX,那麼 MUX 通道 0 將是 i2c-16,一直到 MUX 通道 3 的 i2c-19。
核心軟體開發人員能夠在 DTS 中將扇出的 MUX 通道固定到一個靜態的邏輯 I2C 匯流排號。本文件將不詳細介紹如何在 DTS 中實現這一點,但我們可以在以下檔案中看到一個示例:arch/arm/boot/dts/aspeed-bmc-facebook-wedge400.dts
在上面的示例中,物理 I2C 匯流排 2 上有一個地址為 0x70 的 8 通道 I2C MUX。該 MUX 的通道 2 在 DTS 中定義為 imux18,並透過 aliases 部分中的 i2c18 = &imux18; 行固定到邏輯 I2C 匯流排號 18。
更進一步,可以設計一種邏輯 I2C 匯流排號方案,讓人類易於記憶或算術計算。例如,我們可以將匯流排 3 上 MUX 的扇出通道固定為從 30 開始。因此,30 將是匯流排 3 上 MUX 通道 0 的邏輯匯流排號,37 將是匯流排 3 上 MUX 通道 7 的邏輯匯流排號。
I2C 裝置¶
在之前的章節中,我們主要討論了 I2C 匯流排。本節中,讓我們看看我們可以從 I2C 裝置目錄中學到什麼,其連結名稱格式為 ${bus}-${addr}。名稱中的 ${bus} 部分是邏輯 I2C 匯流排的十進位制數字,而 ${addr} 部分是每個裝置的 I2C 地址的十六進位制數字。
I2C 裝置目錄內容¶
在每個 I2C 裝置目錄下,都有一個名為 name 的檔案。此檔案指示用於核心驅動程式探測此裝置的裝置名稱。使用 cat 命令讀取其內容。例如
/sys/bus/i2c/devices/i2c-73$ cat 73-0040/name
ina230
/sys/bus/i2c/devices/i2c-73$ cat 73-0070/name
pca9546
/sys/bus/i2c/devices/i2c-73$ cat 73-0072/name
pca9547
有一個名為 driver 的符號連結,用於說明是哪個 Linux 核心驅動程式用於探測此裝置
/sys/bus/i2c/devices/i2c-73$ readlink -f 73-0040/driver
/sys/bus/i2c/drivers/ina2xx
/sys/bus/i2c/devices/i2c-73$ readlink -f 73-0072/driver
/sys/bus/i2c/drivers/pca954x
但是,如果 driver 連結一開始就不存在,則可能意味著核心驅動程式由於某些錯誤未能探測到此裝置。錯誤可能在 dmesg 中找到
/sys/bus/i2c/devices/i2c-73$ ls 73-0070/driver
ls: 73-0070/driver: No such file or directory
/sys/bus/i2c/devices/i2c-73$ dmesg | grep 73-0070
pca954x 73-0070: probe failed
pca954x 73-0070: probe failed
根據 I2C 裝置的型別以及用於探測該裝置的核心驅動程式,裝置目錄中的內容可能會有所不同。
I2C MUX 裝置¶
雖然您可能在前面的章節中已經瞭解了這一點,但 I2C MUX 裝置在其裝置目錄內會有符號連結 channel-*。這些符號連結指向其邏輯 I2C 匯流排目錄
/sys/bus/i2c/devices/i2c-73$ ls -l 73-0072/channel-*
lrwxrwxrwx ... 73-0072/channel-0 -> ../i2c-78
lrwxrwxrwx ... 73-0072/channel-1 -> ../i2c-79
lrwxrwxrwx ... 73-0072/channel-2 -> ../i2c-80
lrwxrwxrwx ... 73-0072/channel-3 -> ../i2c-81
lrwxrwxrwx ... 73-0072/channel-4 -> ../i2c-82
lrwxrwxrwx ... 73-0072/channel-5 -> ../i2c-83
lrwxrwxrwx ... 73-0072/channel-6 -> ../i2c-84
lrwxrwxrwx ... 73-0072/channel-7 -> ../i2c-85
I2C 感測器裝置 / Hwmon¶
I2C 感測器裝置也很常見。如果它們成功地被核心 hwmon(硬體監控)驅動程式繫結,您將在 I2C 裝置目錄中看到一個 hwmon 目錄。繼續深入,您將找到 I2C 感測器裝置的 Hwmon Sysfs
/sys/bus/i2c/devices/i2c-73/73-0040/hwmon/hwmon17$ ls
curr1_input in0_lcrit_alarm name subsystem
device in1_crit power uevent
in0_crit in1_crit_alarm power1_crit update_interval
in0_crit_alarm in1_input power1_crit_alarm
in0_input in1_lcrit power1_input
in0_lcrit in1_lcrit_alarm shunt_resistor
有關 Hwmon Sysfs 的更多資訊,請參閱文件
在 I2C Sysfs 中例項化 I2C 裝置¶
請參閱 如何例項化 I2C 裝置 的“方法 4:從使用者空間例項化”部分