-
Notifications
You must be signed in to change notification settings - Fork 7.9k
drivers: serial: sf32lb: add uart interrupt support #96299
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,5 +1,6 @@ | ||||||
/* | ||||||
* Copyright (c) Core Devices LLC | ||||||
* Copyright (c) Qingsong Gou <gouqs@hotmail.com> | ||||||
* SPDX-License-Identifier: Apache-2.0 | ||||||
*/ | ||||||
|
||||||
|
@@ -11,6 +12,7 @@ | |||||
#include <zephyr/drivers/clock_control/sf32lb.h> | ||||||
#include <zephyr/drivers/pinctrl.h> | ||||||
#include <zephyr/drivers/uart.h> | ||||||
#include <zephyr/irq.h> | ||||||
|
||||||
#include <register.h> | ||||||
|
||||||
|
@@ -35,13 +37,34 @@ | |||||
/* minimal BRR: INT=1, FRAC=0 (0x10) */ | ||||||
#define UART_BRR_MIN 0x10U | ||||||
|
||||||
struct uart_sf32lb_data { | ||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN | ||||||
uart_irq_callback_user_data_t irq_callback; | ||||||
void *cb_data; | ||||||
#endif | ||||||
}; | ||||||
|
||||||
struct uart_sf32lb_config { | ||||||
uintptr_t base; | ||||||
const struct pinctrl_dev_config *pcfg; | ||||||
struct sf32lb_clock_dt_spec clock; | ||||||
struct uart_config uart_cfg; | ||||||
#if CONFIG_UART_INTERRUPT_DRIVEN | ||||||
void (*irq_config_func)(const struct device *dev); | ||||||
#endif | ||||||
}; | ||||||
|
||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN | ||||||
static void uart_sf32lb_isr(const struct device *dev) | ||||||
{ | ||||||
struct uart_sf32lb_data *data = dev->data; | ||||||
|
||||||
if (data->irq_callback) { | ||||||
data->irq_callback(dev, data->cb_data); | ||||||
} | ||||||
Comment on lines
+62
to
+64
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is there any flag that has to be cleared, like TCCF? |
||||||
} | ||||||
#endif | ||||||
|
||||||
static int uart_sf32lb_configure(const struct device *dev, const struct uart_config *cfg) | ||||||
{ | ||||||
const struct uart_sf32lb_config *config = dev->config; | ||||||
|
@@ -177,9 +200,174 @@ static void uart_sf32lb_poll_out(const struct device *dev, uint8_t c) | |||||
} | ||||||
} | ||||||
|
||||||
static int uart_sf32lb_err_check(const struct device *dev) | ||||||
{ | ||||||
const struct uart_sf32lb_config *config = dev->config; | ||||||
uint32_t isr = sys_read32(config->base + UART_ISR); | ||||||
int err = 0; | ||||||
|
||||||
if (isr & USART_ISR_ORE) { | ||||||
err |= UART_ERROR_OVERRUN; | ||||||
} | ||||||
|
||||||
if (isr & USART_ISR_PE) { | ||||||
err |= UART_ERROR_PARITY; | ||||||
} | ||||||
|
||||||
if (isr & USART_ISR_FE) { | ||||||
err |= UART_ERROR_FRAMING; | ||||||
} | ||||||
|
||||||
if (isr & USART_ISR_NF) { | ||||||
err |= UART_ERROR_NOISE; | ||||||
} | ||||||
|
||||||
/* clear error flags */ | ||||||
sys_write32(USART_ICR_ORECF | USART_ICR_PECF | USART_ICR_FECF | USART_ICR_NCF, | ||||||
config->base + UART_ICR); | ||||||
|
||||||
return err; | ||||||
} | ||||||
|
||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN | ||||||
static int uart_sf32lb_fifo_fill(const struct device *dev, const uint8_t *tx_data, int len) | ||||||
{ | ||||||
const struct uart_sf32lb_config *config = dev->config; | ||||||
int i; | ||||||
|
||||||
for (i = 0; i < len; i++) { | ||||||
if (!sys_test_bit(config->base + UART_ISR, USART_ISR_TXE_Pos)) { | ||||||
break; | ||||||
} | ||||||
sys_write8(tx_data[i], config->base + UART_TDR); | ||||||
} | ||||||
|
||||||
return i; | ||||||
} | ||||||
|
||||||
static int uart_sf32lb_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) | ||||||
{ | ||||||
const struct uart_sf32lb_config *config = dev->config; | ||||||
int i; | ||||||
|
||||||
for (i = 0; i < size; i++) { | ||||||
if (!sys_test_bit(config->base + UART_ISR, USART_ISR_RXNE_Pos)) { | ||||||
break; | ||||||
} | ||||||
rx_data[i] = sys_read8(config->base + UART_RDR); | ||||||
} | ||||||
|
||||||
return i; | ||||||
} | ||||||
|
||||||
static void uart_sf32lb_irq_tx_enable(const struct device *dev) | ||||||
{ | ||||||
const struct uart_sf32lb_config *config = dev->config; | ||||||
|
||||||
sys_set_bit(config->base + UART_CR1, USART_CR1_TE_Pos); | ||||||
} | ||||||
|
||||||
static void uart_sf32lb_irq_tx_disable(const struct device *dev) | ||||||
{ | ||||||
const struct uart_sf32lb_config *config = dev->config; | ||||||
|
||||||
sys_clear_bit(config->base + UART_CR1, USART_CR1_TE_Pos); | ||||||
} | ||||||
|
||||||
static int uart_sf32lb_irq_tx_ready(const struct device *dev) | ||||||
{ | ||||||
const struct uart_sf32lb_config *config = dev->config; | ||||||
|
||||||
return sys_test_bit(config->base + UART_ISR, USART_ISR_TXE_Pos); | ||||||
} | ||||||
|
||||||
static int uart_sf32lb_irq_tx_complete(const struct device *dev) | ||||||
{ | ||||||
const struct uart_sf32lb_config *config = dev->config; | ||||||
|
||||||
return sys_test_bit(config->base + UART_ISR, USART_ISR_TC_Pos); | ||||||
} | ||||||
|
||||||
static int uart_sf32lb_irq_rx_ready(const struct device *dev) | ||||||
{ | ||||||
const struct uart_sf32lb_config *config = dev->config; | ||||||
|
||||||
return sys_test_bit(config->base + UART_ISR, USART_ISR_RXNE_Pos); | ||||||
} | ||||||
|
||||||
static void uart_sf32lb_irq_err_enable(const struct device *dev) | ||||||
{ | ||||||
const struct uart_sf32lb_config *config = dev->config; | ||||||
|
||||||
sys_set_bit(config->base + UART_CR1, USART_CR1_PEIE_Pos); | ||||||
sys_set_bit(config->base + UART_CR3, USART_CR3_EIE_Pos); | ||||||
} | ||||||
|
||||||
static void uart_sf32lb_irq_err_disable(const struct device *dev) | ||||||
{ | ||||||
const struct uart_sf32lb_config *config = dev->config; | ||||||
|
||||||
sys_clear_bit(config->base + UART_CR1, USART_CR1_PEIE_Pos); | ||||||
sys_clear_bit(config->base + UART_CR3, USART_CR3_EIE_Pos); | ||||||
} | ||||||
|
||||||
static int uart_sf32lb_irq_is_pending(const struct device *dev) | ||||||
{ | ||||||
const struct uart_sf32lb_config *config = dev->config; | ||||||
|
||||||
return sys_read32(config->base + UART_ISR) == 0U ? 0 : 1; | ||||||
} | ||||||
|
||||||
static int uart_sf32lb_irq_update(const struct device *dev) | ||||||
{ | ||||||
ARG_UNUSED(dev); | ||||||
return 1; | ||||||
ck-telecom marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
} | ||||||
|
||||||
static void uart_sf32lb_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb, | ||||||
void *user_data) | ||||||
{ | ||||||
struct uart_sf32lb_data *data = dev->data; | ||||||
|
||||||
data->irq_callback = cb; | ||||||
data->cb_data = user_data; | ||||||
} | ||||||
|
||||||
static void uart_sf32lb_irq_rx_enable(const struct device *dev) | ||||||
{ | ||||||
const struct uart_sf32lb_config *config = dev->config; | ||||||
|
||||||
sys_set_bit(config->base + UART_CR3, USART_ISR_RXNE); | ||||||
} | ||||||
|
||||||
static void uart_sf32lb_irq_rx_disable(const struct device *dev) | ||||||
{ | ||||||
const struct uart_sf32lb_config *config = dev->config; | ||||||
|
||||||
sys_clear_bit(config->base + UART_CR3, USART_ISR_RXNE); | ||||||
} | ||||||
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ | ||||||
|
||||||
static const struct uart_driver_api uart_sf32lb_api = { | ||||||
.poll_in = uart_sf32lb_poll_in, | ||||||
.poll_out = uart_sf32lb_poll_out, | ||||||
.err_check = uart_sf32lb_err_check, | ||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN | ||||||
.fifo_fill = uart_sf32lb_fifo_fill, | ||||||
.fifo_read = uart_sf32lb_fifo_read, | ||||||
.irq_tx_enable = uart_sf32lb_irq_tx_enable, | ||||||
.irq_tx_disable = uart_sf32lb_irq_tx_disable, | ||||||
.irq_tx_complete = uart_sf32lb_irq_tx_complete, | ||||||
.irq_tx_ready = uart_sf32lb_irq_tx_ready, | ||||||
.irq_rx_enable = uart_sf32lb_irq_rx_enable, | ||||||
.irq_rx_disable = uart_sf32lb_irq_rx_disable, | ||||||
.irq_rx_ready = uart_sf32lb_irq_rx_ready, | ||||||
.irq_err_enable = uart_sf32lb_irq_err_enable, | ||||||
.irq_err_disable = uart_sf32lb_irq_err_disable, | ||||||
.irq_is_pending = uart_sf32lb_irq_is_pending, | ||||||
.irq_update = uart_sf32lb_irq_update, | ||||||
.irq_callback_set = uart_sf32lb_irq_callback_set, | ||||||
#endif | ||||||
}; | ||||||
|
||||||
static int uart_sf32lb_init(const struct device *dev) | ||||||
|
@@ -208,11 +396,22 @@ static int uart_sf32lb_init(const struct device *dev) | |||||
return ret; | ||||||
} | ||||||
|
||||||
#if CONFIG_UART_INTERRUPT_DRIVEN | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Kconfigs are either defined or not defined) |
||||||
config->irq_config_func(dev); | ||||||
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ | ||||||
|
||||||
return 0; | ||||||
} | ||||||
|
||||||
#define SF32LB_UART_DEFINE(index) \ | ||||||
PINCTRL_DT_INST_DEFINE(index); \ | ||||||
IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, \ | ||||||
(static void uart_sf32lb_irq_config_func_##index(const struct device *dev) \ | ||||||
{ \ | ||||||
IRQ_CONNECT(DT_INST_IRQN(index), DT_INST_IRQ(index, priority), uart_sf32lb_isr, \ | ||||||
DEVICE_DT_INST_GET(index), 0); \ | ||||||
irq_enable(DT_INST_IRQN(index)); \ | ||||||
})); \ | ||||||
\ | ||||||
static const struct uart_sf32lb_config uart_sf32lb_cfg_##index = { \ | ||||||
.base = DT_INST_REG_ADDR(index), \ | ||||||
|
@@ -231,9 +430,14 @@ static int uart_sf32lb_init(const struct device *dev) | |||||
? UART_CFG_FLOW_CTRL_RTS_CTS \ | ||||||
: UART_CFG_FLOW_CTRL_NONE, \ | ||||||
}, \ | ||||||
IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, \ | ||||||
(.irq_config_func = uart_sf32lb_irq_config_func_##index,)) \ | ||||||
}; \ | ||||||
\ | ||||||
DEVICE_DT_INST_DEFINE(index, uart_sf32lb_init, NULL, NULL, &uart_sf32lb_cfg_##index, \ | ||||||
PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, &uart_sf32lb_api); | ||||||
static struct uart_sf32lb_data uart_sf32lb_data_##index; \ | ||||||
\ | ||||||
DEVICE_DT_INST_DEFINE(index, uart_sf32lb_init, NULL, \ | ||||||
&uart_sf32lb_data_##index, &uart_sf32lb_cfg_##index, PRE_KERNEL_1, \ | ||||||
CONFIG_SERIAL_INIT_PRIORITY, &uart_sf32lb_api); | ||||||
|
||||||
DT_INST_FOREACH_STATUS_OKAY(SF32LB_UART_DEFINE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.