Difference between spi_driver.id_table and spi_driver.driver.of_match_table
Asked Answered
R

2

6

I'm currently trying to understand how Linux drivers work. As far as I know, A driver's probe/init function is called when the kernel parses the corresponding .compatible string in the device tree. However, in the arizona-spi driver it looks like there are multiple compatible strings referenced in different members:

static const struct spi_device_id arizona_spi_ids[] = {
  { "wm5102", WM5102 },
  { "wm5110", WM5110 },
  { },
};
MODULE_DEVICE_TABLE(spi, arizona_spi_ids);

static struct spi_driver arizona_spi_driver = {
  .driver = {
    .name   = "arizona",
    .owner  = THIS_MODULE,
    .pm = &arizona_pm_ops,

    // Contains e.g. "wlf,wm5102"
    .of_match_table = of_match_ptr(arizona_of_match),

  },
  .probe    = arizona_spi_probe,
  .remove   = arizona_spi_remove,
  .id_table = arizona_spi_ids,      // Contains "wm5102" and "wm5110"
};

This is an excerpt from here.

So what is the difference between arizona_spi_driver.id_table and arizona_spi_driver.driver.of_match_table?

Representational answered 27/10, 2014 at 8:54 Comment(0)
S
6

There are several mechanism for driver matching. The id_table is intended to be used for finding a match from stripped device-tree entries (without vendor part), while of_match_table is used to find a match from full device-tree entries (the ones with vendor part).

If you check, arizona_of_match is defined as this:

const struct of_device_id arizona_of_match[] = {
    { .compatible = "wlf,wm5102", .data = (void *)WM5102 },
    { .compatible = "wlf,wm5110", .data = (void *)WM5110 },
    { .compatible = "wlf,wm8280", .data = (void *)WM8280 },
    { .compatible = "wlf,wm8997", .data = (void *)WM8997 },
    {},
};

wlf is the vendor part for this case, while arizona_spi_ids doesn't contain the vendor part.

Hence, if you have something like this in your device tree:

compatible = "myvendor,wm5102"

Your device will match against id_table but not against of_match_table since the vendor is different.

The kernel will do matching against of_match_table first before check id_table (see spi_get_device_id in here). The device matching priority is: of_match_table > acpi_driver > id_table.

Sciamachy answered 3/10, 2015 at 15:19 Comment(0)
P
0

I can elaborate on samsi's answer with a bit more detail:

Near the bottom of your arizona-spi.c driver (just above the module license, description, etc.), you'll see a helper macro call:

module_spi_driver(arizona_spi_driver);

For modules that don't do anything special during module_init/module_exit(), this helper macro helps to reduce a bit of boilerplate, but essentially this is a call to:

spi_driver_register(&arizona_spi_driver);

If you are to follow all the function calls through to where the matching takes place, you'll see something like this:

spi_driver_register();
    --> driver_register();
       --> bus_add_driver(drv);
          --> driver_attach(drv);

The code will look at the bus (spi) and iterate over each device on the bus, calling __driver_attach on each one:

int driver_attach(struct device_driver *drv)
{
    return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}

__driver_attach will look for the existence of a drv->bus->match function pointer, which in this case exists, and you will find it in drivers/spi/spi.c:

struct bus_type spi_bus_type = {
    .name       = "spi",
    .dev_attrs  = spi_dev_attrs,
    .match      = spi_match_device, <--- here
    .uevent     = spi_uevent,
    .suspend    = spi_suspend,
    .resume     = spi_resume,
};

spi_match_device() will first check for a driver override, then check for a Device Tree / OF-style match, then an ACPI match, then the ID table from your driver, (arizona_spi_ids), then lastly attempt a modalias match with the driver name.

static int spi_match_device(struct device *dev, struct device_driver *drv)
{
    const struct spi_device *spi = to_spi_device(dev);
    const struct spi_driver *sdrv = to_spi_driver(drv);

    /* Check override first, and if set, only use the named driver */
    if (spi->driver_override)
        return strcmp(spi->driver_override, drv->name) == 0;

    /* Attempt an OF style match */
    if (of_driver_match_device(dev, drv))
        return 1;

    /* Then try ACPI */
    if (acpi_driver_match_device(dev, drv))
        return 1;

    if (sdrv->id_table)
        return !!spi_match_id(sdrv->id_table, spi);

    return strcmp(spi->modalias, drv->name) == 0;
}

In order for a Device Tree / OF match to occur, you need an exact match with a node in your device tree, for example:

Device Tree Node:

my_device@1 {
    compatible = "wlf,model", "wlf,model-rev2";
    ...
}

OF match table in your driver:

static const struct of_device_id my_driver_of_match[] = {
    { .compatible = "wlf,model" },
    { .compatible = "wlf,model-rev1" },
    { .compatible = NULL }
};

In this case "wlf,model" in your DT matches with "wlf,model" in your OF match table. If an exact match doesn't occur, it will fall through to an ID table match, then to an ACPI match, and so on.

In your case, it looks like it failed a DT match, but succeeded on an ID table match in your driver.

Peebles answered 1/5, 2024 at 1:58 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.