]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/spi/spi-bcm2835.c
spi: bcm2835: Drop dma_pending flag
[linux.git] / drivers / spi / spi-bcm2835.c
index 6f243a90c844d5078faeb442fb620e6ef37e750e..60255ac837f549918ce63769deefd9a0ad8e2334 100644 (file)
@@ -25,7 +25,9 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h> /* FIXME: using chip internals */
+#include <linux/gpio/driver.h> /* FIXME: using chip internals */
 #include <linux/of_irq.h>
 #include <linux/spi/spi.h>
 
@@ -92,7 +94,6 @@ MODULE_PARM_DESC(polling_limit_us,
  * @rx_prologue: bytes received without DMA if first RX sglist entry's
  *     length is not a multiple of 4 (to overcome hardware limitation)
  * @tx_spillover: whether @tx_prologue spills over to second TX sglist entry
- * @dma_pending: whether a DMA transfer is in progress
  * @debugfs_dir: the debugfs directory - neede to remove debugfs when
  *      unloading the module
  * @count_transfer_polling: count of how often polling mode is used
@@ -115,7 +116,6 @@ struct bcm2835_spi {
        int tx_prologue;
        int rx_prologue;
        unsigned int tx_spillover;
-       unsigned int dma_pending;
 
        struct dentry *debugfs_dir;
        u64 count_transfer_polling;
@@ -539,6 +539,8 @@ static void bcm2835_spi_undo_prologue(struct bcm2835_spi *bs)
                sg_dma_address(&tfr->tx_sg.sgl[1]) -= 4;
                sg_dma_len(&tfr->tx_sg.sgl[1])     += 4;
        }
+
+       bs->tx_prologue = 0;
 }
 
 static void bcm2835_spi_dma_done(void *data)
@@ -554,10 +556,8 @@ static void bcm2835_spi_dma_done(void *data)
         * is called the tx-dma must have finished - can't get to this
         * situation otherwise...
         */
-       if (cmpxchg(&bs->dma_pending, true, false)) {
-               dmaengine_terminate_async(ctlr->dma_tx);
-               bcm2835_spi_undo_prologue(bs);
-       }
+       dmaengine_terminate_async(ctlr->dma_tx);
+       bcm2835_spi_undo_prologue(bs);
 
        /* and mark as completed */;
        complete(&ctlr->xfer_completion);
@@ -632,9 +632,6 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
        /* start TX early */
        dma_async_issue_pending(ctlr->dma_tx);
 
-       /* mark as dma pending */
-       bs->dma_pending = 1;
-
        /* set the DMA length */
        bcm2835_wr(bs, BCM2835_SPI_DLEN, bs->tx_len);
 
@@ -650,7 +647,6 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
        if (ret) {
                /* need to reset on errors */
                dmaengine_terminate_sync(ctlr->dma_tx);
-               bs->dma_pending = false;
                goto err_reset_hw;
        }
 
@@ -834,7 +830,8 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
        bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv);
 
        /* handle all the 3-wire mode */
-       if ((spi->mode & SPI_3WIRE) && (tfr->rx_buf))
+       if (spi->mode & SPI_3WIRE && tfr->rx_buf &&
+           tfr->rx_buf != ctlr->dummy_rx)
                cs |= BCM2835_SPI_CS_REN;
        else
                cs &= ~BCM2835_SPI_CS_REN;
@@ -914,11 +911,10 @@ static void bcm2835_spi_handle_err(struct spi_controller *ctlr,
        struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
 
        /* if an error occurred and we have an active dma, then terminate */
-       if (cmpxchg(&bs->dma_pending, true, false)) {
-               dmaengine_terminate_sync(ctlr->dma_tx);
-               dmaengine_terminate_sync(ctlr->dma_rx);
-               bcm2835_spi_undo_prologue(bs);
-       }
+       dmaengine_terminate_sync(ctlr->dma_tx);
+       dmaengine_terminate_sync(ctlr->dma_rx);
+       bcm2835_spi_undo_prologue(bs);
+
        /* and reset */
        bcm2835_spi_reset_hw(ctlr);
 }
