doc: dts: update howtos with new API

Document the use of DEVICE_DT_GET() to fetch device pointers at
compile time, and update the documentation on defining device
instances to use the devicetree macros.

Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
This commit is contained in:
Peter Bigot 2021-01-06 08:39:01 -06:00 committed by Kumar Gala
commit 92324d9a4d

View file

@ -88,12 +88,13 @@ works best for your requirements. Here are some examples:
/* Option 4: by path */
#define MY_SERIAL DT_PATH(soc, serial_40002000)
Once you have a node identifier, get the ``struct device`` by combining
Once you have a node identifier there are two ways to proceed. The
classic way is to get the ``struct device`` by combining
:c:func:`DT_LABEL` with :c:func:`device_get_binding`:
.. code-block:: c
struct device *uart_dev = device_get_binding(DT_LABEL(MY_SERIAL));
const struct device *uart_dev = device_get_binding(DT_LABEL(MY_SERIAL));
You can then use ``uart_dev`` with :ref:`uart_api` API functions like
:c:func:`uart_configure`. Similar code will work for other device types; just
@ -103,6 +104,23 @@ There's no need to override the ``label`` property to something else: just make
a node identifier and pass it to ``DT_LABEL`` to get the right string to pass
to ``device_get_binding()``.
The second way to get a device is to use :c:func:`DEVICE_DT_GET`:
.. code-block:: c
const struct device *uart_dev = DEVICE_DT_GET(MY_SERIAL);
if (!device_is_ready(uart_dev)) {
/* Not ready, do not use */
return -ENODEV;
}
This idiom fetches the device pointer at build-time, which is useful when you
want to store the device pointer as configuration data. But because the
device may not be initialized, or may have failed to initialize, you must
verify that the device is ready to be used before passing it to any API
functions. (This check is done for you by :c:func:`device_get_binding`.)
If you're having trouble, see :ref:`dt-trouble`. The first thing to check is
that the node has ``status = "okay"``, like this:
@ -111,7 +129,7 @@ that the node has ``status = "okay"``, like this:
#define MY_SERIAL DT_NODELABEL(my_serial)
#if DT_NODE_HAS_STATUS(MY_SERIAL, okay)
struct device *uart_dev = device_get_binding(DT_LABEL(MY_SERIAL));
const struct device *uart_dev = device_get_binding(DT_LABEL(MY_SERIAL));
#else
#error "Node is disabled"
#endif
@ -439,10 +457,10 @@ using instance numbers. Do this after defining ``my_api_funcs``.
MY_DEV_INIT_LEVEL, MY_DEV_INIT_PRIORITY, \
&my_api_funcs);
Notice the use of APIs like :c:func:`DT_INST_LABEL` and :c:func:`DT_INST_PROP`
to access devicetree node data. These APIs retrieve data from the devicetree
for instance number ``inst`` of the node with compatible determined by
``DT_DRV_COMPAT``.
Notice the use of APIs like :c:func:`DT_INST_PROP` and
:c:func:`DEVICE_DT_INST_DEFINE` to access devicetree node data. These
APIs retrieve data from the devicetree for instance number ``inst`` of
the node with compatible determined by ``DT_DRV_COMPAT``.
Finally, pass the instantiation macro to :c:func:`DT_INST_FOREACH_STATUS_OKAY`:
@ -508,7 +526,7 @@ devicetree to operate on specific device nodes:
.freq = DT_PROP(MYDEV(idx), clock_frequency), \
}; \
static const struct my_dev_cfg my_cfg_##idx = { /* ... */ }; \
DEVICE_DT_INST_DEFINE(idx, \
DEVICE_DT_DEFINE(MYDEV(idx), \
my_dev_init_function, \
device_pm_control_nop, \
&my_data_##idx, \
@ -516,8 +534,8 @@ devicetree to operate on specific device nodes:
MY_DEV_INIT_LEVEL, MY_DEV_INIT_PRIORITY, \
&my_api_funcs)
Notice the use of APIs like :c:func:`DT_LABEL` and :c:func:`DT_PROP` to access
devicetree node data.
Notice the use of APIs like :c:func:`DT_PROP` and
:c:func:`DEVICE_DT_DEFINE` to access devicetree node data.
Finally, manually detect each enabled devicetree node and use
``CREATE_MY_DEVICE`` to instantiate each ``struct device``: