drivers: spi: spi_context.h: remove multithreading dependency
Replace semaphores with proper atomic flags when used without multithreading enabled. Signed-off-by: Michal Kozikowski <michal.kozikowski@nordicsemi.no>
This commit is contained in:
parent
7af55237da
commit
df65918cfa
6 changed files with 94 additions and 11 deletions
|
@ -24,6 +24,7 @@ config SPI_SHELL
|
||||||
|
|
||||||
config SPI_ASYNC
|
config SPI_ASYNC
|
||||||
bool "Asynchronous call support"
|
bool "Asynchronous call support"
|
||||||
|
depends on MULTITHREADING
|
||||||
select POLL
|
select POLL
|
||||||
help
|
help
|
||||||
This option enables the asynchronous API calls.
|
This option enables the asynchronous API calls.
|
||||||
|
|
|
@ -5,7 +5,6 @@ menuconfig SPI_NRFX
|
||||||
bool "nRF SPI nrfx drivers"
|
bool "nRF SPI nrfx drivers"
|
||||||
default y
|
default y
|
||||||
depends on SOC_FAMILY_NORDIC_NRF
|
depends on SOC_FAMILY_NORDIC_NRF
|
||||||
depends on MULTITHREADING
|
|
||||||
select GPIO
|
select GPIO
|
||||||
select PINCTRL
|
select PINCTRL
|
||||||
help
|
help
|
||||||
|
|
|
@ -28,12 +28,21 @@ enum spi_ctx_runtime_op_mode {
|
||||||
|
|
||||||
struct spi_context {
|
struct spi_context {
|
||||||
const struct spi_config *config;
|
const struct spi_config *config;
|
||||||
|
#ifdef CONFIG_MULTITHREADING
|
||||||
const struct spi_config *owner;
|
const struct spi_config *owner;
|
||||||
|
#endif
|
||||||
const struct gpio_dt_spec *cs_gpios;
|
const struct gpio_dt_spec *cs_gpios;
|
||||||
size_t num_cs_gpios;
|
size_t num_cs_gpios;
|
||||||
|
|
||||||
|
#ifdef CONFIG_MULTITHREADING
|
||||||
struct k_sem lock;
|
struct k_sem lock;
|
||||||
struct k_sem sync;
|
struct k_sem sync;
|
||||||
|
#else
|
||||||
|
/* An atomic flag that signals completed transfer
|
||||||
|
* when threads are not enabled.
|
||||||
|
*/
|
||||||
|
atomic_t ready;
|
||||||
|
#endif /* CONFIG_MULTITHREADING */
|
||||||
int sync_status;
|
int sync_status;
|
||||||
|
|
||||||
#ifdef CONFIG_SPI_ASYNC
|
#ifdef CONFIG_SPI_ASYNC
|
||||||
|
@ -106,6 +115,7 @@ static inline void spi_context_lock(struct spi_context *ctx,
|
||||||
void *callback_data,
|
void *callback_data,
|
||||||
const struct spi_config *spi_cfg)
|
const struct spi_config *spi_cfg)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_MULTITHREADING
|
||||||
bool already_locked = (spi_cfg->operation & SPI_LOCK_ON) &&
|
bool already_locked = (spi_cfg->operation & SPI_LOCK_ON) &&
|
||||||
(k_sem_count_get(&ctx->lock) == 0) &&
|
(k_sem_count_get(&ctx->lock) == 0) &&
|
||||||
(ctx->owner == spi_cfg);
|
(ctx->owner == spi_cfg);
|
||||||
|
@ -114,6 +124,7 @@ static inline void spi_context_lock(struct spi_context *ctx,
|
||||||
k_sem_take(&ctx->lock, K_FOREVER);
|
k_sem_take(&ctx->lock, K_FOREVER);
|
||||||
ctx->owner = spi_cfg;
|
ctx->owner = spi_cfg;
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_MULTITHREADING */
|
||||||
|
|
||||||
#ifdef CONFIG_SPI_ASYNC
|
#ifdef CONFIG_SPI_ASYNC
|
||||||
ctx->asynchronous = asynchronous;
|
ctx->asynchronous = asynchronous;
|
||||||
|
@ -131,6 +142,7 @@ static inline void spi_context_lock(struct spi_context *ctx,
|
||||||
*/
|
*/
|
||||||
static inline void spi_context_release(struct spi_context *ctx, int status)
|
static inline void spi_context_release(struct spi_context *ctx, int status)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_MULTITHREADING
|
||||||
#ifdef CONFIG_SPI_SLAVE
|
#ifdef CONFIG_SPI_SLAVE
|
||||||
if (status >= 0 && (ctx->config->operation & SPI_LOCK_ON)) {
|
if (status >= 0 && (ctx->config->operation & SPI_LOCK_ON)) {
|
||||||
return;
|
return;
|
||||||
|
@ -148,6 +160,7 @@ static inline void spi_context_release(struct spi_context *ctx, int status)
|
||||||
k_sem_give(&ctx->lock);
|
k_sem_give(&ctx->lock);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SPI_ASYNC */
|
#endif /* CONFIG_SPI_ASYNC */
|
||||||
|
#endif /* CONFIG_MULTITHREADING */
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t spi_context_total_tx_len(struct spi_context *ctx);
|
static inline size_t spi_context_total_tx_len(struct spi_context *ctx);
|
||||||
|
@ -173,6 +186,7 @@ static inline int spi_context_wait_for_completion(struct spi_context *ctx)
|
||||||
|
|
||||||
if (wait) {
|
if (wait) {
|
||||||
k_timeout_t timeout;
|
k_timeout_t timeout;
|
||||||
|
uint32_t timeout_ms;
|
||||||
|
|
||||||
/* Do not use any timeout in the slave mode, as in this case
|
/* Do not use any timeout in the slave mode, as in this case
|
||||||
* it is not known when the transfer will actually start and
|
* it is not known when the transfer will actually start and
|
||||||
|
@ -180,10 +194,10 @@ static inline int spi_context_wait_for_completion(struct spi_context *ctx)
|
||||||
*/
|
*/
|
||||||
if (IS_ENABLED(CONFIG_SPI_SLAVE) && spi_context_is_slave(ctx)) {
|
if (IS_ENABLED(CONFIG_SPI_SLAVE) && spi_context_is_slave(ctx)) {
|
||||||
timeout = K_FOREVER;
|
timeout = K_FOREVER;
|
||||||
|
timeout_ms = UINT32_MAX;
|
||||||
} else {
|
} else {
|
||||||
uint32_t tx_len = spi_context_total_tx_len(ctx);
|
uint32_t tx_len = spi_context_total_tx_len(ctx);
|
||||||
uint32_t rx_len = spi_context_total_rx_len(ctx);
|
uint32_t rx_len = spi_context_total_rx_len(ctx);
|
||||||
uint32_t timeout_ms;
|
|
||||||
|
|
||||||
timeout_ms = MAX(tx_len, rx_len) * 8 * 1000 /
|
timeout_ms = MAX(tx_len, rx_len) * 8 * 1000 /
|
||||||
ctx->config->frequency;
|
ctx->config->frequency;
|
||||||
|
@ -191,11 +205,38 @@ static inline int spi_context_wait_for_completion(struct spi_context *ctx)
|
||||||
|
|
||||||
timeout = K_MSEC(timeout_ms);
|
timeout = K_MSEC(timeout_ms);
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_MULTITHREADING
|
||||||
if (k_sem_take(&ctx->sync, timeout)) {
|
if (k_sem_take(&ctx->sync, timeout)) {
|
||||||
LOG_ERR("Timeout waiting for transfer complete");
|
LOG_ERR("Timeout waiting for transfer complete");
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (timeout_ms == UINT32_MAX) {
|
||||||
|
/* In slave mode, we wait indefinitely, so we can go idle. */
|
||||||
|
unsigned int key = irq_lock();
|
||||||
|
|
||||||
|
while (!atomic_get(&ctx->ready)) {
|
||||||
|
k_cpu_atomic_idle(key);
|
||||||
|
key = irq_lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->ready = 0;
|
||||||
|
irq_unlock(key);
|
||||||
|
} else {
|
||||||
|
const uint32_t tms = k_uptime_get_32();
|
||||||
|
|
||||||
|
while (!atomic_get(&ctx->ready) && (k_uptime_get_32() - tms < timeout_ms)) {
|
||||||
|
k_busy_wait(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx->ready) {
|
||||||
|
LOG_ERR("Timeout waiting for transfer complete");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->ready = 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_MULTITHREADING */
|
||||||
status = ctx->sync_status;
|
status = ctx->sync_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,10 +280,15 @@ static inline void spi_context_complete(struct spi_context *ctx,
|
||||||
ctx->owner = NULL;
|
ctx->owner = NULL;
|
||||||
k_sem_give(&ctx->lock);
|
k_sem_give(&ctx->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
ctx->sync_status = status;
|
ctx->sync_status = status;
|
||||||
|
#ifdef CONFIG_MULTITHREADING
|
||||||
k_sem_give(&ctx->sync);
|
k_sem_give(&ctx->sync);
|
||||||
|
#else
|
||||||
|
atomic_set(&ctx->ready, 1);
|
||||||
|
#endif /* CONFIG_MULTITHREADING */
|
||||||
#endif /* CONFIG_SPI_ASYNC */
|
#endif /* CONFIG_SPI_ASYNC */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,10 +401,12 @@ static inline void spi_context_unlock_unconditionally(struct spi_context *ctx)
|
||||||
/* Forcing CS to go to inactive status */
|
/* Forcing CS to go to inactive status */
|
||||||
_spi_context_cs_control(ctx, false, true);
|
_spi_context_cs_control(ctx, false, true);
|
||||||
|
|
||||||
|
#ifdef CONFIG_MULTITHREADING
|
||||||
if (!k_sem_count_get(&ctx->lock)) {
|
if (!k_sem_count_get(&ctx->lock)) {
|
||||||
ctx->owner = NULL;
|
ctx->owner = NULL;
|
||||||
k_sem_give(&ctx->lock);
|
k_sem_give(&ctx->lock);
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_MULTITHREADING */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -278,7 +278,11 @@ static int transceive(const struct device *dev,
|
||||||
finish_transaction(dev, -ETIMEDOUT);
|
finish_transaction(dev, -ETIMEDOUT);
|
||||||
|
|
||||||
/* Clean up the driver state. */
|
/* Clean up the driver state. */
|
||||||
|
#ifdef CONFIG_MULTITHREADING
|
||||||
k_sem_reset(&dev_data->ctx.sync);
|
k_sem_reset(&dev_data->ctx.sync);
|
||||||
|
#else
|
||||||
|
dev_data->ctx.ready = 0;
|
||||||
|
#endif /* CONFIG_MULTITHREADING */
|
||||||
}
|
}
|
||||||
|
|
||||||
spi_context_cs_control(&dev_data->ctx, false);
|
spi_context_cs_control(&dev_data->ctx, false);
|
||||||
|
@ -432,8 +436,10 @@ static int spi_nrfx_init(const struct device *dev)
|
||||||
nrfx_isr, nrfx_spi_##idx##_irq_handler, 0); \
|
nrfx_isr, nrfx_spi_##idx##_irq_handler, 0); \
|
||||||
} \
|
} \
|
||||||
static struct spi_nrfx_data spi_##idx##_data = { \
|
static struct spi_nrfx_data spi_##idx##_data = { \
|
||||||
SPI_CONTEXT_INIT_LOCK(spi_##idx##_data, ctx), \
|
IF_ENABLED(CONFIG_MULTITHREADING, \
|
||||||
SPI_CONTEXT_INIT_SYNC(spi_##idx##_data, ctx), \
|
(SPI_CONTEXT_INIT_LOCK(spi_##idx##_data, ctx),)) \
|
||||||
|
IF_ENABLED(CONFIG_MULTITHREADING, \
|
||||||
|
(SPI_CONTEXT_INIT_SYNC(spi_##idx##_data, ctx),)) \
|
||||||
SPI_CONTEXT_CS_GPIOS_INITIALIZE(SPI(idx), ctx) \
|
SPI_CONTEXT_CS_GPIOS_INITIALIZE(SPI(idx), ctx) \
|
||||||
.dev = DEVICE_DT_GET(SPI(idx)), \
|
.dev = DEVICE_DT_GET(SPI(idx)), \
|
||||||
.busy = false, \
|
.busy = false, \
|
||||||
|
|
|
@ -598,7 +598,11 @@ static int transceive(const struct device *dev,
|
||||||
finish_transaction(dev, -ETIMEDOUT);
|
finish_transaction(dev, -ETIMEDOUT);
|
||||||
|
|
||||||
/* Clean up the driver state. */
|
/* Clean up the driver state. */
|
||||||
|
#ifdef CONFIG_MULTITHREADING
|
||||||
k_sem_reset(&dev_data->ctx.sync);
|
k_sem_reset(&dev_data->ctx.sync);
|
||||||
|
#else
|
||||||
|
dev_data->ctx.ready = 0;
|
||||||
|
#endif /* CONFIG_MULTITHREADING */
|
||||||
#ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58
|
#ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58
|
||||||
anomaly_58_workaround_clear(dev_data);
|
anomaly_58_workaround_clear(dev_data);
|
||||||
#endif
|
#endif
|
||||||
|
@ -817,8 +821,10 @@ static int spi_nrfx_init(const struct device *dev)
|
||||||
[CONFIG_SPI_NRFX_RAM_BUFFER_SIZE] \
|
[CONFIG_SPI_NRFX_RAM_BUFFER_SIZE] \
|
||||||
SPIM_MEMORY_SECTION(idx);)) \
|
SPIM_MEMORY_SECTION(idx);)) \
|
||||||
static struct spi_nrfx_data spi_##idx##_data = { \
|
static struct spi_nrfx_data spi_##idx##_data = { \
|
||||||
SPI_CONTEXT_INIT_LOCK(spi_##idx##_data, ctx), \
|
IF_ENABLED(CONFIG_MULTITHREADING, \
|
||||||
SPI_CONTEXT_INIT_SYNC(spi_##idx##_data, ctx), \
|
(SPI_CONTEXT_INIT_LOCK(spi_##idx##_data, ctx),)) \
|
||||||
|
IF_ENABLED(CONFIG_MULTITHREADING, \
|
||||||
|
(SPI_CONTEXT_INIT_SYNC(spi_##idx##_data, ctx),)) \
|
||||||
SPI_CONTEXT_CS_GPIOS_INITIALIZE(SPIM(idx), ctx) \
|
SPI_CONTEXT_CS_GPIOS_INITIALIZE(SPIM(idx), ctx) \
|
||||||
IF_ENABLED(SPI_BUFFER_IN_RAM, \
|
IF_ENABLED(SPI_BUFFER_IN_RAM, \
|
||||||
(.tx_buffer = spim_##idx##_tx_buffer, \
|
(.tx_buffer = spim_##idx##_tx_buffer, \
|
||||||
|
|
|
@ -39,7 +39,11 @@ BUILD_ASSERT(!IS_ENABLED(CONFIG_PM_DEVICE_SYSTEM_MANAGED));
|
||||||
struct spi_nrfx_data {
|
struct spi_nrfx_data {
|
||||||
struct spi_context ctx;
|
struct spi_context ctx;
|
||||||
const struct device *dev;
|
const struct device *dev;
|
||||||
|
#ifdef CONFIG_MULTITHREADING
|
||||||
struct k_sem wake_sem;
|
struct k_sem wake_sem;
|
||||||
|
#else
|
||||||
|
atomic_t woken_up;
|
||||||
|
#endif
|
||||||
struct gpio_callback wake_cb_data;
|
struct gpio_callback wake_cb_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -193,7 +197,11 @@ static void wake_callback(const struct device *dev, struct gpio_callback *cb,
|
||||||
|
|
||||||
(void)gpio_pin_interrupt_configure_dt(&dev_config->wake_gpio,
|
(void)gpio_pin_interrupt_configure_dt(&dev_config->wake_gpio,
|
||||||
GPIO_INT_DISABLE);
|
GPIO_INT_DISABLE);
|
||||||
|
#ifdef CONFIG_MULTITHREADING
|
||||||
k_sem_give(&dev_data->wake_sem);
|
k_sem_give(&dev_data->wake_sem);
|
||||||
|
#else
|
||||||
|
atomic_set(&dev_data->woken_up, 1);
|
||||||
|
#endif /* CONFIG_MULTITHREADING */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wait_for_wake(struct spi_nrfx_data *dev_data,
|
static void wait_for_wake(struct spi_nrfx_data *dev_data,
|
||||||
|
@ -206,7 +214,19 @@ static void wait_for_wake(struct spi_nrfx_data *dev_data,
|
||||||
dev_config->wake_gpio.pin) == 0) {
|
dev_config->wake_gpio.pin) == 0) {
|
||||||
(void)gpio_pin_interrupt_configure_dt(&dev_config->wake_gpio,
|
(void)gpio_pin_interrupt_configure_dt(&dev_config->wake_gpio,
|
||||||
GPIO_INT_LEVEL_HIGH);
|
GPIO_INT_LEVEL_HIGH);
|
||||||
|
#ifdef CONFIG_MULTITHREADING
|
||||||
(void)k_sem_take(&dev_data->wake_sem, K_FOREVER);
|
(void)k_sem_take(&dev_data->wake_sem, K_FOREVER);
|
||||||
|
#else
|
||||||
|
unsigned int key = irq_lock();
|
||||||
|
|
||||||
|
while (!atomic_get(&dev_data->woken_up)) {
|
||||||
|
k_cpu_atomic_idle(key);
|
||||||
|
key = irq_lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_data->woken_up = 0;
|
||||||
|
irq_unlock(key);
|
||||||
|
#endif /* CONFIG_MULTITHREADING */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,11 +502,14 @@ static int spi_nrfx_init(const struct device *dev)
|
||||||
nrfx_isr, nrfx_spis_##idx##_irq_handler, 0); \
|
nrfx_isr, nrfx_spis_##idx##_irq_handler, 0); \
|
||||||
} \
|
} \
|
||||||
static struct spi_nrfx_data spi_##idx##_data = { \
|
static struct spi_nrfx_data spi_##idx##_data = { \
|
||||||
SPI_CONTEXT_INIT_LOCK(spi_##idx##_data, ctx), \
|
IF_ENABLED(CONFIG_MULTITHREADING, \
|
||||||
SPI_CONTEXT_INIT_SYNC(spi_##idx##_data, ctx), \
|
(SPI_CONTEXT_INIT_LOCK(spi_##idx##_data, ctx),)) \
|
||||||
|
IF_ENABLED(CONFIG_MULTITHREADING, \
|
||||||
|
(SPI_CONTEXT_INIT_SYNC(spi_##idx##_data, ctx),)) \
|
||||||
.dev = DEVICE_DT_GET(SPIS(idx)), \
|
.dev = DEVICE_DT_GET(SPIS(idx)), \
|
||||||
.wake_sem = Z_SEM_INITIALIZER( \
|
IF_ENABLED(CONFIG_MULTITHREADING, \
|
||||||
spi_##idx##_data.wake_sem, 0, 1), \
|
(.wake_sem = Z_SEM_INITIALIZER( \
|
||||||
|
spi_##idx##_data.wake_sem, 0, 1),)) \
|
||||||
}; \
|
}; \
|
||||||
PINCTRL_DT_DEFINE(SPIS(idx)); \
|
PINCTRL_DT_DEFINE(SPIS(idx)); \
|
||||||
static const struct spi_nrfx_config spi_##idx##z_config = { \
|
static const struct spi_nrfx_config spi_##idx##z_config = { \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue