api: uart: Add new asynchronous UART API.

Added new UART API, that allows for longer transmissions, leaves
IRQ handling on driver side and allows for DMA usage.

Signed-off-by: Mieszko Mierunski <mieszko.mierunski@nordicsemi.no>
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 6685a6a..2bd8de2 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -28,12 +28,19 @@
 	  This is an option to be enabled by individual serial driver
 	  to signal that the driver and hardware supports interrupts.
 
+config UART_ASYNC_API
+	bool "Enable new asynchronous UART API [EXPERIMENTAL]"
+	help
+	  This option enables new asynchronous UART API.
+
+if UART_ASYNC_API=n
 config UART_INTERRUPT_DRIVEN
 	bool "Enable UART Interrupt support"
 	depends on SERIAL_SUPPORT_INTERRUPT
 	help
 	  This option enables interrupt support for UART allowing console
 	  input and other UART based drivers.
+endif
 
 config UART_LINE_CTRL
 	bool "Enable Serial Line Control API"
diff --git a/include/uart.h b/include/uart.h
index 806ce01..b5aa802 100644
--- a/include/uart.h
+++ b/include/uart.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Nordic Semiconductor ASA
+ * Copyright (c) 2018-2019 Nordic Semiconductor ASA
  * Copyright (c) 2015 Wind River Systems, Inc.
  *
  * SPDX-License-Identifier: Apache-2.0
@@ -29,6 +29,204 @@
 
 #include <device.h>
 
