Line data Source code
1 0 : /*
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 0 : 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 1 : 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 1 : #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 1 : _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 dev UART device. Device must support asynchronous API.
113 : *
114 : * @retval 0 On successful initialization.
115 : */
116 1 : int uart_async_to_irq_init(const struct device *dev);
117 :
118 : /* @brief Enable RX for interrupt driven API.
119 : *
120 : * @param dev UART device. Device must support asynchronous API.
121 : *
122 : * @retval 0 on successful operation.
123 : * @retval -EINVAL if adaption layer has wrong configuration.
124 : * @retval negative value Error reported by the UART API.
125 : */
126 0 : int uart_async_to_irq_rx_enable(const struct device *dev);
127 :
128 : /* @brief Disable RX for interrupt driven API.
129 : *
130 : * @param dev UART device. Device must support asynchronous API.
131 : *
132 : * @retval 0 on successful operation.
133 : * @retval -EINVAL if adaption layer has wrong configuration.
134 : * @retval negative value Error reported by the UART API.
135 : */
136 0 : int uart_async_to_irq_rx_disable(const struct device *dev);
137 :
138 : /* Starting from here API is internal only. */
139 :
140 : /** @cond INTERNAL_HIDDEN
141 : * @brief Structure used by the adaptation layer.
142 : */
143 : struct uart_async_to_irq_config {
144 : /** Pointer to the TX buffer. */
145 : uint8_t *tx_buf;
146 :
147 : /** TX buffer length. */
148 : size_t tx_len;
149 :
150 : /** UART Asynchronous RX helper configuration. */
151 : struct uart_async_rx_config async_rx;
152 :
153 : /** Async API used by the a2i layer. */
154 : const struct uart_async_to_irq_async_api *api;
155 :
156 : /** Trampoline callback. */
157 : uart_async_to_irq_trampoline trampoline;
158 :
159 : /** Initial baudrate. */
160 : uint32_t baudrate;
161 :
162 : /** Instance logging handler. */
163 : LOG_INSTANCE_PTR_DECLARE(log);
164 : };
165 :
166 : /** @brief Asynchronous API used by the adaptation layer. */
167 : struct uart_async_to_irq_async_api {
168 : int (*callback_set)(const struct device *dev,
169 : uart_callback_t callback,
170 : void *user_data);
171 :
172 : int (*tx)(const struct device *dev, const uint8_t *buf, size_t len,
173 : int32_t timeout);
174 : int (*tx_abort)(const struct device *dev);
175 :
176 : int (*rx_enable)(const struct device *dev, uint8_t *buf, size_t len,
177 : int32_t timeout);
178 : int (*rx_buf_rsp)(const struct device *dev, uint8_t *buf, size_t len);
179 : int (*rx_disable)(const struct device *dev);
180 : };
181 :
182 : /** @brief Structure holding receiver data. */
183 : struct uart_async_to_irq_rx_data {
184 : /** Asynchronous RX helper data. */
185 : struct uart_async_rx async_rx;
186 :
187 : /** Semaphore for pending on RX disable. */
188 : struct k_sem sem;
189 :
190 : /** Number of pending buffer requests which weren't handled because lack of free buffers. */
191 : atomic_t pending_buf_req;
192 : };
193 :
194 : /** @brief Structure holding transmitter data. */
195 : struct uart_async_to_irq_tx_data {
196 : /** TX buffer. */
197 : uint8_t *buf;
198 :
199 : /** Length of the buffer. */
200 : size_t len;
201 : };
202 :
203 : /** @brief Data associated with the asynchronous to the interrupt driven API adaptation layer. */
204 : struct uart_async_to_irq_data {
205 : /** User callback for interrupt driven API. */
206 : uart_irq_callback_user_data_t callback;
207 :
208 : /** User data. */
209 : void *user_data;
210 :
211 : /** Interrupt request counter. */
212 : atomic_t irq_req;
213 :
214 : /** RX specific data. */
215 : struct uart_async_to_irq_rx_data rx;
216 :
217 : /** TX specific data. */
218 : struct uart_async_to_irq_tx_data tx;
219 :
220 : /** Spinlock. */
221 : struct k_spinlock lock;
222 :
223 : /** Internally used flags for holding the state of the a2i layer. */
224 : atomic_t flags;
225 : };
226 :
227 : /** Interrupt driven FIFO fill function. */
228 : int z_uart_async_to_irq_fifo_fill(const struct device *dev,
229 : const uint8_t *buf,
230 : int len);
231 :
232 : /** Interrupt driven FIFO read function. */
233 : int z_uart_async_to_irq_fifo_read(const struct device *dev,
234 : uint8_t *buf,
235 : const int len);
236 :
237 : /** Interrupt driven transfer enabling function. */
238 : void z_uart_async_to_irq_irq_tx_enable(const struct device *dev);
239 :
240 : /** Interrupt driven transfer disabling function */
241 : void z_uart_async_to_irq_irq_tx_disable(const struct device *dev);
242 :
243 : /** Interrupt driven transfer ready function */
244 : int z_uart_async_to_irq_irq_tx_ready(const struct device *dev);
245 :
246 : /** Interrupt driven receiver enabling function */
247 : void z_uart_async_to_irq_irq_rx_enable(const struct device *dev);
248 :
249 : /** Interrupt driven receiver disabling function */
250 : void z_uart_async_to_irq_irq_rx_disable(const struct device *dev);
251 :
252 : /** Interrupt driven transfer complete function */
253 : int z_uart_async_to_irq_irq_tx_complete(const struct device *dev);
254 :
255 : /** Interrupt driven receiver ready function */
256 : int z_uart_async_to_irq_irq_rx_ready(const struct device *dev);
257 :
258 : /** Interrupt driven error enabling function */
259 : void z_uart_async_to_irq_irq_err_enable(const struct device *dev);
260 :
261 : /** Interrupt driven error disabling function */
262 : void z_uart_async_to_irq_irq_err_disable(const struct device *dev);
263 :
264 : /** Interrupt driven pending status function */
265 : int z_uart_async_to_irq_irq_is_pending(const struct device *dev);
266 :
267 : /** Interrupt driven interrupt update function */
268 : int z_uart_async_to_irq_irq_update(const struct device *dev);
269 :
270 : /** Set the irq callback function */
271 : void z_uart_async_to_irq_irq_callback_set(const struct device *dev,
272 : uart_irq_callback_user_data_t cb,
273 : void *user_data);
274 :
275 : /** @endcond */
276 :
277 : #ifdef __cplusplus
278 : }
279 : #endif
280 :
281 : /** @} */
282 :
283 : #endif /* ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_TO_IRQ_H_ */
|