api: Add asynchronous call support to SPI API
Adding a struct k_poll_signal parameter to driver's API unique exposed function. If not NULL, the call will be handled as asynchronous and will return right after the transaction has started, on the contrary of current logic where is waits for the transaction to finish (= synchronous). In order to save stack, let's move the device pointer to struct spi_config. So the call is still at a maximum of 4 parameters. Adapting spi_dw.c and spi driver sample to the change so it still builts. Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
This commit is contained in:
parent
b9838475ac
commit
761a1d9429
|
@ -250,18 +250,17 @@ static int spi_dw_configure(const struct spi_dw_config *info,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int spi_dw_transceive(struct device *dev,
|
||||
struct spi_config *config,
|
||||
static int spi_dw_transceive(struct spi_config *config,
|
||||
const struct spi_buf **tx_bufs,
|
||||
struct spi_buf **rx_bufs)
|
||||
{
|
||||
const struct spi_dw_config *info = dev->config->config_info;
|
||||
struct spi_dw_data *spi = dev->driver_data;
|
||||
const struct spi_dw_config *info = config->dev->config->config_info;
|
||||
struct spi_dw_data *spi = config->dev->driver_data;
|
||||
u32_t rx_thsld = DW_SPI_RXFTLR_DFLT;
|
||||
u32_t imask = DW_SPI_IMR_UNMASK;
|
||||
int ret = 0;
|
||||
|
||||
SYS_LOG_DBG("%p, %p, %p", dev, tx_bufs, rx_bufs);
|
||||
SYS_LOG_DBG("%p, %p, %p", config->dev, tx_bufs, rx_bufs);
|
||||
|
||||
/* Check status */
|
||||
if (test_bit_ssienr(info->regs) || test_bit_sr_busy(info->regs)) {
|
||||
|
|
121
include/spi.h
121
include/spi.h
|
@ -124,6 +124,7 @@ struct spi_cs_control {
|
|||
/**
|
||||
* @brief SPI controller configuration structure
|
||||
*
|
||||
* dev is a valid pointer to an actual SPI device
|
||||
* frequency is the bus frequency in Hertz
|
||||
* operation is a bit field with the following parts:
|
||||
* operational mode [ 0 ] - master or slave.
|
||||
|
@ -139,9 +140,12 @@ struct spi_cs_control {
|
|||
* emulated through a gpio line, or NULL otherwise.
|
||||
*/
|
||||
struct spi_config {
|
||||
struct device *dev;
|
||||
|
||||
u32_t frequency;
|
||||
u16_t operation;
|
||||
u16_t slave;
|
||||
|
||||
struct spi_cs_control *cs;
|
||||
};
|
||||
|
||||
|
@ -163,17 +167,29 @@ struct spi_buf {
|
|||
* @brief Callback API for I/O
|
||||
* See spi_transceive() for argument descriptions
|
||||
*/
|
||||
typedef int (*spi_api_io)(struct device *dev,
|
||||
struct spi_config *config,
|
||||
typedef int (*spi_api_io)(struct spi_config *config,
|
||||
const struct spi_buf **tx_bufs,
|
||||
struct spi_buf **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 spi_config *config,
|
||||
const struct spi_buf **tx_bufs,
|
||||
struct spi_buf **rx_bufs,
|
||||
struct k_poll_signal *async);
|
||||
|
||||
/**
|
||||
* @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_POLL
|
||||
spi_api_io_async transceive_async;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -181,7 +197,6 @@ struct spi_driver_api {
|
|||
*
|
||||
* Note: This function is synchronous.
|
||||
*
|
||||
* @param dev is a valid pointer to an actual SPI device
|
||||
* @param config Pointer to a valid spi_config structure instance.
|
||||
* @param tx_bufs NULL terminated buffer array where data to be sent
|
||||
* originates from, or NULL if none.
|
||||
|
@ -190,14 +205,13 @@ struct spi_driver_api {
|
|||
*
|
||||
* @retval 0 If successful, negative errno code otherwise.
|
||||
*/
|
||||
static inline int spi_transceive(struct device *dev,
|
||||
struct spi_config *config,
|
||||
static inline int spi_transceive(struct spi_config *config,
|
||||
const struct spi_buf **tx_bufs,
|
||||
struct spi_buf **rx_bufs)
|
||||
{
|
||||
const struct spi_driver_api *api = dev->driver_api;
|
||||
const struct spi_driver_api *api = config->dev->driver_api;
|
||||
|
||||
return api->transceive(dev, config, tx_bufs, rx_bufs);
|
||||
return api->transceive(config, tx_bufs, rx_bufs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -205,20 +219,18 @@ static inline int spi_transceive(struct device *dev,
|
|||
*
|
||||
* Note: This function is synchronous.
|
||||
*
|
||||
* @param dev is a valid pointer to an actual SPI device
|
||||
* @param config Pointer to a valid spi_config structure instance.
|
||||
* @param rx_bufs NULL terminated buffer array where data to be read
|
||||
* will be written to.
|
||||
*
|
||||
* @retval 0 If successful, negative errno code otherwise.
|
||||
*/
|
||||
static inline int spi_read(struct device *dev,
|
||||
struct spi_config *config,
|
||||
static inline int spi_read(struct spi_config *config,
|
||||
struct spi_buf **rx_bufs)
|
||||
{
|
||||
const struct spi_driver_api *api = dev->driver_api;
|
||||
const struct spi_driver_api *api = config->dev->driver_api;
|
||||
|
||||
return api->transceive(dev, config, NULL, rx_bufs);
|
||||
return api->transceive(config, NULL, rx_bufs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -226,22 +238,97 @@ static inline int spi_read(struct device *dev,
|
|||
*
|
||||
* Note: This function is synchronous.
|
||||
*
|
||||
* @param dev is a valid pointer to an actual SPI device
|
||||
* @param config Pointer to a valid spi_config structure instance.
|
||||
* @param tx_bufs NULL terminated buffer array where data to be sent
|
||||
* originates from.
|
||||
*
|
||||
* @retval 0 If successful, negative errno code otherwise.
|
||||
*/
|
||||
static inline int spi_write(struct device *dev,
|
||||
struct spi_config *config,
|
||||
static inline int spi_write(struct spi_config *config,
|
||||
const struct spi_buf **tx_bufs)
|
||||
{
|
||||
const struct spi_driver_api *api = dev->driver_api;
|
||||
const struct spi_driver_api *api = config->dev->driver_api;
|
||||
|
||||
return api->transceive(dev, config, tx_bufs, NULL);
|
||||
return api->transceive(config, tx_bufs, NULL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_POLL
|
||||
/**
|
||||
* @brief Read/write the specified amount of data from the SPI driver.
|
||||
*
|
||||
* Note: This function is asynchronous.
|
||||
*
|
||||
* @param config Pointer to a valid spi_config structure instance.
|
||||
* @param tx_bufs NULL terminated buffer array where data to be sent
|
||||
* originates from, or NULL if none.
|
||||
* @param rx_bufs NULL terminated 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.
|
||||
*/
|
||||
static inline int spi_transceive_async(struct spi_config *config,
|
||||
const struct spi_buf **tx_bufs,
|
||||
struct spi_buf **rx_bufs,
|
||||
struct k_poll_signal *async)
|
||||
{
|
||||
const struct spi_driver_api *api = config->dev->driver_api;
|
||||
|
||||
return api->transceive_async(config, tx_bufs, rx_bufs, async);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read the specified amount of data from the SPI driver.
|
||||
*
|
||||
* Note: This function is asynchronous.
|
||||
*
|
||||
* @param config Pointer to a valid spi_config structure instance.
|
||||
* @param rx_bufs NULL terminated 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.
|
||||
*/
|
||||
static inline int spi_read_async(struct spi_config *config,
|
||||
struct spi_buf **rx_bufs,
|
||||
struct k_poll_signal *async)
|
||||
{
|
||||
const struct spi_driver_api *api = config->dev->driver_api;
|
||||
|
||||
return api->transceive_async(config, NULL, rx_bufs, async);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write the specified amount of data from the SPI driver.
|
||||
*
|
||||
* Note: This function is asynchronous.
|
||||
*
|
||||
* @param config Pointer to a valid spi_config structure instance.
|
||||
* @param tx_bufs NULL terminated 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.
|
||||
*/
|
||||
static inline int spi_write_async(struct spi_config *config,
|
||||
const struct spi_buf **tx_bufs,
|
||||
struct k_poll_signal *async)
|
||||
{
|
||||
const struct spi_driver_api *api = config->dev->driver_api;
|
||||
|
||||
return api->transceive_async(config, tx_bufs, NULL, async);
|
||||
}
|
||||
#endif /* CONFIG_POLL */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -72,8 +72,6 @@ struct spi_config spi_fast = {
|
|||
.cs = SPI_CS,
|
||||
};
|
||||
|
||||
struct device *spi_dev;
|
||||
|
||||
static int cs_ctrl_gpio_config(struct spi_cs_control *cs)
|
||||
{
|
||||
if (cs) {
|
||||
|
@ -102,7 +100,7 @@ static int spi_complete_loop(struct spi_config *spi_conf)
|
|||
struct spi_buf *rx_bufs[] = { &rx, NULL };
|
||||
int ret;
|
||||
|
||||
ret = spi_transceive(spi_dev, spi_conf, tx_bufs, rx_bufs);
|
||||
ret = spi_transceive(spi_conf, tx_bufs, rx_bufs);
|
||||
if (ret) {
|
||||
SYS_LOG_ERR("Code %d", ret);
|
||||
return -1;
|
||||
|
@ -133,7 +131,7 @@ static int spi_rx_half_start(struct spi_config *spi_conf)
|
|||
|
||||
memset(buffer_rx, 0, BUF_SIZE);
|
||||
|
||||
ret = spi_transceive(spi_dev, spi_conf, tx_bufs, rx_bufs);
|
||||
ret = spi_transceive(spi_conf, tx_bufs, rx_bufs);
|
||||
if (ret) {
|
||||
SYS_LOG_ERR("Code %d", ret);
|
||||
return -1;
|
||||
|
@ -167,7 +165,7 @@ static int spi_rx_half_end(struct spi_config *spi_conf)
|
|||
|
||||
memset(buffer_rx, 0, BUF_SIZE);
|
||||
|
||||
ret = spi_transceive(spi_dev, spi_conf, tx_bufs, rx_bufs);
|
||||
ret = spi_transceive(spi_conf, tx_bufs, rx_bufs);
|
||||
if (ret) {
|
||||
SYS_LOG_ERR("Code %d", ret);
|
||||
return -1;
|
||||
|
@ -206,7 +204,7 @@ static int spi_rx_every_4(struct spi_config *spi_conf)
|
|||
|
||||
memset(buffer_rx, 0, BUF_SIZE);
|
||||
|
||||
ret = spi_transceive(spi_dev, spi_conf, tx_bufs, rx_bufs);
|
||||
ret = spi_transceive(spi_conf, tx_bufs, rx_bufs);
|
||||
if (ret) {
|
||||
SYS_LOG_ERR("Code %d", ret);
|
||||
return -1;
|
||||
|
@ -231,12 +229,14 @@ void main(void)
|
|||
return;
|
||||
}
|
||||
|
||||
spi_dev = device_get_binding(SPI_DRV_NAME);
|
||||
if (!spi_dev) {
|
||||
spi_slow.dev = device_get_binding(SPI_DRV_NAME);
|
||||
if (!spi_slow.dev) {
|
||||
SYS_LOG_ERR("Cannot find %s!\n", SPI_DRV_NAME);
|
||||
return;
|
||||
}
|
||||
|
||||
spi_fast.dev = spi_slow.dev;
|
||||
|
||||
if (spi_complete_loop(&spi_slow) ||
|
||||
spi_rx_half_start(&spi_slow) ||
|
||||
spi_rx_half_end(&spi_slow) ||
|
||||
|
|
Loading…
Reference in a new issue