At the moment all drivers have to parse the cs-gpios on their own and have to implement the mapping. By this commit we add the support to handle this within the core and if there is a valid CS GPIO for a device we assign it accordingly. Signed-off-by: Marco Felsch <m.felsch@xxxxxxxxxxxxxx> --- drivers/spi/spi.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++ include/spi/spi.h | 9 +++++++ 2 files changed, 75 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 36d0653a191c..c239de9d8549 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -8,6 +8,8 @@ */ #include <common.h> +#include <linux/device.h> +#include <linux/gpio/consumer.h> #include <linux/spi/spi-mem.h> #include <spi/spi.h> #include <xfuncs.h> @@ -64,6 +66,8 @@ struct spi_device *spi_new_device(struct spi_controller *ctrl, proxy = xzalloc(sizeof *proxy); proxy->master = ctrl; proxy->chip_select = chip->chip_select; + if (ctrl->cs_gpiods) + proxy->cs_gpiod = ctrl->cs_gpiods[chip->chip_select]; proxy->max_speed_hz = chip->max_speed_hz; proxy->mode = chip->mode; proxy->bits_per_word = chip->bits_per_word ? chip->bits_per_word : 8; @@ -215,6 +219,62 @@ static void scan_boardinfo(struct spi_controller *ctrl) } } +/** + * spi_get_gpio_descs() - grab chip select GPIOs for the master + * @ctlr: The SPI master to grab GPIO descriptors for + */ +static int spi_get_gpio_descs(struct spi_controller *ctlr) +{ + int nb, i; + struct gpio_desc **cs; + struct device *dev = ctlr->dev; + + nb = gpiod_count(dev, "cs"); + if (nb < 0) { + /* No GPIOs at all is fine, else return the error */ + if (nb == -ENOENT) + return 0; + return nb; + } + + ctlr->num_chipselect = max_t(int, nb, ctlr->num_chipselect); + + cs = devm_kcalloc(dev, ctlr->num_chipselect, sizeof(*cs), + GFP_KERNEL); + if (!cs) + return -ENOMEM; + ctlr->cs_gpiods = cs; + + for (i = 0; i < nb; i++) { + /* + * Most chipselects are active low, the inverted + * semantics are handled by special quirks in gpiolib, + * so initializing them GPIOD_OUT_LOW here means + * "unasserted", in most cases this will drive the physical + * line high. + */ + cs[i] = gpiod_get_index_optional(dev, "cs", i, GPIOD_OUT_LOW); + if (IS_ERR(cs[i])) + return PTR_ERR(cs[i]); + + if (cs[i]) { + /* + * If we find a CS GPIO, name it after the device and + * chip select line. + */ + char *gpioname; + + gpioname = basprintf("%s CS%d", dev_name(dev), i); + if (!gpioname) + return -ENOMEM; + gpiod_set_consumer_name(cs[i], gpioname); + free(gpioname); + } + } + + return 0; +} + static int spi_controller_check_ops(struct spi_controller *ctlr) { /* @@ -285,6 +345,12 @@ int spi_register_controller(struct spi_controller *ctrl) if (ctrl->bus_num < 0) ctrl->bus_num = dyn_bus_id--; + if (ctrl->use_gpio_descriptors) { + status = spi_get_gpio_descs(ctrl); + if (status) + return status; + } + list_add_tail(&ctrl->list, &spi_controller_list); spi_of_register_slaves(ctrl); diff --git a/include/spi/spi.h b/include/spi/spi.h index 9261d508befd..53d6bd32e025 100644 --- a/include/spi/spi.h +++ b/include/spi/spi.h @@ -8,6 +8,7 @@ #include <linux/kernel.h> #include <linux/string.h> #include <linux/bitops.h> +#include <linux/gpio/consumer.h> struct spi_controller_mem_ops; struct spi_message; @@ -99,6 +100,7 @@ struct spi_device { void *controller_state; void *controller_data; const char *modalias; + struct gpio_desc *cs_gpiod; /* Chip select gpio desc */ /* * likely need more hooks for more protocol options affecting how @@ -156,6 +158,9 @@ static inline void spi_set_ctldata(struct spi_device *spi, void *state) * the device whose settings are being modified. * @transfer: adds a message to the controller's transfer queue. * @cleanup: frees controller-specific state + * @cs_gpiods: Array of GPIO descriptors to use as chip select lines; one per CS + * number. Any individual value may be NULL for CS lines that + * are not GPIOs (driven by the SPI controller itself). * @list: link with the global spi_controller list * * Each SPI controller can communicate with one or more @spi_device @@ -233,6 +238,10 @@ struct spi_controller { /* called on release() to free memory provided by spi_controller */ void (*cleanup)(struct spi_device *spi); + /* GPIO chip select */ + struct gpio_desc **cs_gpiods; + bool use_gpio_descriptors; + struct list_head list; }; -- 2.39.5