You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by GitBox <gi...@apache.org> on 2022/06/29 07:26:39 UTC

[GitHub] [incubator-nuttx] pkarashchenko commented on a diff in pull request #6539: ESP32-S2: Add driver for I2C peripheral in Master mode

pkarashchenko commented on code in PR #6539:
URL: https://github.com/apache/incubator-nuttx/pull/6539#discussion_r909241025


##########
arch/xtensa/src/esp32s2/esp32s2_i2c.c:
##########
@@ -0,0 +1,1702 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_i2c.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>
+
+#ifdef CONFIG_ESP32S2_I2C
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/clock.h>
+#include <nuttx/irq.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/semaphore.h>
+
+#include <arch/board/board.h>
+
+#include "esp32s2_gpio.h"
+#include "esp32s2_i2c.h"
+#include "esp32s2_irq.h"
+
+#include "xtensa.h"
+#include "hardware/esp32s2_gpio_sigmap.h"
+#include "hardware/esp32s2_i2c.h"
+#include "hardware/esp32s2_soc.h"
+#include "hardware/esp32s2_system.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Command format */
+
+#define I2C_BASE_CMD(_cmd, _check_ack) (((_cmd) << 11) + \
+                                        ((_check_ack) << 8))
+
+#define I2C_SEND_CMD(_cmd, _check_ack, _bytes) (((_cmd) << 11) + \
+                                                ((_check_ack) << 8) + \
+                                                (_bytes))
+
+#define I2C_RECV_CMD(_cmd, _ack_val, _bytes) (((_cmd) << 11) + \
+                                              ((_ack_val) << 10) + \
+                                              (_bytes))

Review Comment:
   Optional
   ```suggestion
   #define I2C_BASE_CMD(_cmd, _check_ack) (((_cmd) << 11) | \
                                           ((_check_ack) << 8))
   
   #define I2C_SEND_CMD(_cmd, _check_ack, _bytes) (((_cmd) << 11) | \
                                                   ((_check_ack) << 8) | \
                                                   (_bytes))
   
   #define I2C_RECV_CMD(_cmd, _ack_val, _bytes) (((_cmd) << 11) | \
                                                 ((_ack_val) << 10) | \
                                                 (_bytes))
   ```



##########
arch/xtensa/src/esp32s2/esp32s2_i2c.c:
##########
@@ -0,0 +1,1702 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_i2c.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>
+
+#ifdef CONFIG_ESP32S2_I2C
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/clock.h>
+#include <nuttx/irq.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/semaphore.h>
+
+#include <arch/board/board.h>
+
+#include "esp32s2_gpio.h"
+#include "esp32s2_i2c.h"
+#include "esp32s2_irq.h"
+
+#include "xtensa.h"
+#include "hardware/esp32s2_gpio_sigmap.h"
+#include "hardware/esp32s2_i2c.h"
+#include "hardware/esp32s2_soc.h"
+#include "hardware/esp32s2_system.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Command format */
+
+#define I2C_BASE_CMD(_cmd, _check_ack) (((_cmd) << 11) + \
+                                        ((_check_ack) << 8))
+
+#define I2C_SEND_CMD(_cmd, _check_ack, _bytes) (((_cmd) << 11) + \
+                                                ((_check_ack) << 8) + \
+                                                (_bytes))
+
+#define I2C_RECV_CMD(_cmd, _ack_val, _bytes) (((_cmd) << 11) + \
+                                              ((_ack_val) << 10) + \
+                                              (_bytes))
+
+/* Helper */
+
+#ifdef CONFIG_I2C_POLLED
+#define TIMESPEC_TO_US(sec, nano)  ((sec * USEC_PER_SEC) + (nano / NSEC_PER_USEC))

Review Comment:
   ```suggestion
   #define TIMESPEC_TO_US(sec, nano)  ((sec) * USEC_PER_SEC + (nano) / NSEC_PER_USEC)
   ```



