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

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

commit dda55419f9a6ea434f4320aa21543095be7d3efd
Author: Eren Terzioglu <[email protected]>
AuthorDate: Thu Jun 20 16:21:06 2024 +0300

    esp32[c3|c6|h2]: Add I2C master support
---
 .../esp32c3/boards/esp32c3-generic/index.rst       |    8 +
 Documentation/platforms/risc-v/esp32c3/index.rst   |    2 +-
 .../esp32c6/boards/esp32c6-devkitc/index.rst       |    8 +
 .../esp32c6/boards/esp32c6-devkitm/index.rst       |    8 +
 Documentation/platforms/risc-v/esp32c6/index.rst   |    2 +-
 .../risc-v/esp32h2/boards/esp32h2-devkit/index.rst |    8 +
 Documentation/platforms/risc-v/esp32h2/index.rst   |    2 +-
 arch/risc-v/src/common/espressif/Kconfig           |   61 +
 arch/risc-v/src/common/espressif/Make.defs         |    4 +
 arch/risc-v/src/common/espressif/esp_i2c.c         | 1607 ++++++++++++++++++++
 arch/risc-v/src/common/espressif/esp_i2c.h         |   91 ++
 arch/risc-v/src/esp32c3/hal_esp32c3.mk             |    2 +
 arch/risc-v/src/esp32c6/hal_esp32c6.mk             |    2 +
 arch/risc-v/src/esp32h2/hal_esp32h2.mk             |    2 +
 .../risc-v/esp32c3/common/include/esp_board_i2c.h  |   74 +
 boards/risc-v/esp32c3/common/src/Make.defs         |    4 +
 boards/risc-v/esp32c3/common/src/esp_board_i2c.c   |   82 +
 .../esp32c3/esp32c3-generic/configs/i2c/defconfig  |   52 +
 .../esp32c3/esp32c3-generic/src/esp32c3_bringup.c  |   12 +
 .../risc-v/esp32c6/common/include/esp_board_i2c.h  |   74 +
 boards/risc-v/esp32c6/common/src/Make.defs         |    4 +
 boards/risc-v/esp32c6/common/src/esp_board_i2c.c   |   82 +
 .../esp32c6/esp32c6-devkitc/configs/i2c/defconfig  |   54 +
 .../esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c  |   12 +
 .../esp32c6/esp32c6-devkitm/configs/i2c/defconfig  |   54 +
 .../esp32c6/esp32c6-devkitm/src/esp32c6_bringup.c  |   12 +
 .../risc-v/esp32h2/common/include/esp_board_i2c.h  |   74 +
 boards/risc-v/esp32h2/common/src/Make.defs         |    4 +
 boards/risc-v/esp32h2/common/src/esp_board_i2c.c   |   90 ++
 .../esp32h2/esp32h2-devkit/configs/i2c/defconfig   |   54 +
 .../esp32h2/esp32h2-devkit/src/esp32h2_bringup.c   |   12 +
 31 files changed, 2554 insertions(+), 3 deletions(-)

diff --git 
a/Documentation/platforms/risc-v/esp32c3/boards/esp32c3-generic/index.rst 
b/Documentation/platforms/risc-v/esp32c3/boards/esp32c3-generic/index.rst
index dc505e2acb..8c3728b10f 100644
--- a/Documentation/platforms/risc-v/esp32c3/boards/esp32c3-generic/index.rst
+++ b/Documentation/platforms/risc-v/esp32c3/boards/esp32c3-generic/index.rst
@@ -84,6 +84,14 @@ We can use the interrupt pin to send a signal when the 
interrupt fires::
 The pin is configured as a rising edge interrupt, so after issuing the
 above command, connect it to 3.3V.
 
+i2c
+---
+
+This configuration can be used to scan and manipulate I2C devices.
+You can scan for all I2C devices using the following command::
+
+    nsh> i2c dev 0x00 0x7f
+
 nsh
 ---
 
diff --git a/Documentation/platforms/risc-v/esp32c3/index.rst 
b/Documentation/platforms/risc-v/esp32c3/index.rst
index 642c02dfe6..79020922fe 100644
--- a/Documentation/platforms/risc-v/esp32c3/index.rst
+++ b/Documentation/platforms/risc-v/esp32c3/index.rst
@@ -165,7 +165,7 @@ CDC Console  Yes    Rev.3
 DMA          No
 eFuse        No
 GPIO         Yes
-I2C          No
+I2C          Yes
 LED_PWM      Yes
 RNG          No
 RSA          No
diff --git 
a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst 
b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst
index ba479f1768..b48028e343 100644
--- a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst
+++ b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitc/index.rst
@@ -119,6 +119,14 @@ We can use the interrupt pin to send a signal when the 
interrupt fires::
 The pin is configured as a rising edge interrupt, so after issuing the
 above command, connect it to 3.3V.
 
+i2c
+---
+
+This configuration can be used to scan and manipulate I2C devices.
+You can scan for all I2C devices using the following command::
+
+    nsh> i2c dev 0x00 0x7f
+
 nsh
 ---
 
diff --git 
a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitm/index.rst 
b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitm/index.rst
index 7cfd47a6b9..cfc632f2a9 100644
--- a/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitm/index.rst
+++ b/Documentation/platforms/risc-v/esp32c6/boards/esp32c6-devkitm/index.rst
@@ -119,6 +119,14 @@ We can use the interrupt pin to send a signal when the 
interrupt fires::
 The pin is configured as a rising edge interrupt, so after issuing the
 above command, connect it to 3.3V.
 
+i2c
+---
+
+This configuration can be used to scan and manipulate I2C devices.
+You can scan for all I2C devices using the following command::
+
+    nsh> i2c dev 0x00 0x7f
+
 nsh
 ---
 
diff --git a/Documentation/platforms/risc-v/esp32c6/index.rst 
b/Documentation/platforms/risc-v/esp32c6/index.rst
index 636ca5bbfe..1d5377b751 100644
--- a/Documentation/platforms/risc-v/esp32c6/index.rst
+++ b/Documentation/platforms/risc-v/esp32c6/index.rst
@@ -147,7 +147,7 @@ ECC              No
 eFuse            No
 GPIO             Yes
 HMAC             No
-I2C              No
+I2C              Yes
 I2S              No
 Int. Temp.       No
 LED              No
diff --git 
a/Documentation/platforms/risc-v/esp32h2/boards/esp32h2-devkit/index.rst 
b/Documentation/platforms/risc-v/esp32h2/boards/esp32h2-devkit/index.rst
index 56f181408c..b03b3702a1 100644
--- a/Documentation/platforms/risc-v/esp32h2/boards/esp32h2-devkit/index.rst
+++ b/Documentation/platforms/risc-v/esp32h2/boards/esp32h2-devkit/index.rst
@@ -118,6 +118,14 @@ We can use the interrupt pin to send a signal when the 
interrupt fires::
 The pin is configured as a rising edge interrupt, so after issuing the
 above command, connect it to 3.3V.
 
+i2c
+---
+
+This configuration can be used to scan and manipulate I2C devices.
+You can scan for all I2C devices using the following command::
+
+    nsh> i2c dev 0x00 0x7f
+
 nsh
 ---
 
diff --git a/Documentation/platforms/risc-v/esp32h2/index.rst 
b/Documentation/platforms/risc-v/esp32h2/index.rst
index 3f5d8d17b9..0a63e9fea2 100644
--- a/Documentation/platforms/risc-v/esp32h2/index.rst
+++ b/Documentation/platforms/risc-v/esp32h2/index.rst
@@ -147,7 +147,7 @@ ECC              No
 eFuse            No
 GPIO             Yes
 HMAC             No
-I2C              No
+I2C              Yes
 I2S              No
 Int. Temp.       No
 LED              No
diff --git a/arch/risc-v/src/common/espressif/Kconfig 
b/arch/risc-v/src/common/espressif/Kconfig
index 5e10163143..2b048e2d55 100644
--- a/arch/risc-v/src/common/espressif/Kconfig
+++ b/arch/risc-v/src/common/espressif/Kconfig
@@ -11,16 +11,19 @@ choice ESPRESSIF_CHIP_SERIES
 
 config ESPRESSIF_ESP32C3
        bool "ESP32-C3"
+       select ARCH_HAVE_I2CRESET
        ---help---
                ESP32-C3 chip with a single RISC-V IMC core, no embedded Flash 
memory
 
 config ESPRESSIF_ESP32C6
        bool "ESP32-C6"
+       select ARCH_HAVE_I2CRESET
        ---help---
                Espressif ESP32-C6 (RV32IMAC).
 
 config ESPRESSIF_ESP32H2
        bool "ESP32-H2"
+       select ARCH_HAVE_I2CRESET
        ---help---
                Espressif ESP32-H2 (RV32IMC).
 
@@ -314,6 +317,23 @@ config ESPRESSIF_LEDC
        select PWM
        select ARCH_HAVE_PWM_MULTICHAN
 
+config ESPRESSIF_I2C
+       bool
+       default n
+
+config ESPRESSIF_I2C0
+       bool "I2C 0"
+       default n
+       select ESPRESSIF_I2C
+       select I2C
+
+config ESPRESSIF_I2C1
+       bool "I2C 1"
+       default n
+       depends on ARCH_CHIP_ESP32H2
+       select ESPRESSIF_I2C
+       select I2C
+
 config ESPRESSIF_SPI
        bool
        default n
