This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new ded321a515 xtensa/esp32s2: Add support to TWAI/CANBus controller
ded321a515 is described below

commit ded321a515eac9532c958e40eb310e9ecb5e7087
Author: Eren Terzioglu <[email protected]>
AuthorDate: Fri Aug 25 14:50:49 2023 +0300

    xtensa/esp32s2: Add support to TWAI/CANBus controller
---
 .../esp32s2/boards/esp32s2-kaluga-1/index.rst      |   20 +-
 .../esp32s2/boards/esp32s2-saola-1/index.rst       |   18 +
 Documentation/platforms/xtensa/esp32s2/index.rst   |    2 +-
 arch/xtensa/include/esp32s2/irq.h                  |    4 +-
 arch/xtensa/src/esp32s2/Kconfig                    |   56 +
 arch/xtensa/src/esp32s2/Make.defs                  |    4 +
 arch/xtensa/src/esp32s2/esp32s2_twai.c             | 1260 ++++++++++++++++++++
 arch/xtensa/src/esp32s2/esp32s2_twai.h             |   77 ++
 arch/xtensa/src/esp32s2/hardware/esp32s2_soc.h     |    1 +
 arch/xtensa/src/esp32s2/hardware/esp32s2_system.h  |   24 +-
 arch/xtensa/src/esp32s2/hardware/esp32s2_twai.h    |  792 ++++++++++++
 .../esp32s2/common/scripts/esp32s2_peripherals.ld  |    2 +-
 boards/xtensa/esp32s2/common/src/Make.defs         |    4 +
 .../xtensa/esp32s2/common/src/esp32s2_board_twai.c |   89 ++
 .../esp32s2-kaluga-1/configs/twai/defconfig        |   46 +
 .../esp32s2-kaluga-1/src/esp32s2-kaluga-1.h        |   11 +
 .../esp32s2/esp32s2-kaluga-1/src/esp32s2_bringup.c |   11 +
 .../esp32s2/esp32s2-saola-1/configs/twai/defconfig |   46 +
 .../esp32s2/esp32s2-saola-1/src/esp32s2-saola-1.h  |   11 +
 .../esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c  |   11 +
 20 files changed, 2472 insertions(+), 17 deletions(-)

diff --git 
a/Documentation/platforms/xtensa/esp32s2/boards/esp32s2-kaluga-1/index.rst 
b/Documentation/platforms/xtensa/esp32s2/boards/esp32s2-kaluga-1/index.rst
index 7b3ae91adc..97c25616cd 100644
--- a/Documentation/platforms/xtensa/esp32s2/boards/esp32s2-kaluga-1/index.rst
+++ b/Documentation/platforms/xtensa/esp32s2/boards/esp32s2-kaluga-1/index.rst
@@ -295,4 +295,22 @@ After successfully built and flashed, run on the boards' 
terminal::
   16 bits/sample and 48KHz. These arguments can be supplied to select
   different audio formats, for instance::
 
-    nxlooper> loopback 2 8 44100
\ No newline at end of file
+    nxlooper> loopback 2 8 44100
+
+twai
+----
+
+This configuration enables the support for the TWAI (Two-Wire Automotive 
Interface) driver.
+You can test it by connecting TWAI RX and TWAI TX pins which are GPIO0 and 
GPIO2 by default
+to a external transceiver or connecting TWAI RX to TWAI TX pin by enabling
+the ``Device Drivers -> CAN Driver Support -> CAN loopback mode`` option and 
running the ``can`` example::
+
+    nsh> can
+    nmsgs: 0
+    min ID: 1 max ID: 2047
+    Bit timing:
+      Baud: 1000000
+      TSEG1: 15
+      TSEG2: 4
+        SJW: 3
+      ID:    1 DLC: 1
diff --git 
a/Documentation/platforms/xtensa/esp32s2/boards/esp32s2-saola-1/index.rst 
b/Documentation/platforms/xtensa/esp32s2/boards/esp32s2-saola-1/index.rst
index 0fe1cf2711..3868944a8e 100644
--- a/Documentation/platforms/xtensa/esp32s2/boards/esp32s2-saola-1/index.rst
+++ b/Documentation/platforms/xtensa/esp32s2/boards/esp32s2-saola-1/index.rst
@@ -348,6 +348,24 @@ To test it, just run the following::
 
 Where x in the timer instance.
 
+twai
+----
+
+This configuration enables the support for the TWAI (Two-Wire Automotive 
Interface) driver.
+You can test it by connecting TWAI RX and TWAI TX pins which are GPIO0 and 
GPIO2 by default
+to a external transceiver or connecting TWAI RX to TWAI TX pin by enabling
+the ``Device Drivers -> CAN Driver Support -> CAN loopback mode`` option and 
running the ``can`` example::
+
+    nsh> can
+    nmsgs: 0
+    min ID: 1 max ID: 2047
+    Bit timing:
+      Baud: 1000000
+      TSEG1: 15
+      TSEG2: 4
+        SJW: 3
+      ID:    1 DLC: 1
+
 watchdog
 --------
 
diff --git a/Documentation/platforms/xtensa/esp32s2/index.rst 
b/Documentation/platforms/xtensa/esp32s2/index.rst
index 0aeb9a5ab9..0b06ca092d 100644
--- a/Documentation/platforms/xtensa/esp32s2/index.rst
+++ b/Documentation/platforms/xtensa/esp32s2/index.rst
@@ -98,7 +98,7 @@ Peripheral Support NOTES
 ========== ======= =====
 ADC          No
 AES          No
-CAN/TWAI     No
+CAN/TWAI     Yes
 DMA          Yes
 eFuse        No
 Ethernet     No
diff --git a/arch/xtensa/include/esp32s2/irq.h 
b/arch/xtensa/include/esp32s2/irq.h
index 9028fa850b..9c7e4734d9 100644
--- a/arch/xtensa/include/esp32s2/irq.h
+++ b/arch/xtensa/include/esp32s2/irq.h
@@ -98,7 +98,7 @@
 
 #define ESP32S2_PERIPH_LEDC              45
 #define ESP32S2_PERIPH_EFUSE             46
-#define ESP32S2_PERIPH_CAN               47
+#define ESP32S2_PERIPH_TWAI              47
 #define ESP32S2_PERIPH_USB               48
 #define ESP32S2_PERIPH_RTC_CORE          49
 
@@ -227,7 +227,7 @@
 
 #define ESP32S2_IRQ_LEDC              (XTENSA_IRQ_FIRSTPERIPH + 
ESP32S2_PERIPH_LEDC)
 #define ESP32S2_IRQ_EFUSE             (XTENSA_IRQ_FIRSTPERIPH + 
ESP32S2_PERIPH_EFUSE)
-#define ESP32S2_IRQ_CAN               (XTENSA_IRQ_FIRSTPERIPH + 
ESP32S2_PERIPH_CAN)
+#define ESP32S2_IRQ_TWAI              (XTENSA_IRQ_FIRSTPERIPH + 
ESP32S2_PERIPH_TWAI)
 #define ESP32S2_IRQ_USB               (XTENSA_IRQ_FIRSTPERIPH + 
ESP32S2_PERIPH_USB)
 #define ESP32S2_IRQ_RTC_CORE          (XTENSA_IRQ_FIRSTPERIPH + 
ESP32S2_PERIPH_RTC_CORE)
 
diff --git a/arch/xtensa/src/esp32s2/Kconfig b/arch/xtensa/src/esp32s2/Kconfig
index 061303ca43..923c47c34d 100644
--- a/arch/xtensa/src/esp32s2/Kconfig
+++ b/arch/xtensa/src/esp32s2/Kconfig
@@ -446,6 +446,11 @@ config ESP32S2_I2C1
        select ESP32S2_I2C
        select I2C
 
+config ESP32S2_TWAI
+       bool "TWAI (CAN)"
+       default n
+       select CAN
+
 config ESP32S2_LEDC
        bool "LEDC (PWM)"
        default n
@@ -671,6 +676,57 @@ config ESP32S2_I2CTIMEOMS
 
 endmenu # I2C Configuration
 
+menu "TWAI driver options"
+       depends on ESP32S2_TWAI
+
+if ESP32S2_TWAI
+
+config ESP32S2_TWAI_TXPIN
+       int "TWAI TX Pin"
+       default 0
+
+config ESP32S2_TWAI_RXPIN
+       int "TWAI RX Pin"
+       default 2
+
+config ESP32S2_TWAI_BITRATE
+       int "TWAI bitrate"
+       default 1000000
+       ---help---
+               TWAI bit rate.
+
+config ESP32S2_TWAI_SAMPLEP
+       int "TWAI sample point"
+       default 80
+       ---help---
+               TWAI sample point location as a percent value.
+
+config ESP32S2_TWAI_SJW
+       int "TWAI synchronization jump width"
+       default 3
+       ---help---
+               SJW limits the number of Time Quanta corrections during bit
+               Resynchronization.
+
+config ESP32S2_TWAI_SAM
+       bool "TWAI sampling"
+       default n
+       ---help---
+               The bus is sampled 3 times (recommended for low to medium speed 
buses
+               to spikes on the bus-line).
+
+endif # ESP32S2_TWAI
+
+config ESP32S2_TWAI_REGDEBUG
+       bool "TWAI register level debug"
+       depends on DEBUG_CAN_INFO
+       default n
+       ---help---
+               Output detailed register-level TWAI debug information. Requires 
also
+               CONFIG_DEBUG_CAN_INFO.
+
+endmenu #ESP32S2_TWAI
+
 menu "SPI Flash Configuration"
 
 choice ESP32S2_FLASH_MODE
diff --git a/arch/xtensa/src/esp32s2/Make.defs 
b/arch/xtensa/src/esp32s2/Make.defs
index ef8cd92ba0..b65f571bae 100644
--- a/arch/xtensa/src/esp32s2/Make.defs
+++ b/arch/xtensa/src/esp32s2/Make.defs
@@ -59,6 +59,10 @@ ifeq ($(CONFIG_ESP32S2_I2S),y)
 CHIP_CSRCS += esp32s2_i2s.c
 endif
 
+ifeq ($(CONFIG_ESP32S2_TWAI),y)
+CHIP_CSRCS += esp32s2_twai.c
+endif
+
 ifeq ($(CONFIG_ESP32S2_LEDC),y)
 CHIP_CSRCS += esp32s2_ledc.c
 endif
