From 62a49211b158066cad133f8a08df75d3ad03a577 Mon Sep 17 00:00:00 2001 From: Marcelo Roberto Jimenez Date: Mon, 8 Dec 2025 23:16:41 -0300 Subject: [PATCH] drivers: serial: uart_xmc4xxx: Enable run time configuration This patch enables run time configuration for the XMC4xxx serial ports. Signed-off-by: Marcelo Roberto Jimenez --- .../xmc45_relax_kit/xmc45_relax_kit.dts | 2 + .../xmc47_relax_kit/xmc47_relax_kit.dts | 4 + drivers/serial/uart_xmc4xxx.c | 206 +++++++++++++++++- .../boards/xmc45_relax_kit.overlay | 2 + .../boards/xmc47_relax_kit.overlay | 2 + 5 files changed, 213 insertions(+), 3 deletions(-) diff --git a/boards/infineon/xmc45_relax_kit/xmc45_relax_kit.dts b/boards/infineon/xmc45_relax_kit/xmc45_relax_kit.dts index b578d244bea..f5f1dc32b53 100644 --- a/boards/infineon/xmc45_relax_kit/xmc45_relax_kit.dts +++ b/boards/infineon/xmc45_relax_kit/xmc45_relax_kit.dts @@ -111,6 +111,8 @@ fifo-start-offset = <0>; fifo-tx-size = <16>; fifo-rx-size = <16>; + data-bits = <8>; + stop-bits = "1"; status = "okay"; }; diff --git a/boards/infineon/xmc47_relax_kit/xmc47_relax_kit.dts b/boards/infineon/xmc47_relax_kit/xmc47_relax_kit.dts index 11bd2f42e3c..528142633a2 100644 --- a/boards/infineon/xmc47_relax_kit/xmc47_relax_kit.dts +++ b/boards/infineon/xmc47_relax_kit/xmc47_relax_kit.dts @@ -102,6 +102,8 @@ fifo-start-offset = <0>; fifo-tx-size = <16>; fifo-rx-size = <16>; + data-bits = <8>; + stop-bits = "1"; status = "okay"; }; @@ -116,6 +118,8 @@ fifo-start-offset = <0>; fifo-tx-size = <0>; fifo-rx-size = <0>; + data-bits = <8>; + stop-bits = "1"; status = "okay"; }; diff --git a/drivers/serial/uart_xmc4xxx.c b/drivers/serial/uart_xmc4xxx.c index 074cee62ad1..d132589d206 100644 --- a/drivers/serial/uart_xmc4xxx.c +++ b/drivers/serial/uart_xmc4xxx.c @@ -53,6 +53,7 @@ struct uart_dma_stream { struct uart_xmc4xxx_data { XMC_UART_CH_CONFIG_t config; + struct uart_config *uart_cfg; #if defined(CONFIG_UART_INTERRUPT_DRIVEN) uart_irq_callback_user_data_t user_cb; void *user_data; @@ -102,6 +103,162 @@ static void uart_xmc4xxx_poll_out(const struct device *dev, unsigned char c) XMC_UART_CH_Transmit(config->uart, c); } +static int convert_config_xmc4xxx_to_zephyr(struct uart_config *zephyr, + const XMC_UART_CH_CONFIG_t *x) +{ + struct uart_config z; + + z.baudrate = x->baudrate; + + switch (x->parity_mode) { + case XMC_USIC_CH_PARITY_MODE_NONE: + z.parity = UART_CFG_PARITY_NONE; + break; + case XMC_USIC_CH_PARITY_MODE_ODD: + z.parity = UART_CFG_PARITY_ODD; + break; + case XMC_USIC_CH_PARITY_MODE_EVEN: + z.parity = UART_CFG_PARITY_EVEN; + break; + /* XMC4xxx has no support for MARK and SPACE parity */ + /* + * case XMC_USIC_CH_PARITY_MODE_MARK: + * z.parity = UART_CFG_PARITY_MARK; + * break; + * case XMC_USIC_CH_PARITY_MODE_SPACE: + * z.parity = UART_CFG_PARITY_SPACE; + * break; + */ + default: + return -EINVAL; + } + + switch (x->stop_bits) { + case 1: + z.stop_bits = UART_CFG_STOP_BITS_1; + break; + case 2: + z.stop_bits = UART_CFG_STOP_BITS_2; + break; + default: + return -EINVAL; + } + + switch (x->data_bits) { + case 5: + z.data_bits = UART_CFG_DATA_BITS_5; + break; + case 6: + z.data_bits = UART_CFG_DATA_BITS_6; + break; + case 7: + z.data_bits = UART_CFG_DATA_BITS_7; + break; + case 8: + z.data_bits = UART_CFG_DATA_BITS_8; + break; + case 9: + z.data_bits = UART_CFG_DATA_BITS_9; + break; + default: + return -EINVAL; + } + + z.flow_ctrl = UART_CFG_FLOW_CTRL_NONE; + + *zephyr = z; + + return 0; +} + +static int convert_config_zephyr_to_xmc4xxx(XMC_UART_CH_CONFIG_t *xmc, const struct uart_config *z) +{ + XMC_UART_CH_CONFIG_t x; + + x.baudrate = z->baudrate; + + /* When zero -> will always use "fractional divider mode". */ + x.normal_divider_mode = 0; + + switch (z->data_bits) { + case UART_CFG_DATA_BITS_5: + x.data_bits = 5; + break; + case UART_CFG_DATA_BITS_6: + x.data_bits = 6; + break; + case UART_CFG_DATA_BITS_7: + x.data_bits = 7; + break; + case UART_CFG_DATA_BITS_8: + x.data_bits = 8; + break; + case UART_CFG_DATA_BITS_9: + x.data_bits = 9; + break; + default: + return -EINVAL; + } + + /* When zero -> driver takes care. */ + x.frame_length = 0; + + switch (z->stop_bits) { + case UART_CFG_STOP_BITS_0_5: + x.stop_bits = 1; + return -EINVAL; + case UART_CFG_STOP_BITS_1: + x.stop_bits = 1; + break; + case UART_CFG_STOP_BITS_1_5: + x.stop_bits = 1; + return -EINVAL; + case UART_CFG_STOP_BITS_2: + x.stop_bits = 2; + break; + default: + x.stop_bits = 1; + return -EINVAL; + } + + /* When zero -> driver actual oversampling == 16 */ + x.oversampling = 0; + + switch (z->parity) { + case UART_CFG_PARITY_NONE: + x.parity_mode = XMC_USIC_CH_PARITY_MODE_NONE; + break; + case UART_CFG_PARITY_ODD: + x.parity_mode = XMC_USIC_CH_PARITY_MODE_ODD; + break; + case UART_CFG_PARITY_EVEN: + x.parity_mode = XMC_USIC_CH_PARITY_MODE_EVEN; + break; + case UART_CFG_PARITY_MARK: + x.parity_mode = UART_CFG_PARITY_NONE; + return -ENOTSUP; + case UART_CFG_PARITY_SPACE: + x.parity_mode = UART_CFG_PARITY_NONE; + return -ENOTSUP; + default: + return -EINVAL; + } + + switch (z->flow_ctrl) { + case UART_CFG_FLOW_CTRL_NONE: + break; + case UART_CFG_FLOW_CTRL_RTS_CTS: + case UART_CFG_FLOW_CTRL_DTR_DSR: + case UART_CFG_FLOW_CTRL_RS485: + return -ENOTSUP; + default: + return -EINVAL; + } + *xmc = x; + + return 0; +} + #if defined(CONFIG_UART_ASYNC_API) static inline void async_timer_start(struct k_work_delayable *work, int32_t timeout) { @@ -892,8 +1049,10 @@ static int uart_xmc4xxx_init(const struct device *dev) struct uart_xmc4xxx_data *data = dev->data; uint8_t fifo_offset = config->fifo_start_offset; - data->config.data_bits = 8U; - data->config.stop_bits = 1U; + ret = convert_config_zephyr_to_xmc4xxx(&data->config, data->uart_cfg); + if (ret) { + return ret; + } XMC_UART_CH_Init(config->uart, &(data->config)); @@ -941,9 +1100,41 @@ static int uart_xmc4xxx_init(const struct device *dev) return ret; } +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE +static int uart_xmc4xxx_configure(const struct device *dev, const struct uart_config *cfg) +{ + int ret; + struct uart_xmc4xxx_data *data = dev->data; + struct uart_config uart_cfg_bak = *data->uart_cfg; + + *data->uart_cfg = *cfg; + ret = uart_xmc4xxx_init(dev); + if (ret) { + *data->uart_cfg = uart_cfg_bak; + } + + return ret; +} + +static int uart_xmc4xxx_config_get(const struct device *dev, struct uart_config *cfg) +{ + int ret; + struct uart_xmc4xxx_data *data = dev->data; + + ret = convert_config_xmc4xxx_to_zephyr(data->uart_cfg, &data->config); + *cfg = *data->uart_cfg; + + return ret; +} +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ + static DEVICE_API(uart, uart_xmc4xxx_driver_api) = { .poll_in = uart_xmc4xxx_poll_in, .poll_out = uart_xmc4xxx_poll_out, +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE + .configure = uart_xmc4xxx_configure, + .config_get = uart_xmc4xxx_config_get, +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ #if defined(CONFIG_UART_INTERRUPT_DRIVEN) .fifo_fill = uart_xmc4xxx_fifo_fill, .fifo_read = uart_xmc4xxx_fifo_read, @@ -1018,8 +1209,17 @@ static DEVICE_API(uart, uart_xmc4xxx_driver_api) = { PINCTRL_DT_INST_DEFINE(index); \ XMC4XXX_IRQ_HANDLER(index) \ \ + static struct uart_config uart_cfg_##index = { \ + .baudrate = DT_INST_PROP(index, current_speed), \ + .parity = DT_INST_ENUM_IDX(index, parity), \ + .stop_bits = DT_INST_ENUM_IDX(index, stop_bits), \ + .data_bits = DT_INST_ENUM_IDX(index, data_bits), \ + .flow_ctrl = DT_INST_PROP(index, hw_flow_control) ? UART_CFG_FLOW_CTRL_RTS_CTS \ + : UART_CFG_FLOW_CTRL_NONE, \ + }; \ + \ static struct uart_xmc4xxx_data xmc4xxx_data_##index = { \ - .config.baudrate = DT_INST_PROP(index, current_speed), \ + .uart_cfg = &uart_cfg_##index, \ UART_DMA_CHANNEL(index, tx, MEMORY_TO_PERIPHERAL, 8, 1) \ UART_DMA_CHANNEL(index, rx, PERIPHERAL_TO_MEMORY, 1, 8)}; \ \ diff --git a/tests/drivers/uart/uart_async_api/boards/xmc45_relax_kit.overlay b/tests/drivers/uart/uart_async_api/boards/xmc45_relax_kit.overlay index 69ed39b0220..447c7e4cd40 100644 --- a/tests/drivers/uart/uart_async_api/boards/xmc45_relax_kit.overlay +++ b/tests/drivers/uart/uart_async_api/boards/xmc45_relax_kit.overlay @@ -15,6 +15,8 @@ dut: &usic2ch0 { fifo-start-offset = <0>; fifo-tx-size = <0>; fifo-rx-size = <0>; + data-bits = <8>; + stop-bits = "1"; status = "okay"; }; diff --git a/tests/drivers/uart/uart_async_api/boards/xmc47_relax_kit.overlay b/tests/drivers/uart/uart_async_api/boards/xmc47_relax_kit.overlay index a6db8e6f8d8..8697af51d43 100644 --- a/tests/drivers/uart/uart_async_api/boards/xmc47_relax_kit.overlay +++ b/tests/drivers/uart/uart_async_api/boards/xmc47_relax_kit.overlay @@ -20,6 +20,8 @@ dut: &usic1ch1 { fifo-start-offset = <0>; fifo-tx-size = <0>; fifo-rx-size = <0>; + data-bits = <8>; + stop-bits = "1"; }; &uart_tx_p3_15_u1c1 {