Skip to main content Why Device Tree and Board Description Affect Driver Probe | IoT Worker

Why Device Tree and Board Description Affect Driver Probe

A common Linux device-debugging problem looks like this: the driver code did not change, the kernel boots, but the device never probes. The log may only say probe failed, or the driver may never be entered at all.

The problem is not always in C code.

On many embedded Linux platforms, whether a driver can find a device and obtain register ranges, interrupts, clocks, power supplies, GPIOs, and DMA channels first depends on whether the board description is correct. On ARM, RISC-V, and many embedded platforms, that description is usually Device Tree.

A useful first model is: a driver describes how to operate a kind of hardware; Device Tree describes which hardware exists on this board, where it is connected, and which resources it needs. The kernel matches the two, and only then can probe run.

Device Tree node
-> compatible matches driver
-> kernel creates device
-> driver probe runs
-> driver reads reg / interrupts / clocks / regulators / gpios
-> hardware is initialized

Device Tree is not merely a driver parameter file. It is one of the ways the kernel learns what board it is running on.

Why Drivers Should Not Guess Board Wiring

The same chip can appear on many boards.

The peripheral IP may be the same, but board wiring can differ:

  • I2C address
  • GPIO wiring
  • interrupt line and controller
  • clock source
  • power regulator
  • reset polarity
  • pinmux configuration
  • DMA channel

If all of this is hardcoded in the driver, the same driver becomes hard to reuse. Every board would require driver changes.

Device Tree moves “how the hardware is wired” out of the driver. The driver knows which resources this device type needs; the board description supplies the concrete resources.

That is why the same driver can work on board A and fail on board B because of DTS alone.

compatible Decides Whether a Driver Matches

One of the most important Device Tree properties is compatible.

It tells the kernel what kind of device the node describes.

Simplified example:

sensor@48 {
    compatible = "vendor,temp-sensor-v2", "vendor,temp-sensor";
    reg = <0x48>;
};

The driver usually has a match table:

static const struct of_device_id sensor_of_match[] = {
    { .compatible = "vendor,temp-sensor" },
    { }
};

If the node’s compatible matches the driver’s table, the kernel can bind the device to the driver and call probe.

If compatible is wrong, the driver is not built in, the module is not loaded, or the bus node is disabled, probe may never happen.

So when “the driver does not enter probe,” the first question is usually not registers. Check whether the device exists, whether compatible matches, and whether the driver is present.

reg Means Different Things on Different Buses

The meaning of reg depends on the parent bus.

For an MMIO device, reg usually describes physical register address and size:

uart0: serial@10000000 {
    compatible = "vendor,uart";
    reg = <0x10000000 0x1000>;
};

The driver obtains that resource and maps registers.

For an I2C device, reg is usually the slave address:

eeprom@50 {
    compatible = "atmel,24c02";
    reg = <0x50>;
};

For an SPI device, reg often means chip select.

So reg does not always mean “register address.” It must be interpreted with the parent bus, #address-cells, and #size-cells.

Many DTS bugs come from writing a syntactically valid reg that has the wrong meaning for the bus.

interrupts Are Not Plain Numbers

When a device needs interrupts, Device Tree describes where the interrupt comes from and how it triggers.

Example:

touch@38 {
    compatible = "vendor,touch";
    reg = <0x38>;
    interrupt-parent = <&gpio1>;
    interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
};

The 12 is not a global Linux IRQ number. It is an interrupt specifier relative to interrupt-parent. The kernel translates it through the interrupt-controller hierarchy into an internal IRQ.

If the interrupt parent is wrong, the trigger type is wrong, the GPIO is not configured as input, or pinmux is wrong, probe may succeed but the driver never receives interrupts, or it may get an interrupt storm.

So “the driver gets no interrupt” is not always a request_irq() issue. It may be a board-level interrupt description issue.

clocks, resets, and regulators Are Hardware Preconditions

Many peripherals are not usable immediately after registers are mapped.

They may need:

  • clocks enabled
  • reset deasserted
  • power regulators enabled
  • voltage configured
  • pinctrl configured
  • power-stabilization delays

Device Tree commonly contains properties like:

clocks = <&clk 5>;
resets = <&reset 2>;
vdd-supply = <&vdd_3v3>;
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins>;

The driver obtains and enables these resources through kernel clock, reset, regulator, and pinctrl frameworks during probe.

If power is missing, registers may read invalid values.
If the clock is missing, register access may time out.
If reset is not released, the device never responds.
If pinctrl is wrong, signals never reach the pins.

