You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by je...@apache.org on 2021/02/01 10:44:41 UTC

[mynewt-core] 01/02: hw/mcu/da1469x: Add UART driver

This is an automated email from the ASF dual-hosted git repository.

jerzy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit d4b7ca6682614697b7faf2ecd596bd2c92c0af07
Author: Jerzy Kasenberg <je...@codecoup.pl>
AuthorDate: Mon Dec 14 12:35:33 2020 +0100

    hw/mcu/da1469x: Add UART driver
    
    Driver that shuts down UART when RX line goes low to minimize
    power consumption.
---
 .../include/uart_da1469x/uart_da1469x.h            |  70 +++
 hw/drivers/uart/uart_da1469x/pkg.yml               |  28 +
 hw/drivers/uart/uart_da1469x/src/uart_da1469x.c    | 563 +++++++++++++++++++++
 hw/drivers/uart/uart_da1469x/syscfg.yml            |  25 +
 4 files changed, 686 insertions(+)

diff --git a/hw/drivers/uart/uart_da1469x/include/uart_da1469x/uart_da1469x.h b/hw/drivers/uart/uart_da1469x/include/uart_da1469x/uart_da1469x.h
new file mode 100644
index 0000000..7360207
--- /dev/null
+++ b/hw/drivers/uart/uart_da1469x/include/uart_da1469x/uart_da1469x.h
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef __DRIVERS_UART_DA1469X_H_
+#define __DRIVERS_UART_DA1469X_H_
+
+#include "uart/uart.h"
+#include "mcu/da1469x_hal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct da1469x_uart_hw_data;
+
+struct da1469x_uart_dev {
+    struct uart_dev dev;
+    /* Common UART parameters. */
+    struct uart_conf uc;
+    /* DA1469x specific configuration. */
+    struct da1469x_uart_cfg da1469x_cfg;
+
+    /* driver state data */
+    uint8_t active : 1;
+    uint8_t tx_started : 1;
+    uint8_t rx_started : 1;
+    uint8_t rx_stalled : 1;
+    uint8_t rx_data;
+
+    /* Callout used to re-enable UART after it RX pin went high. */
+    struct os_callout wakeup_callout;
+    /* Event raised from interrupt (busy/break) that will setup RX pin to GPIO with interrupt in task context. */
+    struct os_event setup_wakeup_event;
+    /* Hardware configuration, register addresses bit mask and such. */
+    const struct da1469x_uart_hw_data *hw;
+};
+
+/**
+ * Creates UART OS device
+ *
+ * @param dev - device structure to initialize
+ * @param name - device name (must end with character 0|1|2 like "uart0")
+ * @param priority - priority for os_dev_create
+ * @param da1469x_cfg - UART parameters
+ * @return 0 on success,
+ */
+int da1469x_uart_dev_create(struct da1469x_uart_dev *dev, const char *name, uint8_t priority,
+                            const struct da1469x_uart_cfg *da1469x_cfg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DRIVERS_UART_DA1469X_H_ */
diff --git a/hw/drivers/uart/uart_da1469x/pkg.yml b/hw/drivers/uart/uart_da1469x/pkg.yml
new file mode 100644
index 0000000..cd1a182
--- /dev/null
+++ b/hw/drivers/uart/uart_da1469x/pkg.yml
@@ -0,0 +1,28 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: hw/drivers/uart/uart_da1469x
+pkg.description: UART driver for DA1469X
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+pkg.apis:
+pkg.deps:
+    - "@apache-mynewt-core/hw/hal"
+    - "@apache-mynewt-core/hw/drivers/uart"
diff --git a/hw/drivers/uart/uart_da1469x/src/uart_da1469x.c b/hw/drivers/uart/uart_da1469x/src/uart_da1469x.c
new file mode 100644
index 0000000..c40686a
--- /dev/null
+++ b/hw/drivers/uart/uart_da1469x/src/uart_da1469x.c
@@ -0,0 +1,563 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <bsp.h>
+#include "uart/uart.h"
+#include "mcu/da1469x_pd.h"
+#include "mcu/da1469x_hal.h"
+#include "hal/hal_gpio.h"
+#include "uart_da1469x/uart_da1469x.h"
+
+static void da1469x_uart_uart_isr(void);
+static void da1469x_uart_uart2_isr(void);
+static void da1469x_uart_uart3_isr(void);
+
+struct da1469x_uart_hw_data {
+    UART2_Type *regs;
+    IRQn_Type irqn;
+    mcu_gpio_func rx_pin_func;
+    mcu_gpio_func tx_pin_func;
+    mcu_gpio_func rts_pin_func;
+    mcu_gpio_func cts_pin_func;
+    /* Mask for (RE)SET_CLK_COM_REG */
+    uint8_t clk_com_mask;
+    void (*isr)(void);
+};
+
+static const struct da1469x_uart_hw_data da1469x_uart0_hw = {
+    .regs = (UART2_Type *)UART,
+    .irqn = UART_IRQn,
+    .rx_pin_func = MCU_GPIO_FUNC_UART_RX,
+    .tx_pin_func = MCU_GPIO_FUNC_UART_TX,
+    .rts_pin_func = MCU_GPIO_FUNC_GPIO,
+    .cts_pin_func = MCU_GPIO_FUNC_GPIO,
+    .clk_com_mask = CRG_COM_RESET_CLK_COM_REG_UART_ENABLE_Msk,
+    .isr = da1469x_uart_uart_isr,
+};
+
+static const struct da1469x_uart_hw_data da1469x_uart1_hw = {
+    .regs = (UART2_Type *)UART2,
+    .irqn = UART2_IRQn,
+    .rx_pin_func = MCU_GPIO_FUNC_UART2_RX,
+    .tx_pin_func = MCU_GPIO_FUNC_UART2_TX,
+    .rts_pin_func = MCU_GPIO_FUNC_UART2_RTSN,
+    .cts_pin_func = MCU_GPIO_FUNC_UART2_CTSN,
+    .clk_com_mask = CRG_COM_RESET_CLK_COM_REG_UART2_ENABLE_Msk,
+    .isr = da1469x_uart_uart2_isr,
+};
+
+static const struct da1469x_uart_hw_data da1469x_uart2_hw = {
+    .regs = (UART2_Type *)UART3,
+    .irqn = UART3_IRQn,
+    .rx_pin_func = MCU_GPIO_FUNC_UART3_RX,
+    .tx_pin_func = MCU_GPIO_FUNC_UART3_TX,
+    .rts_pin_func = MCU_GPIO_FUNC_UART3_RTSN,
+    .cts_pin_func = MCU_GPIO_FUNC_UART3_CTSN,
+    .clk_com_mask = CRG_COM_RESET_CLK_COM_REG_UART3_ENABLE_Msk,
+    .isr = da1469x_uart_uart3_isr,
+};
+
+static struct da1469x_uart_dev *da1469x_dev0;
+static struct da1469x_uart_dev *da1469x_dev1;
+static struct da1469x_uart_dev *da1469x_dev2;
+
+static void da1469x_uart_uart_configure(struct da1469x_uart_dev *dev);
+static void da1469x_uart_uart_shutdown(struct da1469x_uart_dev *dev);
+
+static void
+da1469x_uart_on_wakeup_callout_cb(struct os_event *ev)
+{
+    struct da1469x_uart_dev *dev = ev->ev_arg;
+
+    da1469x_uart_uart_configure(dev);
+}
+
+static void
+da1469x_uart_on_wakeup_gpio_cb(void *arg)
+{
+    struct da1469x_uart_dev *dev = arg;
+
+    hal_gpio_irq_disable(dev->da1469x_cfg.pin_rx);
+    hal_gpio_irq_release(dev->da1469x_cfg.pin_rx);
+
+    os_callout_reset(&dev->wakeup_callout,
+                     os_time_ms_to_ticks32(MYNEWT_VAL(UART_DA1469X_WAKEUP_DELAY_MS)));
+}
+
+static void
+da1469x_uart_on_setup_wakeup_cb(struct os_event *ev)
+{
+    struct da1469x_uart_dev *dev = ev->ev_arg;
+
+    hal_gpio_irq_init(dev->da1469x_cfg.pin_rx, da1469x_uart_on_wakeup_gpio_cb, dev,
+                      HAL_GPIO_TRIG_RISING, HAL_GPIO_PULL_NONE);
+    hal_gpio_irq_enable(dev->da1469x_cfg.pin_rx);
+}
+
+static void
+da1469x_uart_setup_wakeup(struct da1469x_uart_dev *dev)
+{
+    os_eventq_put(os_eventq_dflt_get(), &dev->setup_wakeup_event);
+}
+
+static inline void
+da1469x_uart_tx_intr_enable(struct da1469x_uart_dev *dev)
+{
+    dev->hw->regs->UART2_IER_DLH_REG |= UART2_UART2_IER_DLH_REG_PTIME_DLH7_Msk |
+                                        UART2_UART2_IER_DLH_REG_ETBEI_DLH1_Msk;
+}
+
+static inline void
+da1469x_uart_tx_intr_disable(struct da1469x_uart_dev *dev)
+{
+    dev->hw->regs->UART2_IER_DLH_REG &= ~(UART2_UART2_IER_DLH_REG_PTIME_DLH7_Msk |
+                                          UART2_UART2_IER_DLH_REG_ETBEI_DLH1_Msk);
+}
+
+static inline void
+da1469x_uart_lsr_intr_enable(struct da1469x_uart_dev *dev)
+{
+    dev->hw->regs->UART2_IER_DLH_REG |= UART2_UART2_IER_DLH_REG_ELSI_DLH2_Msk;
+}
+
+static inline void
+da1469x_uart_rx_intr_enable(struct da1469x_uart_dev *dev)
+{
+    dev->hw->regs->UART2_IER_DLH_REG |= UART2_UART2_IER_DLH_REG_ERBFI_DLH0_Msk;
+}
+
+static inline void
+da1469x_uart_rx_intr_disable(struct da1469x_uart_dev *dev)
+{
+    dev->hw->regs->UART2_IER_DLH_REG &= ~UART2_UART2_IER_DLH_REG_ERBFI_DLH0_Msk;
+}
+
+static void
+da1469x_uart_isr_thr_empty(struct da1469x_uart_dev *dev)
+{
+    struct uart_conf *uc = &dev->uc;
+    int ch;
+
+    while (dev->hw->regs->UART2_USR_REG & UART2_UART2_USR_REG_UART_TFNF_Msk) {
+        ch = uc->uc_tx_char(uc->uc_cb_arg);
+        if (ch < 0) {
+            da1469x_uart_tx_intr_disable(dev);
+            dev->tx_started = 0;
+            if (uc->uc_tx_done) {
+                uc->uc_tx_done(uc->uc_cb_arg);
+            }
+            break;
+        }
+
+        dev->hw->regs->UART2_RBR_THR_DLL_REG = ch;
+    }
+}
+
+static void
+da1469x_uart_isr_recv_data(struct da1469x_uart_dev *dev)
+{
+    int ch;
+
+    dev->rx_data = dev->hw->regs->UART2_RBR_THR_DLL_REG;
+
+    ch = dev->uc.uc_rx_char(dev->uc.uc_cb_arg, dev->rx_data);
+    if (ch < 0) {
+        da1469x_uart_rx_intr_disable(dev);
+        dev->rx_stalled = 1;
+    }
+}
+
+static void
+da1469x_uart_isr(struct da1469x_uart_dev *dev)
+{
+    UART2_Type *uart = dev->hw->regs;
+    bool no_intr = false;
+
+    os_trace_isr_enter();
+
+    while (!no_intr) {
+        /*
+         * NOTE: should be UART2_UART2_IIR_FCR_REG_IIR_FCR_Msk below but this is
+         *     defined (incorrectly) as 0xFF so incorrect value is read.
+         */
+        switch (uart->UART2_IIR_FCR_REG & 0x0F) {
+        case 0x01: /* no interrupt pending */
+            no_intr = true;
+            break;
+        case 0x02: /* THR empty */
+            da1469x_uart_isr_thr_empty(dev);
+            break;
+        case 0x04: /* received data available */
+            da1469x_uart_isr_recv_data(dev);
+            break;
+        case 0x06: /* receiver line status */
+            if (uart->UART2_LSR_REG & UART2_UART2_LSR_REG_UART_BI_Msk) {
+                da1469x_uart_uart_shutdown(dev);
+                da1469x_uart_setup_wakeup(dev);
+                no_intr = true;
+            }
+            break;
+        case 0x07: /* busy detect */
+            (void)uart->UART2_USR_REG;
+            da1469x_uart_uart_shutdown(dev);
+            da1469x_uart_setup_wakeup(dev);
+            no_intr = true;
+            break;
+        case 0x0c: /* character timeout */
+            break;
+        default:
+            assert(0);
+            break;
+        }
+    }
+
+    os_trace_isr_exit();
+}
+
+static void
+da1469x_uart_uart_isr(void)
+{
+    da1469x_uart_isr(da1469x_dev0);
+}
+
+static void
+da1469x_uart_uart2_isr(void)
+{
+    da1469x_uart_isr(da1469x_dev1);
+}
+
+static void
+da1469x_uart_uart3_isr(void)
+{
+    da1469x_uart_isr(da1469x_dev2);
+}
+
+static void
+da1469x_uart_uart_configure(struct da1469x_uart_dev *dev)
+{
+    struct uart_conf *uc = &dev->uc;
+    uint32_t baudrate_cfg;
+    uint32_t reg;
+    UART2_Type *uart = dev->hw->regs;
+    IRQn_Type irqn = dev->hw->irqn;
+
+    da1469x_pd_acquire(MCU_PD_DOMAIN_COM);
+
+    NVIC_DisableIRQ(irqn);
+
+    if (dev->da1469x_cfg.pin_rx >= 0) {
+        /* Turn RX pin to GPIO input during configuration to avoid busy state */
+        mcu_gpio_set_pin_function(dev->da1469x_cfg.pin_rx, MCU_GPIO_MODE_INPUT,
+                                  MCU_GPIO_FUNC_GPIO);
+    }
+
+    /* Reset UART */
+    CRG_COM->RESET_CLK_COM_REG = dev->hw->clk_com_mask;
+    CRG_COM->SET_CLK_COM_REG = dev->hw->clk_com_mask;
+    uart->UART2_SRR_REG = UART2_UART2_SRR_REG_UART_UR_Msk |
+                          UART2_UART2_SRR_REG_UART_RFR_Msk |
+                          UART2_UART2_SRR_REG_UART_XFR_Msk;
+
+    /* Configure baudrate */
+    baudrate_cfg = (32000000 - 1 + (uc->uc_speed / 2)) / uc->uc_speed;
+    uart->UART2_LCR_REG |= UART2_UART2_LCR_REG_UART_DLAB_Msk;
+    uart->UART2_IER_DLH_REG = (baudrate_cfg >> 12) & 0xff;
+    uart->UART2_RBR_THR_DLL_REG = (baudrate_cfg >> 4) & 0xff;
+    uart->UART2_DLF_REG = baudrate_cfg & 0x0f;
+    uart->UART2_LCR_REG &= ~UART2_UART2_LCR_REG_UART_DLAB_Msk;
+
+    /* Configure frame */
+    reg = 0;
+    switch (uc->uc_parity) {
+    case UART_PARITY_NONE:
+        break;
+    case UART_PARITY_EVEN:
+        reg |= UART2_UART2_LCR_REG_UART_EPS_Msk;
+        /* no break */
+    case UART_PARITY_ODD:
+        reg |= UART2_UART2_LCR_REG_UART_PEN_Msk;
+        break;
+    }
+    reg |= (uc->uc_stopbits - 1) << UART2_UART2_LCR_REG_UART_STOP_Pos;
+    reg |= (uc->uc_databits - 5) << UART2_UART2_LCR_REG_UART_DLS_Pos;
+    uart->UART2_LCR_REG = reg;
+
+    /* Enable flow-control if requested and supported */
+    if (uc->uc_flow_ctl == UART_FLOW_CTL_RTS_CTS) {
+        uart->UART2_MCR_REG |= UART2_UART2_MCR_REG_UART_AFCE_Msk |
+                               UART2_UART2_MCR_REG_UART_RTS_Msk;
+    }
+    /* Enable hardware FIFO */
+    uart->UART2_SFE_REG = UART2_UART2_SFE_REG_UART_SHADOW_FIFO_ENABLE_Msk;
+    uart->UART2_SRT_REG = 0;
+    uart->UART2_STET_REG = 0;
+
+    dev->active = 1;
+    dev->rx_stalled = 0;
+    dev->tx_started = 0;
+
+    da1469x_uart_lsr_intr_enable(dev);
+
+    mcu_gpio_set_pin_function(dev->da1469x_cfg.pin_tx, MCU_GPIO_MODE_OUTPUT,
+                              dev->hw->tx_pin_func);
+
+    if (dev->da1469x_cfg.pin_rx >= 0) {
+        mcu_gpio_set_pin_function(dev->da1469x_cfg.pin_rx,
+                                  dev->da1469x_cfg.rx_pullup ? MCU_GPIO_MODE_INPUT_PULLUP : MCU_GPIO_MODE_INPUT,
+                                  dev->hw->rx_pin_func);
+        da1469x_uart_rx_intr_enable(dev);
+    }
+
+    if (dev->da1469x_cfg.pin_rts >= 0) {
+        mcu_gpio_set_pin_function(dev->da1469x_cfg.pin_rts, MCU_GPIO_MODE_OUTPUT,
+                                  dev->hw->rts_pin_func);
+    }
+
+    if (dev->da1469x_cfg.pin_cts >= 0) {
+        mcu_gpio_set_pin_function(dev->da1469x_cfg.pin_cts, MCU_GPIO_MODE_INPUT,
+                                  dev->hw->cts_pin_func);
+    }
+
+    NVIC_ClearPendingIRQ(irqn);
+    NVIC_EnableIRQ(irqn);
+}
+
+static void
+da1469x_uart_uart_shutdown(struct da1469x_uart_dev *dev)
+{
+    dev->active = 0;
+
+    /*
+     * Reset UART before disabling clock to avoid any unexpected behavior after
+     * clock is enabled again.
+     */
+    dev->hw->regs->UART2_SRR_REG = UART2_UART2_SRR_REG_UART_UR_Msk |
+                                   UART2_UART2_SRR_REG_UART_RFR_Msk |
+                                   UART2_UART2_SRR_REG_UART_XFR_Msk;
+    NVIC_DisableIRQ(dev->hw->irqn);
+    NVIC_ClearPendingIRQ(dev->hw->irqn);
+
+    CRG_COM->RESET_CLK_COM_REG = dev->hw->clk_com_mask;
+
+    da1469x_pd_release(MCU_PD_DOMAIN_COM);
+}
+
+static int
+da1469x_uart_open(struct os_dev *odev, uint32_t wait, void *arg)
+{
+    struct da1469x_uart_dev *dev = (struct da1469x_uart_dev *)odev;
+    struct uart_conf *uc = (struct uart_conf *)arg;
+    (void)wait;
+
+    if (!uc) {
+        return OS_EINVAL;
+    }
+
+    if (odev->od_flags & OS_DEV_F_STATUS_OPEN) {
+        return OS_EBUSY;
+    }
+
+    dev->uc = *uc;
+
+    if (uc->uc_speed < 1200 || uc->uc_speed > 1000000) {
+        return OS_INVALID_PARM;
+    }
+
+    if ((uc->uc_databits < 5) || (uc->uc_databits > 8) ||
+        (uc->uc_stopbits < 1) || (uc->uc_stopbits > 2)) {
+        return OS_INVALID_PARM;
+    }
+
+    if ((uc->uc_parity != UART_PARITY_NONE) &&
+        (uc->uc_parity != UART_PARITY_ODD) &&
+        (uc->uc_parity != UART_PARITY_EVEN)) {
+        return OS_INVALID_PARM;
+    }
+
+    if (uc->uc_flow_ctl == UART_FLOW_CTL_RTS_CTS) {
+#if MYNEWT_VAL(UART_0)
+        if (dev->hw->regs == (UART2_Type *)UART) {
+            return OS_INVALID_PARM;
+        }
+#endif
+        if (dev->da1469x_cfg.pin_rts < 0 || dev->da1469x_cfg.pin_cts < 0) {
+            return OS_INVALID_PARM;
+        }
+    }
+
+    da1469x_uart_uart_configure(dev);
+
+    return OS_OK;
+}
+
+static int
+da1469x_uart_close(struct os_dev *odev)
+{
+    struct da1469x_uart_dev *dev = (struct da1469x_uart_dev *)odev;
+
+    da1469x_uart_uart_shutdown(dev);
+
+    return OS_OK;
+}
+
+static void
+da1469x_uart_drain_tx(struct da1469x_uart_dev *dev)
+{
+    struct uart_conf *uc = &dev->uc;
+    int ch;
+
+    while (1) {
+        ch = uc->uc_tx_char(uc->uc_cb_arg);
+        if (ch < 0) {
+            if (uc->uc_tx_done) {
+                uc->uc_tx_done(uc->uc_cb_arg);
+            }
+            break;
+        }
+    }
+}
+
+static void
+da1469x_uart_start_tx(struct uart_dev *udev)
+{
+    struct da1469x_uart_dev *dev = (struct da1469x_uart_dev *)udev;
+    os_sr_t sr;
+
+    if (!dev->active) {
+        da1469x_uart_drain_tx(dev);
+        return;
+    }
+
+    OS_ENTER_CRITICAL(sr);
+
+    if (dev->tx_started == 0) {
+        dev->tx_started = 1;
+        da1469x_uart_tx_intr_enable(dev);
+    }
+
+    OS_EXIT_CRITICAL(sr);
+}
+
+static void
+da1469x_uart_start_rx(struct uart_dev *udev)
+{
+    struct da1469x_uart_dev *dev = (struct da1469x_uart_dev *)udev;
+    int ch;
+    os_sr_t sr;
+
+    OS_ENTER_CRITICAL(sr);
+
+    if (dev->rx_stalled) {
+        ch = dev->uc.uc_rx_char(dev->uc.uc_cb_arg, dev->rx_data);
+        if (ch >= 0) {
+            dev->rx_stalled = 0;
+            da1469x_uart_rx_intr_enable(dev);
+        }
+    }
+
+    OS_EXIT_CRITICAL(sr);
+}
+
+static void
+da1469x_uart_blocking_tx(struct uart_dev *udev, uint8_t byte)
+{
+    struct da1469x_uart_dev *dev = (struct da1469x_uart_dev *)udev;
+    UART2_Type *uart = dev->hw->regs;
+
+    if (!dev->active) {
+        return;
+    }
+
+    while (!(uart->UART2_USR_REG & UART2_UART2_USR_REG_UART_TFNF_Msk)) {
+        /* Wait until FIFO has free space */
+    }
+
+    uart->UART2_RBR_THR_DLL_REG = byte;
+
+    while (!(uart->UART2_USR_REG & UART2_UART2_USR_REG_UART_TFE_Msk) ||
+            (uart->UART2_USR_REG & UART2_UART2_USR_REG_UART_BUSY_Msk)) {
+        /* Wait until FIFO is empty and UART finished tx */
+    }
+}
+
+static int
+da1469x_uart_init(struct os_dev *odev, void *arg)
+{
+    struct da1469x_uart_dev *dev = (struct da1469x_uart_dev *)odev;
+    struct da1469x_uart_cfg *cfg = arg;
+
+    if (cfg->pin_rx >= 0) {
+        os_callout_init(&dev->wakeup_callout, os_eventq_dflt_get(),
+                        da1469x_uart_on_wakeup_callout_cb, dev);
+
+        dev->setup_wakeup_event.ev_cb = da1469x_uart_on_setup_wakeup_cb;
+        dev->setup_wakeup_event.ev_arg = dev;
+    }
+
+    OS_DEV_SETHANDLERS(odev, da1469x_uart_open, da1469x_uart_close);
+
+    dev->dev.ud_funcs.uf_start_tx = da1469x_uart_start_tx;
+    dev->dev.ud_funcs.uf_start_rx = da1469x_uart_start_rx;
+    dev->dev.ud_funcs.uf_blocking_tx = da1469x_uart_blocking_tx;
+
+    dev->da1469x_cfg = *cfg;
+
+    NVIC_DisableIRQ(dev->hw->irqn);
+    NVIC_SetPriority(dev->hw->irqn, (1 << __NVIC_PRIO_BITS) - 1);
+    NVIC_SetVector(dev->hw->irqn, (uint32_t)dev->hw->isr);
+
+    return OS_OK;
+}
+
+int
+da1469x_uart_dev_create(struct da1469x_uart_dev *dev, const char *name, uint8_t priority,
+                        const struct da1469x_uart_cfg *da1469x_cfg)
+{
+    size_t uart_num_idx;
+    int uart_num;
+
+    if (dev == NULL || name == NULL || da1469x_cfg == NULL) {
+        return OS_EINVAL;
+    }
+
+    /* Get UART number from device name last character. */
+    uart_num_idx = strlen(name) - 1;
+    uart_num = name[uart_num_idx] - '0';
+
+    if (MYNEWT_VAL(UART_0) && uart_num == 0) {
+        dev->hw = &da1469x_uart0_hw;
+        assert(da1469x_dev0 == NULL);
+        da1469x_dev0 = dev;
+    } else if (MYNEWT_VAL(UART_1) && uart_num == 1) {
+        dev->hw = &da1469x_uart1_hw;
+        assert(da1469x_dev1 == NULL);
+        da1469x_dev1 = dev;
+    } else if (MYNEWT_VAL(UART_2) && uart_num == 2) {
+        dev->hw = &da1469x_uart2_hw;
+        assert(da1469x_dev2 == NULL);
+        da1469x_dev2 = dev;
+    } else {
+        return OS_ENOENT;
+    }
+
+    return os_dev_create((struct os_dev *)dev, name, OS_DEV_INIT_PRIMARY, priority, da1469x_uart_init,
+                         (void *)da1469x_cfg);
+}
diff --git a/hw/drivers/uart/uart_da1469x/syscfg.yml b/hw/drivers/uart/uart_da1469x/syscfg.yml
new file mode 100644
index 0000000..ca71fdb
--- /dev/null
+++ b/hw/drivers/uart/uart_da1469x/syscfg.yml
@@ -0,0 +1,25 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+syscfg.defs:
+    UART_DA1469X_WAKEUP_DELAY_MS:
+       description: >
+          Delay between detected high state on RX line (i.e. UART is attached)
+          and configuring UART. This is to ensure RX is debounced properly.
+       value: 100