##########
arch/xtensa/src/esp32s2/esp32s2_i2c.c:
##########
@@ -0,0 +1,1702 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_i2c.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>
+
+#ifdef CONFIG_ESP32S2_I2C
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/clock.h>
+#include <nuttx/irq.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/semaphore.h>
+
+#include <arch/board/board.h>
+
+#include "esp32s2_gpio.h"
+#include "esp32s2_i2c.h"
+#include "esp32s2_irq.h"
+
+#include "xtensa.h"
+#include "hardware/esp32s2_gpio_sigmap.h"
+#include "hardware/esp32s2_i2c.h"
+#include "hardware/esp32s2_soc.h"
+#include "hardware/esp32s2_system.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Command format */
+
+#define I2C_BASE_CMD(_cmd, _check_ack) (((_cmd) << 11) + \
+                                        ((_check_ack) << 8))
+
+#define I2C_SEND_CMD(_cmd, _check_ack, _bytes) (((_cmd) << 11) + \
+                                                ((_check_ack) << 8) + \
+                                                (_bytes))
+
+#define I2C_RECV_CMD(_cmd, _ack_val, _bytes) (((_cmd) << 11) + \
+                                              ((_ack_val) << 10) + \
+                                              (_bytes))
+
+/* Helper */
+
+#ifdef CONFIG_I2C_POLLED
+#define TIMESPEC_TO_US(sec, nano)  ((sec * USEC_PER_SEC) + (nano / NSEC_PER_USEC))
+#endif
+
+#define ESP32S2_I2CTIMEOTICKS \
+    (SEC2TICK(CONFIG_ESP32S2_I2CTIMEOSEC) + MSEC2TICK(CONFIG_ESP32S2_I2CTIMEOMS))
+
+/* Default option */
+
+#define I2C_FIFO_SIZE (32)
+
+#define I2C_FILTER_CYC_NUM_DEF (7)
+
+#define I2C_CLK_FREQ_DEF (100 * 1000)
+
+#define I2C_INT_ERR_MASK (I2C_NACK_INT_ENA | \
+                          I2C_TIME_OUT_INT_ENA | \
+                          I2C_ARBITRATION_LOST_INT_ENA)
+
+#define I2C_SCL_CYC_NUM_DEF 9
+
+/* Access I2C FIFO Data registers via Peripheral Bus 2 (PeriBus2).
+ * Refer to ESP32-S2 Technical Reference Manual, section 3.3.5 for further
+ * details.
+ */
+
+#define FIFO_DATA_REG(i) (0x60013000 + (i) * 0x14000 + 0x001c)
+
+/* I2C event trace logic.
+ * NOTE: trace uses the internal, non-standard, low-level debug interface
+ * syslog() but does not require that any other debug is enabled.
+ */
+
+#ifndef CONFIG_I2C_TRACE
+#  define i2c_tracereset(p)
+#  define i2c_tracenew(p,s)
+#  define i2c_traceevent(p,e,a,s)
+#  define i2c_tracedump(p)
+#endif
+
+#ifndef CONFIG_I2C_NTRACE
+#  define CONFIG_I2C_NTRACE 32
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* I2C state */
+
+enum esp32s2_i2cstate_e
+{
+  I2CSTATE_IDLE = 0,
+  I2CSTATE_PROC,
+  I2CSTATE_STOP,
+#ifndef CONFIG_I2C_POLLED
+  I2CSTATE_FINISH,
+#endif
+  I2CSTATE_ERROR
+};
+
+/* I2C hardware command */
+
+enum i2c_opmode_e
+{
+  I2C_CMD_RESTART = 0,        /* I2C restart command */
+  I2C_CMD_WRITE,              /* I2C write command */
+  I2C_CMD_READ,               /* I2C read command */
+  I2C_CMD_STOP,               /* I2C stop command */
+  I2C_CMD_END                 /* I2C end command */
+};
+
+#ifdef CONFIG_I2C_TRACE
+
+/* Trace events */
+
+enum esp32s2_trace_e
+{
+  I2CEVENT_NONE = 0,      /* No events have occurred with this status */
+  I2CEVENT_SENDADDR,      /* Start/Master bit set and address sent, param = addr */
+  I2CEVENT_SENDBYTE,      /* Send byte, param = bytes */
+  I2CEVENT_RCVMODEEN,     /* Receive mode enabled, param = 0 */
+  I2CEVENT_RCVBYTE,       /* Read more dta, param = bytes */
+  I2CEVENT_STOP,          /* Last byte sten, send stop, param = length */
+  I2CEVENT_ERROR          /* Error occurred, param = 0 */
+};
+
+/* Trace data */
+
+struct esp32s2_trace_s
+{
+  uint32_t status;            /* I2C 32-bit SR status */
+  uint32_t count;             /* Interrupt count when status change */
+  enum esp32s2_trace_e event; /* Last event that occurred with this status */
+  uint32_t parm;              /* Parameter associated with the event */
+  clock_t time;               /* First of event or first status */
+};
+
+#endif /* CONFIG_I2C_TRACE */
+
+/* I2C Device hardware configuration */
+
+struct esp32s2_i2c_config_s
+{
+  uint32_t clk_freq;          /* Clock frequency */
+
+  uint8_t scl_pin;            /* GPIO configuration for SCL as SCL */
+  uint8_t sda_pin;            /* GPIO configuration for SDA as SDA */
+
+#ifndef CONFIG_I2C_POLLED
+  uint8_t periph;             /* Peripheral ID */
+  uint8_t irq;                /* Interrupt ID */
+#endif
+
+  uint32_t clk_bit;           /* Clock enable bit */
+  uint32_t rst_bit;           /* I2C reset bit */
+
+  uint32_t scl_insig;         /* I2C SCL input signal index */
+  uint32_t scl_outsig;        /* I2C SCL output signal index */
+
+  uint32_t sda_insig;         /* I2C SDA input signal index */
+  uint32_t sda_outsig;        /* I2C SDA output signal index */
+};
+
+/* I2C Device Private Data */
+
+struct esp32s2_i2c_priv_s
+{
+  const struct i2c_ops_s *ops; /* Standard I2C operations */
+
+  uint32_t id;                 /* I2C instance */
+
+  /* Port configuration */
+
+  const struct esp32s2_i2c_config_s *config;
+  int refs;                    /* Reference count */
+  sem_t sem_excl;              /* Mutual exclusion semaphore */
+
+#ifndef CONFIG_I2C_POLLED
+  sem_t sem_isr;               /* Interrupt wait semaphore */
+  int cpuint;                  /* CPU interrupt assigned to this I2C */
+#endif
+
+  /* I2C work state (see enum esp32s2_i2cstate_e) */
+
+  volatile enum esp32s2_i2cstate_e i2cstate;
+
+  struct i2c_msg_s *msgv;      /* Message list */
+
+  uint8_t msgid;               /* Current message ID */
+  ssize_t bytes;               /* Processed data bytes */
+
+  uint32_t error;              /* I2C transform error */
+
+  bool ready_read;             /* If I2C has read data */
+
+  uint32_t clk_freq;           /* Current I2C Clock frequency */
+
+#ifdef CONFIG_I2C_TRACE
+  /* I2C trace support */
+
+  int tndx;                    /* Trace array index */
+  clock_t start_time;          /* Time when the trace was started */
+
+  /* The actual trace data */
+
+  struct esp32s2_trace_s trace[CONFIG_I2C_NTRACE];
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void i2c_init_clock(struct esp32s2_i2c_priv_s *priv,
+                           uint32_t clock);
+static void i2c_init(struct esp32s2_i2c_priv_s *priv);
+static void i2c_deinit(struct esp32s2_i2c_priv_s *priv);
+static int i2c_transfer(struct i2c_master_s *dev, struct i2c_msg_s *msgs,
+                        int count);
+static inline void i2c_process(struct esp32s2_i2c_priv_s *priv,
+                               uint32_t status);
+static void i2c_sem_init(struct esp32s2_i2c_priv_s *priv);
+static void i2c_sem_destroy(struct esp32s2_i2c_priv_s *priv);
+static void i2c_sem_post(struct esp32s2_i2c_priv_s *priv);
+static int i2c_sem_wait(struct esp32s2_i2c_priv_s *priv);
+#ifndef CONFIG_I2C_POLLED
+static int i2c_sem_waitdone(struct esp32s2_i2c_priv_s *priv);
+#endif
+#ifdef CONFIG_I2C_POLLED
+static int i2c_polling_waitdone(struct esp32s2_i2c_priv_s *priv);
+#endif
+static void i2c_clear_bus(struct esp32s2_i2c_priv_s *priv);
+static void i2c_reset_fsmc(struct esp32s2_i2c_priv_s *priv);
+#ifdef CONFIG_I2C_RESET
+static int i2c_reset(struct i2c_master_s *dev);
+#endif
+
+#ifdef CONFIG_I2C_TRACE
+static void i2c_tracereset(struct esp32s2_i2c_priv_s *priv);
+static void i2c_tracenew(struct esp32s2_i2c_priv_s *priv, uint32_t status);
+static void i2c_traceevent(struct esp32s2_i2c_priv_s *priv,
+                           enum esp32s2_trace_e event,
+                           uint32_t parm,
+                           uint32_t status);
+static void i2c_tracedump(struct esp32s2_i2c_priv_s *priv);
+#endif /* CONFIG_I2C_TRACE */
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* I2C interface */
+
+static const struct i2c_ops_s g_esp32s2_i2c_ops =
+{
+  .transfer = i2c_transfer
+#ifdef CONFIG_I2C_RESET
+  , .reset  = i2c_reset
+#endif
+};
+
+/* I2C device structures */
+
+#ifdef CONFIG_ESP32S2_I2C0
+static const struct esp32s2_i2c_config_s g_esp32s2_i2c0_config =
+{
+  .clk_freq   = I2C_CLK_FREQ_DEF,
+  .scl_pin    = CONFIG_ESP32S2_I2C0_SCLPIN,
+  .sda_pin    = CONFIG_ESP32S2_I2C0_SDAPIN,
+#ifndef CONFIG_I2C_POLLED
+  .periph     = ESP32S2_PERIPH_I2C_EXT0,
+  .irq        = ESP32S2_IRQ_I2C_EXT0,
+#endif
+  .clk_bit    = SYSTEM_I2C_EXT0_CLK_EN,
+  .rst_bit    = SYSTEM_I2C_EXT0_RST,
+  .scl_insig  = I2CEXT0_SCL_IN_IDX,
+  .scl_outsig = I2CEXT0_SCL_OUT_IDX,
+  .sda_insig  = I2CEXT0_SDA_IN_IDX,
+  .sda_outsig = I2CEXT0_SDA_OUT_IDX
+};
+
+static struct esp32s2_i2c_priv_s g_esp32s2_i2c0_priv =
+{
+  .ops        = &g_esp32s2_i2c_ops,
+  .id         = ESP32S2_I2C0,
+  .config     = &g_esp32s2_i2c0_config,
+  .refs       = 0,
+  .i2cstate   = I2CSTATE_IDLE,
+  .msgv       = NULL,
+  .msgid      = 0,
+  .bytes      = 0,
+  .ready_read = false
+};
+#endif /* CONFIG_ESP32S2_I2C0 */
+
+#ifdef CONFIG_ESP32S2_I2C1
+static const struct esp32s2_i2c_config_s g_esp32s2_i2c1_config =
+{
+  .clk_freq   = I2C_CLK_FREQ_DEF,
+  .scl_pin    = CONFIG_ESP32S2_I2C1_SCLPIN,
+  .sda_pin    = CONFIG_ESP32S2_I2C1_SDAPIN,
+#ifndef CONFIG_I2C_POLLED
+  .periph     = ESP32S2_PERIPH_I2C_EXT1,
+  .irq        = ESP32S2_IRQ_I2C_EXT1,
+#endif
+  .clk_bit    = SYSTEM_I2C_EXT1_CLK_EN,
+  .rst_bit    = SYSTEM_I2C_EXT1_RST,
+  .scl_insig  = I2CEXT1_SCL_IN_IDX,
+  .scl_outsig = I2CEXT1_SCL_OUT_IDX,
+  .sda_insig  = I2CEXT1_SDA_IN_IDX,
+  .sda_outsig = I2CEXT1_SDA_OUT_IDX
+};
+
+static struct esp32s2_i2c_priv_s g_esp32s2_i2c1_priv =
+{
+  .ops        = &g_esp32s2_i2c_ops,
+  .id         = ESP32S2_I2C1,
+  .config     = &g_esp32s2_i2c1_config,
+  .refs       = 0,
+  .i2cstate   = I2CSTATE_IDLE,
+  .msgv       = NULL,
+  .msgid      = 0,
+  .bytes      = 0,
+  .ready_read = false
+};
+#endif /* CONFIG_ESP32S2_I2C1 */
+
+/* Trace events strings */
+
+#ifdef CONFIG_I2C_TRACE
+static const char *g_trace_names[] =
+{
+  "NONE      ",
+  "SENDADDR  ",
+  "SENDBYTE  ",
+  "RCVMODEEN ",
+  "RCVBYTE   ",
+  "STOP      ",
+  "ERROR     "
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: i2c_reset_fifo
+ *
+ * Description:
+ *   Reset I2C RX and TX hardware FIFO.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_reset_fifo(struct esp32s2_i2c_priv_s *priv)
+{
+  uint32_t bits = I2C_TX_FIFO_RST | I2C_RX_FIFO_RST;
+
+  modifyreg32(I2C_FIFO_CONF_REG(priv->id), 0, bits);
+  modifyreg32(I2C_FIFO_CONF_REG(priv->id), bits, 0);
+}
+
+/****************************************************************************
+ * Name: i2c_intr_enable
+ *
+ * Description:
+ *   Enable I2C interrupts.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_intr_enable(struct esp32s2_i2c_priv_s *priv)
+{
+  putreg32(UINT32_MAX, I2C_INT_CLR_REG(priv->id));
+
+  putreg32(I2C_TRANS_COMPLETE_INT_ENA | I2C_END_DETECT_INT_ENA |
+           I2C_INT_ERR_MASK, I2C_INT_ENA_REG(priv->id));
+}
+
+/****************************************************************************
+ * Name: i2c_intr_disable
+ *
+ * Description:
+ *   Disable I2C interrupts.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_intr_disable(struct esp32s2_i2c_priv_s *priv)
+{
+  putreg32(0, I2C_INT_ENA_REG(priv->id));
+
+  putreg32(UINT32_MAX, I2C_INT_CLR_REG(priv->id));
+}
+
+/****************************************************************************
+ * Name: i2c_sendstart
+ *
+ * Description:
+ *   Send I2C start signal.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_sendstart(struct esp32s2_i2c_priv_s *priv)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+
+  /* Write I2C command registers */
+
+  putreg32(I2C_BASE_CMD(I2C_CMD_RESTART, 0), I2C_COMD0_REG(priv->id));
+  putreg32(I2C_SEND_CMD(I2C_CMD_WRITE, 1, 1), I2C_COMD1_REG(priv->id));
+  putreg32(I2C_BASE_CMD(I2C_CMD_END, 0), I2C_COMD2_REG(priv->id));
+
+  /* Write data to FIFO register */
+
+  if ((msg->flags & I2C_M_READ) == 0)
+    {
+      putreg32(I2C_WRITEADDR8(msg->addr), FIFO_DATA_REG(priv->id));
+    }
+  else
+    {
+      putreg32(I2C_READADDR8(msg->addr), FIFO_DATA_REG(priv->id));
+    }
+
+  /* Enable I2C master TX interrupt */
+
+  i2c_intr_enable(priv);
+
+  /* Configure the I2C to trigger a transaction */
+
+  modifyreg32(I2C_CTR_REG(priv->id), 0, I2C_TRANS_START);
+}
+
+/****************************************************************************
+ * Name: i2c_senddata
+ *
+ * Description:
+ *   Send I2C data.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_senddata(struct esp32s2_i2c_priv_s *priv)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+  int n = msg->length - priv->bytes;
+
+  n = n < I2C_FIFO_SIZE ? n : I2C_FIFO_SIZE;
+
+  putreg32(I2C_SEND_CMD(I2C_CMD_WRITE, 1, n), I2C_COMD0_REG(priv->id));
+  putreg32(I2C_BASE_CMD(I2C_CMD_END, 0), I2C_COMD1_REG(priv->id));
+
+  for (int i = 0; i < n; i++)
+    {
+      putreg32(msg->buffer[priv->bytes + i], FIFO_DATA_REG(priv->id));
+    }
+
+  priv->bytes += n;
+
+  /* Enable I2C master TX interrupt */
+
+  i2c_intr_enable(priv);
+
+  /* Configure the I2C to trigger a transaction */
+
+  modifyreg32(I2C_CTR_REG(priv->id), 0, I2C_TRANS_START);
+}
+
+/****************************************************************************
+ * Name: i2c_recvdata
+ *
+ * Description:
+ *   Transfer data from the FIFO to the driver buffer.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_recvdata(struct esp32s2_i2c_priv_s *priv)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+  uint32_t cmd = getreg32(I2C_COMD0_REG(priv->id));
+  uint8_t n = cmd & 0xff;
+  uint32_t data = 0;
+
+  for (int i = 0; i < n; i++)
+    {
+      data = getreg32(FIFO_DATA_REG(priv->id));
+      msg->buffer[priv->bytes + i] = data & 0xff;
+    }
+
+  priv->bytes += n;
+}
+
+/****************************************************************************
+ * Name: i2c_startrecv
+ *
+ * Description:
+ *   Configure I2C to prepare receiving data and it will create an interrupt
+ *   to receive real data.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_startrecv(struct esp32s2_i2c_priv_s *priv)
+{
+  int ack_value;
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+  int n = msg->length - priv->bytes;
+
+  if (n > 1)
+    {
+      n -= 1;
+      n = n < I2C_FIFO_SIZE ? n : I2C_FIFO_SIZE;
+      ack_value = 0;
+    }
+  else
+    {
+      ack_value = 1;
+    }
+
+  putreg32(I2C_RECV_CMD(I2C_CMD_READ, ack_value, n),
+           I2C_COMD0_REG(priv->id));
+  putreg32(I2C_BASE_CMD(I2C_CMD_END, 0), I2C_COMD1_REG(priv->id));
+
+  /* Enable I2C master RX interrupt */
+
+  i2c_intr_enable(priv);
+
+  /* Configure the I2C to trigger a transaction */
+
+  modifyreg32(I2C_CTR_REG(priv->id), 0, I2C_TRANS_START);
+}
+
+/****************************************************************************
+ * Name: i2c_sendstop
+ *
+ * Description:
+ *   Send I2C STOP signal.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_sendstop(struct esp32s2_i2c_priv_s *priv)
+{
+  putreg32(I2C_BASE_CMD(I2C_CMD_STOP, 0), I2C_COMD0_REG(priv->id));
+
+  /* Enable I2C master TX interrupt */
+
+  i2c_intr_enable(priv);
+
+  /* Configure the I2C to trigger a transaction */
+
+  modifyreg32(I2C_CTR_REG(priv->id), 0, I2C_TRANS_START);
+}
+
+/****************************************************************************
+ * Name: i2c_init_clock
+ *
+ * Description:
+ *   Initialize I2C hardware clock.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *   bus_freq      - Clock frequency of the I2C bus in Hz.
+ *
+ ****************************************************************************/
+
+static void i2c_init_clock(struct esp32s2_i2c_priv_s *priv,
+                           uint32_t bus_freq)
+{
+  if (bus_freq == priv->clk_freq)
+    {
+      return;
+    }
+
+  uint32_t reg_value = 0;
+  uint32_t scl_low = 0;
+  uint32_t scl_high = 0;
+  uint32_t scl_wait_high = 0;
+  uint32_t sda_hold = 0;
+  uint32_t sda_sample = 0;
+  uint32_t setup = 0;
+  uint32_t hold = 0;
+  uint32_t timeout = 0;
+  uint32_t source_clk = APB_CLK_FREQ;
+  uint32_t half_cycle = source_clk / bus_freq / 2;
+
+  scl_low       = half_cycle - 1;
+  putreg32(scl_low, I2C_SCL_LOW_PERIOD_REG(priv->id));
+
+  /* By default, scl_wait_high must be less than scl_high */
+
+  scl_high      = half_cycle / 2 + 2;
+  scl_wait_high = half_cycle - scl_high;
+
+  reg_value     = VALUE_TO_FIELD(scl_high, I2C_SCL_HIGH_PERIOD);
+  reg_value    |= VALUE_TO_FIELD(scl_wait_high, I2C_SCL_WAIT_HIGH_PERIOD);
+  putreg32(reg_value, I2C_SCL_HIGH_PERIOD_REG(priv->id));
+
+  sda_hold      = half_cycle / 2;
+  putreg32(sda_hold, I2C_SDA_HOLD_REG(priv->id));
+
+  /* scl_wait_high < sda_sample <= scl_high */
+
+  sda_sample    = half_cycle / 2 - 1;
+  putreg32(sda_sample, I2C_SDA_SAMPLE_REG(priv->id));
+
+  setup         = half_cycle;
+  putreg32(setup, I2C_SCL_RSTART_SETUP_REG(priv->id));
+  putreg32(setup, I2C_SCL_STOP_SETUP_REG(priv->id));
+
+  hold          = half_cycle;
+  putreg32(hold - 1, I2C_SCL_START_HOLD_REG(priv->id));
+  putreg32(hold, I2C_SCL_STOP_HOLD_REG(priv->id));
+
+  /* By default, we set the timeout value to 10 bus cycles */
+
+  timeout       = half_cycle * 20;
+  reg_value     = I2C_TIME_OUT_EN;
+  reg_value    |= VALUE_TO_FIELD(timeout, I2C_TIME_OUT_VALUE);
+  putreg32(reg_value, I2C_TO_REG(priv->id));
+
+  /* Set current bus clock frequency */
+
+  priv->clk_freq = bus_freq;
+}
+
+/****************************************************************************
+ * Name: i2c_init
+ *
+ * Description:
+ *   Initialize I2C hardware.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_init(struct esp32s2_i2c_priv_s *priv)
+{
+  const struct esp32s2_i2c_config_s *config = priv->config;
+
+  esp32s2_gpiowrite(config->scl_pin, 1);
+  esp32s2_configgpio(config->scl_pin, INPUT_PULLUP | OUTPUT_OPEN_DRAIN);
+  esp32s2_gpio_matrix_out(config->scl_pin, config->scl_outsig, 0, 0);
+  esp32s2_gpio_matrix_in(config->scl_pin, config->scl_insig, 0);
+
+  esp32s2_gpiowrite(config->sda_pin, 1);
+  esp32s2_configgpio(config->sda_pin, INPUT_PULLUP | OUTPUT_OPEN_DRAIN);
+  esp32s2_gpio_matrix_out(config->sda_pin, config->sda_outsig, 0, 0);
+  esp32s2_gpio_matrix_in(config->sda_pin, config->sda_insig, 0);
+
+  /* Enable I2C hardware */
+
+  modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, 0, config->clk_bit);
+  modifyreg32(SYSTEM_PERIP_RST_EN0_REG, config->rst_bit, 0);
+
+  /* Disable I2C interrupts */
+
+  i2c_intr_disable(priv);
+
+  /* Initialize I2C Master */
+
+  putreg32(I2C_MS_MODE | I2C_CLK_EN | I2C_SCL_FORCE_OUT | I2C_SDA_FORCE_OUT,
+           I2C_CTR_REG(priv->id));
+
+  /* Set FIFO mode */
+
+  modifyreg32(I2C_FIFO_CONF_REG(priv->id), I2C_NONFIFO_EN, 0);
+
+  /* Ensure I2C data mode is set to MSB */
+
+  modifyreg32(I2C_CTR_REG(priv->id), I2C_TX_LSB_FIRST | I2C_RX_LSB_FIRST, 0);
+
+  i2c_reset_fifo(priv);
+
+  /* Configure the hardware filter function */
+
+  putreg32(I2C_SCL_FILTER_EN |
+             VALUE_TO_FIELD(I2C_FILTER_CYC_NUM_DEF, I2C_SCL_FILTER_THRES),
+           I2C_SCL_FILTER_CFG_REG(priv->id));
+  putreg32(I2C_SDA_FILTER_EN |
+             VALUE_TO_FIELD(I2C_FILTER_CYC_NUM_DEF, I2C_SDA_FILTER_THRES),
+           I2C_SDA_FILTER_CFG_REG(priv->id));
+
+  /* Set I2C source clock */
+
+  modifyreg32(I2C_CTR_REG(priv->id), 0, I2C_REF_ALWAYS_ON);
+
+  /* Configure I2C bus frequency */
+
+  i2c_init_clock(priv, config->clk_freq);
+}
+
+/****************************************************************************
+ * Name: i2c_deinit
+ *
+ * Description:
+ *   Disable I2C hardware.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_deinit(struct esp32s2_i2c_priv_s *priv)
+{
+  const struct esp32s2_i2c_config_s *config = priv->config;
+
+  priv->clk_freq = 0;
+
+  modifyreg32(SYSTEM_PERIP_RST_EN0_REG, 0, config->rst_bit);
+  modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, config->clk_bit, 0);
+}
+
+/****************************************************************************
+ * Name: i2c_reset_fsmc
+ *
+ * Description:
+ *   Reset I2C hardware state machine and registers.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_reset_fsmc(struct esp32s2_i2c_priv_s *priv)
+{
+  /* Reset FSM machine */
+
+  modifyreg32(I2C_CTR_REG(priv->id), 0, I2C_FSM_RST);
+
+  i2c_clear_bus(priv);
+}
+
+/****************************************************************************
+ * Name: i2c_sem_waitdone
+ *
+ * Description:
+ *   Wait for a transfer to complete.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success. A negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_I2C_POLLED
+static int i2c_sem_waitdone(struct esp32s2_i2c_priv_s *priv)
+{
+  /* Wait on ISR semaphore */
+
+  return nxsem_tickwait_uninterruptible(&priv->sem_isr,
+                                        ESP32S2_I2CTIMEOTICKS);
+}
+#endif
+
+/****************************************************************************
+ * Name: i2c_polling_waitdone
+ *
+ * Description:
+ *   Wait for a transfer to complete by polling status interrupt registers,
+ *   which indicates the status of the I2C operations. This function is only
+ *   used in polling driven mode.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ * Returned Values:
+ *   Zero (OK) is returned on successfull transfer. -ETIMEDOUT is returned
+ *   in case a transfer didn't finish within the timeout interval. And ERROR
+ *   is returned in case of any I2C error during the transfer has happened.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_POLLED
+static int i2c_polling_waitdone(struct esp32s2_i2c_priv_s *priv)
+{
+  int ret;
+  clock_t current;
+  clock_t timeout;
+  uint32_t status = 0;
+
+  /* Get the current absolute time and add an offset as timeout.
+   * Preferable to use monotonic, so in case the time changes,
+   * the time reference is kept, i.e., current time can't jump
+   * forward and backwards.
+   */
+
+  current = clock_systime_ticks();
+  timeout = current + SEC2TICK(10);
+
+  /* Loop while a transfer is in progress
+   * and an error didn't occur within the timeout
+   */
+
+  while ((current < timeout) && (priv->error == 0))
+    {
+      /* Check if any interrupt triggered, clear them
+       * process the operation.
+       */
+
+      status = getreg32(I2C_INT_STATUS_REG(priv->id));
+      if (status != 0)
+        {
+          /* Check if the stop operation ended. Don't use
+           * I2CSTATE_FINISH, because it is set before the stop
+           * signal really ends. This works for interrupts because
+           * the i2c_state is checked in the next interrupt when
+           * stop signal has concluded. This is not the case of
+           * polling.
+           */
+
+          if ((status & I2C_TRANS_COMPLETE_INT_ST) != 0)
+            {
+              putreg32(status, I2C_INT_CLR_REG(priv->id));
+              break;
+            }
+
+          putreg32(status, I2C_INT_CLR_REG(priv->id));
+          i2c_process(priv, status);
+        }
+
+      /* Update current time */
+
+      current = clock_systime_ticks();
+    }
+
+  /* Return a negated value in case of timeout, and in the other scenarios
+   * return a positive value.
+   * The transfer function will check the status of priv to check the other
+   * scenarios.
+   */
+
+  if (current >= timeout)
+    {
+      ret = -ETIMEDOUT;
+    }
+  else if (priv->error != 0)
+    {
+      ret = ERROR;
+    }
+  else
+    {
+      ret = OK;
+    }
+
+  /* Disable all interrupts */
+
+  i2c_intr_disable(priv);
+
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: i2c_sem_wait
+ *
+ * Description:
+ *   Take the exclusive access, waiting as necessary.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success. A negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int i2c_sem_wait(struct esp32s2_i2c_priv_s *priv)
+{
+  return nxsem_wait_uninterruptible(&priv->sem_excl);
+}
+
+/****************************************************************************
+ * Name: i2c_sem_post
+ *
+ * Description:
+ *   Release the mutual exclusion semaphore.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_sem_post(struct esp32s2_i2c_priv_s *priv)
+{
+  nxsem_post(&priv->sem_excl);
+}
+
+/****************************************************************************
+ * Name: i2c_sem_destroy
+ *
+ * Description:
+ *   Destroy semaphores.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_sem_destroy(struct esp32s2_i2c_priv_s *priv)
+{
+  nxsem_destroy(&priv->sem_excl);
+#ifndef CONFIG_I2C_POLLED
+  nxsem_destroy(&priv->sem_isr);
+#endif
+}
+
+/****************************************************************************
+ * Name: i2c_sem_init
+ *
+ * Description:
+ *   Initialize semaphores.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_sem_init(struct esp32s2_i2c_priv_s *priv)
+{
+  nxsem_init(&priv->sem_excl, 0, 1);
+
+  /* This semaphore is used for signaling and, hence, should not have
+   * priority inheritance enabled.
+   */
+
+#ifndef CONFIG_I2C_POLLED
+  nxsem_init(&priv->sem_isr, 0, 0);
+  nxsem_set_protocol(&priv->sem_isr, SEM_PRIO_NONE);
+#endif
+}
+
+/****************************************************************************
+ * Device Driver Operations
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: i2c_transfer
+ *
+ * Description:
+ *   Generic I2C transfer function.
+ *
+ * Parameters:
+ *   dev           - Device-specific state data
+ *   msgs          - A pointer to a set of message descriptors
+ *   count         - The number of transfers to perform
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success. A negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int i2c_transfer(struct i2c_master_s *dev, struct i2c_msg_s *msgs,
+                        int count)
+{
+  int ret = OK;
+  struct esp32s2_i2c_priv_s *priv = (struct esp32s2_i2c_priv_s *)dev;
+
+  DEBUGASSERT(count > 0);
+
+  ret = i2c_sem_wait(priv);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* If previous state is different than idle,
+   * reset the FSMC to the idle state.
+   */
+
+  if (priv->i2cstate != I2CSTATE_IDLE)
+    {
+      i2c_reset_fsmc(priv);
+      priv->i2cstate = I2CSTATE_IDLE;
+    }
+
+  /* Transfer the messages to the internal struct
+   * and loop count times to make all transfers.
+   */
+
+  priv->msgv = msgs;
+
+  for (int i = 0; i < count; i++)
+    {
+      /* Clear TX and RX FIFOs. */
+
+      i2c_reset_fifo(priv);
+
+      priv->bytes      = 0;
+      priv->msgid      = i;
+      priv->ready_read = false;
+      priv->error      = 0;
+      priv->i2cstate   = I2CSTATE_PROC;
+
+      /* Set the SCLK frequency for the current msg. */
+
+      i2c_init_clock(priv, msgs[i].frequency);
+
+      if ((msgs[i].flags & I2C_M_NOSTART) != 0)
+        {
+          i2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->bytes,
+                         getreg32(I2C_SR_REG(priv->id)));
+          i2c_senddata(priv);
+
+          if (priv->bytes == msgs[i].length)
+            {
+              if ((msgs[i].flags & I2C_M_NOSTOP) == 0)
+                {
+                  priv->i2cstate = I2CSTATE_STOP;
+                }
+#ifndef CONFIG_I2C_POLLED
+              else
+                {
+                  priv->i2cstate = I2CSTATE_FINISH;
+                }
+#endif
+            }
+        }
+      else
+        {
+          /* Reset I2C trace logic */
+
+          i2c_tracereset(priv);
+
+          i2c_traceevent(priv, I2CEVENT_SENDADDR, msgs[i].addr,
+                         getreg32(I2C_SR_REG(priv->id)));
+
+          i2c_sendstart(priv);
+        }
+
+#ifndef CONFIG_I2C_POLLED
+      if (i2c_sem_waitdone(priv) < 0)
+        {
+          /* Timed out - transfer was not completed within the timeout */
+
+          i2cerr("Message %" PRIu8 " timed out.\n", priv->msgid);
+          ret = -ETIMEDOUT;
+          break;
+        }
+      else
+        {
+          if (priv->error != 0)
+            {
+              /* An error occurred */
+
+              i2cerr("Transfer error %" PRIu32 "\n", priv->error);
+              ret = -EIO;
+              break;
+            }
+          else
+            {
+              /* Successful transfer, update the I2C state to idle */
+
+              priv->i2cstate = I2CSTATE_IDLE;
+              ret = OK;
+            }
+        }
+#else
+      ret = i2c_polling_waitdone(priv);
+      if (ret < 0)
+        {
+          if (ret == -ETIMEDOUT)
+            {
+              break;
+            }
+          else
+            {
+              ret = -EIO;
+              break;
+            }
+        }
+      else
+        {
+          /* Successful transfer, update the I2C state to idle */
+
+          priv->i2cstate = I2CSTATE_IDLE;
+          ret = OK;
+        }
+#endif
+
+      i2cinfo("Message %" PRIu8 " transfer complete.\n", priv->msgid);
+    }
+
+  /* Dump the trace result */
+
+  i2c_tracedump(priv);
+
+  i2c_sem_post(priv);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: i2c_clear_bus
+ *
+ * Description:
+ *   Clear I2C bus, when the slave is stuck in a deadlock and keeps pulling
+ *   the bus low, master can control the SCL bus to generate 9 CLKs.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_clear_bus(struct esp32s2_i2c_priv_s *priv)
+{
+  modifyreg32(I2C_SCL_SP_CONF_REG(priv->id),
+              I2C_SCL_RST_SLV_EN | I2C_SCL_RST_SLV_NUM_M,
+              VALUE_TO_FIELD(I2C_SCL_CYC_NUM_DEF, I2C_SCL_RST_SLV_NUM));
+
+  modifyreg32(I2C_SCL_SP_CONF_REG(priv->id), 0, I2C_SCL_RST_SLV_EN);
+}
+
+/****************************************************************************
+ * Name: i2c_reset
+ *
+ * Description:
+ *   Perform an I2C bus reset in an attempt to break loose stuck I2C devices.
+ *
+ * Input Parameters:
+ *   dev   - Device-specific state data
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_RESET
+static int i2c_reset(struct i2c_master_s *dev)
+{
+  irqstate_t flags;
+  struct esp32s2_i2c_priv_s *priv = (struct esp32s2_i2c_priv_s *)dev;
+
+  DEBUGASSERT(dev != NULL);
+  DEBUGASSERT(priv->refs > 0);
+
+  flags = enter_critical_section();
+
+  i2c_reset_fsmc(priv);
+
+  /* Clear bus */
+
+  i2c_clear_bus(priv);
+
+  priv->i2cstate   = I2CSTATE_IDLE;
+  priv->msgid      = 0;
+  priv->bytes      = 0;
+  priv->ready_read = false;
+
+  leave_critical_section(flags);
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: i2c_traceclear
+ *
+ * Description:
+ *   Set I2C trace fields to default value.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_TRACE
+static void i2c_traceclear(struct esp32s2_i2c_priv_s *priv)
+{
+  struct esp32s2_trace_s *trace = &priv->trace[priv->tndx];
+
+  trace->status = 0;
+  trace->count  = 0;
+  trace->event  = I2CEVENT_NONE;
+  trace->parm   = 0;
+  trace->time   = 0;
+}
+#endif /* CONFIG_I2C_TRACE */
+
+/****************************************************************************
+ * Name: i2c_tracereset
+ *
+ * Description:
+ *   Reset the trace info for a new data collection.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_TRACE
+static void i2c_tracereset(struct esp32s2_i2c_priv_s *priv)
+{
+  priv->tndx       = 0;
+  priv->start_time = clock_systime_ticks();
+  i2c_traceclear(priv);
+}
+#endif /* CONFIG_I2C_TRACE */
+
+/****************************************************************************
+ * Name: i2c_tracenew
+ *
+ * Description:
+ *   Create a new trace entry.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *   status        - Current value of I2C status register.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_TRACE
+static void i2c_tracenew(struct esp32s2_i2c_priv_s *priv, uint32_t status)
+{
+  struct esp32s2_trace_s *trace = &priv->trace[priv->tndx];
+
+  /* Check if the current entry is already initialized or if its status had
+   * already changed
+   */
+
+  if (trace->count == 0 || status != trace->status)
+    {
+      /* Check whether the status changed */
+
+      if (trace->count != 0)
+        {
+          /* Bump up the trace index (unless we are out of trace entries) */
+
+          if (priv->tndx >= (CONFIG_I2C_NTRACE - 1))
+            {
+              i2cerr("ERROR: Trace table overflow\n");
+              return;
+            }
+
+          priv->tndx++;
+          trace = &priv->trace[priv->tndx];
+        }
+
+      /* Initialize the new trace entry */
+
+      i2c_traceclear(priv);
+      trace->status = status;
+      trace->count  = 1;
+      trace->time   = clock_systime_ticks();
+    }
+  else
+    {
+      /* Just increment the count of times that we have seen this status */
+
+      trace->count++;
+    }
+}
+#endif /* CONFIG_I2C_TRACE */
+
+/****************************************************************************
+ * Name: i2c_traceevent
+ *
+ * Description:
+ *   Record a new trace event.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *   event         - Event to be recorded on the trace.
+ *   parm          - Parameter associated with the event.
+ *   status        - Current value of I2C status register.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_TRACE
+static void i2c_traceevent(struct esp32s2_i2c_priv_s *priv,
+                           enum esp32s2_trace_e event,
+                           uint32_t parm,
+                           uint32_t status)
+{
+  /* Check for new trace setup */
+
+  i2c_tracenew(priv, status);
+
+  if (event != I2CEVENT_NONE)
+    {
+      struct esp32s2_trace_s *trace = &priv->trace[priv->tndx];
+
+      /* Initialize the new trace entry */
+
+      trace->event  = event;
+      trace->parm   = parm;
+
+      /* Bump up the trace index (unless we are out of trace entries) */
+
+      if (priv->tndx >= (CONFIG_I2C_NTRACE - 1))
+        {
+          i2cerr("ERROR: Trace table overflow\n");
+          return;
+        }
+
+      priv->tndx++;
+      i2c_traceclear(priv);
+    }
+}
+#endif /* CONFIG_I2C_TRACE */
+
+/****************************************************************************
+ * Name: i2c_tracedump
+ *
+ * Description:
+ *   Dump the trace results.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_TRACE
+static void i2c_tracedump(struct esp32s2_i2c_priv_s *priv)
+{
+  syslog(LOG_DEBUG, "Elapsed time: %" PRIu32 "\n",
+         clock_systime_ticks() - priv->start_time);
+
+  for (int i = 0; i < priv->tndx; i++)
+    {
+      struct esp32s2_trace_s *trace = &priv->trace[i];
+      syslog(LOG_DEBUG,
+             "%2d. STATUS: %08" PRIx32 " COUNT: %3" PRIu32 " EVENT: %s(%2d)"
+             " PARM: %08" PRIx32 " TIME: %" PRIu32 "\n",
+             i + 1, trace->status, trace->count, g_trace_names[trace->event],
+             trace->event, trace->parm, trace->time - priv->start_time);
+    }
+}
+#endif /* CONFIG_I2C_TRACE */
+
+/****************************************************************************
+ * Name: i2c_irq
+ *
+ * Description:
+ *   This is the common I2C interrupt handler. It will be invoked when an
+ *   interrupt is received on the device.
+ *
+ * Parameters:
+ *   cpuint        - CPU interrupt index
+ *   context       - Context data from the ISR
+ *   arg           - Opaque pointer to the internal driver state structure.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success. A negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_I2C_POLLED
+static int i2c_irq(int cpuint, void *context, void *arg)
+{
+  struct esp32s2_i2c_priv_s *priv = (struct esp32s2_i2c_priv_s *)arg;
+
+  /* Get the interrupt status and clear the interrupts that
+   * triggered.
+   */
+
+  uint32_t irq_status = getreg32(I2C_INT_STATUS_REG(priv->id));
+  putreg32(irq_status, I2C_INT_CLR_REG(priv->id));
+
+  i2c_process(priv, irq_status);
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: i2c_process
+ *
+ * Description:
+ *   This routine manages the transfer. It's called after some specific
+ *   commands from the I2C controller are executed or in case of errors.
+ *   It's responsible for writing/reading operations and transferring data
+ *   from/to FIFO.
+ *   It's called in the interrupt and polled driven mode.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *   status        - The current interrupt status register.
+ *
+ ****************************************************************************/
+
+static void i2c_process(struct esp32s2_i2c_priv_s *priv, uint32_t status)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+
+  /* Check for any errors */
+
+  if ((I2C_INT_ERR_MASK & status) != 0)
+    {
+      /* Save the errors, register the error event, disable interrupts
+       * and release the semaphore to conclude the transfer.
+       */
+
+      priv->error = status & I2C_INT_ERR_MASK;
+      priv->i2cstate = I2CSTATE_ERROR;
+      i2c_traceevent(priv, I2CEVENT_ERROR, priv->error,
+                     getreg32(I2C_SR_REG(priv->id)));
+      i2c_intr_disable(priv);
+#ifndef CONFIG_I2C_POLLED
+      nxsem_post(&priv->sem_isr);
+#endif
+    }
+  else /* If no error */
+    {
+      /* If a transfer has just initialized */
+
+      if (priv->i2cstate == I2CSTATE_PROC)
+        {
+          /* Check the flags to perform a read or write operation */
+
+          if ((msg->flags & I2C_M_READ) != 0)
+            {
+              /* RX FIFO has available data */
+
+              if (priv->ready_read)
+                {
+                  i2c_traceevent(priv, I2CEVENT_RCVBYTE, priv->bytes,
+                                 getreg32(I2C_SR_REG(priv->id)));
+                  i2c_recvdata(priv);
+
+                  priv->ready_read = false;
+                }
+
+              /* Received all data. Finish the transaction
+               * and update the I2C state.
+               */
+
+              if (priv->bytes == msg->length)
+                {
+                  i2c_traceevent(priv, I2CEVENT_STOP, msg->length,
+                                 getreg32(I2C_SR_REG(priv->id)));
+                  i2c_sendstop(priv);
+#ifndef CONFIG_I2C_POLLED
+                  priv->i2cstate = I2CSTATE_FINISH;
+#endif
+                }
+              else /* Start a receive operation */
+                {
+                  i2c_traceevent(priv, I2CEVENT_RCVMODEEN, 0,
+                                 getreg32(I2C_SR_REG(priv->id)));
+                  i2c_startrecv(priv);
+
+                  priv->ready_read = true;
+                }
+            }
+          else /* Write operation */
+            {
+              i2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->bytes,
+                             getreg32(I2C_SR_REG(priv->id)));
+              i2c_senddata(priv);
+
+              /* Finally sent the entire message. Update the I2C state to
+               * send a stop signal in the next interrupt.
+               */
+
+              if (priv->bytes == msg->length)
+                {
+                  if ((msg->flags & I2C_M_NOSTOP) == 0)
+                    {
+                      priv->i2cstate = I2CSTATE_STOP;
+                    }
+#ifndef CONFIG_I2C_POLLED
+                  else
+                    {
+                      priv->i2cstate = I2CSTATE_FINISH;
+                    }
+#endif
+                }
+            }
+        }
+      else if (priv->i2cstate == I2CSTATE_STOP)
+        {
+          /* Transmitted all data. Finish the transaction sending a stop
+           * and update the I2C state.
+           */
+
+          i2c_traceevent(priv, I2CEVENT_STOP, msg->length,
+                         getreg32(I2C_SR_REG(priv->id)));
+          i2c_sendstop(priv);
+#ifndef CONFIG_I2C_POLLED
+          priv->i2cstate = I2CSTATE_FINISH;
+#endif
+        }
+#ifndef CONFIG_I2C_POLLED
+      else if (priv->i2cstate == I2CSTATE_FINISH)
+        {
+          /* Disable all interrupts and release the semaphore */
+
+          i2c_intr_disable(priv);
+          nxsem_post(&priv->sem_isr);
+        }
+#endif
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s2_i2cbus_initialize
+ *
+ * Description:
+ *   Initialize the selected I2C port. And return a pointer to an unique
+ *   instance of struct i2c_master_s. This function may be called to obtain
+ *   multiple instances of the interface, each of which may be set up with a
+ *   different frequency and slave address.
+ *
+ * Parameters:
+ *   port          - Port number of the I2C interface to be initialized.
+ *
+ * Returned Value:
+ *   Pointer to valid I2C device structure is returned on success.
+ *   A NULL pointer is returned on failure.
+ *
+ ****************************************************************************/
+
+struct i2c_master_s *esp32s2_i2cbus_initialize(int port)
+{
+  irqstate_t flags;
+  struct esp32s2_i2c_priv_s *priv;
+#ifndef CONFIG_I2C_POLLED
+  const struct esp32s2_i2c_config_s *config;
+  int ret;
+#endif
+
+  switch (port)
+    {
+#ifdef CONFIG_ESP32S2_I2C0
+    case ESP32S2_I2C0:
+      priv = &g_esp32s2_i2c0_priv;
+      break;
+#endif
+#ifdef CONFIG_ESP32S2_I2C1
+    case ESP32S2_I2C1:
+      priv = &g_esp32s2_i2c1_priv;
+      break;
+#endif
+    default:
+      return NULL;

Review Comment:
   please add 2 spaces for case block



##########
arch/xtensa/src/esp32s2/esp32s2_i2c.c:
##########
@@ -0,0 +1,1702 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_i2c.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>
+
+#ifdef CONFIG_ESP32S2_I2C
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/clock.h>
+#include <nuttx/irq.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/semaphore.h>
+
+#include <arch/board/board.h>
+
+#include "esp32s2_gpio.h"
+#include "esp32s2_i2c.h"
+#include "esp32s2_irq.h"
+
+#include "xtensa.h"
+#include "hardware/esp32s2_gpio_sigmap.h"
+#include "hardware/esp32s2_i2c.h"
+#include "hardware/esp32s2_soc.h"
+#include "hardware/esp32s2_system.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Command format */
+
+#define I2C_BASE_CMD(_cmd, _check_ack) (((_cmd) << 11) + \
+                                        ((_check_ack) << 8))
+
+#define I2C_SEND_CMD(_cmd, _check_ack, _bytes) (((_cmd) << 11) + \
+                                                ((_check_ack) << 8) + \
+                                                (_bytes))
+
+#define I2C_RECV_CMD(_cmd, _ack_val, _bytes) (((_cmd) << 11) + \
+                                              ((_ack_val) << 10) + \
+                                              (_bytes))
+
+/* Helper */
+
+#ifdef CONFIG_I2C_POLLED
+#define TIMESPEC_TO_US(sec, nano)  ((sec * USEC_PER_SEC) + (nano / NSEC_PER_USEC))
+#endif
+
+#define ESP32S2_I2CTIMEOTICKS \
+    (SEC2TICK(CONFIG_ESP32S2_I2CTIMEOSEC) + MSEC2TICK(CONFIG_ESP32S2_I2CTIMEOMS))
+
+/* Default option */
+
+#define I2C_FIFO_SIZE (32)
+
+#define I2C_FILTER_CYC_NUM_DEF (7)
+
+#define I2C_CLK_FREQ_DEF (100 * 1000)
+
+#define I2C_INT_ERR_MASK (I2C_NACK_INT_ENA | \
+                          I2C_TIME_OUT_INT_ENA | \
+                          I2C_ARBITRATION_LOST_INT_ENA)
+
+#define I2C_SCL_CYC_NUM_DEF 9
+
+/* Access I2C FIFO Data registers via Peripheral Bus 2 (PeriBus2).
+ * Refer to ESP32-S2 Technical Reference Manual, section 3.3.5 for further
+ * details.
+ */
+
+#define FIFO_DATA_REG(i) (0x60013000 + (i) * 0x14000 + 0x001c)
+
+/* I2C event trace logic.
+ * NOTE: trace uses the internal, non-standard, low-level debug interface
+ * syslog() but does not require that any other debug is enabled.
+ */
+
+#ifndef CONFIG_I2C_TRACE
+#  define i2c_tracereset(p)
+#  define i2c_tracenew(p,s)
+#  define i2c_traceevent(p,e,a,s)
+#  define i2c_tracedump(p)
+#endif
+
+#ifndef CONFIG_I2C_NTRACE
+#  define CONFIG_I2C_NTRACE 32
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* I2C state */
+
+enum esp32s2_i2cstate_e
+{
+  I2CSTATE_IDLE = 0,
+  I2CSTATE_PROC,
+  I2CSTATE_STOP,
+#ifndef CONFIG_I2C_POLLED
+  I2CSTATE_FINISH,
+#endif
+  I2CSTATE_ERROR
+};
+
+/* I2C hardware command */
+
+enum i2c_opmode_e
+{
+  I2C_CMD_RESTART = 0,        /* I2C restart command */
+  I2C_CMD_WRITE,              /* I2C write command */
+  I2C_CMD_READ,               /* I2C read command */
+  I2C_CMD_STOP,               /* I2C stop command */
+  I2C_CMD_END                 /* I2C end command */
+};
+
+#ifdef CONFIG_I2C_TRACE
+
+/* Trace events */
+
+enum esp32s2_trace_e
+{
+  I2CEVENT_NONE = 0,      /* No events have occurred with this status */
+  I2CEVENT_SENDADDR,      /* Start/Master bit set and address sent, param = addr */
+  I2CEVENT_SENDBYTE,      /* Send byte, param = bytes */
+  I2CEVENT_RCVMODEEN,     /* Receive mode enabled, param = 0 */
+  I2CEVENT_RCVBYTE,       /* Read more dta, param = bytes */
+  I2CEVENT_STOP,          /* Last byte sten, send stop, param = length */
+  I2CEVENT_ERROR          /* Error occurred, param = 0 */
+};
+
+/* Trace data */
+
+struct esp32s2_trace_s
+{
+  uint32_t status;            /* I2C 32-bit SR status */
+  uint32_t count;             /* Interrupt count when status change */
+  enum esp32s2_trace_e event; /* Last event that occurred with this status */
+  uint32_t parm;              /* Parameter associated with the event */
+  clock_t time;               /* First of event or first status */
+};
+
+#endif /* CONFIG_I2C_TRACE */
+
+/* I2C Device hardware configuration */
+
+struct esp32s2_i2c_config_s
+{
+  uint32_t clk_freq;          /* Clock frequency */
+
+  uint8_t scl_pin;            /* GPIO configuration for SCL as SCL */
+  uint8_t sda_pin;            /* GPIO configuration for SDA as SDA */
+
+#ifndef CONFIG_I2C_POLLED
+  uint8_t periph;             /* Peripheral ID */
+  uint8_t irq;                /* Interrupt ID */
+#endif
+
+  uint32_t clk_bit;           /* Clock enable bit */
+  uint32_t rst_bit;           /* I2C reset bit */
+
+  uint32_t scl_insig;         /* I2C SCL input signal index */
+  uint32_t scl_outsig;        /* I2C SCL output signal index */
+
+  uint32_t sda_insig;         /* I2C SDA input signal index */
+  uint32_t sda_outsig;        /* I2C SDA output signal index */
+};
+
+/* I2C Device Private Data */
+
+struct esp32s2_i2c_priv_s
+{
+  const struct i2c_ops_s *ops; /* Standard I2C operations */
+
+  uint32_t id;                 /* I2C instance */
+
+  /* Port configuration */
+
+  const struct esp32s2_i2c_config_s *config;
+  int refs;                    /* Reference count */
+  sem_t sem_excl;              /* Mutual exclusion semaphore */
+
+#ifndef CONFIG_I2C_POLLED
+  sem_t sem_isr;               /* Interrupt wait semaphore */
+  int cpuint;                  /* CPU interrupt assigned to this I2C */
+#endif
+
+  /* I2C work state (see enum esp32s2_i2cstate_e) */
+
+  volatile enum esp32s2_i2cstate_e i2cstate;
+
+  struct i2c_msg_s *msgv;      /* Message list */
+
+  uint8_t msgid;               /* Current message ID */
+  ssize_t bytes;               /* Processed data bytes */
+
+  uint32_t error;              /* I2C transform error */
+
+  bool ready_read;             /* If I2C has read data */
+
+  uint32_t clk_freq;           /* Current I2C Clock frequency */
+
+#ifdef CONFIG_I2C_TRACE
+  /* I2C trace support */
+
+  int tndx;                    /* Trace array index */
+  clock_t start_time;          /* Time when the trace was started */
+
+  /* The actual trace data */
+
+  struct esp32s2_trace_s trace[CONFIG_I2C_NTRACE];
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void i2c_init_clock(struct esp32s2_i2c_priv_s *priv,
+                           uint32_t clock);
+static void i2c_init(struct esp32s2_i2c_priv_s *priv);
+static void i2c_deinit(struct esp32s2_i2c_priv_s *priv);
+static int i2c_transfer(struct i2c_master_s *dev, struct i2c_msg_s *msgs,
+                        int count);
+static inline void i2c_process(struct esp32s2_i2c_priv_s *priv,
+                               uint32_t status);
+static void i2c_sem_init(struct esp32s2_i2c_priv_s *priv);
+static void i2c_sem_destroy(struct esp32s2_i2c_priv_s *priv);
+static void i2c_sem_post(struct esp32s2_i2c_priv_s *priv);
+static int i2c_sem_wait(struct esp32s2_i2c_priv_s *priv);
+#ifndef CONFIG_I2C_POLLED
+static int i2c_sem_waitdone(struct esp32s2_i2c_priv_s *priv);
+#endif
+#ifdef CONFIG_I2C_POLLED
+static int i2c_polling_waitdone(struct esp32s2_i2c_priv_s *priv);
+#endif
+static void i2c_clear_bus(struct esp32s2_i2c_priv_s *priv);
+static void i2c_reset_fsmc(struct esp32s2_i2c_priv_s *priv);
+#ifdef CONFIG_I2C_RESET
+static int i2c_reset(struct i2c_master_s *dev);
+#endif
+
+#ifdef CONFIG_I2C_TRACE
+static void i2c_tracereset(struct esp32s2_i2c_priv_s *priv);
+static void i2c_tracenew(struct esp32s2_i2c_priv_s *priv, uint32_t status);
+static void i2c_traceevent(struct esp32s2_i2c_priv_s *priv,
+                           enum esp32s2_trace_e event,
+                           uint32_t parm,
+                           uint32_t status);
+static void i2c_tracedump(struct esp32s2_i2c_priv_s *priv);
+#endif /* CONFIG_I2C_TRACE */
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* I2C interface */
+
+static const struct i2c_ops_s g_esp32s2_i2c_ops =
+{
+  .transfer = i2c_transfer
+#ifdef CONFIG_I2C_RESET
+  , .reset  = i2c_reset
+#endif
+};
+
+/* I2C device structures */
+
+#ifdef CONFIG_ESP32S2_I2C0
+static const struct esp32s2_i2c_config_s g_esp32s2_i2c0_config =
+{
+  .clk_freq   = I2C_CLK_FREQ_DEF,
+  .scl_pin    = CONFIG_ESP32S2_I2C0_SCLPIN,
+  .sda_pin    = CONFIG_ESP32S2_I2C0_SDAPIN,
+#ifndef CONFIG_I2C_POLLED
+  .periph     = ESP32S2_PERIPH_I2C_EXT0,
+  .irq        = ESP32S2_IRQ_I2C_EXT0,
+#endif
+  .clk_bit    = SYSTEM_I2C_EXT0_CLK_EN,
+  .rst_bit    = SYSTEM_I2C_EXT0_RST,
+  .scl_insig  = I2CEXT0_SCL_IN_IDX,
+  .scl_outsig = I2CEXT0_SCL_OUT_IDX,
+  .sda_insig  = I2CEXT0_SDA_IN_IDX,
+  .sda_outsig = I2CEXT0_SDA_OUT_IDX
+};
+
+static struct esp32s2_i2c_priv_s g_esp32s2_i2c0_priv =
+{
+  .ops        = &g_esp32s2_i2c_ops,
+  .id         = ESP32S2_I2C0,
+  .config     = &g_esp32s2_i2c0_config,
+  .refs       = 0,
+  .i2cstate   = I2CSTATE_IDLE,
+  .msgv       = NULL,
+  .msgid      = 0,
+  .bytes      = 0,
+  .ready_read = false
+};
+#endif /* CONFIG_ESP32S2_I2C0 */
+
+#ifdef CONFIG_ESP32S2_I2C1
+static const struct esp32s2_i2c_config_s g_esp32s2_i2c1_config =
+{
+  .clk_freq   = I2C_CLK_FREQ_DEF,
+  .scl_pin    = CONFIG_ESP32S2_I2C1_SCLPIN,
+  .sda_pin    = CONFIG_ESP32S2_I2C1_SDAPIN,
+#ifndef CONFIG_I2C_POLLED
+  .periph     = ESP32S2_PERIPH_I2C_EXT1,
+  .irq        = ESP32S2_IRQ_I2C_EXT1,
+#endif
+  .clk_bit    = SYSTEM_I2C_EXT1_CLK_EN,
+  .rst_bit    = SYSTEM_I2C_EXT1_RST,
+  .scl_insig  = I2CEXT1_SCL_IN_IDX,
+  .scl_outsig = I2CEXT1_SCL_OUT_IDX,
+  .sda_insig  = I2CEXT1_SDA_IN_IDX,
+  .sda_outsig = I2CEXT1_SDA_OUT_IDX
+};
+
+static struct esp32s2_i2c_priv_s g_esp32s2_i2c1_priv =
+{
+  .ops        = &g_esp32s2_i2c_ops,
+  .id         = ESP32S2_I2C1,
+  .config     = &g_esp32s2_i2c1_config,
+  .refs       = 0,
+  .i2cstate   = I2CSTATE_IDLE,
+  .msgv       = NULL,
+  .msgid      = 0,
+  .bytes      = 0,
+  .ready_read = false
+};
+#endif /* CONFIG_ESP32S2_I2C1 */
+
+/* Trace events strings */
+
+#ifdef CONFIG_I2C_TRACE
+static const char *g_trace_names[] =
+{
+  "NONE      ",
+  "SENDADDR  ",
+  "SENDBYTE  ",
+  "RCVMODEEN ",
+  "RCVBYTE   ",
+  "STOP      ",
+  "ERROR     "
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: i2c_reset_fifo
+ *
+ * Description:
+ *   Reset I2C RX and TX hardware FIFO.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_reset_fifo(struct esp32s2_i2c_priv_s *priv)
+{
+  uint32_t bits = I2C_TX_FIFO_RST | I2C_RX_FIFO_RST;
+
+  modifyreg32(I2C_FIFO_CONF_REG(priv->id), 0, bits);
+  modifyreg32(I2C_FIFO_CONF_REG(priv->id), bits, 0);
+}
+
+/****************************************************************************
+ * Name: i2c_intr_enable
+ *
+ * Description:
+ *   Enable I2C interrupts.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_intr_enable(struct esp32s2_i2c_priv_s *priv)
+{
+  putreg32(UINT32_MAX, I2C_INT_CLR_REG(priv->id));
+
+  putreg32(I2C_TRANS_COMPLETE_INT_ENA | I2C_END_DETECT_INT_ENA |
+           I2C_INT_ERR_MASK, I2C_INT_ENA_REG(priv->id));
+}
+
+/****************************************************************************
+ * Name: i2c_intr_disable
+ *
+ * Description:
+ *   Disable I2C interrupts.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_intr_disable(struct esp32s2_i2c_priv_s *priv)
+{
+  putreg32(0, I2C_INT_ENA_REG(priv->id));
+
+  putreg32(UINT32_MAX, I2C_INT_CLR_REG(priv->id));
+}
+
+/****************************************************************************
+ * Name: i2c_sendstart
+ *
+ * Description:
+ *   Send I2C start signal.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_sendstart(struct esp32s2_i2c_priv_s *priv)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+
+  /* Write I2C command registers */
+
+  putreg32(I2C_BASE_CMD(I2C_CMD_RESTART, 0), I2C_COMD0_REG(priv->id));
+  putreg32(I2C_SEND_CMD(I2C_CMD_WRITE, 1, 1), I2C_COMD1_REG(priv->id));
+  putreg32(I2C_BASE_CMD(I2C_CMD_END, 0), I2C_COMD2_REG(priv->id));
+
+  /* Write data to FIFO register */
+
+  if ((msg->flags & I2C_M_READ) == 0)
+    {
+      putreg32(I2C_WRITEADDR8(msg->addr), FIFO_DATA_REG(priv->id));
+    }
+  else
+    {
+      putreg32(I2C_READADDR8(msg->addr), FIFO_DATA_REG(priv->id));
+    }
+
+  /* Enable I2C master TX interrupt */
+
+  i2c_intr_enable(priv);
+
+  /* Configure the I2C to trigger a transaction */
+
+  modifyreg32(I2C_CTR_REG(priv->id), 0, I2C_TRANS_START);
+}
+
+/****************************************************************************
+ * Name: i2c_senddata
+ *
+ * Description:
+ *   Send I2C data.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_senddata(struct esp32s2_i2c_priv_s *priv)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+  int n = msg->length - priv->bytes;
+
+  n = n < I2C_FIFO_SIZE ? n : I2C_FIFO_SIZE;
+
+  putreg32(I2C_SEND_CMD(I2C_CMD_WRITE, 1, n), I2C_COMD0_REG(priv->id));
+  putreg32(I2C_BASE_CMD(I2C_CMD_END, 0), I2C_COMD1_REG(priv->id));
+
+  for (int i = 0; i < n; i++)
+    {
+      putreg32(msg->buffer[priv->bytes + i], FIFO_DATA_REG(priv->id));
+    }
+
+  priv->bytes += n;
+
+  /* Enable I2C master TX interrupt */
+
+  i2c_intr_enable(priv);
+
+  /* Configure the I2C to trigger a transaction */
+
+  modifyreg32(I2C_CTR_REG(priv->id), 0, I2C_TRANS_START);
+}
+
+/****************************************************************************
+ * Name: i2c_recvdata
+ *
+ * Description:
+ *   Transfer data from the FIFO to the driver buffer.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_recvdata(struct esp32s2_i2c_priv_s *priv)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+  uint32_t cmd = getreg32(I2C_COMD0_REG(priv->id));
+  uint8_t n = cmd & 0xff;
+  uint32_t data = 0;
+
+  for (int i = 0; i < n; i++)
+    {
+      data = getreg32(FIFO_DATA_REG(priv->id));
+      msg->buffer[priv->bytes + i] = data & 0xff;
+    }
+
+  priv->bytes += n;
+}
+
+/****************************************************************************
+ * Name: i2c_startrecv
+ *
+ * Description:
+ *   Configure I2C to prepare receiving data and it will create an interrupt
+ *   to receive real data.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_startrecv(struct esp32s2_i2c_priv_s *priv)
+{
+  int ack_value;
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+  int n = msg->length - priv->bytes;
+
+  if (n > 1)
+    {
+      n -= 1;
+      n = n < I2C_FIFO_SIZE ? n : I2C_FIFO_SIZE;
+      ack_value = 0;
+    }
+  else
+    {
+      ack_value = 1;
+    }
+
+  putreg32(I2C_RECV_CMD(I2C_CMD_READ, ack_value, n),
+           I2C_COMD0_REG(priv->id));
+  putreg32(I2C_BASE_CMD(I2C_CMD_END, 0), I2C_COMD1_REG(priv->id));
+
+  /* Enable I2C master RX interrupt */
+
+  i2c_intr_enable(priv);
+
+  /* Configure the I2C to trigger a transaction */
+
+  modifyreg32(I2C_CTR_REG(priv->id), 0, I2C_TRANS_START);
+}
+
+/****************************************************************************
+ * Name: i2c_sendstop
+ *
+ * Description:
+ *   Send I2C STOP signal.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_sendstop(struct esp32s2_i2c_priv_s *priv)
+{
+  putreg32(I2C_BASE_CMD(I2C_CMD_STOP, 0), I2C_COMD0_REG(priv->id));
+
+  /* Enable I2C master TX interrupt */
+
+  i2c_intr_enable(priv);
+
+  /* Configure the I2C to trigger a transaction */
+
+  modifyreg32(I2C_CTR_REG(priv->id), 0, I2C_TRANS_START);
+}
+
+/****************************************************************************
+ * Name: i2c_init_clock
+ *
+ * Description:
+ *   Initialize I2C hardware clock.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *   bus_freq      - Clock frequency of the I2C bus in Hz.
+ *
+ ****************************************************************************/
+
+static void i2c_init_clock(struct esp32s2_i2c_priv_s *priv,
+                           uint32_t bus_freq)
+{
+  if (bus_freq == priv->clk_freq)
+    {
+      return;
+    }
+
+  uint32_t reg_value = 0;
+  uint32_t scl_low = 0;
+  uint32_t scl_high = 0;
+  uint32_t scl_wait_high = 0;
+  uint32_t sda_hold = 0;
+  uint32_t sda_sample = 0;
+  uint32_t setup = 0;
+  uint32_t hold = 0;
+  uint32_t timeout = 0;
+  uint32_t source_clk = APB_CLK_FREQ;
+  uint32_t half_cycle = source_clk / bus_freq / 2;
+
+  scl_low       = half_cycle - 1;
+  putreg32(scl_low, I2C_SCL_LOW_PERIOD_REG(priv->id));
+
+  /* By default, scl_wait_high must be less than scl_high */
+
+  scl_high      = half_cycle / 2 + 2;
+  scl_wait_high = half_cycle - scl_high;
+
+  reg_value     = VALUE_TO_FIELD(scl_high, I2C_SCL_HIGH_PERIOD);
+  reg_value    |= VALUE_TO_FIELD(scl_wait_high, I2C_SCL_WAIT_HIGH_PERIOD);
+  putreg32(reg_value, I2C_SCL_HIGH_PERIOD_REG(priv->id));
+
+  sda_hold      = half_cycle / 2;
+  putreg32(sda_hold, I2C_SDA_HOLD_REG(priv->id));
+
+  /* scl_wait_high < sda_sample <= scl_high */
+
+  sda_sample    = half_cycle / 2 - 1;
+  putreg32(sda_sample, I2C_SDA_SAMPLE_REG(priv->id));
+
+  setup         = half_cycle;
+  putreg32(setup, I2C_SCL_RSTART_SETUP_REG(priv->id));
+  putreg32(setup, I2C_SCL_STOP_SETUP_REG(priv->id));
+
+  hold          = half_cycle;
+  putreg32(hold - 1, I2C_SCL_START_HOLD_REG(priv->id));
+  putreg32(hold, I2C_SCL_STOP_HOLD_REG(priv->id));
+
+  /* By default, we set the timeout value to 10 bus cycles */
+
+  timeout       = half_cycle * 20;
+  reg_value     = I2C_TIME_OUT_EN;
+  reg_value    |= VALUE_TO_FIELD(timeout, I2C_TIME_OUT_VALUE);
+  putreg32(reg_value, I2C_TO_REG(priv->id));
+
+  /* Set current bus clock frequency */
+
+  priv->clk_freq = bus_freq;
+}
+
+/****************************************************************************
+ * Name: i2c_init
+ *
+ * Description:
+ *   Initialize I2C hardware.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_init(struct esp32s2_i2c_priv_s *priv)
+{
+  const struct esp32s2_i2c_config_s *config = priv->config;
+
+  esp32s2_gpiowrite(config->scl_pin, 1);
+  esp32s2_configgpio(config->scl_pin, INPUT_PULLUP | OUTPUT_OPEN_DRAIN);
+  esp32s2_gpio_matrix_out(config->scl_pin, config->scl_outsig, 0, 0);
+  esp32s2_gpio_matrix_in(config->scl_pin, config->scl_insig, 0);
+
+  esp32s2_gpiowrite(config->sda_pin, 1);
+  esp32s2_configgpio(config->sda_pin, INPUT_PULLUP | OUTPUT_OPEN_DRAIN);
+  esp32s2_gpio_matrix_out(config->sda_pin, config->sda_outsig, 0, 0);
+  esp32s2_gpio_matrix_in(config->sda_pin, config->sda_insig, 0);
+
+  /* Enable I2C hardware */
+
+  modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, 0, config->clk_bit);
+  modifyreg32(SYSTEM_PERIP_RST_EN0_REG, config->rst_bit, 0);
+
+  /* Disable I2C interrupts */
+
+  i2c_intr_disable(priv);
+
+  /* Initialize I2C Master */
+
+  putreg32(I2C_MS_MODE | I2C_CLK_EN | I2C_SCL_FORCE_OUT | I2C_SDA_FORCE_OUT,
+           I2C_CTR_REG(priv->id));
+
+  /* Set FIFO mode */
+
+  modifyreg32(I2C_FIFO_CONF_REG(priv->id), I2C_NONFIFO_EN, 0);
+
+  /* Ensure I2C data mode is set to MSB */
+
+  modifyreg32(I2C_CTR_REG(priv->id), I2C_TX_LSB_FIRST | I2C_RX_LSB_FIRST, 0);
+
+  i2c_reset_fifo(priv);
+
+  /* Configure the hardware filter function */
+
+  putreg32(I2C_SCL_FILTER_EN |
+             VALUE_TO_FIELD(I2C_FILTER_CYC_NUM_DEF, I2C_SCL_FILTER_THRES),
+           I2C_SCL_FILTER_CFG_REG(priv->id));
+  putreg32(I2C_SDA_FILTER_EN |
+             VALUE_TO_FIELD(I2C_FILTER_CYC_NUM_DEF, I2C_SDA_FILTER_THRES),
+           I2C_SDA_FILTER_CFG_REG(priv->id));
+
+  /* Set I2C source clock */
+
+  modifyreg32(I2C_CTR_REG(priv->id), 0, I2C_REF_ALWAYS_ON);
+
+  /* Configure I2C bus frequency */
+
+  i2c_init_clock(priv, config->clk_freq);
+}
+
+/****************************************************************************
+ * Name: i2c_deinit
+ *
+ * Description:
+ *   Disable I2C hardware.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_deinit(struct esp32s2_i2c_priv_s *priv)
+{
+  const struct esp32s2_i2c_config_s *config = priv->config;
+
+  priv->clk_freq = 0;
+
+  modifyreg32(SYSTEM_PERIP_RST_EN0_REG, 0, config->rst_bit);
+  modifyreg32(SYSTEM_PERIP_CLK_EN0_REG, config->clk_bit, 0);
+}
+
+/****************************************************************************
+ * Name: i2c_reset_fsmc
+ *
+ * Description:
+ *   Reset I2C hardware state machine and registers.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_reset_fsmc(struct esp32s2_i2c_priv_s *priv)
+{
+  /* Reset FSM machine */
+
+  modifyreg32(I2C_CTR_REG(priv->id), 0, I2C_FSM_RST);
+
+  i2c_clear_bus(priv);
+}
+
+/****************************************************************************
+ * Name: i2c_sem_waitdone
+ *
+ * Description:
+ *   Wait for a transfer to complete.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success. A negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_I2C_POLLED
+static int i2c_sem_waitdone(struct esp32s2_i2c_priv_s *priv)
+{
+  /* Wait on ISR semaphore */
+
+  return nxsem_tickwait_uninterruptible(&priv->sem_isr,
+                                        ESP32S2_I2CTIMEOTICKS);
+}
+#endif
+
+/****************************************************************************
+ * Name: i2c_polling_waitdone
+ *
+ * Description:
+ *   Wait for a transfer to complete by polling status interrupt registers,
+ *   which indicates the status of the I2C operations. This function is only
+ *   used in polling driven mode.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ * Returned Values:
+ *   Zero (OK) is returned on successfull transfer. -ETIMEDOUT is returned
+ *   in case a transfer didn't finish within the timeout interval. And ERROR
+ *   is returned in case of any I2C error during the transfer has happened.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_POLLED
+static int i2c_polling_waitdone(struct esp32s2_i2c_priv_s *priv)
+{
+  int ret;
+  clock_t current;
+  clock_t timeout;
+  uint32_t status = 0;
+
+  /* Get the current absolute time and add an offset as timeout.
+   * Preferable to use monotonic, so in case the time changes,
+   * the time reference is kept, i.e., current time can't jump
+   * forward and backwards.
+   */
+
+  current = clock_systime_ticks();
+  timeout = current + SEC2TICK(10);
+
+  /* Loop while a transfer is in progress
+   * and an error didn't occur within the timeout
+   */
+
+  while ((current < timeout) && (priv->error == 0))
+    {
+      /* Check if any interrupt triggered, clear them
+       * process the operation.
+       */
+
+      status = getreg32(I2C_INT_STATUS_REG(priv->id));
+      if (status != 0)
+        {
+          /* Check if the stop operation ended. Don't use
+           * I2CSTATE_FINISH, because it is set before the stop
+           * signal really ends. This works for interrupts because
+           * the i2c_state is checked in the next interrupt when
+           * stop signal has concluded. This is not the case of
+           * polling.
+           */
+
+          if ((status & I2C_TRANS_COMPLETE_INT_ST) != 0)
+            {
+              putreg32(status, I2C_INT_CLR_REG(priv->id));
+              break;
+            }
+
+          putreg32(status, I2C_INT_CLR_REG(priv->id));
+          i2c_process(priv, status);
+        }
+
+      /* Update current time */
+
+      current = clock_systime_ticks();
+    }
+
+  /* Return a negated value in case of timeout, and in the other scenarios
+   * return a positive value.
+   * The transfer function will check the status of priv to check the other
+   * scenarios.
+   */
+
+  if (current >= timeout)
+    {
+      ret = -ETIMEDOUT;
+    }
+  else if (priv->error != 0)
+    {
+      ret = ERROR;
+    }
+  else
+    {
+      ret = OK;
+    }
+
+  /* Disable all interrupts */
+
+  i2c_intr_disable(priv);
+
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: i2c_sem_wait
+ *
+ * Description:
+ *   Take the exclusive access, waiting as necessary.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success. A negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int i2c_sem_wait(struct esp32s2_i2c_priv_s *priv)
+{
+  return nxsem_wait_uninterruptible(&priv->sem_excl);
+}
+
+/****************************************************************************
+ * Name: i2c_sem_post
+ *
+ * Description:
+ *   Release the mutual exclusion semaphore.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_sem_post(struct esp32s2_i2c_priv_s *priv)
+{
+  nxsem_post(&priv->sem_excl);
+}
+
+/****************************************************************************
+ * Name: i2c_sem_destroy
+ *
+ * Description:
+ *   Destroy semaphores.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_sem_destroy(struct esp32s2_i2c_priv_s *priv)
+{
+  nxsem_destroy(&priv->sem_excl);
+#ifndef CONFIG_I2C_POLLED
+  nxsem_destroy(&priv->sem_isr);
+#endif
+}
+
+/****************************************************************************
+ * Name: i2c_sem_init
+ *
+ * Description:
+ *   Initialize semaphores.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_sem_init(struct esp32s2_i2c_priv_s *priv)
+{
+  nxsem_init(&priv->sem_excl, 0, 1);
+
+  /* This semaphore is used for signaling and, hence, should not have
+   * priority inheritance enabled.
+   */
+
+#ifndef CONFIG_I2C_POLLED
+  nxsem_init(&priv->sem_isr, 0, 0);
+  nxsem_set_protocol(&priv->sem_isr, SEM_PRIO_NONE);
+#endif
+}
+
+/****************************************************************************
+ * Device Driver Operations
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: i2c_transfer
+ *
+ * Description:
+ *   Generic I2C transfer function.
+ *
+ * Parameters:
+ *   dev           - Device-specific state data
+ *   msgs          - A pointer to a set of message descriptors
+ *   count         - The number of transfers to perform
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success. A negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int i2c_transfer(struct i2c_master_s *dev, struct i2c_msg_s *msgs,
+                        int count)
+{
+  int ret = OK;
+  struct esp32s2_i2c_priv_s *priv = (struct esp32s2_i2c_priv_s *)dev;
+
+  DEBUGASSERT(count > 0);
+
+  ret = i2c_sem_wait(priv);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* If previous state is different than idle,
+   * reset the FSMC to the idle state.
+   */
+
+  if (priv->i2cstate != I2CSTATE_IDLE)
+    {
+      i2c_reset_fsmc(priv);
+      priv->i2cstate = I2CSTATE_IDLE;
+    }
+
+  /* Transfer the messages to the internal struct
+   * and loop count times to make all transfers.
+   */
+
+  priv->msgv = msgs;
+
+  for (int i = 0; i < count; i++)
+    {
+      /* Clear TX and RX FIFOs. */
+
+      i2c_reset_fifo(priv);
+
+      priv->bytes      = 0;
+      priv->msgid      = i;
+      priv->ready_read = false;
+      priv->error      = 0;
+      priv->i2cstate   = I2CSTATE_PROC;
+
+      /* Set the SCLK frequency for the current msg. */
+
+      i2c_init_clock(priv, msgs[i].frequency);
+
+      if ((msgs[i].flags & I2C_M_NOSTART) != 0)
+        {
+          i2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->bytes,
+                         getreg32(I2C_SR_REG(priv->id)));
+          i2c_senddata(priv);
+
+          if (priv->bytes == msgs[i].length)
+            {
+              if ((msgs[i].flags & I2C_M_NOSTOP) == 0)
+                {
+                  priv->i2cstate = I2CSTATE_STOP;
+                }
+#ifndef CONFIG_I2C_POLLED
+              else
+                {
+                  priv->i2cstate = I2CSTATE_FINISH;
+                }
+#endif
+            }
+        }
+      else
+        {
+          /* Reset I2C trace logic */
+
+          i2c_tracereset(priv);
+
+          i2c_traceevent(priv, I2CEVENT_SENDADDR, msgs[i].addr,
+                         getreg32(I2C_SR_REG(priv->id)));
+
+          i2c_sendstart(priv);
+        }
+
+#ifndef CONFIG_I2C_POLLED
+      if (i2c_sem_waitdone(priv) < 0)
+        {
+          /* Timed out - transfer was not completed within the timeout */
+
+          i2cerr("Message %" PRIu8 " timed out.\n", priv->msgid);
+          ret = -ETIMEDOUT;
+          break;
+        }
+      else
+        {
+          if (priv->error != 0)
+            {
+              /* An error occurred */
+
+              i2cerr("Transfer error %" PRIu32 "\n", priv->error);
+              ret = -EIO;
+              break;
+            }
+          else
+            {
+              /* Successful transfer, update the I2C state to idle */
+
+              priv->i2cstate = I2CSTATE_IDLE;
+              ret = OK;
+            }
+        }
+#else
+      ret = i2c_polling_waitdone(priv);
+      if (ret < 0)
+        {
+          if (ret == -ETIMEDOUT)
+            {
+              break;
+            }
+          else
+            {
+              ret = -EIO;
+              break;
+            }
+        }
+      else
+        {
+          /* Successful transfer, update the I2C state to idle */
+
+          priv->i2cstate = I2CSTATE_IDLE;
+          ret = OK;
+        }
+#endif
+
+      i2cinfo("Message %" PRIu8 " transfer complete.\n", priv->msgid);
+    }
+
+  /* Dump the trace result */
+
+  i2c_tracedump(priv);
+
+  i2c_sem_post(priv);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: i2c_clear_bus
+ *
+ * Description:
+ *   Clear I2C bus, when the slave is stuck in a deadlock and keeps pulling
+ *   the bus low, master can control the SCL bus to generate 9 CLKs.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void i2c_clear_bus(struct esp32s2_i2c_priv_s *priv)
+{
+  modifyreg32(I2C_SCL_SP_CONF_REG(priv->id),
+              I2C_SCL_RST_SLV_EN | I2C_SCL_RST_SLV_NUM_M,
+              VALUE_TO_FIELD(I2C_SCL_CYC_NUM_DEF, I2C_SCL_RST_SLV_NUM));
+
+  modifyreg32(I2C_SCL_SP_CONF_REG(priv->id), 0, I2C_SCL_RST_SLV_EN);
+}
+
+/****************************************************************************
+ * Name: i2c_reset
+ *
+ * Description:
+ *   Perform an I2C bus reset in an attempt to break loose stuck I2C devices.
+ *
+ * Input Parameters:
+ *   dev   - Device-specific state data
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_RESET
+static int i2c_reset(struct i2c_master_s *dev)
+{
+  irqstate_t flags;
+  struct esp32s2_i2c_priv_s *priv = (struct esp32s2_i2c_priv_s *)dev;
+
+  DEBUGASSERT(dev != NULL);
+  DEBUGASSERT(priv->refs > 0);
+
+  flags = enter_critical_section();
+
+  i2c_reset_fsmc(priv);
+
+  /* Clear bus */
+
+  i2c_clear_bus(priv);
+
+  priv->i2cstate   = I2CSTATE_IDLE;
+  priv->msgid      = 0;
+  priv->bytes      = 0;
+  priv->ready_read = false;
+
+  leave_critical_section(flags);
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: i2c_traceclear
+ *
+ * Description:
+ *   Set I2C trace fields to default value.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_TRACE
+static void i2c_traceclear(struct esp32s2_i2c_priv_s *priv)
+{
+  struct esp32s2_trace_s *trace = &priv->trace[priv->tndx];
+
+  trace->status = 0;
+  trace->count  = 0;
+  trace->event  = I2CEVENT_NONE;
+  trace->parm   = 0;
+  trace->time   = 0;
+}
+#endif /* CONFIG_I2C_TRACE */
+
+/****************************************************************************
+ * Name: i2c_tracereset
+ *
+ * Description:
+ *   Reset the trace info for a new data collection.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_TRACE
+static void i2c_tracereset(struct esp32s2_i2c_priv_s *priv)
+{
+  priv->tndx       = 0;
+  priv->start_time = clock_systime_ticks();
+  i2c_traceclear(priv);
+}
+#endif /* CONFIG_I2C_TRACE */
+
+/****************************************************************************
+ * Name: i2c_tracenew
+ *
+ * Description:
+ *   Create a new trace entry.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *   status        - Current value of I2C status register.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_TRACE
+static void i2c_tracenew(struct esp32s2_i2c_priv_s *priv, uint32_t status)
+{
+  struct esp32s2_trace_s *trace = &priv->trace[priv->tndx];
+
+  /* Check if the current entry is already initialized or if its status had
+   * already changed
+   */
+
+  if (trace->count == 0 || status != trace->status)
+    {
+      /* Check whether the status changed */
+
+      if (trace->count != 0)
+        {
+          /* Bump up the trace index (unless we are out of trace entries) */
+
+          if (priv->tndx >= (CONFIG_I2C_NTRACE - 1))
+            {
+              i2cerr("ERROR: Trace table overflow\n");
+              return;
+            }
+
+          priv->tndx++;
+          trace = &priv->trace[priv->tndx];
+        }
+
+      /* Initialize the new trace entry */
+
+      i2c_traceclear(priv);
+      trace->status = status;
+      trace->count  = 1;
+      trace->time   = clock_systime_ticks();
+    }
+  else
+    {
+      /* Just increment the count of times that we have seen this status */
+
+      trace->count++;
+    }
+}
+#endif /* CONFIG_I2C_TRACE */
+
+/****************************************************************************
+ * Name: i2c_traceevent
+ *
+ * Description:
+ *   Record a new trace event.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *   event         - Event to be recorded on the trace.
+ *   parm          - Parameter associated with the event.
+ *   status        - Current value of I2C status register.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_TRACE
+static void i2c_traceevent(struct esp32s2_i2c_priv_s *priv,
+                           enum esp32s2_trace_e event,
+                           uint32_t parm,
+                           uint32_t status)
+{
+  /* Check for new trace setup */
+
+  i2c_tracenew(priv, status);
+
+  if (event != I2CEVENT_NONE)
+    {
+      struct esp32s2_trace_s *trace = &priv->trace[priv->tndx];
+
+      /* Initialize the new trace entry */
+
+      trace->event  = event;
+      trace->parm   = parm;
+
+      /* Bump up the trace index (unless we are out of trace entries) */
+
+      if (priv->tndx >= (CONFIG_I2C_NTRACE - 1))
+        {
+          i2cerr("ERROR: Trace table overflow\n");
+          return;
+        }
+
+      priv->tndx++;
+      i2c_traceclear(priv);
+    }
+}
+#endif /* CONFIG_I2C_TRACE */
+
+/****************************************************************************
+ * Name: i2c_tracedump
+ *
+ * Description:
+ *   Dump the trace results.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_TRACE
+static void i2c_tracedump(struct esp32s2_i2c_priv_s *priv)
+{
+  syslog(LOG_DEBUG, "Elapsed time: %" PRIu32 "\n",
+         clock_systime_ticks() - priv->start_time);
+
+  for (int i = 0; i < priv->tndx; i++)
+    {
+      struct esp32s2_trace_s *trace = &priv->trace[i];
+      syslog(LOG_DEBUG,
+             "%2d. STATUS: %08" PRIx32 " COUNT: %3" PRIu32 " EVENT: %s(%2d)"
+             " PARM: %08" PRIx32 " TIME: %" PRIu32 "\n",
+             i + 1, trace->status, trace->count, g_trace_names[trace->event],
+             trace->event, trace->parm, trace->time - priv->start_time);
+    }
+}
+#endif /* CONFIG_I2C_TRACE */
+
+/****************************************************************************
+ * Name: i2c_irq
+ *
+ * Description:
+ *   This is the common I2C interrupt handler. It will be invoked when an
+ *   interrupt is received on the device.
+ *
+ * Parameters:
+ *   cpuint        - CPU interrupt index
+ *   context       - Context data from the ISR
+ *   arg           - Opaque pointer to the internal driver state structure.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success. A negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_I2C_POLLED
+static int i2c_irq(int cpuint, void *context, void *arg)
+{
+  struct esp32s2_i2c_priv_s *priv = (struct esp32s2_i2c_priv_s *)arg;
+
+  /* Get the interrupt status and clear the interrupts that
+   * triggered.
+   */
+
+  uint32_t irq_status = getreg32(I2C_INT_STATUS_REG(priv->id));
+  putreg32(irq_status, I2C_INT_CLR_REG(priv->id));
+
+  i2c_process(priv, irq_status);
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: i2c_process
+ *
+ * Description:
+ *   This routine manages the transfer. It's called after some specific
+ *   commands from the I2C controller are executed or in case of errors.
+ *   It's responsible for writing/reading operations and transferring data
+ *   from/to FIFO.
+ *   It's called in the interrupt and polled driven mode.
+ *
+ * Parameters:
+ *   priv          - Pointer to the internal driver state structure.
+ *   status        - The current interrupt status register.
+ *
+ ****************************************************************************/
+
+static void i2c_process(struct esp32s2_i2c_priv_s *priv, uint32_t status)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+
+  /* Check for any errors */
+
+  if ((I2C_INT_ERR_MASK & status) != 0)
+    {
+      /* Save the errors, register the error event, disable interrupts
+       * and release the semaphore to conclude the transfer.
+       */
+
+      priv->error = status & I2C_INT_ERR_MASK;
+      priv->i2cstate = I2CSTATE_ERROR;
+      i2c_traceevent(priv, I2CEVENT_ERROR, priv->error,
+                     getreg32(I2C_SR_REG(priv->id)));
+      i2c_intr_disable(priv);
+#ifndef CONFIG_I2C_POLLED
+      nxsem_post(&priv->sem_isr);
+#endif
+    }
+  else /* If no error */
+    {
+      /* If a transfer has just initialized */
+
+      if (priv->i2cstate == I2CSTATE_PROC)
+        {
+          /* Check the flags to perform a read or write operation */
+
+          if ((msg->flags & I2C_M_READ) != 0)
+            {
+              /* RX FIFO has available data */
+
+              if (priv->ready_read)
+                {
+                  i2c_traceevent(priv, I2CEVENT_RCVBYTE, priv->bytes,
+                                 getreg32(I2C_SR_REG(priv->id)));
+                  i2c_recvdata(priv);
+
+                  priv->ready_read = false;
+                }
+
+              /* Received all data. Finish the transaction
+               * and update the I2C state.
+               */
+
+              if (priv->bytes == msg->length)
+                {
+                  i2c_traceevent(priv, I2CEVENT_STOP, msg->length,
+                                 getreg32(I2C_SR_REG(priv->id)));
+                  i2c_sendstop(priv);
+#ifndef CONFIG_I2C_POLLED
+                  priv->i2cstate = I2CSTATE_FINISH;
+#endif
+                }
+              else /* Start a receive operation */
+                {
+                  i2c_traceevent(priv, I2CEVENT_RCVMODEEN, 0,
+                                 getreg32(I2C_SR_REG(priv->id)));
+                  i2c_startrecv(priv);
+
+                  priv->ready_read = true;
+                }
+            }
+          else /* Write operation */
+            {
+              i2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->bytes,
+                             getreg32(I2C_SR_REG(priv->id)));
+              i2c_senddata(priv);
+
+              /* Finally sent the entire message. Update the I2C state to
+               * send a stop signal in the next interrupt.
+               */
+
+              if (priv->bytes == msg->length)
+                {
+                  if ((msg->flags & I2C_M_NOSTOP) == 0)
+                    {
+                      priv->i2cstate = I2CSTATE_STOP;
+                    }
+#ifndef CONFIG_I2C_POLLED
+                  else
+                    {
+                      priv->i2cstate = I2CSTATE_FINISH;
+                    }
+#endif
+                }
+            }
+        }
+      else if (priv->i2cstate == I2CSTATE_STOP)
+        {
+          /* Transmitted all data. Finish the transaction sending a stop
+           * and update the I2C state.
+           */
+
+          i2c_traceevent(priv, I2CEVENT_STOP, msg->length,
+                         getreg32(I2C_SR_REG(priv->id)));
+          i2c_sendstop(priv);
+#ifndef CONFIG_I2C_POLLED
+          priv->i2cstate = I2CSTATE_FINISH;
+#endif
+        }
+#ifndef CONFIG_I2C_POLLED
+      else if (priv->i2cstate == I2CSTATE_FINISH)
+        {
+          /* Disable all interrupts and release the semaphore */
+
+          i2c_intr_disable(priv);
+          nxsem_post(&priv->sem_isr);
+        }
+#endif
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s2_i2cbus_initialize
+ *
+ * Description:
+ *   Initialize the selected I2C port. And return a pointer to an unique
+ *   instance of struct i2c_master_s. This function may be called to obtain
+ *   multiple instances of the interface, each of which may be set up with a
+ *   different frequency and slave address.
+ *
+ * Parameters:
+ *   port          - Port number of the I2C interface to be initialized.
+ *
+ * Returned Value:
+ *   Pointer to valid I2C device structure is returned on success.
+ *   A NULL pointer is returned on failure.
+ *
+ ****************************************************************************/
+
+struct i2c_master_s *esp32s2_i2cbus_initialize(int port)
+{
+  irqstate_t flags;
+  struct esp32s2_i2c_priv_s *priv;
+#ifndef CONFIG_I2C_POLLED
+  const struct esp32s2_i2c_config_s *config;
+  int ret;
+#endif
+
+  switch (port)
+    {
+#ifdef CONFIG_ESP32S2_I2C0
+    case ESP32S2_I2C0:
+      priv = &g_esp32s2_i2c0_priv;
+      break;
+#endif
+#ifdef CONFIG_ESP32S2_I2C1
+    case ESP32S2_I2C1:
+      priv = &g_esp32s2_i2c1_priv;
+      break;
+#endif
+    default:
+      return NULL;
+    }
+
+  flags = enter_critical_section();
+
+  if ((volatile int)priv->refs++ != 0)

Review Comment:
   I'm not sure why `volatile int` cast is needed here. Maybe better if `refs` itself is a `volatile int` and drop the cast here



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org