From 0683d4dc3d6972f0aa80cec538ffe516d629b291 Mon Sep 17 00:00:00 2001 From: Niclas Finne Date: Fri, 17 Nov 2017 16:10:45 +0100 Subject: [PATCH] Imported SPI API from Yanzi Networks internal Contiki fork. --- arch/cpu/cc2538/Makefile.cc2538 | 3 +- arch/cpu/cc2538/spi-dev-arch.c | 185 ++++++++++++++++++++++++++++ arch/cpu/cc2538/spi-dev-arch.h | 44 +++++++ os/dev/spi-dev.c | 207 ++++++++++++++++++++++++++++++++ os/dev/spi-dev.h | 104 ++++++++++++++++ 5 files changed, 542 insertions(+), 1 deletion(-) create mode 100644 arch/cpu/cc2538/spi-dev-arch.c create mode 100644 arch/cpu/cc2538/spi-dev-arch.h create mode 100644 os/dev/spi-dev.c create mode 100644 os/dev/spi-dev.h diff --git a/arch/cpu/cc2538/Makefile.cc2538 b/arch/cpu/cc2538/Makefile.cc2538 index 03758aa9b..eb6d8a6b8 100644 --- a/arch/cpu/cc2538/Makefile.cc2538 +++ b/arch/cpu/cc2538/Makefile.cc2538 @@ -15,7 +15,8 @@ CONTIKI_CPU_DIRS = . dev usb usb/common usb/common/cdc-acm ### CPU-dependent source files CONTIKI_CPU_SOURCEFILES += soc.c clock.c rtimer-arch.c uart.c watchdog.c -CONTIKI_CPU_SOURCEFILES += nvic.c sys-ctrl.c gpio.c ioc.c spi.c adc.c +CONTIKI_CPU_SOURCEFILES += nvic.c sys-ctrl.c gpio.c ioc.c adc.c +CONTIKI_CPU_SOURCEFILES += spi.c spi-dev-arch.c CONTIKI_CPU_SOURCEFILES += crypto.c aes.c ecb.c cbc.c ctr.c cbc-mac.c gcm.c CONTIKI_CPU_SOURCEFILES += ccm.c sha256.c gpio-hal-arch.c CONTIKI_CPU_SOURCEFILES += cc2538-aes-128.c cc2538-ccm-star.c diff --git a/arch/cpu/cc2538/spi-dev-arch.c b/arch/cpu/cc2538/spi-dev-arch.c new file mode 100644 index 000000000..b20e5da5f --- /dev/null +++ b/arch/cpu/cc2538/spi-dev-arch.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2016-2017, Yanzi Networks. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "dev/spi-dev.h" +#include "spi-arch.h" + +#define DEBUG 0 +#if DEBUG +#include +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +#ifdef PLATFORM_HAS_SPI_DEV_ARCH +/*---------------------------------------------------------------------------*/ +static void +spix_wait_tx_ready(int spi_instance) +{ + int reg = spi_instance == 0 ? SSI0_BASE : SSI1_BASE; + + /* Infinite loop until SR_TNF - Transmit FIFO Not Full */ + while(!(REG(reg + SSI_SR) & SSI_SR_TNF)); +} +/*---------------------------------------------------------------------------*/ +static int +spix_read_buf(int spi_instance) +{ + int reg = spi_instance == 0 ? SSI0_BASE : SSI1_BASE; + + return REG(reg + SSI_DR); +} +/*---------------------------------------------------------------------------*/ +static void +spix_write_buf(int spi_instance, int data) +{ + int reg = spi_instance == 0 ? SSI0_BASE : SSI1_BASE; + + REG(reg + SSI_DR) = data; +} +/*---------------------------------------------------------------------------*/ +static void +spix_wait_eotx(int spi_instance) +{ + int reg = spi_instance == 0 ? SSI0_BASE : SSI1_BASE; + + /* wait until not busy */ + while(REG(reg + SSI_SR) & SSI_SR_BSY); +} +/*---------------------------------------------------------------------------*/ +static void +spix_wait_eorx(int spi_instance) +{ + int reg = spi_instance == 0 ? SSI0_BASE : SSI1_BASE; + + /* wait as long as receive is empty */ + while(!(REG(reg + SSI_SR) & SSI_SR_RNE)); +} +/*---------------------------------------------------------------------------*/ +spi_dev_status_t +spi_dev_arch_lock(spi_device_t *dev) +{ + spi_bus_t *bus; + bus = dev->bus; + + if(bus->lock) { + return SPI_DEV_STATUS_BUS_LOCKED; + } + /* Add support for timeout also!!! */ + bus->lock = 1; + bus->lock_device = dev; + + PRINTF("SPI: lock\n"); + + return SPI_DEV_STATUS_OK; +} +/*---------------------------------------------------------------------------*/ +int +spi_dev_arch_has_lock(spi_device_t *dev) +{ + return dev->bus->lock_device == dev; +} +/*---------------------------------------------------------------------------*/ +int +spi_dev_arch_is_bus_locked(spi_device_t *dev) +{ + return dev->bus->lock; +} +/*---------------------------------------------------------------------------*/ +spi_dev_status_t +spi_dev_arch_unlock(spi_device_t *dev) +{ + dev->bus->lock = 0; + dev->bus->lock_device = NULL; + + PRINTF("SPI: unlock\n"); + return SPI_DEV_STATUS_OK; +} +/*---------------------------------------------------------------------------*/ +spi_dev_status_t +spi_dev_arch_restart_timeout(spi_device_t *dev) +{ + /* do nothing at the moment */ + return SPI_DEV_STATUS_OK; +} +/*---------------------------------------------------------------------------*/ +/* Assumes that checking dev and bus is not NULL before calling this */ +spi_dev_status_t +spi_dev_arch_transfer(spi_device_t *dev, + const uint8_t *write_buf, int wlen, + uint8_t *inbuf, int rlen, int ignore_len) +{ + int i; + int totlen; + uint8_t c; + uint8_t spi_instance; + + spi_instance = dev->bus->config.instance; + + PRINTF("SPI: transfer (r:%d,w:%d) ", rlen, wlen); + + if(write_buf == NULL && wlen > 0) { + return SPI_DEV_STATUS_EINVAL; + } + if(inbuf == NULL && rlen > 0) { + return SPI_DEV_STATUS_EINVAL; + } + + totlen = MAX(rlen + ignore_len, wlen); + + if(totlen == 0) { + /* Nothing to do */ + return SPI_DEV_STATUS_OK; + } + + PRINTF("%c%c%c: %u ", rlen > 0 ? 'R' : '-', wlen > 0 ? 'W' : '-', + ignore_len > 0 ? 'S' : '-', totlen); + + for(i = 0; i < totlen; i++) { + spix_wait_tx_ready(spi_instance); + c = i < wlen ? write_buf[i] : 0; + spix_write_buf(spi_instance, c); + PRINTF("%c%02x->", i < rlen ? ' ' : '#', c); + spix_wait_eotx(spi_instance); + spix_wait_eorx(spi_instance); + c = spix_read_buf(spi_instance); + if(i < rlen) { + inbuf[i] = c; + } + PRINTF("%02x", c); + } + + PRINTF("\n"); + return SPI_DEV_STATUS_OK; +} +/*---------------------------------------------------------------------------*/ +#endif /* PLATFORM_HAS_SPI_DEV_ARCH */ diff --git a/arch/cpu/cc2538/spi-dev-arch.h b/arch/cpu/cc2538/spi-dev-arch.h new file mode 100644 index 000000000..88ca67f24 --- /dev/null +++ b/arch/cpu/cc2538/spi-dev-arch.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016-2017, Yanzi Networks. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SPI_DEV_ARCH_H_ +#define SPI_DEV_ARCH_H_ + +#include + +/* The SPI instance for the CC2538 */ +typedef struct spi_bus_config { + uint8_t instance; +} spi_bus_config_t; + +typedef struct spi_device_config { +} spi_device_config_t; + +#endif /* SPI_DEV_ARCH_H_ */ diff --git a/os/dev/spi-dev.c b/os/dev/spi-dev.c new file mode 100644 index 000000000..be4418fcd --- /dev/null +++ b/os/dev/spi-dev.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2016-2017, Yanzi Networks. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "dev/spi-dev.h" + +/*---------------------------------------------------------------------------*/ +spi_dev_status_t +spi_dev_acquire(spi_device_t *dev) +{ + if(dev == NULL || dev->bus == NULL) { + return SPI_DEV_STATUS_EINVAL; + } + /* lock the bus */ + return spi_dev_arch_lock(dev); +} +/*---------------------------------------------------------------------------*/ +spi_dev_status_t +spi_dev_release(spi_device_t *dev) +{ + if(dev == NULL || dev->bus == NULL) { + return SPI_DEV_STATUS_EINVAL; + } + /* unlock the bus */ + return spi_dev_arch_unlock(dev); +} +/*---------------------------------------------------------------------------*/ +int +spi_dev_has_bus(spi_device_t *dev) +{ + if(dev == NULL || dev->bus == NULL) { + return 0; + } + return spi_dev_arch_has_lock(dev); +} +/*---------------------------------------------------------------------------*/ +spi_dev_status_t +spi_dev_restart_timeout(spi_device_t *dev) +{ + if(!spi_dev_has_bus(dev)) { + return SPI_DEV_STATUS_EINVAL; + } + return spi_dev_arch_restart_timeout(dev); +} +/*---------------------------------------------------------------------------*/ +spi_dev_status_t +spi_dev_write_byte(spi_device_t *dev, uint8_t data) +{ + if(dev == NULL || dev->bus == NULL) { + return SPI_DEV_STATUS_EINVAL; + } + + if(!spi_dev_arch_has_lock(dev)) { + return SPI_DEV_STATUS_BUS_LOCKED; + } + return spi_dev_arch_transfer(dev, &data, 1, 0, 0, 0); +} +/*---------------------------------------------------------------------------*/ +spi_dev_status_t +spi_dev_write(spi_device_t *dev, const uint8_t *data, int size) +{ + if(dev == NULL || dev->bus == NULL) { + return SPI_DEV_STATUS_EINVAL; + } + + if(!spi_dev_arch_has_lock(dev)) { + return SPI_DEV_STATUS_BUS_LOCKED; + } + return spi_dev_arch_transfer(dev, data, size, 0, 0, 0); +} +/*---------------------------------------------------------------------------*/ +spi_dev_status_t +spi_dev_read_byte(spi_device_t *dev, uint8_t *buf) +{ + if(dev == NULL || dev->bus == NULL) { + return SPI_DEV_STATUS_EINVAL; + } + + if(!spi_dev_arch_has_lock(dev)) { + return SPI_DEV_STATUS_BUS_LOCKED; + } + return spi_dev_arch_transfer(dev, NULL, 0, buf, 1, 0); +} +/*---------------------------------------------------------------------------*/ +spi_dev_status_t +spi_dev_read(spi_device_t *dev, uint8_t *buf, int size) +{ + if(dev == NULL || dev->bus == NULL) { + return SPI_DEV_STATUS_EINVAL; + } + + if(!spi_dev_arch_has_lock(dev)) { + return SPI_DEV_STATUS_BUS_LOCKED; + } + return spi_dev_arch_transfer(dev, NULL, 0, buf, size, 0); +} +/*---------------------------------------------------------------------------*/ +spi_dev_status_t +spi_dev_read_skip(spi_device_t *dev, int size) +{ + if(dev == NULL || dev->bus == NULL) { + return SPI_DEV_STATUS_EINVAL; + } + + if(!spi_dev_arch_has_lock(dev)) { + return SPI_DEV_STATUS_BUS_LOCKED; + } + return spi_dev_arch_transfer(dev, NULL, 0, NULL, 0, size); +} +/*---------------------------------------------------------------------------*/ +spi_dev_status_t +spi_dev_transfer(spi_device_t *dev, + const uint8_t *wdata, int wsize, + uint8_t *rbuf, int rsize, int ignore) +{ + if(dev == NULL || dev->bus == NULL) { + return SPI_DEV_STATUS_EINVAL; + } + + if(!spi_dev_arch_has_lock(dev)) { + return SPI_DEV_STATUS_BUS_LOCKED; + } + + if(wdata == NULL && wsize > 0) { + return SPI_DEV_STATUS_EINVAL; + } + + if(rbuf == NULL && rsize > 0) { + return SPI_DEV_STATUS_EINVAL; + } + + return spi_dev_arch_transfer(dev, wdata, wsize, rbuf, rsize, ignore); +} +/*---------------------------------------------------------------------------*/ +/* Chip select can only be done when the bus is locked to this device */ +spi_dev_status_t +spi_dev_chip_select(spi_device_t *dev, uint8_t on) +{ + if(dev == NULL || dev->bus == NULL) { + return SPI_DEV_STATUS_EINVAL; + } + if(spi_dev_has_bus(dev)) { + return dev->chip_select(on); + } + return SPI_DEV_STATUS_BUS_NOT_OWNED; +} +/*---------------------------------------------------------------------------*/ +spi_dev_status_t +spi_dev_read_register(spi_device_t *dev, uint8_t reg, uint8_t *data, int size) +{ + spi_dev_status_t status; + if(dev == NULL || dev->bus == NULL) { + return SPI_DEV_STATUS_EINVAL; + } + + /* write the register first (will read a status) */ + status = spi_dev_write_byte(dev, reg); + if(status != SPI_DEV_STATUS_OK) { + return status; + } + /* then read the value (will read the value) */ + status = spi_dev_read(dev, data, size); + if(status != SPI_DEV_STATUS_OK) { + return status; + } + return status; +} +/*---------------------------------------------------------------------------*/ +spi_dev_status_t +spi_dev_strobe(spi_device_t *dev, uint8_t strobe, uint8_t *result) +{ + if(dev == NULL || dev->bus == NULL) { + return SPI_DEV_STATUS_EINVAL; + } + + if(!spi_dev_arch_has_lock(dev)) { + return SPI_DEV_STATUS_BUS_LOCKED; + } + return spi_dev_arch_transfer(dev, &strobe, 1, result, 1, 0); +} +/*---------------------------------------------------------------------------*/ diff --git a/os/dev/spi-dev.h b/os/dev/spi-dev.h new file mode 100644 index 000000000..48068261f --- /dev/null +++ b/os/dev/spi-dev.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016-2017, Yanzi Networks. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SPI_DEV_H_ +#define SPI_DEV_H_ + +#include "contiki.h" + +#ifdef PLATFORM_HAS_SPI_DEV_ARCH +#include "spi-dev-arch.h" +#endif + +typedef enum { + SPI_DEV_STATUS_OK, + SPI_DEV_STATUS_TIMEOUT, + SPI_DEV_STATUS_EINVAL, + SPI_DEV_STATUS_BUS_LOCKED, + SPI_DEV_STATUS_BUS_NOT_OWNED +} spi_dev_status_t; + +typedef struct spi_device spi_device_t; + +typedef struct spi_bus { + /* for locking the bus */ + spi_device_t *lock_device; + volatile uint8_t lock; +#ifdef PLATFORM_HAS_SPI_DEV_ARCH + spi_bus_config_t config; +#endif /* PLATFORM_HAS_SPI_DEV_ARCH */ +} spi_bus_t; + +struct spi_device { + spi_bus_t *bus; + /* timeout in milliseconds for this device */ + uint16_t timeout; + /* chip-select for this SPI chip - 1 = CS */ + uint8_t (* chip_select)(int on); +#ifdef PLATFORM_HAS_SPI_DEV_ARCH + spi_device_config_t config; +#endif +}; + +/* call for all spi devices */ +spi_dev_status_t spi_dev_acquire(spi_device_t *dev); +spi_dev_status_t spi_dev_release(spi_device_t *dev); +spi_dev_status_t spi_dev_restart_timeout(spi_device_t *dev); +int spi_dev_has_bus(spi_device_t *dev); +spi_dev_status_t spi_dev_write_byte(spi_device_t *dev, uint8_t data); +spi_dev_status_t spi_dev_read_byte(spi_device_t *dev, uint8_t *data); +spi_dev_status_t spi_dev_write(spi_device_t *dev, + const uint8_t *data, int size); +spi_dev_status_t spi_dev_read(spi_device_t *dev, uint8_t *data, int size); +spi_dev_status_t spi_dev_read_skip(spi_device_t *dev, int size); +spi_dev_status_t spi_dev_transfer(spi_device_t *dev, + const uint8_t *data, int wsize, + uint8_t *buf, int rsize, int ignore); +spi_dev_status_t spi_dev_chip_select(spi_device_t *dev, uint8_t on); +spi_dev_status_t spi_dev_strobe(spi_device_t *dev, uint8_t strobe, + uint8_t *status); +spi_dev_status_t spi_dev_read_register(spi_device_t *dev, uint8_t reg, + uint8_t *data, int size); + +/* Arch functions needed per CPU */ +spi_dev_status_t spi_dev_arch_lock(spi_device_t *dev); +spi_dev_status_t spi_dev_arch_unlock(spi_device_t *dev); +int spi_dev_arch_has_lock(spi_device_t *dev); +int spi_dev_arch_is_bus_locked(spi_device_t *dev); + +/* Initialize the spi bus */ +spi_dev_status_t spi_dev_arch_init(spi_device_t *dev); +spi_dev_status_t spi_dev_arch_transfer(spi_device_t *dev, + const uint8_t *data, int wlen, + uint8_t *buf, int rlen, + int ignore_len); +spi_dev_status_t spi_dev_arch_restart_timeout(spi_device_t *dev); + +#endif /* SPI_DEV_H */