diff --git a/arch/xtensa/src/esp32/chip/esp32_uart.h b/arch/xtensa/src/esp32/chip/esp32_uart.h index f13a5c234c..8e86e436b3 100644 --- a/arch/xtensa/src/esp32/chip/esp32_uart.h +++ b/arch/xtensa/src/esp32/chip/esp32_uart.h @@ -39,7 +39,8 @@ #define REG_UART_BASE(i) (DR_REG_UART_BASE + (i) * 0x10000 + (i > 1 ? 0xe000 : 0)) -#define UART_FIFO_REG(i) (REG_UART_BASE(i) + 0x0) +#define UART_FIFO_OFFSET 0x00 +#define UART_FIFO_REG(i) (REG_UART_BASE(i) + UART_FIFO_OFFSET) /* UART_RXFIFO_RD_BYTE : RO ;bitpos:[7:0] ;default: 8'b0 ; */ /* Description: This register stores one byte data read by rx fifo.*/ @@ -49,7 +50,8 @@ #define UART_RXFIFO_RD_BYTE_V 0xFF #define UART_RXFIFO_RD_BYTE_S 0 -#define UART_INT_RAW_REG(i) (REG_UART_BASE(i) + 0x4) +#define UART_INT_RAW_OFFSET 0x04 +#define UART_INT_RAW_REG(i) (REG_UART_BASE(i) + UART_INT_RAW_OFFSET) /* UART_AT_CMD_CHAR_DET_INT_RAW : RO ;bitpos:[18] ;default: 1'b0 ; */ /* Description: This interrupt raw bit turns to high level when receiver @@ -241,7 +243,8 @@ #define UART_RXFIFO_FULL_INT_RAW_V 0x1 #define UART_RXFIFO_FULL_INT_RAW_S 0 -#define UART_INT_ST_REG(i) (REG_UART_BASE(i) + 0x8) +#define UART_INT_ST_OFFSET 0x08 +#define UART_INT_ST_REG(i) (REG_UART_BASE(i) + UART_INT_ST_OFFSET) /* UART_AT_CMD_CHAR_DET_INT_ST : RO ;bitpos:[18] ;default: 1'b0 ; */ /* Description: This is the status bit for at_cmd_det_int_raw when @@ -432,7 +435,8 @@ #define UART_RXFIFO_FULL_INT_ST_V 0x1 #define UART_RXFIFO_FULL_INT_ST_S 0 -#define UART_INT_ENA_REG(i) (REG_UART_BASE(i) + 0xC) +#define UART_INT_ENA_OFFSET 0x0c +#define UART_INT_ENA_REG(i) (REG_UART_BASE(i) + UART_INT_ENA_OFFSET) /* UART_AT_CMD_CHAR_DET_INT_ENA : R/W ;bitpos:[18] ;default: 1'b0 ; */ /* Description: This is the enable bit for at_cmd_char_det_int_st register.*/ @@ -586,7 +590,8 @@ #define UART_RXFIFO_FULL_INT_ENA_V 0x1 #define UART_RXFIFO_FULL_INT_ENA_S 0 -#define UART_INT_CLR_REG(i) (REG_UART_BASE(i) + 0x10) +#define UART_INT_CLR_OFFSET 0x10 +#define UART_INT_CLR_REG(i) (REG_UART_BASE(i) + UART_INT_CLR_OFFSET) /* UART_AT_CMD_CHAR_DET_INT_CLR : WO ;bitpos:[18] ;default: 1'b0 ; */ /* Description: Set this bit to clear the at_cmd_char_det_int_raw interrupt.*/ @@ -744,7 +749,8 @@ #define UART_RXFIFO_FULL_INT_CLR_V 0x1 #define UART_RXFIFO_FULL_INT_CLR_S 0 -#define UART_CLKDIV_REG(i) (REG_UART_BASE(i) + 0x14) +#define UART_CLKDIV_OFFSET 0x14 +#define UART_CLKDIV_REG(i) (REG_UART_BASE(i) + UART_CLKDIV_OFFSET) /* UART_CLKDIV_FRAG : R/W ;bitpos:[23:20] ;default: 4'h0 ; */ /* Description: The register value is the decimal part of the frequency @@ -766,7 +772,8 @@ #define UART_CLKDIV_V 0xFFFFF #define UART_CLKDIV_S 0 -#define UART_AUTOBAUD_REG(i) (REG_UART_BASE(i) + 0x18) +#define UART_AUTOBAUD_OFFSET 0x18 +#define UART_AUTOBAUD_REG(i) (REG_UART_BASE(i) + UART_AUTOBAUD_OFFSET) /* UART_GLITCH_FILT : R/W ;bitpos:[15:8] ;default: 8'h10 ; */ /* Description: when input pulse width is lower then this value igore this @@ -786,7 +793,8 @@ #define UART_AUTOBAUD_EN_V 0x1 #define UART_AUTOBAUD_EN_S 0 -#define UART_STATUS_REG(i) (REG_UART_BASE(i) + 0x1C) +#define UART_STATUS_OFFSET 0x1c +#define UART_STATUS_REG(i) (REG_UART_BASE(i) + UART_STATUS_OFFSET) /* UART_TXD : RO ;bitpos:[31] ;default: 8'h0 ; */ /* Description: This register represent the level value of the internal @@ -895,7 +903,8 @@ #define UART_RXFIFO_CNT_V 0xFF #define UART_RXFIFO_CNT_S 0 -#define UART_CONF0_REG(i) (REG_UART_BASE(i) + 0x20) +#define UART_CONF0_OFFSET 0x20 +#define UART_CONF0_REG(i) (REG_UART_BASE(i) + UART_CONF0_OFFSET) /* UART_TICK_REF_ALWAYS_ON : R/W ;bitpos:[27] ;default: 1'b1 ; */ /* Description: This register is used to select the clock.1.apb clock @@ -1127,7 +1136,8 @@ #define UART_PARITY_V 0x1 #define UART_PARITY_S 0 -#define UART_CONF1_REG(i) (REG_UART_BASE(i) + 0x24) +#define UART_CONF1_OFFSET 0x24 +#define UART_CONF1_REG(i) (REG_UART_BASE(i) + UART_CONF1_OFFSET) /* UART_RX_TOUT_EN : R/W ;bitpos:[31] ;default: 1'b0 ; */ /* Description: This is the enble bit for uart receiver's timeout function.*/ @@ -1190,7 +1200,8 @@ #define UART_RXFIFO_FULL_THRHD_V 0x7F #define UART_RXFIFO_FULL_THRHD_S 0 -#define UART_LOWPULSE_REG(i) (REG_UART_BASE(i) + 0x28) +#define UART_LOWPULSE_OFFSET 0x28 +#define UART_LOWPULSE_REG(i) (REG_UART_BASE(i) + UART_LOWPULSE_OFFSET) /* UART_LOWPULSE_MIN_CNT : RO ;bitpos:[19:0] ;default: 20'hFFFFF ; */ /* Description: This register stores the value of the minimum duration time @@ -1202,7 +1213,8 @@ #define UART_LOWPULSE_MIN_CNT_V 0xFFFFF #define UART_LOWPULSE_MIN_CNT_S 0 -#define UART_HIGHPULSE_REG(i) (REG_UART_BASE(i) + 0x2C) +#define UART_HIGHPULSE_OFFSET 0x2c +#define UART_HIGHPULSE_REG(i) (REG_UART_BASE(i) + UART_HIGHPULSE_OFFSET) /* UART_HIGHPULSE_MIN_CNT : RO ;bitpos:[19:0] ;default: 20'hFFFFF ; */ /* Description: This register stores the value of the maxinum duration time @@ -1214,7 +1226,8 @@ #define UART_HIGHPULSE_MIN_CNT_V 0xFFFFF #define UART_HIGHPULSE_MIN_CNT_S 0 -#define UART_RXD_CNT_REG(i) (REG_UART_BASE(i) + 0x30) +#define UART_RXD_CNT_OFFSET 0x30 +#define UART_RXD_CNT_REG(i) (REG_UART_BASE(i) + UART_RXD_CNT_OFFSET) /* UART_RXD_EDGE_CNT : RO ;bitpos:[9:0] ;default: 10'h0 ; */ /* Description: This register stores the count of rxd edge change. it is @@ -1226,7 +1239,8 @@ #define UART_RXD_EDGE_CNT_V 0x3FF #define UART_RXD_EDGE_CNT_S 0 -#define UART_FLOW_CONF_REG(i) (REG_UART_BASE(i) + 0x34) +#define UART_FLOW_CONF_OFFSET 0x34 +#define UART_FLOW_CONF_REG(i) (REG_UART_BASE(i) + UART_FLOW_CONF_OFFSET) /* UART_SEND_XOFF : R/W ;bitpos:[5] ;default: 1'b0 ; */ /* Description: Set this bit to send xoff char. it is cleared by hardware @@ -1288,7 +1302,8 @@ #define UART_SW_FLOW_CON_EN_V 0x1 #define UART_SW_FLOW_CON_EN_S 0 -#define UART_SLEEP_CONF_REG(i) (REG_UART_BASE(i) + 0x38) +#define UART_SLEEP_CONF_OFFSET 0x38 +#define UART_SLEEP_CONF_REG(i) (REG_UART_BASE(i) + UART_SLEEP_CONF_OFFSET) /* UART_ACTIVE_THRESHOLD : R/W ;bitpos:[9:0] ;default: 10'hf0 ; */ /* Description: When the input rxd edge changes more than this register @@ -1300,7 +1315,8 @@ #define UART_ACTIVE_THRESHOLD_V 0x3FF #define UART_ACTIVE_THRESHOLD_S 0 -#define UART_SWFC_CONF_REG(i) (REG_UART_BASE(i) + 0x3C) +#define UART_SWFC_CONF_OFFSET 0x3c +#define UART_SWFC_CONF_REG(i) (REG_UART_BASE(i) + UART_SWFC_CONF_OFFSET) /* UART_XOFF_CHAR : R/W ;bitpos:[31:24] ;default: 8'h13 ; */ /* Description: This register stores the xoff flow control char.*/ @@ -1340,7 +1356,8 @@ #define UART_XON_THRESHOLD_V 0xFF #define UART_XON_THRESHOLD_S 0 -#define UART_IDLE_CONF_REG(i) (REG_UART_BASE(i) + 0x40) +#define UART_IDLE_CONF_OFFSET 0x40 +#define UART_IDLE_CONF_REG(i) (REG_UART_BASE(i) + UART_IDLE_CONF_OFFSET) /* UART_TX_BRK_NUM : R/W ;bitpos:[27:20] ;default: 8'ha ; */ /* Description: This register is used to configure the num of 0 send after @@ -1374,7 +1391,8 @@ #define UART_RX_IDLE_THRHD_V 0x3FF #define UART_RX_IDLE_THRHD_S 0 -#define UART_RS485_CONF_REG(i) (REG_UART_BASE(i) + 0x44) +#define UART_RS485_CONF_OFFSET 0x44 +#define UART_RS485_CONF_REG(i) (REG_UART_BASE(i) + UART_RS485_CONF_OFFSET) /* UART_RS485_TX_DLY_NUM : R/W ;bitpos:[9:6] ;default: 4'b0 ; */ /* Description: This register is used to delay the transmitter's internal @@ -1441,6 +1459,7 @@ #define UART_RS485_EN_V 0x1 #define UART_RS485_EN_S 0 +#define UART_AT_CMD_PRECNT_OFFSET 0x48 #define UART_AT_CMD_PRECNT_REG(i) (REG_UART_BASE(i) + 0x48) /* UART_PRE_IDLE_NUM : R/W ;bitpos:[23:0] ;default: 24'h186a00 ; */ @@ -1455,7 +1474,8 @@ #define UART_PRE_IDLE_NUM_V 0xFFFFFF #define UART_PRE_IDLE_NUM_S 0 -#define UART_AT_CMD_POSTCNT_REG(i) (REG_UART_BASE(i) + 0x4c) +#define UART_AT_CMD_POSTCNT_OFFSET 0x4c +#define UART_AT_CMD_POSTCNT_REG(i) (REG_UART_BASE(i) + UART_AT_CMD_POSTCNT_OFFSET) /* UART_POST_IDLE_NUM : R/W ;bitpos:[23:0] ;default: 24'h186a00 ; */ /* Description: This register is used to configure the duration time between @@ -1468,6 +1488,7 @@ #define UART_POST_IDLE_NUM_V 0xFFFFFF #define UART_POST_IDLE_NUM_S 0 +#define UART_AT_CMD_GAPTOUT_OFFSET 0x50 #define UART_AT_CMD_GAPTOUT_REG(i) (REG_UART_BASE(i) + 0x50) /* UART_RX_GAP_TOUT : R/W ;bitpos:[23:0] ;default: 24'h1e00 ; */ @@ -1481,7 +1502,8 @@ #define UART_RX_GAP_TOUT_V 0xFFFFFF #define UART_RX_GAP_TOUT_S 0 -#define UART_AT_CMD_CHAR_REG(i) (REG_UART_BASE(i) + 0x54) +#define UART_AT_CMD_CHAR_OFFSET 0x54 +#define UART_AT_CMD_CHAR_REG(i) (REG_UART_BASE(i) + UART_AT_CMD_CHAR_OFFSET) /* UART_CHAR_NUM : R/W ;bitpos:[15:8] ;default: 8'h3 ; */ /* Description: This register is used to configure the num of continous @@ -1503,7 +1525,8 @@ #define UART_AT_CMD_CHAR_V 0xFF #define UART_AT_CMD_CHAR_S 0 -#define UART_MEM_CONF_REG(i) (REG_UART_BASE(i) + 0x58) +#define UART_MEM_CONF_OFFSET 0x58 +#define UART_MEM_CONF_REG(i) (REG_UART_BASE(i) + UART_MEM_CONF_OFFSET) /* UART_TX_MEM_EMPTY_THRHD : R/W ;bitpos:[30:28] ;default: 3'h0 ; */ /* Description: refer to txfifo_empty_thrhd 's describtion.*/ @@ -1583,7 +1606,8 @@ #define UART_MEM_PD_V 0x1 #define UART_MEM_PD_S 0 -#define UART_MEM_TX_STATUS_REG(i) (REG_UART_BASE(i) + 0x5c) +#define UART_MEM_TX_STATUS_OFFSET 0x5c +#define UART_MEM_TX_STATUS_REG(i) (REG_UART_BASE(i) + UART_MEM_TX_STATUS_OFFSET) /* UART_MEM_TX_STATUS : RO ;bitpos:[23:0] ;default: 24'h0 ; */ /* Description: */ @@ -1593,7 +1617,8 @@ #define UART_MEM_TX_STATUS_V 0xFFFFFF #define UART_MEM_TX_STATUS_S 0 -#define UART_MEM_RX_STATUS_REG(i) (REG_UART_BASE(i) + 0x60) +#define UART_MEM_RX_STATUS_OFFSET 0x60 +#define UART_MEM_RX_STATUS_REG(i) (REG_UART_BASE(i) + UART_MEM_RX_STATUS_OFFSET) /* UART_MEM_RX_STATUS : RO ;bitpos:[23:0] ;default: 24'h0 ; */ /* Description: */ @@ -1603,7 +1628,8 @@ #define UART_MEM_RX_STATUS_V 0xFFFFFF #define UART_MEM_RX_STATUS_S 0 -#define UART_MEM_CNT_STATUS_REG(i) (REG_UART_BASE(i) + 0x64) +#define UART_MEM_CNT_STATUS_OFFSET 0x64 +#define UART_MEM_CNT_STATUS_REG(i) (REG_UART_BASE(i) + UART_MEM_CNT_STATUS_OFFSET) /* UART_TX_MEM_CNT : RO ;bitpos:[5:3] ;default: 3'b0 ; */ /* Description: refer to the txfifo_cnt's describtion.*/ @@ -1621,6 +1647,7 @@ #define UART_RX_MEM_CNT_V 0x7 #define UART_RX_MEM_CNT_S 0 +#define UART_POSPULSE_OFFSET 0x68 #define UART_POSPULSE_REG(i) (REG_UART_BASE(i) + 0x68) /* UART_POSEDGE_MIN_CNT : RO ;bitpos:[19:0] ;default: 20'hFFFFF ; */ @@ -1633,7 +1660,8 @@ #define UART_POSEDGE_MIN_CNT_V 0xFFFFF #define UART_POSEDGE_MIN_CNT_S 0 -#define UART_NEGPULSE_REG(i) (REG_UART_BASE(i) + 0x6c) +#define UART_NEGPULSE_OFFSET 0x6c +#define UART_NEGPULSE_REG(i) (REG_UART_BASE(i) + UART_NEGPULSE_OFFSET) /* UART_NEGEDGE_MIN_CNT : RO ;bitpos:[19:0] ;default: 20'hFFFFF ; */ /* Description: This register stores the count of rxd negedge edge. it is @@ -1645,6 +1673,7 @@ #define UART_NEGEDGE_MIN_CNT_V 0xFFFFF #define UART_NEGEDGE_MIN_CNT_S 0 +#define UART_DATE_OFFSET 0x78 #define UART_DATE_REG(i) (REG_UART_BASE(i) + 0x78) /* UART_DATE : R/W ;bitpos:[31:0] ;default: 32'h15122500 ; */ @@ -1655,7 +1684,8 @@ #define UART_DATE_V 0xFFFFFFFF #define UART_DATE_S 0 -#define UART_ID_REG(i) (REG_UART_BASE(i) + 0x7C) +#define UART_ID_OFFSET 0x7c +#define UART_ID_REG(i) (REG_UART_BASE(i) + UART_ID_OFFSET) /* UART_ID : R/W ;bitpos:[31:0] ;default: 32'h0500 ; */ /* Description: */ diff --git a/arch/xtensa/src/esp32/esp32_gpio.c b/arch/xtensa/src/esp32/esp32_gpio.c index c40b6b097a..6b5bd108f1 100644 --- a/arch/xtensa/src/esp32/esp32_gpio.c +++ b/arch/xtensa/src/esp32/esp32_gpio.c @@ -161,6 +161,7 @@ int esp32_configgpio(int pin, gpio_pinattr_t attr) uintptr_t regaddr; uint32_t func; uint32_t cntrl; + unsigned int pinmode; DEBUGASSERT(pin >=0 && pin <= ESP32_NIRQ_GPIO); @@ -212,17 +213,18 @@ int esp32_configgpio(int pin, gpio_pinattr_t attr) func |= FUN_IE; - if ((attr & (INPUT | OUTPUT)) != 0) + pinmode = (attr & PINMODE_MASK); + if (pinmode == INPUT | pinmode == OUTPUT) { func |= (uint32_t)(2 << MCU_SEL_S); } - else if (attr == SPECIAL) + else if ((attr & FUNCTION_MASK) == SPECIAL) { func |= (uint32_t)((((pin) == 1 || (pin) == 3) ? 0 : 1) << MCU_SEL_S); } - else + else /* if ((attr & FUNCTION) != 0) */ { - func |= (uint32_t)((attr >> 5) << MCU_SEL_S); + func |= (uint32_t)((attr >> FUNCTION_SHIFT) << MCU_SEL_S); } if ((attr & OPEN_DRAIN) != 0) diff --git a/arch/xtensa/src/esp32/esp32_gpio.h b/arch/xtensa/src/esp32/esp32_gpio.h index f765917d43..ea09df2439 100644 --- a/arch/xtensa/src/esp32/esp32_gpio.h +++ b/arch/xtensa/src/esp32/esp32_gpio.h @@ -42,22 +42,46 @@ /* Bit-encoded input to esp32_configgpio() **********************************/ -/* Encoded pin attributes used with esp32_configgpio() */ +/* Encoded pin attributes used with esp32_configgpio() + * + * 8 7 6 5 4 3 2 1 0 + * -- -- -- -- -- -- -- -- -- + * FN FN FN OD PD PU F O I + */ -#define INPUT 0x01 -#define OUTPUT 0x02 -#define PULLUP 0x04 -#define INPUT_PULLUP 0x05 -#define PULLDOWN 0x08 -#define INPUT_PULLDOWN 0x09 -#define OPEN_DRAIN 0x10 -#define OUTPUT_OPEN_DRAIN 0x12 -#define SPECIAL 0xf0 -#define FUNCTION_0 0x00 -#define FUNCTION_1 0x20 -#define FUNCTION_2 0x40 -#define FUNCTION_3 0x70 -#define FUNCTION_4 0x80 +#define PINMODE_SHIFT 0 +#define PINMODE_MASK (7 << PINMODE_SHIFT) +# define INPUT (1 << 0) +# define OUTPUT (1 << 1) +# define FUNCTION (1 << 2) + +#define PULLUP (1 << 3) +#define PULLDOWN (1 << 4) +#define OPEN_DRAIN (1 << 5) +#define FUNCTION_SHIFT 6 +#define FUNCTION_MASK (7 << FUNCTION_SHIFT) +# define FUNCTION_0 (0 << FUNCTION_SHIFT) +# define FUNCTION_1 (1 << FUNCTION_SHIFT) +# define FUNCTION_2 (2 << FUNCTION_SHIFT) +# define FUNCTION_3 (3 << FUNCTION_SHIFT) +# define FUNCTION_4 (4 << FUNCTION_SHIFT) +# define SPECIAL (7 << FUNCTION_SHIFT) + +#define INPUT_PULLUP (INPUT | PULLUP) +#define INPUT_PULLDOWN (INPUT | PULLDOWN) +#define OUTPUT_OPEN_DRAIN (OUTPUT | OPEN_DRAIN) +#define INPUT_FUNCTION (INPUT | FUNCTION) +# define INPUT_FUNCTION_0 (INPUT_FUNCTION | FUNCTION_0) +# define INPUT_FUNCTION_1 (INPUT_FUNCTION | FUNCTION_1) +# define INPUT_FUNCTION_2 (INPUT_FUNCTION | FUNCTION_2) +# define INPUT_FUNCTION_3 (INPUT_FUNCTION | FUNCTION_3) +# define INPUT_FUNCTION_4 (INPUT_FUNCTION | FUNCTION_4) +#define OUTPUT_FUNCTION (OUTPUT | FUNCTION) +# define OUTPUT_FUNCTION_0 (OUTPUT_FUNCTION | FUNCTION_0) +# define OUTPUT_FUNCTION_1 (OUTPUT_FUNCTION | FUNCTION_1) +# define OUTPUT_FUNCTION_2 (OUTPUT_FUNCTION | FUNCTION_2) +# define OUTPUT_FUNCTION_3 (OUTPUT_FUNCTION | FUNCTION_3) +# define OUTPUT_FUNCTION_4 (OUTPUT_FUNCTION | FUNCTION_4) /* Interrupt type used with esp32_gpioirqenable() */ @@ -78,7 +102,7 @@ /* Must be big enough to hold the the above encodings */ -typedef uint8_t gpio_pinattr_t; +typedef uint16_t gpio_pinattr_t; typedef uint8_t gpio_intrtype_t; /**************************************************************************** diff --git a/arch/xtensa/src/esp32/esp32_serial.c b/arch/xtensa/src/esp32/esp32_serial.c new file mode 100644 index 0000000000..eb6bd3c8cf --- /dev/null +++ b/arch/xtensa/src/esp32/esp32_serial.c @@ -0,0 +1,1212 @@ +/**************************************************************************** + * arch/xtensa/src/esp32/esp32_serial.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SERIAL_TERMIOS +# include +#endif + +#include +#include +#include + +#include +#include + +#include "xtensa.h" +#include "chip/esp32_soc.h" +#include "chip/esp32_iomux.h" +#include "chip/esp32_gpio_sigmap.h" +#include "chip/esp32_uart.h" +#include "esp32_config.h" +#include "esp32_cpuint.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef USE_SERIALDRIVER + +/* Which UART with be tty0/console and which tty1-2? */ + +/* First pick the console and ttys0. This could be any of UART0-5 */ + +#if defined(CONFIG_UART0_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart0port /* UART0 is console */ +# define TTYS0_DEV g_uart0port /* UART0 is ttyS0 */ +# define UART0_ASSIGNED 1 +#elif defined(CONFIG_UART1_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart1port /* UART1 is console */ +# define TTYS0_DEV g_uart1port /* UART1 is ttyS0 */ +# define UART1_ASSIGNED 1 +#elif defined(CONFIG_UART2_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart2port /* UART2 is console */ +# define TTYS0_DEV g_uart2port /* UART2 is ttyS0 */ +# define UART2_ASSIGNED 1 +#else +# undef CONSOLE_DEV /* No console */ +# if defined(CONFIG_ESP32_UART0) +# define TTYS0_DEV g_uart0port /* UART0 is ttyS0 */ +# define UART0_ASSIGNED 1 +# elif defined(CONFIG_ESP32_UART1) +# define TTYS0_DEV g_uart1port /* UART1 is ttyS0 */ +# define UART1_ASSIGNED 1 +# elif defined(CONFIG_ESP32_UART2) +# define TTYS0_DEV g_uart2port /* UART2 is ttyS0 */ +# define UART2_ASSIGNED 1 +#endif + +/* Pick ttys1. This could be any of UART0-2 excluding the console + * UART. + */ + +#if defined(CONFIG_ESP32_UART0) && !defined(UART0_ASSIGNED) +# define TTYS1_DEV g_uart0port /* UART0 is ttyS1 */ +# define UART0_ASSIGNED 1 +#elif defined(CONFIG_ESP32_UART1) && !defined(UART1_ASSIGNED) +# define TTYS1_DEV g_uart1port /* UART1 is ttyS1 */ +# define UART1_ASSIGNED 1 +#elif defined(CONFIG_ESP32_UART2) && !defined(UART2_ASSIGNED) +# define TTYS1_DEV g_uart2port /* UART2 is ttyS1 */ +# define UART2_ASSIGNED 1 +#endif + +/* Pick ttys2. This could be one of UART1-2. It can't be UART0 + * because that was either assigned as ttyS0 or ttys1. One of these + * could also be the console. + */ + +#if defined(CONFIG_ESP32_UART1) && !defined(UART1_ASSIGNED) +# define TTYS2_DEV g_uart1port /* UART1 is ttyS2 */ +# define UART1_ASSIGNED 1 +#elif defined(CONFIG_ESP32_UART2) && !defined(UART2_ASSIGNED) +# define TTYS2_DEV g_uart2port /* UART2 is ttyS2 */ +# define UART2_ASSIGNED 1 +#endif + +/* UART source clock for BAUD generation */ + +#define UART_CLK_FREQ APB_CLK_FREQ + +/**************************************************************************** + * Private Types + ****************************************************************************/ +/* Constant properties of the UART. Other configuration setting may be + * changable via Termios IOCTL calls. + */ + +struct esp32_config_s +{ + const uint32_t uartbase; /* Base address of UART registers */ + xcpt_t handler; /* Interrupt handler */ + uint8_t periph; /* UART peripheral ID */ + uint8_t irq; /* IRQ number assigned to the peripheral */ + uint8_t txpin; /* Tx pin number (0-39) */ + uint8_t rxpin; /* Rx pin number (0-39) */ + uint8_t txsig; /* Tx signal */ + uint8_t rxsig; /* Rx signal */ +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + uint8_t rtspin; /* RTS pin number (0-39) */ + uint8_t ctspin; /* CTS pin number (0-39) */ + uint8_t rtssig; /* RTS signal */ + uint8_t ctssig; /* CTS signal */ +#endif +}; + +/* Current state of the UART */ + +struct esp32_dev_s +{ + const struct esp32_config_s *config /* Constant configuration */ + uint32_t baud; /* Configured baud */ + uint32_t sr; /* Saved status bits */ + uint8_t cpuint; /* CPU interrupt assigned to this UART */ + uint8_t parity; /* 0=none, 1=odd, 2=even */ + uint8_t bits; /* Number of bits (5-9) */ + bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */ +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + bool flowc; /* Input flow control (RTS) enabled */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int esp32_setup(struct uart_dev_s *dev); +static void esp32_shutdown(struct uart_dev_s *dev); +static int esp32_attach(struct uart_dev_s *dev); +static void esp32_detach(struct uart_dev_s *dev); +static int esp32_interrupt(struct uart_dev_s *dev); +#ifdef CONFIG_ESP32_UART0 +static int esp32_uart0_interrupt(int cpuint, void *context); +#endif +#ifdef CONFIG_ESP32_UART1 +static int esp32_uart1_interrupt(int cpuint, void *context); +#endif +#ifdef CONFIG_ESP32_UART2 +static int esp32_uart2_interrupt(int cpuint, void *context); +#endif +static int esp32_ioctl(struct file *filep, int cmd, unsigned long arg); +static int esp32_receive(struct uart_dev_s *dev, uint32_t *status); +static void esp32_rxint(struct uart_dev_s *dev, bool enable); +static bool esp32_rxavailable(struct uart_dev_s *dev); +static void esp32_send(struct uart_dev_s *dev, int ch); +static void esp32_txint(struct uart_dev_s *dev, bool enable); +static bool esp32_txready(struct uart_dev_s *dev); +static bool esp32_txempty(struct uart_dev_s *dev); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct uart_ops_s g_uart_ops = +{ + .setup = esp32_setup, + .shutdown = esp32_shutdown, + .attach = esp32_attach, + .detach = esp32_detach, + .ioctl = esp32_ioctl, + .receive = esp32_receive, + .rxint = esp32_rxint, + .rxavailable = esp32_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = NULL, +#endif + .send = esp32_send, + .txint = esp32_txint, + .txready = esp32_txready, + .txempty = esp32_txempty, +}; + +/* I/O buffers */ + +#ifdef CONFIG_ESP32_UART0 +static char g_uart0rxbuffer[CONFIG_UART0_RXBUFSIZE]; +static char g_uart0txbuffer[CONFIG_UART0_TXBUFSIZE]; +#endif +#ifdef CONFIG_ESP32_UART1 +static char g_uart1rxbuffer[CONFIG_UART1_RXBUFSIZE]; +static char g_uart1txbuffer[CONFIG_UART1_TXBUFSIZE]; +#endif +#ifdef CONFIG_ESP32_UART2 +static char g_uart2rxbuffer[CONFIG_UART2_RXBUFSIZE]; +static char g_uart2txbuffer[CONFIG_UART2_TXBUFSIZE]; +#endif + +/* This describes the state of the UART0 port. */ + +#ifdef CONFIG_ESP32_UART0 +static struct const esp32_config_s g_uart0config = +{ + .uartbase = DR_REG_UART_BASE, + .handler = esp32_uart0_interrupt, + .periph = ESP32_PERIPH_UART, + .irq = ESP32_IRQ_UART, + .txpin = CONFIG_ESP32_UART0_TXPIN, + .rxpin = CONFIG_ESP32_UART0_RXPIN, + .txsig = U0TXD_OUT_IDX, + .rxsig = U0RXD_IN_IDX, +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + .rtspin = CONFIG_ESP32_UART0_RTSPIN, + .ctspin = CONFIG_ESP32_UART0_CTSPIN, + .rtssig = U0RTS_OUT_IDX, + .ctssig = U0CTS_IN_IDX, +#endif +}; + +static struct esp32_dev_s g_uart0priv = +{ + .config = &g_uart0config; + .baud = CONFIG_UART0_BAUD, + .parity = CONFIG_UART0_PARITY, + .bits = CONFIG_UART0_BITS, + .stopbits2 = CONFIG_UART0_2STOP, +}; + +static uart_dev_t g_uart0port = +{ + .recv = + { + .size = CONFIG_UART0_RXBUFSIZE, + .buffer = g_uart0rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART0_TXBUFSIZE, + .buffer = g_uart0txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart0priv, +}; +#endif + +/* This describes the state of the UART1 port. */ + +#ifdef CONFIG_ESP32_UART1 +static struct const esp32_config_s g_uart1config = +{ + .uartbase = DR_REG_UART1_BASE, + .handler = esp32_uart1_interrupt, + .periph = ESP32_PERIPH_UART1, + .irq = ESP32_IRQ_UART1, + .txpin = CONFIG_ESP32_UART1_TXPIN, + .rxpin = CONFIG_ESP32_UART1_RXPIN, + .txsig = U1TXD_OUT_IDX, + .rxsig = U1RXD_IN_IDX, +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + .rtspin = CONFIG_ESP32_UART1_RTSPIN, + .ctspin = CONFIG_ESP32_UART1_CTSPIN, + .rtssig = U1RTS_OUT_IDX, + .ctssig = U1CTS_IN_IDX, +#endif +}; + +static struct esp32_dev_s g_uart1priv = +{ + .config = &g_uart1config; + .baud = CONFIG_UART1_BAUD, + .parity = CONFIG_UART1_PARITY, + .bits = CONFIG_UART1_BITS, + .stopbits2 = CONFIG_UART1_2STOP, +}; + +static uart_dev_t g_uart1port = +{ + .recv = + { + .size = CONFIG_UART1_RXBUFSIZE, + .buffer = g_uart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART1_TXBUFSIZE, + .buffer = g_uart1txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart1priv, +}; +#endif + +/* This describes the state of the UART2 port. */ + +#ifdef CONFIG_ESP32_UART2 +static struct const esp32_config_s g_uart2config = +{ + .uartbase = DR_REG_UART2_BASE, + .handler = esp32_uart2_interrupt, + .periph = ESP32_PERIPH_UART2, + .irq = ESP32_IRQ_UART2, + .txpin = CONFIG_ESP32_UART2_TXPIN, + .rxpin = CONFIG_ESP32_UART2_RXPIN, + .txsig = U2TXD_OUT_IDX, + .rxsig = U2RXD_IN_IDX, +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + .rtspin = CONFIG_ESP32_UART2_RTSPIN, + .ctspin = CONFIG_ESP32_UART2_CTSPIN, + .rtssig = U2RTS_OUT_IDX, + .ctssig = U2CTS_IN_IDX, +#endif +}; + +static struct esp32_dev_s g_uart2priv = +{ + .config = &g_uart2config; + .baud = CONFIG_UART2_BAUD, + .parity = CONFIG_UART2_PARITY, + .bits = CONFIG_UART2_BITS, + .stopbits2 = CONFIG_UART2_2STOP, +}; + +static uart_dev_t g_uart2port = +{ + .recv = + { + .size = CONFIG_UART2_RXBUFSIZE, + .buffer = g_uart2rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART2_TXBUFSIZE, + .buffer = g_uart2txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart2priv, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32_serialin + ****************************************************************************/ + +static inline uint32_t esp32_serialin(struct esp32_dev_s *priv, int offset) +{ + return getreg32(priv->config->uartbase + offset); +} + +/**************************************************************************** + * Name: esp32_serialout + ****************************************************************************/ + +static inline void esp32_serialout(struct esp32_dev_s *priv, int offset, + uint32_t value) +{ + putreg32(value, priv->config->uartbase + offset); +} + +/**************************************************************************** + * Name: esp32_restoreuartint + ****************************************************************************/ + +static inline void esp32_restoreuartint(struct esp32_dev_s *priv, + uint32_t intena) +{ + /* Restore the previous interrupt state (assuming all interrupts disabled) */ + + esp32_serialout(priv, UART_INT_ENA_OFFSET, intena); +} + +/**************************************************************************** + * Name: esp32_disableallints + ****************************************************************************/ + +static void esp32_disableallints(struct esp32_dev_s *priv, uint32_t *intena) +{ + irqstate_t flags; + + /* The following must be atomic */ + + flags = enter_critical_section(); + + if (intena) + { + /* Return the current interrupt mask */ + + *intena = esp32_serialin(priv, UART_INT_ENA_OFFSET); + } + + /* Disable all interrupts */ + + esp32_serialout(priv, UART_INT_ENA_OFFSET, 0); + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: esp32_setup + * + * Description: + * Configure the UART baud, bits, parity, etc. This method is called the + * first time that the serial port is opened. + * + ****************************************************************************/ + +static int esp32_setup(struct uart_dev_s *dev) +{ + struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv; +#ifndef CONFIG_SUPPRESS_UART_CONFIG + uint32_t clkdiv; + uint32_t regval; + uint32_t conf0; + + /* Note: The logic here depends on the fact that that the UART module + * was enabled and the pins were configured in esp32_lowsetup(). + */ + + /* The shutdown method will put the UART in a known, disabled state */ + + esp32_shutdown(dev); + + /* Set up the CONF0 register. */ + + conf0 = UART_TICK_REF_ALWAYS_ON; + +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + /* Check if flow control is enabled */ + + if (priv->flowc) + { + /* Enable hardware flow control */ + + conf0 |= UART_TX_FLOW_EN; + } +#endif + + /* OR in settings for the selected number of bits */ + + if (priv->bits == 5) + { + /* 0=5 bits */ + } + else if (priv->bits == 6) + { + conf0 |= (1 << UART_BIT_NUM_S); /* 1=6 bits */ + } + else if (priv->bits == 7) + { + conf0 |= (2 << UART_BIT_NUM_S); /* 2=7 bits */ + } + else /* if (priv->bits == 8) */ + { + conf0 |= (3 << UART_BIT_NUM_S); /* 3=8 bits */ + } + + /* OR in settings for the selected parity */ + + if (priv->parity == 1) + { + conf0 |= UART_PARITY_EN; + } + else if (priv->parity == 2) + { + conf0 |= UART_PARITY_EN | UART_PARITY; + } + + /* OR in settings for the number of stop bits */ + + if (priv->stopbits2) + { + conf0 |= 3 << UART_STOP_BIT_NUM_S; + } + else + { + conf0 |= 1 << UART_STOP_BIT_NUM_S; + } + + /* Configure the UART BAUD */ + + clkdiv = (UART_CLK_FREQ << 4) / priv->baud; + + regval = (clkdiv >> 4) << UART_CLKDIV_S; + regval |= (clkdiv & 15) << UART_CLKDIV_FRAG_S; + esp32_serialout(priv, UART_CLKDIV_OFFSET, regval); + + /* Configure UART pins + * + * Internal signals can be output to multiple GPIO pads. + * But only one GPIO pad can connect with input signal + */ + + esp32_configgpio(priv->config->txpin, OUTPUT_FUNCTION_2); + gpio_matrix_out(priv->config->txpin, priv->config->txsig, 0, 0); + + esp32_configgpio(priv->config->rxpin, INPUT_FUNCTION_2); + gpio_matrix_in(priv->config->rxpin, priv->config->rxsig, 0); + +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + esp32_configgpio(priv->config->rtspin, OUTPUT_FUNCTION_2); + gpio_matrix_out(priv->config->rtspin, priv->config->rtssig, 0, 0); + + esp32_configgpio(priv->config->ctspin, INPUT_FUNCTION_2); + gpio_matrix_in(priv->config->ctspin, priv->config->ctssig, 0); +#endif + + /* Enable RX and error interrupts. Clear and pending interrtupt */ + + regval = UART_RXFIFO_FULL_INT_ENA | UART_FRM_ERR_INT_ENA | + UART_RXFIFO_TOUT_INT_ENA; + esp32_serialout(priv, UART_INT_ENA_OFFSET, regval); + + esp32_serialout(priv, UART_INT_CLR_OFFSET, 0xffffffff); + + /* Configure and enable the UART */ + + esp32_serialout(priv, UART_CONF0_OFFSET, conf0); + regval = (112 << UART_RXFIFO_FULL_THRHD_S) | + (0x02 << UART_RX_TOUT_THRHD_S) | + UART_RX_TOUT_EN; + esp32_serialout(priv, UART_CONF1_OFFSET, regval); +#endif + + return OK; +} + +/**************************************************************************** + * Name: esp32_shutdown + * + * Description: + * Disable the UART. This method is called when the serial port is + * closed. It is assumed that esp32_detach was called earlier in the + * shutdown sequence. + * + ****************************************************************************/ + +static void esp32_shutdown(struct uart_dev_s *dev) +{ + struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv; + + /* Disable all UART interrupts */ + + esp32_disableallints(priv, NULL); + + /* Revert pins to inputs and detach UART signals */ + + esp32_configgpio(priv->config->txpin, INPUT); + gpio_matrix_out(MATRIX_DETACH_OUT_SIG, priv->txsig, true, false); + + esp32_configgpio(priv->config->rxpin, INPUT); + gpio_matrix_in(MATRIX_DETACH_IN_LOW_PIN, priv->rxsig, false); + +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + esp32_configgpio(priv->config->rtspin, INPUT); + gpio_matrix_out(MATRIX_DETACH_OUT_SIG, priv->rtssig, true, false); + + esp32_configgpio(priv->config->ctspin, INPUT); + gpio_matrix_in(MATRIX_DETACH_IN_LOW_PIN, priv->ctssig, false); +#endif + + /* Unconfigure and disable the UART */ + + esp32_serialout(priv, UART_CONF0_OFFSET, 0); + esp32_serialout(priv, UART_CONF1_OFFSET, 0); + + esp32_serialout(priv, UART_INT_ENA_OFFSET, 0); + esp32_serialout(priv, UART_INT_CLR_OFFSET, 0xffffffff); +} + +/**************************************************************************** + * Name: esp32_attach + * + * Description: + * Configure the UART to operation in interrupt driven mode. This method is + * called when the serial port is opened. Normally, this is just after the + * the setup() method is called, however, the serial console may operate in + * a non-interrupt driven mode during the boot phase. + * + * RX and TX interrupts are not enabled when by the attach method (unless the + * hardware supports multiple levels of interrupt enabling). The RX and TX + * interrupts are not enabled until the txint() and rxint() methods are called. + * + ****************************************************************************/ + +static int esp32_attach(struct uart_dev_s *dev) +{ + struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv; + int cpu; + int ret = OK; + + /* Allocate a level-sensitive, priority 1 CPU interrupt for the UART */ + + priv->cpuint = esp32_alloc_levelint(1); + if (priv->cpuint < 0) + { + ret = priv->cpuint; + } + + /* Set up to receive peripheral interrupts on the current CPU */ + +#ifdef CONFIG_SMP + cpu = up_cpu_index(); +#else + cpu = 0; +#endif + + /* Attach the GPIO peripheral to the allocated CPU interrupt */ + + up_disable_irq(g_gpio_cpuint); + esp32_attach_peripheral(cpu, priv->config->periph, priv->cpuint); + + /* Attach and enable the IRQ */ + + ret = irq_attach(priv->config->irq, priv->config->handler); + if (ret == OK) + { + /* Enable the CPU interrupt (RX and TX interrupts are still disabled + * in the UART + */ + + up_enable_irq(priv->cpuint); + } + + return ret; +} + +/**************************************************************************** + * Name: esp32_detach + * + * Description: + * Detach UART interrupts. This method is called when the serial port is + * closed normally just before the shutdown method is called. The exception + * is the serial console which is never shutdown. + * + ****************************************************************************/ + +static void esp32_detach(struct uart_dev_s *dev) +{ + struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv; + + /* Disable and detach the CPU interrupt */ + + up_disable_irq(priv->cpuint); + irq_detach(priv->config->irq); + + /* Disassociate the peripheral interrupt from the CPU interrupt */ + + esp32_detach_peripheral(cpu, priv->config->periph); + + /* And release the CPU interrupt */ + + esp32_free_cpuint(priv->cpuint); + priv->cpuint = 0xff; +} + +/**************************************************************************** + * Name: esp32_interrupt + * + * Description: + * This is the common UART interrupt handler. It will be invoked + * when an interrupt received on the device. It should call + * uart_transmitchars or uart_receivechar to perform the appropriate data + * transfers. + * + ****************************************************************************/ + +static int esp32_interrupt(struct uart_dev_s *dev) +{ + struct esp32_dev_s *priv; + uint32_t pending; + uint32_t intena; + int passes; + bool handled; + + DEBUGASSERT(dev && dev->priv); + priv = (struct esp32_dev_s *)dev->priv; + + /* Loop until there are no characters to be transferred or, until we have + * been looping for a long time. + */ + + handled = true; + for (passes = 0; passes < 256 && handled; passes++) + { + handled = false; + + /* Get the UART status (we are only interested in the unmasked interrupts). */ + + priv->sr = esp32_serialin(priv, ESP32_UART_SR_OFFSET); + intena = esp32_serialin(priv, ESP32_UART_IMR_OFFSET); + pending = priv->sr & intena; + + /* Handle an incoming, receive byte. RXRDY: At least one complete character + * has been received and US_RHR has not yet been read. + */ + + if ((pending & UART_INT_RXRDY) != 0) + { + /* Received data ready... process incoming bytes */ + + uart_recvchars(dev); + handled = true; + } + + /* Handle outgoing, transmit bytes. TXRDY: There is no character in the + * US_THR. + */ + + if ((pending & UART_INT_TXRDY) != 0) + { + /* Transmit data register empty ... process outgoing bytes */ + + uart_xmitchars(dev); + handled = true; + } + } + + return OK; +} + +/**************************************************************************** + * Name: esp32_uart[n]_interrupt + * + * Description: + * UART interrupt handlers + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32_UART0 +static int esp32_uart0_interrupt(int cpuint, void *context) +{ + return esp32_interrupt(&g_uart0port); +} +#endif +#ifdef CONFIG_ESP32_UART1 +static int esp32_uart1_interrupt(int cpuint, void *context) +{ + return esp32_interrupt(&g_uart1port); +} +#endif +#ifdef CONFIG_ESP32_UART2 +static int esp32_uart2_interrupt(int cpuint, void *context) +{ + return esp32_interrupt(&g_uart2port); +} +#endif + +/**************************************************************************** + * Name: esp32_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + ****************************************************************************/ + +static int esp32_ioctl(struct file *filep, int cmd, unsigned long arg) +{ +#if defined(CONFIG_SERIAL_TERMIOS) || defined(CONFIG_SERIAL_TIOCSERGSTRUCT) + struct inode *inode = filep->f_inode; + struct uart_dev_s *dev = inode->i_private; +#endif + int ret = OK; + + switch (cmd) + { +#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT + case TIOCSERGSTRUCT: + { + struct esp32_dev_s *user = (struct esp32_dev_s *)arg; + if (!user) + { + ret = -EINVAL; + } + else + { + memcpy(user, dev, sizeof(struct esp32_dev_s)); + } + } + break; +#endif + +#ifdef CONFIG_SERIAL_TERMIOS + case TCGETS: + { + struct termios *termiosp = (struct termios *)arg; + struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv; + + if (!termiosp) + { + ret = -EINVAL; + break; + } + + /* Return baud */ + + cfsetispeed(termiosp, priv->baud); + + /* Return parity */ + + termiosp->c_cflag = ((priv->parity != 0) ? PARENB : 0) | + ((priv->parity == 1) ? PARODD : 0); + + /* Return stop bits */ + + termiosp->c_cflag |= (priv->stopbits2) ? CSTOPB : 0; + + /* Return flow control */ + +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + termiosp->c_cflag |= (priv->flowc) ? (CCTS_OFLOW | CRTS_IFLOW): 0; +#endif + /* Return number of bits */ + + switch (priv->bits) + { + case 5: + termiosp->c_cflag |= CS5; + break; + + case 6: + termiosp->c_cflag |= CS6; + break; + + case 7: + termiosp->c_cflag |= CS7; + break; + + default: + case 8: + termiosp->c_cflag |= CS8; + break; + + case 9: + termiosp->c_cflag |= CS8 /* CS9 */; + break; + } + } + break; + + case TCSETS: + { + struct termios *termiosp = (struct termios *)arg; + struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv; + uint32_t baud; + uint32_t intena; + uint8_t parity; + uint8_t nbits; + bool stop2; +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + bool flowc; +#endif + + if (!termiosp) + { + ret = -EINVAL; + break; + } + + /* Decode baud. */ + + ret = OK; + baud = cfgetispeed(termiosp); + + /* Decode number of bits */ + + switch (termiosp->c_cflag & CSIZE) + { + case CS5: + nbits = 5; + break; + + case CS6: + nbits = 6; + break; + + case CS7: + nbits = 7; + break; + + case CS8: + nbits = 8; + break; +#if 0 + case CS9: + nbits = 9; + break; +#endif + default: + ret = -EINVAL; + break; + } + + /* Decode parity */ + + if ((termiosp->c_cflag & PARENB) != 0) + { + parity = (termiosp->c_cflag & PARODD) ? 1 : 2; + } + else + { + parity = 0; + } + + /* Decode stop bits */ + + stop2 = (termiosp->c_cflag & CSTOPB) != 0; + + /* Decode flow control */ + +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + flowc = (termiosp->c_cflag & (CCTS_OFLOW | CRTS_IFLOW)) != 0; +#endif + /* Verify that all settings are valid before committing */ + + if (ret == OK) + { + /* Commit */ + + priv->baud = baud; + priv->parity = parity; + priv->bits = nbits; + priv->stopbits2 = stop2; +#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL) + priv->flowc = flowc; +#endif + /* effect the changes immediately - note that we do not + * implement TCSADRAIN / TCSAFLUSH + */ + + esp32_disableallints(priv, &intena); + ret = esp32_setup(dev); + + /* Restore the interrupt state */ + + esp32_restoreuartint(priv, intena); + } + } + break; +#endif /* CONFIG_SERIAL_TERMIOS */ + + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: esp32_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the UART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +static int esp32_receive(struct uart_dev_s *dev, uint32_t *status) +{ + struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv; + + /* Return the error information in the saved status */ + + *status = priv->sr; + priv->sr = 0; + + /* Then return the actual received byte */ + + return (int)(esp32_serialin(priv, ESP32_UART_RHR_OFFSET) & 0xff); +} + +/**************************************************************************** + * Name: esp32_rxint + * + * Description: + * Call to enable or disable RXRDY interrupts + * + ****************************************************************************/ + +static void esp32_rxint(struct uart_dev_s *dev, bool enable) +{ + struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv; + + if (enable) + { + /* Receive an interrupt when their is anything in the Rx data register (or an Rx + * timeout occurs). + */ + +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + esp32_serialout(priv, ESP32_UART_IER_OFFSET, UART_INT_RXRDY); +#endif + } + else + { + esp32_serialout(priv, ESP32_UART_IDR_OFFSET, UART_INT_RXRDY); + } +} + +/**************************************************************************** + * Name: esp32_rxavailable + * + * Description: + * Return true if the receive holding register is not empty + * + ****************************************************************************/ + +static bool esp32_rxavailable(struct uart_dev_s *dev) +{ + struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv; + return ((esp32_serialin(priv, ESP32_UART_SR_OFFSET) & UART_INT_RXRDY) != 0); +} + +/**************************************************************************** + * Name: esp32_send + * + * Description: + * This method will send one byte on the UART. + * + ****************************************************************************/ + +static void esp32_send(struct uart_dev_s *dev, int ch) +{ + struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv; + esp32_serialout(priv, ESP32_UART_THR_OFFSET, (uint32_t)ch); +} + +/**************************************************************************** + * Name: esp32_txint + * + * Description: + * Call to enable or disable TX interrupts + * + ****************************************************************************/ + +static void esp32_txint(struct uart_dev_s *dev, bool enable) +{ + struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv; + irqstate_t flags; + + flags = enter_critical_section(); + if (enable) + { + /* Set to receive an interrupt when the TX holding register register + * is empty + */ + +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + esp32_serialout(priv, ESP32_UART_IER_OFFSET, UART_INT_TXRDY); + + /* Fake a TX interrupt here by just calling uart_xmitchars() with + * interrupts disabled (note this may recurse). + */ + + uart_xmitchars(dev); + +#endif + } + else + { + /* Disable the TX interrupt */ + + esp32_serialout(priv, ESP32_UART_IDR_OFFSET, UART_INT_TXRDY); + } + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: esp32_txready + * + * Description: + * Return true if the transmit holding register is empty (TXRDY) + * + ****************************************************************************/ + +static bool esp32_txready(struct uart_dev_s *dev) +{ + struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv; + return ((esp32_serialin(priv, ESP32_UART_SR_OFFSET) & UART_INT_TXRDY) != 0); +} + +/**************************************************************************** + * Name: esp32_txempty + * + * Description: + * Return true if the transmit holding and shift registers are empty + * + ****************************************************************************/ + +static bool esp32_txempty(struct uart_dev_s *dev) +{ + struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv; + return ((esp32_serialin(priv, ESP32_UART_SR_OFFSET) & UART_INT_TXEMPTY) != 0); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_earlyserialinit + * + * Description: + * Performs the low level UART initialization early in debug so that the + * serial console will be available during bootup. This must be called + * before up_serialinit. + * + ****************************************************************************/ + +#ifdef USE_EARLYSERIALINIT +void up_earlyserialinit(void) +{ + /* NOTE: All GPIO configuration for the UARTs was performed in + * esp32_lowsetup + */ + + /* Disable all UARTS */ + + esp32_disableallints(TTYS0_DEV.priv, NULL); +#ifdef TTYS1_DEV + esp32_disableallints(TTYS1_DEV.priv, NULL); +#endif +#ifdef TTYS2_DEV + esp32_disableallints(TTYS2_DEV.priv, NULL); +#endif + + /* Configuration whichever one is the console */ + +#ifdef HAVE_SERIAL_CONSOLE + CONSOLE_DEV.isconsole = true; + esp32_setup(&CONSOLE_DEV); +#endif +} +#endif + +/**************************************************************************** + * Name: up_serialinit + * + * Description: + * Register serial console and serial ports. This assumes + * that up_earlyserialinit was called previously. + * + ****************************************************************************/ + +void up_serialinit(void) +{ + /* Register the console */ + +#ifdef HAVE_SERIAL_CONSOLE + (void)uart_register("/dev/console", &CONSOLE_DEV); +#endif + + /* Register all UARTs */ + + (void)uart_register("/dev/ttyS0", &TTYS0_DEV); +#ifdef TTYS1_DEV + (void)uart_register("/dev/ttyS1", &TTYS1_DEV); +#endif +#ifdef TTYS2_DEV + (void)uart_register("/dev/ttyS2", &TTYS2_DEV); +#endif +} + +#endif /* USE_SERIALDRIVER */ diff --git a/arch/xtensa/src/esp32/rom/esp32_gpio.h b/arch/xtensa/src/esp32/rom/esp32_gpio.h index a6089d33b7..fc2e6ded25 100644 --- a/arch/xtensa/src/esp32/rom/esp32_gpio.h +++ b/arch/xtensa/src/esp32/rom/esp32_gpio.h @@ -38,6 +38,14 @@ #include "chip/gpio_reg.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MATRIX_DETACH_OUT_SIG 0x100 /* Detach an OUTPUT signal */ +#define MATRIX_DETACH_IN_LOW_PIN 0x30 /* Detach non-inverted INPUT signal */ +#define MATRIX_DETACH_IN_LOW_HIGH 0x38 /* Detach inverted INPUT signal */ + /**************************************************************************** * Public Types ****************************************************************************/