diff --git a/arch/xtensa/src/esp32s2/esp32s2_twai.c 
b/arch/xtensa/src/esp32s2/esp32s2_twai.c
new file mode 100644
index 0000000000..5fd09b0f19
--- /dev/null
+++ b/arch/xtensa/src/esp32s2/esp32s2_twai.c
@@ -0,0 +1,1260 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_twai.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <arch/board/board.h>
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/spinlock.h>
+
+#include "xtensa.h"
+
+#include "esp32s2_gpio.h"
+#include "esp32s2_twai.h"
+#include "esp32s2_irq.h"
+#include "esp32s2_clockconfig.h"
+
+#include "hardware/esp32s2_system.h"
+#include "hardware/esp32s2_gpio_sigmap.h"
+
+#if defined(CONFIG_ESP32S2_TWAI)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+/* Default values written to various registers on initialization */
+
+#define TWAI_INIT_TEC             0
+#define TWAI_INIT_REC             0
+#define TWAI_INIT_EWL             96
+
+/* Exclude data overrun (bit[3]) and brp_div (bit[4]) */
+
+#define TWAI_DEFAULT_INTERRUPTS   0xe7
+
+#define TWAI_ACCEPTANCE_CODE      0x0           /* 32-bit address to match */
+#define TWAI_ACCEPTANCE_MASK      0xffffffff    /* 32-bit address mask */
+
+#ifdef CONFIG_ESP32S2_TWAI
+
+/* A TWAI bit rate must be provided */
+
+#  ifndef CONFIG_ESP32S2_TWAI_BITRATE
+#    error "CONFIG_ESP32S2_TWAI_BITRATE is not defined"
+#  endif
+
+/* If no sample point is provided, use a sample point of 80 */
+
+#  ifndef CONFIG_ESP32S2_TWAI_SAMPLEP
+#    define CONFIG_ESP32S2_TWAI_SAMPLEP 80
+#  endif
+#endif
+
+/* If no Synchronization Jump Width is provided, use a SJW of 3 */
+
+#ifndef CONFIG_ESP32S2_TWAI_SJW
+#  define CONFIG_ESP32S2_TWAI_SJW 3
+#endif
+
+/* Debug ********************************************************************/
+
+/* Non-standard debug that may be enabled just for testing TWAI */
+
+#ifndef CONFIG_DEBUG_CAN_INFO
+#  undef CONFIG_ESP32S2_TWAI_REGDEBUG
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* CAN hardware-dependent bit-timing constant
+ * Used for calculating and checking bit-timing parameters
+ */
+
+struct can_bittiming_const
+{
+  uint32_t tseg1_min;  /* Time segment 1 */
+  uint32_t tseg1_max;
+  uint32_t tseg2_min;  /* Time segment 2 */
+  uint32_t tseg2_max;
+  uint32_t sjw_min;    /* Synchronization jump width */
+  uint32_t sjw_max;
+  uint32_t brp_min;    /* Bit-rate prescaler */
+  uint32_t brp_max;
+  uint32_t brp_inc;
+};
+
+struct twai_dev_s
+{
+  /* Device configuration */
+
+  const struct can_bittiming_const *bittiming_const;
+  uint8_t port;       /* TWAI port number */
+  uint8_t periph;     /* Peripheral ID */
+  uint8_t irq;        /* IRQ associated with this TWAI */
+  int8_t cpuint;      /* CPU interrupt assigned to this TWAI */
+  uint32_t bitrate;   /* Configured bit rate */
+  uint32_t samplep;   /* Configured sample point */
+  uint32_t sjw;       /* Synchronization jump width */
+  uint32_t base;      /* TWAI register base address */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* TWAI Register access */
+
+#ifdef CONFIG_ESP32S2_TWAI_REGDEBUG
+static void twai_printreg(uint32_t addr, uint32_t value);
+#endif
+
+static uint32_t twai_getreg(uint32_t addr);
+static void twai_putreg(uint32_t addr, uint32_t value);
+
+/* TWAI methods */
+
+static void esp32s2twai_reset(struct can_dev_s *dev);
+static int  esp32s2twai_setup(struct can_dev_s *dev);
+static void esp32s2twai_shutdown(struct can_dev_s *dev);
+static void esp32s2twai_rxint(struct can_dev_s *dev, bool enable);
+static void esp32s2twai_txint(struct can_dev_s *dev, bool enable);
+static int  esp32s2twai_ioctl(struct can_dev_s *dev, int cmd,
+                              unsigned long arg);
+static int  esp32s2twai_remoterequest(struct can_dev_s *dev,
+                                      uint16_t id);
+static int  esp32s2twai_send(struct can_dev_s *dev,
+                             struct can_msg_s *msg);
+static bool esp32s2twai_txready(struct can_dev_s *dev);
+static bool esp32s2twai_txempty(struct can_dev_s *dev);
+
+/* TWAI interrupts */
+
+static int esp32s2twai_interrupt(int irq, void *context, void *arg);
+
+/* TWAI acceptance filter */
+
+static void esp32s2twai_set_acc_filter(uint32_t code, uint32_t mask,
+                                       bool single_filter);
+
+/* TWAI bit-timing initialization */
+
+static int twai_baud_rate(struct twai_dev_s *priv, int rate, int clock,
+                          int sjw, int sampl_pt, int flags);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct can_bittiming_const esp32s2_twai_bittiming_const =
+{
+  .tseg1_min        = 1,
+  .tseg1_max        = 16,
+  .tseg2_min        = 1,
+  .tseg2_max        = 8,
+  .sjw_min          = 1,
+  .sjw_max          = 3,
+  .brp_min          = 1,
+  .brp_max          = 16384,
+  .brp_inc          = 1,
+};
+
+static const struct can_ops_s g_twaiops =
+{
+  .co_reset         = esp32s2twai_reset,
+  .co_setup         = esp32s2twai_setup,
+  .co_shutdown      = esp32s2twai_shutdown,
+  .co_rxint         = esp32s2twai_rxint,
+  .co_txint         = esp32s2twai_txint,
+  .co_ioctl         = esp32s2twai_ioctl,
+  .co_remoterequest = esp32s2twai_remoterequest,
+  .co_send          = esp32s2twai_send,
+  .co_txready       = esp32s2twai_txready,
+  .co_txempty       = esp32s2twai_txempty,
+};
+
+#ifdef CONFIG_ESP32S2_TWAI
+static struct twai_dev_s g_twaipriv =
+{
+  .bittiming_const  = &esp32s2_twai_bittiming_const,
+  .port             = 0,
+  .periph           = ESP32S2_PERIPH_TWAI,
+  .irq              = ESP32S2_IRQ_TWAI,
+  .cpuint           = -ENOMEM,
+  .bitrate          = CONFIG_ESP32S2_TWAI_BITRATE,
+  .samplep          = CONFIG_ESP32S2_TWAI_SAMPLEP,
+  .sjw              = CONFIG_ESP32S2_TWAI_SJW,
+  .base             = DR_REG_TWAI_BASE,
+};
+
+static struct can_dev_s g_twaidev =
+{
+  .cd_ops           = &g_twaiops,
+  .cd_priv          = &g_twaipriv,
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: twai_printreg
+ *
+ * Description:
+ *   Print the value read from a register.
+ *
+ * Input Parameters:
+ *   addr - The register address
+ *   value - The register value
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_TWAI_REGDEBUG
+static void twai_printreg(uint32_t addr, uint32_t value)
+{
+  static uint32_t prevaddr = 0;
+  static uint32_t preval   = 0;
+  static uint32_t count    = 0;
+
+  /* Is this the same value that we read from the same register last time?
+   * Are we polling the register?  If so, suppress some of the output.
+   */
+
+  if (addr == prevaddr && value == preval)
+    {
+      if (count == 0xffffffff || ++count > 3)
+        {
+          if (count == 4)
+            {
+              caninfo("...\n");
+            }
+
+          return;
+        }
+    }
+
+  /* No this is a new address or value */
+
+  else
+    {
+      /* Did we print "..." for the previous value? */
+
+      if (count > 3)
+        {
+          /* Yes.. then show how many times the value repeated */
+
+          caninfo("[repeats %d more times]\n", count - 3);
+        }
+
+      /* Save the new address, value, and count */
+
+      prevaddr = addr;
+      preval   = value;
+      count    = 1;
+    }
+
+  /* Show the register value read */
+
+  caninfo("%08x->%08x\n", addr, value);
+}
+#endif
+
+/****************************************************************************
+ * Name: twai_getreg
+ *
+ * Description:
+ *   Read the value of an TWAI register.
+ *
+ * Input Parameters:
+ *   addr - The address to the register to read
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_TWAI_REGDEBUG
+static uint32_t twai_getreg(uint32_t addr)
+{
+  uint32_t value;
+
+  /* Read the value from the register */
+
+  value = getreg32(addr);
+  twai_printreg(addr, value);
+  return value;
+}
+#else
+static uint32_t twai_getreg(uint32_t addr)
+{
+  return getreg32(addr);
+}
+#endif
+
+/****************************************************************************
+ * Name: twai_putreg
+ *
+ * Description:
+ *   Set the value of an TWAI register.
+ *
+ * Input Parameters:
+ *   addr - The address to the register to write
+ *   value - The value to write to the register
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32S2_TWAI_REGDEBUG
+static void twai_putreg(uint32_t addr, uint32_t value)
+{
+  /* Show the register value being written */
+
+  caninfo("%08x<-%08x\n", addr, value);
+
+  /* Write the value */
+
+  putreg32(value, addr);
+}
+#else
+static void twai_putreg(uint32_t addr, uint32_t value)
+{
+  putreg32(value, addr);
+}
+#endif
+
+/****************************************************************************
+ * Name: esp32s2twai_reset
+ *
+ * Description:
+ *   Reset the TWAI device.  Called early to initialize the hardware. This
+ *   function is called, before esp32s2_twai_setup() and on error conditions.
+ *
+ * Input Parameters:
+ *   dev - An instance of the "upper half" CAN driver state structure.
+ *
+ * Returned Value:
+ *  None
+ *
+ ****************************************************************************/
+
+static void esp32s2twai_reset(struct can_dev_s *dev)
+{
+  struct twai_dev_s *priv = (struct twai_dev_s *)dev->cd_priv;
+  irqstate_t flags;
+  int ret;
+
+  caninfo("TWAI\n");
+
+  flags = enter_critical_section();
+
+  /* Disable the TWAI and stop ongoing transmissions */
+
+  uint32_t mode_value = TWAI_RESET_MODE_M | TWAI_LISTEN_ONLY_MODE_M;
+  twai_putreg(TWAI_MODE_REG, mode_value);                 /* Enter Reset Mode 
*/
+
+  twai_putreg(TWAI_INT_ENA_REG, 0);                       /* Disable 
interrupts */
+  twai_getreg(TWAI_STATUS_REG);                           /* Clear status bits 
*/
+
+  twai_putreg(TWAI_TX_ERR_CNT_REG, TWAI_INIT_TEC);        /* TEC */
+  twai_putreg(TWAI_RX_ERR_CNT_REG, TWAI_INIT_REC);        /* REC */
+  twai_putreg(TWAI_ERR_WARNING_LIMIT_REG, TWAI_INIT_EWL); /* EWL */
+
+  esp32s2twai_set_acc_filter(TWAI_ACCEPTANCE_CODE,
+                             TWAI_ACCEPTANCE_MASK, true);
+
+  /* Set bit timing */
+
+  ret = twai_baud_rate(priv, priv->bitrate, esp_clk_apb_freq(),
+                       priv->sjw, priv->samplep, 0);
+
+  if (ret != OK)
+    {
+      canerr("ERROR: Failed to set bit timing: %d\n", ret);
+    }
+
+  /* Restart the TWAI */
+
+#ifdef CONFIG_CAN_LOOPBACK
+  twai_putreg(TWAI_MODE_REG, TWAI_SELF_TEST_MODE_M); /* Leave Reset Mode, 
enter Test Mode */
+#else
+  twai_putreg(TWAI_MODE_REG, 0);                     /* Leave Reset Mode */
+#endif
+
+  /* Abort transmission, release RX buffer and clear overrun.
+   * Command register can only be modified when in Operation Mode.
+   */
+
+  twai_putreg(TWAI_CMD_REG, TWAI_ABORT_TX_M | TWAI_RELEASE_BUF_M |
+              TWAI_CLR_OVERRUN_M);
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: esp32s2twai_setup
+ *
+ * Description:
+ *   Configure the TWAI. This method is called the first time that the TWAI
+ *   device is opened.  This will occur when the port is first opened.
+ *   This setup includes configuring and attaching TWAI interrupts.
+ *
+ * Input Parameters:
+ *   dev - An instance of the "upper half" CAN driver state structure.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int esp32s2twai_setup(struct can_dev_s *dev)
+{
+  struct twai_dev_s *priv = (struct twai_dev_s *)dev->cd_priv;
+  irqstate_t flags;
+  int ret = OK;
+
+  caninfo("TWAI\n");
+
+  flags = enter_critical_section();
+
+  twai_putreg(TWAI_INT_ENA_REG, TWAI_DEFAULT_INTERRUPTS);
+
+  twai_getreg(TWAI_INT_RAW_REG);          /* clear latched interrupts */
+
+  if (priv->cpuint != -ENOMEM)
+    {
+      /* Disable the provided CPU Interrupt to configure it. */
+
+      up_disable_irq(priv->irq);
+    }
+
+  priv->cpuint = esp32s2_setup_irq(priv->periph,
+                                   ESP32S2_INT_PRIO_DEF,
+                                   ESP32S2_CPUINT_LEVEL);
+  if (priv->cpuint < 0)
+    {
+      /* Failed to allocate a CPU interrupt of this type. */
+
+      ret = priv->cpuint;
+      leave_critical_section(flags);
+
+      return ret;
+    }
+
+  ret = irq_attach(priv->irq, esp32s2twai_interrupt, dev);
+  if (ret != OK)
+    {
+      /* Failed to attach IRQ, so CPU interrupt must be freed. */
+
+      esp32s2_teardown_irq(priv->periph, priv->cpuint);
+      priv->cpuint = -ENOMEM;
+      leave_critical_section(flags);
+
+      return ret;
+    }
+
+  /* Enable the CPU interrupt that is linked to the TWAI device. */
+
+  up_enable_irq(priv->irq);
+
+  leave_critical_section(flags);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp32s2twai_shutdown
+ *
+ * Description:
+ *   Disable the TWAI.  This method is called when the TWAI device is closed.
+ *   This method reverses the operation the setup method.
+ *
+ * Input Parameters:
+ *   dev - An instance of the "upper half" CAN driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp32s2twai_shutdown(struct can_dev_s *dev)
+{
+  struct twai_dev_s *priv = (struct twai_dev_s *)dev->cd_priv;
+
+#ifdef CONFIG_DEBUG_CAN_INFO
+  caninfo("shutdown TWAI\n");
+#endif
+
+  if (priv->cpuint != -ENOMEM)
+    {
+      /* Disable cpu interrupt */
+
+      up_disable_irq(priv->irq);
+
+      /* Dissociate the IRQ from the ISR */
+
+      irq_detach(priv->irq);
+
+      /* Free cpu interrupt that is attached to this peripheral */
+
+      esp32s2_teardown_irq(priv->periph, priv->cpuint);
+      priv->cpuint = -ENOMEM;
+    }
+}
+
+/****************************************************************************
+ * Name: esp32s2twai_rxint
+ *
+ * Description:
+ *   Call to enable or disable RX interrupts.
+ *
+ * Input Parameters:
+ *   dev - An instance of the "upper half" CAN driver state structure.
+ *   enable - Enable or disable receive interrupt.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp32s2twai_rxint(struct can_dev_s *dev, bool enable)
+{
+  struct twai_dev_s *priv = (struct twai_dev_s *)dev->cd_priv;
+  uint32_t regval;
+  irqstate_t flags;
+
+  caninfo("TWAI enable: %d\n", enable);
+
+  /* The INT_ENA register is also modified from the interrupt handler,
+   * so we have to protect this code section.
+   */
+
+  flags = enter_critical_section();
+
+  regval = twai_getreg(TWAI_INT_ENA_REG);
+  if (enable)
+    {
+      regval |= TWAI_RX_INT_ENA_M;
+    }
+  else
+    {
+      regval &= ~TWAI_RX_INT_ENA_M;
+    }
+
+  twai_putreg(TWAI_INT_ENA_REG, regval);
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: esp32s2twai_txint
+ *
+ * Description:
+ *   Call to enable or disable TX interrupts.
+ *
+ * Input Parameters:
+ *   dev - An instance of the "upper half" CAN driver state structure.
+ *   enable - Enable or disable transmit interrupt.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp32s2twai_txint(struct can_dev_s *dev, bool enable)
+{
+  struct twai_dev_s *priv = (struct twai_dev_s *)dev->cd_priv;
+  uint32_t regval;
+  irqstate_t flags;
+
+  caninfo("TWAI enable: %d\n", enable);
+
+  /* Only disabling of the TX interrupt is supported here.  The TX interrupt
+   * is automatically enabled just before a message is sent in order to avoid
+   * lost TX interrupts.
+   */
+
+  if (!enable)
+    {
+      /* TX interrupts are also disabled from the interrupt handler, so we
+       * have to protect this code section.
+       */
+
+      flags = enter_critical_section();
+
+      /* Disable all TX interrupts */
+
+      regval = twai_getreg(TWAI_INT_ENA_REG);
+      regval &= ~(TWAI_TX_INT_ENA_M);
+      twai_putreg(TWAI_INT_ENA_REG, regval);
+      leave_critical_section(flags);
+    }
+}
+
+/****************************************************************************
+ * Name: esp32s2twai_ioctl
+ *
+ * Description:
+ *   All ioctl calls will be routed through this method
+ *
+ * Input Parameters:
+ *   dev - An instance of the "upper half" CAN driver state structure.
+ *   cmd - A ioctl command.
+ *   arg - A ioctl argument.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int esp32s2twai_ioctl(struct can_dev_s *dev, int cmd,
+                             unsigned long arg)
+{
+  struct twai_dev_s *priv = (struct twai_dev_s *)dev->cd_priv;
+  int ret = -ENOTTY;
+
+  caninfo("TWAI cmd=%04x arg=%lu\n", cmd, arg);
+
+  /* Handle the command */
+
+  switch (cmd)
+    {
+      /* CANIOC_GET_BITTIMING:
+       *   Description:    Return the current bit timing settings
+       *   Argument:       A pointer to a write-able instance of struct
+       *                   canioc_bittiming_s in which current bit timing
+       *                   values will be returned.
+       *   Returned Value: Zero (OK) is returned on success.  Otherwise -1
+       *                   (ERROR) is returned with the errno variable set
+       *                   to indicate the nature of the error.
+       *   Dependencies:   None
+       */
+
+      case CANIOC_GET_BITTIMING:
+        {
+          struct canioc_bittiming_s *bt =
+            (struct canioc_bittiming_s *)arg;
+          uint32_t timing0;
+          uint32_t timing1;
+          uint32_t brp;
+
+          DEBUGASSERT(bt != NULL);
+
+          timing0 = twai_getreg(TWAI_BUS_TIMING_0_REG);
+          timing1 = twai_getreg(TWAI_BUS_TIMING_1_REG);
+
+          brp = ((timing0 & TWAI_BAUD_PRESC_M) + 1) * 2;
+          bt->bt_sjw = ((timing0 & TWAI_SYNC_JUMP_WIDTH_M) >>
+                       TWAI_SYNC_JUMP_WIDTH_S) + 1;
+
+          bt->bt_tseg1 = ((timing1 & TWAI_TIME_SEG1_M) >>
+                         TWAI_TIME_SEG1_S) + 1;
+          bt->bt_tseg2 = ((timing1 & TWAI_TIME_SEG2_M) >>
+                         TWAI_TIME_SEG2_S)+ 1;
+          bt->bt_baud = esp_clk_apb_freq() /
+              (brp * (bt->bt_tseg1 + bt->bt_tseg2 + 1));
+
+          ret = OK;
+        }
+        break;
+
+      /* Unsupported/unrecognized command */
+
+      default:
+        canerr("ERROR: Unrecognized command: %04x\n", cmd);
+        break;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp32s2twai_remoterequest
+ *
+ * Description:
+ *   Send a remote request
+ *
+ * Input Parameters:
+ *   dev - An instance of the "upper half" can driver state structure.
+ *   id  - Requested 11-bit data frame identifier
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int esp32s2twai_remoterequest(struct can_dev_s *dev, uint16_t id)
+{
+  canwarn("Remote request not implemented\n");
+  return -ENOSYS;
+}
+
+/****************************************************************************
+ * Name: esp32s2twai_send
+ *
+ * Description:
+ *    Send one TWAI message.
+ *
+ *    One TWAI-message consists of a maximum of 10 bytes.  A message is
+ *    composed of at least the first 2 bytes (when there are no data bytes).
+ *
+ *    Byte 0:      Bits 0-7: Bits 3-10 of the 11-bit TWAI identifier
+ *    Byte 1:      Bits 5-7: Bits 0-2 of the 11-bit TWAI identifier
+ *                 Bit 4:    Remote Transmission Request (RTR)
+ *                 Bits 0-3: Data Length Code (DLC)
+ *    Bytes 2-10: TWAI data
+ *
+ * Input Parameters:
+ *   dev - An instance of the "upper half" CAN driver state structure.
+ *   msg - A message to send.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int esp32s2twai_send(struct can_dev_s *dev,
+                            struct can_msg_s *msg)
+{
+  struct twai_dev_s *priv = (struct twai_dev_s *)dev->cd_priv;
+  uint32_t regval;
+  uint32_t i;
+  uint32_t len;
+  uint32_t id;
+  uint32_t frame_info;
+  irqstate_t flags;
+  int ret = OK;
+
+  caninfo("TWAI ID: %" PRIu32 " DLC: %" PRIu8 "\n",
+          (uint32_t)msg->cm_hdr.ch_id, msg->cm_hdr.ch_dlc);
+
+  len = (uint32_t)msg->cm_hdr.ch_dlc;
+  if (len > CAN_MAXDATALEN) len = CAN_MAXDATALEN;
+
+  frame_info = len;
+
+  if (msg->cm_hdr.ch_rtr)
+    {
+      frame_info |= (1 << 6);
+    }
+
+  flags = enter_critical_section();
+
+  /* Make sure that TX interrupts are enabled BEFORE sending the
+   * message.
+   *
+   * NOTE: The INT_ENA is also modified from the interrupt handler, but the
+   * following is safe because interrupts are disabled here.
+   */
+
+  regval  = twai_getreg(TWAI_INT_ENA_REG);
+  regval |= TWAI_TX_INT_ENA_M;
+  twai_putreg(TWAI_INT_ENA_REG, regval);
+
+  /* Set up the transfer */
+
+#ifdef CONFIG_CAN_EXTID
+  if (msg->cm_hdr.ch_extid)
+    {
+      /* The provided ID should be 29 bits */
+
+      id = (uint32_t)msg->cm_hdr.ch_id;
+      DEBUGASSERT((id & ~CAN_MAX_EXTMSGID) == 0);
+      frame_info |= (1 << 7);
+      twai_putreg(TWAI_DATA_0_REG, frame_info);
+
+      id <<= 3;
+      twai_putreg(TWAI_DATA_4_REG, id & 0xff);
+      id >>= 8;
+      twai_putreg(TWAI_DATA_3_REG, id & 0xff);
+      id >>= 8;
+      twai_putreg(TWAI_DATA_2_REG, id & 0xff);
+      id >>= 8;
+      twai_putreg(TWAI_DATA_1_REG, id & 0xff);
+      for (i = 0; i < len; i++)
+        {
+          twai_putreg(TWAI_DATA_5_REG + (i * 4), msg->cm_data[i]);
+        }
+    }
+  else
+#endif
+    {
+      /* The provided ID should be 11 bits */
+
+      id = (uint32_t)msg->cm_hdr.ch_id;
+      DEBUGASSERT((id & ~CAN_MAX_STDMSGID) == 0);
+      twai_putreg(TWAI_DATA_0_REG, frame_info);
+      id <<= 5;
+      twai_putreg(TWAI_DATA_1_REG, (id >> 8) & 0xff);
+      twai_putreg(TWAI_DATA_2_REG, id & 0xff);
+      for (i = 0; i < len; i++)
+        {
+          twai_putreg(TWAI_DATA_3_REG + (i * 4), msg->cm_data[i]);
+        }
+    }
+
+  /* Send the message */
+
+#ifdef CONFIG_CAN_LOOPBACK
+  twai_putreg(TWAI_CMD_REG, TWAI_SELF_RX_REQ_M | TWAI_ABORT_TX_M);
+#else
+  twai_putreg(TWAI_CMD_REG, TWAI_TX_REQ_M);
+#endif
+  leave_critical_section(flags);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp32s2twai_txready
+ *
+ * Description:
+ *   Return true if the TWAI hardware can accept another TX message.
+ *
+ * Input Parameters:
+ *   dev - An instance of the "upper half" CAN driver state structure.
+ *
+ * Returned Value:
+ *   True if the TWAI hardware is ready to accept another TX message.
+ *
+ ****************************************************************************/
+
+static bool esp32s2twai_txready(struct can_dev_s *dev)
+{
+  struct twai_dev_s *priv = dev->cd_priv;
+  uint32_t regval = twai_getreg(TWAI_STATUS_REG);
+
+  caninfo("TWAI txready: %d\n", ((regval & TWAI_TX_BUF_ST_M) != 0));
+  return ((regval & TWAI_TX_BUF_ST_M) != 0);
+}
+
+/****************************************************************************
+ * Name: esp32s2twai_txempty
+ *
+ * Description:
+ *   Return true if all message have been sent.  If for example, the TWAI
+ *   hardware implements FIFOs, then this would mean the transmit FIFO is
+ *   empty.  This method is called when the driver needs to make sure that
+ *   all characters are "drained" from the TX hardware before calling
+ *   co_shutdown().
+ *
+ * Input Parameters:
+ *   dev - An instance of the "upper half" CAN driver state structure.
+ *
+ * Returned Value:
+ *   True if there are no pending TX transfers in the TWAI hardware.
+ *
+ ****************************************************************************/
+
+static bool esp32s2twai_txempty(struct can_dev_s *dev)
+{
+  struct twai_dev_s *priv = dev->cd_priv;
+  uint32_t regval = twai_getreg(TWAI_STATUS_REG);
+
+  caninfo("TWAI txempty: %d\n", ((regval & TWAI_TX_BUF_ST_M) != 0));
+  return ((regval & TWAI_TX_BUF_ST_M) != 0);
+}
+
+/****************************************************************************
+ * Name: esp32s2twai_interrupt
+ *
+ * Description:
+ *   TWAI RX/TX interrupt handler
+ *
+ * Input Parameters:
+ *   irq - The IRQ number of the interrupt.
+ *   context - The register state save array at the time of the interrupt.
+ *   arg - The pointer to driver structure.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int esp32s2twai_interrupt(int irq, void *context, void *arg)
+{
+#ifdef CONFIG_ESP32S2_TWAI
+  struct can_dev_s *dev = (struct can_dev_s *)arg;
+  struct can_hdr_s hdr;
+  uint8_t data[8];
+  uint32_t frame_info;
+  uint32_t len;
+  uint32_t datastart;
+  uint32_t regval;
+  uint32_t i;
+
+  /* Read the interrupt register results in clearing bits  */
+
+  regval = twai_getreg(TWAI_INT_RAW_REG);
+
+  /* Check for a receive interrupt */
+
+  if ((regval & TWAI_RX_INT_ST_M) != 0)
+    {
+      memset(&hdr, 0, sizeof(hdr));
+      memset(data, 0, sizeof(data));
+
+      frame_info = twai_getreg(TWAI_DATA_0_REG);
+
+      /* Construct the TWAI header */
+
+      if (frame_info & (1 << 6))
+        {
+          hdr.ch_rtr    = 1;
+        }
+
+#ifdef CONFIG_CAN_EXTID
+      if (frame_info & (1 << 7))
+        {
+          /* The provided ID should be 29 bits */
+
+          hdr.ch_extid = 1;
+          hdr.ch_id =
+          (twai_getreg(TWAI_DATA_1_REG) << 21) +
+          (twai_getreg(TWAI_DATA_2_REG) << 13) +
+          (twai_getreg(TWAI_DATA_3_REG) << 5) +
+          (twai_getreg(TWAI_DATA_4_REG) >> 3);
+          datastart = TWAI_DATA_5_REG;
+        }
+      else
+#endif
+        {
+          /* The provided ID should be 11 bits */
+
+          hdr.ch_id =
+          (twai_getreg(TWAI_DATA_1_REG) << 3) +
+          (twai_getreg(TWAI_DATA_2_REG) >> 5);
+          datastart = TWAI_DATA_3_REG;
+        }
+
+      len = frame_info & 0xf;
+      if (len > CAN_MAXDATALEN) len = CAN_MAXDATALEN;
+      hdr.ch_dlc = len;
+
+      for (i = 0; i < len; i++)
+        {
+          data[i] = twai_getreg(datastart + (i * 4));
+        }
+
+      /* Release the receive buffer */
+
+      twai_putreg(TWAI_CMD_REG, TWAI_RELEASE_BUF_M);
+
+#ifdef CONFIG_CAN_ERRORS
+      hdr.ch_error  = 0; /* Error reporting not supported */
+#endif
+      can_receive(dev, &hdr, data);
+    }
+
+  /* Check for TX buffer complete */
+
+  if ((regval & TWAI_TX_INT_ST_M) != 0)
+    {
+      /* Disable all further TX buffer interrupts */
+
+      regval  = twai_getreg(TWAI_INT_ENA_REG);
+      regval &= ~TWAI_TX_INT_ENA_M;
+      twai_putreg(TWAI_INT_ENA_REG, regval);
+
+      /* Indicate that the TX is done and a new TX buffer is available */
+
+      can_txdone(dev);
+    }
+
+#endif
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp32s2twai_set_acc_filter
+ *
+ * Description:
+ *   Call to set acceptance filter.
+ *   Must be called in reset mode.
+ *
+ * Input Parameters:
+ *   code - Acceptance Code.
+ *   mask - Acceptance Mask.
+ *   single_filter - Whether to enable single filter mode.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp32s2twai_set_acc_filter(uint32_t code, uint32_t mask,
+                                       bool single_filter)
+{
+  uint32_t regval;
+  uint32_t code_swapped = __builtin_bswap32(code);
+  uint32_t mask_swapped = __builtin_bswap32(mask);
+
+  regval = twai_getreg(TWAI_MODE_REG);
+  if (single_filter)
+    {
+      regval |= TWAI_RX_FILTER_MODE_M;
+    }
+  else
+    {
+      regval &= ~(TWAI_RX_FILTER_MODE_M);
+    }
+
+  twai_putreg(TWAI_MODE_REG, regval);
+
+  for (int i = 0; i < 4; i++)
+    {
+      twai_putreg(TWAI_DATA_0_REG + (i * 4),
+                  ((code_swapped >> (i * 8)) & 0xff));
+      twai_putreg(TWAI_DATA_4_REG + (i * 4),
+                  ((mask_swapped >> (i * 8)) & 0xff));
+    }
+}
+
+/****************************************************************************
+ * Name: twai_baud_rate
+ *
+ * Description:
+ *   Set the CAN bus timing registers based on the configured bit-rate and
+ *   sample point position.
+ *
+ * The bit timing logic monitors the serial bus-line and performs sampling
+ * and adjustment of the sample point by synchronizing on the start-bit edge
+ * and resynchronizing on the following edges.
+ *
+ * Its operation may be explained simply by splitting nominal bit time into
+ * three segments as follows:
+ *
+ * 1. Synchronization segment (SYNC_SEG): a bit change is expected to occur
+ *    within this time segment. It has a fixed length of one time quantum
+ *    (1 x tCAN).
+ * 2. Bit segment 1 (BS1): defines the location of the sample point. It
+ *    includes the PROP_SEG and PHASE_SEG1 of the CAN standard. Its duration
+ *    is programmable between 1 and 16 time quanta but may be automatically
+ *    lengthened to compensate for positive phase drifts due to differences
+ *    in the frequency of the various nodes of the network.
+ * 3. Bit segment 2 (BS2): defines the location of the transmit point. It
+ *    represents the PHASE_SEG2 of the CAN standard. Its duration is
+ *    programmable between 1 and 8 time quanta but may also be automatically
+ *    shortened to compensate for negative phase drifts.
+ *
+ * Pictorially:
+ *
+ *  |<----------------- NOMINAL BIT TIME ----------------->|
+ *  |<- SYNC_SEG ->|<------ BS1 ------>|<------ BS2 ------>|
+ *  |<---- Tq ---->|<----- Tbs1 ------>|<----- Tbs2 ------>|
+ *
+ * Where
+ *   Tbs1 is the duration of the BS1 segment
+ *   Tbs2 is the duration of the BS2 segment
+ *   Tq is the "Time Quantum"
+ *
+ * Relationships:
+ *
+ *   baud = 1 / bit_time
+ *   bit_time = Tq + Tbs1 + Tbs2
+ *   Tbs1 = Tq * ts1
+ *   Tbs2 = Tq * ts2
+ *   Tq = brp * Tcan
+ *
+ *   Where:
+ *     Tcan is the period of the APB clock
+ *
+ * Input Parameters:
+ *   priv     - A reference to the CAN block status
+ *   rate     - The resolution of one timing quanta, in Hz
+ *   clock    - Clock source frequency
+ *   sjw      - Max time quanta jump for synchronize
+ *   sampl_pt - Enables triple sampling
+ *   flags    - Flag for configuration
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int twai_baud_rate(struct twai_dev_s *priv, int rate, int clock,
+                          int sjw, int sampl_pt, int flags)
+{
+  const struct can_bittiming_const *timing =
+      &esp32s2_twai_bittiming_const;
+  int best_error = 1000000000;
+  int error;
+  int best_tseg = 0;
+  int best_brp = 0;
+  int best_rate = 0;
+  int brp = 0;
+  int tseg = 0;
+  int tseg1 = 0;
+  int tseg2 = 0;
+  uint32_t timing0;
+  uint32_t timing1;
+
+  /* tseg even = round down, odd = round up */
+
+  for (tseg = (0 + 0 + 2) * 2;
+       tseg <= (timing->tseg2_max + timing->tseg1_max + 2) * 2 + 1; tseg++)
+    {
+      brp = clock / ((1 + tseg / 2) * rate) + tseg % 2;
+      if (brp == 0 || brp > 64)
+        {
+          continue;
+        }
+
+      error = rate - clock / (brp * (1 + tseg / 2));
+      if (error < 0)
+        {
+          error = -error;
+        }
+
+      if (error <= best_error)
+        {
+          best_error = error;
+          best_tseg = tseg / 2;
+          best_brp = brp;
+          best_rate = clock / (brp * (1 + tseg / 2));
+        }
+    }
+
+  if (best_error && (rate / best_error < 10))
+    {
+      canerr("baud rate %d is not possible with %d Hz clock\n",
+              rate, clock);
+      canerr("%d bps. brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d\n",
+              best_rate, best_brp, best_tseg, tseg1, tseg2);
+      return -EINVAL;
+    }
+
+  tseg2 = best_tseg - (sampl_pt * (best_tseg + 1)) / 100 + 1;
+  if (tseg2 < 0)
+    {
+      tseg2 = 0;
+    }
+
+  if (tseg2 > timing->tseg2_max)
+    {
+      tseg2 = timing->tseg2_max;
+    }
+
+  tseg1 = best_tseg - tseg2;
+  if (tseg1 > timing->tseg1_max)
+    {
+      tseg1 = timing->tseg1_max;
+      tseg2 = best_tseg - tseg1;
+    }
+
+  caninfo("TS1: %d TS2: %d BRP: %d\n", tseg1, tseg2, best_brp);
+
+  /* Configure bit timing */
+
+  timing0 = (best_brp / 2) - 1;
+  timing0 |= (sjw - 1) << TWAI_SYNC_JUMP_WIDTH_S;
+
+  timing1 = tseg1 - 1;
+  timing1 |= (tseg2 - 1) << TWAI_TIME_SEG2_S;
+
+#ifdef CONFIG_ESP32S2_TWAI_SAM
+  /* The bus is sampled 3 times (recommended for low to medium speed buses
+   * to spikes on the bus-line).
+   */
+
+  timing1 |= CONFIG_ESP32S2_TWAI_SAM << TWAI_TIME_SAMP_S;
+#endif
+
+  twai_putreg(TWAI_BUS_TIMING_0_REG, timing0);
+  twai_putreg(TWAI_BUS_TIMING_1_REG, timing1);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s2_twaiinitialize
+ *
+ * Description:
+ *   Initialize the selected TWAI port
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Valid TWAI device structure reference on success; a NULL on failure
+ *
+ ****************************************************************************/
+
+struct can_dev_s *esp32s2_twaiinitialize(void)
+{
+  struct can_dev_s *twaidev;
+  irqstate_t flags;
+
+  caninfo("TWAI\n");
+
+#ifdef CONFIG_ESP32S2_TWAI
+  twaidev = &g_twaidev;
+
+  flags = enter_critical_section();
+
+  /* Enable power to the TWAI module and
+   * Enable clocking to the TWAI module
+   */
+
+  modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, 0, SYSTEM_TWAI_CLK_EN);
+  modifyreg32(SYSTEM_PERIP_RST_EN0_REG, SYSTEM_TWAI_RST, 0);
+
+  /* Configure CAN GPIO pins */
+
+  esp32s2_configgpio(CONFIG_ESP32S2_TWAI_TXPIN, OUTPUT_FUNCTION_2);
+  esp32s2_gpio_matrix_out(CONFIG_ESP32S2_TWAI_TXPIN, TWAI_TX_IDX, 0, 0);
+
+  esp32s2_configgpio(CONFIG_ESP32S2_TWAI_RXPIN, INPUT_FUNCTION_2);
+  esp32s2_gpio_matrix_in(CONFIG_ESP32S2_TWAI_RXPIN, TWAI_RX_IDX, 0);
+
+  leave_critical_section(flags);
+#endif
+
+  /* Then just perform a TWAI reset operation */
+
+  esp32s2twai_reset(twaidev);
+
+  return twaidev;
+}
+#endif
diff --git a/arch/xtensa/src/esp32s2/esp32s2_twai.h 
b/arch/xtensa/src/esp32s2/esp32s2_twai.h
new file mode 100644
index 0000000000..074b8ec415
--- /dev/null
+++ b/arch/xtensa/src/esp32s2/esp32s2_twai.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_twai.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_TWAI_H
+#define __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_TWAI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/can/can.h>
+#include "hardware/esp32s2_twai.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Public Functions Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s2_twaiinitialize
+ *
+ * Description:
+ *   Initialize the selected CAN port
+ *
+ * Input Parameters:
+ *   Port number (for hardware that has multiple TWAI interfaces)
+ *
+ * Returned Value:
+ *   Valid TWAI device structure reference on success; a NULL on failure
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_CAN) && defined(CONFIG_ESP32S2_TWAI)
+struct can_dev_s *esp32s2_twaiinitialize(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_TWAI_H */
diff --git a/arch/xtensa/src/esp32s2/hardware/esp32s2_soc.h 
b/arch/xtensa/src/esp32s2/hardware/esp32s2_soc.h
index 6f6277909c..24b1895e28 100644
--- a/arch/xtensa/src/esp32s2/hardware/esp32s2_soc.h
+++ b/arch/xtensa/src/esp32s2/hardware/esp32s2_soc.h
@@ -264,6 +264,7 @@
 #define DR_REG_SPI4_BASE                        0x3f437000
 #define DR_REG_USB_WRAP_BASE                    0x3f439000
 #define DR_REG_APB_SARADC_BASE                  0x3f440000
+#define DR_REG_TWAI_BASE                        0x6002B000
 #define DR_REG_USB_BASE                         0x60080000
 
 #define REG_UHCI_BASE(i)         (DR_REG_UHCI0_BASE)
diff --git a/arch/xtensa/src/esp32s2/hardware/esp32s2_system.h 
b/arch/xtensa/src/esp32s2/hardware/esp32s2_system.h
index cfad41ab6e..189d6a30b1 100644
--- a/arch/xtensa/src/esp32s2/hardware/esp32s2_system.h
+++ b/arch/xtensa/src/esp32s2/hardware/esp32s2_system.h
@@ -455,14 +455,14 @@
 #define SYSTEM_PWM1_CLK_EN_V  0x00000001
 #define SYSTEM_PWM1_CLK_EN_S  20
 
-/* SYSTEM_CAN_CLK_EN : R/W; bitpos: [19]; default: 0;
- * Set this bit to enable clock of CAN.
+/* SYSTEM_TWAI_CLK_EN : R/W; bitpos: [19]; default: 0;
+ * Set this bit to enable clock of TWAI.
  */
 
-#define SYSTEM_CAN_CLK_EN    (BIT(19))
-#define SYSTEM_CAN_CLK_EN_M  (SYSTEM_CAN_CLK_EN_V << SYSTEM_CAN_CLK_EN_S)
-#define SYSTEM_CAN_CLK_EN_V  0x00000001
-#define SYSTEM_CAN_CLK_EN_S  19
+#define SYSTEM_TWAI_CLK_EN   (BIT(19))
+#define SYSTEM_TWAI_CLK_EN_M (SYSTEM_TWAI_CLK_EN_V << SYSTEM_TWAI_CLK_EN_S)
+#define SYSTEM_TWAI_CLK_EN_V 0x00000001
+#define SYSTEM_TWAI_CLK_EN_S 19
 
 /* SYSTEM_I2C_EXT1_CLK_EN : R/W; bitpos: [18]; default: 0;
  * Set this bit to enable clock of I2C EXT1.
@@ -809,14 +809,14 @@
 #define SYSTEM_PWM1_RST_V  0x00000001
 #define SYSTEM_PWM1_RST_S  20
 
-/* SYSTEM_CAN_RST : R/W; bitpos: [19]; default: 0;
- * Set this bit to reset CAN.
+/* SYSTEM_TWAI_RST : R/W; bitpos: [19]; default: 0;
+ * Set this bit to reset TWAI.
  */
 
-#define SYSTEM_CAN_RST    (BIT(19))
-#define SYSTEM_CAN_RST_M  (SYSTEM_CAN_RST_V << SYSTEM_CAN_RST_S)
-#define SYSTEM_CAN_RST_V  0x00000001
-#define SYSTEM_CAN_RST_S  19
+#define SYSTEM_TWAI_RST   (BIT(19))
+#define SYSTEM_TWAI_RST_M (SYSTEM_TWAI_RST_V << SYSTEM_TWAI_RST_S)
+#define SYSTEM_TWAI_RST_V 0x00000001
+#define SYSTEM_TWAI_RST_S 19
 
 /* SYSTEM_I2C_EXT1_RST : R/W; bitpos: [18]; default: 0;
  * Set this bit to reset I2C EXT1.
diff --git a/arch/xtensa/src/esp32s2/hardware/esp32s2_twai.h 
b/arch/xtensa/src/esp32s2/hardware/esp32s2_twai.h
new file mode 100644
index 0000000000..cc02591b4b
--- /dev/null
+++ b/arch/xtensa/src/esp32s2/hardware/esp32s2_twai.h
@@ -0,0 +1,792 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/hardware/esp32s2_twai.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_ESP32S2_TWAI_H
+#define __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_ESP32S2_TWAI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include "esp32s2_soc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* TWAI_MODE_REG register
+ * Mode Register
+ */
+
+#define TWAI_MODE_REG (DR_REG_TWAI_BASE + 0x0)
+
+/* TWAI_RX_FILTER_MODE : R/W; bitpos: [3]; default: 0;
+ * This bit is used to configure the filter mode. 0: Dual filter mode; 1:
+ * Single filter mode.
+ */
+
+#define TWAI_RX_FILTER_MODE    (BIT(3))
+#define TWAI_RX_FILTER_MODE_M  (TWAI_RX_FILTER_MODE_V << TWAI_RX_FILTER_MODE_S)
+#define TWAI_RX_FILTER_MODE_V  0x00000001
+#define TWAI_RX_FILTER_MODE_S  3
+
+/* TWAI_SELF_TEST_MODE : R/W; bitpos: [2]; default: 0;
+ * 1: Self test mode. In this mode the TX nodes can perform a successful
+ * transmission without receiving the acknowledge signal. This mode is often
+ * used to test a single node with the self reception request command.
+ */
+
+#define TWAI_SELF_TEST_MODE    (BIT(2))
+#define TWAI_SELF_TEST_MODE_M  (TWAI_SELF_TEST_MODE_V << TWAI_SELF_TEST_MODE_S)
+#define TWAI_SELF_TEST_MODE_V  0x00000001
+#define TWAI_SELF_TEST_MODE_S  2
+
+/* TWAI_LISTEN_ONLY_MODE : R/W; bitpos: [1]; default: 0;
+ * 1: Listen only mode. In this mode the nodes will only receive messages
+ * from the bus, without generating the acknowledge signal nor updating the
+ * RX error counter.
+ */
+
+#define TWAI_LISTEN_ONLY_MODE    (BIT(1))
+#define TWAI_LISTEN_ONLY_MODE_M  (TWAI_LISTEN_ONLY_MODE_V << 
TWAI_LISTEN_ONLY_MODE_S)
+#define TWAI_LISTEN_ONLY_MODE_V  0x00000001
+#define TWAI_LISTEN_ONLY_MODE_S  1
+
+/* TWAI_RESET_MODE : R/W; bitpos: [0]; default: 1;
+ * This bit is used to configure the operating mode of the TWAI Controller.
+ * 1: Reset mode; 0: Operating mode.
+ */
+
+#define TWAI_RESET_MODE    (BIT(0))
+#define TWAI_RESET_MODE_M  (TWAI_RESET_MODE_V << TWAI_RESET_MODE_S)
+#define TWAI_RESET_MODE_V  0x00000001
+#define TWAI_RESET_MODE_S  0
+
+/* TWAI_CMD_REG register
+ * Command Register
+ */
+
+#define TWAI_CMD_REG (DR_REG_TWAI_BASE + 0x4)
+
+/* TWAI_SELF_RX_REQ : WO; bitpos: [4]; default: 0;
+ * Self reception request command. Set the bit to 1 to allow a message be
+ * transmitted and received simultaneously.
+ */
+
+#define TWAI_SELF_RX_REQ    (BIT(4))
+#define TWAI_SELF_RX_REQ_M  (TWAI_SELF_RX_REQ_V << TWAI_SELF_RX_REQ_S)
+#define TWAI_SELF_RX_REQ_V  0x00000001
+#define TWAI_SELF_RX_REQ_S  4
+
+/* TWAI_CLR_OVERRUN : WO; bitpos: [3]; default: 0;
+ * Set the bit to 1 to clear the data overrun status bit.
+ */
+
+#define TWAI_CLR_OVERRUN    (BIT(3))
+#define TWAI_CLR_OVERRUN_M  (TWAI_CLR_OVERRUN_V << TWAI_CLR_OVERRUN_S)
+#define TWAI_CLR_OVERRUN_V  0x00000001
+#define TWAI_CLR_OVERRUN_S  3
+
+/* TWAI_RELEASE_BUF : WO; bitpos: [2]; default: 0;
+ * Set the bit to 1 to release the RX buffer.
+ */
+
+#define TWAI_RELEASE_BUF    (BIT(2))
+#define TWAI_RELEASE_BUF_M  (TWAI_RELEASE_BUF_V << TWAI_RELEASE_BUF_S)
+#define TWAI_RELEASE_BUF_V  0x00000001
+#define TWAI_RELEASE_BUF_S  2
+
+/* TWAI_ABORT_TX : WO; bitpos: [1]; default: 0;
+ * Set the bit to 1 to cancel a pending transmission request.
+ */
+
+#define TWAI_ABORT_TX    (BIT(1))
+#define TWAI_ABORT_TX_M  (TWAI_ABORT_TX_V << TWAI_ABORT_TX_S)
+#define TWAI_ABORT_TX_V  0x00000001
+#define TWAI_ABORT_TX_S  1
+
+/* TWAI_TX_REQ : WO; bitpos: [0]; default: 0;
+ * Set the bit to 1 to allow the driving nodes start transmission.
+ */
+
+#define TWAI_TX_REQ    (BIT(0))
+#define TWAI_TX_REQ_M  (TWAI_TX_REQ_V << TWAI_TX_REQ_S)
+#define TWAI_TX_REQ_V  0x00000001
+#define TWAI_TX_REQ_S  0
+
+/* TWAI_STATUS_REG register
+ * Status register
+ */
+
+#define TWAI_STATUS_REG (DR_REG_TWAI_BASE + 0x8)
+
+/* TWAI_MISS_ST : RO; bitpos: [8]; default: 0;
+ * This bit reflects whether the data packet in the RX FIFO is complete. 1:
+ * The current packet is missing; 0: The current packet is complete
+ */
+
+#define TWAI_MISS_ST    (BIT(8))
+#define TWAI_MISS_ST_M  (TWAI_MISS_ST_V << TWAI_MISS_ST_S)
+#define TWAI_MISS_ST_V  0x00000001
+#define TWAI_MISS_ST_S  8
+
+/* TWAI_BUS_OFF_ST : RO; bitpos: [7]; default: 0;
+ * 1: In bus-off status, the TWAI Controller is no longer involved in bus
+ * activities.
+ */
+
+#define TWAI_BUS_OFF_ST    (BIT(7))
+#define TWAI_BUS_OFF_ST_M  (TWAI_BUS_OFF_ST_V << TWAI_BUS_OFF_ST_S)
+#define TWAI_BUS_OFF_ST_V  0x00000001
+#define TWAI_BUS_OFF_ST_S  7
+
+/* TWAI_ERR_ST : RO; bitpos: [6]; default: 0;
+ * 1: At least one of the RX/TX error counter has reached or exceeded the
+ * value set in register TWAI_ERR_WARNING_LIMIT_REG.
+ */
+
+#define TWAI_ERR_ST    (BIT(6))
+#define TWAI_ERR_ST_M  (TWAI_ERR_ST_V << TWAI_ERR_ST_S)
+#define TWAI_ERR_ST_V  0x00000001
+#define TWAI_ERR_ST_S  6
+
+/* TWAI_TX_ST : RO; bitpos: [5]; default: 0;
+ * 1: The TWAI Controller is transmitting a message to the bus.
+ */
+
+#define TWAI_TX_ST    (BIT(5))
+#define TWAI_TX_ST_M  (TWAI_TX_ST_V << TWAI_TX_ST_S)
+#define TWAI_TX_ST_V  0x00000001
+#define TWAI_TX_ST_S  5
+
+/* TWAI_RX_ST : RO; bitpos: [4]; default: 0;
+ * 1: The TWAI Controller is receiving a message from the bus.
+ */
+
+#define TWAI_RX_ST    (BIT(4))
+#define TWAI_RX_ST_M  (TWAI_RX_ST_V << TWAI_RX_ST_S)
+#define TWAI_RX_ST_V  0x00000001
+#define TWAI_RX_ST_S  4
+
+/* TWAI_TX_COMPLETE : RO; bitpos: [3]; default: 0;
+ * 1: The TWAI controller has successfully received a packet from the bus.
+ */
+
+#define TWAI_TX_COMPLETE    (BIT(3))
+#define TWAI_TX_COMPLETE_M  (TWAI_TX_COMPLETE_V << TWAI_TX_COMPLETE_S)
+#define TWAI_TX_COMPLETE_V  0x00000001
+#define TWAI_TX_COMPLETE_S  3
+
+/* TWAI_TX_BUF_ST : RO; bitpos: [2]; default: 0;
+ * 1: The TX buffer is empty, the CPU may write a message into it.
+ */
+
+#define TWAI_TX_BUF_ST    (BIT(2))
+#define TWAI_TX_BUF_ST_M  (TWAI_TX_BUF_ST_V << TWAI_TX_BUF_ST_S)
+#define TWAI_TX_BUF_ST_V  0x00000001
+#define TWAI_TX_BUF_ST_S  2
+
+/* TWAI_OVERRUN_ST : RO; bitpos: [1]; default: 0;
+ * 1: The RX FIFO is full and data overrun has occurred.
+ */
+
+#define TWAI_OVERRUN_ST    (BIT(1))
+#define TWAI_OVERRUN_ST_M  (TWAI_OVERRUN_ST_V << TWAI_OVERRUN_ST_S)
+#define TWAI_OVERRUN_ST_V  0x00000001
+#define TWAI_OVERRUN_ST_S  1
+
+/* TWAI_RX_BUF_ST : RO; bitpos: [0]; default: 0;
+ * 1: The data in the RX buffer is not empty, with at least one received
+ * data packet.
+ */
+
+#define TWAI_RX_BUF_ST    (BIT(0))
+#define TWAI_RX_BUF_ST_M  (TWAI_RX_BUF_ST_V << TWAI_RX_BUF_ST_S)
+#define TWAI_RX_BUF_ST_V  0x00000001
+#define TWAI_RX_BUF_ST_S  0
+
+/* TWAI_INT_RAW_REG register
+ * Interrupt Register
+ */
+
+#define TWAI_INT_RAW_REG (DR_REG_TWAI_BASE + 0xc)
+
+/* TWAI_BUS_ERR_INT_ST : RO; bitpos: [7]; default: 0;
+ * Error interrupt. If this bit is set to 1, it indicates an error is
+ * detected on the bus.
+ */
+
+#define TWAI_BUS_ERR_INT_ST    (BIT(7))
+#define TWAI_BUS_ERR_INT_ST_M  (TWAI_BUS_ERR_INT_ST_V << TWAI_BUS_ERR_INT_ST_S)
+#define TWAI_BUS_ERR_INT_ST_V  0x00000001
+#define TWAI_BUS_ERR_INT_ST_S  7
+
+/* TWAI_ARB_LOST_INT_ST : RO; bitpos: [6]; default: 0;
+ * Arbitration lost interrupt. If this bit is set to 1, it indicates an
+ * arbitration lost interrupt is generated.
+ */
+
+#define TWAI_ARB_LOST_INT_ST    (BIT(6))
+#define TWAI_ARB_LOST_INT_ST_M  (TWAI_ARB_LOST_INT_ST_V << 
TWAI_ARB_LOST_INT_ST_S)
+#define TWAI_ARB_LOST_INT_ST_V  0x00000001
+#define TWAI_ARB_LOST_INT_ST_S  6
+
+/* TWAI_ERR_PASSIVE_INT_ST : RO; bitpos: [5]; default: 0;
+ * Error passive interrupt. If this bit is set to 1, it indicates the TWAI
+ * Controller is switched between error active status and error passive
+ * status due to the change of error counters.
+ */
+
+#define TWAI_ERR_PASSIVE_INT_ST    (BIT(5))
+#define TWAI_ERR_PASSIVE_INT_ST_M  (TWAI_ERR_PASSIVE_INT_ST_V << 
TWAI_ERR_PASSIVE_INT_ST_S)
+#define TWAI_ERR_PASSIVE_INT_ST_V  0x00000001
+#define TWAI_ERR_PASSIVE_INT_ST_S  5
+
+/* TWAI_OVERRUN_INT_ST : RO; bitpos: [3]; default: 0;
+ * Data overrun interrupt. If this bit is set to 1, it indicates a data
+ * overrun interrupt is generated in the RX FIFO.
+ */
+
+#define TWAI_OVERRUN_INT_ST    (BIT(3))
+#define TWAI_OVERRUN_INT_ST_M  (TWAI_OVERRUN_INT_ST_V << TWAI_OVERRUN_INT_ST_S)
+#define TWAI_OVERRUN_INT_ST_V  0x00000001
+#define TWAI_OVERRUN_INT_ST_S  3
+
+/* TWAI_ERR_WARN_INT_ST : RO; bitpos: [2]; default: 0;
+ * Error warning interrupt. If this bit is set to 1, it indicates the error
+ * status signal and the bus-off status signal of Status register have
+ * changed (e.g., switched from 0 to 1 or from 1 to 0).
+ */
+
+#define TWAI_ERR_WARN_INT_ST    (BIT(2))
+#define TWAI_ERR_WARN_INT_ST_M  (TWAI_ERR_WARN_INT_ST_V << 
TWAI_ERR_WARN_INT_ST_S)
+#define TWAI_ERR_WARN_INT_ST_V  0x00000001
+#define TWAI_ERR_WARN_INT_ST_S  2
+
+/* TWAI_TX_INT_ST : RO; bitpos: [1]; default: 0;
+ * Transmit interrupt. If this bit is set to 1, it indicates the message
+ * transmitting mis- sion is finished and a new transmission is able to
+ * execute.
+ */
+
+#define TWAI_TX_INT_ST    (BIT(1))
+#define TWAI_TX_INT_ST_M  (TWAI_TX_INT_ST_V << TWAI_TX_INT_ST_S)
+#define TWAI_TX_INT_ST_V  0x00000001
+#define TWAI_TX_INT_ST_S  1
+
+/* TWAI_RX_INT_ST : RO; bitpos: [0]; default: 0;
+ * Receive interrupt. If this bit is set to 1, it indicates there are
+ * messages to be handled in the RX FIFO.
+ */
+
+#define TWAI_RX_INT_ST    (BIT(0))
+#define TWAI_RX_INT_ST_M  (TWAI_RX_INT_ST_V << TWAI_RX_INT_ST_S)
+#define TWAI_RX_INT_ST_V  0x00000001
+#define TWAI_RX_INT_ST_S  0
+
+/* TWAI_INT_ENA_REG register
+ * Interrupt Enable Register
+ */
+
+#define TWAI_INT_ENA_REG (DR_REG_TWAI_BASE + 0x10)
+
+/* TWAI_BUS_ERR_INT_ENA : R/W; bitpos: [7]; default: 0;
+ * Set this bit to 1 to enable error interrupt.
+ */
+
+#define TWAI_BUS_ERR_INT_ENA    (BIT(7))
+#define TWAI_BUS_ERR_INT_ENA_M  (TWAI_BUS_ERR_INT_ENA_V << 
TWAI_BUS_ERR_INT_ENA_S)
+#define TWAI_BUS_ERR_INT_ENA_V  0x00000001
+#define TWAI_BUS_ERR_INT_ENA_S  7
+
+/* TWAI_ARB_LOST_INT_ENA : R/W; bitpos: [6]; default: 0;
+ * Set this bit to 1 to enable arbitration lost interrupt.
+ */
+
+#define TWAI_ARB_LOST_INT_ENA    (BIT(6))
+#define TWAI_ARB_LOST_INT_ENA_M  (TWAI_ARB_LOST_INT_ENA_V << 
TWAI_ARB_LOST_INT_ENA_S)
+#define TWAI_ARB_LOST_INT_ENA_V  0x00000001
+#define TWAI_ARB_LOST_INT_ENA_S  6
+
+/* TWAI_ERR_PASSIVE_INT_ENA : R/W; bitpos: [5]; default: 0;
+ * Set this bit to 1 to enable error passive interrupt.
+ */
+
+#define TWAI_ERR_PASSIVE_INT_ENA    (BIT(5))
+#define TWAI_ERR_PASSIVE_INT_ENA_M  (TWAI_ERR_PASSIVE_INT_ENA_V << 
TWAI_ERR_PASSIVE_INT_ENA_S)
+#define TWAI_ERR_PASSIVE_INT_ENA_V  0x00000001
+#define TWAI_ERR_PASSIVE_INT_ENA_S  5
+
+/* TWAI_OVERRUN_INT_ENA : R/W; bitpos: [3]; default: 0;
+ * Set this bit to 1 to enable data overrun interrupt.
+ */
+
+#define TWAI_OVERRUN_INT_ENA    (BIT(3))
+#define TWAI_OVERRUN_INT_ENA_M  (TWAI_OVERRUN_INT_ENA_V << 
TWAI_OVERRUN_INT_ENA_S)
+#define TWAI_OVERRUN_INT_ENA_V  0x00000001
+#define TWAI_OVERRUN_INT_ENA_S  3
+
+/* TWAI_ERR_WARN_INT_ENA : R/W; bitpos: [2]; default: 0;
+ * Set this bit to 1 to enable error warning interrupt.
+ */
+
+#define TWAI_ERR_WARN_INT_ENA    (BIT(2))
+#define TWAI_ERR_WARN_INT_ENA_M  (TWAI_ERR_WARN_INT_ENA_V << 
TWAI_ERR_WARN_INT_ENA_S)
+#define TWAI_ERR_WARN_INT_ENA_V  0x00000001
+#define TWAI_ERR_WARN_INT_ENA_S  2
+
+/* TWAI_TX_INT_ENA : R/W; bitpos: [1]; default: 0;
+ * Set this bit to 1 to enable transmit interrupt.
+ */
+
+#define TWAI_TX_INT_ENA    (BIT(1))
+#define TWAI_TX_INT_ENA_M  (TWAI_TX_INT_ENA_V << TWAI_TX_INT_ENA_S)
+#define TWAI_TX_INT_ENA_V  0x00000001
+#define TWAI_TX_INT_ENA_S  1
+
+/* TWAI_RX_INT_ENA : R/W; bitpos: [0]; default: 0;
+ * Set this bit to 1 to enable receive interrupt.
+ */
+
+#define TWAI_RX_INT_ENA    (BIT(0))
+#define TWAI_RX_INT_ENA_M  (TWAI_RX_INT_ENA_V << TWAI_RX_INT_ENA_S)
+#define TWAI_RX_INT_ENA_V  0x00000001
+#define TWAI_RX_INT_ENA_S  0
+
+/* TWAI_BUS_TIMING_0_REG register
+ * Bus Timing Register 0
+ */
+
+#define TWAI_BUS_TIMING_0_REG (DR_REG_TWAI_BASE + 0x18)
+
+/* TWAI_SYNC_JUMP_WIDTH : RO | R/W; bitpos: [15:14]; default: 0;
+ * Synchronization Jump Width (SJW), 1 \verb+~+ 14 Tq wide.
+ */
+
+#define TWAI_SYNC_JUMP_WIDTH    0x00000003
+#define TWAI_SYNC_JUMP_WIDTH_M  (TWAI_SYNC_JUMP_WIDTH_V << 
TWAI_SYNC_JUMP_WIDTH_S)
+#define TWAI_SYNC_JUMP_WIDTH_V  0x00000003
+#define TWAI_SYNC_JUMP_WIDTH_S  14
+
+/* TWAI_BAUD_PRESC : RO | R/W; bitpos: [13:0]; default: 0;
+ * Baud Rate Prescaler, determines the frequency dividing ratio.
+ */
+
+#define TWAI_BAUD_PRESC    0x00003fff
+#define TWAI_BAUD_PRESC_M  (TWAI_BAUD_PRESC_V << TWAI_BAUD_PRESC_S)
+#define TWAI_BAUD_PRESC_V  0x00003fff
+#define TWAI_BAUD_PRESC_S  0
+
+/* TWAI_BUS_TIMING_1_REG register
+ * Bus Timing Register 1
+ */
+
+#define TWAI_BUS_TIMING_1_REG (DR_REG_TWAI_BASE + 0x1c)
+
+/* TWAI_TIME_SAMP : RO | R/W; bitpos: [7]; default: 0;
+ * The number of sample points. 0: the bus is sampled once; 1: the bus is
+ * sampled three times
+ */
+
+#define TWAI_TIME_SAMP    (BIT(7))
+#define TWAI_TIME_SAMP_M  (TWAI_TIME_SAMP_V << TWAI_TIME_SAMP_S)
+#define TWAI_TIME_SAMP_V  0x00000001
+#define TWAI_TIME_SAMP_S  7
+
+/* TWAI_TIME_SEG2 : RO | R/W; bitpos: [6:4]; default: 0;
+ * The width of PBS2.
+ */
+
+#define TWAI_TIME_SEG2    0x00000007
+#define TWAI_TIME_SEG2_M  (TWAI_TIME_SEG2_V << TWAI_TIME_SEG2_S)
+#define TWAI_TIME_SEG2_V  0x00000007
+#define TWAI_TIME_SEG2_S  4
+
+/* TWAI_TIME_SEG1 : RO | R/W; bitpos: [3:0]; default: 0;
+ * The width of PBS1.
+ */
+
+#define TWAI_TIME_SEG1    0x0000000f
+#define TWAI_TIME_SEG1_M  (TWAI_TIME_SEG1_V << TWAI_TIME_SEG1_S)
+#define TWAI_TIME_SEG1_V  0x0000000f
+#define TWAI_TIME_SEG1_S  0
+
+/* TWAI_ARB_LOST_CAP_REG register
+ * Arbitration Lost Capture Register
+ */
+
+#define TWAI_ARB_LOST_CAP_REG (DR_REG_TWAI_BASE + 0x2c)
+
+/* TWAI_ARB_LOST_CAP : RO; bitpos: [4:0]; default: 0;
+ * This register contains information about the bit position of lost
+ * arbitration.
+ */
+
+#define TWAI_ARB_LOST_CAP    0x0000001f
+#define TWAI_ARB_LOST_CAP_M  (TWAI_ARB_LOST_CAP_V << TWAI_ARB_LOST_CAP_S)
+#define TWAI_ARB_LOST_CAP_V  0x0000001f
+#define TWAI_ARB_LOST_CAP_S  0
+
+/* TWAI_ERR_CODE_CAP_REG register
+ * Error Code Capture Register
+ */
+
+#define TWAI_ERR_CODE_CAP_REG (DR_REG_TWAI_BASE + 0x30)
+
+/* TWAI_ECC_TYPE : RO; bitpos: [7:6]; default: 0;
+ * This register contains information about error types: 00: bit error; 01:
+ * form error; 10: stuff error; 11: other type of error
+ */
+
+#define TWAI_ECC_TYPE    0x00000003
+#define TWAI_ECC_TYPE_M  (TWAI_ECC_TYPE_V << TWAI_ECC_TYPE_S)
+#define TWAI_ECC_TYPE_V  0x00000003
+#define TWAI_ECC_TYPE_S  6
+
+/* TWAI_ECC_DIRECTION : RO; bitpos: [5]; default: 0;
+ * This register contains information about transmission direction of the
+ * node when error occurs. 1: Error occurs when receiving a message; 0:
+ * Error occurs when transmitting a message
+ */
+
+#define TWAI_ECC_DIRECTION    (BIT(5))
+#define TWAI_ECC_DIRECTION_M  (TWAI_ECC_DIRECTION_V << TWAI_ECC_DIRECTION_S)
+#define TWAI_ECC_DIRECTION_V  0x00000001
+#define TWAI_ECC_DIRECTION_S  5
+
+/* TWAI_ECC_SEGMENT : RO; bitpos: [4:0]; default: 0;
+ * This register contains information about the location of errors, see
+ * Table 181 for details.
+ */
+
+#define TWAI_ECC_SEGMENT    0x0000001f
+#define TWAI_ECC_SEGMENT_M  (TWAI_ECC_SEGMENT_V << TWAI_ECC_SEGMENT_S)
+#define TWAI_ECC_SEGMENT_V  0x0000001f
+#define TWAI_ECC_SEGMENT_S  0
+
+/* TWAI_ERR_WARNING_LIMIT_REG register
+ * Error Warning Limit Register
+ */
+
+#define TWAI_ERR_WARNING_LIMIT_REG (DR_REG_TWAI_BASE + 0x34)
+
+/* TWAI_ERR_WARNING_LIMIT : RO | R/W; bitpos: [7:0]; default: 96;
+ * Error warning threshold. In the case when any of a error counter value
+ * exceeds the threshold, or all the error counter values are below the
+ * threshold, an error warning interrupt will be triggered (given the enable
+ * signal is valid).
+ */
+
+#define TWAI_ERR_WARNING_LIMIT    0x000000ff
+#define TWAI_ERR_WARNING_LIMIT_M  (TWAI_ERR_WARNING_LIMIT_V << 
TWAI_ERR_WARNING_LIMIT_S)
+#define TWAI_ERR_WARNING_LIMIT_V  0x000000ff
+#define TWAI_ERR_WARNING_LIMIT_S  0
+
+/* TWAI_RX_ERR_CNT_REG register
+ * Receive Error Counter Register
+ */
+
+#define TWAI_RX_ERR_CNT_REG (DR_REG_TWAI_BASE + 0x38)
+
+/* TWAI_RX_ERR_CNT : RO | R/W; bitpos: [7:0]; default: 0;
+ * The RX error counter register, reflects value changes under reception
+ * status.
+ */
+
+#define TWAI_RX_ERR_CNT    0x000000ff
+#define TWAI_RX_ERR_CNT_M  (TWAI_RX_ERR_CNT_V << TWAI_RX_ERR_CNT_S)
+#define TWAI_RX_ERR_CNT_V  0x000000ff
+#define TWAI_RX_ERR_CNT_S  0
+
+/* TWAI_TX_ERR_CNT_REG register
+ * Transmit Error Counter Register
+ */
+
+#define TWAI_TX_ERR_CNT_REG (DR_REG_TWAI_BASE + 0x3c)
+
+/* TWAI_TX_ERR_CNT : RO | R/W; bitpos: [7:0]; default: 0;
+ * The TX error counter register, reflects value changes under transmission
+ * status.
+ */
+
+#define TWAI_TX_ERR_CNT    0x000000ff
+#define TWAI_TX_ERR_CNT_M  (TWAI_TX_ERR_CNT_V << TWAI_TX_ERR_CNT_S)
+#define TWAI_TX_ERR_CNT_V  0x000000ff
+#define TWAI_TX_ERR_CNT_S  0
+
+/* TWAI_DATA_0_REG register
+ * Data register 0
+ */
+
+#define TWAI_DATA_0_REG (DR_REG_TWAI_BASE + 0x40)
+
+/* TWAI_TX_BYTE_0 : WO; bitpos: [7:0]; default: 0;
+ * In reset mode, it is acceptance code register 0 with R/W Permission. In
+ * operation mode, it stores the 0th byte information of the data to be
+ * transmitted under operating mode.
+ */
+
+#define TWAI_TX_BYTE_0    0x000000ff
+#define TWAI_TX_BYTE_0_M  (TWAI_TX_BYTE_0_V << TWAI_TX_BYTE_0_S)
+#define TWAI_TX_BYTE_0_V  0x000000ff
+#define TWAI_TX_BYTE_0_S  0
+
+/* TWAI_DATA_1_REG register
+ * Data register 1
+ */
+
+#define TWAI_DATA_1_REG (DR_REG_TWAI_BASE + 0x44)
+
+/* TWAI_TX_BYTE_1 : WO; bitpos: [7:0]; default: 0;
+ * In reset mode, it is acceptance code register 1 with R/W Permission. In
+ * operation mode, it stores the 1st byte information of the data to be
+ * transmitted under operating mode.
+ */
+
+#define TWAI_TX_BYTE_1    0x000000ff
+#define TWAI_TX_BYTE_1_M  (TWAI_TX_BYTE_1_V << TWAI_TX_BYTE_1_S)
+#define TWAI_TX_BYTE_1_V  0x000000ff
+#define TWAI_TX_BYTE_1_S  0
+
+/* TWAI_DATA_2_REG register
+ * Data register 2
+ */
+
+#define TWAI_DATA_2_REG (DR_REG_TWAI_BASE + 0x48)
+
+/* TWAI_TX_BYTE_2 : WO; bitpos: [7:0]; default: 0;
+ * In reset mode, it is acceptance code register 2 with R/W Permission. In
+ * operation mode, it stores the 2nd byte information of the data to be
+ * transmitted under operating mode.
+ */
+
+#define TWAI_TX_BYTE_2    0x000000ff
+#define TWAI_TX_BYTE_2_M  (TWAI_TX_BYTE_2_V << TWAI_TX_BYTE_2_S)
+#define TWAI_TX_BYTE_2_V  0x000000ff
+#define TWAI_TX_BYTE_2_S  0
+
+/* TWAI_DATA_3_REG register
+ * Data register 3
+ */
+
+#define TWAI_DATA_3_REG (DR_REG_TWAI_BASE + 0x4c)
+
+/* TWAI_TX_BYTE_3 : WO; bitpos: [7:0]; default: 0;
+ * In reset mode, it is acceptance code register 3 with R/W Permission. In
+ * operation mode, it stores the 3rd byte information of the data to be
+ * transmitted under operating mode.
+ */
+
+#define TWAI_TX_BYTE_3    0x000000ff
+#define TWAI_TX_BYTE_3_M  (TWAI_TX_BYTE_3_V << TWAI_TX_BYTE_3_S)
+#define TWAI_TX_BYTE_3_V  0x000000ff
+#define TWAI_TX_BYTE_3_S  0
+
+/* TWAI_DATA_4_REG register
+ * Data register 4
+ */
+
+#define TWAI_DATA_4_REG (DR_REG_TWAI_BASE + 0x50)
+
+/* TWAI_TX_BYTE_4 : WO; bitpos: [7:0]; default: 0;
+ * In reset mode, it is acceptance mask register 0 with R/W Permission. In
+ * operation mode, it stores the 4th byte information of the data to be
+ * transmitted under operating mode.
+ */
+
+#define TWAI_TX_BYTE_4    0x000000ff
+#define TWAI_TX_BYTE_4_M  (TWAI_TX_BYTE_4_V << TWAI_TX_BYTE_4_S)
+#define TWAI_TX_BYTE_4_V  0x000000ff
+#define TWAI_TX_BYTE_4_S  0
+
+/* TWAI_DATA_5_REG register
+ * Data register 5
+ */
+
+#define TWAI_DATA_5_REG (DR_REG_TWAI_BASE + 0x54)
+
+/* TWAI_TX_BYTE_5 : WO; bitpos: [7:0]; default: 0;
+ * In reset mode, it is acceptance mask register 1 with R/W Permission. In
+ * operation mode, it stores the 5th byte information of the data to be
+ * transmitted under operating mode.
+ */
+
+#define TWAI_TX_BYTE_5    0x000000ff
+#define TWAI_TX_BYTE_5_M  (TWAI_TX_BYTE_5_V << TWAI_TX_BYTE_5_S)
+#define TWAI_TX_BYTE_5_V  0x000000ff
+#define TWAI_TX_BYTE_5_S  0
+
+/* TWAI_DATA_6_REG register
+ * Data register 6
+ */
+
+#define TWAI_DATA_6_REG (DR_REG_TWAI_BASE + 0x58)
+
+/* TWAI_TX_BYTE_6 : WO; bitpos: [7:0]; default: 0;
+ * In reset mode, it is acceptance mask register 2 with R/W Permission. In
+ * operation mode, it stores the 6th byte information of the data to be
+ * transmitted under operating mode.
+ */
+
+#define TWAI_TX_BYTE_6    0x000000ff
+#define TWAI_TX_BYTE_6_M  (TWAI_TX_BYTE_6_V << TWAI_TX_BYTE_6_S)
+#define TWAI_TX_BYTE_6_V  0x000000ff
+#define TWAI_TX_BYTE_6_S  0
+
+/* TWAI_DATA_7_REG register
+ * Data register 7
+ */
+
+#define TWAI_DATA_7_REG (DR_REG_TWAI_BASE + 0x5c)
+
+/* TWAI_TX_BYTE_7 : WO; bitpos: [7:0]; default: 0;
+ * In reset mode, it is acceptance mask register 3 with R/W Permission. In
+ * operation mode, it stores the 7th byte information of the data to be
+ * transmitted under operating mode.
+ */
+
+#define TWAI_TX_BYTE_7    0x000000ff
+#define TWAI_TX_BYTE_7_M  (TWAI_TX_BYTE_7_V << TWAI_TX_BYTE_7_S)
+#define TWAI_TX_BYTE_7_V  0x000000ff
+#define TWAI_TX_BYTE_7_S  0
+
+/* TWAI_DATA_8_REG register
+ * Data register 8
+ */
+
+#define TWAI_DATA_8_REG (DR_REG_TWAI_BASE + 0x60)
+
+/* TWAI_TX_BYTE_8 : WO; bitpos: [7:0]; default: 0;
+ * Stored the 8th byte information of the data to be transmitted under
+ * operating mode.
+ */
+
+#define TWAI_TX_BYTE_8    0x000000ff
+#define TWAI_TX_BYTE_8_M  (TWAI_TX_BYTE_8_V << TWAI_TX_BYTE_8_S)
+#define TWAI_TX_BYTE_8_V  0x000000ff
+#define TWAI_TX_BYTE_8_S  0
+
+/* TWAI_DATA_9_REG register
+ * Data register 9
+ */
+
+#define TWAI_DATA_9_REG (DR_REG_TWAI_BASE + 0x64)
+
+/* TWAI_TX_BYTE_9 : WO; bitpos: [7:0]; default: 0;
+ * Stored the 9th byte information of the data to be transmitted under
+ * operating mode.
+ */
+
+#define TWAI_TX_BYTE_9    0x000000ff
+#define TWAI_TX_BYTE_9_M  (TWAI_TX_BYTE_9_V << TWAI_TX_BYTE_9_S)
+#define TWAI_TX_BYTE_9_V  0x000000ff
+#define TWAI_TX_BYTE_9_S  0
+
+/* TWAI_DATA_10_REG register
+ * Data register 10
+ */
+
+#define TWAI_DATA_10_REG (DR_REG_TWAI_BASE + 0x68)
+
+/* TWAI_TX_BYTE_10 : WO; bitpos: [7:0]; default: 0;
+ * Stored the 10th byte information of the data to be transmitted under
+ * operating mode.
+ */
+
+#define TWAI_TX_BYTE_10    0x000000ff
+#define TWAI_TX_BYTE_10_M  (TWAI_TX_BYTE_10_V << TWAI_TX_BYTE_10_S)
+#define TWAI_TX_BYTE_10_V  0x000000ff
+#define TWAI_TX_BYTE_10_S  0
+
+/* TWAI_DATA_11_REG register
+ * Data register 11
+ */
+
+#define TWAI_DATA_11_REG (DR_REG_TWAI_BASE + 0x6c)
+
+/* TWAI_TX_BYTE_11 : WO; bitpos: [7:0]; default: 0;
+ * Stored the 11th byte information of the data to be transmitted under
+ * operating mode.
+ */
+
+#define TWAI_TX_BYTE_11    0x000000ff
+#define TWAI_TX_BYTE_11_M  (TWAI_TX_BYTE_11_V << TWAI_TX_BYTE_11_S)
+#define TWAI_TX_BYTE_11_V  0x000000ff
+#define TWAI_TX_BYTE_11_S  0
+
+/* TWAI_DATA_12_REG register
+ * Data register 12
+ */
+
+#define TWAI_DATA_12_REG (DR_REG_TWAI_BASE + 0x70)
+
+/* TWAI_TX_BYTE_12 : WO; bitpos: [7:0]; default: 0;
+ * Stored the 12th byte information of the data to be transmitted under
+ * operating mode.
+ */
+
+#define TWAI_TX_BYTE_12    0x000000ff
+#define TWAI_TX_BYTE_12_M  (TWAI_TX_BYTE_12_V << TWAI_TX_BYTE_12_S)
+#define TWAI_TX_BYTE_12_V  0x000000ff
+#define TWAI_TX_BYTE_12_S  0
+
+/* TWAI_RX_MESSAGE_CNT_REG register
+ * Receive Message Counter Register
+ */
+
+#define TWAI_RX_MESSAGE_CNT_REG (DR_REG_TWAI_BASE + 0x74)
+
+/* TWAI_RX_MESSAGE_COUNTER : RO; bitpos: [6:0]; default: 0;
+ * This register reflects the number of messages available within the RX
+ * FIFO.
+ */
+
+#define TWAI_RX_MESSAGE_COUNTER    0x0000007f
+#define TWAI_RX_MESSAGE_COUNTER_M  (TWAI_RX_MESSAGE_COUNTER_V << 
TWAI_RX_MESSAGE_COUNTER_S)
+#define TWAI_RX_MESSAGE_COUNTER_V  0x0000007f
+#define TWAI_RX_MESSAGE_COUNTER_S  0
+
+/* TWAI_CLOCK_DIVIDER_REG register
+ * Clock Divider register
+ */
+
+#define TWAI_CLOCK_DIVIDER_REG (DR_REG_TWAI_BASE + 0x7c)
+
+/* TWAI_CLOCK_OFF : RO | R/W; bitpos: [8]; default: 0;
+ * This bit can be configured under reset mode. 1: Disable the external
+ * CLKOUT pin; 0: Enable the external CLKOUT pin
+ */
+
+#define TWAI_CLOCK_OFF    (BIT(8))
+#define TWAI_CLOCK_OFF_M  (TWAI_CLOCK_OFF_V << TWAI_CLOCK_OFF_S)
+#define TWAI_CLOCK_OFF_V  0x00000001
+#define TWAI_CLOCK_OFF_S  8
+
+/* TWAI_CD : R/W; bitpos: [7:0]; default: 0;
+ * These bits are used to configure frequency dividing coefficients of the
+ * external CLKOUT pin.
+ */
+
+#define TWAI_CD    0x000000ff
+#define TWAI_CD_M  (TWAI_CD_V << TWAI_CD_S)
+#define TWAI_CD_V  0x000000ff
+#define TWAI_CD_S  0
+
+#endif /* __ARCH_XTENSA_SRC_ESP32S2_HARDWARE_ESP32S2_TWAI_H */
diff --git a/boards/xtensa/esp32s2/common/scripts/esp32s2_peripherals.ld 
b/boards/xtensa/esp32s2/common/scripts/esp32s2_peripherals.ld
index 8ce267b2fb..a0bfd1bc7f 100644
--- a/boards/xtensa/esp32s2/common/scripts/esp32s2_peripherals.ld
+++ b/boards/xtensa/esp32s2/common/scripts/esp32s2_peripherals.ld
@@ -44,9 +44,9 @@ PROVIDE ( SPI2 = 0x3f424000 );
 PROVIDE ( SPI3 = 0x3f425000 );
 PROVIDE ( SYSCON = 0x3f426000 );
 PROVIDE ( I2C1 = 0x3f427000 );
-PROVIDE ( TWAI = 0x3f42b000 );
 PROVIDE ( APB_SARADC = 0x3f440000 );
 PROVIDE ( DEDIC_GPIO = 0x3f4cf000 );
+PROVIDE ( TWAI = 0x6002B000 );
 PROVIDE ( USB0     = 0x60080000 );
 PROVIDE ( USBH     = 0x60080000 );
 PROVIDE ( USB_WRAP = 0x3f439000 );
diff --git a/boards/xtensa/esp32s2/common/src/Make.defs 
b/boards/xtensa/esp32s2/common/src/Make.defs
index f7335a4f9c..9b22ffa636 100644
--- a/boards/xtensa/esp32s2/common/src/Make.defs
+++ b/boards/xtensa/esp32s2/common/src/Make.defs
@@ -36,6 +36,10 @@ ifeq ($(CONFIG_ESP32S2_I2S),y)
   CSRCS += esp32s2_board_i2sdev.c
 endif
 
+ifeq ($(CONFIG_ESP32S2_TWAI),y)
+  CSRCS += esp32s2_board_twai.c
+endif
+
 ifeq ($(CONFIG_AUDIO_CS4344),y)
   CSRCS += esp32s2_cs4344.c
 endif
diff --git a/boards/xtensa/esp32s2/common/src/esp32s2_board_twai.c 
b/boards/xtensa/esp32s2/common/src/esp32s2_board_twai.c
new file mode 100644
index 0000000000..73c56476ac
--- /dev/null
+++ b/boards/xtensa/esp32s2/common/src/esp32s2_board_twai.c
@@ -0,0 +1,89 @@
+/****************************************************************************
+ * boards/xtensa/esp32s2/common/src/esp32s2_board_twai.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/can/can.h>
+#include <arch/board/board.h>
+
+#include "chip.h"
+
+#include "esp32s2_twai.h"
+
+#ifdef CONFIG_CAN
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_twai_setup
+ *
+ * Description:
+ *  Initialize TWAI and register the TWAI device
+ *
+ ****************************************************************************/
+
+int board_twai_setup(void)
+{
+#ifdef CONFIG_ESP32S2_TWAI
+  struct can_dev_s *twai;
+  int ret;
+
+  /* Call esp32s2_twaiinitialize() to get an instance of the TWAI
+   * interface
+   * */
+
+  twai = esp32s2_twaiinitialize();
+  if (twai == NULL)
+    {
+      canerr("ERROR:  Failed to get TWAI interface\n");
+      return -ENODEV;
+    }
+
+  /* Register the TWAI driver at "/dev/can0" */
+
+  ret = can_register("/dev/can0", twai);
+  if (ret < 0)
+    {
+      canerr("ERROR: TWAI1 register failed: %d\n", ret);
+      return ret;
+    }
+
+  return OK;
+#else
+  return -ENODEV;
+#endif
+}
+
+#endif /* CONFIG_CAN */
diff --git a/boards/xtensa/esp32s2/esp32s2-kaluga-1/configs/twai/defconfig 
b/boards/xtensa/esp32s2/esp32s2-kaluga-1/configs/twai/defconfig
new file mode 100644
index 0000000000..36aefdfb45
--- /dev/null
+++ b/boards/xtensa/esp32s2/esp32s2-kaluga-1/configs/twai/defconfig
@@ -0,0 +1,46 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed 
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that 
includes your
+# modifications.
+#
+# CONFIG_ARCH_LEDS is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+CONFIG_ARCH="xtensa"
+CONFIG_ARCH_BOARD="esp32s2-kaluga-1"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_ESP32S2_KALUGA_1=y
+CONFIG_ARCH_CHIP="esp32s2"
+CONFIG_ARCH_CHIP_ESP32S2=y
+CONFIG_ARCH_CHIP_ESP32S2WROVER=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_XTENSA=y
+CONFIG_BOARD_LOOPSPERMSEC=16717
+CONFIG_BUILTIN=y
+CONFIG_ESP32S2_TWAI=y
+CONFIG_ESP32S2_UART0=y
+CONFIG_EXAMPLES_CAN=y
+CONFIG_FS_PROCFS=y
+CONFIG_HAVE_CXX=y
+CONFIG_HAVE_CXXINITIALIZE=y
+CONFIG_IDLETHREAD_STACKSIZE=3072
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INTELHEX_BINARY=y
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_LINELEN=64
+CONFIG_NSH_READLINE=y
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_RAM_SIZE=114688
+CONFIG_RAM_START=0x20000000
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_WAITPID=y
+CONFIG_START_DAY=6
+CONFIG_START_MONTH=12
+CONFIG_START_YEAR=2011
+CONFIG_SYSLOG_BUFFER=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2-kaluga-1.h 
b/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2-kaluga-1.h
index a8e0b2c770..21e3325c3f 100644
--- a/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2-kaluga-1.h
+++ b/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2-kaluga-1.h
@@ -166,6 +166,17 @@ int board_i2c_init(void);
 int board_i2sdev_initialize(void);
 #endif
 
