/*
 * Copyright (c) 2015 Intel Corporation.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef ZEPHYR_INCLUDE_DEVICE_H_
#define ZEPHYR_INCLUDE_DEVICE_H_

/**
 * @brief Device Driver APIs
 * @defgroup io_interfaces Device Driver APIs
 * @{
 * @}
 */
/**
 * @brief Miscellaneous Drivers APIs
 * @defgroup misc_interfaces Miscellaneous Drivers APIs
 * @ingroup io_interfaces
 * @{
 * @}
 */
/**
 * @brief Device Model APIs
 * @defgroup device_model Device Model APIs
 * @{
 */

#include <init.h>
#include <linker/sections.h>
#include <pm/device.h>
#include <sys/device_mmio.h>
#include <sys/util.h>

#ifdef __cplusplus
extern "C" {
#endif

/** @brief Type used to represent devices and functions.
 *
 * The extreme values and zero have special significance. Negative
 * values identify functionality that does not correspond to a Zephyr
 * device, such as the system clock or a SYS_INIT() function.
 */
typedef int16_t device_handle_t;

/** @brief Flag value used in lists of device handles to separate
 * distinct groups.
 *
 * This is the minimum value for the device_handle_t type.
 */
#define DEVICE_HANDLE_SEP INT16_MIN

/** @brief Flag value used in lists of device handles to indicate the
 * end of the list.
 *
 * This is the maximum value for the device_handle_t type.
 */
#define DEVICE_HANDLE_ENDS INT16_MAX

/** @brief Flag value used to identify an unknown device. */
#define DEVICE_HANDLE_NULL 0

#define Z_DEVICE_MAX_NAME_LEN	48

/**
 * @def DEVICE_NAME_GET
 *
 * @brief Expands to the full name of a global device object
 *
 * @details Return the full name of a device object symbol created by
 * DEVICE_DEFINE(), using the dev_name provided to DEVICE_DEFINE().
 *
 * It is meant to be used for declaring extern symbols pointing on device
 * objects before using the DEVICE_GET macro to get the device object.
 *
 * @param name The same as dev_name provided to DEVICE_DEFINE()
 *
 * @return The expanded name of the device object created by DEVICE_DEFINE()
 */
#define DEVICE_NAME_GET(name) _CONCAT(__device_, name)

/**
 * @def SYS_DEVICE_DEFINE
 *
 * @brief Run an initialization function at boot at specified priority,
 * and define device PM control function.
 *
 * @details Invokes DEVICE_DEFINE() with no power management support
 * (@p pm_control_fn), no API (@p api_ptr), and a device name derived from
 * the @p init_fn name (@p dev_name).
 */
#define SYS_DEVICE_DEFINE(drv_name, init_fn, pm_control_fn, level, prio) \
    DEVICE_DEFINE(Z_SYS_NAME(init_fn), drv_name, init_fn,		\
              pm_control_fn,					\
              NULL, NULL, level, prio, NULL)

/**
 * @def DEVICE_DEFINE
 *
 * @brief Create device object and set it up for boot time initialization,
 * with the option to device_pm_control. In case of Device Idle Power
 * Management is enabled, make sure the device is in suspended state after
 * initialization.
 *
 * @details This macro defines a device object that is automatically
 * configured by the kernel during system initialization. Note that
 * devices set up with this macro will not be accessible from user mode
 * since the API is not specified;
 *
 * @param dev_name Device name. This must be less than Z_DEVICE_MAX_NAME_LEN
 * characters (including terminating NUL) in order to be looked up from user
 * mode with device_get_binding().
 *
 * @param drv_name The name this instance of the driver exposes to
 * the system.
 *
 * @param init_fn Address to the init function of the driver.
 *
 * @param pm_control_fn Pointer to pm_control function.
 * Can be NULL if not implemented.
 *
 * @param data_ptr Pointer to the device's private data.
 *
 * @param cfg_ptr The address to the structure containing the
 * configuration information for this instance of the driver.
 *
 * @param level The initialization level. See SYS_INIT() for
 * details.
 *
 * @param prio Priority within the selected initialization level. See
 * SYS_INIT() for details.
 *
 * @param api_ptr Provides an initial pointer to the API function struct
 * used by the driver. Can be NULL.
 */
#define DEVICE_DEFINE(dev_name, drv_name, init_fn, pm_control_fn,	\
              data_ptr, cfg_ptr, level, prio, api_ptr)		\
    Z_DEVICE_DEFINE(DT_INVALID_NODE, dev_name, drv_name, init_fn,	\
            pm_control_fn,					\
            data_ptr, cfg_ptr, level, prio, api_ptr)

