diff options
Diffstat (limited to 'drivers/spi/spi.c')
-rw-r--r-- | drivers/spi/spi.c | 101 |
1 files changed, 79 insertions, 22 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 718cc1f49230..ab095acdb2a8 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -30,6 +30,7 @@ #include <linux/slab.h> #include <linux/mod_devicetable.h> #include <linux/spi/spi.h> +#include <linux/of_gpio.h> #include <linux/pm_runtime.h> #include <linux/export.h> #include <linux/sched.h> @@ -333,6 +334,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; } @@ -350,15 +352,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; } @@ -382,6 +385,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... @@ -492,8 +498,7 @@ static void spi_match_master_to_boardinfo(struct spi_master *master, * The board info passed can safely be __initdata ... but be careful of * any embedded pointers (platform_data, etc), they're copied as-is. */ -int __devinit -spi_register_board_info(struct spi_board_info const *info, unsigned n) +int spi_register_board_info(struct spi_board_info const *info, unsigned n) { struct boardinfo *bi; int i; @@ -806,7 +811,7 @@ err_init_queue: /*-------------------------------------------------------------------------*/ -#if defined(CONFIG_OF) && !defined(CONFIG_SPARC) +#if defined(CONFIG_OF) /** * of_register_spi_devices() - Register child devices onto the SPI bus * @master: Pointer to spi_master device @@ -861,6 +866,8 @@ static void of_register_spi_devices(struct spi_master *master) spi->mode |= SPI_CPOL; if (of_find_property(nc, "spi-cs-high", NULL)) spi->mode |= SPI_CS_HIGH; + if (of_find_property(nc, "spi-3wire", NULL)) + spi->mode |= SPI_3WIRE; /* Device speed */ prop = of_get_property(nc, "spi-max-frequency", &len); @@ -1046,6 +1053,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() @@ -1077,6 +1122,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 */ @@ -1257,7 +1306,7 @@ EXPORT_SYMBOL_GPL(spi_busnum_to_master); int spi_setup(struct spi_device *spi) { unsigned bad_bits; - int status; + int status = 0; /* help drivers fail *cleanly* when they need options * that aren't supported with their current master @@ -1272,7 +1321,8 @@ int spi_setup(struct spi_device *spi) if (!spi->bits_per_word) spi->bits_per_word = 8; - status = spi->master->setup(spi); + if (spi->master->setup) + status = spi->master->setup(spi); dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s" "%u bits/w, %u Hz max --> %d\n", @@ -1291,6 +1341,7 @@ EXPORT_SYMBOL_GPL(spi_setup); static int __spi_async(struct spi_device *spi, struct spi_message *message) { struct spi_master *master = spi->master; + struct spi_transfer *xfer; /* Half-duplex links include original MicroWire, and ones with * only one data pin like SPI_3WIRE (switches direction) or where @@ -1299,7 +1350,6 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) */ if ((master->flags & SPI_MASTER_HALF_DUPLEX) || (spi->mode & SPI_3WIRE)) { - struct spi_transfer *xfer; unsigned flags = master->flags; list_for_each_entry(xfer, &message->transfers, transfer_list) { @@ -1312,6 +1362,15 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) } } + /** + * Set transfer bits_per_word as spi device default if it is not + * set for this transfer. + */ + list_for_each_entry(xfer, &message->transfers, transfer_list) { + if (!xfer->bits_per_word) + xfer->bits_per_word = spi->bits_per_word; + } + message->spi = spi; message->status = -EINPROGRESS; return master->transfer(spi, message); @@ -1588,12 +1647,18 @@ int spi_write_then_read(struct spi_device *spi, struct spi_transfer x[2]; u8 *local_buf; - /* Use preallocated DMA-safe buffer. We can't avoid copying here, - * (as a pure convenience thing), but we can keep heap costs - * out of the hot path ... + /* Use preallocated DMA-safe buffer if we can. We can't avoid + * copying here, (as a pure convenience thing), but we can + * keep heap costs out of the hot path unless someone else is + * using the pre-allocated buffer or the transfer is too large. */ - if ((n_tx + n_rx) > SPI_BUFSIZ) - return -EINVAL; + if ((n_tx + n_rx) > SPI_BUFSIZ || !mutex_trylock(&lock)) { + local_buf = kmalloc(max((unsigned)SPI_BUFSIZ, n_tx + n_rx), GFP_KERNEL); + if (!local_buf) + return -ENOMEM; + } else { + local_buf = buf; + } spi_message_init(&message); memset(x, 0, sizeof x); @@ -1606,14 +1671,6 @@ int spi_write_then_read(struct spi_device *spi, spi_message_add_tail(&x[1], &message); } - /* ... unless someone else is using the pre-allocated buffer */ - if (!mutex_trylock(&lock)) { - local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL); - if (!local_buf) - return -ENOMEM; - } else - local_buf = buf; - memcpy(local_buf, txbuf, n_tx); x[0].tx_buf = local_buf; x[1].rx_buf = local_buf + n_tx; |