drivers/spi: Remove legacy NRF5 master and slave drivers

As legacy SPI API is being removed.

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
This commit is contained in:
Tomasz Bursztyka 2018-03-28 11:30:25 +02:00 committed by Carles Cufí
commit 13dba12b9a
5 changed files with 6 additions and 1208 deletions

View file

@ -1,13 +1,8 @@
if(CONFIG_SPI_LEGACY_API)
zephyr_sources_ifdef(CONFIG_SPIM_NRF52 spim_nrf52_legacy.c)
zephyr_sources_ifdef(CONFIG_SPIS_NRF5 spis_nrf5_legacy.c)
else()
zephyr_sources_ifdef(CONFIG_SPI_DW spi_dw.c)
zephyr_sources_ifdef(CONFIG_SPI_INTEL spi_intel.c)
zephyr_sources_ifdef(CONFIG_SPI_STM32 spi_ll_stm32.c)
zephyr_sources_ifdef(CONFIG_SPI_MCUX_DSPI spi_mcux_dspi.c)
zephyr_sources_ifdef(CONFIG_SPI_SAM0 spi_sam0.c)
zephyr_sources_ifdef(CONFIG_NRFX_SPI spi_nrfx_spi.c)
endif()
zephyr_sources_ifdef(CONFIG_SPI_DW spi_dw.c)
zephyr_sources_ifdef(CONFIG_SPI_INTEL spi_intel.c)
zephyr_sources_ifdef(CONFIG_SPI_STM32 spi_ll_stm32.c)
zephyr_sources_ifdef(CONFIG_SPI_MCUX_DSPI spi_mcux_dspi.c)
zephyr_sources_ifdef(CONFIG_SPI_SAM0 spi_sam0.c)
zephyr_sources_ifdef(CONFIG_NRFX_SPI spi_nrfx_spi.c)
zephyr_sources_ifdef(CONFIG_USERSPACE spi_handlers.c)

View file

@ -288,14 +288,6 @@ config SPI_5_OP_MODES
2 is SLAVE mode only
3 is both modes are available.
if SPI_LEGACY_API
source "drivers/spi/Kconfig.nrf5_legacy"
endif # SPI_LEGACY_API
if !SPI_LEGACY_API
config SPI_INTEL
bool "Intel SPI controller driver"
depends on CPU_MINUTEIA
@ -315,6 +307,4 @@ source "drivers/spi/Kconfig.sam0"
source "drivers/spi/Kconfig.nrfx"
endif # !SPI_LEGACY_API
endif # SPI

View file

