diff --git a/drivers/spi/spi_context.h b/drivers/spi/spi_context.h index 96d39ab0e9e..773d870864f 100644 --- a/drivers/spi/spi_context.h +++ b/drivers/spi/spi_context.h @@ -25,6 +25,10 @@ struct spi_context { struct k_sem lock; struct k_sem sync; +#ifdef CONFIG_POLL + struct k_poll_signal *signal; + bool asynchronous; +#endif const struct spi_buf **current_tx; struct spi_buf **current_rx; @@ -46,24 +50,55 @@ static inline bool spi_context_configured(struct spi_context *ctx, return !!(ctx->config == config); } -static inline void spi_context_lock(struct spi_context *ctx) +static inline void spi_context_lock(struct spi_context *ctx, + bool asynchronous, + struct k_poll_signal *signal) { k_sem_take(&ctx->lock, K_FOREVER); + +#ifdef CONFIG_POLL + ctx->asynchronous = asynchronous; + ctx->signal = signal; +#endif } -static inline void spi_context_release(struct spi_context *ctx) +static inline void spi_context_release(struct spi_context *ctx, int status) { +#ifdef CONFIG_POLL + if (!ctx->asynchronous || status) { + k_sem_give(&ctx->lock); + } +#else k_sem_give(&ctx->lock); +#endif } static inline void spi_context_wait_for_completion(struct spi_context *ctx) { +#ifdef CONFIG_POLL + if (!ctx->asynchronous) { + k_sem_take(&ctx->sync, K_FOREVER); + } +#else k_sem_take(&ctx->sync, K_FOREVER); +#endif } -static inline void spi_context_complete(struct spi_context *ctx) +static inline void spi_context_complete(struct spi_context *ctx, int status) { +#ifdef CONFIG_POLL + if (!ctx->asynchronous) { + k_sem_give(&ctx->sync); + } else { + if (ctx->signal) { + k_poll_signal(ctx->signal, status); + } + + k_sem_give(&ctx->lock); + } +#else k_sem_give(&ctx->sync); +#endif } static inline void spi_context_cs_configure(struct spi_context *ctx) diff --git a/drivers/spi/spi_dw.c b/drivers/spi/spi_dw.c index 46f838e93bd..279d38d496a 100644 --- a/drivers/spi/spi_dw.c +++ b/drivers/spi/spi_dw.c @@ -75,7 +75,7 @@ out: SYS_LOG_DBG("SPI transaction completed %s error", error ? "with" : "without"); - spi_context_complete(&spi->ctx); + spi_context_complete(&spi->ctx, error ? -EIO : 0); } static void push_data(struct device *dev) @@ -250,9 +250,11 @@ static int spi_dw_configure(const struct spi_dw_config *info, return 0; } -static int spi_dw_transceive(struct spi_config *config, - const struct spi_buf **tx_bufs, - struct spi_buf **rx_bufs) +static int transceive(struct spi_config *config, + const struct spi_buf **tx_bufs, + struct spi_buf **rx_bufs, + bool asynchronous, + struct k_poll_signal *signal) { const struct spi_dw_config *info = config->dev->config->config_info; struct spi_dw_data *spi = config->dev->driver_data; @@ -260,15 +262,13 @@ static int spi_dw_transceive(struct spi_config *config, u32_t imask = DW_SPI_IMR_UNMASK; int ret = 0; - 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)) { SYS_LOG_DBG("Controller is busy"); return -EBUSY; } - spi_context_lock(&spi->ctx); + spi_context_lock(&spi->ctx, asynchronous, signal); /* Configure */ ret = spi_dw_configure(info, spi, config); @@ -311,11 +311,32 @@ static int spi_dw_transceive(struct spi_config *config, ret = -EIO; } out: - spi_context_release(&spi->ctx); + spi_context_release(&spi->ctx, ret); return ret; } +static int spi_dw_transceive(struct spi_config *config, + const struct spi_buf **tx_bufs, + struct spi_buf **rx_bufs) +{ + SYS_LOG_DBG("%p, %p, %p", config->dev, tx_bufs, rx_bufs); + + return transceive(config, tx_bufs, rx_bufs, false, NULL); +} + +#ifdef CONFIG_POLL +static int spi_dw_transceive_async(struct spi_config *config, + const struct spi_buf **tx_bufs, + struct spi_buf **rx_bufs, + struct k_poll_signal *async) +{ + SYS_LOG_DBG("%p, %p, %p, %p", config->dev, tx_bufs, rx_bufs, async); + + return transceive(config, tx_bufs, rx_bufs, true, async); +} +#endif /* CONFIG_POLL */ + void spi_dw_isr(struct device *dev) { const struct spi_dw_config *info = dev->config->config_info; @@ -349,6 +370,9 @@ out: static const struct spi_driver_api dw_spi_api = { .transceive = spi_dw_transceive, +#ifdef CONFIG_POLL + .transceive_async = spi_dw_transceive_async, +#endif }; int spi_dw_init(struct device *dev) @@ -367,7 +391,7 @@ int spi_dw_init(struct device *dev) SYS_LOG_DBG("Designware SPI driver initialized on device: %p", dev); - spi_context_release(&spi->ctx); + spi_context_release(&spi->ctx, 0); return 0; }