..
    Copyright (c) 2018..2020 Bobby Noelte
    SPDX-License-Identifier: Apache-2.0

.. _zephyr_device_declare:

Zephyr device declaration
#########################

The Zephyr module provides functions to generate driver device instantiations.

::

    cogeno.import_module('zephyr')

The device delaration functions generate device instances code for all devices
activated ('status' = 'ok') in the board device tree file matching the provided
compatibles.

Most of the parameters aim at filling the DEVICE_AND_API_INIT macro.
Other parameters are there to help code generation to fit driver specifics.

Instance code will only be generated if the Kconfig variable is set. The
variable name is build with the device node label name (e.g: CONFIG_I2C_1).

Driver info templates
*********************

The device declaration functions work on templates that feature placeholder
substitution.

Device instance property placeholders:

- ${device-name}: device instance name.
                  Name is generated by the declaration function.
- ${driver-name}: device instance driver name.
                  Name is taken from the device tree node property 'label'.
- ${device-data}: device instance data structure name.
                  Name is generated by the declaration function.
- ${device-config-info}: device instance configuration structure name.
                         Name is generated by the declaration function.
- ${device-config-irq}: device instance interrupt configuration function name.
                        Name is generated by the declaration function.

Device instance device tree property placeholders:

* ${[path to DTS property]}: device instance device tree node property.
    The property path supports every node property that is documented in the
    node yaml bindings. It also supports yaml heuristics, like 'bus-master' and
    will use documented '"#cells"'.

Device tree property placeholders:

- ${[device id]:[path to DTS property]}: device node property value.
    The device node property is defined by the property path of the device
    given by the device id.
    The device id is usually also taken from a DTS property e.g.
    ${${clock/0/controller}:device-name}.

KConfig configuration parameter placeholders:

- ${CONFIG_[configuration parameter]}: KConfig configuration parameter value.

Example:

'c' template code between triple quotes (""" """) that should provide
the expected code to be generated for the driver structures.


.. code-block:: python

     """
     #if CONFIG_SPI_STM32_INTERRUPT
     DEVICE_DECLARE(${device-name});
     static void ${device-config-irq}(struct device *dev)
     {
             IRQ_CONNECT(${interrupts/0/irq}, ${interrupts/0/priority}, \\
                         spi_stm32_isr, \\
                         DEVICE_GET(${device-name}), 0);
             irq_enable(${interrupts/0/irq});
     }
     #endif
     static const struct spi_stm32_config ${device-config-info} = {
             .spi = (SPI_TypeDef *)${reg/0/address/0},
             .pclken.bus = ${clocks/0/bus},
             .pclken.enr = ${clocks/0/bits},
     #if CONFIG_SPI_STM32_INTERRUPT
             .config_irq = ${device-config-irq},
     #endif
     };
     static struct spi_stm32_data ${device-data} = {
             SPI_CONTEXT_INIT_LOCK(${device-data}, ctx),
             SPI_CONTEXT_INIT_SYNC(${device-data}, ctx),
     };
     """

Declaration of a single device instance
***************************************

.. function:: zephyr.device_declare_single(device_config, driver_name, device_init, device_pm_control, device_level, device_prio, device_api, device_info)

    Generate device instance code for a device instance that:

    - matches the driver name that
    - is activated ('status' = 'ok') in the board device tree file and that is
    - configured by Kconfig.

    :param device_config:
        Configuration variables for device instantiation.
        (e.g. 'CONFIG_SPI_0')
    :param driver_name:
        Driver name for device instantiation.
        (e.g. 'SPI_0')
    :param device_init:
        Device initialisation function.
        (e.g. 'spi_stm32_init')
    :param: device_pm_control:
        Device power management function.
        (e.g. 'device_pm_control_nop')
    :param device_level:
        Driver initialisation level.
        (e.g. 'PRE_KERNEL_1')
    :param device_prios:
        Driver initialisation priority definition.
        (e.g. 32)
    :param device_api:
        Identifier of the device api.
        (e.g. 'spi_stm32_driver_api')
    :param device_info:
        Device info template for device driver config, data and interrupt
        initialisation.
    :param device_defaults:
        Default property values.
        (e.g. { 'label' : 'My default label' })

