From 743179849015dc71bb2ea63d8cd4bfa7fdfb4bc6 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Thu, 15 Nov 2012 20:19:57 +0100 Subject: of_spi: add generic binding support to specify cs gpio This will allow to use gpio for chip select with no modification in the driver binding When use the cs-gpios, the gpio number will be passed via the cs_gpio field and the number of chip select will automatically increased with max(hw cs, gpio cs). So if for example the controller has 2 CS lines, and the cs-gpios property looks like this: cs-gpios = <&gpio1 0 0> <0> <&gpio1 1 0> <&gpio1 2 0>; Then it should be configured so that num_chipselect = 4 with the following mapping: cs0 : &gpio1 0 0 cs1 : native cs2 : &gpio1 1 0 cs3 : &gpio1 2 0 Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Cc: devicetree-discuss@lists.ozlabs.org Cc: spi-devel-general@lists.sourceforge.net Signed-off-by: Richard Genoud [grant.likely: fixed up type of cs count so min() can do type checking] Signed-off-by: Grant Likely --- drivers/spi/spi.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) (limited to 'drivers/spi/spi.c') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 84c2861d6f4d..1587a4a5ff41 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -327,6 +328,7 @@ struct spi_device *spi_alloc_device(struct spi_master *master) spi->dev.parent = &master->dev; spi->dev.bus = &spi_bus_type; spi->dev.release = spidev_release; + spi->cs_gpio = -EINVAL; device_initialize(&spi->dev); return spi; } @@ -344,15 +346,16 @@ EXPORT_SYMBOL_GPL(spi_alloc_device); int spi_add_device(struct spi_device *spi) { static DEFINE_MUTEX(spi_add_lock); - struct device *dev = spi->master->dev.parent; + struct spi_master *master = spi->master; + struct device *dev = master->dev.parent; struct device *d; int status; /* Chipselects are numbered 0..max; validate. */ - if (spi->chip_select >= spi->master->num_chipselect) { + if (spi->chip_select >= master->num_chipselect) { dev_err(dev, "cs%d >= max %d\n", spi->chip_select, - spi->master->num_chipselect); + master->num_chipselect); return -EINVAL; } @@ -376,6 +379,9 @@ int spi_add_device(struct spi_device *spi) goto done; } + if (master->cs_gpios) + spi->cs_gpio = master->cs_gpios[spi->chip_select]; + /* Drivers may modify this initial i/o setup, but will * normally rely on the device being setup. Devices * using SPI_CS_HIGH can't coexist well otherwise... @@ -946,6 +952,44 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size) } EXPORT_SYMBOL_GPL(spi_alloc_master); +#ifdef CONFIG_OF +static int of_spi_register_master(struct spi_master *master) +{ + u16 nb; + int i, *cs; + struct device_node *np = master->dev.of_node; + + if (!np) + return 0; + + nb = of_gpio_named_count(np, "cs-gpios"); + master->num_chipselect = max(nb, master->num_chipselect); + + if (nb < 1) + return 0; + + cs = devm_kzalloc(&master->dev, + sizeof(int) * master->num_chipselect, + GFP_KERNEL); + master->cs_gpios = cs; + + if (!master->cs_gpios) + return -ENOMEM; + + memset(cs, -EINVAL, master->num_chipselect); + + for (i = 0; i < nb; i++) + cs[i] = of_get_named_gpio(np, "cs-gpios", i); + + return 0; +} +#else +static int of_spi_register_master(struct spi_master *master) +{ + return 0; +} +#endif + /** * spi_register_master - register SPI master controller * @master: initialized master, originally from spi_alloc_master() @@ -977,6 +1021,10 @@ int spi_register_master(struct spi_master *master) if (!dev) return -ENODEV; + status = of_spi_register_master(master); + if (status) + return status; + /* even if it's just one always-selected device, there must * be at least one chipselect */ -- cgit v1.2.3