diff options
Diffstat (limited to 'drivers/spi')
29 files changed, 771 insertions, 282 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 62e2242ad7e0..c4f19887987b 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 @@ -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 762da0741148..78f24ca36fcf 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 40c3d43c9292..f40b34cdf2fc 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 000000000000..17b34cbadc03 --- /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 000000000000..73575dfe6916 --- /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 562ff83debd9..7b811e38c7ad 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 ce538dad526b..181cf2262006 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 276a3884fb3c..63700ab7bd9f 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 6d207afec8cb..46c6d58e1fda 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 3f3dc1226edf..ba68da12cdf0 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 29f33143b795..729215885250 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 6d2acad34f64..83a103a76481 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 2f675d32df0e..bf9728773247 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-espi.c b/drivers/spi/spi-fsl-espi.c index 68b4254069c0..a7f94b6a9e70 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -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-spi.c b/drivers/spi/spi-fsl-spi.c index c15a34ba71f5..ed792880c9d6 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -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-mxs.c b/drivers/spi/spi-mxs.c index 2884f0c2f5f0..c3f8d3a22472 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -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-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 68441fa448de..352eed7463ac 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 c4675fa8b645..345e7d61c399 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -179,8 +179,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; @@ -360,6 +360,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; diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 1189cfd96477..f1f0a587e4fc 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2136,7 +2136,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.c b/drivers/spi/spi-pxa2xx.c index fe792106bdc5..46f45ca2c694 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 c0743604b906..f96ea8a38d64 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 c850dfdfa9e3..ad87a98f8f68 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -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) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 2a4354dcd661..543075b80f16 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -636,48 +636,38 @@ 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, p->rx_dma_addr, len, DMA_FROM_DEVICE, 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 (!desc_rx) { + ret = -EAGAIN; + goto no_dma_rx; + } - 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; + goto no_dma_rx; } - dma_async_issue_pending(p->master->dma_rx); } 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 +678,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,14 +731,14 @@ 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); +no_dma_rx: return ret; } diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 95ac276eaafe..6f0602fd7401 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -312,6 +312,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) >> @@ -438,7 +440,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); diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index e4a85ada861d..795bcbc0131b 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 3548ce25c08f..cd66fe7b78a9 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 5f183baa91a9..2501a8373e89 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 41e158187f9d..0dc5df5233a9 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 e0531baf2782..e19512ffc40e 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 |