zephyr/include/spi.h

427 lines
13 KiB
C
Raw Normal View History

/*
* Copyright (c) 2015 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Public API for SPI drivers and applications
*/
#ifndef __SPI_H__
#define __SPI_H__
/**
* @brief SPI Interface
* @defgroup spi_interface SPI Interface
* @ingroup io_interfaces
* @{
*/
#include <zephyr/types.h>
#include <stddef.h>
#include <device.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief SPI operational mode
*/
#define SPI_OP_MODE_MASTER 0
#define SPI_OP_MODE_SLAVE BIT(0)
#define SPI_OP_MODE_MASK 0x1
#define SPI_OP_MODE_GET(_operation_) ((_operation_) & SPI_OP_MODE_MASK)
/**
* @brief SPI Polarity & Phase Modes
*/
/**
* Clock Polarity: if set, clock idle state will be 1
* and active state will be 0. If untouched, the inverse will be true
* which is the default.
*/
#define SPI_MODE_CPOL BIT(1)
/**
* Clock Phase: this dictates when is the data captured, and depends
* clock's polarity. When SPI_MODE_CPOL is set and this bit as well,
* capture will occur on low to high transition and high to low if
* this bit is not set (default). This is fully reversed if CPOL is
* not set.
*/
#define SPI_MODE_CPHA BIT(2)
/**
* Whatever data is transmitted is looped-back to the receiving buffer of
* the controller. This is fully controller dependent as some may not
* support this, and can be used for testing purposes only.
*/
#define SPI_MODE_LOOP BIT(3)
#define SPI_MODE_MASK (0xE)
#define SPI_MODE_GET(_mode_) \
((_mode_) & SPI_MODE_MASK)
/**
* @brief SPI Transfer modes (host controller dependent)
*/
#define SPI_TRANSFER_MSB (0)
#define SPI_TRANSFER_LSB BIT(4)
/**
* @brief SPI word size
*/
#define SPI_WORD_SIZE_SHIFT (5)
#define SPI_WORD_SIZE_MASK (0x3F << SPI_WORD_SIZE_SHIFT)
#define SPI_WORD_SIZE_GET(_operation_) \
(((_operation_) & SPI_WORD_SIZE_MASK) >> SPI_WORD_SIZE_SHIFT)
#define SPI_WORD_SET(_word_size_) \
((_word_size_) << SPI_WORD_SIZE_SHIFT)
/**
* @brief SPI MISO lines
*
* Some controllers support dual, quad or octal MISO lines connected to slaves.
* Default is single, which is the case most of the time.
*/
#define SPI_LINES_SINGLE (0 << 11)
#define SPI_LINES_DUAL (1 << 11)
#define SPI_LINES_QUAD (2 << 11)
#define SPI_LINES_OCTAL (3 << 11)
#define SPI_LINES_MASK (0x3 << 11)
/**
* @brief Specific SPI devices control bits
*/
/* Requests - if possible - to keep CS asserted after the transaction */
#define SPI_HOLD_ON_CS BIT(13)
/* Keep the device locked after the transaction for the current config.
* Use this with extreme caution (see spi_release() below) as it will
* prevent other callers to access the SPI device until spi_release() is
* properly called.
*/
#define SPI_LOCK_ON BIT(14)
/* Active high logic on CS - Usually, and by default, CS logic is active
* low. However, some devices may require the reverse logic: active high.
* This bit will request the controller to use that logic. Note that not
* all controllers are able to handle that natively. In this case deferring
* the CS control to a gpio line through struct spi_cs_control would be
* the solution.
*/
#define SPI_CS_ACTIVE_HIGH BIT(15)
/**
* @brief SPI Chip Select control structure
*
* This can be used to control a CS line via a GPIO line, instead of
* using the controller inner CS logic.
*
* @param gpio_dev is a valid pointer to an actual GPIO device. A NULL pointer
* can be provided to full inhibit CS control if necessary.
* @param gpio_pin is a number representing the gpio PIN that will be used
* to act as a CS line
* @param delay is a delay in microseconds to wait before starting the
* transmission and before releasing the CS line
*/
struct spi_cs_control {
struct device *gpio_dev;
u32_t gpio_pin;
u32_t delay;
};
/**
* @brief SPI controller configuration structure
*
* @param dev is a valid pointer to an actual SPI device
* @param frequency is the bus frequency in Hertz
* @param operation is a bit field with the following parts:
*
* operational mode [ 0 ] - master or slave.
* mode [ 1 : 3 ] - Polarity, phase and loop mode.
* transfer [ 4 ] - LSB or MSB first.
* word_size [ 5 : 10 ] - Size of a data frame in bits.
* lines [ 11 : 12 ] - MISO lines: Single/Dual/Quad/Octal.
* cs_hold [ 13 ] - Hold on the CS line if possible.
* lock_on [ 14 ] - Keep resource locked for the caller.
* cs_active_high [ 15 ] - Active high CS logic.
* @param slave is the slave number from 0 to host controller slave limit.
* @param cs is a valid pointer on a struct spi_cs_control is CS line is
* emulated through a gpio line, or NULL otherwise.
*
* @note Only cs_hold and lock_on can be changed between consecutive
* transceive call. Rest of the attributes are not meant to be tweaked.
*/
struct spi_config {
u32_t frequency;
u16_t operation;
u16_t slave;
const struct spi_cs_control *cs;
};
/**
* @brief SPI buffer structure
*
* @param buf is a valid pointer on a data buffer, or NULL otherwise.
* @param len is the length of the buffer or, if buf is NULL, will be the
* length which as to be sent as dummy bytes (as TX buffer) or
* the length of bytes that should be skipped (as RX buffer).
*/
struct spi_buf {
void *buf;
size_t len;
};
/**
* @brief SPI buffer array structure
*
* @param buffers is a valid pointer on an array of spi_buf, or NULL.
* @param count is the length of the array pointed by buffers.
*/
struct spi_buf_set {
const struct spi_buf *buffers;
size_t count;
};
/**
* @typedef spi_api_io
* @brief Callback API for I/O
* See spi_transceive() for argument descriptions
*/
typedef int (*spi_api_io)(struct device *dev,
const struct spi_config *config,
const struct spi_buf_set *tx_bufs,
const struct spi_buf_set *rx_bufs);
/**
* @typedef spi_api_io
* @brief Callback API for asynchronous I/O
* See spi_transceive_async() for argument descriptions
*/
typedef int (*spi_api_io_async)(struct device *dev,
const struct spi_config *config,
const struct spi_buf_set *tx_bufs,
const struct spi_buf_set *rx_bufs,
struct k_poll_signal *async);
/**
* @typedef spi_api_release
* @brief Callback API for unlocking SPI device.
* See spi_release() for argument descriptions
*/
typedef int (*spi_api_release)(struct device *dev,
const struct spi_config *config);
/**
* @brief SPI driver API
* This is the mandatory API any SPI driver needs to expose.
*/
struct spi_driver_api {
spi_api_io transceive;
#ifdef CONFIG_SPI_ASYNC
spi_api_io_async transceive_async;
#endif /* CONFIG_SPI_ASYNC */
spi_api_release release;
};
/**
* @brief Read/write the specified amount of data from the SPI driver.
*
* Note: This function is synchronous.
*
* @param dev Pointer to the device structure for the driver instance
* @param config Pointer to a valid spi_config structure instance.
* @param tx_bufs Buffer array where data to be sent originates from,
* or NULL if none.
* @param rx_bufs Buffer array where data to be read will be written to,
* or NULL if none.
*
* @retval 0 If successful, negative errno code otherwise. In case of slave
* transaction: if successful it will return the amount of frames
* received, negative errno code otherwise.
*/
__syscall int spi_transceive(struct device *dev,
const struct spi_config *config,
const struct spi_buf_set *tx_bufs,
const struct spi_buf_set *rx_bufs);
static inline int _impl_spi_transceive(struct device *dev,
const struct spi_config *config,
const struct spi_buf_set *tx_bufs,
const struct spi_buf_set *rx_bufs)
{
const struct spi_driver_api *api =
(const struct spi_driver_api *)dev->driver_api;
return api->transceive(dev, config, tx_bufs, rx_bufs);
}
/**
* @brief Read the specified amount of data from the SPI driver.
*
* Note: This function is synchronous.
*
* @param dev Pointer to the device structure for the driver instance
* @param config Pointer to a valid spi_config structure instance.
* @param rx_bufs Buffer array where data to be read will be written to.
*
* @retval 0 If successful, negative errno code otherwise.
*
* @note This function is an helper function calling spi_transceive.
*/
static inline int spi_read(struct device *dev,
const struct spi_config *config,
const struct spi_buf_set *rx_bufs)
{
return spi_transceive(dev, config, NULL, rx_bufs);
}
/**
* @brief Write the specified amount of data from the SPI driver.
*
* Note: This function is synchronous.
*
* @param dev Pointer to the device structure for the driver instance
* @param config Pointer to a valid spi_config structure instance.
* @param tx_bufs Buffer array where data to be sent originates from.
*
* @retval 0 If successful, negative errno code otherwise.
*
* @note This function is an helper function calling spi_transceive.
*/
static inline int spi_write(struct device *dev,
const struct spi_config *config,
const struct spi_buf_set *tx_bufs)
{
return spi_transceive(dev, config, tx_bufs, NULL);
}
#ifdef CONFIG_SPI_ASYNC
/**
* @brief Read/write the specified amount of data from the SPI driver.
*
* Note: This function is asynchronous.
*
* @param dev Pointer to the device structure for the driver instance
* @param config Pointer to a valid spi_config structure instance.
* @param tx_bufs Buffer array where data to be sent originates from,
* or NULL if none.
* @param rx_bufs Buffer array where data to be read will be written to,
* or NULL if none.
* @param async A pointer to a valid and ready to be signaled
* struct k_poll_signal. (Note: if NULL this function will not
* notify the end of the transaction, and whether it went
* successfully or not).
*
* @retval 0 If successful, negative errno code otherwise. In case of slave
* transaction: if successful it will return the amount of frames
* received, negative errno code otherwise.
*/
static inline int spi_transceive_async(struct device *dev,
const struct spi_config *config,
const struct spi_buf_set *tx_bufs,
const struct spi_buf_set *rx_bufs,
struct k_poll_signal *async)
{
const struct spi_driver_api *api =
(const struct spi_driver_api *)dev->driver_api;
return api->transceive_async(dev, config, tx_bufs, rx_bufs, async);
}
/**
* @brief Read the specified amount of data from the SPI driver.
*
* Note: This function is asynchronous.
*
* @param dev Pointer to the device structure for the driver instance
* @param config Pointer to a valid spi_config structure instance.
* @param rx_bufs Buffer array where data to be read will be written to.
* @param async A pointer to a valid and ready to be signaled
* struct k_poll_signal. (Note: if NULL this function will not
* notify the end of the transaction, and whether it went
* successfully or not).
*
* @retval 0 If successful, negative errno code otherwise.
*
* @note This function is an helper function calling spi_transceive_async.
*/
static inline int spi_read_async(struct device *dev,
const struct spi_config *config,
const struct spi_buf_set *rx_bufs,
struct k_poll_signal *async)
{
return spi_transceive_async(dev, config, NULL, rx_bufs, async);
}
/**
* @brief Write the specified amount of data from the SPI driver.
*
* Note: This function is asynchronous.
*
* @param dev Pointer to the device structure for the driver instance
* @param config Pointer to a valid spi_config structure instance.
* @param tx_bufs Buffer array where data to be sent originates from.
* @param async A pointer to a valid and ready to be signaled
* struct k_poll_signal. (Note: if NULL this function will not
* notify the end of the transaction, and whether it went
* successfully or not).
*
* @retval 0 If successful, negative errno code otherwise.
*
* @note This function is an helper function calling spi_transceive_async.
*/
static inline int spi_write_async(struct device *dev,
const struct spi_config *config,
const struct spi_buf_set *tx_bufs,
struct k_poll_signal *async)
{
return spi_transceive_async(dev, config, tx_bufs, NULL, async);
}
#endif /* CONFIG_SPI_ASYNC */
/**
* @brief Release the SPI device locked on by the current config
*
* Note: This synchronous function is used to release the lock on the SPI
* device that was kept if, and if only, given config parameter was
* the last one to be used (in any of the above functions) and if
* it has the SPI_LOCK_ON bit set into its operation bits field.
* This can be used if the caller needs to keep its hand on the SPI
* device for consecutive transactions.
*
* @param dev Pointer to the device structure for the driver instance
* @param config Pointer to a valid spi_config structure instance.
*/
__syscall int spi_release(struct device *dev,
const struct spi_config *config);
static inline int _impl_spi_release(struct device *dev,
const struct spi_config *config)
{
const struct spi_driver_api *api =
(const struct spi_driver_api *)dev->driver_api;
return api->release(dev, config);
}
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#include <syscalls/spi.h>
#endif /* __SPI_H__ */