/**
 * @def DEVICE_DT_NAME
 *
 * @brief Return a string name for a devicetree node.
 *
 * @details This macro returns a string literal usable as a device name
 * from a devicetree node. If the node has a "label" property, its value is
 * returned. Otherwise, the node's full "node-name@@unit-address" name is
 * returned.
 *
 * @param node_id The devicetree node identifier.
 */
#define DEVICE_DT_NAME(node_id) \
    DT_PROP_OR(node_id, label, DT_NODE_FULL_NAME(node_id))

/**
 * @def DEVICE_DT_DEFINE
 *
 * @brief Like DEVICE_DEFINE but taking metadata from a devicetree node.
 *
 * @details This macro defines a device object that is automatically
 * configured by the kernel during system initialization. The device
 * object name is derived from the node identifier (encoding the
 * devicetree path to the node), and the driver name is from the @p
 * label property of the devicetree node.
 *
 * The device is declared with extern visibility, so device objects
 * defined through this API can be obtained directly through
 * DEVICE_DT_GET() using @p node_id. Before using the pointer the
 * referenced object should be checked using device_is_ready().
 *
 * @param node_id The devicetree node identifier.
 *
 * @param init_fn Address to the init function of the driver.
 *
 * @param pm_control_fn Pointer to pm_control function.
 * Can be NULL if not implemented.
 *
 * @param data_ptr Pointer to the device's private data.
 *
 * @param cfg_ptr The address to the structure containing the
 * configuration information for this instance of the driver.
 *
 * @param level The initialization level. See SYS_INIT() for
 * details.
 *
 * @param prio Priority within the selected initialization level. See
 * SYS_INIT() for details.
 *
 * @param api_ptr Provides an initial pointer to the API function struct
 * used by the driver. Can be NULL.
 */
#define DEVICE_DT_DEFINE(node_id, init_fn, pm_control_fn,		\
             data_ptr, cfg_ptr, level, prio,		\
             api_ptr, ...)					\
    Z_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_NAME(node_id),		\
            DEVICE_DT_NAME(node_id), init_fn,		\
            pm_control_fn,					\
            data_ptr, cfg_ptr, level, prio,			\
            api_ptr, __VA_ARGS__)

/**
 * @def DEVICE_DT_INST_DEFINE
 *
 * @brief Like DEVICE_DT_DEFINE for an instance of a DT_DRV_COMPAT compatible
 *
 * @param inst instance number. This is replaced by
 * <tt>DT_DRV_COMPAT(inst)</tt> in the call to DEVICE_DT_DEFINE.
 *
 * @param ... other parameters as expected by DEVICE_DT_DEFINE.
 */
#define DEVICE_DT_INST_DEFINE(inst, ...) \
    DEVICE_DT_DEFINE(DT_DRV_INST(inst), __VA_ARGS__)

/**
 * @def DEVICE_DT_NAME_GET
 *
 * @brief The name of the struct device object for @p node_id
 *
 * @details Return the full name of a device object symbol created by
 * DEVICE_DT_DEFINE(), using the dev_name derived from @p node_id
 *
 * It is meant to be used for declaring extern symbols pointing on device
 * objects before using the DEVICE_DT_GET macro to get the device object.
 *
 * @param node_id The same as node_id provided to DEVICE_DT_DEFINE()
 *
 * @return The expanded name of the device object created by
 * DEVICE_DT_DEFINE()
 */
