Device Tree of_device_id Data Matching – Free Linux Device Drivers Course

Device Tree of_device_id Data Matching
Free Linux Device Drivers Course — Lecture 6.10
Kernel 6.x Ready
Hands-On Driver Demo
100% Free

In this free Linux kernel development course lecture, we look at device tree of_device_id matching — the mechanism that lets one Linux driver support several different hardware variants through a single of_match_table. This is a core part of any free embedded Linux course covering platform and device tree drivers, and it directly answers a question every driver author eventually hits: how do I write one probe function that behaves correctly for three or four related chips?

free linux kernel development course
free linux device drivers course
free embedded linux course
device tree of_device_id
of_match_table

What You Will Learn

struct of_device_id layout
Matching multiple compatible strings
MODULE_DEVICE_TABLE registration
Reading of_node inside probe
of_match_device() and the data pointer

Prerequisites

You should already be comfortable with platform drivers (module_platform_driver, probe/remove) and the basic device tree ideas from earlier lectures in this free Linux device drivers course — node naming, reg property, and compatible property matching.

Inside struct of_device_id

Every entry in an of_match_table is a struct of_device_id, declared in include/linux/mod_devicetable.h. Two fields matter most for driver authors:

of_device_id Fields
Field Purpose
compatible[128] String compared against the device node’s compatible property. Must match exactly.
data Opaque pointer the driver author sets. Can point to a config struct, function table, or integer cast as a pointer.

The data field is what makes this pattern powerful: it lets one probe function retrieve variant-specific configuration without a chain of if (strcmp(...)) checks.

Matching More Than One Compatible String

A single driver can register interest in several device tree nodes by listing multiple entries in its of_match_table array. Here is an original example for a fictional sensor family:

#include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/platform_device.h>

static const struct of_device_id ep_sensor_dt_ids[] = {
    { .compatible = "ep,sensor-v1", },
    { .compatible = "ep,sensor-v2", },
    { .compatible = "ep,sensor-v3", },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ep_sensor_dt_ids);

The array must always end with an empty sentinel entry, or the kernel’s matching loop will walk past the end of your array. Once the array is filled, attach it to the driver’s of_match_table:

static struct platform_driver ep_sensor_driver = {
    .probe  = ep_sensor_probe,
    .remove = ep_sensor_remove,
    .driver = {
        .name           = "ep-sensor",
        .of_match_table = ep_sensor_dt_ids,
    },
};
module_platform_driver(ep_sensor_driver);

On kernel 6.x, .remove takes a single argument and returns void — the older int-returning form was fully retired, so make sure your driver skeleton reflects that.

Registering the Table With MODULE_DEVICE_TABLE

Filling the array only makes it visible to your own driver. To let the kernel’s device list and module auto-loading tools (like modprobe and depmod) see your supported compatible strings, register the table:

MODULE_DEVICE_TABLE(of, ep_sensor_dt_ids);

This macro embeds the compatible strings into the compiled module’s metadata, which you can inspect with:

$ modinfo ep_sensor.ko | grep alias
alias:          of:N*T*Cep,sensor-v3
alias:          of:N*T*Cep,sensor-v2
alias:          of:N*T*Cep,sensor-v1

Declaring the Node in Device Tree

A device tree node can list more than one compatible string, ordered from most specific to most generic. The kernel tries them left to right until one matches a registered driver:

ep_sensor0: sensor@40000000 {
    compatible = "ep,sensor-v3", "ep,sensor-v1";
    reg = <0x40000000 0x1000>;
    interrupts = <0 45 4>;
};

Reading of_node Inside probe()

Once matched, your probe function receives a struct platform_device *pdev. The associated device tree node is reachable through pdev->dev.of_node:

static int ep_sensor_probe(struct platform_device *pdev)
{
    struct device_node *np = pdev->dev.of_node;
    u32 gain;

    if (!np) {
        dev_err(&pdev->dev, "no device tree node found\n");
        return -ENODEV;
    }

    if (of_property_read_u32(np, "ep,gain", &gain))
        gain = 1;

    dev_info(&pdev->dev, "probing with gain=%u\n", gain);
    return 0;
}