@ -1,279 +0,0 @@
# Kconfig - nrf5 series MDK SPI support
#
# Copyright (c) 2017, Intel Corp.
# Copyright (c) 2016-2017, Linaro Limited.
#
# SPDX-License-Identifier: Apache-2.0
#
# TODO add nrf51 master
menuconfig SPI_NRF5
bool "nRF5 SPI drivers"
depends on SOC_FAMILY_NRF5 && GPIO_NRF5_P0
default n
help
Enable support for nRF5 MCU series SPI drivers. Peripherals
with the same instance id can not be used together, e.g., SPIM0 and I2C_0
(TWIM0) and SPIS0. You may need to disable I2C_0 or I2C_1.
if SPI_NRF5
# nordic twiX0, spiX0, spi0 instances can not be used at the same time
if SPI_0 && !I2C_0
choice
prompt "SPI Port 0 Driver type"
optional
# TODO: rename to SPIM0_NRF5 when nRF51 SPIM driver is available.
config SPIM0_NRF52
bool "nRF52 SPIM0"
depends on SOC_SERIES_NRF52X
help
nRF52 SPI Master with EasyDMA on port 0
# On nRF51, SPI0 is SPIM-only.
config SPIS0_NRF52
bool "nRF52 SPIS0"
depends on SOC_SERIES_NRF52X
help
nRF51 and nRF52 SPI Slave with EasyDMA on port 0
endchoice
if SPIM0_NRF52
config SPIM0_NRF52_GPIO_SCK_PIN
int "SCK pin number"
range 0 31
help
GPIO pin number for SCK
config SPIM0_NRF52_GPIO_MOSI_PIN
int "MOSI pin number"
range 0 31
help
GPIO pin number to use for MOSI
config SPIM0_NRF52_GPIO_MISO_PIN
int "MISO pin number"
range 0 31
help
GPIO pin number for MISO
config SPIM0_NRF52_GPIO_SS_PIN_0
int "CS0 pin number"
range 0 255
default 255
help
Slave Select (Chip Select) gpio pin number for line n. Not used value
is 255 (0xff).
config SPIM0_NRF52_GPIO_SS_PIN_1
int "CS1 pin number"
range 0 255
default 255
help
Slave Select (Chip Select) gpio pin number for line n. Not used value
is 255 (0xff).
config SPIM0_NRF52_GPIO_SS_PIN_2
int "CS2 pin number"
range 0 255
default 255
help
Slave Select (Chip Select) gpio pin number for line n. Not used value
is 255 (0xff).
config SPIM0_NRF52_GPIO_SS_PIN_3
int "CS3 pin number"
range 0 255
default 255
help
Slave Select (Chip Select) gpio pin number for line n. Not used value
is 255 (0xff).
config SPIM0_NRF52_ORC
hex "Over Read Character"
default 0x00
range 0x00 0xff
help
This option configures what value to send when the TX char count is
less than the RX count.
endif # SPIM0_NRF52
if SPIS0_NRF52
config SPIS0_NRF52_GPIO_SCK_PIN
int "SCK pin number"
range 0 31
help
GPIO pin number for SCK
config SPIS0_NRF52_GPIO_MOSI_PIN
int "MOSI pin number"
range 0 31
help
GPIO pin number for MOSI
config SPIS0_NRF52_GPIO_MISO_PIN
int "MISO pin number"
range 0 31
help
GPIO pin number for MISO
config SPIS0_NRF52_GPIO_CSN_PIN
int "CSN pin number"
range 0 255
default 255
help
GPIO pin number for slave select (chip select). Not used value
is 255 (0xff).
config SPIS0_NRF52_DEF
hex "Default character"
default 0
help
Default character. Character clocked out in case of an ignored
transaction.
endif # SPIS0_NRF5
endif # SPI_0 && !I2C_0
# nordic twiX1, spiX1, spi1 instances can not be use at the same time
if SPI_1 && !I2C_1
choice
prompt "SPI Port 1 Driver type"
optional
config SPIM1_NRF52
bool "nRF52 SPIM1"
depends on SOC_SERIES_NRF52X
help
nRF52 SPI Master with EasyDMA on port 0
config SPIS1_NRF5
bool "nRF5 SPIS1"
depends on (SOC_SERIES_NRF52X || SOC_SERIES_NRF51X)
help
nRF51 and nRF52 SPI Slave with EasyDMA on port 1
endchoice
if SPIM1_NRF52
config SPIM1_NRF52_GPIO_SCK_PIN
int "SCK pin number"
range 0 31
help
GPIO pin number for SCK
config SPIM1_NRF52_GPIO_MOSI_PIN
int "MOSI pin number"
range 0 31
help
GPIO pin number to use for MOSI
config SPIM1_NRF52_GPIO_MISO_PIN
int "MISO pin number"
range 0 31
help
GPIO pin number for MISO
config SPIM1_NRF52_GPIO_SS_PIN_0
int "CS0 pin number"
range 0 255
default 255
help
Slave Select (Chip Select) gpio pin number for line n. Not used value
is 255 (0xff).
config SPIM1_NRF52_GPIO_SS_PIN_1
int "CS1 pin number"
range 0 255
default 255
help
Slave Select (Chip Select) gpio pin number for line n. Not used value
is 255 (0xff).
config SPIM1_NRF52_GPIO_SS_PIN_2
int "CS2 pin number"
range 0 255
default 255
help
Slave Select (Chip Select) gpio pin number for line n. Not used value
is 255 (0xff).
config SPIM1_NRF52_GPIO_SS_PIN_3
int "CS3 pin number"
range 0 255
default 255
help
Slave Select (Chip Select) gpio pin number for line n. Not used value
is 255 (0xff).
config SPIM1_NRF52_ORC
hex "Over Read Character"
default 0x00
range 0x00 0xff
help
This option configures what value to send when the TX char count is
less than the RX count.
endif # SPIM1_NRF52
if SPIS1_NRF5
config SPIS1_NRF5_GPIO_SCK_PIN
int "SCK pin number"
range 0 31
help
GPIO pin number for SCK
config SPIS1_NRF5_GPIO_MOSI_PIN
int "MOSI pin number"
range 0 31
help
GPIO pin number for MOSI
config SPIS1_NRF5_GPIO_MISO_PIN
int "MISO pin number"
range 0 31
help
GPIO pin number for MISO
config SPIS1_NRF5_GPIO_CSN_PIN
int "CSN pin number"
range 0 255
default 255
help
GPIO pin number for slave select (chip select). Not used value
is 255 (0xff).
config SPIS1_NRF5_DEF
hex "Default character"
default 0
help
Default character. Character clocked out in case of an ignored
transaction.
endif # SPIS1_NRF5
endif # SPI_1 && !I2C_1
# hidden compile options
config SPIM_NRF52
bool
depends on !I2C_0 || !I2C_1
default y if (SPIM0_NRF52 || SPIM1_NRF52)
config SPIS_NRF5
bool
depends on !I2C_0 || !I2C_1
default y if (SPIS0_NRF52 || SPIS1_NRF5)
endif # SPI_NRF5

View file

