blob: dd14fd0334f73b859e85ba320ecaa291e688840a [file] [log] [blame]
/****************************************************************************
* arch/risc-v/src/common/espressif/esp_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 <nuttx/config.h>
#ifdef CONFIG_ESPRESSIF_SPI
#include <assert.h>
#include <debug.h>
#include <sys/param.h>
#include <sys/types.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/clock.h>
#include <nuttx/mutex.h>
#include <nuttx/spi/spi.h>
#include <arch/board/board.h>
#include "esp_spi.h"
#include "esp_irq.h"
#include "esp_gpio.h"
#include "riscv_internal.h"
#include "hal/spi_hal.h"
#include "hal/spi_types.h"
#include "hal/spi_hal.h"
#include "esp_clk_tree.h"
#include "hal/clk_tree_hal.h"
#include "periph_ctrl.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#if CONFIG_ESPRESSIF_SPI_TEST_MODE
# define MOSI_PIN_ATTR (OUTPUT_FUNCTION_2 | INPUT_FUNCTION_2 | PULLUP)
# define MISO_PIN_ATTR (OUTPUT_FUNCTION_2 | INPUT_FUNCTION_2 | PULLUP)
#else
# define MOSI_PIN_ATTR (OUTPUT_FUNCTION_2)
# define MISO_PIN_ATTR (INPUT_FUNCTION_2 | PULLUP)
#endif
#define SPI2_IOMUX_MISOPIN 2
#define SPI2_IOMUX_MOSIPIN 7
#define SPI2_IOMUX_CLKPIN 6
#define SPI2_IOMUX_CSPIN 10
/* Check if Chip-Select pin will be controlled via software */
#ifdef CONFIG_ESPRESSIF_SPI_SWCS
# define SPI_HAVE_SWCS TRUE
#else
# define SPI_HAVE_SWCS FALSE
#endif
/* Verify whether SPI has been assigned IOMUX pins.
* Otherwise, SPI signals will be routed via GPIO Matrix.
*/
#define SPI_IS_CS_IOMUX (CONFIG_ESPRESSIF_SPI2_CSPIN == SPI2_IOMUX_CSPIN)
#define SPI_IS_CLK_IOMUX (CONFIG_ESPRESSIF_SPI2_CLKPIN == SPI2_IOMUX_CLKPIN)
#define SPI_IS_MOSI_IOMUX (CONFIG_ESPRESSIF_SPI2_MOSIPIN == SPI2_IOMUX_MOSIPIN)
#define SPI_IS_MISO_IOMUX (CONFIG_ESPRESSIF_SPI2_MISOPIN == SPI2_IOMUX_MISOPIN)
#define SPI_VIA_IOMUX (SPI_IS_CS_IOMUX || SPI_HAVE_SWCS) && \
(SPI_IS_CLK_IOMUX) && \
(SPI_IS_MOSI_IOMUX) && \
(SPI_IS_MISO_IOMUX)
/* SPI default width */
#define SPI_DEFAULT_WIDTH (8)
/* SPI default mode */
#define SPI_DEFAULT_MODE (SPIDEV_MODE0)
/* SPI Maximum buffer size in bytes */
#define SPI_MAX_BUF_SIZE (64)
/****************************************************************************
* Private Types
****************************************************************************/
/* SPI Device hardware configuration */
struct esp_spi_config_s
{
uint32_t width; /* SPI default width */
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 */
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 esp_spi_priv_s
{
/* Externally visible part of the SPI interface */
struct spi_dev_s spi_dev;
/* Port configuration */
const struct esp_spi_config_s *config;
int refs; /* Reference count */
mutex_t lock; /* Held while chip is selected for mutual exclusion */
uint8_t nbits; /* Actual SPI send/receive bits once transmission */
uint8_t id; /* ID number of SPI interface */
uint8_t module; /* Module ID of SPI interface */
spi_hal_context_t *ctx; /* Context struct of common layer */
spi_hal_config_t *cfg;
spi_hal_dev_config_t *dev_cfg; /* Device configuration struct of common layer */
spi_hal_timing_param_t *timing_param; /* Timing struct of common layer */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int esp_spi_lock(struct spi_dev_s *dev, bool lock);
#ifndef CONFIG_ESPRESSIF_SPI_UDCS
static void esp_spi_select(struct spi_dev_s *dev,
uint32_t devid, bool selected);
#endif
static uint32_t esp_spi_setfrequency(struct spi_dev_s *dev,
uint32_t frequency);
static void esp_spi_setmode(struct spi_dev_s *dev,
enum spi_mode_e mode);
static void esp_spi_setbits(struct spi_dev_s *dev, int nbits);
#ifdef CONFIG_SPI_HWFEATURES
static int esp_spi_hwfeatures(struct spi_dev_s *dev,
spi_hwfeatures_t features);
#endif
static uint32_t esp_spi_send(struct spi_dev_s *dev, uint32_t wd);
static void esp_spi_exchange(struct spi_dev_s *dev,
const void *txbuffer,
void *rxbuffer, size_t nwords);
static void esp_spi_poll_exchange(struct esp_spi_priv_s *priv,
const void *txbuffer,
void *rxbuffer,
size_t nwords);
#ifndef CONFIG_SPI_EXCHANGE
static void esp_spi_sndblock(struct spi_dev_s *dev,
const void *txbuffer,
size_t nwords);
static void esp_spi_recvblock(struct spi_dev_s *dev,
void *rxbuffer,
size_t nwords);
#endif
#ifdef CONFIG_SPI_TRIGGER
static int esp_spi_trigger(struct spi_dev_s *dev);
#endif
static void esp_spi_init(struct spi_dev_s *dev);
static void esp_spi_deinit(struct spi_dev_s *dev);
/****************************************************************************
* Private Data
****************************************************************************/
#ifdef CONFIG_ESPRESSIF_SPI2
spi_hal_config_t cfg =
{
0
};
spi_hal_context_t ctx =
{
0
};
spi_hal_dev_config_t dev_cfg =
{
.mode = SPI_DEFAULT_MODE,
.cs_setup = 0,
.cs_hold = 0,
.cs_pin_id = 0,
.timing_conf =
{
0
},
{
0
}
};
spi_hal_timing_param_t timing_param =
{
.no_compensate = 0,
.half_duplex = 0,
.input_delay_ns = 0,
#ifdef SPI_VIA_IOMUX
.use_gpio = 0,
#else
.use_gpio = 1,
#endif
.duty_cycle = 0,
.clk_src_hz = 0,
.expected_freq = 0,
};
static const struct esp_spi_config_s esp_spi2_config =
{
.width = SPI_DEFAULT_WIDTH,
.cs_pin = CONFIG_ESPRESSIF_SPI2_CSPIN,
.mosi_pin = CONFIG_ESPRESSIF_SPI2_MOSIPIN,
.miso_pin = CONFIG_ESPRESSIF_SPI2_MISOPIN,
.clk_pin = CONFIG_ESPRESSIF_SPI2_CLKPIN,
.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_ops_s esp_spi2_ops =
{
.lock = esp_spi_lock,
#ifdef CONFIG_ESPRESSIF_SPI_UDCS
.select = esp_spi2_select,
#else
.select = esp_spi_select,
#endif
.setfrequency = esp_spi_setfrequency,
.setmode = esp_spi_setmode,
.setbits = esp_spi_setbits,
#ifdef CONFIG_SPI_HWFEATURES
.hwfeatures = esp_spi_hwfeatures,
#endif
.status = esp_spi2_status,
#ifdef CONFIG_SPI_CMDDATA
.cmddata = esp_spi2_cmddata,
#endif
.send = esp_spi_send,
#ifdef CONFIG_SPI_EXCHANGE
.exchange = esp_spi_exchange,
#else
.sndblock = esp_spi_sndblock,
.recvblock = esp_spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = esp_spi_trigger,
#endif
.registercallback = NULL,
};
static struct esp_spi_priv_s esp_spi2_priv =
{
.spi_dev =
{
.ops = &esp_spi2_ops
},
.config = &esp_spi2_config,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.id = SPI2_HOST,
.module = PERIPH_SPI2_MODULE,
.nbits = 0,
.cfg = &cfg,
.dev_cfg = &dev_cfg,
.ctx = &ctx,
.timing_param = &timing_param,
};
#endif /* CONFIG_ESPRESSIF_SPI2 */
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: esp_spi_lock
*
* Description:
* Lock or unlock the SPI device.
*
* Input Parameters:
* dev - Device-specific state data
* lock - true: Lock SPI bus, false: unlock SPI bus
*
* Returned Value:
* The result of lock or unlock the SPI device.
*
****************************************************************************/
static int esp_spi_lock(struct spi_dev_s *dev, bool lock)
{
int ret;
struct esp_spi_priv_s *priv = (struct esp_spi_priv_s *)dev;
if (lock)
{
ret = nxmutex_lock(&priv->lock);
}
else
{
ret = nxmutex_unlock(&priv->lock);
}
return ret;
}
/****************************************************************************
* Name: esp_spi_select
*
* Description:
* Enable/disable the SPI chip select. The implementation of this method
* must include handshaking: If a device is selected, it must hold off
* all other attempts to select the device until the device is deselected.
*
* If ESPRESSIF_SPI_SWCS is disabled, the driver will use hardware CS so
* that once transmission is started the hardware selects the device and
* when this transmission is done hardware deselects the device
* automatically.
* So, this function will do nothing.
*
* Input Parameters:
* dev - Device-specific state data
* devid - Identifies the device to select
* selected - true: slave selected, false: slave de-selected
*
* Returned Value:
* None.
*
****************************************************************************/
#ifndef CONFIG_ESPRESSIF_SPI_UDCS
static void esp_spi_select(struct spi_dev_s *dev,
uint32_t devid, bool selected)
{
#if SPI_HAVE_SWCS
struct esp_spi_priv_s *priv = (struct esp_spi_priv_s *)dev;
bool value = selected ? false : true;
esp_gpiowrite(priv->config->cs_pin, value);
#endif
spiinfo("devid: %08" PRIx32 " CS: %s\n",
devid, selected ? "select" : "free");
}
#endif
/****************************************************************************
* Name: esp_spi_setfrequency
*
* Description:
* Set the SPI frequency.
*
* Input Parameters:
* dev - Device-specific state data
* frequency - The requested SPI frequency
*
* Returned Value:
* Returns the current selected frequency.
*
****************************************************************************/
static uint32_t esp_spi_setfrequency(struct spi_dev_s *dev,
uint32_t frequency)
{
struct esp_spi_priv_s *priv = (struct esp_spi_priv_s *)dev;
if (priv->timing_param->clk_src_hz == frequency)
{
/* Requested frequency is the same as the current frequency. */
return priv->timing_param->clk_src_hz;
}
spi_hal_cal_clock_conf(priv->timing_param,
NULL,
&(priv->dev_cfg->timing_conf));
priv->timing_param->expected_freq = frequency;
spiinfo("frequency=%" PRIu32 ", actual=%" PRIu32 "\n",
priv->timing_param->expected_freq,
priv->timing_param->clk_src_hz);
return priv->timing_param->clk_src_hz;
}
/****************************************************************************
* Name: esp_spi_setmode
*
* Description:
* Set the SPI mode.
*
* Input Parameters:
* dev - Device-specific state data
* mode - The requested SPI mode
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp_spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode)
{
struct esp_spi_priv_s *priv = (struct esp_spi_priv_s *)dev;
spiinfo("mode=%d\n", mode);
/* Has the mode changed? */
if (mode != priv->dev_cfg->mode)
{
if (mode > SPIDEV_MODE3 || mode < SPIDEV_MODE0)
{
spierr("Invalid mode: %d\n", mode);
DEBUGPANIC();
return;
}
else
{
spi_ll_master_set_mode(priv->ctx->hw, mode);
}
priv->dev_cfg->mode = mode;
}
}
/****************************************************************************
* Name: esp_spi_setbits
*
* Description:
* Set the number of bits per word.
*
* Input Parameters:
* dev - Device-specific state data
* nbits - The number of bits in an SPI word.
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp_spi_setbits(struct spi_dev_s *dev, int nbits)
{
struct esp_spi_priv_s *priv = (struct esp_spi_priv_s *)dev;
spiinfo("nbits=%d\n", nbits);
priv->nbits = nbits;
}
/****************************************************************************
* Name: esp_spi_hwfeatures
*
* Description:
* Set hardware-specific feature flags.
*
* Input Parameters:
* dev - Device-specific state data
* features - H/W feature flags
*
* Returned Value:
* Zero (OK) if the selected H/W features are enabled; A negated errno
* value if any H/W feature is not supportable.
*
****************************************************************************/
#ifdef CONFIG_SPI_HWFEATURES
static int esp_spi_hwfeatures(struct spi_dev_s *dev,
spi_hwfeatures_t features)
{
/* Other H/W features are not supported */
return (features == 0) ? OK : -ENOSYS;
}
#endif
/****************************************************************************
* Name: esp_spi_poll_send
*
* Description:
* Send one word on SPI by polling mode.
*
* Input Parameters:
* priv - SPI private state data
* wd - The word to send. The size of the data is determined by the
* number of bits selected for the SPI interface.
*
* Returned Value:
* Received value.
*
****************************************************************************/
static uint32_t esp_spi_poll_send(struct esp_spi_priv_s *priv, uint32_t wd)
{
uint32_t val;
spi_hal_trans_config_t trans =
{
0
};
spi_hal_setup_device(priv->ctx, priv->dev_cfg);
trans.tx_bitlen = priv->nbits;
trans.rx_bitlen = priv->nbits;
trans.rcv_buffer = (uint8_t *)&val;
trans.send_buffer = (uint8_t *)&wd;
trans.cs_keep_active = priv->dev_cfg->cs_hold;
trans.line_mode.data_lines = 2;
trans.line_mode.addr_lines = 1;
trans.line_mode.cmd_lines = 1;
priv->ctx->trans_config = trans;
spi_ll_set_mosi_bitlen(priv->ctx->hw, priv->nbits);
spi_hal_prepare_data(priv->ctx, priv->dev_cfg, &trans);
spi_hal_user_start(priv->ctx);
while (!spi_hal_usr_is_done(priv->ctx));
spi_hal_fetch_result(priv->ctx);
spiinfo("send=0x%" PRIx32 " and recv=0x%" PRIx32 "\n", wd, val);
return val;
}
/****************************************************************************
* Name: esp_spi_send
*
* Description:
* Send one word on SPI.
*
* Input Parameters:
* dev - Device-specific state data
* wd - The word to send. The size of the data is determined by the
* number of bits selected for the SPI interface.
*
* Returned Value:
* Received value.
*
****************************************************************************/
static uint32_t esp_spi_send(struct spi_dev_s *dev, uint32_t wd)
{
struct esp_spi_priv_s *priv = (struct esp_spi_priv_s *)dev;
return esp_spi_poll_send(priv, wd);
}
/****************************************************************************
* Name: esp_spi_poll_exchange
*
* Description:
* Exchange a block of data from SPI.
*
* Input Parameters:
* priv - SPI private state data
* txbuffer - A pointer to the buffer of data to be sent
* rxbuffer - A pointer to the buffer in which to receive data
* nwords - The length of data that to be exchanged in units of words.
* The wordsize is determined by the number of bits-per-word
* selected for the SPI interface. If nbits <= 8, the data is
* packed into uint8_t's; if nbits >8, the data is packed into
* uint16_t's
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp_spi_poll_exchange(struct esp_spi_priv_s *priv,
const void *txbuffer,
void *rxbuffer,
size_t nwords)
{
const uint32_t total_bytes = nwords * (priv->nbits / 8);
uintptr_t bytes_remaining = total_bytes;
uint8_t *tp = (uint8_t *)txbuffer;
uint8_t *rp = (uint8_t *)rxbuffer;
spi_hal_trans_config_t trans =
{
0
};
spi_hal_setup_device(priv->ctx, priv->dev_cfg);
trans.cs_keep_active = priv->dev_cfg->cs_hold;
trans.line_mode.data_lines = 2;
trans.line_mode.addr_lines = 1;
trans.line_mode.cmd_lines = 1;
while (bytes_remaining != 0)
{
uint32_t transfer_size = MIN(SPI_MAX_BUF_SIZE, bytes_remaining);
/* Write data words to data buffer registers.
* SPI peripheral contains 16 registers (W0 - W15).
*/
trans.tx_bitlen = transfer_size * 8;
trans.rx_bitlen = transfer_size * 8;
trans.rcv_buffer = (uint8_t *)rp;
trans.send_buffer = (uint8_t *)tp;
priv->ctx->trans_config = trans;
spi_hal_prepare_data(priv->ctx, priv->dev_cfg, &trans);
spi_ll_set_mosi_bitlen(priv->ctx->hw, (transfer_size * 8));
spi_hal_user_start(priv->ctx);
while (!spi_hal_usr_is_done(priv->ctx));
if (rp != NULL)
{
spi_hal_fetch_result(priv->ctx);
}
bytes_remaining -= transfer_size;
tp += transfer_size;
rp += transfer_size;
}
}
/****************************************************************************
* Name: esp_spi_exchange
*
* Description:
* Exchange a block of data from SPI.
*
* Input Parameters:
* dev - Device-specific state data
* txbuffer - A pointer to the buffer of data to be sent
* rxbuffer - A pointer to the buffer in which to receive data
* nwords - The length of data that to be exchanged in units of words.
* The wordsize is determined by the number of bits-per-word
* selected for the SPI interface. If nbits <= 8, the data is
* packed into uint8_t's; if nbits >8, the data is packed into
* uint16_t's
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp_spi_exchange(struct spi_dev_s *dev,
const void *txbuffer,
void *rxbuffer,
size_t nwords)
{
struct esp_spi_priv_s *priv = (struct esp_spi_priv_s *)dev;
esp_spi_poll_exchange(priv, txbuffer, rxbuffer, nwords);
}
#ifndef CONFIG_SPI_EXCHANGE
/****************************************************************************
* Name: esp_spi_sndblock
*
* Description:
* Send a block of data on SPI.
*
* Input Parameters:
* dev - Device-specific state data
* txbuffer - A pointer to the buffer of data to be sent
* nwords - The length of data to send from the buffer in number of
* words. The wordsize is determined by the number of
* bits-per-word selected for the SPI interface. If nbits <= 8,
* the data is packed into uint8_t's; if nbits >8, the data is
* packed into uint16_t's
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp_spi_sndblock(struct spi_dev_s *dev,
const void *txbuffer,
size_t nwords)
{
spiinfo("txbuffer=%p nwords=%d\n", txbuffer, nwords);
esp_spi_exchange(dev, txbuffer, NULL, nwords);
}
/****************************************************************************
* Name: esp_spi_recvblock
*
* Description:
* Receive a block of data from SPI.
*
* Input Parameters:
* dev - Device-specific state data
* rxbuffer - A pointer to the buffer in which to receive data
* nwords - The length of data that can be received in the buffer in
* number of words. The wordsize is determined by the number of
* bits-per-word selected for the SPI interface. If nbits <= 8,
* the data is packed into uint8_t's; if nbits >8, the data is
* packed into uint16_t's
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp_spi_recvblock(struct spi_dev_s *dev,
void *rxbuffer,
size_t nwords)
{
spiinfo("rxbuffer=%p nwords=%d\n", rxbuffer, nwords);
esp_spi_exchange(dev, NULL, rxbuffer, nwords);
}
#endif
/****************************************************************************
* Name: esp_spi_trigger
*
* Description:
* Trigger a previously configured DMA transfer.
*
* Input Parameters:
* dev - Device-specific state data
*
* Returned Value:
* -OK - Trigger was fired
* -ENOSYS - Trigger not fired due to lack of DMA or low level support
* -EIO - Trigger not fired because not previously primed
*
****************************************************************************/
#ifdef CONFIG_SPI_TRIGGER
static int esp_spi_trigger(struct spi_dev_s *dev)
{
return -ENOSYS;
}
#endif
/****************************************************************************
* Name: esp_spi_init
*
* Description:
* Initialize SPI hardware interface.
*
* Input Parameters:
* dev - Device-specific state data
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp_spi_init(struct spi_dev_s *dev)
{
struct esp_spi_priv_s *priv = (struct esp_spi_priv_s *)dev;
const struct esp_spi_config_s *config = priv->config;
uint32_t regval;
esp_gpiowrite(config->cs_pin, true);
esp_gpiowrite(config->mosi_pin, true);
esp_gpiowrite(config->miso_pin, true);
esp_gpiowrite(config->clk_pin, true);
#if SPI_HAVE_SWCS
esp_configgpio(config->cs_pin, OUTPUT_FUNCTION_2);
esp_gpio_matrix_out(config->cs_pin, SIG_GPIO_OUT_IDX, 0, 0);
#endif
#if SPI_VIA_IOMUX
#if !SPI_HAVE_SWCS
esp_configgpio(config->cs_pin, OUTPUT_FUNCTION_3);
esp_gpio_matrix_out(config->cs_pin, SIG_GPIO_OUT_IDX, 0, 0);
#endif
esp_configgpio(config->mosi_pin, OUTPUT_FUNCTION_3);
esp_gpio_matrix_out(config->mosi_pin, SIG_GPIO_OUT_IDX, 0, 0);
esp_configgpio(config->miso_pin, INPUT_FUNCTION_3 | PULLUP);
esp_gpio_matrix_out(config->miso_pin, SIG_GPIO_OUT_IDX, 0, 0);
esp_configgpio(config->clk_pin, OUTPUT_FUNCTION_3);
esp_gpio_matrix_out(config->clk_pin, SIG_GPIO_OUT_IDX, 0, 0);
#else
#if !SPI_HAVE_SWCS
esp_configgpio(config->cs_pin, OUTPUT_FUNCTION_2);
esp_gpio_matrix_out(config->cs_pin, config->cs_outsig, 0, 0);
#endif
esp_configgpio(config->mosi_pin, MOSI_PIN_ATTR);
esp_gpio_matrix_out(config->mosi_pin, config->mosi_outsig, 0, 0);
esp_configgpio(config->miso_pin, MISO_PIN_ATTR);
esp_gpio_matrix_in(config->miso_pin, config->miso_insig, 0);
esp_configgpio(config->clk_pin, OUTPUT_FUNCTION_2);
esp_gpio_matrix_out(config->clk_pin, config->clk_outsig, 0, 0);
#endif
periph_module_enable(priv->module);
spi_hal_init(priv->ctx, priv->id, priv->cfg);
priv->dev_cfg->timing_conf.clock_source = SPI_CLK_SRC_DEFAULT;
esp_spi_setfrequency(dev, priv->timing_param->expected_freq);
esp_spi_setbits(dev, config->width);
esp_spi_setmode(dev, priv->dev_cfg->mode);
spi_hal_setup_device(priv->ctx, priv->dev_cfg);
}
/****************************************************************************
* Name: esp_spi_deinit
*
* Description:
* Deinitialize SPI hardware interface.
*
* Input Parameters:
* dev - Device-specific state data
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp_spi_deinit(struct spi_dev_s *dev)
{
struct esp_spi_priv_s *priv = (struct esp_spi_priv_s *)dev;
periph_module_disable(priv->module);
spi_hal_deinit(priv->ctx);
priv->nbits = 0;
}
/****************************************************************************
* Name: esp_spibus_initialize
*
* Description:
* Initialize the selected SPI bus.
*
* Input Parameters:
* port - Port number (for hardware that has multiple SPI interfaces)
*
* Returned Value:
* Valid SPI device structure reference on success; NULL on failure.
*
****************************************************************************/
struct spi_dev_s *esp_spibus_initialize(int port)
{
struct spi_dev_s *spi_dev;
struct esp_spi_priv_s *priv;
switch (port)
{
#ifdef CONFIG_ESPRESSIF_SPI2
case ESPRESSIF_SPI2:
priv = &esp_spi2_priv;
break;
#endif
default:
return NULL;
}
spi_dev = (struct spi_dev_s *)priv;
nxmutex_lock(&priv->lock);
if (priv->refs != 0)
{
priv->refs++;
nxmutex_unlock(&priv->lock);
return spi_dev;
}
esp_spi_init(spi_dev);
priv->refs++;
nxmutex_unlock(&priv->lock);
return spi_dev;
}
/****************************************************************************
* Name: esp_spibus_uninitialize
*
* Description:
* Uninitialize an SPI bus.
*
* Input Parameters:
* dev - Device-specific state data
*
* Returned Value:
* Zero (OK) is returned on success. Otherwise -1 (ERROR).
*
****************************************************************************/
int esp_spibus_uninitialize(struct spi_dev_s *dev)
{
struct esp_spi_priv_s *priv = (struct esp_spi_priv_s *)dev;
DEBUGASSERT(dev);
if (priv->refs == 0)
{
return ERROR;
}
nxmutex_lock(&priv->lock);
if (--priv->refs != 0)
{
nxmutex_unlock(&priv->lock);
return OK;
}
esp_spi_deinit(dev);
nxmutex_unlock(&priv->lock);
return OK;
}
#endif /* CONFIG_ESPRESSIF_SPI */