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>
diff --git a/drivers/spi/spi_context.h b/drivers/spi/spi_context.h
index 557e81a..12abeaa 100644
--- a/drivers/spi/spi_context.h
+++ b/drivers/spi/spi_context.h
@@ -27,6 +27,8 @@
struct spi_context {
const struct spi_config *config;
const struct spi_config *owner;
+ const struct gpio_dt_spec *cs_gpios;
+ size_t num_cs_gpios;
struct k_sem lock;
struct k_sem sync;
@@ -57,6 +59,20 @@
#define SPI_CONTEXT_INIT_SYNC(_data, _ctx_name) \
._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,
const struct spi_config *config)
{
@@ -183,6 +199,32 @@
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)
{
int ret;