@@ -1208,6 +1228,47 @@ endif # PWM_MULTICHAN && PWM_NCHANNELS > 1
 
 endmenu # LEDC configuration
 
+menu "I2C Configuration"
+       depends on ESPRESSIF_I2C
+
+if ESPRESSIF_I2C0
+
+config ESPRESSIF_I2C0_SCLPIN
+       int "I2C0 SCL Pin"
+       default 6
+       range 0 21
+
+config ESPRESSIF_I2C0_SDAPIN
+       int "I2C0 SDA Pin"
+       default 5
+       range 0 21
+
+endif # ESPRESSIF_I2C0
+
+if ESPRESSIF_I2C1
+
+config ESPRESSIF_I2C1_SCLPIN
+       int "I2C1 SCL Pin"
+       default 2
+       range 0 21
+
+config ESPRESSIF_I2C1_SDAPIN
+       int "I2C1 SDA Pin"
+       default 1
+       range 0 21
+
+endif # ESPRESSIF_I2C1
+
+config ESPRESSIF_I2CTIMEOSEC
+       int "Timeout seconds"
+       default 0
+
+config ESPRESSIF_I2CTIMEOMS
+       int "Timeout milliseconds"
+       default 500
+
+endmenu # I2C configuration
+
 menu "High Resolution Timer"
        depends on ESPRESSIF_HR_TIMER
 
diff --git a/arch/risc-v/src/common/espressif/Make.defs 
b/arch/risc-v/src/common/espressif/Make.defs
index 9daf4e270e..d75ab3dac1 100644
--- a/arch/risc-v/src/common/espressif/Make.defs
+++ b/arch/risc-v/src/common/espressif/Make.defs
@@ -84,6 +84,10 @@ ifeq ($(CONFIG_ESP_RMT),y)
        endif
 endif
 
+ifeq ($(CONFIG_ESPRESSIF_I2C),y)
+       CHIP_CSRCS += esp_i2c.c
+endif
+
 ifeq ($(CONFIG_ESPRESSIF_SPI),y)
        CHIP_CSRCS += esp_spi.c
        ifeq ($(CONFIG_SPI_SLAVE),y)