Declaration of multiple device instances
****************************************

.. function:: zephyr.device_declare_multi(device_configs, driver_names, device_inits, device_levels, device_prios, device_api, device_info)

    Generate device instances code for all device instances that:

    - match the driver names that
    - are activated ('status' = 'ok') in the board device tree file and that are
    - configured by Kconfig.

    :param device_configs:
        A list of configuration variables for device instantiation.
        (e.g. ['CONFIG_SPI_0', 'CONFIG_SPI_1'])
    :param driver_names:
        A list of driver names for device instantiation. The list shall be
        ordered the same way as the list of device configs.
        (e.g. ['SPI_0', 'SPI_1'])
    :param device_inits:
        A list of device initialisation functions or a single function.
        The list shall be ordered as the list of device configs.
        (e.g. 'spi_stm32_init')
    :param: device_pm_controls:
        A list of device power management functions or a single function.
        The list shall be ordered as the list of device configs.
        (e.g. 'device_pm_control_nop')
    :param device_levels:
        A list of driver initialisation levels or a single level definition.
        The list shall be ordered as the list of device configs.
        (e.g. 'PRE_KERNEL_1')
    :param device_prios:
        A list of driver initialisation priorities or a single priority
        definition. The list shall be ordered as the list of device configs.
        (e.g. 32)
    :param device_api:
        Identifier of the device api.
        (e.g. 'spi_stm32_driver_api')
    :param device_info:
        Device info template for device driver config, data and interrupt
        initialisation.
    :param device_defaults:
        Default property values.
        (e.g. { 'label' : 'My default label' })

Example:

.. code-block:: C

    /**
     * @code{.cogeno}
     * cogeno.import_module('zephyr')
     *
     * device_configs = ['CONFIG_SPI_{}'.format(x) for x in range(1, 4)]
     * driver_names = ['SPI_{}'.format(x) for x in range(1, 4)]
     * device_inits = 'spi_stm32_init'
     * device_pm_controls = 'device_pm_control_nop'
     * device_levels = 'POST_KERNEL'
     * device_prios = 'CONFIG_SPI_INIT_PRIORITY'
     * device_api = 'spi_stm32_driver_api'
     * device_info = \
     * """
     * #if CONFIG_SPI_STM32_INTERRUPT
     * DEVICE_DECLARE(${device-name});
     * static void ${device-config-irq}(struct device *dev)
     * {
     *         IRQ_CONNECT(${interrupts/0/irq}, ${interrupts/0/priority}, \\
     *                     spi_stm32_isr, \\
     *                     DEVICE_GET(${device-name}), 0);
     *         irq_enable(${interrupts/0/irq});
     * }
     * #endif
     * static const struct spi_stm32_config ${device-config-info} = {
     *         .spi = (SPI_TypeDef *)${reg/0/address/0},
     *         .pclken.bus = ${clocks/0/bus},
     *         .pclken.enr = ${clocks/0/bits},
     * #if CONFIG_SPI_STM32_INTERRUPT
     *         .config_irq = ${device-config-irq},
     * #endif
     * };
     * static struct spi_stm32_data ${device-data} = {
     *         SPI_CONTEXT_INIT_LOCK(${device-data}, ctx),
     *         SPI_CONTEXT_INIT_SYNC(${device-data}, ctx),
     * };
     * """
     *
     * zephyr.device_declare_multi( \
     *     device_configs,
     *     driver_names,
     *     device_inits,
     *     device_pm_controls,
     *     device_levels,
     *     device_prios,
     *     device_api,
     *     device_info)
     * @endcode{.cogeno}
     */
    /** @code{.codeins}@endcode */
