From da470d6ab857d04fa99ca3d5c16e6d87457d3e1d Mon Sep 17 00:00:00 2001 From: Aravind Thokala Date: Tue, 27 Jun 2017 22:01:11 +0530 Subject: spi/ath79: Fix checkpatch warnings This patch fixes the checkpatch.pl warnings on the driver file. Signed-off-by: Aravind Thokala Signed-off-by: Mark Brown --- drivers/spi/spi-ath79.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index b89cee11f418..0719bd484891 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -39,15 +39,15 @@ struct ath79_spi { u32 reg_ctrl; void __iomem *base; struct clk *clk; - unsigned rrw_delay; + unsigned int rrw_delay; }; -static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg) +static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned int reg) { return ioread32(sp->base + reg); } -static inline void ath79_spi_wr(struct ath79_spi *sp, unsigned reg, u32 val) +static inline void ath79_spi_wr(struct ath79_spi *sp, unsigned int reg, u32 val) { iowrite32(val, sp->base + reg); } @@ -57,7 +57,7 @@ static inline struct ath79_spi *ath79_spidev_to_sp(struct spi_device *spi) return spi_master_get_devdata(spi->master); } -static inline void ath79_spi_delay(struct ath79_spi *sp, unsigned nsecs) +static inline void ath79_spi_delay(struct ath79_spi *sp, unsigned int nsecs) { if (nsecs > sp->rrw_delay) ndelay(nsecs - sp->rrw_delay); @@ -148,9 +148,8 @@ static int ath79_spi_setup_cs(struct spi_device *spi) static void ath79_spi_cleanup_cs(struct spi_device *spi) { - if (gpio_is_valid(spi->cs_gpio)) { + if (gpio_is_valid(spi->cs_gpio)) gpio_free(spi->cs_gpio); - } } static int ath79_spi_setup(struct spi_device *spi) @@ -176,7 +175,7 @@ static void ath79_spi_cleanup(struct spi_device *spi) spi_bitbang_cleanup(spi); } -static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs, +static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned int nsecs, u32 word, u8 bits) { struct ath79_spi *sp = ath79_spidev_to_sp(spi); -- cgit v1.2.3 From c3c25ea712c909e40d11024dcf6e4b19a2fc247b Mon Sep 17 00:00:00 2001 From: Aravind Thokala Date: Tue, 27 Jun 2017 21:37:10 +0530 Subject: spi/bcm63xx-hspi: Fix checkpatch warnings This patch fixes the checkpatch.pl warnings on the driver file. Signed-off-by: Aravind Thokala Signed-off-by: Mark Brown --- drivers/spi/spi-bcm63xx-hsspi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index 4da2d4a524ca..475a79015aa6 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -108,7 +108,7 @@ struct bcm63xx_hsspi { u8 cs_polarity; }; -static void bcm63xx_hsspi_set_cs(struct bcm63xx_hsspi *bs, unsigned cs, +static void bcm63xx_hsspi_set_cs(struct bcm63xx_hsspi *bs, unsigned int cs, bool active) { u32 reg; @@ -127,7 +127,7 @@ static void bcm63xx_hsspi_set_cs(struct bcm63xx_hsspi *bs, unsigned cs, static void bcm63xx_hsspi_set_clk(struct bcm63xx_hsspi *bs, struct spi_device *spi, int hz) { - unsigned profile = spi->chip_select; + unsigned int profile = spi->chip_select; u32 reg; reg = DIV_ROUND_UP(2048, DIV_ROUND_UP(bs->speed_hz, hz)); @@ -154,7 +154,7 @@ static void bcm63xx_hsspi_set_clk(struct bcm63xx_hsspi *bs, static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t) { struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master); - unsigned chip_select = spi->chip_select; + unsigned int chip_select = spi->chip_select; u16 opcode = 0; int pending = t->len; int step_size = HSSPI_BUFFER_LEN; -- cgit v1.2.3 From fd8d4e2d1f20e9a5dbbdb16ee9b594726a7c5a2d Mon Sep 17 00:00:00 2001 From: jiada wang Date: Thu, 8 Jun 2017 14:16:00 +0900 Subject: spi: imx: introduce fifo_size and has_dmamode in spi_imx_devtype_data Different ECSPI controller has different fifosize and DMA capability, instead of calling functions to identify these information by check devtype. add fifo_size and has_dmamode to spi_imx_devtype_data. so that these information can be directly accessed. Signed-off-by: Jiada Wang Reviewed-by: Sascha Hauer Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index f9698b7aeb3b..d3093f355dfb 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -74,6 +74,8 @@ struct spi_imx_devtype_data { void (*trigger)(struct spi_imx_data *); int (*rx_available)(struct spi_imx_data *); void (*reset)(struct spi_imx_data *); + bool has_dmamode; + unsigned int fifo_size; enum spi_imx_devtype devtype; }; @@ -125,11 +127,6 @@ static inline int is_imx51_ecspi(struct spi_imx_data *d) return d->devtype_data->devtype == IMX51_ECSPI; } -static inline unsigned spi_imx_get_fifosize(struct spi_imx_data *d) -{ - return is_imx51_ecspi(d) ? 64 : 8; -} - #define MXC_SPI_BUF_RX(type) \ static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx) \ { \ @@ -219,7 +216,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4) return false; - for (i = spi_imx_get_fifosize(spi_imx) / 2; i > 0; i--) { + for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) { if (!(transfer->len % (i * bytes_per_word))) break; } @@ -693,6 +690,8 @@ static struct spi_imx_devtype_data imx1_cspi_devtype_data = { .trigger = mx1_trigger, .rx_available = mx1_rx_available, .reset = mx1_reset, + .fifo_size = 8, + .has_dmamode = false, .devtype = IMX1_CSPI, }; @@ -702,6 +701,8 @@ static struct spi_imx_devtype_data imx21_cspi_devtype_data = { .trigger = mx21_trigger, .rx_available = mx21_rx_available, .reset = mx21_reset, + .fifo_size = 8, + .has_dmamode = false, .devtype = IMX21_CSPI, }; @@ -712,6 +713,8 @@ static struct spi_imx_devtype_data imx27_cspi_devtype_data = { .trigger = mx21_trigger, .rx_available = mx21_rx_available, .reset = mx21_reset, + .fifo_size = 8, + .has_dmamode = false, .devtype = IMX27_CSPI, }; @@ -721,6 +724,8 @@ static struct spi_imx_devtype_data imx31_cspi_devtype_data = { .trigger = mx31_trigger, .rx_available = mx31_rx_available, .reset = mx31_reset, + .fifo_size = 8, + .has_dmamode = false, .devtype = IMX31_CSPI, }; @@ -731,6 +736,8 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = { .trigger = mx31_trigger, .rx_available = mx31_rx_available, .reset = mx31_reset, + .fifo_size = 8, + .has_dmamode = true, .devtype = IMX35_CSPI, }; @@ -740,6 +747,8 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = { .trigger = mx51_ecspi_trigger, .rx_available = mx51_ecspi_rx_available, .reset = mx51_ecspi_reset, + .fifo_size = 64, + .has_dmamode = true, .devtype = IMX51_ECSPI, }; @@ -791,7 +800,7 @@ static void spi_imx_chipselect(struct spi_device *spi, int is_active) static void spi_imx_push(struct spi_imx_data *spi_imx) { - while (spi_imx->txfifo < spi_imx_get_fifosize(spi_imx)) { + while (spi_imx->txfifo < spi_imx->devtype_data->fifo_size) { if (!spi_imx->count) break; spi_imx->tx(spi_imx); @@ -938,7 +947,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx, if (of_machine_is_compatible("fsl,imx6dl")) return 0; - spi_imx->wml = spi_imx_get_fifosize(spi_imx) / 2; + spi_imx->wml = spi_imx->devtype_data->fifo_size / 2; /* Prepare for TX DMA: */ master->dma_tx = dma_request_slave_channel_reason(dev, "tx"); @@ -1262,7 +1271,7 @@ static int spi_imx_probe(struct platform_device *pdev) * Only validated on i.mx35 and i.mx6 now, can remove the constraint * if validated on other chips. */ - if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx)) { + if (spi_imx->devtype_data->has_dmamode) { ret = spi_imx_sdma_init(&pdev->dev, spi_imx, master); if (ret == -EPROBE_DEFER) goto out_clk_put; -- cgit v1.2.3 From 26e4bb8670fc615aaaf26bd1332511333d2b6363 Mon Sep 17 00:00:00 2001 From: jiada wang Date: Thu, 8 Jun 2017 14:16:01 +0900 Subject: spi: imx: add selection for iMX53 and iMX6 controller ECSPI contorller for iMX53 and iMX6 has few hardware issues comparing to iMX51. The change add possibility to detect which controller is used to apply possible workaround and limitations. Signed-off-by: Jiada Wang Acked-by: Rob Herring Reviewed-by: Sascha Hauer Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/fsl-imx-cspi.txt | 1 + drivers/spi/spi-imx.c | 26 ++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt index 31b5b21598ff..5bf13960f7f4 100644 --- a/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt +++ b/Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt @@ -9,6 +9,7 @@ Required properties: - "fsl,imx31-cspi" for SPI compatible with the one integrated on i.MX31 - "fsl,imx35-cspi" for SPI compatible with the one integrated on i.MX35 - "fsl,imx51-ecspi" for SPI compatible with the one integrated on i.MX51 + - "fsl,imx53-ecspi" for SPI compatible with the one integrated on i.MX53 and later Soc - reg : Offset and length of the register set for the device - interrupts : Should contain CSPI/eCSPI interrupt - cs-gpios : Specifies the gpio pins to be used for chipselects. diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index d3093f355dfb..424dd013451e 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -63,7 +63,8 @@ enum spi_imx_devtype { IMX27_CSPI, IMX31_CSPI, IMX35_CSPI, /* CSPI on all i.mx except above */ - IMX51_ECSPI, /* ECSPI on i.mx51 and later */ + IMX51_ECSPI, /* ECSPI on i.mx51 */ + IMX53_ECSPI, /* ECSPI on i.mx53 and later */ }; struct spi_imx_data; @@ -127,6 +128,11 @@ static inline int is_imx51_ecspi(struct spi_imx_data *d) return d->devtype_data->devtype == IMX51_ECSPI; } +static inline int is_imx53_ecspi(struct spi_imx_data *d) +{ + return d->devtype_data->devtype == IMX53_ECSPI; +} + #define MXC_SPI_BUF_RX(type) \ static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx) \ { \ @@ -752,6 +758,17 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = { .devtype = IMX51_ECSPI, }; +static struct spi_imx_devtype_data imx53_ecspi_devtype_data = { + .intctrl = mx51_ecspi_intctrl, + .config = mx51_ecspi_config, + .trigger = mx51_ecspi_trigger, + .rx_available = mx51_ecspi_rx_available, + .reset = mx51_ecspi_reset, + .fifo_size = 64, + .has_dmamode = true, + .devtype = IMX53_ECSPI, +}; + static const struct platform_device_id spi_imx_devtype[] = { { .name = "imx1-cspi", @@ -771,6 +788,9 @@ static const struct platform_device_id spi_imx_devtype[] = { }, { .name = "imx51-ecspi", .driver_data = (kernel_ulong_t) &imx51_ecspi_devtype_data, + }, { + .name = "imx53-ecspi", + .driver_data = (kernel_ulong_t) &imx53_ecspi_devtype_data, }, { /* sentinel */ } @@ -783,6 +803,7 @@ static const struct of_device_id spi_imx_dt_ids[] = { { .compatible = "fsl,imx31-cspi", .data = &imx31_cspi_devtype_data, }, { .compatible = "fsl,imx35-cspi", .data = &imx35_cspi_devtype_data, }, { .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, }, + { .compatible = "fsl,imx53-ecspi", .data = &imx53_ecspi_devtype_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, spi_imx_dt_ids); @@ -1218,7 +1239,8 @@ static int spi_imx_probe(struct platform_device *pdev) spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message; 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)) + if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) || + is_imx53_ecspi(spi_imx)) spi_imx->bitbang.master->mode_bits |= SPI_LOOP | SPI_READY; spi_imx->spi_drctl = spi_drctl; -- cgit v1.2.3 From 676a4e3bab445d53fca4756865e2c0e2a87c38d6 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Sat, 8 Jul 2017 10:41:18 +0200 Subject: spi: pxa2xx: Only claim CS GPIOs when the slave device is created Avoid hogging chip select GPIOs just because they are listed for the master. They might be mulitplexed and, if no slave device is attached, used for different purposes. Moreover, this strategy avoids having to allocate a cs_gpiods structure. Tested on the IOT2000 where the second SPI bus is connected to an Arduino-compatible connector and multiplexed between SPI, GPIO and PWM usage. Signed-off-by: Jan Kiszka Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 59 +++++++++++++++++------------------------------- 1 file changed, 21 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 38d053682892..be991266a6ce 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1213,21 +1213,33 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip, struct pxa2xx_spi_chip *chip_info) { struct driver_data *drv_data = spi_master_get_devdata(spi->master); + struct device *pdev = &drv_data->pdev->dev; + struct gpio_desc *gpiod; int err = 0; + int count; if (chip == NULL) return 0; - if (drv_data->cs_gpiods) { - struct gpio_desc *gpiod; + count = gpiod_count(pdev, "cs"); + if (count > 0) { + if (spi->chip_select >= count) + return -EINVAL; + + gpiod = gpiod_get_index(pdev, "cs", spi->chip_select, + GPIOD_OUT_HIGH); + if (IS_ERR(gpiod)) { + /* Means use native chip select */ + if (PTR_ERR(gpiod) == -ENOENT) + return 0; - gpiod = drv_data->cs_gpiods[spi->chip_select]; - if (gpiod) { - chip->gpio_cs = desc_to_gpio(gpiod); - chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH; - gpiod_set_value(gpiod, chip->gpio_cs_inverted); + return PTR_ERR(gpiod); } + chip->gpio_cs = desc_to_gpio(gpiod); + chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH; + gpiod_set_value(gpiod, chip->gpio_cs_inverted); + return 0; } @@ -1415,8 +1427,7 @@ static void cleanup(struct spi_device *spi) if (!chip) return; - if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods && - gpio_is_valid(chip->gpio_cs)) + if (drv_data->ssp_type != CE4100_SSP && gpio_is_valid(chip->gpio_cs)) gpio_free(chip->gpio_cs); kfree(chip); @@ -1752,38 +1763,10 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) master->num_chipselect = platform_info->num_chipselect; count = gpiod_count(&pdev->dev, "cs"); - if (count > 0) { - int i; - + if (count > 0) master->num_chipselect = max_t(int, count, master->num_chipselect); - drv_data->cs_gpiods = devm_kcalloc(&pdev->dev, - master->num_chipselect, sizeof(struct gpio_desc *), - GFP_KERNEL); - if (!drv_data->cs_gpiods) { - status = -ENOMEM; - goto out_error_clock_enabled; - } - - for (i = 0; i < master->num_chipselect; i++) { - struct gpio_desc *gpiod; - - gpiod = devm_gpiod_get_index(dev, "cs", i, - GPIOD_OUT_HIGH); - if (IS_ERR(gpiod)) { - /* Means use native chip select */ - if (PTR_ERR(gpiod) == -ENOENT) - continue; - - status = (int)PTR_ERR(gpiod); - goto out_error_clock_enabled; - } else { - drv_data->cs_gpiods[i] = gpiod; - } - } - } - tasklet_init(&drv_data->pump_transfers, pump_transfers, (unsigned long)drv_data); -- cgit v1.2.3 From 61a8dec502b873879fa240ec7614601523b46a43 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 12 Jul 2017 12:26:01 +0200 Subject: spi: sh-msiof: Limit minimum divider on R-Car Gen3 On R-Car Gen3 SoCs (excluding R-Car H3 ES1.x, which cannot be used for SPI due to a hardware erratum), BRPS x BRDV = 1/1 is an invalid divider setting. Implement this limitation using an SoC/family-specific minimum divider. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index c304c7167866..0eb1e9583485 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -38,6 +38,7 @@ struct sh_msiof_chipdata { u16 tx_fifo_size; u16 rx_fifo_size; u16 master_flags; + u16 min_div; }; struct sh_msiof_spi_priv { @@ -49,6 +50,7 @@ struct sh_msiof_spi_priv { struct completion done; unsigned int tx_fifo_size; unsigned int rx_fifo_size; + unsigned int min_div; void *tx_dma_page; void *rx_dma_page; dma_addr_t tx_dma_addr; @@ -261,6 +263,8 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, if (!WARN_ON(!spi_hz || !parent_rate)) div = DIV_ROUND_UP(parent_rate, spi_hz); + div = max_t(unsigned long, div, p->min_div); + for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_div_table); k++) { brps = DIV_ROUND_UP(div, sh_msiof_spi_div_table[k].div); /* SCR_BRDV_DIV_1 is valid only if BRPS is x 1/1 or x 1/2 */ @@ -998,24 +1002,33 @@ static const struct sh_msiof_chipdata sh_data = { .tx_fifo_size = 64, .rx_fifo_size = 64, .master_flags = 0, + .min_div = 1, +}; + +static const struct sh_msiof_chipdata rcar_gen2_data = { + .tx_fifo_size = 64, + .rx_fifo_size = 64, + .master_flags = SPI_MASTER_MUST_TX, + .min_div = 1, }; -static const struct sh_msiof_chipdata r8a779x_data = { +static const struct sh_msiof_chipdata rcar_gen3_data = { .tx_fifo_size = 64, .rx_fifo_size = 64, .master_flags = SPI_MASTER_MUST_TX, + .min_div = 2, }; static const struct of_device_id sh_msiof_match[] = { { .compatible = "renesas,sh-mobile-msiof", .data = &sh_data }, - { .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data }, - { .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data }, - { .compatible = "renesas,msiof-r8a7792", .data = &r8a779x_data }, - { .compatible = "renesas,msiof-r8a7793", .data = &r8a779x_data }, - { .compatible = "renesas,msiof-r8a7794", .data = &r8a779x_data }, - { .compatible = "renesas,rcar-gen2-msiof", .data = &r8a779x_data }, - { .compatible = "renesas,msiof-r8a7796", .data = &r8a779x_data }, - { .compatible = "renesas,rcar-gen3-msiof", .data = &r8a779x_data }, + { .compatible = "renesas,msiof-r8a7790", .data = &rcar_gen2_data }, + { .compatible = "renesas,msiof-r8a7791", .data = &rcar_gen2_data }, + { .compatible = "renesas,msiof-r8a7792", .data = &rcar_gen2_data }, + { .compatible = "renesas,msiof-r8a7793", .data = &rcar_gen2_data }, + { .compatible = "renesas,msiof-r8a7794", .data = &rcar_gen2_data }, + { .compatible = "renesas,rcar-gen2-msiof", .data = &rcar_gen2_data }, + { .compatible = "renesas,msiof-r8a7796", .data = &rcar_gen3_data }, + { .compatible = "renesas,rcar-gen3-msiof", .data = &rcar_gen3_data }, { .compatible = "renesas,sh-msiof", .data = &sh_data }, /* Deprecated */ {}, }; @@ -1230,6 +1243,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, p); p->master = master; p->info = info; + p->min_div = chipdata->min_div; init_completion(&p->done); -- cgit v1.2.3 From f12a616e0cdee71440b72f7602825db424d37879 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 14 Jul 2017 11:42:46 +0200 Subject: spi: loopback-test: provide loop_req option. Provide a module parameter to request internal loop by the SPI master controller. This should make loop testing easier without extra HW modification. For test automation a logic analyzer is recommended for host controller-independent verification. An example test rig configuration and procedure: i.MX6S RIoRBoard Logic Analyzer ----------------------------------------- (J13 4) GND ------------- GND (J13 6) CSPI3-CLK ------> PIN 3 (J13 8) CSPI3-MOSI <----- PIN 2 ^ - internal loop configured by SPI_LOOP | or can be user external jamper. (J13 10) CSPI3-MISO -----> PIN 1 grab some data and decode it: sigrok-cli -d fx2lafw --time 160000 --config samplerate=10m \ --channels 0-2 -o dump.sr sigrok-cli -i dump.sr -P spi:mosi=1:clk=2 > result_for_regression_tests Signed-off-by: Oleksij Rempel Signed-off-by: Mark Brown --- drivers/spi/spi-loopback-test.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index 3459965004f8..0d3c56e2526c 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -51,6 +51,12 @@ MODULE_PARM_DESC(loopback, "is checked to match tx_buf after the spi_message " \ "is executed"); +int loop_req; +module_param(loop_req, int, 0); +MODULE_PARM_DESC(loop_req, + "if set controller will be asked to enable test loop mode. " \ + "If controller supported it, MISO and MOSI will be connected"); + /* run only a specific test */ int run_only_test = -1; module_param(run_only_test, int, 0); @@ -313,6 +319,16 @@ static int spi_loopback_test_probe(struct spi_device *spi) { int ret; + if (loop_req) { + spi->mode = SPI_LOOP | spi->mode; + ret = spi_setup(spi); + if (ret) { + dev_err(&spi->dev, "SPI setup with SPI_LOOP failed (%d)\n", + ret); + return ret; + } + } + dev_info(&spi->dev, "Executing spi-loopback-tests\n"); ret = spi_test_run_tests(spi, spi_tests); -- cgit v1.2.3 From 59a8831da31ebdabf82cac82bf01270d215bf149 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 18 Jul 2017 13:42:32 +0100 Subject: spi: loopback-test: make several module parameters static Several module parameters are local to the source, so make them static. Cleans up several sparse warnings such as: "symbol 'loop_req' was not declared. Should it be static?" Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- drivers/spi/spi-loopback-test.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index 0d3c56e2526c..64a1e6f212c1 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -32,45 +32,45 @@ #include "spi-test.h" /* flag to only simulate transfers */ -int simulate_only; +static int simulate_only; module_param(simulate_only, int, 0); MODULE_PARM_DESC(simulate_only, "if not 0 do not execute the spi message"); /* dump spi messages */ -int dump_messages; +static int dump_messages; module_param(dump_messages, int, 0); MODULE_PARM_DESC(dump_messages, "=1 dump the basic spi_message_structure, " \ "=2 dump the spi_message_structure including data, " \ "=3 dump the spi_message structure before and after execution"); /* the device is jumpered for loopback - enabling some rx_buf tests */ -int loopback; +static int loopback; module_param(loopback, int, 0); MODULE_PARM_DESC(loopback, "if set enable loopback mode, where the rx_buf " \ "is checked to match tx_buf after the spi_message " \ "is executed"); -int loop_req; +static int loop_req; module_param(loop_req, int, 0); MODULE_PARM_DESC(loop_req, "if set controller will be asked to enable test loop mode. " \ "If controller supported it, MISO and MOSI will be connected"); /* run only a specific test */ -int run_only_test = -1; +static int run_only_test = -1; 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; +static 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; +static int check_ranges = 1; module_param(check_ranges, int, 0644); MODULE_PARM_DESC(check_ranges, "checks rx_buffer pattern are valid"); -- cgit v1.2.3 From 25c56c88a4627e7fdbfa12a4c20c75e2ccb366d1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 18 Jul 2017 16:43:31 -0500 Subject: spi: Convert to using %pOF instead of full_name Now that we have a custom printf format specifier, convert users of full_name to use %pOF instead. This is preparation to remove storing of the full path string for each node. Signed-off-by: Rob Herring Reviewed-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-orion.c | 4 ++-- drivers/spi/spi.c | 27 +++++++++++---------------- 2 files changed, 13 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 28fc9f161b9d..4b6dd73b80da 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -669,8 +669,8 @@ static int orion_spi_probe(struct platform_device *pdev) status = of_property_read_u32(np, "reg", &cs); if (status) { dev_err(&pdev->dev, - "%s has no valid 'reg' property (%d)\n", - np->full_name, status); + "%pOF has no valid 'reg' property (%d)\n", + np, status); status = 0; continue; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 4fcbb0aa71d3..0725c78b0de6 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1583,8 +1583,8 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, if (spi_controller_is_slave(ctlr)) { if (strcmp(nc->name, "slave")) { - dev_err(&ctlr->dev, "%s is not called 'slave'\n", - nc->full_name); + dev_err(&ctlr->dev, "%pOF is not called 'slave'\n", + nc); return -EINVAL; } return 0; @@ -1593,8 +1593,8 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, /* Device address */ rc = of_property_read_u32(nc, "reg", &value); if (rc) { - dev_err(&ctlr->dev, "%s has no valid 'reg' property (%d)\n", - nc->full_name, rc); + dev_err(&ctlr->dev, "%pOF has no valid 'reg' property (%d)\n", + nc, rc); return rc; } spi->chip_select = value; @@ -1603,8 +1603,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, rc = of_property_read_u32(nc, "spi-max-frequency", &value); if (rc) { dev_err(&ctlr->dev, - "%s has no valid 'spi-max-frequency' property (%d)\n", - nc->full_name, rc); + "%pOF has no valid 'spi-max-frequency' property (%d)\n", nc, rc); return rc; } spi->max_speed_hz = value; @@ -1621,8 +1620,7 @@ of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc) /* Alloc an spi_device */ spi = spi_alloc_device(ctlr); if (!spi) { - dev_err(&ctlr->dev, "spi_device alloc error for %s\n", - nc->full_name); + dev_err(&ctlr->dev, "spi_device alloc error for %pOF\n", nc); rc = -ENOMEM; goto err_out; } @@ -1631,8 +1629,7 @@ of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc) rc = of_modalias_node(nc, spi->modalias, sizeof(spi->modalias)); if (rc < 0) { - dev_err(&ctlr->dev, "cannot find modalias for %s\n", - nc->full_name); + dev_err(&ctlr->dev, "cannot find modalias for %pOF\n", nc); goto err_out; } @@ -1647,8 +1644,7 @@ of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc) /* Register the new device */ rc = spi_add_device(spi); if (rc) { - dev_err(&ctlr->dev, "spi_device register error %s\n", - nc->full_name); + dev_err(&ctlr->dev, "spi_device register error %pOF\n", nc); goto err_of_node_put; } @@ -1682,8 +1678,7 @@ static void of_register_spi_devices(struct spi_controller *ctlr) spi = of_register_spi_device(ctlr, nc); if (IS_ERR(spi)) { dev_warn(&ctlr->dev, - "Failed to create SPI device for %s\n", - nc->full_name); + "Failed to create SPI device for %pOF\n", nc); of_node_clear_flag(nc, OF_POPULATED); } } @@ -3311,8 +3306,8 @@ static int of_spi_notify(struct notifier_block *nb, unsigned long action, put_device(&ctlr->dev); if (IS_ERR(spi)) { - pr_err("%s: failed to create for '%s'\n", - __func__, rd->dn->full_name); + pr_err("%s: failed to create for '%pOF'\n", + __func__, rd->dn); of_node_clear_flag(rd->dn, OF_POPULATED); return notifier_from_errno(PTR_ERR(spi)); } -- cgit v1.2.3 From d5e9a4a433f7d082538268501fa684ada2c76552 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 19 Jul 2017 17:26:20 +0200 Subject: spi: stm32: explicitly request exclusive reset control Commit a53e35db70d1 ("reset: Ensure drivers are explicit when requesting reset lines") started to transition the reset control request API calls to explicitly state whether the driver needs exclusive or shared reset control behavior. Convert all drivers requesting exclusive resets to the explicit API call so the temporary transition helpers can be removed. No functional changes. Cc: Mark Brown Cc: Maxime Coquelin Cc: Alexandre Torgue Cc: linux-spi@vger.kernel.org Signed-off-by: Philipp Zabel Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 75644bcd938b..680cdf549506 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -1132,7 +1132,7 @@ static int stm32_spi_probe(struct platform_device *pdev) goto err_master_put; } - spi->rst = devm_reset_control_get(&pdev->dev, NULL); + spi->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (!IS_ERR(spi->rst)) { reset_control_assert(spi->rst); udelay(2); -- cgit v1.2.3 From 36bc7491f9558efef9a678f7d2555b3ecafd6d82 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 19 Jul 2017 17:26:21 +0200 Subject: spi: sun6i: explicitly request exclusive reset control Commit a53e35db70d1 ("reset: Ensure drivers are explicit when requesting reset lines") started to transition the reset control request API calls to explicitly state whether the driver needs exclusive or shared reset control behavior. Convert all drivers requesting exclusive resets to the explicit API call so the temporary transition helpers can be removed. No functional changes. Cc: Mark Brown Cc: Maxime Ripard Cc: Chen-Yu Tsai Cc: linux-spi@vger.kernel.org Signed-off-by: Philipp Zabel Signed-off-by: Mark Brown --- drivers/spi/spi-sun6i.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index 03a773a9531a..fb38234249a8 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -502,7 +502,7 @@ static int sun6i_spi_probe(struct platform_device *pdev) init_completion(&sspi->done); - sspi->rstc = devm_reset_control_get(&pdev->dev, NULL); + sspi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(sspi->rstc)) { dev_err(&pdev->dev, "Couldn't get reset controller\n"); ret = PTR_ERR(sspi->rstc); -- cgit v1.2.3 From 73b32756cec3128882165bd845956fe467a23ad4 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 19 Jul 2017 17:26:22 +0200 Subject: spi: tegra20-slink: explicitly request exclusive reset control Commit a53e35db70d1 ("reset: Ensure drivers are explicit when requesting reset lines") started to transition the reset control request API calls to explicitly state whether the driver needs exclusive or shared reset control behavior. Convert all drivers requesting exclusive resets to the explicit API call so the temporary transition helpers can be removed. No functional changes. Cc: Laxman Dewangan Cc: Mark Brown Cc: Thierry Reding Cc: Jonathan Hunter Cc: linux-spi@vger.kernel.org Cc: linux-tegra@vger.kernel.org Signed-off-by: Philipp Zabel Signed-off-by: Mark Brown --- drivers/spi/spi-tegra20-slink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 0c06ce424210..3e12d5f87ee4 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -1081,7 +1081,7 @@ static int tegra_slink_probe(struct platform_device *pdev) goto exit_free_irq; } - tspi->rst = devm_reset_control_get(&pdev->dev, "spi"); + tspi->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi"); if (IS_ERR(tspi->rst)) { dev_err(&pdev->dev, "can not get reset\n"); ret = PTR_ERR(tspi->rst); -- cgit v1.2.3 From d006edb4202fc8160e7b5ba10c264b153e1f3e2d Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 19 Jul 2017 17:26:23 +0200 Subject: spi: tegra114: explicitly request exclusive reset control Commit a53e35db70d1 ("reset: Ensure drivers are explicit when requesting reset lines") started to transition the reset control request API calls to explicitly state whether the driver needs exclusive or shared reset control behavior. Convert all drivers requesting exclusive resets to the explicit API call so the temporary transition helpers can be removed. No functional changes. Cc: Laxman Dewangan Cc: Mark Brown Cc: Thierry Reding Cc: Jonathan Hunter Cc: linux-spi@vger.kernel.org Cc: linux-tegra@vger.kernel.org Signed-off-by: Philipp Zabel Signed-off-by: Mark Brown --- drivers/spi/spi-tegra114.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 08012ae5aa66..44550182a4a3 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -1083,7 +1083,7 @@ static int tegra_spi_probe(struct platform_device *pdev) goto exit_free_irq; } - tspi->rst = devm_reset_control_get(&pdev->dev, "spi"); + tspi->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi"); if (IS_ERR(tspi->rst)) { dev_err(&pdev->dev, "can not get reset\n"); ret = PTR_ERR(tspi->rst); -- cgit v1.2.3 From e60dfe0782f251bb529f233e259dffdc8d786624 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 19 Jul 2017 17:26:24 +0200 Subject: spi: tegra20-sflash: explicitly request exclusive reset control Commit a53e35db70d1 ("reset: Ensure drivers are explicit when requesting reset lines") started to transition the reset control request API calls to explicitly state whether the driver needs exclusive or shared reset control behavior. Convert all drivers requesting exclusive resets to the explicit API call so the temporary transition helpers can be removed. No functional changes. Cc: Laxman Dewangan Cc: Mark Brown Cc: Thierry Reding Cc: Jonathan Hunter Cc: linux-spi@vger.kernel.org Cc: linux-tegra@vger.kernel.org Signed-off-by: Philipp Zabel Signed-off-by: Mark Brown --- drivers/spi/spi-tegra20-sflash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 2c797ee2664d..22893a7e0aa0 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -485,7 +485,7 @@ static int tegra_sflash_probe(struct platform_device *pdev) goto exit_free_irq; } - tsd->rst = devm_reset_control_get(&pdev->dev, "spi"); + tsd->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi"); if (IS_ERR(tsd->rst)) { dev_err(&pdev->dev, "can not get reset\n"); ret = PTR_ERR(tsd->rst); -- cgit v1.2.3 From 808f5154a75669fb08e1cc7019a4707836e21870 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 24 Jul 2017 22:44:45 +0100 Subject: spi: pic32: fix spelling mistakes on macro names Trivial fix to spelling mistakes macros; fix EMPTY spellings: RX_FIFO_EMTPY -> RX_FIFO_EMPTY TX_FIFO_EMTPY -> TX_FIFO_EMPTY Note that there are no other occurrances of these macros in the source. Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- drivers/spi/spi-pic32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c index fefb688a3432..f8a45af1fa9f 100644 --- a/drivers/spi/spi-pic32.c +++ b/drivers/spi/spi-pic32.c @@ -52,14 +52,14 @@ struct pic32_spi_regs { /* Bit fields of SPI Control Register */ #define CTRL_RX_INT_SHIFT 0 /* Rx interrupt generation */ -#define RX_FIFO_EMTPY 0 +#define RX_FIFO_EMPTY 0 #define RX_FIFO_NOT_EMPTY 1 /* not empty */ #define RX_FIFO_HALF_FULL 2 /* full by half or more */ #define RX_FIFO_FULL 3 /* completely full */ #define CTRL_TX_INT_SHIFT 2 /* TX interrupt generation */ #define TX_FIFO_ALL_EMPTY 0 /* completely empty */ -#define TX_FIFO_EMTPY 1 /* empty */ +#define TX_FIFO_EMPTY 1 /* empty */ #define TX_FIFO_HALF_EMPTY 2 /* empty by half or more */ #define TX_FIFO_NOT_FULL 3 /* atleast one empty */ -- cgit v1.2.3 From 8bc85a871436525cc38f819bbc122d216730e905 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 25 Jul 2017 09:57:08 +0200 Subject: spi: loopback-test: implement testing with no CS To run spi-loopback-tests on HW without modifications, we need to disable Chip Select. This should avoid surprising side effects for SPI devices by testing patterns. Signed-off-by: Oleksij Rempel Signed-off-by: Mark Brown --- drivers/spi/spi-loopback-test.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index 64a1e6f212c1..bed7403bb6b3 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -57,6 +57,11 @@ MODULE_PARM_DESC(loop_req, "if set controller will be asked to enable test loop mode. " \ "If controller supported it, MISO and MOSI will be connected"); +static int no_cs; +module_param(no_cs, int, 0); +MODULE_PARM_DESC(no_cs, + "if set Chip Select (CS) will not be used"); + /* run only a specific test */ static int run_only_test = -1; module_param(run_only_test, int, 0); @@ -319,11 +324,12 @@ static int spi_loopback_test_probe(struct spi_device *spi) { int ret; - if (loop_req) { - spi->mode = SPI_LOOP | spi->mode; + if (loop_req || no_cs) { + spi->mode |= loop_req ? SPI_LOOP : 0; + spi->mode |= no_cs ? SPI_NO_CS : 0; ret = spi_setup(spi); if (ret) { - dev_err(&spi->dev, "SPI setup with SPI_LOOP failed (%d)\n", + dev_err(&spi->dev, "SPI setup with SPI_LOOP or SPI_NO_CS failed (%d)\n", ret); return ret; } -- cgit v1.2.3 From ab2f357223eb8fa6acc96bfa002053b6f1f92341 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 25 Jul 2017 09:57:09 +0200 Subject: spi: imx: add SPI_NO_CS support To run spi-loopback-tests on HW without modifications, we need to disable Chip Select. This should avoid surprising side effects for SPI devices by testing patterns. Signed-off-by: Oleksij Rempel Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 424dd013451e..930e47597db3 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -813,6 +813,9 @@ static void spi_imx_chipselect(struct spi_device *spi, int is_active) int active = is_active != BITBANG_CS_INACTIVE; int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH); + if (spi->mode & SPI_NO_CS) + return; + if (!gpio_is_valid(spi->cs_gpio)) return; @@ -1139,6 +1142,9 @@ static int spi_imx_setup(struct spi_device *spi) dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__, spi->mode, spi->bits_per_word, spi->max_speed_hz); + if (spi->mode & SPI_NO_CS) + return 0; + if (gpio_is_valid(spi->cs_gpio)) gpio_direction_output(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); @@ -1238,7 +1244,8 @@ static int spi_imx_probe(struct platform_device *pdev) spi_imx->bitbang.master->cleanup = spi_imx_cleanup; spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message; spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message; - spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ + | SPI_NO_CS; if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) || is_imx53_ecspi(spi_imx)) spi_imx->bitbang.master->mode_bits |= SPI_LOOP | SPI_READY; -- cgit v1.2.3 From 2856670f23a92ab72db850d73f30c0b4b6ba5a76 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 26 Jul 2017 16:14:00 +0300 Subject: spi: core: Propagate error code of add_uevent_var() add_uevent_var() can fail, let caller know about this. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 4fcbb0aa71d3..fe7bba9241ea 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -321,8 +321,7 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env) if (rc != -ENODEV) return rc; - add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias); - return 0; + return add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias); } struct bus_type spi_bus_type = { -- cgit v1.2.3 From 6ac5a435ae6739c06ebbf79939e86e721b88a90f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 27 Jul 2017 14:37:08 +0300 Subject: spi: pxa2xx: Revert "Only claim CS GPIOs when the slave device is created" There is a valid case to call setup() following by setup_cs() several times for the same chip. With the commit 676a4e3bab44 ("spi: pxa2xx: Only claim CS GPIOs when the slave device is created") it is not possible anymore due to GPIO line being requested already during the first call to setup_cs(). For now, revert the commit to make things work again. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 59 +++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index be991266a6ce..38d053682892 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1213,33 +1213,21 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip, struct pxa2xx_spi_chip *chip_info) { struct driver_data *drv_data = spi_master_get_devdata(spi->master); - struct device *pdev = &drv_data->pdev->dev; - struct gpio_desc *gpiod; int err = 0; - int count; if (chip == NULL) return 0; - count = gpiod_count(pdev, "cs"); - if (count > 0) { - if (spi->chip_select >= count) - return -EINVAL; - - gpiod = gpiod_get_index(pdev, "cs", spi->chip_select, - GPIOD_OUT_HIGH); - if (IS_ERR(gpiod)) { - /* Means use native chip select */ - if (PTR_ERR(gpiod) == -ENOENT) - return 0; + if (drv_data->cs_gpiods) { + struct gpio_desc *gpiod; - return PTR_ERR(gpiod); + gpiod = drv_data->cs_gpiods[spi->chip_select]; + if (gpiod) { + chip->gpio_cs = desc_to_gpio(gpiod); + chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH; + gpiod_set_value(gpiod, chip->gpio_cs_inverted); } - chip->gpio_cs = desc_to_gpio(gpiod); - chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH; - gpiod_set_value(gpiod, chip->gpio_cs_inverted); - return 0; } @@ -1427,7 +1415,8 @@ static void cleanup(struct spi_device *spi) if (!chip) return; - if (drv_data->ssp_type != CE4100_SSP && gpio_is_valid(chip->gpio_cs)) + if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods && + gpio_is_valid(chip->gpio_cs)) gpio_free(chip->gpio_cs); kfree(chip); @@ -1763,10 +1752,38 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) master->num_chipselect = platform_info->num_chipselect; count = gpiod_count(&pdev->dev, "cs"); - if (count > 0) + if (count > 0) { + int i; + master->num_chipselect = max_t(int, count, master->num_chipselect); + drv_data->cs_gpiods = devm_kcalloc(&pdev->dev, + master->num_chipselect, sizeof(struct gpio_desc *), + GFP_KERNEL); + if (!drv_data->cs_gpiods) { + status = -ENOMEM; + goto out_error_clock_enabled; + } + + for (i = 0; i < master->num_chipselect; i++) { + struct gpio_desc *gpiod; + + gpiod = devm_gpiod_get_index(dev, "cs", i, + GPIOD_OUT_HIGH); + if (IS_ERR(gpiod)) { + /* Means use native chip select */ + if (PTR_ERR(gpiod) == -ENOENT) + continue; + + status = (int)PTR_ERR(gpiod); + goto out_error_clock_enabled; + } else { + drv_data->cs_gpiods[i] = gpiod; + } + } + } + tasklet_init(&drv_data->pump_transfers, pump_transfers, (unsigned long)drv_data); -- cgit v1.2.3 From 054e532f8f90daaf9d70a2cf2ce31e69a4e68031 Mon Sep 17 00:00:00 2001 From: Kamal Dasu Date: Wed, 26 Jul 2017 19:20:15 -0400 Subject: spi: bcm-qspi: Remove hardcoded settings and spi-nor.h dependency The newly added broadcom qspi driver in drivers/spi produces a build warning when CONFIG_MTD is disabled: include/linux/mtd/cfi.h:76:2: #warning No CONFIG_MTD_CFI_Ix selected. No NOR chip support can work. [-Werror=cpp] There has been discussion on this in the link provided below. This fix in SPI controller drivers implementing the ->spi_flash_read handler, now uses the settings provided inside the 'struct spi_flash_read_message' parameter instead of hardcoding them. Made changes to bcm_qspi_bspi_set_flex_mode() to set the BSPI controller using the passed msg structure and remove the need to include file by removing all use of SPINOR_OP_READ* macros. Fixes: 4e3b2d236fe0 ("spi: bcm-qspi: Add BSPI spi-nor flash controller driver") Link: https://patchwork.kernel.org/patch/9624585/ Signed-off-by: Kamal Dasu Signed-off-by: Mark Brown --- drivers/spi/spi-bcm-qspi.c | 89 +++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index b19722ba908c..6ef6c44f39f5 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -349,76 +348,60 @@ static void bcm_qspi_bspi_set_xfer_params(struct bcm_qspi *qspi, u8 cmd_byte, bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, flex_mode); } -static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, int width, - int addrlen, int hp) +static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, + struct spi_flash_read_message *msg, + int hp) { int bpc = 0, bpp = 0; - u8 command = SPINOR_OP_READ_FAST; - int flex_mode = 1, rv = 0; - bool spans_4byte = false; + u8 command = msg->read_opcode; + int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE; + int addrlen = msg->addr_width; + int addr_nbits = msg->addr_nbits ? msg->addr_nbits : SPI_NBITS_SINGLE; + int flex_mode = 1; dev_dbg(&qspi->pdev->dev, "set flex mode w %x addrlen %x hp %d\n", width, addrlen, hp); - if (addrlen == BSPI_ADDRLEN_4BYTES) { + if (addrlen == BSPI_ADDRLEN_4BYTES) bpp = BSPI_BPP_ADDR_SELECT_MASK; - spans_4byte = true; - } - bpp |= 8; + bpp |= msg->dummy_bytes * (8/addr_nbits); switch (width) { case SPI_NBITS_SINGLE: if (addrlen == BSPI_ADDRLEN_3BYTES) /* default mode, does not need flex_cmd */ flex_mode = 0; - else - command = SPINOR_OP_READ_FAST_4B; break; case SPI_NBITS_DUAL: bpc = 0x00000001; if (hp) { bpc |= 0x00010100; /* address and mode are 2-bit */ bpp = BSPI_BPP_MODE_SELECT_MASK; - command = OPCODE_DIOR; - if (spans_4byte) - command = OPCODE_DIOR_4B; - } else { - command = SPINOR_OP_READ_1_1_2; - if (spans_4byte) - command = SPINOR_OP_READ_1_1_2_4B; } break; case SPI_NBITS_QUAD: bpc = 0x00000002; if (hp) { bpc |= 0x00020200; /* address and mode are 4-bit */ - bpp = 4; /* dummy cycles */ - bpp |= BSPI_BPP_ADDR_SELECT_MASK; - command = OPCODE_QIOR; - if (spans_4byte) - command = OPCODE_QIOR_4B; - } else { - command = SPINOR_OP_READ_1_1_4; - if (spans_4byte) - command = SPINOR_OP_READ_1_1_4_4B; + bpp |= BSPI_BPP_MODE_SELECT_MASK; } break; default: - rv = -EINVAL; - break; + return -EINVAL; } - if (rv == 0) - bcm_qspi_bspi_set_xfer_params(qspi, command, bpp, bpc, - flex_mode); + bcm_qspi_bspi_set_xfer_params(qspi, command, bpp, bpc, flex_mode); - return rv; + return 0; } -static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi, int width, - int addrlen, int hp) +static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi, + struct spi_flash_read_message *msg, + int hp) { + int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE; + int addrlen = msg->addr_width; u32 data = bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL); dev_dbg(&qspi->pdev->dev, "set override mode w %x addrlen %x hp %d\n", @@ -430,7 +413,6 @@ static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi, int width, data &= ~(BSPI_STRAP_OVERRIDE_CTRL_DATA_QUAD | BSPI_STRAP_OVERRIDE_CTRL_DATA_DUAL); break; - case SPI_NBITS_QUAD: /* clear dual mode and set quad mode */ data &= ~BSPI_STRAP_OVERRIDE_CTRL_DATA_DUAL; @@ -455,15 +437,17 @@ static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi, int width, /* set the override mode */ data |= BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE; bcm_qspi_write(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL, data); - bcm_qspi_bspi_set_xfer_params(qspi, SPINOR_OP_READ_FAST, 0, 0, 0); + bcm_qspi_bspi_set_xfer_params(qspi, msg->read_opcode, 0, 0, 0); return 0; } static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi, - int width, int addrlen, int hp) + struct spi_flash_read_message *msg, int hp) { int error = 0; + int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE; + int addrlen = msg->addr_width; /* default mode */ qspi->xfer_mode.flex_mode = true; @@ -475,23 +459,13 @@ static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi, mask = BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE; if (val & mask || qspi->s3_strap_override_ctrl & mask) { qspi->xfer_mode.flex_mode = false; - bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, - 0); - - if ((val | qspi->s3_strap_override_ctrl) & - BSPI_STRAP_OVERRIDE_CTRL_DATA_DUAL) - width = SPI_NBITS_DUAL; - else if ((val | qspi->s3_strap_override_ctrl) & - BSPI_STRAP_OVERRIDE_CTRL_DATA_QUAD) - width = SPI_NBITS_QUAD; - - error = bcm_qspi_bspi_set_override(qspi, width, addrlen, - hp); + bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, 0); + error = bcm_qspi_bspi_set_override(qspi, msg, hp); } } if (qspi->xfer_mode.flex_mode) - error = bcm_qspi_bspi_set_flex_mode(qspi, width, addrlen, hp); + error = bcm_qspi_bspi_set_flex_mode(qspi, msg, hp); if (error) { dev_warn(&qspi->pdev->dev, @@ -981,7 +955,7 @@ static int bcm_qspi_flash_read(struct spi_device *spi, struct bcm_qspi *qspi = spi_master_get_devdata(spi->master); int ret = 0; bool mspi_read = false; - u32 io_width, addrlen, addr, len; + u32 addr, len; u_char *buf; buf = msg->buf; @@ -1010,9 +984,7 @@ static int bcm_qspi_flash_read(struct spi_device *spi, if (mspi_read) return bcm_qspi_mspi_flash_read(spi, msg); - io_width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE; - addrlen = msg->addr_width; - ret = bcm_qspi_bspi_set_mode(qspi, io_width, addrlen, -1); + ret = bcm_qspi_bspi_set_mode(qspi, msg, -1); if (!ret) ret = bcm_qspi_bspi_flash_read(spi, msg); @@ -1422,6 +1394,11 @@ static int __maybe_unused bcm_qspi_suspend(struct device *dev) { struct bcm_qspi *qspi = dev_get_drvdata(dev); + /* store the override strap value */ + if (!bcm_qspi_bspi_ver_three(qspi)) + qspi->s3_strap_override_ctrl = + bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL); + spi_master_suspend(qspi->master); clk_disable(qspi->clk); bcm_qspi_hw_uninit(qspi); -- cgit v1.2.3 From d35f2dc9a2a84f4985d8b16b47040fd6291788ad Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 27 Jul 2017 18:49:33 +0300 Subject: spi: pxa2xx: Don't touch CS pin until we have a transfer pending GPIO descriptors, when being requested, may configure pin at the same time. In case of SPI chip select we shouldn't do any assumptions of the state of pin since we don't know yet what chip is connected there and if it uses high or low active state. So, leave the state of pin as is until transfer will start. Fixes: 99f499cd6504 ("spi: pxa2xx: Add support for GPIO descriptor chip selects") Signed-off-by: Andy Shevchenko Acked-by: Mika Westeberg Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 38d053682892..6e5af88b7c6f 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1769,8 +1769,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) for (i = 0; i < master->num_chipselect; i++) { struct gpio_desc *gpiod; - gpiod = devm_gpiod_get_index(dev, "cs", i, - GPIOD_OUT_HIGH); + gpiod = devm_gpiod_get_index(dev, "cs", i, GPIOD_ASIS); if (IS_ERR(gpiod)) { /* Means use native chip select */ if (PTR_ERR(gpiod) == -ENOENT) -- cgit v1.2.3 From c18d925fca20d33c3d04e5002a883f62d699543e Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Thu, 3 Aug 2017 13:40:32 +0200 Subject: spi: pxa2xx: Convert to GPIO descriptor API where possible We still need to request/free GPIOs passed via the legacy path of pxa2xx_spi_chip::gpio_cs, but we can use the gpiod API otherwise. Consistently use the descriptor API instead of the legacy one. Signed-off-by: Jan Kiszka Acked-by: Mika Westerberg Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 32 ++++++++++++++++---------------- drivers/spi/spi-pxa2xx.h | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 6e5af88b7c6f..4cb515a3104c 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -402,8 +402,8 @@ static void cs_assert(struct driver_data *drv_data) return; } - if (gpio_is_valid(chip->gpio_cs)) { - gpio_set_value(chip->gpio_cs, chip->gpio_cs_inverted); + if (chip->gpiod_cs) { + gpiod_set_value(chip->gpiod_cs, chip->gpio_cs_inverted); return; } @@ -424,8 +424,8 @@ static void cs_deassert(struct driver_data *drv_data) return; } - if (gpio_is_valid(chip->gpio_cs)) { - gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted); + if (chip->gpiod_cs) { + gpiod_set_value(chip->gpiod_cs, !chip->gpio_cs_inverted); return; } @@ -1213,17 +1213,16 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip, struct pxa2xx_spi_chip *chip_info) { struct driver_data *drv_data = spi_master_get_devdata(spi->master); + struct gpio_desc *gpiod; int err = 0; if (chip == NULL) return 0; if (drv_data->cs_gpiods) { - struct gpio_desc *gpiod; - gpiod = drv_data->cs_gpiods[spi->chip_select]; if (gpiod) { - chip->gpio_cs = desc_to_gpio(gpiod); + chip->gpiod_cs = gpiod; chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH; gpiod_set_value(gpiod, chip->gpio_cs_inverted); } @@ -1237,8 +1236,10 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip, /* NOTE: setup() can be called multiple times, possibly with * different chip_info, release previously requested GPIO */ - if (gpio_is_valid(chip->gpio_cs)) - gpio_free(chip->gpio_cs); + if (chip->gpiod_cs) { + gpio_free(desc_to_gpio(chip->gpiod_cs)); + chip->gpiod_cs = NULL; + } /* If (*cs_control) is provided, ignore GPIO chip select */ if (chip_info->cs_control) { @@ -1254,11 +1255,11 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip, return err; } - chip->gpio_cs = chip_info->gpio_cs; + gpiod = gpio_to_desc(chip_info->gpio_cs); + chip->gpiod_cs = gpiod; chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH; - err = gpio_direction_output(chip->gpio_cs, - !chip->gpio_cs_inverted); + err = gpiod_direction_output(gpiod, !chip->gpio_cs_inverted); } return err; @@ -1317,8 +1318,7 @@ static int setup(struct spi_device *spi) } chip->frm = spi->chip_select; - } else - chip->gpio_cs = -1; + } chip->enable_dma = drv_data->master_info->enable_dma; chip->timeout = TIMOUT_DFLT; } @@ -1416,8 +1416,8 @@ static void cleanup(struct spi_device *spi) return; if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods && - gpio_is_valid(chip->gpio_cs)) - gpio_free(chip->gpio_cs); + chip->gpiod_cs) + gpio_free(desc_to_gpio(chip->gpiod_cs)); kfree(chip); } diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 2823a00a9405..94f7b0713281 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -83,7 +83,7 @@ struct chip_data { u16 lpss_tx_threshold; u8 enable_dma; union { - int gpio_cs; + struct gpio_desc *gpiod_cs; unsigned int frm; }; int gpio_cs_inverted; -- cgit v1.2.3 From e0bcb680b152c96ee4b561abbeb18743cdcc5ae3 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 6 Aug 2017 23:15:31 +0300 Subject: spi: use of_property_read_bool() Use a bit more compact of_property_read_bool() calls instead of the of_find_property() calls -- symmetrically with the of_property_read_u32() calls already done in of_spi_parse_dt(). Signed-off-by: Sergei Shtylyov Signed-off-by: Mark Brown --- drivers/spi/spi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index fe7bba9241ea..aed78093b130 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1532,15 +1532,15 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, int rc; /* Mode (clock phase/polarity/etc.) */ - if (of_find_property(nc, "spi-cpha", NULL)) + if (of_property_read_bool(nc, "spi-cpha")) spi->mode |= SPI_CPHA; - if (of_find_property(nc, "spi-cpol", NULL)) + if (of_property_read_bool(nc, "spi-cpol")) spi->mode |= SPI_CPOL; - if (of_find_property(nc, "spi-cs-high", NULL)) + if (of_property_read_bool(nc, "spi-cs-high")) spi->mode |= SPI_CS_HIGH; - if (of_find_property(nc, "spi-3wire", NULL)) + if (of_property_read_bool(nc, "spi-3wire")) spi->mode |= SPI_3WIRE; - if (of_find_property(nc, "spi-lsb-first", NULL)) + if (of_property_read_bool(nc, "spi-lsb-first")) spi->mode |= SPI_LSB_FIRST; /* Device DUAL/QUAD mode */ -- cgit v1.2.3 From 43de979ddc099c57858b243619c66e2f663a2f97 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Mon, 7 Aug 2017 20:40:18 +0800 Subject: spi: rockchip: Slightly rework return value handling Slightly rework return value handling, no functional changes. Signed-off-by: Jeffy Chen Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 0b4a52b3e1dc..5497650992c7 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -666,7 +666,7 @@ static bool rockchip_spi_can_dma(struct spi_master *master, static int rockchip_spi_probe(struct platform_device *pdev) { - int ret = 0; + int ret; struct rockchip_spi *rs; struct spi_master *master; struct resource *mem; @@ -703,13 +703,13 @@ static int rockchip_spi_probe(struct platform_device *pdev) } ret = clk_prepare_enable(rs->apb_pclk); - if (ret) { + if (ret < 0) { dev_err(&pdev->dev, "Failed to enable apb_pclk\n"); goto err_put_master; } ret = clk_prepare_enable(rs->spiclk); - if (ret) { + if (ret < 0) { dev_err(&pdev->dev, "Failed to enable spi_clk\n"); goto err_disable_apbclk; } @@ -786,7 +786,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) } ret = devm_spi_register_master(&pdev->dev, master); - if (ret) { + if (ret < 0) { dev_err(&pdev->dev, "Failed to register master\n"); goto err_free_dma_rx; } @@ -834,12 +834,12 @@ static int rockchip_spi_remove(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int rockchip_spi_suspend(struct device *dev) { - int ret = 0; + int ret; struct spi_master *master = dev_get_drvdata(dev); struct rockchip_spi *rs = spi_master_get_devdata(master); ret = spi_master_suspend(rs->master); - if (ret) + if (ret < 0) return ret; if (!pm_runtime_suspended(dev)) { @@ -849,12 +849,12 @@ static int rockchip_spi_suspend(struct device *dev) pinctrl_pm_select_sleep_state(dev); - return ret; + return 0; } static int rockchip_spi_resume(struct device *dev) { - int ret = 0; + int ret; struct spi_master *master = dev_get_drvdata(dev); struct rockchip_spi *rs = spi_master_get_devdata(master); @@ -878,7 +878,7 @@ static int rockchip_spi_resume(struct device *dev) clk_disable_unprepare(rs->apb_pclk); } - return ret; + return 0; } #endif /* CONFIG_PM_SLEEP */ @@ -901,14 +901,14 @@ static int rockchip_spi_runtime_resume(struct device *dev) struct rockchip_spi *rs = spi_master_get_devdata(master); ret = clk_prepare_enable(rs->apb_pclk); - if (ret) + if (ret < 0) return ret; ret = clk_prepare_enable(rs->spiclk); - if (ret) + if (ret < 0) clk_disable_unprepare(rs->apb_pclk); - return ret; + return 0; } #endif /* CONFIG_PM */ -- cgit v1.2.3 From 6a06e895b262621a81b3b08126b4bc5e1b8eef05 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Mon, 7 Aug 2017 20:40:19 +0800 Subject: spi: rockchip: Fix clock handling in remove We are assuming clocks enabled when calling rockchip_spi_remove, which is not always true. Those clocks might already been disabled by the runtime PM at that time. Call pm_runtime_get_sync before trying to disable clocks to avoid that. Signed-off-by: Jeffy Chen Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 5497650992c7..a75fd9bb76de 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -816,11 +816,15 @@ static int rockchip_spi_remove(struct platform_device *pdev) struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct rockchip_spi *rs = spi_master_get_devdata(master); - pm_runtime_disable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); clk_disable_unprepare(rs->spiclk); clk_disable_unprepare(rs->apb_pclk); + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + if (rs->dma_tx.ch) dma_release_channel(rs->dma_tx.ch); if (rs->dma_rx.ch) -- cgit v1.2.3 From d38c4ae194bb8a3d8cf7d95378c5b2799cdd0a3b Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Mon, 7 Aug 2017 20:40:20 +0800 Subject: spi: rockchip: Fix clock handling in suspend/resume The runtime suspend callback might be called by pm domain framework at suspend_noirq stage. It would try to disable the clocks which already been disabled by rockchip_spi_suspend. Call pm_runtime_force_suspend/pm_runtime_force_resume when suspend/resume to avoid that. Signed-off-by: Jeffy Chen Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index a75fd9bb76de..34f6440a5255 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -846,10 +846,9 @@ static int rockchip_spi_suspend(struct device *dev) if (ret < 0) return ret; - if (!pm_runtime_suspended(dev)) { - clk_disable_unprepare(rs->spiclk); - clk_disable_unprepare(rs->apb_pclk); - } + ret = pm_runtime_force_suspend(dev); + if (ret < 0) + return ret; pinctrl_pm_select_sleep_state(dev); @@ -864,17 +863,9 @@ static int rockchip_spi_resume(struct device *dev) pinctrl_pm_select_default_state(dev); - if (!pm_runtime_suspended(dev)) { - ret = clk_prepare_enable(rs->apb_pclk); - if (ret < 0) - return ret; - - ret = clk_prepare_enable(rs->spiclk); - if (ret < 0) { - clk_disable_unprepare(rs->apb_pclk); - return ret; - } - } + ret = pm_runtime_force_resume(dev); + if (ret < 0) + return ret; ret = spi_master_resume(rs->master); if (ret < 0) { -- cgit v1.2.3 From 128345b13d9b6a84d12f6b3c478e70acc21a96ac Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 7 Aug 2017 17:42:55 +0200 Subject: spi: fix building SPI_PXA on MMP When the audio driver selects CONFIG_PXA_SSP on ARCH_MMP as a loadable module, and the PXA SPI driver is built-in, we get a link error in the SPI driver: drivers/spi/spi-pxa2xx.o: In function `pxa2xx_spi_remove': spi-pxa2xx.c:(.text+0x5f0): undefined reference to `pxa_ssp_free' drivers/spi/spi-pxa2xx.o: In function `pxa2xx_spi_probe': spi-pxa2xx.c:(.text+0xeac): undefined reference to `pxa_ssp_request' spi-pxa2xx.c:(.text+0x1468): undefined reference to `pxa_ssp_free' spi-pxa2xx.c:(.text+0x15bc): undefined reference to `pxa_ssp_free' The problem is that the PXA SPI driver only uses 'select SSP' specifically when building it for PXA, but we can also build it for PCI, which is meant for Intel x86 SoCs that use the same SPI block. When the sound driver forces the SSP to be a loadable module, the IS_ENABLED() check in include/linux/pxa2xx_ssp.h triggers but the spi driver can't reference the exported symbols. I had a different approach before, making the PCI case depend on X86, which fixed the problem by avoiding the MMP case. This goes a different route, making the driver select PXA_SSP also on MMP, which has an SSP that none of the boards in mainline Linux use for SPI. There is no harm in always enabling the build on MMP (PCI or not PCI), so I do that too, to document that this hardware is actually available on MMP. Link: https://patchwork.kernel.org/patch/8879921/ Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 9b31351fe429..f9f9b0940746 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -518,8 +518,8 @@ config SPI_PPC4xx config SPI_PXA2XX tristate "PXA2xx SSP SPI master" - depends on (ARCH_PXA || PCI || ACPI) - select PXA_SSP if ARCH_PXA + depends on (ARCH_PXA || ARCH_MMP || PCI || ACPI) + select PXA_SSP if ARCH_PXA || ARCH_MMP help This enables using a PXA2xx or Sodaville SSP port as a SPI master controller. The driver can be configured to use any SSP port and -- cgit v1.2.3 From 48767fd8982d39d90a9e83b1461dc5feedf73e29 Mon Sep 17 00:00:00 2001 From: Naga Sureshkumar Relli Date: Tue, 8 Aug 2017 10:59:33 +0200 Subject: spi: cadence: change sequence of calling runtime_enable call pm_runtime_enable after set_active other wise it will enable clock always. Signed-off-by: Naga Sureshkumar Relli Signed-off-by: Michal Simek Signed-off-by: Mark Brown --- drivers/spi/spi-cadence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index f0b5c7b91f37..5e02f9b91688 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -576,10 +576,10 @@ static int cdns_spi_probe(struct platform_device *pdev) goto clk_dis_apb; } - pm_runtime_enable(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); ret = of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs); if (ret < 0) -- cgit v1.2.3 From 802740890c4200c9266aee3139c5bd8e9b154e8f Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Tue, 8 Aug 2017 11:00:03 +0200 Subject: spi: cadence: Add support for context loss Context could be lost across the suspend and resume. Reinit the driver to tide over. Signed-off-by: Shubhrajyoti Datta Signed-off-by: Michal Simek Signed-off-by: Mark Brown --- drivers/spi/spi-cadence.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 5e02f9b91688..5c9516ae4942 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -704,7 +704,9 @@ static int __maybe_unused cdns_spi_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct spi_master *master = platform_get_drvdata(pdev); + struct cdns_spi *xspi = spi_master_get_devdata(master); + cdns_spi_init_hw(xspi); return spi_master_resume(master); } -- cgit v1.2.3 From 9a6b94796ae6feaf275ec6200e9b2964db208182 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 7 Aug 2017 23:45:02 -0500 Subject: spi: xlp: fix error return code in xlp_spi_probe() platform_get_irq() returns an error code, but the spi-xlp driver ignores it and always returns -EINVAL. This is not correct and, prevents -EPROBE_DEFER from being propagated properly. Notice that platform_get_irq() no longer returns 0 on error: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e330b9a6bb35dc7097a4f02cb1ae7b6f96df92af Print and propagate the return value of platform_get_irq on failure. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- drivers/spi/spi-xlp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-xlp.c b/drivers/spi/spi-xlp.c index 80cb4d6af892..74a01b09a8a5 100644 --- a/drivers/spi/spi-xlp.c +++ b/drivers/spi/spi-xlp.c @@ -393,8 +393,8 @@ static int xlp_spi_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "no IRQ resource found\n"); - return -EINVAL; + dev_err(&pdev->dev, "no IRQ resource found: %d\n", irq); + return irq; } err = devm_request_irq(&pdev->dev, irq, xlp_spi_interrupt, 0, pdev->name, xspi); -- cgit v1.2.3 From ba8afe94723e9ba665aee9cca649fb2c80f7304c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 7 Aug 2017 23:52:34 -0500 Subject: spi/bcm63xx: fix error return code in bcm63xx_spi_probe() platform_get_irq() returns an error code, but the spi-bcm63xx driver ignores it and always returns -ENXIO. This is not correct and, prevents -EPROBE_DEFER from being propagated properly. Notice that platform_get_irq() no longer returns 0 on error: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e330b9a6bb35dc7097a4f02cb1ae7b6f96df92af Print and propagate the return value of platform_get_irq on failure. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- drivers/spi/spi-bcm63xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 84c7356ce5b4..bfe5754768f9 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -530,8 +530,8 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(dev, "no irq\n"); - return -ENXIO; + dev_err(dev, "no irq: %d\n", irq); + return irq; } clk = devm_clk_get(dev, "spi"); -- cgit v1.2.3 From 378da4a65f3a0390837b38145bb5d8c2d20c2cf7 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 7 Aug 2017 23:59:44 -0500 Subject: spi/bcm63xx-hspi: fix error return code in bcm63xx_hsspi_probe() platform_get_irq() returns an error code, but the spi-bcm63xx-hsspi driver ignores it and always returns -ENXIO. This is not correct and, prevents -EPROBE_DEFER from being propagated properly. Notice that platform_get_irq() no longer returns 0 on error: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e330b9a6bb35dc7097a4f02cb1ae7b6f96df92af Print and propagate the return value of platform_get_irq on failure. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- drivers/spi/spi-bcm63xx-hsspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index 4da2d4a524ca..b03fc1850ae9 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -338,8 +338,8 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(dev, "no irq\n"); - return -ENXIO; + dev_err(dev, "no irq: %d\n", irq); + return irq; } res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- cgit v1.2.3 From b702b9fb393ed1c19ab3ecb1552757522c982746 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 28 Jul 2017 12:22:48 +0530 Subject: spi: qup: Enable chip select support Enable chip select support for QUP versions later than v1. The chip select support was broken in QUP version 1. Hence the chip select support was removed earlier in an earlier commit (4a8573abe "spi: qup: Remove chip select function"). Since the chip select support is functional in recent versions of QUP, re-enabling it for QUP versions later than v1. Signed-off-by: Sham Muthayyan Signed-off-by: Varadarajan Narayanan Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 1bfa889b8427..c0d4defc1c13 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -750,6 +750,24 @@ err_tx: return ret; } +static void spi_qup_set_cs(struct spi_device *spi, bool val) +{ + struct spi_qup *controller; + u32 spi_ioc; + u32 spi_ioc_orig; + + controller = spi_master_get_devdata(spi->master); + spi_ioc = readl_relaxed(controller->base + SPI_IO_CONTROL); + spi_ioc_orig = spi_ioc; + if (!val) + spi_ioc |= SPI_IO_C_FORCE_CS; + else + spi_ioc &= ~SPI_IO_C_FORCE_CS; + + if (spi_ioc != spi_ioc_orig) + writel_relaxed(spi_ioc, controller->base + SPI_IO_CONTROL); +} + static int spi_qup_probe(struct platform_device *pdev) { struct spi_master *master; @@ -846,6 +864,9 @@ static int spi_qup_probe(struct platform_device *pdev) if (of_device_is_compatible(dev->of_node, "qcom,spi-qup-v1.1.1")) controller->qup_v1 = 1; + if (!controller->qup_v1) + master->set_cs = spi_qup_set_cs; + spin_lock_init(&controller->lock); init_completion(&controller->done); -- cgit v1.2.3 From 32ecab999f80370e5853cb907aa053ec4d64f86f Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 28 Jul 2017 12:22:49 +0530 Subject: spi: qup: Setup DMA mode correctly To operate in DMA mode, the buffer should be aligned and the size of the transfer should be a multiple of block size (for v1). And the no. of words being transferred should be programmed in the count registers appropriately. Signed-off-by: Andy Gross Signed-off-by: Varadarajan Narayanan Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 118 +++++++++++++++++++++++--------------------------- 1 file changed, 55 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index c0d4defc1c13..abe799bbc67f 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -149,11 +149,18 @@ struct spi_qup { int rx_bytes; int qup_v1; - int use_dma; + int mode; struct dma_slave_config rx_conf; struct dma_slave_config tx_conf; }; +static inline bool spi_qup_is_dma_xfer(int mode) +{ + if (mode == QUP_IO_M_MODE_DMOV || mode == QUP_IO_M_MODE_BAM) + return true; + + return false; +} static inline bool spi_qup_is_valid_state(struct spi_qup *controller) { @@ -424,7 +431,7 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) error = -EIO; } - if (!controller->use_dma) { + if (!spi_qup_is_dma_xfer(controller->mode)) { if (opflags & QUP_OP_IN_SERVICE_FLAG) spi_qup_fifo_read(controller, xfer); @@ -443,34 +450,11 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static u32 -spi_qup_get_mode(struct spi_master *master, struct spi_transfer *xfer) -{ - struct spi_qup *qup = spi_master_get_devdata(master); - u32 mode; - - qup->w_size = 4; - - if (xfer->bits_per_word <= 8) - qup->w_size = 1; - else if (xfer->bits_per_word <= 16) - qup->w_size = 2; - - qup->n_words = xfer->len / qup->w_size; - - if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32))) - mode = QUP_IO_M_MODE_FIFO; - else - mode = QUP_IO_M_MODE_BLOCK; - - return mode; -} - /* set clock freq ... bits per word */ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) { struct spi_qup *controller = spi_master_get_devdata(spi->master); - u32 config, iomode, mode, control; + u32 config, iomode, control; int ret, n_words; if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) { @@ -491,25 +475,30 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) return -EIO; } - mode = spi_qup_get_mode(spi->master, xfer); + controller->w_size = DIV_ROUND_UP(xfer->bits_per_word, 8); + controller->n_words = xfer->len / controller->w_size; n_words = controller->n_words; - if (mode == QUP_IO_M_MODE_FIFO) { + if (n_words <= (controller->in_fifo_sz / sizeof(u32))) { + + controller->mode = QUP_IO_M_MODE_FIFO; + writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT); writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT); /* must be zero for FIFO */ writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT); writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT); - } else if (!controller->use_dma) { + } else if (spi->master->can_dma && + spi->master->can_dma(spi->master, spi, xfer) && + spi->master->cur_msg_mapped) { + + controller->mode = QUP_IO_M_MODE_BAM; + writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT); writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT); /* must be zero for BLOCK and BAM */ writel_relaxed(0, controller->base + QUP_MX_READ_CNT); writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT); - } else { - mode = QUP_IO_M_MODE_BAM; - writel_relaxed(0, controller->base + QUP_MX_READ_CNT); - writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT); if (!controller->qup_v1) { void __iomem *input_cnt; @@ -528,19 +517,28 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT); } + } else { + + controller->mode = QUP_IO_M_MODE_BLOCK; + + writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT); + writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT); + /* must be zero for BLOCK and BAM */ + writel_relaxed(0, controller->base + QUP_MX_READ_CNT); + writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT); } iomode = readl_relaxed(controller->base + QUP_IO_M_MODES); /* Set input and output transfer mode */ iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK); - if (!controller->use_dma) + if (!spi_qup_is_dma_xfer(controller->mode)) iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN); else iomode |= QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN; - iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT); - iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT); + iomode |= (controller->mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT); + iomode |= (controller->mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT); writel_relaxed(iomode, controller->base + QUP_IO_M_MODES); @@ -581,7 +579,7 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) config |= xfer->bits_per_word - 1; config |= QUP_CONFIG_SPI_MODE; - if (controller->use_dma) { + if (spi_qup_is_dma_xfer(controller->mode)) { if (!xfer->tx_buf) config |= QUP_CONFIG_NO_OUTPUT; if (!xfer->rx_buf) @@ -599,7 +597,7 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) * status change in BAM mode */ - if (mode == QUP_IO_M_MODE_BAM) + if (spi_qup_is_dma_xfer(controller->mode)) mask = QUP_OP_IN_SERVICE_FLAG | QUP_OP_OUT_SERVICE_FLAG; writel_relaxed(mask, controller->base + QUP_OPERATIONAL_MASK); @@ -633,7 +631,7 @@ static int spi_qup_transfer_one(struct spi_master *master, controller->tx_bytes = 0; spin_unlock_irqrestore(&controller->lock, flags); - if (controller->use_dma) + if (spi_qup_is_dma_xfer(controller->mode)) ret = spi_qup_do_dma(master, xfer); else ret = spi_qup_do_pio(master, xfer); @@ -641,14 +639,6 @@ static int spi_qup_transfer_one(struct spi_master *master, if (ret) goto exit; - if (spi_qup_set_state(controller, QUP_STATE_RUN)) { - dev_warn(controller->dev, "cannot set EXECUTE state\n"); - goto exit; - } - - if (!wait_for_completion_timeout(&controller->done, timeout)) - ret = -ETIMEDOUT; - exit: spi_qup_set_state(controller, QUP_STATE_RESET); spin_lock_irqsave(&controller->lock, flags); @@ -657,7 +647,7 @@ exit: ret = controller->error; spin_unlock_irqrestore(&controller->lock, flags); - if (ret && controller->use_dma) + if (ret && spi_qup_is_dma_xfer(controller->mode)) spi_qup_dma_terminate(master, xfer); return ret; @@ -668,26 +658,28 @@ static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi, { struct spi_qup *qup = spi_master_get_devdata(master); size_t dma_align = dma_get_cache_alignment(); - u32 mode; - - qup->use_dma = 0; + int n_words; - if (xfer->rx_buf && (xfer->len % qup->in_blk_sz || - IS_ERR_OR_NULL(master->dma_rx) || - !IS_ALIGNED((size_t)xfer->rx_buf, dma_align))) - return false; + if (xfer->rx_buf) { + if (!IS_ALIGNED((size_t)xfer->rx_buf, dma_align) || + IS_ERR_OR_NULL(master->dma_rx)) + return false; + if (qup->qup_v1 && (xfer->len % qup->in_blk_sz)) + return false; + } - if (xfer->tx_buf && (xfer->len % qup->out_blk_sz || - IS_ERR_OR_NULL(master->dma_tx) || - !IS_ALIGNED((size_t)xfer->tx_buf, dma_align))) - return false; + if (xfer->tx_buf) { + if (!IS_ALIGNED((size_t)xfer->tx_buf, dma_align) || + IS_ERR_OR_NULL(master->dma_tx)) + return false; + if (qup->qup_v1 && (xfer->len % qup->out_blk_sz)) + return false; + } - mode = spi_qup_get_mode(master, xfer); - if (mode == QUP_IO_M_MODE_FIFO) + n_words = xfer->len / DIV_ROUND_UP(xfer->bits_per_word, 8); + if (n_words <= (qup->in_fifo_sz / sizeof(u32))) return false; - qup->use_dma = 1; - return true; } -- cgit v1.2.3 From 5f13fd60b1e709b9387877b0b65d605df9fff1d6 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 28 Jul 2017 12:22:50 +0530 Subject: spi: qup: Add completion timeout Add i/o completion timeout for DMA and PIO modes. Signed-off-by: Andy Gross Signed-off-by: Varadarajan Narayanan Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index abe799bbc67f..fdd34c3ce426 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -331,8 +331,10 @@ static void spi_qup_dma_terminate(struct spi_master *master, dmaengine_terminate_all(master->dma_rx); } -static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer) +static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer, + unsigned long timeout) { + struct spi_qup *qup = spi_master_get_devdata(master); dma_async_tx_callback rx_done = NULL, tx_done = NULL; int ret; @@ -357,10 +359,14 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer) dma_async_issue_pending(master->dma_tx); } + if (!wait_for_completion_timeout(&qup->done, timeout)) + return -ETIMEDOUT; + return 0; } -static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer) +static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer, + unsigned long timeout) { struct spi_qup *qup = spi_master_get_devdata(master); int ret; @@ -379,6 +385,9 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer) spi_qup_fifo_write(qup, xfer); + if (!wait_for_completion_timeout(&qup->done, timeout)) + return -ETIMEDOUT; + return 0; } @@ -632,9 +641,9 @@ static int spi_qup_transfer_one(struct spi_master *master, spin_unlock_irqrestore(&controller->lock, flags); if (spi_qup_is_dma_xfer(controller->mode)) - ret = spi_qup_do_dma(master, xfer); + ret = spi_qup_do_dma(master, xfer, timeout); else - ret = spi_qup_do_pio(master, xfer); + ret = spi_qup_do_pio(master, xfer, timeout); if (ret) goto exit; -- cgit v1.2.3 From ce00bab3187f9fc1afac07914959bff0c52547c2 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 28 Jul 2017 12:22:51 +0530 Subject: spi: qup: Place the QUP in run mode before DMA Signed-off-by: Andy Gross Signed-off-by: Varadarajan Narayanan Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index fdd34c3ce426..f1aa5c15d180 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -343,6 +343,14 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer, else if (xfer->tx_buf) tx_done = spi_qup_dma_done; + /* before issuing the descriptors, set the QUP to run */ + ret = spi_qup_set_state(qup, QUP_STATE_RUN); + if (ret) { + dev_warn(qup->dev, "%s(%d): cannot set RUN state\n", + __func__, __LINE__); + return ret; + } + if (xfer->rx_buf) { ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done); if (ret) @@ -385,6 +393,13 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer, spi_qup_fifo_write(qup, xfer); + ret = spi_qup_set_state(qup, QUP_STATE_RUN); + if (ret) { + dev_warn(qup->dev, "%s(%d): cannot set RUN state\n", + __func__, __LINE__); + return ret; + } + if (!wait_for_completion_timeout(&qup->done, timeout)) return -ETIMEDOUT; -- cgit v1.2.3 From d9a09a6c0c98d57e5a248c3b9bb10f63d475dfdb Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 28 Jul 2017 12:22:52 +0530 Subject: spi: qup: Fix error handling in spi_qup_prep_sg Signed-off-by: Varadarajan Narayanan Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index f1aa5c15d180..ef952946375a 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -311,8 +311,8 @@ static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer, } desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags); - if (!desc) - return -EINVAL; + if (IS_ERR_OR_NULL(desc)) + return desc ? PTR_ERR(desc) : -EINVAL; desc->callback = callback; desc->callback_param = qup; -- cgit v1.2.3 From ce7dfc71c1123a4bc7ddc628fc759ede0f58a2fe Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 28 Jul 2017 12:22:53 +0530 Subject: spi: qup: Fix transaction done signaling Wait to signal done until we get all of the interrupts we are expecting to get for a transaction. If we don't wait for the input done flag, we can be in between transactions when the done flag comes in and this can mess up the next transaction. While here cleaning up the code which sets controller->xfer = NULL and restores it in the ISR. This looks to be some debug code which is not required. Signed-off-by: Andy Gross Signed-off-by: Varadarajan Narayanan Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index ef952946375a..a7c630c4788c 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -409,29 +409,16 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer, static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) { struct spi_qup *controller = dev_id; - struct spi_transfer *xfer; + struct spi_transfer *xfer = controller->xfer; u32 opflags, qup_err, spi_err; - unsigned long flags; int error = 0; - spin_lock_irqsave(&controller->lock, flags); - xfer = controller->xfer; - controller->xfer = NULL; - spin_unlock_irqrestore(&controller->lock, flags); - qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS); spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS); opflags = readl_relaxed(controller->base + QUP_OPERATIONAL); writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS); writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS); - writel_relaxed(opflags, controller->base + QUP_OPERATIONAL); - - if (!xfer) { - dev_err_ratelimited(controller->dev, "unexpected irq %08x %08x %08x\n", - qup_err, spi_err, opflags); - return IRQ_HANDLED; - } if (qup_err) { if (qup_err & QUP_ERROR_OUTPUT_OVER_RUN) @@ -455,7 +442,9 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) error = -EIO; } - if (!spi_qup_is_dma_xfer(controller->mode)) { + if (spi_qup_is_dma_xfer(controller->mode)) { + writel_relaxed(opflags, controller->base + QUP_OPERATIONAL); + } else { if (opflags & QUP_OP_IN_SERVICE_FLAG) spi_qup_fifo_read(controller, xfer); @@ -463,12 +452,7 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) spi_qup_fifo_write(controller, xfer); } - spin_lock_irqsave(&controller->lock, flags); - controller->error = error; - controller->xfer = xfer; - spin_unlock_irqrestore(&controller->lock, flags); - - if (controller->rx_bytes == xfer->len || error) + if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error) complete(&controller->done); return IRQ_HANDLED; @@ -666,7 +650,6 @@ static int spi_qup_transfer_one(struct spi_master *master, exit: spi_qup_set_state(controller, QUP_STATE_RESET); spin_lock_irqsave(&controller->lock, flags); - controller->xfer = NULL; if (!ret) ret = controller->error; spin_unlock_irqrestore(&controller->lock, flags); -- cgit v1.2.3 From 7538726f9ddaa53b72d61116728cf2d189b05202 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 28 Jul 2017 12:22:54 +0530 Subject: spi: qup: Do block sized read/write in block mode This patch corrects the behavior of the BLOCK transactions. During block transactions, the controller must be read/written to in block size transactions. Signed-off-by: Andy Gross Signed-off-by: Varadarajan Narayanan Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 151 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 119 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index a7c630c4788c..8cfa112bb142 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -82,6 +82,8 @@ #define QUP_IO_M_MODE_BAM 3 /* QUP_OPERATIONAL fields */ +#define QUP_OP_IN_BLOCK_READ_REQ BIT(13) +#define QUP_OP_OUT_BLOCK_WRITE_REQ BIT(12) #define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11) #define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10) #define QUP_OP_IN_SERVICE_FLAG BIT(9) @@ -154,6 +156,13 @@ struct spi_qup { struct dma_slave_config tx_conf; }; +static inline bool spi_qup_is_flag_set(struct spi_qup *controller, u32 flag) +{ + u32 opflag = readl_relaxed(controller->base + QUP_OPERATIONAL); + + return (opflag & flag) != 0; +} + static inline bool spi_qup_is_dma_xfer(int mode) { if (mode == QUP_IO_M_MODE_DMOV || mode == QUP_IO_M_MODE_BAM) @@ -214,29 +223,26 @@ static int spi_qup_set_state(struct spi_qup *controller, u32 state) return 0; } -static void spi_qup_fifo_read(struct spi_qup *controller, - struct spi_transfer *xfer) +static void spi_qup_read_from_fifo(struct spi_qup *controller, + struct spi_transfer *xfer, u32 num_words) { u8 *rx_buf = xfer->rx_buf; - u32 word, state; - int idx, shift, w_size; + int i, shift, num_bytes; + u32 word; - w_size = controller->w_size; - - while (controller->rx_bytes < xfer->len) { - - state = readl_relaxed(controller->base + QUP_OPERATIONAL); - if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY)) - break; + for (; num_words; num_words--) { word = readl_relaxed(controller->base + QUP_INPUT_FIFO); + num_bytes = min_t(int, xfer->len - controller->rx_bytes, + controller->w_size); + if (!rx_buf) { - controller->rx_bytes += w_size; + controller->rx_bytes += num_bytes; continue; } - for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) { + for (i = 0; i < num_bytes; i++, controller->rx_bytes++) { /* * The data format depends on bytes per SPI word: * 4 bytes: 0x12345678 @@ -244,38 +250,80 @@ static void spi_qup_fifo_read(struct spi_qup *controller, * 1 byte : 0x00000012 */ shift = BITS_PER_BYTE; - shift *= (w_size - idx - 1); + shift *= (controller->w_size - i - 1); rx_buf[controller->rx_bytes] = word >> shift; } } } -static void spi_qup_fifo_write(struct spi_qup *controller, +static void spi_qup_read(struct spi_qup *controller, struct spi_transfer *xfer) { - const u8 *tx_buf = xfer->tx_buf; - u32 word, state, data; - int idx, w_size; + u32 remainder, words_per_block, num_words; + bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK; + + remainder = DIV_ROUND_UP(xfer->len - controller->rx_bytes, + controller->w_size); + words_per_block = controller->in_blk_sz >> 2; + + do { + /* ACK by clearing service flag */ + writel_relaxed(QUP_OP_IN_SERVICE_FLAG, + controller->base + QUP_OPERATIONAL); + + if (is_block_mode) { + num_words = (remainder > words_per_block) ? + words_per_block : remainder; + } else { + if (!spi_qup_is_flag_set(controller, + QUP_OP_IN_FIFO_NOT_EMPTY)) + break; - w_size = controller->w_size; + num_words = 1; + } - while (controller->tx_bytes < xfer->len) { + /* read up to the maximum transfer size available */ + spi_qup_read_from_fifo(controller, xfer, num_words); - state = readl_relaxed(controller->base + QUP_OPERATIONAL); - if (state & QUP_OP_OUT_FIFO_FULL) + remainder -= num_words; + + /* if block mode, check to see if next block is available */ + if (is_block_mode && !spi_qup_is_flag_set(controller, + QUP_OP_IN_BLOCK_READ_REQ)) break; + } while (remainder); + + /* + * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block + * mode reads, it has to be cleared again at the very end + */ + if (is_block_mode && spi_qup_is_flag_set(controller, + QUP_OP_MAX_INPUT_DONE_FLAG)) + writel_relaxed(QUP_OP_IN_SERVICE_FLAG, + controller->base + QUP_OPERATIONAL); + +} + +static void spi_qup_write_to_fifo(struct spi_qup *controller, + struct spi_transfer *xfer, u32 num_words) +{ + const u8 *tx_buf = xfer->tx_buf; + int i, num_bytes; + u32 word, data; + + for (; num_words; num_words--) { word = 0; - for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) { - if (!tx_buf) { - controller->tx_bytes += w_size; - break; + num_bytes = min_t(int, xfer->len - controller->tx_bytes, + controller->w_size); + if (tx_buf) + for (i = 0; i < num_bytes; i++) { + data = tx_buf[controller->tx_bytes + i]; + word |= data << (BITS_PER_BYTE * (3 - i)); } - data = tx_buf[controller->tx_bytes]; - word |= data << (BITS_PER_BYTE * (3 - idx)); - } + controller->tx_bytes += num_bytes; writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO); } @@ -288,6 +336,44 @@ static void spi_qup_dma_done(void *data) complete(&qup->done); } +static void spi_qup_write(struct spi_qup *controller, + struct spi_transfer *xfer) +{ + bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK; + u32 remainder, words_per_block, num_words; + + remainder = DIV_ROUND_UP(xfer->len - controller->tx_bytes, + controller->w_size); + words_per_block = controller->out_blk_sz >> 2; + + do { + /* ACK by clearing service flag */ + writel_relaxed(QUP_OP_OUT_SERVICE_FLAG, + controller->base + QUP_OPERATIONAL); + + if (is_block_mode) { + num_words = (remainder > words_per_block) ? + words_per_block : remainder; + } else { + if (spi_qup_is_flag_set(controller, + QUP_OP_OUT_FIFO_FULL)) + break; + + num_words = 1; + } + + spi_qup_write_to_fifo(controller, xfer, num_words); + + remainder -= num_words; + + /* if block mode, check to see if next block is available */ + if (is_block_mode && !spi_qup_is_flag_set(controller, + QUP_OP_OUT_BLOCK_WRITE_REQ)) + break; + + } while (remainder); +} + static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer, enum dma_transfer_direction dir, dma_async_tx_callback callback) @@ -391,7 +477,8 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer, return ret; } - spi_qup_fifo_write(qup, xfer); + if (qup->mode == QUP_IO_M_MODE_FIFO) + spi_qup_write(qup, xfer); ret = spi_qup_set_state(qup, QUP_STATE_RUN); if (ret) { @@ -446,10 +533,10 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) writel_relaxed(opflags, controller->base + QUP_OPERATIONAL); } else { if (opflags & QUP_OP_IN_SERVICE_FLAG) - spi_qup_fifo_read(controller, xfer); + spi_qup_read(controller, xfer); if (opflags & QUP_OP_OUT_SERVICE_FLAG) - spi_qup_fifo_write(controller, xfer); + spi_qup_write(controller, xfer); } if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error) -- cgit v1.2.3 From 94b9149febddcd367de75d2706a32183e2abbaa7 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 28 Jul 2017 12:22:55 +0530 Subject: spi: qup: refactor spi_qup_io_config into two functions This is in preparation for handling transactions larger than 64K-1 bytes in block mode, which is currently unsupported and quietly fails. We need to break these into two functions 1) prep is called once per spi_message and 2) io_config is called once per spi-qup bus transaction This is just refactoring, there should be no functional change Signed-off-by: Matthew McClintock Signed-off-by: Varadarajan Narayanan Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 91 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 8cfa112bb142..ff5aa08b5725 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -545,12 +545,11 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) return IRQ_HANDLED; } -/* set clock freq ... bits per word */ -static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) +/* set clock freq ... bits per word, determine mode */ +static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer) { struct spi_qup *controller = spi_master_get_devdata(spi->master); - u32 config, iomode, control; - int ret, n_words; + int ret; if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) { dev_err(controller->dev, "too big size for loopback %d > %d\n", @@ -565,32 +564,56 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) return -EIO; } - if (spi_qup_set_state(controller, QUP_STATE_RESET)) { - dev_err(controller->dev, "cannot set RESET state\n"); - return -EIO; - } - controller->w_size = DIV_ROUND_UP(xfer->bits_per_word, 8); controller->n_words = xfer->len / controller->w_size; - n_words = controller->n_words; - - if (n_words <= (controller->in_fifo_sz / sizeof(u32))) { + if (controller->n_words <= (controller->in_fifo_sz / sizeof(u32))) controller->mode = QUP_IO_M_MODE_FIFO; + else if (spi->master->can_dma && + spi->master->can_dma(spi->master, spi, xfer) && + spi->master->cur_msg_mapped) + controller->mode = QUP_IO_M_MODE_BAM; + else + controller->mode = QUP_IO_M_MODE_BLOCK; + + return 0; +} + +/* prep qup for another spi transaction of specific type */ +static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) +{ + struct spi_qup *controller = spi_master_get_devdata(spi->master); + u32 config, iomode, control; + unsigned long flags; + + spin_lock_irqsave(&controller->lock, flags); + controller->xfer = xfer; + controller->error = 0; + controller->rx_bytes = 0; + controller->tx_bytes = 0; + spin_unlock_irqrestore(&controller->lock, flags); + + + if (spi_qup_set_state(controller, QUP_STATE_RESET)) { + dev_err(controller->dev, "cannot set RESET state\n"); + return -EIO; + } - writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT); - writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT); + switch (controller->mode) { + case QUP_IO_M_MODE_FIFO: + writel_relaxed(controller->n_words, + controller->base + QUP_MX_READ_CNT); + writel_relaxed(controller->n_words, + controller->base + QUP_MX_WRITE_CNT); /* must be zero for FIFO */ writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT); writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT); - } else if (spi->master->can_dma && - spi->master->can_dma(spi->master, spi, xfer) && - spi->master->cur_msg_mapped) { - - controller->mode = QUP_IO_M_MODE_BAM; - - writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT); - writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT); + break; + case QUP_IO_M_MODE_BAM: + writel_relaxed(controller->n_words, + controller->base + QUP_MX_INPUT_CNT); + writel_relaxed(controller->n_words, + controller->base + QUP_MX_OUTPUT_CNT); /* must be zero for BLOCK and BAM */ writel_relaxed(0, controller->base + QUP_MX_READ_CNT); writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT); @@ -608,19 +631,25 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) if (xfer->tx_buf) writel_relaxed(0, input_cnt); else - writel_relaxed(n_words, input_cnt); + writel_relaxed(controller->n_words, input_cnt); writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT); } - } else { - - controller->mode = QUP_IO_M_MODE_BLOCK; - - writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT); - writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT); + break; + case QUP_IO_M_MODE_BLOCK: + reinit_completion(&controller->done); + writel_relaxed(controller->n_words, + controller->base + QUP_MX_INPUT_CNT); + writel_relaxed(controller->n_words, + controller->base + QUP_MX_OUTPUT_CNT); /* must be zero for BLOCK and BAM */ writel_relaxed(0, controller->base + QUP_MX_READ_CNT); writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT); + break; + default: + dev_err(controller->dev, "unknown mode = %d\n", + controller->mode); + return -EIO; } iomode = readl_relaxed(controller->base + QUP_IO_M_MODES); @@ -709,6 +738,10 @@ static int spi_qup_transfer_one(struct spi_master *master, unsigned long timeout, flags; int ret = -EIO; + ret = spi_qup_io_prep(spi, xfer); + if (ret) + return ret; + ret = spi_qup_io_config(spi, xfer); if (ret) return ret; -- cgit v1.2.3 From 3b5ea2c981dd470882bdc83e548dd15a942dbf4d Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 28 Jul 2017 12:22:56 +0530 Subject: spi: qup: call io_config in mode specific function DMA transactions should only only need to call io_config only once, but block mode might call it several times to setup several transactions so it can handle reads/writes larger than the max size per transaction, so we move the call to the do_ functions. This is just refactoring, there should be no functional change Signed-off-by: Matthew McClintock Signed-off-by: Varadarajan Narayanan Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index ff5aa08b5725..1aa60785bf98 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -156,6 +156,8 @@ struct spi_qup { struct dma_slave_config tx_conf; }; +static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer); + static inline bool spi_qup_is_flag_set(struct spi_qup *controller, u32 flag) { u32 opflag = readl_relaxed(controller->base + QUP_OPERATIONAL); @@ -417,11 +419,12 @@ static void spi_qup_dma_terminate(struct spi_master *master, dmaengine_terminate_all(master->dma_rx); } -static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer, +static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer, unsigned long timeout) { - struct spi_qup *qup = spi_master_get_devdata(master); dma_async_tx_callback rx_done = NULL, tx_done = NULL; + struct spi_master *master = spi->master; + struct spi_qup *qup = spi_master_get_devdata(master); int ret; if (xfer->rx_buf) @@ -429,6 +432,10 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer, else if (xfer->tx_buf) tx_done = spi_qup_dma_done; + ret = spi_qup_io_config(spi, xfer); + if (ret) + return ret; + /* before issuing the descriptors, set the QUP to run */ ret = spi_qup_set_state(qup, QUP_STATE_RUN); if (ret) { @@ -459,12 +466,17 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer, return 0; } -static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer, +static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer, unsigned long timeout) { + struct spi_master *master = spi->master; struct spi_qup *qup = spi_master_get_devdata(master); int ret; + ret = spi_qup_io_config(spi, xfer); + if (ret) + return ret; + ret = spi_qup_set_state(qup, QUP_STATE_RUN); if (ret) { dev_warn(qup->dev, "cannot set RUN state\n"); @@ -742,10 +754,6 @@ static int spi_qup_transfer_one(struct spi_master *master, if (ret) return ret; - ret = spi_qup_io_config(spi, xfer); - if (ret) - return ret; - timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC); timeout = DIV_ROUND_UP(xfer->len * 8, timeout); timeout = 100 * msecs_to_jiffies(timeout); @@ -760,9 +768,9 @@ static int spi_qup_transfer_one(struct spi_master *master, spin_unlock_irqrestore(&controller->lock, flags); if (spi_qup_is_dma_xfer(controller->mode)) - ret = spi_qup_do_dma(master, xfer, timeout); + ret = spi_qup_do_dma(spi, xfer, timeout); else - ret = spi_qup_do_pio(master, xfer, timeout); + ret = spi_qup_do_pio(spi, xfer, timeout); if (ret) goto exit; -- cgit v1.2.3 From 5dc47fefe1d470da47dd400796bbf93ffe82fd33 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 28 Jul 2017 12:22:57 +0530 Subject: spi: qup: allow block mode to generate multiple transactions This let's you write more to the SPI bus than 64K-1 which is important if the block size of a SPI device is >= 64K or some other device wants to do something larger. This has the benefit of completely removing spi_message from the spi-qup transactions Signed-off-by: Matthew McClintock Signed-off-by: Varadarajan Narayanan Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 128 +++++++++++++++++++++++++++++++------------------- 1 file changed, 80 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 1aa60785bf98..707b1ec427fa 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -120,7 +120,7 @@ #define SPI_NUM_CHIPSELECTS 4 -#define SPI_MAX_DMA_XFER (SZ_64K - 64) +#define SPI_MAX_XFER (SZ_64K - 64) /* high speed mode is when bus rate is greater then 26MHz */ #define SPI_HS_MIN_RATE 26000000 @@ -149,6 +149,8 @@ struct spi_qup { int n_words; int tx_bytes; int rx_bytes; + const u8 *tx_buf; + u8 *rx_buf; int qup_v1; int mode; @@ -173,6 +175,12 @@ static inline bool spi_qup_is_dma_xfer(int mode) return false; } +/* get's the transaction size length */ +static inline unsigned int spi_qup_len(struct spi_qup *controller) +{ + return controller->n_words * controller->w_size; +} + static inline bool spi_qup_is_valid_state(struct spi_qup *controller) { u32 opstate = readl_relaxed(controller->base + QUP_STATE); @@ -225,10 +233,9 @@ static int spi_qup_set_state(struct spi_qup *controller, u32 state) return 0; } -static void spi_qup_read_from_fifo(struct spi_qup *controller, - struct spi_transfer *xfer, u32 num_words) +static void spi_qup_read_from_fifo(struct spi_qup *controller, u32 num_words) { - u8 *rx_buf = xfer->rx_buf; + u8 *rx_buf = controller->rx_buf; int i, shift, num_bytes; u32 word; @@ -236,8 +243,9 @@ static void spi_qup_read_from_fifo(struct spi_qup *controller, word = readl_relaxed(controller->base + QUP_INPUT_FIFO); - num_bytes = min_t(int, xfer->len - controller->rx_bytes, - controller->w_size); + num_bytes = min_t(int, spi_qup_len(controller) - + controller->rx_bytes, + controller->w_size); if (!rx_buf) { controller->rx_bytes += num_bytes; @@ -258,13 +266,12 @@ static void spi_qup_read_from_fifo(struct spi_qup *controller, } } -static void spi_qup_read(struct spi_qup *controller, - struct spi_transfer *xfer) +static void spi_qup_read(struct spi_qup *controller) { u32 remainder, words_per_block, num_words; bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK; - remainder = DIV_ROUND_UP(xfer->len - controller->rx_bytes, + remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->rx_bytes, controller->w_size); words_per_block = controller->in_blk_sz >> 2; @@ -285,7 +292,7 @@ static void spi_qup_read(struct spi_qup *controller, } /* read up to the maximum transfer size available */ - spi_qup_read_from_fifo(controller, xfer, num_words); + spi_qup_read_from_fifo(controller, num_words); remainder -= num_words; @@ -307,18 +314,18 @@ static void spi_qup_read(struct spi_qup *controller, } -static void spi_qup_write_to_fifo(struct spi_qup *controller, - struct spi_transfer *xfer, u32 num_words) +static void spi_qup_write_to_fifo(struct spi_qup *controller, u32 num_words) { - const u8 *tx_buf = xfer->tx_buf; + const u8 *tx_buf = controller->tx_buf; int i, num_bytes; u32 word, data; for (; num_words; num_words--) { word = 0; - num_bytes = min_t(int, xfer->len - controller->tx_bytes, - controller->w_size); + num_bytes = min_t(int, spi_qup_len(controller) - + controller->tx_bytes, + controller->w_size); if (tx_buf) for (i = 0; i < num_bytes; i++) { data = tx_buf[controller->tx_bytes + i]; @@ -338,13 +345,12 @@ static void spi_qup_dma_done(void *data) complete(&qup->done); } -static void spi_qup_write(struct spi_qup *controller, - struct spi_transfer *xfer) +static void spi_qup_write(struct spi_qup *controller) { bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK; u32 remainder, words_per_block, num_words; - remainder = DIV_ROUND_UP(xfer->len - controller->tx_bytes, + remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->tx_bytes, controller->w_size); words_per_block = controller->out_blk_sz >> 2; @@ -364,7 +370,7 @@ static void spi_qup_write(struct spi_qup *controller, num_words = 1; } - spi_qup_write_to_fifo(controller, xfer, num_words); + spi_qup_write_to_fifo(controller, num_words); remainder -= num_words; @@ -471,36 +477,62 @@ static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer, { struct spi_master *master = spi->master; struct spi_qup *qup = spi_master_get_devdata(master); - int ret; + int ret, n_words, iterations, offset = 0; - ret = spi_qup_io_config(spi, xfer); - if (ret) - return ret; + n_words = qup->n_words; + iterations = n_words / SPI_MAX_XFER; /* round down */ + qup->rx_buf = xfer->rx_buf; + qup->tx_buf = xfer->tx_buf; - ret = spi_qup_set_state(qup, QUP_STATE_RUN); - if (ret) { - dev_warn(qup->dev, "cannot set RUN state\n"); - return ret; - } + do { + if (iterations) + qup->n_words = SPI_MAX_XFER; + else + qup->n_words = n_words % SPI_MAX_XFER; - ret = spi_qup_set_state(qup, QUP_STATE_PAUSE); - if (ret) { - dev_warn(qup->dev, "cannot set PAUSE state\n"); - return ret; - } + if (qup->tx_buf && offset) + qup->tx_buf = xfer->tx_buf + offset * SPI_MAX_XFER; - if (qup->mode == QUP_IO_M_MODE_FIFO) - spi_qup_write(qup, xfer); + if (qup->rx_buf && offset) + qup->rx_buf = xfer->rx_buf + offset * SPI_MAX_XFER; - ret = spi_qup_set_state(qup, QUP_STATE_RUN); - if (ret) { - dev_warn(qup->dev, "%s(%d): cannot set RUN state\n", - __func__, __LINE__); - return ret; - } + /* + * if the transaction is small enough, we need + * to fallback to FIFO mode + */ + if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32))) + qup->mode = QUP_IO_M_MODE_FIFO; - if (!wait_for_completion_timeout(&qup->done, timeout)) - return -ETIMEDOUT; + ret = spi_qup_io_config(spi, xfer); + if (ret) + return ret; + + ret = spi_qup_set_state(qup, QUP_STATE_RUN); + if (ret) { + dev_warn(qup->dev, "cannot set RUN state\n"); + return ret; + } + + ret = spi_qup_set_state(qup, QUP_STATE_PAUSE); + if (ret) { + dev_warn(qup->dev, "cannot set PAUSE state\n"); + return ret; + } + + if (qup->mode == QUP_IO_M_MODE_FIFO) + spi_qup_write(qup); + + ret = spi_qup_set_state(qup, QUP_STATE_RUN); + if (ret) { + dev_warn(qup->dev, "cannot set RUN state\n"); + return ret; + } + + if (!wait_for_completion_timeout(&qup->done, timeout)) + return -ETIMEDOUT; + + offset++; + } while (iterations--); return 0; } @@ -508,7 +540,6 @@ static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer, static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) { struct spi_qup *controller = dev_id; - struct spi_transfer *xfer = controller->xfer; u32 opflags, qup_err, spi_err; int error = 0; @@ -545,10 +576,10 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) writel_relaxed(opflags, controller->base + QUP_OPERATIONAL); } else { if (opflags & QUP_OP_IN_SERVICE_FLAG) - spi_qup_read(controller, xfer); + spi_qup_read(controller); if (opflags & QUP_OP_OUT_SERVICE_FLAG) - spi_qup_write(controller, xfer); + spi_qup_write(controller); } if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error) @@ -755,7 +786,8 @@ static int spi_qup_transfer_one(struct spi_master *master, return ret; timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC); - timeout = DIV_ROUND_UP(xfer->len * 8, timeout); + timeout = DIV_ROUND_UP(min_t(unsigned long, SPI_MAX_XFER, + xfer->len) * 8, timeout); timeout = 100 * msecs_to_jiffies(timeout); reinit_completion(&controller->done); @@ -969,7 +1001,7 @@ static int spi_qup_probe(struct platform_device *pdev) master->dev.of_node = pdev->dev.of_node; master->auto_runtime_pm = true; master->dma_alignment = dma_get_cache_alignment(); - master->max_dma_len = SPI_MAX_DMA_XFER; + master->max_dma_len = SPI_MAX_XFER; platform_set_drvdata(pdev, master); -- cgit v1.2.3 From a841b24e627ca2d3b6a23ca00a4908bfe8f3a5ef Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 28 Jul 2017 12:22:58 +0530 Subject: spi: qup: refactor spi_qup_prep_sg Take specific sgl and nent to be prepared. This is in preparation for splitting DMA into multiple transacations, this contains no code changes just refactoring. Signed-off-by: Matthew McClintock Signed-off-by: Varadarajan Narayanan Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 707b1ec427fa..1af3b41ac12d 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -382,27 +382,20 @@ static void spi_qup_write(struct spi_qup *controller) } while (remainder); } -static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer, - enum dma_transfer_direction dir, +static int spi_qup_prep_sg(struct spi_master *master, struct scatterlist *sgl, + unsigned int nents, enum dma_transfer_direction dir, dma_async_tx_callback callback) { struct spi_qup *qup = spi_master_get_devdata(master); unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE; struct dma_async_tx_descriptor *desc; - struct scatterlist *sgl; struct dma_chan *chan; dma_cookie_t cookie; - unsigned int nents; - if (dir == DMA_MEM_TO_DEV) { + if (dir == DMA_MEM_TO_DEV) chan = master->dma_tx; - nents = xfer->tx_sg.nents; - sgl = xfer->tx_sg.sgl; - } else { + else chan = master->dma_rx; - nents = xfer->rx_sg.nents; - sgl = xfer->rx_sg.sgl; - } desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags); if (IS_ERR_OR_NULL(desc)) @@ -451,7 +444,9 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer, } if (xfer->rx_buf) { - ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done); + ret = spi_qup_prep_sg(master, xfer->rx_sg.sgl, + xfer->rx_sg.nents, DMA_DEV_TO_MEM, + rx_done); if (ret) return ret; @@ -459,7 +454,9 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer, } if (xfer->tx_buf) { - ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV, tx_done); + ret = spi_qup_prep_sg(master, xfer->tx_sg.sgl, + xfer->tx_sg.nents, DMA_MEM_TO_DEV, + tx_done); if (ret) return ret; -- cgit v1.2.3 From 5884e17ef3cb3dac2e83e466246cf033bfba0e2f Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 28 Jul 2017 12:22:59 +0530 Subject: spi: qup: allow multiple DMA transactions per spi xfer Much like the block mode changes, we are breaking up DMA transactions into 64K chunks so we can reset the QUP engine. Signed-off-by: Matthew McClintock Signed-off-by: Varadarajan Narayanan Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 92 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 1af3b41ac12d..3c2c2c0ed9ab 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -418,12 +418,35 @@ static void spi_qup_dma_terminate(struct spi_master *master, dmaengine_terminate_all(master->dma_rx); } +static u32 spi_qup_sgl_get_nents_len(struct scatterlist *sgl, u32 max, + u32 *nents) +{ + struct scatterlist *sg; + u32 total = 0; + + *nents = 0; + + for (sg = sgl; sg; sg = sg_next(sg)) { + unsigned int len = sg_dma_len(sg); + + /* check for overflow as well as limit */ + if (((total + len) < total) || ((total + len) > max)) + break; + + total += len; + (*nents)++; + } + + return total; +} + static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer, unsigned long timeout) { dma_async_tx_callback rx_done = NULL, tx_done = NULL; struct spi_master *master = spi->master; struct spi_qup *qup = spi_master_get_devdata(master); + struct scatterlist *tx_sgl, *rx_sgl; int ret; if (xfer->rx_buf) @@ -431,40 +454,57 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer, else if (xfer->tx_buf) tx_done = spi_qup_dma_done; - ret = spi_qup_io_config(spi, xfer); - if (ret) - return ret; + rx_sgl = xfer->rx_sg.sgl; + tx_sgl = xfer->tx_sg.sgl; - /* before issuing the descriptors, set the QUP to run */ - ret = spi_qup_set_state(qup, QUP_STATE_RUN); - if (ret) { - dev_warn(qup->dev, "%s(%d): cannot set RUN state\n", - __func__, __LINE__); - return ret; - } + do { + u32 rx_nents, tx_nents; + + if (rx_sgl) + qup->n_words = spi_qup_sgl_get_nents_len(rx_sgl, + SPI_MAX_XFER, &rx_nents) / qup->w_size; + if (tx_sgl) + qup->n_words = spi_qup_sgl_get_nents_len(tx_sgl, + SPI_MAX_XFER, &tx_nents) / qup->w_size; + if (!qup->n_words) + return -EIO; - if (xfer->rx_buf) { - ret = spi_qup_prep_sg(master, xfer->rx_sg.sgl, - xfer->rx_sg.nents, DMA_DEV_TO_MEM, - rx_done); + ret = spi_qup_io_config(spi, xfer); if (ret) return ret; - dma_async_issue_pending(master->dma_rx); - } - - if (xfer->tx_buf) { - ret = spi_qup_prep_sg(master, xfer->tx_sg.sgl, - xfer->tx_sg.nents, DMA_MEM_TO_DEV, - tx_done); - if (ret) + /* before issuing the descriptors, set the QUP to run */ + ret = spi_qup_set_state(qup, QUP_STATE_RUN); + if (ret) { + dev_warn(qup->dev, "cannot set RUN state\n"); return ret; + } + if (rx_sgl) { + ret = spi_qup_prep_sg(master, rx_sgl, rx_nents, + DMA_DEV_TO_MEM, rx_done); + if (ret) + return ret; + dma_async_issue_pending(master->dma_rx); + } - dma_async_issue_pending(master->dma_tx); - } + if (tx_sgl) { + ret = spi_qup_prep_sg(master, tx_sgl, tx_nents, + DMA_MEM_TO_DEV, tx_done); + if (ret) + return ret; + + dma_async_issue_pending(master->dma_tx); + } + + if (!wait_for_completion_timeout(&qup->done, timeout)) + return -ETIMEDOUT; + + for (; rx_sgl && rx_nents--; rx_sgl = sg_next(rx_sgl)) + ; + for (; tx_sgl && tx_nents--; tx_sgl = sg_next(tx_sgl)) + ; - if (!wait_for_completion_timeout(&qup->done, timeout)) - return -ETIMEDOUT; + } while (rx_sgl || tx_sgl); return 0; } -- cgit v1.2.3 From cd595b99af24b8efa4a6a8889ad65f4d270fd644 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 28 Jul 2017 12:23:00 +0530 Subject: spi: qup: Ensure done detection This patch fixes an issue where a SPI transaction has completed, but the done condition is missed. This occurs because at the time of interrupt the MAX_INPUT_DONE_FLAG is not asserted. However, in the process of reading blocks of data from the FIFO, the last portion of data comes in. The opflags read at the beginning of the irq handler no longer matches the current opflag state. To get around this condition, the block read function should update the opflags so that done detection is correct after the return. Signed-off-by: Andy Gross Signed-off-by: Abhishek Sahu Signed-off-by: Varadarajan Narayanan Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 3c2c2c0ed9ab..4c3c938360f4 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -266,7 +266,7 @@ static void spi_qup_read_from_fifo(struct spi_qup *controller, u32 num_words) } } -static void spi_qup_read(struct spi_qup *controller) +static void spi_qup_read(struct spi_qup *controller, u32 *opflags) { u32 remainder, words_per_block, num_words; bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK; @@ -305,10 +305,12 @@ static void spi_qup_read(struct spi_qup *controller) /* * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block - * mode reads, it has to be cleared again at the very end + * reads, it has to be cleared again at the very end. However, be sure + * to refresh opflags value because MAX_INPUT_DONE_FLAG may now be + * present and this is used to determine if transaction is complete */ - if (is_block_mode && spi_qup_is_flag_set(controller, - QUP_OP_MAX_INPUT_DONE_FLAG)) + *opflags = readl_relaxed(controller->base + QUP_OPERATIONAL); + if (is_block_mode && *opflags & QUP_OP_MAX_INPUT_DONE_FLAG) writel_relaxed(QUP_OP_IN_SERVICE_FLAG, controller->base + QUP_OPERATIONAL); @@ -613,7 +615,7 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) writel_relaxed(opflags, controller->base + QUP_OPERATIONAL); } else { if (opflags & QUP_OP_IN_SERVICE_FLAG) - spi_qup_read(controller); + spi_qup_read(controller, &opflags); if (opflags & QUP_OP_OUT_SERVICE_FLAG) spi_qup_write(controller); -- cgit v1.2.3 From 4d023737b2efcaac36e4e6bbfdce3a3b377f3946 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 28 Jul 2017 12:23:01 +0530 Subject: spi: qup: Fix QUP version identify method Use of_device_get_match_data to identify QUP version instead of of_device_is_compatible. Signed-off-by: Varadarajan Narayanan Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 4c3c938360f4..1364516e87c2 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1058,9 +1059,7 @@ static int spi_qup_probe(struct platform_device *pdev) else if (!ret) master->can_dma = spi_qup_can_dma; - /* set v1 flag if device is version 1 */ - if (of_device_is_compatible(dev->of_node, "qcom,spi-qup-v1.1.1")) - controller->qup_v1 = 1; + controller->qup_v1 = (int)of_device_get_match_data(dev); if (!controller->qup_v1) master->set_cs = spi_qup_set_cs; @@ -1256,7 +1255,7 @@ static int spi_qup_remove(struct platform_device *pdev) } static const struct of_device_id spi_qup_dt_match[] = { - { .compatible = "qcom,spi-qup-v1.1.1", }, + { .compatible = "qcom,spi-qup-v1.1.1", .data = (void *)1, }, { .compatible = "qcom,spi-qup-v2.1.1", }, { .compatible = "qcom,spi-qup-v2.2.1", }, { } -- cgit v1.2.3 From 345fef75d7c55e63f7a109f7a26ff35718c5f028 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 9 Aug 2017 10:46:48 -0500 Subject: spi: spi-sh: fix error return code in spi_sh_probe() platform_get_irq() returns an error code, but the spi-sh driver ignores it and always returns -ENODEV. This is not correct and, prevents -EPROBE_DEFER from being propagated properly. Print and propagate the return value of platform_get_irq on failure. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- drivers/spi/spi-sh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c index 2bf53f0e27d9..50e0ea9acf8b 100644 --- a/drivers/spi/spi-sh.c +++ b/drivers/spi/spi-sh.c @@ -446,8 +446,8 @@ static int spi_sh_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "platform_get_irq error\n"); - return -ENODEV; + dev_err(&pdev->dev, "platform_get_irq error: %d\n", irq); + return irq; } master = spi_alloc_master(&pdev->dev, sizeof(struct spi_sh_data)); -- cgit v1.2.3 From 1232978a0dff2d361c3d43cd74e46200c9933466 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 9 Aug 2017 08:51:25 +1200 Subject: spi: spi-ep93xx: remove io wrappers The io wrappers just add obfuscation to the driver. Remove them. Signed-off-by: H Hartley Sweeten Signed-off-by: Chris Packham Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 72 +++++++++++++++++------------------------------- 1 file changed, 25 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index b5d766064b7b..49c42a6c2be1 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -72,7 +72,7 @@ * struct ep93xx_spi - EP93xx SPI controller structure * @pdev: pointer to platform device * @clk: clock for the controller - * @regs_base: pointer to ioremap()'d registers + * @mmio: pointer to ioremap()'d registers * @sspdr_phys: physical address of the SSPDR register * @wait: wait here until given transfer is completed * @current_msg: message that is currently processed (or %NULL if none) @@ -92,7 +92,7 @@ struct ep93xx_spi { const struct platform_device *pdev; struct clk *clk; - void __iomem *regs_base; + void __iomem *mmio; unsigned long sspdr_phys; struct completion wait; struct spi_message *current_msg; @@ -111,28 +111,6 @@ struct ep93xx_spi { /* converts bits per word to CR0.DSS value */ #define bits_per_word_to_dss(bpw) ((bpw) - 1) -static void ep93xx_spi_write_u8(const struct ep93xx_spi *espi, - u16 reg, u8 value) -{ - writeb(value, espi->regs_base + reg); -} - -static u8 ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg) -{ - return readb(spi->regs_base + reg); -} - -static void ep93xx_spi_write_u16(const struct ep93xx_spi *espi, - u16 reg, u16 value) -{ - writew(value, espi->regs_base + reg); -} - -static u16 ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg) -{ - return readw(spi->regs_base + reg); -} - static int ep93xx_spi_enable(const struct ep93xx_spi *espi) { u8 regval; @@ -142,9 +120,9 @@ static int ep93xx_spi_enable(const struct ep93xx_spi *espi) if (err) return err; - regval = ep93xx_spi_read_u8(espi, SSPCR1); + regval = readb(espi->mmio + SSPCR1); regval |= SSPCR1_SSE; - ep93xx_spi_write_u8(espi, SSPCR1, regval); + writeb(regval, espi->mmio + SSPCR1); return 0; } @@ -153,9 +131,9 @@ static void ep93xx_spi_disable(const struct ep93xx_spi *espi) { u8 regval; - regval = ep93xx_spi_read_u8(espi, SSPCR1); + regval = readb(espi->mmio + SSPCR1); regval &= ~SSPCR1_SSE; - ep93xx_spi_write_u8(espi, SSPCR1, regval); + writeb(regval, espi->mmio + SSPCR1); clk_disable(espi->clk); } @@ -164,18 +142,18 @@ static void ep93xx_spi_enable_interrupts(const struct ep93xx_spi *espi) { u8 regval; - regval = ep93xx_spi_read_u8(espi, SSPCR1); + regval = readb(espi->mmio + SSPCR1); regval |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE); - ep93xx_spi_write_u8(espi, SSPCR1, regval); + writeb(regval, espi->mmio + SSPCR1); } static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi) { u8 regval; - regval = ep93xx_spi_read_u8(espi, SSPCR1); + regval = readb(espi->mmio + SSPCR1); regval &= ~(SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE); - ep93xx_spi_write_u8(espi, SSPCR1, regval); + writeb(regval, espi->mmio + SSPCR1); } /** @@ -252,8 +230,8 @@ static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi, spi->mode, div_cpsr, div_scr, dss); dev_dbg(&espi->pdev->dev, "setup: cr0 %#x\n", cr0); - ep93xx_spi_write_u8(espi, SSPCPSR, div_cpsr); - ep93xx_spi_write_u16(espi, SSPCR0, cr0); + writeb(div_cpsr, espi->mmio + SSPCPSR); + writew(cr0, espi->mmio + SSPCR0); return 0; } @@ -265,14 +243,14 @@ static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t) if (t->tx_buf) tx_val = ((u16 *)t->tx_buf)[espi->tx]; - ep93xx_spi_write_u16(espi, SSPDR, tx_val); + writew(tx_val, espi->mmio + SSPDR); espi->tx += sizeof(tx_val); } else { u8 tx_val = 0; if (t->tx_buf) tx_val = ((u8 *)t->tx_buf)[espi->tx]; - ep93xx_spi_write_u8(espi, SSPDR, tx_val); + writeb(tx_val, espi->mmio + SSPDR); espi->tx += sizeof(tx_val); } } @@ -282,14 +260,14 @@ static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t) if (t->bits_per_word > 8) { u16 rx_val; - rx_val = ep93xx_spi_read_u16(espi, SSPDR); + rx_val = readw(espi->mmio + SSPDR); if (t->rx_buf) ((u16 *)t->rx_buf)[espi->rx] = rx_val; espi->rx += sizeof(rx_val); } else { u8 rx_val; - rx_val = ep93xx_spi_read_u8(espi, SSPDR); + rx_val = readb(espi->mmio + SSPDR); if (t->rx_buf) ((u8 *)t->rx_buf)[espi->rx] = rx_val; espi->rx += sizeof(rx_val); @@ -313,7 +291,7 @@ static int ep93xx_spi_read_write(struct ep93xx_spi *espi) struct spi_transfer *t = msg->state; /* read as long as RX FIFO has frames in it */ - while ((ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE)) { + while ((readb(espi->mmio + SSPSR) & SSPSR_RNE)) { ep93xx_do_read(espi, t); espi->fifo_level--; } @@ -615,14 +593,14 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi, * Just to be sure: flush any data from RX FIFO. */ timeout = jiffies + msecs_to_jiffies(SPI_TIMEOUT); - while (ep93xx_spi_read_u16(espi, SSPSR) & SSPSR_RNE) { + while (readw(espi->mmio + SSPSR) & SSPSR_RNE) { if (time_after(jiffies, timeout)) { dev_warn(&espi->pdev->dev, "timeout while flushing RX FIFO\n"); msg->status = -ETIMEDOUT; return; } - ep93xx_spi_read_u16(espi, SSPDR); + readw(espi->mmio + SSPDR); } /* @@ -671,7 +649,7 @@ static int ep93xx_spi_transfer_one_message(struct spi_master *master, static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id) { struct ep93xx_spi *espi = dev_id; - u8 irq_status = ep93xx_spi_read_u8(espi, SSPIIR); + u8 irq_status = readb(espi->mmio + SSPIIR); /* * If we got ROR (receive overrun) interrupt we know that something is @@ -679,7 +657,7 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id) */ if (unlikely(irq_status & SSPIIR_RORIS)) { /* clear the overrun interrupt */ - ep93xx_spi_write_u8(espi, SSPICR, 0); + writeb(0, espi->mmio + SSPICR); dev_warn(&espi->pdev->dev, "receive overrun, aborting the message\n"); espi->current_msg->status = -EIO; @@ -862,9 +840,9 @@ static int ep93xx_spi_probe(struct platform_device *pdev) espi->sspdr_phys = res->start + SSPDR; - espi->regs_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(espi->regs_base)) { - error = PTR_ERR(espi->regs_base); + espi->mmio = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(espi->mmio)) { + error = PTR_ERR(espi->mmio); goto fail_release_master; } @@ -879,7 +857,7 @@ static int ep93xx_spi_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "DMA setup failed. Falling back to PIO\n"); /* make sure that the hardware is disabled */ - ep93xx_spi_write_u8(espi, SSPCR1, 0); + writeb(0, espi->mmio + SSPCR1); error = devm_spi_register_master(&pdev->dev, master); if (error) { -- cgit v1.2.3 From 8447e4781f033f56cb18c2ec0301ea5d207877fc Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 9 Aug 2017 08:51:26 +1200 Subject: spi: spi-ep93xx: use 32-bit read/write for all registers All the EP93xx SSP registers are 32-bit. Since most of the upper bits are unused, this driver tries to be tricky and uses 8 or 16-bit I/O to access the registers. This really just adds a bit of confusion. Simplify the I/O by using 32-bit read/write's for all of the registers. Signed-off-by: H Hartley Sweeten [chris: use u32 instead of unsigned int] Signed-off-by: Chris Packham Reviewed-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 83 ++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 49c42a6c2be1..0bd792020471 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -113,47 +113,47 @@ struct ep93xx_spi { static int ep93xx_spi_enable(const struct ep93xx_spi *espi) { - u8 regval; + u32 val; int err; err = clk_enable(espi->clk); if (err) return err; - regval = readb(espi->mmio + SSPCR1); - regval |= SSPCR1_SSE; - writeb(regval, espi->mmio + SSPCR1); + val = readl(espi->mmio + SSPCR1); + val |= SSPCR1_SSE; + writel(val, espi->mmio + SSPCR1); return 0; } static void ep93xx_spi_disable(const struct ep93xx_spi *espi) { - u8 regval; + u32 val; - regval = readb(espi->mmio + SSPCR1); - regval &= ~SSPCR1_SSE; - writeb(regval, espi->mmio + SSPCR1); + val = readl(espi->mmio + SSPCR1); + val &= ~SSPCR1_SSE; + writel(val, espi->mmio + SSPCR1); clk_disable(espi->clk); } static void ep93xx_spi_enable_interrupts(const struct ep93xx_spi *espi) { - u8 regval; + u32 val; - regval = readb(espi->mmio + SSPCR1); - regval |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE); - writeb(regval, espi->mmio + SSPCR1); + val = readl(espi->mmio + SSPCR1); + val |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE); + writel(val, espi->mmio + SSPCR1); } static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi) { - u8 regval; + u32 val; - regval = readb(espi->mmio + SSPCR1); - regval &= ~(SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE); - writeb(regval, espi->mmio + SSPCR1); + val = readl(espi->mmio + SSPCR1); + val &= ~(SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE); + writel(val, espi->mmio + SSPCR1); } /** @@ -230,47 +230,41 @@ static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi, spi->mode, div_cpsr, div_scr, dss); dev_dbg(&espi->pdev->dev, "setup: cr0 %#x\n", cr0); - writeb(div_cpsr, espi->mmio + SSPCPSR); - writew(cr0, espi->mmio + SSPCR0); + writel(div_cpsr, espi->mmio + SSPCPSR); + writel(cr0, espi->mmio + SSPCR0); return 0; } static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t) { - if (t->bits_per_word > 8) { - u16 tx_val = 0; + u32 val = 0; + if (t->bits_per_word > 8) { if (t->tx_buf) - tx_val = ((u16 *)t->tx_buf)[espi->tx]; - writew(tx_val, espi->mmio + SSPDR); - espi->tx += sizeof(tx_val); + val = ((u16 *)t->tx_buf)[espi->tx]; + espi->tx += 2; } else { - u8 tx_val = 0; - if (t->tx_buf) - tx_val = ((u8 *)t->tx_buf)[espi->tx]; - writeb(tx_val, espi->mmio + SSPDR); - espi->tx += sizeof(tx_val); + val = ((u8 *)t->tx_buf)[espi->tx]; + espi->tx += 1; } + writel(val, espi->mmio + SSPDR); } static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t) { - if (t->bits_per_word > 8) { - u16 rx_val; + u32 val; - rx_val = readw(espi->mmio + SSPDR); + val = readl(espi->mmio + SSPDR); + if (t->bits_per_word > 8) { if (t->rx_buf) - ((u16 *)t->rx_buf)[espi->rx] = rx_val; - espi->rx += sizeof(rx_val); + ((u16 *)t->rx_buf)[espi->rx] = val; + espi->rx += 2; } else { - u8 rx_val; - - rx_val = readb(espi->mmio + SSPDR); if (t->rx_buf) - ((u8 *)t->rx_buf)[espi->rx] = rx_val; - espi->rx += sizeof(rx_val); + ((u8 *)t->rx_buf)[espi->rx] = val; + espi->rx += 1; } } @@ -291,7 +285,7 @@ static int ep93xx_spi_read_write(struct ep93xx_spi *espi) struct spi_transfer *t = msg->state; /* read as long as RX FIFO has frames in it */ - while ((readb(espi->mmio + SSPSR) & SSPSR_RNE)) { + while ((readl(espi->mmio + SSPSR) & SSPSR_RNE)) { ep93xx_do_read(espi, t); espi->fifo_level--; } @@ -593,14 +587,14 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi, * Just to be sure: flush any data from RX FIFO. */ timeout = jiffies + msecs_to_jiffies(SPI_TIMEOUT); - while (readw(espi->mmio + SSPSR) & SSPSR_RNE) { + while (readl(espi->mmio + SSPSR) & SSPSR_RNE) { if (time_after(jiffies, timeout)) { dev_warn(&espi->pdev->dev, "timeout while flushing RX FIFO\n"); msg->status = -ETIMEDOUT; return; } - readw(espi->mmio + SSPDR); + readl(espi->mmio + SSPDR); } /* @@ -649,15 +643,14 @@ static int ep93xx_spi_transfer_one_message(struct spi_master *master, static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id) { struct ep93xx_spi *espi = dev_id; - u8 irq_status = readb(espi->mmio + SSPIIR); /* * If we got ROR (receive overrun) interrupt we know that something is * wrong. Just abort the message. */ - if (unlikely(irq_status & SSPIIR_RORIS)) { + if (readl(espi->mmio + SSPIIR) & SSPIIR_RORIS) { /* clear the overrun interrupt */ - writeb(0, espi->mmio + SSPICR); + writel(0, espi->mmio + SSPICR); dev_warn(&espi->pdev->dev, "receive overrun, aborting the message\n"); espi->current_msg->status = -EIO; @@ -857,7 +850,7 @@ static int ep93xx_spi_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "DMA setup failed. Falling back to PIO\n"); /* make sure that the hardware is disabled */ - writeb(0, espi->mmio + SSPCR1); + writel(0, espi->mmio + SSPCR1); error = devm_spi_register_master(&pdev->dev, master); if (error) { -- cgit v1.2.3 From 16779622be1c8959d6a665e2b6886bb33885fcb1 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 9 Aug 2017 08:51:27 +1200 Subject: spi: spi-ep93xx: add spi master prepare_transfer_hardware() This driver currently enables the hardware at the start of every message and disabled it when the message is complete. Make it a bit smarter by adding the prepare_transfer_hardware() and unprepare_transfer_hardware() callbacks so that the core can enable/disable the hardware based on spi message queue. Signed-off-by: H Hartley Sweeten [chris: use u32 instead of unsigned int] Signed-off-by: Chris Packham Reviewed-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 72 ++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 0bd792020471..ce6ec164f2f2 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -111,33 +111,6 @@ struct ep93xx_spi { /* converts bits per word to CR0.DSS value */ #define bits_per_word_to_dss(bpw) ((bpw) - 1) -static int ep93xx_spi_enable(const struct ep93xx_spi *espi) -{ - u32 val; - int err; - - err = clk_enable(espi->clk); - if (err) - return err; - - val = readl(espi->mmio + SSPCR1); - val |= SSPCR1_SSE; - writel(val, espi->mmio + SSPCR1); - - return 0; -} - -static void ep93xx_spi_disable(const struct ep93xx_spi *espi) -{ - u32 val; - - val = readl(espi->mmio + SSPCR1); - val &= ~SSPCR1_SSE; - writel(val, espi->mmio + SSPCR1); - - clk_disable(espi->clk); -} - static void ep93xx_spi_enable_interrupts(const struct ep93xx_spi *espi) { u32 val; @@ -571,17 +544,6 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi, { unsigned long timeout; struct spi_transfer *t; - int err; - - /* - * Enable the SPI controller and its clock. - */ - err = ep93xx_spi_enable(espi); - if (err) { - dev_err(&espi->pdev->dev, "failed to enable SPI controller\n"); - msg->status = err; - return; - } /* * Just to be sure: flush any data from RX FIFO. @@ -619,7 +581,6 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi, * deselect the device and disable the SPI controller. */ ep93xx_spi_cs_control(msg->spi, false); - ep93xx_spi_disable(espi); } static int ep93xx_spi_transfer_one_message(struct spi_master *master, @@ -679,6 +640,37 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static int ep93xx_spi_prepare_hardware(struct spi_master *master) +{ + struct ep93xx_spi *espi = spi_master_get_devdata(master); + u32 val; + int ret; + + ret = clk_enable(espi->clk); + if (ret) + return ret; + + val = readl(espi->mmio + SSPCR1); + val |= SSPCR1_SSE; + writel(val, espi->mmio + SSPCR1); + + return 0; +} + +static int ep93xx_spi_unprepare_hardware(struct spi_master *master) +{ + struct ep93xx_spi *espi = spi_master_get_devdata(master); + u32 val; + + val = readl(espi->mmio + SSPCR1); + val &= ~SSPCR1_SSE; + writel(val, espi->mmio + SSPCR1); + + clk_disable(espi->clk); + + return 0; +} + static bool ep93xx_spi_dma_filter(struct dma_chan *chan, void *filter_param) { if (ep93xx_dma_chan_is_m2p(chan)) @@ -780,6 +772,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev) if (!master) return -ENOMEM; + master->prepare_transfer_hardware = ep93xx_spi_prepare_hardware; + master->unprepare_transfer_hardware = ep93xx_spi_unprepare_hardware; master->transfer_one_message = ep93xx_spi_transfer_one_message; master->bus_num = pdev->id; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; -- cgit v1.2.3 From ac8d06df9a1f40a9feb759dd7ef5664328ae7694 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 9 Aug 2017 08:51:28 +1200 Subject: spi: spi-ep93xx: absorb the interrupt enable/disable helpers These are each only called once. Just absorb them into the callers. Signed-off-by: H Hartley Sweeten [chris: use u32 instead of unsigned int] Signed-off-by: Chris Packham Reviewed-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index ce6ec164f2f2..041842e0d028 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -111,24 +111,6 @@ struct ep93xx_spi { /* converts bits per word to CR0.DSS value */ #define bits_per_word_to_dss(bpw) ((bpw) - 1) -static void ep93xx_spi_enable_interrupts(const struct ep93xx_spi *espi) -{ - u32 val; - - val = readl(espi->mmio + SSPCR1); - val |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE); - writel(val, espi->mmio + SSPCR1); -} - -static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi) -{ - u32 val; - - val = readl(espi->mmio + SSPCR1); - val &= ~(SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE); - writel(val, espi->mmio + SSPCR1); -} - /** * ep93xx_spi_calc_divisors() - calculates SPI clock divisors * @espi: ep93xx SPI controller struct @@ -282,7 +264,12 @@ static void ep93xx_spi_pio_transfer(struct ep93xx_spi *espi) * FIFO, enable interrupts, and wait for the transfer to complete. */ if (ep93xx_spi_read_write(espi)) { - ep93xx_spi_enable_interrupts(espi); + u32 val; + + val = readl(espi->mmio + SSPCR1); + val |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE); + writel(val, espi->mmio + SSPCR1); + wait_for_completion(&espi->wait); } } @@ -604,6 +591,7 @@ static int ep93xx_spi_transfer_one_message(struct spi_master *master, static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id) { struct ep93xx_spi *espi = dev_id; + u32 val; /* * If we got ROR (receive overrun) interrupt we know that something is @@ -635,8 +623,12 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id) * any case we disable interrupts and notify the worker to handle * any post-processing of the message. */ - ep93xx_spi_disable_interrupts(espi); + val = readl(espi->mmio + SSPCR1); + val &= ~(SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE); + writel(val, espi->mmio + SSPCR1); + complete(&espi->wait); + return IRQ_HANDLED; } -- cgit v1.2.3 From 48738831018003c80f1131e77a25b8e832bec6f1 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 9 Aug 2017 08:51:29 +1200 Subject: spi: spi-ep93xx: pass the spi_master pointer around Change the parameters for some of the functions so that the spi_master pointer is passed around instead of the private data ep93xx_spi pointer. This allows removing the 'pdev' member of the private data and will help with some later cleanup. Signed-off-by: H Hartley Sweeten Reviewed-by: Andy Shevchenko Signed-off-by: Chris Packham Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 90 ++++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 041842e0d028..2d80e36f5015 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -70,7 +70,6 @@ /** * struct ep93xx_spi - EP93xx SPI controller structure - * @pdev: pointer to platform device * @clk: clock for the controller * @mmio: pointer to ioremap()'d registers * @sspdr_phys: physical address of the SSPDR register @@ -90,7 +89,6 @@ * the client */ struct ep93xx_spi { - const struct platform_device *pdev; struct clk *clk; void __iomem *mmio; unsigned long sspdr_phys; @@ -113,15 +111,15 @@ struct ep93xx_spi { /** * ep93xx_spi_calc_divisors() - calculates SPI clock divisors - * @espi: ep93xx SPI controller struct + * @master: SPI master * @rate: desired SPI output clock rate * @div_cpsr: pointer to return the cpsr (pre-scaler) divider * @div_scr: pointer to return the scr divider */ -static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi, +static int ep93xx_spi_calc_divisors(struct spi_master *master, u32 rate, u8 *div_cpsr, u8 *div_scr) { - struct spi_master *master = platform_get_drvdata(espi->pdev); + struct ep93xx_spi *espi = spi_master_get_devdata(master); unsigned long spi_clk_rate = clk_get_rate(espi->clk); int cpsr, scr; @@ -162,17 +160,18 @@ static void ep93xx_spi_cs_control(struct spi_device *spi, bool enable) gpio_set_value(spi->cs_gpio, !enable); } -static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi, +static int ep93xx_spi_chip_setup(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { + struct ep93xx_spi *espi = spi_master_get_devdata(master); u8 dss = bits_per_word_to_dss(xfer->bits_per_word); u8 div_cpsr = 0; u8 div_scr = 0; u16 cr0; int err; - err = ep93xx_spi_calc_divisors(espi, xfer->speed_hz, + err = ep93xx_spi_calc_divisors(master, xfer->speed_hz, &div_cpsr, &div_scr); if (err) return err; @@ -181,9 +180,9 @@ static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi, cr0 |= (spi->mode & (SPI_CPHA | SPI_CPOL)) << SSPCR0_MODE_SHIFT; cr0 |= dss; - dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n", + dev_dbg(&master->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n", spi->mode, div_cpsr, div_scr, dss); - dev_dbg(&espi->pdev->dev, "setup: cr0 %#x\n", cr0); + dev_dbg(&master->dev, "setup: cr0 %#x\n", cr0); writel(div_cpsr, espi->mmio + SSPCPSR); writel(cr0, espi->mmio + SSPCR0); @@ -234,8 +233,9 @@ static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t) * When this function is finished, RX FIFO should be empty and TX FIFO should be * full. */ -static int ep93xx_spi_read_write(struct ep93xx_spi *espi) +static int ep93xx_spi_read_write(struct spi_master *master) { + struct ep93xx_spi *espi = spi_master_get_devdata(master); struct spi_message *msg = espi->current_msg; struct spi_transfer *t = msg->state; @@ -257,13 +257,15 @@ static int ep93xx_spi_read_write(struct ep93xx_spi *espi) return -EINPROGRESS; } -static void ep93xx_spi_pio_transfer(struct ep93xx_spi *espi) +static void ep93xx_spi_pio_transfer(struct spi_master *master) { + struct ep93xx_spi *espi = spi_master_get_devdata(master); + /* * Now everything is set up for the current transfer. We prime the TX * FIFO, enable interrupts, and wait for the transfer to complete. */ - if (ep93xx_spi_read_write(espi)) { + if (ep93xx_spi_read_write(master)) { u32 val; val = readl(espi->mmio + SSPCR1); @@ -276,7 +278,7 @@ static void ep93xx_spi_pio_transfer(struct ep93xx_spi *espi) /** * ep93xx_spi_dma_prepare() - prepares a DMA transfer - * @espi: ep93xx SPI controller struct + * @master: SPI master * @dir: DMA transfer direction * * Function configures the DMA, maps the buffer and prepares the DMA @@ -284,8 +286,10 @@ static void ep93xx_spi_pio_transfer(struct ep93xx_spi *espi) * in case of failure. */ static struct dma_async_tx_descriptor * -ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir) +ep93xx_spi_dma_prepare(struct spi_master *master, + enum dma_transfer_direction dir) { + struct ep93xx_spi *espi = spi_master_get_devdata(master); struct spi_transfer *t = espi->current_msg->state; struct dma_async_tx_descriptor *txd; enum dma_slave_buswidth buswidth; @@ -361,7 +365,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir) } if (WARN_ON(len)) { - dev_warn(&espi->pdev->dev, "len = %zu expected 0!\n", len); + dev_warn(&master->dev, "len = %zu expected 0!\n", len); return ERR_PTR(-EINVAL); } @@ -379,15 +383,16 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir) /** * ep93xx_spi_dma_finish() - finishes with a DMA transfer - * @espi: ep93xx SPI controller struct + * @master: SPI master * @dir: DMA transfer direction * * Function finishes with the DMA transfer. After this, the DMA buffer is * unmapped. */ -static void ep93xx_spi_dma_finish(struct ep93xx_spi *espi, +static void ep93xx_spi_dma_finish(struct spi_master *master, enum dma_transfer_direction dir) { + struct ep93xx_spi *espi = spi_master_get_devdata(master); struct dma_chan *chan; struct sg_table *sgt; @@ -407,22 +412,23 @@ static void ep93xx_spi_dma_callback(void *callback_param) complete(callback_param); } -static void ep93xx_spi_dma_transfer(struct ep93xx_spi *espi) +static void ep93xx_spi_dma_transfer(struct spi_master *master) { + struct ep93xx_spi *espi = spi_master_get_devdata(master); struct spi_message *msg = espi->current_msg; struct dma_async_tx_descriptor *rxd, *txd; - rxd = ep93xx_spi_dma_prepare(espi, DMA_DEV_TO_MEM); + rxd = ep93xx_spi_dma_prepare(master, DMA_DEV_TO_MEM); if (IS_ERR(rxd)) { - dev_err(&espi->pdev->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd)); + dev_err(&master->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd)); msg->status = PTR_ERR(rxd); return; } - txd = ep93xx_spi_dma_prepare(espi, DMA_MEM_TO_DEV); + txd = ep93xx_spi_dma_prepare(master, DMA_MEM_TO_DEV); if (IS_ERR(txd)) { - ep93xx_spi_dma_finish(espi, DMA_DEV_TO_MEM); - dev_err(&espi->pdev->dev, "DMA TX failed: %ld\n", PTR_ERR(txd)); + ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM); + dev_err(&master->dev, "DMA TX failed: %ld\n", PTR_ERR(txd)); msg->status = PTR_ERR(txd); return; } @@ -440,13 +446,13 @@ static void ep93xx_spi_dma_transfer(struct ep93xx_spi *espi) wait_for_completion(&espi->wait); - ep93xx_spi_dma_finish(espi, DMA_MEM_TO_DEV); - ep93xx_spi_dma_finish(espi, DMA_DEV_TO_MEM); + ep93xx_spi_dma_finish(master, DMA_MEM_TO_DEV); + ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM); } /** * ep93xx_spi_process_transfer() - processes one SPI transfer - * @espi: ep93xx SPI controller struct + * @master: SPI master * @msg: current message * @t: transfer to process * @@ -454,17 +460,18 @@ static void ep93xx_spi_dma_transfer(struct ep93xx_spi *espi) * transfer is complete (may sleep) and updates @msg->status based on whether * transfer was successfully processed or not. */ -static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi, +static void ep93xx_spi_process_transfer(struct spi_master *master, struct spi_message *msg, struct spi_transfer *t) { + struct ep93xx_spi *espi = spi_master_get_devdata(master); int err; msg->state = t; - err = ep93xx_spi_chip_setup(espi, msg->spi, t); + err = ep93xx_spi_chip_setup(master, msg->spi, t); if (err) { - dev_err(&espi->pdev->dev, + dev_err(&master->dev, "failed to setup chip for transfer\n"); msg->status = err; return; @@ -479,9 +486,9 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi, * So in these cases we will be using PIO and don't bother for DMA. */ if (espi->dma_rx && t->len > SPI_FIFO_SIZE) - ep93xx_spi_dma_transfer(espi); + ep93xx_spi_dma_transfer(master); else - ep93xx_spi_pio_transfer(espi); + ep93xx_spi_pio_transfer(master); /* * In case of error during transmit, we bail out from processing @@ -516,7 +523,7 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi, /* * ep93xx_spi_process_message() - process one SPI message - * @espi: ep93xx SPI controller struct + * @master: SPI master * @msg: message to process * * This function processes a single SPI message. We go through all transfers in @@ -526,9 +533,10 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi, * @msg->status contains %0 in case of success or negative error code in case of * failure. */ -static void ep93xx_spi_process_message(struct ep93xx_spi *espi, +static void ep93xx_spi_process_message(struct spi_master *master, struct spi_message *msg) { + struct ep93xx_spi *espi = spi_master_get_devdata(master); unsigned long timeout; struct spi_transfer *t; @@ -538,7 +546,7 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi, timeout = jiffies + msecs_to_jiffies(SPI_TIMEOUT); while (readl(espi->mmio + SSPSR) & SSPSR_RNE) { if (time_after(jiffies, timeout)) { - dev_warn(&espi->pdev->dev, + dev_warn(&master->dev, "timeout while flushing RX FIFO\n"); msg->status = -ETIMEDOUT; return; @@ -558,7 +566,7 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi, ep93xx_spi_cs_control(msg->spi, true); list_for_each_entry(t, &msg->transfers, transfer_list) { - ep93xx_spi_process_transfer(espi, msg, t); + ep93xx_spi_process_transfer(master, msg, t); if (msg->status) break; } @@ -580,7 +588,7 @@ static int ep93xx_spi_transfer_one_message(struct spi_master *master, msg->actual_length = 0; espi->current_msg = msg; - ep93xx_spi_process_message(espi, msg); + ep93xx_spi_process_message(master, msg); espi->current_msg = NULL; spi_finalize_current_message(master); @@ -590,7 +598,8 @@ static int ep93xx_spi_transfer_one_message(struct spi_master *master, static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id) { - struct ep93xx_spi *espi = dev_id; + struct spi_master *master = dev_id; + struct ep93xx_spi *espi = spi_master_get_devdata(master); u32 val; /* @@ -600,7 +609,7 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id) if (readl(espi->mmio + SSPIIR) & SSPIIR_RORIS) { /* clear the overrun interrupt */ writel(0, espi->mmio + SSPICR); - dev_warn(&espi->pdev->dev, + dev_warn(&master->dev, "receive overrun, aborting the message\n"); espi->current_msg->status = -EIO; } else { @@ -608,7 +617,7 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id) * Interrupt is either RX (RIS) or TX (TIS). For both cases we * simply execute next data transfer. */ - if (ep93xx_spi_read_write(espi)) { + if (ep93xx_spi_read_write(master)) { /* * In normal case, there still is some processing left * for current transfer. Let's wait for the next @@ -815,7 +824,6 @@ static int ep93xx_spi_probe(struct platform_device *pdev) */ master->max_speed_hz = clk_get_rate(espi->clk) / 2; master->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256); - espi->pdev = pdev; espi->sspdr_phys = res->start + SSPDR; @@ -826,7 +834,7 @@ static int ep93xx_spi_probe(struct platform_device *pdev) } error = devm_request_irq(&pdev->dev, irq, ep93xx_spi_interrupt, - 0, "ep93xx-spi", espi); + 0, "ep93xx-spi", master); if (error) { dev_err(&pdev->dev, "failed to request irq\n"); goto fail_release_master; -- cgit v1.2.3 From c7a909cf25c6e1198f5a261d2af0503985871e1a Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 9 Aug 2017 08:51:30 +1200 Subject: spi: spi-ep93xx: remove private data 'current_msg' The currently in-flight message can be found from the spi master. Use that instead and remove the private data pointer. Signed-off-by: H Hartley Sweeten Reviewed-by: Andy Shevchenko Signed-off-by: Chris Packham Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 2d80e36f5015..cf7d8175bf79 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -74,7 +74,6 @@ * @mmio: pointer to ioremap()'d registers * @sspdr_phys: physical address of the SSPDR register * @wait: wait here until given transfer is completed - * @current_msg: message that is currently processed (or %NULL if none) * @tx: current byte in transfer to transmit * @rx: current byte in transfer to receive * @fifo_level: how full is FIFO (%0..%SPI_FIFO_SIZE - %1). Receiving one @@ -93,7 +92,6 @@ struct ep93xx_spi { void __iomem *mmio; unsigned long sspdr_phys; struct completion wait; - struct spi_message *current_msg; size_t tx; size_t rx; size_t fifo_level; @@ -236,8 +234,7 @@ static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t) static int ep93xx_spi_read_write(struct spi_master *master) { struct ep93xx_spi *espi = spi_master_get_devdata(master); - struct spi_message *msg = espi->current_msg; - struct spi_transfer *t = msg->state; + struct spi_transfer *t = master->cur_msg->state; /* read as long as RX FIFO has frames in it */ while ((readl(espi->mmio + SSPSR) & SSPSR_RNE)) { @@ -290,7 +287,7 @@ ep93xx_spi_dma_prepare(struct spi_master *master, enum dma_transfer_direction dir) { struct ep93xx_spi *espi = spi_master_get_devdata(master); - struct spi_transfer *t = espi->current_msg->state; + struct spi_transfer *t = master->cur_msg->state; struct dma_async_tx_descriptor *txd; enum dma_slave_buswidth buswidth; struct dma_slave_config conf; @@ -415,13 +412,12 @@ static void ep93xx_spi_dma_callback(void *callback_param) static void ep93xx_spi_dma_transfer(struct spi_master *master) { struct ep93xx_spi *espi = spi_master_get_devdata(master); - struct spi_message *msg = espi->current_msg; struct dma_async_tx_descriptor *rxd, *txd; rxd = ep93xx_spi_dma_prepare(master, DMA_DEV_TO_MEM); if (IS_ERR(rxd)) { dev_err(&master->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd)); - msg->status = PTR_ERR(rxd); + master->cur_msg->status = PTR_ERR(rxd); return; } @@ -429,7 +425,7 @@ static void ep93xx_spi_dma_transfer(struct spi_master *master) if (IS_ERR(txd)) { ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM); dev_err(&master->dev, "DMA TX failed: %ld\n", PTR_ERR(txd)); - msg->status = PTR_ERR(txd); + master->cur_msg->status = PTR_ERR(txd); return; } @@ -587,9 +583,7 @@ static int ep93xx_spi_transfer_one_message(struct spi_master *master, msg->status = 0; msg->actual_length = 0; - espi->current_msg = msg; ep93xx_spi_process_message(master, msg); - espi->current_msg = NULL; spi_finalize_current_message(master); @@ -611,7 +605,7 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id) writel(0, espi->mmio + SSPICR); dev_warn(&master->dev, "receive overrun, aborting the message\n"); - espi->current_msg->status = -EIO; + master->cur_msg->status = -EIO; } else { /* * Interrupt is either RX (RIS) or TX (TIS). For both cases we -- cgit v1.2.3 From d9a017713d909697f528a3f6569d5deb7477cea1 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 9 Aug 2017 08:51:31 +1200 Subject: spi: spi-ep93xx: use the default master transfer queueing mechanism Update this driver to the default implementation of transfer_one_message(). Signed-off-by: H Hartley Sweeten Reviewed-by: Andy Shevchenko Signed-off-by: Chris Packham Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 322 ++++++++++++++++------------------------------- 1 file changed, 108 insertions(+), 214 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index cf7d8175bf79..e5cc07357746 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -73,7 +73,6 @@ * @clk: clock for the controller * @mmio: pointer to ioremap()'d registers * @sspdr_phys: physical address of the SSPDR register - * @wait: wait here until given transfer is completed * @tx: current byte in transfer to transmit * @rx: current byte in transfer to receive * @fifo_level: how full is FIFO (%0..%SPI_FIFO_SIZE - %1). Receiving one @@ -91,7 +90,6 @@ struct ep93xx_spi { struct clk *clk; void __iomem *mmio; unsigned long sspdr_phys; - struct completion wait; size_t tx; size_t rx; size_t fifo_level; @@ -123,8 +121,7 @@ static int ep93xx_spi_calc_divisors(struct spi_master *master, /* * Make sure that max value is between values supported by the - * controller. Note that minimum value is already checked in - * ep93xx_spi_transfer_one_message(). + * controller. */ rate = clamp(rate, master->min_speed_hz, master->max_speed_hz); @@ -149,15 +146,6 @@ static int ep93xx_spi_calc_divisors(struct spi_master *master, return -EINVAL; } -static void ep93xx_spi_cs_control(struct spi_device *spi, bool enable) -{ - if (spi->mode & SPI_CS_HIGH) - enable = !enable; - - if (gpio_is_valid(spi->cs_gpio)) - gpio_set_value(spi->cs_gpio, !enable); -} - static int ep93xx_spi_chip_setup(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) @@ -188,34 +176,38 @@ static int ep93xx_spi_chip_setup(struct spi_master *master, return 0; } -static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t) +static void ep93xx_do_write(struct spi_master *master) { + struct ep93xx_spi *espi = spi_master_get_devdata(master); + struct spi_transfer *xfer = master->cur_msg->state; u32 val = 0; - if (t->bits_per_word > 8) { - if (t->tx_buf) - val = ((u16 *)t->tx_buf)[espi->tx]; + if (xfer->bits_per_word > 8) { + if (xfer->tx_buf) + val = ((u16 *)xfer->tx_buf)[espi->tx]; espi->tx += 2; } else { - if (t->tx_buf) - val = ((u8 *)t->tx_buf)[espi->tx]; + if (xfer->tx_buf) + val = ((u8 *)xfer->tx_buf)[espi->tx]; espi->tx += 1; } writel(val, espi->mmio + SSPDR); } -static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t) +static void ep93xx_do_read(struct spi_master *master) { + struct ep93xx_spi *espi = spi_master_get_devdata(master); + struct spi_transfer *xfer = master->cur_msg->state; u32 val; val = readl(espi->mmio + SSPDR); - if (t->bits_per_word > 8) { - if (t->rx_buf) - ((u16 *)t->rx_buf)[espi->rx] = val; + if (xfer->bits_per_word > 8) { + if (xfer->rx_buf) + ((u16 *)xfer->rx_buf)[espi->rx] = val; espi->rx += 2; } else { - if (t->rx_buf) - ((u8 *)t->rx_buf)[espi->rx] = val; + if (xfer->rx_buf) + ((u8 *)xfer->rx_buf)[espi->rx] = val; espi->rx += 1; } } @@ -234,45 +226,26 @@ static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t) static int ep93xx_spi_read_write(struct spi_master *master) { struct ep93xx_spi *espi = spi_master_get_devdata(master); - struct spi_transfer *t = master->cur_msg->state; + struct spi_transfer *xfer = master->cur_msg->state; /* read as long as RX FIFO has frames in it */ while ((readl(espi->mmio + SSPSR) & SSPSR_RNE)) { - ep93xx_do_read(espi, t); + ep93xx_do_read(master); espi->fifo_level--; } /* write as long as TX FIFO has room */ - while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) { - ep93xx_do_write(espi, t); + while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < xfer->len) { + ep93xx_do_write(master); espi->fifo_level++; } - if (espi->rx == t->len) + if (espi->rx == xfer->len) return 0; return -EINPROGRESS; } -static void ep93xx_spi_pio_transfer(struct spi_master *master) -{ - struct ep93xx_spi *espi = spi_master_get_devdata(master); - - /* - * Now everything is set up for the current transfer. We prime the TX - * FIFO, enable interrupts, and wait for the transfer to complete. - */ - if (ep93xx_spi_read_write(master)) { - u32 val; - - val = readl(espi->mmio + SSPCR1); - val |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE); - writel(val, espi->mmio + SSPCR1); - - wait_for_completion(&espi->wait); - } -} - /** * ep93xx_spi_dma_prepare() - prepares a DMA transfer * @master: SPI master @@ -287,7 +260,7 @@ ep93xx_spi_dma_prepare(struct spi_master *master, enum dma_transfer_direction dir) { struct ep93xx_spi *espi = spi_master_get_devdata(master); - struct spi_transfer *t = master->cur_msg->state; + struct spi_transfer *xfer = master->cur_msg->state; struct dma_async_tx_descriptor *txd; enum dma_slave_buswidth buswidth; struct dma_slave_config conf; @@ -295,10 +268,10 @@ ep93xx_spi_dma_prepare(struct spi_master *master, struct sg_table *sgt; struct dma_chan *chan; const void *buf, *pbuf; - size_t len = t->len; + size_t len = xfer->len; int i, ret, nents; - if (t->bits_per_word > 8) + if (xfer->bits_per_word > 8) buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; else buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; @@ -308,14 +281,14 @@ ep93xx_spi_dma_prepare(struct spi_master *master, if (dir == DMA_DEV_TO_MEM) { chan = espi->dma_rx; - buf = t->rx_buf; + buf = xfer->rx_buf; sgt = &espi->rx_sgt; conf.src_addr = espi->sspdr_phys; conf.src_addr_width = buswidth; } else { chan = espi->dma_tx; - buf = t->tx_buf; + buf = xfer->tx_buf; sgt = &espi->tx_sgt; conf.dst_addr = espi->sspdr_phys; @@ -406,10 +379,15 @@ static void ep93xx_spi_dma_finish(struct spi_master *master, static void ep93xx_spi_dma_callback(void *callback_param) { - complete(callback_param); + struct spi_master *master = callback_param; + + ep93xx_spi_dma_finish(master, DMA_MEM_TO_DEV); + ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM); + + spi_finalize_current_transfer(master); } -static void ep93xx_spi_dma_transfer(struct spi_master *master) +static int ep93xx_spi_dma_transfer(struct spi_master *master) { struct ep93xx_spi *espi = spi_master_get_devdata(master); struct dma_async_tx_descriptor *rxd, *txd; @@ -417,177 +395,29 @@ static void ep93xx_spi_dma_transfer(struct spi_master *master) rxd = ep93xx_spi_dma_prepare(master, DMA_DEV_TO_MEM); if (IS_ERR(rxd)) { dev_err(&master->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd)); - master->cur_msg->status = PTR_ERR(rxd); - return; + return PTR_ERR(rxd); } txd = ep93xx_spi_dma_prepare(master, DMA_MEM_TO_DEV); if (IS_ERR(txd)) { ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM); dev_err(&master->dev, "DMA TX failed: %ld\n", PTR_ERR(txd)); - master->cur_msg->status = PTR_ERR(txd); - return; + return PTR_ERR(txd); } /* We are ready when RX is done */ rxd->callback = ep93xx_spi_dma_callback; - rxd->callback_param = &espi->wait; + rxd->callback_param = master; - /* Now submit both descriptors and wait while they finish */ + /* Now submit both descriptors and start DMA */ dmaengine_submit(rxd); dmaengine_submit(txd); dma_async_issue_pending(espi->dma_rx); dma_async_issue_pending(espi->dma_tx); - wait_for_completion(&espi->wait); - - ep93xx_spi_dma_finish(master, DMA_MEM_TO_DEV); - ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM); -} - -/** - * ep93xx_spi_process_transfer() - processes one SPI transfer - * @master: SPI master - * @msg: current message - * @t: transfer to process - * - * This function processes one SPI transfer given in @t. Function waits until - * transfer is complete (may sleep) and updates @msg->status based on whether - * transfer was successfully processed or not. - */ -static void ep93xx_spi_process_transfer(struct spi_master *master, - struct spi_message *msg, - struct spi_transfer *t) -{ - struct ep93xx_spi *espi = spi_master_get_devdata(master); - int err; - - msg->state = t; - - err = ep93xx_spi_chip_setup(master, msg->spi, t); - if (err) { - dev_err(&master->dev, - "failed to setup chip for transfer\n"); - msg->status = err; - return; - } - - espi->rx = 0; - espi->tx = 0; - - /* - * There is no point of setting up DMA for the transfers which will - * fit into the FIFO and can be transferred with a single interrupt. - * So in these cases we will be using PIO and don't bother for DMA. - */ - if (espi->dma_rx && t->len > SPI_FIFO_SIZE) - ep93xx_spi_dma_transfer(master); - else - ep93xx_spi_pio_transfer(master); - - /* - * In case of error during transmit, we bail out from processing - * the message. - */ - if (msg->status) - return; - - msg->actual_length += t->len; - - /* - * After this transfer is finished, perform any possible - * post-transfer actions requested by the protocol driver. - */ - if (t->delay_usecs) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(usecs_to_jiffies(t->delay_usecs)); - } - if (t->cs_change) { - if (!list_is_last(&t->transfer_list, &msg->transfers)) { - /* - * In case protocol driver is asking us to drop the - * chipselect briefly, we let the scheduler to handle - * any "delay" here. - */ - ep93xx_spi_cs_control(msg->spi, false); - cond_resched(); - ep93xx_spi_cs_control(msg->spi, true); - } - } -} - -/* - * ep93xx_spi_process_message() - process one SPI message - * @master: SPI master - * @msg: message to process - * - * This function processes a single SPI message. We go through all transfers in - * the message and pass them to ep93xx_spi_process_transfer(). Chipselect is - * asserted during the whole message (unless per transfer cs_change is set). - * - * @msg->status contains %0 in case of success or negative error code in case of - * failure. - */ -static void ep93xx_spi_process_message(struct spi_master *master, - struct spi_message *msg) -{ - struct ep93xx_spi *espi = spi_master_get_devdata(master); - unsigned long timeout; - struct spi_transfer *t; - - /* - * Just to be sure: flush any data from RX FIFO. - */ - timeout = jiffies + msecs_to_jiffies(SPI_TIMEOUT); - while (readl(espi->mmio + SSPSR) & SSPSR_RNE) { - if (time_after(jiffies, timeout)) { - dev_warn(&master->dev, - "timeout while flushing RX FIFO\n"); - msg->status = -ETIMEDOUT; - return; - } - readl(espi->mmio + SSPDR); - } - - /* - * We explicitly handle FIFO level. This way we don't have to check TX - * FIFO status using %SSPSR_TNF bit which may cause RX FIFO overruns. - */ - espi->fifo_level = 0; - - /* - * Assert the chipselect. - */ - ep93xx_spi_cs_control(msg->spi, true); - - list_for_each_entry(t, &msg->transfers, transfer_list) { - ep93xx_spi_process_transfer(master, msg, t); - if (msg->status) - break; - } - - /* - * Now the whole message is transferred (or failed for some reason). We - * deselect the device and disable the SPI controller. - */ - ep93xx_spi_cs_control(msg->spi, false); -} - -static int ep93xx_spi_transfer_one_message(struct spi_master *master, - struct spi_message *msg) -{ - struct ep93xx_spi *espi = spi_master_get_devdata(master); - - msg->state = NULL; - msg->status = 0; - msg->actual_length = 0; - - ep93xx_spi_process_message(master, msg); - - spi_finalize_current_message(master); - - return 0; + /* signal that we need to wait for completion */ + return 1; } static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id) @@ -630,11 +460,76 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id) val &= ~(SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE); writel(val, espi->mmio + SSPCR1); - complete(&espi->wait); + spi_finalize_current_transfer(master); return IRQ_HANDLED; } +static int ep93xx_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct ep93xx_spi *espi = spi_master_get_devdata(master); + u32 val; + int ret; + + ret = ep93xx_spi_chip_setup(master, spi, xfer); + if (ret) { + dev_err(&master->dev, "failed to setup chip for transfer\n"); + return ret; + } + + master->cur_msg->state = xfer; + espi->rx = 0; + espi->tx = 0; + + /* + * There is no point of setting up DMA for the transfers which will + * fit into the FIFO and can be transferred with a single interrupt. + * So in these cases we will be using PIO and don't bother for DMA. + */ + if (espi->dma_rx && xfer->len > SPI_FIFO_SIZE) + return ep93xx_spi_dma_transfer(master); + + /* Using PIO so prime the TX FIFO and enable interrupts */ + ep93xx_spi_read_write(master); + + val = readl(espi->mmio + SSPCR1); + val |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE); + writel(val, espi->mmio + SSPCR1); + + /* signal that we need to wait for completion */ + return 1; +} + +static int ep93xx_spi_prepare_message(struct spi_master *master, + struct spi_message *msg) +{ + struct ep93xx_spi *espi = spi_master_get_devdata(master); + unsigned long timeout; + + /* + * Just to be sure: flush any data from RX FIFO. + */ + timeout = jiffies + msecs_to_jiffies(SPI_TIMEOUT); + while (readl(espi->mmio + SSPSR) & SSPSR_RNE) { + if (time_after(jiffies, timeout)) { + dev_warn(&master->dev, + "timeout while flushing RX FIFO\n"); + return -ETIMEDOUT; + } + readl(espi->mmio + SSPDR); + } + + /* + * We explicitly handle FIFO level. This way we don't have to check TX + * FIFO status using %SSPSR_TNF bit which may cause RX FIFO overruns. + */ + espi->fifo_level = 0; + + return 0; +} + static int ep93xx_spi_prepare_hardware(struct spi_master *master) { struct ep93xx_spi *espi = spi_master_get_devdata(master); @@ -769,7 +664,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev) master->prepare_transfer_hardware = ep93xx_spi_prepare_hardware; master->unprepare_transfer_hardware = ep93xx_spi_unprepare_hardware; - master->transfer_one_message = ep93xx_spi_transfer_one_message; + master->prepare_message = ep93xx_spi_prepare_message; + master->transfer_one = ep93xx_spi_transfer_one; master->bus_num = pdev->id; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); @@ -810,8 +706,6 @@ static int ep93xx_spi_probe(struct platform_device *pdev) goto fail_release_master; } - init_completion(&espi->wait); - /* * Calculate maximum and minimum supported clock rates * for the controller. -- cgit v1.2.3 From 6f38f125ffc4d87768129644fb485eca7382f0b1 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 10 Aug 2017 14:13:26 +0200 Subject: spi: qup: hide warning for uninitialized variable The added conditionals in this function apparently confused gcc to the point that it no longer sees the code is safe and instead shows a false-positive warning: drivers/spi/spi-qup.c: In function 'spi_qup_transfer_one': drivers/spi/spi-qup.c:507:28: error: 'tx_nents' may be used uninitialized in this function [-Werror=maybe-uninitialized] drivers/spi/spi-qup.c:464:17: note: 'tx_nents' was declared here drivers/spi/spi-qup.c:505:28: error: 'rx_nents' may be used uninitialized in this function [-Werror=maybe-uninitialized] drivers/spi/spi-qup.c:464:7: note: 'rx_nents' was declared here This moves the initialization to a place that makes it obvious to the compiler. Fixes: 5884e17ef3cb ("spi: qup: allow multiple DMA transactions per spi xfer") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 1364516e87c2..e9ecd67cd817 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -427,8 +427,6 @@ static u32 spi_qup_sgl_get_nents_len(struct scatterlist *sgl, u32 max, struct scatterlist *sg; u32 total = 0; - *nents = 0; - for (sg = sgl; sg; sg = sg_next(sg)) { unsigned int len = sg_dma_len(sg); @@ -461,7 +459,7 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer, tx_sgl = xfer->tx_sg.sgl; do { - u32 rx_nents, tx_nents; + u32 rx_nents = 0, tx_nents = 0; if (rx_sgl) qup->n_words = spi_qup_sgl_get_nents_len(rx_sgl, -- cgit v1.2.3 From 88a19814de71aafe4de4868e1e13cd8b9a06a861 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 10 Aug 2017 14:13:27 +0200 Subject: spi: qup: fix 64-bit build warning On 64-bit systems, pointers are wider than 'int' variables, so we get a warning about a cast between them: drivers/spi/spi-qup.c:1060:23: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] This changes the code to use the correct uintptr_t cast. Fixes: 4d023737b2ef ("spi: qup: Fix QUP version identify method") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index e9ecd67cd817..974a8ce58b68 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -1057,7 +1057,7 @@ static int spi_qup_probe(struct platform_device *pdev) else if (!ret) master->can_dma = spi_qup_can_dma; - controller->qup_v1 = (int)of_device_get_match_data(dev); + controller->qup_v1 = (uintptr_t)of_device_get_match_data(dev); if (!controller->qup_v1) master->set_cs = spi_qup_set_cs; -- cgit v1.2.3 From 6b860e69e873be247d19174ab6b24d0b5741bf8c Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Mon, 14 Aug 2017 16:34:22 +0800 Subject: spi: rockchip: add compatible string for rv1108 spi The spi on rv1108 is the same as other rockchip based socs, add compatible string for it. Signed-off-by: Andy Yan Acked-by: Rob Herring Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-rockchip.txt | 1 + drivers/spi/spi-rockchip.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.txt b/Documentation/devicetree/bindings/spi/spi-rockchip.txt index 83da4931d832..6e3ffacbba32 100644 --- a/Documentation/devicetree/bindings/spi/spi-rockchip.txt +++ b/Documentation/devicetree/bindings/spi/spi-rockchip.txt @@ -6,6 +6,7 @@ and display controllers using the SPI communication interface. Required Properties: - compatible: should be one of the following. + "rockchip,rv1108-spi" for rv1108 SoCs. "rockchip,rk3036-spi" for rk3036 SoCS. "rockchip,rk3066-spi" for rk3066 SoCs. "rockchip,rk3188-spi" for rk3188 SoCs. diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 34f6440a5255..474033e2149e 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -914,6 +914,7 @@ static const struct dev_pm_ops rockchip_spi_pm = { }; static const struct of_device_id rockchip_spi_dt_match[] = { + { .compatible = "rockchip,rv1108-spi", }, { .compatible = "rockchip,rk3036-spi", }, { .compatible = "rockchip,rk3066-spi", }, { .compatible = "rockchip,rk3188-spi", }, -- cgit v1.2.3 From e19b63cd3cb7ebf1ca73d9c4f58934149337ed24 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Aug 2017 11:33:11 +0200 Subject: spi: altera: Switch to SPI core transfer queue management The Altera SPI driver currently uses the spi-bitbang infrastructure for transfer queue management, but non of the bitbang functionality itself. This is because when the driver was written this was the only way to not have to do queue management in the driver itself. Nowadays transfer queue management is available from the SPI driver core itself and using the bitbang infrastructure just adds an additional level of indirection. Switch the driver over to using the core queue management directly. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 1 - drivers/spi/spi-altera.c | 94 ++++++++++++++---------------------------------- 2 files changed, 27 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 9b31351fe429..acf566f06241 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -55,7 +55,6 @@ comment "SPI Master Controller Drivers" config SPI_ALTERA tristate "Altera SPI Controller" - select SPI_BITBANG help This is the driver for the Altera SPI Controller. diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c index b95010e72452..bfac34068999 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -45,10 +44,6 @@ #define ALTERA_SPI_CONTROL_SSO_MSK 0x400 struct altera_spi { - /* bitbang has to be first */ - struct spi_bitbang bitbang; - struct completion done; - void __iomem *base; int irq; int len; @@ -66,39 +61,18 @@ static inline struct altera_spi *altera_spi_to_hw(struct spi_device *sdev) return spi_master_get_devdata(sdev->master); } -static void altera_spi_chipsel(struct spi_device *spi, int value) +static void altera_spi_set_cs(struct spi_device *spi, bool is_high) { struct altera_spi *hw = altera_spi_to_hw(spi); - if (spi->mode & SPI_CS_HIGH) { - switch (value) { - case BITBANG_CS_INACTIVE: - writel(1 << spi->chip_select, - hw->base + ALTERA_SPI_SLAVE_SEL); - hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK; - writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); - break; - - case BITBANG_CS_ACTIVE: - hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK; - writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); - writel(0, hw->base + ALTERA_SPI_SLAVE_SEL); - break; - } + if (is_high) { + hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK; + writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); + writel(0, hw->base + ALTERA_SPI_SLAVE_SEL); } else { - switch (value) { - case BITBANG_CS_INACTIVE: - hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK; - writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); - break; - - case BITBANG_CS_ACTIVE: - writel(1 << spi->chip_select, - hw->base + ALTERA_SPI_SLAVE_SEL); - hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK; - writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); - break; - } + writel(BIT(spi->chip_select), hw->base + ALTERA_SPI_SLAVE_SEL); + hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK; + writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); } } @@ -116,9 +90,10 @@ static inline unsigned int hw_txbyte(struct altera_spi *hw, int count) return 0; } -static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t) +static int altera_spi_txrx(struct spi_master *master, + struct spi_device *spi, struct spi_transfer *t) { - struct altera_spi *hw = altera_spi_to_hw(spi); + struct altera_spi *hw = spi_master_get_devdata(master); hw->tx = t->tx_buf; hw->rx = t->rx_buf; @@ -133,11 +108,6 @@ static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t) /* send the first byte */ writel(hw_txbyte(hw, 0), hw->base + ALTERA_SPI_TXDATA); - - wait_for_completion(&hw->done); - /* disable receive interrupt */ - hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK; - writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); } else { while (hw->count < hw->len) { unsigned int rxd; @@ -164,14 +134,16 @@ static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t) hw->count++; } + spi_finalize_current_transfer(master); } - return hw->count * hw->bytes_per_word; + return t->len; } static irqreturn_t altera_spi_irq(int irq, void *dev) { - struct altera_spi *hw = dev; + struct spi_master *master = dev; + struct altera_spi *hw = spi_master_get_devdata(master); unsigned int rxd; rxd = readl(hw->base + ALTERA_SPI_RXDATA); @@ -189,10 +161,15 @@ static irqreturn_t altera_spi_irq(int irq, void *dev) hw->count++; - if (hw->count < hw->len) + if (hw->count < hw->len) { writel(hw_txbyte(hw, hw->count), hw->base + ALTERA_SPI_TXDATA); - else - complete(&hw->done); + } else { + /* disable receive interrupt */ + hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK; + writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); + + spi_finalize_current_transfer(master); + } return IRQ_HANDLED; } @@ -214,14 +191,10 @@ static int altera_spi_probe(struct platform_device *pdev) master->mode_bits = SPI_CS_HIGH; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16); master->dev.of_node = pdev->dev.of_node; + master->transfer_one = altera_spi_txrx; + master->set_cs = altera_spi_set_cs; hw = spi_master_get_devdata(master); - platform_set_drvdata(pdev, hw); - - /* setup the state for the bitbang driver */ - hw->bitbang.master = master; - hw->bitbang.chipselect = altera_spi_chipsel; - hw->bitbang.txrx_bufs = altera_spi_txrx; /* find and map our resources */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -239,15 +212,13 @@ static int altera_spi_probe(struct platform_device *pdev) /* irq is optional */ hw->irq = platform_get_irq(pdev, 0); if (hw->irq >= 0) { - init_completion(&hw->done); err = devm_request_irq(&pdev->dev, hw->irq, altera_spi_irq, 0, - pdev->name, hw); + pdev->name, master); if (err) goto exit; } - /* register our spi controller */ - err = spi_bitbang_start(&hw->bitbang); + err = devm_spi_register_master(&pdev->dev, master); if (err) goto exit; dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq); @@ -258,16 +229,6 @@ exit: return err; } -static int altera_spi_remove(struct platform_device *dev) -{ - struct altera_spi *hw = platform_get_drvdata(dev); - struct spi_master *master = hw->bitbang.master; - - spi_bitbang_stop(&hw->bitbang); - spi_master_put(master); - return 0; -} - #ifdef CONFIG_OF static const struct of_device_id altera_spi_match[] = { { .compatible = "ALTR,spi-1.0", }, @@ -279,7 +240,6 @@ MODULE_DEVICE_TABLE(of, altera_spi_match); static struct platform_driver altera_spi_driver = { .probe = altera_spi_probe, - .remove = altera_spi_remove, .driver = { .name = DRV_NAME, .pm = NULL, -- cgit v1.2.3 From b64836a5718bdcce7b23dc06eb1f3a9620cf6214 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 16 Aug 2017 11:33:12 +0200 Subject: spi: altera: Consolidate TX/RX data register access The patterns for accessing the TX/RX data registers is the same for the IRQ and non-IRQ paths. Consolidate the duplicated code into shared helper functions. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- drivers/spi/spi-altera.c | 75 ++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c index bfac34068999..a5adf0d868fc 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -76,18 +76,43 @@ static void altera_spi_set_cs(struct spi_device *spi, bool is_high) } } -static inline unsigned int hw_txbyte(struct altera_spi *hw, int count) +static void altera_spi_tx_word(struct altera_spi *hw) { + unsigned int txd = 0; + if (hw->tx) { switch (hw->bytes_per_word) { case 1: - return hw->tx[count]; + txd = hw->tx[hw->count]; + break; case 2: - return (hw->tx[count * 2] - | (hw->tx[count * 2 + 1] << 8)); + txd = (hw->tx[hw->count * 2] + | (hw->tx[hw->count * 2 + 1] << 8)); + break; } } - return 0; + + writel(txd, hw->base + ALTERA_SPI_TXDATA); +} + +static void altera_spi_rx_word(struct altera_spi *hw) +{ + unsigned int rxd; + + rxd = readl(hw->base + ALTERA_SPI_RXDATA); + if (hw->rx) { + switch (hw->bytes_per_word) { + case 1: + hw->rx[hw->count] = rxd; + break; + case 2: + hw->rx[hw->count * 2] = rxd; + hw->rx[hw->count * 2 + 1] = rxd >> 8; + break; + } + } + + hw->count++; } static int altera_spi_txrx(struct spi_master *master, @@ -107,32 +132,16 @@ static int altera_spi_txrx(struct spi_master *master, writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); /* send the first byte */ - writel(hw_txbyte(hw, 0), hw->base + ALTERA_SPI_TXDATA); + altera_spi_tx_word(hw); } else { while (hw->count < hw->len) { - unsigned int rxd; - - writel(hw_txbyte(hw, hw->count), - hw->base + ALTERA_SPI_TXDATA); + altera_spi_tx_word(hw); while (!(readl(hw->base + ALTERA_SPI_STATUS) & ALTERA_SPI_STATUS_RRDY_MSK)) cpu_relax(); - rxd = readl(hw->base + ALTERA_SPI_RXDATA); - if (hw->rx) { - switch (hw->bytes_per_word) { - case 1: - hw->rx[hw->count] = rxd; - break; - case 2: - hw->rx[hw->count * 2] = rxd; - hw->rx[hw->count * 2 + 1] = rxd >> 8; - break; - } - } - - hw->count++; + altera_spi_rx_word(hw); } spi_finalize_current_transfer(master); } @@ -144,25 +153,11 @@ static irqreturn_t altera_spi_irq(int irq, void *dev) { struct spi_master *master = dev; struct altera_spi *hw = spi_master_get_devdata(master); - unsigned int rxd; - - rxd = readl(hw->base + ALTERA_SPI_RXDATA); - if (hw->rx) { - switch (hw->bytes_per_word) { - case 1: - hw->rx[hw->count] = rxd; - break; - case 2: - hw->rx[hw->count * 2] = rxd; - hw->rx[hw->count * 2 + 1] = rxd >> 8; - break; - } - } - hw->count++; + altera_spi_rx_word(hw); if (hw->count < hw->len) { - writel(hw_txbyte(hw, hw->count), hw->base + ALTERA_SPI_TXDATA); + altera_spi_tx_word(hw); } else { /* disable receive interrupt */ hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK; -- cgit v1.2.3 From 04b37d2d02c0a5ae2f4e59326ef6deaff18e0456 Mon Sep 17 00:00:00 2001 From: Huibin Hong Date: Wed, 16 Aug 2017 10:12:02 +0800 Subject: spi: rockchip: configure CTRLR1 according to size and data frame CTRLR1 is number of data frames, when rx only. When data frame is 8 bit, CTRLR1 is len-1. When data frame is 16 bit, CTRLR1 is (len/2)-1. Signed-off-by: Huibin Hong Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 474033e2149e..fdcf3076681b 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -568,7 +568,13 @@ static void rockchip_spi_config(struct rockchip_spi *rs) writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0); - writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1); + if (rs->n_bytes == 1) + writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1); + else if (rs->n_bytes == 2) + writel_relaxed((rs->len / 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1); + else + writel_relaxed((rs->len * 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1); + writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR); writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); -- cgit v1.2.3 From 9b61e302210eba55768962f2f11e96bb508c2408 Mon Sep 17 00:00:00 2001 From: Suniel Mahesh Date: Thu, 3 Aug 2017 10:05:57 +0530 Subject: spi: Pick spi bus number from Linux idr or spi alias Modify existing code, for automatically picking the spi bus number based on Linux idr scheme as mentioned in FIXME. This patch does the following: (a) Remove the now unnecessary code which was allocating bus numbers using ATOMIC_INIT and atomic_dec_return macros. (b) If we have an alias, pick the bus number from alias ID (c) Convert to linux idr interface Signed-off-by: Suniel Mahesh Signed-off-by: Karthik Tummala Tested-by: Karthik Tummala Signed-off-by: Mark Brown --- drivers/spi/spi.c | 71 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index aed78093b130..b851888a0a0b 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -40,9 +40,13 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include +#define SPI_DYN_FIRST_BUS_NUM 0 + +static DEFINE_IDR(spi_master_idr); static void spidev_release(struct device *dev) { @@ -420,6 +424,7 @@ static LIST_HEAD(spi_controller_list); /* * Used to protect add/del opertion for board_info list and * spi_controller list, and their matching process + * also used to protect object of type struct idr */ static DEFINE_MUTEX(board_lock); @@ -2051,11 +2056,10 @@ static int of_spi_register_master(struct spi_controller *ctlr) */ int spi_register_controller(struct spi_controller *ctlr) { - static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1); struct device *dev = ctlr->dev.parent; struct boardinfo *bi; int status = -ENODEV; - int dynamic = 0; + int id; if (!dev) return -ENODEV; @@ -2071,17 +2075,29 @@ int spi_register_controller(struct spi_controller *ctlr) */ if (ctlr->num_chipselect == 0) return -EINVAL; - - if ((ctlr->bus_num < 0) && ctlr->dev.of_node) - ctlr->bus_num = of_alias_get_id(ctlr->dev.of_node, "spi"); - - /* convention: dynamically assigned bus IDs count down from the max */ + + /* allocate dynamic bus number using Linux idr */ + if ((ctlr->bus_num < 0) && ctlr->dev.of_node) { + id = of_alias_get_id(ctlr->dev.of_node, "spi"); + if (id >= 0) { + ctlr->bus_num = id; + mutex_lock(&board_lock); + id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num, + ctlr->bus_num + 1, GFP_KERNEL); + mutex_unlock(&board_lock); + if (WARN(id < 0, "couldn't get idr")) + return id == -ENOSPC ? -EBUSY : id; + } + } if (ctlr->bus_num < 0) { - /* FIXME switch to an IDR based scheme, something like - * I2C now uses, so we can't run out of "dynamic" IDs - */ - ctlr->bus_num = atomic_dec_return(&dyn_bus_id); - dynamic = 1; + mutex_lock(&board_lock); + id = idr_alloc(&spi_master_idr, ctlr, + SPI_DYN_FIRST_BUS_NUM, 0, GFP_KERNEL); + mutex_unlock(&board_lock); + if (WARN(id < 0, "couldn't get idr")) + return id; + + ctlr->bus_num = id; } INIT_LIST_HEAD(&ctlr->queue); @@ -2099,11 +2115,16 @@ int spi_register_controller(struct spi_controller *ctlr) */ dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num); status = device_add(&ctlr->dev); - if (status < 0) + if (status < 0) { + /* free bus id */ + mutex_lock(&board_lock); + idr_remove(&spi_master_idr, ctlr->bus_num); + mutex_unlock(&board_lock); goto done; - dev_dbg(dev, "registered %s %s%s\n", + } + dev_dbg(dev, "registered %s %s\n", spi_controller_is_slave(ctlr) ? "slave" : "master", - dev_name(&ctlr->dev), dynamic ? " (dynamic)" : ""); + dev_name(&ctlr->dev)); /* If we're using a queued driver, start the queue */ if (ctlr->transfer) @@ -2112,6 +2133,10 @@ int spi_register_controller(struct spi_controller *ctlr) status = spi_controller_initialize_queue(ctlr); if (status) { device_del(&ctlr->dev); + /* free bus id */ + mutex_lock(&board_lock); + idr_remove(&spi_master_idr, ctlr->bus_num); + mutex_unlock(&board_lock); goto done; } } @@ -2190,8 +2215,20 @@ static int __unregister(struct device *dev, void *null) */ void spi_unregister_controller(struct spi_controller *ctlr) { + struct spi_controller *found; int dummy; + /* First make sure that this controller was ever added */ + mutex_lock(&board_lock); + found = idr_find(&spi_master_idr, ctlr->bus_num); + mutex_unlock(&board_lock); + if (found != ctlr) { + dev_dbg(&ctlr->dev, + "attempting to delete unregistered controller [%s]\n", + dev_name(&ctlr->dev)); + return; + } + if (ctlr->queued) { if (spi_destroy_queue(ctlr)) dev_err(&ctlr->dev, "queue remove failed\n"); @@ -2203,6 +2240,10 @@ void spi_unregister_controller(struct spi_controller *ctlr) dummy = device_for_each_child(&ctlr->dev, NULL, __unregister); device_unregister(&ctlr->dev); + /* free bus id */ + mutex_lock(&board_lock); + idr_remove(&spi_master_idr, ctlr->bus_num); + mutex_unlock(&board_lock); } EXPORT_SYMBOL_GPL(spi_unregister_controller); -- cgit v1.2.3 From 1673c81d9435bcf758da6ccaa291513e34c1cb82 Mon Sep 17 00:00:00 2001 From: jiada wang Date: Thu, 10 Aug 2017 13:50:08 +0900 Subject: spi: imx: dynamic burst length adjust for PIO mode previously burst length (BURST_LENGTH) is always set to equal to bits_per_word, causes a 10us gap between each word in transfer, which significantly affects performance. This patch uses 32 bits transfer to simulate lower bits transfer, and adjusts burst length runtimely to use biggeest burst length as possible to reduce the gaps in transfer for PIO mode. Signed-off-by: Jiada Wang Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 141 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 930e47597db3..cc808a1c765c 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -56,6 +56,7 @@ /* The maximum bytes that a sdma BD can transfer.*/ #define MAX_SDMA_BD_BYTES (1 << 15) +#define MX51_ECSPI_CTRL_MAX_BURST 512 enum spi_imx_devtype { IMX1_CSPI, @@ -77,6 +78,7 @@ struct spi_imx_devtype_data { void (*reset)(struct spi_imx_data *); bool has_dmamode; unsigned int fifo_size; + bool dynamic_burst; enum spi_imx_devtype devtype; }; @@ -97,12 +99,14 @@ struct spi_imx_data { unsigned int bits_per_word; unsigned int spi_drctl; - unsigned int count; + unsigned int count, remainder; void (*tx)(struct spi_imx_data *); void (*rx)(struct spi_imx_data *); void *rx_buf; const void *tx_buf; unsigned int txfifo; /* number of words pushed in tx FIFO */ + unsigned int dynamic_burst, read_u32; + unsigned int word_mask; /* DMA */ bool usedma; @@ -231,6 +235,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, return false; spi_imx->wml = i; + spi_imx->dynamic_burst = 0; return true; } @@ -245,6 +250,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, #define MX51_ECSPI_CTRL_PREDIV_OFFSET 12 #define MX51_ECSPI_CTRL_CS(cs) ((cs) << 18) #define MX51_ECSPI_CTRL_BL_OFFSET 20 +#define MX51_ECSPI_CTRL_BL_MASK (0xfff << 20) #define MX51_ECSPI_CONFIG 0x0c #define MX51_ECSPI_CONFIG_SCLKPHA(cs) (1 << ((cs) + 0)) @@ -272,6 +278,102 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, #define MX51_ECSPI_TESTREG 0x20 #define MX51_ECSPI_TESTREG_LBC BIT(31) +static void spi_imx_buf_rx_swap_u32(struct spi_imx_data *spi_imx) +{ + unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA); + unsigned int bytes_per_word; + + if (spi_imx->rx_buf) { +#ifdef __LITTLE_ENDIAN + bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word); + if (bytes_per_word == 1) + val = cpu_to_be32(val); + else if (bytes_per_word == 2) + val = (val << 16) | (val >> 16); +#endif + val &= spi_imx->word_mask; + *(u32 *)spi_imx->rx_buf = val; + spi_imx->rx_buf += sizeof(u32); + } +} + +static void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx) +{ + unsigned int bytes_per_word; + + bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word); + if (spi_imx->read_u32) { + spi_imx_buf_rx_swap_u32(spi_imx); + return; + } + + if (bytes_per_word == 1) + spi_imx_buf_rx_u8(spi_imx); + else if (bytes_per_word == 2) + spi_imx_buf_rx_u16(spi_imx); +} + +static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx) +{ + u32 val = 0; + unsigned int bytes_per_word; + + if (spi_imx->tx_buf) { + val = *(u32 *)spi_imx->tx_buf; + val &= spi_imx->word_mask; + spi_imx->tx_buf += sizeof(u32); + } + + spi_imx->count -= sizeof(u32); +#ifdef __LITTLE_ENDIAN + bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word); + + if (bytes_per_word == 1) + val = cpu_to_be32(val); + else if (bytes_per_word == 2) + val = (val << 16) | (val >> 16); +#endif + writel(val, spi_imx->base + MXC_CSPITXDATA); +} + +static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx) +{ + u32 ctrl, val; + unsigned int bytes_per_word; + + if (spi_imx->count == spi_imx->remainder) { + ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL); + ctrl &= ~MX51_ECSPI_CTRL_BL_MASK; + if (spi_imx->count > MX51_ECSPI_CTRL_MAX_BURST) { + spi_imx->remainder = spi_imx->count % + MX51_ECSPI_CTRL_MAX_BURST; + val = MX51_ECSPI_CTRL_MAX_BURST * 8 - 1; + } else if (spi_imx->count >= sizeof(u32)) { + spi_imx->remainder = spi_imx->count % sizeof(u32); + val = (spi_imx->count - spi_imx->remainder) * 8 - 1; + } else { + spi_imx->remainder = 0; + val = spi_imx->bits_per_word - 1; + spi_imx->read_u32 = 0; + } + + ctrl |= (val << MX51_ECSPI_CTRL_BL_OFFSET); + writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); + } + + if (spi_imx->count >= sizeof(u32)) { + spi_imx_buf_tx_swap_u32(spi_imx); + return; + } + + bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word); + + if (bytes_per_word == 1) + spi_imx_buf_tx_u8(spi_imx); + else if (bytes_per_word == 2) + spi_imx_buf_tx_u16(spi_imx); +} + /* MX51 eCSPI */ static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx, unsigned int fspi, unsigned int *fres) @@ -698,6 +800,7 @@ static struct spi_imx_devtype_data imx1_cspi_devtype_data = { .reset = mx1_reset, .fifo_size = 8, .has_dmamode = false, + .dynamic_burst = false, .devtype = IMX1_CSPI, }; @@ -709,6 +812,7 @@ static struct spi_imx_devtype_data imx21_cspi_devtype_data = { .reset = mx21_reset, .fifo_size = 8, .has_dmamode = false, + .dynamic_burst = false, .devtype = IMX21_CSPI, }; @@ -721,6 +825,7 @@ static struct spi_imx_devtype_data imx27_cspi_devtype_data = { .reset = mx21_reset, .fifo_size = 8, .has_dmamode = false, + .dynamic_burst = false, .devtype = IMX27_CSPI, }; @@ -732,6 +837,7 @@ static struct spi_imx_devtype_data imx31_cspi_devtype_data = { .reset = mx31_reset, .fifo_size = 8, .has_dmamode = false, + .dynamic_burst = false, .devtype = IMX31_CSPI, }; @@ -744,6 +850,7 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = { .reset = mx31_reset, .fifo_size = 8, .has_dmamode = true, + .dynamic_burst = false, .devtype = IMX35_CSPI, }; @@ -755,6 +862,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = { .reset = mx51_ecspi_reset, .fifo_size = 64, .has_dmamode = true, + .dynamic_burst = true, .devtype = IMX51_ECSPI, }; @@ -827,6 +935,8 @@ static void spi_imx_push(struct spi_imx_data *spi_imx) while (spi_imx->txfifo < spi_imx->devtype_data->fifo_size) { if (!spi_imx->count) break; + if (spi_imx->txfifo && (spi_imx->count == spi_imx->remainder)) + break; spi_imx->tx(spi_imx); spi_imx->txfifo++; } @@ -920,15 +1030,37 @@ static int spi_imx_setupxfer(struct spi_device *spi, spi_imx->speed_hz = t->speed_hz; /* Initialize the functions for transfer */ - if (spi_imx->bits_per_word <= 8) { - spi_imx->rx = spi_imx_buf_rx_u8; - spi_imx->tx = spi_imx_buf_tx_u8; - } else if (spi_imx->bits_per_word <= 16) { - spi_imx->rx = spi_imx_buf_rx_u16; - spi_imx->tx = spi_imx_buf_tx_u16; + if (spi_imx->devtype_data->dynamic_burst) { + u32 mask; + + spi_imx->dynamic_burst = 0; + spi_imx->remainder = 0; + spi_imx->read_u32 = 1; + + mask = (1 << spi_imx->bits_per_word) - 1; + spi_imx->rx = spi_imx_buf_rx_swap; + spi_imx->tx = spi_imx_buf_tx_swap; + spi_imx->dynamic_burst = 1; + spi_imx->remainder = t->len; + + if (spi_imx->bits_per_word <= 8) + spi_imx->word_mask = mask << 24 | mask << 16 + | mask << 8 | mask; + else if (spi_imx->bits_per_word <= 16) + spi_imx->word_mask = mask << 16 | mask; + else + spi_imx->word_mask = mask; } else { - spi_imx->rx = spi_imx_buf_rx_u32; - spi_imx->tx = spi_imx_buf_tx_u32; + if (spi_imx->bits_per_word <= 8) { + spi_imx->rx = spi_imx_buf_rx_u8; + spi_imx->tx = spi_imx_buf_tx_u8; + } else if (spi_imx->bits_per_word <= 16) { + spi_imx->rx = spi_imx_buf_rx_u16; + spi_imx->tx = spi_imx_buf_tx_u16; + } else { + spi_imx->rx = spi_imx_buf_rx_u32; + spi_imx->tx = spi_imx_buf_tx_u32; + } } if (spi_imx_can_dma(spi_imx->bitbang.master, spi, t)) -- cgit v1.2.3 From 9a9a047a39d9173b0639017e5ba249443e76dd9e Mon Sep 17 00:00:00 2001 From: Suniel Mahesh Date: Thu, 17 Aug 2017 18:18:22 +0530 Subject: spi: Kernel coding style fixes Earlier commit: "spi: Pick spi bus number from Linux idr or spi alias" (SHA1:9b61e302210eba55768962f2f11e96bb508c2408) has introduced some checkpatch issues. As pointed by Lukas Wunner this patch does the following: - remove whitespaces - fix warnings, suspect code indent for conditional statements - fix errors, code indent should use tabs - remove spaces at the start of the line Signed-off-by: Suniel Mahesh Signed-off-by: Mark Brown --- drivers/spi/spi.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index b851888a0a0b..f47d1ccdf292 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -424,7 +424,7 @@ static LIST_HEAD(spi_controller_list); /* * Used to protect add/del opertion for board_info list and * spi_controller list, and their matching process - * also used to protect object of type struct idr + * also used to protect object of type struct idr */ static DEFINE_MUTEX(board_lock); @@ -2075,7 +2075,6 @@ int spi_register_controller(struct spi_controller *ctlr) */ if (ctlr->num_chipselect == 0) return -EINVAL; - /* allocate dynamic bus number using Linux idr */ if ((ctlr->bus_num < 0) && ctlr->dev.of_node) { id = of_alias_get_id(ctlr->dev.of_node, "spi"); @@ -2090,16 +2089,14 @@ int spi_register_controller(struct spi_controller *ctlr) } } if (ctlr->bus_num < 0) { - mutex_lock(&board_lock); - id = idr_alloc(&spi_master_idr, ctlr, - SPI_DYN_FIRST_BUS_NUM, 0, GFP_KERNEL); - mutex_unlock(&board_lock); - if (WARN(id < 0, "couldn't get idr")) - return id; - - ctlr->bus_num = id; + mutex_lock(&board_lock); + id = idr_alloc(&spi_master_idr, ctlr, SPI_DYN_FIRST_BUS_NUM, 0, + GFP_KERNEL); + mutex_unlock(&board_lock); + if (WARN(id < 0, "couldn't get idr")) + return id; + ctlr->bus_num = id; } - INIT_LIST_HEAD(&ctlr->queue); spin_lock_init(&ctlr->queue_lock); spin_lock_init(&ctlr->bus_lock_spinlock); @@ -2222,18 +2219,16 @@ void spi_unregister_controller(struct spi_controller *ctlr) mutex_lock(&board_lock); found = idr_find(&spi_master_idr, ctlr->bus_num); mutex_unlock(&board_lock); - if (found != ctlr) { - dev_dbg(&ctlr->dev, + if (found != ctlr) { + dev_dbg(&ctlr->dev, "attempting to delete unregistered controller [%s]\n", dev_name(&ctlr->dev)); - return; - } - + return; + } if (ctlr->queued) { if (spi_destroy_queue(ctlr)) dev_err(&ctlr->dev, "queue remove failed\n"); } - mutex_lock(&board_lock); list_del(&ctlr->list); mutex_unlock(&board_lock); -- cgit v1.2.3 From b590782afe0a99fca84f451252ed7e2d64b2f155 Mon Sep 17 00:00:00 2001 From: Suniel Mahesh Date: Fri, 18 Aug 2017 11:13:40 +0530 Subject: spi: omap: Allocate bus number from spi framework spi framework should allocate bus number dynamically either via Linux IDR or spi alias for master drivers. This patch deletes code pertaining to manual allocation of spi bus number in spi omap2 master driver. Signed-off-by: Suniel Mahesh Signed-off-by: Karthik Tummala Tested-by: Karthik Tummala Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index e048268d8ba2..9bf64e6eca9b 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1338,7 +1338,6 @@ static int omap2_mcspi_probe(struct platform_device *pdev) struct resource *r; int status = 0, i; u32 regs_offset = 0; - static int bus_num = 1; struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; @@ -1374,14 +1373,11 @@ static int omap2_mcspi_probe(struct platform_device *pdev) of_property_read_u32(node, "ti,spi-num-cs", &num_cs); master->num_chipselect = num_cs; - master->bus_num = bus_num++; if (of_get_property(node, "ti,pindir-d0-out-d1-in", NULL)) mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; } else { pdata = dev_get_platdata(&pdev->dev); master->num_chipselect = pdata->num_cs; - if (pdev->id != -1) - master->bus_num = pdev->id; mcspi->pin_dir = pdata->pin_dir; } regs_offset = pdata->regs_offset; -- cgit v1.2.3 From 5904c9d3c9bd52f79718d1806175271b4bd20718 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 23 Aug 2017 15:34:43 +0200 Subject: spi: imx: fix little-endian build The newly added dynamic burst code produces a harmless warning on big-endian configurations: drivers/spi/spi-imx.c: In function 'spi_imx_buf_rx_swap_u32': drivers/spi/spi-imx.c:284:15: error: unused variable 'bytes_per_word' [-Werror=unused-variable] unsigned int bytes_per_word; ^~~~~~~~~~~~~~ drivers/spi/spi-imx.c: In function 'spi_imx_buf_tx_swap_u32': drivers/spi/spi-imx.c:319:15: error: unused variable 'bytes_per_word' [-Werror=unused-variable] unsigned int bytes_per_word; This adds another #ifdef around the variable declaration matching the one on the use. Fixes: 1673c81d9435 ("spi: imx: dynamic burst length adjust for PIO mode") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index cc808a1c765c..6fcb6adf9565 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -281,7 +281,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, static void spi_imx_buf_rx_swap_u32(struct spi_imx_data *spi_imx) { unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA); +#ifdef __LITTLE_ENDIAN unsigned int bytes_per_word; +#endif if (spi_imx->rx_buf) { #ifdef __LITTLE_ENDIAN @@ -316,7 +318,9 @@ static void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx) static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx) { u32 val = 0; +#ifdef __LITTLE_ENDIAN unsigned int bytes_per_word; +#endif if (spi_imx->tx_buf) { val = *(u32 *)spi_imx->tx_buf; -- cgit v1.2.3 From 5b8d5ad2308d2d5f77c8b9aa47d386a192dbb3c7 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 23 Aug 2017 21:39:58 +0530 Subject: spi: pl022: constify amba_id amba_id are not supposed to change at runtime. All functions working with const amba_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Mark Brown --- drivers/spi/spi-pl022.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 2f76e022cc59..4797c57f4263 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2429,7 +2429,7 @@ static struct vendor_data vendor_lsi = { .internal_cs_ctrl = true, }; -static struct amba_id pl022_ids[] = { +static const struct amba_id pl022_ids[] = { { /* * ARM PL022 variant, this has a 16bit wide -- cgit v1.2.3 From 602c8f4485cd1e6de67e41c78db96fa4f6808e53 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Tue, 11 Jul 2017 14:22:11 +1000 Subject: spi: imx: fix use of native chip-selects with devicetree The commonly used mechanism of specifying the hardware or native chip-select on an SPI device in devicetree (that is "cs-gpios = <0>") does not result in the native chip-select being configured for use. So external SPI devices that require use of the native chip-select will not work. You can successfully specify native chip-selects if using a platform setup by specifying the cs-gpio as negative offset by 32. And that works correctly. You cannot use the same method in devicetree. The logic in the spi-imx.c driver during probe uses core spi function of_spi_register_master() in spi.c to parse the "cs-gpios" devicetree tag. For valid GPIO values that will be recorded for use, all other entries in the cs_gpios list will be set to -ENOENT. So entries like "<0>" will be set to -ENOENT in the cs_gpios list. When the SPI device registers are setup the code will use the GPIO listed in the cs_gpios list for the desired chip-select. If the cs_gpio is less then 0 then it is intended to be for a native chip-select, and its cs_gpio value is added to 32 to get the chipselect number to use. Problem is that with devicetree this can only ever be -ENOENT (which is -2), and that alone results in an invalid chip-select number. But also doesn't allow selection of the native chip-select at all. To fix, if the cs_gpio specified for this spi device is not a valid GPIO then use the "chip_select" (that is the native chip-select number) for hardware setup. Signed-off-by: Greg Ungerer Reviewed-by: Vladimir Zapolskiy Tested-by: Vladimir Zapolskiy Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 6fcb6adf9565..babb15f07995 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -622,8 +622,8 @@ static int mx31_config(struct spi_device *spi) reg |= MX31_CSPICTRL_POL; if (spi->mode & SPI_CS_HIGH) reg |= MX31_CSPICTRL_SSPOL; - if (spi->cs_gpio < 0) - reg |= (spi->cs_gpio + 32) << + if (!gpio_is_valid(spi->cs_gpio)) + reg |= (spi->chip_select) << (is_imx35_cspi(spi_imx) ? MX35_CSPICTRL_CS_SHIFT : MX31_CSPICTRL_CS_SHIFT); @@ -714,8 +714,8 @@ static int mx21_config(struct spi_device *spi) reg |= MX21_CSPICTRL_POL; if (spi->mode & SPI_CS_HIGH) reg |= MX21_CSPICTRL_SSPOL; - if (spi->cs_gpio < 0) - reg |= (spi->cs_gpio + 32) << MX21_CSPICTRL_CS_SHIFT; + if (!gpio_is_valid(spi->cs_gpio)) + reg |= spi->chip_select << MX21_CSPICTRL_CS_SHIFT; writel(reg, spi_imx->base + MXC_CSPICTRL); -- cgit v1.2.3 From 1a41aa1376df9e24d0c760df1a6f59765316c457 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 20 Aug 2017 00:18:10 +0200 Subject: spi: spi-falcon: drop check of boot select Do not check which flash type the SoC was booted from before using this driver. Assume that the device tree is correct and use this driver when it was added to device tree. This also removes a build dependency to the SoC code. All device trees I am aware of only have one correct flash device entry in it. The device tree is anyway bundled with the kernel in all systems using device tree I know of. The boot mode can be specified with some pin straps and will select the flash type the rom code will boot from. One SPI, NOR or NAND flash chip can be connect to the EBU and used to load the first stage boot loader from. Signed-off-by: Hauke Mehrtens Cc: Mark Brown Cc: linux-spi@vger.kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-falcon.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c index 286b2c81fc6b..f8638e82e5db 100644 --- a/drivers/spi/spi-falcon.c +++ b/drivers/spi/spi-falcon.c @@ -395,11 +395,6 @@ static int falcon_sflash_probe(struct platform_device *pdev) struct spi_master *master; int ret; - if (ltq_boot_select() != BS_SPI) { - dev_err(&pdev->dev, "invalid bootstrap options\n"); - return -ENODEV; - } - master = spi_alloc_master(&pdev->dev, sizeof(*priv)); if (!master) return -ENOMEM; -- cgit v1.2.3