#define DEVICE_DT_NAME_GET(node_id) DEVICE_NAME_GET(Z_DEVICE_DT_DEV_NAME(node_id))

/**
 * @def DEVICE_DT_GET
 *
 * @brief Obtain a pointer to a device object by @p node_id
 *
 * @details Return the address of a device object created by
 * DEVICE_DT_INIT(), using the dev_name derived from @p node_id
 *
 * @param node_id The same as node_id provided to DEVICE_DT_DEFINE()
 *
 * @return A pointer to the device object created by DEVICE_DT_DEFINE()
 */
#define DEVICE_DT_GET(node_id) (&DEVICE_DT_NAME_GET(node_id))

/** @def DEVICE_DT_INST_GET
 *
 * @brief Obtain a pointer to a device object for an instance of a
 *        DT_DRV_COMPAT compatible
 *
 * @param inst instance number
 */
#define DEVICE_DT_INST_GET(inst) DEVICE_DT_GET(DT_DRV_INST(inst))

/**
 * @def DEVICE_DT_GET_ANY
 *
 * @brief Obtain a pointer to a device object by devicetree compatible
 *
 * If any enabled devicetree node has the given compatible and a
 * device object was created from it, this returns that device.
 *
 * If there no such devices, this returns NULL.
 *
 * If there are multiple, this returns an arbitrary one.
 *
 * If this returns non-NULL, the device must be checked for readiness
 * before use, e.g. with device_is_ready().
 *
 * @param compat lowercase-and-underscores devicetree compatible
 * @return a pointer to a device, or NULL
 */
#define DEVICE_DT_GET_ANY(compat)					    \
    COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(compat),			    \
            (DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(compat))), \
            (NULL))

/**
 * @def DEVICE_DT_GET_ONE
 *
 * @brief Obtain a pointer to a device object by devicetree compatible
 *
 * If any enabled devicetree node has the given compatible and a
 * device object was created from it, this returns that device.
 *
 * If there no such devices, this throws a compilation error.
 *
 * If there are multiple, this returns an arbitrary one.
 *
 * If this returns non-NULL, the device must be checked for readiness
 * before use, e.g. with device_is_ready().
 *
 * @param compat lowercase-and-underscores devicetree compatible
 * @return a pointer to a device
 */
#define DEVICE_DT_GET_ONE(compat)					    \
    COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(compat),			    \
            (DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(compat))), \
            (ZERO_OR_COMPILE_ERROR(0)))

/**
 * @def DEVICE_GET
 *
 * @brief Obtain a pointer to a device object by name
 *
 * @details Return the address of a device object created by
 * DEVICE_DEFINE(), using the dev_name provided to DEVICE_DEFINE().
 *
 * @param name The same as dev_name provided to DEVICE_DEFINE()
 *
 * @return A pointer to the device object created by DEVICE_DEFINE()
 */
#define DEVICE_GET(name) (&DEVICE_NAME_GET(name))

/** @def DEVICE_DECLARE
 *
 * @brief Declare a static device object
 *
 * This macro can be used at the top-level to declare a device, such
 * that DEVICE_GET() may be used before the full declaration in
 * DEVICE_DEFINE().
 *
 * This is often useful when configuring interrupts statically in a
 * device's init or per-instance config function, as the init function
 * itself is required by DEVICE_DEFINE() and use of DEVICE_GET()
 * inside it creates a circular dependency.
 *
 * @param name Device name
 */
#define DEVICE_DECLARE(name) static const struct device DEVICE_NAME_GET(name)

typedef void (*device_pm_cb)(const struct device *dev,
                 int status, void *context, void *arg);

/**
 * @brief Runtime device dynamic structure (in RAM) per driver instance
 *
 * Fields in this are expected to be default-initialized to zero. The
 * kernel driver infrastructure and driver access functions are
 * responsible for ensuring that any non-zero initialization is done
 * before they are accessed.
 */
