drivers: spi: CS configuration through devicetree

Add an additional option to the spi_cs_control struct that records how
the pin has been configured in devicetree. For drivers that are not
updated, the CS behaviour is the same as before (Push-Pull).

Use the devicetree knowledge with the GPIO subsystem so that the correct
physical pin levels for the CS pin are automatically selected.

Fixes #26267

Signed-off-by: Jordan Yates <jordan.yates@data61.csiro.au>
This commit is contained in:
Jordan Yates 2020-06-18 15:32:24 +10:00 committed by Kumar Gala
parent a670c95452
commit 5963ebaf33
2 changed files with 20 additions and 21 deletions

View file

@ -147,32 +147,27 @@ static inline void spi_context_complete(struct spi_context *ctx, int status)
#endif /* CONFIG_SPI_ASYNC */
}
static inline int spi_context_cs_active_value(struct spi_context *ctx)
static inline
gpio_dt_flags_t spi_context_cs_active_level(struct spi_context *ctx)
{
if (ctx->config->operation & SPI_CS_ACTIVE_HIGH) {
return 1;
return GPIO_ACTIVE_HIGH;
}
return 0;
}
static inline int spi_context_cs_inactive_value(struct spi_context *ctx)
{
if (ctx->config->operation & SPI_CS_ACTIVE_HIGH) {
return 0;
}
return 1;
return GPIO_ACTIVE_LOW;
}
static inline void spi_context_cs_configure(struct spi_context *ctx)
{
if (ctx->config->cs && ctx->config->cs->gpio_dev) {
/* Validate CS active levels are equivalent */
__ASSERT(spi_context_cs_active_level(ctx) ==
(ctx->config->cs->gpio_dt_flags & GPIO_ACTIVE_LOW),
"Devicetree and spi_context CS levels are not equal");
gpio_pin_configure(ctx->config->cs->gpio_dev,
ctx->config->cs->gpio_pin, GPIO_OUTPUT);
gpio_pin_set(ctx->config->cs->gpio_dev,
ctx->config->cs->gpio_pin,
spi_context_cs_inactive_value(ctx));
ctx->config->cs->gpio_pin,
ctx->config->cs->gpio_dt_flags |
GPIO_OUTPUT_INACTIVE);
} else {
LOG_INF("CS control inhibited (no GPIO device)");
}
@ -184,8 +179,7 @@ static inline void _spi_context_cs_control(struct spi_context *ctx,
if (ctx->config && ctx->config->cs && ctx->config->cs->gpio_dev) {
if (on) {
gpio_pin_set(ctx->config->cs->gpio_dev,
ctx->config->cs->gpio_pin,
spi_context_cs_active_value(ctx));
ctx->config->cs->gpio_pin, 1);
k_busy_wait(ctx->config->cs->delay);
} else {
if (!force_off &&
@ -195,8 +189,7 @@ static inline void _spi_context_cs_control(struct spi_context *ctx,
k_busy_wait(ctx->config->cs->delay);
gpio_pin_set(ctx->config->cs->gpio_dev,
ctx->config->cs->gpio_pin,
spi_context_cs_inactive_value(ctx));
ctx->config->cs->gpio_pin, 0);
}
}
}

View file

@ -22,6 +22,7 @@
#include <zephyr/types.h>
#include <stddef.h>
#include <device.h>
#include <drivers/gpio.h>
#ifdef __cplusplus
extern "C" {
@ -129,11 +130,16 @@ extern "C" {
* to act as a CS line
* @param delay is a delay in microseconds to wait before starting the
* transmission and before releasing the CS line
* @param gpio_dt_flags is the devicetree flags corresponding to how the CS
* line should be driven. GPIO_ACTIVE_LOW/GPIO_ACTIVE_HIGH should be
* equivalent to SPI_CS_ACTIVE_HIGH/SPI_CS_ACTIVE_LOW options in struct
* spi_config.
*/
struct spi_cs_control {
struct device *gpio_dev;
uint32_t gpio_pin;
uint32_t delay;
gpio_pin_t gpio_pin;
gpio_dt_flags_t gpio_dt_flags;
};
/**