1 /*
2  * Copyright (c) 2017, NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_kinetis_lpsci
8 
9 #include <errno.h>
10 #include <zephyr/device.h>
11 #include <zephyr/drivers/uart.h>
12 #include <zephyr/drivers/clock_control.h>
13 #include <zephyr/drivers/pinctrl.h>
14 #include <fsl_lpsci.h>
15 #include <soc.h>
16 #include <zephyr/irq.h>
17 
18 struct mcux_lpsci_config {
19 	UART0_Type *base;
20 	const struct device *clock_dev;
21 	clock_control_subsys_t clock_subsys;
22 	uint32_t baud_rate;
23 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
24 	void (*irq_config_func)(const struct device *dev);
25 #endif
26 	const struct pinctrl_dev_config *pincfg;
27 };
28 
29 struct mcux_lpsci_data {
30 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
31 	uart_irq_callback_user_data_t callback;
32 	void *cb_data;
33 #endif
34 };
35 
mcux_lpsci_poll_in(const struct device * dev,unsigned char * c)36 static int mcux_lpsci_poll_in(const struct device *dev, unsigned char *c)
37 {
38 	const struct mcux_lpsci_config *config = dev->config;
39 	uint32_t flags = LPSCI_GetStatusFlags(config->base);
40 	int ret = -1;
41 
42 	if (flags & kLPSCI_RxDataRegFullFlag) {
43 		*c = LPSCI_ReadByte(config->base);
44 		ret = 0;
45 	}
46 
47 	return ret;
48 }
49 
mcux_lpsci_poll_out(const struct device * dev,unsigned char c)50 static void mcux_lpsci_poll_out(const struct device *dev, unsigned char c)
51 {
52 	const struct mcux_lpsci_config *config = dev->config;
53 
54 	while (!(LPSCI_GetStatusFlags(config->base)
55 		& kLPSCI_TxDataRegEmptyFlag)) {
56 	}
57 
58 	LPSCI_WriteByte(config->base, c);
59 }
60 
mcux_lpsci_err_check(const struct device * dev)61 static int mcux_lpsci_err_check(const struct device *dev)
62 {
63 	const struct mcux_lpsci_config *config = dev->config;
64 	uint32_t flags = LPSCI_GetStatusFlags(config->base);
65 	int err = 0;
66 
67 	if (flags & kLPSCI_RxOverrunFlag) {
68 		err |= UART_ERROR_OVERRUN;
69 	}
70 
71 	if (flags & kLPSCI_ParityErrorFlag) {
72 		err |= UART_ERROR_PARITY;
73 	}
74 
75 	if (flags & kLPSCI_FramingErrorFlag) {
76 		err |= UART_ERROR_FRAMING;
77 	}
78 
79 	LPSCI_ClearStatusFlags(config->base, kLPSCI_RxOverrunFlag |
80 					      kLPSCI_ParityErrorFlag |
81 					      kLPSCI_FramingErrorFlag);
82 
83 	return err;
84 }
85 
86 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
mcux_lpsci_fifo_fill(const struct device * dev,const uint8_t * tx_data,int len)87 static int mcux_lpsci_fifo_fill(const struct device *dev,
88 				const uint8_t *tx_data,
89 				int len)
90 {
91 	const struct mcux_lpsci_config *config = dev->config;
92 	uint8_t num_tx = 0U;
93 
94 	while ((len - num_tx > 0) &&
95 	       (LPSCI_GetStatusFlags(config->base)
96 		& kLPSCI_TxDataRegEmptyFlag)) {
97 
98 		LPSCI_WriteByte(config->base, tx_data[num_tx++]);
99 	}
100 
101 	return num_tx;
102 }
103 
mcux_lpsci_fifo_read(const struct device * dev,uint8_t * rx_data,const int len)104 static int mcux_lpsci_fifo_read(const struct device *dev, uint8_t *rx_data,
105 				const int len)
106 {
107 	const struct mcux_lpsci_config *config = dev->config;
108 	uint8_t num_rx = 0U;
109 
110 	while ((len - num_rx > 0) &&
111 	       (LPSCI_GetStatusFlags(config->base)
112 		& kLPSCI_RxDataRegFullFlag)) {
113 
114 		rx_data[num_rx++] = LPSCI_ReadByte(config->base);
115 	}
116 
117 	return num_rx;
118 }
119 
mcux_lpsci_irq_tx_enable(const struct device * dev)120 static void mcux_lpsci_irq_tx_enable(const struct device *dev)
121 {
122 	const struct mcux_lpsci_config *config = dev->config;
123 	uint32_t mask = kLPSCI_TxDataRegEmptyInterruptEnable;
124 
125 	LPSCI_EnableInterrupts(config->base, mask);
126 }
127 
mcux_lpsci_irq_tx_disable(const struct device * dev)128 static void mcux_lpsci_irq_tx_disable(const struct device *dev)
129 {
130 	const struct mcux_lpsci_config *config = dev->config;
131 	uint32_t mask = kLPSCI_TxDataRegEmptyInterruptEnable;
132 
133 	LPSCI_DisableInterrupts(config->base, mask);
134 }
135 
mcux_lpsci_irq_tx_complete(const struct device * dev)136 static int mcux_lpsci_irq_tx_complete(const struct device *dev)
137 {
138 	const struct mcux_lpsci_config *config = dev->config;
139 	uint32_t flags = LPSCI_GetStatusFlags(config->base);
140 
141 	return (flags & kLPSCI_TransmissionCompleteFlag) != 0U;
142 }
143 
mcux_lpsci_irq_tx_ready(const struct device * dev)144 static int mcux_lpsci_irq_tx_ready(const struct device *dev)
145 {
146 	const struct mcux_lpsci_config *config = dev->config;
147 	uint32_t mask = kLPSCI_TxDataRegEmptyInterruptEnable;
148 	uint32_t flags = LPSCI_GetStatusFlags(config->base);
149 
150 	return (LPSCI_GetEnabledInterrupts(config->base) & mask)
151 		&& (flags & kLPSCI_TxDataRegEmptyFlag);
152 }
153 
mcux_lpsci_irq_rx_enable(const struct device * dev)154 static void mcux_lpsci_irq_rx_enable(const struct device *dev)
155 {
156 	const struct mcux_lpsci_config *config = dev->config;
157 	uint32_t mask = kLPSCI_RxDataRegFullInterruptEnable;
158 
159 	LPSCI_EnableInterrupts(config->base, mask);
160 }
161 
mcux_lpsci_irq_rx_disable(const struct device * dev)162 static void mcux_lpsci_irq_rx_disable(const struct device *dev)
163 {
164 	const struct mcux_lpsci_config *config = dev->config;
165 	uint32_t mask = kLPSCI_RxDataRegFullInterruptEnable;
166 
167 	LPSCI_DisableInterrupts(config->base, mask);
168 }
169 
mcux_lpsci_irq_rx_full(const struct device * dev)170 static int mcux_lpsci_irq_rx_full(const struct device *dev)
171 {
172 	const struct mcux_lpsci_config *config = dev->config;
173 	uint32_t flags = LPSCI_GetStatusFlags(config->base);
174 
175 	return (flags & kLPSCI_RxDataRegFullFlag) != 0U;
176 }
177 
mcux_lpsci_irq_rx_pending(const struct device * dev)178 static int mcux_lpsci_irq_rx_pending(const struct device *dev)
179 {
180 	const struct mcux_lpsci_config *config = dev->config;
181 	uint32_t mask = kLPSCI_RxDataRegFullInterruptEnable;
182 
183 	return (LPSCI_GetEnabledInterrupts(config->base) & mask)
184 		&& mcux_lpsci_irq_rx_full(dev);
185 }
186 
mcux_lpsci_irq_err_enable(const struct device * dev)187 static void mcux_lpsci_irq_err_enable(const struct device *dev)
188 {
189 	const struct mcux_lpsci_config *config = dev->config;
190 	uint32_t mask = kLPSCI_NoiseErrorInterruptEnable |
191 			kLPSCI_FramingErrorInterruptEnable |
192 			kLPSCI_ParityErrorInterruptEnable;
193 
194 	LPSCI_EnableInterrupts(config->base, mask);
195 }
196 
mcux_lpsci_irq_err_disable(const struct device * dev)197 static void mcux_lpsci_irq_err_disable(const struct device *dev)
198 {
199 	const struct mcux_lpsci_config *config = dev->config;
200 	uint32_t mask = kLPSCI_NoiseErrorInterruptEnable |
201 			kLPSCI_FramingErrorInterruptEnable |
202 			kLPSCI_ParityErrorInterruptEnable;
203 
204 	LPSCI_DisableInterrupts(config->base, mask);
205 }
206 
mcux_lpsci_irq_is_pending(const struct device * dev)207 static int mcux_lpsci_irq_is_pending(const struct device *dev)
208 {
209 	return (mcux_lpsci_irq_tx_ready(dev)
210 		|| mcux_lpsci_irq_rx_pending(dev));
211 }
212 
mcux_lpsci_irq_update(const struct device * dev)213 static int mcux_lpsci_irq_update(const struct device *dev)
214 {
215 	return 1;
216 }
217 
mcux_lpsci_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)218 static void mcux_lpsci_irq_callback_set(const struct device *dev,
219 					uart_irq_callback_user_data_t cb,
220 					void *cb_data)
221 {
222 	struct mcux_lpsci_data *data = dev->data;
223 
224 	data->callback = cb;
225 	data->cb_data = cb_data;
226 }
227 
mcux_lpsci_isr(const struct device * dev)228 static void mcux_lpsci_isr(const struct device *dev)
229 {
230 	struct mcux_lpsci_data *data = dev->data;
231 
232 	if (data->callback) {
233 		data->callback(dev, data->cb_data);
234 	}
235 }
236 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
237 
mcux_lpsci_init(const struct device * dev)238 static int mcux_lpsci_init(const struct device *dev)
239 {
240 	const struct mcux_lpsci_config *config = dev->config;
241 	lpsci_config_t uart_config;
242 	uint32_t clock_freq;
243 	int err;
244 
245 	if (!device_is_ready(config->clock_dev)) {
246 		return -ENODEV;
247 	}
248 
249 	if (clock_control_get_rate(config->clock_dev, config->clock_subsys,
250 				   &clock_freq)) {
251 		return -EINVAL;
252 	}
253 
254 	LPSCI_GetDefaultConfig(&uart_config);
255 	uart_config.enableTx = true;
256 	uart_config.enableRx = true;
257 	uart_config.baudRate_Bps = config->baud_rate;
258 
259 	LPSCI_Init(config->base, &uart_config, clock_freq);
260 
261 	err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
262 	if (err < 0) {
263 		return err;
264 	}
265 
266 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
267 	config->irq_config_func(dev);
268 #endif
269 
270 	return 0;
271 }
272 
273 static const struct uart_driver_api mcux_lpsci_driver_api = {
274 	.poll_in = mcux_lpsci_poll_in,
275 	.poll_out = mcux_lpsci_poll_out,
276 	.err_check = mcux_lpsci_err_check,
277 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
278 	.fifo_fill = mcux_lpsci_fifo_fill,
279 	.fifo_read = mcux_lpsci_fifo_read,
280 	.irq_tx_enable = mcux_lpsci_irq_tx_enable,
281 	.irq_tx_disable = mcux_lpsci_irq_tx_disable,
282 	.irq_tx_complete = mcux_lpsci_irq_tx_complete,
283 	.irq_tx_ready = mcux_lpsci_irq_tx_ready,
284 	.irq_rx_enable = mcux_lpsci_irq_rx_enable,
285 	.irq_rx_disable = mcux_lpsci_irq_rx_disable,
286 	.irq_rx_ready = mcux_lpsci_irq_rx_full,
287 	.irq_err_enable = mcux_lpsci_irq_err_enable,
288 	.irq_err_disable = mcux_lpsci_irq_err_disable,
289 	.irq_is_pending = mcux_lpsci_irq_is_pending,
290 	.irq_update = mcux_lpsci_irq_update,
291 	.irq_callback_set = mcux_lpsci_irq_callback_set,
292 #endif
293 };
294 
295 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
296 #define MCUX_LPSCI_CONFIG_FUNC(n)					\
297 	static void mcux_lpsci_config_func_##n(const struct device *dev)	\
298 	{								\
299 		IRQ_CONNECT(DT_INST_IRQN(n),				\
300 			    DT_INST_IRQ(n, priority),			\
301 			    mcux_lpsci_isr, DEVICE_DT_INST_GET(n), 0);	\
302 									\
303 		irq_enable(DT_INST_IRQN(n));				\
304 	}
305 #define MCUX_LPSCI_IRQ_CFG_FUNC_INIT(n)					\
306 	.irq_config_func = mcux_lpsci_config_func_##n
307 #define MCUX_LPSCI_INIT_CFG(n)						\
308 	MCUX_LPSCI_DECLARE_CFG(n, MCUX_LPSCI_IRQ_CFG_FUNC_INIT(n))
309 #else
310 #define MCUX_LPSCI_CONFIG_FUNC(n)
311 #define MCUX_LPSCI_IRQ_CFG_FUNC_INIT
312 #define MCUX_LPSCI_INIT_CFG(n)						\
313 	MCUX_LPSCI_DECLARE_CFG(n, MCUX_LPSCI_IRQ_CFG_FUNC_INIT)
314 #endif
315 
316 #define MCUX_LPSCI_DECLARE_CFG(n, IRQ_FUNC_INIT)			\
317 static const struct mcux_lpsci_config mcux_lpsci_##n##_config = {	\
318 	.base = (UART0_Type *)DT_INST_REG_ADDR(n),			\
319 	.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)),		\
320 	.clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name),\
321 	.baud_rate = DT_INST_PROP(n, current_speed),			\
322 	.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),			\
323 	IRQ_FUNC_INIT							\
324 }
325 
326 #define MCUX_LPSCI_INIT(n)						\
327 	PINCTRL_DT_INST_DEFINE(n);					\
328 									\
329 	static struct mcux_lpsci_data mcux_lpsci_##n##_data;		\
330 									\
331 	static const struct mcux_lpsci_config mcux_lpsci_##n##_config;	\
332 									\
333 	DEVICE_DT_INST_DEFINE(n,					\
334 			    &mcux_lpsci_init,				\
335 			    NULL,					\
336 			    &mcux_lpsci_##n##_data,			\
337 			    &mcux_lpsci_##n##_config,			\
338 			    PRE_KERNEL_1,				\
339 			    CONFIG_SERIAL_INIT_PRIORITY,		\
340 			    &mcux_lpsci_driver_api);			\
341 									\
342 	MCUX_LPSCI_CONFIG_FUNC(n)					\
343 									\
344 	MCUX_LPSCI_INIT_CFG(n);
345 
346 DT_INST_FOREACH_STATUS_OKAY(MCUX_LPSCI_INIT)
347