diff --git a/drivers/serial/Kconfig.renesas_rz b/drivers/serial/Kconfig.renesas_rz index 712529a7b20..ea904e2c2e5 100644 --- a/drivers/serial/Kconfig.renesas_rz +++ b/drivers/serial/Kconfig.renesas_rz @@ -6,6 +6,7 @@ config UART_RENESAS_RZ_SCIF default y depends on DT_HAS_RENESAS_RZ_SCIF_UART_ENABLED select SERIAL_HAS_DRIVER + select SERIAL_SUPPORT_INTERRUPT select USE_RZ_FSP_SCIF_UART select PINCTRL help diff --git a/drivers/serial/uart_renesas_rz_scif.c b/drivers/serial/uart_renesas_rz_scif.c index 6582fe425fa..92fe28cdc8f 100644 --- a/drivers/serial/uart_renesas_rz_scif.c +++ b/drivers/serial/uart_renesas_rz_scif.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "r_scif_uart.h" LOG_MODULE_REGISTER(rz_scif_uart); @@ -17,12 +18,36 @@ struct uart_rz_scif_config { const uart_api_t *fsp_api; }; +struct uart_rz_scif_int { + bool rxi_flag; + bool tei_flag; + bool rx_fifo_busy; + bool irq_rx_enable; + bool irq_tx_enable; + uint8_t rx_byte; + uint8_t tx_byte; + uart_event_t event; +}; + struct uart_rz_scif_data { struct uart_config uart_config; uart_cfg_t *fsp_cfg; + struct uart_rz_scif_int int_data; scif_uart_instance_ctrl_t *fsp_ctrl; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_callback_user_data_t callback; + void *callback_data; +#endif }; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +void scif_uart_rxi_isr(void); +void scif_uart_txi_isr(void); +void scif_uart_tei_isr(void); +void scif_uart_eri_isr(void); +void scif_uart_bri_isr(void); +#endif + static int uart_rz_scif_poll_in(const struct device *dev, unsigned char *c) { struct uart_rz_scif_data *data = dev->data; @@ -41,6 +66,9 @@ static void uart_rz_scif_poll_out(const struct device *dev, unsigned char c) { struct uart_rz_scif_data *data = dev->data; R_SCIFA0_Type *reg = data->fsp_ctrl->p_reg; + uint8_t key; + + key = irq_lock(); while (!reg->FSR_b.TDFE) { } @@ -49,28 +77,27 @@ static void uart_rz_scif_poll_out(const struct device *dev, unsigned char c) while (!reg->FSR_b.TEND) { } + + irq_unlock(key); } static int uart_rz_scif_err_check(const struct device *dev) { struct uart_rz_scif_data *data = dev->data; - R_SCIFA0_Type *reg = data->fsp_ctrl->p_reg; + uart_event_t event = data->int_data.event; + int err = 0; - const uint32_t fsr = reg->FSR; - const uint32_t lsr = reg->LSR; - int errors = 0; - - if ((lsr & R_SCIFA0_LSR_ORER_Msk) != 0) { - errors |= UART_ERROR_OVERRUN; + if (event & UART_EVENT_ERR_OVERFLOW) { + err |= UART_ERROR_OVERRUN; } - if ((fsr & R_SCIFA0_FSR_PER_Msk) != 0) { - errors |= UART_ERROR_PARITY; + if (event & UART_EVENT_ERR_FRAMING) { + err |= UART_ERROR_FRAMING; } - if ((fsr & R_SCIFA0_FSR_FER_Pos) != 0) { - errors |= UART_ERROR_FRAMING; + if (event & UART_EVENT_ERR_PARITY) { + err |= UART_ERROR_PARITY; } - return errors; + return err; } static int uart_rz_scif_apply_config(const struct device *dev) @@ -179,11 +206,6 @@ static int uart_rz_scif_configure(const struct device *dev, const struct uart_co return -EIO; } - R_SCIFA0_Type *reg = data->fsp_ctrl->p_reg; - /* Temporarily disable the DRI interrupt caused by receive data ready */ - /* TODO: support interrupt-driven api */ - reg->SCR_b.RIE = 0; - return err; } @@ -197,6 +219,187 @@ static int uart_rz_scif_config_get(const struct device *dev, struct uart_config #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + +static int uart_rz_scif_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size) +{ + struct uart_rz_scif_data *data = dev->data; + scif_uart_instance_ctrl_t *fsp_ctrl = data->fsp_ctrl; + + fsp_ctrl->tx_src_bytes = size; + fsp_ctrl->p_tx_src = tx_data; + + scif_uart_txi_isr(); + + return (size - fsp_ctrl->tx_src_bytes); +} + +static int uart_rz_scif_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) +{ + struct uart_rz_scif_data *data = dev->data; + + scif_uart_instance_ctrl_t *fsp_ctrl = data->fsp_ctrl; + + fsp_ctrl->rx_dest_bytes = size; + fsp_ctrl->p_rx_dest = rx_data; + + /* Read all available data in the FIFO */ + /* If there are more available data than required, they will be lost */ + if (data->int_data.rxi_flag) { + scif_uart_rxi_isr(); + } else { + scif_uart_tei_isr(); + } + + data->int_data.rx_fifo_busy = false; + + return (size - fsp_ctrl->rx_dest_bytes); +} + +static void uart_rz_scif_irq_rx_enable(const struct device *dev) +{ + const struct uart_rz_scif_config *config = dev->config; + struct uart_rz_scif_data *data = dev->data; + + data->int_data.irq_rx_enable = true; + + /* Prepare 1-byte buffer to receive, it will be overwritten by fifo read */ + config->fsp_api->read(data->fsp_ctrl, &(data->int_data.rx_byte), 1); +} + +static void uart_rz_scif_irq_rx_disable(const struct device *dev) +{ + struct uart_rz_scif_data *data = dev->data; + + data->int_data.irq_rx_enable = false; + data->int_data.rx_fifo_busy = false; +} + +static void uart_rz_scif_irq_tx_enable(const struct device *dev) +{ + struct uart_rz_scif_data *data = dev->data; + const struct uart_rz_scif_config *config = dev->config; + + data->int_data.irq_tx_enable = true; + + /* Trigger TX with a NULL frame */ + /* It is expected not to be sent, and will be overwritten by the fifo fill */ + data->int_data.tx_byte = '\0'; + config->fsp_api->write(data->fsp_ctrl, &data->int_data.tx_byte, 1); +} + +static void uart_rz_scif_irq_tx_disable(const struct device *dev) +{ + struct uart_rz_scif_data *data = dev->data; + + data->int_data.irq_tx_enable = false; +} + +static int uart_rz_scif_irq_tx_ready(const struct device *dev) +{ + struct uart_rz_scif_data *data = dev->data; + + return data->int_data.irq_tx_enable; +} + +static int uart_rz_scif_irq_rx_ready(const struct device *dev) +{ + struct uart_rz_scif_data *data = dev->data; + + return data->int_data.rx_fifo_busy && data->int_data.irq_rx_enable; +} + +static int uart_rz_scif_irq_is_pending(const struct device *dev) +{ + return (uart_rz_scif_irq_tx_ready(dev)) || (uart_rz_scif_irq_rx_ready(dev)); +} + +static void uart_rz_scif_irq_callback_set(const struct device *dev, + uart_irq_callback_user_data_t cb, void *cb_data) +{ + struct uart_rz_scif_data *data = dev->data; + + data->callback = cb; + data->callback_data = cb_data; +} + +static int uart_rz_scif_irq_update(const struct device *dev) +{ + ARG_UNUSED(dev); + return 1; +} + +static void uart_rz_scif_rxi_isr(const struct device *dev) +{ + struct uart_rz_scif_data *data = dev->data; + + data->int_data.rxi_flag = true; + data->int_data.rx_fifo_busy = true; + if (data->callback) { + data->callback(dev, data->callback_data); + } +} + +static void uart_rz_scif_txi_isr(const struct device *dev) +{ + struct uart_rz_scif_data *data = dev->data; + + data->int_data.tei_flag = false; + if (data->callback) { + data->callback(dev, data->callback_data); + } +} + +static void uart_rz_scif_tei_isr(const struct device *dev) +{ + struct uart_rz_scif_data *data = dev->data; + + if (data->int_data.tei_flag) { + scif_uart_tei_isr(); + } else { + data->int_data.rxi_flag = false; + data->int_data.rx_fifo_busy = true; + if (data->callback) { + data->callback(dev, data->callback_data); + } + } +} + +static void uart_rz_scif_eri_isr(const struct device *dev) +{ + scif_uart_eri_isr(); +} + +static void uart_rz_scif_bri_isr(const struct device *dev) +{ + scif_uart_bri_isr(); +} + +static void uart_rz_scif_event_handler(uart_callback_args_t *p_args) +{ + const struct device *dev = (const struct device *)p_args->p_context; + struct uart_rz_scif_data *data = dev->data; + + data->int_data.event = p_args->event; + switch (p_args->event) { + case UART_EVENT_RX_CHAR: + data->int_data.rx_byte = p_args->data; + break; + case UART_EVENT_RX_COMPLETE: + break; + case UART_EVENT_TX_DATA_EMPTY: + data->int_data.tei_flag = true; + break; + case UART_EVENT_TX_COMPLETE: + data->int_data.tei_flag = false; + break; + default: + break; + } +} + +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + static DEVICE_API(uart, uart_rz_scif_driver_api) = { .poll_in = uart_rz_scif_poll_in, .poll_out = uart_rz_scif_poll_out, @@ -205,6 +408,19 @@ static DEVICE_API(uart, uart_rz_scif_driver_api) = { .configure = uart_rz_scif_configure, .config_get = uart_rz_scif_config_get, #endif +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = uart_rz_scif_fifo_fill, + .fifo_read = uart_rz_scif_fifo_read, + .irq_rx_enable = uart_rz_scif_irq_rx_enable, + .irq_rx_disable = uart_rz_scif_irq_rx_disable, + .irq_tx_enable = uart_rz_scif_irq_tx_enable, + .irq_tx_disable = uart_rz_scif_irq_tx_disable, + .irq_tx_ready = uart_rz_scif_irq_tx_ready, + .irq_rx_ready = uart_rz_scif_irq_rx_ready, + .irq_is_pending = uart_rz_scif_irq_is_pending, + .irq_callback_set = uart_rz_scif_irq_callback_set, + .irq_update = uart_rz_scif_irq_update, +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ }; static int uart_rz_scif_init(const struct device *dev) @@ -227,14 +443,24 @@ static int uart_rz_scif_init(const struct device *dev) config->fsp_api->open(data->fsp_ctrl, data->fsp_cfg); - R_SCIFA0_Type *reg = data->fsp_ctrl->p_reg; - /* Temporarily disable the DRI interrupt caused by receive data ready */ - /* TODO: support interrupt-driven api */ - reg->SCR_b.RIE = 0; - return 0; } +#define UART_RZG_IRQ_CONNECT(n, irq_name, isr) \ + do { \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, irq_name, irq), \ + DT_INST_IRQ_BY_NAME(n, irq_name, priority), isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQ_BY_NAME(n, irq_name, irq)); \ + } while (0) + +#define UART_RZG_CONFIG_FUNC(n) \ + UART_RZG_IRQ_CONNECT(n, eri, uart_rz_scif_eri_isr); \ + UART_RZG_IRQ_CONNECT(n, rxi, uart_rz_scif_rxi_isr); \ + UART_RZG_IRQ_CONNECT(n, txi, uart_rz_scif_txi_isr); \ + UART_RZG_IRQ_CONNECT(n, tei, uart_rz_scif_tei_isr); \ + UART_RZG_IRQ_CONNECT(n, bri, uart_rz_scif_bri_isr); + #define UART_RZG_INIT(n) \ static scif_uart_instance_ctrl_t g_uart##n##_ctrl; \ static scif_baud_setting_t g_uart##n##_baud_setting; \ @@ -258,8 +484,6 @@ static int uart_rz_scif_init(const struct device *dev) }; \ static uart_cfg_t g_uart##n##_cfg = { \ .channel = DT_INST_PROP(n, channel), \ - .p_callback = NULL, \ - .p_context = NULL, \ .p_extend = &g_uart##n##_cfg_extend, \ .p_transfer_tx = NULL, \ .p_transfer_rx = NULL, \ @@ -271,10 +495,14 @@ static int uart_rz_scif_init(const struct device *dev) .txi_irq = DT_INST_IRQ_BY_NAME(n, txi, irq), \ .tei_irq = DT_INST_IRQ_BY_NAME(n, tei, irq), \ .eri_irq = DT_INST_IRQ_BY_NAME(n, eri, irq), \ - }; \ + IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, ( \ + .p_callback = uart_rz_scif_event_handler, \ + .p_context = (void *)DEVICE_DT_INST_GET(n),)) }; \ PINCTRL_DT_INST_DEFINE(n); \ static const struct uart_rz_scif_config uart_rz_scif_config_##n = { \ - .pin_config = PINCTRL_DT_INST_DEV_CONFIG_GET(n), .fsp_api = &g_uart_on_scif}; \ + .pin_config = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .fsp_api = &g_uart_on_scif, \ + }; \ static struct uart_rz_scif_data uart_rz_scif_data_##n = { \ .uart_config = \ { \ @@ -290,6 +518,8 @@ static int uart_rz_scif_init(const struct device *dev) }; \ static int uart_rz_scif_init_##n(const struct device *dev) \ { \ + IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, \ + (UART_RZG_CONFIG_FUNC(n);)) \ return uart_rz_scif_init(dev); \ } \ DEVICE_DT_INST_DEFINE(n, &uart_rz_scif_init_##n, NULL, &uart_rz_scif_data_##n, \