diff --git a/arch/risc-v/src/common/espressif/esp_i2c.c 
b/arch/risc-v/src/common/espressif/esp_i2c.c
new file mode 100644
index 0000000000..2cf0f64e67
--- /dev/null
+++ b/arch/risc-v/src/common/espressif/esp_i2c.c
@@ -0,0 +1,1607 @@
+/****************************************************************************
+ * arch/risc-v/src/common/espressif/esp_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_ESPRESSIF_I2C
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+#include <nuttx/mutex.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/i2c/i2c_master.h>
+
+#include <arch/board/board.h>
+
+#include "esp_i2c.h"
+#include "esp_irq.h"
+#include "esp_gpio.h"
+#include "riscv_internal.h"
+
+#include "periph_ctrl.h"
+#include "hal/i2c_hal.h"
+#include "hal/i2c_types.h"
+#include "hal/i2c_ll.h"
+#include "soc/system_reg.h"
+#include "soc/gpio_sig_map.h"
+#include "soc/i2c_periph.h"
+#if defined(CONFIG_ESPRESSIF_ESP32H2) || defined(CONFIG_ESPRESSIF_ESP32C6)
+#  include "soc/pcr_reg.h"
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_ESPRESSIF_ESP32H2
+#  define SYSTEM_I2C_EXT0_CLK_EN PCR_I2C0_CLK_EN
+#  define SYSTEM_I2C_EXT0_RST    PCR_I2C0_RST_EN
+#  define SYSTEM_I2C_EXT1_CLK_EN PCR_I2C1_CLK_EN
+#  define SYSTEM_I2C_EXT1_RST    PCR_I2C1_RST_EN
+#endif
+
+#ifdef CONFIG_ESPRESSIF_ESP32C6
+#  define SYSTEM_I2C_EXT0_CLK_EN PCR_I2C_CLK_EN
+#  define SYSTEM_I2C_EXT0_RST    PCR_I2C_RST_EN
+#endif
+
+#define GET_STATUS(hw) hw->sr.val
+
+#define ESPRESSIF_I2CTIMEOTICKS \
+    (SEC2TICK(CONFIG_ESPRESSIF_I2CTIMEOSEC) + 
MSEC2TICK(CONFIG_ESPRESSIF_I2CTIMEOMS))
+
+/* I2C hardware FIFO depth */
+
+#define I2C_FIFO_SIZE (32)
+
+/* Number of bus cycles filtered by default */
+
+#define I2C_FILTER_CYC_NUM_DEF (7)
+
+/* Number of bus cycles for the master to generate when the slave is in
+ * deadlock
+ */
+
+#define I2C_SCL_CYC_NUM_DEF (9)
+
+/* I2C default clock frequency */
+
+#define I2C_CLK_FREQ_DEF (100 * 1000)
+
+/* Mask for the interrupt errors */
+
+#define I2C_INT_ERR_MASK (I2C_NACK_INT_ENA_M | \
+                          I2C_TIME_OUT_INT_ENA_M | \
+                          I2C_ARBITRATION_LOST_INT_ENA_M)
+
+/* 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 esp_i2c_tracereset(p)
+#  define esp_i2c_tracenew(p,s)
+#  define esp_i2c_traceevent(p,e,a,s)
+#  define esp_i2c_tracedump(p)
+#endif
+
+#ifndef CONFIG_I2C_NTRACE
+#  define CONFIG_I2C_NTRACE 32
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* I2C state */
+
+enum esp_i2cstate_e
+{
+  I2CSTATE_IDLE = 0,
+  I2CSTATE_PROC,
+  I2CSTATE_STOP,
+#ifndef CONFIG_I2C_POLLED
+  I2CSTATE_FINISH,
+#endif
+  I2CSTATE_ERROR
+};
+
+/* I2C hardware command */
+
+enum esp_i2c_opmode_e
+{
+  I2C_CMD_RESTART = 6, /* I2C restart command */
+  I2C_CMD_WRITE = 1,   /* I2C write command */
+  I2C_CMD_READ = 3,    /* I2C read command */
+  I2C_CMD_STOP = 2,    /* I2C stop command */
+  I2C_CMD_END = 4      /* I2C end command */
+};
+
+#ifdef CONFIG_I2C_TRACE
+
+/* Trace events */
+
+enum esp_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 esp_trace_s
+{
+  uint32_t status;           /* I2C 32-bit SR status */
+  uint32_t count;            /* Interrupt count when status change */
+  enum esp_i2cstate_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 esp_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 esp_i2c_priv_s
+{
+  const struct i2c_ops_s *ops; /* Standard I2C operations */
+
+  uint32_t id;                 /* I2C instance */
+
+  /* Port configuration */
+
+  const struct esp_i2c_config_s *config;
+  int refs;                    /* Reference count */
+  mutex_t lock;                /* Mutual exclusion mutex */
+
+#ifndef CONFIG_I2C_POLLED
+  sem_t sem_isr;               /* Interrupt wait semaphore */
+#endif
+
+  /* I2C work state (see enum esp_i2cstate_e) */
+
+  volatile enum esp_i2cstate_e i2cstate;
+
+  struct i2c_msg_s *msgv;      /* Message list */
+
+  uint8_t msgid;               /* Current message ID */
+  ssize_t bytes;               /* Processed data bytes */
+
+#ifndef CONFIG_I2C_POLLED
+  int cpuint;                  /* CPU interrupt assigned to this I2C */
+#endif
+
+  uint32_t error;              /* I2C transform error */
+
+  bool ready_read;             /* If I2C is ready for receiving data */
+
+  uint32_t clk_freq;           /* Current I2C Clock frequency */
+
+  /* I2C trace support */
+
+#ifdef CONFIG_I2C_TRACE
+  int tndx;                    /* Trace array index */
+  clock_t start_time;          /* Time when the trace was started */
+
+  /* The actual trace data */
+
+  struct esp_trace_s trace[CONFIG_I2C_NTRACE];
+
+#endif
+  i2c_hal_context_t *ctx;     /* Common layer struct */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void esp_i2c_reset_fifo(struct esp_i2c_priv_s *priv);
+static void esp_i2c_intr_enable(struct esp_i2c_priv_s *priv);
+static void esp_i2c_intr_enable(struct esp_i2c_priv_s *priv);
+static void esp_i2c_intr_disable(struct esp_i2c_priv_s *priv);
+static void esp_i2c_sendstart(struct esp_i2c_priv_s *priv);
+static void esp_i2c_senddata(struct esp_i2c_priv_s *priv);
+static void esp_i2c_recvdata(struct esp_i2c_priv_s *priv);
+static void esp_i2c_startrecv(struct esp_i2c_priv_s *priv);
+static void esp_i2c_sendstop(struct esp_i2c_priv_s *priv);
+static void esp_i2c_init_clock(struct esp_i2c_priv_s *priv,
+                               uint32_t bus_freq);
+static void esp_i2c_init(struct esp_i2c_priv_s *priv);
+static void esp_i2c_deinit(struct esp_i2c_priv_s *priv);
+static void esp_i2c_reset_fsmc(struct esp_i2c_priv_s *priv);
+static int esp_i2c_sem_waitdone(struct esp_i2c_priv_s *priv);
+#ifdef CONFIG_I2C_POLLED
+static int esp_i2c_polling_waitdone(struct esp_i2c_priv_s *priv);
+#endif /* CONFIG_I2C_POLLED */
+static int  esp_i2c_transfer(struct i2c_master_s *dev,
+                             struct i2c_msg_s *msgs,
+                             int count);
+#ifdef CONFIG_I2C_RESET
+static void esp_i2c_clear_bus(struct esp_i2c_priv_s *priv);
+static int  esp_i2c_reset(struct i2c_master_s *dev);
+#endif /* CONFIG_I2C_RESET */
+#ifdef CONFIG_I2C_TRACE
+static void esp_i2c_traceclear(struct esp_i2c_priv_s *priv);
+static void esp_i2c_tracereset(struct esp_i2c_priv_s *priv);
+static void esp_i2c_tracenew(struct esp_i2c_priv_s *priv,
+                             uint32_t status);
+static void esp_i2c_traceevent(struct esp_i2c_priv_s *priv,
+                               enum esp_trace_e event,
+                               uint32_t parm,
+                               uint32_t status);
+static void esp_i2c_tracedump(struct esp_i2c_priv_s *priv);
+#endif /* CONFIG_I2C_TRACE */
+#ifndef CONFIG_I2C_POLLED
+static int esp_i2c_irq(int cpuint, void *context, void *arg);
+#endif /* CONFIG_I2C_POLLED */
+static inline void esp_i2c_process(struct esp_i2c_priv_s *priv,
+                                   uint32_t status);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* I2C interface */
+
+static const struct i2c_ops_s esp_i2c_ops =
+{
+  .transfer = esp_i2c_transfer
+#ifdef CONFIG_I2C_RESET
+  , .reset  = esp_i2c_reset
+#endif
+};
+
+#ifdef CONFIG_ESPRESSIF_I2C0
+
+i2c_hal_context_t i2c0_ctx =
+{
+  0
+};
+
+/* I2C device structure */
+
+static const struct esp_i2c_config_s esp_i2c0_config =
+{
+  .clk_freq   = I2C_CLK_FREQ_DEF,
+  .scl_pin    = CONFIG_ESPRESSIF_I2C0_SCLPIN,
+  .sda_pin    = CONFIG_ESPRESSIF_I2C0_SDAPIN,
+#ifndef CONFIG_I2C_POLLED
+  .periph     = ETS_I2C_EXT0_INTR_SOURCE,
+  .irq        = ESP_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 esp_i2c_priv_s esp_i2c0_priv =
+{
+  .ops        = &esp_i2c_ops,
+  .id         = 0,
+  .config     = &esp_i2c0_config,
+  .refs       = 0,
+  .lock       = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+  .sem_isr    = SEM_INITIALIZER(0),
+#endif
+  .i2cstate   = I2CSTATE_IDLE,
+  .msgv       = NULL,
+  .msgid      = 0,
+  .bytes      = 0,
+#ifndef CONFIG_I2C_POLLED
+  .cpuint     = -ENOMEM,
+#endif
+  .error      = 0,
+  .ready_read = false,
+  .clk_freq   = 0,
+  .ctx = &i2c0_ctx
+};
+#endif
+
+#ifdef CONFIG_ESPRESSIF_I2C1
+
+i2c_hal_context_t i2c1_ctx =
+{
+  0
+};
+
+/* I2C device structure */
+
+static const struct esp_i2c_config_s esp_i2c1_config =
+{
+  .clk_freq   = I2C_CLK_FREQ_DEF,
+  .scl_pin    = CONFIG_ESPRESSIF_I2C1_SCLPIN,
+  .sda_pin    = CONFIG_ESPRESSIF_I2C1_SDAPIN,
+#ifndef CONFIG_I2C_POLLED
+  .periph     = ETS_I2C_EXT1_INTR_SOURCE,
+  .irq        = ESP_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 esp_i2c_priv_s esp_i2c1_priv =
+{
+  .ops        = &esp_i2c_ops,
+  .id         = 1,
+  .config     = &esp_i2c1_config,
+  .refs       = 0,
+  .lock       = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+  .sem_isr    = SEM_INITIALIZER(0),
+#endif
+  .i2cstate   = I2CSTATE_IDLE,
+  .msgv       = NULL,
+  .msgid      = 0,
+  .bytes      = 0,
+#ifndef CONFIG_I2C_POLLED
+  .cpuint     = -ENOMEM,
+#endif
+  .error      = 0,
+  .ready_read = false,
+  .clk_freq   = 0,
+  .ctx        = &i2c1_ctx
+};
+#endif /* CONFIG_ESPRESSIF_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: esp_i2c_reset_fifo
+ *
+ * Description:
+ *   Reset I2C RX and TX hardware FIFO.
+ *
+ * Parameters:
+ *   priv - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void esp_i2c_reset_fifo(struct esp_i2c_priv_s *priv)
+{
+  i2c_ll_txfifo_rst(priv->ctx->dev);
+  i2c_ll_rxfifo_rst(priv->ctx->dev);
+}
+
+/****************************************************************************
+ * Name: esp_i2c_intr_enable
+ *
+ * Description:
+ *   Enable I2C interrupts.
+ *
+ * Parameters:
+ *   priv - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void esp_i2c_intr_enable(struct esp_i2c_priv_s *priv)
+{
+  i2c_ll_clear_intr_mask(priv->ctx->dev, I2C_LL_INTR_MASK);
+  i2c_ll_enable_intr_mask(priv->ctx->dev, I2C_LL_MASTER_EVENT_INTR);
+}
+
+/****************************************************************************
+ * Name: esp_i2c_intr_disable
+ *
+ * Description:
+ *   Disable I2C interrupts.
+ *
+ * Parameters:
+ *   priv - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void esp_i2c_intr_disable(struct esp_i2c_priv_s *priv)
+{
+  i2c_ll_disable_intr_mask(priv->ctx->dev, I2C_LL_INTR_MASK);
+  i2c_ll_clear_intr_mask(priv->ctx->dev, I2C_LL_INTR_MASK);
+}
+
+/****************************************************************************
+ * Name: esp_i2c_sendstart
+ *
+ * Description:
+ *   Send I2C start signal.
+ *
+ * Parameters:
+ *   priv - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void esp_i2c_sendstart(struct esp_i2c_priv_s *priv)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+  uint32_t fifo_val = 0;
+  i2c_ll_hw_cmd_t restart_cmd;
+  i2c_ll_hw_cmd_t write_cmd;
+  i2c_ll_hw_cmd_t end_cmd;
+
+  /* Write I2C command registers */
+
+  restart_cmd.op_code = I2C_LL_CMD_RESTART;
+
+  write_cmd.byte_num = 1;
+  write_cmd.ack_en = 1;
+  write_cmd.op_code = I2C_LL_CMD_WRITE;
+
+  end_cmd.op_code = I2C_LL_CMD_END;
+
+  i2c_ll_write_cmd_reg(priv->ctx->dev, restart_cmd, 0);
+  i2c_ll_write_cmd_reg(priv->ctx->dev, write_cmd, 1);
+  i2c_ll_write_cmd_reg(priv->ctx->dev, end_cmd, 2);
+
+  /* Write data to FIFO register */
+
+  fifo_val = (msg->addr << 1) | (msg->flags & I2C_M_READ);
+  i2c_ll_write_txfifo(priv->ctx->dev, (uint8_t *)&fifo_val, 1);
+
+  /* Enable I2C master TX interrupt */
+
+  esp_i2c_intr_enable(priv);
+
+  /* Update I2C configuration */
+
+  /* Configure the I2C to trigger a transaction */
+
+  i2c_hal_master_trans_start(priv->ctx);
+}
+
+/****************************************************************************
+ * Name: esp_i2c_senddata
+ *
+ * Description:
+ *   Send I2C data.
+ *
+ * Parameters:
+ *   priv - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void esp_i2c_senddata(struct esp_i2c_priv_s *priv)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+  int n = msg->length - priv->bytes;
+  i2c_ll_hw_cmd_t write_cmd =
+    {
+      .ack_en = 1,
+      .op_code = I2C_LL_CMD_WRITE
+    };
+
+  i2c_ll_hw_cmd_t end_cmd =
+    {
+      .op_code = I2C_LL_CMD_END
+    };
+
+  n = n < I2C_FIFO_SIZE ? n : I2C_FIFO_SIZE;
+
+  write_cmd.byte_num = n;
+  i2c_ll_write_cmd_reg(priv->ctx->dev, write_cmd, 0);
+  i2c_ll_write_cmd_reg(priv->ctx->dev, end_cmd, 1);
+  i2c_ll_write_txfifo(priv->ctx->dev, &msg->buffer[priv->bytes], n);
+  i2c_ll_master_enable_tx_it(priv->ctx->dev);
+
+  priv->bytes += n;
+
+  /* Enable I2C master TX interrupt */
+
+  esp_i2c_intr_enable(priv);
+
+  /* Update I2C configuration */
+
+  /* Configure the I2C to trigger a transaction */
+
+  i2c_hal_master_trans_start(priv->ctx);
+}
+
+/****************************************************************************
+ * Name: esp_i2c_recvdata
+ *
+ * Description:
+ *   Transfer data from the FIFO to the driver buffer.
+ *
+ * Parameters:
+ *   priv - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void esp_i2c_recvdata(struct esp_i2c_priv_s *priv)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+  uint32_t cmd = 0;
+  uint8_t n = 0;
+  uint32_t data = 0;
+
+  i2c_ll_get_rxfifo_cnt(priv->ctx->dev, &cmd);
+  n = cmd & 0xff;
+
+  i2c_ll_read_rxfifo(priv->ctx->dev, &msg->buffer[priv->bytes], n);
+  i2c_ll_master_enable_rx_it(priv->ctx->dev);
+
+  priv->bytes += n;
+}
+
+/****************************************************************************
+ * Name: esp_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 esp_i2c_startrecv(struct esp_i2c_priv_s *priv)
+{
+  int ack_value = 0;
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+  int n = msg->length - priv->bytes;
+  i2c_ll_hw_cmd_t read_cmd;
+  i2c_ll_hw_cmd_t end_cmd;
+
+  if (n > 1)
+    {
+      n -= 1;
+      n = n < I2C_FIFO_SIZE ? n : I2C_FIFO_SIZE;
+      ack_value = 0;
+    }
+  else
+    {
+      ack_value = 1;
+    }
+
+  read_cmd.byte_num = n;
+  read_cmd.ack_val = ack_value;
+  read_cmd.op_code = I2C_LL_CMD_READ;
+  i2c_ll_write_cmd_reg(priv->ctx->dev, read_cmd, 0);
+
+  end_cmd.op_code = I2C_LL_CMD_END;
+  i2c_ll_write_cmd_reg(priv->ctx->dev, end_cmd, 1);
+
+  /* Enable I2C master RX interrupt */
+
+  esp_i2c_intr_enable(priv);
+
+  /* Update I2C configuration */
+
+  /* Configure the I2C to trigger a transaction */
+
+  i2c_hal_master_trans_start(priv->ctx);
+}
+
+/****************************************************************************
+ * Name: esp_i2c_sendstop
+ *
+ * Description:
+ *   Send I2C STOP signal.
+ *
+ * Parameters:
+ *   priv - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void esp_i2c_sendstop(struct esp_i2c_priv_s *priv)
+{
+  i2c_ll_hw_cmd_t stop_cmd =
+    {
+      .op_code = I2C_LL_CMD_STOP
+    };
+
+  i2c_ll_write_cmd_reg(priv->ctx->dev, stop_cmd, 0);
+
+  /* Enable I2C master TX interrupt */
+
+  esp_i2c_intr_enable(priv);
+
+  /* Update I2C configuration */
+
+  /* Configure the I2C to trigger a transaction */
+
+  i2c_hal_master_trans_start(priv->ctx);
+}
+
+/****************************************************************************
+ * Name: esp_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 esp_i2c_init_clock(struct esp_i2c_priv_s *priv,
+                               uint32_t bus_freq)
+{
+  if (bus_freq == priv->clk_freq)
+    {
+      return ;
+    }
+
+  i2c_clock_source_t src_clk = I2C_CLK_SRC_DEFAULT;
+  i2c_hal_set_bus_timing(priv->ctx, priv->config->clk_freq,
+                         src_clk, XTAL_CLK_FREQ);
+  i2c_ll_update(priv->ctx->dev);
+  priv->clk_freq = bus_freq;
+}
+
+/****************************************************************************
+ * Name: esp_i2c_init
+ *
+ * Description:
+ *   Initialize I2C hardware.
+ *
+ * Parameters:
+ *   priv - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void esp_i2c_init(struct esp_i2c_priv_s *priv)
+{
+  const struct esp_i2c_config_s *config = priv->config;
+
+  /* Configure GPIO signals for I2C SCL and SDA pins */
+
+  esp_gpiowrite(config->scl_pin, 1);
+  esp_gpiowrite(config->sda_pin, 1);
+
+  esp_configgpio(config->scl_pin, INPUT_PULLUP | OUTPUT_OPEN_DRAIN);
+  esp_gpio_matrix_out(config->scl_pin, config->scl_outsig, 0, 0);
+  esp_gpio_matrix_in(config->scl_pin, config->scl_insig, 0);
+
+  esp_configgpio(config->sda_pin, INPUT_PULLUP | OUTPUT_OPEN_DRAIN);
+  esp_gpio_matrix_out(config->sda_pin, config->sda_outsig, 0, 0);
+  esp_gpio_matrix_in(config->sda_pin, config->sda_insig, 0);
+
+  /* Enable I2C hardware */
+
+  periph_module_enable(i2c_periph_signal[priv->id].module);
+
+  i2c_hal_init(priv->ctx, priv->id);
+
+  /* Disable I2C interrupts */
+
+  esp_i2c_intr_disable(priv);
+
+  /* Initialize I2C Master  */
+
+  i2c_hal_master_init(priv->ctx);
+
+  /* Configure the hardware filter function */
+
+  i2c_ll_set_filter(priv->ctx->dev, I2C_FILTER_CYC_NUM_DEF);
+
+  /* Initialize I2C bus clock */
+
+  esp_i2c_init_clock(priv, config->clk_freq);
+}
+
+/****************************************************************************
+ * Name: esp_i2c_deinit
+ *
+ * Description:
+ *   Disable I2C hardware.
+ *
+ * Parameters:
+ *   priv - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void esp_i2c_deinit(struct esp_i2c_priv_s *priv)
+{
+  const struct esp_i2c_config_s *config = priv->config;
+
+  priv->clk_freq = 0;
+  i2c_hal_deinit(priv->ctx);
+  periph_module_disable(i2c_periph_signal[priv->id].module);
+}
+
+/****************************************************************************
+ * Name: esp_i2c_reset_fsmc
+ *
+ * Description:
+ *   Reset I2C hardware state machine and registers.
+ *
+ * Parameters:
+ *   priv - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void esp_i2c_reset_fsmc(struct esp_i2c_priv_s *priv)
+{
+  /* Reset FSM machine */
+
+  i2c_hal_master_fsm_rst(priv->ctx);
+}
+
+/****************************************************************************
+ * Name: esp_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 esp_i2c_sem_waitdone(struct esp_i2c_priv_s *priv)
+{
+  return nxsem_tickwait_uninterruptible(&priv->sem_isr,
+                                        ESPRESSIF_I2CTIMEOTICKS);
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_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 esp_i2c_polling_waitdone(struct esp_i2c_priv_s *priv)
+{
+  int ret;
+  clock_t current;
+  clock_t timeout;
+  uint32_t status = 0;
+  i2c_intr_event_t event = 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 ((sclock_t)(current - timeout) < 0 && (priv->error == 0))
+    {
+      /* Check if any interrupt triggered, clear them
+       * process the operation.
+       */
+
+      i2c_ll_get_intr_mask(priv->ctx->dev, &status);
+      if (status != 0)
+        {
+          i2c_ll_master_get_event(priv->ctx->dev, &event);
+          /* 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 (event == I2C_INTR_EVENT_TRANS_DONE)
+            {
+              i2c_ll_clear_intr_mask(priv->ctx->dev, status);
+              break;
+            }
+
+          i2c_ll_clear_intr_mask(priv->ctx->dev, status);
+          esp_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)
+    {
+      ret = ERROR;
+    }
+  else
+    {
+      ret = OK;
+    }
+
+  /* Disable all interrupts */
+
+  esp_i2c_intr_disable(priv);
+
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Device Driver Operations
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_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 esp_i2c_transfer(struct i2c_master_s *dev,
+                            struct i2c_msg_s *msgs,
+                            int count)
+{
+  int ret = OK;
+  struct esp_i2c_priv_s *priv = (struct esp_i2c_priv_s *)dev;
+#ifdef CONFIG_I2C_TRACE
+  uint32_t status = 0;
+#endif
+
+  i2cinfo("Starting transfer request of %d message(s):\n", count);
+
+  DEBUGASSERT(count > 0);
+
+  ret = nxmutex_lock(&priv->lock);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  if (priv->i2cstate != I2CSTATE_IDLE)
+    {
+      esp_i2c_reset_fsmc(priv);
+      priv->i2cstate = I2CSTATE_IDLE;
+    }
+
+  priv->msgv = msgs;
+
+  for (int i = 0; i < count; i++)
+    {
+      esp_i2c_reset_fifo(priv);
+
+      priv->bytes = 0;
+      priv->msgid = i;
+      priv->ready_read = false;
+      priv->error = 0;
+      priv->i2cstate = I2CSTATE_PROC;
+
+      i2cinfo("Sending message %" PRIu8 "...\n", priv->msgid);
+
+      esp_i2c_init_clock(priv, msgs[i].frequency);
+#ifdef CONFIG_I2C_TRACE
+      status = GET_STATUS(priv->ctx->dev);
+#endif
+#ifndef CONFIG_I2C_POLLED
+      if ((msgs[i].flags & I2C_M_NOSTART) != 0)
+        {
+          esp_i2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->bytes, status);
+          esp_i2c_senddata(priv);
+
+          if (priv->bytes == msgs[i].length)
+            {
+              priv->i2cstate = I2CSTATE_STOP;
+              if ((msgs[i].flags & I2C_M_NOSTOP) != 0)
+                {
+                  priv->i2cstate = I2CSTATE_FINISH;
+                }
+            }
+        }
+      else
+#endif
+        {
+          /* Reset I2C trace logic */
+
+          esp_i2c_tracereset(priv);
+
+          esp_i2c_traceevent(priv, I2CEVENT_SENDADDR, msgs[i].addr, status);
+
+          esp_i2c_sendstart(priv);
+        }
+
+#ifndef CONFIG_I2C_POLLED
+      if (esp_i2c_sem_waitdone(priv) < 0)
+        {
+          i2cerr("Message %" PRIu8 " timed out.\n", priv->msgid);
+          ret = -ETIMEDOUT;
+          break;
+        }
+      else
+        {
+          if (priv->error != 0)
+            {
+              i2cerr("Transfer error %" PRIu32 "\n", priv->error);
+              ret = -EIO;
+              break;
+            }
+          else
+            {
+              priv->i2cstate = I2CSTATE_IDLE;
+              ret = OK;
+            }
+        }
+#else
+      ret = esp_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 */
+
+  esp_i2c_tracedump(priv);
+  nxmutex_unlock(&priv->lock);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp_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.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_RESET
+static void esp_i2c_clear_bus(struct esp_i2c_priv_s *priv)
+{
+  i2c_ll_master_clr_bus(priv->ctx->dev);
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_i2c_reset
+ *
+ * Description:
+ *   Perform an I2C bus reset in an attempt to break loose stuck I2C devices.
+ *
+ * Parameters:
+ *   dev - Device-specific state data
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success. A negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_RESET
+static int esp_i2c_reset(struct i2c_master_s *dev)
+{
+  irqstate_t flags;
+  struct esp_i2c_priv_s *priv = (struct esp_i2c_priv_s *)dev;
+
+  DEBUGASSERT(dev);
+
+  DEBUGASSERT(priv->refs > 0);
+
+  flags = enter_critical_section();
+
+  esp_i2c_reset_fsmc(priv);
+
+  /* Clear bus */
+
+  esp_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: esp_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 esp_i2c_traceclear(struct esp_i2c_priv_s *priv)
+{
+  struct esp_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: esp_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 esp_i2c_tracereset(struct esp_i2c_priv_s *priv)
+{
+  priv->tndx       = 0;
+  priv->start_time = clock_systime_ticks();
+  esp_i2c_traceclear(priv);
+}
+#endif /* CONFIG_I2C_TRACE */
+
+/****************************************************************************
+ * Name: esp_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 esp_i2c_tracenew(struct esp_i2c_priv_s *priv,
+                             uint32_t status)
+{
+  struct esp_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 */
+
+      esp_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: esp_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 esp_i2c_traceevent(struct esp_i2c_priv_s *priv,
+                               enum esp_trace_e event,
+                               uint32_t parm,
+                               uint32_t status)
+{
+  /* Check for new trace setup */
+
+  esp_i2c_tracenew(priv, status);
+
+  if (event != I2CEVENT_NONE)
+    {
+      struct esp_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++;
+      esp_i2c_traceclear(priv);
+    }
+}
+#endif /* CONFIG_I2C_TRACE */
+
+/****************************************************************************
+ * Name: esp_i2c_tracedump
+ *
+ * Description:
+ *   Dump the trace results.
+ *
+ * Parameters:
+ *   priv - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_TRACE
+static void esp_i2c_tracedump(struct esp_i2c_priv_s *priv)
+{
+  struct esp_trace_s *trace;
+  int i;
+
+  syslog(LOG_DEBUG, "Elapsed time: %" PRIu32 "\n",
+         (clock_systime_ticks() - priv->start_time));
+
+  for (i = 0; i < priv->tndx; i++)
+    {
+      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: esp_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 esp_i2c_irq(int cpuint, void *context, void *arg)
+{
+  struct esp_i2c_priv_s *priv = (struct esp_i2c_priv_s *)arg;
+  uint32_t irq_status = 0;
+
+  i2c_ll_get_intr_mask(priv->ctx->dev, &irq_status);
+  i2c_ll_clear_intr_mask(priv->ctx->dev, irq_status);
+  esp_i2c_process(priv , irq_status);
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_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 inline void esp_i2c_process(struct esp_i2c_priv_s *priv,
+                                   uint32_t irq_status)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+#ifdef CONFIG_I2C_TRACE
+  uint32_t status = 0;
+  status = GET_STATUS(priv->ctx->dev);
+#endif
+  /* Check for any errors */
+
+  if (I2C_INT_ERR_MASK & irq_status)
+    {
+      priv->error = irq_status & I2C_INT_ERR_MASK;
+      priv->i2cstate = I2CSTATE_ERROR;
+      esp_i2c_traceevent(priv, I2CEVENT_ERROR, priv->error, status);
+      esp_i2c_intr_disable(priv);
+#ifndef CONFIG_I2C_POLLED
+      nxsem_post(&priv->sem_isr);
+#endif
+    }
+  else
+    {
+      if (priv->i2cstate == I2CSTATE_PROC)
+        {
+          if (msg->flags & I2C_M_READ)
+            {
+              if (priv->ready_read)
+                {
+                  esp_i2c_traceevent(priv, I2CEVENT_RCVBYTE, priv->bytes,
+                                     status);
+                  esp_i2c_recvdata(priv);
+
+                  priv->ready_read = false;
+                }
+
+              if (priv->bytes == msg->length)
+                {
+                  esp_i2c_traceevent(priv, I2CEVENT_STOP, msg->length,
+                                     status);
+                  esp_i2c_sendstop(priv);
+#ifndef CONFIG_I2C_POLLED
+                  priv->i2cstate = I2CSTATE_FINISH;
+#endif
+                }
+              else
+                {
+                  esp_i2c_traceevent(priv, I2CEVENT_RCVMODEEN, 0,
+                                     status);
+                  esp_i2c_startrecv(priv);
+
+                  priv->ready_read = true;
+                }
+            }
+          else
+            {
+              esp_i2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->bytes,
+                                 status);
+              esp_i2c_senddata(priv);
+
+              if (priv->bytes == msg->length)
+                {
+                  priv->i2cstate = I2CSTATE_STOP;
+#ifndef CONFIG_I2C_POLLED
+                  if ((msg->flags & I2C_M_NOSTOP) != 0)
+                    {
+                      priv->i2cstate = I2CSTATE_FINISH;
+                    }
+#endif
+                }
+            }
+        }
+      else if (priv->i2cstate == I2CSTATE_STOP)
+        {
+          esp_i2c_traceevent(priv, I2CEVENT_STOP, msg->length,
+                             status);
+          esp_i2c_sendstop(priv);
+
+#ifndef CONFIG_I2C_POLLED
+          priv->i2cstate = I2CSTATE_FINISH;
+#endif
+        }
+#ifndef CONFIG_I2C_POLLED
+      else if (priv->i2cstate == I2CSTATE_FINISH)
+        {
+          esp_i2c_intr_disable(priv);
+          nxsem_post(&priv->sem_isr);
+        }
+#endif
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_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 *esp_i2cbus_initialize(int port)
+{
+  struct esp_i2c_priv_s *priv;
+#ifndef CONFIG_I2C_POLLED
+  const struct esp_i2c_config_s *config;
+  int ret;
+#endif
+
+  switch (port)
+    {
+#ifdef CONFIG_ESPRESSIF_I2C0
+    case ESPRESSIF_I2C0:
+      priv = &esp_i2c0_priv;
+      break;
+#endif
+#ifdef CONFIG_ESPRESSIF_I2C1
+    case ESPRESSIF_I2C1:
+      priv = &esp_i2c1_priv;
+      break;
+#endif
+    default:
+      return NULL;
+    }
+
+  nxmutex_lock(&priv->lock);
+
+  if (priv->refs++ != 0)
+    {
+      nxmutex_unlock(&priv->lock);
+
+      i2cinfo("Returning previously initialized I2C bus. "
+              "Handler: %p\n", priv);
+
+      return (struct i2c_master_s *)priv;
+    }
+
+#ifndef CONFIG_I2C_POLLED
+  config = priv->config;
+  if (priv->cpuint != -ENOMEM)
+    {
+      /* Disable the previous IRQ */
+
+      up_disable_irq(config->irq);
+      esp_teardown_irq(config->periph, priv->cpuint);
+    }
+
+  priv->cpuint = esp_setup_irq(config->periph,
+                               ESP_IRQ_PRIORITY_DEFAULT,
+                               ESP_IRQ_TRIGGER_LEVEL);
+  if (priv->cpuint < 0)
+    {
+      /* Failed to allocate a CPU interrupt of this type. */
+
+      priv->refs--;
+      nxmutex_unlock(&priv->lock);
+
+      return NULL;
+    }
+
+  ret = irq_attach(config->irq, esp_i2c_irq, priv);
+  if (ret != OK)
+    {
+      /* Failed to attach IRQ, free the allocated CPU interrupt */
+
+      esp_teardown_irq(config->periph, priv->cpuint);
+      priv->cpuint = -ENOMEM;
+      priv->refs--;
+      nxmutex_unlock(&priv->lock);
+
+      return NULL;
+    }
+
+  /* Enable the CPU interrupt that is linked to the I2C device. */
+
+  up_enable_irq(config->irq);
+#endif
+
+  esp_i2c_init(priv);
+  nxmutex_unlock(&priv->lock);
+
+  i2cinfo("I2C bus initialized! Handler: %p\n", priv);
+
+  return (struct i2c_master_s *)priv;
+}
+
+/****************************************************************************
+ * Name: esp_i2cbus_uninitialize
+ *
+ * Description:
+ *   De-initialize the selected I2C port and power down the device.
+ *
+ * Parameters:
+ *   dev - Device structure as returned by
+ *         esp_i2cbus_initialize()
+ *
+ * Returned Value:
+ *   OK is returned on success. ERROR is returned when internal reference
+ *   count mismatches or dev points to invalid hardware device.
+ *
+ ****************************************************************************/
+
+int esp_i2cbus_uninitialize(struct i2c_master_s *dev)
+{
+  struct esp_i2c_priv_s *priv = (struct esp_i2c_priv_s *)dev;
+
+  DEBUGASSERT(dev);
+
+  if (priv->refs == 0)
+    {
+      return ERROR;
+    }
+
+  nxmutex_lock(&priv->lock);
+  if (--priv->refs)
+    {
+      nxmutex_unlock(&priv->lock);
+      return OK;
+    }
+
+#ifndef CONFIG_I2C_POLLED
+  up_disable_irq(priv->config->irq);
+  esp_teardown_irq(priv->config->periph, priv->cpuint);
+  priv->cpuint = -ENOMEM;
+#endif
+
+  esp_i2c_deinit(priv);
+  nxmutex_unlock(&priv->lock);
+
+  return OK;
+}
+
+#endif /* CONFIG_ESPRESSIF_I2C */
diff --git a/arch/risc-v/src/common/espressif/esp_i2c.h 
b/arch/risc-v/src/common/espressif/esp_i2c.h
new file mode 100644
index 0000000000..8a51a2ee85
--- /dev/null
+++ b/arch/risc-v/src/common/espressif/esp_i2c.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+ * arch/risc-v/src/common/espressif/esp_i2c.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#ifndef __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_I2C_H
+#define __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_I2C_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/i2c/i2c_master.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_ESPRESSIF_I2C0
+#  define ESPRESSIF_I2C0 0
+#endif
+
+#ifdef CONFIG_ESPRESSIF_I2C1
+#  define ESPRESSIF_I2C1 1
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_i2cbus_initialize
+ *
+ * Description:
+ *   Initialize the selected I2C port. And return a unique instance of struct
+ *   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.
+ *
+ * Input Parameters:
+ *   port - Port number (for hardware that has multiple I2C interfaces)
+ *
+ * Returned Value:
+ *   Valid I2C device structure reference on success; a NULL on failure
+ *
+ ****************************************************************************/
+
+struct i2c_master_s *esp_i2cbus_initialize(int port);
+
+/****************************************************************************
+ * Name: esp_i2cbus_uninitialize
+ *
+ * Description:
+ *   De-initialize the selected I2C port, and power down the device.
+ *
+ * Input Parameters:
+ *   dev - Device structure as returned by the esp_i2cbus_initialize()
+ *
+ * Returned Value:
+ *   OK on success, ERROR when internal reference count mismatch or dev
+ *   points to invalid hardware device.
+ *
+ ****************************************************************************/
+
+int esp_i2cbus_uninitialize(struct i2c_master_s *dev);
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_I2C_H */
diff --git a/arch/risc-v/src/esp32c3/hal_esp32c3.mk 
b/arch/risc-v/src/esp32c3/hal_esp32c3.mk
index e12dc422ac..44c688bcce 100644
--- a/arch/risc-v/src/esp32c3/hal_esp32c3.mk
+++ b/arch/risc-v/src/esp32c3/hal_esp32c3.mk
@@ -125,6 +125,7 @@ CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)mpu_hal.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)mmu_hal.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)rmt_hal.c
+CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)i2c_hal.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_hal.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_hal_iram.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)twai_hal.c
@@ -144,6 +145,7 @@ CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)rmt_periph.c
+CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)i2c_periph.c
 
 ifeq ($(CONFIG_ESPRESSIF_SIMPLE_BOOT),y)
   CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)nuttx$(DELIM)src$(DELIM)bootloader_banner_wrap.c
