.. _dt-bindings-file-syntax: Devicetree bindings syntax ########################## This page documents the syntax of Zephyr's bindings format. Zephyr bindings files are YAML files. A :ref:`simple example ` was given in the introduction page. .. contents:: Contents :local: :depth: 3 Top level keys ************** The top level of a bindings file maps keys to values. The top-level keys look like this: .. code-block:: yaml # A high level description of the device the binding applies to: description: | This is the Vendomatic company's foo-device. Descriptions which span multiple lines (like this) are OK, and are encouraged for complex bindings. See https://yaml-multiline.info/ for formatting help. # You can include definitions from other bindings using this syntax: include: other.yaml # Used to match nodes to this binding: compatible: "manufacturer,foo-device" properties: # Requirements for and descriptions of the properties that this # binding's nodes need to satisfy go here. child-binding: # You can constrain the children of the nodes matching this binding # using this key. # If the node describes bus hardware, like an SPI bus controller # on an SoC, use 'bus:' to say which one, like this: bus: spi # If the node instead appears as a device on a bus, like an external # SPI memory chip, use 'on-bus:' to say what type of bus, like this. # Like 'compatible', this key also influences the way nodes match # bindings. on-bus: spi foo-cells: # "Specifier" cell names for the 'foo' domain go here; example 'foo' # values are 'gpio', 'pwm', and 'dma'. See below for more information. These keys are explained in the following sections. .. _dt-bindings-description: Description *********** A free-form description of node hardware goes here. You can put links to datasheets or example nodes or properties as well. .. _dt-bindings-compatible: Compatible ********** This key is used to match nodes to this binding as described in :ref:`dt-binding-compat`. It should look like this in a binding file: .. code-block:: YAML # Note the comma-separated vendor prefix and device name compatible: "manufacturer,device" This devicetree node would match the above binding: .. code-block:: devicetree device { compatible = "manufacturer,device"; }; Assuming no binding has ``compatible: "manufacturer,device-v2"``, it would also match this node: .. code-block:: devicetree device-2 { compatible = "manufacturer,device-v2", "manufacturer,device"; }; Each node's ``compatible`` property is tried in order. The first matching binding is used. The :ref:`on-bus: ` key can be used to refine the search. If more than one binding for a compatible is found, an error is raised. The ``manufacturer`` prefix identifies the device vendor. See :zephyr_file:`dts/bindings/vendor-prefixes.txt` for a list of accepted vendor prefixes. The ``device`` part is usually from the datasheet. Some bindings apply to a generic class of devices which do not have a specific vendor. In these cases, there is no vendor prefix. One example is the :dtcompatible:`gpio-leds` compatible which is commonly used to describe board LEDs connected to GPIOs. .. _dt-bindings-properties: Properties ********** The ``properties:`` key describes properties that nodes which match the binding contain. For example, a binding for a UART peripheral might look something like this: .. code-block:: YAML compatible: "manufacturer,serial" properties: reg: type: array description: UART peripheral MMIO register space required: true current-speed: type: int description: current baud rate required: true In this example, a node with compatible ``"manufacturer,serial"`` must contain a node named ``current-speed``. The property's value must be a single integer. Similarly, the node must contain a ``reg`` property. The build system uses bindings to generate C macros for devicetree properties that appear in DTS files. You can read more about how to get property values in source code from these macros in :ref:`dt-from-c`. Generally speaking, the build system only generates macros for properties listed in the ``properties:`` key for the matching binding. Properties not mentioned in the binding are generally ignored by the build system. The one exception is that the build system will always generate macros for standard properties, like :ref:`reg `, whose meaning is defined by the devicetree specification. This happens regardless of whether the node has a matching binding or not. Property entry syntax ===================== Property entries in ``properties:`` are written in this syntax: .. code-block:: none : required: type: deprecated: default: description: enum: - - ... - const: specifier-space: .. _dt-bindings-example-properties: Example property definitions ============================ Here are some more examples. .. code-block:: YAML properties: # Describes a property like 'current-speed = <115200>;'. We pretend that # it's obligatory for the example node and set 'required: true'. current-speed: type: int required: true description: Initial baud rate for bar-device # Describes an optional property like 'keys = "foo", "bar";' keys: type: string-array description: Keys for bar-device # Describes an optional property like 'maximum-speed = "full-speed";' # the enum specifies known values that the string property may take maximum-speed: type: string description: Configures USB controllers to work up to a specific speed. enum: - "low-speed" - "full-speed" - "high-speed" - "super-speed" # Describes an optional property like 'resolution = <16>;' # the enum specifies known values that the int property may take resolution: type: int enum: - 8 - 16 - 24 - 32 # Describes a required property '#address-cells = <1>'; the const # specifies that the value for the property is expected to be the value 1 "#address-cells": type: int required: true const: 1 int-with-default: type: int default: 123 description: Value for int register, default is power-up configuration. array-with-default: type: array default: [1, 2, 3] # Same as 'array-with-default = <1 2 3>' string-with-default: type: string default: "foo" string-array-with-default: type: string-array default: ["foo", "bar"] # Same as 'string-array-with-default = "foo", "bar"' uint8-array-with-default: type: uint8-array default: [0x12, 0x34] # Same as 'uint8-array-with-default = [12 34]' required ======== Adding ``required: true`` to a property definition will fail the build if a node matches the binding, but does not contain the property. The default setting is ``required: false``; that is, properties are optional by default. Using ``required: false`` is therefore redundant and strongly discouraged. type ==== The type of a property constrains its values. The following types are available. See :ref:`dt-writing-property-values` for more details about writing values of each type in a DTS file. See :ref:`dt-phandles` for more information about the ``phandle*`` type properties. .. list-table:: :header-rows: 1 :widths: 1 3 2 * - Type - Description - Example in DTS * - ``string`` - exactly one string - ``status = "disabled";`` * - ``int`` - exactly one 32-bit value (cell) - ``current-speed = <115200>;`` * - ``boolean`` - flags that don't take a value when true, and are absent if false - ``hw-flow-control;`` * - ``array`` - zero or more 32-bit values (cells) - ``offsets = <0x100 0x200 0x300>;`` * - ``uint8-array`` - zero or more bytes, in hex ('bytestring' in the Devicetree specification) - ``local-mac-address = [de ad be ef 12 34];`` * - ``string-array`` - zero or more strings - ``dma-names = "tx", "rx";`` * - ``phandle`` - exactly one phandle - ``interrupt-parent = <&gic>;`` * - ``phandles`` - zero or more phandles - ``pinctrl-0 = <&usart2_tx_pd5 &usart2_rx_pd6>;`` * - ``phandle-array`` - a list of phandles and 32-bit cells (usually specifiers) - ``dmas = <&dma0 2>, <&dma0 3>;`` * - ``path`` - a path to a node as a phandle path reference or path string - ``zephyr,bt-c2h-uart = &uart0;`` or ``foo = "/path/to/some/node";`` * - ``compound`` - a catch-all for more complex types (no macros will be generated) - ``foo = <&label>, [01 02];`` deprecated ========== A property with ``deprecated: true`` indicates to both the user and the tooling that the property is meant to be phased out. The tooling will report a warning if the devicetree includes the property that is flagged as deprecated. (This warning is upgraded to an error in the :ref:`twister_script` for upstream pull requests.) The default setting is ``deprecated: false``. Using ``deprecated: false`` is therefore redundant and strongly discouraged. .. _dt-bindings-default: default ======= The optional ``default:`` setting gives a value that will be used if the property is missing from the devicetree node. For example, with this binding fragment: .. code-block:: YAML properties: foo: type: int default: 3 If property ``foo`` is missing in a matching node, then the output will be as if ``foo = <3>;`` had appeared in the DTS (except YAML data types are used for the default value). Note that combining ``default:`` with ``required: true`` will raise an error. For rules related to ``default`` in upstream Zephyr bindings, see :ref:`dt-bindings-default-rules`. See :ref:`dt-bindings-example-properties` for examples. Putting ``default:`` on any property type besides those used in :ref:`dt-bindings-example-properties` will raise an error. enum ==== The ``enum:`` line is followed by a list of values the property may contain. If a property value in DTS is not in the ``enum:`` list in the binding, an error is raised. See :ref:`dt-bindings-example-properties` for examples. const ===== This specifies a constant value the property must take. It is mainly useful for constraining the values of common properties for a particular piece of hardware. .. _dt-bindings-specifier-space: specifier-space =============== .. warning:: It is an abuse of this feature to use it to name properties in unconventional ways. For example, this feature is not meant for cases like naming a property ``my-pin``, then assigning it to the "gpio" specifier space using this feature. Properties which refer to GPIOs should use conventional names, i.e. end in ``-gpios`` or ``-gpio``. This property, if present, manually sets the specifier space associated with a property with type ``phandle-array``. Normally, the specifier space is encoded implicitly in the property name. A property named ``foos`` with type ``phandle-array`` implicitly has specifier space ``foo``. As a special case, ``*-gpios`` properties have specifier space "gpio", so that ``foo-gpios`` will have specifier space "gpio" rather than "foo-gpio". You can use ``specifier-space`` to manually provide a space if using this convention would result in an awkward or unconventional name. For example: .. code-block:: YAML compatible: ... properties: bar: type: phandle-array specifier-space: my-custom-space Above, the ``bar`` property's specifier space is set to "my-custom-space". You could then use the property in a devicetree like this: .. code-block:: DTS controller1: custom-controller@1000 { #my-custom-space-cells = <2>; }; controller2: custom-controller@2000 { #my-custom-space-cells = <1>; }; my-node { bar = <&controller1 10 20>, <&controller2 30>; }; Generally speaking, you should reserve this feature for cases where the implicit specifier space naming convention doesn't work. One appropriate example is an ``mboxes`` property with specifier space "mbox", not "mboxe". You can write this property as follows: .. code-block:: YAML properties: mboxes: type: phandle-array specifier-space: mbox .. _dt-bindings-child: Child-binding ************* ``child-binding`` can be used when a node has children that all share the same properties. Each child gets the contents of ``child-binding`` as its binding, though an explicit ``compatible = ...`` on the child node takes precedence, if a binding is found for it. Consider a binding for a PWM LED node like this one, where the child nodes are required to have a ``pwms`` property: .. code-block:: devicetree pwmleds { compatible = "pwm-leds"; red_pwm_led { pwms = <&pwm3 4 15625000>; }; green_pwm_led { pwms = <&pwm3 0 15625000>; }; /* ... */ }; The binding would look like this: .. code-block:: YAML compatible: "pwm-leds" child-binding: description: LED that uses PWM properties: pwms: type: phandle-array required: true ``child-binding`` also works recursively. For example, this binding: .. code-block:: YAML compatible: foo child-binding: child-binding: properties: my-property: type: int required: true will apply to the ``grandchild`` node in this DTS: .. code-block:: devicetree parent { compatible = "foo"; child { grandchild { my-property = <123>; }; }; }; .. _dt-bindings-bus: Bus *** If the node is a bus controller, use ``bus:`` in the binding to say what type of bus. For example, a binding for a SPI peripheral on an SoC would look like this: .. code-block:: YAML compatible: "manufacturer,spi-peripheral" bus: spi # ... The presence of this key in the binding informs the build system that the children of any node matching this binding appear on this type of bus. This in turn influences the way ``on-bus:`` is used to match bindings for the child nodes. For a single bus supporting multiple protocols, e.g. I3C and I2C, the ``bus:`` in the binding can have a list as value: .. code-block:: YAML compatible: "manufacturer,i3c-controller" bus: [i3c, i2c] # ... .. _dt-bindings-on-bus: On-bus ****** If the node appears as a device on a bus, use ``on-bus:`` in the binding to say what type of bus. For example, a binding for an external SPI memory chip should include this line: .. code-block:: YAML on-bus: spi And a binding for an I2C based temperature sensor should include this line: .. code-block:: YAML on-bus: i2c When looking for a binding for a node, the build system checks if the binding for the parent node contains ``bus: ``. If it does, then only bindings with a matching ``on-bus: `` and bindings without an explicit ``on-bus`` are considered. Bindings with an explicit ``on-bus: `` are searched for first, before bindings without an explicit ``on-bus``. The search repeats for each item in the node's ``compatible`` property, in order. This feature allows the same device to have different bindings depending on what bus it appears on. For example, consider a sensor device with compatible ``manufacturer,sensor`` which can be used via either I2C or SPI. The sensor node may therefore appear in the devicetree as a child node of either an SPI or an I2C controller, like this: .. code-block:: devicetree spi-bus@0 { /* ... some compatible with 'bus: spi', etc. ... */ sensor@0 { compatible = "manufacturer,sensor"; reg = <0>; /* ... */ }; }; i2c-bus@0 { /* ... some compatible with 'bus: i2c', etc. ... */ sensor@79 { compatible = "manufacturer,sensor"; reg = <79>; /* ... */ }; }; You can write two separate binding files which match these individual sensor nodes, even though they have the same compatible: .. code-block:: YAML # manufacturer,sensor-spi.yaml, which matches sensor@0 on the SPI bus: compatible: "manufacturer,sensor" on-bus: spi # manufacturer,sensor-i2c.yaml, which matches sensor@79 on the I2C bus: compatible: "manufacturer,sensor" properties: uses-clock-stretching: type: boolean on-bus: i2c Only ``sensor@79`` can have a ``use-clock-stretching`` property. The bus-sensitive logic ignores :file:`manufacturer,sensor-i2c.yaml` when searching for a binding for ``sensor@0``. .. _dt-bindings-cells: Specifier cell names (\*-cells) ******************************* This section documents how to name the cells in a specifier within a binding. These concepts are discussed in detail later in this guide in :ref:`dt-phandle-arrays`. Consider a binding for a node whose phandle may appear in a ``phandle-array`` property, like the PWM controllers ``pwm1`` and ``pwm2`` in this example: .. code-block:: DTS pwm1: pwm@deadbeef { compatible = "foo,pwm"; #pwm-cells = <2>; }; pwm2: pwm@deadbeef { compatible = "bar,pwm"; #pwm-cells = <1>; }; my-node { pwms = <&pwm1 1 2000>, <&pwm2 3000>; }; The bindings for compatible ``"foo,pwm"`` and ``"bar,pwm"`` must give a name to the cells that appear in a PWM specifier using ``pwm-cells:``, like this: .. code-block:: YAML # foo,pwm.yaml compatible: "foo,pwm" ... pwm-cells: - channel - period # bar,pwm.yaml compatible: "bar,pwm" ... pwm-cells: - period A ``*-names`` (e.g. ``pwm-names``) property can appear on the node as well, giving a name to each entry. This allows the cells in the specifiers to be accessed by name, e.g. using APIs like :c:macro:`DT_PWMS_CHANNEL_BY_NAME`. If the specifier is empty (e.g. ``#clock-cells = <0>``), then ``*-cells`` can either be omitted (recommended) or set to an empty array. Note that an empty array is specified as e.g. ``clock-cells: []`` in YAML. .. _dt-bindings-include: Include ******* Bindings can include other files, which can be used to share common property definitions between bindings. Use the ``include:`` key for this. Its value is either a string or a list. In the simplest case, you can include another file by giving its name as a string, like this: .. code-block:: YAML include: foo.yaml If any file named :file:`foo.yaml` is found (see :ref:`dt-where-bindings-are-located` for the search process), it will be included into this binding. Included files are merged into bindings with a simple recursive dictionary merge. The build system will check that the resulting merged binding is well-formed. It is allowed to include at any level, including ``child-binding``, like this: .. code-block:: YAML # foo.yaml will be merged with content at this level include: foo.yaml child-binding: # bar.yaml will be merged with content at this level include: bar.yaml It is an error if a key appears with a different value in a binding and in a file it includes, with one exception: a binding can have ``required: true`` for a :ref:`property definition ` for which the included file has ``required: false``. The ``required: true`` takes precedence, allowing bindings to strengthen requirements from included files. Note that weakening requirements by having ``required: false`` where the included file has ``required: true`` is an error. This is meant to keep the organization clean. The file :zephyr_file:`base.yaml ` contains definitions for many common properties. When writing a new binding, it is a good idea to check if :file:`base.yaml` already defines some of the needed properties, and include it if it does. Note that you can make a property defined in base.yaml obligatory like this, taking :ref:`reg ` as an example: .. code-block:: YAML reg: required: true This relies on the dictionary merge to fill in the other keys for ``reg``, like ``type``. To include multiple files, you can use a list of strings: .. code-block:: YAML include: - foo.yaml - bar.yaml This includes the files :file:`foo.yaml` and :file:`bar.yaml`. (You can write this list in a single line of YAML as ``include: [foo.yaml, bar.yaml]``.) When including multiple files, any overlapping ``required`` keys on properties in the included files are ORed together. This makes sure that a ``required: true`` is always respected. In some cases, you may want to include some property definitions from a file, but not all of them. In this case, ``include:`` should be a list, and you can filter out just the definitions you want by putting a mapping in the list, like this: .. code-block:: YAML include: - name: foo.yaml property-allowlist: - i-want-this-one - and-this-one - name: bar.yaml property-blocklist: - do-not-include-this-one - or-this-one Each map element must have a ``name`` key which is the filename to include, and may have ``property-allowlist`` and ``property-blocklist`` keys that filter which properties are included. You cannot have a single map element with both ``property-allowlist`` and ``property-blocklist`` keys. A map element with neither ``property-allowlist`` nor ``property-blocklist`` is valid; no additional filtering is done. You can freely intermix strings and mappings in a single ``include:`` list: .. code-block:: YAML include: - foo.yaml - name: bar.yaml property-blocklist: - do-not-include-this-one - or-this-one Finally, you can filter from a child binding like this: .. code-block:: YAML include: - name: bar.yaml child-binding: property-allowlist: - child-prop-to-allow Nexus nodes and maps ******************** All ``phandle-array`` type properties support mapping through ``*-map`` properties, e.g. ``gpio-map``, as defined by the Devicetree specification. This is used, for example, to define connector nodes for common breakout headers, such as the ``arduino_header`` nodes that are conventionally defined in the devicetrees for boards with Arduino compatible expansion headers.