summaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig19
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi-au1550.c2
-rw-r--r--drivers/spi/spi-bcm53xx.c299
-rw-r--r--drivers/spi/spi-bcm53xx.h72
-rw-r--r--drivers/spi/spi-cadence.c1
-rw-r--r--drivers/spi/spi-clps711x.c34
-rw-r--r--drivers/spi/spi-davinci.c108
-rw-r--r--drivers/spi/spi-dw-mid.c65
-rw-r--r--drivers/spi/spi-dw-pci.c69
-rw-r--r--drivers/spi/spi-dw.c78
-rw-r--r--drivers/spi/spi-dw.h11
-rw-r--r--drivers/spi/spi-ep93xx.c1
-rw-r--r--drivers/spi/spi-fsl-cpm.c14
-rw-r--r--drivers/spi/spi-fsl-dspi.c22
-rw-r--r--drivers/spi/spi-fsl-espi.c27
-rw-r--r--drivers/spi/spi-fsl-lib.c6
-rw-r--r--drivers/spi/spi-fsl-spi.c32
-rw-r--r--drivers/spi/spi-imx.c286
-rw-r--r--drivers/spi/spi-mxs.c6
-rw-r--r--drivers/spi/spi-omap-100k.c4
-rw-r--r--drivers/spi/spi-omap2-mcspi.c3
-rw-r--r--drivers/spi/spi-orion.c121
-rw-r--r--drivers/spi/spi-pl022.c2
-rw-r--r--drivers/spi/spi-pxa2xx-pci.c20
-rw-r--r--drivers/spi/spi-pxa2xx.c1
-rw-r--r--drivers/spi/spi-rockchip.c24
-rw-r--r--drivers/spi/spi-rspi.c149
-rw-r--r--drivers/spi/spi-sh-msiof.c106
-rw-r--r--drivers/spi/spi-sirf.c114
-rw-r--r--drivers/spi/spi-tegra114.c9
-rw-r--r--drivers/spi/spi-tegra20-sflash.c3
-rw-r--r--drivers/spi/spi-txx9.c2
-rw-r--r--drivers/spi/spi-xtensa-xtfpga.c1
-rw-r--r--drivers/spi/spi.c46
35 files changed, 1304 insertions, 454 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 62e2242ad7e..84e7c9e6cce 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -69,6 +69,7 @@ config SPI_ATH79
config SPI_ATMEL
tristate "Atmel SPI Controller"
+ depends on HAS_DMA
depends on (ARCH_AT91 || AVR32 || COMPILE_TEST)
help
This selects a driver for the Atmel SPI Controller, present on
@@ -112,6 +113,14 @@ config SPI_AU1550
If you say yes to this option, support will be included for the
PSC SPI controller found on Au1550, Au1200 and Au1300 series.
+config SPI_BCM53XX
+ tristate "Broadcom BCM53xx SPI controller"
+ depends on ARCH_BCM_5301X
+ depends on BCMA_POSSIBLE
+ select BCMA
+ help
+ Enable support for the SPI controller on Broadcom BCM53xx ARM SoCs.
+
config SPI_BCM63XX
tristate "Broadcom BCM63xx SPI controller"
depends on BCM63XX
@@ -185,6 +194,7 @@ config SPI_EFM32
config SPI_EP93XX
tristate "Cirrus Logic EP93xx SPI controller"
+ depends on HAS_DMA
depends on ARCH_EP93XX || COMPILE_TEST
help
This enables using the Cirrus EP93xx SPI controller in master
@@ -314,6 +324,7 @@ config SPI_OMAP_UWIRE
config SPI_OMAP24XX
tristate "McSPI driver for OMAP"
+ depends on HAS_DMA
depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SUPERH
depends on ARCH_OMAP2PLUS || COMPILE_TEST
help
@@ -380,7 +391,7 @@ config SPI_PXA2XX
additional documentation can be found a Documentation/spi/pxa2xx.
config SPI_PXA2XX_PCI
- def_tristate SPI_PXA2XX && PCI
+ def_tristate SPI_PXA2XX && PCI && COMMON_CLK
config SPI_ROCKCHIP
tristate "Rockchip SPI controller driver"
@@ -500,7 +511,7 @@ config SPI_MXS
config SPI_TEGRA114
tristate "NVIDIA Tegra114 SPI Controller"
depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
- depends on RESET_CONTROLLER
+ depends on RESET_CONTROLLER && HAS_DMA
help
SPI driver for NVIDIA Tegra114 SPI Controller interface. This controller
is different than the older SoCs SPI controller and also register interface
@@ -518,7 +529,7 @@ config SPI_TEGRA20_SFLASH
config SPI_TEGRA20_SLINK
tristate "Nvidia Tegra20/Tegra30 SLINK Controller"
depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
- depends on RESET_CONTROLLER
+ depends on RESET_CONTROLLER && HAS_DMA
help
SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
@@ -591,7 +602,7 @@ config SPI_DW_PCI
depends on SPI_DESIGNWARE && PCI
config SPI_DW_MID_DMA
- bool "DMA support for DW SPI controller on Intel Moorestown platform"
+ bool "DMA support for DW SPI controller on Intel MID platform"
depends on SPI_DW_PCI && INTEL_MID_DMAC
config SPI_DW_MMIO
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 762da074114..78f24ca36fc 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o
obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o
+obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o
obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o
obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c
index 40c3d43c929..f40b34cdf2f 100644
--- a/drivers/spi/spi-au1550.c
+++ b/drivers/spi/spi-au1550.c
@@ -945,7 +945,7 @@ static int au1550_spi_remove(struct platform_device *pdev)
spi_bitbang_stop(&hw->bitbang);
free_irq(hw->irq, hw);
iounmap((void __iomem *)hw->regs);
- release_mem_region(r->start, sizeof(psc_spi_t));
+ release_mem_region(hw->ioarea->start, sizeof(psc_spi_t));
if (hw->usedma) {
au1550_spi_dma_rxtmp_free(hw);
diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c
new file mode 100644
index 00000000000..17b34cbadc0
--- /dev/null
+++ b/drivers/spi/spi-bcm53xx.c
@@ -0,0 +1,299 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/bcma/bcma.h>
+#include <linux/spi/spi.h>
+
+#include "spi-bcm53xx.h"
+
+#define BCM53XXSPI_MAX_SPI_BAUD 13500000 /* 216 MHz? */
+
+/* The longest observed required wait was 19 ms */
+#define BCM53XXSPI_SPE_TIMEOUT_MS 80
+
+struct bcm53xxspi {
+ struct bcma_device *core;
+ struct spi_master *master;
+
+ size_t read_offset;
+};
+
+static inline u32 bcm53xxspi_read(struct bcm53xxspi *b53spi, u16 offset)
+{
+ return bcma_read32(b53spi->core, offset);
+}
+
+static inline void bcm53xxspi_write(struct bcm53xxspi *b53spi, u16 offset,
+ u32 value)
+{
+ bcma_write32(b53spi->core, offset, value);
+}
+
+static inline unsigned int bcm53xxspi_calc_timeout(size_t len)
+{
+ /* Do some magic calculation based on length and buad. Add 10% and 1. */
+ return (len * 9000 / BCM53XXSPI_MAX_SPI_BAUD * 110 / 100) + 1;
+}
+
+static int bcm53xxspi_wait(struct bcm53xxspi *b53spi, unsigned int timeout_ms)
+{
+ unsigned long deadline;
+ u32 tmp;
+
+ /* SPE bit has to be 0 before we read MSPI STATUS */
+ deadline = jiffies + BCM53XXSPI_SPE_TIMEOUT_MS * HZ / 1000;
+ do {
+ tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2);
+ if (!(tmp & B53SPI_MSPI_SPCR2_SPE))
+ break;
+ udelay(5);
+ } while (!time_after_eq(jiffies, deadline));
+
+ if (tmp & B53SPI_MSPI_SPCR2_SPE)
+ goto spi_timeout;
+
+ /* Check status */
+ deadline = jiffies + timeout_ms * HZ / 1000;
+ do {
+ tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_MSPI_STATUS);
+ if (tmp & B53SPI_MSPI_MSPI_STATUS_SPIF) {
+ bcm53xxspi_write(b53spi, B53SPI_MSPI_MSPI_STATUS, 0);
+ return 0;
+ }
+
+ cpu_relax();
+ udelay(100);
+ } while (!time_after_eq(jiffies, deadline));
+
+spi_timeout:
+ bcm53xxspi_write(b53spi, B53SPI_MSPI_MSPI_STATUS, 0);
+
+ pr_err("Timeout waiting for SPI to be ready!\n");
+
+ return -EBUSY;
+}
+
+static void bcm53xxspi_buf_write(struct bcm53xxspi *b53spi, u8 *w_buf,
+ size_t len, bool cont)
+{
+ u32 tmp;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ /* Transmit Register File MSB */
+ bcm53xxspi_write(b53spi, B53SPI_MSPI_TXRAM + 4 * (i * 2),
+ (unsigned int)w_buf[i]);
+ }
+
+ for (i = 0; i < len; i++) {
+ tmp = B53SPI_CDRAM_CONT | B53SPI_CDRAM_PCS_DISABLE_ALL |
+ B53SPI_CDRAM_PCS_DSCK;
+ if (!cont && i == len - 1)
+ tmp &= ~B53SPI_CDRAM_CONT;
+ tmp &= ~0x1;
+ /* Command Register File */
+ bcm53xxspi_write(b53spi, B53SPI_MSPI_CDRAM + 4 * i, tmp);
+ }
+
+ /* Set queue pointers */
+ bcm53xxspi_write(b53spi, B53SPI_MSPI_NEWQP, 0);
+ bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP, len - 1);
+
+ if (cont)
+ bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 1);
+
+ /* Start SPI transfer */
+ tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2);
+ tmp |= B53SPI_MSPI_SPCR2_SPE;
+ if (cont)
+ tmp |= B53SPI_MSPI_SPCR2_CONT_AFTER_CMD;
+ bcm53xxspi_write(b53spi, B53SPI_MSPI_SPCR2, tmp);
+
+ /* Wait for SPI to finish */
+ bcm53xxspi_wait(b53spi, bcm53xxspi_calc_timeout(len));
+
+ if (!cont)
+ bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0);
+
+ b53spi->read_offset = len;
+}
+
+static void bcm53xxspi_buf_read(struct bcm53xxspi *b53spi, u8 *r_buf,
+ size_t len, bool cont)
+{
+ u32 tmp;
+ int i;
+
+ for (i = 0; i < b53spi->read_offset + len; i++) {
+ tmp = B53SPI_CDRAM_CONT | B53SPI_CDRAM_PCS_DISABLE_ALL |
+ B53SPI_CDRAM_PCS_DSCK;
+ if (!cont && i == b53spi->read_offset + len - 1)
+ tmp &= ~B53SPI_CDRAM_CONT;
+ tmp &= ~0x1;
+ /* Command Register File */
+ bcm53xxspi_write(b53spi, B53SPI_MSPI_CDRAM + 4 * i, tmp);
+ }
+
+ /* Set queue pointers */
+ bcm53xxspi_write(b53spi, B53SPI_MSPI_NEWQP, 0);
+ bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP,
+ b53spi->read_offset + len - 1);
+
+ if (cont)
+ bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 1);
+
+ /* Start SPI transfer */
+ tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2);
+ tmp |= B53SPI_MSPI_SPCR2_SPE;
+ if (cont)
+ tmp |= B53SPI_MSPI_SPCR2_CONT_AFTER_CMD;
+ bcm53xxspi_write(b53spi, B53SPI_MSPI_SPCR2, tmp);
+
+ /* Wait for SPI to finish */
+ bcm53xxspi_wait(b53spi, bcm53xxspi_calc_timeout(len));
+
+ if (!cont)
+ bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0);
+
+ for (i = 0; i < len; ++i) {
+ int offset = b53spi->read_offset + i;
+
+ /* Data stored in the transmit register file LSB */
+ r_buf[i] = (u8)bcm53xxspi_read(b53spi, B53SPI_MSPI_RXRAM + 4 * (1 + offset * 2));
+ }
+
+ b53spi->read_offset = 0;
+}
+
+static int bcm53xxspi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct bcm53xxspi *b53spi = spi_master_get_devdata(master);
+ u8 *buf;
+ size_t left;
+
+ if (t->tx_buf) {
+ buf = (u8 *)t->tx_buf;
+ left = t->len;
+ while (left) {
+ size_t to_write = min_t(size_t, 16, left);
+ bool cont = left - to_write > 0;
+
+ bcm53xxspi_buf_write(b53spi, buf, to_write, cont);
+ left -= to_write;
+ buf += to_write;
+ }
+ }
+
+ if (t->rx_buf) {
+ buf = (u8 *)t->rx_buf;
+ left = t->len;
+ while (left) {
+ size_t to_read = min_t(size_t, 16 - b53spi->read_offset,
+ left);
+ bool cont = left - to_read > 0;
+
+ bcm53xxspi_buf_read(b53spi, buf, to_read, cont);
+ left -= to_read;
+ buf += to_read;
+ }
+ }
+
+ return 0;
+}
+
+/**************************************************
+ * BCMA
+ **************************************************/
+
+static struct spi_board_info bcm53xx_info = {
+ .modalias = "bcm53xxspiflash",
+};
+
+static const struct bcma_device_id bcm53xxspi_bcma_tbl[] = {
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_QSPI, BCMA_ANY_REV, BCMA_ANY_CLASS),
+ BCMA_CORETABLE_END
+};
+MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcma_tbl);
+
+static int bcm53xxspi_bcma_probe(struct bcma_device *core)
+{
+ struct bcm53xxspi *b53spi;
+ struct spi_master *master;
+ int err;
+
+ if (core->bus->drv_cc.core->id.rev != 42) {
+ pr_err("SPI on SoC with unsupported ChipCommon rev\n");
+ return -ENOTSUPP;
+ }
+
+ master = spi_alloc_master(&core->dev, sizeof(*b53spi));
+ if (!master)
+ return -ENOMEM;
+
+ b53spi = spi_master_get_devdata(master);
+ b53spi->master = master;
+ b53spi->core = core;
+
+ master->transfer_one = bcm53xxspi_transfer_one;
+
+ bcma_set_drvdata(core, b53spi);
+
+ err = devm_spi_register_master(&core->dev, master);
+ if (err) {
+ spi_master_put(master);
+ bcma_set_drvdata(core, NULL);
+ goto out;
+ }
+
+ /* Broadcom SoCs (at least with the CC rev 42) use SPI for flash only */
+ spi_new_device(master, &bcm53xx_info);
+
+out:
+ return err;
+}
+
+static void bcm53xxspi_bcma_remove(struct bcma_device *core)
+{
+ struct bcm53xxspi *b53spi = bcma_get_drvdata(core);
+
+ spi_unregister_master(b53spi->master);
+}
+
+static struct bcma_driver bcm53xxspi_bcma_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = bcm53xxspi_bcma_tbl,
+ .probe = bcm53xxspi_bcma_probe,
+ .remove = bcm53xxspi_bcma_remove,
+};
+
+/**************************************************
+ * Init & exit
+ **************************************************/
+
+static int __init bcm53xxspi_module_init(void)
+{
+ int err = 0;
+
+ err = bcma_driver_register(&bcm53xxspi_bcma_driver);
+ if (err)
+ pr_err("Failed to register bcma driver: %d\n", err);
+
+ return err;
+}
+
+static void __exit bcm53xxspi_module_exit(void)
+{
+ bcma_driver_unregister(&bcm53xxspi_bcma_driver);
+}
+
+module_init(bcm53xxspi_module_init);
+module_exit(bcm53xxspi_module_exit);
+
+MODULE_DESCRIPTION("Broadcom BCM53xx SPI Controller driver");
+MODULE_AUTHOR("Rafał Miłecki <zajec5@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-bcm53xx.h b/drivers/spi/spi-bcm53xx.h
new file mode 100644
index 00000000000..73575dfe691
--- /dev/null
+++ b/drivers/spi/spi-bcm53xx.h
@@ -0,0 +1,72 @@
+#ifndef SPI_BCM53XX_H
+#define SPI_BCM53XX_H
+
+#define B53SPI_BSPI_REVISION_ID 0x000
+#define B53SPI_BSPI_SCRATCH 0x004
+#define B53SPI_BSPI_MAST_N_BOOT_CTRL 0x008
+#define B53SPI_BSPI_BUSY_STATUS 0x00c
+#define B53SPI_BSPI_INTR_STATUS 0x010
+#define B53SPI_BSPI_B0_STATUS 0x014
+#define B53SPI_BSPI_B0_CTRL 0x018
+#define B53SPI_BSPI_B1_STATUS 0x01c
+#define B53SPI_BSPI_B1_CTRL 0x020
+#define B53SPI_BSPI_STRAP_OVERRIDE_CTRL 0x024
+#define B53SPI_BSPI_FLEX_MODE_ENABLE 0x028
+#define B53SPI_BSPI_BITS_PER_CYCLE 0x02c
+#define B53SPI_BSPI_BITS_PER_PHASE 0x030
+#define B53SPI_BSPI_CMD_AND_MODE_BYTE 0x034
+#define B53SPI_BSPI_BSPI_FLASH_UPPER_ADDR_BYTE 0x038
+#define B53SPI_BSPI_BSPI_XOR_VALUE 0x03c
+#define B53SPI_BSPI_BSPI_XOR_ENABLE 0x040
+#define B53SPI_BSPI_BSPI_PIO_MODE_ENABLE 0x044
+#define B53SPI_BSPI_BSPI_PIO_IODIR 0x048
+#define B53SPI_BSPI_BSPI_PIO_DATA 0x04c
+
+/* RAF */
+#define B53SPI_RAF_START_ADDR 0x100
+#define B53SPI_RAF_NUM_WORDS 0x104
+#define B53SPI_RAF_CTRL 0x108
+#define B53SPI_RAF_FULLNESS 0x10c
+#define B53SPI_RAF_WATERMARK 0x110
+#define B53SPI_RAF_STATUS 0x114
+#define B53SPI_RAF_READ_DATA 0x118
+#define B53SPI_RAF_WORD_CNT 0x11c
+#define B53SPI_RAF_CURR_ADDR 0x120
+
+/* MSPI */
+#define B53SPI_MSPI_SPCR0_LSB 0x200
+#define B53SPI_MSPI_SPCR0_MSB 0x204
+#define B53SPI_MSPI_SPCR1_LSB 0x208
+#define B53SPI_MSPI_SPCR1_MSB 0x20c
+#define B53SPI_MSPI_NEWQP 0x210
+#define B53SPI_MSPI_ENDQP 0x214
+#define B53SPI_MSPI_SPCR2 0x218
+#define B53SPI_MSPI_SPCR2_SPE 0x00000040
+#define B53SPI_MSPI_SPCR2_CONT_AFTER_CMD 0x00000080
+#define B53SPI_MSPI_MSPI_STATUS 0x220
+#define B53SPI_MSPI_MSPI_STATUS_SPIF 0x00000001
+#define B53SPI_MSPI_CPTQP 0x224
+#define B53SPI_MSPI_TXRAM 0x240 /* 32 registers, up to 0x2b8 */
+#define B53SPI_MSPI_RXRAM 0x2c0 /* 32 registers, up to 0x33c */
+#define B53SPI_MSPI_CDRAM 0x340 /* 16 registers, up to 0x37c */
+#define B53SPI_CDRAM_PCS_PCS0 0x00000001
+#define B53SPI_CDRAM_PCS_PCS1 0x00000002
+#define B53SPI_CDRAM_PCS_PCS2 0x00000004
+#define B53SPI_CDRAM_PCS_PCS3 0x00000008
+#define B53SPI_CDRAM_PCS_DISABLE_ALL 0x0000000f
+#define B53SPI_CDRAM_PCS_DSCK 0x00000010
+#define B53SPI_CDRAM_BITSE 0x00000040
+#define B53SPI_CDRAM_CONT 0x00000080
+#define B53SPI_MSPI_WRITE_LOCK 0x380
+#define B53SPI_MSPI_DISABLE_FLUSH_GEN 0x384
+
+/* Interrupt */
+#define B53SPI_INTR_RAF_LR_FULLNESS_REACHED 0x3a0
+#define B53SPI_INTR_RAF_LR_TRUNCATED 0x3a4
+#define B53SPI_INTR_RAF_LR_IMPATIENT 0x3a8
+#define B53SPI_INTR_RAF_LR_SESSION_DONE 0x3ac
+#define B53SPI_INTR_RAF_LR_OVERREAD 0x3b0
+#define B53SPI_INTR_MSPI_DONE 0x3b4
+#define B53SPI_INTR_MSPI_HALT_SET_TRANSACTION_DONE 0x3b8
+
+#endif /* SPI_BCM53XX_H */
diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c
index 562ff83debd..7b811e38c7a 100644
--- a/drivers/spi/spi-cadence.c
+++ b/drivers/spi/spi-cadence.c
@@ -677,7 +677,6 @@ static struct platform_driver cdns_spi_driver = {
.remove = cdns_spi_remove,
.driver = {
.name = CDNS_SPI_NAME,
- .owner = THIS_MODULE,
.of_match_table = cdns_spi_of_match,
.pm = &cdns_spi_dev_pm_ops,
},
diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c
index ce538dad526..181cf226200 100644
--- a/drivers/spi/spi-clps711x.c
+++ b/drivers/spi/spi-clps711x.c
@@ -30,7 +30,6 @@
struct spi_clps711x_data {
void __iomem *syncio;
struct regmap *syscon;
- struct regmap *syscon1;
struct clk *spi_clk;
u8 *tx_buf;
@@ -47,27 +46,6 @@ static int spi_clps711x_setup(struct spi_device *spi)
return 0;
}
-static void spi_clps711x_setup_xfer(struct spi_device *spi,
- struct spi_transfer *xfer)
-{
- struct spi_master *master = spi->master;
- struct spi_clps711x_data *hw = spi_master_get_devdata(master);
-
- /* Setup SPI frequency divider */
- if (xfer->speed_hz >= master->max_speed_hz)
- regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
- SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(3));
- else if (xfer->speed_hz >= (master->max_speed_hz / 2))
- regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
- SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(2));
- else if (xfer->speed_hz >= (master->max_speed_hz / 8))
- regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
- SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(1));
- else
- regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
- SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(0));
-}
-
static int spi_clps711x_prepare_message(struct spi_master *master,
struct spi_message *msg)
{
@@ -87,7 +65,7 @@ static int spi_clps711x_transfer_one(struct spi_master *master,
struct spi_clps711x_data *hw = spi_master_get_devdata(master);
u8 data;
- spi_clps711x_setup_xfer(spi, xfer);
+ clk_set_rate(hw->spi_clk, xfer->speed_hz ? : spi->max_speed_hz);
hw->len = xfer->len;
hw->bpw = xfer->bits_per_word;
@@ -176,13 +154,11 @@ static int spi_clps711x_probe(struct platform_device *pdev)
}
}
- hw->spi_clk = devm_clk_get(&pdev->dev, "spi");
+ hw->spi_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(hw->spi_clk)) {
- dev_err(&pdev->dev, "Can't get clocks\n");
ret = PTR_ERR(hw->spi_clk);
goto err_out;
}
- master->max_speed_hz = clk_get_rate(hw->spi_clk);
hw->syscon = syscon_regmap_lookup_by_pdevname("syscon.3");
if (IS_ERR(hw->syscon)) {
@@ -190,12 +166,6 @@ static int spi_clps711x_probe(struct platform_device *pdev)
goto err_out;
}
- hw->syscon1 = syscon_regmap_lookup_by_pdevname("syscon.1");
- if (IS_ERR(hw->syscon1)) {
- ret = PTR_ERR(hw->syscon1);
- goto err_out;
- }
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hw->syncio = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hw->syncio)) {
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 276a3884fb3..63700ab7bd9 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -65,6 +65,7 @@
/* SPIDAT1 (upper 16 bit defines) */
#define SPIDAT1_CSHOLD_MASK BIT(12)
+#define SPIDAT1_WDEL BIT(10)
/* SPIGCR1 */
#define SPIGCR1_CLKMOD_MASK BIT(1)
@@ -167,8 +168,10 @@ static void davinci_spi_rx_buf_u16(u32 data, struct davinci_spi *dspi)
static u32 davinci_spi_tx_buf_u8(struct davinci_spi *dspi)
{
u32 data = 0;
+
if (dspi->tx) {
const u8 *tx = dspi->tx;
+
data = *tx++;
dspi->tx = tx;
}
@@ -178,8 +181,10 @@ static u32 davinci_spi_tx_buf_u8(struct davinci_spi *dspi)
static u32 davinci_spi_tx_buf_u16(struct davinci_spi *dspi)
{
u32 data = 0;
+
if (dspi->tx) {
const u16 *tx = dspi->tx;
+
data = *tx++;
dspi->tx = tx;
}
@@ -209,6 +214,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
{
struct davinci_spi *dspi;
struct davinci_spi_platform_data *pdata;
+ struct davinci_spi_config *spicfg = spi->controller_data;
u8 chip_sel = spi->chip_select;
u16 spidat1 = CS_DEFAULT;
bool gpio_chipsel = false;
@@ -223,6 +229,10 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
gpio = spi->cs_gpio;
}
+ /* program delay transfers if tx_delay is non zero */
+ if (spicfg->wdelay)
+ spidat1 |= SPIDAT1_WDEL;
+
/*
* Board specific chip select logic decides the polarity and cs
* line for the controller
@@ -237,9 +247,9 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
spidat1 |= SPIDAT1_CSHOLD_MASK;
spidat1 &= ~(0x1 << chip_sel);
}
-
- iowrite16(spidat1, dspi->base + SPIDAT1 + 2);
}
+
+ iowrite16(spidat1, dspi->base + SPIDAT1 + 2);
}
/**
@@ -285,7 +295,7 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
int prescale;
dspi = spi_master_get_devdata(spi->master);
- spicfg = (struct davinci_spi_config *)spi->controller_data;
+ spicfg = spi->controller_data;
if (!spicfg)
spicfg = &davinci_spi_default_cfg;
@@ -333,6 +343,14 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
spifmt |= SPIFMT_PHASE_MASK;
/*
+ * Assume wdelay is used only on SPI peripherals that has this field
+ * in SPIFMTn register and when it's configured from board file or DT.
+ */
+ if (spicfg->wdelay)
+ spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT)
+ & SPIFMT_WDELAY_MASK);
+
+ /*
* Version 1 hardware supports two basic SPI modes:
* - Standard SPI mode uses 4 pins, with chipselect
* - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS)
@@ -349,9 +367,6 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
u32 delay = 0;
- spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT)
- & SPIFMT_WDELAY_MASK);
-
if (spicfg->odd_parity)
spifmt |= SPIFMT_ODD_PARITY_MASK;
@@ -383,6 +398,26 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
return 0;
}
+static int davinci_spi_of_setup(struct spi_device *spi)
+{
+ struct davinci_spi_config *spicfg = spi->controller_data;
+ struct device_node *np = spi->dev.of_node;
+ u32 prop;
+
+ if (spicfg == NULL && np) {
+ spicfg = kzalloc(sizeof(*spicfg), GFP_KERNEL);
+ if (!spicfg)
+ return -ENOMEM;
+ *spicfg = davinci_spi_default_cfg;
+ /* override with dt configured values */
+ if (!of_property_read_u32(np, "ti,spi-wdelay", &prop))
+ spicfg->wdelay = (u8)prop;
+ spi->controller_data = spicfg;
+ }
+
+ return 0;
+}
+
/**
* davinci_spi_setup - This functions will set default transfer method
* @spi: spi device on which data transfer to be done
@@ -397,36 +432,33 @@ static int davinci_spi_setup(struct spi_device *spi)
struct spi_master *master = spi->master;
struct device_node *np = spi->dev.of_node;
bool internal_cs = true;
- unsigned long flags = GPIOF_DIR_OUT;
dspi = spi_master_get_devdata(spi->master);
pdata = &dspi->pdata;
- flags |= (spi->mode & SPI_CS_HIGH) ? GPIOF_INIT_LOW : GPIOF_INIT_HIGH;
-
if (!(spi->mode & SPI_NO_CS)) {
if (np && (master->cs_gpios != NULL) && (spi->cs_gpio >= 0)) {
- retval = gpio_request_one(spi->cs_gpio,
- flags, dev_name(&spi->dev));
+ retval = gpio_direction_output(
+ spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
internal_cs = false;
} else if (pdata->chip_sel &&
spi->chip_select < pdata->num_chipselect &&
pdata->chip_sel[spi->chip_select] != SPI_INTERN_CS) {
spi->cs_gpio = pdata->chip_sel[spi->chip_select];
- retval = gpio_request_one(spi->cs_gpio,
- flags, dev_name(&spi->dev));
+ retval = gpio_direction_output(
+ spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
internal_cs = false;
}
- }
- if (retval) {
- dev_err(&spi->dev, "GPIO %d setup failed (%d)\n",
- spi->cs_gpio, retval);
- return retval;
- }
+ if (retval) {
+ dev_err(&spi->dev, "GPIO %d setup failed (%d)\n",
+ spi->cs_gpio, retval);
+ return retval;
+ }
- if (internal_cs)
- set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select);
+ if (internal_cs)
+ set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select);
+ }
if (spi->mode & SPI_READY)
set_io_bits(dspi->base + SPIPC0, SPIPC0_SPIENA_MASK);
@@ -436,13 +468,16 @@ static int davinci_spi_setup(struct spi_device *spi)
else
clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK);
- return retval;
+ return davinci_spi_of_setup(spi);
}
static void davinci_spi_cleanup(struct spi_device *spi)
{
- if (spi->cs_gpio >= 0)
- gpio_free(spi->cs_gpio);
+ struct davinci_spi_config *spicfg = spi->controller_data;
+
+ spi->controller_data = NULL;
+ if (spi->dev.of_node)
+ kfree(spicfg);
}
static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status)
@@ -967,6 +1002,27 @@ static int davinci_spi_probe(struct platform_device *pdev)
if (dspi->version == SPI_VERSION_2)
dspi->bitbang.flags |= SPI_READY;
+ if (pdev->dev.of_node) {
+ int i;
+
+ for (i = 0; i < pdata->num_chipselect; i++) {
+ int cs_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "cs-gpios", i);
+
+ if (cs_gpio == -EPROBE_DEFER) {
+ ret = cs_gpio;
+ goto free_clk;
+ }
+
+ if (gpio_is_valid(cs_gpio)) {
+ ret = devm_gpio_request(&pdev->dev, cs_gpio,
+ dev_name(&pdev->dev));
+ if (ret)
+ goto free_clk;
+ }
+ }
+ }
+
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (r)
dma_rx_chan = r->start;
@@ -985,8 +1041,8 @@ static int davinci_spi_probe(struct platform_device *pdev)
goto free_clk;
dev_info(&pdev->dev, "DMA: supported\n");
- dev_info(&pdev->dev, "DMA: RX channel: %pa, TX channel: %pa, "
- "event queue: %d\n", &dma_rx_chan, &dma_tx_chan,
+ dev_info(&pdev->dev, "DMA: RX channel: %pa, TX channel: %pa, event queue: %d\n",
+ &dma_rx_chan, &dma_tx_chan,
pdata->dma_event_q);
}
diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
index 6d207afec8c..46c6d58e1fd 100644
--- a/drivers/spi/spi-dw-mid.c
+++ b/drivers/spi/spi-dw-mid.c
@@ -1,7 +1,7 @@
/*
* Special handling for DW core on Intel MID platform
*
- * Copyright (c) 2009, Intel Corporation.
+ * Copyright (c) 2009, 2014 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -11,10 +11,6 @@
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/dma-mapping.h>
@@ -39,22 +35,25 @@ static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param)
{
struct dw_spi *dws = param;
- return dws->dmac && (&dws->dmac->dev == chan->device->dev);
+ return dws->dma_dev == chan->device->dev;
}
static int mid_spi_dma_init(struct dw_spi *dws)
{
struct mid_dma *dw_dma = dws->dma_priv;
+ struct pci_dev *dma_dev;
struct intel_mid_dma_slave *rxs, *txs;
dma_cap_mask_t mask;
/*
* Get pci device for DMA controller, currently it could only
- * be the DMA controller of either Moorestown or Medfield
+ * be the DMA controller of Medfield
*/
- dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0813, NULL);
- if (!dws->dmac)
- dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL);
+ dma_dev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL);
+ if (!dma_dev)
+ return -ENODEV;
+
+ dws->dma_dev = &dma_dev->dev;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
@@ -83,13 +82,18 @@ static int mid_spi_dma_init(struct dw_spi *dws)
free_rxchan:
dma_release_channel(dws->rxchan);
err_exit:
- return -1;
-
+ return -EBUSY;
}
static void mid_spi_dma_exit(struct dw_spi *dws)
{
+ if (!dws->dma_inited)
+ return;
+
+ dmaengine_terminate_all(dws->txchan);
dma_release_channel(dws->txchan);
+
+ dmaengine_terminate_all(dws->rxchan);
dma_release_channel(dws->rxchan);
}
@@ -109,8 +113,7 @@ static void dw_spi_dma_done(void *arg)
static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
{
- struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL;
- struct dma_chan *txchan, *rxchan;
+ struct dma_async_tx_descriptor *txdesc, *rxdesc;
struct dma_slave_config txconf, rxconf;
u16 dma_ctrl = 0;
@@ -120,37 +123,34 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
dw_writew(dws, DW_SPI_DMARDLR, 0xf);
dw_writew(dws, DW_SPI_DMATDLR, 0x10);
if (dws->tx_dma)
- dma_ctrl |= 0x2;
+ dma_ctrl |= SPI_DMA_TDMAE;
if (dws->rx_dma)
- dma_ctrl |= 0x1;
+ dma_ctrl |= SPI_DMA_RDMAE;
dw_writew(dws, DW_SPI_DMACR, dma_ctrl);
spi_enable_chip(dws, 1);
}
dws->dma_chan_done = 0;
- txchan = dws->txchan;
- rxchan = dws->rxchan;
/* 2. Prepare the TX dma transfer */
txconf.direction = DMA_MEM_TO_DEV;
txconf.dst_addr = dws->dma_addr;
txconf.dst_maxburst = LNW_DMA_MSIZE_16;
txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ txconf.dst_addr_width = dws->dma_width;
txconf.device_fc = false;
- txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
- (unsigned long) &txconf);
+ dmaengine_slave_config(dws->txchan, &txconf);
memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl));
dws->tx_sgl.dma_address = dws->tx_dma;
dws->tx_sgl.length = dws->len;
- txdesc = dmaengine_prep_slave_sg(txchan,
+ txdesc = dmaengine_prep_slave_sg(dws->txchan,
&dws->tx_sgl,
1,
DMA_MEM_TO_DEV,
- DMA_PREP_INTERRUPT);
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
txdesc->callback = dw_spi_dma_done;
txdesc->callback_param = dws;
@@ -159,27 +159,30 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
rxconf.src_addr = dws->dma_addr;
rxconf.src_maxburst = LNW_DMA_MSIZE_16;
rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ rxconf.src_addr_width = dws->dma_width;
rxconf.device_fc = false;
- rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
- (unsigned long) &rxconf);
+ dmaengine_slave_config(dws->rxchan, &rxconf);
memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl));
dws->rx_sgl.dma_address = dws->rx_dma;
dws->rx_sgl.length = dws->len;
- rxdesc = dmaengine_prep_slave_sg(rxchan,
+ rxdesc = dmaengine_prep_slave_sg(dws->rxchan,
&dws->rx_sgl,
1,
DMA_DEV_TO_MEM,
- DMA_PREP_INTERRUPT);
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
rxdesc->callback = dw_spi_dma_done;
rxdesc->callback_param = dws;
/* rx must be started before tx due to spi instinct */
- rxdesc->tx_submit(rxdesc);
- txdesc->tx_submit(txdesc);
+ dmaengine_submit(rxdesc);
+ dma_async_issue_pending(dws->rxchan);
+
+ dmaengine_submit(txdesc);
+ dma_async_issue_pending(dws->txchan);
+
return 0;
}
@@ -190,7 +193,7 @@ static struct dw_spi_dma_ops mid_dma_ops = {
};
#endif
-/* Some specific info for SPI0 controller on Moorestown */
+/* Some specific info for SPI0 controller on Intel MID */
/* HW info for MRST CLk Control Unit, one 32b reg */
#define MRST_SPI_CLK_BASE 100000000 /* 100m */
diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c
index 3f3dc1226ed..ba68da12cdf 100644
--- a/drivers/spi/spi-dw-pci.c
+++ b/drivers/spi/spi-dw-pci.c
@@ -1,7 +1,7 @@
/*
* PCI interface driver for DW SPI Core
*
- * Copyright (c) 2009, Intel Corporation.
+ * Copyright (c) 2009, 2014 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -11,10 +11,6 @@
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/interrupt.h>
@@ -32,17 +28,22 @@ struct dw_spi_pci {
struct dw_spi dws;
};
-static int spi_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+struct spi_pci_desc {
+ int (*setup)(struct dw_spi *);
+};
+
+static struct spi_pci_desc spi_pci_mid_desc = {
+ .setup = dw_spi_mid_init,
+};
+
+static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct dw_spi_pci *dwpci;
struct dw_spi *dws;
+ struct spi_pci_desc *desc = (struct spi_pci_desc *)ent->driver_data;
int pci_bar = 0;
int ret;
- dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n",
- pdev->vendor, pdev->device);
-
ret = pcim_enable_device(pdev);
if (ret)
return ret;
@@ -58,20 +59,22 @@ static int spi_pci_probe(struct pci_dev *pdev,
/* Get basic io resource and map it */
dws->paddr = pci_resource_start(pdev, pci_bar);
- ret = pcim_iomap_regions(pdev, 1, dev_name(&pdev->dev));
+ ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev));
if (ret)
return ret;
+ dws->regs = pcim_iomap_table(pdev)[pci_bar];
+
dws->bus_num = 0;
dws->num_cs = 4;
dws->irq = pdev->irq;
/*
- * Specific handling for Intel MID paltforms, like dma setup,
+ * Specific handling for paltforms, like dma setup,
* clock rate, FIFO depth.
*/
- if (pdev->device == 0x0800) {
- ret = dw_spi_mid_init(dws);
+ if (desc && desc->setup) {
+ ret = desc->setup(dws);
if (ret)
return ret;
}
@@ -83,6 +86,9 @@ static int spi_pci_probe(struct pci_dev *pdev,
/* PCI hook and SPI hook use the same drv data */
pci_set_drvdata(pdev, dwpci);
+ dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n",
+ pdev->vendor, pdev->device);
+
return 0;
}
@@ -93,41 +99,29 @@ static void spi_pci_remove(struct pci_dev *pdev)
dw_spi_remove_host(&dwpci->dws);
}
-#ifdef CONFIG_PM
-static int spi_suspend(struct pci_dev *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int spi_suspend(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
- int ret;
- ret = dw_spi_suspend_host(&dwpci->dws);
- if (ret)
- return ret;
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
- return ret;
+ return dw_spi_suspend_host(&dwpci->dws);
}
-static int spi_resume(struct pci_dev *pdev)
+static int spi_resume(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
- int ret;
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
- ret = pci_enable_device(pdev);
- if (ret)
- return ret;
return dw_spi_resume_host(&dwpci->dws);
}
-#else
-#define spi_suspend NULL
-#define spi_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(dw_spi_pm_ops, spi_suspend, spi_resume);
+
static const struct pci_device_id pci_ids[] = {
/* Intel MID platform SPI controller 0 */
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) },
+ { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc},
{},
};
@@ -136,8 +130,9 @@ static struct pci_driver dw_spi_driver = {
.id_table = pci_ids,
.probe = spi_pci_probe,
.remove = spi_pci_remove,
- .suspend = spi_suspend,
- .resume = spi_resume,
+ .driver = {
+ .pm = &dw_spi_pm_ops,
+ },
};
module_pci_driver(dw_spi_driver);
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index 29f33143b79..72921588525 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -11,10 +11,6 @@
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/dma-mapping.h>
@@ -59,22 +55,20 @@ struct chip_data {
#ifdef CONFIG_DEBUG_FS
#define SPI_REGS_BUFSIZE 1024
-static ssize_t spi_show_regs(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
+static ssize_t dw_spi_show_regs(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
{
- struct dw_spi *dws;
+ struct dw_spi *dws = file->private_data;
char *buf;
u32 len = 0;
ssize_t ret;
- dws = file->private_data;
-
buf = kzalloc(SPI_REGS_BUFSIZE, GFP_KERNEL);
if (!buf)
return 0;
len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
- "MRST SPI0 registers:\n");
+ "%s registers:\n", dev_name(&dws->master->dev));
len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
"=================================\n");
len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
@@ -110,42 +104,41 @@ static ssize_t spi_show_regs(struct file *file, char __user *user_buf,
len += snprintf(buf + len, SPI_REGS_BUFSIZE - len,
"=================================\n");
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
return ret;
}
-static const struct file_operations mrst_spi_regs_ops = {
+static const struct file_operations dw_spi_regs_ops = {
.owner = THIS_MODULE,
.open = simple_open,
- .read = spi_show_regs,
+ .read = dw_spi_show_regs,
.llseek = default_llseek,
};
-static int mrst_spi_debugfs_init(struct dw_spi *dws)
+static int dw_spi_debugfs_init(struct dw_spi *dws)
{
- dws->debugfs = debugfs_create_dir("mrst_spi", NULL);
+ dws->debugfs = debugfs_create_dir("dw_spi", NULL);
if (!dws->debugfs)
return -ENOMEM;
debugfs_create_file("registers", S_IFREG | S_IRUGO,
- dws->debugfs, (void *)dws, &mrst_spi_regs_ops);
+ dws->debugfs, (void *)dws, &dw_spi_regs_ops);
return 0;
}
-static void mrst_spi_debugfs_remove(struct dw_spi *dws)
+static void dw_spi_debugfs_remove(struct dw_spi *dws)
{
- if (dws->debugfs)
- debugfs_remove_recursive(dws->debugfs);
+ debugfs_remove_recursive(dws->debugfs);
}
#else
-static inline int mrst_spi_debugfs_init(struct dw_spi *dws)
+static inline int dw_spi_debugfs_init(struct dw_spi *dws)
{
return 0;
}
-static inline void mrst_spi_debugfs_remove(struct dw_spi *dws)
+static inline void dw_spi_debugfs_remove(struct dw_spi *dws)
{
}
#endif /* CONFIG_DEBUG_FS */
@@ -177,7 +170,7 @@ static inline u32 rx_max(struct dw_spi *dws)
{
u32 rx_left = (dws->rx_end - dws->rx) / dws->n_bytes;
- return min(rx_left, (u32)dw_readw(dws, DW_SPI_RXFLR));
+ return min_t(u32, rx_left, dw_readw(dws, DW_SPI_RXFLR));
}
static void dw_writer(struct dw_spi *dws)
@@ -228,8 +221,9 @@ static void *next_transfer(struct dw_spi *dws)
struct spi_transfer,
transfer_list);
return RUNNING_STATE;
- } else
- return DONE_STATE;
+ }
+
+ return DONE_STATE;
}
/*
@@ -271,7 +265,7 @@ static void giveback(struct dw_spi *dws)
transfer_list);
if (!last_transfer->cs_change)
- spi_chip_sel(dws, dws->cur_msg->spi, 0);
+ spi_chip_sel(dws, msg->spi, 0);
spi_finalize_current_message(dws->master);
}
@@ -396,7 +390,7 @@ static void pump_transfers(unsigned long data)
goto early_exit;
}
- /* Delay if requested at end of transfer*/
+ /* Delay if requested at end of transfer */
if (message->state == RUNNING_STATE) {
previous = list_entry(transfer->transfer_list.prev,
struct spi_transfer,
@@ -471,10 +465,12 @@ static void pump_transfers(unsigned long data)
*/
if (!dws->dma_mapped && !chip->poll_mode) {
int templen = dws->len / dws->n_bytes;
+
txint_level = dws->fifo_len / 2;
txint_level = (templen > txint_level) ? txint_level : templen;
- imask |= SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI;
+ imask |= SPI_INT_TXEI | SPI_INT_TXOI |
+ SPI_INT_RXUI | SPI_INT_RXOI;
dws->transfer_handler = interrupt_transfer;
}
@@ -515,7 +511,6 @@ static void pump_transfers(unsigned long data)
early_exit:
giveback(dws);
- return;
}
static int dw_spi_transfer_one_message(struct spi_master *master,
@@ -524,7 +519,7 @@ static int dw_spi_transfer_one_message(struct spi_master *master,
struct dw_spi *dws = spi_master_get_devdata(master);
dws->cur_msg = msg;
- /* Initial message state*/
+ /* Initial message state */
dws->cur_msg->state = START_STATE;
dws->cur_transfer = list_entry(dws->cur_msg->transfers.next,
struct spi_transfer,
@@ -547,8 +542,7 @@ static int dw_spi_setup(struct spi_device *spi)
/* Only alloc on first setup */
chip = spi_get_ctldata(spi);
if (!chip) {
- chip = devm_kzalloc(&spi->dev, sizeof(struct chip_data),
- GFP_KERNEL);
+ chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
if (!chip)
return -ENOMEM;
spi_set_ctldata(spi, chip);
@@ -596,6 +590,9 @@ static int dw_spi_setup(struct spi_device *spi)
| (spi->mode << SPI_MODE_OFFSET)
| (chip->tmode << SPI_TMOD_OFFSET);
+ if (spi->mode & SPI_LOOP)
+ chip->cr0 |= 1 << SPI_SRL_OFFSET;
+
if (gpio_is_valid(spi->cs_gpio)) {
ret = gpio_direction_output(spi->cs_gpio,
!(spi->mode & SPI_CS_HIGH));
@@ -606,6 +603,14 @@ static int dw_spi_setup(struct spi_device *spi)
return 0;
}
+static void dw_spi_cleanup(struct spi_device *spi)
+{
+ struct chip_data *chip = spi_get_ctldata(spi);
+
+ kfree(chip);
+ spi_set_ctldata(spi, NULL);
+}
+
/* Restart the controller, disable all interrupts, clean rx fifo */
static void spi_hw_init(struct dw_spi *dws)
{
@@ -619,6 +624,7 @@ static void spi_hw_init(struct dw_spi *dws)
*/
if (!dws->fifo_len) {
u32 fifo;
+
for (fifo = 2; fifo <= 257; fifo++) {
dw_writew(dws, DW_SPI_TXFLTR, fifo);
if (fifo != dw_readw(dws, DW_SPI_TXFLTR))
@@ -646,8 +652,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
dws->prev_chip = NULL;
dws->dma_inited = 0;
dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60);
- snprintf(dws->name, sizeof(dws->name), "dw_spi%d",
- dws->bus_num);
+ snprintf(dws->name, sizeof(dws->name), "dw_spi%d", dws->bus_num);
ret = devm_request_irq(dev, dws->irq, dw_spi_irq, IRQF_SHARED,
dws->name, dws);
@@ -656,11 +661,12 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
goto err_free_master;
}
- master->mode_bits = SPI_CPOL | SPI_CPHA;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
master->bus_num = dws->bus_num;
master->num_chipselect = dws->num_cs;
master->setup = dw_spi_setup;
+ master->cleanup = dw_spi_cleanup;
master->transfer_one_message = dw_spi_transfer_one_message;
master->max_speed_hz = dws->max_freq;
@@ -684,7 +690,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
goto err_dma_exit;
}
- mrst_spi_debugfs_init(dws);
+ dw_spi_debugfs_init(dws);
return 0;
err_dma_exit:
@@ -701,7 +707,7 @@ void dw_spi_remove_host(struct dw_spi *dws)
{
if (!dws)
return;
- mrst_spi_debugfs_remove(dws);
+ dw_spi_debugfs_remove(dws);
if (dws->dma_ops && dws->dma_ops->dma_exit)
dws->dma_ops->dma_exit(dws);
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 6d2acad34f6..83a103a7648 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -74,6 +74,10 @@
#define SPI_INT_RXFI (1 << 4)
#define SPI_INT_MSTI (1 << 5)
+/* Bit fields in DMACR */
+#define SPI_DMA_RDMAE (1 << 0)
+#define SPI_DMA_TDMAE (1 << 1)
+
/* TX RX interrupt level threshold, max can be 256 */
#define SPI_INT_THRESHOLD 32
@@ -140,7 +144,6 @@ struct dw_spi {
dma_addr_t dma_addr; /* phy address of the Data register */
struct dw_spi_dma_ops *dma_ops;
void *dma_priv; /* platform relate info */
- struct pci_dev *dmac;
/* Bus interface info */
void *priv;
@@ -217,11 +220,11 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask)
* Each SPI slave device to work with dw_api controller should
* has such a structure claiming its working mode (PIO/DMA etc),
* which can be save in the "controller_data" member of the
- * struct spi_device
+ * struct spi_device.
*/
struct dw_spi_chip {
- u8 poll_mode; /* 0 for contoller polling mode */
- u8 type; /* SPI/SSP/Micrwire */
+ u8 poll_mode; /* 1 for controller polling mode */
+ u8 type; /* SPI/SSP/MicroWire */
u8 enable_dma;
void (*cs_control)(u32 command);
};
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index 2f675d32df0..bf972877324 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -266,6 +266,7 @@ static int ep93xx_spi_setup(struct spi_device *spi)
if (chip->ops && chip->ops->setup) {
int ret = chip->ops->setup(spi);
+
if (ret) {
kfree(chip);
return ret;
diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c
index 54b06376f03..c5dd20beee2 100644
--- a/drivers/spi/spi-fsl-cpm.c
+++ b/drivers/spi/spi-fsl-cpm.c
@@ -15,17 +15,17 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/spi/spi.h>
-#include <linux/fsl_devices.h>
-#include <linux/dma-mapping.h>
-#include <linux/of_address.h>
#include <asm/cpm.h>
#include <asm/qe.h>
+#include <linux/dma-mapping.h>
+#include <linux/fsl_devices.h>
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
-#include "spi-fsl-lib.h"
#include "spi-fsl-cpm.h"
+#include "spi-fsl-lib.h"
#include "spi-fsl-spi.h"
/* CPM1 and CPM2 are mutually exclusive. */
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 5021ddf03f6..448216025ce 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -13,22 +13,22 @@
*
*/
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
-#include <linux/pm_runtime.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
#define DRIVER_NAME "fsl-dspi"
@@ -493,9 +493,6 @@ static int dspi_probe(struct platform_device *pdev)
}
dspi_regmap_config.lock_arg = dspi;
- dspi_regmap_config.val_format_endian =
- of_property_read_bool(np, "big-endian")
- ? REGMAP_ENDIAN_BIG : REGMAP_ENDIAN_DEFAULT;
dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base,
&dspi_regmap_config);
if (IS_ERR(dspi->regmap)) {
@@ -535,7 +532,6 @@ static int dspi_probe(struct platform_device *pdev)
goto out_clk_put;
}
- pr_info(KERN_INFO "Freescale DSPI master initialized\n");
return ret;
out_clk_put:
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 8ebd724e4c5..a7f94b6a9e7 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -8,19 +8,19 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
-#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/irq.h>
-#include <linux/spi/spi.h>
-#include <linux/platform_device.h>
+#include <linux/err.h>
#include <linux/fsl_devices.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
#include <linux/mm.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
#include <sysdev/fsl_soc.h>
#include "spi-fsl-lib.h"
@@ -452,16 +452,16 @@ static int fsl_espi_setup(struct spi_device *spi)
int retval;
u32 hw_mode;
u32 loop_mode;
- struct spi_mpc8xxx_cs *cs = spi->controller_state;
+ struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi);
if (!spi->max_speed_hz)
return -EINVAL;
if (!cs) {
- cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL);
+ cs = kzalloc(sizeof(*cs), GFP_KERNEL);
if (!cs)
return -ENOMEM;
- spi->controller_state = cs;
+ spi_set_ctldata(spi, cs);
}
mpc8xxx_spi = spi_master_get_devdata(spi->master);
@@ -496,6 +496,14 @@ static int fsl_espi_setup(struct spi_device *spi)
return 0;
}
+static void fsl_espi_cleanup(struct spi_device *spi)
+{
+ struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi);
+
+ kfree(cs);
+ spi_set_ctldata(spi, NULL);
+}
+
void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
{
struct fsl_espi_reg *reg_base = mspi->reg_base;
@@ -605,6 +613,7 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
master->setup = fsl_espi_setup;
+ master->cleanup = fsl_espi_cleanup;
mpc8xxx_spi = spi_master_get_devdata(master);
mpc8xxx_spi->spi_do_one_msg = fsl_espi_do_one_msg;
diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c
index e0b773fc29c..5ddb5b098e4 100644
--- a/drivers/spi/spi-fsl-lib.c
+++ b/drivers/spi/spi-fsl-lib.c
@@ -16,10 +16,10 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/fsl_devices.h>
#include <linux/dma-mapping.h>
+#include <linux/fsl_devices.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/of_platform.h>
#include <linux/spi/spi.h>
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index 9452f674099..ed792880c9d 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -19,25 +19,25 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
#include <linux/delay.h>
-#include <linux/irq.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/spi_bitbang.h>
-#include <linux/platform_device.h>
-#include <linux/fsl_devices.h>
#include <linux/dma-mapping.h>
+#include <linux/fsl_devices.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
-#include <linux/gpio.h>
#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/types.h>
#include "spi-fsl-lib.h"
#include "spi-fsl-cpm.h"
@@ -425,16 +425,16 @@ static int fsl_spi_setup(struct spi_device *spi)
struct fsl_spi_reg *reg_base;
int retval;
u32 hw_mode;
- struct spi_mpc8xxx_cs *cs = spi->controller_state;
+ struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi);
if (!spi->max_speed_hz)
return -EINVAL;
if (!cs) {
- cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL);
+ cs = kzalloc(sizeof(*cs), GFP_KERNEL);
if (!cs)
return -ENOMEM;
- spi->controller_state = cs;
+ spi_set_ctldata(spi, cs);
}
mpc8xxx_spi = spi_master_get_devdata(spi->master);
@@ -496,9 +496,13 @@ static int fsl_spi_setup(struct spi_device *spi)
static void fsl_spi_cleanup(struct spi_device *spi)
{
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi);
if (mpc8xxx_spi->type == TYPE_GRLIB && gpio_is_valid(spi->cs_gpio))
gpio_free(spi->cs_gpio);
+
+ kfree(cs);
+ spi_set_ctldata(spi, NULL);
}
static void fsl_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 5daff2054ae..3637847b537 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -21,6 +21,8 @@
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
@@ -37,6 +39,7 @@
#include <linux/of_device.h>
#include <linux/of_gpio.h>
+#include <linux/platform_data/dma-imx.h>
#include <linux/platform_data/spi-imx.h>
#define DRIVER_NAME "spi_imx"
@@ -51,6 +54,9 @@
#define MXC_INT_RR (1 << 0) /* Receive data ready interrupt */
#define MXC_INT_TE (1 << 1) /* Transmit FIFO empty interrupt */
+/* The maximum bytes that a sdma BD can transfer.*/
+#define MAX_SDMA_BD_BYTES (1 << 15)
+#define IMX_DMA_TIMEOUT (msecs_to_jiffies(3000))
struct spi_imx_config {
unsigned int speed_hz;
unsigned int bpw;
@@ -95,6 +101,16 @@ struct spi_imx_data {
const void *tx_buf;
unsigned int txfifo; /* number of words pushed in tx FIFO */
+ /* DMA */
+ unsigned int dma_is_inited;
+ unsigned int dma_finished;
+ bool usedma;
+ u32 rx_wml;
+ u32 tx_wml;
+ u32 rxt_wml;
+ struct completion dma_rx_completion;
+ struct completion dma_tx_completion;
+
const struct spi_imx_devtype_data *devtype_data;
int chipselect[0];
};
@@ -181,9 +197,21 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
return 7;
}
+static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *transfer)
+{
+ struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
+
+ if (spi_imx->dma_is_inited && (transfer->len > spi_imx->rx_wml)
+ && (transfer->len > spi_imx->tx_wml))
+ return true;
+ return false;
+}
+
#define MX51_ECSPI_CTRL 0x08
#define MX51_ECSPI_CTRL_ENABLE (1 << 0)
#define MX51_ECSPI_CTRL_XCH (1 << 2)
+#define MX51_ECSPI_CTRL_SMC (1 << 3)
#define MX51_ECSPI_CTRL_MODE_MASK (0xf << 4)
#define MX51_ECSPI_CTRL_POSTDIV_OFFSET 8
#define MX51_ECSPI_CTRL_PREDIV_OFFSET 12
@@ -201,6 +229,18 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
#define MX51_ECSPI_INT_TEEN (1 << 0)
#define MX51_ECSPI_INT_RREN (1 << 3)
+#define MX51_ECSPI_DMA 0x14
+#define MX51_ECSPI_DMA_TX_WML_OFFSET 0
+#define MX51_ECSPI_DMA_TX_WML_MASK 0x3F
+#define MX51_ECSPI_DMA_RX_WML_OFFSET 16
+#define MX51_ECSPI_DMA_RX_WML_MASK (0x3F << 16)
+#define MX51_ECSPI_DMA_RXT_WML_OFFSET 24
+#define MX51_ECSPI_DMA_RXT_WML_MASK (0x3F << 24)
+
+#define MX51_ECSPI_DMA_TEDEN_OFFSET 7
+#define MX51_ECSPI_DMA_RXDEN_OFFSET 23
+#define MX51_ECSPI_DMA_RXTDEN_OFFSET 31
+
#define MX51_ECSPI_STAT 0x18
#define MX51_ECSPI_STAT_RR (1 << 3)
@@ -257,17 +297,22 @@ static void __maybe_unused mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int
static void __maybe_unused mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
{
- u32 reg;
-
- reg = readl(spi_imx->base + MX51_ECSPI_CTRL);
- reg |= MX51_ECSPI_CTRL_XCH;
+ u32 reg = readl(spi_imx->base + MX51_ECSPI_CTRL);
+
+ if (!spi_imx->usedma)
+ reg |= MX51_ECSPI_CTRL_XCH;
+ else if (!spi_imx->dma_finished)
+ reg |= MX51_ECSPI_CTRL_SMC;
+ else
+ reg &= ~MX51_ECSPI_CTRL_SMC;
writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
}
static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
struct spi_imx_config *config)
{
- u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0;
+ u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0, dma = 0;
+ u32 tx_wml_cfg, rx_wml_cfg, rxt_wml_cfg;
u32 clk = config->speed_hz, delay;
/*
@@ -319,6 +364,30 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
else /* SCLK is _very_ slow */
usleep_range(delay, delay + 10);
+ /*
+ * Configure the DMA register: setup the watermark
+ * and enable DMA request.
+ */
+ if (spi_imx->dma_is_inited) {
+ dma = readl(spi_imx->base + MX51_ECSPI_DMA);
+
+ spi_imx->tx_wml = spi_imx_get_fifosize(spi_imx) / 2;
+ spi_imx->rx_wml = spi_imx_get_fifosize(spi_imx) / 2;
+ spi_imx->rxt_wml = spi_imx_get_fifosize(spi_imx) / 2;
+ rx_wml_cfg = spi_imx->rx_wml << MX51_ECSPI_DMA_RX_WML_OFFSET;
+ tx_wml_cfg = spi_imx->tx_wml << MX51_ECSPI_DMA_TX_WML_OFFSET;
+ rxt_wml_cfg = spi_imx->rxt_wml << MX51_ECSPI_DMA_RXT_WML_OFFSET;
+ dma = (dma & ~MX51_ECSPI_DMA_TX_WML_MASK
+ & ~MX51_ECSPI_DMA_RX_WML_MASK
+ & ~MX51_ECSPI_DMA_RXT_WML_MASK)
+ | rx_wml_cfg | tx_wml_cfg | rxt_wml_cfg
+ |(1 << MX51_ECSPI_DMA_TEDEN_OFFSET)
+ |(1 << MX51_ECSPI_DMA_RXDEN_OFFSET)
+ |(1 << MX51_ECSPI_DMA_RXTDEN_OFFSET);
+
+ writel(dma, spi_imx->base + MX51_ECSPI_DMA);
+ }
+
return 0;
}
@@ -730,7 +799,186 @@ static int spi_imx_setupxfer(struct spi_device *spi,
return 0;
}
-static int spi_imx_transfer(struct spi_device *spi,
+static void spi_imx_sdma_exit(struct spi_imx_data *spi_imx)
+{
+ struct spi_master *master = spi_imx->bitbang.master;
+
+ if (master->dma_rx) {
+ dma_release_channel(master->dma_rx);
+ master->dma_rx = NULL;
+ }
+
+ if (master->dma_tx) {
+ dma_release_channel(master->dma_tx);
+ master->dma_tx = NULL;
+ }
+
+ spi_imx->dma_is_inited = 0;
+}
+
+static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
+ struct spi_master *master,
+ const struct resource *res)
+{
+ struct dma_slave_config slave_config = {};
+ int ret;
+
+ /* Prepare for TX DMA: */
+ master->dma_tx = dma_request_slave_channel(dev, "tx");
+ if (!master->dma_tx) {
+ dev_err(dev, "cannot get the TX DMA channel!\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ slave_config.direction = DMA_MEM_TO_DEV;
+ slave_config.dst_addr = res->start + MXC_CSPITXDATA;
+ slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ slave_config.dst_maxburst = spi_imx_get_fifosize(spi_imx) / 2;
+ ret = dmaengine_slave_config(master->dma_tx, &slave_config);
+ if (ret) {
+ dev_err(dev, "error in TX dma configuration.\n");
+ goto err;
+ }
+
+ /* Prepare for RX : */
+ master->dma_rx = dma_request_slave_channel(dev, "rx");
+ if (!master->dma_rx) {
+ dev_dbg(dev, "cannot get the DMA channel.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ slave_config.direction = DMA_DEV_TO_MEM;
+ slave_config.src_addr = res->start + MXC_CSPIRXDATA;
+ slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ slave_config.src_maxburst = spi_imx_get_fifosize(spi_imx) / 2;
+ ret = dmaengine_slave_config(master->dma_rx, &slave_config);
+ if (ret) {
+ dev_err(dev, "error in RX dma configuration.\n");
+ goto err;
+ }
+
+ init_completion(&spi_imx->dma_rx_completion);
+ init_completion(&spi_imx->dma_tx_completion);
+ master->can_dma = spi_imx_can_dma;
+ master->max_dma_len = MAX_SDMA_BD_BYTES;
+ spi_imx->bitbang.master->flags = SPI_MASTER_MUST_RX |
+ SPI_MASTER_MUST_TX;
+ spi_imx->dma_is_inited = 1;
+
+ return 0;
+err:
+ spi_imx_sdma_exit(spi_imx);
+ return ret;
+}
+
+static void spi_imx_dma_rx_callback(void *cookie)
+{
+ struct spi_imx_data *spi_imx = (struct spi_imx_data *)cookie;
+
+ complete(&spi_imx->dma_rx_completion);
+}
+
+static void spi_imx_dma_tx_callback(void *cookie)
+{
+ struct spi_imx_data *spi_imx = (struct spi_imx_data *)cookie;
+
+ complete(&spi_imx->dma_tx_completion);
+}
+
+static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
+ struct spi_transfer *transfer)
+{
+ struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL;
+ int ret;
+ u32 dma;
+ int left;
+ struct spi_master *master = spi_imx->bitbang.master;
+ struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
+
+ if (tx) {
+ desc_tx = dmaengine_prep_slave_sg(master->dma_tx,
+ tx->sgl, tx->nents, DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc_tx)
+ goto no_dma;
+
+ desc_tx->callback = spi_imx_dma_tx_callback;
+ desc_tx->callback_param = (void *)spi_imx;
+ dmaengine_submit(desc_tx);
+ }
+
+ if (rx) {
+ desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
+ rx->sgl, rx->nents, DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc_rx)
+ goto no_dma;
+
+ desc_rx->callback = spi_imx_dma_rx_callback;
+ desc_rx->callback_param = (void *)spi_imx;
+ dmaengine_submit(desc_rx);
+ }
+
+ reinit_completion(&spi_imx->dma_rx_completion);
+ reinit_completion(&spi_imx->dma_tx_completion);
+
+ /* Trigger the cspi module. */
+ spi_imx->dma_finished = 0;
+
+ dma = readl(spi_imx->base + MX51_ECSPI_DMA);
+ dma = dma & (~MX51_ECSPI_DMA_RXT_WML_MASK);
+ /* Change RX_DMA_LENGTH trigger dma fetch tail data */
+ left = transfer->len % spi_imx->rxt_wml;
+ if (left)
+ writel(dma | (left << MX51_ECSPI_DMA_RXT_WML_OFFSET),
+ spi_imx->base + MX51_ECSPI_DMA);
+ spi_imx->devtype_data->trigger(spi_imx);
+
+ dma_async_issue_pending(master->dma_tx);
+ dma_async_issue_pending(master->dma_rx);
+ /* Wait SDMA to finish the data transfer.*/
+ ret = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
+ IMX_DMA_TIMEOUT);
+ if (!ret) {
+ pr_warn("%s %s: I/O Error in DMA TX\n",
+ dev_driver_string(&master->dev),
+ dev_name(&master->dev));
+ dmaengine_terminate_all(master->dma_tx);
+ } else {
+ ret = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
+ IMX_DMA_TIMEOUT);
+ if (!ret) {
+ pr_warn("%s %s: I/O Error in DMA RX\n",
+ dev_driver_string(&master->dev),
+ dev_name(&master->dev));
+ spi_imx->devtype_data->reset(spi_imx);
+ dmaengine_terminate_all(master->dma_rx);
+ }
+ writel(dma |
+ spi_imx->rxt_wml << MX51_ECSPI_DMA_RXT_WML_OFFSET,
+ spi_imx->base + MX51_ECSPI_DMA);
+ }
+
+ spi_imx->dma_finished = 1;
+ spi_imx->devtype_data->trigger(spi_imx);
+
+ if (!ret)
+ ret = -ETIMEDOUT;
+ else if (ret > 0)
+ ret = transfer->len;
+
+ return ret;
+
+no_dma:
+ pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
+ dev_driver_string(&master->dev),
+ dev_name(&master->dev));
+ return -EAGAIN;
+}
+
+static int spi_imx_pio_transfer(struct spi_device *spi,
struct spi_transfer *transfer)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
@@ -751,6 +999,24 @@ static int spi_imx_transfer(struct spi_device *spi,
return transfer->len;
}
+static int spi_imx_transfer(struct spi_device *spi,
+ struct spi_transfer *transfer)
+{
+ int ret;
+ struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
+
+ if (spi_imx->bitbang.master->can_dma &&
+ spi_imx_can_dma(spi_imx->bitbang.master, spi, transfer)) {
+ spi_imx->usedma = true;
+ ret = spi_imx_dma_transfer(spi_imx, transfer);
+ if (ret != -EAGAIN)
+ return ret;
+ }
+ spi_imx->usedma = false;
+
+ return spi_imx_pio_transfer(spi, transfer);
+}
+
static int spi_imx_setup(struct spi_device *spi)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
@@ -911,6 +1177,13 @@ static int spi_imx_probe(struct platform_device *pdev)
goto out_put_per;
spi_imx->spi_clk = clk_get_rate(spi_imx->clk_per);
+ /*
+ * Only validated on i.mx6 now, can remove the constrain if validated on
+ * other chips.
+ */
+ if (spi_imx->devtype_data == &imx51_ecspi_devtype_data
+ && spi_imx_sdma_init(&pdev->dev, spi_imx, master, res))
+ dev_err(&pdev->dev, "dma setup error,use pio instead\n");
spi_imx->devtype_data->reset(spi_imx);
@@ -949,6 +1222,7 @@ static int spi_imx_remove(struct platform_device *pdev)
writel(0, spi_imx->base + MXC_CSPICTRL);
clk_unprepare(spi_imx->clk_ipg);
clk_unprepare(spi_imx->clk_per);
+ spi_imx_sdma_exit(spi_imx);
spi_master_put(master);
return 0;
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index 2884f0c2f5f..51460878af0 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -85,7 +85,7 @@ static int mxs_spi_setup_transfer(struct spi_device *dev,
mxs_ssp_set_clk_rate(ssp, hz);
/*
* Save requested rate, hz, rather than the actual rate,
- * ssp->clk_rate. Otherwise we would set the rate every trasfer
+ * ssp->clk_rate. Otherwise we would set the rate every transfer
* when the actual rate is not quite the same as requested rate.
*/
spi->sck = hz;
@@ -154,12 +154,14 @@ static int mxs_ssp_wait(struct mxs_spi *spi, int offset, int mask, bool set)
static void mxs_ssp_dma_irq_callback(void *param)
{
struct mxs_spi *spi = param;
+
complete(&spi->c);
}
static irqreturn_t mxs_ssp_irq_handler(int irq, void *dev_id)
{
struct mxs_ssp *ssp = dev_id;
+
dev_err(ssp->dev, "%s[%i] CTRL1=%08x STATUS=%08x\n",
__func__, __LINE__,
readl(ssp->base + HW_SSP_CTRL1(ssp)),
@@ -189,7 +191,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi,
if (!len)
return -EINVAL;
- dma_xfer = kzalloc(sizeof(*dma_xfer) * sgs, GFP_KERNEL);
+ dma_xfer = kcalloc(sgs, sizeof(*dma_xfer), GFP_KERNEL);
if (!dma_xfer)
return -ENOMEM;
diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c
index 5e91858f6f0..fb522765ce5 100644
--- a/drivers/spi/spi-omap-100k.c
+++ b/drivers/spi/spi-omap-100k.c
@@ -70,10 +70,6 @@
#define SPI_STATUS_WE (1UL << 1)
#define SPI_STATUS_RD (1UL << 0)
-#define WRITE 0
-#define READ 1
-
-
/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
* cache operations; better heuristics consider wordsize and bitrate.
*/
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 68441fa448d..352eed7463a 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -329,7 +329,8 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,
disable_fifo:
if (t->rx_buf != NULL)
chconf &= ~OMAP2_MCSPI_CHCONF_FFER;
- else
+
+ if (t->tx_buf != NULL)
chconf &= ~OMAP2_MCSPI_CHCONF_FFET;
mcspi_write_chconf0(spi, chconf);
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index c4675fa8b64..835cdda6f4f 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/sizes.h>
#include <asm/unaligned.h>
@@ -40,13 +41,27 @@
#define ORION_SPI_MODE_CPHA (1 << 12)
#define ORION_SPI_IF_8_16_BIT_MODE (1 << 5)
#define ORION_SPI_CLK_PRESCALE_MASK 0x1F
+#define ARMADA_SPI_CLK_PRESCALE_MASK 0xDF
#define ORION_SPI_MODE_MASK (ORION_SPI_MODE_CPOL | \
ORION_SPI_MODE_CPHA)
+enum orion_spi_type {
+ ORION_SPI,
+ ARMADA_SPI,
+};
+
+struct orion_spi_dev {
+ enum orion_spi_type typ;
+ unsigned int min_divisor;
+ unsigned int max_divisor;
+ u32 prescale_mask;
+};
+
struct orion_spi {
struct spi_master *master;
void __iomem *base;
struct clk *clk;
+ const struct orion_spi_dev *devdata;
};
static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg)
@@ -83,30 +98,66 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
u32 prescale;
u32 reg;
struct orion_spi *orion_spi;
+ const struct orion_spi_dev *devdata;
orion_spi = spi_master_get_devdata(spi->master);
+ devdata = orion_spi->devdata;
tclk_hz = clk_get_rate(orion_spi->clk);
- /*
- * the supported rates are: 4,6,8...30
- * round up as we look for equal or less speed
- */
- rate = DIV_ROUND_UP(tclk_hz, speed);
- rate = roundup(rate, 2);
+ if (devdata->typ == ARMADA_SPI) {
+ unsigned int clk, spr, sppr, sppr2, err;
+ unsigned int best_spr, best_sppr, best_err;
- /* check if requested speed is too small */
- if (rate > 30)
- return -EINVAL;
+ best_err = speed;
+ best_spr = 0;
+ best_sppr = 0;
- if (rate < 4)
- rate = 4;
+ /* Iterate over the valid range looking for best fit */
+ for (sppr = 0; sppr < 8; sppr++) {
+ sppr2 = 0x1 << sppr;
+
+ spr = tclk_hz / sppr2;
+ spr = DIV_ROUND_UP(spr, speed);
+ if ((spr == 0) || (spr > 15))
+ continue;
+
+ clk = tclk_hz / (spr * sppr2);
+ err = speed - clk;
+
+ if (err < best_err) {
+ best_spr = spr;
+ best_sppr = sppr;
+ best_err = err;
+ }
+ }
- /* Convert the rate to SPI clock divisor value. */
- prescale = 0x10 + rate/2;
+ if ((best_sppr == 0) && (best_spr == 0))
+ return -EINVAL;
+
+ prescale = ((best_sppr & 0x6) << 5) |
+ ((best_sppr & 0x1) << 4) | best_spr;
+ } else {
+ /*
+ * the supported rates are: 4,6,8...30
+ * round up as we look for equal or less speed
+ */
+ rate = DIV_ROUND_UP(tclk_hz, speed);
+ rate = roundup(rate, 2);
+
+ /* check if requested speed is too small */
+ if (rate > 30)
+ return -EINVAL;
+
+ if (rate < 4)
+ rate = 4;
+
+ /* Convert the rate to SPI clock divisor value. */
+ prescale = 0x10 + rate/2;
+ }
reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
- reg = ((reg & ~ORION_SPI_CLK_PRESCALE_MASK) | prescale);
+ reg = ((reg & ~devdata->prescale_mask) | prescale);
writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
return 0;
@@ -179,8 +230,8 @@ static inline int orion_spi_wait_till_ready(struct orion_spi *orion_spi)
for (i = 0; i < ORION_SPI_WAIT_RDY_MAX_LOOP; i++) {
if (readl(spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG)))
return 1;
- else
- udelay(1);
+
+ udelay(1);
}
return -1;
@@ -342,8 +393,31 @@ static int orion_spi_reset(struct orion_spi *orion_spi)
return 0;
}
+static const struct orion_spi_dev orion_spi_dev_data = {
+ .typ = ORION_SPI,
+ .min_divisor = 4,
+ .max_divisor = 30,
+ .prescale_mask = ORION_SPI_CLK_PRESCALE_MASK,
+};
+
+static const struct orion_spi_dev armada_spi_dev_data = {
+ .typ = ARMADA_SPI,
+ .min_divisor = 1,
+ .max_divisor = 1920,
+ .prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK,
+};
+
+static const struct of_device_id orion_spi_of_match_table[] = {
+ { .compatible = "marvell,orion-spi", .data = &orion_spi_dev_data, },
+ { .compatible = "marvell,armada-370-spi", .data = &armada_spi_dev_data, },
+ {}
+};
+MODULE_DEVICE_TABLE(of, orion_spi_of_match_table);
+
static int orion_spi_probe(struct platform_device *pdev)
{
+ const struct of_device_id *of_id;
+ const struct orion_spi_dev *devdata;
struct spi_master *master;
struct orion_spi *spi;
struct resource *r;
@@ -360,6 +434,7 @@ static int orion_spi_probe(struct platform_device *pdev)
master->bus_num = pdev->id;
if (pdev->dev.of_node) {
u32 cell_index;
+
if (!of_property_read_u32(pdev->dev.of_node, "cell-index",
&cell_index))
master->bus_num = cell_index;
@@ -378,6 +453,10 @@ static int orion_spi_probe(struct platform_device *pdev)
spi = spi_master_get_devdata(master);
spi->master = master;
+ of_id = of_match_device(orion_spi_of_match_table, &pdev->dev);
+ devdata = of_id->data;
+ spi->devdata = devdata;
+
spi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(spi->clk)) {
status = PTR_ERR(spi->clk);
@@ -389,8 +468,8 @@ static int orion_spi_probe(struct platform_device *pdev)
goto out;
tclk_hz = clk_get_rate(spi->clk);
- master->max_speed_hz = DIV_ROUND_UP(tclk_hz, 4);
- master->min_speed_hz = DIV_ROUND_UP(tclk_hz, 30);
+ master->max_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->min_divisor);
+ master->min_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->max_divisor);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
spi->base = devm_ioremap_resource(&pdev->dev, r);
@@ -469,12 +548,6 @@ static const struct dev_pm_ops orion_spi_pm_ops = {
NULL)
};
-static const struct of_device_id orion_spi_of_match_table[] = {
- { .compatible = "marvell,orion-spi", },
- {}
-};
-MODULE_DEVICE_TABLE(of, orion_spi_of_match_table);
-
static struct platform_driver orion_spi_driver = {
.driver = {
.name = DRIVER_NAME,
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index d0741b2eabb..f35f723816e 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -2175,7 +2175,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
cs_gpio);
else if (gpio_direction_output(cs_gpio, 1))
dev_err(&adev->dev,
- "could set gpio %d as output\n",
+ "could not set gpio %d as output\n",
cs_gpio);
}
}
diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c
index c1865c92ccb..536c863bebf 100644
--- a/drivers/spi/spi-pxa2xx-pci.c
+++ b/drivers/spi/spi-pxa2xx-pci.c
@@ -7,6 +7,8 @@
#include <linux/of_device.h>
#include <linux/module.h>
#include <linux/spi/pxa2xx_spi.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
enum {
PORT_CE4100,
@@ -21,6 +23,7 @@ struct pxa_spi_info {
int tx_chan_id;
int rx_slave_id;
int rx_chan_id;
+ unsigned long max_clk_rate;
};
static struct pxa_spi_info spi_info_configs[] = {
@@ -32,6 +35,7 @@ static struct pxa_spi_info spi_info_configs[] = {
.tx_chan_id = -1,
.rx_slave_id = -1,
.rx_chan_id = -1,
+ .max_clk_rate = 3686400,
},
[PORT_BYT] = {
.type = LPSS_SSP,
@@ -41,6 +45,7 @@ static struct pxa_spi_info spi_info_configs[] = {
.tx_chan_id = 0,
.rx_slave_id = 1,
.rx_chan_id = 1,
+ .max_clk_rate = 50000000,
},
};
@@ -53,6 +58,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
struct pxa2xx_spi_master spi_pdata;
struct ssp_device *ssp;
struct pxa_spi_info *c;
+ char buf[40];
ret = pcim_enable_device(dev);
if (ret)
@@ -84,6 +90,12 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn;
ssp->type = c->type;
+ snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id);
+ ssp->clk = clk_register_fixed_rate(&dev->dev, buf , NULL,
+ CLK_IS_ROOT, c->max_clk_rate);
+ if (IS_ERR(ssp->clk))
+ return PTR_ERR(ssp->clk);
+
memset(&pi, 0, sizeof(pi));
pi.parent = &dev->dev;
pi.name = "pxa2xx-spi";
@@ -92,8 +104,10 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
pi.size_data = sizeof(spi_pdata);
pdev = platform_device_register_full(&pi);
- if (IS_ERR(pdev))
+ if (IS_ERR(pdev)) {
+ clk_unregister(ssp->clk);
return PTR_ERR(pdev);
+ }
pci_set_drvdata(dev, pdev);
@@ -103,8 +117,12 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
static void pxa2xx_spi_pci_remove(struct pci_dev *dev)
{
struct platform_device *pdev = pci_get_drvdata(dev);
+ struct pxa2xx_spi_master *spi_pdata;
+
+ spi_pdata = dev_get_platdata(&pdev->dev);
platform_device_unregister(pdev);
+ clk_unregister(spi_pdata->ssp.clk);
}
static const struct pci_device_id pxa2xx_spi_pci_devices[] = {
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index fe792106bdc..46f45ca2c69 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -1074,6 +1074,7 @@ static struct acpi_device_id pxa2xx_spi_acpi_match[] = {
{ "INT3430", 0 },
{ "INT3431", 0 },
{ "80860F0E", 0 },
+ { "8086228E", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index c0743604b90..f96ea8a38d6 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -220,7 +220,7 @@ static inline void wait_for_idle(struct rockchip_spi *rs)
do {
if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY))
return;
- } while (time_before(jiffies, timeout));
+ } while (!time_after(jiffies, timeout));
dev_warn(rs->dev, "spi controller is in busy state!\n");
}
@@ -415,7 +415,7 @@ static void rockchip_spi_dma_txcb(void *data)
spin_unlock_irqrestore(&rs->lock, flags);
}
-static int rockchip_spi_dma_transfer(struct rockchip_spi *rs)
+static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
{
unsigned long flags;
struct dma_slave_config rxconf, txconf;
@@ -474,8 +474,6 @@ static int rockchip_spi_dma_transfer(struct rockchip_spi *rs)
dmaengine_submit(txdesc);
dma_async_issue_pending(rs->dma_tx.ch);
}
-
- return 1;
}
static void rockchip_spi_config(struct rockchip_spi *rs)
@@ -499,7 +497,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
}
/* div doesn't support odd number */
- div = rs->max_freq / rs->speed;
+ div = max_t(u32, rs->max_freq / rs->speed, 1);
div = (div + 1) & 0xfffe;
spi_enable_chip(rs, 0);
@@ -529,7 +527,8 @@ static int rockchip_spi_transfer_one(
int ret = 0;
struct rockchip_spi *rs = spi_master_get_devdata(master);
- WARN_ON((readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY));
+ WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) &&
+ (readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY));
if (!xfer->tx_buf && !xfer->rx_buf) {
dev_err(rs->dev, "No buffer for transfer\n");
@@ -556,16 +555,17 @@ static int rockchip_spi_transfer_one(
else if (rs->rx)
rs->tmode = CR0_XFM_RO;
- if (master->can_dma && master->can_dma(master, spi, xfer))
+ /* we need prepare dma before spi was enabled */
+ if (master->can_dma && master->can_dma(master, spi, xfer)) {
rs->use_dma = 1;
- else
+ rockchip_spi_prepare_dma(rs);
+ } else {
rs->use_dma = 0;
+ }
rockchip_spi_config(rs);
- if (rs->use_dma)
- ret = rockchip_spi_dma_transfer(rs);
- else
+ if (!rs->use_dma)
ret = rockchip_spi_pio_transfer(rs);
return ret;
@@ -678,7 +678,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
rs->dma_tx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_TXDR);
rs->dma_rx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_RXDR);
rs->dma_tx.direction = DMA_MEM_TO_DEV;
- rs->dma_tx.direction = DMA_DEV_TO_MEM;
+ rs->dma_rx.direction = DMA_DEV_TO_MEM;
master->can_dma = rockchip_spi_can_dma;
master->dma_tx = rs->dma_tx.ch;
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index c850dfdfa9e..54bb0faec15 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -87,7 +87,7 @@
/* RSPI on SH only */
#define SPCR_TXMD 0x02 /* TX Only Mode (vs. Full Duplex) */
#define SPCR_SPMS 0x01 /* 3-wire Mode (vs. 4-wire) */
-/* QSPI on R-Car M2 only */
+/* QSPI on R-Car Gen2 only */
#define SPCR_WSWAP 0x02 /* Word Swap of read-data for DMAC */
#define SPCR_BSWAP 0x01 /* Byte Swap of read-data for DMAC */
@@ -472,25 +472,52 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
dma_cookie_t cookie;
int ret;
- if (tx) {
- desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx,
- tx->sgl, tx->nents, DMA_TO_DEVICE,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc_tx)
- goto no_dma;
-
- irq_mask |= SPCR_SPTIE;
- }
+ /* First prepare and submit the DMA request(s), as this may fail */
if (rx) {
desc_rx = dmaengine_prep_slave_sg(rspi->master->dma_rx,
rx->sgl, rx->nents, DMA_FROM_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc_rx)
- goto no_dma;
+ if (!desc_rx) {
+ ret = -EAGAIN;
+ goto no_dma_rx;
+ }
+
+ desc_rx->callback = rspi_dma_complete;
+ desc_rx->callback_param = rspi;
+ cookie = dmaengine_submit(desc_rx);
+ if (dma_submit_error(cookie)) {
+ ret = cookie;
+ goto no_dma_rx;
+ }
irq_mask |= SPCR_SPRIE;
}
+ if (tx) {
+ desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx,
+ tx->sgl, tx->nents, DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc_tx) {
+ ret = -EAGAIN;
+ goto no_dma_tx;
+ }
+
+ if (rx) {
+ /* No callback */
+ desc_tx->callback = NULL;
+ } else {
+ desc_tx->callback = rspi_dma_complete;
+ desc_tx->callback_param = rspi;
+ }
+ cookie = dmaengine_submit(desc_tx);
+ if (dma_submit_error(cookie)) {
+ ret = cookie;
+ goto no_dma_tx;
+ }
+
+ irq_mask |= SPCR_SPTIE;
+ }
+
/*
* DMAC needs SPxIE, but if SPxIE is set, the IRQ routine will be
* called. So, this driver disables the IRQ while DMA transfer.
@@ -503,34 +530,24 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
rspi_enable_irq(rspi, irq_mask);
rspi->dma_callbacked = 0;
- if (rx) {
- desc_rx->callback = rspi_dma_complete;
- desc_rx->callback_param = rspi;
- cookie = dmaengine_submit(desc_rx);
- if (dma_submit_error(cookie))
- return cookie;
+ /* Now start DMA */
+ if (rx)
dma_async_issue_pending(rspi->master->dma_rx);
- }
- if (tx) {
- if (rx) {
- /* No callback */
- desc_tx->callback = NULL;
- } else {
- desc_tx->callback = rspi_dma_complete;
- desc_tx->callback_param = rspi;
- }
- cookie = dmaengine_submit(desc_tx);
- if (dma_submit_error(cookie))
- return cookie;
+ if (tx)
dma_async_issue_pending(rspi->master->dma_tx);
- }
ret = wait_event_interruptible_timeout(rspi->wait,
rspi->dma_callbacked, HZ);
if (ret > 0 && rspi->dma_callbacked)
ret = 0;
- else if (!ret)
+ else if (!ret) {
+ dev_err(&rspi->master->dev, "DMA timeout\n");
ret = -ETIMEDOUT;
+ if (tx)
+ dmaengine_terminate_all(rspi->master->dma_tx);
+ if (rx)
+ dmaengine_terminate_all(rspi->master->dma_rx);
+ }
rspi_disable_irq(rspi, irq_mask);
@@ -541,11 +558,16 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
return ret;
-no_dma:
- pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
- dev_driver_string(&rspi->master->dev),
- dev_name(&rspi->master->dev));
- return -EAGAIN;
+no_dma_tx:
+ if (rx)
+ dmaengine_terminate_all(rspi->master->dma_rx);
+no_dma_rx:
+ if (ret == -EAGAIN) {
+ pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
+ dev_driver_string(&rspi->master->dev),
+ dev_name(&rspi->master->dev));
+ }
+ return ret;
}
static void rspi_receive_init(const struct rspi_data *rspi)
@@ -887,20 +909,24 @@ static struct dma_chan *rspi_request_dma_chan(struct device *dev,
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- chan = dma_request_channel(mask, shdma_chan_filter,
- (void *)(unsigned long)id);
+ chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
+ (void *)(unsigned long)id, dev,
+ dir == DMA_MEM_TO_DEV ? "tx" : "rx");
if (!chan) {
- dev_warn(dev, "dma_request_channel failed\n");
+ dev_warn(dev, "dma_request_slave_channel_compat failed\n");
return NULL;
}
memset(&cfg, 0, sizeof(cfg));
cfg.slave_id = id;
cfg.direction = dir;
- if (dir == DMA_MEM_TO_DEV)
+ if (dir == DMA_MEM_TO_DEV) {
cfg.dst_addr = port_addr;
- else
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ } else {
cfg.src_addr = port_addr;
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ }
ret = dmaengine_slave_config(chan, &cfg);
if (ret) {
@@ -916,22 +942,30 @@ static int rspi_request_dma(struct device *dev, struct spi_master *master,
const struct resource *res)
{
const struct rspi_plat_data *rspi_pd = dev_get_platdata(dev);
+ unsigned int dma_tx_id, dma_rx_id;
+
+ if (dev->of_node) {
+ /* In the OF case we will get the slave IDs from the DT */
+ dma_tx_id = 0;
+ dma_rx_id = 0;
+ } else if (rspi_pd && rspi_pd->dma_tx_id && rspi_pd->dma_rx_id) {
+ dma_tx_id = rspi_pd->dma_tx_id;
+ dma_rx_id = rspi_pd->dma_rx_id;
+ } else {
+ /* The driver assumes no error. */
+ return 0;
+ }
- if (!rspi_pd || !rspi_pd->dma_rx_id || !rspi_pd->dma_tx_id)
- return 0; /* The driver assumes no error. */
-
- master->dma_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM,
- rspi_pd->dma_rx_id,
+ master->dma_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV, dma_tx_id,
res->start + RSPI_SPDR);
- if (!master->dma_rx)
+ if (!master->dma_tx)
return -ENODEV;
- master->dma_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV,
- rspi_pd->dma_tx_id,
+ master->dma_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM, dma_rx_id,
res->start + RSPI_SPDR);
- if (!master->dma_tx) {
- dma_release_channel(master->dma_rx);
- master->dma_rx = NULL;
+ if (!master->dma_rx) {
+ dma_release_channel(master->dma_tx);
+ master->dma_tx = NULL;
return -ENODEV;
}
@@ -1024,12 +1058,11 @@ static int rspi_request_irq(struct device *dev, unsigned int irq,
irq_handler_t handler, const char *suffix,
void *dev_id)
{
- const char *base = dev_name(dev);
- size_t len = strlen(base) + strlen(suffix) + 2;
- char *name = devm_kzalloc(dev, len, GFP_KERNEL);
+ const char *name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s",
+ dev_name(dev), suffix);
if (!name)
return -ENOMEM;
- snprintf(name, len, "%s:%s", base, suffix);
+
return devm_request_irq(dev, irq, handler, 0, name, dev_id);
}
@@ -1062,7 +1095,7 @@ static int rspi_probe(struct platform_device *pdev)
master->num_chipselect = rspi_pd->num_chipselect;
else
master->num_chipselect = 2; /* default */
- };
+ }
/* ops parameter check */
if (!ops->set_config_register) {
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 2a4354dcd66..3f365402fcc 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -636,17 +636,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
dma_cookie_t cookie;
int ret;
- if (tx) {
- ier_bits |= IER_TDREQE | IER_TDMAE;
- dma_sync_single_for_device(p->master->dma_tx->device->dev,
- p->tx_dma_addr, len, DMA_TO_DEVICE);
- desc_tx = dmaengine_prep_slave_single(p->master->dma_tx,
- p->tx_dma_addr, len, DMA_TO_DEVICE,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc_tx)
- return -EAGAIN;
- }
-
+ /* First prepare and submit the DMA request(s), as this may fail */
if (rx) {
ier_bits |= IER_RDREQE | IER_RDMAE;
desc_rx = dmaengine_prep_slave_single(p->master->dma_rx,
@@ -654,30 +644,26 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_rx)
return -EAGAIN;
- }
-
- /* 1 stage FIFO watermarks for DMA */
- sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1);
- /* setup msiof transfer mode registers (32-bit words) */
- sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4);
-
- sh_msiof_write(p, IER, ier_bits);
-
- reinit_completion(&p->done);
-
- if (rx) {
desc_rx->callback = sh_msiof_dma_complete;
desc_rx->callback_param = p;
cookie = dmaengine_submit(desc_rx);
- if (dma_submit_error(cookie)) {
- ret = cookie;
- goto stop_ier;
- }
- dma_async_issue_pending(p->master->dma_rx);
+ if (dma_submit_error(cookie))
+ return cookie;
}
if (tx) {
+ ier_bits |= IER_TDREQE | IER_TDMAE;
+ dma_sync_single_for_device(p->master->dma_tx->device->dev,
+ p->tx_dma_addr, len, DMA_TO_DEVICE);
+ desc_tx = dmaengine_prep_slave_single(p->master->dma_tx,
+ p->tx_dma_addr, len, DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc_tx) {
+ ret = -EAGAIN;
+ goto no_dma_tx;
+ }
+
if (rx) {
/* No callback */
desc_tx->callback = NULL;
@@ -688,15 +674,30 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
cookie = dmaengine_submit(desc_tx);
if (dma_submit_error(cookie)) {
ret = cookie;
- goto stop_rx;
+ goto no_dma_tx;
}
- dma_async_issue_pending(p->master->dma_tx);
}
+ /* 1 stage FIFO watermarks for DMA */
+ sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1);
+
+ /* setup msiof transfer mode registers (32-bit words) */
+ sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4);
+
+ sh_msiof_write(p, IER, ier_bits);
+
+ reinit_completion(&p->done);
+
+ /* Now start DMA */
+ if (rx)
+ dma_async_issue_pending(p->master->dma_rx);
+ if (tx)
+ dma_async_issue_pending(p->master->dma_tx);
+
ret = sh_msiof_spi_start(p, rx);
if (ret) {
dev_err(&p->pdev->dev, "failed to start hardware\n");
- goto stop_tx;
+ goto stop_dma;
}
/* wait for tx fifo to be emptied / rx fifo to be filled */
@@ -726,13 +727,12 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
stop_reset:
sh_msiof_reset_str(p);
sh_msiof_spi_stop(p, rx);
-stop_tx:
+stop_dma:
if (tx)
dmaengine_terminate_all(p->master->dma_tx);
-stop_rx:
+no_dma_tx:
if (rx)
dmaengine_terminate_all(p->master->dma_rx);
-stop_ier:
sh_msiof_write(p, IER, 0);
return ret;
}
@@ -928,6 +928,9 @@ static const struct of_device_id sh_msiof_match[] = {
{ .compatible = "renesas,sh-mobile-msiof", .data = &sh_data },
{ .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data },
{ .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data },
+ { .compatible = "renesas,msiof-r8a7792", .data = &r8a779x_data },
+ { .compatible = "renesas,msiof-r8a7793", .data = &r8a779x_data },
+ { .compatible = "renesas,msiof-r8a7794", .data = &r8a779x_data },
{},
};
MODULE_DEVICE_TABLE(of, sh_msiof_match);
@@ -972,20 +975,24 @@ static struct dma_chan *sh_msiof_request_dma_chan(struct device *dev,
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- chan = dma_request_channel(mask, shdma_chan_filter,
- (void *)(unsigned long)id);
+ chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
+ (void *)(unsigned long)id, dev,
+ dir == DMA_MEM_TO_DEV ? "tx" : "rx");
if (!chan) {
- dev_warn(dev, "dma_request_channel failed\n");
+ dev_warn(dev, "dma_request_slave_channel_compat failed\n");
return NULL;
}
memset(&cfg, 0, sizeof(cfg));
cfg.slave_id = id;
cfg.direction = dir;
- if (dir == DMA_MEM_TO_DEV)
+ if (dir == DMA_MEM_TO_DEV) {
cfg.dst_addr = port_addr;
- else
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ } else {
cfg.src_addr = port_addr;
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ }
ret = dmaengine_slave_config(chan, &cfg);
if (ret) {
@@ -1002,12 +1009,22 @@ static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p)
struct platform_device *pdev = p->pdev;
struct device *dev = &pdev->dev;
const struct sh_msiof_spi_info *info = dev_get_platdata(dev);
+ unsigned int dma_tx_id, dma_rx_id;
const struct resource *res;
struct spi_master *master;
struct device *tx_dev, *rx_dev;
- if (!info || !info->dma_tx_id || !info->dma_rx_id)
- return 0; /* The driver assumes no error */
+ if (dev->of_node) {
+ /* In the OF case we will get the slave IDs from the DT */
+ dma_tx_id = 0;
+ dma_rx_id = 0;
+ } else if (info && info->dma_tx_id && info->dma_rx_id) {
+ dma_tx_id = info->dma_tx_id;
+ dma_rx_id = info->dma_rx_id;
+ } else {
+ /* The driver assumes no error */
+ return 0;
+ }
/* The DMA engine uses the second register set, if present */
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -1016,13 +1033,13 @@ static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p)
master = p->master;
master->dma_tx = sh_msiof_request_dma_chan(dev, DMA_MEM_TO_DEV,
- info->dma_tx_id,
+ dma_tx_id,
res->start + TFDR);
if (!master->dma_tx)
return -ENODEV;
master->dma_rx = sh_msiof_request_dma_chan(dev, DMA_DEV_TO_MEM,
- info->dma_rx_id,
+ dma_rx_id,
res->start + RFDR);
if (!master->dma_rx)
goto free_tx_chan;
@@ -1205,6 +1222,9 @@ static 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 },
+ { "spi_r8a7792_msiof", (kernel_ulong_t)&r8a779x_data },
+ { "spi_r8a7793_msiof", (kernel_ulong_t)&r8a779x_data },
+ { "spi_r8a7794_msiof", (kernel_ulong_t)&r8a779x_data },
{},
};
MODULE_DEVICE_TABLE(platform, spi_driver_ids);
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
index 95ac276eaaf..39e2c0a55a2 100644
--- a/drivers/spi/spi-sirf.c
+++ b/drivers/spi/spi-sirf.c
@@ -62,15 +62,15 @@
#define SIRFSOC_SPI_TRAN_DAT_FORMAT_12 (1 << 26)
#define SIRFSOC_SPI_TRAN_DAT_FORMAT_16 (2 << 26)
#define SIRFSOC_SPI_TRAN_DAT_FORMAT_32 (3 << 26)
-#define SIRFSOC_SPI_CMD_BYTE_NUM(x) ((x & 3) << 28)
-#define SIRFSOC_SPI_ENA_AUTO_CLR BIT(30)
-#define SIRFSOC_SPI_MUL_DAT_MODE BIT(31)
+#define SIRFSOC_SPI_CMD_BYTE_NUM(x) ((x & 3) << 28)
+#define SIRFSOC_SPI_ENA_AUTO_CLR BIT(30)
+#define SIRFSOC_SPI_MUL_DAT_MODE BIT(31)
/* Interrupt Enable */
-#define SIRFSOC_SPI_RX_DONE_INT_EN BIT(0)
-#define SIRFSOC_SPI_TX_DONE_INT_EN BIT(1)
-#define SIRFSOC_SPI_RX_OFLOW_INT_EN BIT(2)
-#define SIRFSOC_SPI_TX_UFLOW_INT_EN BIT(3)
+#define SIRFSOC_SPI_RX_DONE_INT_EN BIT(0)
+#define SIRFSOC_SPI_TX_DONE_INT_EN BIT(1)
+#define SIRFSOC_SPI_RX_OFLOW_INT_EN BIT(2)
+#define SIRFSOC_SPI_TX_UFLOW_INT_EN BIT(3)
#define SIRFSOC_SPI_RX_IO_DMA_INT_EN BIT(4)
#define SIRFSOC_SPI_TX_IO_DMA_INT_EN BIT(5)
#define SIRFSOC_SPI_RXFIFO_FULL_INT_EN BIT(6)
@@ -79,7 +79,7 @@
#define SIRFSOC_SPI_TXFIFO_THD_INT_EN BIT(9)
#define SIRFSOC_SPI_FRM_END_INT_EN BIT(10)
-#define SIRFSOC_SPI_INT_MASK_ALL 0x1FFF
+#define SIRFSOC_SPI_INT_MASK_ALL 0x1FFF
/* Interrupt status */
#define SIRFSOC_SPI_RX_DONE BIT(0)
@@ -170,8 +170,7 @@ struct sirfsoc_spi {
* command model
*/
bool tx_by_cmd;
-
- int chipselect[0];
+ bool hw_cs;
};
static void spi_sirfsoc_rx_word_u8(struct sirfsoc_spi *sspi)
@@ -304,7 +303,7 @@ static void spi_sirfsoc_dma_fini_callback(void *data)
complete(dma_complete);
}
-static int spi_sirfsoc_cmd_transfer(struct spi_device *spi,
+static void spi_sirfsoc_cmd_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
struct sirfsoc_spi *sspi;
@@ -312,6 +311,8 @@ static int spi_sirfsoc_cmd_transfer(struct spi_device *spi,
u32 cmd;
sspi = spi_master_get_devdata(spi->master);
+ writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
+ writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
memcpy(&cmd, sspi->tx, t->len);
if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST))
cmd = cpu_to_be32(cmd) >>
@@ -326,10 +327,9 @@ static int spi_sirfsoc_cmd_transfer(struct spi_device *spi,
sspi->base + SIRFSOC_SPI_TX_RX_EN);
if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) {
dev_err(&spi->dev, "cmd transfer timeout\n");
- return 0;
+ return;
}
-
- return t->len;
+ sspi->left_rx_word -= t->len;
}
static void spi_sirfsoc_dma_transfer(struct spi_device *spi,
@@ -438,7 +438,8 @@ static void spi_sirfsoc_pio_transfer(struct spi_device *spi,
sspi->tx_word(sspi);
writel(SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN |
SIRFSOC_SPI_TX_UFLOW_INT_EN |
- SIRFSOC_SPI_RX_OFLOW_INT_EN,
+ SIRFSOC_SPI_RX_OFLOW_INT_EN |
+ SIRFSOC_SPI_RX_IO_DMA_INT_EN,
sspi->base + SIRFSOC_SPI_INT_EN);
writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN,
sspi->base + SIRFSOC_SPI_TX_RX_EN);
@@ -484,7 +485,7 @@ static void spi_sirfsoc_chipselect(struct spi_device *spi, int value)
{
struct sirfsoc_spi *sspi = spi_master_get_devdata(spi->master);
- if (sspi->chipselect[spi->chip_select] == 0) {
+ if (sspi->hw_cs) {
u32 regval = readl(sspi->base + SIRFSOC_SPI_CTRL);
switch (value) {
case BITBANG_CS_ACTIVE:
@@ -502,14 +503,13 @@ static void spi_sirfsoc_chipselect(struct spi_device *spi, int value)
}
writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
} else {
- int gpio = sspi->chipselect[spi->chip_select];
switch (value) {
case BITBANG_CS_ACTIVE:
- gpio_direction_output(gpio,
+ gpio_direction_output(spi->cs_gpio,
spi->mode & SPI_CS_HIGH ? 1 : 0);
break;
case BITBANG_CS_INACTIVE:
- gpio_direction_output(gpio,
+ gpio_direction_output(spi->cs_gpio,
spi->mode & SPI_CS_HIGH ? 0 : 1);
break;
}
@@ -603,8 +603,8 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
sspi->tx_by_cmd = false;
}
/*
- * set spi controller in RISC chipselect mode, we are controlling CS by
- * software BITBANG_CS_ACTIVE and BITBANG_CS_INACTIVE.
+ * it should never set to hardware cs mode because in hardware cs mode,
+ * cs signal can't controlled by driver.
*/
regval |= SIRFSOC_SPI_CS_IO_MODE;
writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
@@ -627,9 +627,17 @@ 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;
+
if (!spi->max_speed_hz)
return -EINVAL;
+ sspi = spi_master_get_devdata(spi->master);
+
+ if (spi->cs_gpio == -ENOENT)
+ sspi->hw_cs = true;
+ else
+ sspi->hw_cs = false;
return spi_sirfsoc_setup_transfer(spi, NULL);
}
@@ -638,19 +646,10 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
struct sirfsoc_spi *sspi;
struct spi_master *master;
struct resource *mem_res;
- int num_cs, cs_gpio, irq;
- int i;
- int ret;
+ int irq;
+ int i, ret;
- ret = of_property_read_u32(pdev->dev.of_node,
- "sirf,spi-num-chipselects", &num_cs);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unable to get chip select number\n");
- goto err_cs;
- }
-
- master = spi_alloc_master(&pdev->dev,
- sizeof(*sspi) + sizeof(int) * num_cs);
+ master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI master\n");
return -ENOMEM;
@@ -658,32 +657,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
sspi = spi_master_get_devdata(master);
- master->num_chipselect = num_cs;
-
- for (i = 0; i < master->num_chipselect; i++) {
- cs_gpio = of_get_named_gpio(pdev->dev.of_node, "cs-gpios", i);
- if (cs_gpio < 0) {
- dev_err(&pdev->dev, "can't get cs gpio from DT\n");
- ret = -ENODEV;
- goto free_master;
- }
-
- sspi->chipselect[i] = cs_gpio;
- if (cs_gpio == 0)
- continue; /* use cs from spi controller */
-
- ret = gpio_request(cs_gpio, DRIVER_NAME);
- if (ret) {
- while (i > 0) {
- i--;
- if (sspi->chipselect[i] > 0)
- gpio_free(sspi->chipselect[i]);
- }
- dev_err(&pdev->dev, "fail to request cs gpios\n");
- goto free_master;
- }
- }
-
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sspi->base = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(sspi->base)) {
@@ -753,7 +726,21 @@ 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;
+ }
+ }
dev_info(&pdev->dev, "registerred, bus number = %d\n", master->bus_num);
return 0;
@@ -768,7 +755,7 @@ free_rx_dma:
dma_release_channel(sspi->rx_chan);
free_master:
spi_master_put(master);
-err_cs:
+
return ret;
}
@@ -776,16 +763,11 @@ static int spi_sirfsoc_remove(struct platform_device *pdev)
{
struct spi_master *master;
struct sirfsoc_spi *sspi;
- int i;
master = platform_get_drvdata(pdev);
sspi = spi_master_get_devdata(master);
spi_bitbang_stop(&sspi->bitbang);
- for (i = 0; i < master->num_chipselect; i++) {
- if (sspi->chipselect[i] > 0)
- gpio_free(sspi->chipselect[i]);
- }
kfree(sspi->dummypage);
clk_disable_unprepare(sspi->clk);
clk_put(sspi->clk);
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index e4a85ada861..795bcbc0131 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -302,6 +302,7 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf(
max_n_32bit = DIV_ROUND_UP(nbytes, 4);
for (count = 0; count < max_n_32bit; count++) {
u32 x = 0;
+
for (i = 0; (i < 4) && nbytes; i++, nbytes--)
x |= (u32)(*tx_buf++) << (i * 8);
tegra_spi_writel(tspi, x, SPI_TX_FIFO);
@@ -312,6 +313,7 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf(
nbytes = written_words * tspi->bytes_per_word;
for (count = 0; count < max_n_32bit; count++) {
u32 x = 0;
+
for (i = 0; nbytes && (i < tspi->bytes_per_word);
i++, nbytes--)
x |= (u32)(*tx_buf++) << (i * 8);
@@ -338,6 +340,7 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf(
len = tspi->curr_dma_words * tspi->bytes_per_word;
for (count = 0; count < rx_full_count; count++) {
u32 x = tegra_spi_readl(tspi, SPI_RX_FIFO);
+
for (i = 0; len && (i < 4); i++, len--)
*rx_buf++ = (x >> i*8) & 0xFF;
}
@@ -345,8 +348,10 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf(
read_words += tspi->curr_dma_words;
} else {
u32 rx_mask = ((u32)1 << t->bits_per_word) - 1;
+
for (count = 0; count < rx_full_count; count++) {
u32 x = tegra_spi_readl(tspi, SPI_RX_FIFO) & rx_mask;
+
for (i = 0; (i < tspi->bytes_per_word); i++)
*rx_buf++ = (x >> (i*8)) & 0xFF;
}
@@ -365,6 +370,7 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf(
if (tspi->is_packed) {
unsigned len = tspi->curr_dma_words * tspi->bytes_per_word;
+
memcpy(tspi->tx_dma_buf, t->tx_buf + tspi->cur_pos, len);
} else {
unsigned int i;
@@ -374,6 +380,7 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf(
for (count = 0; count < tspi->curr_dma_words; count++) {
u32 x = 0;
+
for (i = 0; consume && (i < tspi->bytes_per_word);
i++, consume--)
x |= (u32)(*tx_buf++) << (i * 8);
@@ -396,6 +403,7 @@ static void tegra_spi_copy_spi_rxbuf_to_client_rxbuf(
if (tspi->is_packed) {
unsigned len = tspi->curr_dma_words * tspi->bytes_per_word;
+
memcpy(t->rx_buf + tspi->cur_rx_pos, tspi->rx_dma_buf, len);
} else {
unsigned int i;
@@ -405,6 +413,7 @@ static void tegra_spi_copy_spi_rxbuf_to_client_rxbuf(
for (count = 0; count < tspi->curr_dma_words; count++) {
u32 x = tspi->rx_dma_buf[count] & rx_mask;
+
for (i = 0; (i < tspi->bytes_per_word); i++)
*rx_buf++ = (x >> (i*8)) & 0xFF;
}
diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c
index 3548ce25c08..cd66fe7b78a 100644
--- a/drivers/spi/spi-tegra20-sflash.c
+++ b/drivers/spi/spi-tegra20-sflash.c
@@ -99,7 +99,7 @@
#define SPI_TX_TRIG_MASK (0x3 << 16)
#define SPI_TX_TRIG_1W (0x0 << 16)
#define SPI_TX_TRIG_4W (0x1 << 16)
-#define SPI_DMA_BLK_COUNT(count) (((count) - 1) & 0xFFFF);
+#define SPI_DMA_BLK_COUNT(count) (((count) - 1) & 0xFFFF)
#define SPI_TX_FIFO 0x10
#define SPI_RX_FIFO 0x20
@@ -221,6 +221,7 @@ static int tegra_sflash_read_rx_fifo_to_client_rxbuf(
while (!(status & SPI_RXF_EMPTY)) {
int i;
u32 x = tegra_sflash_readl(tsd, SPI_RX_FIFO);
+
for (i = 0; (i < tsd->bytes_per_word); i++)
*rx_buf++ = (x >> (i*8)) & 0xFF;
read_words++;
diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c
index 5f183baa91a..2501a8373e8 100644
--- a/drivers/spi/spi-txx9.c
+++ b/drivers/spi/spi-txx9.c
@@ -97,6 +97,7 @@ static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c,
int on, unsigned int cs_delay)
{
int val = (spi->mode & SPI_CS_HIGH) ? on : !on;
+
if (on) {
/* deselect the chip with cs_change hint in last transfer */
if (c->last_chipselect >= 0)
@@ -188,6 +189,7 @@ static void txx9spi_work_one(struct txx9spi *c, struct spi_message *m)
if (prev_speed_hz != speed_hz
|| prev_bits_per_word != bits_per_word) {
int n = DIV_ROUND_UP(c->baseclk, speed_hz) - 1;
+
n = clamp(n, SPI_MIN_DIVIDER, SPI_MAX_DIVIDER);
/* enter config mode */
txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR,
diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c
index 41e158187f9..0dc5df5233a 100644
--- a/drivers/spi/spi-xtensa-xtfpga.c
+++ b/drivers/spi/spi-xtensa-xtfpga.c
@@ -46,6 +46,7 @@ static inline unsigned int xtfpga_spi_read32(const struct xtfpga_spi *spi,
static inline void xtfpga_spi_wait_busy(struct xtfpga_spi *xspi)
{
unsigned i;
+
for (i = 0; xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY) &&
i < BUSY_WAIT_US; ++i)
udelay(1);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index e0531baf278..e19512ffc40 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -552,6 +552,9 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n)
struct boardinfo *bi;
int i;
+ if (!n)
+ return -EINVAL;
+
bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
if (!bi)
return -ENOMEM;
@@ -789,27 +792,35 @@ static int spi_transfer_one_message(struct spi_master *master,
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
trace_spi_transfer_start(msg, xfer);
- reinit_completion(&master->xfer_completion);
+ if (xfer->tx_buf || xfer->rx_buf) {
+ reinit_completion(&master->xfer_completion);
- ret = master->transfer_one(master, msg->spi, xfer);
- if (ret < 0) {
- dev_err(&msg->spi->dev,
- "SPI transfer failed: %d\n", ret);
- goto out;
- }
+ ret = master->transfer_one(master, msg->spi, xfer);
+ if (ret < 0) {
+ dev_err(&msg->spi->dev,
+ "SPI transfer failed: %d\n", ret);
+ goto out;
+ }
- if (ret > 0) {
- ret = 0;
- ms = xfer->len * 8 * 1000 / xfer->speed_hz;
- ms += ms + 100; /* some tolerance */
+ if (ret > 0) {
+ ret = 0;
+ ms = xfer->len * 8 * 1000 / xfer->speed_hz;
+ ms += ms + 100; /* some tolerance */
- ms = wait_for_completion_timeout(&master->xfer_completion,
- msecs_to_jiffies(ms));
- }
+ ms = wait_for_completion_timeout(&master->xfer_completion,
+ msecs_to_jiffies(ms));
+ }
- if (ms == 0) {
- dev_err(&msg->spi->dev, "SPI transfer timed out\n");
- msg->status = -ETIMEDOUT;
+ if (ms == 0) {
+ dev_err(&msg->spi->dev,
+ "SPI transfer timed out\n");
+ msg->status = -ETIMEDOUT;
+ }
+ } else {
+ if (xfer->len)
+ dev_err(&msg->spi->dev,
+ "Bufferless transfer has length %u\n",
+ xfer->len);
}
trace_spi_transfer_stop(msg, xfer);
@@ -848,6 +859,7 @@ out:
/**
* spi_finalize_current_transfer - report completion of a transfer
+ * @master: the master reporting completion
*
* Called by SPI drivers using the core transfer_one_message()
* implementation to notify it that the current interrupt driven