struct device_state {
    /** Non-negative result of initializing the device.
     *
     * The absolute value returned when the device initialization
     * function was invoked, or `UINT8_MAX` if the value exceeds
     * an 8-bit integer. If initialized is also set, a zero value
     * indicates initialization succeeded.
     */
    unsigned int init_res : 8;

    /** Indicates the device initialization function has been
     * invoked.
     */
    bool initialized : 1;

#ifdef CONFIG_PM_DEVICE
    /* Power management data */
    struct pm_device pm;
#endif /* CONFIG_PM_DEVICE */
};

/**
 * @brief Runtime device structure (in ROM) per driver instance
 */
struct device {
    /** Name of the device instance */
    const char *name;
    /** Address of device instance config information */
    const void *config;
    /** Address of the API structure exposed by the device instance */
    const void *api;
    /** Address of the common device state */
    struct device_state * const state;
    /** Address of the device instance private data */
    void * const data;
    /** optional pointer to handles associated with the device.
     *
     * This encodes a sequence of sets of device handles that have
     * some relationship to this node. The individual sets are
     * extracted with dedicated API, such as
     * device_required_handles_get().
     */
    const device_handle_t *const handles;
#ifdef CONFIG_PM_DEVICE
    /** Power Management function */
    pm_device_control_callback_t pm_control;
    /** Pointer to device instance power management data */
    struct pm_device * const pm;
#endif
};

/**
 * @brief Get the handle for a given device
 *
 * @param dev the device for which a handle is desired.
 *
 * @return the handle for the device, or DEVICE_HANDLE_NULL if the
 * device does not have an associated handle.
 */
static inline device_handle_t
device_handle_get(const struct device *dev)
{
    device_handle_t ret = DEVICE_HANDLE_NULL;
    extern const struct device __device_start[];

    /* TODO: If/when devices can be constructed that are not part of the
     * fixed sequence we'll need another solution.
     */
    if (dev != NULL) {
        ret = 1 + (device_handle_t)(dev - __device_start);
    }

    return ret;
}

/**
 * @brief Get the device corresponding to a handle.
 *
 * @param dev_handle the device handle
 *
 * @return the device that has that handle, or a null pointer if @p
 * dev_handle does not identify a device.
 */
static inline const struct device *
device_from_handle(device_handle_t dev_handle)
{
    extern const struct device __device_start[];
    extern const struct device __device_end[];
    const struct device *dev = NULL;
    size_t numdev = __device_end - __device_start;

    if ((dev_handle > 0) && ((size_t)dev_handle <= numdev)) {
        dev = &__device_start[dev_handle - 1];
    }

    return dev;
}

/**
 * @brief Prototype for functions used when iterating over a set of devices.
 *
 * Such a function may be used in API that identifies a set of devices and
 * provides a visitor API supporting caller-specific interaction with each
 * device in the set.
 *
 * The visit is said to succeed if the visitor returns a non-negative value.
 *
 * @param dev a device in the set being iterated
 *
 * @param context state used to support the visitor function
 *
 * @return A non-negative number to allow walking to continue, and a negative
 * error code to case the iteration to stop.
 */
typedef int (*device_visitor_callback_t)(const struct device *dev, void *context);

/**
 * @brief Get the set of handles for devicetree dependencies of this device.
 *
 * These are the device dependencies inferred from devicetree.
 *
 * @param dev the device for which dependencies are desired.
 *
 * @param count pointer to a place to store the number of devices provided at
 * the returned pointer. The value is not set if the call returns a null
 * pointer. The value may be set to zero.
 *
 * @return a pointer to a sequence of @p *count device handles, or a null
 * pointer if @p dh does not provide dependency information.
 */
