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:从用户空间实例化”部分