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 */