static inline const device_handle_t *
device_required_handles_get(const struct device *dev,
                size_t *count)
{
    const device_handle_t *rv = dev->handles;

    if (rv != NULL) {
        size_t i = 0;

        while ((rv[i] != DEVICE_HANDLE_ENDS)
               && (rv[i] != DEVICE_HANDLE_SEP)) {
            ++i;
        }
        *count = i;
    }

    return rv;
}

/**
 * @brief Visit every device that @p dev directly requires.
 *
 * Zephyr maintains information about which devices are directly required by
 * another device; for example an I2C-based sensor driver will require an I2C
 * controller for communication. Required devices can derive from
 * statically-defined devicetree relationships or dependencies registered
 * at runtime.
 *
 * This API supports operating on the set of required devices. Example uses
 * include making sure required devices are ready before the requiring device
 * is used, and releasing them when the requiring device is no longer needed.
 *
 * There is no guarantee on the order in which required devices are visited.
 *
 * If the @p visitor function returns a negative value iteration is halted,
 * and the returned value from the visitor is returned from this function.
 *
 * @note This API is not available to unprivileged threads.
 *
 * @param dev a device of interest. The devices that this device depends on
 * will be used as the set of devices to visit. This parameter must not be
 * null.
 *
 * @param visitor_cb the function that should be invoked on each device in the
 * dependency set. This parameter must not be null.
 *
 * @param context state that is passed through to the visitor function. This
 * parameter may be null if @p visitor tolerates a null @p context.
 *
 * @return The number of devices that were visited if all visits succeed, or
 * the negative value returned from the first visit that did not succeed.
 */


/**
 * @}
 */

/**
 * @brief Device Power Management APIs
 * @defgroup device_power_management_api Device Power Management APIs
 * @ingroup power_management_api
 * @{
 */

#if 0


/** @def DEVICE_PM_ACTIVE_STATE
 *
 * @brief device is in ACTIVE power state
 *
 * @details Normal operation of the device. All device context is retained.
 */
#define DEVICE_PM_ACTIVE_STATE          1

/** @def DEVICE_PM_LOW_POWER_STATE
 *
 * @brief device is in LOW power state
 *
 * @details Device context is preserved by the HW and need not be
 * restored by the driver.
 */
#define DEVICE_PM_LOW_POWER_STATE       2

/** @def DEVICE_PM_SUSPEND_STATE
 *
 * @brief device is in SUSPEND power state
 *
 * @details Most device context is lost by the hardware.
 * Device drivers must save and restore or reinitialize any context
 * lost by the hardware
 */
#define DEVICE_PM_SUSPEND_STATE         3

/** @def DEVICE_PM_FORCE_SUSPEND_STATE
 *
 * @brief device is in force SUSPEND power state
 *
 * @details Driver puts the device in suspended state after
 * completing the ongoing transactions and will not process any
 * queued work or will not take any new requests for processing.
 * Most device context is lost by the hardware. Device drivers must
 * save and restore or reinitialize any context lost by the hardware.
 */
#define DEVICE_PM_FORCE_SUSPEND_STATE	4

/** @def DEVICE_PM_OFF_STATE
 *
 * @brief device is in OFF power state
 *
 * @details - Power has been fully removed from the device.
 * The device context is lost when this state is entered, so the OS
 * software will reinitialize the device when powering it back on
 */

#define DEVICE_PM_OFF_STATE             5


/** @def DEVICE_PM_EARLY_SUSPEND_STATE
 *
 * @brief device is in early SUSPEND power state
 *
 */
#define DEVICE_PM_EARLY_SUSPEND_STATE    6

/** @def DEVICE_PM_EARLY_RESUME_STATE
 *
 * @brief device is in early resume power state
 *
 */
#define DEVICE_PM_LATE_RESUME_STATE    7



/* Constants defining support device power commands */
#define DEVICE_PM_SET_POWER_STATE       1
#define DEVICE_PM_GET_POWER_STATE       2

/**
 * @brief Call the get power state function of a device
 *
 * This function lets the caller know the current device
 * power state at any time. This state will be one of the defined
 * power states allowed for the devices in that system
 *
 * @param dev pointer to device structure of the driver instance.
 * @param device_power_state Device power state to be filled by the device
 *
 * @retval 0 If successful.
 * @retval Errno Negative errno code if failure.
 */
