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 lock;
|
||||||
struct k_sem sync;
|
struct k_sem sync;
|
||||||
|
|
||||||
|
#ifdef CONFIG_POLL
|
||||||
|
struct k_poll_signal *signal;
|
||||||
|
bool asynchronous;
|
||||||
|
#endif
|
||||||
const struct spi_buf **current_tx;
|
const struct spi_buf **current_tx;
|
||||||
struct spi_buf **current_rx;
|
struct spi_buf **current_rx;
|
||||||
|
|
||||||
|
@ -46,24 +50,55 @@ static inline bool spi_context_configured(struct spi_context *ctx,
|
||||||
return !!(ctx->config == config);
|
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);
|
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);
|
k_sem_give(&ctx->lock);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
k_sem_give(&ctx->lock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static inline void spi_context_wait_for_completion(struct spi_context *ctx)
|
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);
|
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);
|
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)
|
static inline void spi_context_cs_configure(struct spi_context *ctx)
|
||||||
|
|
|
@ -75,7 +75,7 @@ out:
|
||||||
SYS_LOG_DBG("SPI transaction completed %s error",
|
SYS_LOG_DBG("SPI transaction completed %s error",
|
||||||
error ? "with" : "without");
|
error ? "with" : "without");
|
||||||
|
|
||||||
spi_context_complete(&spi->ctx);
|
spi_context_complete(&spi->ctx, error ? -EIO : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void push_data(struct device *dev)
|
static void push_data(struct device *dev)
|
||||||
|
@ -250,9 +250,11 @@ static int spi_dw_configure(const struct spi_dw_config *info,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spi_dw_transceive(struct spi_config *config,
|
static int transceive(struct spi_config *config,
|
||||||
const struct spi_buf **tx_bufs,
|
const struct spi_buf **tx_bufs,
|
||||||
struct spi_buf **rx_bufs)
|
struct spi_buf **rx_bufs,
|
||||||
|
bool asynchronous,
|
||||||
|
struct k_poll_signal *signal)
|
||||||
{
|
{
|
||||||
const struct spi_dw_config *info = config->dev->config->config_info;
|
const struct spi_dw_config *info = config->dev->config->config_info;
|
||||||
struct spi_dw_data *spi = config->dev->driver_data;
|
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;
|
u32_t imask = DW_SPI_IMR_UNMASK;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
SYS_LOG_DBG("%p, %p, %p", config->dev, tx_bufs, rx_bufs);
|
|
||||||
|
|
||||||
/* Check status */
|
/* Check status */
|
||||||
if (test_bit_ssienr(info->regs) || test_bit_sr_busy(info->regs)) {
|
if (test_bit_ssienr(info->regs) || test_bit_sr_busy(info->regs)) {
|
||||||
SYS_LOG_DBG("Controller is busy");
|
SYS_LOG_DBG("Controller is busy");
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
spi_context_lock(&spi->ctx);
|
spi_context_lock(&spi->ctx, asynchronous, signal);
|
||||||
|
|
||||||
/* Configure */
|
/* Configure */
|
||||||
ret = spi_dw_configure(info, spi, config);
|
ret = spi_dw_configure(info, spi, config);
|
||||||
|
@ -311,11 +311,32 @@ static int spi_dw_transceive(struct spi_config *config,
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
spi_context_release(&spi->ctx);
|
spi_context_release(&spi->ctx, ret);
|
||||||
|
|
||||||
return 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)
|
void spi_dw_isr(struct device *dev)
|
||||||
{
|
{
|
||||||
const struct spi_dw_config *info = dev->config->config_info;
|
const struct spi_dw_config *info = dev->config->config_info;
|
||||||
|
@ -349,6 +370,9 @@ out:
|
||||||
|
|
||||||
static const struct spi_driver_api dw_spi_api = {
|
static const struct spi_driver_api dw_spi_api = {
|
||||||
.transceive = spi_dw_transceive,
|
.transceive = spi_dw_transceive,
|
||||||
|
#ifdef CONFIG_POLL
|
||||||
|
.transceive_async = spi_dw_transceive_async,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
int spi_dw_init(struct device *dev)
|
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);
|
SYS_LOG_DBG("Designware SPI driver initialized on device: %p", dev);
|
||||||
|
|
||||||
spi_context_release(&spi->ctx);
|
spi_context_release(&spi->ctx, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue