drivers: serial: psoc6: Add interrupts support
Current Cypress PSoC-6 serial driver only works using polling mode. Add serial driver interrupt routines to allow use of interrupts. Signed-off-by: Gerson Fernando Budke <gerson.budke@atl-electronics.com>
This commit is contained in:
parent
e6cba8d9c8
commit
2bd130112a
|
@ -8,5 +8,6 @@ config UART_PSOC6
|
|||
bool "PSoC-6 MCU SCB serial driver"
|
||||
depends on SOC_FAMILY_PSOC6
|
||||
select SERIAL_HAS_DRIVER
|
||||
select SERIAL_SUPPORT_INTERRUPT
|
||||
help
|
||||
This option enables the SCB[UART] driver for PSoC-6 SoC family.
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "cy_syslib.h"
|
||||
#include "cy_sysclk.h"
|
||||
#include "cy_scb_uart.h"
|
||||
#include "cy_sysint.h"
|
||||
|
||||
/* UART desired baud rate is 115200 bps (Standard mode).
|
||||
* The UART baud rate = (SCB clock frequency / Oversample).
|
||||
|
@ -46,10 +47,24 @@
|
|||
struct cypress_psoc6_config {
|
||||
CySCB_Type *base;
|
||||
uint32_t periph_id;
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
uart_irq_config_func_t irq_config_func;
|
||||
#endif
|
||||
uint32_t num_pins;
|
||||
struct soc_gpio_pin pins[];
|
||||
};
|
||||
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
struct cypress_psoc6_data {
|
||||
uart_irq_callback_user_data_t irq_cb; /* Interrupt Callback */
|
||||
void *irq_cb_data; /* Interrupt Callback Arg */
|
||||
};
|
||||
|
||||
#define DEV_DATA(dev) \
|
||||
((struct cypress_psoc6_data *const)(dev)->data)
|
||||
|
||||
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
||||
|
||||
/* Populate configuration structure */
|
||||
static const cy_stc_scb_uart_config_t uartConfig = {
|
||||
.uartMode = CY_SCB_UART_STANDARD,
|
||||
|
@ -111,6 +126,10 @@ static int uart_psoc6_init(const struct device *dev)
|
|||
(void) Cy_SCB_UART_Init(config->base, &uartConfig, NULL);
|
||||
Cy_SCB_UART_Enable(config->base);
|
||||
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
config->irq_config_func(dev);
|
||||
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -133,21 +152,214 @@ static void uart_psoc6_poll_out(const struct device *dev, unsigned char c)
|
|||
}
|
||||
}
|
||||
|
||||
static int uart_psoc6_err_check(const struct device *dev)
|
||||
{
|
||||
const struct cypress_psoc6_config *config = dev->config;
|
||||
uint32_t status = Cy_SCB_UART_GetRxFifoStatus(config->base);
|
||||
int errors = 0;
|
||||
|
||||
if (status & CY_SCB_UART_RX_OVERFLOW) {
|
||||
errors |= UART_ERROR_OVERRUN;
|
||||
}
|
||||
|
||||
if (status & CY_SCB_UART_RX_ERR_PARITY) {
|
||||
errors |= UART_ERROR_PARITY;
|
||||
}
|
||||
|
||||
if (status & CY_SCB_UART_RX_ERR_FRAME) {
|
||||
errors |= UART_ERROR_FRAMING;
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
|
||||
static int uart_psoc6_fifo_fill(const struct device *dev,
|
||||
const uint8_t *tx_data,
|
||||
int size)
|
||||
{
|
||||
const struct cypress_psoc6_config *config = dev->config;
|
||||
|
||||
return Cy_SCB_UART_PutArray(config->base, (uint8_t *) tx_data, size);
|
||||
}
|
||||
|
||||
static int uart_psoc6_fifo_read(const struct device *dev,
|
||||
uint8_t *rx_data,
|
||||
const int size)
|
||||
{
|
||||
const struct cypress_psoc6_config *config = dev->config;
|
||||
|
||||
return Cy_SCB_UART_GetArray(config->base, rx_data, size);
|
||||
}
|
||||
|
||||
static void uart_psoc6_irq_tx_enable(const struct device *dev)
|
||||
{
|
||||
const struct cypress_psoc6_config *config = dev->config;
|
||||
|
||||
Cy_SCB_SetTxInterruptMask(config->base, CY_SCB_UART_TX_EMPTY);
|
||||
}
|
||||
|
||||
static void uart_psoc6_irq_tx_disable(const struct device *dev)
|
||||
{
|
||||
const struct cypress_psoc6_config *config = dev->config;
|
||||
|
||||
Cy_SCB_SetTxInterruptMask(config->base, 0);
|
||||
}
|
||||
|
||||
static int uart_psoc6_irq_tx_ready(const struct device *dev)
|
||||
{
|
||||
const struct cypress_psoc6_config *config = dev->config;
|
||||
uint32_t status = Cy_SCB_UART_GetTxFifoStatus(config->base);
|
||||
|
||||
Cy_SCB_UART_ClearTxFifoStatus(config->base, CY_SCB_UART_TX_INTR_MASK);
|
||||
|
||||
return (status & CY_SCB_UART_TX_NOT_FULL);
|
||||
}
|
||||
|
||||
static int uart_psoc6_irq_tx_complete(const struct device *dev)
|
||||
{
|
||||
const struct cypress_psoc6_config *config = dev->config;
|
||||
uint32_t status = Cy_SCB_UART_GetTxFifoStatus(config->base);
|
||||
|
||||
Cy_SCB_UART_ClearTxFifoStatus(config->base, CY_SCB_UART_TX_INTR_MASK);
|
||||
|
||||
return (status & CY_SCB_UART_TX_DONE);
|
||||
}
|
||||
|
||||
static void uart_psoc6_irq_rx_enable(const struct device *dev)
|
||||
{
|
||||
const struct cypress_psoc6_config *config = dev->config;
|
||||
|
||||
Cy_SCB_SetRxInterruptMask(config->base, CY_SCB_UART_RX_NOT_EMPTY);
|
||||
}
|
||||
|
||||
static void uart_psoc6_irq_rx_disable(const struct device *dev)
|
||||
{
|
||||
const struct cypress_psoc6_config *config = dev->config;
|
||||
|
||||
Cy_SCB_SetRxInterruptMask(config->base, 0);
|
||||
}
|
||||
|
||||
static int uart_psoc6_irq_rx_ready(const struct device *dev)
|
||||
{
|
||||
const struct cypress_psoc6_config *config = dev->config;
|
||||
uint32_t status = Cy_SCB_UART_GetRxFifoStatus(config->base);
|
||||
|
||||
Cy_SCB_UART_ClearRxFifoStatus(config->base, CY_SCB_UART_RX_INTR_MASK);
|
||||
|
||||
return (status & CY_SCB_UART_RX_NOT_EMPTY);
|
||||
}
|
||||
|
||||
static void uart_psoc6_irq_err_enable(const struct device *dev)
|
||||
{
|
||||
const struct cypress_psoc6_config *config = dev->config;
|
||||
uint32_t intmask = Cy_SCB_GetRxInterruptMask(config->base) |
|
||||
CY_SCB_UART_RECEIVE_ERR;
|
||||
|
||||
Cy_SCB_SetRxInterruptMask(config->base, intmask);
|
||||
}
|
||||
|
||||
static void uart_psoc6_irq_err_disable(const struct device *dev)
|
||||
{
|
||||
const struct cypress_psoc6_config *config = dev->config;
|
||||
uint32_t intmask = Cy_SCB_GetRxInterruptMask(config->base) &
|
||||
~(CY_SCB_UART_RECEIVE_ERR);
|
||||
|
||||
Cy_SCB_SetRxInterruptMask(config->base, intmask);
|
||||
}
|
||||
|
||||
static int uart_psoc6_irq_is_pending(const struct device *dev)
|
||||
{
|
||||
const struct cypress_psoc6_config *config = dev->config;
|
||||
uint32_t intcause = Cy_SCB_GetInterruptCause(config->base);
|
||||
|
||||
return (intcause & (CY_SCB_TX_INTR | CY_SCB_RX_INTR));
|
||||
}
|
||||
|
||||
static int uart_psoc6_irq_update(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void uart_psoc6_irq_callback_set(const struct device *dev,
|
||||
uart_irq_callback_user_data_t cb,
|
||||
void *cb_data)
|
||||
{
|
||||
struct cypress_psoc6_data *const dev_data = DEV_DATA(dev);
|
||||
|
||||
dev_data->irq_cb = cb;
|
||||
dev_data->irq_cb_data = cb_data;
|
||||
}
|
||||
|
||||
static void uart_psoc6_isr(const struct device *dev)
|
||||
{
|
||||
struct cypress_psoc6_data *const dev_data = DEV_DATA(dev);
|
||||
|
||||
if (dev_data->irq_cb) {
|
||||
dev_data->irq_cb(dev, dev_data->irq_cb_data);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
||||
|
||||
static const struct uart_driver_api uart_psoc6_driver_api = {
|
||||
.poll_in = uart_psoc6_poll_in,
|
||||
.poll_out = uart_psoc6_poll_out,
|
||||
.err_check = uart_psoc6_err_check,
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
.fifo_fill = uart_psoc6_fifo_fill,
|
||||
.fifo_read = uart_psoc6_fifo_read,
|
||||
.irq_tx_enable = uart_psoc6_irq_tx_enable,
|
||||
.irq_tx_disable = uart_psoc6_irq_tx_disable,
|
||||
.irq_tx_ready = uart_psoc6_irq_tx_ready,
|
||||
.irq_rx_enable = uart_psoc6_irq_rx_enable,
|
||||
.irq_rx_disable = uart_psoc6_irq_rx_disable,
|
||||
.irq_tx_complete = uart_psoc6_irq_tx_complete,
|
||||
.irq_rx_ready = uart_psoc6_irq_rx_ready,
|
||||
.irq_err_enable = uart_psoc6_irq_err_enable,
|
||||
.irq_err_disable = uart_psoc6_irq_err_disable,
|
||||
.irq_is_pending = uart_psoc6_irq_is_pending,
|
||||
.irq_update = uart_psoc6_irq_update,
|
||||
.irq_callback_set = uart_psoc6_irq_callback_set,
|
||||
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
#define CY_PSOC6_UART_IRQ_FUNC(n) \
|
||||
static void cy_psoc6_uart##n##_irq_config(const struct device *port) \
|
||||
{ \
|
||||
CY_PSOC6_DT_INST_NVIC_INSTALL(n, \
|
||||
uart_psoc6_isr); \
|
||||
};
|
||||
#define CY_PSOC6_UART_IRQ_SET_FUNC(n) \
|
||||
.irq_config_func = cy_psoc6_uart##n##_irq_config
|
||||
#define CY_PSOC6_UART_DECL_DATA(n) \
|
||||
static struct cypress_psoc6_data cy_psoc6_uart##n##_data = { 0 };
|
||||
#define CY_PSOC6_UART_DECL_DATA_PTR(n) &cy_psoc6_uart##n##_data
|
||||
#else
|
||||
#define CY_PSOC6_UART_IRQ_FUNC(n)
|
||||
#define CY_PSOC6_UART_IRQ_SET_FUNC(n)
|
||||
#define CY_PSOC6_UART_DECL_DATA(n)
|
||||
#define CY_PSOC6_UART_DECL_DATA_PTR(n) NULL
|
||||
#endif
|
||||
|
||||
#define CY_PSOC6_UART_INIT(n) \
|
||||
CY_PSOC6_UART_DECL_DATA(n) \
|
||||
CY_PSOC6_UART_IRQ_FUNC(n) \
|
||||
static const struct cypress_psoc6_config cy_psoc6_uart##n##_config = { \
|
||||
.base = (CySCB_Type *)DT_INST_REG_ADDR(n), \
|
||||
.periph_id = DT_INST_PROP(n, peripheral_id), \
|
||||
\
|
||||
.num_pins = CY_PSOC6_DT_INST_NUM_PINS(n), \
|
||||
.pins = CY_PSOC6_DT_INST_PINS(n), \
|
||||
\
|
||||
CY_PSOC6_UART_IRQ_SET_FUNC(n) \
|
||||
}; \
|
||||
DEVICE_DT_INST_DEFINE(n, &uart_psoc6_init, device_pm_control_nop, \
|
||||
NULL, \
|
||||
CY_PSOC6_UART_DECL_DATA_PTR(n), \
|
||||
&cy_psoc6_uart##n##_config, PRE_KERNEL_1, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
|
||||
&uart_psoc6_driver_api);
|
||||
|
|
Loading…
Reference in a new issue