Skip to content

Commit 124a2f5

Browse files
drivers: serial: add Infineon PSOC4 UART support
Add initial implementation of the Infineon PSOC4 UART driver based on the Peripheral Driver Library (PDL) for PSOC4 (PSoC 4100TP) devices. Features: - UART transmit and receive using PDL SCB UART APIs - Configurable baud rate, parity, stop bits, and data bits from devicetree - Pinctrl integration for TX/RX pins - Support for Zephyr console and shell subsystems - Build-time validation for UART configuration parameters Signed-off-by: Dharun krithik k <[email protected]> Signed-off-by: Sayooj K Karun <[email protected]> Signed-off-by: Manojkumar Konisetty <[email protected]> Signed-off-by: Deepika aerlync <[email protected]>
1 parent 6204c09 commit 124a2f5

File tree

2 files changed

+146
-106
lines changed

2 files changed

+146
-106
lines changed

drivers/serial/uart_ifx_cat1_pdl.c

Lines changed: 57 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212

1313
#define DT_DRV_COMPAT infineon_cat1_uart_pdl
1414

15+
#include <zephyr/logging/log.h>
16+
LOG_MODULE_REGISTER(uart_ifx, CONFIG_UART_LOG_LEVEL);
17+
1518
#include <string.h>
1619
#include <zephyr/irq.h>
1720
#include <zephyr/drivers/uart.h>
@@ -26,13 +29,14 @@
2629

2730
#include <zephyr/drivers/clock_control/clock_control_ifx_cat1.h>
2831
#include <zephyr/dt-bindings/clock/ifx_clock_source_common.h>
32+
#include <zephyr/drivers/serial/uart_ifx.h>
2933

30-
#include <zephyr/logging/log.h>
31-
LOG_MODULE_REGISTER(uart_ifx_cat1, CONFIG_UART_LOG_LEVEL);
32-
33-
#define IFX_CAT1_UART_OVERSAMPLE_MIN 8UL
34-
#define IFX_CAT1_UART_OVERSAMPLE_MAX 16UL
35-
#define IFX_CAT1_UART_MAX_BAUD_PERCENT_DIFFERENCE 10
34+
#define IFX_UART_RX_FIFO_TRIGGER_LEVEL_A 63UL
35+
#define IFX_UART_TX_FIFO_TRIGGER_LEVEL_A 63UL
36+
#define IFX_UART_RX_FIFO_TRIGGER_LEVEL_B 7
37+
#define IFX_UART_TX_FIFO_TRIGGER_LEVEL_B 0
38+
#define IFX_UART_RX_INT_MASK 0UL
39+
#define IFX_UART_TX_INT_MASK 0UL
3640

