drivers: serial: gd32 usart add interrupt support
Add interrupt support for gd32 usart driver. Signed-off-by: HaiLong Yang <hailong.yang@brainco.cn>
This commit is contained in:
parent
9418a4f763
commit
5e035b0f4e
5 changed files with 292 additions and 13 deletions
|
@ -9,6 +9,7 @@ config USART_GD32
|
||||||
default $(dt_compat_enabled,$(DT_COMPAT_GIGADEVICE_GD32_USART))
|
default $(dt_compat_enabled,$(DT_COMPAT_GIGADEVICE_GD32_USART))
|
||||||
depends on SOC_FAMILY_GD32
|
depends on SOC_FAMILY_GD32
|
||||||
select SERIAL_HAS_DRIVER
|
select SERIAL_HAS_DRIVER
|
||||||
|
select SERIAL_SUPPORT_INTERRUPT
|
||||||
select USE_GD32_USART
|
select USE_GD32_USART
|
||||||
help
|
help
|
||||||
This option enables the USART driver for GD32 SoC family.
|
This option enables the USART driver for GD32 SoC family.
|
||||||
|
|
|
@ -14,12 +14,30 @@ struct gd32_usart_config {
|
||||||
uint32_t rcu_periph_clock;
|
uint32_t rcu_periph_clock;
|
||||||
const struct pinctrl_dev_config *pcfg;
|
const struct pinctrl_dev_config *pcfg;
|
||||||
uint32_t parity;
|
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 {
|
struct gd32_usart_data {
|
||||||
uint32_t baud_rate;
|
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)
|
static int usart_gd32_init(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct gd32_usart_config *const cfg = dev->config;
|
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_transmit_config(cfg->reg, USART_TRANSMIT_ENABLE);
|
||||||
usart_enable(cfg->reg);
|
usart_enable(cfg->reg);
|
||||||
|
|
||||||
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
|
cfg->irq_config_func(dev);
|
||||||
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,29 +146,180 @@ static int usart_gd32_err_check(const struct device *dev)
|
||||||
return errors;
|
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 = {
|
static const struct uart_driver_api usart_gd32_driver_api = {
|
||||||
.poll_in = usart_gd32_poll_in,
|
.poll_in = usart_gd32_poll_in,
|
||||||
.poll_out = usart_gd32_poll_out,
|
.poll_out = usart_gd32_poll_out,
|
||||||
.err_check = usart_gd32_err_check,
|
.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) \
|
#define GD32_USART_INIT(n) \
|
||||||
PINCTRL_DT_INST_DEFINE(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), \
|
.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), \
|
.reg = DT_INST_REG_ADDR(n), \
|
||||||
.rcu_periph_clock = DT_INST_PROP(n, rcu_periph_clock), \
|
.rcu_periph_clock = DT_INST_PROP(n, rcu_periph_clock), \
|
||||||
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
|
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
|
||||||
.parity = DT_ENUM_IDX_OR(DT_DRV_INST(n), parity, \
|
.parity = DT_ENUM_IDX_OR(DT_DRV_INST(n), parity, \
|
||||||
UART_CFG_PARITY_NONE), \
|
UART_CFG_PARITY_NONE), \
|
||||||
|
GD32_USART_IRQ_HANDLER_FUNC_INIT(n) \
|
||||||
}; \
|
}; \
|
||||||
DEVICE_DT_INST_DEFINE(n, &usart_gd32_init, \
|
DEVICE_DT_INST_DEFINE(n, &usart_gd32_init, \
|
||||||
NULL, \
|
NULL, \
|
||||||
&usart##n##_gd32_data, \
|
&usart_gd32_data_##n, \
|
||||||
&usart##n##_gd32_config, PRE_KERNEL_1, \
|
&usart_gd32_config_##n, PRE_KERNEL_1, \
|
||||||
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
|
CONFIG_SERIAL_INIT_PRIORITY, \
|
||||||
&usart_gd32_driver_api);
|
&usart_gd32_driver_api);
|
||||||
|
|
||||||
DT_INST_FOREACH_STATUS_OKAY(GD32_USART_INIT)
|
DT_INST_FOREACH_STATUS_OKAY(GD32_USART_INIT)
|
||||||
|
|
|
@ -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 {
|
afio: afio@40010000 {
|
||||||
compatible = "gd,gd32-afio";
|
compatible = "gd,gd32-afio";
|
||||||
reg = <0x40010000 0x400>;
|
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";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -49,9 +49,73 @@
|
||||||
usart0: usart@40011000 {
|
usart0: usart@40011000 {
|
||||||
compatible = "gd,gd32-usart";
|
compatible = "gd,gd32-usart";
|
||||||
reg = <0x40011000 0x400>;
|
reg = <0x40011000 0x400>;
|
||||||
|
interrupts = <37 0>;
|
||||||
rcu-periph-clock = <0x1104>;
|
rcu-periph-clock = <0x1104>;
|
||||||
status = "disabled";
|
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 {
|
pinctrl: pin-controller@40020000 {
|
||||||
|
|
|
@ -11,6 +11,9 @@ properties:
|
||||||
reg:
|
reg:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
required: true
|
||||||
|
|
||||||
rcu-periph-clock:
|
rcu-periph-clock:
|
||||||
type: int
|
type: int
|
||||||
description: Reset Control Unit Peripheral Clock ID
|
description: Reset Control Unit Peripheral Clock ID
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue