From 91882209bf5ed50e853e6b5b065a7f8889a55c67 Mon Sep 17 00:00:00 2001 From: "Xenofon (Fontas) Fafoutis" Date: Tue, 28 Nov 2017 19:03:47 +0000 Subject: [PATCH] HAL SPI API Proposal Documenting the SPI HAL API --- os/dev/spi-dev.h | 104 ---------- os/dev/{spi-dev.c => spi-hal.c} | 174 +++++++++------- os/dev/spi-hal.h | 349 ++++++++++++++++++++++++++++++++ 3 files changed, 445 insertions(+), 182 deletions(-) delete mode 100644 os/dev/spi-dev.h rename os/dev/{spi-dev.c => spi-hal.c} (58%) create mode 100644 os/dev/spi-hal.h diff --git a/os/dev/spi-dev.h b/os/dev/spi-dev.h deleted file mode 100644 index 48068261f..000000000 --- a/os/dev/spi-dev.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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 */ diff --git a/os/dev/spi-dev.c b/os/dev/spi-hal.c similarity index 58% rename from os/dev/spi-dev.c rename to os/dev/spi-hal.c index be4418fcd..c8c84bd7c 100644 --- a/os/dev/spi-dev.c +++ b/os/dev/spi-hal.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2016-2017, Yanzi Networks. + * Copyright (c) 2017, University of Bristol - http://www.bristol.ac.uk/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,122 +29,149 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "dev/spi-dev.h" +#include "spi-hal.h" /*---------------------------------------------------------------------------*/ -spi_dev_status_t -spi_dev_acquire(spi_device_t *dev) +spi_status_t +spi_acquire(spi_device_t *dev) { - if(dev == NULL || dev->bus == NULL) { + spi_status_t r; + + if(dev == NULL || dev->spi_controller >= BOARD_SPI_CONTROLLERS) { return SPI_DEV_STATUS_EINVAL; } + /* lock the bus */ - return spi_dev_arch_lock(dev); + r = spi_arch_lock(dev); + if(r != SPI_DEV_STATUS_OK) { + return r; + } + + /* open the bus */ + return spi_arch_open(dev); } /*---------------------------------------------------------------------------*/ -spi_dev_status_t -spi_dev_release(spi_device_t *dev) +spi_status_t +spi_release(spi_device_t *dev) { - if(dev == NULL || dev->bus == NULL) { + spi_status_t r; + + if(dev == NULL || dev->spi_controller >= BOARD_SPI_CONTROLLERS) { 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; + r = spi_arch_close(dev); + if(r != SPI_DEV_STATUS_OK) { + return r; } - return spi_dev_arch_has_lock(dev); + + /* unlock the bus */ + return spi_arch_unlock(dev); } /*---------------------------------------------------------------------------*/ -spi_dev_status_t -spi_dev_restart_timeout(spi_device_t *dev) +spi_status_t +spi_select(spi_device_t *dev) { - if(!spi_dev_has_bus(dev)) { - return SPI_DEV_STATUS_EINVAL; + return spi_arch_select(dev); +} +/*---------------------------------------------------------------------------*/ +spi_status_t +spi_deselect(spi_device_t *dev) +{ + return spi_arch_deselect(dev); +} +/*---------------------------------------------------------------------------*/ +bool +spi_has_bus(spi_device_t *dev) +{ + if(dev == NULL || dev->spi_controller >= BOARD_SPI_CONTROLLERS) { + return false; } - return spi_dev_arch_restart_timeout(dev); + + return spi_arch_has_lock(dev); } /*---------------------------------------------------------------------------*/ -spi_dev_status_t -spi_dev_write_byte(spi_device_t *dev, uint8_t data) +spi_status_t +spi_write_byte(spi_device_t *dev, uint8_t data) { - if(dev == NULL || dev->bus == NULL) { + if(dev == NULL || dev->spi_controller >= BOARD_SPI_CONTROLLERS) { return SPI_DEV_STATUS_EINVAL; } - if(!spi_dev_arch_has_lock(dev)) { + if(!spi_arch_has_lock(dev)) { return SPI_DEV_STATUS_BUS_LOCKED; } - return spi_dev_arch_transfer(dev, &data, 1, 0, 0, 0); + + return spi_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) +spi_status_t +spi_write(spi_device_t *dev, const uint8_t *data, int size) { - if(dev == NULL || dev->bus == NULL) { + if(dev == NULL || dev->spi_controller >= BOARD_SPI_CONTROLLERS) { return SPI_DEV_STATUS_EINVAL; } - if(!spi_dev_arch_has_lock(dev)) { + if(!spi_arch_has_lock(dev)) { return SPI_DEV_STATUS_BUS_LOCKED; } - return spi_dev_arch_transfer(dev, data, size, 0, 0, 0); + + return spi_arch_transfer(dev, data, size, 0, 0, 0); } /*---------------------------------------------------------------------------*/ -spi_dev_status_t -spi_dev_read_byte(spi_device_t *dev, uint8_t *buf) +spi_status_t +spi_read_byte(spi_device_t *dev, uint8_t *buf) { - if(dev == NULL || dev->bus == NULL) { + if(dev == NULL || dev->spi_controller >= BOARD_SPI_CONTROLLERS) { return SPI_DEV_STATUS_EINVAL; } - if(!spi_dev_arch_has_lock(dev)) { + if(!spi_arch_has_lock(dev)) { return SPI_DEV_STATUS_BUS_LOCKED; } - return spi_dev_arch_transfer(dev, NULL, 0, buf, 1, 0); + + return spi_arch_transfer(dev, NULL, 0, buf, 1, 0); } /*---------------------------------------------------------------------------*/ -spi_dev_status_t -spi_dev_read(spi_device_t *dev, uint8_t *buf, int size) +spi_status_t +spi_read(spi_device_t *dev, uint8_t *buf, int size) { - if(dev == NULL || dev->bus == NULL) { + if(dev == NULL || dev->spi_controller >= BOARD_SPI_CONTROLLERS) { return SPI_DEV_STATUS_EINVAL; } - if(!spi_dev_arch_has_lock(dev)) { + if(!spi_arch_has_lock(dev)) { return SPI_DEV_STATUS_BUS_LOCKED; } - return spi_dev_arch_transfer(dev, NULL, 0, buf, size, 0); + + return spi_arch_transfer(dev, NULL, 0, buf, size, 0); } /*---------------------------------------------------------------------------*/ -spi_dev_status_t -spi_dev_read_skip(spi_device_t *dev, int size) +spi_status_t +spi_read_skip(spi_device_t *dev, int size) { - if(dev == NULL || dev->bus == NULL) { + if(dev == NULL || dev->spi_controller >= BOARD_SPI_CONTROLLERS) { return SPI_DEV_STATUS_EINVAL; } - if(!spi_dev_arch_has_lock(dev)) { + if(!spi_arch_has_lock(dev)) { return SPI_DEV_STATUS_BUS_LOCKED; } - return spi_dev_arch_transfer(dev, NULL, 0, NULL, 0, size); + + return spi_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) +spi_status_t +spi_transfer(spi_device_t *dev, + const uint8_t *wdata, int wsize, + uint8_t *rbuf, int rsize, int ignore) { - if(dev == NULL || dev->bus == NULL) { + if(dev == NULL || dev->spi_controller >= BOARD_SPI_CONTROLLERS) { return SPI_DEV_STATUS_EINVAL; } - if(!spi_dev_arch_has_lock(dev)) { + if(!spi_arch_has_lock(dev)) { return SPI_DEV_STATUS_BUS_LOCKED; } @@ -155,53 +183,43 @@ spi_dev_transfer(spi_device_t *dev, return SPI_DEV_STATUS_EINVAL; } - return spi_dev_arch_transfer(dev, wdata, wsize, rbuf, rsize, ignore); + return spi_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) +spi_status_t +spi_read_register(spi_device_t *dev, uint8_t reg, uint8_t *data, int size) { - 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) { + spi_status_t status; + if(dev == NULL || dev->spi_controller >= BOARD_SPI_CONTROLLERS) { return SPI_DEV_STATUS_EINVAL; } /* write the register first (will read a status) */ - status = spi_dev_write_byte(dev, reg); + status = spi_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); + status = spi_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) +spi_status_t +spi_strobe(spi_device_t *dev, uint8_t strobe, uint8_t *result) { - if(dev == NULL || dev->bus == NULL) { + if(dev == NULL || dev->spi_controller >= BOARD_SPI_CONTROLLERS) { return SPI_DEV_STATUS_EINVAL; } - if(!spi_dev_arch_has_lock(dev)) { + if(!spi_arch_has_lock(dev)) { return SPI_DEV_STATUS_BUS_LOCKED; } - return spi_dev_arch_transfer(dev, &strobe, 1, result, 1, 0); + + return spi_arch_transfer(dev, &strobe, 1, result, 1, 0); } /*---------------------------------------------------------------------------*/ diff --git a/os/dev/spi-hal.h b/os/dev/spi-hal.h new file mode 100644 index 000000000..901da2a25 --- /dev/null +++ b/os/dev/spi-hal.h @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2016-2017, Yanzi Networks. + * Copyright (c) 2017, University of Bristol - http://www.bristol.ac.uk/ + * 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. + */ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup dev + * @{ + * + * \defgroup spi-hal SPI Hardware Abstraction Layer + * + * The SPI HAL provides a set of common functions that can be used in a + * platform-independent fashion. + * + * + * @{ + * + * \file + * Header file for the SPI HAL + */ +/*---------------------------------------------------------------------------*/ +#ifndef SPI_HAL_H_ +#define SPI_HAL_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki.h" +#include "gpio-hal.h" + +#include +#include +/*---------------------------------------------------------------------------*/ +/* Include Arch-Specific conf */ +#ifdef SPI_HAL_CONF_ARCH_HDR_PATH +#include SPI_HAL_CONF_ARCH_HDR_PATH +#else /* PLATFORM_IMPLEMENTS_SPI_HAL */ +#define BOARD_SPI_CONTROLLERS 0 +#endif /* SPI_HAL_CONF_ARCH_HDR_PATH */ +/*---------------------------------------------------------------------------*/ +/** + * \brief SPI return codes + * + * @{ + */ +typedef enum { + SPI_DEV_STATUS_OK, /* Everything OK */ + SPI_DEV_STATUS_EINVAL, /* Erroneous input value */ + SPI_DEV_STATUS_BUS_LOCKED, /* SPI bus is already locked */ + SPI_DEV_STATUS_BUS_NOT_OWNED, /* SPI bus is locked by someone else */ + SPI_DEV_STATUS_CLOSED /* SPI bus has not opened properly */ +} spi_status_t; +/*---------------------------------------------------------------------------*/ +/** + * \brief SPI Device Configuration + * + * This is a structure to an architecture-independent SPI configuration. + * + * @{ + */ + +typedef struct spi_device { + gpio_hal_pin_t pin_spi_sck; /* SPI SCK pin */ + gpio_hal_pin_t pin_spi_miso; /* SPI MISO pin */ + gpio_hal_pin_t pin_spi_mosi; /* SPI MOSI pin */ + gpio_hal_pin_t pin_spi_cs; /* SPI Chip Select pin */ + uint32_t spi_bit_rate; /* SPI bit rate */ + uint8_t spi_pha; /* SPI mode phase */ + uint8_t spi_pol; /* SPI mode polarity */ + uint8_t spi_controller; /* ID of SPI controller to use */ +} spi_device_t; + +/*---------------------------------------------------------------------------*/ +/* These are architecture-independent functions to be used by SPI devices. */ +/*---------------------------------------------------------------------------*/ +/** + * \brief Locks and then opens an SPI controller + * \param dev An SPI device configuration which defines the controller + * to be locked and the opening configuration. + * \return SPI return code + */ +spi_status_t spi_acquire(spi_device_t *dev); + +/** + * \brief Closes and then unlocks an SPI controller + * \param dev An SPI device configuration which defines the controller + * to be closed and unlocked. + * \return SPI return code + * + * Releasing an SPI controller should put it in low-power mode. + * This should work only if the device has already locked the SPI + * controller. + */ +spi_status_t spi_release(spi_device_t *dev); + +/** + * \brief Selects the SPI peripheral + * \param dev An SPI device configuration which defines the CS pin. + * \return SPI return code + * + * Clears the CS pin. This should work only if the device has + * already locked the SPI controller. + */ +spi_status_t spi_select(spi_device_t *dev); + +/** + * \brief Deselects the SPI peripheral + * \param dev An SPI device configuration which defines the CS pin. + * \return SPI return code + * + * Sets the CS pin. Lock is not required. + */ +spi_status_t spi_deselect(spi_device_t *dev); + +/** + * \brief Checks if a device has locked an SPI controller + * \param dev An SPI device configuration which defines the controller. + * \return true if the device has the lock, false otherwise. + */ +bool spi_has_bus(spi_device_t *dev); + +/** + * \brief Writes a single byte to an SPI device + * \param dev An SPI device configuration. + * \param data A byte of data + * \return SPI return code + * + * It should work only if the device has already locked the SPI controller. + */ +spi_status_t spi_write_byte(spi_device_t *dev, uint8_t data); + +/** + * \brief Reads a single byte from an SPI device + * \param dev An SPI device configuration. + * \param data A pointer to a byte of data + * \return SPI return code + * + * It should work only if the device has already locked the SPI controller. + */ +spi_status_t spi_read_byte(spi_device_t *dev, uint8_t *data); + +/** + * \brief Writes a buffer to an SPI device + * \param dev An SPI device configuration. + * \param data A pointer to the data + * \param size Size of the data to write + * \return SPI return code + * + * It should work only if the device has already locked the SPI controller. + */ +spi_status_t spi_write(spi_device_t *dev, + const uint8_t *data, int size); + +/** + * \brief Reads a buffer from an SPI device + * \param dev An SPI device configuration. + * \param data A pointer to the data + * \param size Size of the data to read + * \return SPI return code + * + * It should work only if the device has already locked the SPI controller. + */ +spi_status_t spi_read(spi_device_t *dev, uint8_t *data, int size); + +/** + * \brief Reads and ignores data from an SPI device + * \param dev An SPI device configuration. + * \param size Size of the data to read and ignore + * \return SPI return code + * + * Reads size bytes from the SPI and throws them away. + * It should work only if the device has already locked the SPI controller. + */ +spi_status_t spi_read_skip(spi_device_t *dev, int size); + +/** + * \brief Performs a generic SPI transfer + * \param dev An SPI device configuration. + * \param data A pointer to the data to be written. Set it to NULL to + * skip writing. + * \param wlen Size of data to write. + * \param buf A pointer to buffer to copy the data read. Set to NULL + * to skip reading. + * \param rlen Size of data to read. + * \param ignore_len Size of data to read and ignore. + * \return SPI return code + * + * It should work only if the device has already locked the SPI controller. + * A total of rlen+ignore_len bytes will be read. The first rlen bytes will + * be copied to buf. The remaining ignore_len bytes won't be copied to the + * buffer. The maximum of wlen and rlen+ignore_len of bytes will be transfered. + */ +spi_status_t spi_transfer(spi_device_t *dev, + const uint8_t *data, int wsize, + uint8_t *buf, int rsize, int ignore); + +/** + * \brief Reads and Writes one byte from/to an SPI device + * \param dev An SPI device configuration. + * \param strobe Byte to write + * \param status Pointer to byte to read + * \return SPI return code + * + * It should work only if the device has already locked the SPI controller. + */ +spi_status_t spi_strobe(spi_device_t *dev, uint8_t strobe, + uint8_t *status); + +/** + * \brief Reads a buffer of bytes from a register of an SPI device + * \param dev An SPI device configuration. + * \param reg Register + * \param data A pointer to the data + * \param size Size of the data to read + * \return SPI return code + * + * It should work only if the device has already locked the SPI controller. + */ +spi_status_t spi_read_register(spi_device_t *dev, uint8_t reg, + uint8_t *data, int size); + +/*---------------------------------------------------------------------------*/ +/* These are architecture-specific functions to be implemented by each CPU. */ +/*---------------------------------------------------------------------------*/ + +/** + * \brief Locks an SPI controller to device dev. + * \param dev An SPI device configuration which defines the controller + * to be locked and the device that locks it. + * \return SPI return code + * + */ +spi_status_t spi_arch_lock(spi_device_t *dev); + +/** + * \brief Unlocks an SPI controller. + * \param dev An SPI device configuration which defines the controller + * to be unlocked and the device that unlocks it. + * \return SPI return code + * + */ +spi_status_t spi_arch_unlock(spi_device_t *dev); + +/** + * \brief Checks if a device has locked an SPI controller + * \param dev An SPI device configuration which defines the controller + * to be checked if it is locked and the respective device. + * \return 1 if the device has the lock, 0 otherwise. + * + */ +bool spi_arch_has_lock(spi_device_t *dev); + +/** + * \brief Checks if an SPI controller is locked by any device + * \param dev An SPI device configuration which defines the controller + * to be checked. + * \return 1 if the controller is locked, 0 otherwise. + * + */ +bool spi_arch_is_bus_locked(spi_device_t *dev); + +/** + * \brief Opens an SPI controller to the configuration specified. + * \param dev An SPI device configuration. + * \return SPI return code + * + * This should work only if the device has already locked the SPI + * controller. + * + */ +spi_status_t spi_arch_open(spi_device_t *dev); + +/** + * \brief Closes an SPI controller + * \param dev An SPI device configuration that specifies the controller. + * \return SPI return code + * + * This should turn off the SPI controller to put it in low power mode. + * It should work only if the device has already locked the SPI + * controller. + * + */ +spi_status_t spi_arch_close(spi_device_t *dev); + +/** + * \brief Performs an SPI transfer + * \param dev An SPI device configuration that specifies the controller. + * \param data A pointer to the data to be written. Set it to NULL to + * skip writing. + * \param wlen Length of data to write. + * \param buf A pointer to buffer to copy the data read. Set to NULL + * to skip reading. + * \param rlen Length of data to read. + * \param ignore_len Length of data to read and ignore. + * \return SPI return code + * + * It should work only if the device has already locked the SPI controller. + * A total of rlen+ignore_len bytes will be read. The first rlen bytes will + * be copied to buf. The remaining ignore_len bytes won't be copied to the + * buffer. The maximum of wlen and rlen+ignore_len of bytes will be transfered. + */ +spi_status_t spi_arch_transfer(spi_device_t *dev, + const uint8_t *data, int wlen, + uint8_t *buf, int rlen, + int ignore_len); + +/** + * \brief Selects an SPI device + * \param dev An SPI device configuration that specifies the CS pin. + * \return SPI return code + * + * Clears the CS pin. It should work only if the device has already + * locked the SPI controller. + */ +spi_status_t spi_arch_select(spi_device_t *dev); + +/** + * \brief Deselects an SPI device + * \param dev An SPI device configuration that specifies the CS pin. + * \return SPI return code + * + * Set the CS pin. Locking the SPI controller is not needed. + */ +spi_status_t spi_arch_deselect(spi_device_t *dev); + +#endif /* SPI_HAL_H_ */