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

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

commit 59fe35070814ac4eb8f9ee1bbf4bdc5eaba12c81
Author: Eren Terzioglu <eren.terzio...@espressif.com>
AuthorDate: Wed Feb 26 09:33:25 2025 +0100

    arch/risc-v/espressif: Add I2C slave support
    
    Add I2C slave support for arch layer to risc-v based Espressif devices
    
    Signed-off-by: Eren Terzioglu <eren.terzio...@espressif.com>
---
 arch/risc-v/src/common/espressif/Kconfig           |  49 +-
 arch/risc-v/src/common/espressif/Make.defs         |   5 +-
 arch/risc-v/src/common/espressif/esp_i2c.c         |  12 +-
 arch/risc-v/src/common/espressif/esp_i2c.h         |   4 +-
 arch/risc-v/src/common/espressif/esp_i2c_slave.c   | 957 +++++++++++++++++++++
 .../espressif/{esp_i2c.h => esp_i2c_slave.h}       |  39 +-
 6 files changed, 1030 insertions(+), 36 deletions(-)

diff --git a/arch/risc-v/src/common/espressif/Kconfig 
b/arch/risc-v/src/common/espressif/Kconfig
index a769171459..a30f636b3a 100644
--- a/arch/risc-v/src/common/espressif/Kconfig
+++ b/arch/risc-v/src/common/espressif/Kconfig
@@ -338,9 +338,14 @@ config ESPRESSIF_I2C
        bool
        default n
 
-config ESPRESSIF_I2C_PERIPH
+config ESPRESSIF_I2C_PERIPH_MASTER_MODE
        bool
-       depends on (ESPRESSIF_I2C0 || ESPRESSIF_I2C1)
+       depends on (ESPRESSIF_I2C0_MASTER_MODE || ESPRESSIF_I2C1_MASTER_MODE)
+       default n
+
+config ESPRESSIF_I2C_PERIPH_SLAVE_MODE
+       bool
+       depends on (ESPRESSIF_I2C0_SLAVE_MODE || ESPRESSIF_I2C1_SLAVE_MODE)
        default n
 
 config ESPRESSIF_I2C0
@@ -348,7 +353,6 @@ config ESPRESSIF_I2C0
        default n
        select ESPRESSIF_I2C
        select I2C
-       select ESPRESSIF_I2C_PERIPH
 
 config ESPRESSIF_I2C1
        bool "I2C 1"
@@ -356,7 +360,40 @@ config ESPRESSIF_I2C1
        depends on ARCH_CHIP_ESP32H2
        select ESPRESSIF_I2C
        select I2C
-       select ESPRESSIF_I2C_PERIPH
+
+choice ESPRESSIF_I2C0_MODE
+       prompt "I2C0 Mode"
+       depends on ESPRESSIF_I2C0
+       default ESPRESSIF_I2C0_MASTER_MODE
+
+config ESPRESSIF_I2C0_MASTER_MODE
+       bool "I2C0 Master Mode"
+       select ESPRESSIF_I2C_PERIPH_MASTER_MODE
+
+config ESPRESSIF_I2C0_SLAVE_MODE
+       bool "I2C0 Slave Mode"
+       select I2C_SLAVE
+       select I2C_SLAVE_DRIVER
+       select ESPRESSIF_I2C_PERIPH_SLAVE_MODE
+
+endchoice # ESPRESSIF_I2C0_MODE
+
+choice ESPRESSIF_I2C1_MODE
+       prompt "I2C1 Mode"
+       depends on ESPRESSIF_I2C1
+       default ESPRESSIF_I2C1_MASTER_MODE
+
+config ESPRESSIF_I2C1_MASTER_MODE
+       bool "I2C1 Master Mode"
+       select ESPRESSIF_I2C_PERIPH_MASTER_MODE
+
+config ESPRESSIF_I2C1_SLAVE_MODE
+       bool "I2C1 Slave Mode"
+       select I2C_SLAVE
+       select I2C_SLAVE_DRIVER
+       select ESPRESSIF_I2C_PERIPH_SLAVE_MODE
+
+endchoice # ESPRESSIF_I2C1_MODE
 
 config ESPRESSIF_I2C_BITBANG
        bool "I2C Bitbang"
