drivers/spi: Add support for async call in DW driver in a generic way
All is done through the generic spi_context driver's API as it will be generic to all SPI drivers. Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
This commit is contained in:
parent
761a1d9429
commit
587dd5d275
2 changed files with 71 additions and 12 deletions
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue