Just like for the old driver, for simulation, we cannot get the UART regiter address for the pinctrl config structure from DT, as that cannot match the one allocated at build time. So let's override it at runtime with the correct address which is stored in the UART config structure. Also, do improve the condition for the busy wait during the poll_out, for simulation, so we only busy wait if we will loop/the Tx was busy. Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
1038 lines
30 KiB
C
1038 lines
30 KiB
C
/*
|
|
* Copyright (c) 2023 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* @brief Driver for Nordic Semiconductor nRF UARTE
|
|
*/
|
|
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/sys/util.h>
|
|
#include <zephyr/irq.h>
|
|
#include <zephyr/drivers/uart.h>
|
|
#include <zephyr/drivers/serial/uart_async_to_irq.h>
|
|
#include <zephyr/pm/device.h>
|
|
#include <zephyr/drivers/pinctrl.h>
|
|
#include <zephyr/linker/devicetree_regions.h>
|
|
#include <zephyr/logging/log.h>
|
|
#include <soc.h>
|
|
#include <nrfx_uarte.h>
|
|
#include <helpers/nrfx_gppi.h>
|
|
#include <haly/nrfy_uarte.h>
|
|
#define LOG_MODULE_NAME uarte
|
|
LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_UART_LOG_LEVEL);
|
|
|
|
#define INSTANCE_INT_DRIVEN(periph, prefix, i, _) \
|
|
IS_ENABLED(CONFIG_UART_##prefix##i##_INTERRUPT_DRIVEN)
|
|
|
|
#define INSTANCE_ASYNC(periph, prefix, i, _) \
|
|
IS_ENABLED(CONFIG_UART_##prefix##i##_ASYNC)
|
|
|
|
#define INSTANCE_POLLING(periph, prefix, id, _) \
|
|
UTIL_AND(CONFIG_HAS_HW_NRF_UARTE##prefix##id, \
|
|
UTIL_AND(COND_CODE_1(CONFIG_UART_##prefix##id##_INTERRUPT_DRIVEN, (0), (1)), \
|
|
COND_CODE_1(CONFIG_UART_##prefix##id##_ASYNC, (0), (1))))
|
|
|
|
#define INSTANCE_ENHANCED_POLL_OUT(periph, prefix, i, _) \
|
|
IS_ENABLED(CONFIG_UART_##prefix##i##_ENHANCED_POLL_OUT)
|
|
|
|
/* Macro determining if any instance is using interrupt driven API. */
|
|
#if (NRFX_FOREACH_ENABLED(UARTE, INSTANCE_INT_DRIVEN, (+), (0), _))
|
|
#define UARTE_ANY_INTERRUPT_DRIVEN 1
|
|
#else
|
|
#define UARTE_ANY_INTERRUPT_DRIVEN 0
|
|
#endif
|
|
|
|
/* Macro determining if any instance is enabled and using ASYNC API. */
|
|
#if (NRFX_FOREACH_ENABLED(UARTE, INSTANCE_ASYNC, (+), (0), _))
|
|
#define UARTE_ANY_ASYNC 1
|
|
#else
|
|
#define UARTE_ANY_ASYNC 0
|
|
#endif
|
|
|
|
/* Macro determining if any instance is using only polling API. */
|
|
#if (NRFX_FOREACH_ENABLED(UARTE, INSTANCE_POLLING, (+), (0), _))
|
|
#define UARTE_ANY_POLLING 1
|
|
#else
|
|
#define UARTE_ANY_POLLING 0
|
|
#endif
|
|
|
|
/* Macro determining if any instance is using interrupt driven API. */
|
|
#if (NRFX_FOREACH_ENABLED(UARTE, INSTANCE_ENHANCED_POLL_OUT, (+), (0), _))
|
|
#define UARTE_ENHANCED_POLL_OUT 1
|
|
#else
|
|
#define UARTE_ENHANCED_POLL_OUT 0
|
|
#endif
|
|
|
|
#if UARTE_ANY_INTERRUPT_DRIVEN || UARTE_ANY_ASYNC
|
|
#define UARTE_INT_ASYNC 1
|
|
#else
|
|
#define UARTE_INT_ASYNC 0
|
|
#endif
|
|
|
|
#if defined(UARTE_CONFIG_PARITYTYPE_Msk)
|
|
#define UARTE_ODD_PARITY_ALLOWED 1
|
|
#else
|
|
#define UARTE_ODD_PARITY_ALLOWED 0
|
|
#endif
|
|
|
|
/*
|
|
* RX timeout is divided into time slabs, this define tells how many divisions
|
|
* should be made. More divisions - higher timeout accuracy and processor usage.
|
|
*/
|
|
#define RX_TIMEOUT_DIV 5
|
|
|
|
/* Macro for converting numerical baudrate to register value. It is convenient
|
|
* to use this approach because for constant input it can calculate nrf setting
|
|
* at compile time.
|
|
*/
|
|
#define NRF_BAUDRATE(baudrate) ((baudrate) == 300 ? 0x00014000 :\
|
|
(baudrate) == 600 ? 0x00027000 : \
|
|
(baudrate) == 1200 ? NRF_UARTE_BAUDRATE_1200 : \
|
|
(baudrate) == 2400 ? NRF_UARTE_BAUDRATE_2400 : \
|
|
(baudrate) == 4800 ? NRF_UARTE_BAUDRATE_4800 : \
|
|
(baudrate) == 9600 ? NRF_UARTE_BAUDRATE_9600 : \
|
|
(baudrate) == 14400 ? NRF_UARTE_BAUDRATE_14400 : \
|
|
(baudrate) == 19200 ? NRF_UARTE_BAUDRATE_19200 : \
|
|
(baudrate) == 28800 ? NRF_UARTE_BAUDRATE_28800 : \
|
|
(baudrate) == 31250 ? NRF_UARTE_BAUDRATE_31250 : \
|
|
(baudrate) == 38400 ? NRF_UARTE_BAUDRATE_38400 : \
|
|
(baudrate) == 56000 ? NRF_UARTE_BAUDRATE_56000 : \
|
|
(baudrate) == 57600 ? NRF_UARTE_BAUDRATE_57600 : \
|
|
(baudrate) == 76800 ? NRF_UARTE_BAUDRATE_76800 : \
|
|
(baudrate) == 115200 ? NRF_UARTE_BAUDRATE_115200 : \
|
|
(baudrate) == 230400 ? NRF_UARTE_BAUDRATE_230400 : \
|
|
(baudrate) == 250000 ? NRF_UARTE_BAUDRATE_250000 : \
|
|
(baudrate) == 460800 ? NRF_UARTE_BAUDRATE_460800 : \
|
|
(baudrate) == 921600 ? NRF_UARTE_BAUDRATE_921600 : \
|
|
(baudrate) == 1000000 ? NRF_UARTE_BAUDRATE_1000000 : 0)
|
|
|
|
#define UARTE_DATA_FLAG_TRAMPOLINE BIT(0)
|
|
#define UARTE_DATA_FLAG_RX_ENABLED BIT(1)
|
|
|
|
struct uarte_async_data {
|
|
uart_callback_t user_callback;
|
|
void *user_data;
|
|
|
|
struct k_timer tx_timer;
|
|
struct k_timer rx_timer;
|
|
|
|
k_timeout_t rx_timeout;
|
|
|
|
/* Keeps the most recent error mask. */
|
|
uint32_t err;
|
|
|
|
uint8_t idle_cnt;
|
|
};
|
|
|
|
/* Device data structure */
|
|
struct uarte_nrfx_data {
|
|
struct uart_async_to_irq_data *a2i_data;
|
|
#if CONFIG_UART_USE_RUNTIME_CONFIGURE
|
|
struct uart_config uart_config;
|
|
#endif
|
|
struct uarte_async_data *async;
|
|
atomic_t flags;
|
|
uint8_t rx_byte;
|
|
};
|
|
BUILD_ASSERT(offsetof(struct uarte_nrfx_data, a2i_data) == 0);
|
|
|
|
/* If set then pins are managed when going to low power mode. */
|
|
#define UARTE_CFG_FLAG_GPIO_MGMT BIT(0)
|
|
|
|
/* If set then receiver is not used. */
|
|
#define UARTE_CFG_FLAG_NO_RX BIT(1)
|
|
|
|
/* If set then instance is using interrupt driven API. */
|
|
#define UARTE_CFG_FLAG_INTERRUPT_DRIVEN_API BIT(2)
|
|
|
|
/**
|
|
* @brief Structure for UARTE configuration.
|
|
*/
|
|
struct uarte_nrfx_config {
|
|
const struct uart_async_to_irq_config *a2i_config;
|
|
nrfx_uarte_t nrfx_dev;
|
|
nrfx_uarte_config_t nrfx_config;
|
|
const struct pinctrl_dev_config *pcfg;
|
|
uint32_t flags;
|
|
|
|
LOG_INSTANCE_PTR_DECLARE(log);
|
|
};
|
|
BUILD_ASSERT(offsetof(struct uarte_nrfx_config, a2i_config) == 0);
|
|
|
|
#define UARTE_ERROR_FROM_MASK(mask) \
|
|
((mask) & NRF_UARTE_ERROR_OVERRUN_MASK ? UART_ERROR_OVERRUN \
|
|
: (mask) & NRF_UARTE_ERROR_PARITY_MASK ? UART_ERROR_PARITY \
|
|
: (mask) & NRF_UARTE_ERROR_FRAMING_MASK ? UART_ERROR_FRAMING \
|
|
: (mask) & NRF_UARTE_ERROR_BREAK_MASK ? UART_BREAK \
|
|
: 0)
|
|
|
|
/* Determine if the device has interrupt driven API enabled. */
|
|
#define IS_INT_DRIVEN_API(dev) \
|
|
(UARTE_ANY_INTERRUPT_DRIVEN && \
|
|
(((const struct uarte_nrfx_config *)dev->config)->flags & \
|
|
UARTE_CFG_FLAG_INTERRUPT_DRIVEN_API))
|
|
|
|
/* Determine if the device supports only polling API. */
|
|
#define IS_POLLING_API(dev) \
|
|
(!UARTE_INT_ASYNC || (((struct uarte_nrfx_data *)dev->data)->async == NULL))
|
|
|
|
/* Determine if the device supports asynchronous API. */
|
|
#define IS_ASYNC_API(dev) (!IS_INT_DRIVEN_API(dev) && !IS_POLLING_API(dev))
|
|
|
|
static inline const nrfx_uarte_t *get_nrfx_dev(const struct device *dev)
|
|
{
|
|
const struct uarte_nrfx_config *config = dev->config;
|
|
|
|
return &config->nrfx_dev;
|
|
}
|
|
|
|
static int callback_set(const struct device *dev, uart_callback_t callback, void *user_data)
|
|
{
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
|
|
data->async->user_callback = callback;
|
|
data->async->user_data = user_data;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if UARTE_ANY_ASYNC
|
|
static int api_callback_set(const struct device *dev, uart_callback_t callback, void *user_data)
|
|
{
|
|
if (!IS_ASYNC_API(dev)) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return callback_set(dev, callback, user_data);
|
|
}
|
|
#endif
|
|
|
|
static void on_tx_done(const struct device *dev, const nrfx_uarte_event_t *event)
|
|
{
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
struct uart_event evt = {
|
|
.type = (event->data.tx.flags & NRFX_UARTE_TX_DONE_ABORTED) ?
|
|
UART_TX_ABORTED : UART_TX_DONE,
|
|
.data.tx.buf = event->data.tx.p_buffer,
|
|
.data.tx.len = event->data.tx.length
|
|
};
|
|
bool hwfc;
|
|
|
|
#if CONFIG_UART_USE_RUNTIME_CONFIGURE
|
|
hwfc = data->uart_config.flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS;
|
|
#else
|
|
const struct uarte_nrfx_config *config = dev->config;
|
|
|
|
hwfc = config->nrfx_config.config.hwfc == NRF_UARTE_HWFC_ENABLED;
|
|
#endif
|
|
|
|
if (hwfc) {
|
|
k_timer_stop(&data->async->tx_timer);
|
|
}
|
|
data->async->user_callback(dev, &evt, data->async->user_data);
|
|
}
|
|
|
|
static void on_rx_done(const struct device *dev, const nrfx_uarte_event_t *event)
|
|
{
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
struct uart_event evt;
|
|
|
|
if (event->data.rx.length) {
|
|
if (data->async->err) {
|
|
evt.type = UART_RX_STOPPED;
|
|
evt.data.rx_stop.reason = UARTE_ERROR_FROM_MASK(data->async->err);
|
|
evt.data.rx_stop.data.buf = event->data.rx.p_buffer;
|
|
evt.data.rx_stop.data.len = event->data.rx.length;
|
|
/* Keep error code for uart_err_check(). */
|
|
if (!IS_INT_DRIVEN_API(dev)) {
|
|
data->async->err = 0;
|
|
}
|
|
} else {
|
|
evt.type = UART_RX_RDY,
|
|
evt.data.rx.buf = event->data.rx.p_buffer,
|
|
evt.data.rx.len = event->data.rx.length,
|
|
evt.data.rx.offset = 0;
|
|
}
|
|
data->async->user_callback(dev, &evt, data->async->user_data);
|
|
}
|
|
|
|
evt.type = UART_RX_BUF_RELEASED;
|
|
evt.data.rx_buf.buf = event->data.rx.p_buffer;
|
|
|
|
data->async->user_callback(dev, &evt, data->async->user_data);
|
|
}
|
|
|
|
static void start_rx_timer(struct uarte_nrfx_data *data)
|
|
{
|
|
struct uarte_async_data *adata = data->async;
|
|
|
|
k_timer_start(&adata->rx_timer, adata->rx_timeout, K_NO_WAIT);
|
|
}
|
|
|
|
static void on_rx_byte(const struct device *dev)
|
|
{
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
struct uarte_async_data *adata = data->async;
|
|
const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev);
|
|
|
|
nrfx_uarte_rxdrdy_disable(nrfx_dev);
|
|
adata->idle_cnt = RX_TIMEOUT_DIV;
|
|
start_rx_timer(data);
|
|
}
|
|
|
|
static void on_rx_buf_req(const struct device *dev)
|
|
{
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
struct uarte_async_data *adata = data->async;
|
|
const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev);
|
|
|
|
struct uart_event evt = {
|
|
.type = UART_RX_BUF_REQUEST
|
|
};
|
|
|
|
/* If counter reached zero that indicates that timeout was reached and
|
|
* reception of one buffer was terminated to restart another transfer.
|
|
*/
|
|
if (!K_TIMEOUT_EQ(adata->rx_timeout, K_NO_WAIT)) {
|
|
/* Read and clear any pending new data information. */
|
|
nrfx_uarte_rx_new_data_check(nrfx_dev);
|
|
nrfx_uarte_rxdrdy_enable(nrfx_dev);
|
|
}
|
|
data->async->user_callback(dev, &evt, data->async->user_data);
|
|
}
|
|
|
|
static void on_rx_disabled(const struct device *dev, struct uarte_nrfx_data *data)
|
|
{
|
|
struct uart_event evt = {
|
|
.type = UART_RX_DISABLED
|
|
};
|
|
|
|
atomic_and(&data->flags, ~UARTE_DATA_FLAG_RX_ENABLED);
|
|
k_timer_stop(&data->async->rx_timer);
|
|
|
|
data->async->user_callback(dev, &evt, data->async->user_data);
|
|
}
|
|
|
|
static void trigger_handler(const struct device *dev)
|
|
{
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
|
|
if (UARTE_ANY_INTERRUPT_DRIVEN &&
|
|
atomic_and(&data->flags, ~UARTE_DATA_FLAG_TRAMPOLINE) &
|
|
UARTE_DATA_FLAG_TRAMPOLINE) {
|
|
uart_async_to_irq_trampoline_cb(dev);
|
|
}
|
|
}
|
|
|
|
static void evt_handler(nrfx_uarte_event_t const *event, void *context)
|
|
{
|
|
const struct device *dev = context;
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
|
|
switch (event->type) {
|
|
case NRFX_UARTE_EVT_TX_DONE:
|
|
on_tx_done(dev, event);
|
|
break;
|
|
case NRFX_UARTE_EVT_RX_DONE:
|
|
on_rx_done(dev, event);
|
|
break;
|
|
case NRFX_UARTE_EVT_RX_BYTE:
|
|
on_rx_byte(dev);
|
|
break;
|
|
case NRFX_UARTE_EVT_ERROR:
|
|
data->async->err = event->data.error.error_mask;
|
|
break;
|
|
case NRFX_UARTE_EVT_RX_BUF_REQUEST:
|
|
on_rx_buf_req(dev);
|
|
break;
|
|
case NRFX_UARTE_EVT_RX_DISABLED:
|
|
on_rx_disabled(dev, data);
|
|
break;
|
|
case NRFX_UARTE_EVT_RX_BUF_TOO_LATE:
|
|
/* No support */
|
|
break;
|
|
case NRFX_UARTE_EVT_TRIGGER:
|
|
trigger_handler(dev);
|
|
break;
|
|
default:
|
|
__ASSERT_NO_MSG(0);
|
|
}
|
|
}
|
|
|
|
static int api_tx(const struct device *dev, const uint8_t *buf, size_t len, int32_t timeout)
|
|
{
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev);
|
|
nrfx_err_t err;
|
|
bool hwfc;
|
|
|
|
#if CONFIG_UART_USE_RUNTIME_CONFIGURE
|
|
hwfc = data->uart_config.flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS;
|
|
#else
|
|
const struct uarte_nrfx_config *config = dev->config;
|
|
|
|
hwfc = config->nrfx_config.config.hwfc == NRF_UARTE_HWFC_ENABLED;
|
|
#endif
|
|
|
|
err = nrfx_uarte_tx(nrfx_dev, buf, len, 0);
|
|
if (err != NRFX_SUCCESS) {
|
|
return (err == NRFX_ERROR_BUSY) ? -EBUSY : -EIO;
|
|
}
|
|
|
|
if (hwfc && timeout != SYS_FOREVER_US) {
|
|
k_timer_start(&data->async->tx_timer, K_USEC(timeout), K_NO_WAIT);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int api_tx_abort(const struct device *dev)
|
|
{
|
|
const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev);
|
|
nrfx_err_t err;
|
|
|
|
err = nrfx_uarte_tx_abort(nrfx_dev, false);
|
|
return (err == NRFX_SUCCESS) ? 0 : -EFAULT;
|
|
}
|
|
|
|
static void tx_timeout_handler(struct k_timer *timer)
|
|
{
|
|
const struct device *dev = k_timer_user_data_get(timer);
|
|
|
|
(void)api_tx_abort(dev);
|
|
}
|
|
|
|
static void rx_timeout_handler(struct k_timer *timer)
|
|
{
|
|
const struct device *dev = (const struct device *)k_timer_user_data_get(timer);
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
struct uarte_async_data *adata = data->async;
|
|
const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev);
|
|
|
|
if (nrfx_uarte_rx_new_data_check(nrfx_dev)) {
|
|
adata->idle_cnt = RX_TIMEOUT_DIV - 1;
|
|
} else {
|
|
adata->idle_cnt--;
|
|
if (adata->idle_cnt == 0) {
|
|
(void)nrfx_uarte_rx_abort(nrfx_dev, false, false);
|
|
return;
|
|
}
|
|
}
|
|
|
|
start_rx_timer(data);
|
|
}
|
|
|
|
/* Determine if RX FIFO content shall be kept when device is being disabled.
|
|
* When flow-control is used then we expect to keep RX FIFO content since HWFC
|
|
* enforces lossless communication. However, when HWFC is not used (by any instance
|
|
* then RX FIFO handling feature is disabled in the nrfx_uarte to save space.
|
|
* It is based on assumption that without HWFC it is expected that some data may
|
|
* be lost and there are means to prevent that (keeping receiver always opened by
|
|
* provided reception buffers on time).
|
|
*/
|
|
static inline uint32_t get_keep_fifo_content_flag(const struct device *dev)
|
|
{
|
|
#if CONFIG_UART_USE_RUNTIME_CONFIGURE
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
|
|
if (data->uart_config.flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS) {
|
|
return NRFX_UARTE_RX_ENABLE_KEEP_FIFO_CONTENT;
|
|
}
|
|
#else
|
|
const struct uarte_nrfx_config *config = dev->config;
|
|
|
|
if (config->nrfx_config.config.hwfc == NRF_UARTE_HWFC_ENABLED) {
|
|
return NRFX_UARTE_RX_ENABLE_KEEP_FIFO_CONTENT;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int api_rx_enable(const struct device *dev, uint8_t *buf, size_t len, int32_t timeout)
|
|
{
|
|
nrfx_err_t err;
|
|
const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev);
|
|
const struct uarte_nrfx_config *cfg = dev->config;
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
struct uarte_async_data *adata = data->async;
|
|
uint32_t flags = NRFX_UARTE_RX_ENABLE_CONT |
|
|
get_keep_fifo_content_flag(dev) |
|
|
(IS_ASYNC_API(dev) ? NRFX_UARTE_RX_ENABLE_STOP_ON_END : 0);
|
|
|
|
if (cfg->flags & UARTE_CFG_FLAG_NO_RX) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
if (timeout != SYS_FOREVER_US) {
|
|
adata->idle_cnt = RX_TIMEOUT_DIV + 1;
|
|
adata->rx_timeout = K_USEC(timeout / RX_TIMEOUT_DIV);
|
|
} else {
|
|
adata->rx_timeout = K_NO_WAIT;
|
|
}
|
|
|
|
err = nrfx_uarte_rx_buffer_set(nrfx_dev, buf, len);
|
|
if (err != NRFX_SUCCESS) {
|
|
return -EIO;
|
|
}
|
|
|
|
err = nrfx_uarte_rx_enable(nrfx_dev, flags);
|
|
if (err != NRFX_SUCCESS) {
|
|
return (err == NRFX_ERROR_BUSY) ? -EBUSY : -EIO;
|
|
}
|
|
|
|
atomic_or(&data->flags, UARTE_DATA_FLAG_RX_ENABLED);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int api_rx_buf_rsp(const struct device *dev, uint8_t *buf, size_t len)
|
|
{
|
|
const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev);
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
nrfx_err_t err;
|
|
|
|
if (!(data->flags & UARTE_DATA_FLAG_RX_ENABLED)) {
|
|
return -EACCES;
|
|
}
|
|
|
|
err = nrfx_uarte_rx_buffer_set(nrfx_dev, buf, len);
|
|
switch (err) {
|
|
case NRFX_SUCCESS:
|
|
return 0;
|
|
case NRFX_ERROR_BUSY:
|
|
return -EBUSY;
|
|
default:
|
|
return -EIO;
|
|
}
|
|
}
|
|
|
|
static int api_rx_disable(const struct device *dev)
|
|
{
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
|
|
k_timer_stop(&data->async->rx_timer);
|
|
|
|
return (nrfx_uarte_rx_abort(get_nrfx_dev(dev), true, false) == NRFX_SUCCESS) ? 0 : -EFAULT;
|
|
}
|
|
|
|
static int api_poll_in(const struct device *dev, unsigned char *c)
|
|
{
|
|
const struct uarte_nrfx_config *cfg = dev->config;
|
|
const nrfx_uarte_t *instance = &cfg->nrfx_dev;
|
|
nrfx_err_t err;
|
|
|
|
if (IS_INT_DRIVEN_API(dev)) {
|
|
return uart_fifo_read(dev, c, 1) == 0 ? -1 : 0;
|
|
}
|
|
|
|
if (IS_ASYNC_API(dev)) {
|
|
return -EBUSY;
|
|
}
|
|
|
|
err = nrfx_uarte_rx_ready(instance, NULL);
|
|
if (err == NRFX_SUCCESS) {
|
|
uint8_t *rx_byte = cfg->nrfx_config.rx_cache.p_buffer;
|
|
|
|
*c = *rx_byte;
|
|
err = nrfx_uarte_rx_buffer_set(instance, rx_byte, 1);
|
|
__ASSERT_NO_MSG(err == NRFX_SUCCESS);
|
|
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static void api_poll_out(const struct device *dev, unsigned char out_char)
|
|
{
|
|
const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev);
|
|
nrfx_err_t err;
|
|
|
|
do {
|
|
/* When runtime PM is used we cannot use early return because then
|
|
* we have no information when UART is actually done with the
|
|
* transmission. It reduces UART performance however, polling in
|
|
* general is not power efficient and should be avoided in low
|
|
* power applications.
|
|
*/
|
|
err = nrfx_uarte_tx(nrfx_dev, &out_char, 1, NRFX_UARTE_TX_EARLY_RETURN);
|
|
__ASSERT(err != NRFX_ERROR_INVALID_ADDR, "Invalid address of the buffer");
|
|
|
|
if (err == NRFX_ERROR_BUSY) {
|
|
if (IS_ENABLED(CONFIG_MULTITHREADING) && k_is_preempt_thread()) {
|
|
k_msleep(1);
|
|
} else {
|
|
Z_SPIN_DELAY(3);
|
|
}
|
|
}
|
|
} while (err == NRFX_ERROR_BUSY);
|
|
}
|
|
|
|
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
|
|
/**
|
|
* @brief Set the baud rate
|
|
*
|
|
* This routine set the given baud rate for the UARTE.
|
|
*
|
|
* @param dev UARTE device struct
|
|
* @param baudrate Baud rate
|
|
*
|
|
* @return 0 on success or error code
|
|
*/
|
|
static int baudrate_set(NRF_UARTE_Type *uarte, uint32_t baudrate)
|
|
{
|
|
nrf_uarte_baudrate_t nrf_baudrate = NRF_BAUDRATE(baudrate);
|
|
|
|
if (baudrate == 0) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
nrfy_uarte_baudrate_set(uarte, nrf_baudrate);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int uarte_nrfx_configure(const struct device *dev,
|
|
const struct uart_config *cfg)
|
|
{
|
|
const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev);
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
nrf_uarte_config_t uarte_cfg;
|
|
|
|
#if defined(UARTE_CONFIG_STOP_Msk)
|
|
switch (cfg->stop_bits) {
|
|
case UART_CFG_STOP_BITS_1:
|
|
uarte_cfg.stop = NRF_UARTE_STOP_ONE;
|
|
break;
|
|
case UART_CFG_STOP_BITS_2:
|
|
uarte_cfg.stop = NRF_UARTE_STOP_TWO;
|
|
break;
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
#else
|
|
if (cfg->stop_bits != UART_CFG_STOP_BITS_1) {
|
|
return -ENOTSUP;
|
|
}
|
|
#endif
|
|
|
|
if (cfg->data_bits != UART_CFG_DATA_BITS_8) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
switch (cfg->flow_ctrl) {
|
|
case UART_CFG_FLOW_CTRL_NONE:
|
|
uarte_cfg.hwfc = NRF_UARTE_HWFC_DISABLED;
|
|
break;
|
|
case UART_CFG_FLOW_CTRL_RTS_CTS:
|
|
uarte_cfg.hwfc = NRF_UARTE_HWFC_ENABLED;
|
|
break;
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
#if defined(UARTE_CONFIG_PARITYTYPE_Msk)
|
|
uarte_cfg.paritytype = NRF_UARTE_PARITYTYPE_EVEN;
|
|
#endif
|
|
switch (cfg->parity) {
|
|
case UART_CFG_PARITY_NONE:
|
|
uarte_cfg.parity = NRF_UARTE_PARITY_EXCLUDED;
|
|
break;
|
|
case UART_CFG_PARITY_EVEN:
|
|
uarte_cfg.parity = NRF_UARTE_PARITY_INCLUDED;
|
|
break;
|
|
#if defined(UARTE_CONFIG_PARITYTYPE_Msk)
|
|
case UART_CFG_PARITY_ODD:
|
|
uarte_cfg.parity = NRF_UARTE_PARITY_INCLUDED;
|
|
uarte_cfg.paritytype = NRF_UARTE_PARITYTYPE_ODD;
|
|
break;
|
|
#endif
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
if (baudrate_set(nrfx_dev->p_reg, cfg->baudrate) != 0) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
nrfy_uarte_configure(nrfx_dev->p_reg, &uarte_cfg);
|
|
|
|
data->uart_config = *cfg;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int uarte_nrfx_config_get(const struct device *dev,
|
|
struct uart_config *cfg)
|
|
{
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
|
|
*cfg = data->uart_config;
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
|
|
|
|
#if UARTE_ANY_POLLING || UARTE_ANY_INTERRUPT_DRIVEN
|
|
static int api_err_check(const struct device *dev)
|
|
{
|
|
if (IS_POLLING_API(dev)) {
|
|
const struct uarte_nrfx_config *cfg = dev->config;
|
|
const nrfx_uarte_t *instance = &cfg->nrfx_dev;
|
|
uint32_t mask = nrfx_uarte_errorsrc_get(instance);
|
|
|
|
return mask;
|
|
}
|
|
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
uint32_t rv = data->async->err;
|
|
|
|
data->async->err = 0;
|
|
|
|
return rv;
|
|
}
|
|
#endif
|
|
|
|
static const struct uart_async_to_irq_async_api a2i_api = {
|
|
.callback_set = callback_set,
|
|
.tx = api_tx,
|
|
.tx_abort = api_tx_abort,
|
|
.rx_enable = api_rx_enable,
|
|
.rx_buf_rsp = api_rx_buf_rsp,
|
|
.rx_disable = api_rx_disable,
|
|
};
|
|
|
|
static const struct uart_driver_api uart_nrfx_uarte_driver_api = {
|
|
.poll_in = api_poll_in,
|
|
.poll_out = api_poll_out,
|
|
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
|
|
.configure = uarte_nrfx_configure,
|
|
.config_get = uarte_nrfx_config_get,
|
|
#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
|
|
#if UARTE_ANY_POLLING || UARTE_ANY_INTERRUPT_DRIVEN
|
|
.err_check = api_err_check,
|
|
#endif
|
|
#if UARTE_ANY_ASYNC
|
|
.callback_set = api_callback_set,
|
|
.tx = api_tx,
|
|
.tx_abort = api_tx_abort,
|
|
.rx_enable = api_rx_enable,
|
|
.rx_buf_rsp = api_rx_buf_rsp,
|
|
.rx_disable = api_rx_disable,
|
|
#endif /* UARTE_ANY_ASYNC */
|
|
#if UARTE_ANY_INTERRUPT_DRIVEN
|
|
UART_ASYNC_TO_IRQ_API_INIT(),
|
|
#endif /* UARTE_ANY_INTERRUPT_DRIVEN */
|
|
};
|
|
|
|
static int endtx_stoptx_ppi_init(NRF_UARTE_Type *uarte)
|
|
{
|
|
nrfx_err_t ret;
|
|
uint8_t ch;
|
|
|
|
ret = nrfx_gppi_channel_alloc(&ch);
|
|
if (ret != NRFX_SUCCESS) {
|
|
LOG_ERR("Failed to allocate PPI Channel");
|
|
return -EIO;
|
|
}
|
|
|
|
nrfx_gppi_channel_endpoints_setup(ch,
|
|
nrfy_uarte_event_address_get(uarte, NRF_UARTE_EVENT_ENDTX),
|
|
nrfy_uarte_task_address_get(uarte, NRF_UARTE_TASK_STOPTX));
|
|
nrfx_gppi_channels_enable(BIT(ch));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int start_rx(const struct device *dev)
|
|
{
|
|
const struct uarte_nrfx_config *cfg = dev->config;
|
|
|
|
if (IS_INT_DRIVEN_API(dev)) {
|
|
return uart_async_to_irq_rx_enable(dev);
|
|
}
|
|
|
|
__ASSERT_NO_MSG(IS_POLLING_API(dev));
|
|
|
|
nrfx_err_t err;
|
|
const nrfx_uarte_t *instance = &cfg->nrfx_dev;
|
|
uint8_t *rx_byte = cfg->nrfx_config.rx_cache.p_buffer;
|
|
|
|
err = nrfx_uarte_rx_buffer_set(instance, rx_byte, 1);
|
|
__ASSERT_NO_MSG(err == NRFX_SUCCESS);
|
|
|
|
err = nrfx_uarte_rx_enable(instance, 0);
|
|
__ASSERT_NO_MSG(err == NRFX_SUCCESS || err == NRFX_ERROR_BUSY);
|
|
|
|
(void)err;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void async_to_irq_trampoline(const struct device *dev)
|
|
{
|
|
const struct uarte_nrfx_config *cfg = dev->config;
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
uint32_t prev = atomic_or(&data->flags, UARTE_DATA_FLAG_TRAMPOLINE);
|
|
|
|
if (!(prev & UARTE_DATA_FLAG_TRAMPOLINE)) {
|
|
nrfx_uarte_int_trigger(&cfg->nrfx_dev);
|
|
}
|
|
}
|
|
|
|
static int uarte_nrfx_init(const struct device *dev)
|
|
{
|
|
int err;
|
|
nrfx_err_t nerr;
|
|
const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev);
|
|
const struct uarte_nrfx_config *cfg = dev->config;
|
|
struct uarte_nrfx_data *data = dev->data;
|
|
|
|
#ifdef CONFIG_ARCH_POSIX
|
|
/* For simulation the DT provided peripheral address needs to be corrected */
|
|
((struct pinctrl_dev_config *)cfg->pcfg)->reg = (uintptr_t)nrfx_dev->p_reg;
|
|
#endif
|
|
|
|
err = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
|
|
if (err < 0) {
|
|
return err;
|
|
}
|
|
|
|
if (UARTE_ENHANCED_POLL_OUT && cfg->nrfx_config.tx_stop_on_end) {
|
|
err = endtx_stoptx_ppi_init(nrfx_dev->p_reg);
|
|
if (err < 0) {
|
|
return err;
|
|
}
|
|
}
|
|
|
|
if (UARTE_ANY_INTERRUPT_DRIVEN) {
|
|
if (cfg->a2i_config) {
|
|
err = uart_async_to_irq_init(data->a2i_data, cfg->a2i_config);
|
|
if (err < 0) {
|
|
return err;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IS_ENABLED(UARTE_INT_ASYNC) && data->async) {
|
|
k_timer_init(&data->async->rx_timer, rx_timeout_handler, NULL);
|
|
k_timer_user_data_set(&data->async->rx_timer, (void *)dev);
|
|
k_timer_init(&data->async->tx_timer, tx_timeout_handler, NULL);
|
|
k_timer_user_data_set(&data->async->tx_timer, (void *)dev);
|
|
}
|
|
|
|
nerr = nrfx_uarte_init(nrfx_dev, &cfg->nrfx_config,
|
|
IS_ENABLED(UARTE_INT_ASYNC) ?
|
|
(IS_POLLING_API(dev) ? NULL : evt_handler) : NULL);
|
|
if (nerr == NRFX_SUCCESS && !IS_ASYNC_API(dev) && !(cfg->flags & UARTE_CFG_FLAG_NO_RX)) {
|
|
err = start_rx(dev);
|
|
}
|
|
|
|
switch (nerr) {
|
|
case NRFX_ERROR_INVALID_STATE:
|
|
return -EBUSY;
|
|
case NRFX_ERROR_BUSY:
|
|
return -EACCES;
|
|
case NRFX_ERROR_INVALID_PARAM:
|
|
return -EINVAL;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_PM_DEVICE
|
|
static int stop_rx(const struct device *dev)
|
|
{
|
|
const struct uarte_nrfx_config *cfg = dev->config;
|
|
|
|
if (IS_INT_DRIVEN_API(dev)) {
|
|
return uart_async_to_irq_rx_disable(dev);
|
|
}
|
|
|
|
__ASSERT_NO_MSG(IS_POLLING_API(dev));
|
|
nrfx_err_t err;
|
|
const nrfx_uarte_t *instance = &cfg->nrfx_dev;
|
|
|
|
err = nrfx_uarte_rx_abort(instance, true, true);
|
|
__ASSERT_NO_MSG(err == NRFX_SUCCESS);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int uarte_nrfx_pm_action(const struct device *dev,
|
|
enum pm_device_action action)
|
|
{
|
|
const struct uarte_nrfx_config *cfg = dev->config;
|
|
int ret;
|
|
|
|
switch (action) {
|
|
case PM_DEVICE_ACTION_RESUME:
|
|
if (cfg->flags & UARTE_CFG_FLAG_GPIO_MGMT) {
|
|
ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
}
|
|
if (!IS_ASYNC_API(dev) && !(cfg->flags & UARTE_CFG_FLAG_NO_RX)) {
|
|
return start_rx(dev);
|
|
}
|
|
|
|
break;
|
|
case PM_DEVICE_ACTION_SUSPEND:
|
|
if (!IS_ASYNC_API(dev) && !(cfg->flags & UARTE_CFG_FLAG_NO_RX)) {
|
|
stop_rx(dev);
|
|
}
|
|
|
|
if (cfg->flags & UARTE_CFG_FLAG_GPIO_MGMT) {
|
|
ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_SLEEP);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
break;
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(UARTE_CONFIG_STOP_Msk)
|
|
#define UARTE_HAS_STOP_CONFIG 1
|
|
#endif
|
|
|
|
#define UARTE(idx) DT_NODELABEL(uart##idx)
|
|
#define UARTE_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(UARTE(idx), prop)
|
|
#define UARTE_PROP(idx, prop) DT_PROP(UARTE(idx), prop)
|
|
|
|
/* Macro returning initial log level. Logs are off for UART used for console. */
|
|
#define GET_INIT_LOG_LEVEL(idx) \
|
|
COND_CODE_1(DT_HAS_CHOSEN(zephyr_console), \
|
|
(DT_SAME_NODE(UARTE(idx), \
|
|
DT_CHOSEN(zephyr_console)) ? \
|
|
LOG_LEVEL_NONE : CONFIG_UART_LOG_LEVEL), \
|
|
(CONFIG_UART_LOG_LEVEL))
|
|
|
|
/* Macro puts buffers in dedicated section if device tree property is set. */
|
|
#define UARTE_MEMORY_SECTION(idx) \
|
|
COND_CODE_1(UARTE_HAS_PROP(idx, memory_regions), \
|
|
(__attribute__((__section__(LINKER_DT_NODE_REGION_NAME( \
|
|
DT_PHANDLE(UARTE(idx), memory_regions)))))), \
|
|
())
|
|
|
|
#define UART_NRF_UARTE_DEVICE(idx) \
|
|
LOG_INSTANCE_REGISTER(LOG_MODULE_NAME, idx, GET_INIT_LOG_LEVEL(idx)); \
|
|
static uint8_t uarte##idx##_tx_cache[CONFIG_UART_##idx##_TX_CACHE_SIZE] \
|
|
UARTE_MEMORY_SECTION(idx) __aligned(4); \
|
|
static uint8_t uarte##idx##_rx_cache[CONFIG_UART_##idx##_RX_CACHE_SIZE] \
|
|
UARTE_MEMORY_SECTION(idx) __aligned(4); \
|
|
static nrfx_uarte_rx_cache_t uarte##idx##_rx_cache_scratch; \
|
|
IF_ENABLED(CONFIG_UART_##idx##_INTERRUPT_DRIVEN, \
|
|
(static uint8_t a2i_rx_buf##idx[CONFIG_UART_##idx##_A2I_RX_SIZE];)) \
|
|
PINCTRL_DT_DEFINE(UARTE(idx)); \
|
|
static const struct uart_async_to_irq_config uarte_a2i_config_##idx = \
|
|
UART_ASYNC_TO_IRQ_API_CONFIG_INITIALIZER(&a2i_api, \
|
|
async_to_irq_trampoline, \
|
|
UARTE_PROP(idx, current_speed), \
|
|
uarte##idx##_tx_cache, \
|
|
/* nrfx_uarte driver is using the last byte in the */ \
|
|
/* cache buffer for keeping a byte that is currently*/\
|
|
/* polled out so it cannot be used as a cache buffer*/\
|
|
/* by the adaptation layer. */ \
|
|
sizeof(uarte##idx##_tx_cache) - 1, \
|
|
COND_CODE_1(CONFIG_UART_##idx##_INTERRUPT_DRIVEN, \
|
|
(a2i_rx_buf##idx), (NULL)), \
|
|
COND_CODE_1(CONFIG_UART_##idx##_INTERRUPT_DRIVEN, \
|
|
(sizeof(a2i_rx_buf##idx)), (0)), \
|
|
CONFIG_UART_##idx##_A2I_RX_BUF_COUNT, \
|
|
LOG_INSTANCE_PTR(LOG_MODULE_NAME, idx)); \
|
|
static const struct uarte_nrfx_config uarte_config_##idx = { \
|
|
.a2i_config = IS_ENABLED(CONFIG_UART_##idx## _INTERRUPT_DRIVEN) ? \
|
|
&uarte_a2i_config_##idx : NULL, \
|
|
.nrfx_dev = NRFX_UARTE_INSTANCE(idx), \
|
|
.nrfx_config = { \
|
|
.p_context = (void *)DEVICE_DT_GET(UARTE(idx)), \
|
|
.tx_cache = { \
|
|
.p_buffer = uarte##idx##_tx_cache, \
|
|
.length = CONFIG_UART_##idx##_TX_CACHE_SIZE \
|
|
}, \
|
|
.rx_cache = { \
|
|
.p_buffer = uarte##idx##_rx_cache, \
|
|
.length = CONFIG_UART_##idx##_RX_CACHE_SIZE \
|
|
}, \
|
|
.p_rx_cache_scratch = &uarte##idx##_rx_cache_scratch, \
|
|
.baudrate = NRF_BAUDRATE(UARTE_PROP(idx, current_speed)), \
|
|
.interrupt_priority = DT_IRQ(UARTE(idx), priority), \
|
|
.config = { \
|
|
.hwfc = (UARTE_PROP(idx, hw_flow_control) == \
|
|
UART_CFG_FLOW_CTRL_RTS_CTS) ? \
|
|
NRF_UARTE_HWFC_ENABLED : NRF_UARTE_HWFC_DISABLED, \
|
|
.parity = IS_ENABLED(CONFIG_UART_##idx##_NRF_PARITY_BIT) ? \
|
|
NRF_UARTE_PARITY_INCLUDED : NRF_UARTE_PARITY_EXCLUDED, \
|
|
IF_ENABLED(UARTE_HAS_STOP_CONFIG, (.stop = NRF_UARTE_STOP_ONE,))\
|
|
IF_ENABLED(UARTE_ODD_PARITY_ALLOWED, \
|
|
(.paritytype = NRF_UARTE_PARITYTYPE_EVEN,)) \
|
|
}, \
|
|
.tx_stop_on_end = IS_ENABLED(CONFIG_UART_##idx##_ENHANCED_POLL_OUT), \
|
|
.skip_psel_cfg = true, \
|
|
.skip_gpio_cfg = true, \
|
|
}, \
|
|
.pcfg = PINCTRL_DT_DEV_CONFIG_GET(UARTE(idx)), \
|
|
.flags = (UARTE_PROP(idx, disable_rx) ? UARTE_CFG_FLAG_NO_RX : 0) | \
|
|
(IS_ENABLED(CONFIG_UART_##idx##_GPIO_MANAGEMENT) ? \
|
|
UARTE_CFG_FLAG_GPIO_MGMT : 0) | \
|
|
(IS_ENABLED(CONFIG_UART_##idx##_INTERRUPT_DRIVEN) ? \
|
|
UARTE_CFG_FLAG_INTERRUPT_DRIVEN_API : 0), \
|
|
LOG_INSTANCE_PTR_INIT(log, LOG_MODULE_NAME, idx) \
|
|
}; \
|
|
static struct uart_async_to_irq_data uarte_a2i_data_##idx; \
|
|
static struct uarte_async_data uarte_async_##idx; \
|
|
static struct uarte_nrfx_data uarte_data_##idx = { \
|
|
.a2i_data = IS_ENABLED(CONFIG_UART_##idx##_INTERRUPT_DRIVEN) ? \
|
|
&uarte_a2i_data_##idx : NULL, \
|
|
IF_ENABLED(CONFIG_UART_USE_RUNTIME_CONFIGURE, \
|
|
(.uart_config = { \
|
|
.baudrate = UARTE_PROP(idx, current_speed), \
|
|
.parity = IS_ENABLED(CONFIG_UART_##idx##_NRF_PARITY_BIT) ? \
|
|
UART_CFG_PARITY_EVEN : UART_CFG_PARITY_NONE, \
|
|
.stop_bits = UART_CFG_STOP_BITS_1, \
|
|
.data_bits = UART_CFG_DATA_BITS_8, \
|
|
.flow_ctrl = UARTE_PROP(idx, hw_flow_control) ? \
|
|
UART_CFG_FLOW_CTRL_RTS_CTS : UART_CFG_FLOW_CTRL_NONE, \
|
|
},)) \
|
|
.async = (IS_ENABLED(CONFIG_UART_##idx##_INTERRUPT_DRIVEN) || \
|
|
IS_ENABLED(CONFIG_UART_##idx##_ASYNC)) ? &uarte_async_##idx : NULL \
|
|
}; \
|
|
static int uarte_init_##idx(const struct device *dev) \
|
|
{ \
|
|
COND_CODE_1(INSTANCE_POLLING(_, /*empty*/, idx, _), (), \
|
|
( \
|
|
IRQ_CONNECT(DT_IRQN(UARTE(idx)), DT_IRQ(UARTE(idx), priority), \
|
|
nrfx_isr, nrfx_uarte_##idx##_irq_handler, 0); \
|
|
irq_enable(DT_IRQN(UARTE(idx))); \
|
|
) \
|
|
) \
|
|
return uarte_nrfx_init(dev); \
|
|
} \
|
|
PM_DEVICE_DT_DEFINE(UARTE(idx), uarte_nrfx_pm_action); \
|
|
DEVICE_DT_DEFINE(UARTE(idx), \
|
|
uarte_init_##idx, \
|
|
PM_DEVICE_DT_GET(UARTE(idx)), \
|
|
&uarte_data_##idx, \
|
|
&uarte_config_##idx, \
|
|
PRE_KERNEL_1, \
|
|
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
|
|
&uart_nrfx_uarte_driver_api)
|
|
|
|
/* Macro creates device instance if it is enabled in devicetree. */
|
|
#define UARTE_DEVICE(periph, prefix, id, _) \
|
|
IF_ENABLED(CONFIG_HAS_HW_NRF_UARTE##prefix##id, (UART_NRF_UARTE_DEVICE(prefix##id);))
|
|
|
|
/* Macro iterates over nrfx_uarte instances enabled in the nrfx_config.h. */
|
|
NRFX_FOREACH_ENABLED(UARTE, UARTE_DEVICE, (), (), _)
|