1 /* 2 * Copyright (c) 2023 Nordic Semiconductor ASA 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #ifndef ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_TO_IRQ_H_ 8 #define ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_TO_IRQ_H_ 9 10 #include <zephyr/drivers/uart.h> 11 #include <zephyr/logging/log.h> 12 #include <zephyr/spinlock.h> 13 #include <zephyr/sys/util.h> 14 #include <zephyr/drivers/serial/uart_async_rx.h> 15 16 /** 17 * @brief UART Asynchronous to Interrupt driven API adaptation layer 18 * @ingroup uart_interface 19 * @{ 20 */ 21 22 #ifdef __cplusplus 23 extern "C" { 24 #endif 25 26 /* Forward declarations. */ 27 28 /** @brief Data structure used by the adaptation layer. 29 * 30 * Pointer to that data must be the first element of the UART device data structure. 31 */ 32 struct uart_async_to_irq_data; 33 34 /** @brief Configuration structure used by the adaptation layer. 35 * 36 * Pointer to this data must be the first element of the UART device configuration structure. 37 */ 38 struct uart_async_to_irq_config; 39 40 /* @brief Function that triggers trampoline to the interrupt context. 41 * 42 * This context is used to call user UART interrupt handler. It is to used to 43 * fulfill the requirement that UART interrupt driven API shall be called from 44 * the UART interrupt. Trampoline context shall have the same priority as UART. 45 * 46 * One option may be to use k_timer configured to expire immediately. 47 */ 48 typedef void (*uart_async_to_irq_trampoline)(const struct device *dev); 49 50 /** @brief Callback to be called from trampoline context. 51 * 52 * @param dev UART device. 53 */ 54 void uart_async_to_irq_trampoline_cb(const struct device *dev); 55 56 /** @brief Interrupt driven API initializer. 57 * 58 * It should be used in the initialization of the UART API structure in the 59 * driver to provide interrupt driven API functions. 60 */ 61 #define UART_ASYNC_TO_IRQ_API_INIT() \ 62 .fifo_fill = z_uart_async_to_irq_fifo_fill, \ 63 .fifo_read = z_uart_async_to_irq_fifo_read, \ 64 .irq_tx_enable = z_uart_async_to_irq_irq_tx_enable, \ 65 .irq_tx_disable = z_uart_async_to_irq_irq_tx_disable, \ 66 .irq_tx_ready = z_uart_async_to_irq_irq_tx_ready, \ 67 .irq_rx_enable = z_uart_async_to_irq_irq_rx_enable, \ 68 .irq_rx_disable = z_uart_async_to_irq_irq_rx_disable, \ 69 .irq_tx_complete = z_uart_async_to_irq_irq_tx_complete,\ 70 .irq_rx_ready = z_uart_async_to_irq_irq_rx_ready, \ 71 .irq_err_enable = z_uart_async_to_irq_irq_err_enable, \ 72 .irq_err_disable = z_uart_async_to_irq_irq_err_disable,\ 73 .irq_is_pending = z_uart_async_to_irq_irq_is_pending, \ 74 .irq_update = z_uart_async_to_irq_irq_update, \ 75 .irq_callback_set = z_uart_async_to_irq_irq_callback_set 76 77 /** @brief Configuration structure initializer. 78 * 79 * @param _api Structure with UART asynchronous API. 80 * @param _trampoline Function that trampolines to the interrupt context. 81 * @param _baudrate UART baudrate. 82 * @param _tx_buf TX buffer. 83 * @param _tx_len TX buffer length. 84 * @param _rx_buf RX buffer. 85 * @param _rx_len RX buffer length. 86 * @param _rx_cnt Number of chunks into which RX buffer is divided. 87 * @param _log Logging instance, if not provided (empty) then default is used. 88 */ 89 #define UART_ASYNC_TO_IRQ_API_CONFIG_INITIALIZER(_api, _trampoline, _baudrate, _tx_buf, \ 90 _tx_len, _rx_buf, _rx_len, _rx_cnt, _log) \ 91 { \ 92 .tx_buf = _tx_buf, \ 93 .tx_len = _tx_len, \ 94 .async_rx = { \ 95 .buffer = _rx_buf, \ 96 .length = _rx_len, \ 97 .buf_cnt = _rx_cnt \ 98 }, \ 99 .api = _api, \ 100 .trampoline = _trampoline, \ 101 .baudrate = _baudrate, \ 102 LOG_OBJECT_PTR_INIT(log, \ 103 COND_CODE_1(IS_EMPTY(_log), \ 104 (LOG_OBJECT_PTR(UART_ASYNC_TO_IRQ_LOG_NAME)), \ 105 (_log) \ 106 ) \ 107 ) \ 108 } 109 110 /** @brief Initialize the adaptation layer. 111 * 112 * @param data Data associated with the given adaptation layer instance. 113 * @param config Configuration structure. Must be persistent. 114 * 115 * @retval 0 On successful initialization. 116 */ 117 int uart_async_to_irq_init(struct uart_async_to_irq_data *data, 118 const struct uart_async_to_irq_config *config); 119 120 /* @brief Enable RX for interrupt driven API. 121 * 122 * @param dev UART device. Device must support asynchronous API. 123 * 124 * @retval 0 on successful operation. 125 * @retval -EINVAL if adaption layer has wrong configuration. 126 * @retval negative value Error reported by the UART API. 127 */ 128 int uart_async_to_irq_rx_enable(const struct device *dev); 129 130 /* @brief Disable RX for interrupt driven API. 131 * 132 * @param dev UART device. Device must support asynchronous API. 133 * 134 * @retval 0 on successful operation. 135 * @retval -EINVAL if adaption layer has wrong configuration. 136 * @retval negative value Error reported by the UART API. 137 */ 138 int uart_async_to_irq_rx_disable(const struct device *dev); 139 140 /* Starting from here API is internal only. */ 141 142 /** @cond INTERNAL_HIDDEN 143 * @brief Structure used by the adaptation layer. 144 */ 145 struct uart_async_to_irq_config { 146 /** Pointer to the TX buffer. */ 147 uint8_t *tx_buf; 148 149 /** TX buffer length. */ 150 size_t tx_len; 151 152 /** UART Asynchronous RX helper configuration. */ 153 struct uart_async_rx_config async_rx; 154 155 /** Async API used by the a2i layer. */ 156 const struct uart_async_to_irq_async_api *api; 157 158 /** Trampoline callback. */ 159 uart_async_to_irq_trampoline trampoline; 160 161 /** Initial baudrate. */ 162 uint32_t baudrate; 163 164 /** Instance logging handler. */ 165 LOG_INSTANCE_PTR_DECLARE(log); 166 }; 167 168 /** @brief Asynchronous API used by the adaptation layer. */ 169 struct uart_async_to_irq_async_api { 170 int (*callback_set)(const struct device *dev, 171 uart_callback_t callback, 172 void *user_data); 173 174 int (*tx)(const struct device *dev, const uint8_t *buf, size_t len, 175 int32_t timeout); 176 int (*tx_abort)(const struct device *dev); 177 178 int (*rx_enable)(const struct device *dev, uint8_t *buf, size_t len, 179 int32_t timeout); 180 int (*rx_buf_rsp)(const struct device *dev, uint8_t *buf, size_t len); 181 int (*rx_disable)(const struct device *dev); 182 }; 183 184 /** @brief Structure holding receiver data. */ 185 struct uart_async_to_irq_rx_data { 186 /** Asynchronous RX helper data. */ 187 struct uart_async_rx async_rx; 188 189 /** Semaphore for pending on RX disable. */ 190 struct k_sem sem; 191 192 /** Number of pending buffer requests which weren't handled because lack of free buffers. */ 193 atomic_t pending_buf_req; 194 }; 195 196 /** @brief Structure holding transmitter data. */ 197 struct uart_async_to_irq_tx_data { 198 /** TX buffer. */ 199 uint8_t *buf; 200 201 /** Length of the buffer. */ 202 size_t len; 203 }; 204 205 /** @briref Data associated with the asynchronous to the interrupt driven API adaptation layer. */ 206 struct uart_async_to_irq_data { 207 /** User callback for interrupt driven API. */ 208 uart_irq_callback_user_data_t callback; 209 210 /** User data. */ 211 void *user_data; 212 213 /** Interrupt request counter. */ 214 atomic_t irq_req; 215 216 /** RX specific data. */ 217 struct uart_async_to_irq_rx_data rx; 218 219 /** TX specific data. */ 220 struct uart_async_to_irq_tx_data tx; 221 222 /** Spinlock. */ 223 struct k_spinlock lock; 224 225 /** Internally used flags for holding the state of the a2i layer. */ 226 atomic_t flags; 227 }; 228 229 /** Interrupt driven FIFO fill function. */ 230 int z_uart_async_to_irq_fifo_fill(const struct device *dev, 231 const uint8_t *buf, 232 int len); 233 234 /** Interrupt driven FIFO read function. */ 235 int z_uart_async_to_irq_fifo_read(const struct device *dev, 236 uint8_t *buf, 237 const int len); 238 239 /** Interrupt driven transfer enabling function. */ 240 void z_uart_async_to_irq_irq_tx_enable(const struct device *dev); 241 242 /** Interrupt driven transfer disabling function */ 243 void z_uart_async_to_irq_irq_tx_disable(const struct device *dev); 244 245 /** Interrupt driven transfer ready function */ 246 int z_uart_async_to_irq_irq_tx_ready(const struct device *dev); 247 248 /** Interrupt driven receiver enabling function */ 249 void z_uart_async_to_irq_irq_rx_enable(const struct device *dev); 250 251 /** Interrupt driven receiver disabling function */ 252 void z_uart_async_to_irq_irq_rx_disable(const struct device *dev); 253 254 /** Interrupt driven transfer complete function */ 255 int z_uart_async_to_irq_irq_tx_complete(const struct device *dev); 256 257 /** Interrupt driven receiver ready function */ 258 int z_uart_async_to_irq_irq_rx_ready(const struct device *dev); 259 260 /** Interrupt driven error enabling function */ 261 void z_uart_async_to_irq_irq_err_enable(const struct device *dev); 262 263 /** Interrupt driven error disabling function */ 264 void z_uart_async_to_irq_irq_err_disable(const struct device *dev); 265 266 /** Interrupt driven pending status function */ 267 int z_uart_async_to_irq_irq_is_pending(const struct device *dev); 268 269 /** Interrupt driven interrupt update function */ 270 int z_uart_async_to_irq_irq_update(const struct device *dev); 271 272 /** Set the irq callback function */ 273 void z_uart_async_to_irq_irq_callback_set(const struct device *dev, 274 uart_irq_callback_user_data_t cb, 275 void *user_data); 276 277 /** @endcond */ 278 279 #ifdef __cplusplus 280 } 281 #endif 282 283 /** @} */ 284 285 #endif /* ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_TO_IRQ_H_ */ 286