From 6b1576aa875347c6454d911a2e001138c2cec7d5 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Mon, 10 Oct 2016 09:25:24 -0500 Subject: spi: Add Flag to Enable Slave Select with GPIO Chip Select. Some SPI masters require slave selection before the transfer can begin [1]. The SPI framework currently selects the chip using either 1) the internal CS mechanism or 2) the GPIO CS, but not both. This patch adds a new master->flags define to indicate both the GPIO CS and the internal chip select mechanism should be used. Tested On: Altera CycloneV development kit Compile tested for build errors on x86_64 (allyesconfigs) [1] DesignWare dw_apb_ssi Databook, Version 3.20a (page 39) Signed-off-by: Thor Thayer Signed-off-by: Mark Brown --- drivers/spi/spi.c | 9 +++++++-- include/linux/spi/spi.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 8146ccd35a1a..8708da7c8140 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -697,10 +697,15 @@ static void spi_set_cs(struct spi_device *spi, bool enable) if (spi->mode & SPI_CS_HIGH) enable = !enable; - if (gpio_is_valid(spi->cs_gpio)) + if (gpio_is_valid(spi->cs_gpio)) { gpio_set_value(spi->cs_gpio, !enable); - else if (spi->master->set_cs) + /* Some SPI masters need both GPIO CS & slave_select */ + if ((spi->master->flags & SPI_MASTER_GPIO_SS) && + spi->master->set_cs) + spi->master->set_cs(spi, !enable); + } else if (spi->master->set_cs) { spi->master->set_cs(spi, !enable); + } } #ifdef CONFIG_HAS_DMA diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 4b743ac35396..75c6bd0ac605 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -442,6 +442,7 @@ struct spi_master { #define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */ #define SPI_MASTER_MUST_RX BIT(3) /* requires rx */ #define SPI_MASTER_MUST_TX BIT(4) /* requires tx */ +#define SPI_MASTER_GPIO_SS BIT(5) /* GPIO CS must select slave */ /* * on some hardware transfer / message size may be constrained -- cgit v1.2.3 From 80b444e57948ea4bd5a89fb1f8c404ddab6c1973 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Mon, 10 Oct 2016 09:25:25 -0500 Subject: spi: dw: Set GPIO_SS flag to toggle Slave Select on GPIO CS The Designware SPI master requires slave selection before the transfer can begin [1]. This patch uses the new master flag to indicate both the GPIO CS and the internal chip select should be used. Tested On: Altera CycloneV development kit Compile tested for build errors on x86_64 (allyesconfigs) [1] DesignWare dw_apb_ssi Databook, Version 3.20a (page 39) Signed-off-by: Thor Thayer Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 27960e46135d..b715a26a9148 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -502,6 +502,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) master->handle_err = dw_spi_handle_err; master->max_speed_hz = dws->max_freq; master->dev.of_node = dev->of_node; + master->flags = SPI_MASTER_GPIO_SS; /* Basic HW init */ spi_hw_init(dev, dws); -- cgit v1.2.3 From 8eee6b9dd30d5b20a4c31886057a68bb6a2736c9 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Mon, 10 Oct 2016 09:25:24 -0500 Subject: spi: Add Flag to Enable Slave Select with GPIO Chip Select. Some SPI masters require slave selection before the transfer can begin [1]. The SPI framework currently selects the chip using either 1) the internal CS mechanism or 2) the GPIO CS, but not both. This patch adds a new master->flags define to indicate both the GPIO CS and the internal chip select mechanism should be used. Tested On: Altera CycloneV development kit Compile tested for build errors on x86_64 (allyesconfigs) [1] DesignWare dw_apb_ssi Databook, Version 3.20a (page 39) Signed-off-by: Thor Thayer Signed-off-by: Mark Brown --- drivers/spi/spi.c | 9 +++++++-- include/linux/spi/spi.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5787b723b593..cbe15ab5f8a8 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -697,10 +697,15 @@ static void spi_set_cs(struct spi_device *spi, bool enable) if (spi->mode & SPI_CS_HIGH) enable = !enable; - if (gpio_is_valid(spi->cs_gpio)) + if (gpio_is_valid(spi->cs_gpio)) { gpio_set_value(spi->cs_gpio, !enable); - else if (spi->master->set_cs) + /* Some SPI masters need both GPIO CS & slave_select */ + if ((spi->master->flags & SPI_MASTER_GPIO_SS) && + spi->master->set_cs) + spi->master->set_cs(spi, !enable); + } else if (spi->master->set_cs) { spi->master->set_cs(spi, !enable); + } } #ifdef CONFIG_HAS_DMA diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 4b743ac35396..75c6bd0ac605 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -442,6 +442,7 @@ struct spi_master { #define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */ #define SPI_MASTER_MUST_RX BIT(3) /* requires rx */ #define SPI_MASTER_MUST_TX BIT(4) /* requires tx */ +#define SPI_MASTER_GPIO_SS BIT(5) /* GPIO CS must select slave */ /* * on some hardware transfer / message size may be constrained -- cgit v1.2.3 From b497eb024531b712f9d2c6af0bb55ca558a2674e Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 1 Oct 2016 21:07:52 +0200 Subject: spi: fsl-espi: replace of_get_property with of_property_read_u32 of_property_read_u32 is better here than generic of_get_property: - implicit endianness conversion if needed - implicit checking of size of property Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 7451585a080e..1f97cce615d3 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -545,9 +545,8 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem, struct spi_master *master; struct mpc8xxx_spi *mpc8xxx_spi; struct device_node *nc; - const __be32 *prop; - u32 regval, csmode; - int i, len, ret; + u32 regval, csmode, cs, prop; + int ret; master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi)); if (!master) @@ -599,29 +598,29 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem, /* Init eSPI CS mode register */ for_each_available_child_of_node(master->dev.of_node, nc) { /* get chip select */ - prop = of_get_property(nc, "reg", &len); - if (!prop || len < sizeof(*prop)) - continue; - i = be32_to_cpup(prop); - if (i < 0 || i >= pdata->max_chipselect) + ret = of_property_read_u32(nc, "reg", &cs); + if (ret || cs >= pdata->max_chipselect) continue; csmode = CSMODE_INIT_VAL; + /* check if CSBEF is set in device tree */ - prop = of_get_property(nc, "fsl,csbef", &len); - if (prop && len >= sizeof(*prop)) { + ret = of_property_read_u32(nc, "fsl,csbef", &prop); + if (!ret) { csmode &= ~(CSMODE_BEF(0xf)); - csmode |= CSMODE_BEF(be32_to_cpup(prop)); + csmode |= CSMODE_BEF(prop); } + /* check if CSAFT is set in device tree */ - prop = of_get_property(nc, "fsl,csaft", &len); - if (prop && len >= sizeof(*prop)) { + ret = of_property_read_u32(nc, "fsl,csaft", &prop); + if (!ret) { csmode &= ~(CSMODE_AFT(0xf)); - csmode |= CSMODE_AFT(be32_to_cpup(prop)); + csmode |= CSMODE_AFT(prop); } - fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODEx(i), csmode); - dev_info(dev, "cs=%d, init_csmode=0x%x\n", i, csmode); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODEx(cs), csmode); + + dev_info(dev, "cs=%u, init_csmode=0x%x\n", cs, csmode); } /* Enable SPI interface */ @@ -660,16 +659,16 @@ static int of_fsl_espi_get_chipselects(struct device *dev) { struct device_node *np = dev->of_node; struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); - const u32 *prop; - int len; + u32 num_cs; + int ret; - prop = of_get_property(np, "fsl,espi-num-chipselects", &len); - if (!prop || len < sizeof(*prop)) { + ret = of_property_read_u32(np, "fsl,espi-num-chipselects", &num_cs); + if (ret) { dev_err(dev, "No 'fsl,espi-num-chipselects' property\n"); return -EINVAL; } - pdata->max_chipselect = *prop; + pdata->max_chipselect = num_cs; pdata->cs_control = NULL; return 0; -- cgit v1.2.3 From e4be7053b9d3aa0a97b311ad77528d8b32236590 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 2 Oct 2016 14:22:35 +0200 Subject: spi: fsl-espi: reject MSB-first transfers with word sizes other than 8 or 16 According to the ESPI spec MSB-first transfers are supported for word size 8 and 16 only. Check for this and reject MSB-first transfers with other word sizes. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 1f97cce615d3..65bb70d3bfc4 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -153,6 +153,7 @@ static int fsl_espi_check_message(struct spi_message *m) first = list_first_entry(&m->transfers, struct spi_transfer, transfer_list); + list_for_each_entry(t, &m->transfers, transfer_list) { if (first->bits_per_word != t->bits_per_word || first->speed_hz != t->speed_hz) { @@ -161,6 +162,15 @@ static int fsl_espi_check_message(struct spi_message *m) } } + /* ESPI supports MSB-first transfers for word size 8 / 16 only */ + if (!(m->spi->mode & SPI_LSB_FIRST) && first->bits_per_word != 8 && + first->bits_per_word != 16) { + dev_err(mspi->dev, + "MSB-first transfer not supported for wordsize %u\n", + first->bits_per_word); + return -EINVAL; + } + return 0; } -- cgit v1.2.3 From 923ab15e1a5ce6248601304440e9f30fbf3bb6ab Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 2 Oct 2016 14:22:57 +0200 Subject: spi: fsl-espi: fix handling of word sizes other than 8 bit The code in fsl_espi_tx_buf_lsb and parts of fsl_espi_setup_transfer look very weird and don't reflect the ESPI spec. ESPI stores values with <= 8 bit word size right justified as 8 bit value and values with > 8 bit word size right justified as 16 bit value. Therefore no such shifting is needed. Only case MSB-first with 8 bit word size is correctly handled, and most likely nobody ever used this driver with a different config. On ESPI only the case LSB-first with word size > 8 bit needs a special handling. In this case a little endian 16 bit value has to be written to the TX FIFO what requires a byte swap as the host system is big endian. The same applies to reading from the RX FIFO. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 84 ++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 48 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 65bb70d3bfc4..eea5123abb38 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -112,6 +112,32 @@ static inline void fsl_espi_write_reg8(struct mpc8xxx_spi *mspi, int offset, iowrite8(val, mspi->reg_base + offset); } +static void fsl_espi_memcpy_swab(void *to, const void *from, + struct spi_message *m, + struct spi_transfer *t) +{ + unsigned int len = t->len; + + if (!(m->spi->mode & SPI_LSB_FIRST) || t->bits_per_word <= 8) { + memcpy(to, from, len); + return; + } + + /* In case of LSB-first and bits_per_word > 8 byte-swap all words */ + while (len) + if (len >= 4) { + *(u32 *)to = swahb32p(from); + to += 4; + from += 4; + len -= 4; + } else { + *(u16 *)to = swab16p(from); + to += 2; + from += 2; + len -= 2; + } +} + static void fsl_espi_copy_to_buf(struct spi_message *m, struct mpc8xxx_spi *mspi) { @@ -120,7 +146,7 @@ static void fsl_espi_copy_to_buf(struct spi_message *m, list_for_each_entry(t, &m->transfers, transfer_list) { if (t->tx_buf) - memcpy(buf, t->tx_buf, t->len); + fsl_espi_memcpy_swab(buf, t->tx_buf, m, t); else memset(buf, 0, t->len); buf += t->len; @@ -135,7 +161,7 @@ static void fsl_espi_copy_from_buf(struct spi_message *m, list_for_each_entry(t, &m->transfers, transfer_list) { if (t->rx_buf) - memcpy(t->rx_buf, buf, t->len); + fsl_espi_memcpy_swab(t->rx_buf, buf, m, t); buf += t->len; } } @@ -194,27 +220,6 @@ static void fsl_espi_change_mode(struct spi_device *spi) local_irq_restore(flags); } -static u32 fsl_espi_tx_buf_lsb(struct mpc8xxx_spi *mpc8xxx_spi) -{ - u32 data; - u16 data_h; - u16 data_l; - const u32 *tx = mpc8xxx_spi->tx; - - if (!tx) - return 0; - - data = *tx++ << mpc8xxx_spi->tx_shift; - data_l = data & 0xffff; - data_h = (data >> 16) & 0xffff; - swab16s(&data_l); - swab16s(&data_h); - data = data_h | data_l; - - mpc8xxx_spi->tx = tx; - return data; -} - static void fsl_espi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { @@ -224,23 +229,6 @@ static void fsl_espi_setup_transfer(struct spi_device *spi, u8 pm; struct spi_mpc8xxx_cs *cs = spi->controller_state; - cs->rx_shift = 0; - cs->tx_shift = 0; - cs->get_rx = mpc8xxx_spi_rx_buf_u32; - cs->get_tx = mpc8xxx_spi_tx_buf_u32; - if (bits_per_word <= 8) { - cs->rx_shift = 8 - bits_per_word; - } else { - cs->rx_shift = 16 - bits_per_word; - if (spi->mode & SPI_LSB_FIRST) - cs->get_tx = fsl_espi_tx_buf_lsb; - } - - mpc8xxx_spi->rx_shift = cs->rx_shift; - mpc8xxx_spi->tx_shift = cs->tx_shift; - mpc8xxx_spi->get_rx = cs->get_rx; - mpc8xxx_spi->get_tx = cs->get_tx; - /* mask out bits we are going to set */ cs->hw_mode &= ~(CSMODE_LEN(0xF) | CSMODE_DIV16 | CSMODE_PM(0xF)); @@ -271,7 +259,6 @@ static void fsl_espi_setup_transfer(struct spi_device *spi, static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); - u32 word; int ret; mpc8xxx_spi->len = t->len; @@ -290,8 +277,8 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, SPIM_RNE); /* transmit word */ - word = mpc8xxx_spi->get_tx(mpc8xxx_spi); - fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPITF, word); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPITF, *(u32 *)mpc8xxx_spi->tx); + mpc8xxx_spi->tx += 4; /* Won't hang up forever, SPI bus sometimes got lost interrupts... */ ret = wait_for_completion_timeout(&mpc8xxx_spi->done, 2 * HZ); @@ -468,8 +455,10 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) mspi->len -= rx_nr_bytes; - if (mspi->rx) - mspi->get_rx(rx_data, mspi); + if (mspi->rx) { + *(u32 *)mspi->rx = rx_data; + mspi->rx += 4; + } } if (!(events & SPIE_TNF)) { @@ -487,9 +476,8 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) mspi->count -= 1; if (mspi->count) { - u32 word = mspi->get_tx(mspi); - - fsl_espi_write_reg(mspi, ESPI_SPITF, word); + fsl_espi_write_reg(mspi, ESPI_SPITF, *(u32 *)mspi->tx); + mspi->tx += 4; } else { complete(&mspi->done); } -- cgit v1.2.3 From af9e53fef7015e1e4fe3f32b35e839df392bf4d6 Mon Sep 17 00:00:00 2001 From: Vikram N Date: Fri, 30 Sep 2016 19:53:11 +0530 Subject: spi: omap2-mcspi: Fix modifying platform resource data currently during probe the resource data gets modified and device physical address remains valid only during first load. If the module is unloaded and loaded again, the ioremp will be done on a incorrect address as the resource was modified during previous module load. This patch fixes this issue. Signed-off-by: Vikram N Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index d5157b2222ce..3567e1dfd30d 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1391,15 +1391,13 @@ static int omap2_mcspi_probe(struct platform_device *pdev) goto free_master; } - r->start += regs_offset; - r->end += regs_offset; - mcspi->phys = r->start; - mcspi->base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(mcspi->base)) { status = PTR_ERR(mcspi->base); goto free_master; } + mcspi->phys = r->start + regs_offset; + mcspi->base += regs_offset; mcspi->dev = &pdev->dev; -- cgit v1.2.3 From 144235ea752b4d56d66fe03bb6b7fae7e0032404 Mon Sep 17 00:00:00 2001 From: Fabien Lahoudere Date: Thu, 6 Oct 2016 16:44:27 +0200 Subject: spi: spidev: Add device to spidev device tree compatibility list Entries are needed in the spidev ID list to configure configure it from a device tree. Add entry for the following device: - "ge,achc" : GE Healthcare USB Management Controller The USB Management Controller does not expose USB to the host, but acts as an offload engine, communicating with specific USB based data acquisition devices which are connected to it, extracting the required data and providing it to the host via other methods. SPI is used as an out-of-band configuration channel. Signed-off-by: Fabien Lahoudere Signed-off-by: Mark Brown --- drivers/spi/spidev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 2e05046f866b..9e2e099baf8c 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -696,6 +696,7 @@ static struct class *spidev_class; static const struct of_device_id spidev_dt_ids[] = { { .compatible = "rohm,dh2228fv" }, { .compatible = "lineartechnology,ltc2488" }, + { .compatible = "ge,achc" }, {}, }; MODULE_DEVICE_TABLE(of, spidev_dt_ids); -- cgit v1.2.3 From 2e9c079cccedbe0d47265ca0c8121c8c66ebb241 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 22 Oct 2016 14:33:17 +0000 Subject: spi: omap2-mcspi: Remove redundant return value check of platform_get_resource() Remove unneeded error handling on the result of a call to platform_get_resource() when the value is passed to devm_ioremap_resource(). Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 3567e1dfd30d..79800e991ccd 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1386,11 +1386,6 @@ static int omap2_mcspi_probe(struct platform_device *pdev) regs_offset = pdata->regs_offset; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (r == NULL) { - status = -ENODEV; - goto free_master; - } - mcspi->base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(mcspi->base)) { status = PTR_ERR(mcspi->base); -- cgit v1.2.3 From 2dd33f9cec90499029fd49ffae2922c3f9ccad11 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 20 Oct 2016 00:42:25 +0200 Subject: spi: imx: support DMA for imx35 Support DMA transfers on imx35 and compatible chipsets (imx31, imx25). If DMA can be used, set the start mode control (SMC) bit to start the SPI burst as soon as data is written into the tx fifo. Configure DMA requests when the fifo is half empty during tx or half full during rx. Signed-off-by: Martin Kaiser Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index deb782f6556c..08124b29665e 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -442,6 +442,7 @@ static void mx51_ecspi_reset(struct spi_imx_data *spi_imx) #define MX31_CSPICTRL_ENABLE (1 << 0) #define MX31_CSPICTRL_MASTER (1 << 1) #define MX31_CSPICTRL_XCH (1 << 2) +#define MX31_CSPICTRL_SMC (1 << 3) #define MX31_CSPICTRL_POL (1 << 4) #define MX31_CSPICTRL_PHA (1 << 5) #define MX31_CSPICTRL_SSCTL (1 << 6) @@ -452,6 +453,10 @@ static void mx51_ecspi_reset(struct spi_imx_data *spi_imx) #define MX35_CSPICTRL_CS_SHIFT 12 #define MX31_CSPICTRL_DR_SHIFT 16 +#define MX31_CSPI_DMAREG 0x10 +#define MX31_DMAREG_RH_DEN (1<<4) +#define MX31_DMAREG_TH_DEN (1<<1) + #define MX31_CSPISTATUS 0x14 #define MX31_STATUS_RR (1 << 3) @@ -511,6 +516,9 @@ static int mx31_config(struct spi_device *spi, struct spi_imx_config *config) (is_imx35_cspi(spi_imx) ? MX35_CSPICTRL_CS_SHIFT : MX31_CSPICTRL_CS_SHIFT); + if (spi_imx->usedma) + reg |= MX31_CSPICTRL_SMC; + writel(reg, spi_imx->base + MXC_CSPICTRL); reg = readl(spi_imx->base + MX31_CSPI_TESTREG); @@ -520,6 +528,13 @@ static int mx31_config(struct spi_device *spi, struct spi_imx_config *config) reg &= ~MX31_TEST_LBC; writel(reg, spi_imx->base + MX31_CSPI_TESTREG); + if (spi_imx->usedma) { + /* configure DMA requests when RXFIFO is half full and + when TXFIFO is half empty */ + writel(MX31_DMAREG_RH_DEN | MX31_DMAREG_TH_DEN, + spi_imx->base + MX31_CSPI_DMAREG); + } + return 0; } @@ -1244,10 +1259,10 @@ static int spi_imx_probe(struct platform_device *pdev) 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. + * Only validated on i.mx35 and i.mx6 now, can remove the constraint + * if validated on other chips. */ - if (is_imx51_ecspi(spi_imx)) { + if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx)) { ret = spi_imx_sdma_init(&pdev->dev, spi_imx, master); if (ret == -EPROBE_DEFER) goto out_clk_put; -- cgit v1.2.3 From 8244bd3ab405a1268223a282b32d28031f7e16fe Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 7 Oct 2016 18:55:47 +0800 Subject: spi: change post transfer udelay() to usleep_range() for long delays The spi_transfer parameter delay_usecs allows specifying a time to wait after transferring a spi message. This wait can be quite long - some devices, such as some Chrome OS ECs, require as much as 2000 usecs after a SPI transaction, before it can respond. (cf: arch/arm64/boot/dts/nvidia/tegra132-norrin.dts: google,cros-ec-spi-msg-delay = <2000> ) Blocking a CPU for 2 msecs in a busy loop like this doesn't seem very friendly to other processes, so change the blocking delay to a sleep to allow other things to use this CPU (or so it can sleep). This should be safe to do, because: (a) A post-transaction delay like this is always specified as a minimum wait time (b) A delay here is most likely not very time sensitive, as it occurs after all data has been transferred (c) This delay occurs in a non-critical section of the spi worker thread so where it is safe to sleep. Two caveats: 1) To avoid penalizing short delays, still use udelay for delays < 10us. 2) usleep_range() very often picks the upper bound, an upper bounds 10% should be plenty. Signed-off-by: Daniel Kurtz Signed-off-by: Mark Brown --- drivers/spi/spi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5787b723b593..42f3e1cb9212 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1034,8 +1034,14 @@ static int spi_transfer_one_message(struct spi_master *master, if (msg->status != -EINPROGRESS) goto out; - if (xfer->delay_usecs) - udelay(xfer->delay_usecs); + if (xfer->delay_usecs) { + u16 us = xfer->delay_usecs; + + if (us <= 10) + udelay(us); + else + usleep_range(us, us + DIV_ROUND_UP(us, 10)); + } if (xfer->cs_change) { if (list_is_last(&xfer->transfer_list, -- cgit v1.2.3 From e3cd6cf425bf40061418edf7b295f654301446fe Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 27 Oct 2016 20:24:19 +0200 Subject: spi: fsl-espi: fix merge conflict for commit "avoid processing uninitalized data on error" Commit 5c0ba57744b1 ("spi: fsl-espi: avoid processing uninitalized data on error") applied fine to stable but caused a merge conflict on next. This patch fixes that. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index a7e4c284d50a..4e8a99d0cb63 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -456,7 +456,7 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) mspi->len -= rx_nr_bytes; if (rx_nr_bytes && mspi->rx) { - mspi->get_rx(rx_data, mspi); + *(u32 *)mspi->rx = rx_data; mspi->rx += 4; } } -- cgit v1.2.3 From e9e128a69af2b5fd2a4e01a59cc7e479ce9b8813 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 27 Oct 2016 21:24:01 +0200 Subject: spi: fsl-espi: improve check for SPI_QE_CPU_MODE SPI_QE_CPU_MODE doesn't exist for ESPI and is set by of_mpc8xxx_spi_probe based on DT property "mode". This property is not defined for ESPI, see Documentation/devicetree/bindings/spi/fsl-spi.txt. So print an error message and bail out if SPI_QE_CPU_MODE is set. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 4e8a99d0cb63..f04c2464e854 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -583,8 +583,9 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem, goto err_probe; if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) { - mpc8xxx_spi->rx_shift = 16; - mpc8xxx_spi->tx_shift = 24; + dev_err(dev, "SPI_QE_CPU_MODE is not supported on ESPI!\n"); + ret = -EINVAL; + goto err_probe; } /* SPI controller initializations */ -- cgit v1.2.3 From 54731265966db742dda09008bd9bbe12ae11e93e Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 27 Oct 2016 21:25:58 +0200 Subject: spi: fsl-espi: fix and improve writing to TX FIFO This change addresses two issues: - If the TX FIFO is full the ISR polls until there's free space again. An ISR should never wait for something. - Currently the number of bytes to transfer is rounded up to the next multiple of 4. For most transfers therefore few bytes remain in the TX FIFO after end of transfer. This would cause the next transfer to fail and as a workaround the ESPI block is disabled / re-enabled in fsl_espi_change_mode. This seems to clear the FIFO's (although it's not mentioned in the spec). With this change the TX FIFO is filled as much as possible initially and whenever the ISR is called. Also the exact number of bytes is transferred. The spinlock protects against a potential race if the first interrupt occurs whilst the TX FIFO is still being initially filled. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 68 ++++++++++++++++++++++++++++------------------ drivers/spi/spi-fsl-lib.h | 2 ++ 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index f04c2464e854..95c1fbfe1cbe 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -54,6 +54,8 @@ #define CSMODE_AFT(x) ((x) << 8) #define CSMODE_CG(x) ((x) << 3) +#define FSL_ESPI_FIFO_SIZE 32 + /* Default mode/csmode for eSPI controller */ #define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(3)) #define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \ @@ -200,6 +202,27 @@ static int fsl_espi_check_message(struct spi_message *m) return 0; } +static void fsl_espi_fill_tx_fifo(struct mpc8xxx_spi *mspi, u32 events) +{ + u32 tx_fifo_avail; + + /* if events is zero transfer has not started and tx fifo is empty */ + tx_fifo_avail = events ? SPIE_TXCNT(events) : FSL_ESPI_FIFO_SIZE; + + while (tx_fifo_avail >= min(4U, mspi->tx_len) && mspi->tx_len) + if (mspi->tx_len >= 4) { + fsl_espi_write_reg(mspi, ESPI_SPITF, *(u32 *)mspi->tx); + mspi->tx += 4; + mspi->tx_len -= 4; + tx_fifo_avail -= 4; + } else { + fsl_espi_write_reg8(mspi, ESPI_SPITF, *(u8 *)mspi->tx); + mspi->tx += 1; + mspi->tx_len -= 1; + tx_fifo_avail -= 1; + } +} + static void fsl_espi_change_mode(struct spi_device *spi) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); @@ -262,7 +285,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) int ret; mpc8xxx_spi->len = t->len; - mpc8xxx_spi->count = roundup(t->len, 4) / 4; + mpc8xxx_spi->tx_len = t->len; mpc8xxx_spi->tx = t->tx_buf; mpc8xxx_spi->rx = t->rx_buf; @@ -276,21 +299,22 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) /* enable rx ints */ fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, SPIM_RNE); - /* transmit word */ - fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPITF, *(u32 *)mpc8xxx_spi->tx); - mpc8xxx_spi->tx += 4; + /* Prevent filling the fifo from getting interrupted */ + spin_lock_irq(&mpc8xxx_spi->lock); + fsl_espi_fill_tx_fifo(mpc8xxx_spi, 0); + spin_unlock_irq(&mpc8xxx_spi->lock); /* Won't hang up forever, SPI bus sometimes got lost interrupts... */ ret = wait_for_completion_timeout(&mpc8xxx_spi->done, 2 * HZ); if (ret == 0) dev_err(mpc8xxx_spi->dev, - "Transaction hanging up (left %d bytes)\n", - mpc8xxx_spi->count); + "Transaction hanging up (left %u bytes)\n", + mpc8xxx_spi->tx_len); /* disable rx ints */ fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, 0); - return mpc8xxx_spi->count > 0 ? -EMSGSIZE : 0; + return mpc8xxx_spi->tx_len > 0 ? -EMSGSIZE : 0; } static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans) @@ -461,26 +485,11 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) } } - if (!(events & SPIE_TNF)) { - int ret; - - /* spin until TX is done */ - ret = spin_event_timeout(((events = fsl_espi_read_reg( - mspi, ESPI_SPIE)) & SPIE_TNF), 1000, 0); - if (!ret) { - dev_err(mspi->dev, "tired waiting for SPIE_TNF\n"); - complete(&mspi->done); - return; - } - } + if (mspi->tx_len) + fsl_espi_fill_tx_fifo(mspi, events); - mspi->count -= 1; - if (mspi->count) { - fsl_espi_write_reg(mspi, ESPI_SPITF, *(u32 *)mspi->tx); - mspi->tx += 4; - } else { + if (!mspi->tx_len && !mspi->len) complete(&mspi->done); - } } static irqreturn_t fsl_espi_irq(s32 irq, void *context_data) @@ -488,10 +497,14 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data) struct mpc8xxx_spi *mspi = context_data; u32 events; + spin_lock(&mspi->lock); + /* Get interrupt events(tx/rx) */ events = fsl_espi_read_reg(mspi, ESPI_SPIE); - if (!events) + if (!events) { + spin_unlock_irq(&mspi->lock); return IRQ_NONE; + } dev_vdbg(mspi->dev, "%s: events %x\n", __func__, events); @@ -500,6 +513,8 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data) /* Clear the events */ fsl_espi_write_reg(mspi, ESPI_SPIE, events); + spin_unlock(&mspi->lock); + return IRQ_HANDLED; } @@ -562,6 +577,7 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem, master->max_message_size = fsl_espi_max_message_size; mpc8xxx_spi = spi_master_get_devdata(master); + spin_lock_init(&mpc8xxx_spi->lock); mpc8xxx_spi->local_buf = devm_kmalloc(dev, SPCOM_TRANLEN_MAX, GFP_KERNEL); diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h index 2925c8089fd9..24d8bc84a111 100644 --- a/drivers/spi/spi-fsl-lib.h +++ b/drivers/spi/spi-fsl-lib.h @@ -30,7 +30,9 @@ struct mpc8xxx_spi { void *rx; #if IS_ENABLED(CONFIG_SPI_FSL_ESPI) int len; + unsigned int tx_len; u8 *local_buf; + spinlock_t lock; #endif int subblock; -- cgit v1.2.3 From f895e27f591228704954cc8927d9c61b3f3da90f Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 27 Oct 2016 21:26:08 +0200 Subject: spi: fsl-espi: Rename len in struct mpc8xxx_spi to rx_len and make it unsigned Now that we introduced element tx_len in struct mpc8xxx_spi let's rename element len to rx_len as it actually is the number of bytes to receive. In addition make it unsigned. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 22 +++++++++++----------- drivers/spi/spi-fsl-lib.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 95c1fbfe1cbe..5a7449f3b3b8 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -284,7 +284,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); int ret; - mpc8xxx_spi->len = t->len; + mpc8xxx_spi->rx_len = t->len; mpc8xxx_spi->tx_len = t->len; mpc8xxx_spi->tx = t->tx_buf; @@ -445,28 +445,28 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) int ret; /* Spin until RX is done */ - if (SPIE_RXCNT(events) < min(4, mspi->len)) { + if (SPIE_RXCNT(events) < min(4U, mspi->rx_len)) { ret = spin_event_timeout( !(SPIE_RXCNT(events = fsl_espi_read_reg(mspi, ESPI_SPIE)) < - min(4, mspi->len)), + min(4U, mspi->rx_len)), 10000, 0); /* 10 msec */ if (!ret) dev_err(mspi->dev, "tired waiting for SPIE_RXCNT\n"); } - if (mspi->len >= 4) { + if (mspi->rx_len >= 4) { rx_data = fsl_espi_read_reg(mspi, ESPI_SPIRF); - } else if (mspi->len <= 0) { + } else if (!mspi->rx_len) { dev_err(mspi->dev, "unexpected RX(SPIE_RNE) interrupt occurred,\n" "(local rxlen %d bytes, reg rxlen %d bytes)\n", - min(4, mspi->len), SPIE_RXCNT(events)); + min(4U, mspi->rx_len), SPIE_RXCNT(events)); rx_nr_bytes = 0; } else { - rx_nr_bytes = mspi->len; - tmp = mspi->len; + rx_nr_bytes = mspi->rx_len; + tmp = mspi->rx_len; rx_data = 0; while (tmp--) { rx_data_8 = fsl_espi_read_reg8(mspi, @@ -474,10 +474,10 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) rx_data |= (rx_data_8 << (tmp * 8)); } - rx_data <<= (4 - mspi->len) * 8; + rx_data <<= (4 - mspi->rx_len) * 8; } - mspi->len -= rx_nr_bytes; + mspi->rx_len -= rx_nr_bytes; if (rx_nr_bytes && mspi->rx) { *(u32 *)mspi->rx = rx_data; @@ -488,7 +488,7 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) if (mspi->tx_len) fsl_espi_fill_tx_fifo(mspi, events); - if (!mspi->tx_len && !mspi->len) + if (!mspi->tx_len && !mspi->rx_len) complete(&mspi->done); } diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h index 24d8bc84a111..35a7a1730d0c 100644 --- a/drivers/spi/spi-fsl-lib.h +++ b/drivers/spi/spi-fsl-lib.h @@ -29,7 +29,7 @@ struct mpc8xxx_spi { const void *tx; void *rx; #if IS_ENABLED(CONFIG_SPI_FSL_ESPI) - int len; + unsigned int rx_len; unsigned int tx_len; u8 *local_buf; spinlock_t lock; -- cgit v1.2.3 From b3bec5f95f73520feb05b90244522f24546e96aa Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 27 Oct 2016 21:26:46 +0200 Subject: spi: fsl-espi: simplify and inline function fsl_espi_change_mode The ESPI spec mentions no requirement to turn off the ESPI unit prior to changing the mode. Most likely the ESPI unit is only turned off to clear the FIFO's as before this patch series single bytes could remain in the TX FIFO after transfer end. Therefore remove disabling / re-enabling the ESPI unit. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 5a7449f3b3b8..d5506852e63c 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -223,26 +223,6 @@ static void fsl_espi_fill_tx_fifo(struct mpc8xxx_spi *mspi, u32 events) } } -static void fsl_espi_change_mode(struct spi_device *spi) -{ - struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); - struct spi_mpc8xxx_cs *cs = spi->controller_state; - u32 tmp; - unsigned long flags; - - /* Turn off IRQs locally to minimize time that SPI is disabled. */ - local_irq_save(flags); - - /* Turn off SPI unit prior changing mode */ - tmp = fsl_espi_read_reg(mspi, ESPI_SPMODE); - fsl_espi_write_reg(mspi, ESPI_SPMODE, tmp & ~SPMODE_ENABLE); - fsl_espi_write_reg(mspi, ESPI_SPMODEx(spi->chip_select), - cs->hw_mode); - fsl_espi_write_reg(mspi, ESPI_SPMODE, tmp); - - local_irq_restore(flags); -} - static void fsl_espi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { @@ -276,7 +256,8 @@ static void fsl_espi_setup_transfer(struct spi_device *spi, cs->hw_mode |= CSMODE_PM(pm); - fsl_espi_change_mode(spi); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODEx(spi->chip_select), + cs->hw_mode); } static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) -- cgit v1.2.3 From db1b049fad8b12062edffade8272d604b4019eb7 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 27 Oct 2016 21:28:02 +0200 Subject: spi: fsl-espi: extend and improve transfer error handling Extend and improve transfer error handling - in case of timeout report also number of remaining rx bytes - in case of timeout return ETIMEDOUT instead of EMSGSIZE - add sanity checks after all bytes have been sent / read: - check that HW has flag SPIE_DON set - check that RX / TX FIFO are empty Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index d5506852e63c..a9593f9691ec 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -289,13 +289,13 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) ret = wait_for_completion_timeout(&mpc8xxx_spi->done, 2 * HZ); if (ret == 0) dev_err(mpc8xxx_spi->dev, - "Transaction hanging up (left %u bytes)\n", - mpc8xxx_spi->tx_len); + "Transaction hanging up (left %u tx bytes, %u rx bytes)\n", + mpc8xxx_spi->tx_len, mpc8xxx_spi->rx_len); /* disable rx ints */ fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, 0); - return mpc8xxx_spi->tx_len > 0 ? -EMSGSIZE : 0; + return ret == 0 ? -ETIMEDOUT : 0; } static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans) @@ -469,8 +469,20 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) if (mspi->tx_len) fsl_espi_fill_tx_fifo(mspi, events); - if (!mspi->tx_len && !mspi->rx_len) - complete(&mspi->done); + if (mspi->tx_len || mspi->rx_len) + return; + + /* we're done, but check for errors before returning */ + events = fsl_espi_read_reg(mspi, ESPI_SPIE); + + if (!(events & SPIE_DON)) + dev_err(mspi->dev, + "Transfer done but SPIE_DON isn't set!\n"); + + if (SPIE_RXCNT(events) || SPIE_TXCNT(events) != FSL_ESPI_FIFO_SIZE) + dev_err(mspi->dev, "Transfer done but rx/tx fifo's aren't empty!\n"); + + complete(&mspi->done); } static irqreturn_t fsl_espi_irq(s32 irq, void *context_data) -- cgit v1.2.3 From e508cea45bc31de87b35180a9ba5ef9572ffde3f Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 27 Oct 2016 21:27:56 +0200 Subject: spi: fsl-espi: make better use of the RX FIFO So far an interrupt is triggered whenever there's at least one byte in the RX FIFO. This results in a unnecessarily high number of interrupts. Change this to generate an interrupt if - RX FIFO is half full (except if all bytes to read fit into the RX FIFO anyway) - end of transfer has been reached This way the number of interrupts can be significantly reduced. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index a9593f9691ec..239f0362df61 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -55,9 +55,10 @@ #define CSMODE_CG(x) ((x) << 3) #define FSL_ESPI_FIFO_SIZE 32 +#define FSL_ESPI_RXTHR 15 /* Default mode/csmode for eSPI controller */ -#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(3)) +#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(FSL_ESPI_RXTHR)) #define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \ | CSMODE_AFT(0) | CSMODE_CG(1)) @@ -263,6 +264,7 @@ static void fsl_espi_setup_transfer(struct spi_device *spi, static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); + u32 mask; int ret; mpc8xxx_spi->rx_len = t->len; @@ -277,8 +279,11 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPCOM, (SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1))); - /* enable rx ints */ - fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, SPIM_RNE); + /* enable interrupts */ + mask = SPIM_DON; + if (mpc8xxx_spi->rx_len > FSL_ESPI_FIFO_SIZE) + mask |= SPIM_RXT; + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, mask); /* Prevent filling the fifo from getting interrupted */ spin_lock_irq(&mpc8xxx_spi->lock); -- cgit v1.2.3 From f05689a662d47896da742f5338eab183ed692c1c Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 27 Oct 2016 21:27:35 +0200 Subject: spi: fsl-espi: fix and improve reading from RX FIFO Currently the driver polls in the ISR for enough bytes in the RX FIFO. An ISR should never do this. Change it to read as much as possible whenever the ISR is called. This also allows to significantly simplify the code. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 67 ++++++++++++++-------------------------------- 1 file changed, 20 insertions(+), 47 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 239f0362df61..2f95b19e67f7 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -224,6 +224,24 @@ static void fsl_espi_fill_tx_fifo(struct mpc8xxx_spi *mspi, u32 events) } } +static void fsl_espi_read_rx_fifo(struct mpc8xxx_spi *mspi, u32 events) +{ + u32 rx_fifo_avail = SPIE_RXCNT(events); + + while (rx_fifo_avail >= min(4U, mspi->rx_len) && mspi->rx_len) + if (mspi->rx_len >= 4) { + *(u32 *)mspi->rx = fsl_espi_read_reg(mspi, ESPI_SPIRF); + mspi->rx += 4; + mspi->rx_len -= 4; + rx_fifo_avail -= 4; + } else { + *(u8 *)mspi->rx = fsl_espi_read_reg8(mspi, ESPI_SPIRF); + mspi->rx += 1; + mspi->rx_len -= 1; + rx_fifo_avail -= 1; + } +} + static void fsl_espi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { @@ -423,53 +441,8 @@ static void fsl_espi_cleanup(struct spi_device *spi) static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) { - /* We need handle RX first */ - if (events & SPIE_RNE) { - u32 rx_data, tmp; - u8 rx_data_8; - int rx_nr_bytes = 4; - int ret; - - /* Spin until RX is done */ - if (SPIE_RXCNT(events) < min(4U, mspi->rx_len)) { - ret = spin_event_timeout( - !(SPIE_RXCNT(events = - fsl_espi_read_reg(mspi, ESPI_SPIE)) < - min(4U, mspi->rx_len)), - 10000, 0); /* 10 msec */ - if (!ret) - dev_err(mspi->dev, - "tired waiting for SPIE_RXCNT\n"); - } - - if (mspi->rx_len >= 4) { - rx_data = fsl_espi_read_reg(mspi, ESPI_SPIRF); - } else if (!mspi->rx_len) { - dev_err(mspi->dev, - "unexpected RX(SPIE_RNE) interrupt occurred,\n" - "(local rxlen %d bytes, reg rxlen %d bytes)\n", - min(4U, mspi->rx_len), SPIE_RXCNT(events)); - rx_nr_bytes = 0; - } else { - rx_nr_bytes = mspi->rx_len; - tmp = mspi->rx_len; - rx_data = 0; - while (tmp--) { - rx_data_8 = fsl_espi_read_reg8(mspi, - ESPI_SPIRF); - rx_data |= (rx_data_8 << (tmp * 8)); - } - - rx_data <<= (4 - mspi->rx_len) * 8; - } - - mspi->rx_len -= rx_nr_bytes; - - if (rx_nr_bytes && mspi->rx) { - *(u32 *)mspi->rx = rx_data; - mspi->rx += 4; - } - } + if (mspi->rx_len) + fsl_espi_read_rx_fifo(mspi, events); if (mspi->tx_len) fsl_espi_fill_tx_fifo(mspi, events); -- cgit v1.2.3 From 66b8053e249c76b0d800805dac7e7dc80c3d7764 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 29 Oct 2016 10:53:19 +0200 Subject: spi: fsl-espi: small fix to error path in fsl_espi_irq spin_lock is used to obtain the spinlock, so spin_unlock has to be used here. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 2f95b19e67f7..1d3c9023391d 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -473,7 +473,7 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data) /* Get interrupt events(tx/rx) */ events = fsl_espi_read_reg(mspi, ESPI_SPIE); if (!events) { - spin_unlock_irq(&mspi->lock); + spin_unlock(&mspi->lock); return IRQ_NONE; } -- cgit v1.2.3 From 73aaf15849d9421fa696c3d7785952d8100042b2 Mon Sep 17 00:00:00 2001 From: Paulo Zaneti Date: Sat, 29 Oct 2016 11:02:19 +0200 Subject: spi: fsl-espi: fix support for all available clock rates According to NXP ESPI datasheet, the SPI clock rate is: spi_clk = System_Clock / ( 2 * DIV16 * ( 1 + PM ) ) Where System_Clock is the platform clock divided by 2, DIV16 may be 1 or 16, and PM is a 4 bits integer (0 to 15). Isolating PM on the expression, we get: PM = (System_Clock / ( 2 * DIV16 * spi_clk ) ) - 1 Where System_Clock = mpc8xxx_spi->spibrg / 2, spi_clk = hz, and DIV16 = 1 or DIV16 = 16. So, PM = (mpc8xxx_spi->spibrg / ( 4 * hz) ) - 1 or PM = (mpc8xxx_spi->spibrg / ( 16 * 4 * hz) ) - 1 Current spi-fsl-espi driver can't configure the HW for all supported clock rates. It filters out clock rates for PM = 0 and PM = 1. This patch allows all range of supported clock rates to be configured on the ESPI controller. Signed-off-by: Paulo Zaneti Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 1d3c9023391d..8b3a28739d9a 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -247,8 +247,7 @@ static void fsl_espi_setup_transfer(struct spi_device *spi, { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); int bits_per_word = t ? t->bits_per_word : spi->bits_per_word; - u32 hz = t ? t->speed_hz : spi->max_speed_hz; - u8 pm; + u32 pm, hz = t ? t->speed_hz : spi->max_speed_hz; struct spi_mpc8xxx_cs *cs = spi->controller_state; /* mask out bits we are going to set */ @@ -256,22 +255,19 @@ static void fsl_espi_setup_transfer(struct spi_device *spi, cs->hw_mode |= CSMODE_LEN(bits_per_word - 1); - if ((mpc8xxx_spi->spibrg / hz) > 64) { + pm = DIV_ROUND_UP(mpc8xxx_spi->spibrg, hz * 4) - 1; + + if (pm > 15) { cs->hw_mode |= CSMODE_DIV16; - pm = DIV_ROUND_UP(mpc8xxx_spi->spibrg, hz * 16 * 4); - - WARN_ONCE(pm > 33, "%s: Requested speed is too low: %d Hz. " - "Will use %d Hz instead.\n", dev_name(&spi->dev), - hz, mpc8xxx_spi->spibrg / (4 * 16 * (32 + 1))); - if (pm > 33) - pm = 33; - } else { - pm = DIV_ROUND_UP(mpc8xxx_spi->spibrg, hz * 4); + pm = DIV_ROUND_UP(mpc8xxx_spi->spibrg, hz * 16 * 4) - 1; + + WARN_ONCE(pm > 15, + "%s: Requested speed is too low: %u Hz. Will use %u Hz instead.\n", + dev_name(&spi->dev), hz, + mpc8xxx_spi->spibrg / (4 * 16 * (15 + 1))); + if (pm > 15) + pm = 15; } - if (pm) - pm--; - if (pm < 2) - pm = 2; cs->hw_mode |= CSMODE_PM(pm); -- cgit v1.2.3 From 196737912da5eab055489e0635662a3b7adef6eb Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Wed, 26 Oct 2016 00:00:31 -0700 Subject: spi: sun4i: Allow transfers larger than FIFO size SPI transfers were limited to one FIFO depth, which is 64 bytes. This was an artificial limitation, however, as the hardware can handle much larger bursts. To accommodate this, we enable the interrupt when the Rx FIFO is 3/4 full, and drain the FIFO within the interrupt handler. The 3/4 ratio was chosen arbitrarily, with the intention to reduce the potential number of interrupts. Since the SUN4I_CTL_TP bit is set, the hardware will pause transmission whenever the FIFO is full, so there is no risk of losing data if we can't service the interrupt in time. For the Tx side, enable and use the Tx FIFO 3/4 empty interrupt to replenish the FIFO on large SPI bursts. This requires more care in when the interrupt is left enabled, as this interrupt will continually trigger when the FIFO is less than 1/4 full, even though we acknowledge it. Signed-off-by: Alexandru Gagniuc Acked-by: Maxime Ripard Signed-off-by: Olliver Schinagl Signed-off-by: Mark Brown --- drivers/spi/spi-sun4i.c | 75 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c index 4969dc10684a..c5cd635c28f3 100644 --- a/drivers/spi/spi-sun4i.c +++ b/drivers/spi/spi-sun4i.c @@ -46,6 +46,8 @@ #define SUN4I_CTL_TP BIT(18) #define SUN4I_INT_CTL_REG 0x0c +#define SUN4I_INT_CTL_RF_F34 BIT(4) +#define SUN4I_INT_CTL_TF_E34 BIT(12) #define SUN4I_INT_CTL_TC BIT(16) #define SUN4I_INT_STA_REG 0x10 @@ -61,11 +63,14 @@ #define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8) #define SUN4I_CLK_CTL_DRS BIT(12) +#define SUN4I_MAX_XFER_SIZE 0xffffff + #define SUN4I_BURST_CNT_REG 0x20 -#define SUN4I_BURST_CNT(cnt) ((cnt) & 0xffffff) +#define SUN4I_BURST_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE) #define SUN4I_XMIT_CNT_REG 0x24 -#define SUN4I_XMIT_CNT(cnt) ((cnt) & 0xffffff) +#define SUN4I_XMIT_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE) + #define SUN4I_FIFO_STA_REG 0x28 #define SUN4I_FIFO_STA_RF_CNT_MASK 0x7f @@ -96,6 +101,31 @@ static inline void sun4i_spi_write(struct sun4i_spi *sspi, u32 reg, u32 value) writel(value, sspi->base_addr + reg); } +static inline u32 sun4i_spi_get_tx_fifo_count(struct sun4i_spi *sspi) +{ + u32 reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG); + + reg >>= SUN4I_FIFO_STA_TF_CNT_BITS; + + return reg & SUN4I_FIFO_STA_TF_CNT_MASK; +} + +static inline void sun4i_spi_enable_interrupt(struct sun4i_spi *sspi, u32 mask) +{ + u32 reg = sun4i_spi_read(sspi, SUN4I_INT_CTL_REG); + + reg |= mask; + sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, reg); +} + +static inline void sun4i_spi_disable_interrupt(struct sun4i_spi *sspi, u32 mask) +{ + u32 reg = sun4i_spi_read(sspi, SUN4I_INT_CTL_REG); + + reg &= ~mask; + sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, reg); +} + static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len) { u32 reg, cnt; @@ -118,10 +148,13 @@ static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len) static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len) { + u32 cnt; u8 byte; - if (len > sspi->len) - len = sspi->len; + /* See how much data we can fit */ + cnt = SUN4I_FIFO_DEPTH - sun4i_spi_get_tx_fifo_count(sspi); + + len = min3(len, (int)cnt, sspi->len); while (len--) { byte = sspi->tx_buf ? *sspi->tx_buf++ : 0; @@ -184,10 +217,10 @@ static int sun4i_spi_transfer_one(struct spi_master *master, u32 reg; /* We don't support transfer larger than the FIFO */ - if (tfr->len > SUN4I_FIFO_DEPTH) + if (tfr->len > SUN4I_MAX_XFER_SIZE) return -EMSGSIZE; - if (tfr->tx_buf && tfr->len >= SUN4I_FIFO_DEPTH) + if (tfr->tx_buf && tfr->len >= SUN4I_MAX_XFER_SIZE) return -EMSGSIZE; reinit_completion(&sspi->done); @@ -286,7 +319,11 @@ static int sun4i_spi_transfer_one(struct spi_master *master, sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1); /* Enable the interrupts */ - sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC); + sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TC | + SUN4I_INT_CTL_RF_F34); + /* Only enable Tx FIFO interrupt if we really need it */ + if (tx_len > SUN4I_FIFO_DEPTH) + sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TF_E34); /* Start the transfer */ reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); @@ -306,7 +343,6 @@ static int sun4i_spi_transfer_one(struct spi_master *master, goto out; } - sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH); out: sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0); @@ -322,10 +358,33 @@ static irqreturn_t sun4i_spi_handler(int irq, void *dev_id) /* Transfer complete */ if (status & SUN4I_INT_CTL_TC) { sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC); + sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH); complete(&sspi->done); return IRQ_HANDLED; } + /* Receive FIFO 3/4 full */ + if (status & SUN4I_INT_CTL_RF_F34) { + sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH); + /* Only clear the interrupt _after_ draining the FIFO */ + sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_RF_F34); + return IRQ_HANDLED; + } + + /* Transmit FIFO 3/4 empty */ + if (status & SUN4I_INT_CTL_TF_E34) { + sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH); + + if (!sspi->len) + /* nothing left to transmit */ + sun4i_spi_disable_interrupt(sspi, SUN4I_INT_CTL_TF_E34); + + /* Only clear the interrupt _after_ re-seeding the FIFO */ + sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TF_E34); + + return IRQ_HANDLED; + } + return IRQ_NONE; } -- cgit v1.2.3 From 32df9ff2b88f9b3ef0865837cd6a39c957dab875 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 1 Nov 2016 22:18:39 +0100 Subject: spi: imx: set spi_bus_clk for mx21 and mx27 Introduce additional output parameter in spi_imx_clkdiv_1() function to return result frequency and set it to spi_bus_clk. This fixes division by zero bug, which occurred in spi_imx_calculate_timeout() function. Signed-off-by: Robert Baldyga Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 08124b29665e..32ced64a5bb9 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -173,15 +173,16 @@ static int mxc_clkdivs[] = {0, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, /* MX21, MX27 */ static unsigned int spi_imx_clkdiv_1(unsigned int fin, - unsigned int fspi, unsigned int max) + unsigned int fspi, unsigned int max, unsigned int *fres) { int i; for (i = 2; i < max; i++) if (fspi * mxc_clkdivs[i] >= fin) - return i; + break; - return max; + *fres = fin / mxc_clkdivs[i]; + return i; } /* MX1, MX31, MX35, MX51 CSPI */ @@ -589,9 +590,12 @@ static int mx21_config(struct spi_device *spi, struct spi_imx_config *config) struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_MASTER; unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18; + unsigned int clk; + + reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, config->speed_hz, max, &clk) + << MX21_CSPICTRL_DR_SHIFT; + spi_imx->spi_bus_clk = clk; - reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, config->speed_hz, max) << - MX21_CSPICTRL_DR_SHIFT; reg |= config->bpw - 1; if (spi->mode & SPI_CPHA) -- cgit v1.2.3 From 8ea7ce9cc6dec26db22a97f00523a4bfd3a97d72 Mon Sep 17 00:00:00 2001 From: Milo Kim Date: Fri, 28 Oct 2016 15:54:11 +0900 Subject: spi: sun6i: Add binding for Allwinner H3 SPI controller H3 SPI has same architecture as A31 except FIFO capacity. To configure the buffer size separately, compatible property should be different. Optional DMA specifiers and example are added. Signed-off-by: Milo Kim Acked-by: Maxime Ripard Acked-by: Rob Herring Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-sun6i.txt | 25 ++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/spi-sun6i.txt b/Documentation/devicetree/bindings/spi/spi-sun6i.txt index 21de73db6a05..2ec99b86b622 100644 --- a/Documentation/devicetree/bindings/spi/spi-sun6i.txt +++ b/Documentation/devicetree/bindings/spi/spi-sun6i.txt @@ -1,7 +1,7 @@ -Allwinner A31 SPI controller +Allwinner A31/H3 SPI controller Required properties: -- compatible: Should be "allwinner,sun6i-a31-spi". +- compatible: Should be "allwinner,sun6i-a31-spi" or "allwinner,sun8i-h3-spi". - reg: Should contain register location and length. - interrupts: Should contain interrupt. - clocks: phandle to the clocks feeding the SPI controller. Two are @@ -12,6 +12,11 @@ Required properties: - resets: phandle to the reset controller asserting this device in reset +Optional properties: +- dmas: DMA specifiers for rx and tx dma. See the DMA client binding, + Documentation/devicetree/bindings/dma/dma.txt +- dma-names: DMA request names should include "rx" and "tx" if present. + Example: spi1: spi@01c69000 { @@ -22,3 +27,19 @@ spi1: spi@01c69000 { clock-names = "ahb", "mod"; resets = <&ahb1_rst 21>; }; + +spi0: spi@01c68000 { + compatible = "allwinner,sun8i-h3-spi"; + reg = <0x01c68000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>; + clock-names = "ahb", "mod"; + dmas = <&dma 23>, <&dma 23>; + dma-names = "rx", "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins>; + resets = <&ccu RST_BUS_SPI0>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; +}; -- cgit v1.2.3 From 10565dfd35488c45826201b4ce28597d6b5de3dd Mon Sep 17 00:00:00 2001 From: Milo Kim Date: Fri, 28 Oct 2016 15:54:12 +0900 Subject: spi: sun6i: Support Allwinner H3 SPI controller H3 has two SPI controllers. The size of the buffer is 64 * 8. (8 bit transfer by 64 entry FIFO) A31 has four controllers. The size of the buffer is 128 * 8. (8 bit transfer by 128 entry FIFO) Register maps are sharable, so sun6i SPI driver is reusable with device configuration. Use the variable, 'fifo_depth' instead of fixed value to support both SPI controllers. Signed-off-by: Milo Kim Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- drivers/spi/spi-sun6i.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index 9918a57a6a6e..e3114832c485 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,7 @@ #include #define SUN6I_FIFO_DEPTH 128 +#define SUN8I_FIFO_DEPTH 64 #define SUN6I_GBL_CTL_REG 0x04 #define SUN6I_GBL_CTL_BUS_ENABLE BIT(0) @@ -90,6 +92,7 @@ struct sun6i_spi { const u8 *tx_buf; u8 *rx_buf; int len; + unsigned long fifo_depth; }; static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg) @@ -155,7 +158,9 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool enable) static size_t sun6i_spi_max_transfer_size(struct spi_device *spi) { - return SUN6I_FIFO_DEPTH - 1; + struct sun6i_spi *sspi = spi_master_get_devdata(spi->master); + + return sspi->fifo_depth - 1; } static int sun6i_spi_transfer_one(struct spi_master *master, @@ -170,7 +175,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master, u32 reg; /* We don't support transfer larger than the FIFO */ - if (tfr->len > SUN6I_FIFO_DEPTH) + if (tfr->len > sspi->fifo_depth) return -EINVAL; reinit_completion(&sspi->done); @@ -265,7 +270,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master, SUN6I_BURST_CTL_CNT_STC(tx_len)); /* Fill the TX FIFO */ - sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH); + sun6i_spi_fill_fifo(sspi, sspi->fifo_depth); /* Enable the interrupts */ sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC); @@ -288,7 +293,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master, goto out; } - sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH); + sun6i_spi_drain_fifo(sspi, sspi->fifo_depth); out: sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0); @@ -398,6 +403,8 @@ static int sun6i_spi_probe(struct platform_device *pdev) } sspi->master = master; + sspi->fifo_depth = (unsigned long)of_device_get_match_data(&pdev->dev); + master->max_speed_hz = 100 * 1000 * 1000; master->min_speed_hz = 3 * 1000; master->set_cs = sun6i_spi_set_cs; @@ -470,7 +477,8 @@ static int sun6i_spi_remove(struct platform_device *pdev) } static const struct of_device_id sun6i_spi_match[] = { - { .compatible = "allwinner,sun6i-a31-spi", }, + { .compatible = "allwinner,sun6i-a31-spi", .data = (void *)SUN6I_FIFO_DEPTH }, + { .compatible = "allwinner,sun8i-h3-spi", .data = (void *)SUN8I_FIFO_DEPTH }, {} }; MODULE_DEVICE_TABLE(of, sun6i_spi_match); -- cgit v1.2.3 From e634b76caf830e802731e3491b24726883d1be98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vok=C3=A1=C4=8D?= Date: Fri, 4 Nov 2016 11:30:03 +0100 Subject: spi: spidev_test: Fix input file check when transferring file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check the input file fd instead of spidev fd. The spidev fd is supposed to be OK otherwise the transfer_file() function would not be called at all. Signed-off-by: Michal Vokáč Reviewed-by: Joshua Clayton Signed-off-by: Mark Brown --- tools/spi/spidev_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/spi/spidev_test.c b/tools/spi/spidev_test.c index f046b77cfefe..816f119c9b7b 100644 --- a/tools/spi/spidev_test.c +++ b/tools/spi/spidev_test.c @@ -315,7 +315,7 @@ static void transfer_file(int fd, char *filename) pabort("can't stat input file"); tx_fd = open(filename, O_RDONLY); - if (fd < 0) + if (tx_fd < 0) pabort("can't open input file"); tx = malloc(sb.st_size); -- cgit v1.2.3 From 3be09bec42a800d4f8ead8119c462f3eb4fad435 Mon Sep 17 00:00:00 2001 From: Hiep Cao Minh Date: Fri, 4 Nov 2016 17:38:54 +0900 Subject: spi: rspi: supports 32bytes buffer for DUAL and QUAD This patch supports 32bytes of buffer for DUAL and QUAD in QSPI by Using Transmit/Receive Buffer Data Triggering Number. In order to improve the DUAL and QUAD's performance of SPI while transferring data in PIO mode, it sends/receives each 32bytes data instead of each byte data as current situation. Signed-off-by: Hiep Cao Minh Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index a816f07e168e..3bab75ab1b25 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -413,7 +413,7 @@ static unsigned int qspi_set_send_trigger(struct rspi_data *rspi, return n; } -static void qspi_set_receive_trigger(struct rspi_data *rspi, unsigned int len) +static int qspi_set_receive_trigger(struct rspi_data *rspi, unsigned int len) { unsigned int n; @@ -428,6 +428,7