From 7d93aecdb58d47e8ed90b4a44c0fc9ffb8de941c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 2 Jan 2020 14:38:17 +0100 Subject: spi: Add generic support for unused native cs with cs-gpios Some SPI master controllers always drive a native chip select when performing a transfer. Hence when using both native and GPIO chip selects, at least one native chip select must be left unused, to be driven when performing transfers with slave devices using GPIO chip selects. Currently, to find an unused native chip select, SPI controller drivers need to parse and process cs-gpios theirselves. This is not only duplicated in each driver that needs it, but also duplicates part of the work done later at SPI controller registration time. Note that this cannot be done after spi_register_controller() returns, as at that time, slave devices may have been probed already. Hence add generic support to the SPI subsystem for finding an unused native chip select. Optionally, this unused native chip select, and all other in-use native chip selects, can be validated against the maximum number of native chip selects available on the controller hardware. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200102133822.29346-2-geert+renesas@glider.be Signed-off-by: Mark Brown --- drivers/spi/spi.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5485ef89197c..197c9e0ac2a6 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2464,6 +2464,8 @@ static int spi_get_gpio_descs(struct spi_controller *ctlr) int nb, i; struct gpio_desc **cs; struct device *dev = &ctlr->dev; + unsigned long native_cs_mask = 0; + unsigned int num_cs_gpios = 0; nb = gpiod_count(dev, "cs"); ctlr->num_chipselect = max_t(int, nb, ctlr->num_chipselect); @@ -2505,7 +2507,22 @@ static int spi_get_gpio_descs(struct spi_controller *ctlr) if (!gpioname) return -ENOMEM; gpiod_set_consumer_name(cs[i], gpioname); + num_cs_gpios++; + continue; + } + + if (ctlr->max_native_cs && i >= ctlr->max_native_cs) { + dev_err(dev, "Invalid native chip select %d\n", i); + return -EINVAL; } + native_cs_mask |= BIT(i); + } + + ctlr->unused_native_cs = ffz(native_cs_mask); + if (num_cs_gpios && ctlr->max_native_cs && + ctlr->unused_native_cs >= ctlr->max_native_cs) { + dev_err(dev, "No unused native chip select available\n"); + return -EINVAL; } return 0; -- cgit v1.2.3