static inline int device_get_power_state(const struct device *dev,
                     uint32_t *device_power_state)
{
    return -ENOTSUP;
}

#endif /* CONFIG_PM_DEVICE */
int device_required_foreach(const struct device *dev,
              device_visitor_callback_t visitor_cb,
              void *context);

/**
 * @brief Retrieve the device structure for a driver by name
 *
 * @details Device objects are created via the DEVICE_DEFINE() macro and
 * placed in memory by the linker. If a driver needs to bind to another driver
 * it can use this function to retrieve the device structure of the lower level
 * driver by the name the driver exposes to the system.
 *
 * @param name device name to search for. A null pointer, or a pointer to an
 * empty string, will cause NULL to be returned.
 *
 * @return pointer to device structure; NULL if not found or cannot be used.
 */
__syscall const struct device *device_get_binding(const char *name);

/** @brief Get access to the static array of static devices.
 *
 * @param devices where to store the pointer to the array of
 * statically allocated devices. The array must not be mutated
 * through this pointer.
 *
 * @return the number of statically allocated devices.
 */
size_t z_device_get_all_static(const struct device * *devices);

/** @brief Determine whether a device has been successfully initialized.
 *
 * @param dev pointer to the device in question.
 *
 * @return true if and only if the device is available for use.
 */
bool z_device_ready(const struct device *dev);

/** @brief Determine whether a device is ready for use
 *
 * This is the implementation underlying `device_usable_check()`, without the
 * overhead of a syscall wrapper.
 *
 * @param dev pointer to the device in question.
 *
 * @return a non-positive integer as documented in device_usable_check().
 */
static inline int z_device_usable_check(const struct device *dev)
{
    return z_device_ready(dev) ? 0 : -ENODEV;
}

/** @brief Determine whether a device is ready for use.
 *
 * This checks whether a device can be used, returning 0 if it can, and
 * distinct error values that identify the reason if it cannot.
 *
 * @retval 0 if the device is usable.
 * @retval -ENODEV if the device has not been initialized, the device pointer
 * is NULL or the initialization failed.
 * @retval other negative error codes to indicate additional conditions that
 * make the device unusable.
 */
__syscall int device_usable_check(const struct device *dev);

static inline int z_impl_device_usable_check(const struct device *dev)
{
    return z_device_usable_check(dev);
}

/** @brief Verify that a device is ready for use.
 *
 * Indicates whether the provided device pointer is for a device known to be
 * in a state where it can be used with its standard API.
 *
 * This can be used with device pointers captured from DEVICE_DT_GET(), which
 * does not include the readiness checks of device_get_binding(). At minimum
 * this means that the device has been successfully initialized, but it may
 * take on further conditions (e.g. is not powered down).
 *
 * @param dev pointer to the device in question.
 *
 * @retval true if the device is ready for use.
 * @retval false if the device is not ready for use or if a NULL device pointer
 * is passed as argument.
 */
static inline bool device_is_ready(const struct device *dev)
{
    return device_usable_check(dev) == 0;
}

/**
 * @}
 */

/* Node paths can exceed the maximum size supported by device_get_binding() in user mode,
 * so synthesize a unique dev_name from the devicetree node.
 *
 * The ordinal used in this name can be mapped to the path by
 * examining zephyr/include/generated/device_extern.h header. If the
 * format of this conversion changes, gen_defines should be updated to
 * match it.
 */
#define Z_DEVICE_DT_DEV_NAME(node_id) _CONCAT(dts_ord_, DT_DEP_ORD(node_id))

/* Synthesize a unique name for the device state associated with
 * dev_name.
 */
#define Z_DEVICE_STATE_NAME(dev_name) _CONCAT(__devstate_, dev_name)

