zoukankan      html  css  js  c++  java
  • Linux I2C Sysfs

    概述

    由于I2C MUX (I2C多路复用器)的存在,I2C拓扑会变得很复杂。Linux内核将MUX通道抽象为逻辑I2C总线号。然而,从I2C总线物理编号和MUX拓扑 到 逻辑I2C总线编号的映射还存在认知差距。本文档旨在填补这一空白,以便读者(例如硬件工程师和新软件开发人员)通过了解物理I2C拓扑并浏览Linux shell中的I2C sysfs,了解内核中逻辑I2C总线的概念。这些知识对于使用i2c工具进行开发和调试是非常有用和必要的。

    目标受众

    需要使用Linux shell与运行Linux的系统上的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地址。

    例如:

    $ ls /sys/bus/i2c/devices
    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)部分别名下,可以将I2C总线物理号重命名为逻辑I2C总线级别中的不同数字。以arch/arm/boot/dts/nuvoton-npcm730-gsj.dts 查看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总线抽象了父总线下的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,那么我们将有i2c-16作为MUX通道0,一直到i2c-19作为MUX通道3。内核软件开发人员能够将展开的MUX通道固定到DTS中的静态逻辑I2C总线编号。本文档不会详细介绍如何在DTS中实现此功能,但我们可以在下面看到一个示例:arch/arm/boot/dts/aspeed-bmc-facebook-wedge400.dts

    在上面的示例中,在物理I2C总线2的地址0x70上有一个8通道I2C MUX。MUX的通道2在DTS中定义为imux18,并用i2c18 = &imux18行固定到逻辑I2C总线18; 在aliases节点里。

    进一步说,可以设计一个易于被人类记住或通过算术计算的逻辑I2C总线编号模式。例如,我们可以将MUX在总线3上的展开通道固定在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 (Hardware Monitoring)驱动程序成功绑定,您将在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

    实例化I2C Sysfs中的I2C设备

    参考: 

      如何实例化I2C设备,方法4:从用户空间实例化

    本文来自博客园,作者:王楼小子,转载请注明原文链接:https://www.cnblogs.com/wanglouxiaozi/p/15151710.html

  • 相关阅读:
    彻底理解ThreadLocal(转)
    javascript中神奇的(+)加操作符
    quartz集群调度机制调研及源码分析---转载
    quartz源码解析--转
    通过Spring @PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作
    LeetCode 917. Reverse Only Letters (仅仅反转字母)
    LeetCode 893. Groups of Special-Equivalent Strings (特殊等价字符串组)
    LeetCode 824. Goat Latin (山羊拉丁文)
    LeetCode 443. String Compression (压缩字符串)
    LeetCode 387. First Unique Character in a String (字符串中的第一个唯一字符)
  • 原文地址:https://www.cnblogs.com/wanglouxiaozi/p/15151710.html
Copyright © 2011-2022 走看看