From 9997a858e2ce0e3434bd7d26652f34b560404b59 Mon Sep 17 00:00:00 2001 From: Eren Terzioglu Date: Thu, 12 Oct 2023 18:45:28 +0300 Subject: [PATCH] xtensa/esp32s2: Add SPI slave support --- arch/xtensa/src/esp32s2/Kconfig | 43 +- arch/xtensa/src/esp32s2/Make.defs | 3 + arch/xtensa/src/esp32s2/esp32s2_spi.c | 6 +- arch/xtensa/src/esp32s2/esp32s2_spi.h | 37 + arch/xtensa/src/esp32s2/esp32s2_spi_slave.c | 1706 +++++++++++++++++ .../common/include/esp32s2_board_spidev.h | 74 + .../include/esp32s2_board_spislavedev.h | 74 + boards/xtensa/esp32s2/common/src/Make.defs | 12 + .../src/esp32s2_board_spi.c | 5 +- .../esp32s2/common/src/esp32s2_board_spidev.c | 81 + .../common/src/esp32s2_board_spislavedev.c | 82 + .../esp32s2/esp32s2-kaluga-1/src/Make.defs | 4 - .../esp32s2-kaluga-1/src/esp32s2_board_spi.c | 128 -- .../esp32s2-kaluga-1/src/esp32s2_bringup.c | 37 + .../esp32s2/esp32s2-saola-1/src/Make.defs | 4 - .../esp32s2-saola-1/src/esp32s2_bringup.c | 37 + 16 files changed, 2188 insertions(+), 145 deletions(-) create mode 100644 arch/xtensa/src/esp32s2/esp32s2_spi_slave.c create mode 100644 boards/xtensa/esp32s2/common/include/esp32s2_board_spidev.h create mode 100644 boards/xtensa/esp32s2/common/include/esp32s2_board_spislavedev.h rename boards/xtensa/esp32s2/{esp32s2-saola-1 => common}/src/esp32s2_board_spi.c (96%) create mode 100644 boards/xtensa/esp32s2/common/src/esp32s2_board_spidev.c create mode 100644 boards/xtensa/esp32s2/common/src/esp32s2_board_spislavedev.c delete mode 100644 boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2_board_spi.c diff --git a/arch/xtensa/src/esp32s2/Kconfig b/arch/xtensa/src/esp32s2/Kconfig index c0a9537d0813c..3e56c2c8bf6ae 100644 --- a/arch/xtensa/src/esp32s2/Kconfig +++ b/arch/xtensa/src/esp32s2/Kconfig @@ -512,22 +512,44 @@ config ESP32S2_SPI_UDCS ---help--- Use user-defined CS. +config ESP32S2_SPI2_SLAVE + bool "SPI2 Slave mode" + default n + depends on SPI_SLAVE && ESP32S2_SPI2 + select ESP32S2_GPIO_IRQ + ---help--- + Configure SPI2 to operate in Slave mode. + config ESP32S2_SPI2_DMA bool "SPI2 use DMA" default y depends on ESP32S2_SPI2 +config ESP32S2_SPI3_SLAVE + bool "SPI3 Slave mode" + default n + depends on SPI_SLAVE && ESP32S2_SPI3 + select ESP32S2_GPIO_IRQ + ---help--- + Configure SPI3 to operate in Slave mode. + config ESP32S2_SPI3_DMA bool "SPI3 use DMA" default y depends on ESP32S2_SPI3 -config SPI_DMADESC_NUM - int "SPI DMA maximum number of descriptors" - default 2 +config ESP32S2_SPI_DMA_BUFSIZE + int "SPI Master GDMA buffer size" + default 2048 + depends on ESP32S2_SPI2_DMA || ESP32S2_SPI3_DMA ---help--- - Configure the maximum number of out-link/in-link descriptors to - be chained for a SPI DMA transfer. + This is used to calculate and allocate DMA description buffer, + not really allocate TX/RX buffer. + +config ESP32S2_SPI_SLAVE_BUFSIZE + int "SPI Slave buffer size" + default 2048 + depends on SPI_SLAVE config ESP32S2_SPI_DMATHRESHOLD int "SPI DMA threshold" @@ -559,6 +581,17 @@ config ESP32S2_SPI2_MISOPIN default 13 range 0 48 +config ESP32S2_SPI2_IO2PIN + int "SPI2 IO2 Pin" + default 14 + range 0 48 + depends on ESP32S2_SPI_IO_QIO + +config ESP32S2_SPI2_IO3PIN + int "SPI2 IO3 Pin" + default 9 + range 0 48 + depends on ESP32S2_SPI_IO_QIO endif # ESP32S2_SPI2 if ESP32S2_SPI3 diff --git a/arch/xtensa/src/esp32s2/Make.defs b/arch/xtensa/src/esp32s2/Make.defs index 2ffbc4838541b..4a2fceb1577c6 100644 --- a/arch/xtensa/src/esp32s2/Make.defs +++ b/arch/xtensa/src/esp32s2/Make.defs @@ -69,6 +69,9 @@ endif ifeq ($(CONFIG_ESP32S2_SPI),y) CHIP_CSRCS += esp32s2_spi.c +ifeq ($(CONFIG_SPI_SLAVE),y) +CHIP_CSRCS += esp32s2_spi_slave.c +endif endif #ifeq ($(CONFIG_ESP32S2_SPIFLASH),y) diff --git a/arch/xtensa/src/esp32s2/esp32s2_spi.c b/arch/xtensa/src/esp32s2/esp32s2_spi.c index b591ea8e79f03..ff3e64aaebeb1 100644 --- a/arch/xtensa/src/esp32s2/esp32s2_spi.c +++ b/arch/xtensa/src/esp32s2/esp32s2_spi.c @@ -76,7 +76,11 @@ /* SPI DMA RX/TX number of descriptors */ -#define SPI_DMA_DESC_NUM (CONFIG_SPI_DMADESC_NUM) +# if (CONFIG_ESP32S2_SPI_DMA_BUFSIZE % ESP32S2_DMA_BUFLEN_MAX) > 0 +# define SPI_DMA_DESC_NUM (CONFIG_ESP32S2_SPI_DMA_BUFSIZE / ESP32S2_DMA_BUFLEN_MAX + 1) +# else +# define SPI_DMA_DESC_NUM (CONFIG_ESP32S2_SPI_DMA_BUFSIZE / ESP32S2_DMA_BUFLEN_MAX) +# endif /* SPI DMA reset before exchange */ diff --git a/arch/xtensa/src/esp32s2/esp32s2_spi.h b/arch/xtensa/src/esp32s2/esp32s2_spi.h index 3f569b73c80ad..d7b4973846477 100644 --- a/arch/xtensa/src/esp32s2/esp32s2_spi.h +++ b/arch/xtensa/src/esp32s2/esp32s2_spi.h @@ -46,6 +46,10 @@ extern "C" #include +#ifdef CONFIG_SPI_SLAVE +# include +#endif + #ifdef CONFIG_ESP32S2_SPI2 # define ESP32S2_SPI2 2 #endif @@ -139,6 +143,39 @@ int esp32s2_spi3_cmddata(struct spi_dev_s *dev, int esp32s2_spibus_uninitialize(struct spi_dev_s *dev); +/**************************************************************************** + * Name: esp32s2_spislave_ctrlr_initialize + * + * Description: + * Initialize the selected SPI Slave bus. + * + * Input Parameters: + * port - Port number (for hardware that has multiple SPI Slave interfaces) + * + * Returned Value: + * Valid SPI Slave controller structure reference on success; + * NULL on failure. + * + ****************************************************************************/ + +struct spi_slave_ctrlr_s *esp32s2_spislave_ctrlr_initialize(int port); + +/**************************************************************************** + * Name: esp32s2_spislave_ctrlr_uninitialize + * + * Description: + * Uninitialize an SPI Slave bus. + * + * Input Parameters: + * ctrlr - SPI Slave controller interface instance + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise -1 (ERROR). + * + ****************************************************************************/ + +int esp32s2_spislave_ctrlr_uninitialize(struct spi_slave_ctrlr_s *ctrlr); + #endif /* CONFIG_ESP32S2_SPI */ #ifdef __cplusplus diff --git a/arch/xtensa/src/esp32s2/esp32s2_spi_slave.c b/arch/xtensa/src/esp32s2/esp32s2_spi_slave.c new file mode 100644 index 0000000000000..2af5df88be9f1 --- /dev/null +++ b/arch/xtensa/src/esp32s2/esp32s2_spi_slave.c @@ -0,0 +1,1706 @@ +/**************************************************************************** + * arch/xtensa/src/esp32s2/esp32s2_spi_slave.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 + +#if defined(CONFIG_ESP32S2_SPI) && defined(CONFIG_SPI_SLAVE) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "esp32s2_spi.h" +#include "esp32s2_irq.h" +#include "esp32s2_gpio.h" + +#ifdef CONFIG_ESP32S2_SPI_DMA +#include "esp32s2_dma.h" +#endif + +#include "xtensa.h" +#include "hardware/esp32s2_gpio_sigmap.h" +#include "hardware/esp32s2_pinmap.h" +#include "hardware/esp32s2_spi.h" +#include "hardware/esp32s2_soc.h" +#include "hardware/esp32s2_system.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#define SPI_SLAVE_BUFSIZE (CONFIG_ESP32S2_SPI_SLAVE_BUFSIZE) + +#ifdef CONFIG_ESP32S2_SPI_DMA +/* SPI DMA RX/TX number of descriptors */ + +# if (SPI_SLAVE_BUFSIZE % ESP32S2_DMA_BUFLEN_MAX) > 0 +# define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_DMA_BUFLEN_MAX + 1) +# else +# define SPI_DMA_DESC_NUM (SPI_SLAVE_BUFSIZE / ESP32S2_DMA_BUFLEN_MAX) +# endif + +# define SPI_SLV_INT_EN (SPI_SLV_WR_DMA_DONE_INT_ENA_M | SPI_SLV_RD_DMA_DONE_INT_ENA_M) +# define SPI_SLV_INT_RX SPI_SLV_WR_DMA_DONE_INT_ST_M +# define SPI_SLV_INT_CLR_RX SPI_SLV_WR_DMA_DONE_INT_CLR_M +# define SPI_SLV_INT_TX SPI_SLV_RD_DMA_DONE_INT_ST_M +# define SPI_SLV_INT_CLR_TX SPI_SLV_RD_DMA_DONE_INT_CLR_M +#else +# define SPI_SLV_INT_EN (SPI_SLV_WR_BUF_DONE_INT_ENA_M | SPI_SLV_RD_BUF_DONE_INT_ENA_M) +# define SPI_SLV_INT_RX SPI_SLV_WR_BUF_DONE_INT_ST_M +# define SPI_SLV_INT_CLR_RX SPI_SLV_WR_BUF_DONE_INT_CLR_M +# define SPI_SLV_INT_TX SPI_SLV_RD_BUF_DONE_INT_ST_M +# define SPI_SLV_INT_CLR_TX SPI_SLV_RD_BUF_DONE_INT_CLR_M +#endif /* CONFIG_ESP32S2_SPI_DMA */ + +/* Verify whether SPI has been assigned IOMUX pins. + * Otherwise, SPI signals will be routed via GPIO Matrix. + */ + +#ifdef CONFIG_ESP32S2_SPI2 +# define SPI_IS_CS_IOMUX (CONFIG_ESP32S2_SPI2_CSPIN == SPI2_IOMUX_CSPIN) +# define SPI_IS_CLK_IOMUX (CONFIG_ESP32S2_SPI2_CLKPIN == SPI2_IOMUX_CLKPIN) +# define SPI_IS_MOSI_IOMUX (CONFIG_ESP32S2_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN) +# define SPI_IS_MISO_IOMUX (CONFIG_ESP32S2_SPI2_MISOPIN == SPI2_IOMUX_MISOPIN) +# define SPI_VIA_IOMUX ((SPI_IS_CS_IOMUX) && \ + (SPI_IS_CLK_IOMUX) && \ + (SPI_IS_MOSI_IOMUX) && \ + (SPI_IS_MISO_IOMUX)) +#else +# define SPI_VIA_IOMUX 0 +#endif + +/* SPI Slave interrupt mask */ + +#define SPI_INT_MASK (SPI_IN_DONE_INT_ENA_M | \ + SPI_OUT_DONE_INT_ENA_M | \ + SPI_SLV_WR_DMA_DONE_M | \ + SPI_SLV_RD_DMA_DONE_M | \ + SPI_SLV_WR_BUF_DONE_M | \ + SPI_SLV_RD_BUF_DONE_M) + +/* SPI Slave default width */ + +#define SPI_SLAVE_DEFAULT_WIDTH (8) + +/* SPI Slave default mode */ + +#define SPI_SLAVE_DEFAULT_MODE (SPISLAVE_MODE0) + +/* SPI Slave maximum buffer size in bytes */ + +#define SPI_SLAVE_HW_BUF_SIZE (64) + +#define WORDS2BYTES(_priv, _wn) ((_wn) * ((_priv)->nbits / 8)) +#define BYTES2WORDS(_priv, _bn) ((_bn) / ((_priv)->nbits / 8)) + +#define setbits(bs, a) modifyreg32(a, 0, bs) +#define resetbits(bs, a) modifyreg32(a, bs, 0) + +/* SPI Slave controller hardware configuration */ + +struct spislave_config_s +{ + int32_t width; /* SPI Slave default width */ + enum spi_slave_mode_e mode; /* SPI Slave default mode */ + + uint8_t id; /* SPI device ID: SPIx {2,3} */ + uint8_t cs_pin; /* GPIO configuration for CS */ + uint8_t mosi_pin; /* GPIO configuration for MOSI */ + uint8_t miso_pin; /* GPIO configuration for MISO */ + uint8_t clk_pin; /* GPIO configuration for CLK */ + uint8_t periph; /* Peripheral ID */ + uint8_t irq; /* Interrupt ID */ + uint32_t clk_bit; /* Clock enable bit */ + uint32_t rst_bit; /* SPI reset bit */ +#ifdef CONFIG_ESP32S2_SPI_DMA + uint32_t dma_clk_bit; /* DMA clock enable bit */ + uint32_t dma_rst_bit; /* DMA reset bit */ + uint8_t dma_periph; /* DMA peripheral */ +#endif + uint32_t cs_insig; /* SPI CS input signal index */ + uint32_t cs_outsig; /* SPI CS output signal index */ + uint32_t mosi_insig; /* SPI MOSI input signal index */ + uint32_t mosi_outsig; /* SPI MOSI output signal index */ + uint32_t miso_insig; /* SPI MISO input signal index */ + uint32_t miso_outsig; /* SPI MISO output signal index */ + uint32_t clk_insig; /* SPI CLK input signal index */ + uint32_t clk_outsig; /* SPI CLK output signal index */ +}; + +struct spislave_priv_s +{ + /* Externally visible part of the SPI Slave controller interface */ + + struct spi_slave_ctrlr_s ctrlr; + + /* Reference to SPI Slave device interface */ + + struct spi_slave_dev_s *dev; + + /* Port configuration */ + + const struct spislave_config_s *config; + int refs; /* Reference count */ + int cpu; /* CPU ID */ + int cpuint; /* SPI interrupt ID */ +#ifdef CONFIG_ESP32S2_SPI_DMA + int32_t dma_channel; /* Channel assigned by the GDMA driver */ + + /* DMA RX/TX description */ + + struct esp32s2_dmadesc_s *dma_rxdesc; + struct esp32s2_dmadesc_s *dma_txdesc; + + uint32_t rx_dma_offset; /* Offset of DMA RX buffer */ +#endif + enum spi_slave_mode_e mode; /* Current SPI Slave hardware mode */ + uint8_t nbits; /* Current configured bit width */ + uint32_t tx_length; /* Location of next TX value */ + + /* SPI Slave TX queue buffer */ + + uint8_t tx_buffer[SPI_SLAVE_BUFSIZE]; + uint32_t rx_length; /* Location of next RX value */ + + /* SPI Slave RX queue buffer */ + + uint8_t rx_buffer[SPI_SLAVE_BUFSIZE]; + + /* Flag that indicates whether SPI Slave is currently processing */ + + bool is_processing; + + /* Flag that indicates whether SPI Slave TX is currently enabled */ + + bool is_tx_enabled; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* SPI Slave controller interrupt handlers */ + +static int spislave_cs_interrupt(int irq, void *context, void *arg); +static int spislave_periph_interrupt(int irq, void *context, void *arg); + +/* SPI Slave controller internal functions */ + +static void spislave_setmode(struct spi_slave_ctrlr_s *ctrlr, + enum spi_slave_mode_e mode); +static void spislave_setbits(struct spi_slave_ctrlr_s *ctrlr, int nbits); +static void spislave_store_result(struct spislave_priv_s *priv, + uint32_t recv_bytes); +static void spislave_evict_sent_data(struct spislave_priv_s *priv, + uint32_t sent_bytes); +#ifdef CONFIG_ESP32S2_SPI_DMA +static void spislave_setup_rx_dma(struct spislave_priv_s *priv); +static void spislave_setup_tx_dma(struct spislave_priv_s *priv); +static void spislave_prepare_next_rx(struct spislave_priv_s *priv); +static void spislave_prepare_next_tx(struct spislave_priv_s *priv); +#else +static void spislave_write_tx_buffer(struct spislave_priv_s *priv); +#endif +static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr); +static void spislave_deinitialize(struct spi_slave_ctrlr_s *ctrlr); + +/* SPI Slave controller operations */ + +static void spislave_bind(struct spi_slave_ctrlr_s *ctrlr, + struct spi_slave_dev_s *dev, + enum spi_slave_mode_e mode, + int nbits); +static void spislave_unbind(struct spi_slave_ctrlr_s *ctrlr); +static int spislave_enqueue(struct spi_slave_ctrlr_s *ctrlr, + const void *data, + size_t nwords); +static bool spislave_qfull(struct spi_slave_ctrlr_s *ctrlr); +static void spislave_qflush(struct spi_slave_ctrlr_s *ctrlr); +static size_t spislave_qpoll(struct spi_slave_ctrlr_s *ctrlr); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* SPI2 private data */ + +#ifdef CONFIG_ESP32S2_SPI2 +static const struct spislave_config_s esp32s2_spi2slave_config = +{ + .width = SPI_SLAVE_DEFAULT_WIDTH, + .mode = SPI_SLAVE_DEFAULT_MODE, + .id = 2, + .cs_pin = CONFIG_ESP32S2_SPI2_CSPIN, + .mosi_pin = CONFIG_ESP32S2_SPI2_MOSIPIN, + .miso_pin = CONFIG_ESP32S2_SPI2_MISOPIN, + .clk_pin = CONFIG_ESP32S2_SPI2_CLKPIN, + .periph = ESP32S2_PERIPH_SPI2, + .irq = ESP32S2_IRQ_SPI2, + .clk_bit = SYSTEM_SPI2_CLK_EN, + .rst_bit = SYSTEM_SPI2_RST, +#ifdef CONFIG_ESP32S2_SPI_DMA + .dma_clk_bit = SYSTEM_SPI2_DMA_CLK_EN, + .dma_rst_bit = SYSTEM_SPI2_DMA_RST, + .dma_periph = ESP32S2_DMA_PERIPH_SPI2, +#endif + .cs_insig = FSPICS0_IN_IDX, + .cs_outsig = FSPICS0_OUT_IDX, + .mosi_insig = FSPID_IN_IDX, + .mosi_outsig = FSPID_OUT_IDX, + .miso_insig = FSPIQ_IN_IDX, + .miso_outsig = FSPIQ_OUT_IDX, + .clk_insig = FSPICLK_IN_IDX, + .clk_outsig = FSPICLK_OUT_IDX, +}; + +static const struct spi_slave_ctrlrops_s esp32s2_spi2slave_ops = +{ + .bind = spislave_bind, + .unbind = spislave_unbind, + .enqueue = spislave_enqueue, + .qfull = spislave_qfull, + .qflush = spislave_qflush, + .qpoll = spislave_qpoll +}; + +#ifdef CONFIG_ESP32S2_SPI_DMA + +/* SPI DMA RX/TX description buffer */ + +static struct esp32s2_dmadesc_s esp32s2_spi2_dma_rxdesc[SPI_DMA_DESC_NUM]; +static struct esp32s2_dmadesc_s esp32s2_spi2_dma_txdesc[SPI_DMA_DESC_NUM]; +#endif + +static struct spislave_priv_s esp32s2_spi2slave_priv = +{ + .ctrlr = + { + .ops = &esp32s2_spi2slave_ops + }, + .config = &esp32s2_spi2slave_config, + .cpu = -1, + .cpuint = -ENOMEM, +#ifdef CONFIG_ESP32S2_SPI_DMA + .dma_channel = -ENOMEM, + .dma_rxdesc = esp32s2_spi2_dma_rxdesc, + .dma_txdesc = esp32s2_spi2_dma_txdesc, +#endif + .mode = SPISLAVE_MODE0, + .is_processing = false, + .is_tx_enabled = false +}; +#endif /* CONFIG_ESP32S2_SPI2 */ + +#ifdef CONFIG_ESP32S2_SPI3 +static const struct spislave_config_s esp32s2_spi3slave_config = +{ + .width = SPI_SLAVE_DEFAULT_WIDTH, + .mode = SPI_SLAVE_DEFAULT_MODE, + .id = 3, + .cs_pin = CONFIG_ESP32S2_SPI3_CSPIN, + .mosi_pin = CONFIG_ESP32S2_SPI3_MOSIPIN, + .miso_pin = CONFIG_ESP32S2_SPI3_MISOPIN, + .clk_pin = CONFIG_ESP32S2_SPI3_CLKPIN, + .periph = ESP32S2_PERIPH_SPI3, + .irq = ESP32S2_IRQ_SPI3, + .clk_bit = SYSTEM_SPI3_CLK_EN, + .rst_bit = SYSTEM_SPI3_RST, +#ifdef CONFIG_ESP32S2_SPI_DMA + .dma_clk_bit = SYSTEM_SPI3_DMA_CLK_EN, + .dma_rst_bit = SYSTEM_SPI3_DMA_RST, + .dma_periph = ESP32S2_DMA_PERIPH_SPI3, +#endif + .cs_insig = SPI3_CS0_IN_IDX, + .cs_outsig = SPI3_CS0_OUT_IDX, + .mosi_insig = SPI3_D_IN_IDX, + .mosi_outsig = SPI3_D_OUT_IDX, + .miso_insig = SPI3_Q_IN_IDX, + .miso_outsig = SPI3_Q_OUT_IDX, + .clk_insig = SPI3_CLK_IN_IDX, + .clk_outsig = SPI3_CLK_OUT_MUX_IDX, +}; + +static const struct spi_slave_ctrlrops_s esp32s2_spi3slave_ops = +{ + .bind = spislave_bind, + .unbind = spislave_unbind, + .enqueue = spislave_enqueue, + .qfull = spislave_qfull, + .qflush = spislave_qflush, + .qpoll = spislave_qpoll +}; + +#ifdef CONFIG_ESP32S2_SPI_DMA + +/* SPI DMA RX/TX description buffer */ + +static struct esp32s2_dmadesc_s esp32s2_spi3_dma_rxdesc[SPI_DMA_DESC_NUM]; +static struct esp32s2_dmadesc_s esp32s2_spi3_dma_txdesc[SPI_DMA_DESC_NUM]; +#endif + +static struct spislave_priv_s esp32s2_spi3slave_priv = +{ + .ctrlr = + { + .ops = &esp32s2_spi3slave_ops + }, + .config = &esp32s2_spi3slave_config, + .cpu = -1, + .cpuint = -ENOMEM, +#ifdef CONFIG_ESP32S2_SPI_DMA + .dma_channel = -ENOMEM, + .dma_rxdesc = esp32s2_spi3_dma_rxdesc, + .dma_txdesc = esp32s2_spi3_dma_txdesc, +#endif + .mode = SPISLAVE_MODE0, + .is_processing = false, + .is_tx_enabled = false +}; +#endif /* CONFIG_ESP32S2_SPI3 */ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: spislave_peripheral_reset + * + * Description: + * Reset the SPI Slave peripheral before next transaction. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static inline void spislave_peripheral_reset(struct spislave_priv_s *priv) +{ + setbits(SPI_SOFT_RESET_M, SPI_SLAVE_REG(priv->config->id)); + resetbits(SPI_SOFT_RESET_M, SPI_SLAVE_REG(priv->config->id)); +} + +/**************************************************************************** + * Name: spislave_cpu_tx_fifo_reset + * + * Description: + * Reset the BUF TX AFIFO, which is used to send data out in SPI Slave + * CPU-controlled mode transfer. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static inline void spislave_cpu_tx_fifo_reset(struct spislave_priv_s *priv) +{ + setbits(SPI_AHBM_FIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id)); + resetbits(SPI_AHBM_FIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id)); +} + +/**************************************************************************** + * Name: spislave_dma_tx_fifo_reset + * + * Description: + * Reset the DMA TX AFIFO, which is used to send data out in SPI Slave + * DMA-controlled mode transfer. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S2_SPI_DMA +static inline void spislave_dma_tx_fifo_reset(struct spislave_priv_s *priv) +{ + setbits(SPI_DMA_AFIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id)); + resetbits(SPI_DMA_AFIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id)); +} +#endif + +/**************************************************************************** + * Name: spislave_dma_rx_fifo_reset + * + * Description: + * Reset the RX AFIFO, which is used to receive data in SPI Slave mode + * transfer. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S2_SPI_DMA +static inline void spislave_dma_rx_fifo_reset(struct spislave_priv_s *priv) +{ + setbits(SPI_RX_AFIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id)); + resetbits(SPI_RX_AFIFO_RST_M, SPI_DMA_CONF_REG(priv->config->id)); +} +#endif + +/**************************************************************************** + * Name: spislave_setmode + * + * Description: + * Set the SPI Slave mode. + * + * Input Parameters: + * ctrlr - SPI Slave controller interface instance + * mode - Requested SPI Slave mode + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void spislave_setmode(struct spi_slave_ctrlr_s *ctrlr, + enum spi_slave_mode_e mode) +{ + struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr; + + spiinfo("mode=%d\n", mode); + + /* Has the mode changed? */ + + if (mode != priv->mode) + { + uint32_t ck_idle_edge; + uint32_t rsck_i_edge; + uint32_t tsck_i_edge; + uint32_t clk_mode_13; + + switch (mode) + { + case SPISLAVE_MODE0: /* CPOL=0; CPHA=0 */ + ck_idle_edge = 0; + rsck_i_edge = 0; + tsck_i_edge = 0; + clk_mode_13 = 0; + break; + + case SPISLAVE_MODE1: /* CPOL=0; CPHA=1 */ + ck_idle_edge = 0; + rsck_i_edge = 1; + tsck_i_edge = 1; + clk_mode_13 = 1; + break; + + case SPISLAVE_MODE2: /* CPOL=1; CPHA=0 */ + ck_idle_edge = 1; + rsck_i_edge = 1; + tsck_i_edge = 1; + clk_mode_13 = 0; + break; + + case SPISLAVE_MODE3: /* CPOL=1; CPHA=1 */ + ck_idle_edge = 1; + rsck_i_edge = 0; + tsck_i_edge = 0; + clk_mode_13 = 1; + break; + + default: + spierr("Invalid mode: %d\n", mode); + DEBUGPANIC(); + return; + } + + modifyreg32(SPI_MISC_REG(priv->config->id), + SPI_CK_IDLE_EDGE_M, + VALUE_TO_FIELD(ck_idle_edge, SPI_CK_IDLE_EDGE)); + + modifyreg32(SPI_USER_REG(priv->config->id), + SPI_RSCK_I_EDGE_M | SPI_TSCK_I_EDGE_M, + VALUE_TO_FIELD(rsck_i_edge, SPI_RSCK_I_EDGE) | + VALUE_TO_FIELD(tsck_i_edge, SPI_TSCK_I_EDGE)); + + modifyreg32(SPI_SLAVE_REG(priv->config->id), + SPI_CLK_MODE_13_M | SPI_RSCK_DATA_OUT_M, + VALUE_TO_FIELD(clk_mode_13, SPI_CLK_MODE_13)); + + priv->mode = mode; + } +} + +/**************************************************************************** + * Name: spislave_setbits + * + * Description: + * Set the number of bits per word. + * + * Input Parameters: + * ctrlr - SPI Slave controller interface instance + * nbits - The number of bits in an SPI word + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void spislave_setbits(struct spi_slave_ctrlr_s *ctrlr, int nbits) +{ + struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr; + + spiinfo("nbits=%d\n", nbits); + + priv->nbits = nbits; +} + +/**************************************************************************** + * Name: spislave_cs_interrupt + * + * Description: + * Handler for the GPIO interrupt which is triggered when the chip select + * has toggled to inactive state (active high). + * + * Input Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info + * arg - SPI Slave controller private data + * + * Returned Value: + * Standard interrupt return value. + * + ****************************************************************************/ + +static int spislave_cs_interrupt(int irq, void *context, void *arg) +{ + struct spislave_priv_s *priv = (struct spislave_priv_s *)arg; + + if (priv->is_processing) + { + priv->is_processing = false; + SPIS_DEV_SELECT(priv->dev, false); + } + + return 0; +} + +/**************************************************************************** + * Name: spislave_store_result + * + * Description: + * Fetch data from the SPI hardware data buffer and record the length. + * This is a post transaction operation. + * + * Input Parameters: + * priv - Private SPI Slave controller structure + * recv_bytes - Number of received bytes + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void spislave_store_result(struct spislave_priv_s *priv, + uint32_t recv_bytes) +{ + uint32_t remaining_space = SPI_SLAVE_BUFSIZE - priv->rx_length; + uint32_t bytes_to_copy = recv_bytes; + + if (bytes_to_copy > remaining_space) + { + spiwarn("RX buffer full! Discarded %" PRIu32 " received bytes\n", + bytes_to_copy - remaining_space); + + bytes_to_copy = remaining_space; + } + +#ifdef CONFIG_ESP32S2_SPI_DMA + if (bytes_to_copy) + { + if ((priv->rx_dma_offset != priv->rx_length)) + { + memmove(priv->rx_buffer + priv->rx_length, + priv->rx_buffer + priv->rx_dma_offset, + bytes_to_copy); + + priv->rx_dma_offset = priv->rx_length; + } + + priv->rx_length += bytes_to_copy; + } +#else + /* If DMA is not enabled, software should copy incoming data from data + * buffer registers to receive buffer. + */ + + if (bytes_to_copy) + { + /* Set data_buf_reg with the address of the first data buffer + * register (W0). + */ + + uintptr_t data_buf_reg = SPI_W0_REG(priv->config->id); + + /* Read received data words from SPI hardware data buffer. */ + + for (int i = 0; i < bytes_to_copy; i += sizeof(uint32_t)) + { + uint32_t rbytes = MIN(bytes_to_copy - i, sizeof(uint32_t)); + uint32_t r_wd = getreg32(data_buf_reg); + + memcpy(priv->rx_buffer + priv->rx_length + i, &r_wd, rbytes); + + /* Update data_buf_reg to point to the next data buffer register. */ + + data_buf_reg += sizeof(uint32_t); + } + + priv->rx_length += bytes_to_copy; + } +#endif +} + +/**************************************************************************** + * Name: spislave_prepare_next_rx + * + * Description: + * Prepare the SPI Slave controller for receiving data on the next + * transaction. + * + * Input Parameters: + * priv - Private SPI Slave controller structure + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S2_SPI_DMA +static void spislave_prepare_next_rx(struct spislave_priv_s *priv) +{ + if (priv->rx_length < SPI_SLAVE_BUFSIZE) + { + spislave_setup_rx_dma(priv); + } +} +#endif + +/**************************************************************************** + * Name: spislave_evict_sent_data + * + * Description: + * Evict from the TX buffer data sent on the latest transaction and update + * the length. This is a post transaction operation. + * + * Input Parameters: + * priv - Private SPI Slave controller structure + * sent_bytes - Number of transmitted bytes + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void spislave_evict_sent_data(struct spislave_priv_s *priv, + uint32_t sent_bytes) +{ + if (sent_bytes < priv->tx_length) + { + priv->tx_length -= sent_bytes; + + memmove(priv->tx_buffer, priv->tx_buffer + sent_bytes, + priv->tx_length); + + memset(priv->tx_buffer + priv->tx_length, 0, sent_bytes); + } + else + { + priv->tx_length = 0; + } +} + +/**************************************************************************** + * Name: spislave_write_tx_buffer + * + * Description: + * Write to SPI Slave peripheral hardware data buffer. + * + * Input Parameters: + * priv - Private SPI Slave controller structure + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifndef CONFIG_ESP32S2_SPI_DMA +static void spislave_write_tx_buffer(struct spislave_priv_s *priv) +{ + /* Initialize data_buf_reg with the address of the first data buffer + * register (W0). + */ + + uintptr_t data_buf_reg = SPI_W0_REG(priv->config->id); + + uint32_t transfer_size = MIN(SPI_SLAVE_HW_BUF_SIZE, priv->tx_length); + + /* Write data words to hardware data buffer. + * SPI peripheral contains 16 registers (W0 - W15). + */ + + for (int i = 0; i < transfer_size; i += sizeof(uint32_t)) + { + uint32_t w_wd = UINT32_MAX; + + memcpy(&w_wd, priv->tx_buffer + i, sizeof(uint32_t)); + + putreg32(w_wd, data_buf_reg); + + /* Update data_buf_reg to point to the next data buffer register. */ + + data_buf_reg += sizeof(uint32_t); + } +} +#endif + +/**************************************************************************** + * Name: spislave_setup_rx_dma + * + * Description: + * Configure the SPI Slave peripheral to perform the next RX data transfer + * via DMA. + * + * Input Parameters: + * priv - Private SPI Slave controller structure + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S2_SPI_DMA +static void spislave_setup_rx_dma(struct spislave_priv_s *priv) +{ + uint32_t length = SPI_SLAVE_BUFSIZE - priv->rx_length; + + esp32s2_dma_setup(priv->dma_rxdesc, + SPI_DMA_DESC_NUM, + priv->rx_buffer + priv->rx_length, + length, + false); + esp32s2_dma_load(priv->dma_rxdesc, priv->dma_channel, false); + + priv->rx_dma_offset = priv->rx_length; + + spislave_dma_rx_fifo_reset(priv); + + spislave_peripheral_reset(priv); + + /* Clear input FIFO full error */ + + setbits(SPI_DMA_INFIFO_FULL_ERR_INT_CLR_M, + SPI_DMA_INT_CLR_REG(priv->config->id)); + + /* Enable SPI DMA RX */ + + setbits(SPI_DMA_RX_ENA_M, SPI_DMA_CONF_REG(priv->config->id)); + + esp32s2_dma_enable(priv->dma_channel, false); +} +#endif + +/**************************************************************************** + * Name: spislave_setup_tx_dma + * + * Description: + * Configure the SPI Slave peripheral to perform the next TX data transfer + * via DMA. + * + * Input Parameters: + * priv - Private SPI Slave controller structure + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S2_SPI_DMA +static void spislave_setup_tx_dma(struct spislave_priv_s *priv) +{ + esp32s2_dma_setup(priv->dma_txdesc, + SPI_DMA_DESC_NUM, + priv->tx_buffer, + SPI_SLAVE_BUFSIZE, + true); + esp32s2_dma_load(priv->dma_txdesc, priv->dma_channel, true); + + spislave_dma_tx_fifo_reset(priv); + + spislave_peripheral_reset(priv); + + /* Clear output FIFO empty error */ + + setbits(SPI_DMA_OUTFIFO_EMPTY_ERR_INT_CLR_M, + SPI_DMA_INT_CLR_REG(priv->config->id)); + + /* Enable SPI DMA TX */ + + setbits(SPI_DMA_TX_ENA_M, SPI_DMA_CONF_REG(priv->config->id)); + + esp32s2_dma_enable(priv->dma_channel, true); +} +#endif + +/**************************************************************************** + * Name: spislave_prepare_next_tx + * + * Description: + * Prepare the SPI Slave controller for transmitting data on the next + * transaction. + * + * Input Parameters: + * priv - Private SPI Slave controller structure + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void spislave_prepare_next_tx(struct spislave_priv_s *priv) +{ + if (priv->tx_length != 0) + { +#ifdef CONFIG_ESP32S2_SPI_DMA + spislave_setup_tx_dma(priv); +#else + spislave_peripheral_reset(priv); + + spislave_write_tx_buffer(priv); + + spislave_cpu_tx_fifo_reset(priv); +#endif + + priv->is_tx_enabled = true; + } + else + { + spiwarn("TX buffer empty! Disabling TX for next transaction\n"); + + spislave_cpu_tx_fifo_reset(priv); + + priv->is_tx_enabled = false; + } +} + +/**************************************************************************** + * Name: spislave_periph_interrupt + * + * Description: + * Handler for the SPI Slave controller interrupt which is triggered when a + * transfer is finished. + * + * Input Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info + * arg - SPI Slave controller private data + * + * Returned Value: + * Standard interrupt return value. + * + ****************************************************************************/ + +static int spislave_periph_interrupt(int irq, void *context, void *arg) +{ + struct spislave_priv_s *priv = (struct spislave_priv_s *)arg; + uint32_t regval = getreg32(SPI_SLAVE1_REG(priv->config->id)); + uint32_t transfer_size = REG_MASK(regval, SPI_SLV_DATA_BYTELEN); + + uint32_t int_clear = SPI_IN_DONE_INT_CLR_M | SPI_OUT_DONE_INT_CLR_M; + + if (!priv->is_processing) + { + SPIS_DEV_SELECT(priv->dev, true); + priv->is_processing = true; + } + + /* RX process */ + + if (transfer_size > 0) + { + spislave_store_result(priv, transfer_size); + } + +#ifdef CONFIG_ESP32S2_SPI_DMA + spislave_prepare_next_rx(priv); +#endif + + /* TX process */ + + if (priv->is_tx_enabled && transfer_size > 0) + { + spislave_evict_sent_data(priv, transfer_size); + } + + spislave_prepare_next_tx(priv); + + if (priv->is_processing && esp32s2_gpioread(priv->config->cs_pin)) + { + priv->is_processing = false; + SPIS_DEV_SELECT(priv->dev, false); + } + + /* Clear the trans_done interrupt flag */ + + setbits(int_clear, SPI_DMA_INT_CLR_REG(priv->config->id)); + + return 0; +} + +/**************************************************************************** + * Name: spislave_dma_init + * + * Description: + * Initialize ESP32-S3 SPI Slave connection to GDMA engine. + * + * Input Parameters: + * priv - Private SPI Slave controller structure + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S2_SPI_DMA +void spislave_dma_init(struct spislave_priv_s *priv) +{ + /* Enable GDMA clock for the SPI peripheral */ + + setbits(priv->config->dma_clk_bit, SYSTEM_PERIP_CLK_EN0_REG); + + /* Reset GDMA for the SPI peripheral */ + + resetbits(priv->config->dma_rst_bit, SYSTEM_PERIP_RST_EN0_REG); + + /* Initialize GDMA controller */ + + esp32s2_dma_init(); + + /* Request a GDMA channel for SPI peripheral */ + + priv->dma_channel = esp32s2_dma_request(priv->config->dma_periph, 1, 1, + true); + if (priv->dma_channel < 0) + { + spierr("Failed to allocate GDMA channel\n"); + + DEBUGPANIC(); + } + + /* Disable segment transaction mode for SPI Slave */ + + resetbits(SPI_DMA_SLV_SEG_TRANS_EN_M, SPI_DMA_CONF_REG(priv->config->id)); + + /* Configure DMA In-Link EOF to be generated by trans_done */ + + resetbits(SPI_RX_EOF_EN_M, SPI_DMA_CONF_REG(priv->config->id)); +} +#endif + +/**************************************************************************** + * Name: spislave_initializ_iomux + * + * Description: + * Initialize ESP32-S3 SPI Slave GPIO by IO MUX. + * + * Input Parameters: + * priv - Private SPI Slave controller structure + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#if SPI_VIA_IOMUX != 0 +static void spislave_initializ_iomux(struct spislave_priv_s *priv) +{ + uint32_t attr = INPUT_FUNCTION_5 | DRIVE_0; + const struct spislave_config_s *config = priv->config; + + esp32s2_configgpio(config->cs_pin, attr); + esp32s2_configgpio(config->clk_pin, attr); + + esp32s2_gpio_matrix_out(config->cs_pin, SIG_GPIO_OUT_IDX, 0, 0); + esp32s2_gpio_matrix_out(config->clk_pin, SIG_GPIO_OUT_IDX, 0, 0); + esp32s2_gpio_matrix_out(config->mosi_pin, SIG_GPIO_OUT_IDX, 0, 0); + esp32s2_gpio_matrix_out(config->miso_pin, SIG_GPIO_OUT_IDX, 0, 0); + + esp32s2_configgpio(config->mosi_pin, attr); + esp32s2_configgpio(config->miso_pin, OUTPUT_FUNCTION_5); +} +#endif + +/**************************************************************************** + * Name: spislave_initializ_iomatrix + * + * Description: + * Initialize ESP32-S3 SPI Slave GPIO by IO matrix. + * + * Input Parameters: + * priv - Private SPI Slave controller structure + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#if SPI_VIA_IOMUX == 0 || defined(CONFIG_ESP32S2_SPI3) +static void spislave_initializ_iomatrix(struct spislave_priv_s *priv) +{ + uint32_t attr = INPUT | DRIVE_0; + const struct spislave_config_s *config = priv->config; + + esp32s2_configgpio(config->cs_pin, attr); + esp32s2_gpio_matrix_in(config->cs_pin, config->cs_insig, 0); + + esp32s2_configgpio(config->clk_pin, attr); + esp32s2_gpio_matrix_in(config->clk_pin, config->clk_insig, 0); + + esp32s2_configgpio(config->mosi_pin, attr); + esp32s2_gpio_matrix_in(config->mosi_pin, config->mosi_insig, 0); + + esp32s2_configgpio(config->miso_pin, OUTPUT); + esp32s2_gpio_matrix_out(config->miso_pin, config->miso_outsig, 0, 0); +} +#endif + +/**************************************************************************** + * Name: spislave_gpio_initialize + * + * Description: + * Initialize ESP32-S3 SPI Slave GPIO + * + * Input Parameters: + * priv - Private SPI Slave controller structure + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void spislave_gpio_initialize(struct spislave_priv_s *priv) +{ +#if SPI_VIA_IOMUX != 0 + if (priv->config->id == 2) + { + spislave_initializ_iomux(priv); + } +# ifdef CONFIG_ESP32S2_SPI3 + else + { + spislave_initializ_iomatrix(priv); + } +# endif +#else + spislave_initializ_iomatrix(priv); +#endif +} + +/**************************************************************************** + * Name: spislave_initialize + * + * Description: + * Initialize ESP32-S3 SPI Slave hardware interface. + * + * Input Parameters: + * ctrlr - SPI Slave controller interface instance + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void spislave_initialize(struct spi_slave_ctrlr_s *ctrlr) +{ + uint32_t regval; + struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr; + const struct spislave_config_s *config = priv->config; + + spiinfo("ctrlr=%p\n", ctrlr); + + spislave_gpio_initialize(priv); + + setbits(config->clk_bit, SYSTEM_PERIP_CLK_EN0_REG); + resetbits(config->rst_bit, SYSTEM_PERIP_RST_EN0_REG); + + /* Configure SPI Slave peripheral */ + + putreg32(0, SPI_CLOCK_REG(priv->config->id)); + + regval = SPI_DOUTDIN_M; + putreg32(regval, SPI_USER_REG(priv->config->id)); + + putreg32(0, SPI_CTRL_REG(priv->config->id)); + + regval = SPI_SLAVE_MODE_M; +#ifdef CONFIG_ESP32S2_SPI_DMA + regval |= SPI_SLV_WRDMA_BYTELEN_EN_M | SPI_SLV_RDDMA_BYTELEN_EN_M; +#else + regval |= SPI_SLV_WRBUF_BYTELEN_EN_M | SPI_SLV_RDBUF_BYTELEN_EN_M; +#endif + + putreg32(regval, SPI_SLAVE_REG(priv->config->id)); + + spislave_peripheral_reset(priv); + + /* Use all 64 bytes of the SPI hardware data buffer */ + + resetbits(SPI_USR_MISO_HIGHPART_M | SPI_USR_MOSI_HIGHPART_M, + SPI_USER_REG(priv->config->id)); + + /* Disable interrupts */ + + resetbits(SPI_INT_MASK, SPI_DMA_INT_ENA_REG(priv->config->id)); + +#ifdef CONFIG_ESP32S2_SPI_DMA + spislave_dma_init(priv); +#endif + + esp32s2_gpioirqenable(ESP32S2_PIN2IRQ(config->cs_pin), GPIO_INTR_POSEDGE); + + /* Force a transaction done interrupt. + * This interrupt won't fire yet because we initialized the SPI interrupt + * as disabled. This way, we can just enable the SPI interrupt and the + * interrupt handler will kick in, handling any transactions that are + * queued. + */ + + regval = SPI_IN_DONE_INT_CLR_M | SPI_OUT_DONE_INT_CLR_M; + setbits(regval, SPI_DMA_INT_RAW_REG(priv->config->id)); + setbits(regval, SPI_DMA_INT_ENA_REG(priv->config->id)); +} + +/**************************************************************************** + * Name: spislave_deinitialize + * + * Description: + * Deinitialize ESP32-S3 SPI Slave hardware interface. + * + * Input Parameters: + * ctrlr - SPI Slave controller interface instance + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void spislave_deinitialize(struct spi_slave_ctrlr_s *ctrlr) +{ + struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr; + + esp32s2_gpioirqdisable(ESP32S2_PIN2IRQ(priv->config->cs_pin)); + + /* Disable the trans_done interrupt */ + + resetbits(SPI_IN_DONE_INT_CLR_M, SPI_DMA_INT_ENA_REG(priv->config->id)); + resetbits(SPI_OUT_DONE_INT_CLR_M, SPI_DMA_INT_ENA_REG(priv->config->id)); + +#ifdef CONFIG_ESP32S2_SPI_DMA + resetbits(priv->config->dma_clk_bit, SYSTEM_PERIP_CLK_EN0_REG); + priv->rx_dma_offset = 0; +#endif + + setbits(priv->config->clk_bit, SYSTEM_PERIP_RST_EN0_REG); + resetbits(priv->config->clk_bit, SYSTEM_PERIP_CLK_EN0_REG); + + priv->mode = SPISLAVE_MODE0; + priv->nbits = 0; + priv->tx_length = 0; + priv->rx_length = 0; + priv->is_processing = false; + priv->is_tx_enabled = false; +} + +/**************************************************************************** + * Name: spislave_bind + * + * Description: + * Bind the SPI Slave device interface to the SPI Slave controller + * interface and configure the SPI interface. Upon return, the SPI + * slave controller driver is fully operational and ready to perform + * transfers. + * + * Input Parameters: + * ctrlr - SPI Slave controller interface instance + * dev - SPI Slave device interface instance + * mode - The SPI mode requested + * nbits - The number of bits requests. + * If value is greater than 0, then it implies MSB first + * If value is less than 0, then it implies LSB first with -nbits + * + * Returned Value: + * None. + * + * Assumptions: + * This implementation currently supports only positive "nbits" values, + * i.e., it always configures the SPI Slave controller driver as MSB first. + * + ****************************************************************************/ + +static void spislave_bind(struct spi_slave_ctrlr_s *ctrlr, + struct spi_slave_dev_s *dev, + enum spi_slave_mode_e mode, + int nbits) +{ + struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr; + const void *data = NULL; + irqstate_t flags; + size_t num_words; + + spiinfo("ctrlr=%p dev=%p mode=%d nbits=%d\n", ctrlr, dev, mode, nbits); + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv->dev == NULL); + DEBUGASSERT(dev != NULL); + DEBUGASSERT(nbits > 0); + + flags = enter_critical_section(); + + priv->dev = dev; + + SPIS_DEV_SELECT(dev, false); + + SPIS_DEV_CMDDATA(dev, false); + +#ifdef CONFIG_ESP32S2_SPI_DMA + priv->rx_dma_offset = 0; +#endif + + priv->rx_length = 0; + priv->tx_length = 0; + priv->is_tx_enabled = false; + + spislave_initialize(ctrlr); + + spislave_setmode(ctrlr, mode); + spislave_setbits(ctrlr, nbits); + + num_words = SPIS_DEV_GETDATA(dev, &data); + + if (data != NULL && num_words > 0) + { + size_t num_bytes = WORDS2BYTES(priv, num_words); + memcpy(priv->tx_buffer, data, num_bytes); + priv->tx_length += num_bytes; + } + +#ifdef CONFIG_ESP32S2_SPI_DMA + spislave_prepare_next_rx(priv); +#endif + + /* Enable the CPU interrupt that is linked to the SPI Slave controller */ + + up_enable_irq(priv->config->irq); + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: spislave_unbind + * + * Description: + * Un-bind the SPI Slave device interface from the SPI Slave controller + * interface. Reset the SPI interface and restore the SPI Slave + * controller driver to its initial state. + * + * Input Parameters: + * ctrlr - SPI Slave controller interface instance + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void spislave_unbind(struct spi_slave_ctrlr_s *ctrlr) +{ + struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr; + irqstate_t flags; + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv->dev != NULL); + + spiinfo("Unbinding %p\n", priv->dev); + + flags = enter_critical_section(); + + up_disable_irq(priv->config->irq); + + esp32s2_gpioirqdisable(ESP32S2_PIN2IRQ(priv->config->cs_pin)); + + /* Disable the trans_done interrupt */ + + resetbits(SPI_IN_DONE_INT_CLR_M, SPI_DMA_INT_ENA_REG(priv->config->id)); + resetbits(SPI_OUT_DONE_INT_CLR_M, SPI_DMA_INT_ENA_REG(priv->config->id)); + +#ifdef CONFIG_ESP32S2_SPI_DMA + resetbits(priv->config->dma_clk_bit, SYSTEM_PERIP_CLK_EN0_REG); +#endif + + resetbits(priv->config->clk_bit, SYSTEM_PERIP_CLK_EN0_REG); + + priv->dev = NULL; + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: spislave_enqueue + * + * Description: + * Enqueue the next value to be shifted out from the interface. This adds + * the word to the controller driver for a subsequent transfer but has no + * effect on any in-process or currently "committed" transfers. + * + * Input Parameters: + * ctrlr - SPI Slave controller interface instance + * data - Pointer to the command/data mode data to be shifted out. + * The data width must be aligned to the nbits parameter which was + * previously provided to the bind() method. + * len - Number of units of "nbits" wide to enqueue, + * "nbits" being the data width previously provided to the bind() + * method. + * + * Returned Value: + * Number of data items successfully queued, or a negated errno: + * - "len" if all the data was successfully queued + * - "0..len-1" if queue is full + * - "-errno" in any other error + * + ****************************************************************************/ + +static int spislave_enqueue(struct spi_slave_ctrlr_s *ctrlr, + const void *data, + size_t len) +{ + struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr; + size_t num_bytes = WORDS2BYTES(priv, len); + size_t bufsize; + irqstate_t flags; + int enqueued_words; + + spiinfo("ctrlr=%p, data=%p, num_bytes=%zu\n", ctrlr, data, num_bytes); + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv->dev != NULL); + + flags = enter_critical_section(); + + bufsize = SPI_SLAVE_BUFSIZE - priv->tx_length; + if (bufsize == 0) + { + leave_critical_section(flags); + return -ENOSPC; + } + + num_bytes = MIN(num_bytes, bufsize); + memcpy(priv->tx_buffer + priv->tx_length, data, num_bytes); + priv->tx_length += num_bytes; + + enqueued_words = BYTES2WORDS(priv, num_bytes); + + if (!priv->is_processing) + { + spislave_prepare_next_tx(priv); + } + + leave_critical_section(flags); + + return enqueued_words; +} + +/**************************************************************************** + * Name: spislave_qfull + * + * Description: + * Return true if the queue is full or false if there is space to add an + * additional word to the queue. + * + * Input Parameters: + * ctrlr - SPI Slave controller interface instance + * + * Returned Value: + * true if the output queue is full, false otherwise. + * + ****************************************************************************/ + +static bool spislave_qfull(struct spi_slave_ctrlr_s *ctrlr) +{ + struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr; + irqstate_t flags; + bool is_full; + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv->dev != NULL); + + spiinfo("ctrlr=%p\n", ctrlr); + + flags = enter_critical_section(); + is_full = priv->tx_length == SPI_SLAVE_BUFSIZE; + leave_critical_section(flags); + + return is_full; +} + +/**************************************************************************** + * Name: spislave_qflush + * + * Description: + * Discard all saved values in the output queue. On return from this + * function the output queue will be empty. Any in-progress or otherwise + * "committed" output values may not be flushed. + * + * Input Parameters: + * ctrlr - SPI Slave controller interface instance + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void spislave_qflush(struct spi_slave_ctrlr_s *ctrlr) +{ + struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr; + irqstate_t flags; + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv->dev != NULL); + + spiinfo("ctrlr=%p\n", ctrlr); + + flags = enter_critical_section(); + priv->tx_length = 0; + priv->is_tx_enabled = false; + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: spislave_qpoll + * + * Description: + * Tell the controller to output all the receive queue data. + * + * Input Parameters: + * ctrlr - SPI Slave controller interface instance + * + * Returned Value: + * Number of units of width "nbits" left in the RX queue. If the device + * accepted all the data, the return value will be 0. + * + ****************************************************************************/ + +static size_t spislave_qpoll(struct spi_slave_ctrlr_s *ctrlr) +{ + struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr; + irqstate_t flags; + uint32_t tmp; + uint32_t recv_n; + size_t remaining_words; + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv->dev != NULL); + + spiinfo("ctrlr=%p\n", ctrlr); + + flags = enter_critical_section(); + + tmp = SPIS_DEV_RECEIVE(priv->dev, priv->rx_buffer, + BYTES2WORDS(priv, priv->rx_length)); + recv_n = WORDS2BYTES(priv, tmp); + if (recv_n < priv->rx_length) + { + /* If the upper layer does not receive all of the data from the receive + * buffer, move the remaining data to the head of the buffer. + */ + + priv->rx_length -= recv_n; + memmove(priv->rx_buffer, priv->rx_buffer + recv_n, priv->rx_length); + } + else + { + priv->rx_length = 0; + } + + remaining_words = BYTES2WORDS(priv, priv->rx_length); + + leave_critical_section(flags); + + return remaining_words; +} + +/**************************************************************************** + * Name: esp32s2_spislave_ctrlr_initialize + * + * Description: + * Initialize the selected SPI Slave bus. + * + * Input Parameters: + * port - Port number (for hardware that has multiple SPI Slave interfaces) + * + * Returned Value: + * Valid SPI Slave controller structure reference on success; + * NULL on failure. + * + ****************************************************************************/ + +struct spi_slave_ctrlr_s *esp32s2_spislave_ctrlr_initialize(int port) +{ + struct spi_slave_ctrlr_s *spislave_dev; + struct spislave_priv_s *priv; + irqstate_t flags; + + switch (port) + { +#ifdef CONFIG_ESP32S2_SPI2 + case ESP32S2_SPI2: + priv = &esp32s2_spi2slave_priv; + break; +#endif +#ifdef CONFIG_ESP32S2_SPI3 + case ESP32S2_SPI3: + priv = &esp32s2_spi3slave_priv; + break; +#endif + default: + return NULL; + } + + spislave_dev = (struct spi_slave_ctrlr_s *)priv; + + flags = enter_critical_section(); + + if ((volatile int)priv->refs != 0) + { + leave_critical_section(flags); + + return spislave_dev; + } + + /* Attach IRQ for CS pin interrupt */ + + DEBUGVERIFY(irq_attach(ESP32S2_PIN2IRQ(priv->config->cs_pin), + spislave_cs_interrupt, + priv)); + + priv->cpu = up_cpu_index(); + priv->cpuint = esp32s2_setup_irq(priv->config->periph, + ESP32S2_INT_PRIO_DEF, + ESP32S2_CPUINT_LEVEL); + if (priv->cpuint < 0) + { + /* Failed to allocate a CPU interrupt of this type. */ + + leave_critical_section(flags); + + return NULL; + } + + if (irq_attach(priv->config->irq, spislave_periph_interrupt, priv) != OK) + { + /* Failed to attach IRQ, so CPU interrupt must be freed. */ + + esp32s2_teardown_irq(priv->config->periph, priv->cpuint); + leave_critical_section(flags); + + return NULL; + } + + priv->refs++; + + leave_critical_section(flags); + + return spislave_dev; +} + +/**************************************************************************** + * Name: esp32s2_spislave_ctrlr_uninitialize + * + * Description: + * Uninitialize an SPI Slave bus. + * + * Input Parameters: + * ctrlr - SPI Slave controller interface instance + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise -1 (ERROR). + * + ****************************************************************************/ + +int esp32s2_spislave_ctrlr_uninitialize(struct spi_slave_ctrlr_s *ctrlr) +{ + struct spislave_priv_s *priv = (struct spislave_priv_s *)ctrlr; + irqstate_t flags; + + DEBUGASSERT(ctrlr != NULL); + + if (priv->refs == 0) + { + return ERROR; + } + + flags = enter_critical_section(); + + if (--priv->refs) + { + leave_critical_section(flags); + return OK; + } + + up_disable_irq(priv->config->irq); + esp32s2_teardown_irq(priv->config->periph, priv->cpuint); + priv->cpuint = -ENOMEM; + + spislave_deinitialize(ctrlr); + + leave_critical_section(flags); + + return OK; +} + +#endif /* defined(CONFIG_ESP32S2_SPI) && defined (CONFIG_SPI_SLAVE) */ diff --git a/boards/xtensa/esp32s2/common/include/esp32s2_board_spidev.h b/boards/xtensa/esp32s2/common/include/esp32s2_board_spidev.h new file mode 100644 index 0000000000000..89c4a089af303 --- /dev/null +++ b/boards/xtensa/esp32s2/common/include/esp32s2_board_spidev.h @@ -0,0 +1,74 @@ +/**************************************************************************** + * boards/xtensa/esp32s2/common/include/esp32s2_board_spidev.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_XTENSA_ESP32S2_COMMON_INCLUDE_ESP32S2_BOARD_SPIDEV_H +#define __BOARDS_XTENSA_ESP32S2_COMMON_INCLUDE_ESP32S2_BOARD_SPIDEV_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * 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_spidev_initialize + * + * Description: + * Initialize SPI driver and register the /dev/spi device. + * + * Input Parameters: + * bus - The SPI bus number, used to build the device path as /dev/spiN + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_DRIVER +int board_spidev_initialize(int bus); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_XTENSA_ESP32S2_COMMON_INCLUDE_ESP32S2_BOARD_SPIDEV_H */ diff --git a/boards/xtensa/esp32s2/common/include/esp32s2_board_spislavedev.h b/boards/xtensa/esp32s2/common/include/esp32s2_board_spislavedev.h new file mode 100644 index 0000000000000..e883e5898adc5 --- /dev/null +++ b/boards/xtensa/esp32s2/common/include/esp32s2_board_spislavedev.h @@ -0,0 +1,74 @@ +/**************************************************************************** + * boards/xtensa/esp32s2/common/include/esp32s2_board_spislavedev.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_XTENSA_ESP32S2_COMMON_INCLUDE_ESP32S2_BOARD_SPISLAVEDEV_H +#define __BOARDS_XTENSA_ESP32S2_COMMON_INCLUDE_ESP32S2_BOARD_SPISLAVEDEV_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * 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_spislavedev_initialize + * + * Description: + * Initialize SPI Slave driver and register the /dev/spislv device. + * + * Input Parameters: + * bus - The SPI bus number, used to build the device path as /dev/spislvN + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_SLAVE +int board_spislavedev_initialize(int bus); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_XTENSA_ESP32S2_COMMON_INCLUDE_ESP32S2_BOARD_SPISLAVEDEV_H */ diff --git a/boards/xtensa/esp32s2/common/src/Make.defs b/boards/xtensa/esp32s2/common/src/Make.defs index 9b22ffa636db4..e4c1769b08ee8 100644 --- a/boards/xtensa/esp32s2/common/src/Make.defs +++ b/boards/xtensa/esp32s2/common/src/Make.defs @@ -24,6 +24,18 @@ ifeq ($(CONFIG_WATCHDOG),y) CSRCS += esp32s2_board_wdt.c endif +ifeq ($(CONFIG_ESP32S2_SPI),y) + CSRCS += esp32s2_board_spi.c +endif + +ifeq ($(CONFIG_SPI_DRIVER),y) + CSRCS += esp32s2_board_spidev.c +endif + +ifeq ($(CONFIG_SPI_SLAVE_DRIVER),y) + CSRCS += esp32s2_board_spislavedev.c +endif + ifeq ($(CONFIG_ESP32S2_SPIFLASH),y) CSRCS += esp32s2_board_spiflash.c endif diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_board_spi.c b/boards/xtensa/esp32s2/common/src/esp32s2_board_spi.c similarity index 96% rename from boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_board_spi.c rename to boards/xtensa/esp32s2/common/src/esp32s2_board_spi.c index cf0594795786d..8bd63a60d0c76 100644 --- a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_board_spi.c +++ b/boards/xtensa/esp32s2/common/src/esp32s2_board_spi.c @@ -1,5 +1,5 @@ /**************************************************************************** - * boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_board_spi.c + * boards/xtensa/esp32s2/common/src/esp32s2_board_spi.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -31,7 +31,6 @@ #include #include "esp32s2_gpio.h" -#include "esp32s2-saola-1.h" /**************************************************************************** * Private Functions @@ -70,7 +69,7 @@ int esp32s2_spi2_cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd) * data bits are data or a command. */ - esp32s2_gpiowrite(GPIO_LCD_DC, !cmd); + esp32s2_gpiowrite(CONFIG_ESP32S2_SPI2_MISOPIN, !cmd); return OK; } diff --git a/boards/xtensa/esp32s2/common/src/esp32s2_board_spidev.c b/boards/xtensa/esp32s2/common/src/esp32s2_board_spidev.c new file mode 100644 index 0000000000000..5bec3c86b26c2 --- /dev/null +++ b/boards/xtensa/esp32s2/common/src/esp32s2_board_spidev.c @@ -0,0 +1,81 @@ +/**************************************************************************** + * boards/xtensa/esp32s2/common/src/esp32s2_board_spidev.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 + +#include +#include +#include + +#include + +#include "esp32s2_spi.h" + +#include "esp32s2_board_spidev.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_spidev_initialize + * + * Description: + * Initialize SPI driver and register the /dev/spi device. + * + * Input Parameters: + * port - The SPI bus number, used to build the device path as /dev/spiN + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +int board_spidev_initialize(int port) +{ + int ret; + struct spi_dev_s *spi; + + syslog(LOG_INFO, "Initializing /dev/spi%d...\n", port); + + /* Initialize SPI device */ + + spi = esp32s2_spibus_initialize(port); + if (spi == NULL) + { + syslog(LOG_ERR, "Failed to initialize SPI%d.\n", port); + return -ENODEV; + } + + ret = spi_register(spi, port); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to register /dev/spi%d: %d\n", port, ret); + + esp32s2_spibus_uninitialize(spi); + } + + return ret; +} diff --git a/boards/xtensa/esp32s2/common/src/esp32s2_board_spislavedev.c b/boards/xtensa/esp32s2/common/src/esp32s2_board_spislavedev.c new file mode 100644 index 0000000000000..649c70bdfa7a4 --- /dev/null +++ b/boards/xtensa/esp32s2/common/src/esp32s2_board_spislavedev.c @@ -0,0 +1,82 @@ +/**************************************************************************** + * boards/xtensa/esp32s2/common/src/esp32s2_board_spislavedev.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 + +#include +#include +#include + +#include + +#include "esp32s2_spi.h" + +#include "esp32s2_board_spislavedev.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_spislavedev_initialize + * + * Description: + * Initialize SPI Slave driver and register the /dev/spislv device. + * + * Input Parameters: + * bus - The SPI bus number, used to build the device path as /dev/spislvN + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +int board_spislavedev_initialize(int bus) +{ + int ret; + + struct spi_slave_ctrlr_s *ctrlr; + + spiinfo("Initializing /dev/spislv%d...\n", bus); + + /* Initialize SPI Slave controller device */ + + ctrlr = esp32s2_spislave_ctrlr_initialize(bus); + if (ctrlr == NULL) + { + spierr("Failed to initialize SPI%d as slave.\n", bus); + return -ENODEV; + } + + ret = spi_slave_register(ctrlr, bus); + if (ret < 0) + { + spierr("Failed to register /dev/spislv%d: %d\n", bus, ret); + + esp32s2_spislave_ctrlr_uninitialize(ctrlr); + } + + return ret; +} diff --git a/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/Make.defs b/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/Make.defs index 25d5d1a03d13b..a11ee24c0af0e 100644 --- a/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/Make.defs +++ b/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/Make.defs @@ -41,10 +41,6 @@ ifeq ($(CONFIG_I2C_DRIVER),y) CSRCS += esp32s2_board_i2c.c endif -ifeq ($(CONFIG_ESP32S2_SPI),y) -CSRCS += esp32s2_board_spi.c -endif - ifeq ($(CONFIG_ARCH_BUTTONS),y) CSRCS += esp32s2_buttons.c endif diff --git a/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2_board_spi.c b/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2_board_spi.c deleted file mode 100644 index 92dcc6a9a0e77..0000000000000 --- a/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2_board_spi.c +++ /dev/null @@ -1,128 +0,0 @@ -/**************************************************************************** - * boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2_board_spi.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 - -#include -#include -#include - -#include - -#include - -#include "esp32s2_gpio.h" -#include "esp32s2-kaluga-1.h" - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: esp32s2_spi2_status - ****************************************************************************/ - -#ifdef CONFIG_ESP32S2_SPI2 - -uint8_t esp32s2_spi2_status(struct spi_dev_s *dev, uint32_t devid) -{ - uint8_t status = 0; - - return status; -} - -#endif - -/**************************************************************************** - * Name: esp32s2_spi2_cmddata - ****************************************************************************/ - -#if defined(CONFIG_ESP32S2_SPI2) && defined(CONFIG_SPI_CMDDATA) - -int esp32s2_spi2_cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd) -{ - if (devid == SPIDEV_DISPLAY(0)) - { - /* This is the Data/Command control pad which determines whether the - * data bits are data or a command. - */ - - esp32s2_gpiowrite(GPIO_LCD_DC, !cmd); - - return OK; - } - - spiinfo("devid: %" PRIu32 " CMD: %s\n", devid, cmd ? "command" : - "data"); - - return -ENODEV; -} - -#endif - -/**************************************************************************** - * Name: esp32s2_spi3_status - ****************************************************************************/ - -#ifdef CONFIG_ESP32S2_SPI3 - -uint8_t esp32s2_spi3_status(struct spi_dev_s *dev, uint32_t devid) -{ - uint8_t status = 0; - - return status; -} - -#endif - -/**************************************************************************** - * Name: esp32s2_spi3_cmddata - ****************************************************************************/ - -#if defined(CONFIG_ESP32S2_SPI3) && defined(CONFIG_SPI_CMDDATA) - -int esp32s2_spi3_cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd) -{ - if (devid == SPIDEV_DISPLAY(0)) - { - /* This is the Data/Command control pad which determines whether the - * data bits are data or a command. - */ - - esp32s2_gpiowrite(CONFIG_ESP32S2_SPI3_MISOPIN, !cmd); - - return OK; - } - - spiinfo("devid: %" PRIu32 " CMD: %s\n", devid, cmd ? "command" : - "data"); - - return -ENODEV; -} - -#endif diff --git a/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2_bringup.c b/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2_bringup.c index 559fd99c6c0a9..1571c7d9f0aac 100644 --- a/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2_bringup.c +++ b/boards/xtensa/esp32s2/esp32s2-kaluga-1/src/esp32s2_bringup.c @@ -74,6 +74,16 @@ # include #endif +#ifdef CONFIG_SPI_DRIVER +# include "esp32s2_spi.h" +# include "esp32s2_board_spidev.h" +#endif + +#ifdef CONFIG_SPI_SLAVE_DRIVER +# include "esp32s2_spi.h" +# include "esp32s2_board_spislavedev.h" +#endif + #include "esp32s2-kaluga-1.h" /**************************************************************************** @@ -138,6 +148,33 @@ int esp32s2_bringup(void) } #endif +#ifdef CONFIG_ESP32S2_SPI2 +# ifdef CONFIG_SPI_DRIVER + ret = board_spidev_initialize(ESP32S2_SPI2); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize SPI%d driver: %d\n", + ESP32S2_SPI2, ret); + } +# elif defined(CONFIG_SPI_SLAVE_DRIVER) && defined(CONFIG_ESP32S2_SPI2_SLAVE) + ret = board_spislavedev_initialize(ESP32S2_SPI2); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize SPI%d Slave driver: %d\n", + ESP32S2_SPI2, ret); + } +# endif +#endif + +#if defined(CONFIG_SPI_SLAVE_DRIVER) && defined(CONFIG_ESP32S2_SPI3_SLAVE) + ret = board_spislavedev_initialize(ESP32S2_SPI3); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize SPI%d Slave driver: %d\n", + ESP32S2_SPI3, ret); + } +#endif + /* Register the timer drivers */ #ifdef CONFIG_TIMER diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/src/Make.defs b/boards/xtensa/esp32s2/esp32s2-saola-1/src/Make.defs index bc401f0332389..9cff7c4600d99 100644 --- a/boards/xtensa/esp32s2/esp32s2-saola-1/src/Make.defs +++ b/boards/xtensa/esp32s2/esp32s2-saola-1/src/Make.defs @@ -49,10 +49,6 @@ ifeq ($(CONFIG_SENSORS_BMP180),y) CSRCS += esp32s2_bmp180.c endif -ifeq ($(CONFIG_ESP32S2_SPI),y) -CSRCS += esp32s2_board_spi.c -endif - ifeq ($(CONFIG_ARCH_BUTTONS),y) CSRCS += esp32s2_buttons.c endif diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c index bded3ab92e228..e1c67318b094f 100644 --- a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c +++ b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c @@ -74,6 +74,16 @@ # include "esp32s2_max6675.h" #endif +#ifdef CONFIG_SPI_DRIVER +# include "esp32s2_spi.h" +# include "esp32s2_board_spidev.h" +#endif + +#ifdef CONFIG_SPI_SLAVE_DRIVER +# include "esp32s2_spi.h" +# include "esp32s2_board_spislavedev.h" +#endif + #include "esp32s2-saola-1.h" /**************************************************************************** @@ -162,6 +172,33 @@ int esp32s2_bringup(void) } #endif +#ifdef CONFIG_ESP32S2_SPI2 +# ifdef CONFIG_SPI_DRIVER + ret = board_spidev_initialize(ESP32S2_SPI2); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize SPI%d driver: %d\n", + ESP32S2_SPI2, ret); + } +# elif defined(CONFIG_SPI_SLAVE_DRIVER) && defined(CONFIG_ESP32S2_SPI2_SLAVE) + ret = board_spislavedev_initialize(ESP32S2_SPI2); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize SPI%d Slave driver: %d\n", + ESP32S2_SPI2, ret); + } +# endif +#endif + +#if defined(CONFIG_SPI_SLAVE_DRIVER) && defined(CONFIG_ESP32S2_SPI3_SLAVE) + ret = board_spislavedev_initialize(ESP32S2_SPI3); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize SPI%d Slave driver: %d\n", + ESP32S2_SPI3, ret); + } +#endif + /* Register the timer drivers */ #ifdef CONFIG_TIMER