serial: apbuart interrupt support
Adds driver support for APBUART transmitter and receiver interrupts. Compatible with APBUART implementations without HW FIFO interrupt, for example QEMU. Signed-off-by: Martin Åberg <martin.aberg@gaisler.com>
This commit is contained in:
parent
4888afd793
commit
ae309f8597
2 changed files with 141 additions and 0 deletions
|
@ -5,5 +5,6 @@ config UART_APBUART
|
||||||
bool "ABPUART serial driver"
|
bool "ABPUART serial driver"
|
||||||
depends on SOC_SPARC_LEON
|
depends on SOC_SPARC_LEON
|
||||||
select SERIAL_HAS_DRIVER
|
select SERIAL_HAS_DRIVER
|
||||||
|
select SERIAL_SUPPORT_INTERRUPT
|
||||||
help
|
help
|
||||||
This option enables the APBUART driver for LEON processors.
|
This option enables the APBUART driver for LEON processors.
|
||||||
|
|
|
@ -128,6 +128,10 @@ struct apbuart_dev_cfg {
|
||||||
|
|
||||||
struct apbuart_dev_data {
|
struct apbuart_dev_data {
|
||||||
int usefifo;
|
int usefifo;
|
||||||
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
|
uart_irq_callback_user_data_t cb;
|
||||||
|
void *cb_data;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEV_CFG(dev) \
|
#define DEV_CFG(dev) \
|
||||||
|
@ -299,6 +303,122 @@ static int apbuart_config_get(const struct device *dev, struct uart_config *cfg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
|
static int apbuart_fifo_fill(const struct device *dev, const uint8_t *tx_data,
|
||||||
|
int size)
|
||||||
|
{
|
||||||
|
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; (i < size) && (regs->status & APBUART_STATUS_TE); i++) {
|
||||||
|
regs->data = tx_data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apbuart_fifo_read(const struct device *dev, uint8_t *rx_data,
|
||||||
|
const int size)
|
||||||
|
{
|
||||||
|
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; (i < size) && (regs->status & APBUART_STATUS_DR); i++) {
|
||||||
|
rx_data[i] = regs->data & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void apbuart_irq_tx_enable(const struct device *dev)
|
||||||
|
{
|
||||||
|
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
|
||||||
|
|
||||||
|
regs->ctrl |= APBUART_CTRL_TI;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void apbuart_irq_tx_disable(const struct device *dev)
|
||||||
|
{
|
||||||
|
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
|
||||||
|
|
||||||
|
regs->ctrl &= ~APBUART_CTRL_TI;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apbuart_irq_tx_ready(const struct device *dev)
|
||||||
|
{
|
||||||
|
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
|
||||||
|
|
||||||
|
return !!(regs->status & APBUART_STATUS_TE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apbuart_irq_tx_complete(const struct device *dev)
|
||||||
|
{
|
||||||
|
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
|
||||||
|
|
||||||
|
return !!(regs->status & APBUART_STATUS_TS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void apbuart_irq_rx_enable(const struct device *dev)
|
||||||
|
{
|
||||||
|
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
|
||||||
|
|
||||||
|
regs->ctrl |= APBUART_CTRL_RI;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void apbuart_irq_rx_disable(const struct device *dev)
|
||||||
|
{
|
||||||
|
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
|
||||||
|
|
||||||
|
regs->ctrl &= ~APBUART_CTRL_RI;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apbuart_irq_rx_ready(const struct device *dev)
|
||||||
|
{
|
||||||
|
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
|
||||||
|
|
||||||
|
return !!(regs->status & APBUART_STATUS_DR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apbuart_irq_is_pending(const struct device *dev)
|
||||||
|
{
|
||||||
|
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
|
||||||
|
uint32_t status = regs->status;
|
||||||
|
uint32_t ctrl = regs->ctrl;
|
||||||
|
|
||||||
|
if ((ctrl & APBUART_CTRL_RI) && (status & APBUART_STATUS_DR)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ((ctrl & APBUART_CTRL_TI) && (status & APBUART_STATUS_TE)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apbuart_irq_update(const struct device *dev)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void apbuart_irq_callback_set(const struct device *dev,
|
||||||
|
uart_irq_callback_user_data_t cb,
|
||||||
|
void *cb_data)
|
||||||
|
{
|
||||||
|
struct apbuart_dev_data *const dev_data = DEV_DATA(dev);
|
||||||
|
|
||||||
|
dev_data->cb = cb;
|
||||||
|
dev_data->cb_data = cb_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void apbuart_isr(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct apbuart_dev_data *const dev_data = DEV_DATA(dev);
|
||||||
|
|
||||||
|
if (dev_data->cb) {
|
||||||
|
dev_data->cb(dev, dev_data->cb_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
||||||
|
|
||||||
static int apbuart_init(const struct device *dev)
|
static int apbuart_init(const struct device *dev)
|
||||||
{
|
{
|
||||||
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
|
volatile struct apbuart_regs *regs = (void *) DEV_CFG(dev)->regs;
|
||||||
|
@ -319,6 +439,12 @@ static int apbuart_init(const struct device *dev)
|
||||||
|
|
||||||
regs->status = 0;
|
regs->status = 0;
|
||||||
|
|
||||||
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
|
irq_connect_dynamic(DEV_CFG(dev)->interrupt,
|
||||||
|
0, (void (*)(const void *))apbuart_isr, dev, 0);
|
||||||
|
irq_enable(DEV_CFG(dev)->interrupt);
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,6 +455,20 @@ static const struct uart_driver_api apbuart_driver_api = {
|
||||||
.err_check = apbuart_err_check,
|
.err_check = apbuart_err_check,
|
||||||
.configure = apbuart_configure,
|
.configure = apbuart_configure,
|
||||||
.config_get = apbuart_config_get,
|
.config_get = apbuart_config_get,
|
||||||
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
|
.fifo_fill = apbuart_fifo_fill,
|
||||||
|
.fifo_read = apbuart_fifo_read,
|
||||||
|
.irq_tx_enable = apbuart_irq_tx_enable,
|
||||||
|
.irq_tx_disable = apbuart_irq_tx_disable,
|
||||||
|
.irq_tx_ready = apbuart_irq_tx_ready,
|
||||||
|
.irq_rx_enable = apbuart_irq_rx_enable,
|
||||||
|
.irq_rx_disable = apbuart_irq_rx_disable,
|
||||||
|
.irq_tx_complete = apbuart_irq_tx_complete,
|
||||||
|
.irq_rx_ready = apbuart_irq_rx_ready,
|
||||||
|
.irq_is_pending = apbuart_irq_is_pending,
|
||||||
|
.irq_update = apbuart_irq_update,
|
||||||
|
.irq_callback_set = apbuart_irq_callback_set,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define APBUART_INIT(index) \
|
#define APBUART_INIT(index) \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue