From 10e413faa72c6f728ead2c6cc140f834af7bee8d Mon Sep 17 00:00:00 2001 From: zhengbin Date: Thu, 28 Nov 2019 10:51:52 +0800 Subject: spi/topcliff-pch: Remove unneeded semicolon Fixes coccicheck warning: drivers/spi/spi-topcliff-pch.c:866:47-48: Unneeded semicolon drivers/spi/spi-topcliff-pch.c:881:53-54: Unneeded semicolon Reported-by: Hulk Robot Signed-off-by: zhengbin Link: https://lore.kernel.org/r/1574909512-24260-1-git-send-email-zhengbin13@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-topcliff-pch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 223353fa2d8a..d7ea6af74743 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -863,7 +863,7 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw) /* Set Tx DMA */ param = &dma->param_tx; param->dma_dev = &dma_dev->dev; - param->chan_id = data->ch * 2; /* Tx = 0, 2 */; + param->chan_id = data->ch * 2; /* Tx = 0, 2 */ param->tx_reg = data->io_base_addr + PCH_SPDWR; param->width = width; chan = dma_request_channel(mask, pch_spi_filter, param); @@ -878,7 +878,7 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw) /* Set Rx DMA */ param = &dma->param_rx; param->dma_dev = &dma_dev->dev; - param->chan_id = data->ch * 2 + 1; /* Rx = Tx + 1 */; + param->chan_id = data->ch * 2 + 1; /* Rx = Tx + 1 */ param->rx_reg = data->io_base_addr + PCH_SPDRR; param->width = width; chan = dma_request_channel(mask, pch_spi_filter, param); -- cgit v1.2.3 From 8a6553ecdf976d6a34664bd491f0ea74a15aa982 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 5 Dec 2019 09:34:01 +0100 Subject: spi: stm32: Switch to use GPIO descriptors for CS This switches the STM32 SPI driver over to using GPIO descriptors for chip select. Instead of the callbacks for picking the GPIO lines using the legacy API we just let the core handle it all using descriptors. Cc: Fabien Dessenne Cc: Amelie Delaunay Cc: Cezary Gapinski Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20191205083401.27077-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 47 +++-------------------------------------------- 1 file changed, 3 insertions(+), 44 deletions(-) diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index b222ce8d083e..7d75632c4151 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -973,29 +972,6 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) return IRQ_HANDLED; } -/** - * stm32_spi_setup - setup device chip select - */ -static int stm32_spi_setup(struct spi_device *spi_dev) -{ - int ret = 0; - - if (!gpio_is_valid(spi_dev->cs_gpio)) { - dev_err(&spi_dev->dev, "%d is not a valid gpio\n", - spi_dev->cs_gpio); - return -EINVAL; - } - - dev_dbg(&spi_dev->dev, "%s: set gpio%d output %s\n", __func__, - spi_dev->cs_gpio, - (spi_dev->mode & SPI_CS_HIGH) ? "low" : "high"); - - ret = gpio_direction_output(spi_dev->cs_gpio, - !(spi_dev->mode & SPI_CS_HIGH)); - - return ret; -} - /** * stm32_spi_prepare_msg - set up the controller to transfer a single message */ @@ -1810,7 +1786,7 @@ static int stm32_spi_probe(struct platform_device *pdev) struct spi_master *master; struct stm32_spi *spi; struct resource *res; - int i, ret; + int ret; master = spi_alloc_master(&pdev->dev, sizeof(struct stm32_spi)); if (!master) { @@ -1898,7 +1874,7 @@ static int stm32_spi_probe(struct platform_device *pdev) master->bits_per_word_mask = spi->cfg->get_bpw_mask(spi); master->max_speed_hz = spi->clk_rate / spi->cfg->baud_rate_div_min; master->min_speed_hz = spi->clk_rate / spi->cfg->baud_rate_div_max; - master->setup = stm32_spi_setup; + master->use_gpio_descriptors = true; master->prepare_message = stm32_spi_prepare_msg; master->transfer_one = stm32_spi_transfer_one; master->unprepare_message = stm32_spi_unprepare_msg; @@ -1928,29 +1904,12 @@ static int stm32_spi_probe(struct platform_device *pdev) goto err_dma_release; } - if (!master->cs_gpios) { + if (!master->cs_gpiods) { dev_err(&pdev->dev, "no CS gpios available\n"); ret = -EINVAL; goto err_dma_release; } - for (i = 0; i < master->num_chipselect; i++) { - if (!gpio_is_valid(master->cs_gpios[i])) { - dev_err(&pdev->dev, "%i is not a valid gpio\n", - master->cs_gpios[i]); - ret = -EINVAL; - goto err_dma_release; - } - - ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i], - DRIVER_NAME); - if (ret) { - dev_err(&pdev->dev, "can't get CS gpio %i\n", - master->cs_gpios[i]); - goto err_dma_release; - } - } - dev_info(&pdev->dev, "driver initialized\n"); return 0; -- cgit v1.2.3 From 4a07b8bcd503c842bcf0171cdbccdfdac3d985c3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 5 Dec 2019 10:13:40 +0100 Subject: spi: bitbang: Make chipselect callback optional The ->chipselect() callback on the bit-banged SPI library master is optional if using GPIO descriptors: when using descriptors exclusively without any native chipselects, the core does not even call out the the native ->set_cs() and therefore ->chipselect() on a bit-banged SPI master will not even be called in this case. Make sure to respect the SPI_MASTER_GPIO_SS as used by e.g. spi-gpio.c though: this setting will make the core handle the chip select using GPIO descriptors *AND* call the local chipselect handler. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20191205091340.59850-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index d84e22dd6f9f..68491a8bf7b5 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -329,8 +329,20 @@ static void spi_bitbang_set_cs(struct spi_device *spi, bool enable) int spi_bitbang_init(struct spi_bitbang *bitbang) { struct spi_master *master = bitbang->master; + bool custom_cs; - if (!master || !bitbang->chipselect) + if (!master) + return -EINVAL; + /* + * We only need the chipselect callback if we are actually using it. + * If we just use GPIO descriptors, it is surplus. If the + * SPI_MASTER_GPIO_SS flag is set, we always need to call the + * driver-specific chipselect routine. + */ + custom_cs = (!master->use_gpio_descriptors || + (master->flags & SPI_MASTER_GPIO_SS)); + + if (custom_cs && !bitbang->chipselect) return -EINVAL; mutex_init(&bitbang->lock); @@ -344,7 +356,12 @@ int spi_bitbang_init(struct spi_bitbang *bitbang) master->prepare_transfer_hardware = spi_bitbang_prepare_hardware; master->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware; master->transfer_one = spi_bitbang_transfer_one; - master->set_cs = spi_bitbang_set_cs; + /* + * When using GPIO descriptors, the ->set_cs() callback doesn't even + * get called unless SPI_MASTER_GPIO_SS is set. + */ + if (custom_cs) + master->set_cs = spi_bitbang_set_cs; if (!bitbang->txrx_bufs) { bitbang->use_dma = 0; -- cgit v1.2.3 From 169f9acae08685d4f2a6fd32983958d44e10905d Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Thu, 5 Dec 2019 17:14:21 -0600 Subject: spi: dw: Avoid BUG_ON() in case of host failure If dws is NULL in dw_spi_host_add(), we return the error to the upper callers instead of crashing. The patch replaces BUG_ON by returning -EINVAL to the caller. Signed-off-by: Aditya Pakki Link: https://lore.kernel.org/r/20191205231421.9333-1-pakki001@umn.edu Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index a92aa5cd4fbe..a160d9a141ea 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -460,7 +460,8 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) struct spi_controller *master; int ret; - BUG_ON(dws == NULL); + if (!dws) + return -EINVAL; master = spi_alloc_master(dev, 0); if (!master) -- cgit v1.2.3 From 851c902fd2d09b2ed85181e74b43477b7a3882be Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 11 Dec 2019 14:15:53 +0100 Subject: spi: rspi: Remove obsolete platform_device_id entries Since commits 05104c266ae9a167 ("ARM: shmobile: r7s72100: genmai: Remove legacy board file") and a483dcbfa21f919c ("ARM: shmobile: lager: Remove legacy board support", RZ/A1 and R-Car Gen2 SoCs are only supported in generic DT-only ARM multi-platform builds. The driver doesn't need to match platform devices by name anymore for these platforms, hence remove the corresponding platform_device_id entries. The platform_device_id entry for "rspi" is retained, as it is used by the SH7757 platform, which hasn't been converted to DT yet. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Link: https://lore.kernel.org/r/20191211131553.23960-1-geert+renesas@glider.be Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 7222c7689c3c..74a12f4dee84 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -1314,8 +1314,6 @@ error1: static const struct platform_device_id spi_driver_ids[] = { { "rspi", (kernel_ulong_t)&rspi_ops }, - { "rspi-rz", (kernel_ulong_t)&rspi_rz_ops }, - { "qspi", (kernel_ulong_t)&qspi_ops }, {}, }; -- cgit v1.2.3 From d947c9d26c2381cc10067e76e71bf9ddb0fedb8b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 12 Dec 2019 15:55:42 +0200 Subject: spi: atmel: Use dma_request_chan() instead dma_request_slave_channel() dma_request_slave_channel() is a wrapper on top of dma_request_chan() eating up the error code. By using dma_request_chan() directly the driver can support deferred probing against DMA. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191212135550.4634-2-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 56f0ca361deb..013458cabe3c 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -514,26 +514,19 @@ static int atmel_spi_configure_dma(struct spi_master *master, master->dma_tx = dma_request_chan(dev, "tx"); if (IS_ERR(master->dma_tx)) { err = PTR_ERR(master->dma_tx); - if (err == -EPROBE_DEFER) { - dev_warn(dev, "no DMA channel available at the moment\n"); - goto error_clear; - } - dev_err(dev, - "DMA TX channel not available, SPI unable to use DMA\n"); - err = -EBUSY; + if (err != -EPROBE_DEFER) + dev_err(dev, "No TX DMA channel, DMA is disabled\n"); goto error_clear; } - /* - * No reason to check EPROBE_DEFER here since we have already requested - * tx channel. If it fails here, it's for another reason. - */ - master->dma_rx = dma_request_slave_channel(dev, "rx"); - - if (!master->dma_rx) { - dev_err(dev, - "DMA RX channel not available, SPI unable to use DMA\n"); - err = -EBUSY; + master->dma_rx = dma_request_chan(dev, "rx"); + if (IS_ERR(master->dma_rx)) { + err = PTR_ERR(master->dma_rx); + /* + * No reason to check EPROBE_DEFER here since we have already + * requested tx channel. + */ + dev_err(dev, "No RX DMA channel, DMA is disabled\n"); goto error; } @@ -548,7 +541,7 @@ static int atmel_spi_configure_dma(struct spi_master *master, return 0; error: - if (master->dma_rx) + if (!IS_ERR(master->dma_rx)) dma_release_channel(master->dma_rx); if (!IS_ERR(master->dma_tx)) dma_release_channel(master->dma_tx); -- cgit v1.2.3 From 666224b43b4bd4612ce3b758c038f9bc5c5e3fcb Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 12 Dec 2019 15:55:43 +0200 Subject: spi: bcm2835: Release the DMA channel if probe fails after dma_init The DMA channel was not released if either devm_request_irq() or devm_spi_register_controller() failed. Signed-off-by: Peter Ujfalusi Reviewed-by: Nicolas Saenz Julienne Link: https://lore.kernel.org/r/20191212135550.4634-3-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index fb61a620effc..662d55e9f21d 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -1327,20 +1327,22 @@ static int bcm2835_spi_probe(struct platform_device *pdev) dev_name(&pdev->dev), ctlr); if (err) { dev_err(&pdev->dev, "could not request IRQ: %d\n", err); - goto out_clk_disable; + goto out_dma_release; } err = devm_spi_register_controller(&pdev->dev, ctlr); if (err) { dev_err(&pdev->dev, "could not register SPI controller: %d\n", err); - goto out_clk_disable; + goto out_dma_release; } bcm2835_debugfs_create(bs, dev_name(&pdev->dev)); return 0; +out_dma_release: + bcm2835_dma_release(ctlr, bs); out_clk_disable: clk_disable_unprepare(bs->clk); out_controller_put: -- cgit v1.2.3 From 6133fed0539bc5c059d3a661b61704159ba448a6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 12 Dec 2019 15:55:44 +0200 Subject: spi: bcm2835: Use dma_request_chan() instead dma_request_slave_channel() dma_request_slave_channel() is a wrapper on top of dma_request_chan() eating up the error code. By using dma_request_chan() directly the driver can support deferred probing against DMA. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191212135550.4634-4-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 662d55e9f21d..69df79914504 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -888,8 +888,8 @@ static void bcm2835_dma_release(struct spi_controller *ctlr, } } -static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, - struct bcm2835_spi *bs) +static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, + struct bcm2835_spi *bs) { struct dma_slave_config slave_config; const __be32 *addr; @@ -900,19 +900,24 @@ static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, addr = of_get_address(ctlr->dev.of_node, 0, NULL, NULL); if (!addr) { dev_err(dev, "could not get DMA-register address - not using dma mode\n"); - goto err; + /* Fall back to interrupt mode */ + return 0; } dma_reg_base = be32_to_cpup(addr); /* get tx/rx dma */ - ctlr->dma_tx = dma_request_slave_channel(dev, "tx"); - if (!ctlr->dma_tx) { + ctlr->dma_tx = dma_request_chan(dev, "tx"); + if (IS_ERR(ctlr->dma_tx)) { dev_err(dev, "no tx-dma configuration found - not using dma mode\n"); + ret = PTR_ERR(ctlr->dma_tx); + ctlr->dma_tx = NULL; goto err; } - ctlr->dma_rx = dma_request_slave_channel(dev, "rx"); - if (!ctlr->dma_rx) { + ctlr->dma_rx = dma_request_chan(dev, "rx"); + if (IS_ERR(ctlr->dma_rx)) { dev_err(dev, "no rx-dma configuration found - not using dma mode\n"); + ret = PTR_ERR(ctlr->dma_rx); + ctlr->dma_rx = NULL; goto err_release; } @@ -997,7 +1002,7 @@ static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, /* all went well, so set can_dma */ ctlr->can_dma = bcm2835_spi_can_dma; - return; + return 0; err_config: dev_err(dev, "issue configuring dma: %d - not using DMA mode\n", @@ -1005,7 +1010,14 @@ err_config: err_release: bcm2835_dma_release(ctlr, bs); err: - return; + /* + * Only report error for deferred probing, otherwise fall back to + * interrupt mode + */ + if (ret != -EPROBE_DEFER) + ret = 0; + + return ret; } static int bcm2835_spi_transfer_one_poll(struct spi_controller *ctlr, @@ -1317,7 +1329,9 @@ static int bcm2835_spi_probe(struct platform_device *pdev) clk_prepare_enable(bs->clk); - bcm2835_dma_init(ctlr, &pdev->dev, bs); + err = bcm2835_dma_init(ctlr, &pdev->dev, bs); + if (err) + goto out_clk_disable; /* initialise the hardware with the default polarities */ bcm2835_wr(bs, BCM2835_SPI_CS, -- cgit v1.2.3 From 6bfbf4d0aa0c5ebfd4442e1200b21565703e90ed Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 12 Dec 2019 15:55:45 +0200 Subject: spi: img-spfi: Use dma_request_chan() instead dma_request_slave_channel() dma_request_slave_channel() is a wrapper on top of dma_request_chan() eating up the error code. By using dma_request_chan() directly the driver can support deferred probing against DMA. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191212135550.4634-5-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-img-spfi.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index f4a8f470aecc..8543f5ed1099 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -666,8 +666,22 @@ static int img_spfi_probe(struct platform_device *pdev) master->unprepare_message = img_spfi_unprepare; master->handle_err = img_spfi_handle_err; - spfi->tx_ch = dma_request_slave_channel(spfi->dev, "tx"); - spfi->rx_ch = dma_request_slave_channel(spfi->dev, "rx"); + spfi->tx_ch = dma_request_chan(spfi->dev, "tx"); + if (IS_ERR(spfi->tx_ch)) { + ret = PTR_ERR(spfi->tx_ch); + spfi->tx_ch = NULL; + if (ret == -EPROBE_DEFER) + goto disable_pm; + } + + spfi->rx_ch = dma_request_chan(spfi->dev, "rx"); + if (IS_ERR(spfi->rx_ch)) { + ret = PTR_ERR(spfi->rx_ch); + spfi->rx_ch = NULL; + if (ret == -EPROBE_DEFER) + goto disable_pm; + } + if (!spfi->tx_ch || !spfi->rx_ch) { if (spfi->tx_ch) dma_release_channel(spfi->tx_ch); -- cgit v1.2.3 From 7ccffd41b2d4d180dcdcc03c54c446621e34bca5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 12 Dec 2019 15:55:46 +0200 Subject: spi: mxs: Use dma_request_chan() instead dma_request_slave_channel() dma_request_slave_channel() is a wrapper on top of dma_request_chan() eating up the error code. By using dma_request_chan() directly the driver can support deferred probing against DMA. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191212135550.4634-6-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-mxs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 996c1c8a9c71..dce85ee07cd0 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -590,10 +590,10 @@ static int mxs_spi_probe(struct platform_device *pdev) if (ret) goto out_master_free; - ssp->dmach = dma_request_slave_channel(&pdev->dev, "rx-tx"); - if (!ssp->dmach) { + ssp->dmach = dma_request_chan(&pdev->dev, "rx-tx"); + if (IS_ERR(ssp->dmach)) { dev_err(ssp->dev, "Failed to request DMA\n"); - ret = -ENODEV; + ret = PTR_ERR(ssp->dmach); goto out_master_free; } -- cgit v1.2.3 From 401abb764abb6e42f539528e02127457eb0c5b32 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 12 Dec 2019 15:55:47 +0200 Subject: spi: sirf: Use dma_request_chan() instead dma_request_slave_channel() dma_request_slave_channel() is a wrapper on top of dma_request_chan() eating up the error code. By using dma_request_chan() directly the driver can support deferred probing against DMA. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191212135550.4634-7-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index e1e639191557..8419e6722e17 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -1126,16 +1126,16 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) sspi->bitbang.master->dev.of_node = pdev->dev.of_node; /* request DMA channels */ - sspi->rx_chan = dma_request_slave_channel(&pdev->dev, "rx"); - if (!sspi->rx_chan) { + sspi->rx_chan = dma_request_chan(&pdev->dev, "rx"); + if (IS_ERR(sspi->rx_chan)) { dev_err(&pdev->dev, "can not allocate rx dma channel\n"); - ret = -ENODEV; + ret = PTR_ERR(sspi->rx_chan); goto free_master; } - sspi->tx_chan = dma_request_slave_channel(&pdev->dev, "tx"); - if (!sspi->tx_chan) { + sspi->tx_chan = dma_request_chan(&pdev->dev, "tx"); + if (IS_ERR(sspi->tx_chan)) { dev_err(&pdev->dev, "can not allocate tx dma channel\n"); - ret = -ENODEV; + ret = PTR_ERR(sspi->tx_chan); goto free_rx_dma; } -- cgit v1.2.3 From b5756b777472eceaa84bc180f458f8eaec65da9a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 12 Dec 2019 15:55:48 +0200 Subject: spi: spi-fsl-dspi: Use dma_request_chan() instead dma_request_slave_channel() dma_request_slave_channel() is a wrapper on top of dma_request_chan() eating up the error code. By using dma_request_chan() directly the driver can support deferred probing against DMA. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191212135550.4634-8-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-dspi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 442cff71a0d2..52ccd8397c35 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -395,17 +395,17 @@ static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr) if (!dma) return -ENOMEM; - dma->chan_rx = dma_request_slave_channel(dev, "rx"); - if (!dma->chan_rx) { + dma->chan_rx = dma_request_chan(dev, "rx"); + if (IS_ERR(dma->chan_rx)) { dev_err(dev, "rx dma channel not available\n"); - ret = -ENODEV; + ret = PTR_ERR(dma->chan_rx); return ret; } - dma->chan_tx = dma_request_slave_channel(dev, "tx"); - if (!dma->chan_tx) { + dma->chan_tx = dma_request_chan(dev, "tx"); + if (IS_ERR(dma->chan_tx)) { dev_err(dev, "tx dma channel not available\n"); - ret = -ENODEV; + ret = PTR_ERR(dma->chan_tx); goto err_tx_channel; } -- cgit v1.2.3 From 658606ff4cf680ca97380f6ed7295722b0e991b2 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 12 Dec 2019 15:55:49 +0200 Subject: spi: stm32-qspi: Use dma_request_chan() instead dma_request_slave_channel() dma_request_slave_channel() is a wrapper on top of dma_request_chan() eating up the error code. By using dma_request_chan() directly the driver can support deferred probing against DMA. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191212135550.4634-9-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-stm32-qspi.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 4e726929bb4f..4ef569b47aa6 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -470,10 +470,11 @@ static int stm32_qspi_setup(struct spi_device *spi) return 0; } -static void stm32_qspi_dma_setup(struct stm32_qspi *qspi) +static int stm32_qspi_dma_setup(struct stm32_qspi *qspi) { struct dma_slave_config dma_cfg; struct device *dev = qspi->dev; + int ret = 0; memset(&dma_cfg, 0, sizeof(dma_cfg)); @@ -484,8 +485,13 @@ static void stm32_qspi_dma_setup(struct stm32_qspi *qspi) dma_cfg.src_maxburst = 4; dma_cfg.dst_maxburst = 4; - qspi->dma_chrx = dma_request_slave_channel(dev, "rx"); - if (qspi->dma_chrx) { + qspi->dma_chrx = dma_request_chan(dev, "rx"); + if (IS_ERR(qspi->dma_chrx)) { + ret = PTR_ERR(qspi->dma_chrx); + qspi->dma_chrx = NULL; + if (ret == -EPROBE_DEFER) + goto out; + } else { if (dmaengine_slave_config(qspi->dma_chrx, &dma_cfg)) { dev_err(dev, "dma rx config failed\n"); dma_release_channel(qspi->dma_chrx); @@ -493,8 +499,11 @@ static void stm32_qspi_dma_setup(struct stm32_qspi *qspi) } } - qspi->dma_chtx = dma_request_slave_channel(dev, "tx"); - if (qspi->dma_chtx) { + qspi->dma_chtx = dma_request_chan(dev, "tx"); + if (IS_ERR(qspi->dma_chtx)) { + ret = PTR_ERR(qspi->dma_chtx); + qspi->dma_chtx = NULL; + } else { if (dmaengine_slave_config(qspi->dma_chtx, &dma_cfg)) { dev_err(dev, "dma tx config failed\n"); dma_release_channel(qspi->dma_chtx); @@ -502,7 +511,13 @@ static void stm32_qspi_dma_setup(struct stm32_qspi *qspi) } } +out: init_completion(&qspi->dma_completion); + + if (ret != -EPROBE_DEFER) + ret = 0; + + return ret; } static void stm32_qspi_dma_free(struct stm32_qspi *qspi) @@ -608,7 +623,10 @@ static int stm32_qspi_probe(struct platform_device *pdev) qspi->dev = dev; platform_set_drvdata(pdev, qspi); - stm32_qspi_dma_setup(qspi); + ret = stm32_qspi_dma_setup(qspi); + if (ret) + goto err; + mutex_init(&qspi->lock); ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD -- cgit v1.2.3 From 0a454258febb73e4c60d7f5d9a02d1a8c64fdfb8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 12 Dec 2019 15:55:50 +0200 Subject: spi: stm32: Use dma_request_chan() instead dma_request_slave_channel() dma_request_slave_channel() is a wrapper on top of dma_request_chan() eating up the error code. By using dma_request_chan() directly the driver can support deferred probing against DMA. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20191212135550.4634-10-peter.ujfalusi@ti.com Signed-off-by: Mark Brown --- drivers/spi/spi-stm32.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 7d75632c4151..e041f9c4ec47 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -1879,17 +1879,29 @@ static int stm32_spi_probe(struct platform_device *pdev) master->transfer_one = stm32_spi_transfer_one; master->unprepare_message = stm32_spi_unprepare_msg; - spi->dma_tx = dma_request_slave_channel(spi->dev, "tx"); - if (!spi->dma_tx) + spi->dma_tx = dma_request_chan(spi->dev, "tx"); + if (IS_ERR(spi->dma_tx)) { + ret = PTR_ERR(spi->dma_tx); + spi->dma_tx = NULL; + if (ret == -EPROBE_DEFER) + goto err_clk_disable; + dev_warn(&pdev->dev, "failed to request tx dma channel\n"); - else + } else { master->dma_tx = spi->dma_tx; + } + + spi->dma_rx = dma_request_chan(spi->dev, "rx"); + if (IS_ERR(spi->dma_rx)) { + ret = PTR_ERR(spi->dma_rx); + spi->dma_rx = NULL; + if (ret == -EPROBE_DEFER) + goto err_dma_release; - spi->dma_rx = dma_request_slave_channel(spi->dev, "rx"); - if (!spi->dma_rx) dev_warn(&pdev->dev, "failed to request rx dma channel\n"); - else + } else { master->dma_rx = spi->dma_rx; + } if (spi->dma_tx || spi->dma_rx) master->can_dma = stm32_spi_can_dma; @@ -1901,26 +1913,26 @@ static int stm32_spi_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "spi master registration failed: %d\n", ret); - goto err_dma_release; + goto err_pm_disable; } if (!master->cs_gpiods) { dev_err(&pdev->dev, "no CS gpios available\n"); ret = -EINVAL; - goto err_dma_release; + goto err_pm_disable; } dev_info(&pdev->dev, "driver initialized\n"); return 0; +err_pm_disable: + pm_runtime_disable(&pdev->dev); err_dma_release: if (spi->dma_tx) dma_release_channel(spi->dma_tx); if (spi->dma_rx) dma_release_channel(spi->dma_rx); - - pm_runtime_disable(&pdev->dev); err_clk_disable: clk_disable_unprepare(spi->clk); err_master_put: -- cgit v1.2.3 From cd8fb859a84c1c4f985a582b79050116d2c30c47 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 5 Dec 2019 09:39:15 +0100 Subject: spi: meson-spicc: Use GPIO descriptors Instead of grabbing GPIOs using the legacy interface and handling them in the setup callback, just let the core grab and use the GPIOs using descriptors. Cc: Neil Armstrong Cc: Sunny Luo Signed-off-by: Linus Walleij Acked-by: Neil Armstrong Link: https://lore.kernel.org/r/20191205083915.27650-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-meson-spicc.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index f3f10443f9e2..7f5680fe2568 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -19,7 +19,6 @@ #include #include #include -#include /* * The Meson SPICC controller could support DMA based transfers, but is not @@ -467,35 +466,14 @@ static int meson_spicc_unprepare_transfer(struct spi_master *master) static int meson_spicc_setup(struct spi_device *spi) { - int ret = 0; - if (!spi->controller_state) spi->controller_state = spi_master_get_devdata(spi->master); - else if (gpio_is_valid(spi->cs_gpio)) - goto out_gpio; - else if (spi->cs_gpio == -ENOENT) - return 0; - - if (gpio_is_valid(spi->cs_gpio)) { - ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev)); - if (ret) { - dev_err(&spi->dev, "failed to request cs gpio\n"); - return ret; - } - } - -out_gpio: - ret = gpio_direction_output(spi->cs_gpio, - !(spi->mode & SPI_CS_HIGH)); - return ret; + return 0; } static void meson_spicc_cleanup(struct spi_device *spi) { - if (gpio_is_valid(spi->cs_gpio)) - gpio_free(spi->cs_gpio); - spi->controller_state = NULL; } @@ -564,6 +542,7 @@ static int meson_spicc_probe(struct platform_device *pdev) master->prepare_message = meson_spicc_prepare_message; master->unprepare_transfer_hardware = meson_spicc_unprepare_transfer; master->transfer_one = meson_spicc_transfer_one; + master->use_gpio_descriptors = true; /* Setup max rate according to the Meson GX datasheet */ if ((rate >> 2) > SPICC_MAX_FREQ) -- cgit v1.2.3 From c1795f7cee026b066485de794cff4e5bb9475a98 Mon Sep 17 00:00:00 2001 From: Jean Pihet Date: Wed, 11 Dec 2019 20:39:52 +0100 Subject: spi: spi-ti-qspi: Remove unused macro for fclk frequency The fclk and its rate are retrieved from DT. Signed-off-by: Jean Pihet Cc: Ryan Barnett Cc: Conrad Ratschan Cc: Arnout Vandecappelle Link: https://lore.kernel.org/r/20191211193954.747745-2-jean.pihet@newoldbits.com Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 3cb65371ae3b..a18835128ad0 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -79,8 +79,6 @@ struct ti_qspi { #define QSPI_COMPLETION_TIMEOUT msecs_to_jiffies(2000) -#define QSPI_FCLK 192000000 - /* Clock Control */ #define QSPI_CLK_EN (1 << 31) #define QSPI_CLK_DIV_MAX 0xffff -- cgit v1.2.3 From f4dc4abdce4cc290555604107c04854a911b9441 Mon Sep 17 00:00:00 2001 From: Jim Quinlan Date: Mon, 16 Dec 2019 18:08:02 -0500 Subject: spi: bcm2835: no dev_err() on clk_get() -EPROBE_DEFER Use dev_dbg() on -EPROBE_DEFER and dev_err() on all other errors. Signed-off-by: Jim Quinlan Reviewed-by: Florian Fainelli Reviewed-by: Nicolas Saenz Julienne Link: https://lore.kernel.org/r/20191216230802.45715-2-jquinlan@broadcom.com Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 69df79914504..b784c9fdf9ec 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -1317,7 +1317,10 @@ static int bcm2835_spi_probe(struct platform_device *pdev) bs->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(bs->clk)) { err = PTR_ERR(bs->clk); - dev_err(&pdev->dev, "could not get clk: %d\n", err); + if (err == -EPROBE_DEFER) + dev_dbg(&pdev->dev, "could not get clk: %d\n", err); + else + dev_err(&pdev->dev, "could not get clk: %d\n", err); goto out_controller_put; } -- cgit v1.2.3 From ef32b63bf13e531479a3b1ef6eb2daaf4fcf787a Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Tue, 17 Dec 2019 10:07:15 +0100 Subject: dt-bindings: spi: Convert stm32 spi bindings to json-schema Convert the STM32 spi binding to DT schema format using json-schema Signed-off-by: Benjamin Gaignard CC: Erwan Leray CC: Fabrice Gasnier CC: Amelie Delaunay Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20191217090715.13334-1-benjamin.gaignard@st.com Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-stm32.txt | 62 ------------ .../devicetree/bindings/spi/st,stm32-spi.yaml | 105 +++++++++++++++++++++ 2 files changed, 105 insertions(+), 62 deletions(-) delete mode 100644 Documentation/devicetree/bindings/spi/spi-stm32.txt create mode 100644 Documentation/devicetree/bindings/spi/st,stm32-spi.yaml diff --git a/Documentation/devicetree/bindings/spi/spi-stm32.txt b/Documentation/devicetree/bindings/spi/spi-stm32.txt deleted file mode 100644 index d82755c63eaf..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-stm32.txt +++ /dev/null @@ -1,62 +0,0 @@ -STMicroelectronics STM32 SPI Controller - -The STM32 SPI controller is used to communicate with external devices using -the Serial Peripheral Interface. It supports full-duplex, half-duplex and -simplex synchronous serial communication with external devices. It supports -from 4 to 32-bit data size. Although it can be configured as master or slave, -only master is supported by the driver. - -Required properties: -- compatible: Should be one of: - "st,stm32h7-spi" - "st,stm32f4-spi" -- reg: Offset and length of the device's register set. -- interrupts: Must contain the interrupt id. -- clocks: Must contain an entry for spiclk (which feeds the internal clock - generator). -- #address-cells: Number of cells required to define a chip select address. -- #size-cells: Should be zero. - -Optional properties: -- resets: Must contain the phandle to the reset controller. -- A pinctrl state named "default" may be defined to set pins in mode of - operation for SPI transfer. -- dmas: DMA specifiers for tx and rx dma. DMA fifo mode must be used. See the - STM32 DMA bindings, Documentation/devicetree/bindings/dma/stm32-dma.txt. -- dma-names: DMA request names should include "tx" and "rx" if present. -- cs-gpios: list of GPIO chip selects. See the SPI bus bindings, - Documentation/devicetree/bindings/spi/spi-bus.txt - - -Child nodes represent devices on the SPI bus - See ../spi/spi-bus.txt - -Optional properties: -- st,spi-midi-ns: Only for STM32H7, (Master Inter-Data Idleness) minimum time - delay in nanoseconds inserted between two consecutive data - frames. - - -Example: - spi2: spi@40003800 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "st,stm32h7-spi"; - reg = <0x40003800 0x400>; - interrupts = <36>; - clocks = <&rcc SPI2_CK>; - resets = <&rcc 1166>; - dmas = <&dmamux1 0 39 0x400 0x01>, - <&dmamux1 1 40 0x400 0x01>; - dma-names = "rx", "tx"; - pinctrl-0 = <&spi2_pins_b>; - pinctrl-names = "default"; - cs-gpios = <&gpioa 11 0>; - - aardvark@0 { - compatible = "totalphase,aardvark"; - reg = <0>; - spi-max-frequency = <4000000>; - st,spi-midi-ns = <4000>; - }; - }; diff --git a/Documentation/devicetree/bindings/spi/st,stm32-spi.yaml b/Documentation/devicetree/bindings/spi/st,stm32-spi.yaml new file mode 100644 index 000000000000..f0d979664f07 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/st,stm32-spi.yaml @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/st,stm32-spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics STM32 SPI Controller bindings + +description: | + The STM32 SPI controller is used to communicate with external devices using + the Serial Peripheral Interface. It supports full-duplex, half-duplex and + simplex synchronous serial communication with external devices. It supports + from 4 to 32-bit data size. + +maintainers: + - Erwan Leray + - Fabrice Gasnier + +allOf: + - $ref: "spi-controller.yaml#" + - if: + properties: + compatible: + contains: + const: st,stm32f4-spi + + then: + properties: + st,spi-midi-ns: false + +properties: + compatible: + enum: + - st,stm32f4-spi + - st,stm32h7-spi + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + interrupts: + maxItems: 1 + + resets: + maxItems: 1 + + dmas: + description: | + DMA specifiers for tx and rx dma. DMA fifo mode must be used. See + the STM32 DMA bindings Documentation/devicetree/bindings/dma/stm32-dma.txt. + items: + - description: rx DMA channel + - description: tx DMA channel + + dma-names: + items: + - const: rx + - const: tx + +patternProperties: + "^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-f]+$": + type: object + # SPI slave nodes must be children of the SPI master node and can + # contain the following properties. + properties: + st,spi-midi-ns: + description: | + Only for STM32H7, (Master Inter-Data Idleness) minimum time + delay in nanoseconds inserted between two consecutive data frames. + +required: + - compatible + - reg + - clocks + - interrupts + +examples: + - | + #include + #include + #include + spi@4000b000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32h7-spi"; + reg = <0x4000b000 0x400>; + interrupts = ; + clocks = <&rcc SPI2_K>; + resets = <&rcc SPI2_R>; + dmas = <&dmamux1 0 39 0x400 0x05>, + <&dmamux1 1 40 0x400 0x05>; + dma-names = "rx", "tx"; + cs-gpios = <&gpioa 11 0>; + + aardvark@0 { + compatible = "totalphase,aardvark"; + reg = <0>; + spi-max-frequency = <4000000>; + st,spi-midi-ns = <4000>; + }; + }; + +... -- cgit v1.2.3 From 9859db51387df8a7e8564a211158ff8bf263b0a8 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Tue, 24 Dec 2019 09:58:24 +0900 Subject: spi: uniphier: Change argument of irq functions to private structure This changes each argument of functions uniphier_irq_{enable,disable}() to uniphier_spi_priv because these functions are used not only for spi_device but also for the entire controller. Signed-off-by: Kunihiko Hayashi Link: https://lore.kernel.org/r/1577149107-30670-3-git-send-email-hayashi.kunihiko@socionext.com Signed-off-by: Mark Brown --- drivers/spi/spi-uniphier.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c index 47cde1864630..a44a1a5fb7b0 100644 --- a/drivers/spi/spi-uniphier.c +++ b/drivers/spi/spi-uniphier.c @@ -93,9 +93,9 @@ static inline unsigned int bytes_per_word(unsigned int bits) return bits <= 8 ? 1 : (bits <= 16 ? 2 : 4); } -static inline void uniphier_spi_irq_enable(struct spi_device *spi, u32 mask) +static inline void uniphier_spi_irq_enable(struct uniphier_spi_priv *priv, + u32 mask) { - struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); u32 val; val = readl(priv->base + SSI_IE); @@ -103,9 +103,9 @@ static inline void uniphier_spi_irq_enable(struct spi_device *spi, u32 mask) writel(val, priv->base + SSI_IE); } -static inline void uniphier_spi_irq_disable(struct spi_device *spi, u32 mask) +static inline void uniphier_spi_irq_disable(struct uniphier_spi_priv *priv, + u32 mask) { - struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master); u32 val; val = readl(priv->base + SSI_IE); @@ -339,12 +339,12 @@ static int uniphier_spi_transfer_one_irq(struct spi_master *master, uniphier_spi_fill_tx_fifo(priv); - uniphier_spi_irq_enable(spi, SSI_IE_RCIE | SSI_IE_RORIE); + uniphier_spi_irq_enable(priv, SSI_IE_RCIE | SSI_IE_RORIE); time_left = wait_for_completion_timeout(&priv->xfer_done, msecs_to_jiffies(SSI_TIMEOUT_MS)); - uniphier_spi_irq_disable(spi, SSI_IE_RCIE | SSI_IE_RORIE); + uniphier_spi_irq_disable(priv, SSI_IE_RCIE | SSI_IE_RORIE); if (!time_left) { dev_err(dev, "transfer timeout.\n"); -- cgit v1.2.3 From 11299c5cd8868479e9acfc525ba3c2e882c7ba0c Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Tue, 24 Dec 2019 09:58:25 +0900 Subject: spi: uniphier: Add handle_err callback function This adds master->handle_err() callback function to stop transfer due to error. The function also resets FIFOs and disables interrupt. Signed-off-by: Kunihiko Hayashi Link: https://lore.kernel.org/r/1577149107-30670-4-git-send-email-hayashi.kunihiko@socionext.com Signed-off-by: Mark Brown --- drivers/spi/spi-uniphier.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c index a44a1a5fb7b0..0b255597fdcb 100644 --- a/drivers/spi/spi-uniphier.c +++ b/drivers/spi/spi-uniphier.c @@ -425,6 +425,22 @@ static int uniphier_spi_unprepare_transfer_hardware(struct spi_master *master) return 0; } +static void uniphier_spi_handle_err(struct spi_master *master, + struct spi_message *msg) +{ + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); + u32 val; + + /* stop running spi transfer */ + writel(0, priv->base + SSI_CTL); + + /* reset FIFOs */ + val = SSI_FC_TXFFL | SSI_FC_RXFFL; + writel(val, priv->base + SSI_FC); + + uniphier_spi_irq_disable(priv, SSI_IE_RCIE | SSI_IE_RORIE); +} + static irqreturn_t uniphier_spi_handler(int irq, void *dev_id) { struct uniphier_spi_priv *priv = dev_id; @@ -531,6 +547,7 @@ static int uniphier_spi_probe(struct platform_device *pdev) = uniphier_spi_prepare_transfer_hardware; master->unprepare_transfer_hardware = uniphier_spi_unprepare_transfer_hardware; + master->handle_err = uniphier_spi_handle_err; master->num_chipselect = 1; ret = devm_spi_register_master(&pdev->dev, master); -- cgit v1.2.3 From a68735d7975dde1392f408417c6b5f24c6bf9358 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Tue, 24 Dec 2019 11:52:04 +0800 Subject: spi: fsl-lpspi: use true,false for bool variable Fixes coccicheck warning: drivers/spi/spi-fsl-lpspi.c:472:2-19: WARNING: Assignment of 0/1 to bool variable drivers/spi/spi-fsl-lpspi.c:474:2-19: WARNING: Assignment of 0/1 to bool variable Reported-by: Hulk Robot Signed-off-by: zhengbin Link: https://lore.kernel.org/r/1577159526-33689-2-git-send-email-zhengbin13@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 2cc0ddb4a988..56855d5e9e8b 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -469,9 +469,9 @@ static int fsl_lpspi_setup_transfer(struct spi_controller *controller, fsl_lpspi->watermark = fsl_lpspi->txfifosize; if (fsl_lpspi_can_dma(controller, spi, t)) - fsl_lpspi->usedma = 1; + fsl_lpspi->usedma = true; else - fsl_lpspi->usedma = 0; + fsl_lpspi->usedma = false; return fsl_lpspi_config(fsl_lpspi); } -- cgit v1.2.3 From e6a8b2cc514ccacb9e1885dcc7be0a3251ab4843 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Tue, 24 Dec 2019 11:52:05 +0800 Subject: spi: imx: use true,false for bool variable Fixes coccicheck warning: drivers/spi/spi-imx.c:1233:2-17: WARNING: Assignment of 0/1 to bool variable drivers/spi/spi-imx.c:1235:2-17: WARNING: Assignment of 0/1 to bool variable Reported-by: Hulk Robot Signed-off-by: zhengbin Link: https://lore.kernel.org/r/1577159526-33689-3-git-send-email-zhengbin13@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 49f0099db0cb..f4f28a400a96 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1230,9 +1230,9 @@ static int spi_imx_setupxfer(struct spi_device *spi, } if (spi_imx_can_dma(spi_imx->bitbang.master, spi, t)) - spi_imx->usedma = 1; + spi_imx->usedma = true; else - spi_imx->usedma = 0; + spi_imx->usedma = false; if (is_imx53_ecspi(spi_imx) && spi_imx->slave_mode) { spi_imx->rx = mx53_ecspi_rx_slave; -- cgit v1.2.3 From 0d9c75481a8e0129f82e0b09a5e36eb1cc76c2b8 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Tue, 24 Dec 2019 11:52:06 +0800 Subject: spi: tegra114: use true,false for bool variable Fixes coccicheck warning: drivers/spi/spi-tegra114.c:272:2-17: WARNING: Assignment of 0/1 to bool variable drivers/spi/spi-tegra114.c:275:2-17: WARNING: Assignment of 0/1 to bool variable Reported-by: Hulk Robot Signed-off-by: zhengbin Link: https://lore.kernel.org/r/1577159526-33689-4-git-send-email-zhengbin13@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-tegra114.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index fc40ab146c86..83edabdb41ad 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -269,10 +269,10 @@ static unsigned tegra_spi_calculate_curr_xfer_param( if ((bits_per_word == 8 || bits_per_word == 16 || bits_per_word == 32) && t->len > 3) { - tspi->is_packed = 1; + tspi->is_packed = true; tspi->words_per_32bit = 32/bits_per_word; } else { - tspi->is_packed = 0; + tspi->is_packed = false; tspi->words_per_32bit = 1; } -- cgit v1.2.3 From 28d1dddc59f6b7fc085093e7c1e978b33f0caf4c Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Tue, 24 Dec 2019 09:58:27 +0900 Subject: spi: uniphier: Add DMA transfer mode support This adds DMA transfer mode support for UniPhier SPI controller. Since this controller requires simulteaneous transmission and reception, this indicates SPI_CONTROLLER_MUST_RX and SPI_CONTROLLER_MUST_TX. Because the supported dma controller has alignment restiction, there is also a restriction that 'maxburst' parameters in dma_slave_config corresponds to one word width. Signed-off-by: Kunihiko Hayashi Link: https://lore.kernel.org/r/1577149107-30670-6-git-send-email-hayashi.kunihiko@socionext.com Signed-off-by: Mark Brown --- drivers/spi/spi-uniphier.c | 200 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c index c4e3b96b1038..0fa50979644d 100644 --- a/drivers/spi/spi-uniphier.c +++ b/drivers/spi/spi-uniphier.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,7 @@ struct uniphier_spi_priv { void __iomem *base; + dma_addr_t base_dma_addr; struct clk *clk; struct spi_master *master; struct completion xfer_done; @@ -32,6 +34,7 @@ struct uniphier_spi_priv { unsigned int rx_bytes; const u8 *tx_buf; u8 *rx_buf; + atomic_t dma_busy; bool is_save_param; u8 bits_per_word; @@ -61,11 +64,16 @@ struct uniphier_spi_priv { #define SSI_FPS_FSTRT BIT(14) #define SSI_SR 0x14 +#define SSI_SR_BUSY BIT(7) #define SSI_SR_RNE BIT(0) #define SSI_IE 0x18 +#define SSI_IE_TCIE BIT(4) #define SSI_IE_RCIE BIT(3) +#define SSI_IE_TXRE BIT(2) +#define SSI_IE_RXRE BIT(1) #define SSI_IE_RORIE BIT(0) +#define SSI_IE_ALL_MASK GENMASK(4, 0) #define SSI_IS 0x1c #define SSI_IS_RXRS BIT(9) @@ -87,6 +95,10 @@ struct uniphier_spi_priv { #define SSI_RXDR 0x24 #define SSI_FIFO_DEPTH 8U +#define SSI_FIFO_BURST_NUM 1 + +#define SSI_DMA_RX_BUSY BIT(1) +#define SSI_DMA_TX_BUSY BIT(0) static inline unsigned int bytes_per_word(unsigned int bits) { @@ -334,6 +346,128 @@ static void uniphier_spi_set_cs(struct spi_device *spi, bool enable) writel(val, priv->base + SSI_FPS); } +static bool uniphier_spi_can_dma(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) +{ + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); + unsigned int bpw = bytes_per_word(priv->bits_per_word); + + if ((!master->dma_tx && !master->dma_rx) + || (!master->dma_tx && t->tx_buf) + || (!master->dma_rx && t->rx_buf)) + return false; + + return DIV_ROUND_UP(t->len, bpw) > SSI_FIFO_DEPTH; +} + +static void uniphier_spi_dma_rxcb(void *data) +{ + struct spi_master *master = data; + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); + int state = atomic_fetch_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy); + + uniphier_spi_irq_disable(priv, SSI_IE_RXRE); + + if (!(state & SSI_DMA_TX_BUSY)) + spi_finalize_current_transfer(master); +} + +static void uniphier_spi_dma_txcb(void *data) +{ + struct spi_master *master = data; + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); + int state = atomic_fetch_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy); + + uniphier_spi_irq_disable(priv, SSI_IE_TXRE); + + if (!(state & SSI_DMA_RX_BUSY)) + spi_finalize_current_transfer(master); +} + +static int uniphier_spi_transfer_one_dma(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) +{ + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); + struct dma_async_tx_descriptor *rxdesc = NULL, *txdesc = NULL; + int buswidth; + + atomic_set(&priv->dma_busy, 0); + + uniphier_spi_set_fifo_threshold(priv, SSI_FIFO_BURST_NUM); + + if (priv->bits_per_word <= 8) + buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; + else if (priv->bits_per_word <= 16) + buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; + else + buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; + + if (priv->rx_buf) { + struct dma_slave_config rxconf = { + .direction = DMA_DEV_TO_MEM, + .src_addr = priv->base_dma_addr + SSI_RXDR, + .src_addr_width = buswidth, + .src_maxburst = SSI_FIFO_BURST_NUM, + }; + + dmaengine_slave_config(master->dma_rx, &rxconf); + + rxdesc = dmaengine_prep_slave_sg( + master->dma_rx, + t->rx_sg.sgl, t->rx_sg.nents, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!rxdesc) + goto out_err_prep; + + rxdesc->callback = uniphier_spi_dma_rxcb; + rxdesc->callback_param = master; + + uniphier_spi_irq_enable(priv, SSI_IE_RXRE); + atomic_or(SSI_DMA_RX_BUSY, &priv->dma_busy); + + dmaengine_submit(rxdesc); + dma_async_issue_pending(master->dma_rx); + } + + if (priv->tx_buf) { + struct dma_slave_config txconf = { + .direction = DMA_MEM_TO_DEV, + .dst_addr = priv->base_dma_addr + SSI_TXDR, + .dst_addr_width = buswidth, + .dst_maxburst = SSI_FIFO_BURST_NUM, + }; + + dmaengine_slave_config(master->dma_tx, &txconf); + + txdesc = dmaengine_prep_slave_sg( + master->dma_tx, + t->tx_sg.sgl, t->tx_sg.nents, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!txdesc) + goto out_err_prep; + + txdesc->callback = uniphier_spi_dma_txcb; + txdesc->callback_param = master; + + uniphier_spi_irq_enable(priv, SSI_IE_TXRE); + atomic_or(SSI_DMA_TX_BUSY, &priv->dma_busy); + + dmaengine_submit(txdesc); + dma_async_issue_pending(master->dma_tx); + } + + /* signal that we need to wait for completion */ + return (priv->tx_buf || priv->rx_buf); + +out_err_prep: + if (rxdesc) + dmaengine_terminate_sync(master->dma_rx); + + return -EINVAL; +} + static int uniphier_spi_transfer_one_irq(struct spi_master *master, struct spi_device *spi, struct spi_transfer *t) @@ -395,6 +529,7 @@ static int uniphier_spi_transfer_one(struct spi_master *master, { struct uniphier_spi_priv *priv = spi_master_get_devdata(master); unsigned long threshold; + bool use_dma; /* Terminate and return success for 0 byte length transfer */ if (!t->len) @@ -402,6 +537,10 @@ static int uniphier_spi_transfer_one(struct spi_master *master, uniphier_spi_setup_transfer(spi, t); + use_dma = master->can_dma ? master->can_dma(master, spi, t) : false; + if (use_dma) + return uniphier_spi_transfer_one_dma(master, spi, t); + /* * If the transfer operation will take longer than * SSI_POLL_TIMEOUT_US, it should use irq. @@ -445,7 +584,17 @@ static void uniphier_spi_handle_err(struct spi_master *master, val = SSI_FC_TXFFL | SSI_FC_RXFFL; writel(val, priv->base + SSI_FC); - uniphier_spi_irq_disable(priv, SSI_IE_RCIE | SSI_IE_RORIE); + uniphier_spi_irq_disable(priv, SSI_IE_ALL_MASK); + + if (atomic_read(&priv->dma_busy) & SSI_DMA_TX_BUSY) { + dmaengine_terminate_async(master->dma_tx); + atomic_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy); + } + + if (atomic_read(&priv->dma_busy) & SSI_DMA_RX_BUSY) { + dmaengine_terminate_async(master->dma_rx); + atomic_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy); + } } static irqreturn_t uniphier_spi_handler(int irq, void *dev_id) @@ -493,6 +642,9 @@ static int uniphier_spi_probe(struct platform_device *pdev) { struct uniphier_spi_priv *priv; struct spi_master *master; + struct resource *res; + struct dma_slave_caps caps; + u32 dma_tx_burst = 0, dma_rx_burst = 0; unsigned long clk_rate; int irq; int ret; @@ -507,11 +659,13 @@ static int uniphier_spi_probe(struct platform_device *pdev) priv->master = master; priv->is_save_param = false; - priv->base = devm_platform_ioremap_resource(pdev, 0); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->base)) { ret = PTR_ERR(priv->base); goto out_master_put; } + priv->base_dma_addr = res->start; priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { @@ -555,7 +709,44 @@ static int uniphier_spi_probe(struct platform_device *pdev) master->unprepare_transfer_hardware = uniphier_spi_unprepare_transfer_hardware; master->handle_err = uniphier_spi_handle_err; + master->can_dma = uniphier_spi_can_dma; + master->num_chipselect = 1; + master->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; + + master->dma_tx = dma_request_chan(&pdev->dev, "tx"); + if (IS_ERR_OR_NULL(master->dma_tx)) { + if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) + goto out_disable_clk; + master->dma_tx = NULL; + dma_tx_burst = INT_MAX; + } else { + ret = dma_get_slave_caps(master->dma_tx, &caps); + if (ret) { + dev_err(&pdev->dev, "failed to get TX DMA capacities: %d\n", + ret); + goto out_disable_clk; + } + dma_tx_burst = caps.max_burst; + } + + master->dma_rx = dma_request_chan(&pdev->dev, "rx"); + if (IS_ERR_OR_NULL(master->dma_rx)) { + if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) + goto out_disable_clk; + master->dma_rx = NULL; + dma_rx_burst = INT_MAX; + } else { + ret = dma_get_slave_caps(master->dma_rx, &caps); + if (ret) { + dev_err(&pdev->dev, "failed to get RX DMA capacities: %d\n", + ret); + goto out_disable_clk; + } + dma_rx_burst = caps.max_burst; + } + + master->max_dma_len = min(dma_tx_burst, dma_rx_burst); ret = devm_spi_register_master(&pdev->dev, master); if (ret) @@ -575,6 +766,11 @@ static int uniphier_spi_remove(struct platform_device *pdev) { struct uniphier_spi_priv *priv = platform_get_drvdata(pdev); + if (priv->master->dma_tx) + dma_release_channel(priv->master->dma_tx); + if (priv->master->dma_rx) + dma_release_channel(priv->master->dma_rx); + clk_disable_unprepare(priv->clk); return 0; -- cgit v1.2.3 From f03ee2042b2dc46e3452e87324d90f147de4a944 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 5 Dec 2019 10:24:11 +0100 Subject: spi: oc-tiny: Use GPIO descriptors Switch the OC Tiny driver over to handling CS GPIOs using GPIO descriptors in the core. This driver is entirely relying on GPIOs to be used for chipselect, so let the core pick these out using either device tree or machine descriptors. There are no in-tree users of this driver so no board files need to be patched, out-of-tree boardfiles can use machine descriptor tables, c.f. commit 1dfbf334f123. Cc: Thomas Chou Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20191205092411.64341-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-oc-tiny.c | 50 +---------------------------------------- include/linux/spi/spi_oc_tiny.h | 4 ---- 2 files changed, 1 insertion(+), 53 deletions(-) diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index e2331eb7b47a..9df7c5979c29 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #define DRV_NAME "spi_oc_tiny" @@ -50,8 +49,6 @@ struct tiny_spi { unsigned int txc, rxc; const u8 *txp; u8 *rxp; - int gpio_cs_count; - int *gpio_cs; }; static inline struct tiny_spi *tiny_spi_to_hw(struct spi_device *sdev) @@ -66,16 +63,6 @@ static unsigned int tiny_spi_baud(struct spi_device *spi, unsigned int hz) return min(DIV_ROUND_UP(hw->freq, hz * 2), (1U << hw->baudwidth)) - 1; } -static void tiny_spi_chipselect(struct spi_device *spi, int is_active) -{ - struct tiny_spi *hw = tiny_spi_to_hw(spi); - - if (hw->gpio_cs_count > 0) { - gpio_set_value(hw->gpio_cs[spi->chip_select], - (spi->mode & SPI_CS_HIGH) ? is_active : !is_active); - } -} - static int tiny_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { @@ -203,24 +190,10 @@ static int tiny_spi_of_probe(struct platform_device *pdev) { struct tiny_spi *hw = platform_get_drvdata(pdev); struct device_node *np = pdev->dev.of_node; - unsigned int i; u32 val; if (!np) return 0; - hw->gpio_cs_count = of_gpio_count(np); - if (hw->gpio_cs_count > 0) { - hw->gpio_cs = devm_kcalloc(&pdev->dev, - hw->gpio_cs_count, sizeof(unsigned int), - GFP_KERNEL); - if (!hw->gpio_cs) - return -ENOMEM; - } - for (i = 0; i < hw->gpio_cs_count; i++) { - hw->gpio_cs[i] = of_get_gpio_flags(np, i, NULL); - if (hw->gpio_cs[i] < 0) - return -ENODEV; - } hw->bitbang.master->dev.of_node = pdev->dev.of_node; if (!of_property_read_u32(np, "clock-frequency", &val)) hw->freq = val; @@ -240,7 +213,6 @@ static int tiny_spi_probe(struct platform_device *pdev) struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev); struct tiny_spi *hw; struct spi_master *master; - unsigned int i; int err = -ENODEV; master = spi_alloc_master(&pdev->dev, sizeof(struct tiny_spi)); @@ -249,9 +221,9 @@ static int tiny_spi_probe(struct platform_device *pdev) /* setup the master state. */ master->bus_num = pdev->id; - master->num_chipselect = 255; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->setup = tiny_spi_setup; + master->use_gpio_descriptors = true; hw = spi_master_get_devdata(master); platform_set_drvdata(pdev, hw); @@ -259,7 +231,6 @@ static int tiny_spi_probe(struct platform_device *pdev) /* setup the state for the bitbang driver */ hw->bitbang.master = master; hw->bitbang.setup_transfer = tiny_spi_setup_transfer; - hw->bitbang.chipselect = tiny_spi_chipselect; hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs; /* find and map our resources */ @@ -279,12 +250,6 @@ static int tiny_spi_probe(struct platform_device *pdev) } /* find platform data */ if (platp) { - hw->gpio_cs_count = platp->gpio_cs_count; - hw->gpio_cs = platp->gpio_cs; - if (platp->gpio_cs_count && !platp->gpio_cs) { - err = -EBUSY; - goto exit; - } hw->freq = platp->freq; hw->baudwidth = platp->baudwidth; } else { @@ -292,13 +257,6 @@ static int tiny_spi_probe(struct platform_device *pdev) if (err) goto exit; } - for (i = 0; i < hw->gpio_cs_count; i++) { - err = gpio_request(hw->gpio_cs[i], dev_name(&pdev->dev)); - if (err) - goto exit_gpio; - gpio_direction_output(hw->gpio_cs[i], 1); - } - hw->bitbang.master->num_chipselect = max(1, hw->gpio_cs_count); /* register our spi controller */ err = spi_bitbang_start(&hw->bitbang); @@ -308,9 +266,6 @@ static int tiny_spi_probe(struct platform_device *pdev) return 0; -exit_gpio: - while (i-- > 0) - gpio_free(hw->gpio_cs[i]); exit: spi_master_put(master); return err; @@ -320,11 +275,8 @@ static int tiny_spi_remove(struct platform_device *pdev) { struct tiny_spi *hw = platform_get_drvdata(pdev); struct spi_master *master = hw->bitbang.master; - unsigned int i; spi_bitbang_stop(&hw->bitbang); - for (i = 0; i < hw->gpio_cs_count; i++) - gpio_free(hw->gpio_cs[i]); spi_master_put(master); return 0; } diff --git a/include/linux/spi/spi_oc_tiny.h b/include/linux/spi/spi_oc_tiny.h index a3ecf2feadf2..284872ac130c 100644 --- a/include/linux/spi/spi_oc_tiny.h +++ b/include/linux/spi/spi_oc_tiny.h @@ -6,16 +6,12 @@ * struct tiny_spi_platform_data - platform data of the OpenCores tiny SPI * @freq: input clock freq to the core. * @baudwidth: baud rate divider width of the core. - * @gpio_cs_count: number of gpio pins used for chipselect. - * @gpio_cs: array of gpio pins used for chipselect. * * freq and baudwidth are used only if the divider is programmable. */ struct tiny_spi_platform_data { unsigned int freq; unsigned int baudwidth; - unsigned int gpio_cs_count; - int *gpio_cs; }; #endif /* _LINUX_SPI_SPI_OC_TINY_H */ -- cgit v1.2.3 From f971a2074447726ec9a3feee3648a2e157f08248 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Fri, 27 Dec 2019 03:24:44 +0200 Subject: spi: Catch improper use of PTP system timestamping API We can catch whether the SPI controller has declared it can take care of software timestamping transfers, but didn't. So do it. Signed-off-by: Vladimir Oltean Link: https://lore.kernel.org/r/20191227012444.1204-1-olteanv@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5e4c4532f7f3..5485ef89197c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1680,6 +1680,13 @@ void spi_finalize_current_message(struct spi_controller *ctlr) } } + if (unlikely(ctlr->ptp_sts_supported)) { + list_for_each_entry(xfer, &mesg->transfers, transfer_list) { + WARN_ON_ONCE(xfer->ptp_sts && !xfer->timestamped_pre); + WARN_ON_ONCE(xfer->ptp_sts && !xfer->timestamped_post); + } + } + spi_unmap_msg(ctlr, mesg); if (ctlr->cur_msg_prepared && ctlr->unprepare_message) { -- cgit v1.2.3 From e9aa3b851428282d5e5151a49d4bf0bfdcd72bfe Mon Sep 17 00:00:00 2001 From: Rayagonda Kokatanur Date: Tue, 7 Jan 2020 09:39:12 +0530 Subject: spi: bcm-qspi: Use platform_get_irq_byname_optional() to avoid error message Use platform_get_irq_byname_optional() instead of platform_get_irq_byname() to avoid below error message during probe: [3.265115] bcm_iproc 68c70200.spi: IRQ spi_lr_fullness_reached not found [3.272121] bcm_iproc 68c70200.spi: IRQ spi_lr_session_aborted not found [3.284965] bcm_iproc 68c70200.spi: IRQ spi_lr_impatient not found [3.291344] bcm_iproc 68c70200.spi: IRQ spi_lr_session_done not found [3.297992] bcm_iproc 68c70200.spi: IRQ mspi_done not found [3.303742] bcm_iproc 68c70200.spi: IRQ mspi_halted not found Signed-off-by: Rayagonda Kokatanur Link: https://lore.kernel.org/r/20200107040912.16426-1-rayagonda.kokatanur@broadcom.com Signed-off-by: Mark Brown --- drivers/spi/spi-bcm-qspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 85bad70f59e3..23d295f36c80 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -1293,7 +1293,7 @@ int bcm_qspi_probe(struct platform_device *pdev, name = qspi_irq_tab[val].irq_name; if (qspi_irq_tab[val].irq_source == SINGLE_L2) { /* get the l2 interrupts */ - irq = platform_get_irq_byname(pdev, name); + irq = platform_get_irq_byname_optional(pdev, name); } else if (!num_ints && soc_intc) { /* all mspi, bspi intrs muxed to one L1 intr */ irq = platform_get_irq(pdev, 0); -- cgit v1.2.3 From 7d93aecdb58d47e8ed90b4a44c0fc9ffb8de941c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 2 Jan 2020 14:38:17 +0100 Subject: spi: Add generic support for unused native cs with cs-gpios Some SPI master controllers always drive a native chip select when performing a transfer. Hence when using both native and GPIO chip selects, at least one native chip select must be left unused, to be driven when performing transfers with slave devices using GPIO chip selects. Currently, to find an unused native chip select, SPI controller drivers need to parse and process cs-gpios theirselves. This is not only duplicated in each driver that needs it, but also duplicates part of the work done later at SPI controller registration time. Note that this cannot be done after spi_register_controller() returns, as at that time, slave devices may have been probed already. Hence add generic support to the SPI subsystem for finding an unused native chip select. Optionally, this unused native chip select, and all other in-use native chip selects, can be validated against the maximum number of native chip selects available on the controller hardware. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200102133822.29346-2-geert+renesas@glider.be Signed-off-by: Mark Brown --- drivers/spi/spi.c | 17 +++++++++++++++++ include/linux/spi/spi.h | 8 ++++++++ 2 files changed, 25 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5485ef89197c..197c9e0ac2a6 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2464,6 +2464,8 @@ static int spi_get_gpio_descs(struct spi_controller *ctlr) int nb, i; struct gpio_desc **cs; struct device *dev = &ctlr->dev; + unsigned long native_cs_mask = 0; + unsigned int num_cs_gpios = 0; nb = gpiod_count(dev, "cs"); ctlr->num_chipselect = max_t(int, nb, ctlr->num_chipselect); @@ -2505,7 +2507,22 @@ static int spi_get_gpio_descs(struct spi_controller *ctlr) if (!gpioname) return -ENOMEM; gpiod_set_consumer_name(cs[i], gpioname); + num_cs_gpios++; + continue; + } + + if (ctlr->max_native_cs && i >= ctlr->max_native_cs) { + dev_err(dev, "Invalid native chip select %d\n", i); + return -EINVAL; } + native_cs_mask |= BIT(i); + } + + ctlr->unused_native_cs = ffz(native_cs_mask); + if (num_cs_gpios && ctlr->max_native_cs && + ctlr->unused_native_cs >= ctlr->max_native_cs) { + dev_err(dev, "No unused native chip select available\n"); + return -EINVAL; } return 0; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 98fe8663033a..e4011b852fc3 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -423,6 +423,12 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * GPIO descriptors rather than using global GPIO numbers grabbed by the * driver. This will fill in @cs_gpiods and @cs_gpios should not be used, * and SPI devices will have the cs_gpiod assigned rather than cs_gpio. + * @unused_native_cs: When cs_gpiods is used, spi_register_controller() will + * fill in this field with the first unused native CS, to be used by SPI + * controller drivers that need to drive a native CS when using GPIO CS. + * @max_native_cs: When cs_gpiods is used, and this field is filled in, + * spi_register_controller() will validate all native CS (including the + * unused native CS) against this value. * @statistics: statistics for the spi_controller * @dma_tx: DMA transmit channel * @dma_rx: DMA receive channel @@ -624,6 +630,8 @@ struct spi_controller { int *cs_gpios; struct gpio_desc **cs_gpiods; bool use_gpio_descriptors; + u8 unused_native_cs; + u8 max_native_cs; /* statistics */ struct spi_statistics statistics; -- cgit v1.2.3 From aa32f76e0a409adcd40ef11ed1ed668df8b034f6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 2 Jan 2020 14:38:18 +0100 Subject: spi: sh-msiof: Convert to generic unused native cs handling. Currently the MSIOF SPI driver uses custom code to handle the unused native chip select with GPIO chip selects. Convert the driver to use the new generic handling in the SPI core. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200102133822.29346-3-geert+renesas@glider.be Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 53 +++------------------------------------------- 1 file changed, 3 insertions(+), 50 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 8f134735291f..b3732dc231cb 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include #include @@ -55,7 +53,6 @@ struct sh_msiof_spi_priv { void *rx_dma_page; dma_addr_t tx_dma_addr; dma_addr_t rx_dma_addr; - unsigned short unused_ss; bool native_cs_inited; bool native_cs_high; bool slave_aborted; @@ -587,7 +584,7 @@ static int sh_msiof_prepare_message(struct spi_controller *ctlr, /* Configure pins before asserting CS */ if (spi->cs_gpiod) { - ss = p->unused_ss; + ss = ctlr->unused_native_cs; cs_high = p->native_cs_high; } else { ss = spi->chip_select; @@ -1124,46 +1121,6 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) } #endif -static int sh_msiof_get_cs_gpios(struct sh_msiof_spi_priv *p) -{ - struct device *dev = &p->pdev->dev; - unsigned int used_ss_mask = 0; - unsigned int cs_gpios = 0; - unsigned int num_cs, i; - int ret; - - ret = gpiod_count(dev, "cs"); - if (ret <= 0) - return 0; - - num_cs = max_t(unsigned int, ret, p->ctlr->num_chipselect); - for (i = 0; i < num_cs; i++) { - struct gpio_desc *gpiod; - - gpiod = devm_gpiod_get_index(dev, "cs", i, GPIOD_ASIS); - if (!IS_ERR(gpiod)) { - devm_gpiod_put(dev, gpiod); - cs_gpios++; - continue; - } - - if (PTR_ERR(gpiod) != -ENOENT) - return PTR_ERR(gpiod); - - if (i >= MAX_SS) { - dev_err(dev, "Invalid native chip select %d\n", i); - return -EINVAL; - } - used_ss_mask |= BIT(i); - } - p->unused_ss = ffz(used_ss_mask); - if (cs_gpios && p->unused_ss >= MAX_SS) { - dev_err(dev, "No unused native chip select available\n"); - return -EINVAL; - } - return 0; -} - static struct dma_chan *sh_msiof_request_dma_chan(struct device *dev, enum dma_transfer_direction dir, unsigned int id, dma_addr_t port_addr) { @@ -1373,17 +1330,12 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) if (p->info->rx_fifo_override) p->rx_fifo_size = p->info->rx_fifo_override; - /* Setup GPIO chip selects */ - ctlr->num_chipselect = p->info->num_chipselect; - ret = sh_msiof_get_cs_gpios(p); - if (ret) - goto err1; - /* init controller code */ ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; ctlr->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE; ctlr->flags = chipdata->ctlr_flags; ctlr->bus_num = pdev->id; + ctlr->num_chipselect = p->info->num_chipselect; ctlr->dev.of_node = pdev->dev.of_node; ctlr->setup = sh_msiof_spi_setup; ctlr->prepare_message = sh_msiof_prepare_message; @@ -1392,6 +1344,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) ctlr->auto_runtime_pm = true; ctlr->transfer_one = sh_msiof_transfer_one; ctlr->use_gpio_descriptors = true; + ctlr->max_native_cs = MAX_SS; ret = sh_msiof_request_dma(p); if (ret < 0) -- cgit v1.2.3 From 1bec84ddd85ae7a2b1df5fef3a5c7e5c44cbe36e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 2 Jan 2020 14:38:19 +0100 Subject: spi: rspi: Use dev_warn_once() instead of open-coding Use the helper introduced by commit e135303bd5bebcd2 ("device: Add dev__once variants") instead of open-coding the same operation. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200102133822.29346-4-geert+renesas@glider.be Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 74a12f4dee84..e54a25f848ea 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -620,9 +620,8 @@ no_dma_tx: dmaengine_terminate_all(rspi->ctlr->dma_rx); no_dma_rx: if (ret == -EAGAIN) { - pr_warn_once("%s %s: DMA not available, falling back to PIO\n", - dev_driver_string(&rspi->ctlr->dev), - dev_name(&rspi->ctlr->dev)); + dev_warn_once(&rspi->ctlr->dev, + "DMA not available, falling back to PIO\n"); } return ret; } -- cgit v1.2.3 From 8f2344fa7f54382eeaf4b65d70c74b0b44df7a6b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 2 Jan 2020 14:38:20 +0100 Subject: spi: rspi: Remove set_config_register() macro The set_config_register() macro is used in a single place. Make the code easier to read by just removing it. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200102133822.29346-5-geert+renesas@glider.be Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index e54a25f848ea..9eabef3d6cc4 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -426,8 +426,6 @@ static int qspi_set_receive_trigger(struct rspi_data *rspi, unsigned int len) return n; } -#define set_config_register(spi, n) spi->ops->set_config_register(spi, n) - static void rspi_enable_irq(const struct rspi_data *rspi, u8 enable) { rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | enable, RSPI_SPCR); @@ -940,7 +938,7 @@ static int rspi_prepare_message(struct spi_controller *ctlr, if (spi->mode & SPI_LOOP) rspi->sppcr |= SPPCR_SPLP; - set_config_register(rspi, 8); + rspi->ops->set_config_register(rspi, 8); if (msg->spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)) { -- cgit v1.2.3 From 9815ed8714d26560d09b41f906b96a97f9bc3e3f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 2 Jan 2020 14:38:21 +0100 Subject: spi: rspi: Add support for multiple native chip selects RSPI variants on some SuperH or R-Mobile SoCs support multiple native chip selects. Add support for this by configuring the SSL Assert Signal Setting. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200102133822.29346-6-geert+renesas@glider.be Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 9eabef3d6cc4..2f5a856a9319 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -159,7 +159,7 @@ #define SPCMD_SPIMOD_DUAL SPCMD_SPIMOD0 #define SPCMD_SPIMOD_QUAD SPCMD_SPIMOD1 #define SPCMD_SPRW 0x0010 /* SPI Read/Write Access (Dual/Quad) */ -#define SPCMD_SSLA_MASK 0x0030 /* SSL Assert Signal Setting (RSPI) */ +#define SPCMD_SSLA(i) ((i) << 4) /* SSL Assert Signal Setting */ #define SPCMD_BRDV_MASK 0x000c /* Bit Rate Division Setting */ #define SPCMD_CPOL 0x0002 /* Clock Polarity Setting */ #define SPCMD_CPHA 0x0001 /* Clock Phase Setting */ @@ -933,6 +933,9 @@ static int rspi_prepare_message(struct spi_controller *ctlr, if (spi->mode & SPI_CPHA) rspi->spcmd |= SPCMD_CPHA; + /* Configure slave signal to assert */ + rspi->spcmd |= SPCMD_SSLA(spi->chip_select); + /* CMOS output mode and MOSI signal from previous transfer */ rspi->sppcr = 0; if (spi->mode & SPI_LOOP) -- cgit v1.2.3 From 144d8f9781e60d89dfd614210d2cedbefbba8885 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 2 Jan 2020 14:38:22 +0100 Subject: spi: rspi: Add support for GPIO chip selects Add support for GPIO chip selects using GPIO descriptors. As the RSPI controller always drives a native chip select when performing a transfer, at least one native chip select must be left unused. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200102133822.29346-7-geert+renesas@glider.be Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 2f5a856a9319..85575d45901c 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -242,6 +242,7 @@ struct spi_ops { u16 mode_bits; u16 flags; u16 fifo_size; + u8 num_hw_ss; }; /* @@ -934,7 +935,8 @@ static int rspi_prepare_message(struct spi_controller *ctlr, rspi->spcmd |= SPCMD_CPHA; /* Configure slave signal to assert */ - rspi->spcmd |= SPCMD_SSLA(spi->chip_select); + rspi->spcmd |= SPCMD_SSLA(spi->cs_gpiod ? rspi->ctlr->unused_native_cs + : spi->chip_select); /* CMOS output mode and MOSI signal from previous transfer */ rspi->sppcr = 0; @@ -1123,6 +1125,7 @@ static const struct spi_ops rspi_ops = { .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, .flags = SPI_CONTROLLER_MUST_TX, .fifo_size = 8, + .num_hw_ss = 2, }; static const struct spi_ops rspi_rz_ops = { @@ -1131,6 +1134,7 @@ static const struct spi_ops rspi_rz_ops = { .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, .flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX, .fifo_size = 8, /* 8 for TX, 32 for RX */ + .num_hw_ss = 1, }; static const struct spi_ops qspi_ops = { @@ -1141,6 +1145,7 @@ static const struct spi_ops qspi_ops = { SPI_RX_DUAL | SPI_RX_QUAD, .flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX, .fifo_size = 32, + .num_hw_ss = 1, }; #ifdef CONFIG_OF @@ -1256,6 +1261,8 @@ static int rspi_probe(struct platform_device *pdev) ctlr->mode_bits = ops->mode_bits; ctlr->flags = ops->flags; ctlr->dev.of_node = pdev->dev.of_node; + ctlr->use_gpio_descriptors = true; + ctlr->max_native_cs = rspi->ops->num_hw_ss; ret = platform_get_irq_byname_optional(pdev, "rx"); if (ret < 0) { -- cgit v1.2.3 From 8ae7d44239305362319f3ea32e4e1fd3181649cc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 8 Jan 2020 20:43:19 +0100 Subject: spi: sh-msiof: Do not redefine STR while compile testing STR is a well-known stringify macro so it should be avoided in drivers to avoid warnings like this (MIPS architecture while compile testing): drivers/spi/spi-sh-msiof.c:76:0: warning: "STR" redefined #define STR 0x40 /* Status Register */ arch/mips/include/asm/mipsregs.h:30:0: note: this is the location of the previous definition #define STR(x) __STR(x) To maintain consistency between all register names add a SI prefix to all of them. This also matches register names in datasheet. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Geert Uytterhoeven Tested-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20200108194319.3171-1-krzk@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 418 ++++++++++++++++++++++----------------------- 1 file changed, 209 insertions(+), 209 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index b3732dc231cb..1c11a00a2c36 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -60,140 +60,140 @@ struct sh_msiof_spi_priv { #define MAX_SS 3 /* Maximum number of native chip selects */ -#define TMDR1 0x00 /* Transmit Mode Register 1 */ -#define TMDR2 0x04 /* Transmit Mode Register 2 */ -#define TMDR3 0x08 /* Transmit Mode Register 3 */ -#define RMDR1 0x10 /* Receive Mode Register 1 */ -#define RMDR2 0x14 /* Receive Mode Register 2 */ -#define RMDR3 0x18 /* Receive Mode Register 3 */ -#define TSCR 0x20 /* Transmit Clock Select Register */ -#define RSCR 0x22 /* Receive Clock Select Register (SH, A1, APE6) */ -#define CTR 0x28 /* Control Register */ -#define FCTR 0x30 /* FIFO Control Register */ -#define STR 0x40 /* Status Register */ -#define IER 0x44 /* Interrupt Enable Register */ -#define TDR1 0x48 /* Transmit Control Data Register 1 (SH, A1) */ -#define TDR2 0x4c /* Transmit Control Data Register 2 (SH, A1) */ -#define TFDR 0x50 /* Transmit FIFO Data Register */ -#define RDR1 0x58 /* Receive Control Data Register 1 (SH, A1) */ -#define RDR2 0x5c /* Receive Control Data Register 2 (SH, A1) */ -#define RFDR 0x60 /* Receive FIFO Data Register */ - -/* TMDR1 and RMDR1 */ -#define MDR1_TRMD BIT(31) /* Transfer Mode (1 = Master mode) */ -#define MDR1_SYNCMD_MASK GENMASK(29, 28) /* SYNC Mode */ -#define MDR1_SYNCMD_SPI (2 << 28)/* Level mode/SPI */ -#define MDR1_SYNCMD_LR (3 << 28)/* L/R mode */ -#define MDR1_SYNCAC_SHIFT 25 /* Sync Polarity (1 = Active-low) */ -#define MDR1_BITLSB_SHIFT 24 /* MSB/LSB First (1 = LSB first) */ -#define MDR1_DTDL_SHIFT 20 /* Data Pin Bit Delay for MSIOF_SYNC */ -#define MDR1_SYNCDL_SHIFT 16 /* Frame Sync Signal Timing Delay */ -#define MDR1_FLD_MASK GENMASK(3, 2) /* Frame Sync Signal Interval (0-3) */ -#define MDR1_FLD_SHIFT 2 -#define MDR1_XXSTP BIT(0) /* Transmission/Reception Stop on FIFO */ -/* TMDR1 */ -#define TMDR1_PCON BIT(30) /* Transfer Signal Connection */ -#define TMDR1_SYNCCH_MASK GENMASK(27, 26) /* Sync Signal Channel Select */ -#define TMDR1_SYNCCH_SHIFT 26 /* 0=MSIOF_SYNC, 1=MSIOF_SS1, 2=MSIOF_SS2 */ - -/* TMDR2 and RMDR2 */ -#define MDR2_BITLEN1(i) (((i) - 1) << 24) /* Data Size (8-32 bits) */ -#define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */ -#define MDR2_GRPMASK1 BIT(0) /* Group Output Mask 1 (SH, A1) */ - -/* TSCR and RSCR */ -#define SCR_BRPS_MASK GENMASK(12, 8) /* Prescaler Setting (1-32) */ -#define SCR_BRPS(i) (((i) - 1) << 8) -#define SCR_BRDV_MASK GENMASK(2, 0) /* Baud Rate Generator's Division Ratio */ -#define SCR_BRDV_DIV_2 0 -#define SCR_BRDV_DIV_4 1 -#define SCR_BRDV_DIV_8 2 -#define SCR_BRDV_DIV_16 3 -#define SCR_BRDV_DIV_32 4 -#define SCR_BRDV_DIV_1 7 - -/* CTR */ -#define CTR_TSCKIZ_MASK GENMASK(31, 30) /* Transmit Clock I/O Polarity Select */ -#define CTR_TSCKIZ_SCK BIT(31) /* Disable SCK when TX disabled */ -#define CTR_TSCKIZ_POL_SHIFT 30 /* Transmit Clock Polarity */ -#define CTR_RSCKIZ_MASK GENMASK(29, 28) /* Receive Clock Polarity Select */ -#define CTR_RSCKIZ_SCK BIT(29) /* Must match CTR_TSCKIZ_SCK */ -#define CTR_RSCKIZ_POL_SHIFT 28 /* Receive Clock Polarity */ -#define CTR_TEDG_SHIFT 27 /* Transmit Timing (1 = falling edge) */ -#define CTR_REDG_SHIFT 26 /* Receive Timing (1 = falling edge) */ -#define CTR_TXDIZ_MASK GENMASK(23, 22) /* Pin Output When TX is Disabled */ -#define CTR_TXDIZ_LOW (0 << 22) /* 0 */ -#define CTR_TXDIZ_HIGH (1 << 22) /* 1 */ -#define CTR_TXDIZ_HIZ (2 << 22) /* High-impedance */ -#define CTR_TSCKE BIT(15) /* Transmit Serial Clock Output Enable */ -#define CTR_TFSE BIT(14) /* Transmit Frame Sync Signal Output Enable */ -#define CTR_TXE BIT(9) /* Transmit Enable */ -#define CTR_RXE BIT(8) /* Receive Enable */ -#define CTR_TXRST BIT(1) /* Transmit Reset */ -#define CTR_RXRST BIT(0) /* Receive Reset */ - -/* FCTR */ -#define FCTR_TFWM_MASK GENMASK(31, 29) /* Transmit FIFO Watermark */ -#define FCTR_TFWM_64 (0 << 29) /* Transfer Request when 64 empty stages */ -#define FCTR_TFWM_32 (1 << 29) /* Transfer Request when 32 empty stages */ -#define FCTR_TFWM_24 (2 << 29) /* Transfer Request when 24 empty stages */ -#define FCTR_TFWM_16 (3 << 29) /* Transfer Request when 16 empty stages */ -#define FCTR_TFWM_12 (4 << 29) /* Transfer Request when 12 empty stages */ -#define FCTR_TFWM_8 (5 << 29) /* Transfer Request when 8 empty stages */ -#define FCTR_TFWM_4 (6 << 29) /* Transfer Request when 4 empty stages */ -#define FCTR_TFWM_1 (7 << 29) /* Transfer Request when 1 empty stage */ -#define FCTR_TFUA_MASK GENMASK(26, 20) /* Transmit FIFO Usable Area */ -#define FCTR_TFUA_SHIFT 20 -#define FCTR_TFUA(i) ((i) << FCTR_TFUA_SHIFT) -#define FCTR_RFWM_MASK GENMASK(15, 13) /* Receive FIFO Watermark */ -#define FCTR_RFWM_1 (0 << 13) /* Transfer Request when 1 valid stages */ -#define FCTR_RFWM_4 (1 << 13) /* Transfer Request when 4 valid stages */ -#define FCTR_RFWM_8 (2 << 13) /* Transfer Request when 8 valid stages */ -#define FCTR_RFWM_16 (3 << 13) /* Transfer Request when 16 valid stages */ -#define FCTR_RFWM_32 (4 << 13) /* Transfer Request when 32 valid stages */ -#define FCTR_RFWM_64 (5 << 13) /* Transfer Request when 64 valid stages */ -#define FCTR_RFWM_128 (6 << 13) /* Transfer Request when 128 valid stages */ -#define FCTR_RFWM_256 (7 << 13) /* Transfer Request when 256 valid stages */ -#define FCTR_RFUA_MASK GENMASK(12, 4) /* Receive FIFO Usable Area (0x40 = full) */ -#define FCTR_RFUA_SHIFT 4 -#define FCTR_RFUA(i) ((i) << FCTR_RFUA_SHIFT) - -/* STR */ -#define STR_TFEMP BIT(29) /* Transmit FIFO Empty */ -#define STR_TDREQ BIT(28) /* Transmit Data Transfer Request */ -#define STR_TEOF BIT(23) /* Frame Transmission End */ -#define STR_TFSERR BIT(21) /* Transmit Frame Synchronization Error */ -#define STR_TFOVF BIT(20) /* Transmit FIFO Overflow */ -#define STR_TFUDF BIT(19) /* Transmit FIFO Underflow */ -#define STR_RFFUL BIT(13) /* Receive FIFO Full */ -#define STR_RDREQ BIT(12) /* Receive Data Transfer Request */ -#define STR_REOF BIT(7) /* Frame Reception End */ -#define STR_RFSERR BIT(5) /* Receive Frame Synchronization Error */ -#define STR_RFUDF BIT(4) /* Receive FIFO Underflow */ -#define STR_RFOVF BIT(3) /* Receive FIFO Overflow */ - -/* IER */ -#define IER_TDMAE BIT(31) /* Transmit Data DMA Transfer Req. Enable */ -#define IER_TFEMPE BIT(29) /* Transmit FIFO Empty Enable */ -#define IER_TDREQE BIT(28) /* Transmit Data Transfer Request Enable */ -#define IER_TEOFE BIT(23) /* Frame Transmission End Enable */ -#define IER_TFSERRE BIT(21) /* Transmit Frame Sync Error Enable */ -#define IER_TFOVFE BIT(20) /* Transmit FIFO Overflow Enable */ -#define IER_TFUDFE BIT(19) /* Transmit FIFO Underflow Enable */ -#define IER_RDMAE BIT(15) /* Receive Data DMA Transfer Req. Enable */ -#define IER_RFFULE BIT(13) /* Receive FIFO Full Enable */ -#define IER_RDREQE BIT(12) /* Receive Data Transfer Request Enable */ -#define IER_REOFE BIT(7) /* Frame Reception End Enable */ -#define IER_RFSERRE BIT(5) /* Receive Frame Sync Error Enable */ -#define IER_RFUDFE BIT(4) /* Receive FIFO Underflow Enable */ -#define IER_RFOVFE BIT(3) /* Receive FIFO Overflow Enable */ +#define SITMDR1 0x00 /* Transmit Mode Register 1 */ +#define SITMDR2 0x04 /* Transmit Mode Register 2 */ +#define SITMDR3 0x08 /* Transmit Mode Register 3 */ +#define SIRMDR1 0x10 /* Receive Mode Register 1 */ +#define SIRMDR2 0x14 /* Receive Mode Register 2 */ +#define SIRMDR3 0x18 /* Receive Mode Register 3 */ +#define SITSCR 0x20 /* Transmit Clock Select Register */ +#define SIRSCR 0x22 /* Receive Clock Select Register (SH, A1, APE6) */ +#define SICTR 0x28 /* Control Register */ +#define SIFCTR 0x30 /* FIFO Control Register */ +#define SISTR 0x40 /* Status Register */ +#define SIIER 0x44 /* Interrupt Enable Register */ +#define SITDR1 0x48 /* Transmit Control Data Register 1 (SH, A1) */ +#define SITDR2 0x4c /* Transmit Control Data Register 2 (SH, A1) */ +#define SITFDR 0x50 /* Transmit FIFO Data Register */ +#define SIRDR1 0x58 /* Receive Control Data Register 1 (SH, A1) */ +#define SIRDR2 0x5c /* Receive Control Data Register 2 (SH, A1) */ +#define SIRFDR 0x60 /* Receive FIFO Data Register */ + +/* SITMDR1 and SIRMDR1 */ +#define SIMDR1_TRMD BIT(31) /* Transfer Mode (1 = Master mode) */ +#define SIMDR1_SYNCMD_MASK GENMASK(29, 28) /* SYNC Mode */ +#define SIMDR1_SYNCMD_SPI (2 << 28) /* Level mode/SPI */ +#define SIMDR1_SYNCMD_LR (3 << 28) /* L/R mode */ +#define SIMDR1_SYNCAC_SHIFT 25 /* Sync Polarity (1 = Active-low) */ +#define SIMDR1_BITLSB_SHIFT 24 /* MSB/LSB First (1 = LSB first) */ +#define SIMDR1_DTDL_SHIFT 20 /* Data Pin Bit Delay for MSIOF_SYNC */ +#define SIMDR1_SYNCDL_SHIFT 16 /* Frame Sync Signal Timing Delay */ +#define SIMDR1_FLD_MASK GENMASK(3, 2) /* Frame Sync Signal Interval (0-3) */ +#define SIMDR1_FLD_SHIFT 2 +#define SIMDR1_XXSTP BIT(0) /* Transmission/Reception Stop on FIFO */ +/* SITMDR1 */ +#define SITMDR1_PCON BIT(30) /* Transfer Signal Connection */ +#define SITMDR1_SYNCCH_MASK GENMASK(27, 26) /* Sync Signal Channel Select */ +#define SITMDR1_SYNCCH_SHIFT 26 /* 0=MSIOF_SYNC, 1=MSIOF_SS1, 2=MSIOF_SS2 */ + +/* SITMDR2 and SIRMDR2 */ +#define SIMDR2_BITLEN1(i) (((i) - 1) << 24) /* Data Size (8-32 bits) */ +#define SIMDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */ +#define SIMDR2_GRPMASK1 BIT(0) /* Group Output Mask 1 (SH, A1) */ + +/* SITSCR and SIRSCR */ +#define SISCR_BRPS_MASK GENMASK(12, 8) /* Prescaler Setting (1-32) */ +#define SISCR_BRPS(i) (((i) - 1) << 8) +#define SISCR_BRDV_MASK GENMASK(2, 0) /* Baud Rate Generator's Division Ratio */ +#define SISCR_BRDV_DIV_2 0 +#define SISCR_BRDV_DIV_4 1 +#define SISCR_BRDV_DIV_8 2 +#define SISCR_BRDV_DIV_16 3 +#define SISCR_BRDV_DIV_32 4 +#define SISCR_BRDV_DIV_1 7 + +/* SICTR */ +#define SICTR_TSCKIZ_MASK GENMASK(31, 30) /* Transmit Clock I/O Polarity Select */ +#define SICTR_TSCKIZ_SCK BIT(31) /* Disable SCK when TX disabled */ +#define SICTR_TSCKIZ_POL_SHIFT 30 /* Transmit Clock Polarity */ +#define SICTR_RSCKIZ_MASK GENMASK(29, 28) /* Receive Clock Polarity Select */ +#define SICTR_RSCKIZ_SCK BIT(29) /* Must match CTR_TSCKIZ_SCK */ +#define SICTR_RSCKIZ_POL_SHIFT 28 /* Receive Clock Polarity */ +#define SICTR_TEDG_SHIFT 27 /* Transmit Timing (1 = falling edge) */ +#define SICTR_REDG_SHIFT 26 /* Receive Timing (1 = falling edge) */ +#define SICTR_TXDIZ_MASK GENMASK(23, 22) /* Pin Output When TX is Disabled */ +#define SICTR_TXDIZ_LOW (0 << 22) /* 0 */ +#define SICTR_TXDIZ_HIGH (1 << 22) /* 1 */ +#define SICTR_TXDIZ_HIZ (2 << 22) /* High-impedance */ +#define SICTR_TSCKE BIT(15) /* Transmit Serial Clock Output Enable */ +#define SICTR_TFSE BIT(14) /* Transmit Frame Sync Signal Output Enable */ +#define SICTR_TXE BIT(9) /* Transmit Enable */ +#define SICTR_RXE BIT(8) /* Receive Enable */ +#define SICTR_TXRST BIT(1) /* Transmit Reset */ +#define SICTR_RXRST BIT(0) /* Receive Reset */ + +/* SIFCTR */ +#define SIFCTR_TFWM_MASK GENMASK(31, 29) /* Transmit FIFO Watermark */ +#define SIFCTR_TFWM_64 (0 << 29) /* Transfer Request when 64 empty stages */ +#define SIFCTR_TFWM_32 (1 << 29) /* Transfer Request when 32 empty stages */ +#define SIFCTR_TFWM_24 (2 << 29) /* Transfer Request when 24 empty stages */ +#define SIFCTR_TFWM_16 (3 << 29) /* Transfer Request when 16 empty stages */ +#define SIFCTR_TFWM_12 (4 << 29) /* Transfer Request when 12 empty stages */ +#define SIFCTR_TFWM_8 (5 << 29) /* Transfer Request when 8 empty stages */ +#define SIFCTR_TFWM_4 (6 << 29) /* Transfer Request when 4 empty stages */ +#define SIFCTR_TFWM_1 (7 << 29) /* Transfer Request when 1 empty stage */ +#define SIFCTR_TFUA_MASK GENMASK(26, 20) /* Transmit FIFO Usable Area */ +#define SIFCTR_TFUA_SHIFT 20 +#define SIFCTR_TFUA(i) ((i) << SIFCTR_TFUA_SHIFT) +#define SIFCTR_RFWM_MASK GENMASK(15, 13) /* Receive FIFO Watermark */ +#define SIFCTR_RFWM_1 (0 << 13) /* Transfer Request when 1 valid stages */ +#define SIFCTR_RFWM_4 (1 << 13) /* Transfer Request when 4 valid stages */ +#define SIFCTR_RFWM_8 (2 << 13) /* Transfer Request when 8 valid stages */ +#define SIFCTR_RFWM_16 (3 << 13) /* Transfer Request when 16 valid stages */ +#define SIFCTR_RFWM_32 (4 << 13) /* Transfer Request when 32 valid stages */ +#define SIFCTR_RFWM_64 (5 << 13) /* Transfer Request when 64 valid stages */ +#define SIFCTR_RFWM_128 (6 << 13) /* Transfer Request when 128 valid stages */ +#define SIFCTR_RFWM_256 (7 << 13) /* Transfer Request when 256 valid stages */ +#define SIFCTR_RFUA_MASK GENMASK(12, 4) /* Receive FIFO Usable Area (0x40 = full) */ +#define SIFCTR_RFUA_SHIFT 4 +#define SIFCTR_RFUA(i) ((i) << SIFCTR_RFUA_SHIFT) + +/* SISTR */ +#define SISTR_TFEMP BIT(29) /* Transmit FIFO Empty */ +#define SISTR_TDREQ BIT(28) /* Transmit Data Transfer Request */ +#define SISTR_TEOF BIT(23) /* Frame Transmission End */ +#define SISTR_TFSERR BIT(21) /* Transmit Frame Synchronization Error */ +#define SISTR_TFOVF BIT(20) /* Transmit FIFO Overflow */ +#define SISTR_TFUDF BIT(19) /* Transmit FIFO Underflow */ +#define SISTR_RFFUL BIT(13) /* Receive FIFO Full */ +#define SISTR_RDREQ BIT(12) /* Receive Data Transfer Request */ +#define SISTR_REOF BIT(7) /* Frame Reception End */ +#define SISTR_RFSERR BIT(5) /* Receive Frame Synchronization Error */ +#define SISTR_RFUDF BIT(4) /* Receive FIFO Underflow */ +#define SISTR_RFOVF BIT(3) /* Receive FIFO Overflow */ + +/* SIIER */ +#define SIIER_TDMAE BIT(31) /* Transmit Data DMA Transfer Req. Enable */ +#define SIIER_TFEMPE BIT(29) /* Transmit FIFO Empty Enable */ +#define SIIER_TDREQE BIT(28) /* Transmit Data Transfer Request Enable */ +#define SIIER_TEOFE BIT(23) /* Frame Transmission End Enable */ +#define SIIER_TFSERRE BIT(21) /* Transmit Frame Sync Error Enable */ +#define SIIER_TFOVFE BIT(20) /* Transmit FIFO Overflow Enable */ +#define SIIER_TFUDFE BIT(19) /* Transmit FIFO Underflow Enable */ +#define SIIER_RDMAE BIT(15) /* Receive Data DMA Transfer Req. Enable */ +#define SIIER_RFFULE BIT(13) /* Receive FIFO Full Enable */ +#define SIIER_RDREQE BIT(12) /* Receive Data Transfer Request Enable */ +#define SIIER_REOFE BIT(7) /* Frame Reception End Enable */ +#define SIIER_RFSERRE BIT(5) /* Receive Frame Sync Error Enable */ +#define SIIER_RFUDFE BIT(4) /* Receive FIFO Underflow Enable */ +#define SIIER_RFOVFE BIT(3) /* Receive FIFO Overflow Enable */ static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs) { switch (reg_offs) { - case TSCR: - case RSCR: + case SITSCR: + case SIRSCR: return ioread16(p->mapbase + reg_offs); default: return ioread32(p->mapbase + reg_offs); @@ -204,8 +204,8 @@ static void sh_msiof_write(struct sh_msiof_spi_priv *p, int reg_offs, u32 value) { switch (reg_offs) { - case TSCR: - case RSCR: + case SITSCR: + case SIRSCR: iowrite16(value, p->mapbase + reg_offs); break; default: @@ -220,12 +220,12 @@ static int sh_msiof_modify_ctr_wait(struct sh_msiof_spi_priv *p, u32 mask = clr | set; u32 data; - data = sh_msiof_read(p, CTR); + data = sh_msiof_read(p, SICTR); data &= ~clr; data |= set; - sh_msiof_write(p, CTR, data); + sh_msiof_write(p, SICTR, data); - return readl_poll_timeout_atomic(p->mapbase + CTR, data, + return readl_poll_timeout_atomic(p->mapbase + SICTR, data, (data & mask) == set, 1, 100); } @@ -234,7 +234,7 @@ static irqreturn_t sh_msiof_spi_irq(int irq, void *data) struct sh_msiof_spi_priv *p = data; /* just disable the interrupt and wake up */ - sh_msiof_write(p, IER, 0); + sh_msiof_write(p, SIIER, 0); complete(&p->done); return IRQ_HANDLED; @@ -242,20 +242,20 @@ static irqreturn_t sh_msiof_spi_irq(int irq, void *data) static void sh_msiof_spi_reset_regs(struct sh_msiof_spi_priv *p) { - u32 mask = CTR_TXRST | CTR_RXRST; + u32 mask = SICTR_TXRST | SICTR_RXRST; u32 data; - data = sh_msiof_read(p, CTR); + data = sh_msiof_read(p, SICTR); data |= mask; - sh_msiof_write(p, CTR, data); + sh_msiof_write(p, SICTR, data); - readl_poll_timeout_atomic(p->mapbase + CTR, data, !(data & mask), 1, + readl_poll_timeout_atomic(p->mapbase + SICTR, data, !(data & mask), 1, 100); } static const u32 sh_msiof_spi_div_array[] = { - SCR_BRDV_DIV_1, SCR_BRDV_DIV_2, SCR_BRDV_DIV_4, - SCR_BRDV_DIV_8, SCR_BRDV_DIV_16, SCR_BRDV_DIV_32, + SISCR_BRDV_DIV_1, SISCR_BRDV_DIV_2, SISCR_BRDV_DIV_4, + SISCR_BRDV_DIV_8, SISCR_BRDV_DIV_16, SISCR_BRDV_DIV_32, }; static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, @@ -273,7 +273,7 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, div = DIV_ROUND_UP(parent_rate, spi_hz); if (div <= 1024) { - /* SCR_BRDV_DIV_1 is valid only if BRPS is x 1/1 or x 1/2 */ + /* SISCR_BRDV_DIV_1 is valid only if BRPS is x 1/1 or x 1/2 */ if (!div_pow && div <= 32 && div > 2) div_pow = 1; @@ -292,10 +292,10 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, brps = 32; } - scr = sh_msiof_spi_div_array[div_pow] | SCR_BRPS(brps); - sh_msiof_write(p, TSCR, scr); + scr = sh_msiof_spi_div_array[div_pow] | SISCR_BRPS(brps); + sh_msiof_write(p, SITSCR, scr); if (!(p->ctlr->flags & SPI_CONTROLLER_MUST_TX)) - sh_msiof_write(p, RSCR, scr); + sh_msiof_write(p, SIRSCR, scr); } static u32 sh_msiof_get_delay_bit(u32 dtdl_or_syncdl) @@ -334,8 +334,8 @@ static u32 sh_msiof_spi_get_dtdl_and_syncdl(struct sh_msiof_spi_priv *p) return 0; } - val = sh_msiof_get_delay_bit(p->info->dtdl) << MDR1_DTDL_SHIFT; - val |= sh_msiof_get_delay_bit(p->info->syncdl) << MDR1_SYNCDL_SHIFT; + val = sh_msiof_get_delay_bit(p->info->dtdl) << SIMDR1_DTDL_SHIFT; + val |= sh_msiof_get_delay_bit(p->info->syncdl) << SIMDR1_SYNCDL_SHIFT; return val; } @@ -354,54 +354,54 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, u32 ss, * 1 0 11 11 0 0 * 1 1 11 11 1 1 */ - tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP; - tmp |= !cs_high << MDR1_SYNCAC_SHIFT; - tmp |= lsb_first << MDR1_BITLSB_SHIFT; + tmp = SIMDR1_SYNCMD_SPI | 1 << SIMDR1_FLD_SHIFT | SIMDR1_XXSTP; + tmp |= !cs_high << SIMDR1_SYNCAC_SHIFT; + tmp |= lsb_first << SIMDR1_BITLSB_SHIFT; tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p); if (spi_controller_is_slave(p->ctlr)) { - sh_msiof_write(p, TMDR1, tmp | TMDR1_PCON); + sh_msiof_write(p, SITMDR1, tmp | SITMDR1_PCON); } else { - sh_msiof_write(p, TMDR1, - tmp | MDR1_TRMD | TMDR1_PCON | - (ss < MAX_SS ? ss : 0) << TMDR1_SYNCCH_SHIFT); + sh_msiof_write(p, SITMDR1, + tmp | SIMDR1_TRMD | SITMDR1_PCON | + (ss < MAX_SS ? ss : 0) << SITMDR1_SYNCCH_SHIFT); } if (p->ctlr->flags & SPI_CONTROLLER_MUST_TX) { /* These bits are reserved if RX needs TX */ tmp &= ~0x0000ffff; } - sh_msiof_write(p, RMDR1, tmp); + sh_msiof_write(p, SIRMDR1, tmp); tmp = 0; - tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT; - tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT; + tmp |= SICTR_TSCKIZ_SCK | cpol << SICTR_TSCKIZ_POL_SHIFT; + tmp |= SICTR_RSCKIZ_SCK | cpol << SICTR_RSCKIZ_POL_SHIFT; edge = cpol ^ !cpha; - tmp |= edge << CTR_TEDG_SHIFT; - tmp |= edge << CTR_REDG_SHIFT; - tmp |= tx_hi_z ? CTR_TXDIZ_HIZ : CTR_TXDIZ_LOW; - sh_msiof_write(p, CTR, tmp); + tmp |= edge << SICTR_TEDG_SHIFT; + tmp |= edge << SICTR_REDG_SHIFT; + tmp |= tx_hi_z ? SICTR_TXDIZ_HIZ : SICTR_TXDIZ_LOW; + sh_msiof_write(p, SICTR, tmp); } static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p, const void *tx_buf, void *rx_buf, u32 bits, u32 words) { - u32 dr2 = MDR2_BITLEN1(bits) | MDR2_WDLEN1(words); + u32 dr2 = SIMDR2_BITLEN1(bits) | SIMDR2_WDLEN1(words); if (tx_buf || (p->ctlr->flags & SPI_CONTROLLER_MUST_TX)) - sh_msiof_write(p, TMDR2, dr2); + sh_msiof_write(p, SITMDR2, dr2); else - sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1); + sh_msiof_write(p, SITMDR2, dr2 | SIMDR2_GRPMASK1); if (rx_buf) - sh_msiof_write(p, RMDR2, dr2); + sh_msiof_write(p, SIRMDR2, dr2); } static void sh_msiof_reset_str(struct sh_msiof_spi_priv *p) { - sh_msiof_write(p, STR, - sh_msiof_read(p, STR) & ~(STR_TDREQ | STR_RDREQ)); + sh_msiof_write(p, SISTR, + sh_msiof_read(p, SISTR) & ~(SISTR_TDREQ | SISTR_RDREQ)); } static void sh_msiof_spi_write_fifo_8(struct sh_msiof_spi_priv *p, @@ -411,7 +411,7 @@ static void sh_msiof_spi_write_fifo_8(struct sh_msiof_spi_priv *p, int k; for (k = 0; k < words; k++) - sh_msiof_write(p, TFDR, buf_8[k] << fs); + sh_msiof_write(p, SITFDR, buf_8[k] << fs); } static void sh_msiof_spi_write_fifo_16(struct sh_msiof_spi_priv *p, @@ -421,7 +421,7 @@ static void sh_msiof_spi_write_fifo_16(struct sh_msiof_spi_priv *p, int k; for (k = 0; k < words; k++) - sh_msiof_write(p, TFDR, buf_16[k] << fs); + sh_msiof_write(p, SITFDR, buf_16[k] << fs); } static void sh_msiof_spi_write_fifo_16u(struct sh_msiof_spi_priv *p, @@ -431,7 +431,7 @@ static void sh_msiof_spi_write_fifo_16u(struct sh_msiof_spi_priv *p, int k; for (k = 0; k < words; k++) - sh_msiof_write(p, TFDR, get_unaligned(&buf_16[k]) << fs); + sh_msiof_write(p, SITFDR, get_unaligned(&buf_16[k]) << fs); } static void sh_msiof_spi_write_fifo_32(struct sh_msiof_spi_priv *p, @@ -441,7 +441,7 @@ static void sh_msiof_spi_write_fifo_32(struct sh_msiof_spi_priv *p, int k; for (k = 0; k < words; k++) - sh_msiof_write(p, TFDR, buf_32[k] << fs); + sh_msiof_write(p, SITFDR, buf_32[k] << fs); } static void sh_msiof_spi_write_fifo_32u(struct sh_msiof_spi_priv *p, @@ -451,7 +451,7 @@ static void sh_msiof_spi_write_fifo_32u(struct sh_msiof_spi_priv *p, int k; for (k = 0; k < words; k++) - sh_msiof_write(p, TFDR, get_unaligned(&buf_32[k]) << fs); + sh_msiof_write(p, SITFDR, get_unaligned(&buf_32[k]) << fs); } static void sh_msiof_spi_write_fifo_s32(struct sh_msiof_spi_priv *p, @@ -461,7 +461,7 @@ static void sh_msiof_spi_write_fifo_s32(struct sh_msiof_spi_priv *p, int k; for (k = 0; k < words; k++) - sh_msiof_write(p, TFDR, swab32(buf_32[k] << fs)); + sh_msiof_write(p, SITFDR, swab32(buf_32[k] << fs)); } static void sh_msiof_spi_write_fifo_s32u(struct sh_msiof_spi_priv *p, @@ -471,7 +471,7 @@ static void sh_msiof_spi_write_fifo_s32u(struct sh_msiof_spi_priv *p, int k; for (k = 0; k < words; k++) - sh_msiof_write(p, TFDR, swab32(get_unaligned(&buf_32[k]) << fs)); + sh_msiof_write(p, SITFDR, swab32(get_unaligned(&buf_32[k]) << fs)); } static void sh_msiof_spi_read_fifo_8(struct sh_msiof_spi_priv *p, @@ -481,7 +481,7 @@ static void sh_msiof_spi_read_fifo_8(struct sh_msiof_spi_priv *p, int k; for (k = 0; k < words; k++) - buf_8[k] = sh_msiof_read(p, RFDR) >> fs; + buf_8[k] = sh_msiof_read(p, SIRFDR) >> fs; } static void sh_msiof_spi_read_fifo_16(struct sh_msiof_spi_priv *p, @@ -491,7 +491,7 @@ static void sh_msiof_spi_read_fifo_16(struct sh_msiof_spi_priv *p, int k; for (k = 0; k < words; k++) - buf_16[k] = sh_msiof_read(p, RFDR) >> fs; + buf_16[k] = sh_msiof_read(p, SIRFDR) >> fs; } static void sh_msiof_spi_read_fifo_16u(struct sh_msiof_spi_priv *p, @@ -501,7 +501,7 @@ static void sh_msiof_spi_read_fifo_16u(struct sh_msiof_spi_priv *p, int k; for (k = 0; k < words; k++) - put_unaligned(sh_msiof_read(p, RFDR) >> fs, &buf_16[k]); + put_unaligned(sh_msiof_read(p, SIRFDR) >> fs, &buf_16[k]); } static void sh_msiof_spi_read_fifo_32(struct sh_msiof_spi_priv *p, @@ -511,7 +511,7 @@ static void sh_msiof_spi_read_fifo_32(struct sh_msiof_spi_priv *p, int k; for (k = 0; k < words; k++) - buf_32[k] = sh_msiof_read(p, RFDR) >> fs; + buf_32[k] = sh_msiof_read(p, SIRFDR) >> fs; } static void sh_msiof_spi_read_fifo_32u(struct sh_msiof_spi_priv *p, @@ -521,7 +521,7 @@ static void sh_msiof_spi_read_fifo_32u(struct sh_msiof_spi_priv *p, int k; for (k = 0; k < words; k++) - put_unaligned(sh_msiof_read(p, RFDR) >> fs, &buf_32[k]); + put_unaligned(sh_msiof_read(p, SIRFDR) >> fs, &buf_32[k]); } static void sh_msiof_spi_read_fifo_s32(struct sh_msiof_spi_priv *p, @@ -531,7 +531,7 @@ static void sh_msiof_spi_read_fifo_s32(struct sh_msiof_spi_priv *p, int k; for (k = 0; k < words; k++) - buf_32[k] = swab32(sh_msiof_read(p, RFDR) >> fs); + buf_32[k] = swab32(sh_msiof_read(p, SIRFDR) >> fs); } static void sh_msiof_spi_read_fifo_s32u(struct sh_msiof_spi_priv *p, @@ -541,7 +541,7 @@ static void sh_msiof_spi_read_fifo_s32u(struct sh_msiof_spi_priv *p, int k; for (k = 0; k < words; k++) - put_unaligned(swab32(sh_msiof_read(p, RFDR) >> fs), &buf_32[k]); + put_unaligned(swab32(sh_msiof_read(p, SIRFDR) >> fs), &buf_32[k]); } static int sh_msiof_spi_setup(struct spi_device *spi) @@ -558,17 +558,17 @@ static int sh_msiof_spi_setup(struct spi_device *spi) return 0; /* Configure native chip select mode/polarity early */ - clr = MDR1_SYNCMD_MASK; - set = MDR1_SYNCMD_SPI; + clr = SIMDR1_SYNCMD_MASK; + set = SIMDR1_SYNCMD_SPI; if (spi->mode & SPI_CS_HIGH) - clr |= BIT(MDR1_SYNCAC_SHIFT); + clr |= BIT(SIMDR1_SYNCAC_SHIFT); else - set |= BIT(MDR1_SYNCAC_SHIFT); + set |= BIT(SIMDR1_SYNCAC_SHIFT); pm_runtime_get_sync(&p->pdev->dev); - tmp = sh_msiof_read(p, TMDR1) & ~clr; - sh_msiof_write(p, TMDR1, tmp | set | MDR1_TRMD | TMDR1_PCON); - tmp = sh_msiof_read(p, RMDR1) & ~clr; - sh_msiof_write(p, RMDR1, tmp | set); + tmp = sh_msiof_read(p, SITMDR1) & ~clr; + sh_msiof_write(p, SITMDR1, tmp | set | SIMDR1_TRMD | SITMDR1_PCON); + tmp = sh_msiof_read(p, SIRMDR1) & ~clr; + sh_msiof_write(p, SIRMDR1, tmp | set); pm_runtime_put(&p->pdev->dev); p->native_cs_high = spi->mode & SPI_CS_HIGH; p->native_cs_inited = true; @@ -604,15 +604,15 @@ static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf) /* setup clock and rx/tx signals */ if (!slave) - ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TSCKE); + ret = sh_msiof_modify_ctr_wait(p, 0, SICTR_TSCKE); if (rx_buf && !ret) - ret = sh_msiof_modify_ctr_wait(p, 0, CTR_RXE); + ret = sh_msiof_modify_ctr_wait(p, 0, SICTR_RXE); if (!ret) - ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TXE); + ret = sh_msiof_modify_ctr_wait(p, 0, SICTR_TXE); /* start by setting frame bit */ if (!ret && !slave) - ret = sh_msiof_modify_ctr_wait(p, 0, CTR_TFSE); + ret = sh_msiof_modify_ctr_wait(p, 0, SICTR_TFSE); return ret; } @@ -624,13 +624,13 @@ static int sh_msiof_spi_stop(struct sh_msiof_spi_priv *p, void *rx_buf) /* shut down frame, rx/tx and clock signals */ if (!slave) - ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0); + ret = sh_msiof_modify_ctr_wait(p, SICTR_TFSE, 0); if (!ret) - ret = sh_msiof_modify_ctr_wait(p, CTR_TXE, 0); + ret = sh_msiof_modify_ctr_wait(p, SICTR_TXE, 0); if (rx_buf && !ret) - ret = sh_msiof_modify_ctr_wait(p, CTR_RXE, 0); + ret = sh_msiof_modify_ctr_wait(p, SICTR_RXE, 0); if (!ret && !slave) - ret = sh_msiof_modify_ctr_wait(p, CTR_TSCKE, 0); + ret = sh_msiof_modify_ctr_wait(p, SICTR_TSCKE, 0); return ret; } @@ -685,11 +685,11 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, fifo_shift = 32 - bits; /* default FIFO watermarks for PIO */ - sh_msiof_write(p, FCTR, 0); + sh_msiof_write(p, SIFCTR, 0); /* setup msiof transfer mode registers */ sh_msiof_spi_set_mode_regs(p, tx_buf, rx_buf, bits, words); - sh_msiof_write(p, IER, IER_TEOFE | IER_REOFE); + sh_msiof_write(p, SIIER, SIIER_TEOFE | SIIER_REOFE); /* write tx fifo */ if (tx_buf) @@ -728,7 +728,7 @@ stop_reset: sh_msiof_reset_str(p); sh_msiof_spi_stop(p, rx_buf); stop_ier: - sh_msiof_write(p, IER, 0); + sh_msiof_write(p, SIIER, 0); return ret; } @@ -747,7 +747,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, /* First prepare and submit the DMA request(s), as this may fail */ if (rx) { - ier_bits |= IER_RDREQE | IER_RDMAE; + ier_bits |= SIIER_RDREQE | SIIER_RDMAE; desc_rx = dmaengine_prep_slave_single(p->ctlr->dma_rx, p->rx_dma_addr, len, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -762,7 +762,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, } if (tx) { - ier_bits |= IER_TDREQE | IER_TDMAE; + ier_bits |= SIIER_TDREQE | SIIER_TDMAE; dma_sync_single_for_device(p->ctlr->dma_tx->device->dev, p->tx_dma_addr, len, DMA_TO_DEVICE); desc_tx = dmaengine_prep_slave_single(p->ctlr->dma_tx, @@ -783,12 +783,12 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, } /* 1 stage FIFO watermarks for DMA */ - sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1); + sh_msiof_write(p, SIFCTR, SIFCTR_TFWM_1 | SIFCTR_RFWM_1); /* setup msiof transfer mode registers (32-bit words) */ sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4); - sh_msiof_write(p, IER, ier_bits); + sh_msiof_write(p, SIIER, ier_bits); reinit_completion(&p->done); if (tx) @@ -820,10 +820,10 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, if (ret) goto stop_reset; - sh_msiof_write(p, IER, 0); + sh_msiof_write(p, SIIER, 0); } else { /* wait for tx fifo to be emptied */ - sh_msiof_write(p, IER, IER_TEOFE); + sh_msiof_write(p, SIIER, SIIER_TEOFE); ret = sh_msiof_wait_for_completion(p, &p->done); if (ret) goto stop_reset; @@ -853,7 +853,7 @@ stop_dma: no_dma_tx: if (rx) dmaengine_terminate_all(p->ctlr->dma_rx); - sh_msiof_write(p, IER, 0); + sh_msiof_write(p, SIIER, 0); return ret; } @@ -1189,12 +1189,12 @@ static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p) ctlr = p->ctlr; ctlr->dma_tx = sh_msiof_request_dma_chan(dev, DMA_MEM_TO_DEV, - dma_tx_id, res->start + TFDR); + dma_tx_id, res->start + SITFDR); if (!ctlr->dma_tx) return -ENODEV; ctlr->dma_rx = sh_msiof_request_dma_chan(dev, DMA_DEV_TO_MEM, - dma_rx_id, res->start + RFDR); + dma_rx_id, res->start + SIRFDR); if (!ctlr->dma_rx) goto free_tx_chan; -- cgit v1.2.3 From 603e92ff10a81b965ac41dc9fb3d287408e834fb Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Thu, 9 Jan 2020 13:23:41 +0100 Subject: spi: bcm2835: Raise maximum number of slaves to 4 The "RevPi Connect Flat" PLC offered by KUNBUS has 4 slaves attached to the BCM2835 SPI master. Raise the maximum number of slaves in the driver accordingly. Signed-off-by: Lukas Wunner Reviewed-by: Nicolas Saenz Julienne Link: https://lore.kernel.org/r/01453fd062de2d49bd74a847e13a0781cbf8143d.1578572268.git.lukas@wunner.de Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index b784c9fdf9ec..11c235879bb7 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -68,7 +68,7 @@ #define BCM2835_SPI_FIFO_SIZE 64 #define BCM2835_SPI_FIFO_SIZE_3_4 48 #define BCM2835_SPI_DMA_MIN_LENGTH 96 -#define BCM2835_SPI_NUM_CS 3 /* raise as necessary */ +#define BCM2835_SPI_NUM_CS 4 /* raise as necessary */ #define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ | SPI_NO_CS | SPI_3WIRE) -- cgit v1.2.3 From 0a1eb761ff30cdc089bcc94e1bd540b6956487c5 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Wed, 8 Jan 2020 14:55:19 +0200 Subject: dt-bindings: spi_atmel: add microchip,sam9x60-spi Add microchip,sam9x60-spi to DT bindings documentation. Signed-off-by: Claudiu Beznea Link: https://lore.kernel.org/r/1578488123-26127-13-git-send-email-claudiu.beznea@microchip.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi_atmel.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/spi_atmel.txt b/Documentation/devicetree/bindings/spi/spi_atmel.txt index f99c733d75c1..5bb4a8f1df7a 100644 --- a/Documentation/devicetree/bindings/spi/spi_atmel.txt +++ b/Documentation/devicetree/bindings/spi/spi_atmel.txt @@ -1,7 +1,7 @@ Atmel SPI device Required properties: -- compatible : should be "atmel,at91rm9200-spi". +- compatible : should be "atmel,at91rm9200-spi" or "microchip,sam9x60-spi". - reg: Address and length of the register set for the device - interrupts: Should contain spi interrupt - cs-gpios: chipselects (optional for SPI controller version >= 2 with the -- cgit v1.2.3 From a2ca53b52e007de81752bbb443d828f5950d6d04 Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 9 Dec 2019 22:08:09 +0800 Subject: spi: Add HiSilicon v3xx SPI NOR flash controller driver Add the driver for the HiSilicon v3xx SPI NOR flash controller, commonly found in hi16xx chipsets. This is a different controller than that in drivers/mtd/spi-nor/hisi-sfc.c; indeed, the naming for that driver is poor, since it is really known as FMC, and can support other memory technologies. The driver module name is "hisi-sfc-v3xx", as recommended by HW designer, being an attempt to provide a distinct name - v3xx being the unique controller versioning. Only ACPI firmware is supported. DMA is not supported, and we just use polling mode for operation completion notification. The driver uses the SPI MEM OPs. Signed-off-by: John Garry Link: https://lore.kernel.org/r/1575900490-74467-3-git-send-email-john.garry@huawei.com Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 9 ++ drivers/spi/Makefile | 1 + drivers/spi/spi-hisi-sfc-v3xx.c | 284 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 294 insertions(+) create mode 100644 drivers/spi/spi-hisi-sfc-v3xx.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 870f7797b56b..d6ed0c355954 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -281,6 +281,15 @@ config SPI_FSL_QUADSPI This controller does not support generic SPI messages. It only supports the high-level SPI memory interface. +config SPI_HISI_SFC_V3XX + tristate "HiSilicon SPI-NOR Flash Controller for Hi16XX chipsets" + depends on (ARM64 && ACPI) || COMPILE_TEST + depends on HAS_IOMEM + select CONFIG_MTD_SPI_NOR + help + This enables support for HiSilicon v3xx SPI-NOR flash controller + found in hi16xx chipsets. + config SPI_NXP_FLEXSPI tristate "NXP Flex SPI controller" depends on ARCH_LAYERSCAPE || HAS_IOMEM diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index bb49c9e6d0a0..9b65ec5afc5e 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_SPI_FSL_LPSPI) += spi-fsl-lpspi.o obj-$(CONFIG_SPI_FSL_QUADSPI) += spi-fsl-qspi.o obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o obj-$(CONFIG_SPI_GPIO) += spi-gpio.o +obj-$(CONFIG_SPI_HISI_SFC_V3XX) += spi-hisi-sfc-v3xx.o obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o obj-$(CONFIG_SPI_IMX) += spi-imx.o obj-$(CONFIG_SPI_LANTIQ_SSC) += spi-lantiq-ssc.o diff --git a/drivers/spi/spi-hisi-sfc-v3xx.c b/drivers/spi/spi-hisi-sfc-v3xx.c new file mode 100644 index 000000000000..4cf8fc80a7b7 --- /dev/null +++ b/drivers/spi/spi-hisi-sfc-v3xx.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// HiSilicon SPI NOR V3XX Flash Controller Driver for hi16xx chipsets +// +// Copyright (c) 2019 HiSilicon Technologies Co., Ltd. +// Author: John Garry + +#include +#include +#include +#include +#include +#include +#include +#include + +#define HISI_SFC_V3XX_VERSION (0x1f8) + +#define HISI_SFC_V3XX_CMD_CFG (0x300) +#define HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF 9 +#define HISI_SFC_V3XX_CMD_CFG_RW_MSK BIT(8) +#define HISI_SFC_V3XX_CMD_CFG_DATA_EN_MSK BIT(7) +#define HISI_SFC_V3XX_CMD_CFG_DUMMY_CNT_OFF 4 +#define HISI_SFC_V3XX_CMD_CFG_ADDR_EN_MSK BIT(3) +#define HISI_SFC_V3XX_CMD_CFG_CS_SEL_OFF 1 +#define HISI_SFC_V3XX_CMD_CFG_START_MSK BIT(0) +#define HISI_SFC_V3XX_CMD_INS (0x308) +#define HISI_SFC_V3XX_CMD_ADDR (0x30c) +#define HISI_SFC_V3XX_CMD_DATABUF0 (0x400) + +struct hisi_sfc_v3xx_host { + struct device *dev; + void __iomem *regbase; + int max_cmd_dword; +}; + +#define HISI_SFC_V3XX_WAIT_TIMEOUT_US 1000000 +#define HISI_SFC_V3XX_WAIT_POLL_INTERVAL_US 10 + +static int hisi_sfc_v3xx_wait_cmd_idle(struct hisi_sfc_v3xx_host *host) +{ + u32 reg; + + return readl_poll_timeout(host->regbase + HISI_SFC_V3XX_CMD_CFG, reg, + !(reg & HISI_SFC_V3XX_CMD_CFG_START_MSK), + HISI_SFC_V3XX_WAIT_POLL_INTERVAL_US, + HISI_SFC_V3XX_WAIT_TIMEOUT_US); +} + +static int hisi_sfc_v3xx_adjust_op_size(struct spi_mem *mem, + struct spi_mem_op *op) +{ + struct spi_device *spi = mem->spi; + struct hisi_sfc_v3xx_host *host; + uintptr_t addr = (uintptr_t)op->data.buf.in; + int max_byte_count; + + host = spi_controller_get_devdata(spi->master); + + max_byte_count = host->max_cmd_dword * 4; + + if (!IS_ALIGNED(addr, 4) && op->data.nbytes >= 4) + op->data.nbytes = 4 - (addr % 4); + else if (op->data.nbytes > max_byte_count) + op->data.nbytes = max_byte_count; + + return 0; +} + +/* + * memcpy_{to,from}io doesn't gurantee 32b accesses - which we require for the + * DATABUF registers -so use __io{read,write}32_copy when possible. For + * trailing bytes, copy them byte-by-byte from the DATABUF register, as we + * can't clobber outside the source/dest buffer. + * + * For efficient data read/write, we try to put any start 32b unaligned data + * into a separate transaction in hisi_sfc_v3xx_adjust_op_size(). + */ +static void hisi_sfc_v3xx_read_databuf(struct hisi_sfc_v3xx_host *host, + u8 *to, unsigned int len) +{ + void __iomem *from; + int i; + + from = host->regbase + HISI_SFC_V3XX_CMD_DATABUF0; + + if (IS_ALIGNED((uintptr_t)to, 4)) { + int words = len / 4; + + __ioread32_copy(to, from, words); + + len -= words * 4; + if (len) { + u32 val; + + to += words * 4; + from += words * 4; + + val = __raw_readl(from); + + for (i = 0; i < len; i++, val >>= 8, to++) + *to = (u8)val; + } + } else { + for (i = 0; i < DIV_ROUND_UP(len, 4); i++, from += 4) { + u32 val = __raw_readl(from); + int j; + + for (j = 0; j < 4 && (j + (i * 4) < len); + to++, val >>= 8, j++) + *to = (u8)val; + } + } +} + +static void hisi_sfc_v3xx_write_databuf(struct hisi_sfc_v3xx_host *host, + const u8 *from, unsigned int len) +{ + void __iomem *to; + int i; + + to = host->regbase + HISI_SFC_V3XX_CMD_DATABUF0; + + if (IS_ALIGNED((uintptr_t)from, 4)) { + int words = len / 4; + + __iowrite32_copy(to, from, words); + + len -= words * 4; + if (len) { + u32 val = 0; + + to += words * 4; + from += words * 4; + + for (i = 0; i < len; i++, from++) + val |= *from << i * 8; + __raw_writel(val, to); + } + + } else { + for (i = 0; i < DIV_ROUND_UP(len, 4); i++, to += 4) { + u32 val = 0; + int j; + + for (j = 0; j < 4 && (j + (i * 4) < len); + from++, j++) + val |= *from << j * 8; + __raw_writel(val, to); + } + } +} + +static int hisi_sfc_v3xx_generic_exec_op(struct hisi_sfc_v3xx_host *host, + const struct spi_mem_op *op, + u8 chip_select) +{ + int ret, len = op->data.nbytes; + u32 config = 0; + + if (op->addr.nbytes) + config |= HISI_SFC_V3XX_CMD_CFG_ADDR_EN_MSK; + + if (op->data.dir != SPI_MEM_NO_DATA) { + config |= (len - 1) << HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF; + config |= HISI_SFC_V3XX_CMD_CFG_DATA_EN_MSK; + } + + if (op->data.dir == SPI_MEM_DATA_OUT) + hisi_sfc_v3xx_write_databuf(host, op->data.buf.out, len); + else if (op->data.dir == SPI_MEM_DATA_IN) + config |= HISI_SFC_V3XX_CMD_CFG_RW_MSK; + + config |= op->dummy.nbytes << HISI_SFC_V3XX_CMD_CFG_DUMMY_CNT_OFF | + chip_select << HISI_SFC_V3XX_CMD_CFG_CS_SEL_OFF | + HISI_SFC_V3XX_CMD_CFG_START_MSK; + + writel(op->addr.val, host->regbase + HISI_SFC_V3XX_CMD_ADDR); + writel(op->cmd.opcode, host->regbase + HISI_SFC_V3XX_CMD_INS); + + writel(config, host->regbase + HISI_SFC_V3XX_CMD_CFG); + + ret = hisi_sfc_v3xx_wait_cmd_idle(host); + if (ret) + return ret; + + if (op->data.dir == SPI_MEM_DATA_IN) + hisi_sfc_v3xx_read_databuf(host, op->data.buf.in, len); + + return 0; +} + +static int hisi_sfc_v3xx_exec_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + struct hisi_sfc_v3xx_host *host; + struct spi_device *spi = mem->spi; + u8 chip_select = spi->chip_select; + + host = spi_controller_get_devdata(spi->master); + + return hisi_sfc_v3xx_generic_exec_op(host, op, chip_select); +} + +static const struct spi_controller_mem_ops hisi_sfc_v3xx_mem_ops = { + .adjust_op_size = hisi_sfc_v3xx_adjust_op_size, + .exec_op = hisi_sfc_v3xx_exec_op, +}; + +static int hisi_sfc_v3xx_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct hisi_sfc_v3xx_host *host; + struct spi_controller *ctlr; + u32 version; + int ret; + + ctlr = spi_alloc_master(&pdev->dev, sizeof(*host)); + if (!ctlr) + return -ENOMEM; + + ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | + SPI_TX_DUAL | SPI_TX_QUAD; + + host = spi_controller_get_devdata(ctlr); + host->dev = dev; + + platform_set_drvdata(pdev, host); + + host->regbase = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(host->regbase)) { + ret = PTR_ERR(host->regbase); + goto err_put_master; + } + + ctlr->bus_num = -1; + ctlr->num_chipselect = 1; + ctlr->mem_ops = &hisi_sfc_v3xx_mem_ops; + + version = readl(host->regbase + HISI_SFC_V3XX_VERSION); + + switch (version) { + case 0x351: + host->max_cmd_dword = 64; + break; + default: + host->max_cmd_dword = 16; + break; + } + + ret = devm_spi_register_controller(dev, ctlr); + if (ret) + goto err_put_master; + + dev_info(&pdev->dev, "hw version 0x%x\n", version); + + return 0; + +err_put_master: + spi_master_put(ctlr); + return ret; +} + +#if IS_ENABLED(CONFIG_ACPI) +static const struct acpi_device_id hisi_sfc_v3xx_acpi_ids[] = { + {"HISI0341", 0}, + {} +}; +MODULE_DEVICE_TABLE(acpi, hisi_sfc_v3xx_acpi_ids); +#endif + +static struct platform_driver hisi_sfc_v3xx_spi_driver = { + .driver = { + .name = "hisi-sfc-v3xx", + .acpi_match_table = ACPI_PTR(hisi_sfc_v3xx_acpi_ids), + }, + .probe = hisi_sfc_v3xx_probe, +}; + +module_platform_driver(hisi_sfc_v3xx_spi_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("John Garry "); +MODULE_DESCRIPTION("HiSilicon SPI NOR V3XX Flash Controller Driver for hi16xx chipsets"); -- cgit v1.2.3 From 99eb0a1221ac1083b8c87932c438ef016abdaa05 Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 9 Dec 2019 22:08:10 +0800 Subject: MAINTAINERS: Add a maintainer for the HiSilicon v3xx SFC driver Set John Garry @ Huawei as the maintainer. Signed-off-by: John Garry Link: https://lore.kernel.org/r/1575900490-74467-4-git-send-email-john.garry@huawei.com Signed-off-by: Mark Brown --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index bd5847e802de..8c119bd4f687 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7492,6 +7492,12 @@ S: Supported F: drivers/scsi/hisi_sas/ F: Documentation/devicetree/bindings/scsi/hisilicon-sas.txt +HISILICON V3XX SPI NOR FLASH Controller Driver +M: John Garry +W: http://www.hisilicon.com +S: Maintained +F: drivers/spi/spi-hisi-sfc-v3xx.c + HISILICON QM AND ZIP Controller DRIVER M: Zhou Wang L: linux-crypto@vger.kernel.org -- cgit v1.2.3 From b8d40d7712f10475effc4552eda96b9d44822cfb Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Wed, 8 Jan 2020 13:40:32 -0800 Subject: spi: spi-qcom-qspi: Use device managed memory for clk_bulk_data Currrently the memory for the clk_bulk_data of the QSPI controller is allocated with spi_alloc_master(). The bulk data pointer is passed to devm_clk_bulk_get() which saves it in clk_bulk_devres->clks. When the device is removed later devm_clk_bulk_release() is called and uses the bulk data referenced by the pointer to release the clocks. For this driver this results in accessing memory that has already been freed, since the memory allocated with spi_alloc_master() is released by spi_controller_release(), which is called before the managed resources are released. Use device managed memory for the clock bulk data to fix the issue described above. Signed-off-by: Matthias Kaehlcke Reviewed-by: Douglas Anderson Link: https://lore.kernel.org/r/20200108133948.1.I35ceb4db3ad8cfab78f7cd51494aeff4891339f5@changeid Signed-off-by: Mark Brown --- drivers/spi/spi-qcom-qspi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c index 250fd60e1678..3c4f83bf7084 100644 --- a/drivers/spi/spi-qcom-qspi.c +++ b/drivers/spi/spi-qcom-qspi.c @@ -137,7 +137,7 @@ enum qspi_clocks { struct qcom_qspi { void __iomem *base; struct device *dev; - struct clk_bulk_data clks[QSPI_NUM_CLKS]; + struct clk_bulk_data *clks; struct qspi_xfer xfer; /* Lock to protect xfer and IRQ accessed registers */ spinlock_t lock; @@ -445,6 +445,13 @@ static int qcom_qspi_probe(struct platform_device *pdev) goto exit_probe_master_put; } + ctrl->clks = devm_kcalloc(dev, QSPI_NUM_CLKS, + sizeof(*ctrl->clks), GFP_KERNEL); + if (!ctrl->clks) { + ret = -ENOMEM; + goto exit_probe_master_put; + } + ctrl->clks[QSPI_CLK_CORE].id = "core"; ctrl->clks[QSPI_CLK_IFACE].id = "iface"; ret = devm_clk_bulk_get(dev, QSPI_NUM_CLKS, ctrl->clks); -- cgit v1.2.3 From e97f491450805fe6cbfd482b97b5427b21dec575 Mon Sep 17 00:00:00 2001 From: Jean Pihet Date: Tue, 14 Jan 2020 13:41:24 +0100 Subject: spi: spi-ti-qspi: support large flash devices The TI QSPI IP has limitations: - the MMIO region is 64MB in size - in non-MMIO mode, the transfer can handle 4096 words max. Add support for bigger devices. Use MMIO and DMA transfers below the 64MB boundary, use software generated transfers above. Signed-off-by: Jean Pihet Cc: Ryan Barnett Cc: Conrad Ratschan Cc: Arnout Vandecappelle Link: https://lore.kernel.org/r/20200114124125.361429-2-jean.pihet@newoldbits.com Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index ad2942b3d0a9..0334e2926998 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -525,6 +525,35 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode, QSPI_SPI_SETUP_REG(spi->chip_select)); } +static int ti_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) +{ + struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->master); + size_t max_len; + + if (op->data.dir == SPI_MEM_DATA_IN) { + if (op->addr.val < qspi->mmap_size) { + /* Limit MMIO to the mmaped region */ + if (op->addr.val + op->data.nbytes > qspi->mmap_size) { + max_len = qspi->mmap_size - op->addr.val; + op->data.nbytes = min((size_t) op->data.nbytes, + max_len); + } + } else { + /* + * Use fallback mode (SW generated transfers) above the + * mmaped region. + * Adjust size to comply with the QSPI max frame length. + */ + max_len = QSPI_FRAME; + max_len -= 1 + op->addr.nbytes + op->dummy.nbytes; + op->data.nbytes = min((size_t) op->data.nbytes, + max_len); + } + } + + return 0; +} + static int ti_qspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) { @@ -575,6 +604,7 @@ static int ti_qspi_exec_mem_op(struct spi_mem *mem, static const struct spi_controller_mem_ops ti_qspi_mem_ops = { .exec_op = ti_qspi_exec_mem_op, + .adjust_op_size = ti_qspi_adjust_op_size, }; static int ti_qspi_start_transfer_one(struct spi_master *master, -- cgit v1.2.3 From e7cc5cfbea4c9bd2c452cb81d0829e9259dd84d8 Mon Sep 17 00:00:00 2001 From: Jean Pihet Date: Tue, 14 Jan 2020 13:41:25 +0100 Subject: spi: spi-ti-qspi: optimize byte-transfers Optimize the 8-bit based transfers, as used by the SPI flash devices, by reading the data registers by 32 and 128 bits when possible and copy the contents to the receive buffer. The speed improvement is 4.9x using quad read. Signed-off-by: Jean Pihet Cc: Ryan Barnett Cc: Conrad Ratschan Cc: Arnout Vandecappelle Link: https://lore.kernel.org/r/20200114124125.361429-3-jean.pihet@newoldbits.com Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 54 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 0334e2926998..858fda8ac73e 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -314,6 +314,8 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t, { int wlen; unsigned int cmd; + u32 rx; + u8 rxlen, rx_wlen; u8 *rxbuf; rxbuf = t->rx_buf; @@ -336,14 +338,60 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t, if (qspi_is_busy(qspi)) return -EBUSY; + switch (wlen) { + case 1: + /* + * Optimize the 8-bit words transfers, as used by + * the SPI flash devices. + */ + if (count >= QSPI_WLEN_MAX_BYTES) { + rxlen = QSPI_WLEN_MAX_BYTES; + } else { + rxlen = min(count, 4); + } + rx_wlen = rxlen << 3; + cmd &= ~QSPI_WLEN_MASK; + cmd |= QSPI_WLEN(rx_wlen); + break; + default: + rxlen = wlen; + break; + } + ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); if (ti_qspi_poll_wc(qspi)) { dev_err(qspi->dev, "read timed out\n"); return -ETIMEDOUT; } + switch (wlen) { case 1: - *rxbuf = readb(qspi->base + QSPI_SPI_DATA_REG); + /* + * Optimize the 8-bit words transfers, as used by + * the SPI flash devices. + */ + if (count >= QSPI_WLEN_MAX_BYTES) { + u32 *rxp = (u32 *) rxbuf; + rx = readl(qspi->base + QSPI_SPI_DATA_REG_3); + *rxp++ = be32_to_cpu(rx); + rx = readl(qspi->base + QSPI_SPI_DATA_REG_2); + *rxp++ = be32_to_cpu(rx); + rx = readl(qspi->base + QSPI_SPI_DATA_REG_1); + *rxp++ = be32_to_cpu(rx); + rx = readl(qspi->base + QSPI_SPI_DATA_REG); + *rxp++ = be32_to_cpu(rx); + } else { + u8 *rxp = rxbuf; + rx = readl(qspi->base + QSPI_SPI_DATA_REG); + if (rx_wlen >= 8) + *rxp++ = rx >> (rx_wlen - 8); + if (rx_wlen >= 16) + *rxp++ = rx >> (rx_wlen - 16); + if (rx_wlen >= 24) + *rxp++ = rx >> (rx_wlen - 24); + if (rx_wlen >= 32) + *rxp++ = rx; + } break; case 2: *((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG); @@ -352,8 +400,8 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t, *((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG); break; } - rxbuf += wlen; - count -= wlen; + rxbuf += rxlen; + count -= rxlen; } return 0; -- cgit v1.2.3 From bc3a8b295e5bca9d1ec2622a6ba38289f9fd3d8a Mon Sep 17 00:00:00 2001 From: Philippe Schenker Date: Wed, 4 Dec 2019 14:13:33 +0000 Subject: spi: fsl-lpspi: fix only one cs-gpio working Why it does not work at the moment: - num_chipselect sets the number of cs-gpios that are in the DT. This comes from drivers/spi/spi.c - num_chipselect gets set with devm_spi_register_controller, that is called in drivers/spi/spi.c - devm_spi_register_controller got called after num_chipselect has been used. How this commit fixes the issue: - devm_spi_register_controller gets called before num_chipselect is being used. Fixes: c7a402599504 ("spi: lpspi: use the core way to implement cs-gpio function") Signed-off-by: Philippe Schenker Link: https://lore.kernel.org/r/20191204141312.1411251-1-philippe.schenker@toradex.com Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lpspi.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 56855d5e9e8b..d0b8cc741a24 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -862,6 +862,22 @@ static int fsl_lpspi_probe(struct platform_device *pdev) fsl_lpspi->dev = &pdev->dev; fsl_lpspi->is_slave = is_slave; + controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); + controller->transfer_one = fsl_lpspi_transfer_one; + controller->prepare_transfer_hardware = lpspi_prepare_xfer_hardware; + controller->unprepare_transfer_hardware = lpspi_unprepare_xfer_hardware; + controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + controller->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX; + controller->dev.of_node = pdev->dev.of_node; + controller->bus_num = pdev->id; + controller->slave_abort = fsl_lpspi_slave_abort; + + ret = devm_spi_register_controller(&pdev->dev, controller); + if (ret < 0) { + dev_err(&pdev->dev, "spi_register_controller error.\n"); + goto out_controller_put; + } + if (!fsl_lpspi->is_slave) { for (i = 0; i < controller->num_chipselect; i++) { int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); @@ -885,16 +901,6 @@ static int fsl_lpspi_probe(struct platform_device *pdev) controller->prepare_message = fsl_lpspi_prepare_message; } - controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); - controller->transfer_one = fsl_lpspi_transfer_one; - controller->prepare_transfer_hardware = lpspi_prepare_xfer_hardware; - controller->unprepare_transfer_hardware = lpspi_unprepare_xfer_hardware; - controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; - controller->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX; - controller->dev.of_node = pdev->dev.of_node; - controller->bus_num = pdev->id; - controller->slave_abort = fsl_lpspi_slave_abort; - init_completion(&fsl_lpspi->xfer_done); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -952,12 +958,6 @@ static int fsl_lpspi_probe(struct platform_device *pdev) if (ret < 0) dev_err(&pdev->dev, "dma setup error %d, use pio\n", ret); - ret = devm_spi_register_controller(&pdev->dev, controller); - if (ret < 0) { - dev_err(&pdev->dev, "spi_register_controller error.\n"); - goto out_controller_put; - } - return 0; out_controller_put: -- cgit v1.2.3 From 2f3d8035b0f7a8e781b60e0884551dd8a1173a75 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 14 Jan 2020 16:02:40 +0000 Subject: spi: fsl: simplify error path in of_fsl_spi_probe() No need to 'goto err;' for just doing a return. return directly from where the error happens. Signed-off-by: Christophe Leroy Link: https://lore.kernel.org/r/2a4a7e11b37cfa0558d68f0d35e90d6da858b059.1579017697.git.christophe.leroy@c-s.fr Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-spi.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index fb4159ad6bf6..3b81772fea0d 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -706,8 +706,8 @@ static int of_fsl_spi_probe(struct platform_device *ofdev) struct device_node *np = ofdev->dev.of_node; struct spi_master *master; struct resource mem; - int irq = 0, type; - int ret = -ENOMEM; + int irq, type; + int ret; ret = of_mpc8xxx_spi_probe(ofdev); if (ret) @@ -722,10 +722,8 @@ static int of_fsl_spi_probe(struct platform_device *ofdev) if (spisel_boot) { pinfo->immr_spi_cs = ioremap(get_immrbase() + IMMR_SPI_CS_OFFSET, 4); - if (!pinfo->immr_spi_cs) { - ret = -ENOMEM; - goto err; - } + if (!pinfo->immr_spi_cs) + return -ENOMEM; } #endif /* @@ -744,24 +742,15 @@ static int of_fsl_spi_probe(struct platform_device *ofdev) ret = of_address_to_resource(np, 0, &mem); if (ret) - goto err; + return ret; irq = platform_get_irq(ofdev, 0); - if (irq < 0) { - ret = irq; - goto err; - } + if (irq < 0) + return irq; master = fsl_spi_probe(dev, &mem, irq); - if (IS_ERR(master)) { - ret = PTR_ERR(master); - goto err; - } - - return 0; -err: - return ret; + return PTR_ERR_OR_ZERO(master); } static int of_fsl_spi_remove(struct platform_device *ofdev) -- cgit v1.2.3 From 6925212f328bf2abde0c8f0d037fddd36751d489 Mon Sep 17 00:00:00 2001 From: Jean Pihet Date: Wed, 15 Jan 2020 11:07:00 +0100 Subject: spi: spi-ti-qspi: fix warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/spi/spi-ti-qspi.c: In function ‘ti_qspi_start_transfer_one’: drivers/spi/spi-ti-qspi.c:392:8: warning: ‘rx_wlen’ may be used uninitialized in this function [-Wmaybe-uninitialized] 392 | if (rx_wlen >= 32) | ^ drivers/spi/spi-ti-qspi.c:318:12: note: ‘rx_wlen’ was declared here 318 | u8 rxlen, rx_wlen; | ^~~~~~~ The warning is a false positive; it is not thrown by all compiler versions, e.g. Red Hat Cross 9.2.1-1 but not Linaro GCC 7.5-2019.12. Signed-off-by: Jean Pihet Link: https://lore.kernel.org/r/20200115100700.3357-1-jean.pihet@newoldbits.com Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 858fda8ac73e..366a3e5cca6b 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -332,6 +332,7 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t, break; } wlen = t->bits_per_word >> 3; /* in bytes */ + rx_wlen = wlen; while (count) { dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc); -- cgit v1.2.3 From b4adf5b27d59cdefff1e6fcba99151edea65a9f7 Mon Sep 17 00:00:00 2001 From: Tomer Maimon Date: Wed, 15 Jan 2020 18:22:59 +0200 Subject: spi: npcm-pspi: improve spi transfer performance Improving spi 8 bit per word mode transfer performance by using 16 bit per word transfer and receive when the data length is even and larger than one. Signed-off-by: Tomer Maimon Link: https://lore.kernel.org/r/20200115162301.235926-3-tmaimon77@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-npcm-pspi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c index fe624731c74c..d224aa63dbce 100644 --- a/drivers/spi/spi-npcm-pspi.c +++ b/drivers/spi/spi-npcm-pspi.c @@ -178,6 +178,13 @@ static void npcm_pspi_setup_transfer(struct spi_device *spi, priv->mode = spi->mode; } + /* + * If transfer is even length, and 8 bits per word transfer, + * then implement 16 bits-per-word transfer. + */ + if (priv->bits_per_word == 8 && !(t->len & 0x1)) + t->bits_per_word = 16; + if (!priv->is_save_param || priv->bits_per_word != t->bits_per_word) { npcm_pspi_set_transfer_size(priv, t->bits_per_word); priv->bits_per_word = t->bits_per_word; -- cgit v1.2.3 From b5df0b2ee2ee6b5bdeb55d76c17f695a1aa5388f Mon Sep 17 00:00:00 2001 From: Tomer Maimon Date: Wed, 15 Jan 2020 18:23:01 +0200 Subject: spi: npcm-pspi: modify reset support Modify NPCM perphiral SPI reset support from direct register access to reset controller support. Signed-off-by: Tomer Maimon Link: https://lore.kernel.org/r/20200115162301.235926-5-tmaimon77@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-npcm-pspi.c | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c index d224aa63dbce..7e9e747b5626 100644 --- a/drivers/spi/spi-npcm-pspi.c +++ b/drivers/spi/spi-npcm-pspi.c @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -20,7 +21,7 @@ struct npcm_pspi { struct completion xfer_done; - struct regmap *rst_regmap; + struct reset_control *reset; struct spi_master *master; unsigned int tx_bytes; unsigned int rx_bytes; @@ -59,12 +60,6 @@ struct npcm_pspi { #define NPCM_PSPI_MIN_CLK_DIVIDER 4 #define NPCM_PSPI_DEFAULT_CLK 25000000 -/* reset register */ -#define NPCM7XX_IPSRST2_OFFSET 0x24 - -#define NPCM7XX_PSPI1_RESET BIT(22) -#define NPCM7XX_PSPI2_RESET BIT(23) - static inline unsigned int bytes_per_word(unsigned int bits) { return bits <= 8 ? 1 : 2; @@ -292,9 +287,9 @@ static int npcm_pspi_unprepare_transfer_hardware(struct spi_master *master) static void npcm_pspi_reset_hw(struct npcm_pspi *priv) { - regmap_write(priv->rst_regmap, NPCM7XX_IPSRST2_OFFSET, - NPCM7XX_PSPI1_RESET << priv->id); - regmap_write(priv->rst_regmap, NPCM7XX_IPSRST2_OFFSET, 0x0); + reset_control_assert(priv->reset); + udelay(5); + reset_control_deassert(priv->reset); } static irqreturn_t npcm_pspi_handler(int irq, void *dev_id) @@ -358,10 +353,6 @@ static int npcm_pspi_probe(struct platform_device *pdev) if (num_cs < 0) return num_cs; - pdev->id = of_alias_get_id(np, "spi"); - if (pdev->id < 0) - pdev->id = 0; - master = spi_alloc_master(&pdev->dev, sizeof(*priv)); if (!master) return -ENOMEM; @@ -371,7 +362,6 @@ static int npcm_pspi_probe(struct platform_device *pdev) priv = spi_master_get_devdata(master); priv->master = master; priv->is_save_param = false; - priv->id = pdev->id; priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) { @@ -396,11 +386,10 @@ static int npcm_pspi_probe(struct platform_device *pdev) goto out_disable_clk; } - priv->rst_regmap = - syscon_regmap_lookup_by_compatible("nuvoton,npcm750-rst"); - if (IS_ERR(priv->rst_regmap)) { - dev_err(&pdev->dev, "failed to find nuvoton,npcm750-rst\n"); - return PTR_ERR(priv->rst_regmap); + priv->reset = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(priv->reset)) { + ret = PTR_ERR(priv->reset); + goto out_disable_clk; } /* reset SPI-HW block */ @@ -421,7 +410,7 @@ static int npcm_pspi_probe(struct platform_device *pdev) master->min_speed_hz = DIV_ROUND_UP(clk_hz, NPCM_PSPI_MAX_CLK_DIVIDER); master->mode_bits = SPI_CPHA | SPI_CPOL; master->dev.of_node = pdev->dev.of_node; - master->bus_num = pdev->id; + master->bus_num = -1; master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); master->transfer_one = npcm_pspi_transfer_one; master->prepare_transfer_hardware = @@ -454,7 +443,7 @@ static int npcm_pspi_probe(struct platform_device *pdev) if (ret) goto out_disable_clk; - pr_info("NPCM Peripheral SPI %d probed\n", pdev->id); + pr_info("NPCM Peripheral SPI %d probed\n", master->bus_num); return 0; -- cgit v1.2.3 From a5362b84bdff1def10c136e36ef2126f7f545b2c Mon Sep 17 00:00:00 2001 From: Tomer Maimon Date: Wed, 15 Jan 2020 18:23:00 +0200 Subject: dt-binding: spi: add NPCM PSPI reset binding Add NPCM Peripheral SPI reset binding documentation, Removing unnecessary aliases use. Signed-off-by: Tomer Maimon Acked-by: Rob Herring Link: https://lore.kernel.org/r/20200115162301.235926-4-tmaimon77@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt b/Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt index 1fd9a4406a1d..b98203ca656d 100644 --- a/Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt +++ b/Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt @@ -12,6 +12,7 @@ Required properties: - clock-names: Should be "clk_apb5". - pinctrl-names : a pinctrl state named "default" must be defined. - pinctrl-0 : phandle referencing pin configuration of the device. + - resets : phandle to the reset control for this device. - cs-gpios: Specifies the gpio pins to be used for chipselects. See: Documentation/devicetree/bindings/spi/spi-bus.txt @@ -19,16 +20,6 @@ Optional properties: - clock-frequency : Input clock frequency to the PSPI block in Hz. Default is 25000000 Hz. -Aliases: -- All the SPI controller nodes should be represented in the aliases node using - the following format 'spi{n}' withe the correct numbered in "aliases" node. - -Example: - -aliases { - spi0 = &spi0; -}; - spi0: spi@f0200000 { compatible = "nuvoton,npcm750-pspi"; reg = <0xf0200000 0x1000>; @@ -39,5 +30,6 @@ spi0: spi@f0200000 { interrupts = ; clocks = <&clk NPCM7XX_CLK_APB5>; clock-names = "clk_apb5"; + resets = <&rstc NPCM7XX_RESET_IPSRST2 NPCM7XX_RESET_PSPI1> cs-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>; }; -- cgit v1.2.3