/* * Copyright (c) 2019 Mohamed ElShahawi (extremegtx@hotmail.com) * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT espressif_esp32_uart /* Include esp-idf headers first to avoid redefining BIT() macro */ #include #include #include #include #include #include #include #include #include #include /* * ESP32 UARTx register map structure */ struct uart_esp32_regs_t { uint32_t fifo; uint32_t int_raw; uint32_t int_st; uint32_t int_ena; uint32_t int_clr; uint32_t clk_div; uint32_t auto_baud; uint32_t status; uint32_t conf0; uint32_t conf1; uint32_t lowpulse; uint32_t highpulse; uint32_t rxd_cnt; uint32_t flow_conf; uint32_t sleep_conf; uint32_t swfc_conf; uint32_t idle_conf; uint32_t rs485_conf; uint32_t at_cmd_precnt; uint32_t at_cmd_postcnt; uint32_t at_cmd_gaptout; uint32_t at_cmd_char; uint32_t mem_conf; uint32_t mem_tx_status; uint32_t mem_rx_status; uint32_t mem_cnt_status; uint32_t pospulse; uint32_t negpulse; uint32_t reserved_0; uint32_t reserved_1; uint32_t date; uint32_t id; }; struct uart_esp32_config { struct uart_device_config dev_conf; const char *clock_name; const struct { int tx_out; int rx_in; int rts_out; int cts_in; } signals; const struct { int tx; int rx; int rts; int cts; } pins; const clock_control_subsys_t peripheral_id; const struct { int source; int line; } irq; }; /* driver data */ struct uart_esp32_data { struct uart_config uart_config; struct device *clock_dev; #ifdef CONFIG_UART_INTERRUPT_DRIVEN uart_irq_callback_user_data_t irq_cb; void *irq_cb_data; #endif }; #define DEV_CFG(dev) \ ((const struct uart_esp32_config *const)(dev)->config_info) #define DEV_DATA(dev) \ ((struct uart_esp32_data *)(dev)->driver_data) #define DEV_BASE(dev) \ ((volatile struct uart_esp32_regs_t *)(DEV_CFG(dev))->dev_conf.base) #define UART_TXFIFO_COUNT(status_reg) ((status_reg >> 16) & 0xFF) #define UART_RXFIFO_COUNT(status_reg) ((status_reg >> 0) & 0xFF) #define UART_FIFO_LIMIT 127U #define UART_TX_FIFO_THRESH 0x1 #define UART_RX_FIFO_THRESH 0x1 #define UART_GET_PARITY_ERR(reg) ((reg >> 2) & 0x1) #define UART_GET_FRAME_ERR(reg) ((reg >> 3) & 0x1) #define UART_GET_PARITY(conf0_reg) ((conf0_reg >> 0) & 0x1) #define UART_GET_PARITY_EN(conf0_reg) ((conf0_reg >> 1) & 0x1) #define UART_GET_DATA_BITS(conf0_reg) ((conf0_reg >> 2) & 0x3) #define UART_GET_STOP_BITS(conf0_reg) ((conf0_reg >> 4) & 0x3) #define UART_GET_TX_FLOW(conf0_reg) ((conf0_reg >> 15) & 0x1) #define UART_GET_RX_FLOW(conf1_reg) ((conf1_reg >> 23) & 0x1) /* FIXME: This should be removed when interrupt support added to ESP32 dts */ #define INST_0_ESPRESSIF_ESP32_UART_IRQ_0 12 #define INST_1_ESPRESSIF_ESP32_UART_IRQ_0 17 #define INST_2_ESPRESSIF_ESP32_UART_IRQ_0 18 /* ESP-IDF Naming is not consistent for UART0 with UART1/2 */ #define DPORT_UART0_CLK_EN DPORT_UART_CLK_EN #define DPORT_UART0_RST DPORT_UART_RST static int uart_esp32_poll_in(struct device *dev, unsigned char *p_char) { if (UART_RXFIFO_COUNT(DEV_BASE(dev)->status) == 0) { return -1; } *p_char = DEV_BASE(dev)->fifo; return 0; } static void uart_esp32_poll_out(struct device *dev, unsigned char c) { /* Wait for space in FIFO */ while (UART_TXFIFO_COUNT(DEV_BASE(dev)->status) >= UART_FIFO_LIMIT) { ; /* Wait */ } /* Send a character */ DEV_BASE(dev)->fifo = (uint32_t)c; } static int uart_esp32_err_check(struct device *dev) { uint32_t err = UART_GET_PARITY_ERR(DEV_BASE(dev)->int_st) | UART_GET_FRAME_ERR(DEV_BASE(dev)->int_st); return err; } static int uart_esp32_config_get(struct device *dev, struct uart_config *cfg) { struct uart_esp32_data *data = DEV_DATA(dev); cfg->baudrate = data->uart_config.baudrate; if (UART_GET_PARITY_EN(DEV_BASE(dev)->conf0)) { cfg->parity = UART_GET_PARITY(DEV_BASE(dev)->conf0); } else { cfg->parity = UART_CFG_PARITY_NONE; } cfg->stop_bits = UART_GET_STOP_BITS(DEV_BASE(dev)->conf0); cfg->data_bits = UART_GET_DATA_BITS(DEV_BASE(dev)->conf0); if (UART_GET_TX_FLOW(DEV_BASE(dev)->conf0)) { cfg->flow_ctrl = UART_CFG_FLOW_CTRL_RTS_CTS; } if (UART_GET_RX_FLOW(DEV_BASE(dev)->conf1)) { cfg->flow_ctrl = UART_CFG_FLOW_CTRL_DTR_DSR; } return 0; } static int uart_esp32_set_baudrate(struct device *dev, int baudrate) { uint32_t sys_clk_freq = 0; if (clock_control_get_rate(DEV_DATA(dev)->clock_dev, DEV_CFG(dev)->peripheral_id, &sys_clk_freq)) { return -EINVAL; } uint32_t clk_div = (((sys_clk_freq) << 4) / baudrate); while (UART_TXFIFO_COUNT(DEV_BASE(dev)->status)) { ; /* Wait */ } if (clk_div < 16) { return -EINVAL; } DEV_BASE(dev)->clk_div = ((clk_div >> 4) | (clk_div & 0xf)); return 1; } static int uart_esp32_configure_pins(struct device *dev) { const struct uart_esp32_config *const cfg = DEV_CFG(dev); esp32_rom_gpio_matrix_out(cfg->pins.tx, cfg->signals.tx_out, false, false); esp32_rom_gpio_matrix_in(cfg->pins.rx, cfg->signals.rx_in, false); if (cfg->pins.cts) { esp32_rom_gpio_matrix_out(cfg->pins.cts, cfg->signals.cts_in, false, false); } if (cfg->pins.rts) { esp32_rom_gpio_matrix_in(cfg->pins.rts, cfg->signals.rts_out, false); } return 0; } static int uart_esp32_configure(struct device *dev, const struct uart_config *cfg) { uint32_t conf0 = UART_TICK_REF_ALWAYS_ON; uint32_t conf1 = (UART_RX_FIFO_THRESH << UART_RXFIFO_FULL_THRHD_S) | (UART_TX_FIFO_THRESH << UART_TXFIFO_EMPTY_THRHD_S); uart_esp32_configure_pins(dev); clock_control_on(DEV_DATA(dev)->clock_dev, DEV_CFG(dev)->peripheral_id); /* * Reset RX Buffer by reading all received bytes * Hardware Reset functionality can't be used with UART 1/2 */ while (UART_RXFIFO_COUNT(DEV_BASE(dev)->status) != 0) { (void) DEV_BASE(dev)->fifo; } switch (cfg->parity) { case UART_CFG_PARITY_NONE: conf0 &= ~(UART_PARITY_EN); conf0 &= ~(UART_PARITY); break; case UART_CFG_PARITY_EVEN: conf0 &= ~(UART_PARITY); break; case UART_CFG_PARITY_ODD: conf0 |= UART_PARITY; break; default: return -ENOTSUP; } switch (cfg->stop_bits) { case UART_CFG_STOP_BITS_1: case UART_CFG_STOP_BITS_1_5: case UART_CFG_STOP_BITS_2: conf0 |= cfg->stop_bits << UART_STOP_BIT_NUM_S; break; default: return -ENOTSUP; } if (cfg->data_bits <= UART_CFG_DATA_BITS_8) { conf0 |= cfg->data_bits << UART_BIT_NUM_S; } else { return -ENOTSUP; } switch (cfg->flow_ctrl) { case UART_CFG_FLOW_CTRL_NONE: conf0 &= ~(UART_TX_FLOW_EN); conf1 &= ~(UART_RX_FLOW_EN); break; case UART_CFG_FLOW_CTRL_RTS_CTS: conf0 |= UART_TX_FLOW_EN; conf1 |= UART_RX_FLOW_EN; break; default: return -ENOTSUP; } if (uart_esp32_set_baudrate(dev, cfg->baudrate)) { DEV_DATA(dev)->uart_config.baudrate = cfg->baudrate; } else { return -ENOTSUP; } DEV_BASE(dev)->conf0 = conf0; DEV_BASE(dev)->conf1 = conf1; return 0; } static int uart_esp32_init(struct device *dev) { struct uart_esp32_data *data = DEV_DATA(dev); data->clock_dev = device_get_binding(DEV_CFG(dev)->clock_name); __ASSERT_NO_MSG(data->clock_dev); uart_esp32_configure(dev, &DEV_DATA(dev)->uart_config); #ifdef CONFIG_UART_INTERRUPT_DRIVEN DEV_CFG(dev)->dev_conf.irq_config_func(dev); #endif return 0; } #ifdef CONFIG_UART_INTERRUPT_DRIVEN static int uart_esp32_fifo_fill(struct device *dev, const uint8_t *tx_data, int len) { uint8_t num_tx = 0U; while ((len - num_tx > 0) && UART_TXFIFO_COUNT(DEV_BASE(dev)->status) < UART_FIFO_LIMIT) { DEV_BASE(dev)->fifo = (uint32_t)tx_data[num_tx++]; } return num_tx; } static int uart_esp32_fifo_read(struct device *dev, uint8_t *rx_data, const int len) { uint8_t num_rx = 0U; while ((len - num_rx > 0) && (UART_RXFIFO_COUNT(DEV_BASE(dev)->status) != 0)) { rx_data[num_rx++] = DEV_BASE(dev)->fifo; } return num_rx; } static void uart_esp32_irq_tx_enable(struct device *dev) { DEV_BASE(dev)->int_clr |= UART_TXFIFO_EMPTY_INT_ENA; DEV_BASE(dev)->int_ena |= UART_TXFIFO_EMPTY_INT_ENA; } static void uart_esp32_irq_tx_disable(struct device *dev) { DEV_BASE(dev)->int_ena &= ~(UART_TXFIFO_EMPTY_INT_ENA); } static int uart_esp32_irq_tx_ready(struct device *dev) { return (UART_TXFIFO_COUNT(DEV_BASE(dev)->status) < UART_FIFO_LIMIT); } static void uart_esp32_irq_rx_enable(struct device *dev) { DEV_BASE(dev)->int_clr |= UART_RXFIFO_FULL_INT_ENA; DEV_BASE(dev)->int_ena |= UART_RXFIFO_FULL_INT_ENA; } static void uart_esp32_irq_rx_disable(struct device *dev) { DEV_BASE(dev)->int_ena &= ~(UART_RXFIFO_FULL_INT_ENA); } static int uart_esp32_irq_tx_complete(struct device *dev) { /* check if TX FIFO is empty */ return (UART_TXFIFO_COUNT(DEV_BASE(dev)->status) == 0 ? 1 : 0); } static int uart_esp32_irq_rx_ready(struct device *dev) { return (UART_RXFIFO_COUNT(DEV_BASE(dev)->status) > 0); } static void uart_esp32_irq_err_enable(struct device *dev) { /* enable framing, parity */ DEV_BASE(dev)->int_ena |= UART_FRM_ERR_INT_ENA | UART_PARITY_ERR_INT_ENA; } static void uart_esp32_irq_err_disable(struct device *dev) { DEV_BASE(dev)->int_ena &= ~(UART_FRM_ERR_INT_ENA); DEV_BASE(dev)->int_ena &= ~(UART_PARITY_ERR_INT_ENA); } static int uart_esp32_irq_is_pending(struct device *dev) { return uart_esp32_irq_rx_ready(dev) || uart_esp32_irq_tx_ready(dev); } static int uart_esp32_irq_update(struct device *dev) { DEV_BASE(dev)->int_clr |= UART_RXFIFO_FULL_INT_ENA; DEV_BASE(dev)->int_clr |= UART_TXFIFO_EMPTY_INT_ENA; return 1; } static void uart_esp32_irq_callback_set(struct device *dev, uart_irq_callback_user_data_t cb, void *cb_data) { DEV_DATA(dev)->irq_cb = cb; DEV_DATA(dev)->irq_cb_data = cb_data; } void uart_esp32_isr(void *arg) { struct device *dev = arg; struct uart_esp32_data *data = DEV_DATA(dev); /* Verify if the callback has been registered */ if (data->irq_cb) { data->irq_cb(data->irq_cb_data); } } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ static const struct uart_driver_api uart_esp32_api = { .poll_in = uart_esp32_poll_in, .poll_out = uart_esp32_poll_out, .err_check = uart_esp32_err_check, .configure = uart_esp32_configure, .config_get = uart_esp32_config_get, #ifdef CONFIG_UART_INTERRUPT_DRIVEN .fifo_fill = uart_esp32_fifo_fill, .fifo_read = uart_esp32_fifo_read, .irq_tx_enable = uart_esp32_irq_tx_enable, .irq_tx_disable = uart_esp32_irq_tx_disable, .irq_tx_ready = uart_esp32_irq_tx_ready, .irq_rx_enable = uart_esp32_irq_rx_enable, .irq_rx_disable = uart_esp32_irq_rx_disable, .irq_tx_complete = uart_esp32_irq_tx_complete, .irq_rx_ready = uart_esp32_irq_rx_ready, .irq_err_enable = uart_esp32_irq_err_enable, .irq_err_disable = uart_esp32_irq_err_disable, .irq_is_pending = uart_esp32_irq_is_pending, .irq_update = uart_esp32_irq_update, .irq_callback_set = uart_esp32_irq_callback_set, #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ }; #ifdef CONFIG_UART_INTERRUPT_DRIVEN #define ESP32_UART_IRQ_HANDLER_DECL(idx) \ static void uart_esp32_irq_config_func_##idx(struct device *dev) #define ESP32_UART_IRQ_HANDLER_FUNC(idx) \ .irq_config_func = uart_esp32_irq_config_func_##idx, #define ESP32_UART_IRQ_HANDLER(idx) \ static void uart_esp32_irq_config_func_##idx(struct device *dev) \ { \ esp32_rom_intr_matrix_set(0, ETS_UART##idx##_INTR_SOURCE, \ INST_##idx##_ESPRESSIF_ESP32_UART_IRQ_0); \ IRQ_CONNECT(INST_##idx##_ESPRESSIF_ESP32_UART_IRQ_0, \ 1, \ uart_esp32_isr, \ DEVICE_GET(uart_esp32_##idx), \ 0); \ irq_enable(INST_##idx##_ESPRESSIF_ESP32_UART_IRQ_0); \ } #else #define ESP32_UART_IRQ_HANDLER_DECL(idx) #define ESP32_UART_IRQ_HANDLER_FUNC(idx) #define ESP32_UART_IRQ_HANDLER(idx) #endif #define ESP32_UART_INIT(idx) \ ESP32_UART_IRQ_HANDLER_DECL(idx); \ static const struct uart_esp32_config uart_esp32_cfg_port_##idx = { \ .dev_conf = { \ .base = \ (uint8_t *)DT_INST_REG_ADDR(idx), \ ESP32_UART_IRQ_HANDLER_FUNC(idx) \ }, \ \ .clock_name = DT_INST_CLOCKS_LABEL(idx), \ \ .signals = { \ .tx_out = U##idx##TXD_OUT_IDX, \ .rx_in = U##idx##RXD_IN_IDX, \ .rts_out = U##idx##RTS_OUT_IDX, \ .cts_in = U##idx##CTS_IN_IDX, \ }, \ \ .pins = { \ .tx = DT_INST_PROP(idx, tx_pin), \ .rx = DT_INST_PROP(idx, rx_pin), \ IF_ENABLED( \ DT_INST_PROP(idx, hw_flow_control), \ (.rts = DT_INST_PROP(idx, rts_pin), \ .cts = DT_INST_PROP(idx, cts_pin), \ )) \ }, \ \ .peripheral_id = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(idx, offset), \ .irq = { \ .source = ETS_UART##idx##_INTR_SOURCE, \ .line = INST_##idx##_ESPRESSIF_ESP32_UART_IRQ_0, \ } \ }; \ \ static struct uart_esp32_data uart_esp32_data_##idx = { \ .uart_config = { \ .baudrate = DT_INST_PROP(idx, current_speed),\ .parity = UART_CFG_PARITY_NONE, \ .stop_bits = UART_CFG_STOP_BITS_1, \ .data_bits = UART_CFG_DATA_BITS_8, \ .flow_ctrl = IS_ENABLED( \ DT_INST_PROP(idx, hw_flow_control)) ?\ UART_CFG_FLOW_CTRL_RTS_CTS : UART_CFG_FLOW_CTRL_NONE \ } \ }; \ \ DEVICE_AND_API_INIT(uart_esp32_##idx, \ DT_INST_LABEL(idx), \ uart_esp32_init, \ &uart_esp32_data_##idx, \ &uart_esp32_cfg_port_##idx, \ PRE_KERNEL_1, \ CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ &uart_esp32_api); \ \ ESP32_UART_IRQ_HANDLER(idx) DT_INST_FOREACH_STATUS_OKAY(ESP32_UART_INIT)