zephyr/drivers/serial/uart_ene_kb1200.c

381 lines
10 KiB
C

/*
* Copyright (c) 2023 ENE Technology Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT ene_kb1200_uart
#include <zephyr/kernel.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/drivers/pinctrl.h>
#include <reg/ser.h>
struct kb1200_uart_config {
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
void (*irq_cfg_func)(void);
#endif
struct serial_regs *ser;
const struct pinctrl_dev_config *pcfg;
};
struct kb1200_uart_data {
uart_irq_callback_user_data_t callback;
struct uart_config current_config;
void *callback_data;
uint8_t pending_flag_data;
};
static int kb1200_uart_err_check(const struct device *dev)
{
const struct kb1200_uart_config *config = dev->config;
int err = 0;
if (config->ser->SERSTS & SERSTS_RX_OVERRUN) {
err |= UART_ERROR_OVERRUN;
}
if (config->ser->SERSTS & SERSTS_PARITY_ERROR) {
err |= UART_ERROR_PARITY;
}
if (config->ser->SERSTS & SERSTS_FRAME_ERROR) {
err |= UART_ERROR_FRAMING;
}
return err;
}
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
static int kb1200_uart_configure(const struct device *dev, const struct uart_config *cfg)
{
uint16_t reg_baudrate = 0;
uint8_t reg_parity = 0;
int ret = 0;
const struct kb1200_uart_config *config = dev->config;
struct kb1200_uart_data *data = dev->data;
reg_baudrate = (DIVIDER_BASE_CLK / cfg->baudrate) - 1;
switch (cfg->parity) {
case UART_CFG_PARITY_NONE:
reg_parity = SERCFG_PARITY_NONE;
break;
case UART_CFG_PARITY_ODD:
reg_parity = SERCFG_PARITY_ODD;
break;
case UART_CFG_PARITY_EVEN:
reg_parity = SERCFG_PARITY_EVEN;
break;
case UART_CFG_PARITY_MARK:
case UART_CFG_PARITY_SPACE:
default:
ret = -ENOTSUP;
break;
}
switch (cfg->stop_bits) {
case UART_CFG_STOP_BITS_1:
break;
case UART_CFG_STOP_BITS_0_5:
case UART_CFG_STOP_BITS_1_5:
case UART_CFG_STOP_BITS_2:
default:
ret = -ENOTSUP;
break;
}
switch (cfg->data_bits) {
case UART_CFG_DATA_BITS_8:
break;
case UART_CFG_DATA_BITS_5:
case UART_CFG_DATA_BITS_6:
case UART_CFG_DATA_BITS_7:
case UART_CFG_DATA_BITS_9:
default:
ret = -ENOTSUP;
break;
}
switch (cfg->flow_ctrl) {
case UART_CFG_FLOW_CTRL_NONE:
break;
case UART_CFG_FLOW_CTRL_RTS_CTS:
case UART_CFG_FLOW_CTRL_DTR_DSR:
case UART_CFG_FLOW_CTRL_RS485:
default:
ret = -ENOTSUP;
break;
}
config->ser->SERCFG =
(reg_baudrate << 16) | (reg_parity << 2) | (SERIE_RX_ENABLE | SERIE_TX_ENABLE);
config->ser->SERCTRL = SERCTRL_MODE1;
data->current_config = *cfg;
return ret;
}
static int kb1200_uart_config_get(const struct device *dev, struct uart_config *cfg)
{
struct kb1200_uart_data *data = dev->data;
*cfg = data->current_config;
return 0;
}
#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static int kb1200_uart_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size)
{
const struct kb1200_uart_config *config = dev->config;
uint16_t tx_bytes = 0U;
while ((size - tx_bytes) > 0) {
/* Check Tx FIFO not Full*/
while (config->ser->SERSTS & SERSTS_TX_FULL)
;
/* Put a character into Tx FIFO */
config->ser->SERTBUF = tx_data[tx_bytes];
tx_bytes++;
}
return tx_bytes;
}
static int kb1200_uart_fifo_read(const struct device *dev, uint8_t *rx_data, const int size)
{
const struct kb1200_uart_config *config = dev->config;
uint16_t rx_bytes = 0U;
/* Check Rx FIFO not Empty*/
while ((size - rx_bytes > 0) && (!(config->ser->SERSTS & SERSTS_RX_EMPTY))) {
/* Put a character into Tx FIFO */
rx_data[rx_bytes] = config->ser->SERRBUF;
rx_bytes++;
}
return rx_bytes;
}
static void kb1200_uart_irq_tx_enable(const struct device *dev)
{
const struct kb1200_uart_config *config = dev->config;
config->ser->SERPF = SERPF_TX_EMPTY;
config->ser->SERIE |= SERIE_TX_ENABLE;
}
static void kb1200_uart_irq_tx_disable(const struct device *dev)
{
const struct kb1200_uart_config *config = dev->config;
config->ser->SERIE &= ~SERIE_TX_ENABLE;
config->ser->SERPF = SERPF_TX_EMPTY;
}
static int kb1200_uart_irq_tx_ready(const struct device *dev)
{
struct kb1200_uart_data *data = dev->data;
return (data->pending_flag_data & SERPF_TX_EMPTY) ? 1 : 0;
}
static void kb1200_uart_irq_rx_enable(const struct device *dev)
{
const struct kb1200_uart_config *config = dev->config;
config->ser->SERPF = SERPF_RX_CNT_FULL;
config->ser->SERIE |= SERIE_RX_ENABLE;
}
static void kb1200_uart_irq_rx_disable(const struct device *dev)
{
const struct kb1200_uart_config *config = dev->config;
config->ser->SERIE &= (~SERIE_RX_ENABLE);
config->ser->SERPF = SERPF_RX_CNT_FULL;
}
static int kb1200_uart_irq_rx_ready(const struct device *dev)
{
struct kb1200_uart_data *data = dev->data;
return (data->pending_flag_data & SERPF_RX_CNT_FULL) ? 1 : 0;
}
static void kb1200_uart_irq_err_enable(const struct device *dev)
{
const struct kb1200_uart_config *config = dev->config;
config->ser->SERPF = SERPF_RX_ERROR;
config->ser->SERIE |= SERIE_RX_ERROR;
}
static void kb1200_uart_irq_err_disable(const struct device *dev)
{
const struct kb1200_uart_config *config = dev->config;
config->ser->SERIE &= (~SERIE_RX_ERROR);
config->ser->SERPF = SERPF_RX_ERROR;
}
static int kb1200_uart_irq_is_pending(const struct device *dev)
{
struct kb1200_uart_data *data = dev->data;
return (data->pending_flag_data) ? 1 : 0;
}
static int kb1200_uart_irq_update(const struct device *dev)
{
struct kb1200_uart_data *data = dev->data;
const struct kb1200_uart_config *config = dev->config;
data->pending_flag_data = (config->ser->SERPF) & (config->ser->SERIE);
/*clear pending flag*/
config->ser->SERPF = data->pending_flag_data;
return 1;
}
static void kb1200_uart_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb,
void *cb_data)
{
struct kb1200_uart_data *data = dev->data;
data->callback = cb;
data->callback_data = cb_data;
}
static void kb1200_uart_irq_handler(const struct device *dev)
{
struct kb1200_uart_data *data = dev->data;
if (data->callback) {
data->callback(dev, data->callback_data);
}
}
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
static int kb1200_uart_poll_in(const struct device *dev, unsigned char *c)
{
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
return kb1200_uart_fifo_read(dev, c, 1) ? 0 : -1;
#else
const struct kb1200_uart_config *config = dev->config;
/* Check Rx FIFO not Empty*/
if (config->ser->SERSTS & SERSTS_RX_EMPTY) {
return -1;
}
/* Put a character into Tx FIFO */
*c = config->ser->SERRBUF;
return 0;
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
}
static void kb1200_uart_poll_out(const struct device *dev, unsigned char c)
{
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
kb1200_uart_fifo_fill(dev, &c, 1);
#else
const struct kb1200_uart_config *config = dev->config;
/* Wait Tx FIFO not Full*/
while (config->ser->SERSTS & SER_TxFull) {
;
}
/* Put a character into Tx FIFO */
config->ser->SERTBUF = c;
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
}
static const struct uart_driver_api kb1200_uart_api = {
.poll_in = kb1200_uart_poll_in,
.poll_out = kb1200_uart_poll_out,
.err_check = kb1200_uart_err_check,
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
.configure = kb1200_uart_configure,
.config_get = kb1200_uart_config_get,
#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
.fifo_fill = kb1200_uart_fifo_fill,
.fifo_read = kb1200_uart_fifo_read,
.irq_tx_enable = kb1200_uart_irq_tx_enable,
.irq_tx_disable = kb1200_uart_irq_tx_disable,
.irq_tx_ready = kb1200_uart_irq_tx_ready,
.irq_rx_enable = kb1200_uart_irq_rx_enable,
.irq_rx_disable = kb1200_uart_irq_rx_disable,
.irq_rx_ready = kb1200_uart_irq_rx_ready,
.irq_err_enable = kb1200_uart_irq_err_enable,
.irq_err_disable = kb1200_uart_irq_err_disable,
.irq_is_pending = kb1200_uart_irq_is_pending,
.irq_update = kb1200_uart_irq_update,
.irq_callback_set = kb1200_uart_irq_callback_set,
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
};
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
/* GPIO module instances */
#define KB1200_UART_DEV(inst) DEVICE_DT_INST_GET(inst),
static const struct device *const uart_devices[] = {DT_INST_FOREACH_STATUS_OKAY(KB1200_UART_DEV)};
static void kb1200_uart_isr_wrap(const struct device *dev)
{
for (size_t i = 0; i < ARRAY_SIZE(uart_devices); i++) {
const struct device *dev_ = uart_devices[i];
const struct kb1200_uart_config *config = dev_->config;
if (config->ser->SERIE & config->ser->SERPF) {
kb1200_uart_irq_handler(dev_);
}
}
}
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
static int kb1200_uart_init(const struct device *dev)
{
int ret;
const struct kb1200_uart_config *config = dev->config;
struct kb1200_uart_data *data = dev->data;
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (ret != 0) {
return ret;
}
kb1200_uart_configure(dev, &data->current_config);
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
config->irq_cfg_func();
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
return 0;
}
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static bool init_irq = true;
static void kb1200_uart_irq_init(void)
{
if (init_irq) {
init_irq = false;
IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), kb1200_uart_isr_wrap, NULL,
0);
irq_enable(DT_INST_IRQN(0));
}
}
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
#define KB1200_UART_INIT(n) \
PINCTRL_DT_INST_DEFINE(n); \
static struct kb1200_uart_data kb1200_uart_data_##n = { \
.current_config = { \
.baudrate = DT_INST_PROP(n, current_speed), \
.parity = UART_CFG_PARITY_NONE, \
.stop_bits = UART_CFG_STOP_BITS_1, \
.data_bits = UART_CFG_DATA_BITS_8, \
.flow_ctrl = UART_CFG_FLOW_CTRL_NONE, \
}, \
}; \
static const struct kb1200_uart_config kb1200_uart_config_##n = { \
IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, (.irq_cfg_func = kb1200_uart_irq_init,)) \
.ser = (struct serial_regs *)DT_INST_REG_ADDR(n), \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n)}; \
DEVICE_DT_INST_DEFINE(n, &kb1200_uart_init, NULL, &kb1200_uart_data_##n, \
&kb1200_uart_config_##n, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
&kb1200_uart_api);
DT_INST_FOREACH_STATUS_OKAY(KB1200_UART_INIT)