drivers: spi: esp32: add basic SPI master support
Include SPI master support for blocking and asynchronous calls. Signed-off-by: Glauber Maroto Ferreira <glauber.ferreira@espressif.com>
This commit is contained in:
parent
c0ee8c4a43
commit
74922049ba
10 changed files with 616 additions and 0 deletions
|
@ -71,6 +71,26 @@
|
|||
scl-pin = <5>;
|
||||
};
|
||||
|
||||
&spi2 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "okay";
|
||||
miso-pin = <12>;
|
||||
mosi-pin = <13>;
|
||||
sclk-pin = <14>;
|
||||
csel-pin = <15>;
|
||||
};
|
||||
|
||||
&spi3 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "okay";
|
||||
miso-pin = <19>;
|
||||
mosi-pin = <23>;
|
||||
sclk-pin = <18>;
|
||||
csel-pin = <5>;
|
||||
};
|
||||
|
||||
&trng0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
|
|
@ -21,5 +21,6 @@ zephyr_library_sources_ifdef(CONFIG_SPI_OC_SIMPLE spi_oc_simple.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_SPI_XEC_QMSPI spi_xec_qmspi.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SPI_GECKO spi_gecko.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SPI_XLNX_AXI_QUADSPI spi_xlnx_axi_quadspi.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ESP32_SPIM spi_esp32_spim.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE spi_handlers.c)
|
||||
|
|
|
@ -223,4 +223,6 @@ source "drivers/spi/Kconfig.gecko"
|
|||
|
||||
source "drivers/spi/Kconfig.xlnx"
|
||||
|
||||
source "drivers/spi/Kconfig.esp32"
|
||||
|
||||
endif # SPI
|
||||
|
|
20
drivers/spi/Kconfig.esp32
Normal file
20
drivers/spi/Kconfig.esp32
Normal file
|
@ -0,0 +1,20 @@
|
|||
# ESP32 SPI configuration
|
||||
|
||||
# Copyright (c) 2020 Espressif Systems (Shanghai) Co., Ltd.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
menuconfig ESP32_SPIM
|
||||
bool "ESP32 SPI Master driver"
|
||||
depends on SOC_ESP32
|
||||
default y
|
||||
help
|
||||
Enables support for ESP32 SPI Master driver.
|
||||
|
||||
if ESP32_SPIM
|
||||
|
||||
config SPI_ESP32_INTERRUPT
|
||||
bool "ESP32 SPI interrupt mode"
|
||||
help
|
||||
Enables interrupt support for ESP32 SPI driver.
|
||||
|
||||
endif # ESP32_SPIM
|
436
drivers/spi/spi_esp32_spim.c
Normal file
436
drivers/spi/spi_esp32_spim.c
Normal file
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Espressif Systems (Shanghai) Co., Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT espressif_esp32_spi
|
||||
|
||||
/* Include esp-idf headers first to avoid redefining BIT() macro */
|
||||
#include <hal/spi_hal.h>
|
||||
#include <esp_attr.h>
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(esp32_spi, CONFIG_SPI_LOG_LEVEL);
|
||||
|
||||
#include <soc.h>
|
||||
#include <drivers/spi.h>
|
||||
#include <drivers/gpio/gpio_esp32.h>
|
||||
#include <drivers/clock_control.h>
|
||||
#include "spi_context.h"
|
||||
#include "spi_esp32_spim.h"
|
||||
|
||||
/* pins, signals and interrupts shall be placed into dts */
|
||||
#define MISO_IDX_2 HSPIQ_IN_IDX
|
||||
#define MISO_IDX_3 VSPIQ_IN_IDX
|
||||
#define MOSI_IDX_2 HSPID_OUT_IDX
|
||||
#define MOSI_IDX_3 VSPID_OUT_IDX
|
||||
#define SCLK_IDX_2 HSPICLK_OUT_IDX
|
||||
#define SCLK_IDX_3 VSPICLK_OUT_IDX
|
||||
#define CSEL_IDX_2 HSPICS0_OUT_IDX
|
||||
#define CSEL_IDX_3 VSPICS0_OUT_IDX
|
||||
|
||||
#define INST_2_ESPRESSIF_ESP32_SPI_IRQ_0 13
|
||||
#define INST_3_ESPRESSIF_ESP32_SPI_IRQ_0 17
|
||||
|
||||
static bool spi_esp32_transfer_ongoing(struct spi_esp32_data *data)
|
||||
{
|
||||
return spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx);
|
||||
}
|
||||
|
||||
static inline void spi_esp32_complete(struct spi_esp32_data *data,
|
||||
spi_dev_t *spi, int status)
|
||||
{
|
||||
#ifdef CONFIG_SPI_ESP32_INTERRUPT
|
||||
spi_ll_disable_int(spi);
|
||||
spi_ll_clear_int_stat(spi);
|
||||
#endif
|
||||
|
||||
spi_context_cs_control(&data->ctx, false);
|
||||
|
||||
#ifdef CONFIG_SPI_ESP32_INTERRUPT
|
||||
spi_context_complete(&data->ctx, status);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static int IRAM_ATTR spi_esp32_transfer(const struct device *dev)
|
||||
{
|
||||
struct spi_esp32_data *data = dev->data;
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
spi_hal_context_t *hal = &data->hal;
|
||||
size_t chunk_len = spi_context_max_continuous_chunk(&data->ctx);
|
||||
|
||||
/* clean up and prepare SPI hal */
|
||||
memset((uint32_t *) hal->hw->data_buf, 0, sizeof(hal->hw->data_buf));
|
||||
hal->send_buffer = (uint8_t *) ctx->tx_buf;
|
||||
hal->rcv_buffer = ctx->rx_buf;
|
||||
hal->tx_bitlen = chunk_len << 3;
|
||||
hal->rx_bitlen = chunk_len << 3;
|
||||
|
||||
/* configure SPI */
|
||||
spi_hal_setup_trans(hal);
|
||||
spi_hal_prepare_data(hal);
|
||||
|
||||
/* send data */
|
||||
spi_hal_user_start(hal);
|
||||
spi_context_update_tx(&data->ctx, data->dfs, chunk_len);
|
||||
|
||||
while (!spi_hal_usr_is_done(hal)) {
|
||||
/* nop */
|
||||
}
|
||||
|
||||
/* read data */
|
||||
spi_hal_fetch_result(hal);
|
||||
spi_context_update_rx(&data->ctx, data->dfs, chunk_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spi_esp32_init(const struct device *dev)
|
||||
{
|
||||
const struct spi_esp32_config *cfg = dev->config;
|
||||
struct spi_esp32_data *data = dev->data;
|
||||
|
||||
if (!cfg->clock_dev) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPI_ESP32_INTERRUPT
|
||||
cfg->irq_config_func(dev);
|
||||
#endif
|
||||
|
||||
spi_context_unlock_unconditionally(&data->ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spi_esp32_configure_pin(gpio_pin_t pin, int pin_sig,
|
||||
gpio_flags_t pin_mode)
|
||||
{
|
||||
const char *device_name = gpio_esp32_get_gpio_for_pin(pin);
|
||||
const struct device *gpio;
|
||||
int ret;
|
||||
|
||||
if (!device_name) {
|
||||
LOG_ERR("Could not find GPIO node on devicetree");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gpio = device_get_binding(device_name);
|
||||
if (!gpio) {
|
||||
LOG_ERR("Could not bind to GPIO device");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure(gpio, pin, pin_mode);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("SPI pin configuration failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pin_mode == GPIO_INPUT) {
|
||||
esp32_rom_gpio_matrix_in(pin, pin_sig, false);
|
||||
} else {
|
||||
esp32_rom_gpio_matrix_out(pin, pin_sig, false, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline spi_ll_io_mode_t spi_esp32_get_io_mode(uint16_t operation)
|
||||
{
|
||||
switch (operation & SPI_LINES_MASK) {
|
||||
case SPI_LINES_SINGLE:
|
||||
return SPI_LL_IO_MODE_NORMAL;
|
||||
case SPI_LINES_DUAL:
|
||||
return SPI_LL_IO_MODE_DUAL;
|
||||
case SPI_LINES_OCTAL:
|
||||
return SPI_LL_IO_MODE_QIO;
|
||||
case SPI_LINES_QUAD:
|
||||
return SPI_LL_IO_MODE_QUAD;
|
||||
default:
|
||||
return SPI_LL_IO_MODE_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int IRAM_ATTR spi_esp32_configure(const struct device *dev,
|
||||
const struct spi_config *spi_cfg)
|
||||
{
|
||||
const struct spi_esp32_config *cfg = dev->config;
|
||||
struct spi_esp32_data *data = dev->data;
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
spi_hal_context_t *hal = &data->hal;
|
||||
|
||||
if (spi_context_configured(ctx, spi_cfg)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* enables SPI peripheral */
|
||||
if (clock_control_on(cfg->clock_dev, cfg->clock_subsys)) {
|
||||
LOG_ERR("Could not enable SPI clock");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ctx->config = spi_cfg;
|
||||
|
||||
if (spi_cfg->operation & SPI_OP_MODE_SLAVE) {
|
||||
LOG_ERR("Slave mode not supported");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (spi_cfg->operation & SPI_MODE_LOOP) {
|
||||
LOG_ERR("Loopback mode is not supported");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
spi_esp32_configure_pin(cfg->pins.miso,
|
||||
cfg->signals.miso_s,
|
||||
GPIO_INPUT);
|
||||
|
||||
spi_esp32_configure_pin(cfg->pins.mosi,
|
||||
cfg->signals.mosi_s,
|
||||
GPIO_OUTPUT_LOW);
|
||||
|
||||
spi_esp32_configure_pin(cfg->pins.sclk,
|
||||
cfg->signals.sclk_s,
|
||||
GPIO_OUTPUT);
|
||||
|
||||
if (ctx->config->cs == NULL) {
|
||||
data->hal.cs_setup = 1;
|
||||
data->hal.cs_hold = 1;
|
||||
data->hal.cs_pin_id = 0;
|
||||
|
||||
spi_esp32_configure_pin(cfg->pins.csel,
|
||||
cfg->signals.csel_s,
|
||||
GPIO_OUTPUT | GPIO_ACTIVE_LOW);
|
||||
}
|
||||
|
||||
spi_context_cs_configure(&data->ctx);
|
||||
|
||||
spi_hal_get_clock_conf(hal, spi_cfg->frequency, 128, true, 0, NULL,
|
||||
&data->timing_conf);
|
||||
|
||||
data->hal.timing_conf = &data->timing_conf;
|
||||
data->hal.dummy_bits = data->hal.timing_conf->timing_dummy;
|
||||
|
||||
data->hal.tx_lsbfirst = spi_cfg->operation & SPI_TRANSFER_LSB ? 1 : 0;
|
||||
data->hal.rx_lsbfirst = spi_cfg->operation & SPI_TRANSFER_LSB ? 1 : 0;
|
||||
|
||||
data->hal.io_mode = spi_esp32_get_io_mode(spi_cfg->operation);
|
||||
|
||||
/* SPI mode */
|
||||
data->hal.mode = 0;
|
||||
if (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPOL) {
|
||||
data->hal.mode = BIT(0);
|
||||
}
|
||||
|
||||
if (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPHA) {
|
||||
data->hal.mode |= BIT(1);
|
||||
}
|
||||
|
||||
spi_hal_setup_device(hal);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint8_t spi_esp32_get_frame_size(const struct spi_config *spi_cfg)
|
||||
{
|
||||
uint8_t dfs = SPI_WORD_SIZE_GET(spi_cfg->operation);
|
||||
|
||||
dfs /= 8;
|
||||
|
||||
if ((dfs == 0) || (dfs > 4)) {
|
||||
LOG_WRN("Unsupported dfs, 1-byte size will be used");
|
||||
dfs = 1;
|
||||
}
|
||||
|
||||
return dfs;
|
||||
}
|
||||
|
||||
static int transceive(const struct device *dev,
|
||||
const struct spi_config *spi_cfg,
|
||||
const struct spi_buf_set *tx_bufs,
|
||||
const struct spi_buf_set *rx_bufs, bool asynchronous,
|
||||
struct k_poll_signal *signal)
|
||||
{
|
||||
const struct spi_esp32_config *cfg = dev->config;
|
||||
struct spi_esp32_data *data = dev->data;
|
||||
int ret;
|
||||
|
||||
if (!tx_bufs && !rx_bufs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SPI_ESP32_INTERRUPT
|
||||
if (asynchronous) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
|
||||
spi_context_lock(&data->ctx, asynchronous, signal, spi_cfg);
|
||||
|
||||
ret = spi_esp32_configure(dev, spi_cfg);
|
||||
if (ret) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
data->dfs = spi_esp32_get_frame_size(spi_cfg);
|
||||
|
||||
spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, data->dfs);
|
||||
|
||||
spi_context_cs_control(&data->ctx, true);
|
||||
|
||||
#ifdef CONFIG_SPI_ESP32_INTERRUPT
|
||||
spi_ll_enable_int(cfg->spi);
|
||||
spi_ll_set_int_stat(cfg->spi);
|
||||
#else
|
||||
|
||||
do {
|
||||
spi_esp32_transfer(dev);
|
||||
} while (spi_esp32_transfer_ongoing(data));
|
||||
|
||||
spi_esp32_complete(data, cfg->spi, 0);
|
||||
|
||||
#endif /* CONFIG_SPI_ESP32_INTERRUPT */
|
||||
|
||||
done:
|
||||
spi_context_release(&data->ctx, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPI_ESP32_INTERRUPT
|
||||
static void IRAM_ATTR spi_esp32_isr(const struct device *dev)
|
||||
{
|
||||
const struct spi_esp32_config *cfg = dev->config;
|
||||
struct spi_esp32_data *data = dev->data;
|
||||
|
||||
do {
|
||||
spi_esp32_transfer(dev);
|
||||
} while (spi_esp32_transfer_ongoing(data));
|
||||
|
||||
spi_esp32_complete(data, cfg->spi, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int spi_esp32_transceive(const struct device *dev,
|
||||
const struct spi_config *spi_cfg,
|
||||
const struct spi_buf_set *tx_bufs,
|
||||
const struct spi_buf_set *rx_bufs)
|
||||
{
|
||||
return transceive(dev, spi_cfg, tx_bufs, rx_bufs, false, NULL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPI_ASYNC
|
||||
static int spi_esp32_transceive_async(const struct device *dev,
|
||||
const struct spi_config *spi_cfg,
|
||||
const struct spi_buf_set *tx_bufs,
|
||||
const struct spi_buf_set *rx_bufs,
|
||||
struct k_poll_signal *async)
|
||||
{
|
||||
return transceive(dev, spi_cfg, tx_bufs, rx_bufs, true, async);
|
||||
}
|
||||
#endif /* CONFIG_SPI_ASYNC */
|
||||
|
||||
static int spi_esp32_release(const struct device *dev,
|
||||
const struct spi_config *config)
|
||||
{
|
||||
struct spi_esp32_data *data = dev->data;
|
||||
|
||||
spi_context_unlock_unconditionally(&data->ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_driver_api spi_api = {
|
||||
.transceive = spi_esp32_transceive,
|
||||
#ifdef CONFIG_SPI_ASYNC
|
||||
.transceive_async = spi_esp32_transceive_async,
|
||||
#endif
|
||||
.release = spi_esp32_release
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SPI_ESP32_INTERRUPT
|
||||
#define ESP32_SPI_IRQ_HANDLER_DECL(idx) \
|
||||
static void spi_esp32_irq_config_func_##idx(const struct device *dev)
|
||||
|
||||
#define ESP32_SPI_IRQ_HANDLER_FUNC(idx) \
|
||||
.irq_config_func = spi_esp32_irq_config_func_##idx,
|
||||
|
||||
#define ESP32_SPI_IRQ_HANDLER(idx) \
|
||||
static void spi_esp32_irq_config_func_##idx(const struct device *dev) \
|
||||
{ \
|
||||
intr_matrix_set(0, ETS_SPI##idx##_INTR_SOURCE, \
|
||||
INST_##idx##_ESPRESSIF_ESP32_SPI_IRQ_0); \
|
||||
IRQ_CONNECT(INST_##idx##_ESPRESSIF_ESP32_SPI_IRQ_0, 1, \
|
||||
spi_esp32_isr, DEVICE_DT_GET(DT_NODELABEL(spi##idx)), 0); \
|
||||
irq_enable(INST_##idx##_ESPRESSIF_ESP32_SPI_IRQ_0); \
|
||||
}
|
||||
#else
|
||||
#define ESP32_SPI_IRQ_HANDLER_DECL(idx)
|
||||
#define ESP32_SPI_IRQ_HANDLER_FUNC(idx)
|
||||
#define ESP32_SPI_IRQ_HANDLER(idx)
|
||||
#endif
|
||||
|
||||
#define ESP32_SPI_INIT(idx) \
|
||||
ESP32_SPI_IRQ_HANDLER_DECL(idx); \
|
||||
\
|
||||
static struct spi_esp32_data spi_data_##idx = { \
|
||||
SPI_CONTEXT_INIT_LOCK(spi_data_##idx, ctx), \
|
||||
SPI_CONTEXT_INIT_SYNC(spi_data_##idx, ctx), \
|
||||
.hal = { \
|
||||
.hw = (spi_dev_t *)DT_REG_ADDR(DT_NODELABEL(spi##idx)), \
|
||||
.half_duplex = DT_PROP(DT_NODELABEL(spi##idx), half_duplex), \
|
||||
.as_cs = DT_PROP(DT_NODELABEL(spi##idx), clk_as_cs), \
|
||||
.positive_cs = DT_PROP(DT_NODELABEL(spi##idx), positive_cs), \
|
||||
.dma_enabled = DT_PROP(DT_NODELABEL(spi##idx), dma), \
|
||||
.no_compensate = DT_PROP(DT_NODELABEL(spi##idx), dummy_comp), \
|
||||
.sio = DT_PROP(DT_NODELABEL(spi##idx), sio) \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
static const struct spi_esp32_config spi_config_##idx = { \
|
||||
.spi = (spi_dev_t *)DT_REG_ADDR(DT_NODELABEL(spi##idx)), \
|
||||
\
|
||||
.clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_NODELABEL(spi##idx))), \
|
||||
ESP32_SPI_IRQ_HANDLER_FUNC(idx) \
|
||||
\
|
||||
.signals = { \
|
||||
.miso_s = MISO_IDX_##idx, \
|
||||
.mosi_s = MOSI_IDX_##idx, \
|
||||
.sclk_s = SCLK_IDX_##idx, \
|
||||
.csel_s = CSEL_IDX_##idx \
|
||||
}, \
|
||||
\
|
||||
.pins = { \
|
||||
.miso = DT_PROP(DT_NODELABEL(spi##idx), miso_pin), \
|
||||
.mosi = DT_PROP(DT_NODELABEL(spi##idx), mosi_pin), \
|
||||
.sclk = DT_PROP(DT_NODELABEL(spi##idx), sclk_pin), \
|
||||
.csel = DT_PROP(DT_NODELABEL(spi##idx), csel_pin) \
|
||||
}, \
|
||||
\
|
||||
.clock_subsys = \
|
||||
(clock_control_subsys_t)DT_CLOCKS_CELL( \
|
||||
DT_NODELABEL(spi##idx), offset), \
|
||||
\
|
||||
.irq = { \
|
||||
.source = ETS_SPI##idx##_INTR_SOURCE, \
|
||||
.line = INST_##idx##_ESPRESSIF_ESP32_SPI_IRQ_0 \
|
||||
}, \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_DEFINE(DT_NODELABEL(spi##idx), &spi_esp32_init, \
|
||||
device_pm_control_no, &spi_data_##idx, \
|
||||
&spi_config_##idx, POST_KERNEL, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &spi_api); \
|
||||
\
|
||||
ESP32_SPI_IRQ_HANDLER(idx)
|
||||
|
||||
#if DT_NODE_HAS_STATUS(DT_NODELABEL(spi2), okay)
|
||||
ESP32_SPI_INIT(2);
|
||||
#endif
|
||||
|
||||
#if DT_NODE_HAS_STATUS(DT_NODELABEL(spi3), okay)
|
||||
ESP32_SPI_INIT(3);
|
||||
#endif
|
44
drivers/spi/spi_esp32_spim.h
Normal file
44
drivers/spi/spi_esp32_spim.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Espressif Systems (Shanghai) Co., Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_DRIVERS_SPI_ESP32_SPIM_H_
|
||||
#define ZEPHYR_DRIVERS_SPI_ESP32_SPIM_H_
|
||||
|
||||
struct spi_esp32_config {
|
||||
spi_dev_t *spi;
|
||||
const struct device *clock_dev;
|
||||
void (*irq_config_func)(const struct device *dev);
|
||||
|
||||
struct {
|
||||
int miso_s;
|
||||
int mosi_s;
|
||||
int sclk_s;
|
||||
int csel_s;
|
||||
} signals;
|
||||
|
||||
struct {
|
||||
int miso;
|
||||
int mosi;
|
||||
int sclk;
|
||||
int csel;
|
||||
} pins;
|
||||
|
||||
clock_control_subsys_t clock_subsys;
|
||||
|
||||
struct {
|
||||
int source;
|
||||
int line;
|
||||
} irq;
|
||||
};
|
||||
|
||||
struct spi_esp32_data {
|
||||
struct spi_context ctx;
|
||||
spi_hal_context_t hal;
|
||||
spi_hal_timing_conf_t timing_conf;
|
||||
uint8_t dfs;
|
||||
};
|
||||
|
||||
#endif /* ZEPHYR_DRIVERS_SPI_ESP32_SPIM_H_ */
|
71
dts/bindings/spi/espressif,esp32-spi.yaml
Normal file
71
dts/bindings/spi/espressif,esp32-spi.yaml
Normal file
|
@ -0,0 +1,71 @@
|
|||
description: ESP32 SPI
|
||||
|
||||
compatible: "espressif,esp32-spi"
|
||||
|
||||
include: spi-controller.yaml
|
||||
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
||||
|
||||
interrupts:
|
||||
required: false
|
||||
|
||||
miso-pin:
|
||||
type: int
|
||||
description: MISO pin
|
||||
required: true
|
||||
|
||||
mosi-pin:
|
||||
type: int
|
||||
description: MOSI pin
|
||||
required: true
|
||||
|
||||
sclk-pin:
|
||||
type: int
|
||||
description: SPI generated clock pin
|
||||
required: true
|
||||
|
||||
csel-pin:
|
||||
type: int
|
||||
description: chip select pin
|
||||
required: true
|
||||
|
||||
half-duplex:
|
||||
type: boolean
|
||||
required: false
|
||||
description: |
|
||||
Enable half-duplex communication mode.
|
||||
|
||||
Transmit data before receiving it, instead of simultaneously
|
||||
|
||||
dummy-comp:
|
||||
type: boolean
|
||||
required: false
|
||||
description: Enable dummy SPI compensation cycles
|
||||
|
||||
sio:
|
||||
type: boolean
|
||||
required: false
|
||||
description: |
|
||||
Enable 3-wire mode
|
||||
|
||||
Use MOSI for both sending and receiving data
|
||||
|
||||
dma:
|
||||
type: boolean
|
||||
required: false
|
||||
description: Enable SPI DMA support
|
||||
|
||||
clk-as-cs:
|
||||
type: boolean
|
||||
required: false
|
||||
description: |
|
||||
Support to toggle the CS while the clock toggles
|
||||
|
||||
Output clock on CS line if CS is active
|
||||
|
||||
positive-cs:
|
||||
type: boolean
|
||||
required: false
|
||||
description: Make CS positive during a transaction instead of negative
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <mem.h>
|
||||
#include <xtensa/xtensa.dtsi>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/i2c/i2c.h>
|
||||
|
@ -144,5 +145,21 @@
|
|||
label = "WDT_1";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
spi2: spi@3ff64000 {
|
||||
compatible = "espressif,esp32-spi";
|
||||
reg = <0x3ff64000 DT_SIZE_K(4)>;
|
||||
label = "SPI_2";
|
||||
clocks = <&rtc ESP32_SPI2_MODULE>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
spi3: spi@3ff65000 {
|
||||
compatible = "espressif,esp32-spi";
|
||||
reg = <0x3ff65000 DT_SIZE_K(4)>;
|
||||
label = "SPI_3";
|
||||
clocks = <&rtc ESP32_SPI3_MODULE>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -39,6 +39,9 @@ PROVIDE ( crc32_le = 0x4005cfec );
|
|||
PROVIDE ( Cache_Read_Disable_rom = 0x40009ab8 );
|
||||
PROVIDE ( Cache_Read_Enable_rom = 0x40009a84 );
|
||||
PROVIDE ( Cache_Read_Init_rom = 0x40009950 );
|
||||
PROVIDE ( SPI1 = 0x3ff42fff );
|
||||
PROVIDE ( SPI2 = 0x3ff64fff );
|
||||
PROVIDE ( SPI3 = 0x3ff65fff );
|
||||
|
||||
PROVIDE ( esp32_rom_uart_tx_one_char = 0x40009200 );
|
||||
PROVIDE ( esp32_rom_uart_rx_one_char = 0x400092d0 );
|
||||
|
|
2
tests/drivers/spi/spi_loopback/boards/esp32.conf
Normal file
2
tests/drivers/spi/spi_loopback/boards/esp32.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
CONFIG_SPI_LOOPBACK_DRV_NAME="SPI_3"
|
||||
CONFIG_SPI_ESP32_INTERRUPT=y
|
Loading…
Add table
Add a link
Reference in a new issue