From db8ddef03ad96b2c88739665fdf3161a5e65ba28 Mon Sep 17 00:00:00 2001 From: HaiLong Yang Date: Mon, 8 Nov 2021 11:08:22 +0800 Subject: [PATCH 1/2] drivers: serial: gd32 usart parity bit config Initialize parity bit(Default NONE) from DTS. Signed-off-by: HaiLong Yang --- drivers/serial/usart_gd32.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/serial/usart_gd32.c b/drivers/serial/usart_gd32.c index 16486ef769b25..d72375d7c9627 100644 --- a/drivers/serial/usart_gd32.c +++ b/drivers/serial/usart_gd32.c @@ -5,6 +5,7 @@ #define DT_DRV_COMPAT gd_gd32_usart +#include #include #include @@ -12,6 +13,7 @@ struct gd32_usart_config { uint32_t reg; uint32_t rcu_periph_clock; const struct pinctrl_dev_config *pcfg; + uint32_t parity; }; struct gd32_usart_data { @@ -22,6 +24,8 @@ static int usart_gd32_init(const struct device *dev) { const struct gd32_usart_config *const cfg = dev->config; struct gd32_usart_data *const data = dev->data; + uint32_t word_length; + uint32_t parity; int ret; ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); @@ -29,13 +33,34 @@ static int usart_gd32_init(const struct device *dev) return ret; } + /** + * In order to keep the transfer data size to 8 bits(1 byte), + * append word length to 9BIT if parity bit enabled. + */ + switch (cfg->parity) { + case UART_CFG_PARITY_NONE: + parity = USART_PM_NONE; + word_length = USART_WL_8BIT; + break; + case UART_CFG_PARITY_ODD: + parity = USART_PM_ODD; + word_length = USART_WL_9BIT; + break; + case UART_CFG_PARITY_EVEN: + parity = USART_PM_EVEN; + word_length = USART_WL_9BIT; + break; + default: + return -ENOTSUP; + } + rcu_periph_clock_enable(cfg->rcu_periph_clock); usart_deinit(cfg->reg); usart_baudrate_set(cfg->reg, data->baud_rate); - usart_word_length_set(cfg->reg, USART_WL_8BIT); - usart_parity_config(cfg->reg, USART_PM_NONE); + usart_parity_config(cfg->reg, parity); + usart_word_length_set(cfg->reg, word_length); + /* Default to 1 stop bit */ usart_stop_bit_set(cfg->reg, USART_STB_1BIT); - usart_parity_config(cfg->reg, USART_PM_NONE); usart_receive_config(cfg->reg, USART_RECEIVE_ENABLE); usart_transmit_config(cfg->reg, USART_TRANSMIT_ENABLE); usart_enable(cfg->reg); @@ -114,6 +139,8 @@ static const struct uart_driver_api usart_gd32_driver_api = { .reg = DT_INST_REG_ADDR(n), \ .rcu_periph_clock = DT_INST_PROP(n, rcu_periph_clock), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .parity = DT_ENUM_IDX_OR(DT_DRV_INST(n), parity, \ + UART_CFG_PARITY_NONE), \ }; \ DEVICE_DT_INST_DEFINE(n, &usart_gd32_init, \ NULL, \ From 4dd3ae9ea226e2d07087511dbe0e95e64052064a Mon Sep 17 00:00:00 2001 From: HaiLong Yang Date: Sun, 14 Nov 2021 14:53:55 +0800 Subject: [PATCH 2/2] drivers: serial: gd32 usart add interrupt support Add interrupt support for gd32 usart driver. Signed-off-by: HaiLong Yang --- drivers/serial/Kconfig.gd32 | 1 + drivers/serial/usart_gd32.c | 183 +++++++++++++++++++++- dts/arm/gigadevice/gd32f403/gd32f403.dtsi | 52 +++++- dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi | 66 +++++++- dts/bindings/serial/gd,gd32-usart.yaml | 3 + 5 files changed, 292 insertions(+), 13 deletions(-) diff --git a/drivers/serial/Kconfig.gd32 b/drivers/serial/Kconfig.gd32 index 4cadbd139cdfb..56b823ce0eb13 100644 --- a/drivers/serial/Kconfig.gd32 +++ b/drivers/serial/Kconfig.gd32 @@ -9,6 +9,7 @@ config USART_GD32 default $(dt_compat_enabled,$(DT_COMPAT_GIGADEVICE_GD32_USART)) depends on SOC_FAMILY_GD32 select SERIAL_HAS_DRIVER + select SERIAL_SUPPORT_INTERRUPT select USE_GD32_USART help This option enables the USART driver for GD32 SoC family. diff --git a/drivers/serial/usart_gd32.c b/drivers/serial/usart_gd32.c index d72375d7c9627..8da839684d926 100644 --- a/drivers/serial/usart_gd32.c +++ b/drivers/serial/usart_gd32.c @@ -14,12 +14,30 @@ struct gd32_usart_config { uint32_t rcu_periph_clock; const struct pinctrl_dev_config *pcfg; uint32_t parity; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_config_func_t irq_config_func; +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ }; struct gd32_usart_data { uint32_t baud_rate; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_callback_user_data_t user_cb; + void *user_data; +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ }; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +static void usart_gd32_isr(const struct device *dev) +{ + struct gd32_usart_data *const data = dev->data; + + if (data->user_cb) { + data->user_cb(dev, data->user_data); + } +} +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + static int usart_gd32_init(const struct device *dev) { const struct gd32_usart_config *const cfg = dev->config; @@ -65,6 +83,10 @@ static int usart_gd32_init(const struct device *dev) usart_transmit_config(cfg->reg, USART_TRANSMIT_ENABLE); usart_enable(cfg->reg); +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + cfg->irq_config_func(dev); +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + return 0; } @@ -124,29 +146,180 @@ static int usart_gd32_err_check(const struct device *dev) return errors; } +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +int usart_gd32_fifo_fill(const struct device *dev, const uint8_t *tx_data, + int len) +{ + const struct gd32_usart_config *const cfg = dev->config; + uint8_t num_tx = 0U; + + while ((len - num_tx > 0) && + usart_flag_get(cfg->reg, USART_FLAG_TBE)) { + usart_data_transmit(cfg->reg, tx_data[num_tx++]); + } + + return num_tx; +} + +int usart_gd32_fifo_read(const struct device *dev, uint8_t *rx_data, + const int size) +{ + const struct gd32_usart_config *const cfg = dev->config; + uint8_t num_rx = 0U; + + while ((size - num_rx > 0) && + usart_flag_get(cfg->reg, USART_FLAG_RBNE)) { + rx_data[num_rx++] = usart_data_receive(cfg->reg); + } + + return num_rx; +} + +void usart_gd32_irq_tx_enable(const struct device *dev) +{ + const struct gd32_usart_config *const cfg = dev->config; + + usart_interrupt_enable(cfg->reg, USART_INT_TC); +} + +void usart_gd32_irq_tx_disable(const struct device *dev) +{ + const struct gd32_usart_config *const cfg = dev->config; + + usart_interrupt_disable(cfg->reg, USART_INT_TC); +} + +int usart_gd32_irq_tx_ready(const struct device *dev) +{ + const struct gd32_usart_config *const cfg = dev->config; + + return usart_flag_get(cfg->reg, USART_FLAG_TBE) && + usart_interrupt_flag_get(cfg->reg, USART_INT_FLAG_TC); +} + +int usart_gd32_irq_tx_complete(const struct device *dev) +{ + const struct gd32_usart_config *const cfg = dev->config; + + return usart_flag_get(cfg->reg, USART_FLAG_TC); +} + +void usart_gd32_irq_rx_enable(const struct device *dev) +{ + const struct gd32_usart_config *const cfg = dev->config; + + usart_interrupt_enable(cfg->reg, USART_INT_RBNE); +} + +void usart_gd32_irq_rx_disable(const struct device *dev) +{ + const struct gd32_usart_config *const cfg = dev->config; + + usart_interrupt_disable(cfg->reg, USART_INT_RBNE); +} + +int usart_gd32_irq_rx_ready(const struct device *dev) +{ + const struct gd32_usart_config *const cfg = dev->config; + + return usart_flag_get(cfg->reg, USART_FLAG_RBNE); +} + +void usart_gd32_irq_err_enable(const struct device *dev) +{ + const struct gd32_usart_config *const cfg = dev->config; + + usart_interrupt_enable(cfg->reg, USART_INT_ERR); + usart_interrupt_enable(cfg->reg, USART_INT_PERR); +} + +void usart_gd32_irq_err_disable(const struct device *dev) +{ + const struct gd32_usart_config *const cfg = dev->config; + + usart_interrupt_disable(cfg->reg, USART_INT_ERR); + usart_interrupt_disable(cfg->reg, USART_INT_PERR); +} + +int usart_gd32_irq_is_pending(const struct device *dev) +{ + const struct gd32_usart_config *const cfg = dev->config; + + return ((usart_flag_get(cfg->reg, USART_FLAG_RBNE) && + usart_interrupt_flag_get(cfg->reg, USART_INT_FLAG_RBNE)) || + (usart_flag_get(cfg->reg, USART_FLAG_TC) && + usart_interrupt_flag_get(cfg->reg, USART_INT_FLAG_TC))); +} + +void usart_gd32_irq_callback_set(const struct device *dev, + uart_irq_callback_user_data_t cb, + void *user_data) +{ + struct gd32_usart_data *const data = dev->data; + + data->user_cb = cb; + data->user_data = user_data; +} +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + static const struct uart_driver_api usart_gd32_driver_api = { .poll_in = usart_gd32_poll_in, .poll_out = usart_gd32_poll_out, .err_check = usart_gd32_err_check, +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = usart_gd32_fifo_fill, + .fifo_read = usart_gd32_fifo_read, + .irq_tx_enable = usart_gd32_irq_tx_enable, + .irq_tx_disable = usart_gd32_irq_tx_disable, + .irq_tx_ready = usart_gd32_irq_tx_ready, + .irq_tx_complete = usart_gd32_irq_tx_complete, + .irq_rx_enable = usart_gd32_irq_rx_enable, + .irq_rx_disable = usart_gd32_irq_rx_disable, + .irq_rx_ready = usart_gd32_irq_rx_ready, + .irq_err_enable = usart_gd32_irq_err_enable, + .irq_err_disable = usart_gd32_irq_err_disable, + .irq_is_pending = usart_gd32_irq_is_pending, + .irq_callback_set = usart_gd32_irq_callback_set, +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ }; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +#define GD32_USART_IRQ_HANDLER(n) \ + static void usart_gd32_config_func_##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + usart_gd32_isr, \ + DEVICE_DT_INST_GET(n), \ + 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } +#define GD32_USART_IRQ_HANDLER_FUNC_INIT(n) \ + .irq_config_func = usart_gd32_config_func_##n +#else /* CONFIG_UART_INTERRUPT_DRIVEN */ +#define GD32_USART_IRQ_HANDLER(n) +#define GD32_USART_IRQ_HANDLER_FUNC_INIT(n) +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + #define GD32_USART_INIT(n) \ PINCTRL_DT_INST_DEFINE(n) \ - static struct gd32_usart_data usart##n##_gd32_data = { \ + GD32_USART_IRQ_HANDLER(n) \ + static struct gd32_usart_data usart_gd32_data_##n = { \ .baud_rate = DT_INST_PROP(n, current_speed), \ }; \ - static const struct gd32_usart_config usart##n##_gd32_config = { \ + static const struct gd32_usart_config usart_gd32_config_##n = { \ .reg = DT_INST_REG_ADDR(n), \ .rcu_periph_clock = DT_INST_PROP(n, rcu_periph_clock), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .parity = DT_ENUM_IDX_OR(DT_DRV_INST(n), parity, \ UART_CFG_PARITY_NONE), \ + GD32_USART_IRQ_HANDLER_FUNC_INIT(n) \ }; \ DEVICE_DT_INST_DEFINE(n, &usart_gd32_init, \ NULL, \ - &usart##n##_gd32_data, \ - &usart##n##_gd32_config, PRE_KERNEL_1, \ - CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &usart_gd32_data_##n, \ + &usart_gd32_config_##n, PRE_KERNEL_1, \ + CONFIG_SERIAL_INIT_PRIORITY, \ &usart_gd32_driver_api); DT_INST_FOREACH_STATUS_OKAY(GD32_USART_INIT) diff --git a/dts/arm/gigadevice/gd32f403/gd32f403.dtsi b/dts/arm/gigadevice/gd32f403/gd32f403.dtsi index 9aa5ea2e09711..aae5cf38ebd3f 100644 --- a/dts/arm/gigadevice/gd32f403/gd32f403.dtsi +++ b/dts/arm/gigadevice/gd32f403/gd32f403.dtsi @@ -46,6 +46,51 @@ }; }; + usart0: usart@40013800 { + compatible = "gd,gd32-usart"; + reg = <0x40013800 0x400>; + interrupts = <37 0>; + rcu-periph-clock = <0x60e>; + status = "disabled"; + label = "USART_0"; + }; + + usart1: usart@40004400 { + compatible = "gd,gd32-usart"; + reg = <0x40004400 0x400>; + interrupts = <38 0>; + rcu-periph-clock = <0x712>; + status = "disabled"; + label = "USART_1"; + }; + + usart2: usart@40004800 { + compatible = "gd,gd32-usart"; + reg = <0x40004800 0x400>; + interrupts = <39 0>; + rcu-periph-clock = <0x713>; + status = "disabled"; + label = "USART_2"; + }; + + uart3: usart@40004C00 { + compatible = "gd,gd32-usart"; + reg = <0x40004C00 0x400>; + interrupts = <52 0>; + rcu-periph-clock = <0x714>; + status = "disabled"; + label = "USART_3"; + }; + + uart4: usart@40005000 { + compatible = "gd,gd32-usart"; + reg = <0x40005000 0x400>; + interrupts = <53 0>; + rcu-periph-clock = <0x715>; + status = "disabled"; + label = "USART_4"; + }; + afio: afio@40010000 { compatible = "gd,gd32-afio"; reg = <0x40010000 0x400>; @@ -119,13 +164,6 @@ }; }; - usart0: usart@40013800 { - compatible = "gd,gd32-usart"; - reg = <0x40013800 0x400>; - rcu-periph-clock = <0x60e>; - status = "disabled"; - label = "usart_0"; - }; }; }; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi b/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi index f85500e262d20..d84dd989f9983 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi +++ b/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi @@ -49,9 +49,73 @@ usart0: usart@40011000 { compatible = "gd,gd32-usart"; reg = <0x40011000 0x400>; + interrupts = <37 0>; rcu-periph-clock = <0x1104>; status = "disabled"; - label = "USART0"; + label = "USART_0"; + }; + + usart1: usart@40004400 { + compatible = "gd,gd32-usart"; + reg = <0x40004400 0x400>; + interrupts = <38 0>; + rcu-periph-clock = <0x1011>; + status = "disabled"; + label = "USART_1"; + }; + + usart2: usart@40004800 { + compatible = "gd,gd32-usart"; + reg = <0x40004800 0x400>; + interrupts = <39 0>; + rcu-periph-clock = <0x1012>; + status = "disabled"; + label = "USART_2"; + }; + + uart3: usart@40004c00 { + compatible = "gd,gd32-usart"; + reg = <0x40004c00 0x400>; + interrupts = <52 0>; + rcu-periph-clock = <0x1013>; + status = "disabled"; + label = "USART_3"; + }; + + uart4: usart@40005000 { + compatible = "gd,gd32-usart"; + reg = <0x40005000 0x400>; + interrupts = <52 0>; + rcu-periph-clock = <0x1014>; + status = "disabled"; + label = "USART_4"; + }; + + usart5: usart@40011400 { + compatible = "gd,gd32-usart"; + reg = <0x40011400 0x400>; + interrupts = <71 0>; + rcu-periph-clock = <0x1105>; + status = "disabled"; + label = "USART_5"; + }; + + uart6: usart@40007800 { + compatible = "gd,gd32-usart"; + reg = <0x40007800 0x400>; + interrupts = <82 0>; + rcu-periph-clock = <0x101e>; + status = "disabled"; + label = "USART_6"; + }; + + uart7: usart@40007c00 { + compatible = "gd,gd32-usart"; + reg = <0x40007c00 0x400>; + interrupts = <83 0>; + rcu-periph-clock = <0x101f>; + status = "disabled"; + label = "USART_7"; }; pinctrl: pin-controller@40020000 { diff --git a/dts/bindings/serial/gd,gd32-usart.yaml b/dts/bindings/serial/gd,gd32-usart.yaml index 1110c3bea3305..e93455b54c3e6 100644 --- a/dts/bindings/serial/gd,gd32-usart.yaml +++ b/dts/bindings/serial/gd,gd32-usart.yaml @@ -11,6 +11,9 @@ properties: reg: required: true + interrupts: + required: true + rcu-periph-clock: type: int description: Reset Control Unit Peripheral Clock ID