diff --git a/arch/risc-v/src/esp32c6/hal_esp32c6.mk 
b/arch/risc-v/src/esp32c6/hal_esp32c6.mk
index 0ff90470b3..6c8787704b 100644
--- a/arch/risc-v/src/esp32c6/hal_esp32c6.mk
+++ b/arch/risc-v/src/esp32c6/hal_esp32c6.mk
@@ -125,6 +125,7 @@ CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)ledc_hal_iram.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)lp_timer_hal.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)rmt_hal.c
+CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)i2c_hal.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_hal.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_hal_iram.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)timer_hal.c
@@ -149,6 +150,7 @@ CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)rmt_periph.c
+CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)i2c_periph.c
 
 ifeq ($(CONFIG_ESPRESSIF_SIMPLE_BOOT),y)
   CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)nuttx$(DELIM)src$(DELIM)bootloader_banner_wrap.c
diff --git a/arch/risc-v/src/esp32h2/hal_esp32h2.mk 
b/arch/risc-v/src/esp32h2/hal_esp32h2.mk
index f9fb63a08a..b2ce97af2b 100644
--- a/arch/risc-v/src/esp32h2/hal_esp32h2.mk
+++ b/arch/risc-v/src/esp32h2/hal_esp32h2.mk
@@ -111,6 +111,7 @@ CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)ledc_hal_iram.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)lp_timer_hal.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)rmt_hal.c
+CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)i2c_hal.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_hal.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)spi_hal_iram.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)timer_hal.c
@@ -132,6 +133,7 @@ CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c
 CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)rmt_periph.c
+CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)i2c_periph.c
 
 ifeq ($(CONFIG_ESPRESSIF_SIMPLE_BOOT),y)
   CHIP_CSRCS += 
chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)nuttx$(DELIM)src$(DELIM)bootloader_banner_wrap.c
diff --git a/boards/risc-v/esp32c3/common/include/esp_board_i2c.h 
b/boards/risc-v/esp32c3/common/include/esp_board_i2c.h
new file mode 100644
index 0000000000..0b6b032231
--- /dev/null
+++ b/boards/risc-v/esp32c3/common/include/esp_board_i2c.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+ * boards/risc-v/esp32c3/common/include/esp_board_i2c.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __BOARDS_RISCV_ESP32C3_COMMON_INCLUDE_ESP_BOARD_I2C_H
+#define __BOARDS_RISCV_ESP32C3_COMMON_INCLUDE_ESP_BOARD_I2C_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_i2c_init
+ *
+ * Description:
+ *   Configure the I2C driver.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned
+ *   to indicate the nature of any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_DRIVER
+int board_i2c_init(void);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __BOARDS_RISCV_ESP32C3_COMMON_INCLUDE_ESP_BOARD_I2C_H */
diff --git a/boards/risc-v/esp32c3/common/src/Make.defs 
b/boards/risc-v/esp32c3/common/src/Make.defs
index bf7869e3b8..62737b91f6 100644
--- a/boards/risc-v/esp32c3/common/src/Make.defs
+++ b/boards/risc-v/esp32c3/common/src/Make.defs
@@ -40,6 +40,10 @@ ifeq ($(CONFIG_SPI_SLAVE_DRIVER),y)
   CSRCS += esp_board_spislavedev.c
 endif
 