@@ -1826,12 +1863,12 @@ endif # ESPRESSIF_I2C_BITBANG
 
 config ESPRESSIF_I2CTIMEOSEC
        int "Timeout seconds"
-       depends on ESPRESSIF_I2C_PERIPH
+       depends on ESPRESSIF_I2C_PERIPH_MASTER_MODE
        default 0
 
 config ESPRESSIF_I2CTIMEOMS
        int "Timeout milliseconds"
-       depends on ESPRESSIF_I2C_PERIPH
+       depends on ESPRESSIF_I2C_PERIPH_MASTER_MODE
        default 500
 
 endmenu # I2C configuration
diff --git a/arch/risc-v/src/common/espressif/Make.defs 
b/arch/risc-v/src/common/espressif/Make.defs
index d62602887b..d4778c76a7 100644
--- a/arch/risc-v/src/common/espressif/Make.defs
+++ b/arch/risc-v/src/common/espressif/Make.defs
@@ -108,12 +108,15 @@ ifeq ($(CONFIG_ESPRESSIF_TEMP),y)
 endif
 
 ifeq ($(CONFIG_ESPRESSIF_I2C),y)
-       ifeq ($(CONFIG_ESPRESSIF_I2C_PERIPH),y)
+       ifeq ($(CONFIG_ESPRESSIF_I2C_PERIPH_MASTER_MODE),y)
                CHIP_CSRCS += esp_i2c.c
        endif
        ifeq ($(CONFIG_ESPRESSIF_I2C_BITBANG),y)
                CHIP_CSRCS += esp_i2c_bitbang.c
        endif
+       ifeq ($(CONFIG_ESPRESSIF_I2C_PERIPH_SLAVE_MODE),y)
+               CHIP_CSRCS += esp_i2c_slave.c
+       endif
 endif
 
 ifeq ($(CONFIG_ESPRESSIF_I2S),y)
diff --git a/arch/risc-v/src/common/espressif/esp_i2c.c 
b/arch/risc-v/src/common/espressif/esp_i2c.c
index 29ebbbc8b3..84a6578501 100644
--- a/arch/risc-v/src/common/espressif/esp_i2c.c
+++ b/arch/risc-v/src/common/espressif/esp_i2c.c
@@ -26,7 +26,7 @@
 
 #include <nuttx/config.h>
 
-#ifdef CONFIG_ESPRESSIF_I2C_PERIPH
+#ifdef CONFIG_ESPRESSIF_I2C_PERIPH_MASTER_MODE
 
 #include <sys/types.h>
 #include <stdio.h>
@@ -316,7 +316,7 @@ static const struct i2c_ops_s esp_i2c_ops =
 #endif
 };
 
-#ifdef CONFIG_ESPRESSIF_I2C0
+#ifdef CONFIG_ESPRESSIF_I2C0_MASTER_MODE
 
 i2c_hal_context_t i2c0_ctx =
 {
@@ -366,7 +366,7 @@ static struct esp_i2c_priv_s esp_i2c0_priv =
 };
 #endif
 