/** Synthesize the name of the object that holds device ordinal and
 * dependency data. If the object doesn't come from a devicetree
 * node, use dev_name.
 */
#define Z_DEVICE_HANDLE_NAME(node_id, dev_name)				\
    _CONCAT(__devicehdl_,						\
        COND_CODE_1(DT_NODE_EXISTS(node_id),			\
                (node_id),					\
                (dev_name)))

#define Z_DEVICE_EXTRA_HANDLES(...)				\
    FOR_EACH_NONEMPTY_TERM(IDENTITY, (,), __VA_ARGS__)

#ifdef CONFIG_PM_DEVICE
#define Z_DEVICE_STATE_PM_INIT(node_id, dev_name)			\
    .pm = Z_PM_DEVICE_INIT(Z_DEVICE_STATE_NAME(dev_name).pm, node_id),
#else
#define Z_DEVICE_STATE_PM_INIT(node_id, dev_name)
#endif

/**
 * @brief Utility macro to define and initialize the device state.

 * @param node_id Devicetree node id of the device.
 * @param dev_name Device name.
 */
#define Z_DEVICE_STATE_DEFINE(node_id, dev_name)			\
    static struct device_state Z_DEVICE_STATE_NAME(dev_name)	\
    __attribute__((__section__(".z_devstate"))) = {			\
        Z_DEVICE_STATE_PM_INIT(node_id, dev_name)		\
    };

/* If device power management is enabled, this macro defines a pointer to a
 * device in the z_pm_device_slots region. When invoked for each device, this
 * will effectively result in a device pointer array with the same size of the
 * actual devices list. This is used internally by the device PM subsystem to
 * keep track of suspended devices during system power transitions.
 */
#if CONFIG_PM_DEVICE
#define Z_DEVICE_DEFINE_PM_SLOT(dev_name)				\
    static const Z_DECL_ALIGN(struct device *)			\
    _CONCAT(__pm_device_slot_, DEVICE_NAME_GET(dev_name)) __used	\
    __attribute__((__section__(".z_pm_device_slots")));
#else
#define Z_DEVICE_DEFINE_PM_SLOT(dev_name)
#endif

/* Construct objects that are referenced from struct device. These
 * include power management and dependency handles.
 */
#define Z_DEVICE_DEFINE_PRE(node_id, dev_name, ...)			\
    Z_DEVICE_STATE_DEFINE(node_id, dev_name)			\
    Z_DEVICE_DEFINE_PM_SLOT(dev_name)

/* Helper macros needed for CONFIG_DEVICE_HANDLE_PADDING. These should
 * be deleted when that option is removed.
 *
 * This is implemented "by hand" -- rather than using a helper macro
 * like UTIL_LISTIFY() -- because we need to allow users to wrap
 * DEVICE_DT_DEFINE with UTIL_LISTIFY, like this:
 *
 *     #define DEFINE_FOO_DEVICE(...) DEVICE_DT_DEFINE(...)
 *     UTIL_LISTIFY(N, DEFINE_FOO_DEVICE)
 *
 * If Z_DEVICE_HANDLE_PADDING uses UTIL_LISTIFY, this type of code
 * would fail, because the UTIL_LISTIFY token within the
 * Z_DEVICE_DEFINE_HANDLES expansion would not be expanded again,
 * since it appears in a context where UTIL_LISTIFY is already being
 * expanded. Standard C does not reexpand macros appearing in their
 * own expansion; this would lead to infinite recursions in general.
 */
#define Z_DEVICE_HANDLE_PADDING \
    Z_DEVICE_HANDLE_PADDING_(CONFIG_DEVICE_HANDLE_PADDING)
#define Z_DEVICE_HANDLE_PADDING_(count) \
    Z_DEVICE_HANDLE_PADDING__(count)
#define Z_DEVICE_HANDLE_PADDING__(count) \
    Z_DEVICE_HANDLE_PADDING_ ## count
#define Z_DEVICE_HANDLE_PADDING_10 \
    DEVICE_HANDLE_ENDS, Z_DEVICE_HANDLE_PADDING_9