+/** @brief Line control signals. */
+enum uart_line_ctrl {
+	UART_LINE_CTRL_RTS = (1 << 1),
+	UART_LINE_CTRL_DTR = (1 << 2),
+	UART_LINE_CTRL_DCD = (1 << 3),
+	UART_LINE_CTRL_DSR = (1 << 4),
+};
+
+/**
+ * @brief Types of events passed to callback in UART_ASYNC_API
+ *
+ * Receiving:
+ * 1. To start receiving, uart_rx_enable has to be called with first buffer
+ * 2. When receiving starts to current buffer, UART_RX_BUF_REQUEST will be
+ *    generated, in response to that user can either:
+ *
+ *    - Provide second buffer using uart_rx_buf_rsp, when first buffer is
+ *      filled, receiving will automatically start to second buffer.
+ *    - Ignore the event, this way when current buffer is filled UART_RX_DONE
+ *      event will be generated and receiving will be stopped.
+ *
+ * 3. If some data was received and timeout occurred UART_RX_RDY event will be
+ *    generated. It can happen multiples times for the same buffer. RX timeout
+ *    is counted from last byte received i.e. if no data was received, there
+ *    won't be any timeout event.
+ * 4. After buffer is filled UART_RX_RDY will be generated, immediately
+ *    followed by UART_RX_BUF_RELEASED indicating that current buffer is no
+ *    longer used.
+ * 5. If there was second buffer provided, it will become current buffer and
+ *    we start again at point 2.
+ *    If no second buffer was specified receiving is stopped and
+ *    UART_RX_DISABLED event is generated. After that whole process can be
+ *    repeated.
+ *
+ * Any time during reception UART_RX_STOPPED event can occur. It will be
+ * followed by UART_RX_BUF_RELEASED event for every buffer currently passed to
+ * driver and finally by UART_RX_DISABLED event.
+ *
+ * Receiving can be disabled using uart_rx_disable, after calling that
+ * function any data received will be lost, UART_RX_BUF_RELEASED event will be
+ * generated for every buffer currently passed to driver and UART_RX_DISABLED
+ * event will occur.
+ *
+ * Transmitting:
+ * 1. Transmitting starts by uart_tx function.
+ * 2. If whole buffer was transmitted UART_TX_DONE is generated.
+ *    If timeout occurred UART_TX_ABORTED will be generated.
+ *
+ * Transmitting can be aborted using uart_tx_abort, after calling that
+ * function UART_TX_ABORTED event will be generated.
+ *
+ */
+enum uart_event_type {
+	/** @brief Whole TX buffer was transmitted. */
+	UART_TX_DONE,
+	/**
+	 * @brief Transmitting aborted due to timeout or uart_tx_abort call
+	 *
+	 * When flow control is enabled, there is a possibility that TX transfer
+	 * won't finish in the allotted time. Some data may have been
+	 * transferred, information about it can be found in event data.
+	 */
+	UART_TX_ABORTED,
+	/**
+	 * @brief Received data is ready for processing.
+	 *
+	 * This event is generated in two cases:
+	 * - When RX timeout occurred, and data was stored in provided buffer.
+	 *   This can happen multiple times in the same buffer.
+	 * - When provided buffer is full.
+	 */
+	UART_RX_RDY,
+	/**
+	 * @brief Driver requests next buffer for continuous reception.
+	 *
+	 * This event is triggered when receiving has started for a new buffer,
+	 * i.e. it's time to provide a next buffer for a seamless switchover to
+	 * it. For continuous reliable receiving, user should provide another RX
+	 * buffer in response to this event, using uart_rx_buf_rsp function
+	 *
+	 * If uart_rx_buf_rsp is not called before current buffer
+	 * is filled up, receiving will stop.
+	 */
+	UART_RX_BUF_REQUEST,
+	/**
+	 * @brief Buffer is no longer used by UART driver.
+	 */
+	UART_RX_BUF_RELEASED,
+	/**
+	 * @brief RX has been disabled and can be reenabled.
+	 *
+	 * This event is generated whenever receiver has been stopped, disabled
+	 * or finished its operation and can be enabled again using
+	 * uart_rx_enable
+	 */
+	UART_RX_DISABLED,
+	/**
+	 * @brief RX has stopped due to external event.
+	 *
+	 * Reason is one of uart_rx_stop_reason.
+	 */
+	UART_RX_STOPPED,
+};
+
+
+/**
+ * @brief Reception stop reasons.
+ *
+ * Values that correspond to events or errors responsible for stopping
+ * receiving.
+ *
+ * We start counting from 1, to not use 0 which is treated as no error.
+ */
+enum uart_rx_stop_reason {
+	/**
+	 * @brief Break interrupt
+	 *
+	 * A break interrupt was received. This happens when the serial input
+	 * is held at a logic '0' state for longer than the sum of
+	 * start time + data bits + parity + stop bits.
+	 */
+	UART_BREAK = 1,
+	/** @brief Overrun error */
+	UART_ERROR_OVERRUN,
+	/** @brief Parity error */
+	UART_ERROR_PARITY,
+	/** @brief Framing error */
+	UART_ERROR_FRAMING,
+};
+
+/** @brief Backward compatibility defines, deprecated */
+#define UART_ERROR_BREAK UART_BREAK
+#define LINE_CTRL_BAUD_RATE (1 << 0)
+#define LINE_CTRL_RTS UART_LINE_CTRL_RTS
+#define LINE_CTRL_DTR UART_LINE_CTRL_DTR
+#define LINE_CTRL_DCD UART_LINE_CTRL_DCD
+#define LINE_CTRL_DSR UART_LINE_CTRL_DSR
+
+
+/** @brief UART TX event data. */
+struct uart_event_tx {
+	/** @brief Pointer to current buffer. */
+	const u8_t *buf;
+	/** @brief Number of bytes sent. */
+	size_t len;
+};
+
+/** @brief UART RX event data. */
+struct uart_event_rx {
+	/** @brief Pointer to current buffer. */
+	u8_t *buf;
+	/** @brief Offset from buffer start to currently received data. */
+	size_t offset;
+	/** @brief Number of bytes received. */
+	size_t len;
+};
+
+/** @brief UART RX buffer released event data. */
+struct uart_event_rx_buf {
+	/* @brief Pointer to buffer that is no longer in use. */
+	u8_t *buf;
+};
+
+/** @brief UART RX stopped data. */
+struct uart_event_rx_stop {
+	/** @brief Reason why receiving stopped */
+	enum uart_rx_stop_reason reason;
+	/** @brief Last received data. */
+	struct uart_event_rx data;
+};
+
+/** @brief Structure containing information about current event. */
+struct uart_event {
+	/** @brief Type of event */
+	enum uart_event_type type;
+	/** @brief Event data */
+	union {
+		/** @brief UART_TX_DONE and UART_TX_ABORTED events data. */
+		struct uart_event_tx tx;
+		/** @brief UART_RX_RDY event data. */
+		struct uart_event_rx rx;
+		/** @brief UART_RX_BUF_RELEASED event data. */
+		struct uart_event_rx_buf rx_buf;
+		/** @brief UART_RX_STOPPED event data. */
+		struct uart_event_rx_stop rx_stop;
+	} data;
+};
+
+/**
+ * @typedef uart_callback_t
+ * @brief Define the application callback function signature for
+ * uart_set_callback() function.
+ *
+ * @param evt	    Pointer to uart_event structure.
+ * @param user_data Pointer to data specified by user.
+ */
+typedef void (*uart_callback_t)(struct uart_event *evt, void *user_data);
+
 #ifdef CONFIG_PCI
 #include <drivers/pci/pci.h>
 #include <drivers/pci/pci_mgr.h>