-#ifdef CONFIG_ESPRESSIF_I2C1
+#ifdef CONFIG_ESPRESSIF_I2C1_MASTER_MODE
 
 i2c_hal_context_t i2c1_ctx =
 {
@@ -1485,12 +1485,12 @@ struct i2c_master_s *esp_i2cbus_initialize(int port)
 
   switch (port)
     {
-#ifdef CONFIG_ESPRESSIF_I2C0
+#ifdef CONFIG_ESPRESSIF_I2C0_MASTER_MODE
     case ESPRESSIF_I2C0:
       priv = &esp_i2c0_priv;
       break;
 #endif
-#ifdef CONFIG_ESPRESSIF_I2C1
+#ifdef CONFIG_ESPRESSIF_I2C1_MASTER_MODE
     case ESPRESSIF_I2C1:
       priv = &esp_i2c1_priv;
       break;
@@ -1606,4 +1606,4 @@ int esp_i2cbus_uninitialize(struct i2c_master_s *dev)
   return OK;
 }
 
-#endif /* CONFIG_ESPRESSIF_I2C_PERIPH */
+#endif /* CONFIG_ESPRESSIF_I2C_PERIPH_MASTER_MODE */
diff --git a/arch/risc-v/src/common/espressif/esp_i2c.h 
b/arch/risc-v/src/common/espressif/esp_i2c.h
index faea37fc97..7b8def9f1c 100644
--- a/arch/risc-v/src/common/espressif/esp_i2c.h
+++ b/arch/risc-v/src/common/espressif/esp_i2c.h
@@ -53,7 +53,7 @@
  * Public Function Prototypes
  ****************************************************************************/
 
-#ifdef CONFIG_ESPRESSIF_I2C_PERIPH
+#ifdef CONFIG_ESPRESSIF_I2C_PERIPH_MASTER_MODE
 /****************************************************************************
  * Name: esp_i2cbus_initialize
  *
@@ -89,7 +89,7 @@ struct i2c_master_s *esp_i2cbus_initialize(int port);
  ****************************************************************************/
 
 int esp_i2cbus_uninitialize(struct i2c_master_s *dev);
-#endif /* CONFIG_ESPRESSIF_I2C_PERIPH */
+#endif /* CONFIG_ESPRESSIF_I2C_PERIPH_MASTER_MODE */
 
 #endif /* __ASSEMBLY__ */
 #endif /* __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_I2C_H */
diff --git a/arch/risc-v/src/common/espressif/esp_i2c_slave.c 
b/arch/risc-v/src/common/espressif/esp_i2c_slave.c
new file mode 100644
index 0000000000..151f631173
--- /dev/null
+++ b/arch/risc-v/src/common/espressif/esp_i2c_slave.c
@@ -0,0 +1,957 @@
+/****************************************************************************
+ * arch/risc-v/src/common/espressif/esp_i2c_slave.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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_PERIPH_SLAVE_MODE
+
+#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/signal.h>
+#include <nuttx/mutex.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/i2c/i2c_slave.h>
+#include <nuttx/kthread.h>
+#include <arch/board/board.h>
+
+#include "esp_i2c_slave.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
+ ****************************************************************************/
+
+#define I2C_FIFO_FULL_THRESH_VAL      28
+#define I2C_FIFO_EMPTY_THRESH_VAL     5
+#define I2C_SLAVE_TIMEOUT_DEFAULT     32000                /* I2C slave 
timeout value, APB clock cycle number */
+#define I2C_SLAVE_SDA_SAMPLE_DEFAULT  10                   /* I2C slave sample 
time after scl positive edge default value */
+#define I2C_SLAVE_SDA_HOLD_DEFAULT    10                   /* I2C slave hold 
time after scl negative edge default value */
+#ifdef CONFIG_I2C_POLLED
+#define I2C_SLAVE_POLL_RATE           10
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* I2C Device hardware configuration */
+
+struct esp_i2c_config_s
+{
+  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 scl_insig;  /* I2C SCL input 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_slaveops_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
+  int cpuint;                       /* CPU interrupt assigned to this I2C */
+#endif
+
+#ifdef CONFIG_I2C_POLLED
+  bool enabled;
+#endif
+
+  uint32_t error;                   /* I2C transform error */
+  i2c_hal_context_t *ctx;           /* Common layer struct */
+  int addr;                         /* Slave device address */
+  int nbits;                        /* Slave device address bit count */
+  i2c_slave_callback_t *cb;         /* Callback function when interrupt 
happens */
+  void *cb_arg;                     /* Argument of callback function */
+  uint32_t tx_length;               /* Location of next TX value */
+  uint8_t *tx_buffer;               /* I2C Slave TX queue buffer */
+  uint32_t rx_length;               /* Location of next RX value */
+  uint8_t *rx_buffer;               /* I2C Slave RX queue buffer */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int esp_i2c_slave_setownaddress(struct i2c_slave_s *dev, int addr,
+                                       int nbits);
+static int esp_i2c_slave_write(struct i2c_slave_s *dev,
+                               const uint8_t *buffer, int buflen);
+static int esp_i2c_slave_read(struct i2c_slave_s *dev,
+                              uint8_t *buffer, int buflen);
+static int esp_i2c_slave_registercallback(struct i2c_slave_s *dev,
+                                          i2c_slave_callback_t *callback,
+                                          void *arg);
+static void esp_i2c_slave_intr_disable(struct esp_i2c_priv_s *priv);
+static void esp_i2c_slave_init(struct esp_i2c_priv_s *priv);
+static void esp_i2c_slave_deinit(struct esp_i2c_priv_s *priv);
+#ifndef CONFIG_I2C_POLLED
+static int esp_i2c_slave_irq(int cpuint, void *context, void *arg);
+#endif
+#ifdef CONFIG_I2C_POLLED
+static int esp_i2c_slave_polling_waitdone(struct esp_i2c_priv_s *priv);
+#endif /* CONFIG_I2C_POLLED */
+static inline void esp_i2c_process(struct esp_i2c_priv_s *priv,
+                                   uint32_t irq_status);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* I2C interface */
+
+static const struct i2c_slaveops_s esp_i2c_ops =
+{
+  .setownaddress    = esp_i2c_slave_setownaddress,
+  .write            = esp_i2c_slave_write,
+  .read             = esp_i2c_slave_read,
+  .registercallback = esp_i2c_slave_registercallback,
+};
+
+#ifdef CONFIG_ESPRESSIF_I2C0_SLAVE
+
+i2c_hal_context_t i2c0_ctx =
+{
+  0
+};
+
+/* I2C device structure */
+
+static const struct esp_i2c_config_s esp_i2c0_config =
+{
+  .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
+  .scl_insig  = I2CEXT0_SCL_IN_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
+  .cpuint     = -ENOMEM,
+#endif
+
+#ifdef CONFIG_I2C_POLLED
+  .enabled    = false,
+#endif
+
+  .error      = 0,
+  .ctx        = &i2c0_ctx,
+  .addr       = 0,
+  .nbits      = 0,
+  .cb         = NULL,
+  .cb_arg     = NULL,
+  .tx_length  = 0,
+  .tx_buffer  = NULL,
+  .rx_length  = 0,
+  .rx_buffer  = NULL
+};
+#endif
+
+#ifdef CONFIG_ESPRESSIF_I2C1_SLAVE
+
+i2c_hal_context_t i2c1_ctx =
+{
+  0
+};
+
+/* I2C device structure */
+
+static const struct esp_i2c_config_s esp_i2c1_config =
+{
+  .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
+  .scl_insig  = I2CEXT1_SCL_IN_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
+  .cpuint     = -ENOMEM,
+#endif
+
+#ifdef CONFIG_I2C_POLLED
+  .enabled    = false,
+#endif
+
+  .error      = 0,
+  .ctx        = &i2c1_ctx,
+  .addr       = 0,
+  .nbits      = 0,
+  .cb         = NULL,
+  .cb_arg     = NULL,
+  .tx_length  = 0,
+  .tx_buffer  = NULL,
+  .rx_length  = 0,
+  .rx_buffer  = NULL
+};
+#endif /* CONFIG_ESPRESSIF_I2C1 */
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_i2c_slave_setownaddress
+ *
+ * Description:
+ *   Set our own I2C address.
+ *
+ *   One may register a callback to be notified about reception. During the
+ *   slave mode reception, the methods READ and WRITE must be used to
+ *   to handle reads and writes from a master.
+ *
+ * Input Parameters:
+ *   dev     - I2C slave device-specific state data
+ *   address - Our own slave address
+ *   nbits   - The number of address bits provided (7 or 10)
+ *
+ * Returned Value:
+ *   OK when successful, or a negated errno when there is an error.
+ *
+ ****************************************************************************/
+
+static int esp_i2c_slave_setownaddress(struct i2c_slave_s *dev, int addr,
+                                       int nbits)
+{
+  struct esp_i2c_priv_s *priv;
+  irqstate_t flags;
+  bool extended_addr = false;
+
+  DEBUGASSERT(dev);
+  priv = (struct esp_i2c_priv_s *)dev;
+  flags = enter_critical_section();
+
+  if (priv->addr == addr && priv->nbits == nbits)
+    {
+      leave_critical_section(flags);
+      return OK;
+    }
+
+  switch (nbits)
+    {
+      case 7:
+        {
+          priv->addr = addr & 0x7f;
+          priv->nbits = 7;
+        }
+        break;
+
+      case 10:
+        {
+          priv->addr = addr & 0x3ff;
+          priv->nbits = 10;
+          extended_addr = true;
+        }
+        break;
+
+      default:
+        {
+          leave_critical_section(flags);
+          return ERROR;
+        }
+        break;
+    }
+
+  i2c_ll_set_slave_addr(priv->ctx->dev, priv->addr, extended_addr);
+  i2c_ll_update(priv->ctx->dev);
+
+  leave_critical_section(flags);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_i2c_slave_write
+ *
+ * Description:
+ *   Send a block of data on I2C when a bus master wants to read data from
+ *   this particular device.
+ *
+ * Input Parameters:
+ *   dev    - I2C slave device-specific state data
+ *   buffer - A pointer to the read-only buffer of data to be written to the
+ *            device
+ *   buflen - The number of bytes to send from the buffer
+ *
+ * Returned Value:
+ *   Returns the number of items written to the I2C memory.
+ *
+ ****************************************************************************/
+
+static int esp_i2c_slave_write(struct i2c_slave_s *dev,
+                               const uint8_t *buffer, int buflen)
+{
+  struct esp_i2c_priv_s *priv = (struct esp_i2c_priv_s *)dev;
+  irqstate_t flags = enter_critical_section();
+  int cnt = buflen;
+#ifdef CONFIG_I2C_POLLED
+  int ret;
+#endif
+
+  /* Update the registered buffer and length */
+
+  priv->tx_buffer = buffer;
+  priv->tx_length = buflen;
+
+  if (buflen > 0)
+    {
+      i2c_ll_slave_enable_tx_it(priv->ctx->dev);
+    }
+
+#ifdef CONFIG_I2C_POLLED
+  ret = esp_i2c_slave_polling_waitdone(priv);
+  if (ret < 0)
+    {
+      cnt = ret;
+    }
+#endif
+
+  leave_critical_section(flags);
+  return cnt;
+}
+
+/****************************************************************************
+ * Name: esp_i2c_slave_read
+ *
+ * Description:
+ *   Receive a block of data from I2C when a bus master writes data addressed
+ *   to this particular device.
+ *
+ * Input Parameters:
+ *   dev    - I2C slave device-specific state data
+ *   buffer - A pointer to a buffer of data to receive the data from the
+ *            device
+ *   buflen - The maximum size of the buffer
+ *
+ * Returned Value:
+ *   OK when successful, or a negated errno when there is an error.
+ *
+ ****************************************************************************/
+
+static int esp_i2c_slave_read(struct i2c_slave_s *dev,
+                              uint8_t *buffer, int buflen)
+{
+  struct esp_i2c_priv_s *priv = (struct esp_i2c_priv_s *)dev;
+  irqstate_t flags = enter_critical_section();
+
+  /* Update the registered buffer and length */
+
+  i2c_ll_slave_enable_rx_it(priv->ctx->dev);
+  priv->rx_buffer  = buffer;
+  priv->rx_length = buflen;
+
+  leave_critical_section(flags);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_i2c_slave_registercallback
+ *
+ * Description:
+ *   Register a callback function that will be invoked when something is
+ *   received on I2C.
+ *
+ * Input Parameters:
+ *   dev      - I2C slave device-specific state data
+ *   callback - The function to be called when something has been received.
+ *   arg      - User provided argument to be used with the callback
+ *
+ * Returned Value:
+ *   OK when successful, or a negated errno when there is an error.
+ *
+ ****************************************************************************/
+
+static int esp_i2c_slave_registercallback(struct i2c_slave_s *dev,
+                                          i2c_slave_callback_t *callback,
+                                          void *arg)
+{
+  struct esp_i2c_priv_s *priv;
+  irqstate_t flags;
+
+  DEBUGASSERT(dev);
+  DEBUGASSERT(callback);
+
+  priv = (struct esp_i2c_priv_s *)dev;
+  flags = enter_critical_section();
+
+  /* Set callback and callback argument */
+
+  priv->cb = callback;
+  priv->cb_arg = arg;
+
+  leave_critical_section(flags);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp_i2c_slave_intr_disable
+ *
+ * Description:
+ *   Disable I2C interrupts.
+ *
+ * Parameters:
+ *   priv - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void esp_i2c_slave_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_slave_init
+ *
+ * Description:
+ *   Initialize I2C hardware.
+ *
+ * Parameters:
+ *   priv - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void esp_i2c_slave_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);
+  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_slave_intr_disable(priv);
+
+  /* Initialize I2C Slave */
+
+  i2c_hal_slave_init(priv->ctx);
+  i2c_ll_slave_tx_auto_start_en(priv->ctx->dev, true);
+  i2c_ll_set_source_clk(priv->ctx->dev, I2C_CLK_SRC_DEFAULT);
+  i2c_ll_set_slave_addr(priv->ctx->dev, priv->addr, false);
+  i2c_ll_set_rxfifo_full_thr(priv->ctx->dev, I2C_FIFO_FULL_THRESH_VAL);
+  i2c_ll_set_txfifo_empty_thr(priv->ctx->dev, I2C_FIFO_EMPTY_THRESH_VAL);
+
+  /* set timing for data */
+
+  i2c_ll_set_sda_timing(priv->ctx->dev, I2C_SLAVE_SDA_SAMPLE_DEFAULT,
+                        I2C_SLAVE_SDA_HOLD_DEFAULT);
+  i2c_ll_set_tout(priv->ctx->dev, I2C_SLAVE_TIMEOUT_DEFAULT);
+  i2c_ll_slave_enable_rx_it(priv->ctx->dev);
+
+  i2c_ll_update(priv->ctx->dev);
+}
+
+/****************************************************************************
+ * Name: esp_i2c_slave_deinit
+ *
+ * Description:
+ *   Disable I2C hardware.
+ *
+ * Parameters:
+ *   priv - Pointer to the internal driver state structure.
+ *
+ ****************************************************************************/
+
+static void esp_i2c_slave_deinit(struct esp_i2c_priv_s *priv)
+{
+  const struct esp_i2c_config_s *config = priv->config;
+
+  i2c_hal_deinit(priv->ctx);
+  periph_module_disable(i2c_periph_signal[priv->id].module);
+}
+
+/****************************************************************************
+ * 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_slave_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);
+  if (irq_status == 0)
+    {
+      return OK;
+    }
+
+  esp_i2c_process(priv , irq_status);
+  i2c_ll_clear_intr_mask(priv->ctx->dev, irq_status);
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: esp_i2c_slave_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.
+ *
+ ****************************************************************************/
+#ifdef CONFIG_I2C_POLLED
+static int esp_i2c_slave_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;
+
+  current = clock_systime_ticks();
+  timeout = current + SEC2TICK(I2C_SLAVE_POLL_RATE);
+
+  while ((sclock_t)(current - timeout) < 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_slave_get_event(priv->ctx->dev, &event);
+
+          esp_i2c_process(priv, status);
+          i2c_ll_clear_intr_mask(priv->ctx->dev, status);
+        }
+
+      /* Update current time */
+
+      current = clock_systime_ticks();
+    }
+
+  if (current >= timeout)
+    {
+      ret = -ETIMEDOUT;
+    }
+  else
+    {
+      ret = OK;
+    }
+
+  /* Disable all interrupts */
+
+  esp_i2c_slave_intr_disable(priv);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp_i2c_slave_thread
+ *
+ * Description:
+ *   Thread for i2c slave driver in polling mode.
+ *
+ * Parameter:
+ *   argc - Number opf arguments
+ *   argv - Pointer to argument list
+ *
+ * Returned Values:
+ *   Zero (OK)
+ *
+ ****************************************************************************/
+
+static int esp_i2c_slave_thread(int argc, char **argv)
+{
+  struct esp_i2c_priv_s *priv =
+      (struct esp_i2c_priv_s *)((uintptr_t)strtoul(argv[1], NULL, 16));
+  int ret;
+
+  nxsig_usleep(1000);
+  while (true)
+    {
+      esp_i2c_slave_polling_waitdone(priv);
+
+      /* Sleeping thread before checking i2c peripheral */
+
+      nxsig_usleep(100);
+    }
+
+  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.
+ *
+ * Returned Values:
+ *   None
+ *
+ ****************************************************************************/
+
+static void esp_i2c_process(struct esp_i2c_priv_s *priv,
+                                   uint32_t irq_status)
+{
+  i2c_intr_event_t evt_type = I2C_INTR_EVENT_ERR;
+  uint32_t rx_fifo_cnt;
+  uint32_t tx_fifo_rem;
+
+  i2c_ll_slave_get_event(priv->ctx->dev, &evt_type);
+  if (evt_type == I2C_INTR_EVENT_TRANS_DONE ||
+      evt_type == I2C_INTR_EVENT_RXFIFO_FULL)
+    {
+      i2c_ll_get_rxfifo_cnt(priv->ctx->dev, &rx_fifo_cnt);
+      i2c_ll_read_rxfifo(priv->ctx->dev, priv->rx_buffer, rx_fifo_cnt);
+      priv->rx_length -= rx_fifo_cnt;
+
+      /* Code closed for temporary time due to upper layer function issues */
+
+#if 0
+      if (priv->cb != NULL)
+        {
+          priv->cb(priv->cb_arg, I2CS_RX_COMPLETE, rx_fifo_cnt);
+        }
+#endif
+    }
+  else if (evt_type == I2C_INTR_EVENT_TXFIFO_EMPTY)
+    {
+      i2c_ll_get_txfifo_len(priv->ctx->dev, &tx_fifo_rem);
+      if (tx_fifo_rem != 0)
+        {
+          i2c_ll_write_txfifo(priv->ctx->dev, priv->tx_buffer, tx_fifo_rem);
+        }
+      else
+        {
+          i2c_ll_slave_disable_tx_it(priv->ctx->dev);
+        }
+
+      priv->tx_length -= tx_fifo_rem;
+
+      /* Code closed for temporary time due to upper layer function issues */
+
+#if 0
+      if (priv->cb != NULL)
+        {
+          priv->cb(priv->cb_arg, I2CS_TX_COMPLETE, tx_fifo_rem);
+        }
+#endif
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_i2cbus_slave_initialize
+ *
+ * Description:
+ *   Initialize the selected I2C port. And return a pointer to an unique
+ *   instance of struct i2c_slave_s. This function may be called to obtain
+ *   multiple instances of the interface, each of which may be set up with a
+ *   different frequency.
+ *
+ * Parameters:
+ *   port - Port number of the I2C interface to be initialized.
+ *   addr - Adress of the slave device
+ *
+ * Returned Value:
+ *   Pointer to valid I2C device structure is returned on success.
+ *   A NULL pointer is returned on failure.
+ *
+ ****************************************************************************/
+
+struct i2c_slave_s *esp_i2cbus_slave_initialize(int port, int addr)
+{
+  struct esp_i2c_priv_s *priv;
+  int ret;
+#ifndef CONFIG_I2C_POLLED
+  const struct esp_i2c_config_s *config;
+#else
+  char *argv[2];
+  char arg1[32];
+#endif
+
+  switch (port)
+    {
+#ifdef CONFIG_ESPRESSIF_I2C0_SLAVE
+    case ESPRESSIF_I2C0_SLAVE:
+      priv = &esp_i2c0_priv;
+      break;
+#endif
+#ifdef CONFIG_ESPRESSIF_I2C1_SLAVE
+    case ESPRESSIF_I2C1_SLAVE:
+      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_slave_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_slave_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);
+#else
+  /* Create thread for polling sensor data */
+
+  snprintf(arg1, 16, "%p", priv);
+  argv[0] = arg1;
+  argv[1] = NULL;
+
+  ret = kthread_create("esp_i2c_slave_thread",
+                       SCHED_PRIORITY_DEFAULT,
+                       128,
+                       esp_i2c_slave_thread,
+                       argv);
+  if (ret < 0)
+    {
+      kmm_free(priv);
+      return NULL;
+    }
+
+#endif
+
+  priv->addr = addr;
+  esp_i2c_slave_init(priv);
+  nxmutex_unlock(&priv->lock);
+
+#ifdef CONFIG_I2C_POLLED
+  priv->enabled = true;
+#endif
+
+  i2cinfo("I2C bus initialized! Handler: %p\n", priv);
+
+  return (struct i2c_slave_s *)priv;
+}
+
+/****************************************************************************
+ * Name: esp_i2cbus_slave_uninitialize
+ *
+ * Description:
+ *   De-initialize the selected I2C port and power down the device.
+ *
+ * Parameters:
+ *   dev - Device structure as returned by
+ *         esp_i2cbus_slave_uninitialize()
+ *
+ * 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_slave_uninitialize(struct i2c_slave_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
+
+#ifdef CONFIG_I2C_POLLED
+  priv->enabled = false;
+#endif
+
+  esp_i2c_slave_deinit(priv);
+  nxmutex_unlock(&priv->lock);
+
+  return OK;
+}
+
+#endif /* CONFIG_ESPRESSIF_I2C_PERIPH_SLAVE_MODE */
diff --git a/arch/risc-v/src/common/espressif/esp_i2c.h 
b/arch/risc-v/src/common/espressif/esp_i2c_slave.h
similarity index 73%
copy from arch/risc-v/src/common/espressif/esp_i2c.h
copy to arch/risc-v/src/common/espressif/esp_i2c_slave.h
index faea37fc97..4eb7189190 100644
--- a/arch/risc-v/src/common/espressif/esp_i2c.h
+++ b/arch/risc-v/src/common/espressif/esp_i2c_slave.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * arch/risc-v/src/common/espressif/esp_i2c.h
+ * arch/risc-v/src/common/espressif/esp_i2c_slave.h
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -20,12 +20,8 @@
  *
  ****************************************************************************/
 
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#ifndef __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_I2C_H
-#define __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_I2C_H
+#ifndef __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_I2C_SLAVE_H
+#define __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_I2C_SLAVE_H
 
 /****************************************************************************
  * Included Files
@@ -33,7 +29,7 @@
 
 #include <nuttx/config.h>
 
-#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/i2c/i2c_slave.h>
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -41,37 +37,38 @@
 
 #ifndef __ASSEMBLY__
 
-#ifdef CONFIG_ESPRESSIF_I2C0
-#  define ESPRESSIF_I2C0 0
+#ifdef CONFIG_ESPRESSIF_I2C0_SLAVE
+#  define ESPRESSIF_I2C0_SLAVE 0
 #endif
 
-#ifdef CONFIG_ESPRESSIF_I2C1
-#  define ESPRESSIF_I2C1 1
+#ifdef CONFIG_ESPRESSIF_I2C1_SLAVE
+#  define ESPRESSIF_I2C1_SLAVE 1
 #endif
 
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
 
-#ifdef CONFIG_ESPRESSIF_I2C_PERIPH
+#ifdef CONFIG_ESPRESSIF_I2C_PERIPH_SLAVE_MODE
 /****************************************************************************
- * Name: esp_i2cbus_initialize
+ * Name: esp_i2cbus_slave_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
+ *   struct i2c_slave_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.
+ *   different frequency.
  *
  * Input Parameters:
  *   port - Port number (for hardware that has multiple I2C interfaces)
+ *   addr - Adress of the slave device
  *
  * Returned Value:
  *   Valid I2C device structure reference on success; a NULL on failure
  *
  ****************************************************************************/
 
-struct i2c_master_s *esp_i2cbus_initialize(int port);
+struct i2c_slave_s *esp_i2cbus_slave_initialize(int port, int addr);
 
 /****************************************************************************
  * Name: esp_i2cbus_uninitialize
@@ -80,7 +77,7 @@ struct i2c_master_s *esp_i2cbus_initialize(int port);
  *   De-initialize the selected I2C port, and power down the device.
  *
  * Input Parameters:
- *   dev - Device structure as returned by the esp_i2cbus_initialize()
+ *   dev - Device structure as returned by the esp_i2cbus_slave_initialize()
  *
  * Returned Value:
  *   OK on success, ERROR when internal reference count mismatch or dev
@@ -88,8 +85,8 @@ struct i2c_master_s *esp_i2cbus_initialize(int port);
  *
  ****************************************************************************/
 
-int esp_i2cbus_uninitialize(struct i2c_master_s *dev);
-#endif /* CONFIG_ESPRESSIF_I2C_PERIPH */
+int esp_i2cbus_slave_uninitialize(struct i2c_slave_s *dev);
+#endif /* CONFIG_ESPRESSIF_I2C_PERIPH_SLAVE_MODE */
 
 #endif /* __ASSEMBLY__ */
-#endif /* __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_I2C_H */
+#endif /* __ARCH_RISCV_SRC_COMMON_ESPRESSIF_ESP_I2C_SLAVE_H */


Reply via email to