+ifeq ($(CONFIG_I2C_DRIVER),y)
+  CSRCS += esp_board_i2c.c
+endif
+
 ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y)
   CSRCS += esp_board_spiflash.c
 endif
diff --git a/boards/risc-v/esp32c3/common/src/esp_board_i2c.c 
b/boards/risc-v/esp32c3/common/src/esp_board_i2c.c
new file mode 100644
index 0000000000..04ade5e6f9
--- /dev/null
+++ b/boards/risc-v/esp32c3/common/src/esp_board_i2c.c
@@ -0,0 +1,82 @@
+/****************************************************************************
+ * boards/risc-v/esp32c3/common/src/esp_board_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>
+
+#include <debug.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <nuttx/i2c/i2c_master.h>
+
+#include "espressif/esp_i2c.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+static int i2c_driver_init(int bus)
+{
+  struct i2c_master_s *i2c;
+  int ret;
+
+  i2c = esp_i2cbus_initialize(bus);
+  if (i2c == NULL)
+    {
+      i2cerr("Failed to get I2C%d interface\n", bus);
+      return -ENODEV;
+    }
+
+  ret = i2c_register(i2c, bus);
+  if (ret < 0)
+    {
+      i2cerr("Failed to register I2C%d driver: %d\n", bus, ret);
+      esp_i2cbus_uninitialize(i2c);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: board_i2c_init
+ *
+ * Description:
+ *   Configure the I2C driver.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned
+ *   to indicate the nature of any failure.
+ *
+ ****************************************************************************/
+
+int board_i2c_init(void)
+{
+  int ret = OK;
+
+#ifdef CONFIG_ESPRESSIF_I2C0
+  ret = i2c_driver_init(ESPRESSIF_I2C0);
+#endif
+
+  return ret;
+}
diff --git a/boards/risc-v/esp32c3/esp32c3-generic/configs/i2c/defconfig 
b/boards/risc-v/esp32c3/esp32c3-generic/configs/i2c/defconfig
new file mode 100644
index 0000000000..078b54642e
--- /dev/null
+++ b/boards/risc-v/esp32c3/esp32c3-generic/configs/i2c/defconfig
@@ -0,0 +1,52 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed 
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that 
includes your
+# modifications.
+#
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+CONFIG_ARCH="risc-v"
+CONFIG_ARCH_BOARD="esp32c3-generic"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_ESP32C3_GENERIC=y
+CONFIG_ARCH_CHIP="esp32c3"
+CONFIG_ARCH_CHIP_ESP32C3_GENERIC=y
+CONFIG_ARCH_INTERRUPTSTACK=1536
+CONFIG_ARCH_RISCV=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=15000
+CONFIG_BUILTIN=y
+CONFIG_DEV_ZERO=y
+CONFIG_ESPRESSIF_I2C0=y
+CONFIG_FS_PROCFS=y
+CONFIG_I2CTOOL_DEFFREQ=100000
+CONFIG_I2CTOOL_MAXBUS=1
+CONFIG_I2C_RESET=y
+CONFIG_I2C_TRACE=y
+CONFIG_IDLETHREAD_STACKSIZE=2048
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBC_PERROR_STDOUT=y
+CONFIG_LIBC_STRERROR=y
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_READLINE=y
+CONFIG_NSH_STRERROR=y
+CONFIG_PREALLOC_TIMERS=0
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_BACKTRACE=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_START_DAY=29
+CONFIG_START_MONTH=11
+CONFIG_START_YEAR=2019
+CONFIG_SYSTEM_DUMPSTACK=y
+CONFIG_SYSTEM_I2CTOOL=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_bringup.c 
b/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_bringup.c
index 41151e4a01..5e640632b2 100644
--- a/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_bringup.c
+++ b/boards/risc-v/esp32c3/esp32c3-generic/src/esp32c3_bringup.c
@@ -36,6 +36,7 @@
 
 #include "esp_board_ledc.h"
 #include "esp_board_spiflash.h"
