]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/spi/spi.c
Merge tag 'spi-for-linus' of git://git.secretlab.ca/git/linux-2.6
[karo-tx-linux.git] / drivers / spi / spi.c
index 718cc1f49230dded795bc309b231d957ec9c7068..ab095acdb2a8c17e1945652a3dd647ef7cef468a 100644 (file)
@@ -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;