When using GPIO descriptors for CS GPIOs we need to inspect the child node to determine if the 'cs-gpios' active flags should have inverted semantics. Previously, commit 6953c57ab172 ("gpio: of: Handle SPI chipselect legacy bindings") introduced a special quirk to solve the conflict between the 'cs-gpios' flags and the optional SPI slaves flags. The principle is that the SPI slave flag will take precedence when we get a conflict. For more details, see Documentation/devicetree/bindings/spi/spi-controller.yaml. If following the previous commit, we need to add a new quirk to deal with this in ACPI. Instead, this patch introduces a generic implementation to solve this conflict by SPI core. The 'cs-gpios' active rules are as follows: 1) DT (SPI device have active low chip selects by default): device node | cs-gpio | CS pin state active ================+===============+===================== spi-cs-high | - | H - | - | L spi-cs-high | ACTIVE_HIGH | H - | ACTIVE_HIGH | L spi-cs-high | ACTIVE_LOW | H - | ACTIVE_LOW | L 2) ACPI: device node | cs-gpio | CS pin state active ================+===============+===================== PolarityLow | ACTIVE_LOW | L PolarityLow | ACTIVE_HIGH | L PolarityHigh | ACTIVE_LOW | H PolarityHigh | ACTIVE_HIGH | H Signed-off-by: Jay Fang <f.fangjian@xxxxxxxxxx> Signed-off-by: Zihao Tang <tangzihao1@xxxxxxxxxxxxx> --- drivers/spi/spi.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index b08efe8..2c0324d 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -33,6 +33,7 @@ #include <linux/highmem.h> #include <linux/idr.h> #include <linux/platform_data/x86/apple.h> +#include <../gpio/gpiolib.h> #define CREATE_TRACE_POINTS #include <trace/events/spi.h> @@ -604,9 +605,26 @@ int spi_add_device(struct spi_device *spi) } /* Descriptors take precedence */ - if (ctlr->cs_gpiods) + if (ctlr->cs_gpiods) { spi->cs_gpiod = ctlr->cs_gpiods[spi->chip_select]; - else if (ctlr->cs_gpios) + + /* We need to handle the active flag conflict between + * the cs-gpio and the SPI slave. The SPI slave active + * flag will determine the active state of cs-gpio. + */ + if (spi->mode & SPI_CS_HIGH) { + if (test_bit(FLAG_ACTIVE_LOW, &spi->cs_gpiod->flags)) { + dev_warn(&spi->dev, "GPIO handle specifies " + "active low - ignored\n"); + clear_bit(FLAG_ACTIVE_LOW, &spi->cs_gpiod->flags); + } + } else { + if (!test_bit(FLAG_ACTIVE_LOW, &spi->cs_gpiod->flags)) + dev_warn(&spi->dev, "enforce active low on " + "chipselect handle\n"); + set_bit(FLAG_ACTIVE_LOW, &spi->cs_gpiod->flags); + } + } else if (ctlr->cs_gpios) spi->cs_gpio = ctlr->cs_gpios[spi->chip_select]; /* Drivers may modify this initial i/o setup, but will -- 2.7.4