aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2015-05-15 13:57:06 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2015-05-15 13:57:06 +1000
commit2f46f82a399b887809645d177726c3d882229a7d (patch)
tree1e4d1f635e04b819db118ee22d5a30e097243ddc
parent44b0421ba5571b2f38cd2d60d703f1bd8e63010d (diff)
parent17258abbb56b31dfbe2b9839125149b98c5bdcf7 (diff)
Merge remote-tracking branch 'spi/for-next'
-rw-r--r--Documentation/devicetree/bindings/spi/spi-ath79.txt24
-rw-r--r--Documentation/devicetree/bindings/spi/spi_pl022.txt2
-rw-r--r--arch/mips/include/asm/mach-ath79/ath79_spi_platform.h4
-rw-r--r--drivers/spi/Kconfig11
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi-ath79.c34
-rw-r--r--drivers/spi/spi-bcm2835.c392
-rw-r--r--drivers/spi/spi-fsl-dspi.c2
-rw-r--r--drivers/spi/spi-imx.c2
-rw-r--r--drivers/spi/spi-omap2-mcspi.c267
-rw-r--r--drivers/spi/spi-rb4xx.c210
-rw-r--r--drivers/spi/spi-rspi.c15
-rw-r--r--drivers/spi/spi-s3c64xx.c2
-rw-r--r--drivers/spi/spi-sh-msiof.c2
-rw-r--r--drivers/spi/spi-sirf.c65
-rw-r--r--drivers/spi/spi.c11
-rw-r--r--drivers/spi/spidev.c33
17 files changed, 808 insertions, 269 deletions
diff --git a/Documentation/devicetree/bindings/spi/spi-ath79.txt b/Documentation/devicetree/bindings/spi/spi-ath79.txt
new file mode 100644
index 000000000000..f1ad9c367532
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-ath79.txt
@@ -0,0 +1,24 @@
+Binding for Qualcomm Atheros AR7xxx/AR9xxx SPI controller
+
+Required properties:
+- compatible: has to be "qca,<soc-type>-spi", "qca,ar7100-spi" as fallback.
+- reg: Base address and size of the controllers memory area
+- clocks: phandle to the AHB clock.
+- clock-names: has to be "ahb".
+- #address-cells: <1>, as required by generic SPI binding.
+- #size-cells: <0>, also as required by generic SPI binding.
+
+Child nodes as per the generic SPI binding.
+
+Example:
+
+ spi@1F000000 {
+ compatible = "qca,ar9132-spi", "qca,ar7100-spi";
+ reg = <0x1F000000 0x10>;
+
+ clocks = <&pll 2>;
+ clock-names = "ahb";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/spi/spi_pl022.txt b/Documentation/devicetree/bindings/spi/spi_pl022.txt
index 22ed6797216d..4d1673ca8cf8 100644
--- a/Documentation/devicetree/bindings/spi/spi_pl022.txt
+++ b/Documentation/devicetree/bindings/spi/spi_pl022.txt
@@ -4,9 +4,9 @@ Required properties:
- compatible : "arm,pl022", "arm,primecell"
- reg : Offset and length of the register set for the device
- interrupts : Should contain SPI controller interrupt
+- num-cs : total number of chipselects
Optional properties:
-- num-cs : total number of chipselects
- cs-gpios : should specify GPIOs used for chipselects.
The gpios will be referred to as reg = <index> in the SPI child nodes.
If unspecified, a single SPI device without a chip select can be used.
diff --git a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
index aa2283e602fc..aa71216edf99 100644
--- a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
+++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
@@ -16,8 +16,4 @@ struct ath79_spi_platform_data {
unsigned num_chipselect;
};
-struct ath79_spi_controller_data {
- unsigned gpio;
-};
-
#endif /* _ATH79_SPI_PLATFORM_H */
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 72b059081559..5bd7811844ff 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -77,6 +77,7 @@ config SPI_ATMEL
config SPI_BCM2835
tristate "BCM2835 SPI controller"
+ depends on GPIOLIB
depends on ARCH_BCM2835 || COMPILE_TEST
depends on GPIOLIB
help
@@ -221,7 +222,7 @@ config SPI_FALCON
config SPI_GPIO
tristate "GPIO-based bitbanging SPI Master"
- depends on GPIOLIB
+ depends on GPIOLIB || COMPILE_TEST
select SPI_BITBANG
help
This simple GPIO bitbanging SPI master uses the arch-neutral GPIO
@@ -327,7 +328,7 @@ config SPI_MESON_SPIFC
config SPI_OC_TINY
tristate "OpenCores tiny SPI"
- depends on GPIOLIB
+ depends on GPIOLIB || COMPILE_TEST
select SPI_BITBANG
help
This is the driver for OpenCores tiny SPI master controller.
@@ -429,6 +430,12 @@ config SPI_ROCKCHIP
The main usecase of this controller is to use spi flash as boot
device.
+config SPI_RB4XX
+ tristate "Mikrotik RB4XX SPI master"
+ depends on SPI_MASTER && ATH79
+ help
+ SPI controller driver for the Mikrotik RB4xx series boards.
+
config SPI_RSPI
tristate "Renesas RSPI/QSPI controller"
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index d8cbf654976b..0218f39de7d2 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
+obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
spi-s3c24xx-hw-y := spi-s3c24xx.o
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index b02eb4ac0218..bf1f9b32c597 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -79,10 +79,8 @@ static void ath79_spi_chipselect(struct spi_device *spi, int is_active)
}
if (spi->chip_select) {
- struct ath79_spi_controller_data *cdata = spi->controller_data;
-
/* SPI is normally active-low */
- gpio_set_value(cdata->gpio, cs_high);
+ gpio_set_value(spi->cs_gpio, cs_high);
} else {
if (cs_high)
sp->ioc_base |= AR71XX_SPI_IOC_CS0;
@@ -117,11 +115,10 @@ static void ath79_spi_disable(struct ath79_spi *sp)
static int ath79_spi_setup_cs(struct spi_device *spi)
{
- struct ath79_spi_controller_data *cdata;
+ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
int status;
- cdata = spi->controller_data;
- if (spi->chip_select && !cdata)
+ if (spi->chip_select && !gpio_is_valid(spi->cs_gpio))
return -EINVAL;
status = 0;
@@ -134,8 +131,15 @@ static int ath79_spi_setup_cs(struct spi_device *spi)
else
flags |= GPIOF_INIT_HIGH;
- status = gpio_request_one(cdata->gpio, flags,
+ status = gpio_request_one(spi->cs_gpio, flags,
dev_name(&spi->dev));
+ } else {
+ if (spi->mode & SPI_CS_HIGH)
+ sp->ioc_base &= ~AR71XX_SPI_IOC_CS0;
+ else
+ sp->ioc_base |= AR71XX_SPI_IOC_CS0;
+
+ ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
}
return status;
@@ -144,8 +148,7 @@ static int ath79_spi_setup_cs(struct spi_device *spi)
static void ath79_spi_cleanup_cs(struct spi_device *spi)
{
if (spi->chip_select) {
- struct ath79_spi_controller_data *cdata = spi->controller_data;
- gpio_free(cdata->gpio);
+ gpio_free(spi->cs_gpio);
}
}
@@ -217,6 +220,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
}
sp = spi_master_get_devdata(master);
+ master->dev.of_node = pdev->dev.of_node;
platform_set_drvdata(pdev, sp);
pdata = dev_get_platdata(&pdev->dev);
@@ -253,7 +257,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
goto err_put_master;
}
- ret = clk_enable(sp->clk);
+ ret = clk_prepare_enable(sp->clk);
if (ret)
goto err_put_master;
@@ -277,7 +281,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
err_disable:
ath79_spi_disable(sp);
err_clk_disable:
- clk_disable(sp->clk);
+ clk_disable_unprepare(sp->clk);
err_put_master:
spi_master_put(sp->bitbang.master);
@@ -290,7 +294,7 @@ static int ath79_spi_remove(struct platform_device *pdev)
spi_bitbang_stop(&sp->bitbang);
ath79_spi_disable(sp);
- clk_disable(sp->clk);
+ clk_disable_unprepare(sp->clk);
spi_master_put(sp->bitbang.master);
return 0;
@@ -301,12 +305,18 @@ static void ath79_spi_shutdown(struct platform_device *pdev)
ath79_spi_remove(pdev);
}
+static const struct of_device_id ath79_spi_of_match[] = {
+ { .compatible = "qca,ar7100-spi", },
+ { },
+};
+
static struct platform_driver ath79_spi_driver = {
.probe = ath79_spi_probe,
.remove = ath79_spi_remove,
.shutdown = ath79_spi_shutdown,
.driver = {
.name = DRV_NAME,
+ .of_match_table = ath79_spi_of_match,
},
};
module_platform_driver(ath79_spi_driver);
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 37875cf942f7..59705ab23577 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -20,18 +20,22 @@
* GNU General Public License for more details.
*/
+#include <asm/page.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/of_gpio.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
#include <linux/spi/spi.h>
/* SPI register offsets */
@@ -69,7 +73,8 @@
#define BCM2835_SPI_CS_CS_01 0x00000001
#define BCM2835_SPI_POLLING_LIMIT_US 30
-#define BCM2835_SPI_TIMEOUT_MS 30000
+#define BCM2835_SPI_POLLING_JIFFIES 2
+#define BCM2835_SPI_DMA_MIN_LENGTH 96
#define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
| SPI_NO_CS | SPI_3WIRE)
@@ -83,6 +88,7 @@ struct bcm2835_spi {
u8 *rx_buf;
int tx_len;
int rx_len;
+ bool dma_pending;
};
static inline u32 bcm2835_rd(struct bcm2835_spi *bs, unsigned reg)
@@ -128,12 +134,15 @@ static void bcm2835_spi_reset_hw(struct spi_master *master)
/* Disable SPI interrupts and transfer */
cs &= ~(BCM2835_SPI_CS_INTR |
BCM2835_SPI_CS_INTD |
+ BCM2835_SPI_CS_DMAEN |
BCM2835_SPI_CS_TA);
/* and reset RX/TX FIFOS */
cs |= BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX;
/* and reset the SPI_HW */
bcm2835_wr(bs, BCM2835_SPI_CS, cs);
+ /* as well as DLEN */
+ bcm2835_wr(bs, BCM2835_SPI_DLEN, 0);
}
static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
@@ -157,42 +166,6 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
- struct spi_device *spi,
- struct spi_transfer *tfr,
- u32 cs,
- unsigned long xfer_time_us)
-{
- struct bcm2835_spi *bs = spi_master_get_devdata(master);
- /* set timeout to 1 second of maximum polling */
- unsigned long timeout = jiffies + HZ;
-
- /* enable HW block without interrupts */
- bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA);
-
- /* loop until finished the transfer */
- while (bs->rx_len) {
- /* read from fifo as much as possible */
- bcm2835_rd_fifo(bs);
- /* fill in tx fifo as much as possible */
- bcm2835_wr_fifo(bs);
- /* if we still expect some data after the read,
- * check for a possible timeout
- */
- if (bs->rx_len && time_after(jiffies, timeout)) {
- /* Transfer complete - reset SPI HW */
- bcm2835_spi_reset_hw(master);
- /* and return timeout */
- return -ETIMEDOUT;
- }
- }
-
- /* Transfer complete - reset SPI HW */
- bcm2835_spi_reset_hw(master);
- /* and return without waiting for completion */
- return 0;
-}
-
static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *tfr,
@@ -229,6 +202,329 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
return 1;
}
+/*
+ * DMA support
+ *
+ * this implementation has currently a few issues in so far as it does
+ * not work arrount limitations of the HW.
+ *
+ * the main one being that DMA transfers are limited to 16 bit
+ * (so 0 to 65535 bytes) by the SPI HW due to BCM2835_SPI_DLEN
+ *
+ * also we currently assume that the scatter-gather fragments are
+ * all multiple of 4 (except the last) - otherwise we would need
+ * to reset the FIFO before subsequent transfers...
+ * this also means that tx/rx transfers sg's need to be of equal size!
+ *
+ * there may be a few more border-cases we may need to address as well
+ * but unfortunately this would mean splitting up the scatter-gather
+ * list making it slightly unpractical...
+ */
+static void bcm2835_spi_dma_done(void *data)
+{
+ struct spi_master *master = data;
+ struct bcm2835_spi *bs = spi_master_get_devdata(master);
+
+ /* reset fifo and HW */
+ bcm2835_spi_reset_hw(master);
+
+ /* and terminate tx-dma as we do not have an irq for it
+ * because when the rx dma will terminate and this callback
+ * is called the tx-dma must have finished - can't get to this
+ * situation otherwise...
+ */
+ dmaengine_terminate_all(master->dma_tx);
+
+ /* mark as no longer pending */
+ bs->dma_pending = 0;
+
+ /* and mark as completed */;
+ complete(&master->xfer_completion);
+}
+
+static int bcm2835_spi_prepare_sg(struct spi_master *master,
+ struct spi_transfer *tfr,
+ bool is_tx)
+{
+ struct dma_chan *chan;
+ struct scatterlist *sgl;
+ unsigned int nents;
+ enum dma_transfer_direction dir;
+ unsigned long flags;
+
+ struct dma_async_tx_descriptor *desc;
+ dma_cookie_t cookie;
+
+ if (is_tx) {
+ dir = DMA_MEM_TO_DEV;
+ chan = master->dma_tx;
+ nents = tfr->tx_sg.nents;
+ sgl = tfr->tx_sg.sgl;
+ flags = 0 /* no tx interrupt */;
+
+ } else {
+ dir = DMA_DEV_TO_MEM;
+ chan = master->dma_rx;
+ nents = tfr->rx_sg.nents;
+ sgl = tfr->rx_sg.sgl;
+ flags = DMA_PREP_INTERRUPT;
+ }
+ /* prepare the channel */
+ desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
+ if (!desc)
+ return -EINVAL;
+
+ /* set callback for rx */
+ if (!is_tx) {
+ desc->callback = bcm2835_spi_dma_done;
+ desc->callback_param = master;
+ }
+
+ /* submit it to DMA-engine */
+ cookie = dmaengine_submit(desc);
+
+ return dma_submit_error(cookie);
+}
+
+static inline int bcm2835_check_sg_length(struct sg_table *sgt)
+{
+ int i;
+ struct scatterlist *sgl;
+
+ /* check that the sg entries are word-sized (except for last) */
+ for_each_sg(sgt->sgl, sgl, (int)sgt->nents - 1, i) {
+ if (sg_dma_len(sgl) % 4)
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int bcm2835_spi_transfer_one_dma(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr,
+ u32 cs)
+{
+ struct bcm2835_spi *bs = spi_master_get_devdata(master);
+ int ret;
+
+ /* check that the scatter gather segments are all a multiple of 4 */
+ if (bcm2835_check_sg_length(&tfr->tx_sg) ||
+ bcm2835_check_sg_length(&tfr->rx_sg)) {
+ dev_warn_once(&spi->dev,
+ "scatter gather segment length is not a multiple of 4 - falling back to interrupt mode\n");
+ return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs);
+ }
+
+ /* setup tx-DMA */
+ ret = bcm2835_spi_prepare_sg(master, tfr, true);
+ if (ret)
+ return ret;
+
+ /* start TX early */
+ dma_async_issue_pending(master->dma_tx);
+
+ /* mark as dma pending */
+ bs->dma_pending = 1;
+
+ /* set the DMA length */
+ bcm2835_wr(bs, BCM2835_SPI_DLEN, tfr->len);
+
+ /* start the HW */
+ bcm2835_wr(bs, BCM2835_SPI_CS,
+ cs | BCM2835_SPI_CS_TA | BCM2835_SPI_CS_DMAEN);
+
+ /* setup rx-DMA late - to run transfers while
+ * mapping of the rx buffers still takes place
+ * this saves 10us or more.
+ */
+ ret = bcm2835_spi_prepare_sg(master, tfr, false);
+ if (ret) {
+ /* need to reset on errors */
+ dmaengine_terminate_all(master->dma_tx);
+ bcm2835_spi_reset_hw(master);
+ return ret;
+ }
+
+ /* start rx dma late */
+ dma_async_issue_pending(master->dma_rx);
+
+ /* wait for wakeup in framework */
+ return 1;
+}
+
+static bool bcm2835_spi_can_dma(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ /* only run for gpio_cs */
+ if (!gpio_is_valid(spi->cs_gpio))
+ return false;
+
+ /* we start DMA efforts only on bigger transfers */
+ if (tfr->len < BCM2835_SPI_DMA_MIN_LENGTH)
+ return false;
+
+ /* BCM2835_SPI_DLEN has defined a max transfer size as
+ * 16 bit, so max is 65535
+ * we can revisit this by using an alternative transfer
+ * method - ideally this would get done without any more
+ * interaction...
+ */
+ if (tfr->len > 65535) {
+ dev_warn_once(&spi->dev,
+ "transfer size of %d too big for dma-transfer\n",
+ tfr->len);
+ return false;
+ }
+
+ /* if we run rx/tx_buf with word aligned addresses then we are OK */
+ if ((((size_t)tfr->rx_buf & 3) == 0) &&
+ (((size_t)tfr->tx_buf & 3) == 0))
+ return true;
+
+ /* otherwise we only allow transfers within the same page
+ * to avoid wasting time on dma_mapping when it is not practical
+ */
+ if (((size_t)tfr->tx_buf & PAGE_MASK) + tfr->len > PAGE_SIZE) {
+ dev_warn_once(&spi->dev,
+ "Unaligned spi tx-transfer bridging page\n");
+ return false;
+ }
+ if (((size_t)tfr->rx_buf & PAGE_MASK) + tfr->len > PAGE_SIZE) {
+ dev_warn_once(&spi->dev,
+ "Unaligned spi tx-transfer bridging page\n");
+ return false;
+ }
+
+ /* return OK */
+ return true;
+}
+
+static void bcm2835_dma_release(struct spi_master *master)
+{
+ if (master->dma_tx) {
+ dmaengine_terminate_all(master->dma_tx);
+ dma_release_channel(master->dma_tx);
+ master->dma_tx = NULL;
+ }
+ if (master->dma_rx) {
+ dmaengine_terminate_all(master->dma_rx);
+ dma_release_channel(master->dma_rx);
+ master->dma_rx = NULL;
+ }
+}
+
+static void bcm2835_dma_init(struct spi_master *master, struct device *dev)
+{
+ struct dma_slave_config slave_config;
+ const __be32 *addr;
+ dma_addr_t dma_reg_base;
+ int ret;
+
+ /* base address in dma-space */
+ addr = of_get_address(master->dev.of_node, 0, NULL, NULL);
+ if (!addr) {
+ dev_err(dev, "could not get DMA-register address - not using dma mode\n");
+ goto err;
+ }
+ dma_reg_base = be32_to_cpup(addr);
+
+ /* get tx/rx dma */
+ master->dma_tx = dma_request_slave_channel(dev, "tx");
+ if (!master->dma_tx) {
+ dev_err(dev, "no tx-dma configuration found - not using dma mode\n");
+ goto err;
+ }
+ master->dma_rx = dma_request_slave_channel(dev, "rx");
+ if (!master->dma_rx) {
+ dev_err(dev, "no rx-dma configuration found - not using dma mode\n");
+ goto err_release;
+ }
+
+ /* configure DMAs */
+ slave_config.direction = DMA_MEM_TO_DEV;
+ slave_config.dst_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO);
+ slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+ ret = dmaengine_slave_config(master->dma_tx, &slave_config);
+ if (ret)
+ goto err_config;
+
+ slave_config.direction = DMA_DEV_TO_MEM;
+ slave_config.src_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO);
+ slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+ ret = dmaengine_slave_config(master->dma_rx, &slave_config);
+ if (ret)
+ goto err_config;
+
+ /* all went well, so set can_dma */
+ master->can_dma = bcm2835_spi_can_dma;
+ master->max_dma_len = 65535; /* limitation by BCM2835_SPI_DLEN */
+ /* need to do TX AND RX DMA, so we need dummy buffers */
+ master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX;
+
+ return;
+
+err_config:
+ dev_err(dev, "issue configuring dma: %d - not using DMA mode\n",
+ ret);
+err_release:
+ bcm2835_dma_release(master);
+err:
+ return;
+}
+
+static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr,
+ u32 cs,
+ unsigned long xfer_time_us)
+{
+ struct bcm2835_spi *bs = spi_master_get_devdata(master);
+ unsigned long timeout;
+
+ /* enable HW block without interrupts */
+ bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA);
+
+ /* fill in the fifo before timeout calculations
+ * if we are interrupted here, then the data is
+ * getting transferred by the HW while we are interrupted
+ */
+ bcm2835_wr_fifo(bs);
+
+ /* set the timeout */
+ timeout = jiffies + BCM2835_SPI_POLLING_JIFFIES;
+
+ /* loop until finished the transfer */
+ while (bs->rx_len) {
+ /* fill in tx fifo with remaining data */
+ bcm2835_wr_fifo(bs);
+
+ /* read from fifo as much as possible */
+ bcm2835_rd_fifo(bs);
+
+ /* if there is still data pending to read
+ * then check the timeout
+ */
+ if (bs->rx_len && time_after(jiffies, timeout)) {
+ dev_dbg_ratelimited(&spi->dev,
+ "timeout period reached: jiffies: %lu remaining tx/rx: %d/%d - falling back to interrupt mode\n",
+ jiffies - timeout,
+ bs->tx_len, bs->rx_len);
+ /* fall back to interrupt mode */
+ return bcm2835_spi_transfer_one_irq(master, spi,
+ tfr, cs);
+ }
+ }
+
+ /* Transfer complete - reset SPI HW */
+ bcm2835_spi_reset_hw(master);
+ /* and return without waiting for completion */
+ return 0;
+}
+
static int bcm2835_spi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *tfr)
@@ -288,12 +584,26 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
return bcm2835_spi_transfer_one_poll(master, spi, tfr,
cs, xfer_time_us);
+ /* run in dma mode if conditions are right */
+ if (master->can_dma && bcm2835_spi_can_dma(master, spi, tfr))
+ return bcm2835_spi_transfer_one_dma(master, spi, tfr, cs);
+
+ /* run in interrupt-mode */
return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs);
}
static void bcm2835_spi_handle_err(struct spi_master *master,
struct spi_message *msg)
{
+ struct bcm2835_spi *bs = spi_master_get_devdata(master);
+
+ /* if an error occurred and we have an active dma, then terminate */
+ if (bs->dma_pending) {
+ dmaengine_terminate_all(master->dma_tx);
+ dmaengine_terminate_all(master->dma_rx);
+ bs->dma_pending = 0;
+ }
+ /* and reset */
bcm2835_spi_reset_hw(master);
}
@@ -463,6 +773,8 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
goto out_clk_disable;
}
+ bcm2835_dma_init(master, &pdev->dev);
+
/* initialise the hardware with the default polarities */
bcm2835_wr(bs, BCM2835_SPI_CS,
BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
@@ -493,6 +805,8 @@ static int bcm2835_spi_remove(struct platform_device *pdev)
clk_disable_unprepare(bs->clk);
+ bcm2835_dma_release(master);
+
return 0;
}
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 5fe54cda309f..ed0475d83e50 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -566,7 +566,7 @@ static int dspi_probe(struct platform_device *pdev)
goto out_master_put;
}
- dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base,
+ dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
&dspi_regmap_config);
if (IS_ERR(dspi->regmap)) {
dev_err(&pdev->dev, "failed to init regmap: %ld\n",
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index f08e812b2984..eb7d3a6fb14c 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -674,7 +674,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
.devtype = IMX51_ECSPI,
};
-static struct platform_device_id spi_imx_devtype[] = {
+static const struct platform_device_id spi_imx_devtype[] = {
{
.name = "imx1-cspi",
.driver_data = (kernel_ulong_t) &imx1_cspi_devtype_data,
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index d1a5b9fc3eba..a7d85c5ab2fa 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -35,6 +35,7 @@
#include <linux/gcd.h>
#include <linux/spi/spi.h>
+#include <linux/gpio.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
@@ -242,17 +243,20 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
}
-static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
+static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
{
u32 l;
- l = mcspi_cached_chconf0(spi);
- if (cs_active)
- l |= OMAP2_MCSPI_CHCONF_FORCE;
- else
- l &= ~OMAP2_MCSPI_CHCONF_FORCE;
+ if (spi->controller_state) {
+ l = mcspi_cached_chconf0(spi);
- mcspi_write_chconf0(spi, l);
+ if (enable)
+ l &= ~OMAP2_MCSPI_CHCONF_FORCE;
+ else
+ l |= OMAP2_MCSPI_CHCONF_FORCE;
+
+ mcspi_write_chconf0(spi, l);
+ }
}
static void omap2_mcspi_set_master_mode(struct spi_master *master)
@@ -1011,6 +1015,12 @@ static int omap2_mcspi_setup(struct spi_device *spi)
return ret;
}
+ if (gpio_is_valid(spi->cs_gpio)) {
+ if (gpio_request(spi->cs_gpio, dev_name(&spi->dev)) == 0)
+ gpio_direction_output(spi->cs_gpio,
+ !(spi->mode & SPI_CS_HIGH));
+ }
+
ret = pm_runtime_get_sync(mcspi->dev);
if (ret < 0)
return ret;
@@ -1050,9 +1060,13 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
mcspi_dma->dma_tx = NULL;
}
}
+
+ if (gpio_is_valid(spi->cs_gpio))
+ gpio_free(spi->cs_gpio);
}
-static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
+static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
+ struct spi_device *spi, struct spi_transfer *t)
{
/* We only enable one channel at a time -- the one whose message is
@@ -1062,18 +1076,14 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
* chipselect with the FORCE bit ... CS != channel enable.
*/
- struct spi_device *spi;
- struct spi_transfer *t = NULL;
struct spi_master *master;
struct omap2_mcspi_dma *mcspi_dma;
- int cs_active = 0;
struct omap2_mcspi_cs *cs;
struct omap2_mcspi_device_config *cd;
int par_override = 0;
int status = 0;
u32 chconf;
- spi = m->spi;
master = spi->master;
mcspi_dma = mcspi->dma_channels + spi->chip_select;
cs = spi->controller_state;
@@ -1090,103 +1100,84 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
par_override = 1;
omap2_mcspi_set_enable(spi, 0);
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
- status = -EINVAL;
- break;
- }
- if (par_override ||
- (t->speed_hz != spi->max_speed_hz) ||
- (t->bits_per_word != spi->bits_per_word)) {
- par_override = 1;
- status = omap2_mcspi_setup_transfer(spi, t);
- if (status < 0)
- break;
- if (t->speed_hz == spi->max_speed_hz &&
- t->bits_per_word == spi->bits_per_word)
- par_override = 0;
- }
- if (cd && cd->cs_per_word) {
- chconf = mcspi->ctx.modulctrl;
- chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
- mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
- mcspi->ctx.modulctrl =
- mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
- }
-
- if (!cs_active) {
- omap2_mcspi_force_cs(spi, 1);
- cs_active = 1;
- }
-
- chconf = mcspi_cached_chconf0(spi);
- chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
- chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
+ if (par_override ||
+ (t->speed_hz != spi->max_speed_hz) ||
+ (t->bits_per_word != spi->bits_per_word)) {
+ par_override = 1;
+ status = omap2_mcspi_setup_transfer(spi, t);
+ if (status < 0)
+ goto out;
+ if (t->speed_hz == spi->max_speed_hz &&
+ t->bits_per_word == spi->bits_per_word)
+ par_override = 0;
+ }
+ if (cd && cd->cs_per_word) {
+ chconf = mcspi->ctx.modulctrl;
+ chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
+ mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
+ mcspi->ctx.modulctrl =
+ mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
+ }
- if (t->tx_buf == NULL)
- chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
- else if (t->rx_buf == NULL)
- chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
-
- if (cd && cd->turbo_mode && t->tx_buf == NULL) {
- /* Turbo mode is for more than one word */
- if (t->len > ((cs->word_len + 7) >> 3))
- chconf |= OMAP2_MCSPI_CHCONF_TURBO;
- }
+ chconf = mcspi_cached_chconf0(spi);
+ chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
+ chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
+
+ if (t->tx_buf == NULL)
+ chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
+ else if (t->rx_buf == NULL)
+ chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
+
+ if (cd && cd->turbo_mode && t->tx_buf == NULL) {
+ /* Turbo mode is for more than one word */
+ if (t->len > ((cs->word_len + 7) >> 3))
+ chconf |= OMAP2_MCSPI_CHCONF_TURBO;
+ }
- mcspi_write_chconf0(spi, chconf);
+ mcspi_write_chconf0(spi, chconf);
- if (t->len) {
- unsigned count;
+ if (t->len) {
+ unsigned count;
- if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
- (m->is_dma_mapped || t->len >= DMA_MIN_BYTES))
- omap2_mcspi_set_fifo(spi, t, 1);
+ if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
+ (t->len >= DMA_MIN_BYTES))
+ omap2_mcspi_set_fifo(spi, t, 1);
- omap2_mcspi_set_enable(spi, 1);
+ omap2_mcspi_set_enable(spi, 1);
- /* RX_ONLY mode needs dummy data in TX reg */
- if (t->tx_buf == NULL)
- writel_relaxed(0, cs->base
- + OMAP2_MCSPI_TX0);
+ /* RX_ONLY mode needs dummy data in TX reg */
+ if (t->tx_buf == NULL)
+ writel_relaxed(0, cs->base
+ + OMAP2_MCSPI_TX0);
- if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
- (m->is_dma_mapped || t->len >= DMA_MIN_BYTES))
- count = omap2_mcspi_txrx_dma(spi, t);
- else
- count = omap2_mcspi_txrx_pio(spi, t);
- m->actual_length += count;
+ if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
+ (t->len >= DMA_MIN_BYTES))
+ count = omap2_mcspi_txrx_dma(spi, t);
+ else
+ count = omap2_mcspi_txrx_pio(spi, t);
- if (count != t->len) {
- status = -EIO;
- break;
- }
+ if (count != t->len) {
+ status = -EIO;
+ goto out;
}
+ }
- if (t->delay_usecs)
- udelay(t->delay_usecs);
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
- /* ignore the "leave it on after last xfer" hint */
- if (t->cs_change) {
- omap2_mcspi_force_cs(spi, 0);
- cs_active = 0;
- }
+ omap2_mcspi_set_enable(spi, 0);
- omap2_mcspi_set_enable(spi, 0);
+ if (mcspi->fifo_depth > 0)
+ omap2_mcspi_set_fifo(spi, t, 0);
- if (mcspi->fifo_depth > 0)
- omap2_mcspi_set_fifo(spi, t, 0);
- }
+out:
/* Restore defaults if they were overriden */
if (par_override) {
par_override = 0;
status = omap2_mcspi_setup_transfer(spi, NULL);
}
- if (cs_active)
- omap2_mcspi_force_cs(spi, 0);
-
if (cd && cd->cs_per_word) {
chconf = mcspi->ctx.modulctrl;
chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE;
@@ -1200,75 +1191,58 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
if (mcspi->fifo_depth > 0 && t)
omap2_mcspi_set_fifo(spi, t, 0);
- m->status = status;
+ return status;
}
-static int omap2_mcspi_transfer_one_message(struct spi_master *master,
- struct spi_message *m)
+static int omap2_mcspi_transfer_one(struct spi_master *master,
+ struct spi_device *spi, struct spi_transfer *t)
{
- struct spi_device *spi;
struct omap2_mcspi *mcspi;
struct omap2_mcspi_dma *mcspi_dma;
- struct spi_transfer *t;
- int status;
+ const void *tx_buf = t->tx_buf;
+ void *rx_buf = t->rx_buf;
+ unsigned len = t->len;
- spi = m->spi;
mcspi = spi_master_get_devdata(master);
mcspi_dma = mcspi->dma_channels + spi->chip_select;
- m->actual_length = 0;
- m->status = 0;
-
- list_for_each_entry(t, &m->transfers, transfer_list) {
- const void *tx_buf = t->tx_buf;
- void *rx_buf = t->rx_buf;
- unsigned len = t->len;
-
- if ((len && !(rx_buf || tx_buf))) {
- dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
- t->speed_hz,
- len,
- tx_buf ? "tx" : "",
- rx_buf ? "rx" : "",
- t->bits_per_word);
- status = -EINVAL;
- goto out;
- }
- if (m->is_dma_mapped || len < DMA_MIN_BYTES)
- continue;
-
- if (mcspi_dma->dma_tx && tx_buf != NULL) {
- t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf,
- len, DMA_TO_DEVICE);
- if (dma_mapping_error(mcspi->dev, t->tx_dma)) {
- dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
- 'T', len);
- status = -EINVAL;
- goto out;
- }
+ if ((len && !(rx_buf || tx_buf))) {
+ dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
+ t->speed_hz,
+ len,
+ tx_buf ? "tx" : "",
+ rx_buf ? "rx" : "",
+ t->bits_per_word);
+ return -EINVAL;
+ }
+
+ if (len < DMA_MIN_BYTES)
+ goto skip_dma_map;
+
+ if (mcspi_dma->dma_tx && tx_buf != NULL) {
+ t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf,
+ len, DMA_TO_DEVICE);
+ if (dma_mapping_error(mcspi->dev, t->tx_dma)) {
+ dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
+ 'T', len);
+ return -EINVAL;
}
- if (mcspi_dma->dma_rx && rx_buf != NULL) {
- t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(mcspi->dev, t->rx_dma)) {
- dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
- 'R', len);
- if (tx_buf != NULL)
- dma_unmap_single(mcspi->dev, t->tx_dma,
- len, DMA_TO_DEVICE);
- status = -EINVAL;
- goto out;
- }
+ }
+ if (mcspi_dma->dma_rx && rx_buf != NULL) {
+ t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(mcspi->dev, t->rx_dma)) {
+ dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
+ 'R', len);
+ if (tx_buf != NULL)
+ dma_unmap_single(mcspi->dev, t->tx_dma,
+ len, DMA_TO_DEVICE);
+ return -EINVAL;
}
}
- omap2_mcspi_work(mcspi, m);
- /* spi_finalize_current_message() changes the status inside the
- * spi_message, save the status here. */
- status = m->status;
-out:
- spi_finalize_current_message(master);
- return status;
+skip_dma_map:
+ return omap2_mcspi_work_one(mcspi, spi, t);
}
static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
@@ -1347,7 +1321,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
master->setup = omap2_mcspi_setup;
master->auto_runtime_pm = true;
- master->transfer_one_message = omap2_mcspi_transfer_one_message;
+ master->transfer_one = omap2_mcspi_transfer_one;
+ master->set_cs = omap2_mcspi_set_cs;
master->cleanup = omap2_mcspi_cleanup;
master->dev.of_node = node;
master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;
diff --git a/drivers/spi/spi-rb4xx.c b/drivers/spi/spi-rb4xx.c
new file mode 100644
index 000000000000..3641d0e20135
--- /dev/null
+++ b/drivers/spi/spi-rb4xx.c
@@ -0,0 +1,210 @@
+/*
+ * SPI controller driver for the Mikrotik RB4xx boards
+ *
+ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2015 Bert Vermeulen <bert@biot.com>
+ *
+ * This file was based on the patches for Linux 2.6.27.39 published by
+ * MikroTik for their RouterBoard 4xx series devices.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+struct rb4xx_spi {
+ void __iomem *base;
+ struct clk *clk;
+};
+
+static inline u32 rb4xx_read(struct rb4xx_spi *rbspi, u32 reg)
+{
+ return __raw_readl(rbspi->base + reg);
+}
+
+static inline void rb4xx_write(struct rb4xx_spi *rbspi, u32 reg, u32 value)
+{
+ __raw_writel(value, rbspi->base + reg);
+}
+
+static inline void do_spi_clk(struct rb4xx_spi *rbspi, u32 spi_ioc, int value)
+{
+ u32 regval;
+
+ regval = spi_ioc;
+ if (value & BIT(0))
+ regval |= AR71XX_SPI_IOC_DO;
+
+ rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval);
+ rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK);
+}
+
+static void do_spi_byte(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte)
+{
+ int i;
+
+ for (i = 7; i >= 0; i--)
+ do_spi_clk(rbspi, spi_ioc, byte >> i);
+}
+
+/* The CS2 pin is used to clock in a second bit per clock cycle. */
+static inline void do_spi_clk_two(struct rb4xx_spi *rbspi, u32 spi_ioc,
+ u8 value)
+{
+ u32 regval;
+
+ regval = spi_ioc;
+ if (value & BIT(1))
+ regval |= AR71XX_SPI_IOC_DO;
+ if (value & BIT(0))
+ regval |= AR71XX_SPI_IOC_CS2;
+
+ rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval);
+ rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK);
+}
+
+/* Two bits at a time, msb first */
+static void do_spi_byte_two(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte)
+{
+ do_spi_clk_two(rbspi, spi_ioc, byte >> 6);
+ do_spi_clk_two(rbspi, spi_ioc, byte >> 4);
+ do_spi_clk_two(rbspi, spi_ioc, byte >> 2);
+ do_spi_clk_two(rbspi, spi_ioc, byte >> 0);
+}
+
+static void rb4xx_set_cs(struct spi_device *spi, bool enable)
+{
+ struct rb4xx_spi *rbspi = spi_master_get_devdata(spi->master);
+
+ /*
+ * Setting CS is done along with bitbanging the actual values,
+ * since it's all on the same hardware register. However the
+ * CPLD needs CS deselected after every command.
+ */
+ if (enable)
+ rb4xx_write(rbspi, AR71XX_SPI_REG_IOC,
+ AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1);
+}
+
+static int rb4xx_transfer_one(struct spi_master *master,
+ struct spi_device *spi, struct spi_transfer *t)
+{
+ struct rb4xx_spi *rbspi = spi_master_get_devdata(master);
+ int i;
+ u32 spi_ioc;
+ u8 *rx_buf;
+ const u8 *tx_buf;
+
+ /*
+ * Prime the SPI register with the SPI device selected. The m25p80 boot
+ * flash and CPLD share the CS0 pin. This works because the CPLD's
+ * command set was designed to almost not clash with that of the
+ * boot flash.
+ */
+ if (spi->chip_select == 2)
+ /* MMC */
+ spi_ioc = AR71XX_SPI_IOC_CS0;
+ else
+ /* Boot flash and CPLD */
+ spi_ioc = AR71XX_SPI_IOC_CS1;
+
+ tx_buf = t->tx_buf;
+ rx_buf = t->rx_buf;
+ for (i = 0; i < t->len; ++i) {
+ if (t->tx_nbits == SPI_NBITS_DUAL)
+ /* CPLD can use two-wire transfers */
+ do_spi_byte_two(rbspi, spi_ioc, tx_buf[i]);
+ else
+ do_spi_byte(rbspi, spi_ioc, tx_buf[i]);
+ if (!rx_buf)
+ continue;
+ rx_buf[i] = rb4xx_read(rbspi, AR71XX_SPI_REG_RDS);
+ }
+ spi_finalize_current_transfer(master);
+
+ return 0;
+}
+
+static int rb4xx_spi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct clk *ahb_clk;
+ struct rb4xx_spi *rbspi;
+ struct resource *r;
+ int err;
+ void __iomem *spi_base;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ spi_base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(spi_base))
+ return PTR_ERR(spi_base);
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*rbspi));
+ if (!master)
+ return -ENOMEM;
+
+ ahb_clk = devm_clk_get(&pdev->dev, "ahb");
+ if (IS_ERR(ahb_clk))
+ return PTR_ERR(ahb_clk);
+
+ master->bus_num = 0;
+ master->num_chipselect = 3;
+ master->mode_bits = SPI_TX_DUAL;
+ master->bits_per_word_mask = BIT(7);
+ master->flags = SPI_MASTER_MUST_TX;
+ master->transfer_one = rb4xx_transfer_one;
+ master->set_cs = rb4xx_set_cs;
+
+ err = devm_spi_register_master(&pdev->dev, master);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register SPI master\n");
+ return err;
+ }
+
+ err = clk_prepare_enable(ahb_clk);
+ if (err)
+ return err;
+
+ rbspi = spi_master_get_devdata(master);
+ rbspi->base = spi_base;
+ rbspi->clk = ahb_clk;
+ platform_set_drvdata(pdev, rbspi);
+
+ /* Enable SPI */
+ rb4xx_write(rbspi, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
+
+ return 0;
+}
+
+static int rb4xx_spi_remove(struct platform_device *pdev)
+{
+ struct rb4xx_spi *rbspi = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(rbspi->clk);
+
+ return 0;
+}
+
+static struct platform_driver rb4xx_spi_drv = {
+ .probe = rb4xx_spi_probe,
+ .remove = rb4xx_spi_remove,
+ .driver = {
+ .name = "rb4xx-spi",
+ },
+};
+
+module_platform_driver(rb4xx_spi_drv);
+
+MODULE_DESCRIPTION("Mikrotik RB4xx SPI controller driver");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_AUTHOR("Bert Vermeulen <bert@biot.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index f6bac9e77d06..568ea41625f5 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -665,15 +665,12 @@ static bool rspi_can_dma(struct spi_master *master, struct spi_device *spi,
static int rspi_dma_check_then_transfer(struct rspi_data *rspi,
struct spi_transfer *xfer)
{
- if (rspi->master->can_dma && __rspi_can_dma(rspi, xfer)) {
- /* rx_buf can be NULL on RSPI on SH in TX-only Mode */
- int ret = rspi_dma_transfer(rspi, &xfer->tx_sg,
- xfer->rx_buf ? &xfer->rx_sg : NULL);
- if (ret != -EAGAIN)
- return 0;
- }
+ if (!rspi->master->can_dma || !__rspi_can_dma(rspi, xfer))
+ return -EAGAIN;
- return -EAGAIN;
+ /* rx_buf can be NULL on RSPI on SH in TX-only Mode */
+ return rspi_dma_transfer(rspi, &xfer->tx_sg,
+ xfer->rx_buf ? &xfer->rx_sg : NULL);
}
static int rspi_common_transfer(struct rspi_data *rspi,
@@ -1300,7 +1297,7 @@ error1:
return ret;
}
-static struct platform_device_id spi_driver_ids[] = {
+static const struct platform_device_id spi_driver_ids[] = {
{ "rspi", (kernel_ulong_t)&rspi_ops },
{ "rspi-rz", (kernel_ulong_t)&rspi_rz_ops },
{ "qspi", (kernel_ulong_t)&qspi_ops },
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index b1c6731fbf27..2a8c513c4d07 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -1347,7 +1347,7 @@ static struct s3c64xx_spi_port_config exynos7_spi_port_config = {
.quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
};
-static struct platform_device_id s3c64xx_spi_driver_ids[] = {
+static const struct platform_device_id s3c64xx_spi_driver_ids[] = {
{
.name = "s3c2443-spi",
.driver_data = (kernel_ulong_t)&s3c2443_spi_port_config,
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index bcc7c635d8e7..d3370a612d84 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -1263,7 +1263,7 @@ static int sh_msiof_spi_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_device_id spi_driver_ids[] = {
+static const struct platform_device_id spi_driver_ids[] = {
{ "spi_sh_msiof", (kernel_ulong_t)&sh_data },
{ "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data },
{ "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data },
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
index f5715c9f68b0..ae4bd1154141 100644
--- a/drivers/spi/spi-sirf.c
+++ b/drivers/spi/spi-sirf.c
@@ -559,7 +559,8 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
sspi->tx_word = spi_sirfsoc_tx_word_u32;
break;
default:
- BUG();
+ dev_err(&spi->dev, "bpw %d not supported\n", bits_per_word);
+ return -EINVAL;
}
sspi->word_width = DIV_ROUND_UP(bits_per_word, 8);
@@ -630,14 +631,47 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
static int spi_sirfsoc_setup(struct spi_device *spi)
{
struct sirfsoc_spi *sspi;
+ int ret = 0;
sspi = spi_master_get_devdata(spi->master);
if (spi->cs_gpio == -ENOENT)
sspi->hw_cs = true;
- else
+ else {
sspi->hw_cs = false;
- return spi_sirfsoc_setup_transfer(spi, NULL);
+ if (!spi_get_ctldata(spi)) {
+ void *cs = kmalloc(sizeof(int), GFP_KERNEL);
+ if (!cs) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+ ret = gpio_is_valid(spi->cs_gpio);
+ if (!ret) {
+ dev_err(&spi->dev, "no valid gpio\n");
+ ret = -ENOENT;
+ goto exit;
+ }
+ ret = gpio_request(spi->cs_gpio, DRIVER_NAME);
+ if (ret) {
+ dev_err(&spi->dev, "failed to request gpio\n");
+ goto exit;
+ }
+ spi_set_ctldata(spi, cs);
+ }
+ }
+ writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | SIRFSOC_SPI_CS_IO_MODE,
+ sspi->base + SIRFSOC_SPI_CTRL);
+ spi_sirfsoc_chipselect(spi, BITBANG_CS_INACTIVE);
+exit:
+ return ret;
+}
+
+static void spi_sirfsoc_cleanup(struct spi_device *spi)
+{
+ if (spi_get_ctldata(spi)) {
+ gpio_free(spi->cs_gpio);
+ kfree(spi_get_ctldata(spi));
+ }
}
static int spi_sirfsoc_probe(struct platform_device *pdev)
@@ -646,7 +680,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
struct spi_master *master;
struct resource *mem_res;
int irq;
- int i, ret;
+ int ret;
ret = device_reset(&pdev->dev);
if (ret) {
@@ -684,6 +718,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
sspi->bitbang.setup_transfer = spi_sirfsoc_setup_transfer;
sspi->bitbang.txrx_bufs = spi_sirfsoc_transfer;
sspi->bitbang.master->setup = spi_sirfsoc_setup;
+ sspi->bitbang.master->cleanup = spi_sirfsoc_cleanup;
master->bus_num = pdev->id;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(12) |
@@ -723,7 +758,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
/* We are not using dummy delay between command and data */
writel(0, sspi->base + SIRFSOC_SPI_DUMMY_DELAY_CTL);
- sspi->dummypage = kmalloc(2 * PAGE_SIZE, GFP_KERNEL);
+ sspi->dummypage = devm_kzalloc(&pdev->dev, 2 * PAGE_SIZE, GFP_KERNEL);
if (!sspi->dummypage) {
ret = -ENOMEM;
goto free_clk;
@@ -731,27 +766,10 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
ret = spi_bitbang_start(&sspi->bitbang);
if (ret)
- goto free_dummypage;
- for (i = 0; master->cs_gpios && i < master->num_chipselect; i++) {
- if (master->cs_gpios[i] == -ENOENT)
- continue;
- if (!gpio_is_valid(master->cs_gpios[i])) {
- dev_err(&pdev->dev, "no valid gpio\n");
- ret = -EINVAL;
- goto free_dummypage;
- }
- ret = devm_gpio_request(&pdev->dev,
- master->cs_gpios[i], DRIVER_NAME);
- if (ret) {
- dev_err(&pdev->dev, "failed to request gpio\n");
- goto free_dummypage;
- }
- }
+ goto free_clk;
dev_info(&pdev->dev, "registerred, bus number = %d\n", master->bus_num);
return 0;
-free_dummypage:
- kfree(sspi->dummypage);
free_clk:
clk_disable_unprepare(sspi->clk);
clk_put(sspi->clk);
@@ -774,7 +792,6 @@ static int spi_sirfsoc_remove(struct platform_device *pdev)
sspi = spi_master_get_devdata(master);
spi_bitbang_stop(&sspi->bitbang);
- kfree(sspi->dummypage);
clk_disable_unprepare(sspi->clk);
clk_put(sspi->clk);
dma_release_channel(sspi->rx_chan);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 50910d85df5a..d35c1a13217c 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -988,9 +988,6 @@ void spi_finalize_current_message(struct spi_master *master)
spin_lock_irqsave(&master->queue_lock, flags);
mesg = master->cur_msg;
- master->cur_msg = NULL;
-
- queue_kthread_work(&master->kworker, &master->pump_messages);
spin_unlock_irqrestore(&master->queue_lock, flags);
spi_unmap_msg(master, mesg);
@@ -1003,9 +1000,13 @@ void spi_finalize_current_message(struct spi_master *master)
}
}
- trace_spi_message_done(mesg);
-
+ spin_lock_irqsave(&master->queue_lock, flags);
+ master->cur_msg = NULL;
master->cur_msg_prepared = false;
+ queue_kthread_work(&master->kworker, &master->pump_messages);
+ spin_unlock_irqrestore(&master->queue_lock, flags);
+
+ trace_spi_message_done(mesg);
mesg->state = NULL;
if (mesg->complete)
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 92c909eed6b5..dd616ff0ffc5 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -95,37 +95,25 @@ MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");
/*-------------------------------------------------------------------------*/
-/*
- * We can't use the standard synchronous wrappers for file I/O; we
- * need to protect against async removal of the underlying spi_device.
- */
-static void spidev_complete(void *arg)
-{
- complete(arg);
-}
-
static ssize_t
spidev_sync(struct spidev_data *spidev, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done);
int status;
-
- message->complete = spidev_complete;
- message->context = &done;
+ struct spi_device *spi;
spin_lock_irq(&spidev->spi_lock);
- if (spidev->spi == NULL)
+ spi = spidev->spi;
+ spin_unlock_irq(&spidev->spi_lock);
+
+ if (spi == NULL)
status = -ESHUTDOWN;
else
- status = spi_async(spidev->spi, message);
- spin_unlock_irq(&spidev->spi_lock);
+ status = spi_sync(spi, message);
+
+ if (status == 0)
+ status = message->actual_length;
- if (status == 0) {
- wait_for_completion(&done);
- status = message->status;
- if (status == 0)
- status = message->actual_length;
- }
return status;
}
@@ -647,7 +635,6 @@ err_find_dev:
static int spidev_release(struct inode *inode, struct file *filp)
{
struct spidev_data *spidev;
- int status = 0;
mutex_lock(&device_list_lock);
spidev = filp->private_data;
@@ -676,7 +663,7 @@ static int spidev_release(struct inode *inode, struct file *filp)
}
mutex_unlock(&device_list_lock);
- return status;
+ return 0;
}
static const struct file_operations spidev_fops = {