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 | blackbird-op-linux-d25e436c4b68db2895185b24ad1f22499c2f87b0.tar.gz blackbird-op-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 --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 9a7c62f471dc..b402530a7a9a 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -95,6 +95,7 @@ struct spi_imx_data { unsigned int spi_bus_clk; unsigned int bytes_per_word; + unsigned int spi_drctl; unsigned int count; void (*tx)(struct spi_imx_data *); @@ -246,6 +247,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, #define MX51_ECSPI_CTRL_XCH (1 << 2) #define MX51_ECSPI_CTRL_SMC (1 << 3) #define MX51_ECSPI_CTRL_MODE_MASK (0xf << 4) +#define MX51_ECSPI_CTRL_DRCTL(drctl) ((drctl) << 16) #define MX51_ECSPI_CTRL_POSTDIV_OFFSET 8 #define MX51_ECSPI_CTRL_PREDIV_OFFSET 12 #define MX51_ECSPI_CTRL_CS(cs) ((cs) << 18) @@ -355,6 +357,12 @@ static int mx51_ecspi_config(struct spi_device *spi, */ ctrl |= MX51_ECSPI_CTRL_MODE_MASK; + /* + * Enable SPI_RDY handling (falling edge/level triggered). + */ + if (spi->mode & SPI_READY) + ctrl |= MX51_ECSPI_CTRL_DRCTL(spi_imx->spi_drctl); + /* set clock speed */ ctrl |= mx51_ecspi_clkdiv(spi_imx, config->speed_hz, &clk); spi_imx->spi_bus_clk = clk; @@ -1173,7 +1181,7 @@ static int spi_imx_probe(struct platform_device *pdev) struct spi_master *master; struct spi_imx_data *spi_imx; struct resource *res; - int i, ret, irq; + int i, ret, irq, spi_drctl; if (!np && !mxc_platform_info) { dev_err(&pdev->dev, "can't get the platform data\n"); @@ -1181,6 +1189,12 @@ static int spi_imx_probe(struct platform_device *pdev) } master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data)); + ret = of_property_read_u32(np, "fsl,spi-rdy-drctl", &spi_drctl); + if ((ret < 0) || (spi_drctl >= 0x3)) { + /* '11' is reserved */ + spi_drctl = 0; + } + if (!master) return -ENOMEM; @@ -1216,7 +1230,9 @@ static int spi_imx_probe(struct platform_device *pdev) spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message; spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx)) - spi_imx->bitbang.master->mode_bits |= SPI_LOOP; + spi_imx->bitbang.master->mode_bits |= SPI_LOOP | SPI_READY; + + spi_imx->spi_drctl = spi_drctl; init_completion(&spi_imx->xfer_done); diff --git a/drivers/spi/spi-lantiq-ssc.c b/drivers/spi/spi-lantiq-ssc.c index 8a626f7fccea..d5976615d924 100644 --- a/drivers/spi/spi-lantiq-ssc.c +++ b/drivers/spi/spi-lantiq-ssc.c @@ -26,136 +26,140 @@ #include <lantiq_soc.h> #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 +#define LTQ_SPI_RX_IRQ_NAME "spi_rx" +#define LTQ_SPI_TX_IRQ_NAME "spi_tx" +#define LTQ_SPI_ERR_IRQ_NAME "spi_err" +#define LTQ_SPI_FRM_IRQ_NAME "spi_frm" + +#define LTQ_SPI_CLC 0x00 +#define LTQ_SPI_PISEL 0x04 +#define LTQ_SPI_ID 0x08 +#define LTQ_SPI_CON 0x10 +#define LTQ_SPI_STAT 0x14 +#define LTQ_SPI_WHBSTATE 0x18 +#define LTQ_SPI_TB 0x20 +#define LTQ_SPI_RB 0x24 +#define LTQ_SPI_RXFCON 0x30 +#define LTQ_SPI_TXFCON 0x34 +#define LTQ_SPI_FSTAT 0x38 +#define LTQ_SPI_BRT 0x40 +#define LTQ_SPI_BRSTAT 0x44 +#define LTQ_SPI_SFCON 0x60 +#define LTQ_SPI_SFSTAT 0x64 +#define LTQ_SPI_GPOCON 0x70 +#define LTQ_SPI_GPOSTAT 0x74 +#define LTQ_SPI_FPGO 0x78 +#define LTQ_SPI_RXREQ 0x80 +#define LTQ_SPI_RXCNT 0x84 +#define LTQ_SPI_DMACON 0xec +#define LTQ_SPI_IRNEN 0xf4 +#define LTQ_SPI_IRNICR 0xf8 +#define LTQ_SPI_IRNCR 0xfc + +#define LTQ_SPI_CLC_SMC_S 16 /* Clock divider for sleep mode */ +#define LTQ_SPI_CLC_SMC_M (0xFF << LTQ_SPI_CLC_SMC_S) +#define LTQ_SPI_CLC_RMC_S 8 /* Clock divider for normal run mode */ +#define LTQ_SPI_CLC_RMC_M (0xFF << LTQ_SPI_CLC_RMC_S) +#define LTQ_SPI_CLC_DISS BIT(1) /* Disable status bit */ +#define LTQ_SPI_CLC_DISR BIT(0) /* Disable request bit */ + +#define LTQ_SPI_ID_TXFS_S 24 /* Implemented TX FIFO size */ +#define LTQ_SPI_ID_TXFS_M (0x3F << LTQ_SPI_ID_TXFS_S) +#define LTQ_SPI_ID_RXFS_S 16 /* Implemented RX FIFO size */ +#define LTQ_SPI_ID_RXFS_M (0x3F << LTQ_SPI_ID_RXFS_S) +#define LTQ_SPI_ID_MOD_S 8 /* Module ID */ +#define LTQ_SPI_ID_MOD_M (0xff << LTQ_SPI_ID_MOD_S) +#define LTQ_SPI_ID_CFG_S 5 /* DMA interface support */ +#define LTQ_SPI_ID_CFG_M (1 << LTQ_SPI_ID_CFG_S) +#define LTQ_SPI_ID_REV_M 0x1F /* Hardware revision number */ + +#define LTQ_SPI_CON_BM_S 16 /* Data width selection */ +#define LTQ_SPI_CON_BM_M (0x1F << LTQ_SPI_CON_BM_S) +#define LTQ_SPI_CON_EM BIT(24) /* Echo mode */ +#define LTQ_SPI_CON_IDLE BIT(23) /* Idle bit value */ +#define LTQ_SPI_CON_ENBV BIT(22) /* Enable byte valid control */ +#define LTQ_SPI_CON_RUEN BIT(12) /* Receive underflow error enable */ +#define LTQ_SPI_CON_TUEN BIT(11) /* Transmit underflow error enable */ +#define LTQ_SPI_CON_AEN BIT(10) /* Abort error enable */ +#define LTQ_SPI_CON_REN BIT(9) /* Receive overflow error enable */ +#define LTQ_SPI_CON_TEN BIT(8) /* Transmit overflow error enable */ +#define LTQ_SPI_CON_LB BIT(7) /* Loopback control */ +#define LTQ_SPI_CON_PO BIT(6) /* Clock polarity control */ +#define LTQ_SPI_CON_PH BIT(5) /* Clock phase control */ +#define LTQ_SPI_CON_HB BIT(4) /* Heading control */ +#define LTQ_SPI_CON_RXOFF BIT(1) /* Switch receiver off */ +#define LTQ_SPI_CON_TXOFF BIT(0) /* Switch transmitter off */ + +#define LTQ_SPI_STAT_RXBV_S 28 +#define LTQ_SPI_STAT_RXBV_M (0x7 << LTQ_SPI_STAT_RXBV_S) +#define LTQ_SPI_STAT_BSY BIT(13) /* Busy flag */ +#define LTQ_SPI_STAT_RUE BIT(12) /* Receive underflow error flag */ +#define LTQ_SPI_STAT_TUE BIT(11) /* Transmit underflow error flag */ +#define LTQ_SPI_STAT_AE BIT(10) /* Abort error flag */ +#define LTQ_SPI_STAT_RE BIT(9) /* Receive error flag */ +#define LTQ_SPI_STAT_TE BIT(8) /* Transmit error flag */ +#define LTQ_SPI_STAT_ME BIT(7) /* Mode error flag */ +#define LTQ_SPI_STAT_MS BIT(1) /* Master/slave select bit */ +#define LTQ_SPI_STAT_EN BIT(0) /* Enable bit */ +#define LTQ_SPI_STAT_ERRORS (LTQ_SPI_STAT_ME | LTQ_SPI_STAT_TE | \ + LTQ_SPI_STAT_RE | LTQ_SPI_STAT_AE | \ + LTQ_SPI_STAT_TUE | LTQ_SPI_STAT_RUE) + +#define LTQ_SPI_WHBSTATE_SETTUE BIT(15) /* Set transmit underflow error flag */ +#define LTQ_SPI_WHBSTATE_SETAE BIT(14) /* Set abort error flag */ +#define LTQ_SPI_WHBSTATE_SETRE BIT(13) /* Set receive error flag */ +#define LTQ_SPI_WHBSTATE_SETTE BIT(12) /* Set transmit error flag */ +#define LTQ_SPI_WHBSTATE_CLRTUE BIT(11) /* Clear transmit underflow error flag */ +#define LTQ_SPI_WHBSTATE_CLRAE BIT(10) /* Clear abort error flag */ +#define LTQ_SPI_WHBSTATE_CLRRE BIT(9) /* Clear receive error flag */ +#define LTQ_SPI_WHBSTATE_CLRTE BIT(8) /* Clear transmit error flag */ +#define LTQ_SPI_WHBSTATE_SETME BIT(7) /* Set mode error flag */ +#define LTQ_SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */ +#define LTQ_SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */ +#define LTQ_SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */ +#define LTQ_SPI_WHBSTATE_SETMS BIT(3) /* Set master select bit */ +#define LTQ_SPI_WHBSTATE_CLRMS BIT(2) /* Clear master select bit */ +#define LTQ_SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */ +#define LTQ_SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */ +#define LTQ_SPI_WHBSTATE_CLR_ERRORS (LTQ_SPI_WHBSTATE_CLRRUE | \ + LTQ_SPI_WHBSTATE_CLRME | \ + LTQ_SPI_WHBSTATE_CLRTE | \ + LTQ_SPI_WHBSTATE_CLRRE | \ + LTQ_SPI_WHBSTATE_CLRAE | \ + LTQ_SPI_WHBSTATE_CLRTUE) + +#define LTQ_SPI_RXFCON_RXFITL_S 8 /* FIFO interrupt trigger level */ +#define LTQ_SPI_RXFCON_RXFITL_M (0x3F << LTQ_SPI_RXFCON_RXFITL_S) +#define LTQ_SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */ +#define LTQ_SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */ + +#define LTQ_SPI_TXFCON_TXFITL_S 8 /* FIFO interrupt trigger level */ +#define LTQ_SPI_TXFCON_TXFITL_M (0x3F << LTQ_SPI_TXFCON_TXFITL_S) +#define LTQ_SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */ +#define LTQ_SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */ + +#define LTQ_SPI_FSTAT_RXFFL_S 0 +#define LTQ_SPI_FSTAT_RXFFL_M (0x3f << LTQ_SPI_FSTAT_RXFFL_S) +#define LTQ_SPI_FSTAT_TXFFL_S 8 +#define LTQ_SPI_FSTAT_TXFFL_M (0x3f << LTQ_SPI_FSTAT_TXFFL_S) + +#define LTQ_SPI_GPOCON_ISCSBN_S 8 +#define LTQ_SPI_GPOCON_INVOUTN_S 0 + +#define LTQ_SPI_FGPO_SETOUTN_S 8 +#define LTQ_SPI_FGPO_CLROUTN_S 0 + +#define LTQ_SPI_RXREQ_RXCNT_M 0xFFFF /* Receive count value */ +#define LTQ_SPI_RXCNT_TODO_M 0xFFFF /* Recevie to-do value */ + +#define LTQ_SPI_IRNEN_TFI BIT(4) /* TX finished interrupt */ +#define LTQ_SPI_IRNEN_F BIT(3) /* Frame end interrupt request */ +#define LTQ_SPI_IRNEN_E BIT(2) /* Error end interrupt request */ +#define LTQ_SPI_IRNEN_T_XWAY BIT(1) /* Transmit end interrupt request */ +#define LTQ_SPI_IRNEN_R_XWAY BIT(0) /* Receive end interrupt request */ +#define LTQ_SPI_IRNEN_R_XRX BIT(1) /* Transmit end interrupt request */ +#define LTQ_SPI_IRNEN_T_XRX BIT(0) /* Receive end interrupt request */ +#define LTQ_SPI_IRNEN_ALL 0x1F struct lantiq_ssc_hwcfg { unsigned int irnen_r; @@ -208,16 +212,16 @@ static void lantiq_ssc_maskl(const struct lantiq_ssc_spi *spi, u32 clr, static unsigned int tx_fifo_level(const struct lantiq_ssc_spi *spi) { - u32 fstat = lantiq_ssc_readl(spi, SPI_FSTAT); + u32 fstat = lantiq_ssc_readl(spi, LTQ_SPI_FSTAT); - return (fstat & SPI_FSTAT_TXFFL_M) >> SPI_FSTAT_TXFFL_S; + return (fstat & LTQ_SPI_FSTAT_TXFFL_M) >> LTQ_SPI_FSTAT_TXFFL_S; } static unsigned int rx_fifo_level(const struct lantiq_ssc_spi *spi) { - u32 fstat = lantiq_ssc_readl(spi, SPI_FSTAT); + u32 fstat = lantiq_ssc_readl(spi, LTQ_SPI_FSTAT); - return fstat & SPI_FSTAT_RXFFL_M; + return fstat & LTQ_SPI_FSTAT_RXFFL_M; } static unsigned int tx_fifo_free(const struct lantiq_ssc_spi *spi) @@ -227,38 +231,38 @@ static unsigned int tx_fifo_free(const struct lantiq_ssc_spi *spi) static void rx_fifo_reset(const struct lantiq_ssc_spi *spi) { - u32 val = spi->rx_fifo_size << SPI_RXFCON_RXFITL_S; + u32 val = spi->rx_fifo_size << LTQ_SPI_RXFCON_RXFITL_S; - val |= SPI_RXFCON_RXFEN | SPI_RXFCON_RXFLU; - lantiq_ssc_writel(spi, val, SPI_RXFCON); + val |= LTQ_SPI_RXFCON_RXFEN | LTQ_SPI_RXFCON_RXFLU; + lantiq_ssc_writel(spi, val, LTQ_SPI_RXFCON); } static void tx_fifo_reset(const struct lantiq_ssc_spi *spi) { - u32 val = 1 << SPI_TXFCON_TXFITL_S; + u32 val = 1 << LTQ_SPI_TXFCON_TXFITL_S; - val |= SPI_TXFCON_TXFEN | SPI_TXFCON_TXFLU; - lantiq_ssc_writel(spi, val, SPI_TXFCON); + val |= LTQ_SPI_TXFCON_TXFEN | LTQ_SPI_TXFCON_TXFLU; + lantiq_ssc_writel(spi, val, LTQ_SPI_TXFCON); } static void rx_fifo_flush(const struct lantiq_ssc_spi *spi) { - lantiq_ssc_maskl(spi, 0, SPI_RXFCON_RXFLU, SPI_RXFCON); + lantiq_ssc_maskl(spi, 0, LTQ_SPI_RXFCON_RXFLU, LTQ_SPI_RXFCON); } static void tx_fifo_flush(const struct lantiq_ssc_spi *spi) { - lantiq_ssc_maskl(spi, 0, SPI_TXFCON_TXFLU, SPI_TXFCON); + lantiq_ssc_maskl(spi, 0, LTQ_SPI_TXFCON_TXFLU, LTQ_SPI_TXFCON); } static void hw_enter_config_mode(const struct lantiq_ssc_spi *spi) { - lantiq_ssc_writel(spi, SPI_WHBSTATE_CLREN, SPI_WHBSTATE); + lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_CLREN, LTQ_SPI_WHBSTATE); } static void hw_enter_active_mode(const struct lantiq_ssc_spi *spi) { - lantiq_ssc_writel(spi, SPI_WHBSTATE_SETEN, SPI_WHBSTATE); + lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_SETEN, LTQ_SPI_WHBSTATE); } static void hw_setup_speed_hz(const struct lantiq_ssc_spi *spi, @@ -287,7 +291,7 @@ static void hw_setup_speed_hz(const struct lantiq_ssc_spi *spi, 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); + lantiq_ssc_writel(spi, brt, LTQ_SPI_BRT); } static void hw_setup_bits_per_word(const struct lantiq_ssc_spi *spi, @@ -296,9 +300,9 @@ static void hw_setup_bits_per_word(const struct lantiq_ssc_spi *spi, u32 bm; /* CON.BM value = bits_per_word - 1 */ - bm = (bits_per_word - 1) << SPI_CON_BM_S; + bm = (bits_per_word - 1) << LTQ_SPI_CON_BM_S; - lantiq_ssc_maskl(spi, SPI_CON_BM_M, bm, SPI_CON); + lantiq_ssc_maskl(spi, LTQ_SPI_CON_BM_M, bm, LTQ_SPI_CON); } static void hw_setup_clock_mode(const struct lantiq_ssc_spi *spi, @@ -315,28 +319,28 @@ static void hw_setup_clock_mode(const struct lantiq_ssc_spi *spi, * 3 1 1 1 0 */ if (mode & SPI_CPHA) - con_clr |= SPI_CON_PH; + con_clr |= LTQ_SPI_CON_PH; else - con_set |= SPI_CON_PH; + con_set |= LTQ_SPI_CON_PH; if (mode & SPI_CPOL) - con_set |= SPI_CON_PO | SPI_CON_IDLE; + con_set |= LTQ_SPI_CON_PO | LTQ_SPI_CON_IDLE; else - con_clr |= SPI_CON_PO | SPI_CON_IDLE; + con_clr |= LTQ_SPI_CON_PO | LTQ_SPI_CON_IDLE; /* Set heading control */ if (mode & SPI_LSB_FIRST) - con_clr |= SPI_CON_HB; + con_clr |= LTQ_SPI_CON_HB; else - con_set |= SPI_CON_HB; + con_set |= LTQ_SPI_CON_HB; /* Set loopback mode */ if (mode & SPI_LOOP) - con_set |= SPI_CON_LB; + con_set |= LTQ_SPI_CON_LB; else - con_clr |= SPI_CON_LB; + con_clr |= LTQ_SPI_CON_LB; - lantiq_ssc_maskl(spi, con_clr, con_set, SPI_CON); + lantiq_ssc_maskl(spi, con_clr, con_set, LTQ_SPI_CON); } static void lantiq_ssc_hw_init(const struct lantiq_ssc_spi *spi) @@ -347,37 +351,39 @@ static void lantiq_ssc_hw_init(const struct lantiq_ssc_spi *spi) * 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); + lantiq_ssc_writel(spi, 1 << LTQ_SPI_CLC_RMC_S, LTQ_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); + lantiq_ssc_maskl(spi, 0, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_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); + lantiq_ssc_writel(spi, LTQ_SPI_CON_RUEN | LTQ_SPI_CON_AEN | + LTQ_SPI_CON_TEN | LTQ_SPI_CON_REN | LTQ_SPI_CON_TXOFF | + LTQ_SPI_CON_RXOFF, LTQ_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); + lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_SETMS | + LTQ_SPI_WHBSTATE_CLR_ERRORS, + LTQ_SPI_WHBSTATE); /* Reset GPIO/CS registers */ - lantiq_ssc_writel(spi, 0, SPI_GPOCON); - lantiq_ssc_writel(spi, 0xFF00, SPI_FPGO); + lantiq_ssc_writel(spi, 0, LTQ_SPI_GPOCON); + lantiq_ssc_writel(spi, 0xFF00, LTQ_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); + lantiq_ssc_writel(spi, hwcfg->irnen_t | hwcfg->irnen_r | + LTQ_SPI_IRNEN_E, LTQ_SPI_IRNEN); } static int lantiq_ssc_setup(struct spi_device *spidev) @@ -400,13 +406,13 @@ static int lantiq_ssc_setup(struct spi_device *spidev) } /* set GPO pin to CS mode */ - gpocon = 1 << ((cs - spi->base_cs) + SPI_GPOCON_ISCSBN_S); + gpocon = 1 << ((cs - spi->base_cs) + LTQ_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); + lantiq_ssc_maskl(spi, 0, gpocon, LTQ_SPI_GPOCON); return 0; } @@ -442,18 +448,18 @@ static void hw_setup_transfer(struct lantiq_ssc_spi *spi, } /* Configure transmitter and receiver */ - con = lantiq_ssc_readl(spi, SPI_CON); + con = lantiq_ssc_readl(spi, LTQ_SPI_CON); if (t->tx_buf) - con &= ~SPI_CON_TXOFF; + con &= ~LTQ_SPI_CON_TXOFF; else - con |= SPI_CON_TXOFF; + con |= LTQ_SPI_CON_TXOFF; if (t->rx_buf) - con &= ~SPI_CON_RXOFF; + con &= ~LTQ_SPI_CON_RXOFF; else - con |= SPI_CON_RXOFF; + con |= LTQ_SPI_CON_RXOFF; - lantiq_ssc_writel(spi, con, SPI_CON); + lantiq_ssc_writel(spi, con, LTQ_SPI_CON); } static int lantiq_ssc_unprepare_message(struct spi_master *master, @@ -464,7 +470,8 @@ static int lantiq_ssc_unprepare_message(struct spi_master *master, flush_workqueue(spi->wq); /* Disable transmitter and receiver while idle */ - lantiq_ssc_maskl(spi, 0, SPI_CON_TXOFF | SPI_CON_RXOFF, SPI_CON); + lantiq_ssc_maskl(spi, 0, LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF, + LTQ_SPI_CON); return 0; } @@ -503,7 +510,7 @@ static void tx_fifo_write(struct lantiq_ssc_spi *spi) break; } - lantiq_ssc_writel(spi, data, SPI_TB); + lantiq_ssc_writel(spi, data, LTQ_SPI_TB); tx_free--; } } @@ -517,7 +524,7 @@ static void rx_fifo_read_full_duplex(struct lantiq_ssc_spi *spi) unsigned int rx_fill = rx_fifo_level(spi); while (rx_fill) { - data = lantiq_ssc_readl(spi, SPI_RB); + data = lantiq_ssc_readl(spi, LTQ_SPI_RB); switch (spi->bits_per_word) { case 2 ... 8: @@ -563,9 +570,9 @@ static void rx_fifo_read_half_duplex(struct lantiq_ssc_spi *spi) */ 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); + rxbv = (lantiq_ssc_readl(spi, LTQ_SPI_STAT) & + LTQ_SPI_STAT_RXBV_M) >> LTQ_SPI_STAT_RXBV_S; + data = lantiq_ssc_readl(spi, LTQ_SPI_RB); shift = (rxbv - 1) * 8; rx8 = spi->rx; @@ -578,7 +585,7 @@ static void rx_fifo_read_half_duplex(struct lantiq_ssc_spi *spi) spi->rx++; } } else { - data = lantiq_ssc_readl(spi, SPI_RB); + data = lantiq_ssc_readl(spi, LTQ_SPI_RB); rx32 = (u32 *) spi->rx; *rx32++ = data; @@ -603,7 +610,7 @@ static void rx_request(struct lantiq_ssc_spi *spi) if (rxreq > rxreq_max) rxreq = rxreq_max; - lantiq_ssc_writel(spi, rxreq, SPI_RXREQ); + lantiq_ssc_writel(spi, rxreq, LTQ_SPI_RXREQ); } static irqreturn_t lantiq_ssc_xmit_interrupt(int irq, void *data) @@ -642,26 +649,26 @@ completed: 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); + u32 stat = lantiq_ssc_readl(spi, LTQ_SPI_STAT); - if (!(stat & SPI_STAT_ERRORS)) + if (!(stat & LTQ_SPI_STAT_ERRORS)) return IRQ_NONE; - if (stat & SPI_STAT_RUE) + if (stat & LTQ_SPI_STAT_RUE) dev_err(spi->dev, "receive underflow error\n"); - if (stat & SPI_STAT_TUE) + if (stat & LTQ_SPI_STAT_TUE) dev_err(spi->dev, "transmit underflow error\n"); - if (stat & SPI_STAT_AE) + if (stat & LTQ_SPI_STAT_AE) dev_err(spi->dev, "abort error\n"); - if (stat & SPI_STAT_RE) + if (stat & LTQ_SPI_STAT_RE) dev_err(spi->dev, "receive overflow error\n"); - if (stat & SPI_STAT_TE) + if (stat & LTQ_SPI_STAT_TE) dev_err(spi->dev, "transmit overflow error\n"); - if (stat & SPI_STAT_ME) + if (stat & LTQ_SPI_STAT_ME) dev_err(spi->dev, "mode error\n"); /* Clear error flags */ - lantiq_ssc_maskl(spi, 0, SPI_WHBSTATE_CLR_ERRORS, SPI_WHBSTATE); + lantiq_ssc_maskl(spi, 0, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE); /* set bad status so it can be retried */ if (spi->master->cur_msg) @@ -721,9 +728,9 @@ static void lantiq_ssc_bussy_work(struct work_struct *work) end = jiffies + msecs_to_jiffies(timeout); do { - u32 stat = lantiq_ssc_readl(spi, SPI_STAT); + u32 stat = lantiq_ssc_readl(spi, LTQ_SPI_STAT); - if (!(stat & SPI_STAT_BSY)) { + if (!(stat & LTQ_SPI_STAT_BSY)) { spi_finalize_current_transfer(spi->master); return; } @@ -755,9 +762,9 @@ static void lantiq_ssc_set_cs(struct spi_device *spidev, bool enable) if (!!(spidev->mode & SPI_CS_HIGH) == enable) fgpo = (1 << (cs - spi->base_cs)); else - fgpo = (1 << (cs - spi->base_cs + SPI_FGPO_SETOUTN_S)); + fgpo = (1 << (cs - spi->base_cs + LTQ_SPI_FGPO_SETOUTN_S)); - lantiq_ssc_writel(spi, fgpo, SPI_FPGO); + lantiq_ssc_writel(spi, fgpo, LTQ_SPI_FPGO); } static int lantiq_ssc_transfer_one(struct spi_master *master, @@ -772,13 +779,13 @@ static int lantiq_ssc_transfer_one(struct spi_master *master, } static const struct lantiq_ssc_hwcfg lantiq_ssc_xway = { - .irnen_r = SPI_IRNEN_R_XWAY, - .irnen_t = SPI_IRNEN_T_XWAY, + .irnen_r = LTQ_SPI_IRNEN_R_XWAY, + .irnen_t = LTQ_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, + .irnen_r = LTQ_SPI_IRNEN_R_XRX, + .irnen_t = LTQ_SPI_IRNEN_T_XRX, }; static const struct of_device_id lantiq_ssc_match[] = { @@ -814,21 +821,21 @@ static int lantiq_ssc_probe(struct platform_device *pdev) return -ENXIO; } - rx_irq = platform_get_irq_byname(pdev, SPI_RX_IRQ_NAME); + rx_irq = platform_get_irq_byname(pdev, LTQ_SPI_RX_IRQ_NAME); if (rx_irq < 0) { - dev_err(dev, "failed to get %s\n", SPI_RX_IRQ_NAME); + dev_err(dev, "failed to get %s\n", LTQ_SPI_RX_IRQ_NAME); return -ENXIO; } - tx_irq = platform_get_irq_byname(pdev, SPI_TX_IRQ_NAME); + tx_irq = platform_get_irq_byname(pdev, LTQ_SPI_TX_IRQ_NAME); if (tx_irq < 0) { - dev_err(dev, "failed to get %s\n", SPI_TX_IRQ_NAME); + dev_err(dev, "failed to get %s\n", LTQ_SPI_TX_IRQ_NAME); return -ENXIO; } - err_irq = platform_get_irq_byname(pdev, SPI_ERR_IRQ_NAME); + err_irq = platform_get_irq_byname(pdev, LTQ_SPI_ERR_IRQ_NAME); if (err_irq < 0) { - dev_err(dev, "failed to get %s\n", SPI_ERR_IRQ_NAME); + dev_err(dev, "failed to get %s\n", LTQ_SPI_ERR_IRQ_NAME); return -ENXIO; } @@ -849,17 +856,17 @@ static int lantiq_ssc_probe(struct platform_device *pdev) } err = devm_request_irq(dev, rx_irq, lantiq_ssc_xmit_interrupt, - 0, SPI_RX_IRQ_NAME, spi); + 0, LTQ_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); + 0, LTQ_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); + 0, LTQ_SPI_ERR_IRQ_NAME, spi); if (err) goto err_master_put; @@ -916,11 +923,11 @@ static int lantiq_ssc_probe(struct platform_device *pdev) } 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; + id = lantiq_ssc_readl(spi, LTQ_SPI_ID); + spi->tx_fifo_size = (id & LTQ_SPI_ID_TXFS_M) >> LTQ_SPI_ID_TXFS_S; + spi->rx_fifo_size = (id & LTQ_SPI_ID_RXFS_M) >> LTQ_SPI_ID_RXFS_S; + supports_dma = (id & LTQ_SPI_ID_CFG_M) >> LTQ_SPI_ID_CFG_S; + revision = id & LTQ_SPI_ID_REV_M; lantiq_ssc_hw_init(spi); @@ -952,8 +959,8 @@ 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); + lantiq_ssc_writel(spi, 0, LTQ_SPI_IRNEN); + lantiq_ssc_writel(spi, 0, LTQ_SPI_CLC); rx_fifo_flush(spi); tx_fifo_flush(spi); hw_enter_config_mode(spi); @@ -970,7 +977,6 @@ static struct platform_driver lantiq_ssc_driver = { .remove = lantiq_ssc_remove, .driver = { .name = "spi-lantiq-ssc", - .owner = THIS_MODULE, .of_match_table = lantiq_ssc_match, }, }; diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index 50e620f4e8fe..f4875f177df0 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -20,11 +20,13 @@ #include <linux/delay.h> #include <linux/kernel.h> +#include <linux/ktime.h> #include <linux/list.h> #include <linux/list_sort.h> #include <linux/module.h> #include <linux/of_device.h> #include <linux/printk.h> +#include <linux/vmalloc.h> #include <linux/spi/spi.h> #include "spi-test.h" @@ -55,6 +57,18 @@ module_param(run_only_test, int, 0); MODULE_PARM_DESC(run_only_test, "only run the test with this number (0-based !)"); +/* use vmalloc'ed buffers */ +int use_vmalloc; +module_param(use_vmalloc, int, 0644); +MODULE_PARM_DESC(use_vmalloc, + "use vmalloc'ed buffers instead of kmalloc'ed"); + +/* check rx ranges */ +int check_ranges = 1; +module_param(check_ranges, int, 0644); +MODULE_PARM_DESC(check_ranges, + "checks rx_buffer pattern are valid"); + /* the actual tests to execute */ static struct spi_test spi_tests[] = { { @@ -63,9 +77,9 @@ static struct spi_test spi_tests[] = { .iterate_len = { ITERATE_MAX_LEN }, .iterate_tx_align = ITERATE_ALIGN, .iterate_rx_align = ITERATE_ALIGN, + .transfer_count = 1, .transfers = { { - .len = 1, .tx_buf = TX(0), .rx_buf = RX(0), }, @@ -77,9 +91,9 @@ static struct spi_test spi_tests[] = { .iterate_len = { ITERATE_MAX_LEN }, .iterate_tx_align = ITERATE_ALIGN, .iterate_rx_align = ITERATE_ALIGN, + .transfer_count = 1, .transfers = { { - .len = 1, .tx_buf = TX(PAGE_SIZE - 4), .rx_buf = RX(PAGE_SIZE - 4), }, @@ -90,9 +104,9 @@ static struct spi_test spi_tests[] = { .fill_option = FILL_COUNT_8, .iterate_len = { ITERATE_MAX_LEN }, .iterate_tx_align = ITERATE_ALIGN, + .transfer_count = 1, .transfers = { { - .len = 1, .tx_buf = TX(0), }, }, @@ -102,9 +116,9 @@ static struct spi_test spi_tests[] = { .fill_option = FILL_COUNT_8, .iterate_len = { ITERATE_MAX_LEN }, .iterate_rx_align = ITERATE_ALIGN, + .transfer_count = 1, .transfers = { { - .len = 1, .rx_buf = RX(0), }, }, @@ -115,13 +129,12 @@ static struct spi_test spi_tests[] = { .iterate_len = { ITERATE_LEN }, .iterate_tx_align = ITERATE_ALIGN, .iterate_transfer_mask = BIT(0) | BIT(1), + .transfer_count = 2, .transfers = { { - .len = 1, .tx_buf = TX(0), }, { - .len = 1, /* this is why we cant use ITERATE_MAX_LEN */ .tx_buf = TX(SPI_TEST_MAX_SIZE_HALF), }, @@ -132,10 +145,10 @@ static struct spi_test spi_tests[] = { .fill_option = FILL_COUNT_8, .iterate_len = { ITERATE_MAX_LEN }, .iterate_tx_align = ITERATE_ALIGN, - .iterate_transfer_mask = BIT(1), + .iterate_transfer_mask = BIT(0), + .transfer_count = 2, .transfers = { { - .len = 1, .tx_buf = TX(64), }, { @@ -149,14 +162,14 @@ static struct spi_test spi_tests[] = { .fill_option = FILL_COUNT_8, .iterate_len = { ITERATE_MAX_LEN }, .iterate_tx_align = ITERATE_ALIGN, - .iterate_transfer_mask = BIT(0), + .iterate_transfer_mask = BIT(1), + .transfer_count = 2, .transfers = { { .len = 16, .tx_buf = TX(0), }, { - .len = 1, .tx_buf = TX(64), }, }, @@ -167,13 +180,12 @@ static struct spi_test spi_tests[] = { .iterate_len = { ITERATE_MAX_LEN }, .iterate_tx_align = ITERATE_ALIGN, .iterate_transfer_mask = BIT(0) | BIT(1), + .transfer_count = 2, .transfers = { { - .len = 1, .tx_buf = TX(0), }, { - .len = 1, .rx_buf = RX(0), }, }, @@ -184,9 +196,9 @@ static struct spi_test spi_tests[] = { .iterate_len = { ITERATE_MAX_LEN }, .iterate_tx_align = ITERATE_ALIGN, .iterate_transfer_mask = BIT(0), + .transfer_count = 2, .transfers = { { - .len = 1, .tx_buf = TX(0), }, { @@ -201,13 +213,13 @@ static struct spi_test spi_tests[] = { .iterate_len = { ITERATE_MAX_LEN }, .iterate_tx_align = ITERATE_ALIGN, .iterate_transfer_mask = BIT(1), + .transfer_count = 2, .transfers = { { .len = 1, .tx_buf = TX(0), }, { - .len = 1, .rx_buf = RX(0), }, }, @@ -218,14 +230,13 @@ static struct spi_test spi_tests[] = { .iterate_len = { ITERATE_LEN }, .iterate_tx_align = ITERATE_ALIGN, .iterate_transfer_mask = BIT(0) | BIT(1), + .transfer_count = 2, .transfers = { { - .len = 1, .tx_buf = TX(0), .rx_buf = RX(0), }, { - .len = 1, /* making sure we align without overwrite * the reason we can not use ITERATE_MAX_LEN */ @@ -240,9 +251,9 @@ static struct spi_test spi_tests[] = { .iterate_len = { ITERATE_MAX_LEN }, .iterate_tx_align = ITERATE_ALIGN, .iterate_transfer_mask = BIT(0), + .transfer_count = 2, .transfers = { { - .len = 1, /* making sure we align without overwrite */ .tx_buf = TX(1024), .rx_buf = RX(1024), @@ -261,6 +272,7 @@ static struct spi_test spi_tests[] = { .iterate_len = { ITERATE_MAX_LEN }, .iterate_tx_align = ITERATE_ALIGN, .iterate_transfer_mask = BIT(1), + .transfer_count = 2, .transfers = { { .len = 1, @@ -268,13 +280,31 @@ static struct spi_test spi_tests[] = { .rx_buf = RX(0), }, { - .len = 1, /* making sure we align without overwrite */ .tx_buf = TX(1024), .rx_buf = RX(1024), }, }, }, + { + .description = "two tx+rx transfers - delay after transfer", + .fill_option = FILL_COUNT_8, + .iterate_len = { ITERATE_MAX_LEN }, + .iterate_transfer_mask = BIT(0) | BIT(1), + .transfer_count = 2, + .transfers = { + { + .tx_buf = TX(0), + .rx_buf = RX(0), + .delay_usecs = 1000, + }, + { + .tx_buf = TX(0), + .rx_buf = RX(0), + .delay_usecs = 1000, + }, + }, + }, { /* end of tests sequence */ } }; @@ -482,6 +512,36 @@ static int spi_check_rx_ranges(struct spi_device *spi, return ret; } +static int spi_test_check_elapsed_time(struct spi_device *spi, + struct spi_test *test) +{ + int i; + unsigned long long estimated_time = 0; + unsigned long long delay_usecs = 0; + + for (i = 0; i < test->transfer_count; i++) { + struct spi_transfer *xfer = test->transfers + i; + unsigned long long nbits = (unsigned long long)BITS_PER_BYTE * + xfer->len; + + delay_usecs += xfer->delay_usecs; + if (!xfer->speed_hz) + continue; + estimated_time += div_u64(nbits * NSEC_PER_SEC, xfer->speed_hz); + } + + estimated_time += delay_usecs * NSEC_PER_USEC; + if (test->elapsed_time < estimated_time) { + dev_err(&spi->dev, + "elapsed time %lld ns is shorter than minimum estimated time %lld ns\n", + test->elapsed_time, estimated_time); + + return -EINVAL; + } + + return 0; +} + static int spi_test_check_loopback_result(struct spi_device *spi, struct spi_message *msg, void *tx, void *rx) @@ -492,9 +552,11 @@ static int spi_test_check_loopback_result(struct spi_device *spi, int ret; /* checks rx_buffer pattern are valid with loopback or without */ - ret = spi_check_rx_ranges(spi, msg, rx); - if (ret) - return ret; + if (check_ranges) { + ret = spi_check_rx_ranges(spi, msg, rx); + if (ret) + return ret; + } /* if we run without loopback, then return now */ if (!loopback) @@ -503,11 +565,11 @@ static int spi_test_check_loopback_result(struct spi_device *spi, /* if applicable to transfer check that rx_buf is equal to tx_buf */ list_for_each_entry(xfer, &msg->transfers, transfer_list) { /* if there is no rx, then no check is needed */ - if (!xfer->rx_buf) + if (!xfer->len || !xfer->rx_buf) continue; /* so depending on tx_buf we need to handle things */ if (xfer->tx_buf) { - for (i = 1; i < xfer->len; i++) { + for (i = 0; i < xfer->len; i++) { txb = ((u8 *)xfer->tx_buf)[i]; rxb = ((u8 *)xfer->rx_buf)[i]; if (txb != rxb) @@ -745,15 +807,6 @@ static int spi_test_run_iter(struct spi_device *spi, /* copy the test template to test */ memcpy(&test, testtemplate, sizeof(test)); - /* set up test->transfers to the correct count */ - if (!test.transfer_count) { - for (i = 0; - (i < SPI_TEST_MAX_TRANSFERS) && test.transfers[i].len; - i++) { - test.transfer_count++; - } - } - /* if iterate_transfer_mask is not set, * then set it to first transfer only */ @@ -799,8 +852,7 @@ static int spi_test_run_iter(struct spi_device *spi, /* only when bit in transfer mask is set */ if (!(test.iterate_transfer_mask & BIT(i))) continue; - if (len) - test.transfers[i].len = len; + test.transfers[i].len = len; if (test.transfers[i].tx_buf) test.transfers[i].tx_buf += tx_off; if (test.transfers[i].tx_buf) @@ -830,12 +882,16 @@ int spi_test_execute_msg(struct spi_device *spi, struct spi_test *test, /* only if we do not simulate */ if (!simulate_only) { + ktime_t start; + /* dump the complete message before and after the transfer */ if (dump_messages == 3) spi_test_dump_message(spi, msg, true); + start = ktime_get(); /* run spi message */ ret = spi_sync(spi, msg); + test->elapsed_time = ktime_to_ns(ktime_sub(ktime_get(), start)); if (ret == -ETIMEDOUT) { dev_info(&spi->dev, "spi-message timed out - reruning...\n"); @@ -861,6 +917,10 @@ int spi_test_execute_msg(struct spi_device *spi, struct spi_test *test, /* run rx-buffer tests */ ret = spi_test_check_loopback_result(spi, msg, tx, rx); + if (ret) + goto exit; + + ret = spi_test_check_elapsed_time(spi, test); } /* if requested or on error dump message (including data) */ @@ -910,15 +970,6 @@ int spi_test_run_test(struct spi_device *spi, const struct spi_test *test, /* iterate over all the iterable values using macros * (to make it a bit more readable... */ -#define FOR_EACH_ITERATE(var, defaultvalue) \ - for (idx_##var = -1, var = defaultvalue; \ - ((idx_##var < 0) || \ - ( \ - (idx_##var < SPI_TEST_MAX_ITERATE) && \ - (var = test->iterate_##var[idx_##var]) \ - ) \ - ); \ - idx_##var++) #define FOR_EACH_ALIGNMENT(var) \ for (var = 0; \ var < (test->iterate_##var ? \ @@ -928,7 +979,8 @@ int spi_test_run_test(struct spi_device *spi, const struct spi_test *test, 1); \ var++) - FOR_EACH_ITERATE(len, 0) { + for (idx_len = 0; idx_len < SPI_TEST_MAX_ITERATE && + (len = test->iterate_len[idx_len]) != -1; idx_len++) { FOR_EACH_ALIGNMENT(tx_align) { FOR_EACH_ALIGNMENT(rx_align) { /* and run the iteration */ @@ -965,13 +1017,19 @@ int spi_test_run_tests(struct spi_device *spi, /* allocate rx/tx buffers of 128kB size without devm * in the hope that is on a page boundary */ - rx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL); + if (use_vmalloc) + rx = vmalloc(SPI_TEST_MAX_SIZE_PLUS); + else + rx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL); if (!rx) { ret = -ENOMEM; goto out; } - tx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL); + if (use_vmalloc) + tx = vmalloc(SPI_TEST_MAX_SIZE_PLUS); + else + tx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL); if (!tx) { ret = -ENOMEM; goto out; @@ -999,8 +1057,8 @@ int spi_test_run_tests(struct spi_device *spi, } out: - kfree(rx); - kfree(tx); + kvfree(rx); + kvfree(tx); return ret; } EXPORT_SYMBOL_GPL(spi_test_run_tests); diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 79800e991ccd..7275223dbcd4 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -454,6 +454,8 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, int elements = 0; int word_len, element_count; struct omap2_mcspi_cs *cs = spi->controller_state; + void __iomem *chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; + mcspi = spi_master_get_devdata(spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select]; count = xfer->len; @@ -549,8 +551,8 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, if (l & OMAP2_MCSPI_CHCONF_TURBO) { elements--; - if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) - & OMAP2_MCSPI_CHSTAT_RXS)) { + if (!mcspi_wait_for_reg_bit(chstat_reg, + OMAP2_MCSPI_CHSTAT_RXS)) { u32 w; w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); @@ -568,8 +570,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, return count; } } - if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) - & OMAP2_MCSPI_CHSTAT_RXS)) { + if (!mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_RXS)) { u32 w; w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 6b001c4a5640..be2e87ee8b31 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -39,6 +39,8 @@ #define ORION_SPI_IF_CTRL_REG 0x00 #define ORION_SPI_IF_CONFIG_REG 0x04 +#define ORION_SPI_IF_RXLSBF BIT(14) +#define ORION_SPI_IF_TXLSBF BIT(13) #define ORION_SPI_DATA_OUT_REG 0x08 #define ORION_SPI_DATA_IN_REG 0x0c #define ORION_SPI_INT_CAUSE_REG 0x10 @@ -234,6 +236,11 @@ orion_spi_mode_set(struct spi_device *spi) reg |= ORION_SPI_MODE_CPOL; if (spi->mode & SPI_CPHA) reg |= ORION_SPI_MODE_CPHA; + if (spi->mode & SPI_LSB_FIRST) + reg |= ORION_SPI_IF_RXLSBF | ORION_SPI_IF_TXLSBF; + else + reg &= ~(ORION_SPI_IF_RXLSBF | ORION_SPI_IF_TXLSBF); + writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG)); } @@ -591,8 +598,8 @@ static int orion_spi_probe(struct platform_device *pdev) master->bus_num = cell_index; } - /* we support only mode 0, and no options */ - master->mode_bits = SPI_CPHA | SPI_CPOL; + /* we support all 4 SPI modes and LSB first option */ + master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST; master->set_cs = orion_spi_set_cs; master->transfer_one = orion_spi_transfer_one; master->num_chipselect = ORION_NUM_CHIPSELECTS; diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index f7f7ba17b40e..2f76e022cc59 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2074,7 +2074,7 @@ pl022_platform_data_dt_get(struct device *dev) { struct device_node *np = dev->of_node; struct pl022_ssp_controller *pd; - u32 tmp; + u32 tmp = 0; if (!np) { dev_err(dev, "no dt node defined\n"); diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c index f63714ffb62f..52cf0e9189c2 100644 --- a/drivers/spi/spi-sc18is602.c +++ b/drivers/spi/spi-sc18is602.c @@ -21,6 +21,7 @@ #include <linux/i2c.h> #include <linux/delay.h> #include <linux/pm_runtime.h> +#include <linux/of_device.h> #include <linux/of.h> #include <linux/platform_data/sc18is602.h> #include <linux/gpio/consumer.h> @@ -271,7 +272,10 @@ static int sc18is602_probe(struct i2c_client *client, hw->dev = dev; hw->ctrl = 0xff; - hw->id = id->driver_data; + if (client->dev.of_node) + hw->id = (enum chips)of_device_get_match_data(&client->dev); + else + hw->id = id->driver_data; switch (hw->id) { case sc18is602: @@ -323,9 +327,27 @@ static const struct i2c_device_id sc18is602_id[] = { }; MODULE_DEVICE_TABLE(i2c, sc18is602_id); +static const struct of_device_id sc18is602_of_match[] = { + { + .compatible = "nxp,sc18is602", + .data = (void *)sc18is602 + }, + { + .compatible = "nxp,sc18is602b", + .data = (void *)sc18is602b + }, + { + .compatible = "nxp,sc18is603", + .data = (void *)sc18is603 + }, + { }, +}; +MODULE_DEVICE_TABLE(of, sc18is602_of_match); + static struct i2c_driver sc18is602_driver = { .driver = { .name = "sc18is602", + .of_match_table = of_match_ptr(sc18is602_of_match), }, .probe = sc18is602_probe, .id_table = sc18is602_id, diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index e3114832c485..03a773a9531a 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -46,13 +46,19 @@ #define SUN6I_TFR_CTL_XCH BIT(31) #define SUN6I_INT_CTL_REG 0x10 +#define SUN6I_INT_CTL_RF_RDY BIT(0) +#define SUN6I_INT_CTL_TF_ERQ BIT(4) #define SUN6I_INT_CTL_RF_OVF BIT(8) #define SUN6I_INT_CTL_TC BIT(12) #define SUN6I_INT_STA_REG 0x14 #define SUN6I_FIFO_CTL_REG 0x18 +#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_MASK 0xff +#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS 0 #define SUN6I_FIFO_CTL_RF_RST BIT(15) +#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_MASK 0xff +#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS 16 #define SUN6I_FIFO_CTL_TF_RST BIT(31) #define SUN6I_FIFO_STA_REG 0x1c @@ -68,14 +74,16 @@ #define SUN6I_CLK_CTL_CDR1(div) (((div) & SUN6I_CLK_CTL_CDR1_MASK) << 8) #define SUN6I_CLK_CTL_DRS BIT(12) +#define SUN6I_MAX_XFER_SIZE 0xffffff + #define SUN6I_BURST_CNT_REG 0x30 -#define SUN6I_BURST_CNT(cnt) ((cnt) & 0xffffff) +#define SUN6I_BURST_CNT(cnt) ((cnt) & SUN6I_MAX_XFER_SIZE) #define SUN6I_XMIT_CNT_REG 0x34 -#define SUN6I_XMIT_CNT(cnt) ((cnt) & 0xffffff) +#define SUN6I_XMIT_CNT(cnt) ((cnt) & SUN6I_MAX_XFER_SIZE) #define SUN6I_BURST_CTL_CNT_REG 0x38 -#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & 0xffffff) +#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & SUN6I_MAX_XFER_SIZE) #define SUN6I_TXDATA_REG 0x200 #define SUN6I_RXDATA_REG 0x300 @@ -105,6 +113,31 @@ static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value) writel(value, sspi->base_addr + reg); } +static inline u32 sun6i_spi_get_tx_fifo_count(struct sun6i_spi *sspi) +{ + u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG); + + reg >>= SUN6I_FIFO_STA_TF_CNT_BITS; + + return reg & SUN6I_FIFO_STA_TF_CNT_MASK; +} + +static inline void sun6i_spi_enable_interrupt(struct sun6i_spi *sspi, u32 mask) +{ + u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG); + + reg |= mask; + sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg); +} + +static inline void sun6i_spi_disable_interrupt(struct sun6i_spi *sspi, u32 mask) +{ + u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG); + + reg &= ~mask; + sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg); +} + static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len) { u32 reg, cnt; @@ -127,10 +160,13 @@ static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len) static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len) { + u32 cnt; u8 byte; - if (len > sspi->len) - len = sspi->len; + /* See how much data we can fit */ + cnt = sspi->fifo_depth - sun6i_spi_get_tx_fifo_count(sspi); + + len = min3(len, (int)cnt, sspi->len); while (len--) { byte = sspi->tx_buf ? *sspi->tx_buf++ : 0; @@ -158,9 +194,7 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool enable) static size_t sun6i_spi_max_transfer_size(struct spi_device *spi) { - struct sun6i_spi *sspi = spi_master_get_devdata(spi->master); - - return sspi->fifo_depth - 1; + return SUN6I_MAX_XFER_SIZE - 1; } static int sun6i_spi_transfer_one(struct spi_master *master, @@ -170,12 +204,12 @@ static int sun6i_spi_transfer_one(struct spi_master *master, struct sun6i_spi *sspi = spi_master_get_devdata(master); unsigned int mclk_rate, div, timeout; unsigned int start, end, tx_time; + unsigned int trig_level; unsigned int tx_len = 0; int ret = 0; u32 reg; - /* We don't support transfer larger than the FIFO */ - if (tfr->len > sspi->fifo_depth) + if (tfr->len > SUN6I_MAX_XFER_SIZE) return -EINVAL; reinit_completion(&sspi->done); @@ -191,6 +225,17 @@ static int sun6i_spi_transfer_one(struct spi_master *master, SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST); /* + * Setup FIFO interrupt trigger level + * Here we choose 3/4 of the full fifo depth, as it's the hardcoded + * value used in old generation of Allwinner SPI controller. + * (See spi-sun4i.c) + */ + trig_level = sspi->fifo_depth / 4 * 3; + sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG, + (trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) | + (trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS)); + + /* * Setup the transfer control register: Chip Select, * polarities, etc. */ @@ -274,6 +319,10 @@ static int sun6i_spi_transfer_one(struct spi_master *master, /* Enable the interrupts */ sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC); + sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC | + SUN6I_INT_CTL_RF_RDY); + if (tx_len > sspi->fifo_depth) + sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ); /* Start the transfer */ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); @@ -293,8 +342,6 @@ static int sun6i_spi_transfer_one(struct spi_master *master, goto out; } - sun6i_spi_drain_fifo(sspi, sspi->fifo_depth); - out: sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0); @@ -309,10 +356,33 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id) /* Transfer complete */ if (status & SUN6I_INT_CTL_TC) { sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC); + sun6i_spi_drain_fifo(sspi, sspi->fifo_depth); complete(&sspi->done); return IRQ_HANDLED; } + /* Receive FIFO 3/4 full */ + if (status & SUN6I_INT_CTL_RF_RDY) { + sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH); + /* Only clear the interrupt _after_ draining the FIFO */ + sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_RF_RDY); + return IRQ_HANDLED; + } + + /* Transmit FIFO 3/4 empty */ + if (status & SUN6I_INT_CTL_TF_ERQ) { + sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH); + + if (!sspi->len) + /* nothing left to transmit */ + sun6i_spi_disable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ); + + /* Only clear the interrupt _after_ re-seeding the FIFO */ + sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TF_ERQ); + + return IRQ_HANDLED; + } + return IRQ_NONE; } diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 73779cecc3bb..08012ae5aa66 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -837,7 +837,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, SPI_DMA_TIMEOUT); if (WARN_ON(ret == 0)) { dev_err(tspi->dev, - "spi trasfer timeout, err %d\n", ret); + "spi transfer timeout, err %d\n", ret); ret = -EIO; goto complete_xfer; } diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index b6558bb6f9df..2c797ee2664d 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -341,7 +341,7 @@ static int tegra_sflash_transfer_one_message(struct spi_master *master, SPI_DMA_TIMEOUT); if (WARN_ON(ret == 0)) { dev_err(tsd->dev, - "spi trasfer timeout, err %d\n", ret); + "spi transfer timeout, err %d\n", ret); ret = -EIO; goto exit; } diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 85c91f58b42f..0c06ce424210 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -824,7 +824,7 @@ static int tegra_slink_transfer_one(struct spi_master *master, SLINK_DMA_TIMEOUT); if (WARN_ON(ret == 0)) { dev_err(tspi->dev, - "spi trasfer timeout, err %d\n", ret); + "spi transfer timeout, err %d\n", ret); return -EIO; } diff --git a/drivers/spi/spi-test.h b/drivers/spi/spi-test.h index 922c52833239..6ed7b899da8a 100644 --- a/drivers/spi/spi-test.h +++ b/drivers/spi/spi-test.h @@ -48,9 +48,8 @@ * * @msg: a template @spi_message usedfor the default settings * @transfers: array of @spi_transfers that are part of the - * resulting spi_message. The first transfer with len == 0 - * signifies the end of the list - * @transfer_count: normally computed number of transfers with len > 0 + * resulting spi_message. + * @transfer_count: number of transfers * * @run_test: run a specific spi_test - this allows to override * the default implementation of @spi_test_run_transfer @@ -62,8 +61,7 @@ * @expected_return: the expected return code - in some cases we want to * test also for error conditions * - * @iterate_len: list of length to iterate on (in addition to the - * explicitly set @spi_transfer.len) + * @iterate_len: list of length to iterate on * @iterate_tx_align: change the alignment of @spi_transfer.tx_buf * for all values in the below range if set. * the ranges are: @@ -77,6 +75,7 @@ * @fill_option: define the way how tx_buf is filled * @fill_pattern: fill pattern to apply to the tx_buf * (used in some of the @fill_options) + * @elapsed_time: elapsed time in nanoseconds */ struct spi_test { @@ -89,7 +88,7 @@ struct spi_test { int (*execute_msg)(struct spi_device *spi, struct spi_test *test, void *tx, void *rx); int expected_return; - /* iterate over all the non-zero values */ + /* iterate over all values, terminated by a -1 */ int iterate_len[SPI_TEST_MAX_ITERATE]; int iterate_tx_align; int iterate_rx_align; @@ -110,6 +109,7 @@ struct spi_test { #define FILL_TRANSFER_BYTE_32 11 /* fill with the transfer byte - 32 bit */ #define FILL_TRANSFER_NUM 16 /* fill with the transfer number */ u32 fill_pattern; + unsigned long long elapsed_time; }; /* default implementation for @spi_test.run_test */ @@ -126,11 +126,12 @@ int spi_test_execute_msg(struct spi_device *spi, int spi_test_run_tests(struct spi_device *spi, struct spi_test *tests); -/* some of the default @spi_transfer.len to test */ -#define ITERATE_LEN 2, 3, 7, 11, 16, 31, 32, 64, 97, 128, 251, 256, \ +#define ITERATE_LEN_LIST 0, 1, 2, 3, 7, 11, 16, 31, 32, 64, 97, 128, 251, 256, \ 1021, 1024, 1031, 4093, PAGE_SIZE, 4099, 65536, 65537 - -#define ITERATE_MAX_LEN ITERATE_LEN, SPI_TEST_MAX_SIZE - 1, SPI_TEST_MAX_SIZE +/* some of the default @spi_transfer.len to test, terminated by a -1 */ +#define ITERATE_LEN ITERATE_LEN_LIST, -1 +#define ITERATE_MAX_LEN ITERATE_LEN_LIST, (SPI_TEST_MAX_SIZE - 1), \ + SPI_TEST_MAX_SIZE, -1 /* the default alignment to test */ #define ITERATE_ALIGN sizeof(int) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index ad76a44fee6f..c24d9b45a27c 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -33,6 +33,7 @@ #include <linux/pinctrl/consumer.h> #include <linux/mfd/syscon.h> #include <linux/regmap.h> +#include <linux/sizes.h> #include <linux/spi/spi.h> @@ -57,6 +58,8 @@ struct ti_qspi { struct ti_qspi_regs ctx_reg; dma_addr_t mmap_phys_base; + dma_addr_t rx_bb_dma_addr; + void *rx_bb_addr; struct dma_chan *rx_chan; u32 spi_max_frequency; @@ -126,6 +129,8 @@ struct ti_qspi { #define QSPI_SETUP_ADDR_SHIFT 8 #define QSPI_SETUP_DUMMY_SHIFT 10 +#define QSPI_DMA_BUFFER_SIZE SZ_64K + static inline unsigned long ti_qspi_read(struct ti_qspi *qspi, unsigned long reg) { @@ -395,14 +400,12 @@ static int ti_qspi_dma_xfer(struct ti_qspi *qspi, dma_addr_t dma_dst, dma_addr_t dma_src, size_t len) { struct dma_chan *chan = qspi->rx_chan; - struct dma_device *dma_dev = chan->device; dma_cookie_t cookie; enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; struct dma_async_tx_descriptor *tx; int ret; - tx = dma_dev->device_prep_dma_memcpy(chan, dma_dst, dma_src, - len, flags); + tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len, flags); if (!tx) { dev_err(qspi->dev, "device_prep_dma_memcpy error\n"); return -EIO; @@ -431,6 +434,35 @@ static int ti_qspi_dma_xfer(struct ti_qspi *qspi, dma_addr_t dma_dst, return 0; } +static int ti_qspi_dma_bounce_buffer(struct ti_qspi *qspi, + struct spi_flash_read_message *msg) +{ + size_t readsize = msg->len; + void *to = msg->buf; + dma_addr_t dma_src = qspi->mmap_phys_base + msg->from; + int ret = 0; + + /* + * Use bounce buffer as FS like jffs2, ubifs may pass + * buffers that does not belong to kernel lowmem region. + */ + while (readsize != 0) { + size_t xfer_len = min_t(size_t, QSPI_DMA_BUFFER_SIZE, + readsize); + + ret = ti_qspi_dma_xfer(qspi, qspi->rx_bb_dma_addr, + dma_src, xfer_len); + if (ret != 0) + return ret; + memcpy(to, qspi->rx_bb_addr, xfer_len); + readsize -= xfer_len; + dma_src += xfer_len; + to += xfer_len; + } + + return ret; +} + static int ti_qspi_dma_xfer_sg(struct ti_qspi *qspi, struct sg_table rx_sg, loff_t from) { @@ -498,6 +530,12 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi, QSPI_SPI_SETUP_REG(spi->chip_select)); } +static bool ti_qspi_spi_flash_can_dma(struct spi_device *spi, + struct spi_flash_read_message *msg) +{ + return virt_addr_valid(msg->buf); +} + static int ti_qspi_spi_flash_read(struct spi_device *spi, struct spi_flash_read_message *msg) { @@ -511,15 +549,12 @@ static int ti_qspi_spi_flash_read(struct spi_device *spi, ti_qspi_setup_mmap_read(spi, msg); if (qspi->rx_chan) { - if (msg->cur_msg_mapped) { + if (msg->cur_msg_mapped) ret = ti_qspi_dma_xfer_sg(qspi, msg->rx_sg, msg->from); - if (ret) - goto err_unlock; - } else { - dev_err(qspi->dev, "Invalid address for DMA\n"); - ret = -EIO; + else + ret = ti_qspi_dma_bounce_buffer(qspi, msg); + if (ret) goto err_unlock; - } } else { memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len); } @@ -725,6 +760,17 @@ static int ti_qspi_probe(struct platform_device *pdev) ret = 0; goto no_dma; } + qspi->rx_bb_addr = dma_alloc_coherent(qspi->dev, + QSPI_DMA_BUFFER_SIZE, + &qspi->rx_bb_dma_addr, + GFP_KERNEL | GFP_DMA); + if (!qspi->rx_bb_addr) { + dev_err(qspi->dev, + "dma_alloc_coherent failed, using PIO mode\n"); + dma_release_channel(qspi->rx_chan); + goto no_dma; + } + master->spi_flash_can_dma = ti_qspi_spi_flash_can_dma; master->dma_rx = qspi->rx_chan; init_completion(&qspi->transfer_complete); if (res_mmap) @@ -765,6 +811,10 @@ static int ti_qspi_remove(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); + if (qspi->rx_bb_addr) + dma_free_coherent(qspi->dev, QSPI_DMA_BUFFER_SIZE, + qspi->rx_bb_addr, + qspi->rx_bb_dma_addr); if (qspi->rx_chan) dma_release_channel(qspi->rx_chan); diff --git a/drivers/spi/spi-xlp.c b/drivers/spi/spi-xlp.c index bea7a93a6046..80cb4d6af892 100644 --- a/drivers/spi/spi-xlp.c +++ b/drivers/spi/spi-xlp.c @@ -442,6 +442,7 @@ static int xlp_spi_probe(struct platform_device *pdev) #ifdef CONFIG_ACPI static const struct acpi_device_id xlp_spi_acpi_match[] = { { "BRCM900D", 0 }, + { "CAV900D", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, xlp_spi_acpi_match); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 90b5b2efafbf..89254a55eb2e 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -31,6 +31,7 @@ #include <linux/of_gpio.h> #include <linux/pm_runtime.h> #include <linux/pm_domain.h> +#include <linux/property.h> #include <linux/export.h> #include <linux/sched/rt.h> #include <uapi/linux/sched/types.h> @@ -600,13 +601,28 @@ struct spi_device *spi_new_device(struct spi_master *master, proxy->controller_data = chip->controller_data; proxy->controller_state = NULL; - status = spi_add_device(proxy); - if (status < 0) { - spi_dev_put(proxy); - return NULL; + if (chip->properties) { + status = device_add_properties(&proxy->dev, chip->properties); + if (status) { + dev_err(&master->dev, + "failed to add properties to '%s': %d\n", + chip->modalias, status); + goto err_dev_put; + } } + status = spi_add_device(proxy); + if (status < 0) + goto err_remove_props; + return proxy; + +err_remove_props: + if (chip->properties) + device_remove_properties(&proxy->dev); +err_dev_put: + spi_dev_put(proxy); + return NULL; } EXPORT_SYMBOL_GPL(spi_new_device); @@ -664,6 +680,7 @@ static void spi_match_master_to_boardinfo(struct spi_master *master, * * The board info passed can safely be __initdata ... but be careful of * any embedded pointers (platform_data, etc), they're copied as-is. + * Device properties are deep-copied though. * * Return: zero on success, else a negative error code. */ @@ -673,7 +690,7 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n) int i; if (!n) - return -EINVAL; + return 0; bi = kcalloc(n, sizeof(*bi), GFP_KERNEL); if (!bi) @@ -683,6 +700,13 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n) struct spi_master *master; memcpy(&bi->board_info, info, sizeof(*info)); + if (info->properties) { + bi->board_info.properties = + property_entries_dup(info->properties); + if (IS_ERR(bi->board_info.properties)) + return PTR_ERR(bi->board_info.properties); + } + mutex_lock(&board_lock); list_add_tail(&bi->list, &board_list); list_for_each_entry(master, &spi_master_list, list) @@ -1015,7 +1039,7 @@ static int spi_transfer_one_message(struct spi_master *master, ret = 0; ms = 8LL * 1000LL * xfer->len; do_div(ms, xfer->speed_hz); - ms += ms + 100; /* some tolerance */ + ms += ms + 200; /* some tolerance */ if (ms > UINT_MAX) ms = UINT_MAX; @@ -2830,7 +2854,7 @@ int spi_flash_read(struct spi_device *spi, mutex_lock(&master->bus_lock_mutex); mutex_lock(&master->io_mutex); - if (master->dma_rx) { + if (master->dma_rx && master->spi_flash_can_dma(spi, msg)) { rx_dev = master->dma_rx->device->dev; ret = spi_map_buf(master, rx_dev, &msg->rx_sg, msg->buf, msg->len, diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 9e2e099baf8c..9a2a79a871ba 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -697,6 +697,7 @@ static const struct of_device_id spidev_dt_ids[] = { { .compatible = "rohm,dh2228fv" }, { .compatible = "lineartechnology,ltc2488" }, { .compatible = "ge,achc" }, + { .compatible = "semtech,sx1301" }, {}, }; MODULE_DEVICE_TABLE(of, spidev_dt_ids); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 75c6bd0ac605..935bd2854ff1 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -23,6 +23,7 @@ #include <linux/scatterlist.h> struct dma_chan; +struct property_entry; struct spi_master; struct spi_transfer; struct spi_flash_read_message; @@ -375,6 +376,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @unprepare_message: undo any work done by prepare_message(). * @spi_flash_read: to support spi-controller hardwares that provide * accelerated interface to read from flash devices. + * @spi_flash_can_dma: analogous to can_dma() interface, but for + * controllers implementing spi_flash_read. * @flash_read_supported: spi device supports flash read * @cs_gpios: Array of GPIOs to use as chip select lines; one per CS * number. Any individual value may be -ENOENT for CS lines that @@ -538,6 +541,8 @@ struct spi_master { struct spi_message *message); int (*spi_flash_read)(struct spi_device *spi, struct spi_flash_read_message *msg); + bool (*spi_flash_can_dma)(struct spi_device *spi, + struct spi_flash_read_message *msg); bool (*flash_read_supported)(struct spi_device *spi); /* @@ -891,7 +896,7 @@ static inline struct spi_message *spi_message_alloc(unsigned ntrans, gfp_t flags unsigned i; struct spi_transfer *t = (struct spi_transfer *)(m + 1); - INIT_LIST_HEAD(&m->transfers); + spi_message_init_no_memset(m); for (i = 0; i < ntrans; i++, t++) spi_message_add_tail(t, m); } @@ -1209,6 +1214,7 @@ int spi_flash_read(struct spi_device *spi, * @modalias: Initializes spi_device.modalias; identifies the driver. * @platform_data: Initializes spi_device.platform_data; the particular * data stored there is driver-specific. + * @properties: Additional device properties for the device. * @controller_data: Initializes spi_device.controller_data; some * controllers need hints about hardware setup, e.g. for DMA. * @irq: Initializes spi_device.irq; depends on how the board is wired. @@ -1241,10 +1247,12 @@ struct spi_board_info { * * platform_data goes to spi_device.dev.platform_data, * controller_data goes to spi_device.controller_data, + * device properties are copied and attached to spi_device, * irq is copied too */ char modalias[SPI_NAME_SIZE]; const void *platform_data; + const struct property_entry *properties; void *controller_data; int irq; diff --git a/tools/spi/spidev_test.c b/tools/spi/spidev_test.c index 816f119c9b7b..8c590cd1171a 100644 --- a/tools/spi/spidev_test.c +++ b/tools/spi/spidev_test.c @@ -18,6 +18,7 @@ #include <string.h> #include <getopt.h> #include <fcntl.h> +#include <time.h> #include <sys/ioctl.h> #include <linux/ioctl.h> #include <sys/stat.h> @@ -40,6 +41,9 @@ static char *output_file; static uint32_t speed = 500000; static uint16_t delay; static int verbose; +static int transfer_size; +static int iterations; +static int interval = 5; /* interval in seconds for showing transfer rate */ uint8_t default_tx[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -156,13 +160,13 @@ static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len) close(out_fd); } - if (verbose || !output_file) + if (verbose) hex_dump(rx, len, 32, "RX"); } static void print_usage(const char *prog) { - printf("Usage: %s [-DsbdlHOLC3]\n", prog); + printf("Usage: %s [-DsbdlHOLC3vpNR24SI]\n", prog); puts(" -D --device device to use (default /dev/spidev1.1)\n" " -s --speed max speed (Hz)\n" " -d --delay delay (usec)\n" @@ -180,7 +184,9 @@ static void print_usage(const char *prog) " -N --no-cs no chip select\n" " -R --ready slave pulls low to pause\n" " -2 --dual dual transfer\n" - " -4 --quad quad transfer\n"); + " -4 --quad quad transfer\n" + " -S --size transfer size\n" + " -I --iter iterations\n"); exit(1); } @@ -205,11 +211,13 @@ static void parse_opts(int argc, char *argv[]) { "dual", 0, 0, '2' }, { "verbose", 0, 0, 'v' }, { "quad", 0, 0, '4' }, + { "size", 1, 0, 'S' }, + { "iter", 1, 0, 'I' }, { NULL, 0, 0, 0 }, }; int c; - c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR24p:v", + c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR24p:vS:I:", lopts, NULL); if (c == -1) @@ -270,6 +278,12 @@ static void parse_opts(int argc, char *argv[]) case '4': mode |= SPI_TX_QUAD; break; + case 'S': + transfer_size = atoi(optarg); + break; + case 'I': + iterations = atoi(optarg); + break; default: print_usage(argv[0]); break; @@ -336,6 +350,57 @@ static void transfer_file(int fd, char *filename) close(tx_fd); } +static uint64_t _read_count; +static uint64_t _write_count; + +static void show_transfer_rate(void) +{ + static uint64_t prev_read_count, prev_write_count; + double rx_rate, tx_rate; + + rx_rate = ((_read_count - prev_read_count) * 8) / (interval*1000.0); + tx_rate = ((_write_count - prev_write_count) * 8) / (interval*1000.0); + + printf("rate: tx %.1fkbps, rx %.1fkbps\n", rx_rate, tx_rate); + + prev_read_count = _read_count; + prev_write_count = _write_count; +} + +static void transfer_buf(int fd, int len) +{ + uint8_t *tx; + uint8_t *rx; + int i; + + tx = malloc(len); + if (!tx) + pabort("can't allocate tx buffer"); + for (i = 0; i < len; i++) + tx[i] = random(); + + rx = malloc(len); + if (!rx) + pabort("can't allocate rx buffer"); + + transfer(fd, tx, rx, len); + + _write_count += len; + _read_count += len; + + if (mode & SPI_LOOP) { + if (memcmp(tx, rx, len)) { + fprintf(stderr, "transfer error !\n"); + hex_dump(tx, len, 32, "TX"); + hex_dump(rx, len, 32, "RX"); + exit(1); + } + } + + free(rx); + free(tx); +} + int main(int argc, char *argv[]) { int ret = 0; @@ -391,7 +456,25 @@ int main(int argc, char *argv[]) transfer_escaped_string(fd, input_tx); else if (input_file) transfer_file(fd, input_file); - else + else if (transfer_size) { + struct timespec last_stat; + + clock_gettime(CLOCK_MONOTONIC, &last_stat); + + while (iterations-- > 0) { + struct timespec current; + + transfer_buf(fd, transfer_size); + + clock_gettime(CLOCK_MONOTONIC, ¤t); + if (current.tv_sec - last_stat.tv_sec > interval) { + show_transfer_rate(); + last_stat = current; + } + } + printf("total: tx %.1fKB, rx %.1fKB\n", + _write_count/1024.0, _read_count/1024.0); + } else transfer(fd, default_tx, default_rx, sizeof(default_tx)); close(fd); |