+/****************************************************************************
+ * Name: board_twai_setup
+ *
+ * Description:
+ *  Initialize TWAI and register the TWAI device
+ *
+ ****************************************************************************/
+#ifdef CONFIG_ESP32S2_TWAI
+int board_twai_setup(void);
+#endif
+
 /****************************************************************************
  * Name: esp32s2_es8311_initialize
  *
diff --git a/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2_bringup.c 
b/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2_bringup.c
index cb79d5cd70..559fd99c6c 100644
--- a/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2_bringup.c
+++ b/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2_bringup.c
@@ -218,6 +218,17 @@ int esp32s2_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_ESP32S2_TWAI
+
+  /* Initialize TWAI and register the TWAI driver. */
+
+  ret = board_twai_setup();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: board_twai_setup failed: %d\n", ret);
+    }
+#endif
+
 #ifdef CONFIG_INPUT_BUTTONS
   /* Register the BUTTON driver */
 
diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/configs/twai/defconfig 
b/boards/xtensa/esp32s2/esp32s2-saola-1/configs/twai/defconfig
new file mode 100644
index 0000000000..cbb59e2d5a
--- /dev/null
+++ b/boards/xtensa/esp32s2/esp32s2-saola-1/configs/twai/defconfig
@@ -0,0 +1,46 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed 
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that 
includes your
+# modifications.
+#
+# CONFIG_ARCH_LEDS is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+CONFIG_ARCH="xtensa"
+CONFIG_ARCH_BOARD="esp32s2-saola-1"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_ESP32S2_SAOLA_1=y
+CONFIG_ARCH_CHIP="esp32s2"
+CONFIG_ARCH_CHIP_ESP32S2=y
+CONFIG_ARCH_CHIP_ESP32S2WROVER=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_XTENSA=y
+CONFIG_BOARD_LOOPSPERMSEC=16717
+CONFIG_BUILTIN=y
+CONFIG_ESP32S2_TWAI=y
+CONFIG_ESP32S2_UART0=y
+CONFIG_EXAMPLES_CAN=y
+CONFIG_FS_PROCFS=y
+CONFIG_HAVE_CXX=y
+CONFIG_HAVE_CXXINITIALIZE=y
+CONFIG_IDLETHREAD_STACKSIZE=3072
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INTELHEX_BINARY=y
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_LINELEN=64
+CONFIG_NSH_READLINE=y
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_RAM_SIZE=114688
+CONFIG_RAM_START=0x20000000
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_WAITPID=y
+CONFIG_START_DAY=6
+CONFIG_START_MONTH=12
+CONFIG_START_YEAR=2011
+CONFIG_SYSLOG_BUFFER=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2-saola-1.h 
b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2-saola-1.h
index decf704ef7..afbdf5b74d 100644
--- a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2-saola-1.h
+++ b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2-saola-1.h
@@ -220,5 +220,16 @@ int esp32s2_cs4344_initialize(void);
 int esp32s2_pwm_setup(void);
 #endif
 
+/****************************************************************************
+ * Name: board_twai_setup
+ *
+ * Description:
+ *  Initialize TWAI and register the TWAI device
+ *
+ ****************************************************************************/
+#ifdef CONFIG_ESP32S2_TWAI
+int board_twai_setup(void);
+#endif
+
 #endif /* __ASSEMBLY__ */
 #endif /* __BOARDS_XTENSA_ESP32S2_ESP32S2_SAOLA_1_SRC_ESP32S2_SAOLA_1_H */
diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c 
b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c
index eb46a0fe38..bded3ab92e 100644
--- a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c
+++ b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c
@@ -242,6 +242,17 @@ int esp32s2_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_ESP32S2_TWAI
+
+  /* Initialize TWAI and register the TWAI driver. */
+
+  ret = board_twai_setup();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: board_twai_setup failed: %d\n", ret);
+    }
+#endif
+
 #ifdef CONFIG_SENSORS_BMP180
   /* Try to register BMP180 device in I2C0 */
 

Reply via email to