-
Notifications
You must be signed in to change notification settings - Fork 8k
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
Merged
jhedberg
merged 1 commit into
zephyrproject-rtos:main
from
ck-telecom:sf32lb_uart_interrupt
Oct 14, 2025
+210
−2
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
/* | ||
* Copyright (c) Core Devices LLC | ||
* Copyright (c) Qingsong Gou <[email protected]> | ||
* 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,37 @@ | |
/* 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; | ||
#ifdef 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) | ||
{ | ||
const struct uart_sf32lb_config *config = dev->config; | ||
struct uart_sf32lb_data *data = dev->data; | ||
|
||
if (data->irq_callback) { | ||
data->irq_callback(dev, data->cb_data); | ||
} | ||
|
||
sys_write32(USART_ISR_TXE | USART_ICR_TCCF | USART_ISR_RXNE, config->base + UART_ICR); | ||
} | ||
#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 +203,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); | ||
kartben marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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_TXEIE_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_TXEIE_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; | ||
gmarull marked this conversation as resolved.
Show resolved
Hide resolved
gmarull marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
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_CR1, USART_CR1_RXNEIE_Pos); | ||
} | ||
|
||
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_CR1, USART_CR1_RXNEIE_Pos); | ||
} | ||
#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 +399,22 @@ static int uart_sf32lb_init(const struct device *dev) | |
return ret; | ||
} | ||
|
||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN | ||
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 +433,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) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.