+#include "esp_board_i2c.h"
 
 #ifdef CONFIG_WATCHDOG
 #  include "espressif/esp_wdt.h"
@@ -257,6 +258,17 @@ int esp_bringup(void)
     }
 #endif
 
+#if defined(CONFIG_I2C_DRIVER)
+  /* Configure I2C peripheral interfaces */
+
+  ret = board_i2c_init();
+
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "Failed to initialize I2C driver: %d\n", ret);
+    }
+#endif
+
 #ifdef CONFIG_ESPRESSIF_TWAI
 
   /* Initialize TWAI and register the TWAI driver. */
diff --git a/boards/risc-v/esp32c6/common/include/esp_board_i2c.h 
b/boards/risc-v/esp32c6/common/include/esp_board_i2c.h
new file mode 100644
index 0000000000..0670875d14
--- /dev/null
+++ b/boards/risc-v/esp32c6/common/include/esp_board_i2c.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+ * boards/risc-v/esp32c6/common/include/esp_board_i2c.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __BOARDS_RISCV_ESP32C6_COMMON_INCLUDE_ESP_BOARD_I2C_H
+#define __BOARDS_RISCV_ESP32C3_COMMON_INCLUDE_ESP_BOARD_I2C_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_i2c_init
+ *
+ * Description:
+ *   Configure the I2C driver.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned
+ *   to indicate the nature of any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_DRIVER
+int board_i2c_init(void);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __BOARDS_RISCV_ESP32C6_COMMON_INCLUDE_ESP_BOARD_I2C_H */
diff --git a/boards/risc-v/esp32c6/common/src/Make.defs 
b/boards/risc-v/esp32c6/common/src/Make.defs
index 177181975b..f628334a0c 100644
--- a/boards/risc-v/esp32c6/common/src/Make.defs
+++ b/boards/risc-v/esp32c6/common/src/Make.defs
@@ -40,6 +40,10 @@ ifeq ($(CONFIG_SPI_SLAVE_DRIVER),y)
   CSRCS += esp_board_spislavedev.c
 endif
 
+ifeq ($(CONFIG_I2C_DRIVER),y)
+  CSRCS += esp_board_i2c.c
+endif
+
 ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y)
   CSRCS += esp_board_spiflash.c
 endif
diff --git a/boards/risc-v/esp32c6/common/src/esp_board_i2c.c 
b/boards/risc-v/esp32c6/common/src/esp_board_i2c.c
new file mode 100644
index 0000000000..094f742b8e
--- /dev/null
+++ b/boards/risc-v/esp32c6/common/src/esp_board_i2c.c
@@ -0,0 +1,82 @@
+/****************************************************************************
+ * boards/risc-v/esp32c6/common/src/esp_board_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>
+
+#include <debug.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <nuttx/i2c/i2c_master.h>
+
+#include "espressif/esp_i2c.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+static int i2c_driver_init(int bus)
+{
+  struct i2c_master_s *i2c;
+  int ret;
+
+  i2c = esp_i2cbus_initialize(bus);
+  if (i2c == NULL)
+    {
+      i2cerr("Failed to get I2C%d interface\n", bus);
+      return -ENODEV;
+    }
+
+  ret = i2c_register(i2c, bus);
+  if (ret < 0)
+    {
+      i2cerr("Failed to register I2C%d driver: %d\n", bus, ret);
+      esp_i2cbus_uninitialize(i2c);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: board_i2c_init
+ *
+ * Description:
+ *   Configure the I2C driver.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned
+ *   to indicate the nature of any failure.
+ *
+ ****************************************************************************/
+
+int board_i2c_init(void)
+{
+  int ret = OK;
+
+#ifdef CONFIG_ESPRESSIF_I2C0
+  ret = i2c_driver_init(ESPRESSIF_I2C0);
+#endif
+
+  return ret;
+}
diff --git a/boards/risc-v/esp32c6/esp32c6-devkitc/configs/i2c/defconfig 
b/boards/risc-v/esp32c6/esp32c6-devkitc/configs/i2c/defconfig
new file mode 100644
index 0000000000..d1d258708f
--- /dev/null
+++ b/boards/risc-v/esp32c6/esp32c6-devkitc/configs/i2c/defconfig
@@ -0,0 +1,54 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed 
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that 
includes your
+# modifications.
+#
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+CONFIG_ARCH="risc-v"
+CONFIG_ARCH_BOARD="esp32c6-devkitc"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_ESP32C6_DEVKITC=y
+CONFIG_ARCH_CHIP="esp32c6"
+CONFIG_ARCH_CHIP_ESP32C6=y
+CONFIG_ARCH_CHIP_ESP32C6WROOM1=y
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_RISCV=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=15000
+CONFIG_BUILTIN=y
+CONFIG_DEV_ZERO=y
+CONFIG_ESPRESSIF_ESP32C6=y
+CONFIG_ESPRESSIF_I2C0=y
+CONFIG_FS_PROCFS=y
+CONFIG_I2CTOOL_DEFFREQ=100000
+CONFIG_I2CTOOL_MAXBUS=1
+CONFIG_I2C_RESET=y
+CONFIG_I2C_TRACE=y
+CONFIG_IDLETHREAD_STACKSIZE=2048
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBC_PERROR_STDOUT=y
+CONFIG_LIBC_STRERROR=y
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_READLINE=y
+CONFIG_NSH_STRERROR=y
+CONFIG_PREALLOC_TIMERS=0
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_BACKTRACE=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_START_DAY=29
+CONFIG_START_MONTH=11
+CONFIG_START_YEAR=2019
+CONFIG_SYSTEM_DUMPSTACK=y
+CONFIG_SYSTEM_I2CTOOL=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c 
b/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c
index d2af1a6352..a101882620 100644
--- a/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c
+++ b/boards/risc-v/esp32c6/esp32c6-devkitc/src/esp32c6_bringup.c
@@ -36,6 +36,7 @@
 
 #include "esp_board_ledc.h"
 #include "esp_board_spiflash.h"
+#include "esp_board_i2c.h"
 
 #ifdef CONFIG_WATCHDOG
 #  include "espressif/esp_wdt.h"
@@ -226,6 +227,17 @@ int esp_bringup(void)
     }
 #endif
 
+#if defined(CONFIG_I2C_DRIVER)
+  /* Configure I2C peripheral interfaces */
+
+  ret = board_i2c_init();
+
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "Failed to initialize I2C driver: %d\n", ret);
+    }
+#endif
+
 #ifdef CONFIG_ESPRESSIF_TWAI0
 
   /* Initialize TWAI and register the TWAI driver. */
