From cc4a7ffe02c95f537541c91e9842e3710decae6e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 14 Dec 2016 12:20:55 +0100 Subject: spi: fsl-lpspi: Pre-initialize ret in fsl_lpspi_transfer_one_msg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With gcc 4.1.2: drivers/spi/spi-fsl-lpspi.c: In function ‘fsl_lpspi_transfer_one_msg’: drivers/spi/spi-fsl-lpspi.c:369: warning: ‘ret’ may be used uninitialized in this function If the message contains no transfers, the function will set the message's status to an uninitialized value, and will return that uninitialized value. While __spi_validate() should have been called in all paths leading to this, and thus have rejected such messages, we better pre-initialize ret to be safe for future modifications (spi_transfer_one_message() also does this). Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 52551f6d0c7d..2b93bc605b91 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -366,7 +366,7 @@ static int fsl_lpspi_transfer_one_msg(struct spi_master *master, struct spi_transfer *xfer; bool is_first_xfer = true; u32 temp; - int ret; + int ret = 0; msg->status = 0; msg->actual_length = 0; -- cgit v1.2.3-59-g8ed1b From 22c76326bff810d220fffdbaab949d09e2564067 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 9 Dec 2016 20:48:52 +0100 Subject: spi: spi-ath79: support multiple internal chip select lines Several devices with multiple flash chips use the internal chip select lines. Don't assume that chip select 1 and above are GPIO lines. Signed-off-by: Felix Fietkau Signed-off-by: Mark Brown --- drivers/spi/spi-ath79.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index f369174fbd88..3e9b928b563b 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -78,14 +78,16 @@ static void ath79_spi_chipselect(struct spi_device *spi, int is_active) ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); } - if (spi->chip_select) { + if (gpio_is_valid(spi->cs_gpio)) { /* SPI is normally active-low */ gpio_set_value(spi->cs_gpio, cs_high); } else { + u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select); + if (cs_high) - sp->ioc_base |= AR71XX_SPI_IOC_CS0; + sp->ioc_base |= cs_bit; else - sp->ioc_base &= ~AR71XX_SPI_IOC_CS0; + sp->ioc_base &= ~cs_bit; ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); } @@ -118,11 +120,8 @@ static int ath79_spi_setup_cs(struct spi_device *spi) struct ath79_spi *sp = ath79_spidev_to_sp(spi); int status; - if (spi->chip_select && !gpio_is_valid(spi->cs_gpio)) - return -EINVAL; - status = 0; - if (spi->chip_select) { + if (gpio_is_valid(spi->cs_gpio)) { unsigned long flags; flags = GPIOF_DIR_OUT; @@ -134,10 +133,12 @@ static int ath79_spi_setup_cs(struct spi_device *spi) status = gpio_request_one(spi->cs_gpio, flags, dev_name(&spi->dev)); } else { + u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select); + if (spi->mode & SPI_CS_HIGH) - sp->ioc_base &= ~AR71XX_SPI_IOC_CS0; + sp->ioc_base &= ~cs_bit; else - sp->ioc_base |= AR71XX_SPI_IOC_CS0; + sp->ioc_base |= cs_bit; ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); } @@ -147,7 +148,7 @@ static int ath79_spi_setup_cs(struct spi_device *spi) static void ath79_spi_cleanup_cs(struct spi_device *spi) { - if (spi->chip_select) { + if (gpio_is_valid(spi->cs_gpio)) { gpio_free(spi->cs_gpio); } } -- cgit v1.2.3-59-g8ed1b From 91829a9a25cc931b76b01aa091a52e0edd649a72 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 9 Dec 2016 20:48:53 +0100 Subject: spi: spi-ath79: use gpio_set_value_cansleep for GPIO chip select Signed-off-by: Felix Fietkau Signed-off-by: Mark Brown --- drivers/spi/spi-ath79.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index 3e9b928b563b..b89cee11f418 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -80,7 +80,7 @@ static void ath79_spi_chipselect(struct spi_device *spi, int is_active) if (gpio_is_valid(spi->cs_gpio)) { /* SPI is normally active-low */ - gpio_set_value(spi->cs_gpio, cs_high); + gpio_set_value_cansleep(spi->cs_gpio, cs_high); } else { u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select); -- cgit v1.2.3-59-g8ed1b From c2e51ac3d0542440d5b2b8b52ff2ad00751af4da Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 12 Sep 2016 22:50:41 +0200 Subject: spi: core: Extract of_spi_parse_dt() Extract the parsing of SPI slave-specific properties into its own function, so it can be reused later for SPI slave controllers. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi.c | 60 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 24 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 656dd3e3220c..1861255866d7 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1502,37 +1502,18 @@ err_init_queue: /*-------------------------------------------------------------------------*/ #if defined(CONFIG_OF) -static struct spi_device * -of_register_spi_device(struct spi_master *master, struct device_node *nc) +static int of_spi_parse_dt(struct spi_master *master, struct spi_device *spi, + struct device_node *nc) { - struct spi_device *spi; - int rc; u32 value; - - /* Alloc an spi_device */ - spi = spi_alloc_device(master); - if (!spi) { - dev_err(&master->dev, "spi_device alloc error for %s\n", - nc->full_name); - rc = -ENOMEM; - goto err_out; - } - - /* Select device driver */ - rc = of_modalias_node(nc, spi->modalias, - sizeof(spi->modalias)); - if (rc < 0) { - dev_err(&master->dev, "cannot find modalias for %s\n", - nc->full_name); - goto err_out; - } + int rc; /* Device address */ rc = of_property_read_u32(nc, "reg", &value); if (rc) { dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n", nc->full_name, rc); - goto err_out; + return rc; } spi->chip_select = value; @@ -1590,10 +1571,41 @@ of_register_spi_device(struct spi_master *master, struct device_node *nc) if (rc) { dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n", nc->full_name, rc); - goto err_out; + return rc; } spi->max_speed_hz = value; + return 0; +} + +static struct spi_device * +of_register_spi_device(struct spi_master *master, struct device_node *nc) +{ + struct spi_device *spi; + int rc; + + /* Alloc an spi_device */ + spi = spi_alloc_device(master); + if (!spi) { + dev_err(&master->dev, "spi_device alloc error for %s\n", + nc->full_name); + rc = -ENOMEM; + goto err_out; + } + + /* Select device driver */ + rc = of_modalias_node(nc, spi->modalias, + sizeof(spi->modalias)); + if (rc < 0) { + dev_err(&master->dev, "cannot find modalias for %s\n", + nc->full_name); + goto err_out; + } + + rc = of_spi_parse_dt(master, spi, nc); + if (rc) + goto err_out; + /* Store a pointer to the node in the device structure */ of_node_get(nc); spi->dev.of_node = nc; -- cgit v1.2.3-59-g8ed1b From 0cc059abac0dc687dc714f3ec2c8d8a134132f56 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 16 Dec 2016 12:33:59 +0300 Subject: spi: armada-3700: Remove unnecessary condition We checked that "a3700_spi->wait_mask & cause" was set at the beginning of the function so we don't need to check again here. Signed-off-by: Dan Carpenter Acked-by: Romain Perier Signed-off-by: Mark Brown --- drivers/spi/spi-armada-3700.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index 4e921782652f..4e68f34957cc 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -340,8 +340,7 @@ static irqreturn_t a3700_spi_interrupt(int irq, void *dev_id) spireg_write(a3700_spi, A3700_SPI_INT_STAT_REG, cause); /* Wake up the transfer */ - if (a3700_spi->wait_mask & cause) - complete(&a3700_spi->done); + complete(&a3700_spi->done); return IRQ_HANDLED; } -- cgit v1.2.3-59-g8ed1b From 23e291c2e4c84a40a4b3de8539dec95bfda214f1 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 16 Dec 2016 16:59:16 -0800 Subject: spi: rockchip: support "sleep" pin configuration In the pattern of many other devices, support a system-sleep pin configuration. Signed-off-by: Brian Norris Reviewed-by: Douglas Anderson Tested-by: Caesar Wang Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-rockchip.txt | 7 +++++++ drivers/spi/spi-rockchip.c | 5 +++++ 2 files changed, 12 insertions(+) (limited to 'drivers/spi') diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.txt b/Documentation/devicetree/bindings/spi/spi-rockchip.txt index d2ca153614f9..83da4931d832 100644 --- a/Documentation/devicetree/bindings/spi/spi-rockchip.txt +++ b/Documentation/devicetree/bindings/spi/spi-rockchip.txt @@ -31,6 +31,10 @@ Optional Properties: - rx-sample-delay-ns: nanoseconds to delay after the SCLK edge before sampling Rx data (may need to be fine tuned for high capacitance lines). No delay (0) by default. +- pinctrl-names: Names for the pin configuration(s); may be "default" or + "sleep", where the "sleep" configuration may describe the state + the pins should be in during system suspend. See also + pinctrl/pinctrl-bindings.txt. Example: @@ -46,4 +50,7 @@ Example: interrupts = ; clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>; clock-names = "spiclk", "apb_pclk"; + pinctrl-0 = <&spi1_pins>; + pinctrl-1 = <&spi1_sleep>; + pinctrl-names = "default", "sleep"; }; diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 0f89c2169c24..acf31f36b898 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -843,6 +844,8 @@ static int rockchip_spi_suspend(struct device *dev) clk_disable_unprepare(rs->apb_pclk); } + pinctrl_pm_select_sleep_state(dev); + return ret; } @@ -852,6 +855,8 @@ static int rockchip_spi_resume(struct device *dev) struct spi_master *master = dev_get_drvdata(dev); struct rockchip_spi *rs = spi_master_get_devdata(master); + pinctrl_pm_select_default_state(dev); + if (!pm_runtime_suspended(dev)) { ret = clk_prepare_enable(rs->apb_pclk); if (ret < 0) -- cgit v1.2.3-59-g8ed1b From 279e4af7b4bebc6a5bf2d0e5b3209f3dcea94a19 Mon Sep 17 00:00:00 2001 From: Jaedon Shin Date: Fri, 30 Dec 2016 15:30:00 +0900 Subject: spi: bcm-qspi: Enable the driver on BMIPS_GENERIC The Broadcom BCM7XXX ARM and MIPS based SoCs share a similar hardware block for SPI. Signed-off-by: Jaedon Shin Acked-by: Florian Fainelli Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ec4aa252d6e8..c982a01022ba 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -162,7 +162,8 @@ config SPI_BCM63XX_HSSPI config SPI_BCM_QSPI tristate "Broadcom BSPI and MSPI controller support" - depends on ARCH_BRCMSTB || ARCH_BCM || ARCH_BCM_IPROC || COMPILE_TEST + depends on ARCH_BRCMSTB || ARCH_BCM || ARCH_BCM_IPROC || \ + BMIPS_GENERIC || COMPILE_TEST default ARCH_BCM_IPROC help Enables support for the Broadcom SPI flash and MSPI controller. -- cgit v1.2.3-59-g8ed1b From 78d759daceaf0a7058f37c4142bdca9948b6d987 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Thu, 29 Dec 2016 17:27:55 +0100 Subject: spi: bcm53xx: set of_node to let DT specify device(s) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setting of_node of master's dev seems to be a common way of letting it work nicely with DT. This allows specifying device there instead of hardcoding one in the driver code. This was successfully tested with commit 1b47b98acce2 ("ARM: BCM5301X: Add DT entry for SPI controller and NOR flash") Signed-off-by: Rafał Miłecki Signed-off-by: Mark Brown --- drivers/spi/spi-bcm53xx.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c index afb51699dbb5..0c61ad4edb1a 100644 --- a/drivers/spi/spi-bcm53xx.c +++ b/drivers/spi/spi-bcm53xx.c @@ -275,10 +275,6 @@ static int bcm53xxspi_flash_read(struct spi_device *spi, * 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), {}, @@ -311,6 +307,7 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core) b53spi->bspi = true; bcm53xxspi_disable_bspi(b53spi); + master->dev.of_node = dev->of_node; master->transfer_one = bcm53xxspi_transfer_one; if (b53spi->mmio_base) master->spi_flash_read = bcm53xxspi_flash_read; @@ -324,9 +321,6 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core) return err; } - /* Broadcom SoCs (at least with the CC rev 42) use SPI for flash only */ - spi_new_device(master, &bcm53xx_info); - return 0; } -- cgit v1.2.3-59-g8ed1b From cfd6693c06324174ceeac7aed570a0df67db7c4f Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Wed, 21 Dec 2016 11:10:30 +0100 Subject: spi: armada-3700: Replaced raw values for nbits by the SPI macros Currently, function a3700_spi_pin_mode_set() configures the SPI transfer mode according to the value passed as second argument. This value is detected using the raw values from a switch case. This commit replaces these raw values by the corresponding macro constants in linux/spi/spi.h Signed-off-by: Romain Perier Signed-off-by: Mark Brown --- drivers/spi/spi-armada-3700.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index 4e68f34957cc..9bee56ddff39 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -170,12 +170,12 @@ static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi, val &= ~(A3700_SPI_DATA_PIN0 | A3700_SPI_DATA_PIN1); switch (pin_mode) { - case 1: + case SPI_NBITS_SINGLE: break; - case 2: + case SPI_NBITS_DUAL: val |= A3700_SPI_DATA_PIN0; break; - case 4: + case SPI_NBITS_QUAD: val |= A3700_SPI_DATA_PIN1; break; default: -- cgit v1.2.3-59-g8ed1b From 85798e153e6c3834ab2d69ee9d4db7d85f13809d Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Wed, 21 Dec 2016 11:10:29 +0100 Subject: spi: armada-3700: Coding style fixes The following warning are reported by checkpatch.pl: CHECK: Alignment should match open parenthesis +static void a3700_spi_transfer_setup(struct spi_device *spi, + struct spi_transfer *xfer) WARNING: Missing a blank line after declarations + u32 data = le32_to_cpu(val); + memcpy(a3700_spi->rx_buf, &data, 4); total: 0 errors, 1 warnings, 1 checks, 923 lines checked Signed-off-by: Romain Perier Signed-off-by: Mark Brown --- drivers/spi/spi-armada-3700.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index 9bee56ddff39..0baa69325e78 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -420,7 +420,7 @@ static void a3700_spi_fifo_thres_set(struct a3700_spi *a3700_spi, } static void a3700_spi_transfer_setup(struct spi_device *spi, - struct spi_transfer *xfer) + struct spi_transfer *xfer) { struct a3700_spi *a3700_spi; unsigned int byte_len; @@ -561,6 +561,7 @@ static int a3700_spi_fifo_read(struct a3700_spi *a3700_spi) val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG); if (a3700_spi->buf_len >= 4) { u32 data = le32_to_cpu(val); + memcpy(a3700_spi->rx_buf, &data, 4); a3700_spi->buf_len -= 4; -- cgit v1.2.3-59-g8ed1b From ffcfae3823751c72b615b57f700e563667002d09 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 4 Jan 2017 11:15:07 +0100 Subject: spi: rspi: Remove useless memory allocation failure message Printing an error on memory allocation failure is unnecessary. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 9daf50031737..58b7e68013f3 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -1227,10 +1227,8 @@ static int rspi_probe(struct platform_device *pdev) const struct spi_ops *ops; master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data)); - if (master == NULL) { - dev_err(&pdev->dev, "spi_alloc_master error.\n"); + if (master == NULL) return -ENOMEM; - } of_id = of_match_device(rspi_of_match, &pdev->dev); if (of_id) { -- cgit v1.2.3-59-g8ed1b From e7ad4a73364c21f40963a35631b285b60fa3198c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 4 Jan 2017 11:15:08 +0100 Subject: spi: sh-msiof: Remove useless memory allocation failure message Printing an error on memory allocation failure is unnecessary. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 1f00eeb0b5a3..2ce15ca97782 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -1164,10 +1164,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) int ret; master = spi_alloc_master(&pdev->dev, sizeof(struct sh_msiof_spi_priv)); - if (master == NULL) { - dev_err(&pdev->dev, "failed to allocate spi master\n"); + if (master == NULL) return -ENOMEM; - } p = spi_master_get_devdata(master); -- cgit v1.2.3-59-g8ed1b From 25014521603f70225c1e6fa232839614f7b4f692 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Jan 2017 13:47:31 +0200 Subject: spi: pxa2xx-pci: Enable DMA for Intel Merrifield SPI controller on Intel Merrifield is backed by DMA engine. Add necessary bits to support it. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 58d2d48e16a5..868452d8e3e1 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -41,6 +41,13 @@ struct pxa_spi_info { static struct dw_dma_slave byt_tx_param = { .dst_id = 0 }; static struct dw_dma_slave byt_rx_param = { .src_id = 1 }; +static struct dw_dma_slave mrfld3_tx_param = { .dst_id = 15 }; +static struct dw_dma_slave mrfld3_rx_param = { .src_id = 14 }; +static struct dw_dma_slave mrfld5_tx_param = { .dst_id = 13 }; +static struct dw_dma_slave mrfld5_rx_param = { .src_id = 12 }; +static struct dw_dma_slave mrfld6_tx_param = { .dst_id = 11 }; +static struct dw_dma_slave mrfld6_rx_param = { .src_id = 10 }; + static struct dw_dma_slave bsw0_tx_param = { .dst_id = 0 }; static struct dw_dma_slave bsw0_rx_param = { .src_id = 1 }; static struct dw_dma_slave bsw1_tx_param = { .dst_id = 6 }; @@ -93,22 +100,39 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { + struct pci_dev *dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); + struct dw_dma_slave *tx, *rx; + switch (PCI_FUNC(dev->devfn)) { case 0: c->port_id = 3; c->num_chipselect = 1; + c->tx_param = &mrfld3_tx_param; + c->rx_param = &mrfld3_rx_param; break; case 1: c->port_id = 5; c->num_chipselect = 4; + c->tx_param = &mrfld5_tx_param; + c->rx_param = &mrfld5_rx_param; break; case 2: c->port_id = 6; c->num_chipselect = 1; + c->tx_param = &mrfld6_tx_param; + c->rx_param = &mrfld6_rx_param; break; default: return -ENODEV; } + + tx = c->tx_param; + tx->dma_dev = &dma_dev->dev; + + rx = c->rx_param; + rx->dma_dev = &dma_dev->dev; + + c->dma_filter = lpss_dma_filter; return 0; } -- cgit v1.2.3-59-g8ed1b From 66459c5a50a787c474b734b586328f7111ab6df0 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Fri, 6 Jan 2017 04:22:18 -0800 Subject: spi: imx: adjust watermark level according to transfer length Previously DMA watermark level is configured to fifosize/2, DMA mode can be used only when transfer length can be divided by 'watermark level * bpw', which makes DMA mode not pratical. This patch adjusts watermark level to largest number (no bigger than fifosize/2) which can divide 'tranfer length / bpw' for each transfer. Signed-off-by: Jiada Wang Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 32ced64a5bb9..9a7c62f471dc 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -211,7 +211,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *transfer) { struct spi_imx_data *spi_imx = spi_master_get_devdata(master); - unsigned int bpw; + unsigned int bpw, i; if (!master->dma_rx) return false; @@ -228,12 +228,16 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, if (bpw != 1 && bpw != 2 && bpw != 4) return false; - if (transfer->len < spi_imx->wml * bpw) - return false; + for (i = spi_imx_get_fifosize(spi_imx) / 2; i > 0; i--) { + if (!(transfer->len % (i * bpw))) + break; + } - if (transfer->len % (spi_imx->wml * bpw)) + if (i == 0) return false; + spi_imx->wml = i; + return true; } @@ -837,10 +841,6 @@ static int spi_imx_dma_configure(struct spi_master *master, struct dma_slave_config rx = {}, tx = {}; struct spi_imx_data *spi_imx = spi_master_get_devdata(master); - if (bytes_per_word == spi_imx->bytes_per_word) - /* Same as last time */ - return 0; - switch (bytes_per_word) { case 4: buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; -- cgit v1.2.3-59-g8ed1b From e360e72e715f228e426edf0fc99ffa34027ab0ad Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Thu, 29 Dec 2016 20:13:13 +0100 Subject: spi: bcm53xx: (re)license code to the GPL v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My intention was to release this code under GPL v2 license. For some reason my initial commit 0fc6a323e191 ("spi: bcm53xx: driver for SPI controller on Broadcom bcma SoC") totally missed licensing info. MODULE_LICENSE was later added by Axel specifying "GNU Public License v2 or later". This patch clarifies situation by adding a proper header (with Copyright line) and adjusting MODULE_LICENSE. It should be acked by every driver contributor. Signed-off-by: Rafał Miłecki Acked-by: Nicholas Mc Guire Reviewed-by: Jingoo Han Acked-by: Jingoo Han Acked-by: Joe Perches Acked-by: Axel Lin Acked-by: Vaishali Thakkar Signed-off-by: Mark Brown --- drivers/spi/spi-bcm53xx.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c index 0c61ad4edb1a..6e409eabe1c9 100644 --- a/drivers/spi/spi-bcm53xx.c +++ b/drivers/spi/spi-bcm53xx.c @@ -1,3 +1,11 @@ +/* + * Copyright (C) 2014-2016 Rafał Miłecki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include @@ -355,4 +363,4 @@ module_exit(bcm53xxspi_module_exit); MODULE_DESCRIPTION("Broadcom BCM53xx SPI Controller driver"); MODULE_AUTHOR("Rafał Miłecki "); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From e70002c80d4de20a5c61c16ecd4f40a48be3efcf Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Fri, 6 Jan 2017 17:35:13 +0800 Subject: spi: dw: Make debugfs use bus num and make irq name unique Instead of using device name it was suggested that bus number was more appropriate to differentiate debugfs names. Also reduce buffer size to more realistic 32 bytes instead of 128. When request_irq is called the bus number may not be assigned. Therefore the irq name was not unique when dynamic bus number was being used. As per most of the spi drivers use the device name instead. No other use of dws->name could be found so it was removed. Signed-off-by: Phil Reid Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 8 ++++---- drivers/spi/spi-dw.h | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 054012f87567..b217c22ff72f 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -107,9 +107,9 @@ static const struct file_operations dw_spi_regs_ops = { static int dw_spi_debugfs_init(struct dw_spi *dws) { - char name[128]; + char name[32]; - snprintf(name, 128, "dw_spi-%s", dev_name(&dws->master->dev)); + snprintf(name, 32, "dw_spi%d", dws->master->bus_num); dws->debugfs = debugfs_create_dir(name, NULL); if (!dws->debugfs) return -ENOMEM; @@ -486,9 +486,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) dws->type = SSI_MOTO_SPI; dws->dma_inited = 0; dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR); - snprintf(dws->name, sizeof(dws->name), "dw_spi%d", dws->bus_num); - ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dws->name, master); + ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev), + master); if (ret < 0) { dev_err(dev, "can not get IRQ\n"); goto err_free_master; diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index c21ca02f8ec5..da5eab62df34 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -101,7 +101,6 @@ struct dw_spi_dma_ops { struct dw_spi { struct spi_master *master; enum dw_ssi_type type; - char name[16]; void __iomem *regs; unsigned long paddr; -- cgit v1.2.3-59-g8ed1b From 3d63a47a380a873408dad10ca62bd8299b2208f1 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 9 Jan 2017 11:36:10 +0100 Subject: spi: s3c64xx: Don't request/release DMA channels for each SPI transfer Requesting a DMA channel might be a time consuming operation, so there is no need to acquire and release DMA channel for each SPI transfer. DMA channels can be requested during driver probe and kept all the time, also because there are no shared nor dynamically allocated channels on Samsung S3C/S5P/Exynos platforms. While moving dma_requrest_slave_channel calls, lets switch to dma_request_slave_channel_reason(), which returns error codes on failure, which can be properly propagated to the caller (this for example defers SPI probe when DMA controller is not yet available). Signed-off-by: Marek Szyprowski Reviewed-by: Andi Shyti Tested-by: Andi Shyti Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 57 ++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 28 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 28dfdce4beae..849ee82483e4 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -341,43 +341,16 @@ static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable) static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) { struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); - struct device *dev = &sdd->pdev->dev; if (is_polling(sdd)) return 0; - /* Acquire DMA channels */ - sdd->rx_dma.ch = dma_request_slave_channel(dev, "rx"); - if (!sdd->rx_dma.ch) { - dev_err(dev, "Failed to get RX DMA channel\n"); - return -EBUSY; - } spi->dma_rx = sdd->rx_dma.ch; - - sdd->tx_dma.ch = dma_request_slave_channel(dev, "tx"); - if (!sdd->tx_dma.ch) { - dev_err(dev, "Failed to get TX DMA channel\n"); - dma_release_channel(sdd->rx_dma.ch); - return -EBUSY; - } spi->dma_tx = sdd->tx_dma.ch; return 0; } -static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) -{ - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); - - /* Free DMA channels */ - if (!is_polling(sdd)) { - dma_release_channel(sdd->rx_dma.ch); - dma_release_channel(sdd->tx_dma.ch); - } - - return 0; -} - static bool s3c64xx_spi_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) @@ -1094,7 +1067,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer; master->prepare_message = s3c64xx_spi_prepare_message; master->transfer_one = s3c64xx_spi_transfer_one; - master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer; master->num_chipselect = sci->num_cs; master->dma_alignment = 8; master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | @@ -1161,6 +1133,24 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) } } + if (!is_polling(sdd)) { + /* Acquire DMA channels */ + sdd->rx_dma.ch = dma_request_slave_channel_reason(&pdev->dev, + "rx"); + if (IS_ERR(sdd->rx_dma.ch)) { + dev_err(&pdev->dev, "Failed to get RX DMA channel\n"); + ret = PTR_ERR(sdd->rx_dma.ch); + goto err_disable_io_clk; + } + sdd->tx_dma.ch = dma_request_slave_channel_reason(&pdev->dev, + "tx"); + if (IS_ERR(sdd->tx_dma.ch)) { + dev_err(&pdev->dev, "Failed to get TX DMA channel\n"); + ret = PTR_ERR(sdd->tx_dma.ch); + goto err_release_tx_dma; + } + } + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_active(&pdev->dev); @@ -1206,6 +1196,12 @@ err_pm_put: pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); + if (!is_polling(sdd)) + dma_release_channel(sdd->rx_dma.ch); +err_release_tx_dma: + if (!is_polling(sdd)) + dma_release_channel(sdd->tx_dma.ch); +err_disable_io_clk: clk_disable_unprepare(sdd->ioclk); err_disable_src_clk: clk_disable_unprepare(sdd->src_clk); @@ -1226,6 +1222,11 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) writel(0, sdd->regs + S3C64XX_SPI_INT_EN); + if (!is_polling(sdd)) { + dma_release_channel(sdd->rx_dma.ch); + dma_release_channel(sdd->tx_dma.ch); + } + clk_disable_unprepare(sdd->ioclk); clk_disable_unprepare(sdd->src_clk); -- cgit v1.2.3-59-g8ed1b From 102ecc471b9d2f41f10c586f077a0d8e853335f8 Mon Sep 17 00:00:00 2001 From: Gao Pan Date: Wed, 4 Jan 2017 17:38:16 +0800 Subject: spi: fsl-lpspi: fix indentation error This patch fixes the indentation error in spi-fsl-lpspi.c. Signed-off-by: Gao Pan Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 2b93bc605b91..cb3c73007ca1 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -512,9 +512,9 @@ static int fsl_lpspi_remove(struct platform_device *pdev) static struct platform_driver fsl_lpspi_driver = { .driver = { - .name = DRIVER_NAME, - .of_match_table = fsl_lpspi_dt_ids, - }, + .name = DRIVER_NAME, + .of_match_table = fsl_lpspi_dt_ids, + }, .probe = fsl_lpspi_probe, .remove = fsl_lpspi_remove, }; -- cgit v1.2.3-59-g8ed1b From 9c6a3af003c06ef1efc5e243cdbab1be4cb90753 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 3 Jan 2017 18:04:27 +0100 Subject: spi: make falcon-spi bool Falcon spi accesses some ebu functions which are not exported and can not be accessed when build as module. Make this module bool instead. Signed-off-by: Hauke Mehrtens Acked-by: Thomas Langer Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ec4aa252d6e8..e3c256685235 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -263,7 +263,7 @@ config SPI_EP93XX mode. config SPI_FALCON - tristate "Falcon SPI controller support" + bool "Falcon SPI controller support" depends on SOC_FALCON help The external bus unit (EBU) found on the FALC-ON SoC has SPI -- cgit v1.2.3-59-g8ed1b From 72bc7ae0633e2b580217d254114ac6650380b7f6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 13 Jan 2017 10:42:53 +0300 Subject: spi: s3c64xx: potential oops on probe error We accidentally mixed up freeing the rx and tx channels which would a leak and an oops. Fixes: 3d63a47a380a ("spi: s3c64xx: Don't request/release DMA channels for each SPI transfer") Signed-off-by: Dan Carpenter Acked-by: Marek Szyprowski Acked-by: Andi Shyti Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 849ee82483e4..b8cd356d8d10 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -1147,7 +1147,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) if (IS_ERR(sdd->tx_dma.ch)) { dev_err(&pdev->dev, "Failed to get TX DMA channel\n"); ret = PTR_ERR(sdd->tx_dma.ch); - goto err_release_tx_dma; + goto err_release_rx_dma; } } @@ -1196,11 +1196,11 @@ err_pm_put: pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); - if (!is_polling(sdd)) - dma_release_channel(sdd->rx_dma.ch); -err_release_tx_dma: if (!is_polling(sdd)) dma_release_channel(sdd->tx_dma.ch); +err_release_rx_dma: + if (!is_polling(sdd)) + dma_release_channel(sdd->rx_dma.ch); err_disable_io_clk: clk_disable_unprepare(sdd->ioclk); err_disable_src_clk: -- cgit v1.2.3-59-g8ed1b From b03124825b8612bf371e5b4ccc2cd812ed3c2dbb Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 16 Jan 2017 19:44:54 +0100 Subject: spi: pxa2xx: Factor out handle_bad_msg As suggested by Andy Shevchenko: Decouple this corner cause from the general handling logic in ssp_int. Signed-off-by: Jan Kiszka Reviewed-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index d6239fa718be..8c65bc1823f3 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -732,6 +732,20 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) return IRQ_HANDLED; } +static void handle_bad_msg(struct driver_data *drv_data) +{ + pxa2xx_spi_write(drv_data, SSCR0, + pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE); + pxa2xx_spi_write(drv_data, SSCR1, + pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1); + if (!pxa25x_ssp_comp(drv_data)) + pxa2xx_spi_write(drv_data, SSTO, 0); + write_SSSR_CS(drv_data, drv_data->clear_sr); + + dev_err(&drv_data->pdev->dev, + "bad message state in interrupt handler\n"); +} + static irqreturn_t ssp_int(int irq, void *dev_id) { struct driver_data *drv_data = dev_id; @@ -772,20 +786,7 @@ static irqreturn_t ssp_int(int irq, void *dev_id) return IRQ_NONE; if (!drv_data->master->cur_msg) { - - pxa2xx_spi_write(drv_data, SSCR0, - pxa2xx_spi_read(drv_data, SSCR0) - & ~SSCR0_SSE); - pxa2xx_spi_write(drv_data, SSCR1, - pxa2xx_spi_read(drv_data, SSCR1) - & ~drv_data->int_cr1); - if (!pxa25x_ssp_comp(drv_data)) - pxa2xx_spi_write(drv_data, SSTO, 0); - write_SSSR_CS(drv_data, drv_data->clear_sr); - - dev_err(&drv_data->pdev->dev, - "bad message state in interrupt handler\n"); - + handle_bad_msg(drv_data); /* Never fail */ return IRQ_HANDLED; } -- cgit v1.2.3-59-g8ed1b From f9bdb7fdd2cac17bdc9c344b6036e6939fa087cd Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 13 Jan 2017 12:28:04 +0100 Subject: spi: Use kcalloc() in spi_register_board_info() A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus reuse the corresponding function "kcalloc". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- drivers/spi/spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 656dd3e3220c..8c05f27bf642 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -672,7 +672,7 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n) if (!n) return -EINVAL; - bi = kzalloc(n * sizeof(*bi), GFP_KERNEL); + bi = kcalloc(n, sizeof(*bi), GFP_KERNEL); if (!bi) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From d9bc4a8539a518636cd70d498e94787e32ea8fbe Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 13 Jan 2017 13:37:25 +0100 Subject: spi: fsl: Use kmalloc_array() in of_fsl_spi_get_chipselects() A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-spi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 8b290d9d7935..9873d39d1a95 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -727,7 +727,8 @@ static int of_fsl_spi_get_chipselects(struct device *dev) return 0; } - pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL); + pinfo->gpios = kmalloc_array(ngpios, sizeof(*pinfo->gpios), + GFP_KERNEL); if (!pinfo->gpios) return -ENOMEM; memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios)); -- cgit v1.2.3-59-g8ed1b From 5223db0b10c7917d7c6b4f7d8e2c0af0eb1158f5 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 13 Jan 2017 13:33:02 +0100 Subject: spi: fsl: Use kcalloc() in of_fsl_spi_get_chipselects() A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus reuse the corresponding function "kcalloc". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 9873d39d1a95..cdee556037f9 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -733,7 +733,7 @@ static int of_fsl_spi_get_chipselects(struct device *dev) return -ENOMEM; memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios)); - pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags), + pinfo->alow_flags = kcalloc(ngpios, sizeof(*pinfo->alow_flags), GFP_KERNEL); if (!pinfo->alow_flags) { ret = -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 31ae779421098e9a58a3f10e1e09b2c63f4514fa Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 13 Jan 2017 13:50:21 +0100 Subject: spi: fsl: Combine substrings for two messages The script "checkpatch.pl" pointed information out like the following. WARNING: quoted string split across lines Thus fix the affected source code places. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-spi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index cdee556037f9..0fc3452652ae 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -267,10 +267,9 @@ static int fsl_spi_setup_transfer(struct spi_device *spi, if ((mpc8xxx_spi->spibrg / hz) > 64) { cs->hw_mode |= SPMODE_DIV16; pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1; - - WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. " - "Will use %d Hz instead.\n", dev_name(&spi->dev), - hz, mpc8xxx_spi->spibrg / 1024); + WARN_ONCE(pm > 16, + "%s: Requested speed is too low: %d Hz. Will use %d Hz instead.\n", + dev_name(&spi->dev), hz, mpc8xxx_spi->spibrg / 1024); if (pm > 16) pm = 16; } else { @@ -763,8 +762,9 @@ static int of_fsl_spi_get_chipselects(struct device *dev) ret = gpio_direction_output(pinfo->gpios[i], pinfo->alow_flags[i]); if (ret) { - dev_err(dev, "can't set output direction for gpio " - "#%d: %d\n", i, ret); + dev_err(dev, + "can't set output direction for gpio #%d: %d\n", + i, ret); goto err_loop; } } -- cgit v1.2.3-59-g8ed1b From 8b6c8955b5dc21358cb1f67cadc5514d2353375d Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 13 Jan 2017 14:06:10 +0100 Subject: spi/mpc52xx: Use kmalloc_array() in mpc52xx_spi_probe() * A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. * Replace the specification of a data type by a pointer dereference to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- drivers/spi/spi-mpc52xx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index c36002110c30..8cc129efe7ba 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -437,8 +437,9 @@ static int mpc52xx_spi_probe(struct platform_device *op) ms->gpio_cs_count = of_gpio_count(op->dev.of_node); if (ms->gpio_cs_count > 0) { master->num_chipselect = ms->gpio_cs_count; - ms->gpio_cs = kmalloc(ms->gpio_cs_count * sizeof(unsigned int), - GFP_KERNEL); + ms->gpio_cs = kmalloc_array(ms->gpio_cs_count, + sizeof(*ms->gpio_cs), + GFP_KERNEL); if (!ms->gpio_cs) { rc = -ENOMEM; goto err_alloc_gpio; -- cgit v1.2.3-59-g8ed1b From 9c4f0440ba8f3ad57bebb46cfa29a18333fe4860 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 13 Jan 2017 14:14:45 +0100 Subject: spi/mpc52xx: Combine substrings for two messages The script "checkpatch.pl" pointed information out like the following. WARNING: quoted string split across lines Thus fix the affected source code places. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- drivers/spi/spi-mpc52xx.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index 8cc129efe7ba..e8b59ce4dc3a 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -449,8 +449,7 @@ static int mpc52xx_spi_probe(struct platform_device *op) gpio_cs = of_get_gpio(op->dev.of_node, i); if (gpio_cs < 0) { dev_err(&op->dev, - "could not parse the gpio field " - "in oftree\n"); + "could not parse the gpio field in oftree\n"); rc = -ENODEV; goto err_gpio; } @@ -458,8 +457,8 @@ static int mpc52xx_spi_probe(struct platform_device *op) rc = gpio_request(gpio_cs, dev_name(&op->dev)); if (rc) { dev_err(&op->dev, - "can't request spi cs gpio #%d " - "on gpio line %d\n", i, gpio_cs); + "can't request spi cs gpio #%d on gpio line %d\n", + i, gpio_cs); goto err_gpio; } -- cgit v1.2.3-59-g8ed1b From ffcaef5ac27b62b480b94036615b3ae4f1b725fe Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 13 Jan 2017 14:43:06 +0100 Subject: spi/ppc4xx: Combine substrings for a message in spi_ppc4xx_of_probe() The script "checkpatch.pl" pointed information out like the following. WARNING: quoted string split across lines Thus fix the affected source code place. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- drivers/spi/spi-ppc4xx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index dd3d0a218d8b..b2df63c66494 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -428,8 +428,9 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) /* Real CS - set the initial state. */ ret = gpio_request(gpio, np->name); if (ret < 0) { - dev_err(dev, "can't request gpio " - "#%d: %d\n", i, ret); + dev_err(dev, + "can't request gpio #%d: %d\n", + i, ret); goto free_gpios; } -- cgit v1.2.3-59-g8ed1b From 797236f10a095a1742373bca5f284c5ec8afb446 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 13 Jan 2017 14:30:43 +0100 Subject: spi/ppc4xx: Use kcalloc() in spi_ppc4xx_of_probe() * A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus reuse the corresponding function "kcalloc". This issue was detected by using the Coccinelle software. * Replace the specification of a data type by a pointer dereference to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- drivers/spi/spi-ppc4xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index b2df63c66494..967d94844b30 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -411,7 +411,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) if (num_gpios > 0) { int i; - hw->gpios = kzalloc(sizeof(int) * num_gpios, GFP_KERNEL); + hw->gpios = kcalloc(num_gpios, sizeof(*hw->gpios), GFP_KERNEL); if (!hw->gpios) { ret = -ENOMEM; goto free_master; -- cgit v1.2.3-59-g8ed1b From 6ceb3b27b1edd1112f1879cc1f149d39a3da2dc2 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 13 Jan 2017 15:57:03 +0100 Subject: spi/topcliff-pch: Delete an unnecessary return statement in two functions The script "checkpatch.pl" pointed information out like the following. WARNING: void function return statements are not generally useful Thus remove such statements here. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- drivers/spi/spi-topcliff-pch.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index fcb991034c3d..250452a6eead 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -915,7 +915,6 @@ static void pch_spi_release_dma(struct pch_spi_data *data) dma_release_channel(dma->chan_rx); dma->chan_rx = NULL; } - return; } static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) @@ -1292,7 +1291,6 @@ static void pch_free_dma_buf(struct pch_spi_board_data *board_dat, if (dma->rx_buf_dma) dma_free_coherent(&board_dat->pdev->dev, PCH_BUF_SIZE, dma->rx_buf_virt, dma->rx_buf_dma); - return; } static void pch_alloc_dma_buf(struct pch_spi_board_data *board_dat, -- cgit v1.2.3-59-g8ed1b From 84aa0ba12442fa46f461c491c42efdadf6995c96 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 13 Jan 2017 15:25:22 +0100 Subject: spi/topcliff-pch: Use kcalloc() in pch_spi_handle_dma() * Multiplications for the size determination of memory allocations indicated that array data structures should be processed. Thus use the corresponding function "kcalloc". This issue was detected by using the Coccinelle software. * Replace the specification of a data structure by pointer dereferences to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- drivers/spi/spi-topcliff-pch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 250452a6eead..1beeb16e836a 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1007,7 +1007,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) spin_unlock_irqrestore(&data->lock, flags); /* RX */ - dma->sg_rx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); + dma->sg_rx_p = kcalloc(num, sizeof(*dma->sg_rx_p), GFP_ATOMIC); sg_init_table(dma->sg_rx_p, num); /* Initialize SG table */ /* offset, length setting */ sg = dma->sg_rx_p; @@ -1067,7 +1067,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) head = 0; } - dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); + dma->sg_tx_p = kcalloc(num, sizeof(*dma->sg_tx_p), GFP_ATOMIC); sg_init_table(dma->sg_tx_p, num); /* Initialize SG table */ /* offset, length setting */ sg = dma->sg_tx_p; -- cgit v1.2.3-59-g8ed1b From baa35f5734aa1c0207e4e6b8e15079475b1fa252 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 13 Jan 2017 15:46:35 +0100 Subject: spi/topcliff-pch: Improve size determinations in pch_spi_probe() Replace the specification of data structures by pointer dereferences as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- drivers/spi/spi-topcliff-pch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 1beeb16e836a..0a876311b67b 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1539,11 +1539,11 @@ static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id) int i; struct pch_pd_dev_save *pd_dev_save; - pd_dev_save = kzalloc(sizeof(struct pch_pd_dev_save), GFP_KERNEL); + pd_dev_save = kzalloc(sizeof(*pd_dev_save), GFP_KERNEL); if (!pd_dev_save) return -ENOMEM; - board_dat = kzalloc(sizeof(struct pch_spi_board_data), GFP_KERNEL); + board_dat = kzalloc(sizeof(*board_dat), GFP_KERNEL); if (!board_dat) { retval = -ENOMEM; goto err_no_mem; -- cgit v1.2.3-59-g8ed1b From b996356d305fd311eaa652890b255a0ff4d13de4 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 13 Jan 2017 16:36:09 +0100 Subject: spi/topcliff-pch: Combine substrings for four messages The script "checkpatch.pl" pointed information out like the following. WARNING: quoted string split across lines Thus fix the affected source code places. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- drivers/spi/spi-topcliff-pch.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 0a876311b67b..2b9405819075 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -622,8 +622,9 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw) if (n_writes > PCH_MAX_FIFO_DEPTH) n_writes = PCH_MAX_FIFO_DEPTH; - dev_dbg(&data->master->dev, "\n%s:Pulling down SSN low - writing " - "0x2 to SSNXCR\n", __func__); + dev_dbg(&data->master->dev, + "\n%s:Pulling down SSN low - writing 0x2 to SSNXCR\n", + __func__); pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW); for (j = 0; j < n_writes; j++) @@ -1180,14 +1181,16 @@ static void pch_spi_process_messages(struct work_struct *pwork) data->cur_trans = list_entry(data->current_msg->transfers.next, struct spi_transfer, transfer_list); - dev_dbg(&data->master->dev, "%s " - ":Getting 1st transfer message\n", __func__); + dev_dbg(&data->master->dev, + "%s :Getting 1st transfer message\n", + __func__); } else { data->cur_trans = list_entry(data->cur_trans->transfer_list.next, struct spi_transfer, transfer_list); - dev_dbg(&data->master->dev, "%s " - ":Getting next transfer message\n", __func__); + dev_dbg(&data->master->dev, + "%s :Getting next transfer message\n", + __func__); } spin_unlock(&data->lock); @@ -1232,9 +1235,8 @@ static void pch_spi_process_messages(struct work_struct *pwork) /* check for delay */ if (data->cur_trans->delay_usecs) { - dev_dbg(&data->master->dev, "%s:" - "delay in usec=%d\n", __func__, - data->cur_trans->delay_usecs); + dev_dbg(&data->master->dev, "%s:delay in usec=%d\n", + __func__, data->cur_trans->delay_usecs); udelay(data->cur_trans->delay_usecs); } -- cgit v1.2.3-59-g8ed1b From 45e861a1c12cfd717b8e47103f1aaf2e34cc6688 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 13 Jan 2017 17:00:08 +0100 Subject: spi/topcliff-pch: Delete an error message for a failed memory allocation in pch_spi_set_tx() Omit an extra message for a memory allocation failure in this function. Link: http://events.linuxfoundation.org/sites/events/files/slides/LCJ16-Refactor_Strings-WSang_0.pdf Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- drivers/spi/spi-topcliff-pch.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 2b9405819075..97d137591b18 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -591,7 +591,6 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw) if (!data->pkt_rx_buff) { /* flush queue and set status of all transfers to -ENOMEM */ - dev_err(&data->master->dev, "%s :kzalloc failed\n", __func__); list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) { pmsg->status = -ENOMEM; -- cgit v1.2.3-59-g8ed1b From e18a80acd1365e91e3efcd69942d9073936cf851 Mon Sep 17 00:00:00 2001 From: "David E. Box" Date: Thu, 19 Jan 2017 16:25:21 +0200 Subject: spi: pxa2xx: Add support for Intel Gemini Lake Gemini Lake reuses the same LPSS SPI configuration as Broxton Signed-off-by: David E. Box Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index d6239fa718be..3f3751e2b521 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1458,6 +1458,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { { PCI_VDEVICE(INTEL, 0x1ac2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x1ac4), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x1ac6), LPSS_BXT_SSP }, + /* GLK */ + { PCI_VDEVICE(INTEL, 0x31c2), LPSS_BXT_SSP }, + { PCI_VDEVICE(INTEL, 0x31c4), LPSS_BXT_SSP }, + { PCI_VDEVICE(INTEL, 0x31c6), LPSS_BXT_SSP }, /* APL */ { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP }, -- cgit v1.2.3-59-g8ed1b From e51e9b93049f624c179bab2c651995bca22b5bb7 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Sat, 21 Jan 2017 10:06:38 +0100 Subject: spi: pxa2xx: Prepare for edge-triggered interrupts When using the a device with edge-triggered interrupts, such as MSIs, the interrupt handler has to ensure that there is a point in time during its execution where all interrupts sources are silent so that a new event can trigger a new interrupt again. This is achieved here by disabling all interrupt sources for a moment before processing them according to the status register. If a new interrupt should have arrived after we read the status, it will now re-trigger the interrupt, even in edge mode. Signed-off-by: Jan Kiszka Acked-by: Robert Jarzmik Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 8c65bc1823f3..06ade434c083 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -785,6 +785,9 @@ static irqreturn_t ssp_int(int irq, void *dev_id) if (!(status & mask)) return IRQ_NONE; + pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg & ~drv_data->int_cr1); + pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg); + if (!drv_data->master->cur_msg) { handle_bad_msg(drv_data); /* Never fail */ -- cgit v1.2.3-59-g8ed1b From 64e02cb0bdfc7cef0a01e2ad4d567fdc0a74450e Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Sat, 21 Jan 2017 10:06:39 +0100 Subject: spi: pca2xx-pci: Allow MSI Now that the core is ready for edge-triggered interrupts, we can safely allow the PCI versions that provide this to enable the feature and, thus, have less shared interrupts. Signed-off-by: Jan Kiszka Reviewed-by: Andy Shevchenko Reviewed-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 868452d8e3e1..869f188b02eb 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -227,10 +227,16 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ssp = &spi_pdata.ssp; ssp->phys_base = pci_resource_start(dev, 0); ssp->mmio_base = pcim_iomap_table(dev)[0]; - ssp->irq = dev->irq; ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn; ssp->type = c->type; + pci_set_master(dev); + + ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + return ret; + ssp->irq = pci_irq_vector(dev, 0); + snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id); ssp->clk = clk_register_fixed_rate(&dev->dev, buf , NULL, 0, c->max_clk_rate); -- cgit v1.2.3-59-g8ed1b From 88b0aa544af58ce3be125a1845a227264ec9ab89 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 27 Jan 2017 00:21:53 +0800 Subject: spi: When no dma_chan map buffers with spi_master's parent Back before commit 1dccb598df54 ("arm64: simplify dma_get_ops"), for arm64, devices for which dma_ops were not explicitly set were automatically configured to use swiotlb_dma_ops, since this was hard-coded as the global "dma_ops" in arm64_dma_init(). Now that global "dma_ops" has been removed, all devices much have their dma_ops explicitly set by a call to arch_setup_dma_ops(), otherwise the device is assigned dummy_dma_ops, and thus calls to map_sg for such a device will fail (return 0). Mediatek SPI uses DMA but does not use a dma channel. Support for this was added by commit c37f45b5f1cd ("spi: support spi without dma channel to use can_dma()"), which uses the master_spi dev to DMA map buffers. The master_spi device is not a platform device, rather it is created in spi_alloc_device(), and therefore its dma_ops are never set. Therefore, when the mediatek SPI driver when it does DMA (for large SPI transactions > 32 bytes), SPI will use spi_map_buf()->dma_map_sg() to map the buffer for use in DMA. But dma_map_sg()->dma_map_sg_attrs() returns 0, because ops->map_sg is dummy_dma_ops->__dummy_map_sg, and hence spi_map_buf() returns -ENOMEM (-12). Fix this by using the real spi_master's parent device which should be a real physical device with DMA properties. Signed-off-by: Daniel Kurtz Fixes: c37f45b5f1cd ("spi: support spi without dma channel to use can_dma()") Cc: Leilk Liu Signed-off-by: Mark Brown --- drivers/spi/spi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 656dd3e3220c..f4d412e48e1c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -805,12 +805,12 @@ static int __spi_map_msg(struct spi_master *master, struct spi_message *msg) if (master->dma_tx) tx_dev = master->dma_tx->device->dev; else - tx_dev = &master->dev; + tx_dev = master->dev.parent; if (master->dma_rx) rx_dev = master->dma_rx->device->dev; else - rx_dev = &master->dev; + rx_dev = master->dev.parent; list_for_each_entry(xfer, &msg->transfers, transfer_list) { if (!master->can_dma(master, msg->spi, xfer)) @@ -852,12 +852,12 @@ static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg) if (master->dma_tx) tx_dev = master->dma_tx->device->dev; else - tx_dev = &master->dev; + tx_dev = master->dev.parent; if (master->dma_rx) rx_dev = master->dma_rx->device->dev; else - rx_dev = &master->dev; + rx_dev = master->dev.parent; list_for_each_entry(xfer, &msg->transfers, transfer_list) { if (!master->can_dma(master, msg->spi, xfer)) -- cgit v1.2.3-59-g8ed1b From 1ce24864bff40e11500a699789412115fdf244bf Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 27 Jan 2017 00:21:54 +0800 Subject: spi: mediatek: Only do dma for 4-byte aligned buffers Mediatek SPI DMA only works when tx and rx buffer addresses are 4-byte aligned. Unaligned DMA transactions appeared to work previously, since we the spi core was incorrectly using the spi_master device for dma, which had a 0 dma_mask, and therefore the swiotlb dma map operations were falling back to using bounce buffers. Since each DMA transaction would use its own buffer, the mapped starting address of each transaction was always aligned. When doing real DMA, the mapped address will share the alignment of the raw tx/rx buffer provided by the SPI user, which may or may not be aligned. If a buffer is not aligned, we cannot use DMA, and must use FIFO based transaction instead. So, this patch implements a scheme that allows using the FIFO for arbitrary length transactions (larger than the 32-byte FIFO size) by reloading the FIFO in the interrupt handler. Signed-off-by: Daniel Kurtz Cc: Leilk Liu Signed-off-by: Mark Brown --- drivers/spi/spi-mt65xx.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 899d7a8f0889..278867a31950 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -73,7 +73,7 @@ #define MTK_SPI_IDLE 0 #define MTK_SPI_PAUSED 1 -#define MTK_SPI_MAX_FIFO_SIZE 32 +#define MTK_SPI_MAX_FIFO_SIZE 32U #define MTK_SPI_PACKET_SIZE 1024 struct mtk_spi_compatible { @@ -333,7 +333,7 @@ static int mtk_spi_fifo_transfer(struct spi_master *master, struct mtk_spi *mdata = spi_master_get_devdata(master); mdata->cur_transfer = xfer; - mdata->xfer_len = xfer->len; + mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, xfer->len); mtk_spi_prepare_transfer(master, xfer); mtk_spi_setup_packet(master); @@ -410,7 +410,10 @@ static bool mtk_spi_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { - return xfer->len > MTK_SPI_MAX_FIFO_SIZE; + /* Buffers for DMA transactions must be 4-byte aligned */ + return (xfer->len > MTK_SPI_MAX_FIFO_SIZE && + (unsigned long)xfer->tx_buf % 4 == 0 && + (unsigned long)xfer->rx_buf % 4 == 0); } static int mtk_spi_setup(struct spi_device *spi) @@ -451,7 +454,33 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) ®_val, remainder); } } - spi_finalize_current_transfer(master); + + trans->len -= mdata->xfer_len; + if (!trans->len) { + spi_finalize_current_transfer(master); + return IRQ_HANDLED; + } + + if (trans->tx_buf) + trans->tx_buf += mdata->xfer_len; + if (trans->rx_buf) + trans->rx_buf += mdata->xfer_len; + + mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, trans->len); + mtk_spi_setup_packet(master); + + cnt = trans->len / 4; + iowrite32_rep(mdata->base + SPI_TX_DATA_REG, trans->tx_buf, cnt); + + remainder = trans->len % 4; + if (remainder > 0) { + reg_val = 0; + memcpy(®_val, trans->tx_buf + (cnt * 4), remainder); + writel(reg_val, mdata->base + SPI_TX_DATA_REG); + } + + mtk_spi_enable_transfer(master); + return IRQ_HANDLED; } -- cgit v1.2.3-59-g8ed1b From 8324147f38019865b29d03baf28412d2ec0bd828 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 30 Jan 2017 17:47:05 +0100 Subject: spi: fix device-node leaks Make sure to release the device-node reference taken in of_register_spi_device() on errors and when deregistering the device. Fixes: 284b01897340 ("spi: Add OF binding support for SPI busses") Signed-off-by: Johan Hovold Signed-off-by: Mark Brown --- drivers/spi/spi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 8c05f27bf642..59cb26470d70 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -621,8 +621,10 @@ void spi_unregister_device(struct spi_device *spi) if (!spi) return; - if (spi->dev.of_node) + if (spi->dev.of_node) { of_node_clear_flag(spi->dev.of_node, OF_POPULATED); + of_node_put(spi->dev.of_node); + } if (ACPI_COMPANION(&spi->dev)) acpi_device_clear_enumerated(ACPI_COMPANION(&spi->dev)); device_unregister(&spi->dev); @@ -1603,11 +1605,13 @@ of_register_spi_device(struct spi_master *master, struct device_node *nc) if (rc) { dev_err(&master->dev, "spi_device register error %s\n", nc->full_name); - goto err_out; + goto err_of_node_put; } return spi; +err_of_node_put: + of_node_put(nc); err_out: spi_dev_put(spi); return ERR_PTR(rc); -- cgit v1.2.3-59-g8ed1b From 81ab52fd94f32aaa8a9c27b41934e4ae932ca106 Mon Sep 17 00:00:00 2001 From: Kamal Dasu Date: Mon, 30 Jan 2017 16:11:16 -0500 Subject: spi: bcm-qspi: Added mspi read fallback in bcm_qspi_flash_read() Added mspi read fallback under certain circumstances like unaligned buffer, address on short reads. Also takes care of version 3.0 spi controller where flash address crosses 4MB boundary on transfers the driver resorts to mspi reads. Signed-off-by: Kamal Dasu Signed-off-by: Mark Brown --- drivers/spi/spi-bcm-qspi.c | 116 +++++++++++++++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 31 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 14f9dea3173f..b50b6dfc8c48 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -192,9 +192,11 @@ struct bcm_qspi_dev_id { void *dev; }; + struct qspi_trans { struct spi_transfer *trans; int byte; + bool mspi_last_trans; }; struct bcm_qspi { @@ -616,6 +618,16 @@ static int bcm_qspi_setup(struct spi_device *spi) return 0; } +static bool bcm_qspi_mspi_transfer_is_last(struct bcm_qspi *qspi, + struct qspi_trans *qt) +{ + if (qt->mspi_last_trans && + spi_transfer_is_last(qspi->master, qt->trans)) + return true; + else + return false; +} + static int update_qspi_trans_byte_count(struct bcm_qspi *qspi, struct qspi_trans *qt, int flags) { @@ -629,7 +641,6 @@ static int update_qspi_trans_byte_count(struct bcm_qspi *qspi, if (qt->byte >= qt->trans->len) { /* we're at the end of the spi_transfer */ - /* in TX mode, need to pause for a delay or CS change */ if (qt->trans->delay_usecs && (flags & TRANS_STATUS_BREAK_DELAY)) @@ -641,7 +652,7 @@ static int update_qspi_trans_byte_count(struct bcm_qspi *qspi, goto done; dev_dbg(&qspi->pdev->dev, "advance msg exit\n"); - if (spi_transfer_is_last(qspi->master, qt->trans)) + if (bcm_qspi_mspi_transfer_is_last(qspi, qt)) ret = TRANS_STATUS_BREAK_EOM; else ret = TRANS_STATUS_BREAK_NO_BYTES; @@ -885,6 +896,76 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, return ret; } +static int bcm_qspi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *trans) +{ + struct bcm_qspi *qspi = spi_master_get_devdata(master); + int slots; + unsigned long timeo = msecs_to_jiffies(100); + + bcm_qspi_chip_select(qspi, spi->chip_select); + qspi->trans_pos.trans = trans; + qspi->trans_pos.byte = 0; + + while (qspi->trans_pos.byte < trans->len) { + reinit_completion(&qspi->mspi_done); + + slots = write_to_hw(qspi, spi); + if (!wait_for_completion_timeout(&qspi->mspi_done, timeo)) { + dev_err(&qspi->pdev->dev, "timeout waiting for MSPI\n"); + return -ETIMEDOUT; + } + + read_from_hw(qspi, slots); + } + + return 0; +} + +static int bcm_qspi_mspi_flash_read(struct spi_device *spi, + struct spi_flash_read_message *msg) +{ + struct bcm_qspi *qspi = spi_master_get_devdata(spi->master); + struct spi_transfer t[2]; + u8 cmd[6]; + int ret; + + memset(cmd, 0, sizeof(cmd)); + memset(t, 0, sizeof(t)); + + /* tx */ + /* opcode is in cmd[0] */ + cmd[0] = msg->read_opcode; + cmd[1] = msg->from >> (msg->addr_width * 8 - 8); + cmd[2] = msg->from >> (msg->addr_width * 8 - 16); + cmd[3] = msg->from >> (msg->addr_width * 8 - 24); + cmd[4] = msg->from >> (msg->addr_width * 8 - 32); + t[0].tx_buf = cmd; + t[0].len = msg->addr_width + msg->dummy_bytes + 1; + t[0].bits_per_word = spi->bits_per_word; + t[0].tx_nbits = msg->opcode_nbits; + /* lets mspi know that this is not last transfer */ + qspi->trans_pos.mspi_last_trans = false; + ret = bcm_qspi_transfer_one(spi->master, spi, &t[0]); + + /* rx */ + qspi->trans_pos.mspi_last_trans = true; + if (!ret) { + /* rx */ + t[1].rx_buf = msg->buf; + t[1].len = msg->len; + t[1].rx_nbits = msg->data_nbits; + t[1].bits_per_word = spi->bits_per_word; + ret = bcm_qspi_transfer_one(spi->master, spi, &t[1]); + } + + if (!ret) + msg->retlen = msg->len; + + return ret; +} + static int bcm_qspi_flash_read(struct spi_device *spi, struct spi_flash_read_message *msg) { @@ -918,8 +999,7 @@ static int bcm_qspi_flash_read(struct spi_device *spi, mspi_read = true; if (mspi_read) - /* this will make the m25p80 read to fallback to mspi read */ - return -EAGAIN; + return bcm_qspi_mspi_flash_read(spi, msg); io_width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE; addrlen = msg->addr_width; @@ -931,33 +1011,6 @@ static int bcm_qspi_flash_read(struct spi_device *spi, return ret; } -static int bcm_qspi_transfer_one(struct spi_master *master, - struct spi_device *spi, - struct spi_transfer *trans) -{ - struct bcm_qspi *qspi = spi_master_get_devdata(master); - int slots; - unsigned long timeo = msecs_to_jiffies(100); - - bcm_qspi_chip_select(qspi, spi->chip_select); - qspi->trans_pos.trans = trans; - qspi->trans_pos.byte = 0; - - while (qspi->trans_pos.byte < trans->len) { - reinit_completion(&qspi->mspi_done); - - slots = write_to_hw(qspi, spi); - if (!wait_for_completion_timeout(&qspi->mspi_done, timeo)) { - dev_err(&qspi->pdev->dev, "timeout waiting for MSPI\n"); - return -ETIMEDOUT; - } - - read_from_hw(qspi, slots); - } - - return 0; -} - static void bcm_qspi_cleanup(struct spi_device *spi) { struct bcm_qspi_parms *xp = spi_get_ctldata(spi); @@ -1187,6 +1240,7 @@ int bcm_qspi_probe(struct platform_device *pdev, qspi->pdev = pdev; qspi->trans_pos.trans = NULL; qspi->trans_pos.byte = 0; + qspi->trans_pos.mspi_last_trans = true; qspi->master = master; master->bus_num = -1; -- cgit v1.2.3-59-g8ed1b From d9928b4c48a804cf4e4f5695855282bddf7e2c3b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 7 Feb 2017 14:30:03 +0000 Subject: spi: armada-3700: Remove .owner field for driver Remove .owner field if calls are used which set it automatically. Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- drivers/spi/spi-armada-3700.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index 0baa69325e78..3155ab7ad970 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -909,7 +909,6 @@ static int a3700_spi_remove(struct platform_device *pdev) static struct platform_driver a3700_spi_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(a3700_spi_dt_ids), }, .probe = a3700_spi_probe, -- cgit v1.2.3-59-g8ed1b From 379f831a927817c130a62e3ca0082ae685557324 Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Fri, 10 Feb 2017 11:20:19 +0900 Subject: spi: s3c64xx: fix inconsistency between binding and driver Commit a92e7c3d82a1 ("spi: s3c64xx: consider the case when the CS line is not connected") introduced an inconsistency between the binding, where the disconnected CS line was marked as 'no-cs-readback', and the driver. The driver is erroneously checking for that attribute with property name of 'broken-cs'. Check for 'no-cs-readback' in the driver as well. Fixes: a92e7c3d82a1 ("spi: s3c64xx: consider the case when the CS line is not connected") Signed-off-by: Andi Shyti Reviewed-by: Krzysztof Kozlowski Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-s3c64xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 3c09e94cf827..186342b74141 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -1003,7 +1003,7 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev) sci->num_cs = temp; } - sci->no_cs = of_property_read_bool(dev->of_node, "broken-cs"); + sci->no_cs = of_property_read_bool(dev->of_node, "no-cs-readback"); return sci; } -- cgit v1.2.3-59-g8ed1b From 17f84b793c01452e8802ef80324863b8da7d900b Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Tue, 14 Feb 2017 00:31:11 +0100 Subject: spi: lantiq-ssc: add support for Lantiq SSC SPI controller This driver supports the Lantiq SSC SPI controller in master mode. This controller is found on Intel (former Lantiq) SoCs like the Danube, Falcon, xRX200, xRX300. The hardware uses two hardware FIFOs one for received and one for transferred bytes. When the driver writes data into the transmit FIFO the complete word is taken from the FIFO into a shift register. The data from this shift register is then written to the wire. This driver uses the interrupts signaling the status of the FIFOs and not the shift register. It is also possible to use the interrupts for the shift register, but they will send a signal after every word. When using the interrupts for the shift register we get a signal when the last word is written into the shift register and not when it is written to the wire. After all FIFOs are empty the driver busy waits till the hardware is not busy any more and returns the transfer status. Signed-off-by: Daniel Schwierzeck Signed-off-by: Hauke Mehrtens Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-lantiq-ssc.txt | 29 + drivers/spi/Kconfig | 8 + drivers/spi/Makefile | 1 + drivers/spi/spi-lantiq-ssc.c | 983 +++++++++++++++++++++ 4 files changed, 1021 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spi-lantiq-ssc.txt create mode 100644 drivers/spi/spi-lantiq-ssc.c (limited to 'drivers/spi') diff --git a/Documentation/devicetree/bindings/spi/spi-lantiq-ssc.txt b/Documentation/devicetree/bindings/spi/spi-lantiq-ssc.txt new file mode 100644 index 000000000000..6069b95a883d --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-lantiq-ssc.txt @@ -0,0 +1,29 @@ +Lantiq Synchronous Serial Controller (SSC) SPI master driver + +Required properties: +- compatible: "lantiq,ase-spi", "lantiq,falcon-spi", "lantiq,xrx100-spi" +- #address-cells: see spi-bus.txt +- #size-cells: see spi-bus.txt +- reg: address and length of the spi master registers +- interrupts: should contain the "spi_rx", "spi_tx" and "spi_err" interrupt. + + +Optional properties: +- clocks: spi clock phandle +- num-cs: see spi-bus.txt, set to 8 if unset +- base-cs: the number of the first chip select, set to 1 if unset. + +Example: + + +spi: spi@E100800 { + compatible = "lantiq,xrx200-spi", "lantiq,xrx100-spi"; + reg = <0xE100800 0x100>; + interrupt-parent = <&icu0>; + interrupts = <22 23 24>; + interrupt-names = "spi_rx", "spi_tx", "spi_err"; + #address-cells = <1>; + #size-cells = <1>; + num-cs = <6>; + base-cs = <1>; +}; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ec4aa252d6e8..1abba53c2334 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -415,6 +415,14 @@ config SPI_NUC900 help SPI driver for Nuvoton NUC900 series ARM SoCs +config SPI_LANTIQ_SSC + tristate "Lantiq SSC SPI controller" + depends on LANTIQ + help + This driver supports the Lantiq SSC SPI controller in master + mode. This controller is found on Intel (former Lantiq) SoCs like + the Danube, Falcon, xRX200, xRX300. + config SPI_OC_TINY tristate "OpenCores tiny SPI" depends on GPIOLIB || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 7a6b64662c82..b375a7a89216 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o obj-$(CONFIG_SPI_GPIO) += spi-gpio.o obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o obj-$(CONFIG_SPI_IMX) += spi-imx.o +obj-$(CONFIG_SPI_LANTIQ_SSC) += spi-lantiq-ssc.o obj-$(CONFIG_SPI_JCORE) += spi-jcore.o obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o diff --git a/drivers/spi/spi-lantiq-ssc.c b/drivers/spi/spi-lantiq-ssc.c new file mode 100644 index 000000000000..8a626f7fccea --- /dev/null +++ b/drivers/spi/spi-lantiq-ssc.c @@ -0,0 +1,983 @@ +/* + * Copyright (C) 2011-2015 Daniel Schwierzeck + * Copyright (C) 2016 Hauke Mehrtens + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_LANTIQ +#include +#endif + +#define SPI_RX_IRQ_NAME "spi_rx" +#define SPI_TX_IRQ_NAME "spi_tx" +#define SPI_ERR_IRQ_NAME "spi_err" +#define SPI_FRM_IRQ_NAME "spi_frm" + +#define SPI_CLC 0x00 +#define SPI_PISEL 0x04 +#define SPI_ID 0x08 +#define SPI_CON 0x10 +#define SPI_STAT 0x14 +#define SPI_WHBSTATE 0x18 +#define SPI_TB 0x20 +#define SPI_RB 0x24 +#define SPI_RXFCON 0x30 +#define SPI_TXFCON 0x34 +#define SPI_FSTAT 0x38 +#define SPI_BRT 0x40 +#define SPI_BRSTAT 0x44 +#define SPI_SFCON 0x60 +#define SPI_SFSTAT 0x64 +#define SPI_GPOCON 0x70 +#define SPI_GPOSTAT 0x74 +#define SPI_FPGO 0x78 +#define SPI_RXREQ 0x80 +#define SPI_RXCNT 0x84 +#define SPI_DMACON 0xec +#define SPI_IRNEN 0xf4 +#define SPI_IRNICR 0xf8 +#define SPI_IRNCR 0xfc + +#define SPI_CLC_SMC_S 16 /* Clock divider for sleep mode */ +#define SPI_CLC_SMC_M (0xFF << SPI_CLC_SMC_S) +#define SPI_CLC_RMC_S 8 /* Clock divider for normal run mode */ +#define SPI_CLC_RMC_M (0xFF << SPI_CLC_RMC_S) +#define SPI_CLC_DISS BIT(1) /* Disable status bit */ +#define SPI_CLC_DISR BIT(0) /* Disable request bit */ + +#define SPI_ID_TXFS_S 24 /* Implemented TX FIFO size */ +#define SPI_ID_TXFS_M (0x3F << SPI_ID_TXFS_S) +#define SPI_ID_RXFS_S 16 /* Implemented RX FIFO size */ +#define SPI_ID_RXFS_M (0x3F << SPI_ID_RXFS_S) +#define SPI_ID_MOD_S 8 /* Module ID */ +#define SPI_ID_MOD_M (0xff << SPI_ID_MOD_S) +#define SPI_ID_CFG_S 5 /* DMA interface support */ +#define SPI_ID_CFG_M (1 << SPI_ID_CFG_S) +#define SPI_ID_REV_M 0x1F /* Hardware revision number */ + +#define SPI_CON_BM_S 16 /* Data width selection */ +#define SPI_CON_BM_M (0x1F << SPI_CON_BM_S) +#define SPI_CON_EM BIT(24) /* Echo mode */ +#define SPI_CON_IDLE BIT(23) /* Idle bit value */ +#define SPI_CON_ENBV BIT(22) /* Enable byte valid control */ +#define SPI_CON_RUEN BIT(12) /* Receive underflow error enable */ +#define SPI_CON_TUEN BIT(11) /* Transmit underflow error enable */ +#define SPI_CON_AEN BIT(10) /* Abort error enable */ +#define SPI_CON_REN BIT(9) /* Receive overflow error enable */ +#define SPI_CON_TEN BIT(8) /* Transmit overflow error enable */ +#define SPI_CON_LB BIT(7) /* Loopback control */ +#define SPI_CON_PO BIT(6) /* Clock polarity control */ +#define SPI_CON_PH BIT(5) /* Clock phase control */ +#define SPI_CON_HB BIT(4) /* Heading control */ +#define SPI_CON_RXOFF BIT(1) /* Switch receiver off */ +#define SPI_CON_TXOFF BIT(0) /* Switch transmitter off */ + +#define SPI_STAT_RXBV_S 28 +#define SPI_STAT_RXBV_M (0x7 << SPI_STAT_RXBV_S) +#define SPI_STAT_BSY BIT(13) /* Busy flag */ +#define SPI_STAT_RUE BIT(12) /* Receive underflow error flag */ +#define SPI_STAT_TUE BIT(11) /* Transmit underflow error flag */ +#define SPI_STAT_AE BIT(10) /* Abort error flag */ +#define SPI_STAT_RE BIT(9) /* Receive error flag */ +#define SPI_STAT_TE BIT(8) /* Transmit error flag */ +#define SPI_STAT_ME BIT(7) /* Mode error flag */ +#define SPI_STAT_MS BIT(1) /* Master/slave select bit */ +#define SPI_STAT_EN BIT(0) /* Enable bit */ +#define SPI_STAT_ERRORS (SPI_STAT_ME | SPI_STAT_TE | SPI_STAT_RE | \ + SPI_STAT_AE | SPI_STAT_TUE | SPI_STAT_RUE) + +#define SPI_WHBSTATE_SETTUE BIT(15) /* Set transmit underflow error flag */ +#define SPI_WHBSTATE_SETAE BIT(14) /* Set abort error flag */ +#define SPI_WHBSTATE_SETRE BIT(13) /* Set receive error flag */ +#define SPI_WHBSTATE_SETTE BIT(12) /* Set transmit error flag */ +#define SPI_WHBSTATE_CLRTUE BIT(11) /* Clear transmit underflow error flag */ +#define SPI_WHBSTATE_CLRAE BIT(10) /* Clear abort error flag */ +#define SPI_WHBSTATE_CLRRE BIT(9) /* Clear receive error flag */ +#define SPI_WHBSTATE_CLRTE BIT(8) /* Clear transmit error flag */ +#define SPI_WHBSTATE_SETME BIT(7) /* Set mode error flag */ +#define SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */ +#define SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */ +#define SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */ +#define SPI_WHBSTATE_SETMS BIT(3) /* Set master select bit */ +#define SPI_WHBSTATE_CLRMS BIT(2) /* Clear master select bit */ +#define SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */ +#define SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */ +#define SPI_WHBSTATE_CLR_ERRORS (SPI_WHBSTATE_CLRRUE | SPI_WHBSTATE_CLRME | \ + SPI_WHBSTATE_CLRTE | SPI_WHBSTATE_CLRRE | \ + SPI_WHBSTATE_CLRAE | SPI_WHBSTATE_CLRTUE) + +#define SPI_RXFCON_RXFITL_S 8 /* FIFO interrupt trigger level */ +#define SPI_RXFCON_RXFITL_M (0x3F << SPI_RXFCON_RXFITL_S) +#define SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */ +#define SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */ + +#define SPI_TXFCON_TXFITL_S 8 /* FIFO interrupt trigger level */ +#define SPI_TXFCON_TXFITL_M (0x3F << SPI_TXFCON_TXFITL_S) +#define SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */ +#define SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */ + +#define SPI_FSTAT_RXFFL_S 0 +#define SPI_FSTAT_RXFFL_M (0x3f << SPI_FSTAT_RXFFL_S) +#define SPI_FSTAT_TXFFL_S 8 +#define SPI_FSTAT_TXFFL_M (0x3f << SPI_FSTAT_TXFFL_S) + +#define SPI_GPOCON_ISCSBN_S 8 +#define SPI_GPOCON_INVOUTN_S 0 + +#define SPI_FGPO_SETOUTN_S 8 +#define SPI_FGPO_CLROUTN_S 0 + +#define SPI_RXREQ_RXCNT_M 0xFFFF /* Receive count value */ +#define SPI_RXCNT_TODO_M 0xFFFF /* Recevie to-do value */ + +#define SPI_IRNEN_TFI BIT(4) /* TX finished interrupt */ +#define SPI_IRNEN_F BIT(3) /* Frame end interrupt request */ +#define SPI_IRNEN_E BIT(2) /* Error end interrupt request */ +#define SPI_IRNEN_T_XWAY BIT(1) /* Transmit end interrupt request */ +#define SPI_IRNEN_R_XWAY BIT(0) /* Receive end interrupt request */ +#define SPI_IRNEN_R_XRX BIT(1) /* Transmit end interrupt request */ +#define SPI_IRNEN_T_XRX BIT(0) /* Receive end interrupt request */ +#define SPI_IRNEN_ALL 0x1F + +struct lantiq_ssc_hwcfg { + unsigned int irnen_r; + unsigned int irnen_t; +}; + +struct lantiq_ssc_spi { + struct spi_master *master; + struct device *dev; + void __iomem *regbase; + struct clk *spi_clk; + struct clk *fpi_clk; + const struct lantiq_ssc_hwcfg *hwcfg; + + spinlock_t lock; + struct workqueue_struct *wq; + struct work_struct work; + + const u8 *tx; + u8 *rx; + unsigned int tx_todo; + unsigned int rx_todo; + unsigned int bits_per_word; + unsigned int speed_hz; + unsigned int tx_fifo_size; + unsigned int rx_fifo_size; + unsigned int base_cs; +}; + +static u32 lantiq_ssc_readl(const struct lantiq_ssc_spi *spi, u32 reg) +{ + return __raw_readl(spi->regbase + reg); +} + +static void lantiq_ssc_writel(const struct lantiq_ssc_spi *spi, u32 val, + u32 reg) +{ + __raw_writel(val, spi->regbase + reg); +} + +static void lantiq_ssc_maskl(const struct lantiq_ssc_spi *spi, u32 clr, + u32 set, u32 reg) +{ + u32 val = __raw_readl(spi->regbase + reg); + + val &= ~clr; + val |= set; + __raw_writel(val, spi->regbase + reg); +} + +static unsigned int tx_fifo_level(const struct lantiq_ssc_spi *spi) +{ + u32 fstat = lantiq_ssc_readl(spi, SPI_FSTAT); + + return (fstat & SPI_FSTAT_TXFFL_M) >> SPI_FSTAT_TXFFL_S; +} + +static unsigned int rx_fifo_level(const struct lantiq_ssc_spi *spi) +{ + u32 fstat = lantiq_ssc_readl(spi, SPI_FSTAT); + + return fstat & SPI_FSTAT_RXFFL_M; +} + +static unsigned int tx_fifo_free(const struct lantiq_ssc_spi *spi) +{ + return spi->tx_fifo_size - tx_fifo_level(spi); +} + +static void rx_fifo_reset(const struct lantiq_ssc_spi *spi) +{ + u32 val = spi->rx_fifo_size << SPI_RXFCON_RXFITL_S; + + val |= SPI_RXFCON_RXFEN | SPI_RXFCON_RXFLU; + lantiq_ssc_writel(spi, val, SPI_RXFCON); +} + +static void tx_fifo_reset(const struct lantiq_ssc_spi *spi) +{ + u32 val = 1 << SPI_TXFCON_TXFITL_S; + + val |= SPI_TXFCON_TXFEN | SPI_TXFCON_TXFLU; + lantiq_ssc_writel(spi, val, SPI_TXFCON); +} + +static void rx_fifo_flush(const struct lantiq_ssc_spi *spi) +{ + lantiq_ssc_maskl(spi, 0, SPI_RXFCON_RXFLU, SPI_RXFCON); +} + +static void tx_fifo_flush(const struct lantiq_ssc_spi *spi) +{ + lantiq_ssc_maskl(spi, 0, SPI_TXFCON_TXFLU, SPI_TXFCON); +} + +static void hw_enter_config_mode(const struct lantiq_ssc_spi *spi) +{ + lantiq_ssc_writel(spi, SPI_WHBSTATE_CLREN, SPI_WHBSTATE); +} + +static void hw_enter_active_mode(const struct lantiq_ssc_spi *spi) +{ + lantiq_ssc_writel(spi, SPI_WHBSTATE_SETEN, SPI_WHBSTATE); +} + +static void hw_setup_speed_hz(const struct lantiq_ssc_spi *spi, + unsigned int max_speed_hz) +{ + u32 spi_clk, brt; + + /* + * SPI module clock is derived from FPI bus clock dependent on + * divider value in CLC.RMS which is always set to 1. + * + * f_SPI + * baudrate = -------------- + * 2 * (BR + 1) + */ + spi_clk = clk_get_rate(spi->fpi_clk) / 2; + + if (max_speed_hz > spi_clk) + brt = 0; + else + brt = spi_clk / max_speed_hz - 1; + + if (brt > 0xFFFF) + brt = 0xFFFF; + + dev_dbg(spi->dev, "spi_clk %u, max_speed_hz %u, brt %u\n", + spi_clk, max_speed_hz, brt); + + lantiq_ssc_writel(spi, brt, SPI_BRT); +} + +static void hw_setup_bits_per_word(const struct lantiq_ssc_spi *spi, + unsigned int bits_per_word) +{ + u32 bm; + + /* CON.BM value = bits_per_word - 1 */ + bm = (bits_per_word - 1) << SPI_CON_BM_S; + + lantiq_ssc_maskl(spi, SPI_CON_BM_M, bm, SPI_CON); +} + +static void hw_setup_clock_mode(const struct lantiq_ssc_spi *spi, + unsigned int mode) +{ + u32 con_set = 0, con_clr = 0; + + /* + * SPI mode mapping in CON register: + * Mode CPOL CPHA CON.PO CON.PH + * 0 0 0 0 1 + * 1 0 1 0 0 + * 2 1 0 1 1 + * 3 1 1 1 0 + */ + if (mode & SPI_CPHA) + con_clr |= SPI_CON_PH; + else + con_set |= SPI_CON_PH; + + if (mode & SPI_CPOL) + con_set |= SPI_CON_PO | SPI_CON_IDLE; + else + con_clr |= SPI_CON_PO | SPI_CON_IDLE; + + /* Set heading control */ + if (mode & SPI_LSB_FIRST) + con_clr |= SPI_CON_HB; + else + con_set |= SPI_CON_HB; + + /* Set loopback mode */ + if (mode & SPI_LOOP) + con_set |= SPI_CON_LB; + else + con_clr |= SPI_CON_LB; + + lantiq_ssc_maskl(spi, con_clr, con_set, SPI_CON); +} + +static void lantiq_ssc_hw_init(const struct lantiq_ssc_spi *spi) +{ + const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg; + + /* + * Set clock divider for run mode to 1 to + * run at same frequency as FPI bus + */ + lantiq_ssc_writel(spi, 1 << SPI_CLC_RMC_S, SPI_CLC); + + /* Put controller into config mode */ + hw_enter_config_mode(spi); + + /* Clear error flags */ + lantiq_ssc_maskl(spi, 0, SPI_WHBSTATE_CLR_ERRORS, SPI_WHBSTATE); + + /* Enable error checking, disable TX/RX */ + lantiq_ssc_writel(spi, SPI_CON_RUEN | SPI_CON_AEN | SPI_CON_TEN | + SPI_CON_REN | SPI_CON_TXOFF | SPI_CON_RXOFF, SPI_CON); + + /* Setup default SPI mode */ + hw_setup_bits_per_word(spi, spi->bits_per_word); + hw_setup_clock_mode(spi, SPI_MODE_0); + + /* Enable master mode and clear error flags */ + lantiq_ssc_writel(spi, SPI_WHBSTATE_SETMS | SPI_WHBSTATE_CLR_ERRORS, + SPI_WHBSTATE); + + /* Reset GPIO/CS registers */ + lantiq_ssc_writel(spi, 0, SPI_GPOCON); + lantiq_ssc_writel(spi, 0xFF00, SPI_FPGO); + + /* Enable and flush FIFOs */ + rx_fifo_reset(spi); + tx_fifo_reset(spi); + + /* Enable interrupts */ + lantiq_ssc_writel(spi, hwcfg->irnen_t | hwcfg->irnen_r | SPI_IRNEN_E, + SPI_IRNEN); +} + +static int lantiq_ssc_setup(struct spi_device *spidev) +{ + struct spi_master *master = spidev->master; + struct lantiq_ssc_spi *spi = spi_master_get_devdata(master); + unsigned int cs = spidev->chip_select; + u32 gpocon; + + /* GPIOs are used for CS */ + if (gpio_is_valid(spidev->cs_gpio)) + return 0; + + dev_dbg(spi->dev, "using internal chipselect %u\n", cs); + + if (cs < spi->base_cs) { + dev_err(spi->dev, + "chipselect %i too small (min %i)\n", cs, spi->base_cs); + return -EINVAL; + } + + /* set GPO pin to CS mode */ + gpocon = 1 << ((cs - spi->base_cs) + SPI_GPOCON_ISCSBN_S); + + /* invert GPO pin */ + if (spidev->mode & SPI_CS_HIGH) + gpocon |= 1 << (cs - spi->base_cs); + + lantiq_ssc_maskl(spi, 0, gpocon, SPI_GPOCON); + + return 0; +} + +static int lantiq_ssc_prepare_message(struct spi_master *master, + struct spi_message *message) +{ + struct lantiq_ssc_spi *spi = spi_master_get_devdata(master); + + hw_enter_config_mode(spi); + hw_setup_clock_mode(spi, message->spi->mode); + hw_enter_active_mode(spi); + + return 0; +} + +static void hw_setup_transfer(struct lantiq_ssc_spi *spi, + struct spi_device *spidev, struct spi_transfer *t) +{ + unsigned int speed_hz = t->speed_hz; + unsigned int bits_per_word = t->bits_per_word; + u32 con; + + if (bits_per_word != spi->bits_per_word || + speed_hz != spi->speed_hz) { + hw_enter_config_mode(spi); + hw_setup_speed_hz(spi, speed_hz); + hw_setup_bits_per_word(spi, bits_per_word); + hw_enter_active_mode(spi); + + spi->speed_hz = speed_hz; + spi->bits_per_word = bits_per_word; + } + + /* Configure transmitter and receiver */ + con = lantiq_ssc_readl(spi, SPI_CON); + if (t->tx_buf) + con &= ~SPI_CON_TXOFF; + else + con |= SPI_CON_TXOFF; + + if (t->rx_buf) + con &= ~SPI_CON_RXOFF; + else + con |= SPI_CON_RXOFF; + + lantiq_ssc_writel(spi, con, SPI_CON); +} + +static int lantiq_ssc_unprepare_message(struct spi_master *master, + struct spi_message *message) +{ + struct lantiq_ssc_spi *spi = spi_master_get_devdata(master); + + flush_workqueue(spi->wq); + + /* Disable transmitter and receiver while idle */ + lantiq_ssc_maskl(spi, 0, SPI_CON_TXOFF | SPI_CON_RXOFF, SPI_CON); + + return 0; +} + +static void tx_fifo_write(struct lantiq_ssc_spi *spi) +{ + const u8 *tx8; + const u16 *tx16; + const u32 *tx32; + u32 data; + unsigned int tx_free = tx_fifo_free(spi); + + while (spi->tx_todo && tx_free) { + switch (spi->bits_per_word) { + case 2 ... 8: + tx8 = spi->tx; + data = *tx8; + spi->tx_todo--; + spi->tx++; + break; + case 16: + tx16 = (u16 *) spi->tx; + data = *tx16; + spi->tx_todo -= 2; + spi->tx += 2; + break; + case 32: + tx32 = (u32 *) spi->tx; + data = *tx32; + spi->tx_todo -= 4; + spi->tx += 4; + break; + default: + WARN_ON(1); + data = 0; + break; + } + + lantiq_ssc_writel(spi, data, SPI_TB); + tx_free--; + } +} + +static void rx_fifo_read_full_duplex(struct lantiq_ssc_spi *spi) +{ + u8 *rx8; + u16 *rx16; + u32 *rx32; + u32 data; + unsigned int rx_fill = rx_fifo_level(spi); + + while (rx_fill) { + data = lantiq_ssc_readl(spi, SPI_RB); + + switch (spi->bits_per_word) { + case 2 ... 8: + rx8 = spi->rx; + *rx8 = data; + spi->rx_todo--; + spi->rx++; + break; + case 16: + rx16 = (u16 *) spi->rx; + *rx16 = data; + spi->rx_todo -= 2; + spi->rx += 2; + break; + case 32: + rx32 = (u32 *) spi->rx; + *rx32 = data; + spi->rx_todo -= 4; + spi->rx += 4; + break; + default: + WARN_ON(1); + break; + } + + rx_fill--; + } +} + +static void rx_fifo_read_half_duplex(struct lantiq_ssc_spi *spi) +{ + u32 data, *rx32; + u8 *rx8; + unsigned int rxbv, shift; + unsigned int rx_fill = rx_fifo_level(spi); + + /* + * In RX-only mode the bits per word value is ignored by HW. A value + * of 32 is used instead. Thus all 4 bytes per FIFO must be read. + * If remaining RX bytes are less than 4, the FIFO must be read + * differently. The amount of received and valid bytes is indicated + * by STAT.RXBV register value. + */ + while (rx_fill) { + if (spi->rx_todo < 4) { + rxbv = (lantiq_ssc_readl(spi, SPI_STAT) & + SPI_STAT_RXBV_M) >> SPI_STAT_RXBV_S; + data = lantiq_ssc_readl(spi, SPI_RB); + + shift = (rxbv - 1) * 8; + rx8 = spi->rx; + + while (rxbv) { + *rx8++ = (data >> shift) & 0xFF; + rxbv--; + shift -= 8; + spi->rx_todo--; + spi->rx++; + } + } else { + data = lantiq_ssc_readl(spi, SPI_RB); + rx32 = (u32 *) spi->rx; + + *rx32++ = data; + spi->rx_todo -= 4; + spi->rx += 4; + } + rx_fill--; + } +} + +static void rx_request(struct lantiq_ssc_spi *spi) +{ + unsigned int rxreq, rxreq_max; + + /* + * To avoid receive overflows at high clocks it is better to request + * only the amount of bytes that fits into all FIFOs. This value + * depends on the FIFO size implemented in hardware. + */ + rxreq = spi->rx_todo; + rxreq_max = spi->rx_fifo_size * 4; + if (rxreq > rxreq_max) + rxreq = rxreq_max; + + lantiq_ssc_writel(spi, rxreq, SPI_RXREQ); +} + +static irqreturn_t lantiq_ssc_xmit_interrupt(int irq, void *data) +{ + struct lantiq_ssc_spi *spi = data; + + if (spi->tx) { + if (spi->rx && spi->rx_todo) + rx_fifo_read_full_duplex(spi); + + if (spi->tx_todo) + tx_fifo_write(spi); + else if (!tx_fifo_level(spi)) + goto completed; + } else if (spi->rx) { + if (spi->rx_todo) { + rx_fifo_read_half_duplex(spi); + + if (spi->rx_todo) + rx_request(spi); + else + goto completed; + } else { + goto completed; + } + } + + return IRQ_HANDLED; + +completed: + queue_work(spi->wq, &spi->work); + + return IRQ_HANDLED; +} + +static irqreturn_t lantiq_ssc_err_interrupt(int irq, void *data) +{ + struct lantiq_ssc_spi *spi = data; + u32 stat = lantiq_ssc_readl(spi, SPI_STAT); + + if (!(stat & SPI_STAT_ERRORS)) + return IRQ_NONE; + + if (stat & SPI_STAT_RUE) + dev_err(spi->dev, "receive underflow error\n"); + if (stat & SPI_STAT_TUE) + dev_err(spi->dev, "transmit underflow error\n"); + if (stat & SPI_STAT_AE) + dev_err(spi->dev, "abort error\n"); + if (stat & SPI_STAT_RE) + dev_err(spi->dev, "receive overflow error\n"); + if (stat & SPI_STAT_TE) + dev_err(spi->dev, "transmit overflow error\n"); + if (stat & SPI_STAT_ME) + dev_err(spi->dev, "mode error\n"); + + /* Clear error flags */ + lantiq_ssc_maskl(spi, 0, SPI_WHBSTATE_CLR_ERRORS, SPI_WHBSTATE); + + /* set bad status so it can be retried */ + if (spi->master->cur_msg) + spi->master->cur_msg->status = -EIO; + queue_work(spi->wq, &spi->work); + + return IRQ_HANDLED; +} + +static int transfer_start(struct lantiq_ssc_spi *spi, struct spi_device *spidev, + struct spi_transfer *t) +{ + unsigned long flags; + + spin_lock_irqsave(&spi->lock, flags); + + spi->tx = t->tx_buf; + spi->rx = t->rx_buf; + + if (t->tx_buf) { + spi->tx_todo = t->len; + + /* initially fill TX FIFO */ + tx_fifo_write(spi); + } + + if (spi->rx) { + spi->rx_todo = t->len; + + /* start shift clock in RX-only mode */ + if (!spi->tx) + rx_request(spi); + } + + spin_unlock_irqrestore(&spi->lock, flags); + + return t->len; +} + +/* + * The driver only gets an interrupt when the FIFO is empty, but there + * is an additional shift register from which the data is written to + * the wire. We get the last interrupt when the controller starts to + * write the last word to the wire, not when it is finished. Do busy + * waiting till it finishes. + */ +static void lantiq_ssc_bussy_work(struct work_struct *work) +{ + struct lantiq_ssc_spi *spi; + unsigned long long timeout = 8LL * 1000LL; + unsigned long end; + + spi = container_of(work, typeof(*spi), work); + + do_div(timeout, spi->speed_hz); + timeout += timeout + 100; /* some tolerance */ + + end = jiffies + msecs_to_jiffies(timeout); + do { + u32 stat = lantiq_ssc_readl(spi, SPI_STAT); + + if (!(stat & SPI_STAT_BSY)) { + spi_finalize_current_transfer(spi->master); + return; + } + + cond_resched(); + } while (!time_after_eq(jiffies, end)); + + if (spi->master->cur_msg) + spi->master->cur_msg->status = -EIO; + spi_finalize_current_transfer(spi->master); +} + +static void lantiq_ssc_handle_err(struct spi_master *master, + struct spi_message *message) +{ + struct lantiq_ssc_spi *spi = spi_master_get_devdata(master); + + /* flush FIFOs on timeout */ + rx_fifo_flush(spi); + tx_fifo_flush(spi); +} + +static void lantiq_ssc_set_cs(struct spi_device *spidev, bool enable) +{ + struct lantiq_ssc_spi *spi = spi_master_get_devdata(spidev->master); + unsigned int cs = spidev->chip_select; + u32 fgpo; + + if (!!(spidev->mode & SPI_CS_HIGH) == enable) + fgpo = (1 << (cs - spi->base_cs)); + else + fgpo = (1 << (cs - spi->base_cs + SPI_FGPO_SETOUTN_S)); + + lantiq_ssc_writel(spi, fgpo, SPI_FPGO); +} + +static int lantiq_ssc_transfer_one(struct spi_master *master, + struct spi_device *spidev, + struct spi_transfer *t) +{ + struct lantiq_ssc_spi *spi = spi_master_get_devdata(master); + + hw_setup_transfer(spi, spidev, t); + + return transfer_start(spi, spidev, t); +} + +static const struct lantiq_ssc_hwcfg lantiq_ssc_xway = { + .irnen_r = SPI_IRNEN_R_XWAY, + .irnen_t = SPI_IRNEN_T_XWAY, +}; + +static const struct lantiq_ssc_hwcfg lantiq_ssc_xrx = { + .irnen_r = SPI_IRNEN_R_XRX, + .irnen_t = SPI_IRNEN_T_XRX, +}; + +static const struct of_device_id lantiq_ssc_match[] = { + { .compatible = "lantiq,ase-spi", .data = &lantiq_ssc_xway, }, + { .compatible = "lantiq,falcon-spi", .data = &lantiq_ssc_xrx, }, + { .compatible = "lantiq,xrx100-spi", .data = &lantiq_ssc_xrx, }, + {}, +}; +MODULE_DEVICE_TABLE(of, lantiq_ssc_match); + +static int lantiq_ssc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct spi_master *master; + struct resource *res; + struct lantiq_ssc_spi *spi; + const struct lantiq_ssc_hwcfg *hwcfg; + const struct of_device_id *match; + int err, rx_irq, tx_irq, err_irq; + u32 id, supports_dma, revision; + unsigned int num_cs; + + match = of_match_device(lantiq_ssc_match, dev); + if (!match) { + dev_err(dev, "no device match\n"); + return -EINVAL; + } + hwcfg = match->data; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "failed to get resources\n"); + return -ENXIO; + } + + rx_irq = platform_get_irq_byname(pdev, SPI_RX_IRQ_NAME); + if (rx_irq < 0) { + dev_err(dev, "failed to get %s\n", SPI_RX_IRQ_NAME); + return -ENXIO; + } + + tx_irq = platform_get_irq_byname(pdev, SPI_TX_IRQ_NAME); + if (tx_irq < 0) { + dev_err(dev, "failed to get %s\n", SPI_TX_IRQ_NAME); + return -ENXIO; + } + + err_irq = platform_get_irq_byname(pdev, SPI_ERR_IRQ_NAME); + if (err_irq < 0) { + dev_err(dev, "failed to get %s\n", SPI_ERR_IRQ_NAME); + return -ENXIO; + } + + master = spi_alloc_master(dev, sizeof(struct lantiq_ssc_spi)); + if (!master) + return -ENOMEM; + + spi = spi_master_get_devdata(master); + spi->master = master; + spi->dev = dev; + spi->hwcfg = hwcfg; + platform_set_drvdata(pdev, spi); + + spi->regbase = devm_ioremap_resource(dev, res); + if (IS_ERR(spi->regbase)) { + err = PTR_ERR(spi->regbase); + goto err_master_put; + } + + err = devm_request_irq(dev, rx_irq, lantiq_ssc_xmit_interrupt, + 0, SPI_RX_IRQ_NAME, spi); + if (err) + goto err_master_put; + + err = devm_request_irq(dev, tx_irq, lantiq_ssc_xmit_interrupt, + 0, SPI_TX_IRQ_NAME, spi); + if (err) + goto err_master_put; + + err = devm_request_irq(dev, err_irq, lantiq_ssc_err_interrupt, + 0, SPI_ERR_IRQ_NAME, spi); + if (err) + goto err_master_put; + + spi->spi_clk = devm_clk_get(dev, "gate"); + if (IS_ERR(spi->spi_clk)) { + err = PTR_ERR(spi->spi_clk); + goto err_master_put; + } + err = clk_prepare_enable(spi->spi_clk); + if (err) + goto err_master_put; + + /* + * Use the old clk_get_fpi() function on Lantiq platform, till it + * supports common clk. + */ +#if defined(CONFIG_LANTIQ) && !defined(CONFIG_COMMON_CLK) + spi->fpi_clk = clk_get_fpi(); +#else + spi->fpi_clk = clk_get(dev, "freq"); +#endif + if (IS_ERR(spi->fpi_clk)) { + err = PTR_ERR(spi->fpi_clk); + goto err_clk_disable; + } + + num_cs = 8; + of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs); + + spi->base_cs = 1; + of_property_read_u32(pdev->dev.of_node, "base-cs", &spi->base_cs); + + spin_lock_init(&spi->lock); + spi->bits_per_word = 8; + spi->speed_hz = 0; + + master->dev.of_node = pdev->dev.of_node; + master->num_chipselect = num_cs; + master->setup = lantiq_ssc_setup; + master->set_cs = lantiq_ssc_set_cs; + master->handle_err = lantiq_ssc_handle_err; + master->prepare_message = lantiq_ssc_prepare_message; + master->unprepare_message = lantiq_ssc_unprepare_message; + master->transfer_one = lantiq_ssc_transfer_one; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH | + SPI_LOOP; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 8) | + SPI_BPW_MASK(16) | SPI_BPW_MASK(32); + + spi->wq = alloc_ordered_workqueue(dev_name(dev), 0); + if (!spi->wq) { + err = -ENOMEM; + goto err_clk_put; + } + INIT_WORK(&spi->work, lantiq_ssc_bussy_work); + + id = lantiq_ssc_readl(spi, SPI_ID); + spi->tx_fifo_size = (id & SPI_ID_TXFS_M) >> SPI_ID_TXFS_S; + spi->rx_fifo_size = (id & SPI_ID_RXFS_M) >> SPI_ID_RXFS_S; + supports_dma = (id & SPI_ID_CFG_M) >> SPI_ID_CFG_S; + revision = id & SPI_ID_REV_M; + + lantiq_ssc_hw_init(spi); + + dev_info(dev, + "Lantiq SSC SPI controller (Rev %i, TXFS %u, RXFS %u, DMA %u)\n", + revision, spi->tx_fifo_size, spi->rx_fifo_size, supports_dma); + + err = devm_spi_register_master(dev, master); + if (err) { + dev_err(dev, "failed to register spi_master\n"); + goto err_wq_destroy; + } + + return 0; + +err_wq_destroy: + destroy_workqueue(spi->wq); +err_clk_put: + clk_put(spi->fpi_clk); +err_clk_disable: + clk_disable_unprepare(spi->spi_clk); +err_master_put: + spi_master_put(master); + + return err; +} + +static int lantiq_ssc_remove(struct platform_device *pdev) +{ + struct lantiq_ssc_spi *spi = platform_get_drvdata(pdev); + + lantiq_ssc_writel(spi, 0, SPI_IRNEN); + lantiq_ssc_writel(spi, 0, SPI_CLC); + rx_fifo_flush(spi); + tx_fifo_flush(spi); + hw_enter_config_mode(spi); + + destroy_workqueue(spi->wq); + clk_disable_unprepare(spi->spi_clk); + clk_put(spi->fpi_clk); + + return 0; +} + +static struct platform_driver lantiq_ssc_driver = { + .probe = lantiq_ssc_probe, + .remove = lantiq_ssc_remove, + .driver = { + .name = "spi-lantiq-ssc", + .owner = THIS_MODULE, + .of_match_table = lantiq_ssc_match, + }, +}; +module_platform_driver(lantiq_ssc_driver); + +MODULE_DESCRIPTION("Lantiq SSC SPI controller driver"); +MODULE_AUTHOR("Daniel Schwierzeck "); +MODULE_AUTHOR("Hauke Mehrtens "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:spi-lantiq-ssc"); -- cgit v1.2.3-59-g8ed1b From 345309fa7c0c9206a5344d379b174499952d79d9 Mon Sep 17 00:00:00 2001 From: Kamal Dasu Date: Wed, 8 Feb 2017 15:15:04 -0500 Subject: spi: bcm-qspi: Fix bcm_qspi_bspi_read() performance Let bcm_qspi_bspi_flash_read() return all the requested bytes by breaking up the reads for BSPI block into optimal chunks size that a BSPI block can handle. Signed-off-by: Kamal Dasu Signed-off-by: Mark Brown --- drivers/spi/spi-bcm-qspi.c | 83 +++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 37 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index b50b6dfc8c48..99b3057531a5 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -89,7 +89,7 @@ #define BSPI_BPP_MODE_SELECT_MASK BIT(8) #define BSPI_BPP_ADDR_SELECT_MASK BIT(16) -#define BSPI_READ_LENGTH 256 +#define BSPI_READ_LENGTH 512 /* MSPI register offsets */ #define MSPI_SPCR0_LSB 0x000 @@ -824,7 +824,7 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, struct spi_flash_read_message *msg) { struct bcm_qspi *qspi = spi_master_get_devdata(spi->master); - u32 addr = 0, len, len_words; + u32 addr = 0, len, rdlen, len_words; int ret = 0; unsigned long timeo = msecs_to_jiffies(100); struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; @@ -837,7 +837,7 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0); /* - * when using flex mode mode we need to send + * when using flex mode we need to send * the upper address byte to bspi */ if (bcm_qspi_bspi_ver_three(qspi) == false) { @@ -851,47 +851,56 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, else addr = msg->from & 0x00ffffff; - /* set BSPI RAF buffer max read length */ - len = msg->len; - if (len > BSPI_READ_LENGTH) - len = BSPI_READ_LENGTH; - if (bcm_qspi_bspi_ver_three(qspi) == true) addr = (addr + 0xc00000) & 0xffffff; - reinit_completion(&qspi->bspi_done); - bcm_qspi_enable_bspi(qspi); - len_words = (len + 3) >> 2; - qspi->bspi_rf_msg = msg; - qspi->bspi_rf_msg_status = 0; + /* + * read into the entire buffer by breaking the reads + * into RAF buffer read lengths + */ + len = msg->len; qspi->bspi_rf_msg_idx = 0; - qspi->bspi_rf_msg_len = len; - dev_dbg(&qspi->pdev->dev, "bspi xfr addr 0x%x len 0x%x", addr, len); - - bcm_qspi_write(qspi, BSPI, BSPI_RAF_START_ADDR, addr); - bcm_qspi_write(qspi, BSPI, BSPI_RAF_NUM_WORDS, len_words); - bcm_qspi_write(qspi, BSPI, BSPI_RAF_WATERMARK, 0); - if (qspi->soc_intc) { - /* - * clear soc MSPI and BSPI interrupts and enable - * BSPI interrupts. - */ - soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_BSPI_DONE); - soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, true); - } + do { + if (len > BSPI_READ_LENGTH) + rdlen = BSPI_READ_LENGTH; + else + rdlen = len; + + reinit_completion(&qspi->bspi_done); + bcm_qspi_enable_bspi(qspi); + len_words = (rdlen + 3) >> 2; + qspi->bspi_rf_msg = msg; + qspi->bspi_rf_msg_status = 0; + qspi->bspi_rf_msg_len = rdlen; + dev_dbg(&qspi->pdev->dev, + "bspi xfr addr 0x%x len 0x%x", addr, rdlen); + bcm_qspi_write(qspi, BSPI, BSPI_RAF_START_ADDR, addr); + bcm_qspi_write(qspi, BSPI, BSPI_RAF_NUM_WORDS, len_words); + bcm_qspi_write(qspi, BSPI, BSPI_RAF_WATERMARK, 0); + if (qspi->soc_intc) { + /* + * clear soc MSPI and BSPI interrupts and enable + * BSPI interrupts. + */ + soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_BSPI_DONE); + soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, true); + } - /* Must flush previous writes before starting BSPI operation */ - mb(); + /* Must flush previous writes before starting BSPI operation */ + mb(); + bcm_qspi_bspi_lr_start(qspi); + if (!wait_for_completion_timeout(&qspi->bspi_done, timeo)) { + dev_err(&qspi->pdev->dev, "timeout waiting for BSPI\n"); + ret = -ETIMEDOUT; + break; + } - bcm_qspi_bspi_lr_start(qspi); - if (!wait_for_completion_timeout(&qspi->bspi_done, timeo)) { - dev_err(&qspi->pdev->dev, "timeout waiting for BSPI\n"); - ret = -ETIMEDOUT; - } else { - /* set the return length for the caller */ - msg->retlen = len; - } + /* set msg return length */ + msg->retlen += rdlen; + addr += rdlen; + len -= rdlen; + } while (len); return ret; } -- cgit v1.2.3-59-g8ed1b From 973f7dd575891d0e67469861b47f43175553f30a Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 9 Feb 2017 15:32:21 +0000 Subject: spi: bcm-qspi: Remove unnecessary platform_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- drivers/spi/spi-bcm-qspi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 99b3057531a5..958fb4ee972d 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -1408,7 +1408,6 @@ int bcm_qspi_remove(struct platform_device *pdev) { struct bcm_qspi *qspi = platform_get_drvdata(pdev); - platform_set_drvdata(pdev, NULL); bcm_qspi_hw_uninit(qspi); clk_disable_unprepare(qspi->clk); kfree(qspi->dev_ids); -- cgit v1.2.3-59-g8ed1b From 7264abc7000d601726aefb05189ea524ee3995ba Mon Sep 17 00:00:00 2001 From: DongCV Date: Wed, 15 Feb 2017 19:50:51 +0900 Subject: spi: rspi: Fixes bogus received byte in qspi_transfer_in() In qspi_transfer_in(), when receiving the last n (or len) bytes of data, one bogus byte was written in the receive buffer. This code leads to a buffer overflow. "jffs2: jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x03b40000: 0x1900 instead jffs2: jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x03b40004: 0x000c instead" The error message above happens when trying to mount, unmount, and remount a jffs2-formatted device. This patch removed the bogus write to fixes: 3be09bec42a800d4 "spi: rspi: supports 32bytes buffer for DUAL and QUAD" And here is Geert's comment: "spi: rspi: Fix bogus received byte in qspi_transfer_in() When there are less than QSPI_BUFFER_SIZE remaining bytes to be received, qspi_transfer_in() writes one bogus byte in the receive buffer, possibly leading to a buffer overflow. This can be reproduced by mounting, unmounting, and remounting a jffs2-formatted device, causing lots of warnings like: "jffs2: jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x03b40000: 0x1900 instead" Remove the bogus write to fix this. " Signed-off-by: DongCV Reviewed-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 9daf50031737..2ee130138066 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -848,7 +848,6 @@ static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer) ret = rspi_pio_transfer(rspi, NULL, rx, n); if (ret < 0) return ret; - *rx++ = ret; } n -= len; } -- cgit v1.2.3-59-g8ed1b From ad16d4a83ddc86151b4a6efe257ba74eb30f9f8e Mon Sep 17 00:00:00 2001 From: DongCV Date: Wed, 15 Feb 2017 19:50:52 +0900 Subject: spi: rspi: Replaces "n" by "len" in qspi_transfer_*() This patch replaced "n" by "len" bytes of data in qspi_transfer_in() and qspi_transfer_out() function. This will make improving readability. Signed-off-by: DongCV Reviewed-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 2ee130138066..bc3c8686f4d9 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -808,7 +808,7 @@ static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer) for (i = 0; i < len; i++) rspi_write_data(rspi, *tx++); } else { - ret = rspi_pio_transfer(rspi, tx, NULL, n); + ret = rspi_pio_transfer(rspi, tx, NULL, len); if (ret < 0) return ret; } @@ -845,7 +845,7 @@ static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer) for (i = 0; i < len; i++) *rx++ = rspi_read_data(rspi); } else { - ret = rspi_pio_transfer(rspi, NULL, rx, n); + ret = rspi_pio_transfer(rspi, NULL, rx, len); if (ret < 0) return ret; } -- cgit v1.2.3-59-g8ed1b From 55f0cd3fb9c29c20fb94c47e28a9ec8cf704f8c2 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Thu, 16 Feb 2017 13:07:37 -0700 Subject: spi: spi-ep93xx: simplify GPIO chip selects This driver requires a GPIO line to be used for the chip select of each SPI device. Remove the ep93xx_spi_chip_ops definition from the platform data and use the spi core GPIO handling for the chip selects. Fix all the ep93xx platforms that use this driver and remove the old Documentation. Signed-off-by: H Hartley Sweeten Signed-off-by: Mark Brown --- Documentation/spi/ep93xx_spi | 105 ----------------------- arch/arm/mach-ep93xx/edb93xx.c | 31 ++----- arch/arm/mach-ep93xx/simone.c | 63 +++----------- arch/arm/mach-ep93xx/vision_ep9307.c | 88 +++---------------- drivers/spi/spi-ep93xx.c | 139 ++++++++++--------------------- include/linux/platform_data/spi-ep93xx.h | 17 +--- 6 files changed, 74 insertions(+), 369 deletions(-) delete mode 100644 Documentation/spi/ep93xx_spi (limited to 'drivers/spi') diff --git a/Documentation/spi/ep93xx_spi b/Documentation/spi/ep93xx_spi deleted file mode 100644 index 832ddce6e5fb..000000000000 --- a/Documentation/spi/ep93xx_spi +++ /dev/null @@ -1,105 +0,0 @@ -Cirrus EP93xx SPI controller driver HOWTO -========================================= - -ep93xx_spi driver brings SPI master support for EP93xx SPI controller. Chip -selects are implemented with GPIO lines. - -NOTE: If possible, don't use SFRMOUT (SFRM1) signal as a chip select. It will -not work correctly (it cannot be controlled by software). Use GPIO lines -instead. - -Sample configuration -==================== - -Typically driver configuration is done in platform board files (the files under -arch/arm/mach-ep93xx/*.c). In this example we configure MMC over SPI through -this driver on TS-7260 board. You can adapt the code to suit your needs. - -This example uses EGPIO9 as SD/MMC card chip select (this is wired in DIO1 -header on the board). - -You need to select CONFIG_MMC_SPI to use mmc_spi driver. - -arch/arm/mach-ep93xx/ts72xx.c: - -... -#include -#include - -#include - -/* this is our GPIO line used for chip select */ -#define MMC_CHIP_SELECT_GPIO EP93XX_GPIO_LINE_EGPIO9 - -static int ts72xx_mmc_spi_setup(struct spi_device *spi) -{ - int err; - - err = gpio_request(MMC_CHIP_SELECT_GPIO, spi->modalias); - if (err) - return err; - - gpio_direction_output(MMC_CHIP_SELECT_GPIO, 1); - - return 0; -} - -static void ts72xx_mmc_spi_cleanup(struct spi_device *spi) -{ - gpio_set_value(MMC_CHIP_SELECT_GPIO, 1); - gpio_direction_input(MMC_CHIP_SELECT_GPIO); - gpio_free(MMC_CHIP_SELECT_GPIO); -} - -static void ts72xx_mmc_spi_cs_control(struct spi_device *spi, int value) -{ - gpio_set_value(MMC_CHIP_SELECT_GPIO, value); -} - -static struct ep93xx_spi_chip_ops ts72xx_mmc_spi_ops = { - .setup = ts72xx_mmc_spi_setup, - .cleanup = ts72xx_mmc_spi_cleanup, - .cs_control = ts72xx_mmc_spi_cs_control, -}; - -static struct spi_board_info ts72xx_spi_devices[] __initdata = { - { - .modalias = "mmc_spi", - .controller_data = &ts72xx_mmc_spi_ops, - /* - * We use 10 MHz even though the maximum is 7.4 MHz. The driver - * will limit it automatically to max. frequency. - */ - .max_speed_hz = 10 * 1000 * 1000, - .bus_num = 0, - .chip_select = 0, - .mode = SPI_MODE_0, - }, -}; - -static struct ep93xx_spi_info ts72xx_spi_info = { - .num_chipselect = ARRAY_SIZE(ts72xx_spi_devices), -}; - -static void __init ts72xx_init_machine(void) -{ - ... - ep93xx_register_spi(&ts72xx_spi_info, ts72xx_spi_devices, - ARRAY_SIZE(ts72xx_spi_devices)); -} - -The driver can use DMA for the transfers also. In this case ts72xx_spi_info -becomes: - -static struct ep93xx_spi_info ts72xx_spi_info = { - .num_chipselect = ARRAY_SIZE(ts72xx_spi_devices), - .use_dma = true; -}; - -Note that CONFIG_EP93XX_DMA should be enabled as well. - -Thanks to -========= -Martin Guy, H. Hartley Sweeten and others who helped me during development of -the driver. Simplemachines.it donated me a Sim.One board which I used testing -the driver on EP9307. diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c index ad92d9f7e4df..0ac176386789 100644 --- a/arch/arm/mach-ep93xx/edb93xx.c +++ b/arch/arm/mach-ep93xx/edb93xx.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -106,33 +105,10 @@ static struct cs4271_platform_data edb93xx_cs4271_data = { .gpio_nreset = -EINVAL, /* filled in later */ }; -static int edb93xx_cs4271_hw_setup(struct spi_device *spi) -{ - return gpio_request_one(EP93XX_GPIO_LINE_EGPIO6, - GPIOF_OUT_INIT_HIGH, spi->modalias); -} - -static void edb93xx_cs4271_hw_cleanup(struct spi_device *spi) -{ - gpio_free(EP93XX_GPIO_LINE_EGPIO6); -} - -static void edb93xx_cs4271_hw_cs_control(struct spi_device *spi, int value) -{ - gpio_set_value(EP93XX_GPIO_LINE_EGPIO6, value); -} - -static struct ep93xx_spi_chip_ops edb93xx_cs4271_hw = { - .setup = edb93xx_cs4271_hw_setup, - .cleanup = edb93xx_cs4271_hw_cleanup, - .cs_control = edb93xx_cs4271_hw_cs_control, -}; - static struct spi_board_info edb93xx_spi_board_info[] __initdata = { { .modalias = "cs4271", .platform_data = &edb93xx_cs4271_data, - .controller_data = &edb93xx_cs4271_hw, .max_speed_hz = 6000000, .bus_num = 0, .chip_select = 0, @@ -140,8 +116,13 @@ static struct spi_board_info edb93xx_spi_board_info[] __initdata = { }, }; +static int edb93xx_spi_chipselects[] __initdata = { + EP93XX_GPIO_LINE_EGPIO6, +}; + static struct ep93xx_spi_info edb93xx_spi_info __initdata = { - .num_chipselect = ARRAY_SIZE(edb93xx_spi_board_info), + .chipselect = edb93xx_spi_chipselects, + .num_chipselect = ARRAY_SIZE(edb93xx_spi_chipselects), }; static void __init edb93xx_register_spi(void) diff --git a/arch/arm/mach-ep93xx/simone.c b/arch/arm/mach-ep93xx/simone.c index 7bb540c421ee..c7a40f245892 100644 --- a/arch/arm/mach-ep93xx/simone.c +++ b/arch/arm/mach-ep93xx/simone.c @@ -48,56 +48,6 @@ static struct ep93xxfb_mach_info __initdata simone_fb_info = { */ #define MMC_CARD_DETECT_GPIO EP93XX_GPIO_LINE_EGPIO0 -/* - * Up to v1.3, the Sim.One used SFRMOUT as SD card chip select, but this goes - * low between multi-message command blocks. From v1.4, it uses a GPIO instead. - * v1.3 parts will still work, since the signal on SFRMOUT is automatic. - */ -#define MMC_CHIP_SELECT_GPIO EP93XX_GPIO_LINE_EGPIO1 - -/* - * MMC SPI chip select GPIO handling. If you are using SFRMOUT (SFRM1) signal, - * you can leave these empty and pass NULL as .controller_data. - */ - -static int simone_mmc_spi_setup(struct spi_device *spi) -{ - unsigned int gpio = MMC_CHIP_SELECT_GPIO; - int err; - - err = gpio_request(gpio, spi->modalias); - if (err) - return err; - - err = gpio_direction_output(gpio, 1); - if (err) { - gpio_free(gpio); - return err; - } - - return 0; -} - -static void simone_mmc_spi_cleanup(struct spi_device *spi) -{ - unsigned int gpio = MMC_CHIP_SELECT_GPIO; - - gpio_set_value(gpio, 1); - gpio_direction_input(gpio); - gpio_free(gpio); -} - -static void simone_mmc_spi_cs_control(struct spi_device *spi, int value) -{ - gpio_set_value(MMC_CHIP_SELECT_GPIO, value); -} - -static struct ep93xx_spi_chip_ops simone_mmc_spi_ops = { - .setup = simone_mmc_spi_setup, - .cleanup = simone_mmc_spi_cleanup, - .cs_control = simone_mmc_spi_cs_control, -}; - /* * MMC card detection GPIO setup. */ @@ -152,7 +102,6 @@ static struct mmc_spi_platform_data simone_mmc_spi_data = { static struct spi_board_info simone_spi_devices[] __initdata = { { .modalias = "mmc_spi", - .controller_data = &simone_mmc_spi_ops, .platform_data = &simone_mmc_spi_data, /* * We use 10 MHz even though the maximum is 3.7 MHz. The driver @@ -165,8 +114,18 @@ static struct spi_board_info simone_spi_devices[] __initdata = { }, }; +/* + * Up to v1.3, the Sim.One used SFRMOUT as SD card chip select, but this goes + * low between multi-message command blocks. From v1.4, it uses a GPIO instead. + * v1.3 parts will still work, since the signal on SFRMOUT is automatic. + */ +static int simone_spi_chipselects[] __initdata = { + EP93XX_GPIO_LINE_EGPIO1, +}; + static struct ep93xx_spi_info simone_spi_info __initdata = { - .num_chipselect = ARRAY_SIZE(simone_spi_devices), + .chipselect = simone_spi_chipselects, + .num_chipselect = ARRAY_SIZE(simone_spi_chipselects), .use_dma = 1, }; diff --git a/arch/arm/mach-ep93xx/vision_ep9307.c b/arch/arm/mach-ep93xx/vision_ep9307.c index 5cced5988498..1daf9441058c 100644 --- a/arch/arm/mach-ep93xx/vision_ep9307.c +++ b/arch/arm/mach-ep93xx/vision_ep9307.c @@ -175,33 +175,9 @@ static struct cs4271_platform_data vision_cs4271_data = { .gpio_nreset = EP93XX_GPIO_LINE_H(2), }; -static int vision_cs4271_hw_setup(struct spi_device *spi) -{ - return gpio_request_one(EP93XX_GPIO_LINE_EGPIO6, - GPIOF_OUT_INIT_HIGH, spi->modalias); -} - -static void vision_cs4271_hw_cleanup(struct spi_device *spi) -{ - gpio_free(EP93XX_GPIO_LINE_EGPIO6); -} - -static void vision_cs4271_hw_cs_control(struct spi_device *spi, int value) -{ - gpio_set_value(EP93XX_GPIO_LINE_EGPIO6, value); -} - -static struct ep93xx_spi_chip_ops vision_cs4271_hw = { - .setup = vision_cs4271_hw_setup, - .cleanup = vision_cs4271_hw_cleanup, - .cs_control = vision_cs4271_hw_cs_control, -}; - /************************************************************************* * SPI Flash *************************************************************************/ -#define VISION_SPI_FLASH_CS EP93XX_GPIO_LINE_EGPIO7 - static struct mtd_partition vision_spi_flash_partitions[] = { { .name = "SPI bootstrap", @@ -224,68 +200,20 @@ static struct flash_platform_data vision_spi_flash_data = { .nr_parts = ARRAY_SIZE(vision_spi_flash_partitions), }; -static int vision_spi_flash_hw_setup(struct spi_device *spi) -{ - return gpio_request_one(VISION_SPI_FLASH_CS, GPIOF_INIT_HIGH, - spi->modalias); -} - -static void vision_spi_flash_hw_cleanup(struct spi_device *spi) -{ - gpio_free(VISION_SPI_FLASH_CS); -} - -static void vision_spi_flash_hw_cs_control(struct spi_device *spi, int value) -{ - gpio_set_value(VISION_SPI_FLASH_CS, value); -} - -static struct ep93xx_spi_chip_ops vision_spi_flash_hw = { - .setup = vision_spi_flash_hw_setup, - .cleanup = vision_spi_flash_hw_cleanup, - .cs_control = vision_spi_flash_hw_cs_control, -}; - /************************************************************************* * SPI SD/MMC host *************************************************************************/ -#define VISION_SPI_MMC_CS EP93XX_GPIO_LINE_G(2) -#define VISION_SPI_MMC_WP EP93XX_GPIO_LINE_F(0) -#define VISION_SPI_MMC_CD EP93XX_GPIO_LINE_EGPIO15 - static struct mmc_spi_platform_data vision_spi_mmc_data = { .detect_delay = 100, .powerup_msecs = 100, .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, .flags = MMC_SPI_USE_CD_GPIO | MMC_SPI_USE_RO_GPIO, - .cd_gpio = VISION_SPI_MMC_CD, + .cd_gpio = EP93XX_GPIO_LINE_EGPIO15, .cd_debounce = 1, - .ro_gpio = VISION_SPI_MMC_WP, + .ro_gpio = EP93XX_GPIO_LINE_F(0), .caps2 = MMC_CAP2_RO_ACTIVE_HIGH, }; -static int vision_spi_mmc_hw_setup(struct spi_device *spi) -{ - return gpio_request_one(VISION_SPI_MMC_CS, GPIOF_INIT_HIGH, - spi->modalias); -} - -static void vision_spi_mmc_hw_cleanup(struct spi_device *spi) -{ - gpio_free(VISION_SPI_MMC_CS); -} - -static void vision_spi_mmc_hw_cs_control(struct spi_device *spi, int value) -{ - gpio_set_value(VISION_SPI_MMC_CS, value); -} - -static struct ep93xx_spi_chip_ops vision_spi_mmc_hw = { - .setup = vision_spi_mmc_hw_setup, - .cleanup = vision_spi_mmc_hw_cleanup, - .cs_control = vision_spi_mmc_hw_cs_control, -}; - /************************************************************************* * SPI Bus *************************************************************************/ @@ -293,7 +221,6 @@ static struct spi_board_info vision_spi_board_info[] __initdata = { { .modalias = "cs4271", .platform_data = &vision_cs4271_data, - .controller_data = &vision_cs4271_hw, .max_speed_hz = 6000000, .bus_num = 0, .chip_select = 0, @@ -301,7 +228,6 @@ static struct spi_board_info vision_spi_board_info[] __initdata = { }, { .modalias = "sst25l", .platform_data = &vision_spi_flash_data, - .controller_data = &vision_spi_flash_hw, .max_speed_hz = 20000000, .bus_num = 0, .chip_select = 1, @@ -309,7 +235,6 @@ static struct spi_board_info vision_spi_board_info[] __initdata = { }, { .modalias = "mmc_spi", .platform_data = &vision_spi_mmc_data, - .controller_data = &vision_spi_mmc_hw, .max_speed_hz = 20000000, .bus_num = 0, .chip_select = 2, @@ -317,8 +242,15 @@ static struct spi_board_info vision_spi_board_info[] __initdata = { }, }; +static int vision_spi_chipselects[] __initdata = { + EP93XX_GPIO_LINE_EGPIO6, + EP93XX_GPIO_LINE_EGPIO7, + EP93XX_GPIO_LINE_G(2), +}; + static struct ep93xx_spi_info vision_spi_master __initdata = { - .num_chipselect = ARRAY_SIZE(vision_spi_board_info), + .chipselect = vision_spi_chipselects, + .num_chipselect = ARRAY_SIZE(vision_spi_chipselects), .use_dma = 1, }; diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 17a6387e20b5..b5d766064b7b 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -107,16 +108,6 @@ struct ep93xx_spi { void *zeropage; }; -/** - * struct ep93xx_spi_chip - SPI device hardware settings - * @spi: back pointer to the SPI device - * @ops: private chip operations - */ -struct ep93xx_spi_chip { - const struct spi_device *spi; - struct ep93xx_spi_chip_ops *ops; -}; - /* converts bits per word to CR0.DSS value */ #define bits_per_word_to_dss(bpw) ((bpw) - 1) @@ -229,104 +220,36 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi, return -EINVAL; } -static void ep93xx_spi_cs_control(struct spi_device *spi, bool control) -{ - struct ep93xx_spi_chip *chip = spi_get_ctldata(spi); - int value = (spi->mode & SPI_CS_HIGH) ? control : !control; - - if (chip->ops && chip->ops->cs_control) - chip->ops->cs_control(spi, value); -} - -/** - * ep93xx_spi_setup() - setup an SPI device - * @spi: SPI device to setup - * - * This function sets up SPI device mode, speed etc. Can be called multiple - * times for a single device. Returns %0 in case of success, negative error in - * case of failure. When this function returns success, the device is - * deselected. - */ -static int ep93xx_spi_setup(struct spi_device *spi) +static void ep93xx_spi_cs_control(struct spi_device *spi, bool enable) { - struct ep93xx_spi *espi = spi_master_get_devdata(spi->master); - struct ep93xx_spi_chip *chip; + if (spi->mode & SPI_CS_HIGH) + enable = !enable; - chip = spi_get_ctldata(spi); - if (!chip) { - dev_dbg(&espi->pdev->dev, "initial setup for %s\n", - spi->modalias); - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - chip->spi = spi; - chip->ops = spi->controller_data; - - if (chip->ops && chip->ops->setup) { - int ret = chip->ops->setup(spi); - - if (ret) { - kfree(chip); - return ret; - } - } - - spi_set_ctldata(spi, chip); - } - - ep93xx_spi_cs_control(spi, false); - return 0; + if (gpio_is_valid(spi->cs_gpio)) + gpio_set_value(spi->cs_gpio, !enable); } -/** - * ep93xx_spi_cleanup() - cleans up master controller specific state - * @spi: SPI device to cleanup - * - * This function releases master controller specific state for given @spi - * device. - */ -static void ep93xx_spi_cleanup(struct spi_device *spi) -{ - struct ep93xx_spi_chip *chip; - - chip = spi_get_ctldata(spi); - if (chip) { - if (chip->ops && chip->ops->cleanup) - chip->ops->cleanup(spi); - spi_set_ctldata(spi, NULL); - kfree(chip); - } -} - -/** - * ep93xx_spi_chip_setup() - configures hardware according to given @chip - * @espi: ep93xx SPI controller struct - * @chip: chip specific settings - * @speed_hz: transfer speed - * @bits_per_word: transfer bits_per_word - */ static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi, - const struct ep93xx_spi_chip *chip, - u32 speed_hz, u8 bits_per_word) + struct spi_device *spi, + struct spi_transfer *xfer) { - u8 dss = bits_per_word_to_dss(bits_per_word); + u8 dss = bits_per_word_to_dss(xfer->bits_per_word); u8 div_cpsr = 0; u8 div_scr = 0; u16 cr0; int err; - err = ep93xx_spi_calc_divisors(espi, speed_hz, &div_cpsr, &div_scr); + err = ep93xx_spi_calc_divisors(espi, xfer->speed_hz, + &div_cpsr, &div_scr); if (err) return err; cr0 = div_scr << SSPCR0_SCR_SHIFT; - cr0 |= (chip->spi->mode & (SPI_CPHA|SPI_CPOL)) << SSPCR0_MODE_SHIFT; + cr0 |= (spi->mode & (SPI_CPHA | SPI_CPOL)) << SSPCR0_MODE_SHIFT; cr0 |= dss; dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n", - chip->spi->mode, div_cpsr, div_scr, dss); + spi->mode, div_cpsr, div_scr, dss); dev_dbg(&espi->pdev->dev, "setup: cr0 %#x\n", cr0); ep93xx_spi_write_u8(espi, SSPCPSR, div_cpsr); @@ -603,12 +526,11 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi, struct spi_message *msg, struct spi_transfer *t) { - struct ep93xx_spi_chip *chip = spi_get_ctldata(msg->spi); int err; msg->state = t; - err = ep93xx_spi_chip_setup(espi, chip, t->speed_hz, t->bits_per_word); + err = ep93xx_spi_chip_setup(espi, msg->spi, t); if (err) { dev_err(&espi->pdev->dev, "failed to setup chip for transfer\n"); @@ -863,8 +785,13 @@ static int ep93xx_spi_probe(struct platform_device *pdev) struct resource *res; int irq; int error; + int i; info = dev_get_platdata(&pdev->dev); + if (!info) { + dev_err(&pdev->dev, "missing platform data\n"); + return -EINVAL; + } irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -882,14 +809,36 @@ static int ep93xx_spi_probe(struct platform_device *pdev) if (!master) return -ENOMEM; - master->setup = ep93xx_spi_setup; master->transfer_one_message = ep93xx_spi_transfer_one_message; - master->cleanup = ep93xx_spi_cleanup; master->bus_num = pdev->id; - master->num_chipselect = info->num_chipselect; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); + master->num_chipselect = info->num_chipselect; + master->cs_gpios = devm_kzalloc(&master->dev, + sizeof(int) * master->num_chipselect, + GFP_KERNEL); + if (!master->cs_gpios) { + error = -ENOMEM; + goto fail_release_master; + } + + for (i = 0; i < master->num_chipselect; i++) { + master->cs_gpios[i] = info->chipselect[i]; + + if (!gpio_is_valid(master->cs_gpios[i])) + continue; + + error = devm_gpio_request_one(&pdev->dev, master->cs_gpios[i], + GPIOF_OUT_INIT_HIGH, + "ep93xx-spi"); + if (error) { + dev_err(&pdev->dev, "could not request cs gpio %d\n", + master->cs_gpios[i]); + goto fail_release_master; + } + } + platform_set_drvdata(pdev, master); espi = spi_master_get_devdata(master); diff --git a/include/linux/platform_data/spi-ep93xx.h b/include/linux/platform_data/spi-ep93xx.h index 9bb63ac13f04..171a271c2cbd 100644 --- a/include/linux/platform_data/spi-ep93xx.h +++ b/include/linux/platform_data/spi-ep93xx.h @@ -5,25 +5,14 @@ struct spi_device; /** * struct ep93xx_spi_info - EP93xx specific SPI descriptor - * @num_chipselect: number of chip selects on this board, must be - * at least one + * @chipselect: array of gpio numbers to use as chip selects + * @num_chipselect: ARRAY_SIZE(chipselect) * @use_dma: use DMA for the transfers */ struct ep93xx_spi_info { + int *chipselect; int num_chipselect; bool use_dma; }; -/** - * struct ep93xx_spi_chip_ops - operation callbacks for SPI slave device - * @setup: setup the chip select mechanism - * @cleanup: cleanup the chip select mechanism - * @cs_control: control the device chip select - */ -struct ep93xx_spi_chip_ops { - int (*setup)(struct spi_device *spi); - void (*cleanup)(struct spi_device *spi); - void (*cs_control)(struct spi_device *spi, int value); -}; - #endif /* __ASM_MACH_EP93XX_SPI_H */ -- cgit v1.2.3-59-g8ed1b From cce59c225920309e03c2ea350ed6a0e233e33963 Mon Sep 17 00:00:00 2001 From: Prahlad V Date: Fri, 17 Feb 2017 02:03:35 +0530 Subject: spi: ti-qspi: revise ti_qspi_probe() failure flow call spi_master_put() in case of failures after spi_alloc_master(). call pm_runtime_disable() in case of failures after pm_runtime_enable(). Signed-off-by: Prahlad V Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index ec6fb09e2e17..e784d0f64dc1 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -652,7 +652,8 @@ static int ti_qspi_probe(struct platform_device *pdev) r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (r == NULL) { dev_err(&pdev->dev, "missing platform data\n"); - return -ENODEV; + ret = -ENODEV; + goto free_master; } } @@ -669,7 +670,8 @@ static int ti_qspi_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no irq resource?\n"); - return irq; + ret = irq; + goto free_master; } mutex_init(&qspi->list_lock); @@ -685,15 +687,17 @@ static int ti_qspi_probe(struct platform_device *pdev) qspi->ctrl_base = syscon_regmap_lookup_by_phandle(np, "syscon-chipselects"); - if (IS_ERR(qspi->ctrl_base)) - return PTR_ERR(qspi->ctrl_base); + if (IS_ERR(qspi->ctrl_base)) { + ret = PTR_ERR(qspi->ctrl_base); + goto free_master; + } ret = of_property_read_u32_index(np, "syscon-chipselects", 1, &qspi->ctrl_reg); if (ret) { dev_err(&pdev->dev, "couldn't get ctrl_mod reg index\n"); - return ret; + goto free_master; } } @@ -742,6 +746,7 @@ no_dma: if (!ret) return 0; + pm_runtime_disable(&pdev->dev); free_master: spi_master_put(master); return ret; -- cgit v1.2.3-59-g8ed1b From e92f0051c0c65d7bee989884a233cfcd80303bdf Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 5 Feb 2017 15:49:40 +0000 Subject: spi: armada-3700: Remove spi_master_put in a3700_spi_remove() The call to spi_master_put() in a3700_spi_remove() is redundant since the master is registered using devm_spi_register_master() and no reference hold by using spi_master_get() in a3700_spi_remove(). This is detected by Coccinelle semantic patch. Fixes: 5762ab71eb24 ("spi: Add support for Armada 3700 SPI Controller") Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- drivers/spi/spi-armada-3700.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index 3155ab7ad970..56acd3511f73 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -901,7 +901,6 @@ static int a3700_spi_remove(struct platform_device *pdev) struct a3700_spi *spi = spi_master_get_devdata(master); clk_unprepare(spi->clk); - spi_master_put(master); return 0; } -- cgit v1.2.3-59-g8ed1b From 582c97f6868cf70720a17d2421d317333f3ad597 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 18 Feb 2017 17:06:48 +0100 Subject: spi: lantiq-ssc: activate under COMPILE_TEST This driver should compile on all platforms, activate it under compile test. The Lantiq specific parts are under ifdef and should be removed when Lantiq platform supports common clock framework. Signed-off-by: Hauke Mehrtens Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 1abba53c2334..5887beefab90 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -417,7 +417,7 @@ config SPI_NUC900 config SPI_LANTIQ_SSC tristate "Lantiq SSC SPI controller" - depends on LANTIQ + depends on LANTIQ || COMPILE_TEST help This driver supports the Lantiq SSC SPI controller in master mode. This controller is found on Intel (former Lantiq) SoCs like -- cgit v1.2.3-59-g8ed1b From 30fb27239f987c53429f24297f5d46e28d0e16ed Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 18 Feb 2017 10:42:02 +0100 Subject: spi: spi-ti-qspi: Fix error handling 'dma_request_chan_by_mask()' can not return NULL. Try to keep the logic in 'no_dma:' by resetting 'qspi->rx_chan' in case of error. Signed-off-by: Christophe JAILLET Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index ec6fb09e2e17..0fefa6423ff4 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -714,9 +714,10 @@ static int ti_qspi_probe(struct platform_device *pdev) dma_cap_set(DMA_MEMCPY, mask); qspi->rx_chan = dma_request_chan_by_mask(&mask); - if (!qspi->rx_chan) { + if (IS_ERR(qspi->rx_chan)) { dev_err(qspi->dev, "No Rx DMA available, trying mmap mode\n"); + qspi->rx_chan = NULL; ret = 0; goto no_dma; } -- cgit v1.2.3-59-g8ed1b From 7abfe04c47d97243a7aeeb8fe211a15687bff67f Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 18 Feb 2017 10:42:02 +0100 Subject: spi: spi-ti-qspi: Fix error handling 'dma_request_chan_by_mask()' can not return NULL. Try to keep the logic in 'no_dma:' by resetting 'qspi->rx_chan' in case of error. Signed-off-by: Christophe JAILLET Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index e784d0f64dc1..ad76a44fee6f 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -718,9 +718,10 @@ static int ti_qspi_probe(struct platform_device *pdev) dma_cap_set(DMA_MEMCPY, mask); qspi->rx_chan = dma_request_chan_by_mask(&mask); - if (!qspi->rx_chan) { + if (IS_ERR(qspi->rx_chan)) { dev_err(qspi->dev, "No Rx DMA available, trying mmap mode\n"); + qspi->rx_chan = NULL; ret = 0; goto no_dma; } -- cgit v1.2.3-59-g8ed1b