1 /*
2  * Copyright (c) 2018 Cypress
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT cypress_psoc6_uart
7 
8 /** @file
9  * @brief UART driver for Cypress PSOC 6 MCU family.
10  *
11  * Note:
12  * - Error handling is not implemented.
13  * - The driver works only in polling mode, interrupt mode is not implemented.
14  */
15 #include <zephyr/drivers/uart.h>
16 #include <zephyr/drivers/pinctrl.h>
17 #include <soc.h>
18 
19 #include "cy_syslib.h"
20 #include "cy_sysclk.h"
21 #include "cy_scb_uart.h"
22 #include "cy_sysint.h"
23 
24 /* UART desired baud rate is 115200 bps (Standard mode).
25  * The UART baud rate = (SCB clock frequency / Oversample).
26  * For PeriClk = 50 MHz, select divider value 36 and get
27  * SCB clock = (50 MHz / 36) = 1,389 MHz.
28  * Select Oversample = 12.
29  * These setting results UART data rate = 1,389 MHz / 12 = 115750 bps.
30  */
31 #define UART_PSOC6_CONFIG_OVERSAMPLE      (12UL)
32 #define UART_PSOC6_CONFIG_BREAKWIDTH      (11UL)
33 #define UART_PSOC6_CONFIG_DATAWIDTH       (8UL)
34 
35 /* Assign divider type and number for UART */
36 #define UART_PSOC6_UART_CLK_DIV_TYPE     (CY_SYSCLK_DIV_8_BIT)
37 #define UART_PSOC6_UART_CLK_DIV_NUMBER   (PERI_DIV_8_NR - 1u)
38 #define UART_PSOC6_UART_CLK_DIV_VAL      (35UL)
39 
40 /*
41  * Verify Kconfig configuration
42  */
43 
44 struct cypress_psoc6_config {
45 	CySCB_Type *base;
46 	uint32_t periph_id;
47 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
48 	uart_irq_config_func_t	irq_config_func;
49 #endif
50 	const struct pinctrl_dev_config *pcfg;
51 };
52 
53 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
54 struct cypress_psoc6_data {
55 	uart_irq_callback_user_data_t irq_cb;	/* Interrupt Callback */
56 	void *irq_cb_data;			/* Interrupt Callback Arg */
57 };
58 
59 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
60 
61 /* Populate configuration structure */
62 static const cy_stc_scb_uart_config_t uartConfig = {
63 	.uartMode                   = CY_SCB_UART_STANDARD,
64 	.enableMutliProcessorMode   = false,
65 	.smartCardRetryOnNack       = false,
66 	.irdaInvertRx               = false,
67 	.irdaEnableLowPowerReceiver = false,
68 
69 	.oversample                 = UART_PSOC6_CONFIG_OVERSAMPLE,
70 
71 	.enableMsbFirst             = false,
72 	.dataWidth                  = UART_PSOC6_CONFIG_DATAWIDTH,
73 	.parity                     = CY_SCB_UART_PARITY_NONE,
74 	.stopBits                   = CY_SCB_UART_STOP_BITS_1,
75 	.enableInputFilter          = false,
76 	.breakWidth                 = UART_PSOC6_CONFIG_BREAKWIDTH,
77 	.dropOnFrameError           = false,
78 	.dropOnParityError          = false,
79 
80 	.receiverAddress            = 0UL,
81 	.receiverAddressMask        = 0UL,
82 	.acceptAddrInFifo           = false,
83 
84 	.enableCts                  = false,
85 	.ctsPolarity                = CY_SCB_UART_ACTIVE_LOW,
86 	.rtsRxFifoLevel             = 0UL,
87 	.rtsPolarity                = CY_SCB_UART_ACTIVE_LOW,
88 
89 	.rxFifoTriggerLevel  = 0UL,
90 	.rxFifoIntEnableMask = 0UL,
91 	.txFifoTriggerLevel  = 0UL,
92 	.txFifoIntEnableMask = 0UL,
93 };
94 
95 /**
96  * Function Name: uart_psoc6_init()
97  *
98  *  Performs hardware initialization: debug UART.
99  *
100  */
uart_psoc6_init(const struct device * dev)101 static int uart_psoc6_init(const struct device *dev)
102 {
103 	int ret;
104 	const struct cypress_psoc6_config *config = dev->config;
105 
106 	/* Configure dt provided device signals when available */
107 	ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
108 	if (ret < 0) {
109 		return ret;
110 	}
111 
112 	/* Connect assigned divider to be a clock source for UART */
113 	Cy_SysClk_PeriphAssignDivider(config->periph_id,
114 		UART_PSOC6_UART_CLK_DIV_TYPE,
115 		UART_PSOC6_UART_CLK_DIV_NUMBER);
116 
117 	Cy_SysClk_PeriphSetDivider(UART_PSOC6_UART_CLK_DIV_TYPE,
118 		UART_PSOC6_UART_CLK_DIV_NUMBER,
119 		UART_PSOC6_UART_CLK_DIV_VAL);
120 	Cy_SysClk_PeriphEnableDivider(UART_PSOC6_UART_CLK_DIV_TYPE,
121 		UART_PSOC6_UART_CLK_DIV_NUMBER);
122 
123 	/* Configure UART to operate */
124 	(void) Cy_SCB_UART_Init(config->base, &uartConfig, NULL);
125 	Cy_SCB_UART_Enable(config->base);
126 
127 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
128 	config->irq_config_func(dev);
129 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
130 
131 	return 0;
132 }
133 
uart_psoc6_poll_in(const struct device * dev,unsigned char * c)134 static int uart_psoc6_poll_in(const struct device *dev, unsigned char *c)
135 {
136 	const struct cypress_psoc6_config *config = dev->config;
137 	uint32_t rec;
138 
139 	rec = Cy_SCB_UART_Get(config->base);
140 	*c = (unsigned char)(rec & 0xff);
141 
142 	return ((rec == CY_SCB_UART_RX_NO_DATA) ? -1 : 0);
143 }
144 
uart_psoc6_poll_out(const struct device * dev,unsigned char c)145 static void uart_psoc6_poll_out(const struct device *dev, unsigned char c)
146 {
147 	const struct cypress_psoc6_config *config = dev->config;
148 
149 	while (Cy_SCB_UART_Put(config->base, (uint32_t)c) != 1UL) {
150 	}
151 }
152 
uart_psoc6_err_check(const struct device * dev)153 static int uart_psoc6_err_check(const struct device *dev)
154 {
155 	const struct cypress_psoc6_config *config = dev->config;
156 	uint32_t status = Cy_SCB_UART_GetRxFifoStatus(config->base);
157 	int errors = 0;
158 
159 	if (status & CY_SCB_UART_RX_OVERFLOW) {
160 		errors |= UART_ERROR_OVERRUN;
161 	}
162 
163 	if (status & CY_SCB_UART_RX_ERR_PARITY) {
164 		errors |= UART_ERROR_PARITY;
165 	}
166 
167 	if (status & CY_SCB_UART_RX_ERR_FRAME) {
168 		errors |= UART_ERROR_FRAMING;
169 	}
170 
171 	return errors;
172 }
173 
174 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
175 
uart_psoc6_fifo_fill(const struct device * dev,const uint8_t * tx_data,int size)176 static int uart_psoc6_fifo_fill(const struct device *dev,
177 				const uint8_t *tx_data,
178 				int size)
179 {
180 	const struct cypress_psoc6_config *config = dev->config;
181 
182 	return Cy_SCB_UART_PutArray(config->base, (uint8_t *) tx_data, size);
183 }
184 
uart_psoc6_fifo_read(const struct device * dev,uint8_t * rx_data,const int size)185 static int uart_psoc6_fifo_read(const struct device *dev,
186 				uint8_t *rx_data,
187 				const int size)
188 {
189 	const struct cypress_psoc6_config *config = dev->config;
190 
191 	return Cy_SCB_UART_GetArray(config->base, rx_data, size);
192 }
193 
uart_psoc6_irq_tx_enable(const struct device * dev)194 static void uart_psoc6_irq_tx_enable(const struct device *dev)
195 {
196 	const struct cypress_psoc6_config *config = dev->config;
197 
198 	Cy_SCB_SetTxInterruptMask(config->base, CY_SCB_UART_TX_EMPTY);
199 }
200 
uart_psoc6_irq_tx_disable(const struct device * dev)201 static void uart_psoc6_irq_tx_disable(const struct device *dev)
202 {
203 	const struct cypress_psoc6_config *config = dev->config;
204 
205 	Cy_SCB_SetTxInterruptMask(config->base, 0);
206 }
207 
uart_psoc6_irq_tx_ready(const struct device * dev)208 static int uart_psoc6_irq_tx_ready(const struct device *dev)
209 {
210 	const struct cypress_psoc6_config *config = dev->config;
211 	uint32_t status = Cy_SCB_UART_GetTxFifoStatus(config->base);
212 
213 	Cy_SCB_UART_ClearTxFifoStatus(config->base, CY_SCB_UART_TX_INTR_MASK);
214 
215 	return (status & CY_SCB_UART_TX_NOT_FULL);
216 }
217 
uart_psoc6_irq_tx_complete(const struct device * dev)218 static int uart_psoc6_irq_tx_complete(const struct device *dev)
219 {
220 	const struct cypress_psoc6_config *config = dev->config;
221 	uint32_t status = Cy_SCB_UART_GetTxFifoStatus(config->base);
222 
223 	Cy_SCB_UART_ClearTxFifoStatus(config->base, CY_SCB_UART_TX_INTR_MASK);
224 
225 	return (status & CY_SCB_UART_TX_DONE);
226 }
227 
uart_psoc6_irq_rx_enable(const struct device * dev)228 static void uart_psoc6_irq_rx_enable(const struct device *dev)
229 {
230 	const struct cypress_psoc6_config *config = dev->config;
231 
232 	Cy_SCB_SetRxInterruptMask(config->base, CY_SCB_UART_RX_NOT_EMPTY);
233 }
234 
uart_psoc6_irq_rx_disable(const struct device * dev)235 static void uart_psoc6_irq_rx_disable(const struct device *dev)
236 {
237 	const struct cypress_psoc6_config *config = dev->config;
238 
239 	Cy_SCB_SetRxInterruptMask(config->base, 0);
240 }
241 
uart_psoc6_irq_rx_ready(const struct device * dev)242 static int uart_psoc6_irq_rx_ready(const struct device *dev)
243 {
244 	const struct cypress_psoc6_config *config = dev->config;
245 	uint32_t status = Cy_SCB_UART_GetRxFifoStatus(config->base);
246 
247 	Cy_SCB_UART_ClearRxFifoStatus(config->base, CY_SCB_UART_RX_INTR_MASK);
248 
249 	return (status & CY_SCB_UART_RX_NOT_EMPTY);
250 }
251 
uart_psoc6_irq_err_enable(const struct device * dev)252 static void uart_psoc6_irq_err_enable(const struct device *dev)
253 {
254 	const struct cypress_psoc6_config *config = dev->config;
255 	uint32_t intmask = Cy_SCB_GetRxInterruptMask(config->base) |
256 			   CY_SCB_UART_RECEIVE_ERR;
257 
258 	Cy_SCB_SetRxInterruptMask(config->base, intmask);
259 }
260 
uart_psoc6_irq_err_disable(const struct device * dev)261 static void uart_psoc6_irq_err_disable(const struct device *dev)
262 {
263 	const struct cypress_psoc6_config *config = dev->config;
264 	uint32_t intmask = Cy_SCB_GetRxInterruptMask(config->base) &
265 			    ~(CY_SCB_UART_RECEIVE_ERR);
266 
267 	Cy_SCB_SetRxInterruptMask(config->base, intmask);
268 }
269 
uart_psoc6_irq_is_pending(const struct device * dev)270 static int uart_psoc6_irq_is_pending(const struct device *dev)
271 {
272 	const struct cypress_psoc6_config *config = dev->config;
273 	uint32_t intcause = Cy_SCB_GetInterruptCause(config->base);
274 
275 	return (intcause & (CY_SCB_TX_INTR | CY_SCB_RX_INTR));
276 }
277 
uart_psoc6_irq_update(const struct device * dev)278 static int uart_psoc6_irq_update(const struct device *dev)
279 {
280 	ARG_UNUSED(dev);
281 
282 	return 1;
283 }
284 
uart_psoc6_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)285 static void uart_psoc6_irq_callback_set(const struct device *dev,
286 					uart_irq_callback_user_data_t cb,
287 					void *cb_data)
288 {
289 	struct cypress_psoc6_data *const dev_data = dev->data;
290 
291 	dev_data->irq_cb = cb;
292 	dev_data->irq_cb_data = cb_data;
293 }
294 
uart_psoc6_isr(const struct device * dev)295 static void uart_psoc6_isr(const struct device *dev)
296 {
297 	struct cypress_psoc6_data *const dev_data = dev->data;
298 
299 	if (dev_data->irq_cb) {
300 		dev_data->irq_cb(dev, dev_data->irq_cb_data);
301 	}
302 }
303 
304 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
305 
306 static DEVICE_API(uart, uart_psoc6_driver_api) = {
307 	.poll_in = uart_psoc6_poll_in,
308 	.poll_out = uart_psoc6_poll_out,
309 	.err_check = uart_psoc6_err_check,
310 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
311 	.fifo_fill = uart_psoc6_fifo_fill,
312 	.fifo_read = uart_psoc6_fifo_read,
313 	.irq_tx_enable = uart_psoc6_irq_tx_enable,
314 	.irq_tx_disable = uart_psoc6_irq_tx_disable,
315 	.irq_tx_ready = uart_psoc6_irq_tx_ready,
316 	.irq_rx_enable = uart_psoc6_irq_rx_enable,
317 	.irq_rx_disable = uart_psoc6_irq_rx_disable,
318 	.irq_tx_complete = uart_psoc6_irq_tx_complete,
319 	.irq_rx_ready = uart_psoc6_irq_rx_ready,
320 	.irq_err_enable = uart_psoc6_irq_err_enable,
321 	.irq_err_disable = uart_psoc6_irq_err_disable,
322 	.irq_is_pending = uart_psoc6_irq_is_pending,
323 	.irq_update = uart_psoc6_irq_update,
324 	.irq_callback_set = uart_psoc6_irq_callback_set,
325 #endif	/* CONFIG_UART_INTERRUPT_DRIVEN */
326 };
327 
328 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
329 #define CY_PSOC6_UART_IRQ_FUNC(n)						\
330 	static void cy_psoc6_uart##n##_irq_config(const struct device *port)	\
331 	{									\
332 		CY_PSOC6_DT_INST_NVIC_INSTALL(n,				\
333 					      uart_psoc6_isr);			\
334 	};
335 #define CY_PSOC6_UART_IRQ_SET_FUNC(n)						\
336 	.irq_config_func = cy_psoc6_uart##n##_irq_config
337 #define CY_PSOC6_UART_DECL_DATA(n)						\
338 	static struct cypress_psoc6_data cy_psoc6_uart##n##_data = { 0 };
339 #define CY_PSOC6_UART_DECL_DATA_PTR(n) &cy_psoc6_uart##n##_data
340 #else
341 #define CY_PSOC6_UART_IRQ_FUNC(n)
342 #define CY_PSOC6_UART_IRQ_SET_FUNC(n)
343 #define CY_PSOC6_UART_DECL_DATA(n)
344 #define CY_PSOC6_UART_DECL_DATA_PTR(n) NULL
345 #endif
346 
347 #define CY_PSOC6_UART_INIT(n)							\
348 	PINCTRL_DT_INST_DEFINE(n);					        \
349 	CY_PSOC6_UART_DECL_DATA(n)						\
350 	CY_PSOC6_UART_IRQ_FUNC(n)						\
351 	static const struct cypress_psoc6_config cy_psoc6_uart##n##_config = {	\
352 		.base = (CySCB_Type *)DT_INST_REG_ADDR(n),			\
353 		.periph_id = DT_INST_PROP(n, peripheral_id),			\
354 		.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),			\
355 										\
356 		CY_PSOC6_UART_IRQ_SET_FUNC(n)					\
357 	};									\
358 	DEVICE_DT_INST_DEFINE(n, &uart_psoc6_init, NULL,			\
359 			      CY_PSOC6_UART_DECL_DATA_PTR(n),			\
360 			      &cy_psoc6_uart##n##_config, PRE_KERNEL_1,		\
361 			      CONFIG_SERIAL_INIT_PRIORITY,			\
362 			      &uart_psoc6_driver_api);
363 
364 DT_INST_FOREACH_STATUS_OKAY(CY_PSOC6_UART_INIT)
365