serial/stm32: add support for IRQ APIs

The patch extends STM32 serial port driver with support for IRQ API of
the common UART port driver API.

Change-Id: If105e8528ea4ed4181cc4af0c97c24aa874e69e0
Origin: Original
Signed-off-by: Maciej Borzecki <maciek.borzecki@gmail.com>
This commit is contained in:
Maciek Borzecki 2016-03-13 19:37:25 +01:00 committed by Daniel Kalowsky
commit 0cd7ff8d4b
3 changed files with 229 additions and 0 deletions

View file

@ -50,6 +50,13 @@ config UART_STM32_PORT_0_BAUD_RATE
help help
The baud rate for USART1 port to be set to at boot. The baud rate for USART1 port to be set to at boot.
config UART_STM32_PORT_0_IRQ_PRI
int "STM32 USART1 Interrupt Priority"
default 0
depends on UART_STM32_PORT_0 && UART_INTERRUPT_DRIVEN
help
The interrupt priority for USART1 port.
# --- port 1 --- # --- port 1 ---
config UART_STM32_PORT_1 config UART_STM32_PORT_1
@ -75,6 +82,13 @@ config UART_STM32_PORT_1_BAUD_RATE
help help
The baud rate for USART2 port to be set to at boot. The baud rate for USART2 port to be set to at boot.
config UART_STM32_PORT_1_IRQ_PRI
int "STM32 USART2 Interrupt Priority"
default 0
depends on UART_STM32_PORT_1 && UART_INTERRUPT_DRIVEN
help
The interrupt priority for USART2 port.
# --- port 2 --- # --- port 2 ---
config UART_STM32_PORT_2 config UART_STM32_PORT_2
@ -99,3 +113,10 @@ config UART_STM32_PORT_2_BAUD_RATE
depends on UART_STM32_PORT_2 depends on UART_STM32_PORT_2
help help
The baud rate for USART3 port to be set to at boot. The baud rate for USART3 port to be set to at boot.
config UART_STM32_PORT_2_IRQ_PRI
int "STM32 USART3 Interrupt Priority"
default 0
depends on UART_STM32_PORT_2 && UART_INTERRUPT_DRIVEN
help
The interrupt priority for USART3 port.

View file