@ -1,452 +0,0 @@
/*
* Copyright (c) 2017 Intel Corp.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* #define CONFIG_ASSERT
* #define __ASSERT_ON 1
*/
#include <errno.h>
#include <spi.h>
#include <soc.h>
#include <nrf.h>
#include <misc/util.h>
#include <gpio.h>
#define SYS_LOG_DOMAIN "spim"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_SPI_LEVEL
#include <logging/sys_log.h>
/* @todo
*
* Add support for 52840 spim2.
*/
struct spim_nrf52_config {
volatile NRF_SPIM_Type *base;
void (*irq_config_func)(struct device *dev);
struct spi_config default_cfg;
struct {
u8_t sck;
u8_t mosi;
u8_t miso;
#define SS_UNUSED 255
/* Pin number of up to 4 slave devices */
u8_t ss[4];
} psel;
u8_t orc;
};
struct spim_nrf52_data {
struct k_sem sem;
struct device *gpio_port;
u8_t slave;
u8_t stopped:1;
u8_t txd:1;
u8_t rxd:1;
#if (SYS_LOG_LEVEL > SYS_LOG_LEVEL_INFO)
u32_t tx_cnt;
u32_t rx_cnt;
#endif
};
#define NRF52_SPIM_INT_END SPIM_INTENSET_END_Msk
#define NRF52_SPIM_INT_ENDRX SPIM_INTENSET_ENDRX_Msk
#define NRF52_SPIM_INT_ENDTX SPIM_INTENSET_ENDTX_Msk
#define NRF52_SPIM_ENABLE SPIM_ENABLE_ENABLE_Enabled
#define NRF52_SPIM_DISABLE SPIM_ENABLE_ENABLE_Disabled
static void spim_nrf52_print_cfg_registers(struct device *dev)
{
const struct spim_nrf52_config *config = dev->config->config_info;
volatile NRF_SPIM_Type *spim = config->base;
SYS_LOG_DBG("\n"
"SHORTS=0x%x INT=0x%x FREQUENCY=0x%x CONFIG=0x%x\n"
"ENABLE=0x%x SCKPIN=%d MISOPIN=%d MOSIPIN=%d\n"
"RXD.(PTR=0x%x MAXCNT=0x%x AMOUNT=0x%x)\n"
"TXD.(PTR=0x%x MAXCNT=0x%x AMOUNT=0x%x)\n",
spim->SHORTS, spim->INTENSET, spim->FREQUENCY, spim->CONFIG,
spim->ENABLE, spim->PSEL.SCK, spim->PSEL.MISO, spim->PSEL.MOSI,
spim->RXD.PTR, spim->RXD.MAXCNT, spim->RXD.AMOUNT,
spim->TXD.PTR, spim->TXD.MAXCNT, spim->TXD.AMOUNT);
/* maybe unused */
(void)spim;
}
static int spim_nrf52_configure(struct device *dev,
struct spi_config *spi_config)
{
const struct spim_nrf52_config *config = dev->config->config_info;
struct spim_nrf52_data *data = dev->driver_data;
volatile NRF_SPIM_Type *spim = config->base;
u32_t flags;
SYS_LOG_DBG("config=0x%x max_sys_freq=%d", spi_config->config,
spi_config->max_sys_freq);
/* make sure SPIM block is off */
spim->ENABLE = NRF52_SPIM_DISABLE;
spim->INTENCLR = 0xffffffffUL;
spim->SHORTS = 0;
spim->ORC = config->orc;
spim->TXD.LIST = 0;
spim->RXD.LIST = 0;
spim->TXD.MAXCNT = 0;
spim->RXD.MAXCNT = 0;
spim->EVENTS_END = 0;
spim->EVENTS_ENDTX = 0;
spim->EVENTS_ENDRX = 0;
spim->EVENTS_STOPPED = 0;
spim->EVENTS_STARTED = 0;
data->stopped = 1;
data->txd = 0;
data->rxd = 0;
#if (SYS_LOG_LEVEL > SYS_LOG_LEVEL_INFO)
data->tx_cnt = 0;
data->rx_cnt = 0;
#endif
switch (spi_config->max_sys_freq) {
case 125000:
spim->FREQUENCY = SPIM_FREQUENCY_FREQUENCY_K125;
break;
case 250000:
spim->FREQUENCY = SPIM_FREQUENCY_FREQUENCY_K250;
break;
case 500000:
spim->FREQUENCY = SPIM_FREQUENCY_FREQUENCY_K500;
break;
case 1000000:
spim->FREQUENCY = SPIM_FREQUENCY_FREQUENCY_M1;
break;
case 2000000:
spim->FREQUENCY = SPIM_FREQUENCY_FREQUENCY_M2;
break;
case 4000000:
spim->FREQUENCY = SPIM_FREQUENCY_FREQUENCY_M4;
break;
case 8000000:
spim->FREQUENCY = SPIM_FREQUENCY_FREQUENCY_M8;
break;
default:
SYS_LOG_ERR("unsupported frequency sck=%d\n",
spi_config->max_sys_freq);
return -EINVAL;
}
flags = spi_config->config;
/* nrf5 supports only 8 bit word size */
if (SPI_WORD_SIZE_GET(flags) != 8) {
SYS_LOG_ERR("unsupported word size\n");
return -EINVAL;
}
if (flags & SPI_MODE_LOOP) {
SYS_LOG_ERR("loopback unsupported\n");
return -EINVAL;
}
spim->CONFIG = (flags & SPI_TRANSFER_LSB) ?
(SPIM_CONFIG_ORDER_LsbFirst << SPIM_CONFIG_ORDER_Pos) :
(SPIM_CONFIG_ORDER_MsbFirst << SPIM_CONFIG_ORDER_Pos);
spim->CONFIG |= (flags & SPI_MODE_CPOL) ?
(SPIM_CONFIG_CPOL_ActiveLow << SPIM_CONFIG_CPOL_Pos) :
(SPIM_CONFIG_CPOL_ActiveHigh << SPIM_CONFIG_CPOL_Pos);
spim->CONFIG |= (flags & SPI_MODE_CPHA) ?
(SPIM_CONFIG_CPHA_Trailing << SPIM_CONFIG_CPHA_Pos) :
(SPIM_CONFIG_CPHA_Leading << SPIM_CONFIG_CPHA_Pos);
spim->INTENSET = NRF52_SPIM_INT_END;
spim_nrf52_print_cfg_registers(dev);
return 0;
}
static int spim_nrf52_slave_select(struct device *dev, u32_t slave)
{
struct spim_nrf52_data *data = dev->driver_data;
const struct spim_nrf52_config *config = dev->config->config_info;
__ASSERT((slave > 0) && (slave <= 4), "slave=%d", slave);
slave--;
if (config->psel.ss[slave] == SS_UNUSED) {
SYS_LOG_ERR("Slave %d is not configured\n", slave);
return -EINVAL;
}
data->slave = slave;
return 0;
}
static inline void spim_nrf52_csn(struct device *gpio_port, u32_t pin,
bool select)
{
int status;
status = gpio_pin_write(gpio_port, pin, select ? 0x0 : 0x1);
__ASSERT_NO_MSG(status == 0);
}
static int spim_nrf52_transceive(struct device *dev, const void *tx_buf,
u32_t tx_buf_len, void *rx_buf,
u32_t rx_buf_len)
{
const struct spim_nrf52_config *config = dev->config->config_info;
struct spim_nrf52_data *data = dev->driver_data;
volatile NRF_SPIM_Type *spim = config->base;
SYS_LOG_DBG("transceive tx_buf=0x%p rx_buf=0x%p tx_len=0x%x "
"rx_len=0x%x\n", tx_buf, rx_buf, tx_buf_len, rx_buf_len);
if (spim->ENABLE) {
return -EALREADY;
}
spim->ENABLE = NRF52_SPIM_ENABLE;
__ASSERT_NO_MSG(data->stopped);
data->stopped = 0;
if (tx_buf_len) {
__ASSERT_NO_MSG(tx_buf);
spim->TXD.MAXCNT = tx_buf_len;
spim->TXD.PTR = (u32_t)tx_buf;
data->txd = 0;
#if (SYS_LOG_LEVEL > SYS_LOG_LEVEL_INFO)
data->tx_cnt = 0;
#endif
} else {
spim->TXD.MAXCNT = 0;
}
if (rx_buf_len) {
__ASSERT_NO_MSG(rx_buf);
spim->RXD.MAXCNT = rx_buf_len;
spim->RXD.PTR = (u32_t)rx_buf;
data->rxd = 0;
#if (SYS_LOG_LEVEL > SYS_LOG_LEVEL_INFO)
data->rx_cnt = 0;
#endif
} else {
spim->RXD.MAXCNT = 0;
}
if (data->slave != SS_UNUSED) {
spim_nrf52_csn(data->gpio_port, config->psel.ss[data->slave],
true);
}
spim->INTENSET = NRF52_SPIM_INT_END;
SYS_LOG_DBG("spi_xfer %s/%s CS%d\n", rx_buf_len ? "R" : "-",
tx_buf_len ? "W" : "-", data->slave);
/* start SPI transfer transaction */
spim->TASKS_START = 1;
/* Wait for the transfer to complete */
k_sem_take(&data->sem, K_FOREVER);
if (data->slave != SS_UNUSED) {
spim_nrf52_csn(data->gpio_port, config->psel.ss[data->slave],
false);
}
/* Disable SPIM block for power saving */
spim->INTENCLR = 0xffffffffUL;
spim->ENABLE = NRF52_SPIM_DISABLE;
#if (SYS_LOG_LEVEL > SYS_LOG_LEVEL_INFO)
SYS_LOG_DBG("xfer complete rx_cnt=0x%x tx_cnt=0x%x rxd=%d txd=%d "
"stopped=%d\n", data->rx_cnt, data->tx_cnt, data->rxd,
data->txd, data->stopped);
#endif
return 0;
}
static void spim_nrf52_isr(void *arg)
{
struct device *dev = arg;
const struct spim_nrf52_config *config = dev->config->config_info;
struct spim_nrf52_data *data = dev->driver_data;
volatile NRF_SPIM_Type *spim = config->base;
if (spim->EVENTS_END) {
data->rxd = 1;
data->txd = 1;
/* assume spi transaction has stopped */
data->stopped = 1;
/* Cortex M4 specific EVENTS register clearing requires 4 cycles
* delayto avoid re-triggering of interrupt. Call to
* k_sem_give() will ensure this limit.
*/
spim->EVENTS_END = 0;
#if (SYS_LOG_LEVEL > SYS_LOG_LEVEL_INFO)
data->rx_cnt = spim->RXD.AMOUNT;
data->tx_cnt = spim->TXD.AMOUNT;
SYS_LOG_DBG("endrxtx rx_cnt=%d tx_cnt=%d", data->rx_cnt,
data->tx_cnt);
#endif
k_sem_give(&data->sem);
}
}
static int spim_nrf52_init(struct device *dev)
{
const struct spim_nrf52_config *config = dev->config->config_info;
struct spim_nrf52_data *data = dev->driver_data;
volatile NRF_SPIM_Type *spim = config->base;
int status;
int i;
SYS_LOG_DBG("%s", dev->config->name);
data->gpio_port = device_get_binding(CONFIG_GPIO_NRF5_P0_DEV_NAME);
k_sem_init(&data->sem, 0, UINT_MAX);
for (i = 0; i < sizeof(config->psel.ss); i++) {
if (config->psel.ss[i] != SS_UNUSED) {
status = gpio_pin_configure(data->gpio_port,
config->psel.ss[i],
GPIO_DIR_OUT | GPIO_PUD_PULL_UP);
__ASSERT_NO_MSG(status == 0);
spim_nrf52_csn(data->gpio_port, config->psel.ss[i],
false);
SYS_LOG_DBG("CS%d=%d\n", i, config->psel.ss[i]);
}
}
data->slave = SS_UNUSED;
status = gpio_pin_configure(data->gpio_port, config->psel.sck,
GPIO_DIR_OUT);
__ASSERT_NO_MSG(status == 0);
status = gpio_pin_configure(data->gpio_port, config->psel.mosi,
GPIO_DIR_OUT);
__ASSERT_NO_MSG(status == 0);
status = gpio_pin_configure(data->gpio_port, config->psel.miso,
GPIO_DIR_IN);
__ASSERT_NO_MSG(status == 0);
spim->PSEL.SCK = config->psel.sck;
spim->PSEL.MOSI = config->psel.mosi;
spim->PSEL.MISO = config->psel.miso;
status = spim_nrf52_configure(dev, (void *)&config->default_cfg);
if (status) {
return status;
}
config->irq_config_func(dev);
return 0;
}
static const struct spi_driver_api spim_nrf52_driver_api = {
.configure = spim_nrf52_configure,
.slave_select = spim_nrf52_slave_select,
.transceive = spim_nrf52_transceive,
};
/* i2c & spi (SPIM, SPIS, SPI) instance with the same id (e.g. I2C_0 and SPI_0)
* can NOT be used at the same time on nRF5x chip family.
*/
#if defined(CONFIG_SPIM0_NRF52) && !defined(CONFIG_I2C_0)
static void spim_nrf52_config_func_0(struct device *dev);
static const struct spim_nrf52_config spim_nrf52_config_0 = {
.base = NRF_SPIM0,
.irq_config_func = spim_nrf52_config_func_0,
.default_cfg = {
.config = CONFIG_SPI_0_DEFAULT_CFG,
.max_sys_freq = CONFIG_SPI_0_DEFAULT_BAUD_RATE,
},
.psel = {
.sck = CONFIG_SPIM0_NRF52_GPIO_SCK_PIN,
.mosi = CONFIG_SPIM0_NRF52_GPIO_MOSI_PIN,
.miso = CONFIG_SPIM0_NRF52_GPIO_MISO_PIN,
.ss = { CONFIG_SPIM0_NRF52_GPIO_SS_PIN_0,
CONFIG_SPIM0_NRF52_GPIO_SS_PIN_1,
CONFIG_SPIM0_NRF52_GPIO_SS_PIN_2,
CONFIG_SPIM0_NRF52_GPIO_SS_PIN_3 },
},
.orc = CONFIG_SPIM0_NRF52_ORC,
};
static struct spim_nrf52_data spim_nrf52_data_0;
DEVICE_AND_API_INIT(spim_nrf52_0, CONFIG_SPI_0_NAME, spim_nrf52_init,
&spim_nrf52_data_0, &spim_nrf52_config_0,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&spim_nrf52_driver_api);
static void spim_nrf52_config_func_0(struct device *dev)
{
IRQ_CONNECT(NRF5_IRQ_SPI0_TWI0_IRQn, CONFIG_SPI_0_IRQ_PRI,
spim_nrf52_isr, DEVICE_GET(spim_nrf52_0), 0);
irq_enable(NRF5_IRQ_SPI0_TWI0_IRQn);
}
#endif /* CONFIG_SPIM0_NRF52 && !CONFIG_I2C_0 */
#if defined(CONFIG_SPIM1_NRF52) && !defined(CONFIG_I2C_1)
static void spim_nrf52_config_func_1(struct device *dev);
static const struct spim_nrf52_config spim_nrf52_config_1 = {
.base = NRF_SPIM1,
.irq_config_func = spim_nrf52_config_func_1,
.default_cfg = {
.config = CONFIG_SPI_1_DEFAULT_CFG,
.max_sys_freq = CONFIG_SPI_1_DEFAULT_BAUD_RATE,
},
.psel = {
.sck = CONFIG_SPIM1_NRF52_GPIO_SCK_PIN,
.mosi = CONFIG_SPIM1_NRF52_GPIO_MOSI_PIN,
.miso = CONFIG_SPIM1_NRF52_GPIO_MISO_PIN,
.ss = { CONFIG_SPIM1_NRF52_GPIO_SS_PIN_0,
CONFIG_SPIM1_NRF52_GPIO_SS_PIN_1,
CONFIG_SPIM1_NRF52_GPIO_SS_PIN_2,
CONFIG_SPIM1_NRF52_GPIO_SS_PIN_3 },
},
.orc = CONFIG_SPIM1_NRF52_ORC,
};
static struct spim_nrf52_data spim_nrf52_data_1;
DEVICE_AND_API_INIT(spim_nrf52_1, CONFIG_SPI_1_NAME, spim_nrf52_init,
&spim_nrf52_data_1, &spim_nrf52_config_1,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&spim_nrf52_driver_api);
static void spim_nrf52_config_func_1(struct device *dev)
{
IRQ_CONNECT(NRF5_IRQ_SPI1_TWI1_IRQn, CONFIG_SPI_1_IRQ_PRI,
spim_nrf52_isr, DEVICE_GET(spim_nrf52_1), 0);
irq_enable(NRF5_IRQ_SPI1_TWI1_IRQn);
}
#endif /* CONFIG_SPIM1_NRF52 && !CONFIG_I2C_1 */

