drivers: spi: spi_context: improve support of multiple cs gpios

Add extra cs_gpios and num_cs_gpios members into
spi_context structure that will be used to
initialize all defined cs gpios during the driver
initialization using SPI_CONTEXT_CS_GPIOS_INITIALIZE macro.
While at it add a new spi_context_cs_configure_all
function that allows the user to configure
all available cs gpios in inactive mode.

Signed-off-by: Bartosz Bilas <bartosz.bilas@hotmail.com>
This commit is contained in:
Bartosz Bilas 2021-07-30 08:10:42 +02:00 committed by Carles Cufí
commit 54907c7014

View file

@ -27,6 +27,8 @@ enum spi_ctx_runtime_op_mode {
struct spi_context { struct spi_context {
const struct spi_config *config; const struct spi_config *config;
const struct spi_config *owner; const struct spi_config *owner;
const struct gpio_dt_spec *cs_gpios;
size_t num_cs_gpios;
struct k_sem lock; struct k_sem lock;
struct k_sem sync; struct k_sem sync;
@ -57,6 +59,20 @@ struct spi_context {
#define SPI_CONTEXT_INIT_SYNC(_data, _ctx_name) \ #define SPI_CONTEXT_INIT_SYNC(_data, _ctx_name) \
._ctx_name.sync = Z_SEM_INITIALIZER(_data._ctx_name.sync, 0, 1) ._ctx_name.sync = Z_SEM_INITIALIZER(_data._ctx_name.sync, 0, 1)
#define SPI_CONTEXT_CS_GPIO_SPEC_ELEM(_node_id, _prop, _idx) \
GPIO_DT_SPEC_GET_BY_IDX(_node_id, _prop, _idx),
#define SPI_CONTEXT_CS_GPIOS_FOREACH_ELEM(_node_id) \
DT_FOREACH_PROP_ELEM(_node_id, cs_gpios, \
SPI_CONTEXT_CS_GPIO_SPEC_ELEM)
#define SPI_CONTEXT_CS_GPIOS_INITIALIZE(_node_id, _ctx_name) \
._ctx_name.cs_gpios = (const struct gpio_dt_spec []) { \
COND_CODE_1(DT_SPI_HAS_CS_GPIOS(_node_id), \
(SPI_CONTEXT_CS_GPIOS_FOREACH_ELEM(_node_id)), ({0})) \
}, \
._ctx_name.num_cs_gpios = DT_PROP_LEN_OR(_node_id, cs_gpios, 0),
static inline bool spi_context_configured(struct spi_context *ctx, static inline bool spi_context_configured(struct spi_context *ctx,
const struct spi_config *config) const struct spi_config *config)
{ {
@ -183,6 +199,32 @@ gpio_dt_flags_t spi_context_cs_active_level(struct spi_context *ctx)
return GPIO_ACTIVE_LOW; return GPIO_ACTIVE_LOW;
} }
static inline int spi_context_cs_configure_all(struct spi_context *ctx)
{
int ret;
const struct gpio_dt_spec *cs_gpio;
for (cs_gpio = ctx->cs_gpios; cs_gpio < &ctx->cs_gpios[ctx->num_cs_gpios]; cs_gpio++) {
if (!device_is_ready(cs_gpio->port)) {
LOG_ERR("CS GPIO port %s pin %d is not ready",
cs_gpio->port->name, cs_gpio->pin);
return -ENODEV;
}
/* Validate CS active levels are equivalent */
__ASSERT(spi_context_cs_active_level(ctx) ==
(cs_gpio->dt_flags & GPIO_ACTIVE_LOW),
"Devicetree and spi_context CS levels are not equal");
ret = gpio_pin_configure_dt(cs_gpio, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
return ret;
}
}
return 0;
}
static inline int spi_context_cs_configure(struct spi_context *ctx) static inline int spi_context_cs_configure(struct spi_context *ctx)
{ {
int ret; int ret;