Introduction to Devicetree Bindings

Note

For a detailed syntax reference, see Devicetree bindings syntax.

Devicetree nodes are matched to bindings using their compatible properties.

During the Configuration Phase, the build system tries to match each node in the devicetree to a binding file. When this succeeds, the build system uses the information in the binding file both when validating the node’s contents and when generating macros for the node.

A simple example

Here is an example devicetree node:

/* Node in a DTS file */
bar-device {
     compatible = "foo-company,bar-device";
     num-foos = <3>;
};

Here is a minimal binding file which matches the node:

# A YAML binding matching the node

compatible: "foo-company,bar-device"

properties:
  num-foos:
    type: int
    required: true

The build system matches the bar-device node to its YAML binding because the node’s compatible property matches the binding’s compatible: line.

What the build system does with bindings

The build system uses bindings both to validate devicetree nodes and to convert the devicetree’s contents into the generated devicetree_generated.h header file.

For example, the build system would use the above binding to check that the required num-foos property is present in the bar-device node, and that its value, <3>, has the correct type.

The build system will then generate a macro for the bar-device node’s num-foos property, which will expand to the integer literal 3. This macro lets you get the value of the property in C code using the API which is discussed later in this guide in Devicetree access from C/C++.

For another example, the following node would cause a build error, because it has no num-foos property, and this property is marked required in the binding:

bad-node {
     compatible = "foo-company,bar-device";
};

Other ways nodes are matched to bindings

If a node has more than one string in its compatible property, the build system looks for compatible bindings in the listed order and uses the first match.

Take this node as an example:

baz-device {
     compatible = "foo-company,baz-device", "generic-baz-device";
};

The baz-device node would get matched to a binding with a compatible: "generic-baz-device" line if the build system can’t find a binding with a compatible: "foo-company,baz-device" line.

Nodes without compatible properties can be matched to bindings associated with their parent nodes. These are called “child bindings”. If a node describes hardware on a bus, like I2C or SPI, then the bus type is also taken into account when matching nodes to bindings. (See On-bus for details).

See The /zephyr,user node for information about a special node that doesn’t require any binding.

Where bindings are located

Binding file names usually match their compatible: lines. For example, the above example binding would be named foo-company,bar-device.yaml by convention.

The build system looks for bindings in dts/bindings subdirectories of the following places:

The build system will consider any YAML file in any of these, including in any subdirectories, when matching nodes to bindings. A file is considered YAML if its name ends with .yaml or .yml.

Warning

The binding files must be located somewhere inside the dts/bindings subdirectory of the above places.

For example, if my-app is your application directory, then you must place application-specific bindings inside my-app/dts/bindings. So my-app/dts/bindings/serial/my-company,my-serial-port.yaml would be found, but my-app/my-company,my-serial-port.yaml would be ignored.