【问题标题】:adding i2c client devices on x86_64在 x86_64 上添加 i2c 客户端设备
【发布时间】:2018-02-16 03:53:12
【问题描述】:

在我的 x86_64 板上,有来自 MFD 设备的 i2c 总线。此 i2c 总线上有设备。我能够使用 i2cdetect 程序检测这些设备。

# i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- 4c -- -- -- 
50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         

我需要内核自动检测这些设备,所以,我尝试编写 i2c_board_info,如下面的代码所示,但内核仍然无法自动检测这些设备。

#include <linux/init.h>
#include <linux/i2c.h>

#define BUS_NUMBER      0

static struct __init i2c_board_info tst_i2c0_board_info[]  = {                   
    {
        I2C_BOARD_INFO("ltc2990", 0x4c),
    },
    {
        I2C_BOARD_INFO("24c128", 0x57),
    },
};

static int tst_i2c_board_setup(void)
{
    int ret=-1;
    ret = i2c_register_board_info(BUS_NUMBER, tst_i2c0_board_info, ARRAY_SIZE(tst_i2c0_board_info));
    return ret;
}
device_initcall(tst_i2c_board_setup);

关于如何解决这个问题的任何建议?

【问题讨论】:

  • 在 I2C 总线 0 注册后是否调用 tst_i2c_board_setup()
  • @Ash 我对这两种情况都进行了测试,即在总线 0 注册之前和之后调用;通过将 device_initcall 更改为 arch_initcall。它没有帮助
  • 您需要为此使用 ACPI。我会在假期后用例子来回答这个问题,现在只需在 Github 上搜索 meta-acpi 项目以获得最初的想法。

标签: linux-kernel x86 linux-device-driver embedded-linux acpi


【解决方案1】:

通过Documentation/i2c/instantiating-devices 之后,我了解到有几种方法可以做到这一点(例如,0andriy 建议使用 acpi 表等),我使用了“i2c_new_probed_device”方法。以下是使用的代码:

#include <linux/init.h>
#include <linux/i2c.h>

#define BUS_NUMBER      0
#define NUM_DEVICE      2

static const unsigned short normal_i2c[][2] = {
    {0x4c, I2C_CLIENT_END},
    {0x57, I2C_CLIENT_END},
};

static struct i2c_board_info tst_i2c0_board_info[2] = {
        {I2C_BOARD_INFO("ltc2990", 0x4c), },
        {I2C_BOARD_INFO("24c128", 0x57), },
};

static int tst_i2c_board_setup(void)
{
    int i = 0;
    struct i2c_adapter *i2c_adap;

    i2c_adap = i2c_get_adapter(BUS_NUMBER);
    for(i = 0; i < NUM_DEVICE; i++)
        i2c_new_probed_device(i2c_adap, &tst_i2c0_board_info[i],
                           normal_i2c[i], NULL);
    i2c_put_adapter(i2c_adap);

    return 0;
}
late_initcall(tst_i2c_board_setup);

【讨论】:

  • 在工作时,这是对启用 ACPI 的平台的滥用。
  • 我同意,这是匆忙解决的。我将使用基于 ACPI 的方法。
【解决方案2】:

由于您拥有支持 ACPI 的平台,因此最好的方法是为给定设备提供 ASL 摘录。

由于适用于 IoT 的 Intel Galileo 平台,Atmel 24 系列 EEPROM 有自己的 ACPI ID,摘录很简单:

DefinitionBlock ("at24.aml", "SSDT", 5, "", "AT24", 1)
{
    External (_SB_.PCI0.I2C2, DeviceObj)

    Scope (\_SB.PCI0.I2C2)
    {
        Device (EEP0) {
            Name (_HID, "INT3499")
            Name (_DDN, "Atmel AT24 compatible EEPROM")
            Name (_CRS, ResourceTemplate () {
                I2cSerialBusV2 (
                    0x0057,              // I2C Slave Address
                    ControllerInitiated,
                    400000,              // Bus speed
                    AddressingMode7Bit,
                    "\\_SB.PCI0.I2C2",   // Link to ACPI I2C host controller
                    0
                )
            })

            Name (_DSD, Package () {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package () {
                    Package () {"size", 1024},
                    Package () {"pagesize", 32},
                }
            })
        }
    }
}

注意,size 属性被添加到 pending patch 系列中(补丁 add eeprom "size" propertyadd support to fetch eeprom device property "size")。

注意,地址宽度目前是硬编码的 8 位。如果您需要 16 位,则需要创建与上述类似的补丁。

对于 LTC2990 电源监视器,您需要以下摘录:

DefinitionBlock ("ltc2990.aml", "SSDT", 5, "", "PMON", 1)
{
    External (\_SB_.PCI0.I2C2, DeviceObj)

    Scope (\_SB.PCI0.I2C2)
    {
        Device (PMON)
        {
            Name (_HID, "PRP0001")
            Name (_DDN, "Linear Technology LTC2990 power monitor")
            Name (_CRS, ResourceTemplate () {
                I2cSerialBus (
                    0x4c,                   // Bus address
                    ControllerInitiated,    // Don't care
                    400000,                 // Fast mode (400 kHz)
                    AddressingMode7Bit,     // 7-bit addressing
                    "\\_SB.PCI0.I2C2",      // I2C host controller
                    0                       // Must be 0
                )
            })

            Name (_DSD, Package () {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package () {
                    Package () {"compatible", "lltc,ltc2990"},
                }
            })
        }
    }
}

注意,不幸的是,驱动程序中没有兼容的字符串,所以需要像it's done here一样添加它。

在上面的示例中,\\_SB.PCI0.I2C2 是 I2C 主机控制器的绝对路径。

如何应用这些文件:

  • 首先,创建一个文件夹
mkdir -p kernel/firmware/acpi
  • 在该文件夹中以DefinitionBlock() 宏中提到的名称保存文件
  • 创建未压缩的 cpio 存档并将原始 initrd 连接到顶部:
find kernel | cpio -H newc --create > /boot/instrumented_initrd
cat /boot/initrd >> /boot/instrumented_initrd

更多详情请访问SSDT Overlays

其他例子和背后想法的描述可以在meta-acpi GitHub page找到,这里复制了一些材料。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 2013-06-30
  • 2014-02-12
  • 1970-01-01
  • 2020-12-05
  • 2020-08-19
相关资源
最近更新 更多