@@ -930,14 +926,19 @@ static int chip_match_name(struct gpio_chip *chip, void *data)
 
 static int bcm2835_spi_setup(struct spi_device *spi)
 {
-       int err;
        struct gpio_chip *chip;
+       enum gpio_lookup_flags lflags;
+
        /*
         * sanity checking the native-chipselects
         */
        if (spi->mode & SPI_NO_CS)
                return 0;
-       if (gpio_is_valid(spi->cs_gpio))
+       /*
+        * The SPI core has successfully requested the CS GPIO line from the
+        * device tree, so we are done.
+        */
+       if (spi->cs_gpiod)
                return 0;
        if (spi->chip_select > 1) {
                /* error in the case of native CS requested with CS > 1
@@ -948,29 +949,43 @@ static int bcm2835_spi_setup(struct spi_device *spi)
                        "setup: only two native chip-selects are supported\n");
                return -EINVAL;
        }
-       /* now translate native cs to GPIO */
+
+       /*
+        * Translate native CS to GPIO
+        *
+        * FIXME: poking around in the gpiolib internals like this is
+        * not very good practice. Find a way to locate the real problem
+        * and fix it. Why is the GPIO descriptor in spi->cs_gpiod
+        * sometimes not assigned correctly? Erroneous device trees?
+        */
 
        /* get the gpio chip for the base */
        chip = gpiochip_find("pinctrl-bcm2835", chip_match_name);
        if (!chip)
                return 0;
 
-       /* and calculate the real CS */
-       spi->cs_gpio = chip->base + 8 - spi->chip_select;
+       /*
+        * Retrieve the corresponding GPIO line used for CS.
+        * The inversion semantics will be handled by the GPIO core
+        * code, so we pass GPIOS_OUT_LOW for "unasserted" and
+        * the correct flag for inversion semantics. The SPI_CS_HIGH
+        * on spi->mode cannot be checked for polarity in this case
+        * as the flag use_gpio_descriptors enforces SPI_CS_HIGH.
+        */
+       if (of_property_read_bool(spi->dev.of_node, "spi-cs-high"))
+               lflags = GPIO_ACTIVE_HIGH;
+       else
+               lflags = GPIO_ACTIVE_LOW;
+       spi->cs_gpiod = gpiochip_request_own_desc(chip, 8 - spi->chip_select,
+                                                 DRV_NAME,
+                                                 lflags,
+                                                 GPIOD_OUT_LOW);
+       if (IS_ERR(spi->cs_gpiod))
+               return PTR_ERR(spi->cs_gpiod);
 
        /* and set up the "mode" and level */
-       dev_info(&spi->dev, "setting up native-CS%i as GPIO %i\n",
-                spi->chip_select, spi->cs_gpio);
-
-       /* set up GPIO as output and pull to the correct level */
-       err = gpio_direction_output(spi->cs_gpio,
-                                   (spi->mode & SPI_CS_HIGH) ? 0 : 1);
-       if (err) {
-               dev_err(&spi->dev,
-                       "could not set CS%i gpio %i as output: %i",
-                       spi->chip_select, spi->cs_gpio, err);
-               return err;
-       }
+       dev_info(&spi->dev, "setting up native-CS%i to use GPIO\n",
+                spi->chip_select);
 
        return 0;
 }
@@ -979,7 +994,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
 {
        struct spi_controller *ctlr;
        struct bcm2835_spi *bs;
-       struct resource *res;
        int err;
 
        ctlr = spi_alloc_master(&pdev->dev, sizeof(*bs));
@@ -988,6 +1002,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, ctlr);
 
+       ctlr->use_gpio_descriptors = true;
        ctlr->mode_bits = BCM2835_SPI_MODE_BITS;
        ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
        ctlr->num_chipselect = 3;
@@ -999,8 +1014,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
 
        bs = spi_controller_get_devdata(ctlr);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       bs->regs = devm_ioremap_resource(&pdev->dev, res);
+       bs->regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(bs->regs)) {
                err = PTR_ERR(bs->regs);
                goto out_controller_put;
@@ -1015,7 +1029,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
 
        bs->irq = platform_get_irq(pdev, 0);
        if (bs->irq <= 0) {
-               dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq);
                err = bs->irq ? bs->irq : -ENODEV;
                goto out_controller_put;
        }