View file

@ -1,456 +0,0 @@
/* spis_nrf5.c - SPI slave driver for Nordic nRF5x SoCs */
/*
* Copyright (c) 2016, 2017 Linaro Limited.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_SPI_LEVEL
#include <device.h>
#include <errno.h>
#include <logging/sys_log.h>
#include <sys_io.h>
#include <board.h>
#include <init.h>
#include <gpio.h>
#include <spi.h>
#include <nrf.h>
#include <toolchain.h>
typedef void (*spis_nrf5_config_t)(void);
struct spis_nrf5_config {
NRF_SPIS_Type *regs; /* Registers */
spis_nrf5_config_t config_func; /* IRQ config func pointer */
u8_t sck_pin; /* SCK GPIO pin number */
u8_t mosi_pin; /* MOSI GPIO pin number */
u8_t miso_pin; /* MISO GPIO pin number */
u8_t csn_pin; /* CSN GPIO pin number */
u8_t def; /* Default character */
};
struct spis_nrf5_data {
u8_t error;
struct k_sem device_sync_sem; /* synchronisation semaphore */
};
#define DEV_CFG(dev) \
((const struct spis_nrf5_config * const)(dev)->config->config_info)
#define DEV_DATA(dev) \
((struct spis_nrf5_data * const)(dev)->driver_data)
#define SPI_REGS(dev) \
((DEV_CFG(dev))->regs)
/* Register fields */
#define NRF5_SPIS_SHORTCUT_END_ACQUIRE \
(SPIS_SHORTS_END_ACQUIRE_Enabled << SPIS_SHORTS_END_ACQUIRE_Pos)
#define NRF5_SPIS_ORDER_MSB \
(SPIS_CONFIG_ORDER_MsbFirst << SPIS_CONFIG_ORDER_Pos)
#define NRF5_SPIS_ORDER_LSB \
(SPIS_CONFIG_ORDER_LsbFirst << SPIS_CONFIG_ORDER_Pos)
#define NRF5_SPIS_CPHA_LEADING \
(SPIS_CONFIG_CPHA_Leading << SPIS_CONFIG_CPHA_Pos)
#define NRF5_SPIS_CPHA_TRAILING \
(SPIS_CONFIG_CPHA_Trailing << SPIS_CONFIG_CPHA_Pos)
#define NRF5_SPIS_CPOL_HIGH \
(SPIS_CONFIG_CPOL_ActiveHigh << SPIS_CONFIG_CPOL_Pos)
#define NRF5_SPIS_CPOL_LOW \
(SPIS_CONFIG_CPOL_ActiveLow << SPIS_CONFIG_CPOL_Pos)
#define NRF5_SPIS_ENABLED \
(SPIS_ENABLE_ENABLE_Enabled << SPIS_ENABLE_ENABLE_Pos)
#define NRF5_SPIS_CSN_DISABLED_CFG 0xff /* CS disabled value from Kconfig */
#if defined(CONFIG_SOC_SERIES_NRF51X)
#define NRF5_SPIS_CSN_DISABLED (~0U) /* CS disabled register value */
#elif defined(CONFIG_SOC_SERIES_NRF52X)
#define NRF5_SPIS_CSN_DISABLED (1U << 31) /* CS disabled register value */
#endif
static inline bool is_buf_in_ram(const void *buf)
{
return ((((uintptr_t) buf) & 0xE0000000) == 0x20000000);
}
static void spis_nrf5_print_cfg_registers(struct device *dev)
{
__unused NRF_SPIS_Type *regs = SPI_REGS(dev);
__unused u32_t sck, miso, mosi, csn;
__unused u32_t rxd_ptr, rxd_max, rxd_amount;
__unused u32_t txd_ptr, txd_max, txd_amount;
#if defined(CONFIG_SOC_SERIES_NRF51X)
sck = regs->PSELSCK;
miso = regs->PSELMISO;
mosi = regs->PSELMOSI;
csn = regs->PSELCSN;
rxd_ptr = regs->RXDPTR;
rxd_max = regs->MAXRX;
rxd_amount = regs->AMOUNTRX;
txd_ptr = regs->TXDPTR;
txd_max = regs->MAXTX;
txd_amount = regs->AMOUNTTX;
#elif defined(CONFIG_SOC_SERIES_NRF52X)
sck = regs->PSEL.SCK;
miso = regs->PSEL.MISO;
mosi = regs->PSEL.MOSI;
csn = regs->PSEL.CSN;
rxd_ptr = regs->RXD.PTR;
rxd_max = regs->RXD.MAXCNT;
rxd_amount = regs->RXD.AMOUNT;
txd_ptr = regs->TXD.PTR;
txd_max = regs->TXD.MAXCNT;
txd_amount = regs->TXD.AMOUNT;
#endif /* defined(CONFIG_SOC_SERIES_NRF51X) */
SYS_LOG_DBG("\n"
"SHORTS: %x, IRQ: %x, SEMSTAT: %x\n"
"CONFIG: %x, STATUS: %x, ENABLE: %x\n"
"SCKPIN: %x, MISOPIN: %x, MOSIPIN: %x, CSNPIN: %x\n"
"RXD (PTR: %x, MAX: %x, AMOUNT: %x)\n"
"TXD (PTR: %x, MAX: %x, AMOUNT: %x)",
regs->SHORTS, regs->INTENSET, regs->SEMSTAT,
regs->CONFIG, regs->STATUS, regs->ENABLE,
sck, miso, mosi, csn,
rxd_ptr, rxd_max, rxd_amount,
txd_ptr, txd_max, txd_amount);
}
/**
* @brief Configure the SPI host controller for operating against slaves
* @param dev Pointer to the device structure for the driver instance
* @param config Pointer to the application provided configuration
*
* @return 0 if successful, another DEV_* code otherwise.
*/
static int spis_nrf5_configure(struct device *dev, struct spi_config *config)
{
NRF_SPIS_Type *spi_regs = SPI_REGS(dev);
u32_t flags;
/* make sure module is disabled */
spi_regs->ENABLE = 0;
/* TODO: Muck with IRQ priority if needed */
/* Clear any pending events */
spi_regs->EVENTS_ACQUIRED = 0;
spi_regs->EVENTS_ENDRX = 0;
spi_regs->EVENTS_END = 0;
spi_regs->INTENCLR = 0xFFFFFFFF; /* do we need to clear INT ?*/
spi_regs->SHORTS = NRF5_SPIS_SHORTCUT_END_ACQUIRE;
spi_regs->INTENSET |= (SPIS_INTENSET_ACQUIRED_Msk |
SPIS_INTENSET_END_Msk);
/* default transmit and over-read characters */
spi_regs->DEF = DEV_CFG(dev)->def;
spi_regs->ORC = 0x000000AA;
/* user configuration */
flags = config->config;
if (flags & SPI_TRANSFER_LSB) {
spi_regs->CONFIG = NRF5_SPIS_ORDER_LSB;
} else {
spi_regs->CONFIG = NRF5_SPIS_ORDER_MSB;
}
if (flags & SPI_MODE_CPHA) {
spi_regs->CONFIG |= NRF5_SPIS_CPHA_TRAILING;
} else {
spi_regs->CONFIG |= NRF5_SPIS_CPHA_LEADING;
}
if (flags & SPI_MODE_CPOL) {
spi_regs->CONFIG |= NRF5_SPIS_CPOL_LOW;
} else {
spi_regs->CONFIG |= NRF5_SPIS_CPOL_HIGH;
}
/* Enable the SPIS - peripherals sharing same ID will be disabled */
spi_regs->ENABLE = NRF5_SPIS_ENABLED;
spis_nrf5_print_cfg_registers(dev);
SYS_LOG_DBG("SPI Slave Driver configured");
return 0;
}
/**
* @brief Read and/or write a defined amount of data through an SPI driver
*
* @param dev Pointer to the device structure for the driver instance
* @param tx_buf Memory buffer that data should be transferred from
* @param tx_buf_len Size of the memory buffer available for reading from
* @param rx_buf Memory buffer that data should be transferred to
* @param rx_buf_len Size of the memory buffer available for writing to
*
* @return 0 if successful, another DEV_* code otherwise.
*/
static int spis_nrf5_transceive(struct device *dev, const void *tx_buf,
u32_t tx_buf_len, void *rx_buf, u32_t rx_buf_len)
{
NRF_SPIS_Type *spi_regs = SPI_REGS(dev);
struct spis_nrf5_data *priv_data = DEV_DATA(dev);
__ASSERT(!((tx_buf_len && !tx_buf) || (rx_buf_len && !rx_buf)),
"spis_nrf5_transceive: ERROR - NULL buffers");
/* Buffer needs to be in RAM for EasyDMA to work */
if (!tx_buf || !is_buf_in_ram(tx_buf)) {
SYS_LOG_ERR("Invalid TX buf %p", tx_buf);
return -EINVAL;
}
if (!rx_buf || !is_buf_in_ram(rx_buf)) {
SYS_LOG_ERR("Invalid RX buf %p", rx_buf);
return -EINVAL;
}
priv_data->error = 0;
if (spi_regs->SEMSTAT == 1) {
#if defined(CONFIG_SOC_SERIES_NRF51X)
spi_regs->TXDPTR = (u32_t) tx_buf;
spi_regs->RXDPTR = (u32_t) rx_buf;
spi_regs->MAXTX = tx_buf_len;
spi_regs->MAXRX = rx_buf_len;
#elif defined(CONFIG_SOC_SERIES_NRF52X)
spi_regs->TXD.PTR = (u32_t) tx_buf;
spi_regs->RXD.PTR = (u32_t) rx_buf;
spi_regs->TXD.MAXCNT = tx_buf_len;
spi_regs->RXD.MAXCNT = rx_buf_len;
#endif
spi_regs->TASKS_RELEASE = 1;
} else {
SYS_LOG_ERR("Can't get SEM; unfinished transfer?");
return -EIO;
}
/* wait for transfer to complete */
k_sem_take(&priv_data->device_sync_sem, K_FOREVER);
if (priv_data->error) {
priv_data->error = 0;
return -EIO;
}
return 0;
}
/**
* @brief Complete SPI module data transfer operations.
* @param dev Pointer to the device structure for the driver instance
* @param error Error condition (0 = no error, otherwise an error occurred)
* @return None.
*/
static void spis_nrf5_complete(struct device *dev, u32_t error)
{
__unused NRF_SPIS_Type *spi_regs = SPI_REGS(dev);
__unused u32_t txd_amount, rxd_amount;
struct spis_nrf5_data *priv_data = DEV_DATA(dev);
#if defined(CONFIG_SOC_SERIES_NRF51X)
txd_amount = spi_regs->AMOUNTTX;
rxd_amount = spi_regs->AMOUNTRX;
#elif defined(CONFIG_SOC_SERIES_NRF52X)
txd_amount = spi_regs->RXD.AMOUNT;
rxd_amount = spi_regs->TXD.AMOUNT;
#endif
SYS_LOG_DBG("bytes transferred: TX: %u, RX: %u [err %u (%s)]",
txd_amount, rxd_amount,
error, error == 0 ? "OK" : "ERR");
priv_data->error = error ? 1 : 0;
k_sem_give(&priv_data->device_sync_sem);
}
/**
* @brief SPI module interrupt handler.
* @param arg Pointer to the device structure for the driver instance
* @return None.
*/
static void spis_nrf5_isr(void *arg)
{
struct device *dev = arg;
NRF_SPIS_Type *spi_regs = SPI_REGS(dev);
u32_t error;
u32_t tmp;
/* We get an interrupt for the following reasons:
* 1. Semaphore ACQUIRED:
* Semaphore is assigned to the CPU again (always happens
* after END if the END_ACQUIRE SHORTS is set)
* 2. End of Granted SPI transaction:
* Used to unblocked the caller, finishing the transaction
*/
/* NOTE:
* Section 15.8.1 of nrf52 manual suggests reading back the register
* to cause a 4-cycle delay to prevent the interrupt from
* re-occurring
*/
if (spi_regs->EVENTS_END) {
spi_regs->EVENTS_END = 0;
/* force register flush (per spec) */
tmp = spi_regs->EVENTS_END;
/* Read and clear error flags. */
error = spi_regs->STATUS;
spi_regs->STATUS = error;
spis_nrf5_complete(dev, error);
}
if (spi_regs->EVENTS_ACQUIRED) {
spi_regs->EVENTS_ACQUIRED = 0;
/* force registesr flush (per spec) */
tmp = spi_regs->EVENTS_ACQUIRED;
}
}
static const struct spi_driver_api nrf5_spis_api = {
.transceive = spis_nrf5_transceive,
.configure = spis_nrf5_configure,
.slave_select = NULL,
};
#if defined(CONFIG_SOC_SERIES_NRF51X)
static void spis_configure_psel(NRF_SPIS_Type *spi_regs,
const struct spis_nrf5_config *cfg)
{
spi_regs->PSELMOSI = cfg->mosi_pin;
spi_regs->PSELMISO = cfg->miso_pin;
spi_regs->PSELSCK = cfg->sck_pin;
if (cfg->csn_pin == NRF5_SPIS_CSN_DISABLED_CFG) {
spi_regs->PSELCSN = NRF5_SPIS_CSN_DISABLED;
} else {
spi_regs->PSELCSN = cfg->csn_pin;
}
}
#elif defined(CONFIG_SOC_SERIES_NRF52X)
static void spis_configure_psel(NRF_SPIS_Type *spi_regs,
const struct spis_nrf5_config *cfg)
{
spi_regs->PSEL.MOSI = cfg->mosi_pin;
spi_regs->PSEL.MISO = cfg->miso_pin;
spi_regs->PSEL.SCK = cfg->sck_pin;
if (cfg->csn_pin == NRF5_SPIS_CSN_DISABLED_CFG) {
spi_regs->PSEL.CSN = NRF5_SPIS_CSN_DISABLED;
} else {
spi_regs->PSEL.CSN = cfg->csn_pin;
}
}
#else
#error "Unsupported NRF5 SoC"
#endif
static int spis_nrf5_init(struct device *dev)
{
NRF_SPIS_Type *spi_regs = SPI_REGS(dev);
struct spis_nrf5_data *priv_data = DEV_DATA(dev);
const struct spis_nrf5_config *cfg = DEV_CFG(dev);
struct device *gpio_dev;
int ret;
SYS_LOG_DBG("SPI Slave driver init: %p", dev);
/* Enable constant latency for faster SPIS response */
NRF_POWER->TASKS_CONSTLAT = 1;
spi_regs->ENABLE = 0;
gpio_dev = device_get_binding(CONFIG_GPIO_NRF5_P0_DEV_NAME);
ret = gpio_pin_configure(gpio_dev, cfg->miso_pin,
GPIO_DIR_IN | GPIO_PUD_NORMAL);
__ASSERT_NO_MSG(!ret);
ret = gpio_pin_configure(gpio_dev, cfg->mosi_pin,
GPIO_DIR_IN | GPIO_PUD_NORMAL);
__ASSERT_NO_MSG(!ret);
ret = gpio_pin_configure(gpio_dev, cfg->sck_pin,
GPIO_DIR_IN | GPIO_PUD_NORMAL);
__ASSERT_NO_MSG(!ret);
if (cfg->csn_pin != 0xff) {
ret = gpio_pin_configure(gpio_dev, cfg->csn_pin,
GPIO_DIR_IN | GPIO_PUD_PULL_UP);
__ASSERT_NO_MSG(!ret);
}
spis_configure_psel(spi_regs, cfg);
cfg->config_func();
k_sem_init(&priv_data->device_sync_sem, 0, 1);
SYS_LOG_DBG("SPI Slave driver initialized on device: %p", dev);
return 0;
}
/* system bindings */
#ifdef CONFIG_SPIS0_NRF52
static void spis_config_irq_0(void);
static struct spis_nrf5_data spis_nrf5_data_0;
static const struct spis_nrf5_config spis_nrf5_config_0 = {
.regs = NRF_SPIS0,
.config_func = spis_config_irq_0,
.sck_pin = CONFIG_SPIS0_NRF52_GPIO_SCK_PIN,
.mosi_pin = CONFIG_SPIS0_NRF52_GPIO_MOSI_PIN,
.miso_pin = CONFIG_SPIS0_NRF52_GPIO_MISO_PIN,
.csn_pin = CONFIG_SPIS0_NRF52_GPIO_CSN_PIN,
.def = CONFIG_SPIS0_NRF52_DEF,
};
DEVICE_AND_API_INIT(spis_nrf5_port_0, CONFIG_SPI_0_NAME, spis_nrf5_init,
&spis_nrf5_data_0, &spis_nrf5_config_0, PRE_KERNEL_1,
CONFIG_SPI_INIT_PRIORITY, &nrf5_spis_api);
static void spis_config_irq_0(void)
{
IRQ_CONNECT(NRF5_IRQ_SPI0_TWI0_IRQn, CONFIG_SPI_0_IRQ_PRI,
spis_nrf5_isr, DEVICE_GET(spis_nrf5_port_0), 0);
irq_enable(NRF5_IRQ_SPI0_TWI0_IRQn);
}
#endif /* CONFIG_SPIS0_NRF52 */
#ifdef CONFIG_SPIS1_NRF5
static void spis_config_irq_1(void);
static struct spis_nrf5_data spis_nrf5_data_1;
static const struct spis_nrf5_config spis_nrf5_config_1 = {
.regs = NRF_SPIS1,
.config_func = spis_config_irq_1,
.sck_pin = CONFIG_SPIS1_NRF5_GPIO_SCK_PIN,
.mosi_pin = CONFIG_SPIS1_NRF5_GPIO_MOSI_PIN,
.miso_pin = CONFIG_SPIS1_NRF5_GPIO_MISO_PIN,
.csn_pin = CONFIG_SPIS1_NRF5_GPIO_CSN_PIN,
.def = CONFIG_SPIS1_NRF5_DEF,
};
DEVICE_AND_API_INIT(spis_nrf5_port_1, CONFIG_SPI_1_NAME, spis_nrf5_init,
&spis_nrf5_data_1, &spis_nrf5_config_1, PRE_KERNEL_1,
CONFIG_SPI_INIT_PRIORITY, &nrf5_spis_api);
static void spis_config_irq_1(void)
{
IRQ_CONNECT(NRF5_IRQ_SPI1_TWI1_IRQn, CONFIG_SPI_1_IRQ_PRI,
spis_nrf5_isr, DEVICE_GET(spis_nrf5_port_1), 0);
irq_enable(NRF5_IRQ_SPI1_TWI1_IRQn);
}
#endif /* CONFIG_SPIS1_NRF5 */