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 dev UART device. Device must support asynchronous API.
113  *
114  * @retval 0 On successful initialization.
115  */
116 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 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 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_ */
284