/* * Copyright (c) 2023 ENE Technology Inc. * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT ene_kb1200_uart #include #include #include #include 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)