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