@@ -38,33 +236,6 @@
  */
 #define UART_OPTION_AFCE 0x01
 
-/** Common line controls for UART.*/
-#define LINE_CTRL_BAUD_RATE	(1 << 0)
-#define LINE_CTRL_RTS		(1 << 1)
-#define LINE_CTRL_DTR		(1 << 2)
-#define LINE_CTRL_DCD		(1 << 3)
-#define LINE_CTRL_DSR		(1 << 4)
-
-/* Common communication errors for UART.*/
-
-/** @brief Overrun error */
-#define UART_ERROR_OVERRUN  (1 << 0)
-
-/** @brief Parity error */
-#define UART_ERROR_PARITY   (1 << 1)
-
-/** @brief Framing error */
-#define UART_ERROR_FRAMING  (1 << 2)
-
-/**
- * @brief Break interrupt error:
- *
- * A break interrupt was received. This happens when the serial input is
- * held at a logic '0' state for longer than the sum of start time + data bits
- * + parity + stop bits.
- */
-#define UART_ERROR_BREAK    (1 << 3)
-
 /**
  * @brief UART controller configuration structure
  *
@@ -120,7 +291,6 @@
 	UART_CFG_FLOW_CTRL_DTR_DSR,
 };
 
-
 /**
  * @typedef uart_irq_callback_user_data_t
  * @brief Define the application callback function signature for
@@ -175,6 +345,23 @@
 
 /** @brief Driver API structure. */
 struct uart_driver_api {
+
+#ifdef CONFIG_UART_ASYNC_API
+
+	int (*callback_set)(struct device *dev, uart_callback_t callback,
+			    void *user_data);
+
+	int (*tx)(struct device *dev, const u8_t *buf, size_t len,
+		  u32_t timeout);
+	int (*tx_abort)(struct device *dev);
+
+	int (*rx_enable)(struct device *dev, u8_t *buf, size_t len,
+			 u32_t timeout);
+	int (*rx_buf_rsp)(struct device *dev, u8_t *buf, size_t len);
+	int (*rx_disable)(struct device *dev);
+
+#endif
+
 	/** Console I/O function */
 	int (*poll_in)(struct device *dev, unsigned char *p_char);
 	void (*poll_out)(struct device *dev, unsigned char out_char);
@@ -245,16 +432,150 @@
 
 };
 
