Note 6: Reasons for not executing i2c driver probe function after Linux 3.0

Keywords: Linux

No direct results, let me talk about it.

I. Review:

In Note 5: i2c subsystem learning under linux It is based on Linux 2.6. kernel. In Linux 3.0, the device representation of I2C is implemented by board-level program, and I2C device is represented by i2c_client, the device information is loaded by struct i2c_board_info, and the device is loaded into I2C bus by i2c_new_device function.

exp: device.c

static struct i2c_board_info xxx_info = {
    I2C_BOARD_INFO("xxx", 0x48),    //xxx is the matching name!!!
};

driver.c

const struct i2c_device_id xxx_id[] = {
    { "xxx", 0 },    //The xxx in the i2c_device_id structure is the matching name!!!
    { }
};

static struct i2c_driver it6801_drv = {
    .driver = {
        .name = "xxx",
        .owner = THIS_MODULE,
    },
    .probe = xxx_drv_probe,
    .remove = xxx_drv_remove,
    .id_table = xxx_id,
};

Secondly, the new kernel (after Linux 3.0) is introduced into DTS device tree. The description of equipment is all expressed by DTS device tree.

The reason why I implemented the i2c driver and the probe function did not execute - > Problem code:

exp: dts

&i2cN {    //N represents the first N-way i2c bus
   status = "okay";
   xxx@48 {
        status = "okay";
        compatible = "xxx";    //compatible variable is the matching name
        reg = <0x48>;
   };
}

driver:

static const struct of_device_id of_xxx_match[] = {
        { .compatible = "xxx" },    //As you can see, this matches the device in dts
        { /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_xxx_match);

static struct i2c_driver xxx_drv = {
    .driver = {
        .name = "xxx",
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(of_xxx_match),
    },
    .probe = xxx_drv_probe,
    .remove = xxx_drv_remove,
};

After writing the code quickly, I found that my xxx_drv_probe function was not executed. The other two I2C drivers I wrote were also mounted on the first bus, and the other two drivers were running well, emmm... Why not this one? Analysis of the reasons: First, it is suspected that dts is not written correctly, compatible variable name is inconsistent; second, look at / sys/bus/i2c/devices / device, device exists, look at / sys/bus/i2c/drivers / below, my xxx_i2c_driver also exists! That's strange; then I use the arm-linux-nm command to look at my driver and show that xxx_drv_probe is compiled... In the end, the driver is compared with the two drivers, and it is found that the id_table in struct i2c_driver is missing.

driver:

static const struct of_device_id of_xxx_match[] = {
        { .compatible = "xxx" },    //As you can see, this matches the device in dts
        { /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_xxx_match);

const struct i2c_device_id xxx_id[] = {    
    { "xxx", 0 },
    { }
};

static struct i2c_driver xxx_drv = {
    .driver = {
        .name = "xxx",
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(of_xxx_match),
    },
    .probe = xxx_drv_probe,
    .remove = xxx_drv_remove,
    .id_table = xxx_id,    //Although not used, but must be implemented, otherwise the probe function will not be called!!!
};

After adding id_table in struct i2c_driver, the probe function is successfully called, my God!!! Look at the source code with questions, as follows.

i2c bus matching process

Call process:
i2c_add_driver
    -->i2c_register_driver
        -->driver->driver.bus = &i2c_bus_type;
            -->driver_register
                -->bus_add_driver
                    -->driver_attach
                        -->bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);    // Polling for devices on i2c bus
                        -->__driver_attach
                            -->driver_match_device
                            -->driver_probe_device
                                -->really_probe
                                    -->dev->bus->probe(dev);
                                    -->i2c_device_probe<i2c_bus_type;Realization in Structures>
                                        -->if (!driver->probe || !driver->id_table)
                                            -->driver->probe(client, i2c_match_id(driver->id_table, client));
                                                -->xxx_drv_probe<i2c_driver Our driver implements in the architecture probe>

Finally in the true_probe function:

static int really_probe(struct device *dev, struct device_driver *drv)
{
    int ret = 0;

    ... ...//Eliminate irrelevant code

    if (dev->bus->probe) {
        ret = dev->bus->probe(dev);
        if (ret)
            goto probe_failed;
    } else if (drv->probe) {
        ret = drv->probe(dev);
        if (ret)
            goto probe_failed;
    }

    ... ...
}

When registering I2C bus, bus - > probe function has been implemented and i2c_device_probe function has been implemented.

In the i2c_device_probe function:

static int i2c_device_probe(struct device *dev)
{
    struct i2c_client    *client = i2c_verify_client(dev);
    struct i2c_driver    *driver;
    int status;
    
    if (!client)
        return 0;

    ... ...

    driver = to_i2c_driver(dev->driver);
    if (!driver->probe || !driver->id_table)//Judgment shows that if driver - > id_table is empty, direct return will not be executed further. So id_table must be implemented!!! Only then will the probe function be called
        return -ENODEV;

    ... ...

    status = driver->probe(client, i2c_match_id(driver->id_table, client));

    ... ...
}

4. Summarize the reasons why the i2c driver probe written by myself does not execute.

If the id_table of i2c_driver is not implemented in its own driver, it will eventually be in the i2c_device_probe function.

if (!driver->probe || !driver->id_table)     return -ENODEV;

The statement returns directly, so that the xxx_drv_probe function implemented by ourselves can not be invoked!

Therefore, when registering i2c_driver, the id_table in i2c_driver must be implemented!!!

 

Posted by chriscloyd on Tue, 23 Apr 2019 18:09:34 -0700