These failures can look like driver bugs while the real problem is incomplete hardware-resource description.

status Decides Whether a Device Is Enabled

Device Tree nodes often include:

status = "okay";

or:

status = "disabled";

A disabled node usually does not create a device and will not probe.

SoC-level DTSI files often describe many controllers but leave them disabled. The board-level DTS enables only the peripherals that are actually wired on that board.

&i2c1 {
    status = "okay";
    clock-frequency = <400000>;
};

If the parent bus is not enabled, child devices may be correct but still not work. If an unwired peripheral is enabled, the kernel may try to initialize a device that does not exist.

When checking a device node, check both the target node and its parent bus.

Device Tree Describes Hardware, Not Policy

Device Tree is often abused as a private driver configuration table. That blurs boundaries.

A robust principle is: Device Tree should describe hardware facts, not runtime policy.

Good Device Tree content includes:

  • register addresses
  • interrupt wiring
  • GPIO wiring
  • clock sources
  • power connections
  • reset lines
  • pinmux
  • bus addresses
  • fixed board properties

Risky content includes:

  • current business mode
  • user configuration
  • runtime-adjustable thresholds
  • temporary debug flags
  • software policy unrelated to hardware

The boundary can be fuzzy for fixed calibration, board timings, and electrical constraints that cannot be probed automatically. But Device Tree should not become an application configuration center.

Bindings Are the Contract Between DTS and Driver

Device Tree property names should not be invented casually.

Linux usually has binding documents that define what properties a device node may have, which are required, which are optional, and what each one means.

Modern kernels use many YAML bindings, and tools can validate DTS against schemas.

Bindings define the contract between Device Tree and driver:

  • how compatible should be written
  • how many reg ranges exist
  • whether interrupts is required
  • clock names
  • supply property names
  • GPIO polarity
  • child-node structure

If the driver expects reset-gpios but DTS writes rst-gpio, the syntax may pass, but the driver will not find the resource.

So do not only copy another board’s DTS. Read the corresponding binding.

Overlays and Bootloaders Can Modify Device Tree

Device Tree is not always only the .dts source file.

The boot chain may modify it:

  • bootloader selects a different dtb
  • bootloader fills memory size, MAC address, or serial number
  • overlays enable expansion boards
  • firmware changes nodes based on hardware revision
  • kernel parameters affect some device behavior

When debugging, check the Device Tree the kernel actually sees, not only the DTS source.

On Linux, inspect:

/proc/device-tree
/sys/firmware/devicetree/base

If source DTS looks correct but the runtime node is missing, disabled, or overwritten, investigate bootloader, overlays, and hardware-revision selection.

ACPI Solves a Similar Problem

On many PCs and servers, hardware description is provided through ACPI. On embedded ARM/RISC-V platforms, Device Tree is more common.

The formats differ, but the engineering problem is similar: the operating system must know which devices exist, how resources are connected, and how interrupts and power management are described.

So Device Tree is not the only way this issue exists. Any driver model that avoids hardcoded board information needs some hardware-description mechanism.

ACPI is more common on standardized, firmware-driven platforms. Device Tree is more common where board differences are explicit and DTS files describe embedded hardware.

How to Debug Probe Problems

When a driver does not probe, probe fails, interrupts never arrive, or peripheral access times out, split the path.

First, check whether the runtime Device Tree node exists, whether status is enabled, and whether the parent bus is enabled.

Second, check whether compatible matches the driver and whether the driver is built in or loaded.

Third, check whether reg matches bus semantics: MMIO address, I2C address, or SPI chip select.

Fourth, check interrupt description: interrupt-parent, trigger type, GPIO input, and pinmux.

Fifth, check whether resources are complete: clocks, resets, regulators, pinctrl, DMA, and GPIOs.

Sixth, check binding compatibility: property names, cell counts, and child-node structure.

Seventh, check whether bootloader or overlays changed the final dtb. Source correctness does not guarantee runtime correctness.

These questions split “driver does not work” into device creation, resource acquisition, and hardware initialization.

What Matters in Practice

Device Tree is not a side configuration file next to driver code.

It describes board-level hardware facts: where the device is, which bus it is on, which interrupt it uses, which clocks and power supplies it needs, which GPIOs, pinmux, resets, and DMA resources are connected.

The driver owns “how this kind of hardware is operated.” Device Tree owns “how this hardware instance is wired on this board.” The kernel matches them, and then probe can run.

When debugging Linux device problems, do not only read the driver C code. Many root causes live in Device Tree, bindings, bootloader-selected dtb files, overlays, or the board wiring itself.