+#ifdef CONFIG_UART_ASYNC_API
+
+/**
+ * @brief Set event handler function.
+ *
+ * @param dev       UART device structure.
+ * @param callback  Event handler.
+ * @param user_data Data to pass to event handler function.
+ *
+ * @retval 0	    If successful, negative errno code otherwise.
+ */
+static inline int uart_callback_set(struct device *dev,
+				    uart_callback_t callback,
+				    void *user_data)
+{
+	const struct uart_driver_api *api =
+			(const struct uart_driver_api *)dev->driver_api;
+
+	return api->callback_set(dev, callback, user_data);
+}
+
+/**
+ * @brief Send given number of bytes from buffer through UART.
+ *
+ * Function returns immediately and event handler,
+ * set using @ref uart_set_callback, is called after transfer is finished.
+ *
+ * @param dev     UART device structure.
+ * @param buf     Pointer to transmit buffer.
+ * @param len     Length of transmit buffer.
+ * @param timeout Timeout in milliseconds. Valid only if flow control is enabled
+ *
+ * @retval -EBUSY There is already an ongoing transfer.
+ * @retval 0	  If successful, negative errno code otherwise.
+ */
+static inline int uart_tx(struct device *dev,
+			  const u8_t *buf,
+			  size_t len,
+			  u32_t timeout)
+
+{
+	const struct uart_driver_api *api =
+			(const struct uart_driver_api *)dev->driver_api;
+
+	return api->tx(dev, buf, len, timeout);
+}
+
+/**
+ * @brief Abort current TX transmission.
+ *
+ * UART_TX_DONE event will be generated with amount of data sent.
+ *
+ * @param dev UART device structure.
+ *
+ * @retval -EFAULT There is no active transmission.
+ * @retval 0	   If successful, negative errno code otherwise.
+ */
+static inline int uart_tx_abort(struct device *dev)
+{
+	const struct uart_driver_api *api =
+			(const struct uart_driver_api *)dev->driver_api;
+
+	return api->tx_abort(dev);
+}
+
+/**
+ * @brief Start receiving data through UART.
+ *
+ * Function sets given buffer as first buffer for receiving and returns
+ * immediately. After that event handler, set using @ref uart_set_callback,
+ * is called with UART_RX_RDY or UART_RX_BUF_REQUEST events.
+ *
+ * @param dev     UART device structure.
+ * @param buf     Pointer to receive buffer.
+ * @param len     Buffer length.
+ * @param timeout Timeout in milliseconds.
+ *
+ * @retval -EBUSY RX already in progress.
+ * @retval 0	  If successful, negative errno code otherwise.
+ *
+ */
+static inline int uart_rx_enable(struct device *dev, u8_t *buf, size_t len,
+				 u32_t timeout)
+{
+	const struct uart_driver_api *api =
+				(const struct uart_driver_api *)dev->driver_api;
+
+	return api->rx_enable(dev, buf, len, timeout);
+}
+
+/**
+ * @brief Provide receive buffer in response to UART_RX_BUF_REQUEST event.
+ *
+ * Provide pointer to RX buffer, which will be used when current buffer is
+ * filled.
+ *
+ * @note Providing buffer that is already in usage by driver leads to
+ *       undefined behavior. Buffer can be reused when it has been released
+ *       by driver.
+ *
+ * @param dev UART device structure.
+ * @param buf Pointer to receive buffer.
+ * @param len Buffer length.
+ *
+ * @retval -EBUSY Next buffer already set.
+ * @retval 0	  If successful, negative errno code otherwise.
+ *
+ */
+static inline int uart_rx_buf_rsp(struct device *dev, u8_t *buf, size_t len)
+{
+	const struct uart_driver_api *api =
+				(const struct uart_driver_api *)dev->driver_api;
+
+	return api->rx_buf_rsp(dev, buf, len);
+}
+
+/**
+ * @brief Disable RX
+ *
+ * UART_RX_BUF_RELEASED event will be generated for every buffer scheduled,
+ * after that UART_RX_DISABLED event will be generated.
+ *
+ * @param dev UART device structure.
+ *
+ * @retval -EFAULT There is no active reception.
+ * @retval 0	   If successful, negative errno code otherwise.
+ */
+static inline int uart_rx_disable(struct device *dev)
+{
+	const struct uart_driver_api *api =
+			(const struct uart_driver_api *)dev->driver_api;
+
+	return api->rx_disable(dev);
+}
+
+#endif
+
 /**
  * @brief Check whether an error was detected.
  *
  * @param dev UART device structure.
  *
- * @retval UART_ERROR_OVERRUN if an overrun error was detected.
- * @retval UART_ERROR_PARITY if a parity error was detected.
- * @retval UART_ERROR_FRAMING if a framing error was detected.
- * @retval UART_ERROR_BREAK if a break error was detected.
- * @retval 0 Otherwise.
+ * @retval uart_rx_stop_reason If error during receiving occurred.
+ * @retval 0		       Otherwise.
  */
 __syscall int uart_err_check(struct device *dev);
 
@@ -280,6 +601,7 @@
  * @retval -1 If no character was available to read (i.e., the UART
  *            input buffer was empty).
  * @retval -ENOTSUP If the operation is not supported.
+ * @retval -EBUSY If reception was enabled using uart_rx_enabled
  */
 __syscall int uart_poll_in(struct device *dev, unsigned char *p_char);