diff --git a/boards/risc-v/esp32c6/esp32c6-devkitm/configs/i2c/defconfig 
b/boards/risc-v/esp32c6/esp32c6-devkitm/configs/i2c/defconfig
new file mode 100644
index 0000000000..56903a9355
--- /dev/null
+++ b/boards/risc-v/esp32c6/esp32c6-devkitm/configs/i2c/defconfig
@@ -0,0 +1,54 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed 
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that 
includes your
+# modifications.
+#
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+CONFIG_ARCH="risc-v"
+CONFIG_ARCH_BOARD="esp32c6-devkitm"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_ESP32C6_DEVKITM=y
+CONFIG_ARCH_CHIP="esp32c6"
+CONFIG_ARCH_CHIP_ESP32C6=y
+CONFIG_ARCH_CHIP_ESP32C6MINI1=y
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_RISCV=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=15000
+CONFIG_BUILTIN=y
+CONFIG_DEV_ZERO=y
+CONFIG_ESPRESSIF_ESP32C6=y
+CONFIG_ESPRESSIF_I2C0=y
+CONFIG_FS_PROCFS=y
+CONFIG_I2CTOOL_DEFFREQ=100000
+CONFIG_I2CTOOL_MAXBUS=1
+CONFIG_I2C_RESET=y
+CONFIG_I2C_TRACE=y
+CONFIG_IDLETHREAD_STACKSIZE=2048
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBC_PERROR_STDOUT=y
+CONFIG_LIBC_STRERROR=y
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_READLINE=y
+CONFIG_NSH_STRERROR=y
+CONFIG_PREALLOC_TIMERS=0
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_BACKTRACE=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_START_DAY=29
+CONFIG_START_MONTH=11
+CONFIG_START_YEAR=2019
+CONFIG_SYSTEM_DUMPSTACK=y
+CONFIG_SYSTEM_I2CTOOL=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/risc-v/esp32c6/esp32c6-devkitm/src/esp32c6_bringup.c 
b/boards/risc-v/esp32c6/esp32c6-devkitm/src/esp32c6_bringup.c
index d4cf38dc98..d457895ef1 100644
--- a/boards/risc-v/esp32c6/esp32c6-devkitm/src/esp32c6_bringup.c
+++ b/boards/risc-v/esp32c6/esp32c6-devkitm/src/esp32c6_bringup.c
@@ -36,6 +36,7 @@
 
 #include "esp_board_ledc.h"
 #include "esp_board_spiflash.h"
+#include "esp_board_i2c.h"
 
 #ifdef CONFIG_WATCHDOG
 #  include "espressif/esp_wdt.h"
@@ -226,6 +227,17 @@ int esp_bringup(void)
     }
 #endif
 
+#if defined(CONFIG_I2C_DRIVER)
+  /* Configure I2C peripheral interfaces */
+
+  ret = board_i2c_init();
+
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "Failed to initialize I2C driver: %d\n", ret);
+    }
+#endif
+
 #ifdef CONFIG_ESPRESSIF_TWAI0
 
   /* Initialize TWAI and register the TWAI driver. */
diff --git a/boards/risc-v/esp32h2/common/include/esp_board_i2c.h 
b/boards/risc-v/esp32h2/common/include/esp_board_i2c.h
new file mode 100644
index 0000000000..d478a4b640
--- /dev/null
+++ b/boards/risc-v/esp32h2/common/include/esp_board_i2c.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+ * boards/risc-v/esp32h2/common/include/esp_board_i2c.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __BOARDS_RISCV_ESP32H2_COMMON_INCLUDE_ESP_BOARD_I2C_H
+#define __BOARDS_RISCV_ESP32H2_COMMON_INCLUDE_ESP_BOARD_I2C_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_i2c_init
+ *
+ * Description:
+ *   Configure the I2C driver.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned
+ *   to indicate the nature of any failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_DRIVER
+int board_i2c_init(void);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __BOARDS_RISCV_ESP32H2_COMMON_INCLUDE_ESP_BOARD_I2C_H */
diff --git a/boards/risc-v/esp32h2/common/src/Make.defs 
b/boards/risc-v/esp32h2/common/src/Make.defs
index 66daeb3213..74bdae3f2f 100644
--- a/boards/risc-v/esp32h2/common/src/Make.defs
+++ b/boards/risc-v/esp32h2/common/src/Make.defs
@@ -40,6 +40,10 @@ ifeq ($(CONFIG_SPI_SLAVE_DRIVER),y)
   CSRCS += esp_board_spislavedev.c
 endif
 
+ifeq ($(CONFIG_I2C_DRIVER),y)
+  CSRCS += esp_board_i2c.c
+endif
+
 ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y)
   CSRCS += esp_board_spiflash.c
 endif
diff --git a/boards/risc-v/esp32h2/common/src/esp_board_i2c.c 
b/boards/risc-v/esp32h2/common/src/esp_board_i2c.c
new file mode 100644
index 0000000000..76eda63a29
--- /dev/null
+++ b/boards/risc-v/esp32h2/common/src/esp_board_i2c.c
@@ -0,0 +1,90 @@
+/****************************************************************************
+ * boards/risc-v/esp32h2/common/src/esp_board_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>
+
+#include <debug.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <nuttx/i2c/i2c_master.h>
+
+#include "espressif/esp_i2c.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+static int i2c_driver_init(int bus)
+{
+  struct i2c_master_s *i2c;
+  int ret;
+
+  i2c = esp_i2cbus_initialize(bus);
+  if (i2c == NULL)
+    {
+      i2cerr("Failed to get I2C%d interface\n", bus);
+      return -ENODEV;
+    }
+
+  ret = i2c_register(i2c, bus);
+  if (ret < 0)
+    {
+      i2cerr("Failed to register I2C%d driver: %d\n", bus, ret);
+      esp_i2cbus_uninitialize(i2c);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: board_i2c_init
+ *
+ * Description:
+ *   Configure the I2C driver.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; A negated errno value is returned
+ *   to indicate the nature of any failure.
+ *
+ ****************************************************************************/
+
+int board_i2c_init(void)
+{
+  int ret = OK;
+
+#ifdef CONFIG_ESPRESSIF_I2C0
+  ret = i2c_driver_init(ESPRESSIF_I2C0);
+  if (ret != OK)
+    {
+      return ret;
+    }
+#endif
+
+#ifdef CONFIG_ESPRESSIF_I2C1
+  ret = i2c_driver_init(ESPRESSIF_I2C1);
+#endif
+
+  return ret;
+}
diff --git a/boards/risc-v/esp32h2/esp32h2-devkit/configs/i2c/defconfig 
b/boards/risc-v/esp32h2/esp32h2-devkit/configs/i2c/defconfig
new file mode 100644
index 0000000000..1ea79df2b0
--- /dev/null
+++ b/boards/risc-v/esp32h2/esp32h2-devkit/configs/i2c/defconfig
@@ -0,0 +1,54 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed 
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that 
includes your
+# modifications.
+#
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+CONFIG_ARCH="risc-v"
+CONFIG_ARCH_BOARD="esp32h2-devkit"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_ESP32H2_DEVKIT=y
+CONFIG_ARCH_CHIP="esp32h2"
+CONFIG_ARCH_CHIP_ESP32H2=y
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_RISCV=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=15000
+CONFIG_BUILTIN=y
+CONFIG_DEV_ZERO=y
+CONFIG_ESPRESSIF_ESP32H2=y
+CONFIG_ESPRESSIF_I2C0=y
+CONFIG_ESPRESSIF_I2C1=y
+CONFIG_FS_PROCFS=y
+CONFIG_I2CTOOL_DEFFREQ=100000
+CONFIG_I2CTOOL_MAXBUS=1
+CONFIG_I2C_RESET=y
+CONFIG_I2C_TRACE=y
+CONFIG_IDLETHREAD_STACKSIZE=2048
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBC_PERROR_STDOUT=y
+CONFIG_LIBC_STRERROR=y
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_READLINE=y
+CONFIG_NSH_STRERROR=y
+CONFIG_PREALLOC_TIMERS=0
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_BACKTRACE=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_START_DAY=29
+CONFIG_START_MONTH=11
+CONFIG_START_YEAR=2019
+CONFIG_SYSTEM_DUMPSTACK=y
+CONFIG_SYSTEM_I2CTOOL=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c 
b/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c
index 8af13b13f3..19861b777d 100644
--- a/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c
+++ b/boards/risc-v/esp32h2/esp32h2-devkit/src/esp32h2_bringup.c
@@ -36,6 +36,7 @@
 
 #include "esp_board_ledc.h"
 #include "esp_board_spiflash.h"
+#include "esp_board_i2c.h"
 
 #ifdef CONFIG_WATCHDOG
 #  include "espressif/esp_wdt.h"
@@ -218,6 +219,17 @@ int esp_bringup(void)
     }
 #endif
 
+#if defined(CONFIG_I2C_DRIVER)
+  /* Configure I2C peripheral interfaces */
+
+  ret = board_i2c_init();
+
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "Failed to initialize I2C driver: %d\n", ret);
+    }
+#endif
+
 #ifdef CONFIG_ESPRESSIF_TWAI
 
   /* Initialize TWAI and register the TWAI driver. */


Reply via email to