3741
/* Data structure */
3842
struct ifx_cat1_uart_data {
@@ -65,80 +69,11 @@ struct ifx_cat1_uart_config {
6569

6670
typedef void (*ifx_cat1_uart_event_callback_t)(void *callback_arg);
6771

68-
/* Helper API */
69-
static cy_en_scb_uart_parity_t convert_uart_parity_z_to_cy(const enum uart_config_parity parity)
70-
{
71-
cy_en_scb_uart_parity_t cy_parity;
72-
73-
switch (parity) {
74-
case UART_CFG_PARITY_NONE:
75-
cy_parity = CY_SCB_UART_PARITY_NONE;
76-
break;
77-
case UART_CFG_PARITY_ODD:
78-
cy_parity = CY_SCB_UART_PARITY_ODD;
79-
break;
80-
case UART_CFG_PARITY_EVEN:
81-
cy_parity = CY_SCB_UART_PARITY_EVEN;
82-
break;
83-
default:
84-
cy_parity = CY_SCB_UART_PARITY_NONE;
85-
}
86-
return cy_parity;
87-
}
88-
89-
static uint8_t convert_uart_stop_bits_z_to_cy(const enum uart_config_stop_bits stop_bits)
90-
{
91-
uint32_t cy_stop_bits;
92-
93-
switch (stop_bits) {
94-
case UART_CFG_STOP_BITS_1:
95-
cy_stop_bits = CY_SCB_UART_STOP_BITS_1;
96-
break;
97-
98-
case UART_CFG_STOP_BITS_2:
99-
cy_stop_bits = CY_SCB_UART_STOP_BITS_2;
100-
break;
101-
default:
102-
cy_stop_bits = CY_SCB_UART_STOP_BITS_1;
103-
}
104-
return cy_stop_bits;
105-
}
106-
107-
static uint32_t convert_uart_data_bits_z_to_cy(const enum uart_config_data_bits data_bits)
108-
{
109-
uint32_t cy_data_bits;
110-
111-
switch (data_bits) {
112-
case UART_CFG_DATA_BITS_5:
113-
cy_data_bits = 5u;
114-
break;
115-
116-
case UART_CFG_DATA_BITS_6:
117-
cy_data_bits = 6u;
118-
break;
119-
120-
case UART_CFG_DATA_BITS_7:
121-
cy_data_bits = 7u;
122-
break;
123-
124-
case UART_CFG_DATA_BITS_8:
125-
cy_data_bits = 8u;
126-
break;
127-
128-
case UART_CFG_DATA_BITS_9:
129-
cy_data_bits = 9u;
130-
break;
131-
132-
default:
133-
cy_data_bits = 1u;
134-
}
135-
return cy_data_bits;
136-
}
137-
13872
#if defined(CONFIG_SOC_FAMILY_INFINEON_EDGE)
13973
#define IFX_CAT1_INSTANCE_GROUP(instance, group) (((instance) << 4) | (group))
14074
#endif
14175

76+
#if !defined(CONFIG_SOC_FAMILY_INFINEON_PSOC4)
14277
static uint8_t ifx_cat1_get_hfclk_for_peri_group(uint8_t peri_group)
14378
{
14479
#if defined(CONFIG_SOC_SERIES_PSE84)
@@ -190,14 +125,15 @@ static uint8_t ifx_cat1_get_hfclk_for_peri_group(uint8_t peri_group)
190125
#endif
191126
return -EINVAL;
192127
}
128+
#endif
193129

194130
cy_rslt_t ifx_cat1_uart_set_baud(const struct device *dev, uint32_t baudrate)
195131
{
196132
cy_rslt_t status;
197133
struct ifx_cat1_uart_data *data = dev->data;
198134
const struct ifx_cat1_uart_config *const config = dev->config;
199135

200-
uint8_t best_oversample = IFX_CAT1_UART_OVERSAMPLE_MIN;
136+
uint8_t best_oversample = IFX_UART_OVERSAMPLE_MIN;
201137
uint8_t best_difference = 0xFF;
202138
uint32_t divider;
203139

@@ -216,32 +152,28 @@ cy_rslt_t ifx_cat1_uart_set_baud(const struct device *dev, uint32_t baudrate)
216152
uint8_t hfclk = ifx_cat1_get_hfclk_for_peri_group(data->clock_peri_group);
217153

218154
peri_frequency = Cy_SysClk_ClkHfGetFrequency(hfclk);
155+
#else
156+
peri_frequency = Cy_SysClk_ClkHfGetFrequency();
219157
#endif
220-
221-
for (uint8_t i = IFX_CAT1_UART_OVERSAMPLE_MIN; i < IFX_CAT1_UART_OVERSAMPLE_MAX + 1; i++) {
158+
for (uint8_t i = IFX_UART_OVERSAMPLE_MIN; i < IFX_UART_OVERSAMPLE_MAX + 1; i++) {
222159
uint32_t tmp_divider = ((peri_frequency + ((baudrate * i) / 2))) / (baudrate * i);
223160

224161
uint32_t actual_baud = (peri_frequency / (tmp_divider * i));
225-
uint8_t difference = (actual_baud > baudrate)
226-
? ((actual_baud * 100) - (baudrate * 100)) / baudrate
227-
: ((baudrate * 100) - (actual_baud * 100)) / baudrate;
162+
uint8_t difference = ifx_uart_baud_diff(actual_baud, baudrate);
228163

229164
if (difference < best_difference) {
230165
best_difference = difference;
231166
best_oversample = i;
232167
}
233168
}
234169

235-
if (best_difference > IFX_CAT1_UART_MAX_BAUD_PERCENT_DIFFERENCE) {
170+
if (best_difference > IFX_UART_MAX_BAUD_PERCENT_DIFFERENCE) {
236171
status = -EINVAL;
237172
}
238173

239-
best_oversample = best_oversample;
240-
241174
data->scb_config.oversample = best_oversample;
242175

243-
divider = ((peri_frequency + ((baudrate * best_oversample) / 2)) /
244-
(baudrate * best_oversample));
176+
divider = ifx_uart_divider(peri_frequency, baudrate, best_oversample);
245177

246178
en_clk_dst_t clk_idx = ifx_cat1_scb_get_clock_index(data->hw_resource.block_num);
247179

@@ -253,15 +185,15 @@ cy_rslt_t ifx_cat1_uart_set_baud(const struct device *dev, uint32_t baudrate)
253185
divider - 1, 0);
254186
}
255187

188+
if (status < 0) {
189+
return status;
190+
}
191+
256192
/* Configure the UART interface */
257193
#if (CY_IP_MXSCB_VERSION >= 2) || (CY_IP_MXS22SCB_VERSION >= 1)
258-
uint32_t mem_width = (data->scb_config.dataWidth <= CY_SCB_BYTE_WIDTH)
259-
? CY_SCB_MEM_WIDTH_BYTE
260-
: CY_SCB_MEM_WIDTH_HALFWORD;
261-
262194
SCB_CTRL(config->reg_addr) =
263195
_BOOL2FLD(SCB_CTRL_ADDR_ACCEPT, data->scb_config.acceptAddrInFifo) |
264-
_BOOL2FLD(SCB_CTRL_MEM_WIDTH, mem_width) |
196+
_BOOL2FLD(SCB_CTRL_MEM_WIDTH, ifx_uart_mem_width(data->scb_config.dataWidth)) |
265197
_VAL2FLD(SCB_CTRL_OVS, best_oversample - 1) |
266198
_VAL2FLD(SCB_CTRL_MODE, CY_SCB_CTRL_MODE_UART);
267199
#else /* Older versions of the block */
@@ -337,6 +269,22 @@ static int ifx_cat1_uart_err_check(const struct device *dev)
337269
return errors;
338270
}
339271

272+
const uint8_t data_bits_lut[] = {
273+
[UART_CFG_DATA_BITS_5] = 5, [UART_CFG_DATA_BITS_6] = 6, [UART_CFG_DATA_BITS_7] = 7,
274+
[UART_CFG_DATA_BITS_8] = 8, [UART_CFG_DATA_BITS_9] = 9,
275+
};
276+
277+
const uint8_t stop_bits_lut[] = {
278+
[UART_CFG_STOP_BITS_1] = CY_SCB_UART_STOP_BITS_1,
279+
[UART_CFG_STOP_BITS_2] = CY_SCB_UART_STOP_BITS_2,
280+
};
281+
282+
const uint8_t parity_lut[] = {
283+
[UART_CFG_PARITY_NONE] = CY_SCB_UART_PARITY_NONE,
284+
[UART_CFG_PARITY_ODD] = CY_SCB_UART_PARITY_ODD,
285+
[UART_CFG_PARITY_EVEN] = CY_SCB_UART_PARITY_EVEN,
286+
};
287+
340288
static int ifx_cat1_uart_configure(const struct device *dev, const struct uart_config *cfg)
341289
{
342290
__ASSERT_NO_MSG(cfg != NULL);
@@ -494,7 +442,7 @@ static int ifx_cat1_uart_irq_tx_complete(const struct device *dev)
494442
const struct ifx_cat1_uart_config *const config = dev->config;
495443

496444
return Cy_SCB_IsTxComplete(config->reg_addr) ||
497-
(0UL == (data->context.txStatus & CY_SCB_UART_TRANSMIT_ACTIVE));
445+
((data->context.txStatus & CY_SCB_UART_TRANSMIT_ACTIVE) == 0);
498446
}
499447

500448
static void ifx_cat1_uart_irq_rx_enable(const struct device *dev)
@@ -628,28 +576,32 @@ static const cy_stc_scb_uart_config_t _uart_default_config = {
628576
.breakWidth = 11UL,
629577
.dropOnFrameError = false,
630578
.dropOnParityError = false,
579+
#if !defined(CONFIG_SOC_SERIES_PSOC4100TP)
631580
.breaklevel = false,
581+
#else
582+
.breakLevel = false,
583+
#endif
632584
.receiverAddress = 0x0UL,
633585
.receiverAddressMask = 0x0UL,
634586
.acceptAddrInFifo = false,
635587
.enableCts = false,
636588
.ctsPolarity = CY_SCB_UART_ACTIVE_LOW,
637589
.rtsRxFifoLevel = 0UL,
638590
.rtsPolarity = CY_SCB_UART_ACTIVE_LOW,
639-
.rxFifoTriggerLevel = 63UL,
640-
.rxFifoIntEnableMask = 0UL,
641-
.txFifoTriggerLevel = 63UL,
642-
.txFifoIntEnableMask = 0UL,
591+
#if !defined(CONFIG_SOC_SERIES_PSOC4100TP)
592+
.rxFifoTriggerLevel = IFX_UART_RX_FIFO_TRIGGER_LEVEL_A,
593+
#else
594+
.rxFifoTriggerLevel = IFX_UART_RX_FIFO_TRIGGER_LEVEL_B,
595+
#endif
596+
.rxFifoIntEnableMask = IFX_UART_RX_INT_MASK,
597+
#if !defined(CONFIG_SOC_SERIES_PSOC4100TP)
598+
.txFifoTriggerLevel = IFX_UART_TX_FIFO_TRIGGER_LEVEL_A,
599+
#else
600+
.txFifoTriggerLevel = IFX_UART_TX_FIFO_TRIGGER_LEVEL_B,
601+
#endif
602+
.txFifoIntEnableMask = IFX_UART_TX_INT_MASK,
643603
};
644604

645-
#if defined(CY_IP_MXSCB_INSTANCES)
646-
#define _IFX_CAT1_SCB_ARRAY_SIZE (CY_IP_MXSCB_INSTANCES)
647-
#elif defined(CY_IP_M0S8SCB_INSTANCES)
648-
#define _IFX_CAT1_SCB_ARRAY_SIZE (CY_IP_M0S8SCB_INSTANCES)
649-
#elif defined(CY_IP_MXS22SCB_INSTANCES)
650-
#define _IFX_CAT1_SCB_ARRAY_SIZE (CY_IP_MXS22SCB_INSTANCES)
651-
#endif /* CY_IP_MXSCB_INSTANCES */
652-
653605
CySCB_Type *const _IFX_CAT1_SCB_BASE_ADDRESSES[_IFX_CAT1_SCB_ARRAY_SIZE] = {
654606
#ifdef SCB0
655607
SCB0,
@@ -834,7 +786,6 @@ static DEVICE_API(uart, ifx_cat1_uart_driver_api) = {
834786
.irq_update = ifx_cat1_uart_irq_update,
835787
.irq_callback_set = ifx_cat1_uart_irq_callback_set,
836788
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
837-
838789
};
839790

840791
#if (CONFIG_SOC_FAMILY_INFINEON_CAT1C)
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright (c) 2025 Infineon Technologies AG,
3+
* or an affiliate of Infineon Technologies AG.
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#ifndef IFX_UART_H
9+
#define IFX_UART_H
10+
11+
#include <zephyr/drivers/uart.h>
12+
#include <zephyr/drivers/pinctrl.h>
13+
#include <stdint.h>
14+
#include <stdbool.h>
15+
16+
#include <cy_scb_uart.h>
17+
#include <cy_device_headers.h>
18+
#include <cy_sysint.h>
19+
#include <cy_sysclk.h>
20+
#include <zephyr/logging/log.h>
21+
22+
#define IFX_UART_OVERSAMPLE_MIN 8UL
23+
#define IFX_UART_OVERSAMPLE_MAX 16UL
24+
#define IFX_UART_MAX_BAUD_PERCENT_DIFFERENCE 10U
25+
26+
#if defined(CY_IP_MXSCB_INSTANCES)
27+
#define _IFX_CAT1_SCB_ARRAY_SIZE (CY_IP_MXSCB_INSTANCES)
28+
#elif defined(CY_IP_M0S8SCB_INSTANCES)
29+
#define _IFX_CAT1_SCB_ARRAY_SIZE (CY_IP_M0S8SCB_INSTANCES)
30+
#elif defined(CY_IP_MXS22SCB_INSTANCES)
31+
#define _IFX_CAT1_SCB_ARRAY_SIZE (CY_IP_MXS22SCB_INSTANCES)
32+
#endif /* CY_IP_MXSCB_INSTANCES */
33+
34+
extern const uint8_t data_bits_lut[];
35+
extern const uint8_t stop_bits_lut[];
36+
extern const uint8_t parity_lut[];
37+
38+
static inline uint32_t convert_uart_parity_z_to_cy(uint32_t parity)
39+
{
40+
switch (parity) {
41+
case UART_CFG_PARITY_NONE:
42+
return CY_SCB_UART_PARITY_NONE;
43+
case UART_CFG_PARITY_ODD:
44+
return CY_SCB_UART_PARITY_ODD;
45+
case UART_CFG_PARITY_EVEN:
46+
return CY_SCB_UART_PARITY_EVEN;
47+
default:
48+
return CY_SCB_UART_PARITY_NONE;
49+
}
50+
}
51+
52+
static inline uint32_t convert_uart_stop_bits_z_to_cy(uint32_t sb)
53+
{
54+
if (sb <= UART_CFG_STOP_BITS_2) {
55+
return stop_bits_lut[sb];
56+
}
57+
58+
LOG_WRN("Invalid stop bits (%u), defaulting to 1 stop bit", sb);
59+
return CY_SCB_UART_STOP_BITS_1;
60+
}
61+
62+
static inline uint32_t convert_uart_data_bits_z_to_cy(uint32_t db)
63+
{
64+
if (db <= UART_CFG_DATA_BITS_9) {
65+
return data_bits_lut[db];
66+
}
67+
68+
LOG_WRN("Invalid data bits (%u), defaulting to 1 bit", db);
69+
return 1U;
70+
}
71+
72+
static inline uint32_t ifx_uart_baud_diff(uint32_t actual, uint32_t baud)
73+
{
74+
return (actual > baud) ? (((actual - baud) * 100U) / baud)
75+
: (((baud - actual) * 100U) / baud);
76+
}
77+
78+
static inline uint32_t ifx_uart_divider(uint32_t freq, uint32_t baud, uint32_t oversample)
79+
{
80+
return (freq + ((baud * oversample) / 2U)) / (baud * oversample);
81+
}
82+
83+
static inline uint32_t ifx_uart_mem_width(uint32_t data_width)
84+
{
85+
return (data_width <= CY_SCB_BYTE_WIDTH) ? CY_SCB_CTRL_MEM_WIDTH_BYTE
86+
: CY_SCB_CTRL_MEM_WIDTH_HALFWORD;
87+
}
88+
89+
#endif /* IFX_UART_H */

0 commit comments

Comments
 (0)