@ -123,9 +123,148 @@ static inline void __uart_stm32_get_clock(struct device *dev)
ddata->clock = clk; ddata->clock = clk;
} }
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static int uart_stm32_fifo_fill(struct device *dev, const uint8_t *tx_data,
int size)
{
volatile struct uart_stm32 *uart = UART_STRUCT(dev);
size_t num_tx = 0;
/* FIXME: DMA maybe? */
while ((size - num_tx > 0) && (uart->sr.bit.txe)) {
uart->dr.bit.dr = tx_data[num_tx++];
}
return num_tx;
}
static int uart_stm32_fifo_read(struct device *dev, uint8_t *rx_data,
const int size)
{
volatile struct uart_stm32 *uart = UART_STRUCT(dev);
size_t num_rx = 0;
while ((size - num_rx > 0) && (uart->sr.bit.rxne)) {
rx_data[num_rx++] = (uint8_t) uart->dr.bit.dr;
}
return num_rx;
}
static void uart_stm32_irq_tx_enable(struct device *dev)
{
volatile struct uart_stm32 *uart = UART_STRUCT(dev);
uart->cr1.bit.txeie = 1;
}
static void uart_stm32_irq_tx_disable(struct device *dev)
{
volatile struct uart_stm32 *uart = UART_STRUCT(dev);
uart->cr1.bit.txeie = 0;
}
static int uart_stm32_irq_tx_ready(struct device *dev)
{
volatile struct uart_stm32 *uart = UART_STRUCT(dev);
return uart->sr.bit.txe;
}
static int uart_stm32_irq_tx_empty(struct device *dev)
{
volatile struct uart_stm32 *uart = UART_STRUCT(dev);
return uart->sr.bit.txe;
}
static void uart_stm32_irq_rx_enable(struct device *dev)
{
volatile struct uart_stm32 *uart = UART_STRUCT(dev);
uart->cr1.bit.rxneie = 1;
}
static void uart_stm32_irq_rx_disable(struct device *dev)
{
volatile struct uart_stm32 *uart = UART_STRUCT(dev);
uart->cr1.bit.rxneie = 0;
}
static int uart_stm32_irq_rx_ready(struct device *dev)
{
volatile struct uart_stm32 *uart = UART_STRUCT(dev);
return uart->sr.bit.rxne;
}
static void uart_stm32_irq_err_enable(struct device *dev)
{
volatile struct uart_stm32 *uart = UART_STRUCT(dev);
uart->cr3.bit.eie = 1;
}
static void uart_stm32_irq_err_disable(struct device *dev)
{
volatile struct uart_stm32 *uart = UART_STRUCT(dev);
uart->cr3.bit.eie = 0;
}
static int uart_stm32_irq_is_pending(struct device *dev)
{
volatile struct uart_stm32 *uart = UART_STRUCT(dev);
return uart->sr.bit.rxne || uart->sr.bit.txe;
}
static int uart_stm32_irq_update(struct device *dev)
{
return 1;
}
static void uart_stm32_irq_callback_set(struct device *dev,
uart_irq_callback_t cb)
{
struct uart_stm32_data *data = DEV_DATA(dev);
data->user_cb = cb;
}
static void uart_stm32_isr(void *arg)
{
struct device *dev = arg;
struct uart_stm32_data *data = DEV_DATA(dev);
if (data->user_cb) {
data->user_cb(dev);
}
}
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
static struct uart_driver_api uart_stm32_driver_api = { static struct uart_driver_api uart_stm32_driver_api = {
.poll_in = uart_stm32_poll_in, .poll_in = uart_stm32_poll_in,
.poll_out = uart_stm32_poll_out, .poll_out = uart_stm32_poll_out,
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
.fifo_fill = uart_stm32_fifo_fill,
.fifo_read = uart_stm32_fifo_read,
.irq_tx_enable = uart_stm32_irq_tx_enable,
.irq_tx_disable = uart_stm32_irq_tx_disable,
.irq_tx_ready = uart_stm32_irq_tx_ready,
.irq_tx_empty = uart_stm32_irq_tx_empty,
.irq_rx_enable = uart_stm32_irq_rx_enable,
.irq_rx_disable = uart_stm32_irq_rx_disable,
.irq_rx_ready = uart_stm32_irq_rx_ready,
.irq_err_enable = uart_stm32_irq_err_enable,
.irq_err_disable = uart_stm32_irq_err_disable,
.irq_is_pending = uart_stm32_irq_is_pending,
.irq_update = uart_stm32_irq_update,
.irq_callback_set = uart_stm32_irq_callback_set,
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
}; };
/** /**
@ -172,14 +311,24 @@ static int uart_stm32_init(struct device *dev)
dev->driver_api = &uart_stm32_driver_api; dev->driver_api = &uart_stm32_driver_api;
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
cfg->uconf.irq_config_func(dev);
#endif
return 0; return 0;
} }
#ifdef CONFIG_UART_STM32_PORT_0 #ifdef CONFIG_UART_STM32_PORT_0
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static void uart_stm32_irq_config_func_0(struct device *dev);
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
static struct uart_stm32_config uart_stm32_dev_cfg_0 = { static struct uart_stm32_config uart_stm32_dev_cfg_0 = {
.uconf = { .uconf = {
.base = (uint8_t *)USART1_ADDR, .base = (uint8_t *)USART1_ADDR,
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
.irq_config_func = uart_stm32_irq_config_func_0,
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
}, },
#ifdef CONFIG_SOC_STM32F1X #ifdef CONFIG_SOC_STM32F1X
.clock_subsys = UINT_TO_POINTER(STM32F10X_CLOCK_SUBSYS_USART1), .clock_subsys = UINT_TO_POINTER(STM32F10X_CLOCK_SUBSYS_USART1),
@ -194,13 +343,34 @@ DEVICE_INIT(uart_stm32_0, CONFIG_UART_STM32_PORT_0_NAME, &uart_stm32_init,
&uart_stm32_dev_data_0, &uart_stm32_dev_cfg_0, &uart_stm32_dev_data_0, &uart_stm32_dev_cfg_0,
PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static void uart_stm32_irq_config_func_0(struct device *dev)
{
#ifdef CONFIG_SOC_STM32F1X
#define PORT_0_IRQ STM32F1_IRQ_USART1
#endif
IRQ_CONNECT(PORT_0_IRQ,
CONFIG_UART_STM32_PORT_0_IRQ_PRI,
uart_stm32_isr, DEVICE_GET(uart_stm32_0),
0);
irq_enable(PORT_0_IRQ);
}
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
#endif /* CONFIG_UART_STM32_PORT_0 */ #endif /* CONFIG_UART_STM32_PORT_0 */
#ifdef CONFIG_UART_STM32_PORT_1 #ifdef CONFIG_UART_STM32_PORT_1
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static void uart_stm32_irq_config_func_1(struct device *dev);
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
static struct uart_stm32_config uart_stm32_dev_cfg_1 = { static struct uart_stm32_config uart_stm32_dev_cfg_1 = {
.uconf = { .uconf = {
.base = (uint8_t *)USART2_ADDR, .base = (uint8_t *)USART2_ADDR,
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
.irq_config_func = uart_stm32_irq_config_func_1,
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
}, },
#ifdef CONFIG_SOC_STM32F1X #ifdef CONFIG_SOC_STM32F1X
.clock_subsys = UINT_TO_POINTER(STM32F10X_CLOCK_SUBSYS_USART2), .clock_subsys = UINT_TO_POINTER(STM32F10X_CLOCK_SUBSYS_USART2),
@ -215,13 +385,34 @@ DEVICE_INIT(uart_stm32_1, CONFIG_UART_STM32_PORT_1_NAME, &uart_stm32_init,
&uart_stm32_dev_data_1, &uart_stm32_dev_cfg_1, &uart_stm32_dev_data_1, &uart_stm32_dev_cfg_1,
PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static void uart_stm32_irq_config_func_1(struct device *dev)
{
#ifdef CONFIG_SOC_STM32F1X
#define PORT_1_IRQ STM32F1_IRQ_USART2
#endif
IRQ_CONNECT(PORT_1_IRQ,
CONFIG_UART_STM32_PORT_1_IRQ_PRI,
uart_stm32_isr, DEVICE_GET(uart_stm32_1),
0);
irq_enable(PORT_1_IRQ);
}
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
#endif /* CONFIG_UART_STM32_PORT_1 */ #endif /* CONFIG_UART_STM32_PORT_1 */
#ifdef CONFIG_UART_STM32_PORT_2 #ifdef CONFIG_UART_STM32_PORT_2
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static void uart_stm32_irq_config_func_2(struct device *dev);
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
static struct uart_stm32_config uart_stm32_dev_cfg_2 = { static struct uart_stm32_config uart_stm32_dev_cfg_2 = {
.uconf = { .uconf = {
.base = (uint8_t *)USART3_ADDR, .base = (uint8_t *)USART3_ADDR,
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
.irq_config_func = uart_stm32_irq_config_func_2,
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
}, },
#ifdef CONFIG_SOC_STM32F1X #ifdef CONFIG_SOC_STM32F1X
.clock_subsys = UINT_TO_POINTER(STM32F10X_CLOCK_SUBSYS_USART3), .clock_subsys = UINT_TO_POINTER(STM32F10X_CLOCK_SUBSYS_USART3),
@ -236,4 +427,18 @@ DEVICE_INIT(uart_stm32_2, CONFIG_UART_STM32_PORT_2_NAME, &uart_stm32_init,
&uart_stm32_dev_data_2, &uart_stm32_dev_cfg_2, &uart_stm32_dev_data_2, &uart_stm32_dev_cfg_2,
PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static void uart_stm32_irq_config_func_2(struct device *dev)
{
#ifdef CONFIG_SOC_STM32F1X
#define PORT_2_IRQ STM32F1_IRQ_USART3
#endif
IRQ_CONNECT(PORT_2_IRQ,
CONFIG_UART_STM32_PORT_2_IRQ_PRI,
uart_stm32_isr, DEVICE_GET(uart_stm32_2),
0);
irq_enable(PORT_2_IRQ);
}
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
#endif /* CONFIG_UART_STM32_PORT_2 */ #endif /* CONFIG_UART_STM32_PORT_2 */

View file

@ -161,6 +161,9 @@ struct uart_stm32_data {
uint32_t baud_rate; uint32_t baud_rate;
/* clock device */ /* clock device */
struct device *clock; struct device *clock;
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
uart_irq_callback_t user_cb;
#endif
}; };
#endif /* _STM32_UART_H_ */ #endif /* _STM32_UART_H_ */