Linux I2C Sysfs

概述

由于 I2C MUX (I2C 多路复用器) 的存在,I2C 拓扑可能很复杂。 Linux 内核将 MUX 通道抽象为逻辑 I2C 总线号。 然而,在将 I2C 总线物理编号和 MUX 拓扑映射到逻辑 I2C 总线号时,存在知识上的差距。 本文档旨在填补这一空白,以便受众(例如硬件工程师和新软件开发人员)可以通过了解物理 I2C 拓扑并在 Linux shell 中浏览 I2C sysfs 来了解内核中逻辑 I2C 总线的概念。 此知识对于使用 i2c-tools 进行开发和调试非常有用且至关重要。

目标受众

需要在 Linux 系统上使用 Linux shell 与 I2C 子系统进行交互的人员。

先决条件

  1. 了解一般的 Linux shell 文件系统命令和操作。

  2. 了解 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 -lreadlink 读取 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 总线抽象了父总线下方的 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

使用 readlinkls -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 拓扑,如果您的系统上可用,则 i2cdetect -l 命令在I2C 工具中可以轻松地为您提供 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 开始。因此,总线 3 上 MUX 的通道 0 的逻辑总线号将为 30,总线 3 上 MUX 的通道 7 的逻辑总线号将为 37。

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 的更多信息,请参阅文档

sysfs 文件的命名和数据格式标准

在 I2C Sysfs 中实例化 I2C 设备

请参阅 如何实例化 I2C 设备 的“方法 4:从用户空间实例化”部分