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