linux-kernelx86linux-device-driverembedded-linuxacpi

adding i2c client devices on x86_64


On my x86_64 board, there is i2c-bus coming out of a MFD device. There are devices on to this i2c-bus. I am able to detect these devices using i2cdetect program.

# 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: -- -- -- -- -- -- -- --                         

I need the kernel to detect these devices automatically, So, I tried writing i2c_board_info as in given below code, But still, the kernel is not able to detect these devices automatically.

#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);

Any suggestions on how can I solve this ?


Solution

  • Since you have an ACPI-enabled platform the best approach is to provide the ASL excerpts for given devices.

    Because of Intel Galileo platform for IoT the Atmel 24 series EEPROM has got its own ACPI ID and an excerpt will be simple:

    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},
                    }
                })
            }
        }
    }
    

    Note, the size property is being added in a pending patch series (patches add eeprom "size" property and add support to fetch eeprom device property "size").

    Note, the address width is 8-bit as hard coded for now. In case you need to have 16-bit you need to create a similar patches as mentioned above.

    For LTC2990 power monitor you need the following excerpt:

    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"},
                    }
                })
            }
        }
    }
    

    Note, unfortunately there is no compatible string in the driver, so, one needs to add it like it's done here.

    In the examples above \\_SB.PCI0.I2C2 is an absolute path to the I2C host controller.

    How to get those files applied:

    mkdir -p kernel/firmware/acpi
    
    find kernel | cpio -H newc --create > /boot/instrumented_initrd
    cat /boot/initrd >> /boot/instrumented_initrd
    

    More details are available in SSDT Overlays.

    The other examples and description of the idea behind can be found on meta-acpi GitHub page, some materials from which are copied here.