zephyr/doc/guides/dts/api-usage.rst
Kumar Gala fdd85d5ad7 dts: Rename DT_HAS_NODE macro to DT_HAS_NODE_STATUS_OKAY
Rename DT_HAS_NODE to DT_HAS_NODE_STATUS_OKAY so the semantics are
clear.  As going forward DT_HAS_NODE will report if a NODE exists
regardless of its status.

Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
2020-05-06 05:25:41 -05:00

391 lines
13 KiB
ReStructuredText

.. _dt-from-c:
Devicetree access from C/C++
############################
This guide describes Zephyr's ``<devicetree.h>`` API for reading the devicetree
from C source files. It assumes you're familiar with the concepts in
:ref:`devicetree-intro` and :ref:`dt-bindings`. See :ref:`devicetree_api` for
API reference documentation.
.. _dt-node-identifiers:
Node identifiers
****************
To get information about a particular devicetree node, you need a *node
identifier* for it. This is a just a C macro that refers to the node.
There are four types, each of which is created with a different macro:
Path identifiers
These use the node's full path in the devicetree, starting from the
root node. They are mostly useful if you happen to know the exact node
you're looking for. Create these with :c:func:`DT_PATH()`.
Node label identifiers
Unique names which can be given to each node where it is
defined. These are often used when the SoC :file:`.dtsi` gives nodes
names that match the SoC datasheet, like ``i2c_1``, ``spi_2``, etc.
Create these with :c:func:`DT_NODELABEL()`.
Alias identifiers
These are created for properties of the special ``/aliases`` node. They are
useful for supporting applications (like :ref:`blinky <blinky-sample>`,
which uses the ``led0`` alias) that need to refer to *some* device of a
particular type ("the board's user LED") but don't care which exact one is
used. Create these with :c:func:`DT_ALIAS()`.
Instance identifiers
These are used primarily by device drivers, as they're a way to refer to
nodes based on their matching compatible. Create these with
:c:func:`DT_INST()`, but be careful doing so.
.. _dt-node-main-ex:
Here's a DTS fragment for some imaginary hardware we'll return to throughout
this file for examples:
.. literalinclude:: main-example.dts
:language: DTS
:start-after: start-after-here
Here are node identifiers of each type for the ``i2c@40002000`` node:
- ``DT_PATH(soc, i2c_40002000)``
- ``DT_NODELABEL(i2c1)``
- ``DT_ALIAS(sensor_controller)``
- ``DT_INST(x, vnd_soc_i2c)`` for some unknown number ``x``. See the
:c:func:`DT_INST()` documentation for details.
These identifiers are precisely equivalent: they refer to the same node, and
are otherwise interchangeable in the following examples.
.. important::
Non-alphanumeric characters like dash (``-``) and the at sign (``@``) in
devicetree names are converted to underscores (``_``). The names in a DTS
are also converted to lowercase.
.. _node-ids-are-not-values:
Node identifiers are not values
*******************************
There is no way to store one in a variable. You cannot write:
.. code-block:: c
/* These will give you compiler errors: */
void *i2c_0 = DT_INST(0, vnd_soc_i2c);
unsigned int i2c_1 = DT_INST(1, vnd_soc_i2c);
long my_i2c = DT_NODELABEL(i2c1);
If you want something short to save typing, use C macros:
.. code-block:: c
/* Use something like this instead: */
#define MY_I2C DT_NODELABEL(i2c1)
#define INST(i) DT_INST(i, vnd_soc_i2c)
#define I2C_0 INST(0)
#define I2C_1 INST(1)
.. _not-all-dt-nodes:
Not all nodes are usable
************************
Just because :ref:`zephyr.dts <dt-outputs>` has a node doesn't mean you can use
it from a C or C++ source file. The node has to have a matching binding, and
its ``status`` property must be ``"okay"`` (instead of, say, ``"disabled"``).
Use :c:func:`DT_HAS_NODE_STATUS_OKAY` to check if a node identifier is valid for use. The
value is 1 if yes, and 0 if no.
Here are some examples from the :ref:`above devicetree <dt-node-main-ex>`:
.. code-block:: c
DT_HAS_NODE_STATUS_OKAY(DT_PATH(soc, i2c_40002000)) /* 1: node has binding and is enabled */
DT_HAS_NODE_STATUS_OKAY(DT_ALIAS(sensor_controller)) /* 1: that's an alias for the same node */
DT_HAS_NODE_STATUS_OKAY(DT_NODELABEL(i2c1)) /* 1: that's also the same node */
DT_HAS_NODE_STATUS_OKAY(DT_PATH(i2c_40002000)) /* 0: there's no such node */
DT_HAS_NODE_STATUS_OKAY(DT_PATH(soc)) /* 0: the /soc node has no binding */
Property access
***************
The right API to use to read property values depends on the node and property.
- :ref:`dt-checking-property-exists`
- :ref:`simple-properties`
- :ref:`reg-properties`
- :ref:`interrupts-properties`
- :ref:`phandle-properties`
.. _dt-checking-property-exists:
Checking properties and values
==============================
You can use :c:func:`DT_NODE_HAS_PROP()` to check if a node has a property. For
the :ref:`example devicetree <dt-node-main-ex>` above:
.. code-block:: c
DT_NODE_HAS_PROP(DT_NODELABEL(i2c1), clock_frequency) /* expands to 1 */
DT_NODE_HAS_PROP(DT_NODELABEL(i2c1), not_a_property) /* expands to 0 */
.. _simple-properties:
Simple properties
=================
Use ``DT_PROP(node_id, property)`` to read basic integer, boolean, string,
numeric array, and string array properties.
For example, to read the ``clock-frequency`` property's value in the
:ref:`above example <dt-node-main-ex>`:
.. code-block:: c
DT_PROP(DT_PATH(soc, i2c_40002000), clock_frequency) /* This is 100000, */
DT_PROP(DT_NODELABEL(i2c1), clock_frequency) /* and so is this, */
DT_PROP(DT_ALIAS(sensor_controller), clock_frequency) /* and this. */
.. important::
The DTS property ``clock-frequency`` is spelled ``clock_frequency`` in C.
That is, properties also need special characters converted to underscores.
Their names are also forced to lowercase.
Properties with ``string`` and ``boolean`` types work the exact same way. The
``DT_PROP()`` macro expands to a string literal in the case of strings, and the
number 0 or 1 in the case of booleans. For example:
.. code-block:: c
#define I2C1 DT_NODELABEL(i2c1)
DT_PROP(I2C1, status) /* expands to the string literal "okay" */
Properties with type ``array``, ``uint8-array``, and ``string-array`` work
similarly, except ``DT_PROP()`` expands to an array initializer in these cases.
Here is an example devicetree fragment:
.. code-block:: DTS
foo: foo@1234 {
a = <1000 2000 3000>; /* array */
b = [aa bb cc dd]; /* uint8-array */
c = "bar", "baz"; /* string-array */
};
Its properties can be accessed like this:
.. code-block:: c
#define FOO DT_NODELABEL(foo)
int a[] = DT_PROP(FOO, a); /* {1000, 2000, 3000} */
unsigned char b[] = DT_PROP(FOO, b); /* {0xaa, 0xbb, 0xcc, 0xdd} */
char* c[] = DT_PROP(FOO, c); /* {"foo", "bar"} */
You can use :c:func:`DT_PROP_LEN()` to get logical array lengths in number of
elements.
.. code-block:: c
size_t a_len = DT_PROP_LEN(FOO, a); /* 3 */
size_t b_len = DT_PROP_LEN(FOO, b); /* 4 */
size_t c_len = DT_PROP_LEN(FOO, c); /* 2 */
``DT_PROP_LEN()`` cannot be used with the special ``reg`` or ``interrupts``
properties. These have alternative macros which are described next.
.. _reg-properties:
reg properties
==============
See :ref:`dt-important-props` for an introduction to ``reg``.
Given a node identifier ``node_id``, ``DT_NUM_REGS(node_id)`` is the
total number of register blocks in the node's ``reg`` property.
You **cannot** read register block addresses and lengths with ``DT_PROP(node,
reg)``. Instead, if a node only has one register block, use
:c:func:`DT_REG_ADDR` or :c:func:`DT_REG_SIZE`:
- ``DT_REG_ADDR(node_id)``: the given node's register block address
- ``DT_REG_SIZE(node_id)``: its size
Use :c:func:`DT_REG_ADDR_BY_IDX` or :c:func:`DT_REG_SIZE_BY_IDX` instead if the
node has multiple register blocks:
- ``DT_REG_ADDR_BY_IDX(node_id, idx)``: address of register block at index
``idx``
- ``DT_REG_SIZE_BY_IDX(node_id, idx)``: size of block at index ``idx``
The ``idx`` argument to these must be an integer literal or a macro that
expands to one without requiring any arithmetic. In particular, ``idx`` cannot
be a variable. This won't work:
.. code-block:: c
/* This will cause a compiler error. */
for (size_t i = 0; i < DT_NUM_REGS(node_id); i++) {
size_t addr = DT_REG_ADDR_BY_IDX(node_id, i);
}
.. _interrupts-properties:
interrupts properties
=====================
See :ref:`dt-important-props` for a brief introduction to ``interrupts``.
Given a node identifier ``node_id``, ``DT_NUM_IRQS(node_id)`` is the total
number of interrupt specifiers in the node's ``interrupts`` property.
The most general purpose API macro for accessing these is
:c:func:`DT_IRQ_BY_IDX`:
.. code-block:: c
DT_IRQ_BY_IDX(node_id, idx, val)
Here, ``idx`` is the logical index into the ``interrupts`` array, i.e. it is
the index of an individual interrupt specifier in the property. The ``val``
argument is the name of a cell within the interrupt specifier. To use this
macro, check the bindings file for the node you are interested in to find the
``val`` names.
Most Zephyr devicetree bindings have a cell named ``irq``, which is the
interrupt number. You can use :c:func:`DT_IRQN` as a convenient way to get a
processed view of this value.
.. warning::
Here, "processed" reflects Zephyr's devicetree :ref:`dt-scripts`, which
change the ``irq`` number in :ref:`zephyr.dts <devicetree-in-out-files>` to
handle hardware constraints on some SoCs and in accordance with Zephyr's
multilevel interrupt numbering.
This is currently not very well documented, and you'll need to read the
scripts source code and existing drivers for more details if you are writing
a device driver.
.. _phandle-properties:
phandle properties
==================
Property values can refer to other nodes using the ``&another-node`` phandle
syntax introduced in :ref:`dt-writing-property-values`. Properties which
contain phandles have type ``phandle``, ``phandles``, or ``phandle-array`` in
their bindings. We'll call these "phandle properties" for short.
You can convert a phandle to a node identifier using :c:func:`DT_PHANDLE`,
:c:func:`DT_PHANDLE_BY_IDX`, or :c:func:`DT_PHANDLE_BY_NAME`, depending on the
type of property you are working with.
One common use case for phandle properties is referring to other hardware in
the tree. In this case, you usually want to convert the devicetree-level
phandle to a Zephyr driver-level :ref:`struct device <device_model_api>`.
See :ref:`dt-get-device` for ways to do that.
Another common use case is accessing specifier values in a phandle array. The
general purpose APIs for this are :c:func:`DT_PHA_BY_IDX` and :c:func:`DT_PHA`.
There are also hardware-specific shorthands like :c:func:`DT_GPIO_LABEL_BY_IDX`,
:c:func:`DT_GPIO_LABEL`, :c:func:`DT_GPIO_PIN_BY_IDX`, :c:func:`DT_GPIO_PIN`,
:c:func:`DT_GPIO_FLAGS_BY_IDX`, and :c:func:`DT_GPIO_FLAGS`.
See :c:func:`DT_PHA_HAS_CELL_AT_IDX` and :c:func:`DT_PROP_HAS_IDX` for ways to
check if a specifier value is present.
.. _other-devicetree-apis:
Other APIs
**********
Here are pointers to some other available APIs.
- :c:func:`DT_CHOSEN`, :c:func:`DT_HAS_CHOSEN`: for properties
of the special ``/chosen`` node
- :c:func:`DT_HAS_COMPAT`: test if a compatible has a binding and at least one
enabled node
- :c:func:`DT_BUS`: get a node's bus controller, if there is one
- :c:func:`DT_ENUM_IDX`: for properties whose values are among a fixed list of
choices
Flash partitions
****************
These currently must be managed via the legacy API. See
:ref:`legacy_flash_partitions`.
Device driver conveniences
**************************
Special purpose macros are available for writing device drivers, which usually
rely on :ref:`instance identifiers <dt-node-identifiers>`.
To use these, you must define ``DT_DRV_COMPAT`` to the ``compat`` value your
driver implements support for. This ``compat`` value is what you would pass to
:c:func:`DT_INST`.
If you do that, you can access the properties of individual instances of your
compatible with less typing, like this:
.. code-block:: c
#include <devicetree.h>
#define DT_DRV_COMPAT my_driver_compat
/* This is same thing as DT_INST(0, my_driver_compat): */
DT_DRV_INST(0)
/*
* This is the same thing as
* DT_PROP(DT_INST(0, my_driver_compat), clock_frequency)
*/
DT_INST_PROP(0, clock_frequency)
See :ref:`devicetree-inst-apis` for a generic API reference.
Hardware specific APIs
**********************
Convenience macros built on top of the above APIs are also defined to help
readability for hardware specific code. See :ref:`devicetree-hw-api` for
details.
Generated macros
****************
While the :file:`devicetree.h` API is not generated, it does rely on a
generated C header which is put into every application build directory:
:ref:`devicetree_unfixed.h <dt-outputs>`. This file contains macros with
devicetree data.
These macros have tricky naming conventions which the `devicetree_api` API
abstracts away. They should be considered an implementation detail, but it's
useful to understand them since they will frequently be seen in compiler error
messages.
This section contains an Augmented Backus-Naur Form grammar for these
generated macros, with examples and more details in comments. See `RFC 7405`_
(which extends `RFC 5234`_) for a syntax specification.
.. literalinclude:: macros.bnf
:language: abnf
.. _RFC 7405: https://tools.ietf.org/html/rfc7405
.. _RFC 5234: https://tools.ietf.org/html/rfc5234