#define Z_DEVICE_HANDLE_PADDING_9 \
    DEVICE_HANDLE_ENDS, Z_DEVICE_HANDLE_PADDING_8
#define Z_DEVICE_HANDLE_PADDING_8 \
    DEVICE_HANDLE_ENDS, Z_DEVICE_HANDLE_PADDING_7
#define Z_DEVICE_HANDLE_PADDING_7 \
    DEVICE_HANDLE_ENDS, Z_DEVICE_HANDLE_PADDING_6
#define Z_DEVICE_HANDLE_PADDING_6 \
    DEVICE_HANDLE_ENDS, Z_DEVICE_HANDLE_PADDING_5
#define Z_DEVICE_HANDLE_PADDING_5 \
    DEVICE_HANDLE_ENDS, Z_DEVICE_HANDLE_PADDING_4
#define Z_DEVICE_HANDLE_PADDING_4 \
    DEVICE_HANDLE_ENDS, Z_DEVICE_HANDLE_PADDING_3
#define Z_DEVICE_HANDLE_PADDING_3 \
    DEVICE_HANDLE_ENDS, Z_DEVICE_HANDLE_PADDING_2
#define Z_DEVICE_HANDLE_PADDING_2 \
    DEVICE_HANDLE_ENDS, Z_DEVICE_HANDLE_PADDING_1
#define Z_DEVICE_HANDLE_PADDING_1 \
    DEVICE_HANDLE_ENDS, Z_DEVICE_HANDLE_PADDING_0
#define Z_DEVICE_HANDLE_PADDING_0 EMPTY


#ifdef CONFIG_PM_DEVICE
#define Z_DEVICE_DEFINE_PM_INIT(dev_name, pm_control_fn)		\
    .pm_control = (pm_control_fn),					\
    .pm = &Z_DEVICE_STATE_NAME(dev_name).pm,
#else
#define Z_DEVICE_DEFINE_PM_INIT(dev_name, pm_control_fn)
#endif

#define Z_DEVICE_DEFINE_INIT(node_id, dev_name, pm_control_fn)		\
        Z_DEVICE_DEFINE_PM_INIT(dev_name, pm_control_fn)
/* Like DEVICE_DEFINE but takes a node_id AND a dev_name, and trailing
 * dependency handles that come from outside devicetree.
 */
#define Z_DEVICE_DEFINE(node_id, dev_name, drv_name, init_fn, pm_control_fn, \
            data_ptr, cfg_ptr, level, prio, api_ptr, ...)	\
    Z_DEVICE_DEFINE_PRE(node_id, dev_name, __VA_ARGS__)		\
    COND_CODE_1(DT_NODE_EXISTS(node_id), (), (static))		\
        const Z_DECL_ALIGN(struct device)			\
        DEVICE_NAME_GET(dev_name) __used			\
    __attribute__((__section__(".z_device_" #level STRINGIFY(prio)"_"))) = { \
        .name = drv_name,					\
        .config = (cfg_ptr),					\
        .api = (api_ptr),					\
        .state = &Z_DEVICE_STATE_NAME(dev_name),		\
        .data = (data_ptr),					\
        Z_DEVICE_DEFINE_INIT(node_id, dev_name, pm_control_fn)	\
    };								\
    BUILD_ASSERT(sizeof(Z_STRINGIFY(drv_name)) <= Z_DEVICE_MAX_NAME_LEN, \
             Z_STRINGIFY(DEVICE_NAME_GET(drv_name)) " too long"); \
    Z_INIT_ENTRY_DEFINE(DEVICE_NAME_GET(dev_name), init_fn,		\
        (&DEVICE_NAME_GET(dev_name)), level, prio)

#ifdef __cplusplus
}
#endif

/* device_extern is generated based on devicetree nodes */
#include <device_extern.h>

#include <syscalls/device.h>

#endif /* ZEPHYR_INCLUDE_DEVICE_H_ */
