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:
parent
e7de85b534
commit
13dba12b9a
5 changed files with 6 additions and 1208 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
Loading…
Add table
Add a link
Reference in a new issue