diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-03 12:31:39 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-03 12:31:39 -0700 |
commit | d25e436c4b68db2895185b24ad1f22499c2f87b0 (patch) | |
tree | dd66245410513f09d2439ef0b34cf1d131696bed | |
parent | a90f0e9ebb88ba7b0efea4e7d9defc0c2b96f712 (diff) | |
parent | 282ec0ea65dab88fda51b5b9b649958ae42f4ac0 (diff) | |
download | linux-d25e436c4b68db2895185b24ad1f22499c2f87b0.tar.gz linux-d25e436c4b68db2895185b24ad1f22499c2f87b0.tar.bz2 linux-d25e436c4b68db2895185b24ad1f22499c2f87b0.zip |
Merge tag 'spi-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi updates from Mark Brown:
"There's quite a lot of small driver specific fixes and enhancements in
this release but the main activity has been around the loopback and
spidev test drivers which is good to see as it should hopefully help
improve the quality of all the drivers as people start to make use of
the new code:
- Additional tests in the loopback test driver for vmalloc()
compatibility and around delays together with fixes for existing
tests.
- Support for testing continuous data transfer for use in soak
testing.
- Device property support for board info platforms.
- Support for registering empty sets of devices via board info
(useful when writing code to enumerate hardware automatically)"
* tag 'spi-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (52 commits)
spi: cadence: Allow for GPIO pins to be used as chipselects
spi-imx: Implements handling of the SPI_READY mode flag.
spi: tegra: fix spelling mistake: "trasfer" -> "transfer"
spi: spi-ti-qspi: Use bounce buffer if read buffer is not DMA'ble
spi: Add can_dma like interface for spi_flash_read
spi: dw: Disable clock after unregistering the host
spi: double time out tolerance
spi: atmel: add deepest PM support to SAMA5D2
spi: atmel: factorize reusable code for SPI controller init
spi: orion: add LSB support
spi: pl022: don't use uninitialized variable
spi: loopback-test: fix spelling mistake: "minimam" -> "minimum"
spi: dynamycally allocated message initialization
spi: spi-ti-qspi: Remove unused dma_dev variable
spi: omap2-mcspi: poll OMAP2_MCSPI_CHSTAT_RXS for PIO transfer
spi: spi-ti-qspi: Use dma_engine wrapper for dma memcpy call
spi: spidev_test: add option to continuously transfer data
spi: loopback-test: fix potential integer overflow on multiple
spi: sun6i: update max transfer size reported
spi: pl022: Document property values
...
32 files changed, 964 insertions, 410 deletions
diff --git a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt index 8bc95e2fc47f..31b5b21598ff 100644 --- a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt +++ b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt @@ -23,6 +23,12 @@ See the clock consumer binding, Obsolete properties: - fsl,spi-num-chipselects : Contains the number of the chipselect +Optional properties: +- fsl,spi-rdy-drctl: Integer, representing the value of DRCTL, the register +controlling the SPI_READY handling. Note that to enable the DRCTL consideration, +the SPI_READY mode-flag needs to be set too. +Valid values are: 0 (disabled), 1 (edge-triggered burst) and 2 (level-triggered burst). + Example: ecspi@70010000 { @@ -35,4 +41,5 @@ ecspi@70010000 { <&gpio3 25 0>; /* GPIO3_25 */ dmas = <&sdma 3 7 1>, <&sdma 4 7 2>; dma-names = "rx", "tx"; + fsl,spi-rdy-drctl = <1>; }; diff --git a/Documentation/devicetree/bindings/spi/spi-bcm63xx-hsspi.txt b/Documentation/devicetree/bindings/spi/spi-bcm63xx-hsspi.txt new file mode 100644 index 000000000000..37b29ee13860 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-bcm63xx-hsspi.txt @@ -0,0 +1,33 @@ +Binding for Broadcom BCM6328 High Speed SPI controller + +Required properties: +- compatible: must contain of "brcm,bcm6328-hsspi". +- reg: Base address and size of the controllers memory area. +- interrupts: Interrupt for the SPI block. +- clocks: phandles of the SPI clock and the PLL clock. +- clock-names: must be "hsspi", "pll". +- #address-cells: <1>, as required by generic SPI binding. +- #size-cells: <0>, also as required by generic SPI binding. + +Optional properties: +- num-cs: some controllers have less than 8 cs signals. Defaults to 8 + if absent. + +Child nodes as per the generic SPI binding. + +Example: + + spi@10001000 { + compatible = "brcm,bcm6328-hsspi"; + reg = <0x10001000 0x600>; + + interrupts = <29>; + + clocks = <&clkctl 9>, <&hsspi_pll>; + clock-names = "hsspi", "pll"; + + num-cs = <2>; + + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/spi/spi-bcm63xx.txt b/Documentation/devicetree/bindings/spi/spi-bcm63xx.txt new file mode 100644 index 000000000000..1c16f6692613 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-bcm63xx.txt @@ -0,0 +1,33 @@ +Binding for Broadcom BCM6348/BCM6358 SPI controller + +Required properties: +- compatible: must contain one of "brcm,bcm6348-spi", "brcm,bcm6358-spi". +- reg: Base address and size of the controllers memory area. +- interrupts: Interrupt for the SPI block. +- clocks: phandle of the SPI clock. +- clock-names: has to be "spi". +- #address-cells: <1>, as required by generic SPI binding. +- #size-cells: <0>, also as required by generic SPI binding. + +Optional properties: +- num-cs: some controllers have less than 8 cs signals. Defaults to 8 + if absent. + +Child nodes as per the generic SPI binding. + +Example: + + spi@10000800 { + compatible = "brcm,bcm6368-spi", "brcm,bcm6358-spi"; + reg = <0x10000800 0x70c>; + + interrupts = <1>; + + clocks = <&clkctl 9>; + clock-names = "spi"; + + num-cs = <5>; + + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/spi/spi_pl022.txt b/Documentation/devicetree/bindings/spi/spi_pl022.txt index 4d1673ca8cf8..7638b4968ddb 100644 --- a/Documentation/devicetree/bindings/spi/spi_pl022.txt +++ b/Documentation/devicetree/bindings/spi/spi_pl022.txt @@ -30,7 +30,10 @@ contain the following properties. 0: SPI 1: Texas Instruments Synchronous Serial Frame Format 2: Microwire (Half Duplex) -- pl022,com-mode : polling, interrupt or dma +- pl022,com-mode : specifies the transfer mode: + 0: interrupt mode + 1: polling mode (default mode if property not present) + 2: DMA mode - pl022,rx-level-trig : Rx FIFO watermark level - pl022,tx-level-trig : Tx FIFO watermark level - pl022,ctrl-len : Microwire interface: Control length @@ -56,9 +59,7 @@ Example: spi-max-frequency = <12000000>; spi-cpol; spi-cpha; - pl022,hierarchy = <0>; pl022,interface = <0>; - pl022,slave-tx-disable; pl022,com-mode = <0x2>; pl022,rx-level-trig = <0>; pl022,tx-level-trig = <0>; @@ -67,4 +68,3 @@ Example: pl022,duplex = <0>; }; }; - diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index 26696b693e63..17a1eb14847a 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -169,6 +169,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = { #ifdef CONFIG_ARM64 { "APMC0D0F", APD_ADDR(xgene_i2c_desc) }, { "BRCM900D", APD_ADDR(vulcan_spi_desc) }, + { "CAV900D", APD_ADDR(vulcan_spi_desc) }, #endif { } }; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 25ae7f2e44b5..1761c9004fc1 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -715,7 +715,7 @@ config SPI_XILINX config SPI_XLP tristate "Netlogic XLP SPI controller driver" - depends on CPU_XLP || ARCH_VULCAN || COMPILE_TEST + depends on CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST help Enable support for the SPI controller on the Netlogic XLP SoCs. Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, XLP9XX diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 0e7712bac3b6..1eb83c9613d5 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1464,6 +1464,25 @@ static int atmel_spi_gpio_cs(struct platform_device *pdev) return 0; } +static void atmel_spi_init(struct atmel_spi *as) +{ + spi_writel(as, CR, SPI_BIT(SWRST)); + spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ + if (as->caps.has_wdrbt) { + spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS) + | SPI_BIT(MSTR)); + } else { + spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS)); + } + + if (as->use_pdc) + spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); + spi_writel(as, CR, SPI_BIT(SPIEN)); + + if (as->fifo_size) + spi_writel(as, CR, SPI_BIT(FIFOEN)); +} + static int atmel_spi_probe(struct platform_device *pdev) { struct resource *regs; @@ -1572,26 +1591,14 @@ static int atmel_spi_probe(struct platform_device *pdev) as->spi_clk = clk_get_rate(clk); - spi_writel(as, CR, SPI_BIT(SWRST)); - spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ - if (as->caps.has_wdrbt) { - spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS) - | SPI_BIT(MSTR)); - } else { - spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS)); - } - - if (as->use_pdc) - spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); - spi_writel(as, CR, SPI_BIT(SPIEN)); - as->fifo_size = 0; if (!of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size", &as->fifo_size)) { dev_info(&pdev->dev, "Using FIFO (%u data)\n", as->fifo_size); - spi_writel(as, CR, SPI_BIT(FIFOEN)); } + atmel_spi_init(as); + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_active(&pdev->dev); @@ -1695,8 +1702,17 @@ static int atmel_spi_suspend(struct device *dev) static int atmel_spi_resume(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); + struct atmel_spi *as = spi_master_get_devdata(master); int ret; + ret = clk_prepare_enable(as->clk); + if (ret) + return ret; + + atmel_spi_init(as); + + clk_disable_unprepare(as->clk); + if (!pm_runtime_suspended(dev)) { ret = atmel_spi_runtime_resume(dev); if (ret) diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index 55789f7cda92..5514cd02e93a 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -19,6 +19,7 @@ #include <linux/interrupt.h> #include <linux/spi/spi.h> #include <linux/mutex.h> +#include <linux/of.h> #define HSSPI_GLOBAL_CTRL_REG 0x0 #define GLOBAL_CTRL_CS_POLARITY_SHIFT 0 @@ -91,6 +92,7 @@ #define HSSPI_MAX_SYNC_CLOCK 30000000 +#define HSSPI_SPI_MAX_CS 8 #define HSSPI_BUS_NUM 1 /* 0 is legacy SPI */ struct bcm63xx_hsspi { @@ -332,7 +334,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct clk *clk; int irq, ret; - u32 reg, rate; + u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -351,8 +353,16 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) return PTR_ERR(clk); rate = clk_get_rate(clk); - if (!rate) - return -EINVAL; + if (!rate) { + struct clk *pll_clk = devm_clk_get(dev, "pll"); + + if (IS_ERR(pll_clk)) + return PTR_ERR(pll_clk); + + rate = clk_get_rate(pll_clk); + if (!rate) + return -EINVAL; + } ret = clk_prepare_enable(clk); if (ret) @@ -374,8 +384,17 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) mutex_init(&bs->bus_mutex); init_completion(&bs->done); - master->bus_num = HSSPI_BUS_NUM; - master->num_chipselect = 8; + master->dev.of_node = dev->of_node; + if (!dev->of_node) + master->bus_num = HSSPI_BUS_NUM; + + of_property_read_u32(dev->of_node, "num-cs", &num_cs); + if (num_cs > 8) { + dev_warn(dev, "unsupported number of cs (%i), reducing to 8\n", + num_cs); + num_cs = HSSPI_SPI_MAX_CS; + } + master->num_chipselect = num_cs; master->setup = bcm63xx_hsspi_setup; master->transfer_one_message = bcm63xx_hsspi_transfer_one; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | @@ -461,10 +480,16 @@ static int bcm63xx_hsspi_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(bcm63xx_hsspi_pm_ops, bcm63xx_hsspi_suspend, bcm63xx_hsspi_resume); +static const struct of_device_id bcm63xx_hsspi_of_match[] = { + { .compatible = "brcm,bcm6328-hsspi", }, + { }, +}; + static struct platform_driver bcm63xx_hsspi_driver = { .driver = { .name = "bcm63xx-hsspi", .pm = &bcm63xx_hsspi_pm_ops, + .of_match_table = bcm63xx_hsspi_of_match, }, .probe = bcm63xx_hsspi_probe, .remove = bcm63xx_hsspi_remove, diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index fee747030ee6..247f71b02235 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -26,6 +26,7 @@ #include <linux/completion.h> #include <linux/err.h> #include <linux/pm_runtime.h> +#include <linux/of.h> /* BCM 6338/6348 SPI core */ #define SPI_6348_RSET_SIZE 64 @@ -428,6 +429,13 @@ static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static size_t bcm63xx_spi_max_length(struct spi_device *spi) +{ + struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); + + return bs->fifo_size; +} + static const unsigned long bcm6348_spi_reg_offsets[] = { [SPI_CMD] = SPI_6348_CMD, [SPI_INT_STATUS] = SPI_6348_INT_STATUS, @@ -477,21 +485,48 @@ static const struct platform_device_id bcm63xx_spi_dev_match[] = { }, }; +static const struct of_device_id bcm63xx_spi_of_match[] = { + { .compatible = "brcm,bcm6348-spi", .data = &bcm6348_spi_reg_offsets }, + { .compatible = "brcm,bcm6358-spi", .data = &bcm6358_spi_reg_offsets }, + { }, +}; + static int bcm63xx_spi_probe(struct platform_device *pdev) { struct resource *r; const unsigned long *bcm63xx_spireg; struct device *dev = &pdev->dev; - int irq; + int irq, bus_num; struct spi_master *master; struct clk *clk; struct bcm63xx_spi *bs; int ret; + u32 num_cs = BCM63XX_SPI_MAX_CS; - if (!pdev->id_entry->driver_data) - return -EINVAL; + if (dev->of_node) { + const struct of_device_id *match; + + match = of_match_node(bcm63xx_spi_of_match, dev->of_node); + if (!match) + return -EINVAL; + bcm63xx_spireg = match->data; + + of_property_read_u32(dev->of_node, "num-cs", &num_cs); + if (num_cs > BCM63XX_SPI_MAX_CS) { + dev_warn(dev, "unsupported number of cs (%i), reducing to 8\n", + num_cs); + num_cs = BCM63XX_SPI_MAX_CS; + } - bcm63xx_spireg = (const unsigned long *)pdev->id_entry->driver_data; + bus_num = -1; + } else if (pdev->id_entry->driver_data) { + const struct platform_device_id *match = pdev->id_entry; + + bcm63xx_spireg = (const unsigned long *)match->driver_data; + bus_num = BCM63XX_SPI_BUS_NUM; + } else { + return -EINVAL; + } irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -536,11 +571,14 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) goto out_err; } - master->bus_num = BCM63XX_SPI_BUS_NUM; - master->num_chipselect = BCM63XX_SPI_MAX_CS; + master->dev.of_node = dev->of_node; + master->bus_num = bus_num; + master->num_chipselect = num_cs; master->transfer_one_message = bcm63xx_spi_transfer_one; master->mode_bits = MODEBITS; master->bits_per_word_mask = SPI_BPW_MASK(8); + master->max_transfer_size = bcm63xx_spi_max_length; + master->max_message_size = bcm63xx_spi_max_length; master->auto_runtime_pm = true; bs->msg_type_shift = bs->reg_offsets[SPI_MSG_TYPE_SHIFT]; bs->msg_ctl_width = bs->reg_offsets[SPI_MSG_CTL_WIDTH]; @@ -624,6 +662,7 @@ static struct platform_driver bcm63xx_spi_driver = { .driver = { .name = "bcm63xx-spi", .pm = &bcm63xx_spi_pm_ops, + .of_match_table = bcm63xx_spi_of_match, }, .id_table = bcm63xx_spi_dev_match, .probe = bcm63xx_spi_probe, diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 1c57ce64abba..f0b5c7b91f37 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -13,6 +13,7 @@ #include <linux/clk.h> #include <linux/delay.h> +#include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> @@ -127,6 +128,10 @@ struct cdns_spi { u32 is_decoded_cs; }; +struct cdns_spi_device_data { + bool gpio_requested; +}; + /* Macros for the SPI controller read/write */ static inline u32 cdns_spi_read(struct cdns_spi *xspi, u32 offset) { @@ -456,6 +461,64 @@ static int cdns_unprepare_transfer_hardware(struct spi_master *master) return 0; } +static int cdns_spi_setup(struct spi_device *spi) +{ + + int ret = -EINVAL; + struct cdns_spi_device_data *cdns_spi_data = spi_get_ctldata(spi); + + /* this is a pin managed by the controller, leave it alone */ + if (spi->cs_gpio == -ENOENT) + return 0; + + /* this seems to be the first time we're here */ + if (!cdns_spi_data) { + cdns_spi_data = kzalloc(sizeof(*cdns_spi_data), GFP_KERNEL); + if (!cdns_spi_data) + return -ENOMEM; + cdns_spi_data->gpio_requested = false; + spi_set_ctldata(spi, cdns_spi_data); + } + + /* if we haven't done so, grab the gpio */ + if (!cdns_spi_data->gpio_requested && gpio_is_valid(spi->cs_gpio)) { + ret = gpio_request_one(spi->cs_gpio, + (spi->mode & SPI_CS_HIGH) ? + GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, + dev_name(&spi->dev)); + if (ret) + dev_err(&spi->dev, "can't request chipselect gpio %d\n", + spi->cs_gpio); + else + cdns_spi_data->gpio_requested = true; + } else { + if (gpio_is_valid(spi->cs_gpio)) { + int mode = ((spi->mode & SPI_CS_HIGH) ? + GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH); + + ret = gpio_direction_output(spi->cs_gpio, mode); + if (ret) + dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n", + spi->cs_gpio, ret); + } + } + + return ret; +} + +static void cdns_spi_cleanup(struct spi_device *spi) +{ + struct cdns_spi_device_data *cdns_spi_data = spi_get_ctldata(spi); + + if (cdns_spi_data) { + if (cdns_spi_data->gpio_requested) + gpio_free(spi->cs_gpio); + kfree(cdns_spi_data); + spi_set_ctldata(spi, NULL); + } + +} + /** * cdns_spi_probe - Probe method for the SPI driver * @pdev: Pointer to the platform_device structure @@ -555,6 +618,8 @@ static int cdns_spi_probe(struct platform_device *pdev) master->transfer_one = cdns_transfer_one; master->unprepare_transfer_hardware = cdns_unprepare_transfer_hardware; master->set_cs = cdns_spi_chipselect; + master->setup = cdns_spi_setup; + master->cleanup = cdns_spi_cleanup; master->auto_runtime_pm = true; master->mode_bits = SPI_CPOL | SPI_CPHA; diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 02fb96797ac8..595acdcfc7d0 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -109,6 +109,8 @@ #define SPIDEF 0x4c #define SPIFMT0 0x50 +#define DMA_MIN_BYTES 16 + /* SPI Controller driver's private data. */ struct davinci_spi { struct spi_bitbang bitbang; @@ -389,6 +391,7 @@ static int davinci_spi_of_setup(struct spi_device *spi) { struct davinci_spi_config *spicfg = spi->controller_data; struct device_node *np = spi->dev.of_node; + struct davinci_spi *dspi = spi_master_get_devdata(spi->master); u32 prop; if (spicfg == NULL && np) { @@ -400,6 +403,9 @@ static int davinci_spi_of_setup(struct spi_device *spi) if (!of_property_read_u32(np, "ti,spi-wdelay", &prop)) spicfg->wdelay = (u8)prop; spi->controller_data = spicfg; + + if (dspi->dma_rx && dspi->dma_tx) + spicfg->io_type = SPI_IO_TYPE_DMA; } return 0; @@ -467,6 +473,22 @@ static void davinci_spi_cleanup(struct spi_device *spi) kfree(spicfg); } +static bool davinci_spi_can_dma(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct davinci_spi_config *spicfg = spi->controller_data; + bool can_dma = false; + + if (spicfg) + can_dma = (spicfg->io_type == SPI_IO_TYPE_DMA) && + (xfer->len >= DMA_MIN_BYTES) && + !is_vmalloc_addr(xfer->rx_buf) && + !is_vmalloc_addr(xfer->tx_buf); + + return can_dma; +} + static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status) { struct device *sdev = dspi->bitbang.master->dev.parent; @@ -581,8 +603,6 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) struct davinci_spi_config *spicfg; struct davinci_spi_platform_data *pdata; unsigned uninitialized_var(rx_buf_count); - void *dummy_buf = NULL; - struct scatterlist sg_rx, sg_tx; dspi = spi_master_get_devdata(spi->master); pdata = &dspi->pdata; @@ -605,10 +625,9 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) reinit_completion(&dspi->done); - if (spicfg->io_type == SPI_IO_TYPE_INTR) - set_io_bits(dspi->base + SPIINT, SPIINT_MASKINT); - - if (spicfg->io_type != SPI_IO_TYPE_DMA) { + if (!davinci_spi_can_dma(spi->master, spi, t)) { + if (spicfg->io_type != SPI_IO_TYPE_POLL) + set_io_bits(dspi->base + SPIINT, SPIINT_MASKINT); /* start the transfer */ dspi->wcount--; tx_data = dspi->get_tx(dspi); @@ -630,51 +649,28 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) }; struct dma_async_tx_descriptor *rxdesc; struct dma_async_tx_descriptor *txdesc; - void *buf; - - dummy_buf = kzalloc(t->len, GFP_KERNEL); - if (!dummy_buf) - goto err_alloc_dummy_buf; dmaengine_slave_config(dspi->dma_rx, &dma_rx_conf); dmaengine_slave_config(dspi->dma_tx, &dma_tx_conf); - sg_init_table(&sg_rx, 1); - if (!t->rx_buf) - buf = dummy_buf; - else - buf = t->rx_buf; - t->rx_dma = dma_map_single(&spi->dev, buf, - t->len, DMA_FROM_DEVICE); - if (dma_mapping_error(&spi->dev, !t->rx_dma)) { - ret = -EFAULT; - goto err_rx_map; - } - sg_dma_address(&sg_rx) = t->rx_dma; - sg_dma_len(&sg_rx) = t->len; - - sg_init_table(&sg_tx, 1); - if (!t->tx_buf) - buf = dummy_buf; - else - buf = (void *)t->tx_buf; - t->tx_dma = dma_map_single(&spi->dev, buf, - t->len, DMA_TO_DEVICE); - if (dma_mapping_error(&spi->dev, t->tx_dma)) { - ret = -EFAULT; - goto err_tx_map; - } - sg_dma_address(&sg_tx) = t->tx_dma; - sg_dma_len(&sg_tx) = t->len; - rxdesc = dmaengine_prep_slave_sg(dspi->dma_rx, - &sg_rx, 1, DMA_DEV_TO_MEM, + t->rx_sg.sgl, t->rx_sg.nents, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!rxdesc) goto err_desc; + if (!t->tx_buf) { + /* To avoid errors when doing rx-only transfers with + * many SG entries (> 20), use the rx buffer as the + * dummy tx buffer so that dma reloads are done at the + * same time for rx and tx. + */ + t->tx_sg.sgl = t->rx_sg.sgl; + t->tx_sg.nents = t->rx_sg.nents; + } + txdesc = dmaengine_prep_slave_sg(dspi->dma_tx, - &sg_tx, 1, DMA_MEM_TO_DEV, + t->tx_sg.sgl, t->tx_sg.nents, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!txdesc) goto err_desc; @@ -710,16 +706,9 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) } clear_io_bits(dspi->base + SPIINT, SPIINT_MASKALL); - if (spicfg->io_type == SPI_IO_TYPE_DMA) { + if (davinci_spi_can_dma(spi->master, spi, t)) clear_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN); - dma_unmap_single(&spi->dev, t->rx_dma, - t->len, DMA_FROM_DEVICE); - dma_unmap_single(&spi->dev, t->tx_dma, - t->len, DMA_TO_DEVICE); - kfree(dummy_buf); - } - clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK); set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK); @@ -742,12 +731,6 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) return t->len; err_desc: - dma_unmap_single(&spi->dev, t->tx_dma, t->len, DMA_TO_DEVICE); -err_tx_map: - dma_unmap_single(&spi->dev, t->rx_dma, t->len, DMA_FROM_DEVICE); -err_rx_map: - kfree(dummy_buf); -err_alloc_dummy_buf: return ret; } @@ -988,8 +971,10 @@ static int davinci_spi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->num_chipselect = pdata->num_chipselect; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16); + master->flags = SPI_MASTER_MUST_RX; master->setup = davinci_spi_setup; master->cleanup = davinci_spi_cleanup; + master->can_dma = davinci_spi_can_dma; dspi->bitbang.chipselect = davinci_spi_chipselect; dspi->bitbang.setup_transfer = davinci_spi_setup_transfer; diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 447497e9124c..d25cc4037e23 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -115,8 +115,8 @@ static int dw_spi_mmio_remove(struct platform_device *pdev) { struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev); - clk_disable_unprepare(dwsmmio->clk); dw_spi_remove_host(&dwsmmio->dws); + clk_disable_unprepare(dwsmmio->clk); return 0; } diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 14c8e7ce1913..15201645bdc4 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -1002,7 +1002,8 @@ static int dspi_probe(struct platform_device *pdev) if (IS_ERR(dspi->regmap)) { dev_err(&pdev->dev, "failed to init regmap: %ld\n", PTR_ERR(dspi->regmap)); - return PTR_ERR(dspi->regmap); + ret = PTR_ERR(dspi->regmap); + goto out_master_put; } dspi_init(dspi); diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 0fc3452652ae..8f2e97857e8b 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -814,7 +814,7 @@ static int of_fsl_spi_probe(struct platform_device *ofdev) struct device_node *np = ofdev->dev.of_node; struct spi_master *master; struct resource mem; - int irq, type; + int irq = 0, type; int ret = -ENOMEM; ret = of_mpc8xxx_spi_probe(ofdev); @@ -847,6 +847,7 @@ static int of_fsl_spi_probe(struct platform_device *ofdev) return 0; err: + irq_dispose_mapping(irq); if (type == TYPE_FSL) of_fsl_spi_free_chipselects(dev); return ret; diff |