Finding Which Entry Matched With of_match_device()

Knowing that a node matched is not the same as knowing which compatible string matched. When your driver supports multiple variants and you stored different data per entry, use of_match_device() to recover the exact entry that triggered the probe:

static const struct of_device_id ep_sensor_dt_ids[] = {
    { .compatible = "ep,sensor-v1", .data = (void *)1 },
    { .compatible = "ep,sensor-v2", .data = (void *)2 },
    { .compatible = "ep,sensor-v3", .data = (void *)3 },
    { }
};
MODULE_DEVICE_TABLE(of, ep_sensor_dt_ids);

static int ep_sensor_probe(struct platform_device *pdev)
{
    const struct of_device_id *match;
    unsigned long variant;

    match = of_match_device(ep_sensor_dt_ids, &pdev->dev);
    if (!match)
        return -ENODEV;

    variant = (unsigned long)match->data;
    dev_info(&pdev->dev, "matched sensor variant %lu\n", variant);
    return 0;
}
Match Flow
1 Kernel walks device tree, reads node’s compatible property
2 Platform core compares it against every registered of_match_table
3 On match, probe() is called with pdev->dev.of_node set
4 Driver calls of_match_device() to recover the matched entry and its data

Common Mistakes

Mistake Fix
Forgetting the sentinel entry in of_match_table Always end the array with an empty {}
Casting data to a pointer type larger than the stored integer Keep casts consistent (unsigned long round-trip is safest)
Assuming of_node is always non-NULL Check it, since ACPI or legacy board-file probing won’t set it
Skipping MODULE_DEVICE_TABLE Add it so modprobe/depmod can auto-load your module

Best Practices

  • List device tree compatible strings from most specific to most generic in the DT node itself.
  • Keep of_device_id.data pointing to read-only const data where possible.
  • Use dev_info()/dev_err() instead of plain printk so messages are tied to the correct device in logs.
  • Always pair a filled of_match_table with a MODULE_DEVICE_TABLE() call.

Real-World Use Case

UART controllers, I2C sensor families, and SPI flash drivers frequently ship several silicon revisions that share 90% of their register layout. Rather than maintaining separate kernel modules, vendors register one driver with several compatible strings and use of_device_id.data to carry the small set of differences — register offsets, quirks, or feature flags — between revisions.

Summary / Key Takeaways

  • struct of_device_id carries a 128-byte compatible string and an opaque data pointer.
  • of_match_table can list multiple compatible entries for one driver.
  • MODULE_DEVICE_TABLE(of, …) exposes your supported compatible strings for module auto-loading.
  • of_match_device() recovers the exact matched entry, including its data field, inside probe().

Frequently Asked Questions

What happens if two of_device_id entries in different drivers use the same compatible string?

The platform core matches the first driver it finds registered with that compatible string; having duplicate compatible strings across unrelated drivers is a misconfiguration and should be avoided.

Can of_device_id.data point to a full struct instead of a small integer?

Yes. It is common to point data at a const struct holding function pointers, register offsets, or capability flags for that specific hardware variant.

Is MODULE_DEVICE_TABLE mandatory for the driver to work?

The driver still matches and probes without it, but module auto-loading via modprobe based on the device tree compatible string will not work without this macro.

Does of_match_device() work for ACPI-based platform devices too?

No, of_match_device() only walks the of_match_table. ACPI matching uses acpi_match_device() with an acpi_device_id table instead.

What is the maximum length of a compatible string?

The compatible field in struct of_device_id is a fixed 128-byte char array, so the string plus its null terminator must fit within that limit.

Should I use of_match_device() or platform_get_device_id() to detect the variant?

Use of_match_device() for device tree platforms and platform_get_device_id() for the parallel id_table matching path used by non-DT and MFD-style platform devices; the two mechanisms are independent.

Continue the Free Linux Kernel Development Course

Next: of_match_ptr, CONFIG_OF, and driving multiple hardware variants from one probe function.

 

Leave a Reply

Your email address will not be published. Required fields are marked *