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