From 0e793ba77c18382f08e440260fe72bc6fce2a3cb Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 21 Apr 2021 11:14:02 +0100 Subject: [PATCH 01/86] spi: Make of_register_spi_device also set the fwnode Currently, the SPI core doesn't set the struct device fwnode pointer when it creates a new SPI device. This means when the device is registered the fwnode is NULL and the check in device_add which sets the fwnode->dev pointer is skipped. This wasn't previously an issue, however these two patches: commit 4731210c09f5 ("gpiolib: Bind gpio_device to a driver to enable fw_devlink=on by default") commit ced2af419528 ("gpiolib: Don't probe gpio_device if it's not the primary device") Added some code to the GPIO core which relies on using that fwnode->dev pointer to determine if a driver is bound to the fwnode and if not bind a stub GPIO driver. This means the GPIO providers behind SPI will get both the expected driver and this stub driver causing the stub driver to fail if it attempts to request any pin configuration. For example on my system: madera-pinctrl madera-pinctrl: pin gpio5 already requested by madera-pinctrl; cannot claim for gpiochip3 madera-pinctrl madera-pinctrl: pin-4 (gpiochip3) status -22 madera-pinctrl madera-pinctrl: could not request pin 4 (gpio5) from group aif1 on device madera-pinctrl gpio_stub_drv gpiochip3: Error applying setting, reverse things back gpio_stub_drv: probe of gpiochip3 failed with error -22 The firmware node on the device created by the GPIO framework is set through the of_node pointer hence things generally actually work, however that fwnode->dev is never set, as the check was skipped at device_add time. This fix appears to match how the I2C subsystem handles the same situation. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20210421101402.8468-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 904a353798b6..862a9bb69129 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2047,6 +2047,7 @@ of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc) /* Store a pointer to the node in the device structure */ of_node_get(nc); spi->dev.of_node = nc; + spi->dev.fwnode = of_fwnode_handle(nc); /* Register the new device */ rc = spi_add_device(spi); From dbaca8e56ea3f23fa215f48c2d46dd03ede06e02 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Apr 2021 19:44:24 +0300 Subject: [PATCH 02/86] spi: Allow to have all native CSs in use along with GPIOs The commit 7d93aecdb58d ("spi: Add generic support for unused native cs with cs-gpios") excludes the valid case for the controllers that doesn't need to switch native CS in order to perform the transfer, i.e. when 0 native ... ... - 1 native GPIO + 1 GPIO ... ... where defines maximum of native CSs supported by the controller. To allow this, bail out from spi_get_gpio_descs() conditionally for the controllers which explicitly marked with SPI_MASTER_GPIO_SS. Fixes: 7d93aecdb58d ("spi: Add generic support for unused native cs with cs-gpios") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210420164425.40287-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 862a9bb69129..2e5dca20c8d0 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2612,8 +2612,9 @@ static int spi_get_gpio_descs(struct spi_controller *ctlr) } ctlr->unused_native_cs = ffz(native_cs_mask); - if (num_cs_gpios && ctlr->max_native_cs && - ctlr->unused_native_cs >= ctlr->max_native_cs) { + + if ((ctlr->flags & SPI_MASTER_GPIO_SS) && 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; } From f60d7270c8a3d2beb1c23ae0da42497afa3584c2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Apr 2021 19:44:25 +0300 Subject: [PATCH 03/86] spi: Avoid undefined behaviour when counting unused native CSs ffz(), that has been used to count unused native CSs, might cause undefined behaviour when called against ~0U. To fix that, open code it with ffs(~value) - 1. Fixes: 7d93aecdb58d ("spi: Add generic support for unused native cs with cs-gpios") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210420164425.40287-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 2e5dca20c8d0..6fe2a9509675 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2611,7 +2611,7 @@ static int spi_get_gpio_descs(struct spi_controller *ctlr) native_cs_mask |= BIT(i); } - ctlr->unused_native_cs = ffz(native_cs_mask); + ctlr->unused_native_cs = ffs(~native_cs_mask) - 1; if ((ctlr->flags & SPI_MASTER_GPIO_SS) && num_cs_gpios && ctlr->max_native_cs && ctlr->unused_native_cs >= ctlr->max_native_cs) { From 66fe740317c82b0caa68ed8d756536d4ff7e910c Mon Sep 17 00:00:00 2001 From: Jay Fang Date: Mon, 10 May 2021 14:58:20 +0800 Subject: [PATCH 04/86] spi: ppc4xx: include instead of Include the more general linux/io.h instead of asm/io.h as checkpatch suggests. Signed-off-by: Jay Fang Link: https://lore.kernel.org/r/1620629903-15493-2-git-send-email-f.fangjian@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-ppc4xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index d8ee363fb714..9e3974551204 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include From 856a9260e17129303102a7d4a5f71b7a8739e5b9 Mon Sep 17 00:00:00 2001 From: Jay Fang Date: Mon, 10 May 2021 14:58:21 +0800 Subject: [PATCH 05/86] spi: omap-100k: Clean the value of 'status' is not used An error code is set to 'status' before exiting list_for_each_entry() loop, but the value of 'status' is not used as below: list_for_each_entry(t, &m->transfers, transfer_list) { if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { status = -EINVAL; break; } ... } status = omap1_spi100k_setup_transfer(spi, NULL); Signed-off-by: Jay Fang Link: https://lore.kernel.org/r/1620629903-15493-3-git-send-email-f.fangjian@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 7062f2902253..dc9b86b648ac 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -296,7 +296,6 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master, list_for_each_entry(t, &m->transfers, transfer_list) { if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { - status = -EINVAL; break; } status = omap1_spi100k_setup_transfer(spi, t); @@ -315,7 +314,6 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master, m->actual_length += count; if (count != t->len) { - status = -EIO; break; } } From db56d03049524114696aa7158560d8f0e064c487 Mon Sep 17 00:00:00 2001 From: Jay Fang Date: Mon, 10 May 2021 14:58:22 +0800 Subject: [PATCH 06/86] spi: delete repeated words in comments Drop repeated words in spi-bcm2835aux.c {are} Drop repeated words in spi-dw-mmio.c {the} Drop repeated words in spi-geni-qcom.c {our} Drop repeated words in spi-pl022.c {on} Drop repeated words in spi-ppc4xx.c {the} Signed-off-by: Jay Fang Link: https://lore.kernel.org/r/1620629903-15493-4-git-send-email-f.fangjian@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835aux.c | 2 +- drivers/spi/spi-dw-mmio.c | 2 +- drivers/spi/spi-geni-qcom.c | 4 ++-- drivers/spi/spi-pl022.c | 4 ++-- drivers/spi/spi-ppc4xx.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c index 75589ac6e95f..37eab100a7d8 100644 --- a/drivers/spi/spi-bcm2835aux.c +++ b/drivers/spi/spi-bcm2835aux.c @@ -384,7 +384,7 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master, bs->pending = 0; /* Calculate the estimated time in us the transfer runs. Note that - * there are are 2 idle clocks cycles after each chunk getting + * there are 2 idle clocks cycles after each chunk getting * transferred - in our case the chunk size is 3 bytes, so we * approximate this by 9 cycles/byte. This is used to find the number * of Hz per byte per polling limit. E.g., we can transfer 1 byte in diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 17c06039a74d..3379720cfcb8 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -56,7 +56,7 @@ struct dw_spi_mscc { /* * The Designware SPI controller (referred to as master in the documentation) * automatically deasserts chip select when the tx fifo is empty. The chip - * selects then needs to be either driven as GPIOs or, for the first 4 using the + * selects then needs to be either driven as GPIOs or, for the first 4 using * the SPI boot controller registers. the final chip select is an OR gate * between the Designware SPI controller and the SPI boot controller. */ diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index 3d0d8ddd5772..b3861fb88711 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -639,8 +639,8 @@ static irqreturn_t geni_spi_isr(int irq, void *data) complete(&mas->abort_done); /* - * It's safe or a good idea to Ack all of our our interrupts at the - * end of the function. Specifically: + * It's safe or a good idea to Ack all of our interrupts at the end + * of the function. Specifically: * - M_CMD_DONE_EN / M_RX_FIFO_LAST_EN: Edge triggered interrupts and * clearing Acks. Clearing at the end relies on nobody else having * started a new transfer yet or else we could be clearing _their_ diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 0c9e3f270f05..feebda66f56e 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -288,7 +288,7 @@ #define SPI_POLLING_TIMEOUT 1000 /* - * The type of reading going on on this chip + * The type of reading going on this chip */ enum ssp_reading { READING_NULL, @@ -298,7 +298,7 @@ enum ssp_reading { }; /* - * The type of writing going on on this chip + * The type of writing going on this chip */ enum ssp_writing { WRITING_NULL, diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 9e3974551204..76874a7cca9b 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -326,7 +326,7 @@ static void spi_ppc4xx_enable(struct ppc4xx_spi *hw) { /* * On all 4xx PPC's the SPI bus is shared/multiplexed with - * the 2nd I2C bus. We need to enable the the SPI bus before + * the 2nd I2C bus. We need to enable the SPI bus before * using it. */ From 9e37a3ab0627011fb63875e9a93094b6fc8ddf48 Mon Sep 17 00:00:00 2001 From: Jay Fang Date: Mon, 10 May 2021 14:58:23 +0800 Subject: [PATCH 07/86] spi: spi-loopback-test: Fix 'tx_buf' might be 'rx_buf' In function 'spi_test_run_iter': Value 'tx_buf' might be 'rx_buf'. Signed-off-by: Jay Fang Link: https://lore.kernel.org/r/1620629903-15493-5-git-send-email-f.fangjian@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-loopback-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index f1cf2232f0b5..4d4f77a186a9 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -875,7 +875,7 @@ static int spi_test_run_iter(struct spi_device *spi, test.transfers[i].len = len; if (test.transfers[i].tx_buf) test.transfers[i].tx_buf += tx_off; - if (test.transfers[i].tx_buf) + if (test.transfers[i].rx_buf) test.transfers[i].rx_buf += rx_off; } From f2eed8caa336e31d672804a8725dadba0415f19d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 23 Apr 2021 21:24:28 +0300 Subject: [PATCH 08/86] spi: pxa2xx: Use one point of return when ->probe() fails When we can't allocate SPI controller, jump to the error path rather than return locally. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210423182441.50272-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 5e59ba075bc7..2f5618883ac3 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1705,8 +1705,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) if (!controller) { dev_err(&pdev->dev, "cannot alloc spi_controller\n"); - pxa_ssp_free(ssp); - return -ENOMEM; + status = -ENOMEM; + goto out_error_controller_alloc; } drv_data = spi_controller_get_devdata(controller); drv_data->controller = controller; From 9e43c9a8d5de4810ea9688519d55b5e46784d84a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 23 Apr 2021 21:24:29 +0300 Subject: [PATCH 09/86] spi: pxa2xx: Utilize MMIO and physical base from struct ssp_device We have a duplication of MMIO and physical base addresses in the struct driver_data, get rid of it and reuse members from struct ssp_device instead. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210423182441.50272-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-dma.c | 4 ++-- drivers/spi/spi-pxa2xx.c | 4 +--- drivers/spi/spi-pxa2xx.h | 14 ++++---------- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index 37567bc7a523..3b27f356a18f 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -94,14 +94,14 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data, cfg.direction = dir; if (dir == DMA_MEM_TO_DEV) { - cfg.dst_addr = drv_data->ssdr_physical; + cfg.dst_addr = drv_data->ssp->phys_base + SSDR; cfg.dst_addr_width = width; cfg.dst_maxburst = chip->dma_burst_size; sgt = &xfer->tx_sg; chan = drv_data->controller->dma_tx; } else { - cfg.src_addr = drv_data->ssdr_physical; + cfg.src_addr = drv_data->ssp->phys_base + SSDR; cfg.src_addr_width = width; cfg.src_maxburst = chip->dma_burst_size; diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 2f5618883ac3..d89db682179d 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -325,7 +325,7 @@ static void lpss_ssp_setup(struct driver_data *drv_data) u32 value; config = lpss_get_config(drv_data); - drv_data->lpss_base = drv_data->ioaddr + config->offset; + drv_data->lpss_base = drv_data->ssp->mmio_base + config->offset; /* Enable software chip select control */ value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl); @@ -1733,8 +1733,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) drv_data->ssp_type = ssp->type; - drv_data->ioaddr = ssp->mmio_base; - drv_data->ssdr_physical = ssp->phys_base + SSDR; if (pxa25x_ssp_comp(drv_data)) { switch (drv_data->ssp_type) { case QUARK_X1000_SSP: diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 1400472bc986..ad9980ebefa6 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -33,10 +33,6 @@ struct driver_data { /* PXA hookup */ struct pxa2xx_spi_controller *controller_info; - /* SSP register addresses */ - void __iomem *ioaddr; - phys_addr_t ssdr_physical; - /* SSP masks*/ u32 dma_cr1; u32 int_cr1; @@ -87,16 +83,14 @@ struct chip_data { void (*cs_control)(u32 command); }; -static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data, - unsigned reg) +static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data, u32 reg) { - return __raw_readl(drv_data->ioaddr + reg); + return pxa_ssp_read_reg(drv_data->ssp, reg); } -static inline void pxa2xx_spi_write(const struct driver_data *drv_data, - unsigned reg, u32 val) +static inline void pxa2xx_spi_write(const struct driver_data *drv_data, u32 reg, u32 val) { - __raw_writel(val, drv_data->ioaddr + reg); + pxa_ssp_write_reg(drv_data->ssp, reg, val); } #define DMA_ALIGNMENT 8 From c3dce24c40cc7cd07deca5b81b763eae66f30856 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 23 Apr 2021 21:24:30 +0300 Subject: [PATCH 10/86] spi: pxa2xx: Utilize struct device from struct ssp_device We have a duplication of struct device in the struct driver_data, get rid of it and reuse member from struct ssp_device instead. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210423182441.50272-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-dma.c | 12 +++++------- drivers/spi/spi-pxa2xx-pci.c | 1 + drivers/spi/spi-pxa2xx.c | 12 +++++------- drivers/spi/spi-pxa2xx.h | 4 ---- 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index 3b27f356a18f..2e4a49567146 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -111,7 +111,7 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data, ret = dmaengine_slave_config(chan, &cfg); if (ret) { - dev_warn(&drv_data->pdev->dev, "DMA slave config failed\n"); + dev_warn(drv_data->ssp->dev, "DMA slave config failed\n"); return NULL; } @@ -125,7 +125,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr; if (status & SSSR_ROR) { - dev_err(&drv_data->pdev->dev, "FIFO overrun\n"); + dev_err(drv_data->ssp->dev, "FIFO overrun\n"); dmaengine_terminate_async(drv_data->controller->dma_rx); dmaengine_terminate_async(drv_data->controller->dma_tx); @@ -145,16 +145,14 @@ int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, tx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_MEM_TO_DEV, xfer); if (!tx_desc) { - dev_err(&drv_data->pdev->dev, - "failed to get DMA TX descriptor\n"); + dev_err(drv_data->ssp->dev, "failed to get DMA TX descriptor\n"); err = -EBUSY; goto err_tx; } rx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_DEV_TO_MEM, xfer); if (!rx_desc) { - dev_err(&drv_data->pdev->dev, - "failed to get DMA RX descriptor\n"); + dev_err(drv_data->ssp->dev, "failed to get DMA RX descriptor\n"); err = -EBUSY; goto err_rx; } @@ -191,8 +189,8 @@ void pxa2xx_spi_dma_stop(struct driver_data *drv_data) int pxa2xx_spi_dma_setup(struct driver_data *drv_data) { struct pxa2xx_spi_controller *pdata = drv_data->controller_info; - struct device *dev = &drv_data->pdev->dev; struct spi_controller *controller = drv_data->controller; + struct device *dev = drv_data->ssp->dev; dma_cap_mask_t mask; dma_cap_zero(mask); diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 1833f5876e9f..f588fad77fc0 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -239,6 +239,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, spi_pdata.dma_burst_size = c->dma_burst_size ? c->dma_burst_size : 1; ssp = &spi_pdata.ssp; + ssp->dev = &dev->dev; ssp->phys_base = pci_resource_start(dev, 0); ssp->mmio_base = pcim_iomap_table(dev)[0]; ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn; diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index d89db682179d..0f3f7d725937 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -628,7 +628,7 @@ static void int_error_stop(struct driver_data *drv_data, const char *msg) pxa2xx_spi_flush(drv_data); pxa2xx_spi_off(drv_data); - dev_err(&drv_data->pdev->dev, "%s\n", msg); + dev_err(drv_data->ssp->dev, "%s\n", msg); drv_data->controller->cur_msg->status = -EIO; spi_finalize_current_transfer(drv_data->controller); @@ -731,8 +731,7 @@ static void handle_bad_msg(struct driver_data *drv_data) pxa2xx_spi_write(drv_data, SSTO, 0); write_SSSR_CS(drv_data, drv_data->clear_sr); - dev_err(&drv_data->pdev->dev, - "bad message state in interrupt handler\n"); + dev_err(drv_data->ssp->dev, "bad message state in interrupt handler\n"); } static irqreturn_t ssp_int(int irq, void *dev_id) @@ -748,7 +747,7 @@ static irqreturn_t ssp_int(int irq, void *dev_id) * the IRQ was not for us (we shouldn't be RPM suspended when the * interrupt is enabled). */ - if (pm_runtime_suspended(&drv_data->pdev->dev)) + if (pm_runtime_suspended(drv_data->ssp->dev)) return IRQ_NONE; /* @@ -1158,7 +1157,7 @@ static int pxa2xx_spi_slave_abort(struct spi_controller *controller) pxa2xx_spi_flush(drv_data); pxa2xx_spi_off(drv_data); - dev_dbg(&drv_data->pdev->dev, "transfer aborted\n"); + dev_dbg(drv_data->ssp->dev, "transfer aborted\n"); drv_data->controller->cur_msg->status = -EINTR; spi_finalize_current_transfer(drv_data->controller); @@ -1645,7 +1644,7 @@ static int pxa2xx_spi_fw_translate_cs(struct spi_controller *controller, { struct driver_data *drv_data = spi_controller_get_devdata(controller); - if (has_acpi_companion(&drv_data->pdev->dev)) { + if (has_acpi_companion(drv_data->ssp->dev)) { switch (drv_data->ssp_type) { /* * For Atoms the ACPI DeviceSelection used by the Windows @@ -1711,7 +1710,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) drv_data = spi_controller_get_devdata(controller); drv_data->controller = controller; drv_data->controller_info = platform_info; - drv_data->pdev = pdev; drv_data->ssp = ssp; controller->dev.of_node = pdev->dev.of_node; diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index ad9980ebefa6..6724d7e056ce 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -20,9 +19,6 @@ #include struct driver_data { - /* Driver model hookup */ - struct platform_device *pdev; - /* SSP Info */ struct ssp_device *ssp; From 0e4768713e71dd224633fd7e00ad358bc48f433a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 23 Apr 2021 21:24:31 +0300 Subject: [PATCH 11/86] spi: pxa2xx: Replace header inclusions by forward declarations When the data structure is only referred by pointer, compiler may not need to see the contents of the data type. Thus, we may replace header inclusions by respective forward declarations. Due to above add missed headers as well. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210423182441.50272-5-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-dma.c | 4 ++-- drivers/spi/spi-pxa2xx-pci.c | 1 + drivers/spi/spi-pxa2xx.c | 2 ++ drivers/spi/spi-pxa2xx.h | 18 ++++++++++-------- include/linux/spi/pxa2xx_spi.h | 2 ++ 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index 2e4a49567146..e00dbadd39ec 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -9,11 +9,11 @@ #include #include #include -#include #include #include -#include + #include +#include #include "spi-pxa2xx.h" diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index f588fad77fc0..a259be12d326 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -8,6 +8,7 @@ #include #include #include + #include #include diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 0f3f7d725937..1d4c7f4217ed 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include + #include #include diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 6724d7e056ce..739e264feaa6 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -7,16 +7,18 @@ #ifndef SPI_PXA2XX_H #define SPI_PXA2XX_H -#include -#include -#include -#include #include -#include -#include +#include +#include #include -#include -#include + +#include + +struct gpio_desc; +struct pxa2xx_spi_controller; +struct spi_controller; +struct spi_device; +struct spi_transfer; struct driver_data { /* SSP Info */ diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h index 31f00c7f4f59..1e0e2f136319 100644 --- a/include/linux/spi/pxa2xx_spi.h +++ b/include/linux/spi/pxa2xx_spi.h @@ -5,6 +5,8 @@ #ifndef __linux_pxa2xx_spi_h #define __linux_pxa2xx_spi_h +#include + #include #define PXA2XX_CS_ASSERT (0x01) From 5edc24901f4d469f8fc943004f73655933e89dbf Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 23 Apr 2021 21:24:32 +0300 Subject: [PATCH 12/86] spi: pxa2xx: Unify ifdeffery used in the headers The two headers have quite different ifdeffery to prevent multiple inclusion. Unify them with the pattern that in particular reflects their location. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210423182441.50272-6-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- include/linux/pxa2xx_ssp.h | 6 +++--- include/linux/spi/pxa2xx_spi.h | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/linux/pxa2xx_ssp.h b/include/linux/pxa2xx_ssp.h index 7f73b26ed22e..14b049840faf 100644 --- a/include/linux/pxa2xx_ssp.h +++ b/include/linux/pxa2xx_ssp.h @@ -11,8 +11,8 @@ * PXA3xx SSP1, SSP2, SSP3, SSP4 */ -#ifndef __LINUX_SSP_H -#define __LINUX_SSP_H +#ifndef __LINUX_PXA2XX_SSP_H +#define __LINUX_PXA2XX_SSP_H #include #include @@ -270,4 +270,4 @@ static inline struct ssp_device *pxa_ssp_request_of(const struct device_node *n, static inline void pxa_ssp_free(struct ssp_device *ssp) {} #endif -#endif +#endif /* __LINUX_PXA2XX_SSP_H */ diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h index 1e0e2f136319..12ef04d0896d 100644 --- a/include/linux/spi/pxa2xx_spi.h +++ b/include/linux/spi/pxa2xx_spi.h @@ -2,8 +2,8 @@ /* * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs */ -#ifndef __linux_pxa2xx_spi_h -#define __linux_pxa2xx_spi_h +#ifndef __LINUX_SPI_PXA2XX_SPI_H +#define __LINUX_SPI_PXA2XX_SPI_H #include @@ -51,4 +51,5 @@ struct pxa2xx_spi_chip { extern void pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_controller *info); #endif -#endif + +#endif /* __LINUX_SPI_PXA2XX_SPI_H */ From 1beb37b0e3f98708bfb37778049764b4500756da Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 23 Apr 2021 21:24:33 +0300 Subject: [PATCH 13/86] spi: pxa2xx: Group Intel Quark specific definitions DDS_RATE is Intel Quark specific definition. Move it to the rest Intel Quark related. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210423182441.50272-7-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- include/linux/pxa2xx_ssp.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/linux/pxa2xx_ssp.h b/include/linux/pxa2xx_ssp.h index 14b049840faf..1b6c1a0922bd 100644 --- a/include/linux/pxa2xx_ssp.h +++ b/include/linux/pxa2xx_ssp.h @@ -38,7 +38,6 @@ struct device_node; #define SSDR (0x10) /* SSP Data Write/Data Read Register */ #define SSTO (0x28) /* SSP Time Out Register */ -#define DDS_RATE (0x28) /* SSP DDS Clock Rate Register (Intel Quark) */ #define SSPSP (0x2C) /* SSP Programmable Serial Protocol */ #define SSTSA (0x30) /* SSP Tx Timeslot Active */ #define SSRSA (0x34) /* SSP Rx Timeslot Active */ @@ -105,6 +104,9 @@ struct device_node; #define CE4100_SSCR1_RFT GENMASK(11, 10) /* Receive FIFO Threshold (mask) */ #define CE4100_SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..4] */ +/* Intel Quark X1000 */ +#define DDS_RATE 0x28 /* SSP DDS Clock Rate Register */ + /* QUARK_X1000 SSCR0 bit definition */ #define QUARK_X1000_SSCR0_DSS GENMASK(4, 0) /* Data Size Select (mask) */ #define QUARK_X1000_SSCR0_DataSize(x) ((x) - 1) /* Data Size Select [4..32] */ From 026a1dc1af52742c5897e64a3431445371a71871 Mon Sep 17 00:00:00 2001 From: Jay Fang Date: Thu, 6 May 2021 15:08:08 +0800 Subject: [PATCH 14/86] spi: spi-topcliff-pch: Fix potential double free in pch_spi_process_messages() pch_spi_set_tx() frees data->pkt_tx_buff on failure of kzalloc() for data->pkt_rx_buff, but its caller, pch_spi_process_messages(), will free data->pkt_tx_buff again. Set data->pkt_tx_buff to NULL after kfree() to avoid double free. Signed-off-by: Jay Fang Link: https://lore.kernel.org/r/1620284888-65215-1-git-send-email-f.fangjian@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-topcliff-pch.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index b8870784fc6e..8c4615b76339 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -580,8 +580,10 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw) data->pkt_tx_buff = kzalloc(size, GFP_KERNEL); if (data->pkt_tx_buff != NULL) { data->pkt_rx_buff = kzalloc(size, GFP_KERNEL); - if (!data->pkt_rx_buff) + if (!data->pkt_rx_buff) { kfree(data->pkt_tx_buff); + data->pkt_tx_buff = NULL; + } } if (!data->pkt_rx_buff) { From 029d32a892a860017d33ff8d9598259731e776ad Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 6 May 2021 13:52:59 +0200 Subject: [PATCH 15/86] spi: dw-apb-ssi: Integrate Renesas RZ/N1 SPI controller Originally, the Renesas RZ/N1 SPI Controller DT bindings were not integrated in the main DT bindings for the Synopsys DesignWare Synchronous Serial Interface, but in its own file, as the RZ/N1 controller has additional registers for software CS control and DMA. As so far DMA is not supported on RZ/N1, and json-schema can handle any possible differences fine, integrate the RZ/N1 compatible values in the main DT bindings for the Synopsys DW SSI. Signed-off-by: Geert Uytterhoeven Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/aef15aa119ed02487ded4691141678bc1040c3b4.1620301936.git.geert+renesas@glider.be Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/renesas,rzn1-spi.txt | 11 ----------- .../devicetree/bindings/spi/snps,dw-apb-ssi.yaml | 6 ++++++ 2 files changed, 6 insertions(+), 11 deletions(-) delete mode 100644 Documentation/devicetree/bindings/spi/renesas,rzn1-spi.txt diff --git a/Documentation/devicetree/bindings/spi/renesas,rzn1-spi.txt b/Documentation/devicetree/bindings/spi/renesas,rzn1-spi.txt deleted file mode 100644 index fb1a6728638d..000000000000 --- a/Documentation/devicetree/bindings/spi/renesas,rzn1-spi.txt +++ /dev/null @@ -1,11 +0,0 @@ -Renesas RZ/N1 SPI Controller - -This controller is based on the Synopsys DW Synchronous Serial Interface and -inherits all properties defined in snps,dw-apb-ssi.txt except for the -compatible property. - -Required properties: -- compatible : The device specific string followed by the generic RZ/N1 string. - Therefore it must be one of: - "renesas,r9a06g032-spi", "renesas,rzn1-spi" - "renesas,r9a06g033-spi", "renesas,rzn1-spi" diff --git a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml index 4825157cd92e..ca91201a9926 100644 --- a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml +++ b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml @@ -67,6 +67,12 @@ properties: const: baikal,bt1-sys-ssi - description: Canaan Kendryte K210 SoS SPI Controller const: canaan,k210-spi + - description: Renesas RZ/N1 SPI Controller + items: + - enum: + - renesas,r9a06g032-spi # RZ/N1D + - renesas,r9a06g033-spi # RZ/N1S + - const: renesas,rzn1-spi # RZ/N1 reg: minItems: 1 From e7a1a3abea373e41ba7dfe0fbc93cb79b6a3a529 Mon Sep 17 00:00:00 2001 From: Tian Tao Date: Thu, 29 Apr 2021 19:20:48 +0800 Subject: [PATCH 16/86] spi: omap-100k: Fix the length judgment problem word_len should be checked in the omap1_spi100k_setup_transfer function to see if it exceeds 32. Signed-off-by: Tian Tao Link: https://lore.kernel.org/r/1619695248-39045-1-git-send-email-tiantao6@hisilicon.com Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 7062f2902253..f104470605b3 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -241,7 +241,7 @@ static int omap1_spi100k_setup_transfer(struct spi_device *spi, else word_len = spi->bits_per_word; - if (spi->bits_per_word > 32) + if (word_len > 32) return -EINVAL; cs->word_len = word_len; From 86b1d8ecb5f1f271a660ce0b882658447f85904a Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 7 May 2021 17:07:59 +0200 Subject: [PATCH 17/86] spi: tegra114: Fix an error message 'ret' is known to be 0 here. No error code is available, so just remove it from the error message. Fixes: f333a331ad ("spi/tegra114: add spi driver") Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/e2593974c9484b7055177ad0c9237c8e343946be.1620399829.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- drivers/spi/spi-tegra114.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index a2e5907276e7..5131141bbf0d 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -1071,8 +1071,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, ret = wait_for_completion_timeout(&tspi->xfer_completion, SPI_DMA_TIMEOUT); if (WARN_ON(ret == 0)) { - dev_err(tspi->dev, - "spi transfer timeout, err %d\n", ret); + dev_err(tspi->dev, "spi transfer timeout\n"); if (tspi->is_curr_dma_xfer && (tspi->cur_direction & DATA_DIR_TX)) dmaengine_terminate_all(tspi->tx_dma_chan); From 665a990fdbea66a4d2af0287420f8266631be2ab Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 7 May 2021 18:26:39 +0200 Subject: [PATCH 18/86] spi: tegra210-quad: Fix an error message 'ret' is known to be 0 here. No error code is available, so just remove it from the error message. Fixes: 921fc1838fb0 ("spi: tegra210-quad: Add support for Tegra210 QSPI controller") Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/b990c1bb5830196142c3d70e3e3c6c0245a7e75f.1620404705.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- drivers/spi/spi-tegra210-quad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c index 2f806f4b2c34..2354ca1e3858 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -1028,7 +1028,7 @@ static int tegra_qspi_transfer_one_message(struct spi_master *master, struct spi ret = wait_for_completion_timeout(&tqspi->xfer_completion, QSPI_DMA_TIMEOUT); if (WARN_ON(ret == 0)) { - dev_err(tqspi->dev, "transfer timeout: %d\n", ret); + dev_err(tqspi->dev, "transfer timeout\n"); if (tqspi->is_curr_dma_xfer && (tqspi->cur_direction & DATA_DIR_TX)) dmaengine_terminate_all(tqspi->tx_dma_chan); if (tqspi->is_curr_dma_xfer && (tqspi->cur_direction & DATA_DIR_RX)) From ab77fe8935c57d1339d3df64957f32e87f0d5ef3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 15:41:27 +0300 Subject: [PATCH 19/86] spi: pxa2xx: Introduce int_stop_and_reset() helper Currently we have three times the same few lines repeated in the code. Deduplicate them by newly introduced int_stop_and_reset() helper. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510124134.24638-8-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 1d4c7f4217ed..5572eec68381 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -620,13 +620,20 @@ static void reset_sccr1(struct driver_data *drv_data) pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg); } -static void int_error_stop(struct driver_data *drv_data, const char *msg) +static void int_stop_and_reset(struct driver_data *drv_data) { - /* Stop and reset SSP */ + /* Clear and disable interrupts */ write_SSSR_CS(drv_data, drv_data->clear_sr); reset_sccr1(drv_data); - if (!pxa25x_ssp_comp(drv_data)) - pxa2xx_spi_write(drv_data, SSTO, 0); + if (pxa25x_ssp_comp(drv_data)) + return; + + pxa2xx_spi_write(drv_data, SSTO, 0); +} + +static void int_error_stop(struct driver_data *drv_data, const char *msg) +{ + int_stop_and_reset(drv_data); pxa2xx_spi_flush(drv_data); pxa2xx_spi_off(drv_data); @@ -638,11 +645,7 @@ static void int_error_stop(struct driver_data *drv_data, const char *msg) static void int_transfer_complete(struct driver_data *drv_data) { - /* Clear and disable interrupts */ - write_SSSR_CS(drv_data, drv_data->clear_sr); - reset_sccr1(drv_data); - if (!pxa25x_ssp_comp(drv_data)) - pxa2xx_spi_write(drv_data, SSTO, 0); + int_stop_and_reset(drv_data); spi_finalize_current_transfer(drv_data->controller); } @@ -1151,11 +1154,7 @@ static int pxa2xx_spi_slave_abort(struct spi_controller *controller) { struct driver_data *drv_data = spi_controller_get_devdata(controller); - /* Stop and reset SSP */ - write_SSSR_CS(drv_data, drv_data->clear_sr); - reset_sccr1(drv_data); - if (!pxa25x_ssp_comp(drv_data)) - pxa2xx_spi_write(drv_data, SSTO, 0); + int_stop_and_reset(drv_data); pxa2xx_spi_flush(drv_data); pxa2xx_spi_off(drv_data); From 4761d2e7e51cfbe6fdb4e95903d407927f519f50 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 15:41:28 +0300 Subject: [PATCH 20/86] spi: pxa2xx: Reuse int_error_stop() in pxa2xx_spi_slave_abort() It appears that pxa2xx_spi_slave_abort()almost repeats the functionality of the int_error_stop(). Reuse int_error_stop() in pxa2xx_spi_slave_abort(). Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510124134.24638-9-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 5572eec68381..087c84e605b9 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -631,7 +631,7 @@ static void int_stop_and_reset(struct driver_data *drv_data) pxa2xx_spi_write(drv_data, SSTO, 0); } -static void int_error_stop(struct driver_data *drv_data, const char *msg) +static void int_error_stop(struct driver_data *drv_data, const char *msg, int err) { int_stop_and_reset(drv_data); pxa2xx_spi_flush(drv_data); @@ -639,7 +639,7 @@ static void int_error_stop(struct driver_data *drv_data, const char *msg) dev_err(drv_data->ssp->dev, "%s\n", msg); - drv_data->controller->cur_msg->status = -EIO; + drv_data->controller->cur_msg->status = err; spi_finalize_current_transfer(drv_data->controller); } @@ -658,12 +658,12 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) u32 irq_status = pxa2xx_spi_read(drv_data, SSSR) & irq_mask; if (irq_status & SSSR_ROR) { - int_error_stop(drv_data, "interrupt_transfer: fifo overrun"); + int_error_stop(drv_data, "interrupt_transfer: fifo overrun", -EIO); return IRQ_HANDLED; } if (irq_status & SSSR_TUR) { - int_error_stop(drv_data, "interrupt_transfer: fifo underrun"); + int_error_stop(drv_data, "interrupt_transfer: fifo underrun", -EIO); return IRQ_HANDLED; } @@ -1154,14 +1154,7 @@ static int pxa2xx_spi_slave_abort(struct spi_controller *controller) { struct driver_data *drv_data = spi_controller_get_devdata(controller); - int_stop_and_reset(drv_data); - pxa2xx_spi_flush(drv_data); - pxa2xx_spi_off(drv_data); - - dev_dbg(drv_data->ssp->dev, "transfer aborted\n"); - - drv_data->controller->cur_msg->status = -EINTR; - spi_finalize_current_transfer(drv_data->controller); + int_error_stop(drv_data, "transfer aborted", -EINTR); return 0; } From 0c8ccd8b267fc735e4621774ce62728f27d42863 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 15:41:29 +0300 Subject: [PATCH 21/86] spi: pxa2xx: Use pxa_ssp_enable()/pxa_ssp_disable() in the driver There are few places that repeat the logic of pxa_ssp_enable() and pxa_ssp_disable(). Use them instead of open coded variants. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510124134.24638-10-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-dma.c | 4 +--- drivers/spi/spi-pxa2xx.c | 36 ++++++++++++++++++------------------ include/linux/pxa2xx_ssp.h | 16 ++++++++++++++++ sound/soc/pxa/pxa-ssp.c | 16 ---------------- 4 files changed, 35 insertions(+), 37 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index e00dbadd39ec..5ca01ad7f460 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -50,9 +50,7 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, if (error) { /* In case we got an error we disable the SSP now */ - pxa2xx_spi_write(drv_data, SSCR0, - pxa2xx_spi_read(drv_data, SSCR0) - & ~SSCR0_SSE); + pxa_ssp_disable(drv_data->ssp); msg->status = -EIO; } diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 087c84e605b9..a27f51f5db65 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -286,13 +286,11 @@ static u32 pxa2xx_configure_sscr0(const struct driver_data *drv_data, case QUARK_X1000_SSP: return clk_div | QUARK_X1000_SSCR0_Motorola - | QUARK_X1000_SSCR0_DataSize(bits > 32 ? 8 : bits) - | SSCR0_SSE; + | QUARK_X1000_SSCR0_DataSize(bits > 32 ? 8 : bits); default: return clk_div | SSCR0_Motorola | SSCR0_DataSize(bits > 16 ? bits - 16 : bits) - | SSCR0_SSE | (bits > 16 ? SSCR0_EDSS : 0); } } @@ -498,8 +496,7 @@ static void pxa2xx_spi_off(struct driver_data *drv_data) if (is_mmp2_ssp(drv_data)) return; - pxa2xx_spi_write(drv_data, SSCR0, - pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE); + pxa_ssp_disable(drv_data->ssp); } static int null_writer(struct driver_data *drv_data) @@ -1098,25 +1095,26 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, (pxa2xx_spi_read(drv_data, DDS_RATE) != chip->dds_rate)) pxa2xx_spi_write(drv_data, DDS_RATE, chip->dds_rate); + /* Stop the SSP */ + if (!is_mmp2_ssp(drv_data)) + pxa_ssp_disable(drv_data->ssp); + + if (!pxa25x_ssp_comp(drv_data)) + pxa2xx_spi_write(drv_data, SSTO, chip->timeout); + /* see if we need to reload the config registers */ if ((pxa2xx_spi_read(drv_data, SSCR0) != cr0) || (pxa2xx_spi_read(drv_data, SSCR1) & change_mask) != (cr1 & change_mask)) { - /* stop the SSP, and update the other bits */ - if (!is_mmp2_ssp(drv_data)) - pxa2xx_spi_write(drv_data, SSCR0, cr0 & ~SSCR0_SSE); - if (!pxa25x_ssp_comp(drv_data)) - pxa2xx_spi_write(drv_data, SSTO, chip->timeout); /* first set CR1 without interrupt and service enables */ pxa2xx_spi_write(drv_data, SSCR1, cr1 & change_mask); - /* restart the SSP */ + /* Update the other bits */ pxa2xx_spi_write(drv_data, SSCR0, cr0); - - } else { - if (!pxa25x_ssp_comp(drv_data)) - pxa2xx_spi_write(drv_data, SSTO, chip->timeout); } + /* Restart the SSP */ + pxa_ssp_enable(drv_data->ssp); + if (is_mmp2_ssp(drv_data)) { u8 tx_level = (pxa2xx_spi_read(drv_data, SSSR) & SSSR_TFL_MASK) >> 8; @@ -1786,8 +1784,9 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) controller->min_speed_hz = DIV_ROUND_UP(controller->max_speed_hz, 512); + pxa_ssp_disable(ssp); + /* Load default SSP configuration */ - pxa2xx_spi_write(drv_data, SSCR0, 0); switch (drv_data->ssp_type) { case QUARK_X1000_SSP: tmp = QUARK_X1000_SSCR1_RxTresh(RX_THRESH_QUARK_X1000_DFLT) | @@ -1928,7 +1927,7 @@ static int pxa2xx_spi_remove(struct platform_device *pdev) spi_unregister_controller(drv_data->controller); /* Disable the SSP at the peripheral and SOC level */ - pxa2xx_spi_write(drv_data, SSCR0, 0); + pxa_ssp_disable(ssp); clk_disable_unprepare(ssp->clk); /* Release DMA */ @@ -1957,7 +1956,8 @@ static int pxa2xx_spi_suspend(struct device *dev) status = spi_controller_suspend(drv_data->controller); if (status != 0) return status; - pxa2xx_spi_write(drv_data, SSCR0, 0); + + pxa_ssp_disable(ssp); if (!pm_runtime_suspended(dev)) clk_disable_unprepare(ssp->clk); diff --git a/include/linux/pxa2xx_ssp.h b/include/linux/pxa2xx_ssp.h index 1b6c1a0922bd..fdfbe17e15f4 100644 --- a/include/linux/pxa2xx_ssp.h +++ b/include/linux/pxa2xx_ssp.h @@ -254,6 +254,22 @@ static inline u32 pxa_ssp_read_reg(struct ssp_device *dev, u32 reg) return __raw_readl(dev->mmio_base + reg); } +static inline void pxa_ssp_enable(struct ssp_device *ssp) +{ + u32 sscr0; + + sscr0 = pxa_ssp_read_reg(ssp, SSCR0) | SSCR0_SSE; + pxa_ssp_write_reg(ssp, SSCR0, sscr0); +} + +static inline void pxa_ssp_disable(struct ssp_device *ssp) +{ + u32 sscr0; + + sscr0 = pxa_ssp_read_reg(ssp, SSCR0) & ~SSCR0_SSE; + pxa_ssp_write_reg(ssp, SSCR0, sscr0); +} + #if IS_ENABLED(CONFIG_PXA_SSP) struct ssp_device *pxa_ssp_request(int port, const char *label); void pxa_ssp_free(struct ssp_device *); diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index b941adcbb8f9..939e7e28486a 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -61,22 +61,6 @@ static void dump_registers(struct ssp_device *ssp) pxa_ssp_read_reg(ssp, SSACD)); } -static void pxa_ssp_enable(struct ssp_device *ssp) -{ - uint32_t sscr0; - - sscr0 = __raw_readl(ssp->mmio_base + SSCR0) | SSCR0_SSE; - __raw_writel(sscr0, ssp->mmio_base + SSCR0); -} - -static void pxa_ssp_disable(struct ssp_device *ssp) -{ - uint32_t sscr0; - - sscr0 = __raw_readl(ssp->mmio_base + SSCR0) & ~SSCR0_SSE; - __raw_writel(sscr0, ssp->mmio_base + SSCR0); -} - static void pxa_ssp_set_dma_params(struct ssp_device *ssp, int width4, int out, struct snd_dmaengine_dai_dma_data *dma) { From 1bed378c6b9116c51ae59b970cf3d9b4e9e62ced Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 15:41:30 +0300 Subject: [PATCH 22/86] spi: pxa2xx: Extract pxa2xx_spi_update() helper There are few places that repeat the logic of "update if changed". Extract pxa2xx_spi_update() helper to deduplicate that. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510124134.24638-11-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index a27f51f5db65..54eaa048651f 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -200,6 +200,12 @@ static bool is_mmp2_ssp(const struct driver_data *drv_data) return drv_data->ssp_type == MMP2_SSP; } +static void pxa2xx_spi_update(const struct driver_data *drv_data, u32 reg, u32 mask, u32 value) +{ + if ((pxa2xx_spi_read(drv_data, reg) & mask) != value) + pxa2xx_spi_write(drv_data, reg, value & mask); +} + static u32 pxa2xx_spi_get_ssrc1_change_mask(const struct driver_data *drv_data) { switch (drv_data->ssp_type) { @@ -1081,19 +1087,12 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, dma_mapped ? "DMA" : "PIO"); if (is_lpss_ssp(drv_data)) { - if ((pxa2xx_spi_read(drv_data, SSIRF) & 0xff) - != chip->lpss_rx_threshold) - pxa2xx_spi_write(drv_data, SSIRF, - chip->lpss_rx_threshold); - if ((pxa2xx_spi_read(drv_data, SSITF) & 0xffff) - != chip->lpss_tx_threshold) - pxa2xx_spi_write(drv_data, SSITF, - chip->lpss_tx_threshold); + pxa2xx_spi_update(drv_data, SSIRF, GENMASK(7, 0), chip->lpss_rx_threshold); + pxa2xx_spi_update(drv_data, SSITF, GENMASK(15, 0), chip->lpss_tx_threshold); } - if (is_quark_x1000_ssp(drv_data) && - (pxa2xx_spi_read(drv_data, DDS_RATE) != chip->dds_rate)) - pxa2xx_spi_write(drv_data, DDS_RATE, chip->dds_rate); + if (is_quark_x1000_ssp(drv_data)) + pxa2xx_spi_update(drv_data, DDS_RATE, GENMASK(23, 0), chip->dds_rate); /* Stop the SSP */ if (!is_mmp2_ssp(drv_data)) @@ -1102,15 +1101,11 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, if (!pxa25x_ssp_comp(drv_data)) pxa2xx_spi_write(drv_data, SSTO, chip->timeout); + /* first set CR1 without interrupt and service enables */ + pxa2xx_spi_update(drv_data, SSCR1, change_mask, cr1); + /* see if we need to reload the config registers */ - if ((pxa2xx_spi_read(drv_data, SSCR0) != cr0) - || (pxa2xx_spi_read(drv_data, SSCR1) & change_mask) - != (cr1 & change_mask)) { - /* first set CR1 without interrupt and service enables */ - pxa2xx_spi_write(drv_data, SSCR1, cr1 & change_mask); - /* Update the other bits */ - pxa2xx_spi_write(drv_data, SSCR0, cr0); - } + pxa2xx_spi_update(drv_data, SSCR0, GENMASK(31, 0), cr0); /* Restart the SSP */ pxa_ssp_enable(drv_data->ssp); From 42c80cd439a938569a86f6ae135d38c1cda5569b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 15:41:31 +0300 Subject: [PATCH 23/86] spi: pxa2xx: Extract clear_SSCR1_bits() helper There are few places that repeat the logic of "clear some bits in SSCR1". Extract clear_SSCR1_bits() helper to deduplicate that. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510124134.24638-12-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-dma.c | 4 +--- drivers/spi/spi-pxa2xx.c | 7 ++----- drivers/spi/spi-pxa2xx.h | 5 +++++ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index 5ca01ad7f460..e581027e99f9 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -41,9 +41,7 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, } /* Clear status & disable interrupts */ - pxa2xx_spi_write(drv_data, SSCR1, - pxa2xx_spi_read(drv_data, SSCR1) - & ~drv_data->dma_cr1); + clear_SSCR1_bits(drv_data, drv_data->dma_cr1); write_SSSR_CS(drv_data, drv_data->clear_sr); if (!pxa25x_ssp_comp(drv_data)) pxa2xx_spi_write(drv_data, SSTO, 0); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 54eaa048651f..3a4ad16614f7 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -733,8 +733,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) static void handle_bad_msg(struct driver_data *drv_data) { pxa2xx_spi_off(drv_data); - pxa2xx_spi_write(drv_data, SSCR1, - pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1); + clear_SSCR1_bits(drv_data, drv_data->int_cr1); if (!pxa25x_ssp_comp(drv_data)) pxa2xx_spi_write(drv_data, SSTO, 0); write_SSSR_CS(drv_data, drv_data->clear_sr); @@ -1161,9 +1160,7 @@ static void pxa2xx_spi_handle_err(struct spi_controller *controller, pxa2xx_spi_off(drv_data); /* Clear and disable interrupts and service requests */ write_SSSR_CS(drv_data, drv_data->clear_sr); - pxa2xx_spi_write(drv_data, SSCR1, - pxa2xx_spi_read(drv_data, SSCR1) - & ~(drv_data->int_cr1 | drv_data->dma_cr1)); + clear_SSCR1_bits(drv_data, drv_data->int_cr1 | drv_data->dma_cr1); if (!pxa25x_ssp_comp(drv_data)) pxa2xx_spi_write(drv_data, SSTO, 0); diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 739e264feaa6..ed63f7165cd8 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -105,6 +105,11 @@ static inline int pxa25x_ssp_comp(struct driver_data *drv_data) } } +static inline void clear_SSCR1_bits(const struct driver_data *drv_data, u32 bits) +{ + pxa2xx_spi_write(drv_data, SSCR1, pxa2xx_spi_read(drv_data, SSCR1) & ~bits); +} + static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val) { if (drv_data->ssp_type == CE4100_SSP || From 6d380132eaea536bef641f21847c8a7987e96ad8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 15:41:32 +0300 Subject: [PATCH 24/86] spi: pxa2xx: Extract read_SSSR_bits() helper There are few places that repeat the logic of "read some bits from SSSR". Extract read_SSSR_bits() helper to deduplicate that. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510124134.24638-13-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-dma.c | 9 +++------ drivers/spi/spi-pxa2xx.c | 26 +++++++++++--------------- drivers/spi/spi-pxa2xx.h | 7 ++++++- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index e581027e99f9..f022d82dcb1b 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -34,11 +34,8 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, * might not know about the error yet. So we re-check the * ROR bit here before we clear the status register. */ - if (!error) { - u32 status = pxa2xx_spi_read(drv_data, SSSR) - & drv_data->mask_sr; - error = status & SSSR_ROR; - } + if (!error) + error = read_SSSR_bits(drv_data, drv_data->mask_sr) & SSSR_ROR; /* Clear status & disable interrupts */ clear_SSCR1_bits(drv_data, drv_data->dma_cr1); @@ -119,7 +116,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) { u32 status; - status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr; + status = read_SSSR_bits(drv_data, drv_data->mask_sr); if (status & SSSR_ROR) { dev_err(drv_data->ssp->dev, "FIFO overrun\n"); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 3a4ad16614f7..af3f01de8f5b 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -247,7 +247,7 @@ static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data) break; } - return (pxa2xx_spi_read(drv_data, SSSR) & mask) == mask; + return read_SSSR_bits(drv_data, mask) == mask; } static void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data, @@ -488,7 +488,7 @@ int pxa2xx_spi_flush(struct driver_data *drv_data) unsigned long limit = loops_per_jiffy << 1; do { - while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) + while (read_SSSR_bits(drv_data, SSSR_RNE)) pxa2xx_spi_read(drv_data, SSDR); } while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY) && --limit); write_SSSR_CS(drv_data, SSSR_ROR); @@ -523,8 +523,7 @@ static int null_reader(struct driver_data *drv_data) { u8 n_bytes = drv_data->n_bytes; - while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) - && (drv_data->rx < drv_data->rx_end)) { + while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) { pxa2xx_spi_read(drv_data, SSDR); drv_data->rx += n_bytes; } @@ -546,8 +545,7 @@ static int u8_writer(struct driver_data *drv_data) static int u8_reader(struct driver_data *drv_data) { - while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) - && (drv_data->rx < drv_data->rx_end)) { + while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) { *(u8 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR); ++drv_data->rx; } @@ -569,8 +567,7 @@ static int u16_writer(struct driver_data *drv_data) static int u16_reader(struct driver_data *drv_data) { - while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) - && (drv_data->rx < drv_data->rx_end)) { + while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) { *(u16 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR); drv_data->rx += 2; } @@ -592,8 +589,7 @@ static int u32_writer(struct driver_data *drv_data) static int u32_reader(struct driver_data *drv_data) { - while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) - && (drv_data->rx < drv_data->rx_end)) { + while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) { *(u32 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR); drv_data->rx += 4; } @@ -655,10 +651,11 @@ static void int_transfer_complete(struct driver_data *drv_data) static irqreturn_t interrupt_transfer(struct driver_data *drv_data) { - u32 irq_mask = (pxa2xx_spi_read(drv_data, SSCR1) & SSCR1_TIE) ? - drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS; + u32 irq_status; - u32 irq_status = pxa2xx_spi_read(drv_data, SSSR) & irq_mask; + irq_status = read_SSSR_bits(drv_data, drv_data->mask_sr); + if (!(pxa2xx_spi_read(drv_data, SSCR1) & SSCR1_TIE)) + irq_status &= ~SSSR_TFS; if (irq_status & SSSR_ROR) { int_error_stop(drv_data, "interrupt_transfer: fifo overrun", -EIO); @@ -1110,8 +1107,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, pxa_ssp_enable(drv_data->ssp); if (is_mmp2_ssp(drv_data)) { - u8 tx_level = (pxa2xx_spi_read(drv_data, SSSR) - & SSSR_TFL_MASK) >> 8; + u8 tx_level = read_SSSR_bits(drv_data, SSSR_TFL_MASK) >> 8; if (tx_level) { /* On MMP2, flipping SSE doesn't to empty TXFIFO. */ diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index ed63f7165cd8..d2cb40f97c4b 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -110,11 +110,16 @@ static inline void clear_SSCR1_bits(const struct driver_data *drv_data, u32 bits pxa2xx_spi_write(drv_data, SSCR1, pxa2xx_spi_read(drv_data, SSCR1) & ~bits); } +static inline u32 read_SSSR_bits(const struct driver_data *drv_data, u32 bits) +{ + return pxa2xx_spi_read(drv_data, SSSR) & bits; +} + static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val) { if (drv_data->ssp_type == CE4100_SSP || drv_data->ssp_type == QUARK_X1000_SSP) - val |= pxa2xx_spi_read(drv_data, SSSR) & SSSR_ALT_FRM_MASK; + val |= read_SSSR_bits(drv_data, SSSR_ALT_FRM_MASK); pxa2xx_spi_write(drv_data, SSSR, val); } From eca32c3974c0664f88fed90b327f473bd18a4809 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 15:41:33 +0300 Subject: [PATCH 25/86] spi: pxa2xx: Constify struct driver_data parameter In a couple of functions the contents of struct driver_data are not altered, hence we may constify the respective function parameter. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510124134.24638-14-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index d2cb40f97c4b..5c6a5e0f249e 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -93,7 +93,7 @@ static inline void pxa2xx_spi_write(const struct driver_data *drv_data, u32 reg, #define DMA_ALIGNMENT 8 -static inline int pxa25x_ssp_comp(struct driver_data *drv_data) +static inline int pxa25x_ssp_comp(const struct driver_data *drv_data) { switch (drv_data->ssp_type) { case PXA25x_SSP: @@ -115,7 +115,7 @@ static inline u32 read_SSSR_bits(const struct driver_data *drv_data, u32 bits) return pxa2xx_spi_read(drv_data, SSSR) & bits; } -static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val) +static inline void write_SSSR_CS(const struct driver_data *drv_data, u32 val) { if (drv_data->ssp_type == CE4100_SSP || drv_data->ssp_type == QUARK_X1000_SSP) From 3fdb59cf10b020b32b9f1dfc78611320623dcb3e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 15:41:34 +0300 Subject: [PATCH 26/86] spi: pxa2xx: Introduce special type for Merrifield SPIs Intel Merrifield SPI is actually more closer to PXA3xx. It has extended FIFO (32 bytes) and additional registers to get or set FIFO thresholds. Introduce new type for Intel Merrifield SPI host controllers and handle bigger FIFO size. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510124134.24638-15-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 2 +- drivers/spi/spi-pxa2xx.c | 32 +++++++++++++++++++++++++++++--- include/linux/pxa2xx_ssp.h | 16 ++++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index a259be12d326..dce9ade9a4df 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -179,7 +179,7 @@ static struct pxa_spi_info spi_info_configs[] = { .rx_param = &bsw2_rx_param, }, [PORT_MRFLD] = { - .type = PXA27x_SSP, + .type = MRFLD_SSP, .max_clk_rate = 25000000, .setup = mrfld_spi_setup, }, diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index af3f01de8f5b..5985b39e2dd6 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -200,6 +200,11 @@ static bool is_mmp2_ssp(const struct driver_data *drv_data) return drv_data->ssp_type == MMP2_SSP; } +static bool is_mrfld_ssp(const struct driver_data *drv_data) +{ + return drv_data->ssp_type == MRFLD_SSP; +} + static void pxa2xx_spi_update(const struct driver_data *drv_data, u32 reg, u32 mask, u32 value) { if ((pxa2xx_spi_read(drv_data, reg) & mask) != value) @@ -1087,6 +1092,15 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, pxa2xx_spi_update(drv_data, SSITF, GENMASK(15, 0), chip->lpss_tx_threshold); } + if (is_mrfld_ssp(drv_data)) { + u32 thresh = 0; + + thresh |= SFIFOTT_RxThresh(chip->lpss_rx_threshold); + thresh |= SFIFOTT_TxThresh(chip->lpss_tx_threshold); + + pxa2xx_spi_update(drv_data, SFIFOTT, 0xffffffff, thresh); + } + if (is_quark_x1000_ssp(drv_data)) pxa2xx_spi_update(drv_data, DDS_RATE, GENMASK(23, 0), chip->dds_rate); @@ -1253,6 +1267,11 @@ static int setup(struct spi_device *spi) tx_hi_thres = 0; rx_thres = RX_THRESH_QUARK_X1000_DFLT; break; + case MRFLD_SSP: + tx_thres = TX_THRESH_MRFLD_DFLT; + tx_hi_thres = 0; + rx_thres = RX_THRESH_MRFLD_DFLT; + break; case CE4100_SSP: tx_thres = TX_THRESH_CE4100_DFLT; tx_hi_thres = 0; @@ -1328,9 +1347,16 @@ static int setup(struct spi_device *spi) chip->cr1 |= SSCR1_SPH; } - chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres); - chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres) - | SSITF_TxHiThresh(tx_hi_thres); + if (is_lpss_ssp(drv_data)) { + chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres); + chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres) | + SSITF_TxHiThresh(tx_hi_thres); + } + + if (is_mrfld_ssp(drv_data)) { + chip->lpss_rx_threshold = rx_thres; + chip->lpss_tx_threshold = tx_thres; + } /* set dma burst and threshold outside of chip_info path so that if * chip_info goes away after setting chip->enable_dma, the diff --git a/include/linux/pxa2xx_ssp.h b/include/linux/pxa2xx_ssp.h index fdfbe17e15f4..2b21bc1f3c73 100644 --- a/include/linux/pxa2xx_ssp.h +++ b/include/linux/pxa2xx_ssp.h @@ -183,6 +183,21 @@ struct device_node; #define SSACD_ACPS(x) ((x) << 4) /* Audio clock PLL select */ #define SSACD_SCDX8 BIT(7) /* SYSCLK division ratio select */ +/* Intel Merrifield SSP */ +#define SFIFOL 0x68 /* FIFO level */ +#define SFIFOTT 0x6c /* FIFO trigger threshold */ + +#define RX_THRESH_MRFLD_DFLT 16 +#define TX_THRESH_MRFLD_DFLT 16 + +#define SFIFOL_TFL_MASK GENMASK(15, 0) /* Transmit FIFO Level mask */ +#define SFIFOL_RFL_MASK GENMASK(31, 16) /* Receive FIFO Level mask */ + +#define SFIFOTT_TFT GENMASK(15, 0) /* Transmit FIFO Threshold (mask) */ +#define SFIFOTT_TxThresh(x) (((x) - 1) << 0) /* TX FIFO trigger threshold / level */ +#define SFIFOTT_RFT GENMASK(31, 16) /* Receive FIFO Threshold (mask) */ +#define SFIFOTT_RxThresh(x) (((x) - 1) << 16) /* RX FIFO trigger threshold / level */ + /* LPSS SSP */ #define SSITF 0x44 /* TX FIFO trigger level */ #define SSITF_TxHiThresh(x) (((x) - 1) << 0) @@ -205,6 +220,7 @@ enum pxa_ssp_type { MMP2_SSP, PXA910_SSP, CE4100_SSP, + MRFLD_SSP, QUARK_X1000_SSP, LPSS_LPT_SSP, /* Keep LPSS types sorted with lpss_platforms[] */ LPSS_BYT_SSP, From 86b8bff7e3ac6775113639d88db7448a8b47f0c1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 16:11:20 +0300 Subject: [PATCH 27/86] spi: Convert to use predefined time multipliers We have a lot of hard coded values in nanoseconds or other units. Use predefined constants to make it more clear. While at it, add or amend comments in the corresponding functions. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510131120.49253-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index f9885c096563..407420977a73 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1118,10 +1118,20 @@ static int spi_transfer_wait(struct spi_controller *ctlr, if (!speed_hz) speed_hz = 100000; - ms = 8LL * 1000LL * xfer->len; + /* + * For each byte we wait for 8 cycles of the SPI clock. + * Since speed is defined in Hz and we want milliseconds, + * use respective multiplier, but before the division, + * otherwise we may get 0 for short transfers. + */ + ms = 8LL * MSEC_PER_SEC * xfer->len; do_div(ms, speed_hz); - ms += ms + 200; /* some tolerance */ + /* + * Increase it twice and add 200 ms tolerance, use + * predefined maximum in case of overflow. + */ + ms += ms + 200; if (ms > UINT_MAX) ms = UINT_MAX; @@ -1144,10 +1154,10 @@ static void _spi_transfer_delay_ns(u32 ns) { if (!ns) return; - if (ns <= 1000) { + if (ns <= NSEC_PER_USEC) { ndelay(ns); } else { - u32 us = DIV_ROUND_UP(ns, 1000); + u32 us = DIV_ROUND_UP(ns, NSEC_PER_USEC); if (us <= 10) udelay(us); @@ -1167,21 +1177,25 @@ int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer) switch (unit) { case SPI_DELAY_UNIT_USECS: - delay *= 1000; + delay *= NSEC_PER_USEC; break; - case SPI_DELAY_UNIT_NSECS: /* nothing to do here */ + case SPI_DELAY_UNIT_NSECS: + /* Nothing to do here */ break; case SPI_DELAY_UNIT_SCK: /* clock cycles need to be obtained from spi_transfer */ if (!xfer) return -EINVAL; - /* if there is no effective speed know, then approximate - * by underestimating with half the requested hz + /* + * If there is unknown effective speed, approximate it + * by underestimating with half of the requested hz. */ hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2; if (!hz) return -EINVAL; - delay *= DIV_ROUND_UP(1000000000, hz); + + /* Convert delay to nanoseconds */ + delay *= DIV_ROUND_UP(NSEC_PER_SEC, hz); break; default: return -EINVAL; @@ -1213,6 +1227,7 @@ EXPORT_SYMBOL_GPL(spi_delay_exec); static void _spi_transfer_cs_change_delay(struct spi_message *msg, struct spi_transfer *xfer) { + u32 default_delay_ns = 10 * NSEC_PER_USEC; u32 delay = xfer->cs_change_delay.value; u32 unit = xfer->cs_change_delay.unit; int ret; @@ -1220,16 +1235,16 @@ static void _spi_transfer_cs_change_delay(struct spi_message *msg, /* return early on "fast" mode - for everything but USECS */ if (!delay) { if (unit == SPI_DELAY_UNIT_USECS) - _spi_transfer_delay_ns(10000); + _spi_transfer_delay_ns(default_delay_ns); return; } ret = spi_delay_exec(&xfer->cs_change_delay, xfer); if (ret) { dev_err_once(&msg->spi->dev, - "Use of unsupported delay unit %i, using default of 10us\n", - unit); - _spi_transfer_delay_ns(10000); + "Use of unsupported delay unit %i, using default of %luus\n", + unit, default_delay_ns / NSEC_PER_USEC); + _spi_transfer_delay_ns(default_delay_ns); } } From 532259bfd1c12d561215c32b94cd9bb7c997bc6f Mon Sep 17 00:00:00 2001 From: Zou Wei Date: Tue, 11 May 2021 15:08:42 +0800 Subject: [PATCH 28/86] spi: altera: Remove redundant dev_err call in dfl_spi_altera_probe() There is a error message within devm_ioremap_resource already, so remove the dev_err call to avoid redundant error message. Reported-by: Hulk Robot Signed-off-by: Zou Wei Link: https://lore.kernel.org/r/1620716922-108572-1-git-send-email-zou_wei@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-altera-dfl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-altera-dfl.c b/drivers/spi/spi-altera-dfl.c index 3e32e4fe5895..39a3e1a032e0 100644 --- a/drivers/spi/spi-altera-dfl.c +++ b/drivers/spi/spi-altera-dfl.c @@ -148,10 +148,8 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev) base = devm_ioremap_resource(dev, &dfl_dev->mmio_res); - if (IS_ERR(base)) { - dev_err(dev, "%s get mem resource fail!\n", __func__); + if (IS_ERR(base)) return PTR_ERR(base); - } config_spi_master(base, master); dev_dbg(dev, "%s cs %u bpm 0x%x mode 0x%x\n", __func__, From 40b82c2d9a78593201a3a62dc9239d6405334561 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 16:12:11 +0300 Subject: [PATCH 29/86] spi: Use SPI_MODE_X_MASK Use SPI_MODE_X_MASK instead of open coded variant. While at it, fix format specifier and drop explicit casting. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510131217.49357-1-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 407420977a73..956dce3aafca 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3441,8 +3441,8 @@ int spi_setup(struct spi_device *spi) spi_set_thread_rt(spi->controller); } - dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n", - (int) (spi->mode & (SPI_CPOL | SPI_CPHA)), + dev_dbg(&spi->dev, "setup mode %lu, %s%s%s%s%u bits/w, %u Hz max --> %d\n", + spi->mode & SPI_MODE_X_MASK, (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "", (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "", (spi->mode & SPI_3WIRE) ? "3wire, " : "", From dd507b5ec7ba44ab51e1a8404d04e815a91b472f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 16:12:12 +0300 Subject: [PATCH 30/86] spi: spidev: Use SPI_MODE_X_MASK Use SPI_MODE_X_MASK instead of open coded variant. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510131217.49357-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spidev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index f56e0e975a46..24e9469ea35b 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -59,7 +59,7 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS); * * REVISIT should changing those flags be privileged? */ -#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \ +#define SPI_MODE_MASK (SPI_MODE_X_MASK | SPI_CS_HIGH \ | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \ | SPI_NO_CS | SPI_READY | SPI_TX_DUAL \ | SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL \ From 56f47edf33fb55ab9381f61d60cf34c7578f3d75 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 16:12:13 +0300 Subject: [PATCH 31/86] spi: npcm-pspi: Use SPI_MODE_X_MASK Use SPI_MODE_X_MASK instead of open coded variant. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510131217.49357-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-npcm-pspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c index 56d10c4511db..1668a347e003 100644 --- a/drivers/spi/spi-npcm-pspi.c +++ b/drivers/spi/spi-npcm-pspi.c @@ -105,7 +105,7 @@ static void npcm_pspi_set_mode(struct spi_device *spi) u16 regtemp; u16 mode_val; - switch (spi->mode & (SPI_CPOL | SPI_CPHA)) { + switch (spi->mode & SPI_MODE_X_MASK) { case SPI_MODE_0: mode_val = 0; break; From a2f2db6b2a8708f6ac592a362e34fb330f874cea Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 16:12:14 +0300 Subject: [PATCH 32/86] spi: oc-tiny: Use SPI_MODE_X_MASK Use SPI_MODE_X_MASK instead of open coded variant. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510131217.49357-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-oc-tiny.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index f3843f0ff260..38c14c4e4e21 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -86,7 +86,7 @@ static int tiny_spi_setup(struct spi_device *spi) hw->speed_hz = spi->max_speed_hz; hw->baud = tiny_spi_baud(spi, hw->speed_hz); } - hw->mode = spi->mode & (SPI_CPOL | SPI_CPHA); + hw->mode = spi->mode & SPI_MODE_X_MASK; return 0; } From fdb217a38808e041f6eca8c550f1b5981e401a45 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 16:12:15 +0300 Subject: [PATCH 33/86] spi: omap-uwire: Use SPI_MODE_X_MASK Use SPI_MODE_X_MASK instead of open coded variant. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510131217.49357-5-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-omap-uwire.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 71402f71ddd8..ceb479f5c88f 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -330,7 +330,7 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t) if (spi->mode & SPI_CPOL) flags |= UWIRE_CLK_INVERTED; - switch (spi->mode & (SPI_CPOL | SPI_CPHA)) { + switch (spi->mode & SPI_MODE_X_MASK) { case SPI_MODE_0: case SPI_MODE_3: flags |= UWIRE_WRITE_FALLING_EDGE | UWIRE_READ_RISING_EDGE; From 4ccf05579b9d0f15443a0edc860e2be7472ccfc1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 16:12:16 +0300 Subject: [PATCH 34/86] spi: ppc4xx: Use SPI_MODE_X_MASK Use SPI_MODE_X_MASK instead of open coded variant. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510131217.49357-6-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-ppc4xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 76874a7cca9b..59d201acbb39 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -235,7 +235,7 @@ static int spi_ppc4xx_setup(struct spi_device *spi) */ cs->mode = SPI_PPC4XX_MODE_SPE; - switch (spi->mode & (SPI_CPHA | SPI_CPOL)) { + switch (spi->mode & SPI_MODE_X_MASK) { case SPI_MODE_0: cs->mode |= SPI_CLK_MODE0; break; From 038b9de42269f33aca3e3741214c863a4e9328d0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 May 2021 16:12:17 +0300 Subject: [PATCH 35/86] spi: uniphier: Use SPI_MODE_X_MASK Use SPI_MODE_X_MASK instead of open coded variant. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210510131217.49357-7-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-uniphier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c index 6a9ef8ee3cc9..8900e51e1a1c 100644 --- a/drivers/spi/spi-uniphier.c +++ b/drivers/spi/spi-uniphier.c @@ -142,7 +142,7 @@ static void uniphier_spi_set_mode(struct spi_device *spi) * FSTRT start frame timing * 0: rising edge of clock, 1: falling edge of clock */ - switch (spi->mode & (SPI_CPOL | SPI_CPHA)) { + switch (spi->mode & SPI_MODE_X_MASK) { case SPI_MODE_0: /* CKPHS=1, CKINIT=0, CKDLY=1, FSTRT=0 */ val1 = SSI_CKS_CKPHS | SSI_CKS_CKDLY; From 94acf80755c8d8dd066d4f5a2afbdf393f0e2afd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 May 2021 17:03:43 +0300 Subject: [PATCH 36/86] spi: pxa2xx: Propagate firmware node to the child SPI controller device SPI core may utilize properties and resources provided by the parent device. Propagate firmware node to the child SPI controller device for that. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210517140351.901-2-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 5985b39e2dd6..38eef9033468 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1718,7 +1718,9 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) drv_data->controller_info = platform_info; drv_data->ssp = ssp; - controller->dev.of_node = pdev->dev.of_node; + controller->dev.of_node = dev->of_node; + controller->dev.fwnode = dev->fwnode; + /* the spi->mode bits understood by this driver: */ controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; From 778c12e69481d544e6fcfa45b23ae3c5379b5a02 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 May 2021 17:03:44 +0300 Subject: [PATCH 37/86] spi: pxa2xx: Switch to use SPI core GPIO (descriptor) CS handling SPI core has been already providing the GPIO CS handling. Use it. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210517140351.901-3-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 51 +++------------------------------------- drivers/spi/spi-pxa2xx.h | 3 --- 2 files changed, 3 insertions(+), 51 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 38eef9033468..d19cea4ed946 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1198,25 +1198,12 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_controller *controller) static int setup_cs(struct spi_device *spi, struct chip_data *chip, struct pxa2xx_spi_chip *chip_info) { - struct driver_data *drv_data = - spi_controller_get_devdata(spi->controller); struct gpio_desc *gpiod; int err = 0; if (chip == NULL) return 0; - if (drv_data->cs_gpiods) { - gpiod = drv_data->cs_gpiods[spi->chip_select]; - if (gpiod) { - chip->gpiod_cs = gpiod; - chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH; - gpiod_set_value(gpiod, chip->gpio_cs_inverted); - } - - return 0; - } - if (chip_info == NULL) return 0; @@ -1430,8 +1417,7 @@ static void cleanup(struct spi_device *spi) if (!chip) return; - if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods && - chip->gpiod_cs) + if (drv_data->ssp_type != CE4100_SSP && chip->gpiod_cs) gpiod_put(chip->gpiod_cs); kfree(chip); @@ -1682,7 +1668,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) struct driver_data *drv_data; struct ssp_device *ssp; const struct lpss_config *config; - int status, count; + int status; u32 tmp; platform_info = dev_get_platdata(dev); @@ -1861,38 +1847,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) } } controller->num_chipselect = platform_info->num_chipselect; - - count = gpiod_count(&pdev->dev, "cs"); - if (count > 0) { - int i; - - controller->num_chipselect = max_t(int, count, - controller->num_chipselect); - - drv_data->cs_gpiods = devm_kcalloc(&pdev->dev, - controller->num_chipselect, sizeof(struct gpio_desc *), - GFP_KERNEL); - if (!drv_data->cs_gpiods) { - status = -ENOMEM; - goto out_error_clock_enabled; - } - - for (i = 0; i < controller->num_chipselect; i++) { - struct gpio_desc *gpiod; - - gpiod = devm_gpiod_get_index(dev, "cs", i, GPIOD_ASIS); - if (IS_ERR(gpiod)) { - /* Means use native chip select */ - if (PTR_ERR(gpiod) == -ENOENT) - continue; - - status = PTR_ERR(gpiod); - goto out_error_clock_enabled; - } else { - drv_data->cs_gpiods[i] = gpiod; - } - } - } + controller->use_gpio_descriptors = true; if (platform_info->is_slave) { drv_data->gpiod_ready = devm_gpiod_get_optional(dev, diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 5c6a5e0f249e..672dfd4863cc 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -53,9 +53,6 @@ struct driver_data { void __iomem *lpss_base; - /* GPIOs for chip selects */ - struct gpio_desc **cs_gpiods; - /* Optional slave FIFO ready signal */ struct gpio_desc *gpiod_ready; }; From de6926f307e7ff605f3e37f11a4b3cc20c85c365 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 May 2021 17:03:45 +0300 Subject: [PATCH 38/86] spi: pxa2xx: Switch to use SPI core GPIO (legacy) CS handling SPI core has been already providing the GPIO CS handling. Use it. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210517140351.901-4-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 59 ++++++++++++++++++---------------------- drivers/spi/spi-pxa2xx.h | 12 ++++---- 2 files changed, 32 insertions(+), 39 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index d19cea4ed946..1a0bcd3bac1f 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -441,11 +441,6 @@ static void cs_assert(struct spi_device *spi) return; } - if (chip->gpiod_cs) { - gpiod_set_value(chip->gpiod_cs, chip->gpio_cs_inverted); - return; - } - if (is_lpss_ssp(drv_data)) lpss_ssp_cs_control(spi, true); } @@ -471,11 +466,6 @@ static void cs_deassert(struct spi_device *spi) return; } - if (chip->gpiod_cs) { - gpiod_set_value(chip->gpiod_cs, !chip->gpio_cs_inverted); - return; - } - if (is_lpss_ssp(drv_data)) lpss_ssp_cs_control(spi, false); } @@ -1195,11 +1185,19 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_controller *controller) return 0; } +static void cleanup_cs(struct spi_device *spi) +{ + if (!gpio_is_valid(spi->cs_gpio)) + return; + + gpio_free(spi->cs_gpio); + spi->cs_gpio = -ENOENT; +} + static int setup_cs(struct spi_device *spi, struct chip_data *chip, struct pxa2xx_spi_chip *chip_info) { - struct gpio_desc *gpiod; - int err = 0; + struct driver_data *drv_data = spi_controller_get_devdata(spi->controller); if (chip == NULL) return 0; @@ -1207,13 +1205,13 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip, if (chip_info == NULL) return 0; + if (drv_data->ssp_type == CE4100_SSP) + return 0; + /* NOTE: setup() can be called multiple times, possibly with * different chip_info, release previously requested GPIO */ - if (chip->gpiod_cs) { - gpiod_put(chip->gpiod_cs); - chip->gpiod_cs = NULL; - } + cleanup_cs(spi); /* If (*cs_control) is provided, ignore GPIO chip select */ if (chip_info->cs_control) { @@ -1222,21 +1220,25 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip, } if (gpio_is_valid(chip_info->gpio_cs)) { - err = gpio_request(chip_info->gpio_cs, "SPI_CS"); + int gpio = chip_info->gpio_cs; + int err; + + err = gpio_request(gpio, "SPI_CS"); if (err) { - dev_err(&spi->dev, "failed to request chip select GPIO%d\n", - chip_info->gpio_cs); + dev_err(&spi->dev, "failed to request chip select GPIO%d\n", gpio); return err; } - gpiod = gpio_to_desc(chip_info->gpio_cs); - chip->gpiod_cs = gpiod; - chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH; + err = gpio_direction_output(gpio, !(spi->mode & SPI_CS_HIGH)); + if (err) { + gpio_free(gpio); + return err; + } - err = gpiod_direction_output(gpiod, !chip->gpio_cs_inverted); + spi->cs_gpio = gpio; } - return err; + return 0; } static int setup(struct spi_device *spi) @@ -1411,15 +1413,8 @@ static int setup(struct spi_device *spi) static void cleanup(struct spi_device *spi) { struct chip_data *chip = spi_get_ctldata(spi); - struct driver_data *drv_data = - spi_controller_get_devdata(spi->controller); - - if (!chip) - return; - - if (drv_data->ssp_type != CE4100_SSP && chip->gpiod_cs) - gpiod_put(chip->gpiod_cs); + cleanup_cs(spi); kfree(chip); } diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 672dfd4863cc..a91fe6edb275 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -62,19 +62,17 @@ struct chip_data { u32 dds_rate; u32 timeout; u8 n_bytes; + u8 enable_dma; u32 dma_burst_size; - u32 threshold; u32 dma_threshold; + u32 threshold; u16 lpss_rx_threshold; u16 lpss_tx_threshold; - u8 enable_dma; - union { - struct gpio_desc *gpiod_cs; - unsigned int frm; - }; - int gpio_cs_inverted; + int (*write)(struct driver_data *drv_data); int (*read)(struct driver_data *drv_data); + + unsigned int frm; void (*cs_control)(u32 command); }; From ccd60b2030a04b91977d9fee9e0ec6469ac4cd1b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 May 2021 17:03:46 +0300 Subject: [PATCH 39/86] spi: pxa2xx: Drop duplicate chip_select in struct chip_data The struct chip_data had been introduced in order to keep the parameters that may be provided on stack during device allocation. There is no need to duplicate parameters there, which are carried on by SPI device itself. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210517140351.901-5-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 4 +--- drivers/spi/spi-pxa2xx.h | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 1a0bcd3bac1f..fb80f6013d54 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -432,7 +432,7 @@ static void cs_assert(struct spi_device *spi) spi_controller_get_devdata(spi->controller); if (drv_data->ssp_type == CE4100_SSP) { - pxa2xx_spi_write(drv_data, SSSR, chip->frm); + pxa2xx_spi_write(drv_data, SSSR, spi->chip_select); return; } @@ -1303,8 +1303,6 @@ static int setup(struct spi_device *spi) kfree(chip); return -EINVAL; } - - chip->frm = spi->chip_select; } chip->enable_dma = drv_data->controller_info->enable_dma; chip->timeout = TIMOUT_DFLT; diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index a91fe6edb275..db9de46110ad 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -72,7 +72,6 @@ struct chip_data { int (*write)(struct driver_data *drv_data); int (*read)(struct driver_data *drv_data); - unsigned int frm; void (*cs_control)(u32 command); }; From eb743ec600be596553bf4e42c85b0bbc65083791 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 May 2021 17:03:47 +0300 Subject: [PATCH 40/86] spi: pxa2xx: Drop unneeded '!= 0' comparisons In the few places it's redundant to compare against 0. Drop the unneeded comparisons. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210517140351.901-6-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index fb80f6013d54..f24851b3c020 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1380,8 +1380,8 @@ static int setup(struct spi_device *spi) } chip->cr1 &= ~(SSCR1_SPO | SSCR1_SPH); - chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0) - | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0); + chip->cr1 |= ((spi->mode & SPI_CPHA) ? SSCR1_SPH : 0) | + ((spi->mode & SPI_CPOL) ? SSCR1_SPO : 0); if (spi->mode & SPI_LOOP) chip->cr1 |= SSCR1_LBM; @@ -1859,7 +1859,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) /* Register with the SPI framework */ platform_set_drvdata(pdev, drv_data); status = spi_register_controller(controller); - if (status != 0) { + if (status) { dev_err(&pdev->dev, "problem registering spi controller\n"); goto out_error_pm_runtime_enabled; } @@ -1918,7 +1918,7 @@ static int pxa2xx_spi_suspend(struct device *dev) int status; status = spi_controller_suspend(drv_data->controller); - if (status != 0) + if (status) return status; pxa_ssp_disable(ssp); From 684a3ac720c3fd4c09ae5aa3d349861bf12dcff6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 May 2021 17:03:48 +0300 Subject: [PATCH 41/86] spi: pxa2xx: Fix printf() specifiers Instead of explicit casting use proper specifier in one case, and fix specifier signness in another. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210517140351.901-7-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index f24851b3c020..f8264771b360 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -983,8 +983,8 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, /* warn ... we force this to PIO mode */ dev_warn_ratelimited(&spi->dev, - "DMA disabled for transfer length %ld greater than %d\n", - (long)transfer->len, MAX_DMA_LEN); + "DMA disabled for transfer length %u greater than %d\n", + transfer->len, MAX_DMA_LEN); } /* Setup the transfer state based on the type of transfer */ @@ -1115,8 +1115,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, if (tx_level) { /* On MMP2, flipping SSE doesn't to empty TXFIFO. */ - dev_warn(&spi->dev, "%d bytes of garbage in TXFIFO!\n", - tx_level); + dev_warn(&spi->dev, "%u bytes of garbage in Tx FIFO!\n", tx_level); if (tx_level > transfer->len) tx_level = transfer->len; drv_data->tx += tx_level; From 8083d6b812cac5e38db9c707b41cd478beed4a0c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 May 2021 17:03:49 +0300 Subject: [PATCH 42/86] spi: pxa2xx: Fix style of and typos in the comments and messages Fix style of the comments and messages along with typos in them. While at it, update Intel Copyright year. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210517140351.901-8-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-dma.c | 4 +- drivers/spi/spi-pxa2xx-pci.c | 5 ++- drivers/spi/spi-pxa2xx.c | 71 ++++++++++++++++++---------------- drivers/spi/spi-pxa2xx.h | 2 +- include/linux/pxa2xx_ssp.h | 9 +++-- include/linux/spi/pxa2xx_spi.h | 12 ++++-- 6 files changed, 58 insertions(+), 45 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index f022d82dcb1b..be563f0dd03a 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -2,7 +2,7 @@ /* * PXA2xx SPI DMA engine support. * - * Copyright (C) 2013, Intel Corporation + * Copyright (C) 2013, 2021 Intel Corporation * Author: Mika Westerberg */ @@ -26,7 +26,7 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, * It is possible that one CPU is handling ROR interrupt and other * just gets DMA completion. Calling pump_transfers() twice for the * same transfer leads to problems thus we prevent concurrent calls - * by using ->dma_running. + * by using dma_running. */ if (atomic_dec_and_test(&drv_data->dma_running)) { /* diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index dce9ade9a4df..9c9992d4f547 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * CE4100's SPI device is more or less the same one as found on PXA + * PCI glue driver for SPI PXA2xx compatible controllers. + * CE4100's SPI device is more or less the same one as found on PXA. * - * Copyright (C) 2016, Intel Corporation + * Copyright (C) 2016, 2021 Intel Corporation */ #include #include diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index f8264771b360..94b1585de203 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs - * Copyright (C) 2013, Intel Corporation + * Copyright (C) 2013, 2021 Intel Corporation */ #include @@ -40,11 +40,11 @@ MODULE_ALIAS("platform:pxa2xx-spi"); #define TIMOUT_DFLT 1000 /* - * for testing SSCR1 changes that require SSP restart, basically - * everything except the service and interrupt enables, the pxa270 developer + * For testing SSCR1 changes that require SSP restart, basically + * everything except the service and interrupt enables, the PXA270 developer * manual says only SSCR1_SCFR, SSCR1_SPH, SSCR1_SPO need to be in this - * list, but the PXA255 dev man says all bits without really meaning the - * service and interrupt enables + * list, but the PXA255 developer manual says all bits without really meaning + * the service and interrupt enables. */ #define SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_SCFR \ | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \ @@ -653,12 +653,12 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) irq_status &= ~SSSR_TFS; if (irq_status & SSSR_ROR) { - int_error_stop(drv_data, "interrupt_transfer: fifo overrun", -EIO); + int_error_stop(drv_data, "interrupt_transfer: FIFO overrun", -EIO); return IRQ_HANDLED; } if (irq_status & SSSR_TUR) { - int_error_stop(drv_data, "interrupt_transfer: fifo underrun", -EIO); + int_error_stop(drv_data, "interrupt_transfer: FIFO underrun", -EIO); return IRQ_HANDLED; } @@ -670,7 +670,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) } } - /* Drain rx fifo, Fill tx fifo and prevent overruns */ + /* Drain Rx FIFO, Fill Tx FIFO and prevent overruns */ do { if (drv_data->read(drv_data)) { int_transfer_complete(drv_data); @@ -691,8 +691,8 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) sccr1_reg &= ~SSCR1_TIE; /* - * PXA25x_SSP has no timeout, set up rx threshould for the - * remaining RX bytes. + * PXA25x_SSP has no timeout, set up Rx threshold for + * the remaining Rx bytes. */ if (pxa25x_ssp_comp(drv_data)) { u32 rx_thre; @@ -914,7 +914,7 @@ static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate) /* * Calculate the divisor for the SCR (Serial Clock Rate), avoiding - * that the SSP transmission rate can be greater than the device rate + * that the SSP transmission rate can be greater than the device rate. */ if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP) return (DIV_ROUND_UP(ssp_clk, 2 * rate) - 1) & 0xff; @@ -972,7 +972,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, /* Check if we can DMA this transfer */ if (transfer->len > MAX_DMA_LEN && chip->enable_dma) { - /* reject already-mapped transfers; PIO won't always work */ + /* Reject already-mapped transfers; PIO won't always work */ if (message->is_dma_mapped || transfer->rx_dma || transfer->tx_dma) { dev_err(&spi->dev, @@ -981,7 +981,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, return -EINVAL; } - /* warn ... we force this to PIO mode */ + /* Warn ... we force this to PIO mode */ dev_warn_ratelimited(&spi->dev, "DMA disabled for transfer length %u greater than %d\n", transfer->len, MAX_DMA_LEN); @@ -1026,8 +1026,8 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, u32_writer : null_writer; } /* - * if bits/word is changed in dma mode, then must check the - * thresholds and burst also + * If bits per word is changed in DMA mode, then must check + * the thresholds and burst also. */ if (chip->enable_dma) { if (pxa2xx_spi_set_dma_burst_and_threshold(chip, @@ -1101,10 +1101,10 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, if (!pxa25x_ssp_comp(drv_data)) pxa2xx_spi_write(drv_data, SSTO, chip->timeout); - /* first set CR1 without interrupt and service enables */ + /* First set CR1 without interrupt and service enables */ pxa2xx_spi_update(drv_data, SSCR1, change_mask, cr1); - /* see if we need to reload the config registers */ + /* See if we need to reload the configuration registers */ pxa2xx_spi_update(drv_data, SSCR0, GENMASK(31, 0), cr0); /* Restart the SSP */ @@ -1114,7 +1114,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, u8 tx_level = read_SSSR_bits(drv_data, SSSR_TFL_MASK) >> 8; if (tx_level) { - /* On MMP2, flipping SSE doesn't to empty TXFIFO. */ + /* On MMP2, flipping SSE doesn't to empty Tx FIFO. */ dev_warn(&spi->dev, "%u bytes of garbage in Tx FIFO!\n", tx_level); if (tx_level > transfer->len) tx_level = transfer->len; @@ -1134,7 +1134,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, /* * Release the data by enabling service requests and interrupts, - * without changing any mode bits + * without changing any mode bits. */ pxa2xx_spi_write(drv_data, SSCR1, cr1); @@ -1207,12 +1207,13 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip, if (drv_data->ssp_type == CE4100_SSP) return 0; - /* NOTE: setup() can be called multiple times, possibly with - * different chip_info, release previously requested GPIO + /* + * NOTE: setup() can be called multiple times, possibly with + * different chip_info, release previously requested GPIO. */ cleanup_cs(spi); - /* If (*cs_control) is provided, ignore GPIO chip select */ + /* If ->cs_control() is provided, ignore GPIO chip select */ if (chip_info->cs_control) { chip->cs_control = chip_info->cs_control; return 0; @@ -1288,7 +1289,7 @@ static int setup(struct spi_device *spi) break; } - /* Only alloc on first setup */ + /* Only allocate on the first setup */ chip = spi_get_ctldata(spi); if (!chip) { chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); @@ -1307,8 +1308,10 @@ static int setup(struct spi_device *spi) chip->timeout = TIMOUT_DFLT; } - /* protocol drivers may change the chip settings, so... - * if chip_info exists, use it */ + /* + * Protocol drivers may change the chip settings, so... + * if chip_info exists, use it. + */ chip_info = spi->controller_data; /* chip_info isn't always needed */ @@ -1344,11 +1347,13 @@ static int setup(struct spi_device *spi) chip->lpss_tx_threshold = tx_thres; } - /* set dma burst and threshold outside of chip_info path so that if - * chip_info goes away after setting chip->enable_dma, the - * burst and threshold can still respond to changes in bits_per_word */ + /* + * Set DMA burst and threshold outside of chip_info path so that if + * chip_info goes away after setting chip->enable_dma, the burst and + * threshold can still respond to changes in bits_per_word. + */ if (chip->enable_dma) { - /* set up legal burst and threshold for dma */ + /* Set up legal burst and threshold for DMA */ if (pxa2xx_spi_set_dma_burst_and_threshold(chip, spi, spi->bits_per_word, &chip->dma_burst_size, @@ -1677,7 +1682,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) ssp = &platform_info->ssp; if (!ssp->mmio_base) { - dev_err(&pdev->dev, "failed to get ssp\n"); + dev_err(&pdev->dev, "failed to get SSP\n"); return -ENODEV; } @@ -1699,7 +1704,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) controller->dev.of_node = dev->of_node; controller->dev.fwnode = dev->fwnode; - /* the spi->mode bits understood by this driver: */ + /* The spi->mode bits understood by this driver: */ controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; controller->bus_num = ssp->port_id; @@ -1787,7 +1792,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) QUARK_X1000_SSCR1_TxTresh(TX_THRESH_QUARK_X1000_DFLT); pxa2xx_spi_write(drv_data, SSCR1, tmp); - /* using the Motorola SPI protocol and use 8 bit frame */ + /* Using the Motorola SPI protocol and use 8 bit frame */ tmp = QUARK_X1000_SSCR0_Motorola | QUARK_X1000_SSCR0_DataSize(8); pxa2xx_spi_write(drv_data, SSCR0, tmp); break; @@ -1859,7 +1864,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, drv_data); status = spi_register_controller(controller); if (status) { - dev_err(&pdev->dev, "problem registering spi controller\n"); + dev_err(&pdev->dev, "problem registering SPI controller\n"); goto out_error_pm_runtime_enabled; } diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index db9de46110ad..9a20fb88e50f 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs - * Copyright (C) 2013, Intel Corporation + * Copyright (C) 2013, 2021 Intel Corporation */ #ifndef SPI_PXA2XX_H diff --git a/include/linux/pxa2xx_ssp.h b/include/linux/pxa2xx_ssp.h index 2b21bc1f3c73..a3fec2de512f 100644 --- a/include/linux/pxa2xx_ssp.h +++ b/include/linux/pxa2xx_ssp.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (C) 2003 Russell King, All Rights Reserved. + * Copyright (C) 2003 Russell King, All Rights Reserved. * * This driver supports the following PXA CPU/SSP ports:- * @@ -59,7 +59,7 @@ struct device_node; /* PXA27x, PXA3xx */ #define SSCR0_EDSS BIT(20) /* Extended data size select */ #define SSCR0_NCS BIT(21) /* Network clock select */ -#define SSCR0_RIM BIT(22) /* Receive FIFO overrrun interrupt mask */ +#define SSCR0_RIM BIT(22) /* Receive FIFO overrun interrupt mask */ #define SSCR0_TUM BIT(23) /* Transmit FIFO underrun interrupt mask */ #define SSCR0_FRDC GENMASK(26, 24) /* Frame rate divider control (mask) */ #define SSCR0_SlotsPerFrm(x) (((x) - 1) << 24) /* Time slots per frame [1..8] */ @@ -126,7 +126,7 @@ struct device_node; #define QUARK_X1000_SSCR1_EFWR BIT(16) /* Enable FIFO Write/Read */ #define QUARK_X1000_SSCR1_STRF BIT(17) /* Select FIFO or EFWR */ -/* extra bits in PXA255, PXA26x and PXA27x SSP ports */ +/* Extra bits in PXA255, PXA26x and PXA27x SSP ports */ #define SSCR0_TISSP (1 << 4) /* TI Sync Serial Protocol */ #define SSCR0_PSP (3 << 4) /* PSP - Programmable Serial Protocol */ @@ -222,7 +222,8 @@ enum pxa_ssp_type { CE4100_SSP, MRFLD_SSP, QUARK_X1000_SSP, - LPSS_LPT_SSP, /* Keep LPSS types sorted with lpss_platforms[] */ + /* Keep LPSS types sorted with lpss_platforms[] */ + LPSS_LPT_SSP, LPSS_BYT_SSP, LPSS_BSW_SSP, LPSS_SPT_SSP, diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h index 12ef04d0896d..eaab121ee575 100644 --- a/include/linux/spi/pxa2xx_spi.h +++ b/include/linux/spi/pxa2xx_spi.h @@ -14,7 +14,10 @@ struct dma_chan; -/* device.platform_data for SSP controller devices */ +/* + * The platform data for SSP controller devices + * (resides in device.platform_data). + */ struct pxa2xx_spi_controller { u16 num_chipselect; u8 enable_dma; @@ -30,8 +33,11 @@ struct pxa2xx_spi_controller { struct ssp_device ssp; }; -/* spi_board_info.controller_data for SPI slave devices, - * copied to spi_device.platform_data ... mostly for dma tuning +/* + * The controller specific data for SPI slave devices + * (resides in spi_board_info.controller_data), + * copied to spi_device.platform_data ... mostly for + * DMA tuning. */ struct pxa2xx_spi_chip { u8 tx_threshold; From f96e6c0ef63b981d295547ef624f4da7c820e097 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 May 2021 17:03:50 +0300 Subject: [PATCH 43/86] spi: pxa2xx: Update documentation to point out that it's outdated Update documentation by pointing out that it's applicable mostly for a legacy platform. While at it, add couple of points with regard to ACPI, Device Tree, and automatic DMA enablement. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210517140351.901-9-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- Documentation/spi/pxa2xx.rst | 58 ++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/Documentation/spi/pxa2xx.rst b/Documentation/spi/pxa2xx.rst index 882d3cc72cc2..6312968acfe9 100644 --- a/Documentation/spi/pxa2xx.rst +++ b/Documentation/spi/pxa2xx.rst @@ -2,43 +2,47 @@ PXA2xx SPI on SSP driver HOWTO ============================== -This a mini howto on the pxa2xx_spi driver. The driver turns a PXA2xx -synchronous serial port into a SPI master controller +This a mini HOWTO on the pxa2xx_spi driver. The driver turns a PXA2xx +synchronous serial port into an SPI master controller (see Documentation/spi/spi-summary.rst). The driver has the following features -- Support for any PXA2xx SSP +- Support for any PXA2xx and compatible SSP. - SSP PIO and SSP DMA data transfers. - External and Internal (SSPFRM) chip selects. - Per slave device (chip) configuration. - Full suspend, freeze, resume support. -The driver is built around a "spi_message" fifo serviced by workqueue and a -tasklet. The workqueue, "pump_messages", drives message fifo and the tasklet -(pump_transfer) is responsible for queuing SPI transactions and setting up and -launching the dma/interrupt driven transfers. +The driver is built around a &struct spi_message FIFO serviced by kernel +thread. The kernel thread, spi_pump_messages(), drives message FIFO and +is responsible for queuing SPI transactions and setting up and launching +the DMA or interrupt driven transfers. Declaring PXA2xx Master Controllers ----------------------------------- -Typically a SPI master is defined in the arch/.../mach-*/board-*.c as a -"platform device". The master configuration is passed to the driver via a table -found in include/linux/spi/pxa2xx_spi.h:: +Typically, for a legacy platform, an SPI master is defined in the +arch/.../mach-*/board-*.c as a "platform device". The master configuration +is passed to the driver via a table found in include/linux/spi/pxa2xx_spi.h:: struct pxa2xx_spi_controller { u16 num_chipselect; u8 enable_dma; + ... }; The "pxa2xx_spi_controller.num_chipselect" field is used to determine the number of slave device (chips) attached to this SPI master. The "pxa2xx_spi_controller.enable_dma" field informs the driver that SSP DMA should -be used. This caused the driver to acquire two DMA channels: rx_channel and -tx_channel. The rx_channel has a higher DMA service priority the tx_channel. +be used. This caused the driver to acquire two DMA channels: Rx channel and +Tx channel. The Rx channel has a higher DMA service priority than the Tx channel. See the "PXA2xx Developer Manual" section "DMA Controller". +For the new platforms the description of the controller and peripheral devices +comes from Device Tree or ACPI. + NSSP MASTER SAMPLE ------------------ -Below is a sample configuration using the PXA255 NSSP:: +Below is a sample configuration using the PXA255 NSSP for a legacy platform:: static struct resource pxa_spi_nssp_resources[] = { [0] = { @@ -79,9 +83,10 @@ Below is a sample configuration using the PXA255 NSSP:: Declaring Slave Devices ----------------------- -Typically each SPI slave (chip) is defined in the arch/.../mach-*/board-*.c -using the "spi_board_info" structure found in "linux/spi/spi.h". See -"Documentation/spi/spi-summary.rst" for additional information. +Typically, for a legacy platform, each SPI slave (chip) is defined in the +arch/.../mach-*/board-*.c using the "spi_board_info" structure found in +"linux/spi/spi.h". See "Documentation/spi/spi-summary.rst" for additional +information. Each slave device attached to the PXA must provide slave specific configuration information via the structure "pxa2xx_spi_chip" found in @@ -101,9 +106,9 @@ device. All fields are optional. }; The "pxa2xx_spi_chip.tx_threshold" and "pxa2xx_spi_chip.rx_threshold" fields are -used to configure the SSP hardware fifo. These fields are critical to the +used to configure the SSP hardware FIFO. These fields are critical to the performance of pxa2xx_spi driver and misconfiguration will result in rx -fifo overruns (especially in PIO mode transfers). Good default values are:: +FIFO overruns (especially in PIO mode transfers). Good default values are:: .tx_threshold = 8, .rx_threshold = 8, @@ -118,7 +123,7 @@ use a value of 8. The driver will determine a reasonable default if dma_burst_size == 0. The "pxa2xx_spi_chip.timeout" fields is used to efficiently handle -trailing bytes in the SSP receiver fifo. The correct value for this field is +trailing bytes in the SSP receiver FIFO. The correct value for this field is dependent on the SPI bus speed ("spi_board_info.max_speed_hz") and the specific slave device. Please note that the PXA2xx SSP 1 does not support trailing byte timeouts and must busy-wait any trailing bytes. @@ -131,19 +136,19 @@ testing. The "pxa2xx_spi_chip.cs_control" field is used to point to a board specific function for asserting/deasserting a slave device chip select. If the field is NULL, the pxa2xx_spi master controller driver assumes that the SSP port is -configured to use SSPFRM instead. +configured to use GPIO or SSPFRM instead. NOTE: the SPI driver cannot control the chip select if SSPFRM is used, so the chipselect is dropped after each spi_transfer. Most devices need chip select -asserted around the complete message. Use SSPFRM as a GPIO (through cs_control) +asserted around the complete message. Use SSPFRM as a GPIO (through a descriptor) to accommodate these chips. NSSP SLAVE SAMPLE ----------------- -The pxa2xx_spi_chip structure is passed to the pxa2xx_spi driver in the -"spi_board_info.controller_data" field. Below is a sample configuration using -the PXA255 NSSP. +For a legacy platform or in some other cases, the pxa2xx_spi_chip structure +is passed to the pxa2xx_spi driver in the "spi_board_info.controller_data" +field. Below is a sample configuration using the PXA255 NSSP. :: @@ -212,7 +217,9 @@ DMA and PIO I/O Support ----------------------- The pxa2xx_spi driver supports both DMA and interrupt driven PIO message transfers. The driver defaults to PIO mode and DMA transfers must be enabled -by setting the "enable_dma" flag in the "pxa2xx_spi_controller" structure. The DMA +by setting the "enable_dma" flag in the "pxa2xx_spi_controller" structure. +For the newer platforms, that are known to support DMA, the driver will enable +it automatically and try it first with a possible fallback to PIO. The DMA mode supports both coherent and stream based DMA mappings. The following logic is used to determine the type of I/O to be used on @@ -236,5 +243,4 @@ a per "spi_transfer" basis:: THANKS TO --------- - David Brownell and others for mentoring the development of this driver. From 70252440b2b6337d03f2b95bc475fedbea79072f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 May 2021 17:03:51 +0300 Subject: [PATCH 44/86] spi: pxa2xx: Use predefined mask when programming FIFO thresholds The predefined mask for threshold modification can be used in case of Intel Merrifield SPI. Replace open-coded value with predefined mask when programming FIFO thresholds. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210517140351.901-10-andriy.shevchenko@linux.intel.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 94b1585de203..bdf9a283efc3 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1083,12 +1083,13 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller, } if (is_mrfld_ssp(drv_data)) { + u32 mask = SFIFOTT_RFT | SFIFOTT_TFT; u32 thresh = 0; thresh |= SFIFOTT_RxThresh(chip->lpss_rx_threshold); thresh |= SFIFOTT_TxThresh(chip->lpss_tx_threshold); - pxa2xx_spi_update(drv_data, SFIFOTT, 0xffffffff, thresh); + pxa2xx_spi_update(drv_data, SFIFOTT, mask, thresh); } if (is_quark_x1000_ssp(drv_data)) From 6328caf043208556e782a53a284c9acfcf6be3b0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 May 2021 10:15:36 +0200 Subject: [PATCH 45/86] spi: fix some invalid char occurrences MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One of the author names got an invalid char, probably due to a bad charset conversion, being replaced by the REPLACEMENT CHARACTER U+fffd ('�'). Use the author's e-mail has the characters without accents, as also used at the .mailmap file. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/ff8d296e1fdcc4f1c6df94434a5720bcedcd0ecf.1621412009.git.mchehab+huawei@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 2 +- drivers/spi/spi-omap2-mcspi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 96490888e9f1..20b047172965 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -6,7 +6,7 @@ * * Copyright (C) 2005, 2006 Nokia Corporation * Author: Samuel Ortiz and - * Juha Yrj�l� + * Juha Yrjola */ #include #include diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 999c22736416..e24520e87cff 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -4,7 +4,7 @@ * * Copyright (C) 2005, 2006 Nokia Corporation * Author: Samuel Ortiz and - * Juha Yrj�l� + * Juha Yrjola */ #include From a2bd5afd59c1dec8e559096c3a5c912360c267ca Mon Sep 17 00:00:00 2001 From: Zhiqi Song Date: Tue, 18 May 2021 09:38:16 +0800 Subject: [PATCH 46/86] spi: lm70llp: add parenthesis for sizeof Fix missing parenthesis of sizeof reported by checkpatch.pl: WARNING: sizeof *pp should be sizeof(*pp). The kernel coding style suggests thinking of sizeof as a function and add parenthesis. Cc: Kaiwan N Billimoria Signed-off-by: Zhiqi Song Link: https://lore.kernel.org/r/1621301902-64158-2-git-send-email-songzhiqi1@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-lm70llp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-lm70llp.c b/drivers/spi/spi-lm70llp.c index f914b8d2043e..ead0507c63be 100644 --- a/drivers/spi/spi-lm70llp.c +++ b/drivers/spi/spi-lm70llp.c @@ -202,7 +202,7 @@ static void spi_lm70llp_attach(struct parport *p) * the lm70 driver could verify it, reading the manf ID. */ - master = spi_alloc_master(p->physport->dev, sizeof *pp); + master = spi_alloc_master(p->physport->dev, sizeof(*pp)); if (!master) { status = -ENOMEM; goto out_fail; From 722cb2b197e125d6816aac43ec2d411c7b22daa9 Mon Sep 17 00:00:00 2001 From: Zhiqi Song Date: Tue, 18 May 2021 09:38:17 +0800 Subject: [PATCH 47/86] spi: mpc512x-psc: add parenthesis for sizeof Fix missing parenthesis of sizeof reported by checkpatch.pl: WARNING: sizeof *pp should be sizeof(*pp). The kernel coding style suggests thinking of sizeof as a function and add parenthesis. Signed-off-by: Zhiqi Song Link: https://lore.kernel.org/r/1621301902-64158-3-git-send-email-songzhiqi1@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-mpc512x-psc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index ea1b07953d38..78a9bca8cc68 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -369,7 +369,7 @@ static int mpc512x_psc_spi_setup(struct spi_device *spi) return -EINVAL; if (!cs) { - cs = kzalloc(sizeof *cs, GFP_KERNEL); + cs = kzalloc(sizeof(*cs), GFP_KERNEL); if (!cs) return -ENOMEM; @@ -491,7 +491,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, void *tempp; struct clk *clk; - master = spi_alloc_master(dev, sizeof *mps); + master = spi_alloc_master(dev, sizeof(*mps)); if (master == NULL) return -ENOMEM; From ac7357ac769e3b4bd52e691f22d745c89126069f Mon Sep 17 00:00:00 2001 From: Zhiqi Song Date: Tue, 18 May 2021 09:38:18 +0800 Subject: [PATCH 48/86] spi: mpc52xx: add parenthesis for sizeof Fix missing parenthesis of sizeof reported by checkpatch.pl: WARNING: sizeof *pp should be sizeof(*pp). The kernel coding style suggests thinking of sizeof as a function and add parenthesis. Signed-off-by: Zhiqi Song Link: https://lore.kernel.org/r/1621301902-64158-4-git-send-email-songzhiqi1@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-mpc52xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index 124cba7213f1..51041526546d 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -415,7 +415,7 @@ static int mpc52xx_spi_probe(struct platform_device *op) } dev_dbg(&op->dev, "allocating spi_master struct\n"); - master = spi_alloc_master(&op->dev, sizeof *ms); + master = spi_alloc_master(&op->dev, sizeof(*ms)); if (!master) { rc = -ENOMEM; goto err_alloc; From 75d4c2d64b30c8583b82afdcc9dc4db2083dee5b Mon Sep 17 00:00:00 2001 From: Zhiqi Song Date: Tue, 18 May 2021 09:38:19 +0800 Subject: [PATCH 49/86] spi: mpc52xx-psc: add parenthesis for sizeof Fix missing parenthesis of sizeof reported by checkpatch.pl: WARNING: sizeof *pp should be sizeof(*pp). The kernel coding style suggests thinking of sizeof as a function and add parenthesis. Signed-off-by: Zhiqi Song Link: https://lore.kernel.org/r/1621301902-64158-5-git-send-email-songzhiqi1@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-mpc52xx-psc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c index 17935e71b02f..21ef5d481faf 100644 --- a/drivers/spi/spi-mpc52xx-psc.c +++ b/drivers/spi/spi-mpc52xx-psc.c @@ -265,7 +265,7 @@ static int mpc52xx_psc_spi_setup(struct spi_device *spi) return -EINVAL; if (!cs) { - cs = kzalloc(sizeof *cs, GFP_KERNEL); + cs = kzalloc(sizeof(*cs), GFP_KERNEL); if (!cs) return -ENOMEM; spi->controller_state = cs; @@ -365,7 +365,7 @@ static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, struct spi_master *master; int ret; - master = spi_alloc_master(dev, sizeof *mps); + master = spi_alloc_master(dev, sizeof(*mps)); if (master == NULL) return -ENOMEM; From 8267dc6d6889235e6dac21156cc9d6e5d5319d3b Mon Sep 17 00:00:00 2001 From: Zhiqi Song Date: Tue, 18 May 2021 09:38:20 +0800 Subject: [PATCH 50/86] spi: omap2-mcspi: add parenthesis for sizeof Fix missing parenthesis of sizeof reported by checkpatch.pl: WARNING: sizeof *pp should be sizeof(*pp). The kernel coding style suggests thinking of sizeof as a function and add parenthesis. Signed-off-by: Zhiqi Song Link: https://lore.kernel.org/r/1621301902-64158-6-git-send-email-songzhiqi1@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 999c22736416..a06c8f499c51 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1040,7 +1040,7 @@ static int omap2_mcspi_setup(struct spi_device *spi) struct omap2_mcspi_cs *cs = spi->controller_state; if (!cs) { - cs = kzalloc(sizeof *cs, GFP_KERNEL); + cs = kzalloc(sizeof(*cs), GFP_KERNEL); if (!cs) return -ENOMEM; cs->base = mcspi->base + spi->chip_select * 0x14; From 19bae51b0191129fd9a6d163678404b77cab24c9 Mon Sep 17 00:00:00 2001 From: Zhiqi Song Date: Tue, 18 May 2021 09:38:21 +0800 Subject: [PATCH 51/86] spi: omap-uwire: add parenthesis for sizeof Fix missing parenthesis of sizeof reported by checkpatch.pl: WARNING: sizeof *pp should be sizeof(*pp). The kernel coding style suggests thinking of sizeof as a function and add parenthesis. Signed-off-by: Zhiqi Song Link: https://lore.kernel.org/r/1621301902-64158-7-git-send-email-songzhiqi1@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-omap-uwire.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index ceb479f5c88f..c975e8640560 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -453,7 +453,7 @@ static int uwire_probe(struct platform_device *pdev) struct uwire_spi *uwire; int status; - master = spi_alloc_master(&pdev->dev, sizeof *uwire); + master = spi_alloc_master(&pdev->dev, sizeof(*uwire)); if (!master) return -ENODEV; From 07c74f844b740a858e40fe6c15dd9a2f3b7f6476 Mon Sep 17 00:00:00 2001 From: Zhiqi Song Date: Tue, 18 May 2021 09:38:22 +0800 Subject: [PATCH 52/86] spi: ppc4xx: add parenthesis for sizeof Fix missing parenthesis of sizeof reported by checkpatch.pl: WARNING: sizeof *pp should be sizeof(*pp). The kernel coding style suggests thinking of sizeof as a function and add parenthesis. Signed-off-by: Zhiqi Song Link: https://lore.kernel.org/r/1621301902-64158-8-git-send-email-songzhiqi1@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-ppc4xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 59d201acbb39..d65f047b6c82 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -223,7 +223,7 @@ static int spi_ppc4xx_setup(struct spi_device *spi) } if (cs == NULL) { - cs = kzalloc(sizeof *cs, GFP_KERNEL); + cs = kzalloc(sizeof(*cs), GFP_KERNEL); if (!cs) return -ENOMEM; spi->controller_state = cs; @@ -349,7 +349,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) int ret; const unsigned int *clk; - master = spi_alloc_master(dev, sizeof *hw); + master = spi_alloc_master(dev, sizeof(*hw)); if (master == NULL) return -ENOMEM; master->dev.of_node = np; From dbfac814bb73624613f47d6e70391053ab6b8960 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Fri, 21 May 2021 17:47:45 +0800 Subject: [PATCH 53/86] spi: pxa2xx: Fix inconsistent indenting Eliminate the follow smatch warning: drivers/spi/spi-pxa2xx-pci.c:260 pxa2xx_spi_pci_probe() warn: inconsistent indenting. Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/1621590465-73594-1-git-send-email-jiapeng.chong@linux.alibaba.com Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 9c9992d4f547..2e134eb4bd2c 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -257,7 +257,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id); ssp->clk = clk_register_fixed_rate(&dev->dev, buf, NULL, 0, c->max_clk_rate); - if (IS_ERR(ssp->clk)) + if (IS_ERR(ssp->clk)) return PTR_ERR(ssp->clk); memset(&pi, 0, sizeof(pi)); From 42a7dfa26fc6df1624d7c2955200e5053dd0b818 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Sat, 22 May 2021 09:44:52 +0200 Subject: [PATCH 54/86] spi: ath79: drop platform data The ath79 platform has been converted to pure OF. The platform data is not needed anymore because of this. Signed-off-by: David Bauer Link: https://lore.kernel.org/r/20210522074453.39299-1-mail@david-bauer.net Signed-off-by: Mark Brown --- drivers/spi/spi-ath79.c | 8 -------- include/linux/platform_data/spi-ath79.h | 16 ---------------- 2 files changed, 24 deletions(-) delete mode 100644 include/linux/platform_data/spi-ath79.h diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index 98ace748cd98..497d5c028496 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -19,7 +19,6 @@ #include #include #include -#include #define DRV_NAME "ath79-spi" @@ -138,7 +137,6 @@ static int ath79_spi_probe(struct platform_device *pdev) { struct spi_master *master; struct ath79_spi *sp; - struct ath79_spi_platform_data *pdata; unsigned long rate; int ret; @@ -152,15 +150,9 @@ static int ath79_spi_probe(struct platform_device *pdev) master->dev.of_node = pdev->dev.of_node; platform_set_drvdata(pdev, sp); - pdata = dev_get_platdata(&pdev->dev); - master->use_gpio_descriptors = true; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); master->flags = SPI_MASTER_GPIO_SS; - if (pdata) { - master->bus_num = pdata->bus_num; - master->num_chipselect = pdata->num_chipselect; - } sp->bitbang.master = master; sp->bitbang.chipselect = ath79_spi_chipselect; diff --git a/include/linux/platform_data/spi-ath79.h b/include/linux/platform_data/spi-ath79.h deleted file mode 100644 index 81a388ff58cc..000000000000 --- a/include/linux/platform_data/spi-ath79.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Platform data definition for Atheros AR71XX/AR724X/AR913X SPI controller - * - * Copyright (C) 2008-2010 Gabor Juhos - */ - -#ifndef _ATH79_SPI_PLATFORM_H -#define _ATH79_SPI_PLATFORM_H - -struct ath79_spi_platform_data { - unsigned bus_num; - unsigned num_chipselect; -}; - -#endif /* _ATH79_SPI_PLATFORM_H */ From ab053f48f9264ed5c714d0427b3115f121d4c476 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Sat, 22 May 2021 09:44:53 +0200 Subject: [PATCH 55/86] spi: ath79: set number of chipselect lines All chipsets from AR7100 up to QCA9563 have three dedicated chipselect lines for the integrated SPI controller. Set the number of chipselect lines available on the controller to this value. Signed-off-by: David Bauer Link: https://lore.kernel.org/r/20210522074453.39299-2-mail@david-bauer.net Signed-off-by: Mark Brown --- drivers/spi/spi-ath79.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index 497d5c028496..d1e287d2d9cd 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -153,6 +153,7 @@ static int ath79_spi_probe(struct platform_device *pdev) master->use_gpio_descriptors = true; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); master->flags = SPI_MASTER_GPIO_SS; + master->num_chipselect = 3; sp->bitbang.master = master; sp->bitbang.chipselect = ath79_spi_chipselect; From 5cb4e1f33e5eeadbce3814282e010d4dd31816af Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 26 May 2021 22:56:55 +0300 Subject: [PATCH 56/86] spi: Enable tracing of the SPI setup CS selection It is helpful to see what state of CS signal was during one or another SPI operation. All the same for SPI setup. Enable tracing of the SPI setup and CS selection. Signed-off-by: Andy Shevchenko Message-Id: <20210526195655.75691-1-andriy.shevchenko@linux.intel.com> Signed-off-by: Mark Brown --- drivers/spi/spi.c | 4 +++ include/trace/events/spi.h | 57 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 956dce3aafca..20932752a7ef 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -804,6 +804,8 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force) (spi->controller->last_cs_mode_high == (spi->mode & SPI_CS_HIGH))) return; + trace_spi_set_cs(spi, activate); + spi->controller->last_cs_enable = enable; spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH; @@ -3441,6 +3443,8 @@ int spi_setup(struct spi_device *spi) spi_set_thread_rt(spi->controller); } + trace_spi_setup(spi, status); + dev_dbg(&spi->dev, "setup mode %lu, %s%s%s%s%u bits/w, %u Hz max --> %d\n", spi->mode & SPI_MODE_X_MASK, (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "", diff --git a/include/trace/events/spi.h b/include/trace/events/spi.h index 0dd9171d2ad8..c0d9844befd7 100644 --- a/include/trace/events/spi.h +++ b/include/trace/events/spi.h @@ -42,6 +42,63 @@ DEFINE_EVENT(spi_controller, spi_controller_busy, ); +TRACE_EVENT(spi_setup, + TP_PROTO(struct spi_device *spi, int status), + TP_ARGS(spi, status), + + TP_STRUCT__entry( + __field(int, bus_num) + __field(int, chip_select) + __field(unsigned long, mode) + __field(unsigned int, bits_per_word) + __field(unsigned int, max_speed_hz) + __field(int, status) + ), + + TP_fast_assign( + __entry->bus_num = spi->controller->bus_num; + __entry->chip_select = spi->chip_select; + __entry->mode = spi->mode; + __entry->bits_per_word = spi->bits_per_word; + __entry->max_speed_hz = spi->max_speed_hz; + __entry->status = status; + ), + + TP_printk("spi%d.%d setup mode %lu, %s%s%s%s%u bits/w, %u Hz max --> %d", + __entry->bus_num, __entry->chip_select, + (__entry->mode & SPI_MODE_X_MASK), + (__entry->mode & SPI_CS_HIGH) ? "cs_high, " : "", + (__entry->mode & SPI_LSB_FIRST) ? "lsb, " : "", + (__entry->mode & SPI_3WIRE) ? "3wire, " : "", + (__entry->mode & SPI_LOOP) ? "loopback, " : "", + __entry->bits_per_word, __entry->max_speed_hz, + __entry->status) +); + +TRACE_EVENT(spi_set_cs, + TP_PROTO(struct spi_device *spi, bool enable), + TP_ARGS(spi, enable), + + TP_STRUCT__entry( + __field(int, bus_num) + __field(int, chip_select) + __field(unsigned long, mode) + __field(bool, enable) + ), + + TP_fast_assign( + __entry->bus_num = spi->controller->bus_num; + __entry->chip_select = spi->chip_select; + __entry->mode = spi->mode; + __entry->enable = enable; + ), + + TP_printk("spi%d.%d %s%s", + __entry->bus_num, __entry->chip_select, + __entry->enable ? "activate" : "deactivate", + (__entry->mode & SPI_CS_HIGH) ? ", cs_high" : "") +); + DECLARE_EVENT_CLASS(spi_message, TP_PROTO(struct spi_message *msg), From ec679bda639fe84b78d473526ae27c74dea383fb Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Thu, 27 May 2021 23:32:00 +0200 Subject: [PATCH 57/86] spi: bcm2835: Allow arbitrary number of slaves Since commit 571e31fa60b3 ("spi: bcm2835: Cache CS register value for ->prepare_message()"), the number of slaves has been limited by a compile-time constant. This was necessitated by statically-sized arrays in the driver private data which contain per-slave register values. As suggested by Mark, move those register values to a per-slave controller_state which is allocated on ->setup and freed on ->cleanup. The limitation on the number of slaves is thus lifted. Signed-off-by: Lukas Wunner Cc: Joe Burmeister Cc: Phil Elwell Link: https://lore.kernel.org/r/a847c01f09400801e74e0630bf5a0197591554da.1622150204.git.lukas@wunner.de Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835.c | 204 ++++++++++++++++++++++---------------- 1 file changed, 119 insertions(+), 85 deletions(-) diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index fe40626e45aa..5f8771fe1a31 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -68,7 +68,6 @@ #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 24 /* raise as necessary */ #define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ | SPI_NO_CS | SPI_3WIRE) @@ -96,8 +95,6 @@ MODULE_PARM_DESC(polling_limit_us, * @rx_prologue: bytes received without DMA if first RX sglist entry's * length is not a multiple of 4 (to overcome hardware limitation) * @tx_spillover: whether @tx_prologue spills over to second TX sglist entry - * @prepare_cs: precalculated CS register value for ->prepare_message() - * (uses slave-specific clock polarity and phase settings) * @debugfs_dir: the debugfs directory - neede to remove debugfs when * unloading the module * @count_transfer_polling: count of how often polling mode is used @@ -107,7 +104,7 @@ MODULE_PARM_DESC(polling_limit_us, * These are counted as well in @count_transfer_polling and * @count_transfer_irq * @count_transfer_dma: count how often dma mode is used - * @chip_select: SPI slave currently selected + * @slv: SPI slave currently selected * (used by bcm2835_spi_dma_tx_done() to write @clear_rx_cs) * @tx_dma_active: whether a TX DMA descriptor is in progress * @rx_dma_active: whether a RX DMA descriptor is in progress @@ -115,11 +112,6 @@ MODULE_PARM_DESC(polling_limit_us, * @fill_tx_desc: preallocated TX DMA descriptor used for RX-only transfers * (cyclically copies from zero page to TX FIFO) * @fill_tx_addr: bus address of zero page - * @clear_rx_desc: preallocated RX DMA descriptor used for TX-only transfers - * (cyclically clears RX FIFO by writing @clear_rx_cs to CS register) - * @clear_rx_addr: bus address of @clear_rx_cs - * @clear_rx_cs: precalculated CS register value to clear RX FIFO - * (uses slave-specific clock polarity and phase settings) */ struct bcm2835_spi { void __iomem *regs; @@ -134,7 +126,6 @@ struct bcm2835_spi { int tx_prologue; int rx_prologue; unsigned int tx_spillover; - u32 prepare_cs[BCM2835_SPI_NUM_CS]; struct dentry *debugfs_dir; u64 count_transfer_polling; @@ -142,14 +133,28 @@ struct bcm2835_spi { u64 count_transfer_irq_after_polling; u64 count_transfer_dma; - u8 chip_select; + struct bcm2835_spidev *slv; unsigned int tx_dma_active; unsigned int rx_dma_active; struct dma_async_tx_descriptor *fill_tx_desc; dma_addr_t fill_tx_addr; - struct dma_async_tx_descriptor *clear_rx_desc[BCM2835_SPI_NUM_CS]; +}; + +/** + * struct bcm2835_spidev - BCM2835 SPI slave + * @prepare_cs: precalculated CS register value for ->prepare_message() + * (uses slave-specific clock polarity and phase settings) + * @clear_rx_desc: preallocated RX DMA descriptor used for TX-only transfers + * (cyclically clears RX FIFO by writing @clear_rx_cs to CS register) + * @clear_rx_addr: bus address of @clear_rx_cs + * @clear_rx_cs: precalculated CS register value to clear RX FIFO + * (uses slave-specific clock polarity and phase settings) + */ +struct bcm2835_spidev { + u32 prepare_cs; + struct dma_async_tx_descriptor *clear_rx_desc; dma_addr_t clear_rx_addr; - u32 clear_rx_cs[BCM2835_SPI_NUM_CS] ____cacheline_aligned; + u32 clear_rx_cs ____cacheline_aligned; }; #if defined(CONFIG_DEBUG_FS) @@ -624,8 +629,7 @@ static void bcm2835_spi_dma_tx_done(void *data) /* busy-wait for TX FIFO to empty */ while (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE)) - bcm2835_wr(bs, BCM2835_SPI_CS, - bs->clear_rx_cs[bs->chip_select]); + bcm2835_wr(bs, BCM2835_SPI_CS, bs->slv->clear_rx_cs); bs->tx_dma_active = false; smp_wmb(); @@ -646,18 +650,18 @@ static void bcm2835_spi_dma_tx_done(void *data) /** * bcm2835_spi_prepare_sg() - prepare and submit DMA descriptor for sglist * @ctlr: SPI master controller - * @spi: SPI slave * @tfr: SPI transfer * @bs: BCM2835 SPI controller + * @slv: BCM2835 SPI slave * @is_tx: whether to submit DMA descriptor for TX or RX sglist * * Prepare and submit a DMA descriptor for the TX or RX sglist of @tfr. * Return 0 on success or a negative error number. */ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr, - struct spi_device *spi, struct spi_transfer *tfr, struct bcm2835_spi *bs, + struct bcm2835_spidev *slv, bool is_tx) { struct dma_chan *chan; @@ -697,7 +701,7 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr, } else if (!tfr->rx_buf) { desc->callback = bcm2835_spi_dma_tx_done; desc->callback_param = ctlr; - bs->chip_select = spi->chip_select; + bs->slv = slv; } /* submit it to DMA-engine */ @@ -709,8 +713,8 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr, /** * bcm2835_spi_transfer_one_dma() - perform SPI transfer using DMA engine * @ctlr: SPI master controller - * @spi: SPI slave * @tfr: SPI transfer + * @slv: BCM2835 SPI slave * @cs: CS register * * For *bidirectional* transfers (both tx_buf and rx_buf are non-%NULL), set up @@ -754,8 +758,8 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr, * performed at the end of an RX-only transfer. */ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr, - struct spi_device *spi, struct spi_transfer *tfr, + struct bcm2835_spidev *slv, u32 cs) { struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); @@ -773,7 +777,7 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr, /* setup tx-DMA */ if (bs->tx_buf) { - ret = bcm2835_spi_prepare_sg(ctlr, spi, tfr, bs, true); + ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, slv, true); } else { cookie = dmaengine_submit(bs->fill_tx_desc); ret = dma_submit_error(cookie); @@ -799,9 +803,9 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr, * this saves 10us or more. */ if (bs->rx_buf) { - ret = bcm2835_spi_prepare_sg(ctlr, spi, tfr, bs, false); + ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, slv, false); } else { - cookie = dmaengine_submit(bs->clear_rx_desc[spi->chip_select]); + cookie = dmaengine_submit(slv->clear_rx_desc); ret = dma_submit_error(cookie); } if (ret) { @@ -850,8 +854,6 @@ static bool bcm2835_spi_can_dma(struct spi_controller *ctlr, static void bcm2835_dma_release(struct spi_controller *ctlr, struct bcm2835_spi *bs) { - int i; - if (ctlr->dma_tx) { dmaengine_terminate_sync(ctlr->dma_tx); @@ -870,17 +872,6 @@ static void bcm2835_dma_release(struct spi_controller *ctlr, if (ctlr->dma_rx) { dmaengine_terminate_sync(ctlr->dma_rx); - - for (i = 0; i < BCM2835_SPI_NUM_CS; i++) - if (bs->clear_rx_desc[i]) - dmaengine_desc_free(bs->clear_rx_desc[i]); - - if (bs->clear_rx_addr) - dma_unmap_single(ctlr->dma_rx->device->dev, - bs->clear_rx_addr, - sizeof(bs->clear_rx_cs), - DMA_TO_DEVICE); - dma_release_channel(ctlr->dma_rx); ctlr->dma_rx = NULL; } @@ -892,7 +883,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, struct dma_slave_config slave_config; const __be32 *addr; dma_addr_t dma_reg_base; - int ret, i; + int ret; /* base address in dma-space */ addr = of_get_address(ctlr->dev.of_node, 0, NULL, NULL); @@ -972,35 +963,6 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, if (ret) goto err_config; - bs->clear_rx_addr = dma_map_single(ctlr->dma_rx->device->dev, - bs->clear_rx_cs, - sizeof(bs->clear_rx_cs), - DMA_TO_DEVICE); - if (dma_mapping_error(ctlr->dma_rx->device->dev, bs->clear_rx_addr)) { - dev_err(dev, "cannot map clear_rx_cs - not using DMA mode\n"); - bs->clear_rx_addr = 0; - ret = -ENOMEM; - goto err_release; - } - - for (i = 0; i < BCM2835_SPI_NUM_CS; i++) { - bs->clear_rx_desc[i] = dmaengine_prep_dma_cyclic(ctlr->dma_rx, - bs->clear_rx_addr + i * sizeof(u32), - sizeof(u32), 0, - DMA_MEM_TO_DEV, 0); - if (!bs->clear_rx_desc[i]) { - dev_err(dev, "cannot prepare clear_rx_desc - not using DMA mode\n"); - ret = -ENOMEM; - goto err_release; - } - - ret = dmaengine_desc_set_reuse(bs->clear_rx_desc[i]); - if (ret) { - dev_err(dev, "cannot reuse clear_rx_desc - not using DMA mode\n"); - goto err_release; - } - } - /* all went well, so set can_dma */ ctlr->can_dma = bcm2835_spi_can_dma; @@ -1082,9 +1044,10 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr, struct spi_transfer *tfr) { struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); + struct bcm2835_spidev *slv = spi_get_ctldata(spi); unsigned long spi_hz, clk_hz, cdiv; unsigned long hz_per_byte, byte_limit; - u32 cs = bs->prepare_cs[spi->chip_select]; + u32 cs = slv->prepare_cs; /* set clock */ spi_hz = tfr->speed_hz; @@ -1133,7 +1096,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr, * this 1 idle clock cycle pattern but runs the spi clock without gaps */ if (ctlr->can_dma && bcm2835_spi_can_dma(ctlr, spi, tfr)) - return bcm2835_spi_transfer_one_dma(ctlr, spi, tfr, cs); + return bcm2835_spi_transfer_one_dma(ctlr, tfr, slv, cs); /* run in interrupt-mode */ return bcm2835_spi_transfer_one_irq(ctlr, spi, tfr, cs, true); @@ -1144,6 +1107,7 @@ static int bcm2835_spi_prepare_message(struct spi_controller *ctlr, { struct spi_device *spi = msg->spi; struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); + struct bcm2835_spidev *slv = spi_get_ctldata(spi); int ret; if (ctlr->can_dma) { @@ -1162,7 +1126,7 @@ static int bcm2835_spi_prepare_message(struct spi_controller *ctlr, * Set up clock polarity before spi_transfer_one_message() asserts * chip select to avoid a gratuitous clock signal edge. */ - bcm2835_wr(bs, BCM2835_SPI_CS, bs->prepare_cs[spi->chip_select]); + bcm2835_wr(bs, BCM2835_SPI_CS, slv->prepare_cs); return 0; } @@ -1188,17 +1152,81 @@ static int chip_match_name(struct gpio_chip *chip, void *data) return !strcmp(chip->label, data); } +static void bcm2835_spi_cleanup(struct spi_device *spi) +{ + struct bcm2835_spidev *slv = spi_get_ctldata(spi); + struct spi_controller *ctlr = spi->controller; + + if (slv->clear_rx_desc) + dmaengine_desc_free(slv->clear_rx_desc); + + if (slv->clear_rx_addr) + dma_unmap_single(ctlr->dma_rx->device->dev, + slv->clear_rx_addr, + sizeof(u32), + DMA_TO_DEVICE); + + kfree(slv); +} + +static int bcm2835_spi_setup_dma(struct spi_controller *ctlr, + struct spi_device *spi, + struct bcm2835_spi *bs, + struct bcm2835_spidev *slv) +{ + int ret; + + if (!ctlr->dma_rx) + return 0; + + slv->clear_rx_addr = dma_map_single(ctlr->dma_rx->device->dev, + &slv->clear_rx_cs, + sizeof(u32), + DMA_TO_DEVICE); + if (dma_mapping_error(ctlr->dma_rx->device->dev, slv->clear_rx_addr)) { + dev_err(&spi->dev, "cannot map clear_rx_cs\n"); + slv->clear_rx_addr = 0; + return -ENOMEM; + } + + slv->clear_rx_desc = dmaengine_prep_dma_cyclic(ctlr->dma_rx, + slv->clear_rx_addr, + sizeof(u32), 0, + DMA_MEM_TO_DEV, 0); + if (!slv->clear_rx_desc) { + dev_err(&spi->dev, "cannot prepare clear_rx_desc\n"); + return -ENOMEM; + } + + ret = dmaengine_desc_set_reuse(slv->clear_rx_desc); + if (ret) { + dev_err(&spi->dev, "cannot reuse clear_rx_desc\n"); + return ret; + } + + return 0; +} + static int bcm2835_spi_setup(struct spi_device *spi) { struct spi_controller *ctlr = spi->controller; struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); + struct bcm2835_spidev *slv = spi_get_ctldata(spi); struct gpio_chip *chip; + int ret; u32 cs; - if (spi->chip_select >= BCM2835_SPI_NUM_CS) { - dev_err(&spi->dev, "only %d chip-selects supported\n", - BCM2835_SPI_NUM_CS - 1); - return -EINVAL; + if (!slv) { + slv = kzalloc(ALIGN(sizeof(*slv), dma_get_cache_alignment()), + GFP_KERNEL); + if (!slv) + return -ENOMEM; + + spi_set_ctldata(spi, slv); + + ret = bcm2835_spi_setup_dma(ctlr, spi, bs, slv); + if (ret) + goto err_cleanup; } /* @@ -1212,20 +1240,19 @@ static int bcm2835_spi_setup(struct spi_device *spi) cs |= BCM2835_SPI_CS_CPOL; if (spi->mode & SPI_CPHA) cs |= BCM2835_SPI_CS_CPHA; - bs->prepare_cs[spi->chip_select] = cs; + slv->prepare_cs = cs; /* * Precalculate SPI slave's CS register value to clear RX FIFO * in case of a TX-only DMA transfer. */ if (ctlr->dma_rx) { - bs->clear_rx_cs[spi->chip_select] = cs | - BCM2835_SPI_CS_TA | - BCM2835_SPI_CS_DMAEN | - BCM2835_SPI_CS_CLEAR_RX; + slv->clear_rx_cs = cs | BCM2835_SPI_CS_TA | + BCM2835_SPI_CS_DMAEN | + BCM2835_SPI_CS_CLEAR_RX; dma_sync_single_for_device(ctlr->dma_rx->device->dev, - bs->clear_rx_addr, - sizeof(bs->clear_rx_cs), + slv->clear_rx_addr, + sizeof(u32), DMA_TO_DEVICE); } @@ -1247,7 +1274,8 @@ static int bcm2835_spi_setup(struct spi_device *spi) */ dev_err(&spi->dev, "setup: only two native chip-selects are supported\n"); - return -EINVAL; + ret = -EINVAL; + goto err_cleanup; } /* @@ -1268,14 +1296,20 @@ static int bcm2835_spi_setup(struct spi_device *spi) DRV_NAME, GPIO_LOOKUP_FLAGS_DEFAULT, GPIOD_OUT_LOW); - if (IS_ERR(spi->cs_gpiod)) - return PTR_ERR(spi->cs_gpiod); + if (IS_ERR(spi->cs_gpiod)) { + ret = PTR_ERR(spi->cs_gpiod); + goto err_cleanup; + } /* and set up the "mode" and level */ dev_info(&spi->dev, "setting up native-CS%i to use GPIO\n", spi->chip_select); return 0; + +err_cleanup: + bcm2835_spi_cleanup(spi); + return ret; } static int bcm2835_spi_probe(struct platform_device *pdev) @@ -1284,8 +1318,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) struct bcm2835_spi *bs; int err; - ctlr = devm_spi_alloc_master(&pdev->dev, ALIGN(sizeof(*bs), - dma_get_cache_alignment())); + ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*bs)); if (!ctlr) return -ENOMEM; @@ -1296,6 +1329,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) ctlr->bits_per_word_mask = SPI_BPW_MASK(8); ctlr->num_chipselect = 3; ctlr->setup = bcm2835_spi_setup; + ctlr->cleanup = bcm2835_spi_cleanup; ctlr->transfer_one = bcm2835_spi_transfer_one; ctlr->handle_err = bcm2835_spi_handle_err; ctlr->prepare_message = bcm2835_spi_prepare_message; From c955a0cc8a286e5da1ebb88c19201e9bab8c2422 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 May 2021 18:27:52 +0200 Subject: [PATCH 58/86] spi: spi-mem: add automatic poll status functions With STM32 QSPI, it is possible to poll the status register of the device. This could be done to offload the CPU during an operation (erase or program a SPI NAND for example). spi_mem_poll_status API has been added to handle this feature. This new function take care of the offload/non-offload cases. For the non-offload case, use read_poll_timeout() to poll the status in order to release CPU during this phase. For example, previously, when erasing large area, in non-offload case, CPU load can reach ~50%, now it decrease to ~35%. Signed-off-by: Patrice Chotard Signed-off-by: Christophe Kerello Reviewed-by: Boris Brezillon Link: https://lore.kernel.org/r/20210518162754.15940-2-patrice.chotard@foss.st.com Signed-off-by: Mark Brown --- drivers/spi/spi-mem.c | 86 +++++++++++++++++++++++++++++++++++++ include/linux/spi/spi-mem.h | 16 +++++++ 2 files changed, 102 insertions(+) diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 1513553e4080..177b3e21febf 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -6,6 +6,7 @@ * Author: Boris Brezillon */ #include +#include #include #include #include @@ -743,6 +744,91 @@ static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv) return container_of(drv, struct spi_mem_driver, spidrv.driver); } +static int spi_mem_read_status(struct spi_mem *mem, + const struct spi_mem_op *op, + u16 *status) +{ + const u8 *bytes = (u8 *)op->data.buf.in; + int ret; + + ret = spi_mem_exec_op(mem, op); + if (ret) + return ret; + + if (op->data.nbytes > 1) + *status = ((u16)bytes[0] << 8) | bytes[1]; + else + *status = bytes[0]; + + return 0; +} + +/** + * spi_mem_poll_status() - Poll memory device status + * @mem: SPI memory device + * @op: the memory operation to execute + * @mask: status bitmask to ckeck + * @match: (status & mask) expected value + * @initial_delay_us: delay in us before starting to poll + * @polling_delay_us: time to sleep between reads in us + * @timeout_ms: timeout in milliseconds + * + * This function polls a status register and returns when + * (status & mask) == match or when the timeout has expired. + * + * Return: 0 in case of success, -ETIMEDOUT in case of error, + * -EOPNOTSUPP if not supported. + */ +int spi_mem_poll_status(struct spi_mem *mem, + const struct spi_mem_op *op, + u16 mask, u16 match, + unsigned long initial_delay_us, + unsigned long polling_delay_us, + u16 timeout_ms) +{ + struct spi_controller *ctlr = mem->spi->controller; + int ret = -EOPNOTSUPP; + int read_status_ret; + u16 status; + + if (op->data.nbytes < 1 || op->data.nbytes > 2 || + op->data.dir != SPI_MEM_DATA_IN) + return -EINVAL; + + if (ctlr->mem_ops && ctlr->mem_ops->poll_status) { + ret = spi_mem_access_start(mem); + if (ret) + return ret; + + ret = ctlr->mem_ops->poll_status(mem, op, mask, match, + initial_delay_us, polling_delay_us, + timeout_ms); + + spi_mem_access_end(mem); + } + + if (ret == -EOPNOTSUPP) { + if (!spi_mem_supports_op(mem, op)) + return ret; + + if (initial_delay_us < 10) + udelay(initial_delay_us); + else + usleep_range((initial_delay_us >> 2) + 1, + initial_delay_us); + + ret = read_poll_timeout(spi_mem_read_status, read_status_ret, + (read_status_ret || ((status) & mask) == match), + polling_delay_us, timeout_ms * 1000, false, mem, + op, &status); + if (read_status_ret) + return read_status_ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(spi_mem_poll_status); + static int spi_mem_probe(struct spi_device *spi) { struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver); diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h index 2b65c9edc34e..85e2ff7b840d 100644 --- a/include/linux/spi/spi-mem.h +++ b/include/linux/spi/spi-mem.h @@ -250,6 +250,9 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem) * the currently mapped area), and the caller of * spi_mem_dirmap_write() is responsible for calling it again in * this case. + * @poll_status: poll memory device status until (status & mask) == match or + * when the timeout has expired. It fills the data buffer with + * the last status value. * * This interface should be implemented by SPI controllers providing an * high-level interface to execute SPI memory operation, which is usually the @@ -274,6 +277,12 @@ struct spi_controller_mem_ops { u64 offs, size_t len, void *buf); ssize_t (*dirmap_write)(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, const void *buf); + int (*poll_status)(struct spi_mem *mem, + const struct spi_mem_op *op, + u16 mask, u16 match, + unsigned long initial_delay_us, + unsigned long polling_rate_us, + unsigned long timeout_ms); }; /** @@ -369,6 +378,13 @@ devm_spi_mem_dirmap_create(struct device *dev, struct spi_mem *mem, void devm_spi_mem_dirmap_destroy(struct device *dev, struct spi_mem_dirmap_desc *desc); +int spi_mem_poll_status(struct spi_mem *mem, + const struct spi_mem_op *op, + u16 mask, u16 match, + unsigned long initial_delay_us, + unsigned long polling_delay_us, + u16 timeout_ms); + int spi_mem_driver_register_with_owner(struct spi_mem_driver *drv, struct module *owner); From 8941cd8d295e40f8ea1c0a5045d6d068b8e33eec Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 May 2021 18:27:53 +0200 Subject: [PATCH 59/86] mtd: spinand: use the spi-mem poll status APIs Make use of spi-mem poll status APIs to let advanced controllers optimize wait operations. This should also fix the high CPU usage for system that don't have a dedicated STATUS poll block logic. Signed-off-by: Patrice Chotard Signed-off-by: Christophe Kerello Reviewed-by: Boris Brezillon Acked-by: Miquel Raynal Link: https://lore.kernel.org/r/20210518162754.15940-3-patrice.chotard@foss.st.com Signed-off-by: Mark Brown --- drivers/mtd/nand/spi/core.c | 45 ++++++++++++++++++++++++++----------- include/linux/mtd/spinand.h | 22 ++++++++++++++++++ 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 17f63f95f4a2..3131fae0c715 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -473,20 +473,26 @@ static int spinand_erase_op(struct spinand_device *spinand, return spi_mem_exec_op(spinand->spimem, &op); } -static int spinand_wait(struct spinand_device *spinand, u8 *s) +static int spinand_wait(struct spinand_device *spinand, + unsigned long initial_delay_us, + unsigned long poll_delay_us, + u8 *s) { - unsigned long timeo = jiffies + msecs_to_jiffies(400); + struct spi_mem_op op = SPINAND_GET_FEATURE_OP(REG_STATUS, + spinand->scratchbuf); u8 status; int ret; - do { - ret = spinand_read_status(spinand, &status); - if (ret) - return ret; + ret = spi_mem_poll_status(spinand->spimem, &op, STATUS_BUSY, 0, + initial_delay_us, + poll_delay_us, + SPINAND_WAITRDY_TIMEOUT_MS); + if (ret) + return ret; - if (!(status & STATUS_BUSY)) - goto out; - } while (time_before(jiffies, timeo)); + status = *spinand->scratchbuf; + if (!(status & STATUS_BUSY)) + goto out; /* * Extra read, just in case the STATUS_READY bit has changed @@ -526,7 +532,10 @@ static int spinand_reset_op(struct spinand_device *spinand) if (ret) return ret; - return spinand_wait(spinand, NULL); + return spinand_wait(spinand, + SPINAND_RESET_INITIAL_DELAY_US, + SPINAND_RESET_POLL_DELAY_US, + NULL); } static int spinand_lock_block(struct spinand_device *spinand, u8 lock) @@ -549,7 +558,10 @@ static int spinand_read_page(struct spinand_device *spinand, if (ret) return ret; - ret = spinand_wait(spinand, &status); + ret = spinand_wait(spinand, + SPINAND_READ_INITIAL_DELAY_US, + SPINAND_READ_POLL_DELAY_US, + &status); if (ret < 0) return ret; @@ -585,7 +597,10 @@ static int spinand_write_page(struct spinand_device *spinand, if (ret) return ret; - ret = spinand_wait(spinand, &status); + ret = spinand_wait(spinand, + SPINAND_WRITE_INITIAL_DELAY_US, + SPINAND_WRITE_POLL_DELAY_US, + &status); if (!ret && (status & STATUS_PROG_FAILED)) return -EIO; @@ -768,7 +783,11 @@ static int spinand_erase(struct nand_device *nand, const struct nand_pos *pos) if (ret) return ret; - ret = spinand_wait(spinand, &status); + ret = spinand_wait(spinand, + SPINAND_ERASE_INITIAL_DELAY_US, + SPINAND_ERASE_POLL_DELAY_US, + &status); + if (!ret && (status & STATUS_ERASE_FAILED)) ret = -EIO; diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 6bb92f26833e..6988956b8492 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -170,6 +170,28 @@ struct spinand_op; struct spinand_device; #define SPINAND_MAX_ID_LEN 4 +/* + * For erase, write and read operation, we got the following timings : + * tBERS (erase) 1ms to 4ms + * tPROG 300us to 400us + * tREAD 25us to 100us + * In order to minimize latency, the min value is divided by 4 for the + * initial delay, and dividing by 20 for the poll delay. + * For reset, 5us/10us/500us if the device is respectively + * reading/programming/erasing when the RESET occurs. Since we always + * issue a RESET when the device is IDLE, 5us is selected for both initial + * and poll delay. + */ +#define SPINAND_READ_INITIAL_DELAY_US 6 +#define SPINAND_READ_POLL_DELAY_US 5 +#define SPINAND_RESET_INITIAL_DELAY_US 5 +#define SPINAND_RESET_POLL_DELAY_US 5 +#define SPINAND_WRITE_INITIAL_DELAY_US 75 +#define SPINAND_WRITE_POLL_DELAY_US 15 +#define SPINAND_ERASE_INITIAL_DELAY_US 250 +#define SPINAND_ERASE_POLL_DELAY_US 50 + +#define SPINAND_WAITRDY_TIMEOUT_MS 400 /** * struct spinand_id - SPI NAND id structure From 86d1c6bbae32122c5f703b2d8acccf5d4258f2bb Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 May 2021 18:27:54 +0200 Subject: [PATCH 60/86] spi: stm32-qspi: add automatic poll status feature STM32 QSPI is able to automatically poll a specified register inside the memory and relieve the CPU from this task. As example, when erasing a large memory area, we got cpu load equal to 50%. This patch allows to perform the same operation with a cpu load around 2%. Signed-off-by: Christophe Kerello Signed-off-by: Patrice Chotard Link: https://lore.kernel.org/r/20210518162754.15940-4-patrice.chotard@foss.st.com Signed-off-by: Mark Brown --- drivers/spi/spi-stm32-qspi.c | 86 ++++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 7e640ccc7e77..69fd220a2894 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -36,6 +36,7 @@ #define CR_FTIE BIT(18) #define CR_SMIE BIT(19) #define CR_TOIE BIT(20) +#define CR_APMS BIT(22) #define CR_PRESC_MASK GENMASK(31, 24) #define QSPI_DCR 0x04 @@ -53,6 +54,7 @@ #define QSPI_FCR 0x0c #define FCR_CTEF BIT(0) #define FCR_CTCF BIT(1) +#define FCR_CSMF BIT(3) #define QSPI_DLR 0x10 @@ -107,6 +109,7 @@ struct stm32_qspi { u32 clk_rate; struct stm32_qspi_flash flash[STM32_QSPI_MAX_NORCHIP]; struct completion data_completion; + struct completion match_completion; u32 fmode; struct dma_chan *dma_chtx; @@ -115,6 +118,7 @@ struct stm32_qspi { u32 cr_reg; u32 dcr_reg; + unsigned long status_timeout; /* * to protect device configuration, could be different between @@ -128,11 +132,20 @@ static irqreturn_t stm32_qspi_irq(int irq, void *dev_id) struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id; u32 cr, sr; + cr = readl_relaxed(qspi->io_base + QSPI_CR); sr = readl_relaxed(qspi->io_base + QSPI_SR); + if (cr & CR_SMIE && sr & SR_SMF) { + /* disable irq */ + cr &= ~CR_SMIE; + writel_relaxed(cr, qspi->io_base + QSPI_CR); + complete(&qspi->match_completion); + + return IRQ_HANDLED; + } + if (sr & (SR_TEF | SR_TCF)) { /* disable irq */ - cr = readl_relaxed(qspi->io_base + QSPI_CR); cr &= ~CR_TCIE & ~CR_TEIE; writel_relaxed(cr, qspi->io_base + QSPI_CR); complete(&qspi->data_completion); @@ -319,6 +332,24 @@ out: return err; } +static int stm32_qspi_wait_poll_status(struct stm32_qspi *qspi, + const struct spi_mem_op *op) +{ + u32 cr; + + reinit_completion(&qspi->match_completion); + cr = readl_relaxed(qspi->io_base + QSPI_CR); + writel_relaxed(cr | CR_SMIE, qspi->io_base + QSPI_CR); + + if (!wait_for_completion_timeout(&qspi->match_completion, + msecs_to_jiffies(qspi->status_timeout))) + return -ETIMEDOUT; + + writel_relaxed(FCR_CSMF, qspi->io_base + QSPI_FCR); + + return 0; +} + static int stm32_qspi_get_mode(struct stm32_qspi *qspi, u8 buswidth) { if (buswidth == 4) @@ -332,7 +363,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); struct stm32_qspi_flash *flash = &qspi->flash[mem->spi->chip_select]; u32 ccr, cr; - int timeout, err = 0; + int timeout, err = 0, err_poll_status = 0; dev_dbg(qspi->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n", op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, @@ -378,6 +409,9 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) if (op->addr.nbytes && qspi->fmode != CCR_FMODE_MM) writel_relaxed(op->addr.val, qspi->io_base + QSPI_AR); + if (qspi->fmode == CCR_FMODE_APM) + err_poll_status = stm32_qspi_wait_poll_status(qspi, op); + err = stm32_qspi_tx(qspi, op); /* @@ -387,7 +421,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) * byte of device (device size - fifo size). like device size is not * knows, the prefetching is always stop. */ - if (err || qspi->fmode == CCR_FMODE_MM) + if (err || err_poll_status || qspi->fmode == CCR_FMODE_MM) goto abort; /* wait end of tx in indirect mode */ @@ -406,15 +440,49 @@ abort: cr, !(cr & CR_ABORT), 1, STM32_ABT_TIMEOUT_US); - writel_relaxed(FCR_CTCF, qspi->io_base + QSPI_FCR); + writel_relaxed(FCR_CTCF | FCR_CSMF, qspi->io_base + QSPI_FCR); - if (err || timeout) - dev_err(qspi->dev, "%s err:%d abort timeout:%d\n", - __func__, err, timeout); + if (err || err_poll_status || timeout) + dev_err(qspi->dev, "%s err:%d err_poll_status:%d abort timeout:%d\n", + __func__, err, err_poll_status, timeout); return err; } +static int stm32_qspi_poll_status(struct spi_mem *mem, const struct spi_mem_op *op, + u16 mask, u16 match, + unsigned long initial_delay_us, + unsigned long polling_rate_us, + unsigned long timeout_ms) +{ + struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); + int ret; + + if (!spi_mem_supports_op(mem, op)) + return -EOPNOTSUPP; + + ret = pm_runtime_get_sync(qspi->dev); + if (ret < 0) { + pm_runtime_put_noidle(qspi->dev); + return ret; + } + + mutex_lock(&qspi->lock); + + writel_relaxed(mask, qspi->io_base + QSPI_PSMKR); + writel_relaxed(match, qspi->io_base + QSPI_PSMAR); + qspi->fmode = CCR_FMODE_APM; + qspi->status_timeout = timeout_ms; + + ret = stm32_qspi_send(mem, op); + mutex_unlock(&qspi->lock); + + pm_runtime_mark_last_busy(qspi->dev); + pm_runtime_put_autosuspend(qspi->dev); + + return ret; +} + static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) { struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); @@ -527,7 +595,7 @@ static int stm32_qspi_setup(struct spi_device *spi) flash->presc = presc; mutex_lock(&qspi->lock); - qspi->cr_reg = 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN; + qspi->cr_reg = CR_APMS | 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN; writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); /* set dcr fsize to max address */ @@ -607,6 +675,7 @@ static const struct spi_controller_mem_ops stm32_qspi_mem_ops = { .exec_op = stm32_qspi_exec_op, .dirmap_create = stm32_qspi_dirmap_create, .dirmap_read = stm32_qspi_dirmap_read, + .poll_status = stm32_qspi_poll_status, }; static int stm32_qspi_probe(struct platform_device *pdev) @@ -661,6 +730,7 @@ static int stm32_qspi_probe(struct platform_device *pdev) } init_completion(&qspi->data_completion); + init_completion(&qspi->match_completion); qspi->clk = devm_clk_get(dev, NULL); if (IS_ERR(qspi->clk)) { From 5fa5e6dec762305a783e918a90a05369fc10e346 Mon Sep 17 00:00:00 2001 From: Dan Sneddon Date: Wed, 2 Jun 2021 09:08:14 -0700 Subject: [PATCH 61/86] spi: atmel: Switch to transfer_one transfer method Switch from using our own transfer_one_message routine to using the one provided by the SPI core. Signed-off-by: Dan Sneddon Link: https://lore.kernel.org/r/20210602160816.4890-1-dan.sneddon@microchip.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 124 +++++++++++----------------------------- 1 file changed, 33 insertions(+), 91 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 7cd5fe00dfc1..0e693e72c922 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -863,7 +863,6 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as, * lock is held, spi irq is blocked */ static void atmel_spi_pdc_next_xfer(struct spi_master *master, - struct spi_message *msg, struct spi_transfer *xfer) { struct atmel_spi *as = spi_master_get_devdata(master); @@ -879,12 +878,12 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master, spi_writel(as, RPR, rx_dma); spi_writel(as, TPR, tx_dma); - if (msg->spi->bits_per_word > 8) + if (xfer->bits_per_word > 8) len >>= 1; spi_writel(as, RCR, len); spi_writel(as, TCR, len); - dev_dbg(&msg->spi->dev, + dev_dbg(&master->dev, " start xfer %p: len %u tx %p/%08llx rx %p/%08llx\n", xfer, xfer->len, xfer->tx_buf, (unsigned long long)xfer->tx_dma, xfer->rx_buf, @@ -898,12 +897,12 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master, spi_writel(as, RNPR, rx_dma); spi_writel(as, TNPR, tx_dma); - if (msg->spi->bits_per_word > 8) + if (xfer->bits_per_word > 8) len >>= 1; spi_writel(as, RNCR, len); spi_writel(as, TNCR, len); - dev_dbg(&msg->spi->dev, + dev_dbg(&master->dev, " next xfer %p: len %u tx %p/%08llx rx %p/%08llx\n", xfer, xfer->len, xfer->tx_buf, (unsigned long long)xfer->tx_dma, xfer->rx_buf, @@ -1273,12 +1272,28 @@ static int atmel_spi_setup(struct spi_device *spi) return 0; } +static void atmel_spi_set_cs(struct spi_device *spi, bool enable) +{ + struct atmel_spi *as = spi_master_get_devdata(spi->master); + /* the core doesn't really pass us enable/disable, but CS HIGH vs CS LOW + * since we already have routines for activate/deactivate translate + * high/low to active/inactive + */ + enable = (!!(spi->mode & SPI_CS_HIGH) == enable); + + if (enable) { + cs_activate(as, spi); + } else { + cs_deactivate(as, spi); + } + +} + static int atmel_spi_one_transfer(struct spi_master *master, - struct spi_message *msg, + struct spi_device *spi, struct spi_transfer *xfer) { struct atmel_spi *as; - struct spi_device *spi = msg->spi; u8 bits; u32 len; struct atmel_spi_device *asd; @@ -1287,11 +1302,8 @@ static int atmel_spi_one_transfer(struct spi_master *master, unsigned long dma_timeout; as = spi_master_get_devdata(master); - - if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) { - dev_dbg(&spi->dev, "missing rx or tx buf\n"); - return -EINVAL; - } + /* This lock was orignally taken in atmel_spi_trasfer_one_message */ + atmel_spi_lock(as); asd = spi->controller_state; bits = (asd->csr >> 4) & 0xf; @@ -1305,13 +1317,13 @@ static int atmel_spi_one_transfer(struct spi_master *master, * DMA map early, for performance (empties dcache ASAP) and * better fault reporting. */ - if ((!msg->is_dma_mapped) + if ((!master->cur_msg_mapped) && as->use_pdc) { if (atmel_spi_dma_map_xfer(as, xfer) < 0) return -ENOMEM; } - atmel_spi_set_xfer_speed(as, msg->spi, xfer); + atmel_spi_set_xfer_speed(as, spi, xfer); as->done_status = 0; as->current_transfer = xfer; @@ -1320,7 +1332,7 @@ static int atmel_spi_one_transfer(struct spi_master *master, reinit_completion(&as->xfer_completion); if (as->use_pdc) { - atmel_spi_pdc_next_xfer(master, msg, xfer); + atmel_spi_pdc_next_xfer(master, xfer); } else if (atmel_spi_use_dma(as, xfer)) { len = as->current_remaining_bytes; ret = atmel_spi_next_xfer_dma_submit(master, @@ -1328,7 +1340,8 @@ static int atmel_spi_one_transfer(struct spi_master *master, if (ret) { dev_err(&spi->dev, "unable to use DMA, fallback to PIO\n"); - atmel_spi_next_xfer_pio(master, xfer); + as->done_status = ret; + break; } else { as->current_remaining_bytes -= len; if (as->current_remaining_bytes < 0) @@ -1381,90 +1394,18 @@ static int atmel_spi_one_transfer(struct spi_master *master, } else if (atmel_spi_use_dma(as, xfer)) { atmel_spi_stop_dma(master); } - - if (!msg->is_dma_mapped - && as->use_pdc) - atmel_spi_dma_unmap_xfer(master, xfer); - - return 0; - - } else { - /* only update length if no error */ - msg->actual_length += xfer->len; } - if (!msg->is_dma_mapped + if (!master->cur_msg_mapped && as->use_pdc) atmel_spi_dma_unmap_xfer(master, xfer); - spi_transfer_delay_exec(xfer); - - if (xfer->cs_change) { - if (list_is_last(&xfer->transfer_list, - &msg->transfers)) { - as->keep_cs = true; - } else { - cs_deactivate(as, msg->spi); - udelay(10); - cs_activate(as, msg->spi); - } - } - - return 0; -} - -static int atmel_spi_transfer_one_message(struct spi_master *master, - struct spi_message *msg) -{ - struct atmel_spi *as; - struct spi_transfer *xfer; - struct spi_device *spi = msg->spi; - int ret = 0; - - as = spi_master_get_devdata(master); - - dev_dbg(&spi->dev, "new message %p submitted for %s\n", - msg, dev_name(&spi->dev)); - - atmel_spi_lock(as); - cs_activate(as, spi); - - as->keep_cs = false; - - msg->status = 0; - msg->actual_length = 0; - - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - trace_spi_transfer_start(msg, xfer); - - ret = atmel_spi_one_transfer(master, msg, xfer); - if (ret) - goto msg_done; - - trace_spi_transfer_stop(msg, xfer); - } - if (as->use_pdc) atmel_spi_disable_pdc_transfer(as); - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - dev_dbg(&spi->dev, - " xfer %p: len %u tx %p/%pad rx %p/%pad\n", - xfer, xfer->len, - xfer->tx_buf, &xfer->tx_dma, - xfer->rx_buf, &xfer->rx_dma); - } - -msg_done: - if (!as->keep_cs) - cs_deactivate(as, msg->spi); - atmel_spi_unlock(as); - msg->status = as->done_status; - spi_finalize_current_message(spi->master); - - return ret; + return as->done_status; } static void atmel_spi_cleanup(struct spi_device *spi) @@ -1554,7 +1495,8 @@ static int atmel_spi_probe(struct platform_device *pdev) master->num_chipselect = 4; master->setup = atmel_spi_setup; master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX); - master->transfer_one_message = atmel_spi_transfer_one_message; + master->transfer_one = atmel_spi_one_transfer; + master->set_cs = atmel_spi_set_cs; master->cleanup = atmel_spi_cleanup; master->auto_runtime_pm = true; master->max_dma_len = SPI_MAX_DMA_XFER; From 4abd641501663493764949f045ebf9f8c0da0307 Mon Sep 17 00:00:00 2001 From: Dan Sneddon Date: Wed, 2 Jun 2021 09:08:15 -0700 Subject: [PATCH 62/86] spi: atmel: Reduce spin lock usage The current implementation of the driver holds a spin lock for the duration of the transfer, releasing it only to enable interrupts for short periods of time. As this would prevent any interrupt from happening, this could cause system performance issues every time a SPI message is sent. Since the spi core now handles message syncronization we can reduce the amount of time the spin-lock is held to the regions where both the calling thread and the interrupt might interract. Signed-off-by: Dan Sneddon Link: https://lore.kernel.org/r/20210602160816.4890-2-dan.sneddon@microchip.com Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 0e693e72c922..2ef74885ffa2 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -700,7 +700,6 @@ static void atmel_spi_next_xfer_pio(struct spi_master *master, static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, struct spi_transfer *xfer, u32 *plen) - __must_hold(&as->lock) { struct atmel_spi *as = spi_master_get_devdata(master); struct dma_chan *rxchan = master->dma_rx; @@ -716,8 +715,6 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, if (!rxchan || !txchan) return -ENODEV; - /* release lock for DMA operations */ - atmel_spi_unlock(as); *plen = xfer->len; @@ -786,15 +783,12 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, rxchan->device->device_issue_pending(rxchan); txchan->device->device_issue_pending(txchan); - /* take back lock */ - atmel_spi_lock(as); return 0; err_dma: spi_writel(as, IDR, SPI_BIT(OVRES)); atmel_spi_stop_dma(master); err_exit: - atmel_spi_lock(as); return -ENOMEM; } @@ -1053,8 +1047,6 @@ atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer) /* Interrupt * - * No need for locking in this Interrupt handler: done_status is the - * only information modified. */ static irqreturn_t atmel_spi_pio_interrupt(int irq, void *dev_id) @@ -1302,8 +1294,6 @@ static int atmel_spi_one_transfer(struct spi_master *master, unsigned long dma_timeout; as = spi_master_get_devdata(master); - /* This lock was orignally taken in atmel_spi_trasfer_one_message */ - atmel_spi_lock(as); asd = spi->controller_state; bits = (asd->csr >> 4) & 0xf; @@ -1332,7 +1322,9 @@ static int atmel_spi_one_transfer(struct spi_master *master, reinit_completion(&as->xfer_completion); if (as->use_pdc) { + atmel_spi_lock(as); atmel_spi_pdc_next_xfer(master, xfer); + atmel_spi_unlock(as); } else if (atmel_spi_use_dma(as, xfer)) { len = as->current_remaining_bytes; ret = atmel_spi_next_xfer_dma_submit(master, @@ -1348,14 +1340,13 @@ static int atmel_spi_one_transfer(struct spi_master *master, as->current_remaining_bytes = 0; } } else { + atmel_spi_lock(as); atmel_spi_next_xfer_pio(master, xfer); + atmel_spi_unlock(as); } - /* interrupts are disabled, so free the lock for schedule */ - atmel_spi_unlock(as); dma_timeout = wait_for_completion_timeout(&as->xfer_completion, SPI_DMA_TIMEOUT); - atmel_spi_lock(as); if (WARN_ON(dma_timeout == 0)) { dev_err(&spi->dev, "spi transfer timeout\n"); as->done_status = -EIO; @@ -1403,8 +1394,6 @@ static int atmel_spi_one_transfer(struct spi_master *master, if (as->use_pdc) atmel_spi_disable_pdc_transfer(as); - atmel_spi_unlock(as); - return as->done_status; } From 6829222b408f5aa5222c18ea3f492cac19fa9405 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 4 Jun 2021 09:50:09 +0200 Subject: [PATCH 63/86] spi: stm32-qspi: Fix W=1 build warning Fix the following compilation warning using W=1 build: arm-linux-gnueabi-ld: drivers/spi/spi-stm32-qspi.o: in function `stm32_qspi_poll_status': Reported-by: kernel test robot Signed-off-by: Patrice Chotard Link: https://lore.kernel.org/r/20210604075009.25914-1-patrice.chotard@foss.st.com Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index f4481fe48bf0..e71a4c514f7b 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -806,6 +806,7 @@ config SPI_STM32_QSPI tristate "STMicroelectronics STM32 QUAD SPI controller" depends on ARCH_STM32 || COMPILE_TEST depends on OF + depends on SPI_MEM help This enables support for the Quad SPI controller in master mode. This driver does not support generic SPI. The implementation only From 2b2142f247ebeef74aaadc1a646261c19627fd7e Mon Sep 17 00:00:00 2001 From: Jay Fang Date: Fri, 4 Jun 2021 14:55:18 +0800 Subject: [PATCH 64/86] spi: hisi-kunpeng: Add debugfs support This patch uses debugfs_regset32 interface to create the registers dump file. Use it instead of creating a generic debugfs file with manually written read callback function. With these entries, users can check all the SPI controller registers during run time. Signed-off-by: Jay Fang Link: https://lore.kernel.org/r/1622789718-13977-1-git-send-email-f.fangjian@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-hisi-kunpeng.c | 51 +++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c index 3f986ba1c328..58b823a16fc4 100644 --- a/drivers/spi/spi-hisi-kunpeng.c +++ b/drivers/spi/spi-hisi-kunpeng.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -126,6 +127,7 @@ struct hisi_spi { void __iomem *regs; int irq; u32 fifo_len; /* depth of the FIFO buffer */ + u16 bus_num; /* Current message transfer state info */ const void *tx; @@ -133,8 +135,49 @@ struct hisi_spi { void *rx; unsigned int rx_len; u8 n_bytes; /* current is a 1/2/4 bytes op */ + + struct dentry *debugfs; + struct debugfs_regset32 regset; }; +#define HISI_SPI_DBGFS_REG(_name, _off) \ +{ \ + .name = _name, \ + .offset = _off, \ +} + +static const struct debugfs_reg32 hisi_spi_regs[] = { + HISI_SPI_DBGFS_REG("CSCR", HISI_SPI_CSCR), + HISI_SPI_DBGFS_REG("CR", HISI_SPI_CR), + HISI_SPI_DBGFS_REG("ENR", HISI_SPI_ENR), + HISI_SPI_DBGFS_REG("FIFOC", HISI_SPI_FIFOC), + HISI_SPI_DBGFS_REG("IMR", HISI_SPI_IMR), + HISI_SPI_DBGFS_REG("DIN", HISI_SPI_DIN), + HISI_SPI_DBGFS_REG("DOUT", HISI_SPI_DOUT), + HISI_SPI_DBGFS_REG("SR", HISI_SPI_SR), + HISI_SPI_DBGFS_REG("RISR", HISI_SPI_RISR), + HISI_SPI_DBGFS_REG("ISR", HISI_SPI_ISR), + HISI_SPI_DBGFS_REG("ICR", HISI_SPI_ICR), + HISI_SPI_DBGFS_REG("VERSION", HISI_SPI_VERSION), +}; + +static int hisi_spi_debugfs_init(struct hisi_spi *hs) +{ + char name[32]; + + snprintf(name, 32, "hisi_spi%d", hs->bus_num); + hs->debugfs = debugfs_create_dir(name, NULL); + if (!hs->debugfs) + return -ENOMEM; + + hs->regset.regs = hisi_spi_regs; + hs->regset.nregs = ARRAY_SIZE(hisi_spi_regs); + hs->regset.base = hs->regs; + debugfs_create_regset32("registers", 0400, hs->debugfs, &hs->regset); + + return 0; +} + static u32 hisi_spi_busy(struct hisi_spi *hs) { return readl(hs->regs + HISI_SPI_SR) & SR_BUSY; @@ -424,6 +467,7 @@ static int hisi_spi_probe(struct platform_device *pdev) hs = spi_controller_get_devdata(master); hs->dev = dev; hs->irq = irq; + hs->bus_num = pdev->id; hs->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(hs->regs)) @@ -446,7 +490,7 @@ static int hisi_spi_probe(struct platform_device *pdev) master->use_gpio_descriptors = true; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); - master->bus_num = pdev->id; + master->bus_num = hs->bus_num; master->setup = hisi_spi_setup; master->cleanup = hisi_spi_cleanup; master->transfer_one = hisi_spi_transfer_one; @@ -462,6 +506,9 @@ static int hisi_spi_probe(struct platform_device *pdev) return ret; } + if (hisi_spi_debugfs_init(hs)) + dev_info(dev, "failed to create debugfs dir\n"); + ret = spi_register_controller(master); if (ret) { dev_err(dev, "failed to register spi master, ret=%d\n", ret); @@ -478,7 +525,9 @@ static int hisi_spi_probe(struct platform_device *pdev) static int hisi_spi_remove(struct platform_device *pdev) { struct spi_controller *master = platform_get_drvdata(pdev); + struct hisi_spi *hs = spi_controller_get_devdata(master); + debugfs_remove_recursive(hs->debugfs); spi_unregister_controller(master); return 0; From 4ccf359849ce709f4bf0214b4b5b8b6891d38770 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 9 Jun 2021 09:19:18 +0200 Subject: [PATCH 65/86] spi: remove spi_set_cs_timing() No one seems to be using this global and exported function, so remove it as it is no longer needed. Cc: Mark Brown Signed-off-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20210609071918.2852069-1-gregkh@linuxfoundation.org Signed-off-by: Mark Brown --- drivers/spi/spi.c | 73 ----------------------------------------- include/linux/spi/spi.h | 5 --- 2 files changed, 78 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ac892cc83171..a0a232669dc1 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3472,79 +3472,6 @@ int spi_setup(struct spi_device *spi) } EXPORT_SYMBOL_GPL(spi_setup); -/** - * spi_set_cs_timing - configure CS setup, hold, and inactive delays - * @spi: the device that requires specific CS timing configuration - * @setup: CS setup time specified via @spi_delay - * @hold: CS hold time specified via @spi_delay - * @inactive: CS inactive delay between transfers specified via @spi_delay - * - * Return: zero on success, else a negative error code. - */ -int spi_set_cs_timing(struct spi_device *spi, struct spi_delay *setup, - struct spi_delay *hold, struct spi_delay *inactive) -{ - struct device *parent = spi->controller->dev.parent; - size_t len; - int status; - - if (spi->controller->set_cs_timing && - !(spi->cs_gpiod || gpio_is_valid(spi->cs_gpio))) { - mutex_lock(&spi->controller->io_mutex); - - if (spi->controller->auto_runtime_pm) { - status = pm_runtime_get_sync(parent); - if (status < 0) { - mutex_unlock(&spi->controller->io_mutex); - pm_runtime_put_noidle(parent); - dev_err(&spi->controller->dev, "Failed to power device: %d\n", - status); - return status; - } - - status = spi->controller->set_cs_timing(spi, setup, - hold, inactive); - pm_runtime_mark_last_busy(parent); - pm_runtime_put_autosuspend(parent); - } else { - status = spi->controller->set_cs_timing(spi, setup, hold, - inactive); - } - - mutex_unlock(&spi->controller->io_mutex); - return status; - } - - if ((setup && setup->unit == SPI_DELAY_UNIT_SCK) || - (hold && hold->unit == SPI_DELAY_UNIT_SCK) || - (inactive && inactive->unit == SPI_DELAY_UNIT_SCK)) { - dev_err(&spi->dev, - "Clock-cycle delays for CS not supported in SW mode\n"); - return -ENOTSUPP; - } - - len = sizeof(struct spi_delay); - - /* copy delays to controller */ - if (setup) - memcpy(&spi->controller->cs_setup, setup, len); - else - memset(&spi->controller->cs_setup, 0, len); - - if (hold) - memcpy(&spi->controller->cs_hold, hold, len); - else - memset(&spi->controller->cs_hold, 0, len); - - if (inactive) - memcpy(&spi->controller->cs_inactive, inactive, len); - else - memset(&spi->controller->cs_inactive, 0, len); - - return 0; -} -EXPORT_SYMBOL_GPL(spi_set_cs_timing); - static int _spi_xfer_word_delay_update(struct spi_transfer *xfer, struct spi_device *spi) { diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 74239d65c7fd..f924160e995f 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -1108,11 +1108,6 @@ static inline void spi_message_free(struct spi_message *m) kfree(m); } -extern int spi_set_cs_timing(struct spi_device *spi, - struct spi_delay *setup, - struct spi_delay *hold, - struct spi_delay *inactive); - extern int spi_setup(struct spi_device *spi); extern int spi_async(struct spi_device *spi, struct spi_message *message); extern int spi_async_locked(struct spi_device *spi, From 3acbacfcb3a78eb53d6fa7bc1599dcdaf043465e Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 1 Jun 2021 20:07:21 +0800 Subject: [PATCH 66/86] spi: spi-mem: fix doc warning in spi-mem.c Fix the following make W=1 warning: drivers/spi/spi-mem.c:819: warning: expecting prototype for spi_mem_driver_unregister_with_owner(). Prototype was for spi_mem_driver_unregister() instead Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20210601120721.3198488-1-yangyingliang@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 177b3e21febf..37f4443ce9a0 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -896,7 +896,7 @@ int spi_mem_driver_register_with_owner(struct spi_mem_driver *memdrv, EXPORT_SYMBOL_GPL(spi_mem_driver_register_with_owner); /** - * spi_mem_driver_unregister_with_owner() - Unregister a SPI memory driver + * spi_mem_driver_unregister() - Unregister a SPI memory driver * @memdrv: the SPI memory driver to unregister * * Unregisters a SPI memory driver. From 95730d5eb73170a6d225a9998c478be273598634 Mon Sep 17 00:00:00 2001 From: zpershuai Date: Sun, 13 Jun 2021 13:29:32 +0800 Subject: [PATCH 67/86] spi: meson-spicc: fix a wrong goto jump for avoiding memory leak. In meson_spifc_probe function, when enable the device pclk clock is error, it should use clk_disable_unprepare to release the core clock. Signed-off-by: zpershuai Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/1623562172-22056-1-git-send-email-zpershuai@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-meson-spicc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index ecba6b4a5d85..51aef2c6e966 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -725,7 +725,7 @@ static int meson_spicc_probe(struct platform_device *pdev) ret = clk_prepare_enable(spicc->pclk); if (ret) { dev_err(&pdev->dev, "pclk clock enable failed\n"); - goto out_master; + goto out_core_clk; } device_reset_optional(&pdev->dev); @@ -764,9 +764,11 @@ static int meson_spicc_probe(struct platform_device *pdev) return 0; out_clk: - clk_disable_unprepare(spicc->core); clk_disable_unprepare(spicc->pclk); +out_core_clk: + clk_disable_unprepare(spicc->core); + out_master: spi_master_put(master); From b2d501c13470409ee7613855b17e5e5ec4111e1c Mon Sep 17 00:00:00 2001 From: zpershuai Date: Sun, 13 Jun 2021 13:29:16 +0800 Subject: [PATCH 68/86] spi: meson-spicc: fix memory leak in meson_spicc_probe when meson_spicc_clk_init returns failed, it should goto the out_clk label. Signed-off-by: zpershuai Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/1623562156-21995-1-git-send-email-zpershuai@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-meson-spicc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index 51aef2c6e966..b2c4621db34d 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -752,7 +752,7 @@ static int meson_spicc_probe(struct platform_device *pdev) ret = meson_spicc_clk_init(spicc); if (ret) { dev_err(&pdev->dev, "clock registration failed\n"); - goto out_master; + goto out_clk; } ret = devm_spi_register_master(&pdev->dev, master); From 3ce6c9e2617ebc09b2d55cc88134b90c19ff6d31 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Tue, 25 May 2021 11:10:03 +0200 Subject: [PATCH 69/86] spi: add of_device_uevent_modalias support Add OF support as already done for ACPI to take driver MODULE_DEVICE_TABLE(of, ..) into account. For example with this change a spi nor device MODALIAS changes from: MODALIAS=spi:spi-nor to MODALIAS=of:Nspi-flashT(null)Cjedec,spi-nor Signed-off-by: Marco Felsch Link: https://lore.kernel.org/r/20210525091003.18228-1-m.felsch@pengutronix.de Signed-off-by: Mark Brown --- drivers/spi/spi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index a0a232669dc1..8553e7d48f66 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -363,6 +363,10 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env) const struct spi_device *spi = to_spi_device(dev); int rc; + rc = of_device_uevent_modalias(dev, env); + if (rc != -ENODEV) + return rc; + rc = acpi_device_uevent_modalias(dev, env); if (rc != -ENODEV) return rc; From 6a5976f23dc38749afcb62cc3acf5e3e2b53d5ba Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 15 Jun 2021 11:01:15 +0200 Subject: [PATCH 70/86] spi: stm32-qspi: Remove unused qspi field of struct stm32_qspi_flash Remove struct stm32_qspi_flash's field qspi which is not used. Fixes: c530cd1d9d5e ("spi: spi-mem: add stm32 qspi controller") Signed-off-by: Patrice Chotard Link: https://lore.kernel.org/r/20210615090115.30702-1-patrice.chotard@foss.st.com Signed-off-by: Mark Brown --- drivers/spi/spi-stm32-qspi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 69fd220a2894..15fbd69a4c46 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -93,7 +93,6 @@ #define STM32_AUTOSUSPEND_DELAY -1 struct stm32_qspi_flash { - struct stm32_qspi *qspi; u32 cs; u32 presc; }; @@ -590,7 +589,6 @@ static int stm32_qspi_setup(struct spi_device *spi) presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1; flash = &qspi->flash[spi->chip_select]; - flash->qspi = qspi; flash->cs = spi->chip_select; flash->presc = presc; From aa7968682a2b8a9cecf1d7d07e1c8ae8c08d211e Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Sat, 5 Jun 2021 09:38:11 +0900 Subject: [PATCH 71/86] spi: convert Cadence SPI bindings to YAML Convert spi for Cadence SPI bindings documentation to YAML. Signed-off-by: Nobuhiro Iwamatsu Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210605003811.858676-1-iwamatsu@nigauri.org Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-cadence.txt | 30 --------- .../devicetree/bindings/spi/spi-cadence.yaml | 66 +++++++++++++++++++ 2 files changed, 66 insertions(+), 30 deletions(-) delete mode 100644 Documentation/devicetree/bindings/spi/spi-cadence.txt create mode 100644 Documentation/devicetree/bindings/spi/spi-cadence.yaml diff --git a/Documentation/devicetree/bindings/spi/spi-cadence.txt b/Documentation/devicetree/bindings/spi/spi-cadence.txt deleted file mode 100644 index 05a2ef945664..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-cadence.txt +++ /dev/null @@ -1,30 +0,0 @@ -Cadence SPI controller Device Tree Bindings -------------------------------------------- - -Required properties: -- compatible : Should be "cdns,spi-r1p6" or "xlnx,zynq-spi-r1p6". -- reg : Physical base address and size of SPI registers map. -- interrupts : Property with a value describing the interrupt - number. -- clock-names : List of input clock names - "ref_clk", "pclk" - (See clock bindings for details). -- clocks : Clock phandles (see clock bindings for details). - -Optional properties: -- num-cs : Number of chip selects used. - If a decoder is used, this will be the number of - chip selects after the decoder. -- is-decoded-cs : Flag to indicate whether decoder is used or not. - -Example: - - spi@e0007000 { - compatible = "xlnx,zynq-spi-r1p6"; - clock-names = "ref_clk", "pclk"; - clocks = <&clkc 26>, <&clkc 35>; - interrupt-parent = <&intc>; - interrupts = <0 49 4>; - num-cs = <4>; - is-decoded-cs = <0>; - reg = <0xe0007000 0x1000>; - } ; diff --git a/Documentation/devicetree/bindings/spi/spi-cadence.yaml b/Documentation/devicetree/bindings/spi/spi-cadence.yaml new file mode 100644 index 000000000000..9787be21318e --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-cadence.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/spi-cadence.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cadence SPI controller Device Tree Bindings + +maintainers: + - Michal Simek + +allOf: + - $ref: "spi-controller.yaml#" + +properties: + compatible: + enum: + - cdns,spi-r1p6 + - xlnx,zynq-spi-r1p6 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clock-names: + items: + - const: ref_clk + - const: pclk + + clocks: + maxItems: 2 + + num-cs: + description: | + Number of chip selects used. If a decoder is used, + this will be the number of chip selects after the + decoder. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 4 + default: 4 + + is-decoded-cs: + description: | + Flag to indicate whether decoder is used or not. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1 ] + default: 0 + +unevaluatedProperties: false + +examples: + - | + spi@e0007000 { + compatible = "xlnx,zynq-spi-r1p6"; + clock-names = "ref_clk", "pclk"; + clocks = <&clkc 26>, <&clkc 35>; + interrupt-parent = <&intc>; + interrupts = <0 49 4>; + num-cs = <4>; + is-decoded-cs = <0>; + reg = <0xe0007000 0x1000>; + }; +... From 476ad3ff8952db3569a77d9ed4a067c5f0f4b733 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Sat, 5 Jun 2021 09:29:31 +0900 Subject: [PATCH 72/86] spi: xilinx: convert to yaml Convert SPI for Xilinx bindings documentation to YAML schemas. Signed-off-by: Nobuhiro Iwamatsu Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210605002931.858031-1-iwamatsu@nigauri.org Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-xilinx.txt | 23 -------- .../devicetree/bindings/spi/spi-xilinx.yaml | 57 +++++++++++++++++++ 2 files changed, 57 insertions(+), 23 deletions(-) delete mode 100644 Documentation/devicetree/bindings/spi/spi-xilinx.txt create mode 100644 Documentation/devicetree/bindings/spi/spi-xilinx.yaml diff --git a/Documentation/devicetree/bindings/spi/spi-xilinx.txt b/Documentation/devicetree/bindings/spi/spi-xilinx.txt deleted file mode 100644 index 5f4ed3e5c994..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-xilinx.txt +++ /dev/null @@ -1,23 +0,0 @@ -Xilinx SPI controller Device Tree Bindings -------------------------------------------------- - -Required properties: -- compatible : Should be "xlnx,xps-spi-2.00.a", "xlnx,xps-spi-2.00.b" or "xlnx,axi-quad-spi-1.00.a" -- reg : Physical base address and size of SPI registers map. -- interrupts : Property with a value describing the interrupt - number. - -Optional properties: -- xlnx,num-ss-bits : Number of chip selects used. -- xlnx,num-transfer-bits : Number of bits per transfer. This will be 8 if not specified - -Example: - axi_quad_spi@41e00000 { - compatible = "xlnx,xps-spi-2.00.a"; - interrupt-parent = <&intc>; - interrupts = <0 31 1>; - reg = <0x41e00000 0x10000>; - xlnx,num-ss-bits = <0x1>; - xlnx,num-transfer-bits = <32>; - }; - diff --git a/Documentation/devicetree/bindings/spi/spi-xilinx.yaml b/Documentation/devicetree/bindings/spi/spi-xilinx.yaml new file mode 100644 index 000000000000..593f7693bace --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-xilinx.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/spi-xilinx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xilinx SPI controller Device Tree Bindings + +maintainers: + - Michal Simek + +allOf: + - $ref: "spi-controller.yaml#" + +properties: + compatible: + enum: + - xlnx,xps-spi-2.00.a + - xlnx,xps-spi-2.00.b + - xlnx,axi-quad-spi-1.00.a + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + xlnx,num-ss-bits: + description: Number of chip selects used. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 32 + + xlnx,num-transfer-bits: + description: Number of bits per transfer. This will be 8 if not specified. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [8, 16, 32] + default: 8 + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + spi0: spi@41e00000 { + compatible = "xlnx,xps-spi-2.00.a"; + interrupt-parent = <&intc>; + interrupts = <0 31 1>; + reg = <0x41e00000 0x10000>; + xlnx,num-ss-bits = <0x1>; + xlnx,num-transfer-bits = <32>; + }; +... From 0c79378c01999bd60057c475f163ec807c24891f Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 21 Jun 2021 19:53:55 +0200 Subject: [PATCH 73/86] spi: add ancillary device support Introduce support for ancillary devices, similar to existing implementation for I2C. This is useful for devices having multiple chip-selects, for example some microcontrollers provide a normal SPI interface and a flashing SPI interface. Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20210621175359.126729-2-sebastian.reichel@collabora.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 161 +++++++++++++++++++++++++++++----------- include/linux/spi/spi.h | 2 + 2 files changed, 120 insertions(+), 43 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 8553e7d48f66..572ad95c1d4f 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -564,6 +564,55 @@ static void spi_cleanup(struct spi_device *spi) spi->controller->cleanup(spi); } +static int __spi_add_device(struct spi_device *spi) +{ + struct spi_controller *ctlr = spi->controller; + struct device *dev = ctlr->dev.parent; + int status; + + status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check); + if (status) { + dev_err(dev, "chipselect %d already in use\n", + spi->chip_select); + return status; + } + + /* Controller may unregister concurrently */ + if (IS_ENABLED(CONFIG_SPI_DYNAMIC) && + !device_is_registered(&ctlr->dev)) { + return -ENODEV; + } + + /* Descriptors take precedence */ + if (ctlr->cs_gpiods) + spi->cs_gpiod = ctlr->cs_gpiods[spi->chip_select]; + else if (ctlr->cs_gpios) + spi->cs_gpio = ctlr->cs_gpios[spi->chip_select]; + + /* Drivers may modify this initial i/o setup, but will + * normally rely on the device being setup. Devices + * using SPI_CS_HIGH can't coexist well otherwise... + */ + status = spi_setup(spi); + if (status < 0) { + dev_err(dev, "can't setup %s, status %d\n", + dev_name(&spi->dev), status); + return status; + } + + /* Device may be bound to an active driver when this returns */ + status = device_add(&spi->dev); + if (status < 0) { + dev_err(dev, "can't add %s, status %d\n", + dev_name(&spi->dev), status); + spi_cleanup(spi); + } else { + dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev)); + } + + return status; +} + /** * spi_add_device - Add spi_device allocated with spi_alloc_device * @spi: spi_device to register @@ -594,54 +643,31 @@ int spi_add_device(struct spi_device *spi) * its configuration. Lock against concurrent add() calls. */ mutex_lock(&spi_add_lock); - - status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check); - if (status) { - dev_err(dev, "chipselect %d already in use\n", - spi->chip_select); - goto done; - } - - /* Controller may unregister concurrently */ - if (IS_ENABLED(CONFIG_SPI_DYNAMIC) && - !device_is_registered(&ctlr->dev)) { - status = -ENODEV; - goto done; - } - - /* Descriptors take precedence */ - if (ctlr->cs_gpiods) - spi->cs_gpiod = ctlr->cs_gpiods[spi->chip_select]; - else if (ctlr->cs_gpios) - spi->cs_gpio = ctlr->cs_gpios[spi->chip_select]; - - /* Drivers may modify this initial i/o setup, but will - * normally rely on the device being setup. Devices - * using SPI_CS_HIGH can't coexist well otherwise... - */ - status = spi_setup(spi); - if (status < 0) { - dev_err(dev, "can't setup %s, status %d\n", - dev_name(&spi->dev), status); - goto done; - } - - /* Device may be bound to an active driver when this returns */ - status = device_add(&spi->dev); - if (status < 0) { - dev_err(dev, "can't add %s, status %d\n", - dev_name(&spi->dev), status); - spi_cleanup(spi); - } else { - dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev)); - } - -done: + status = __spi_add_device(spi); mutex_unlock(&spi_add_lock); return status; } EXPORT_SYMBOL_GPL(spi_add_device); +static int spi_add_device_locked(struct spi_device *spi) +{ + struct spi_controller *ctlr = spi->controller; + struct device *dev = ctlr->dev.parent; + + /* Chipselects are numbered 0..max; validate. */ + if (spi->chip_select >= ctlr->num_chipselect) { + dev_err(dev, "cs%d >= max %d\n", spi->chip_select, + ctlr->num_chipselect); + return -EINVAL; + } + + /* Set the bus ID string */ + spi_dev_set_name(spi); + + WARN_ON(!mutex_is_locked(&spi_add_lock)); + return __spi_add_device(spi); +} + /** * spi_new_device - instantiate one new SPI device * @ctlr: Controller to which device is connected @@ -2125,6 +2151,55 @@ static void of_register_spi_devices(struct spi_controller *ctlr) static void of_register_spi_devices(struct spi_controller *ctlr) { } #endif +/** + * spi_new_ancillary_device() - Register ancillary SPI device + * @spi: Pointer to the main SPI device registering the ancillary device + * @chip_select: Chip Select of the ancillary device + * + * Register an ancillary SPI device; for example some chips have a chip-select + * for normal device usage and another one for setup/firmware upload. + * + * This may only be called from main SPI device's probe routine. + * + * Return: 0 on success; negative errno on failure + */ +struct spi_device *spi_new_ancillary_device(struct spi_device *spi, + u8 chip_select) +{ + struct spi_device *ancillary; + int rc = 0; + + /* Alloc an spi_device */ + ancillary = spi_alloc_device(spi->controller); + if (!ancillary) { + rc = -ENOMEM; + goto err_out; + } + + strlcpy(ancillary->modalias, "dummy", sizeof(ancillary->modalias)); + + /* Use provided chip-select for ancillary device */ + ancillary->chip_select = chip_select; + + /* Take over SPI mode/speed from SPI main device */ + ancillary->max_speed_hz = spi->max_speed_hz; + ancillary->mode = ancillary->mode; + + /* Register the new device */ + rc = spi_add_device_locked(ancillary); + if (rc) { + dev_err(&spi->dev, "failed to register ancillary device\n"); + goto err_out; + } + + return ancillary; + +err_out: + spi_dev_put(ancillary); + return ERR_PTR(rc); +} +EXPORT_SYMBOL_GPL(spi_new_ancillary_device); + #ifdef CONFIG_ACPI struct acpi_spi_lookup { struct spi_controller *ctlr; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index f924160e995f..3ada36175e5f 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -299,6 +299,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) driver_unregister(&sdrv->driver); } +extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 chip_select); + /* use a define to avoid include chaining to get THIS_MODULE */ #define spi_register_driver(driver) \ __spi_register_driver(THIS_MODULE, driver) From d90609a4b72dbfe42da2a55f3078c35e669948e0 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 21 Jun 2021 19:53:56 +0200 Subject: [PATCH 74/86] spi: dt-bindings: support devices with multiple chipselects Add binding support for devices, that have more than one chip select. A typical example are SPI connected microcontroller, that can also be programmed over SPI like NXP Kinetis or chips with a configuration and a data chip select, such as Microchip's MRF89XA transceiver. Reviewed-by: Rob Herring Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20210621175359.126729-3-sebastian.reichel@collabora.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-controller.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/spi-controller.yaml b/Documentation/devicetree/bindings/spi/spi-controller.yaml index 0477396e4945..faef4f6f55b8 100644 --- a/Documentation/devicetree/bindings/spi/spi-controller.yaml +++ b/Documentation/devicetree/bindings/spi/spi-controller.yaml @@ -114,8 +114,11 @@ patternProperties: Compatible of the SPI device. reg: - minimum: 0 - maximum: 256 + minItems: 1 + maxItems: 256 + items: + minimum: 0 + maximum: 256 description: Chip select used by the device. From 0d7993b234c9fad8cb6bec6adfaa74694ba85ecb Mon Sep 17 00:00:00 2001 From: Mirko Vogt Date: Mon, 14 Jun 2021 16:45:07 +0200 Subject: [PATCH 75/86] spi: spi-sun6i: Fix chipselect/clock bug The current sun6i SPI implementation initializes the transfer too early, resulting in SCK going high before the transfer. When using an additional (gpio) chipselect with sun6i, the chipselect is asserted at a time when clock is high, making the SPI transfer fail. This is due to SUN6I_GBL_CTL_BUS_ENABLE being written into SUN6I_GBL_CTL_REG at an early stage. Moving that to the transfer function, hence, right before the transfer starts, mitigates that problem. Fixes: 3558fe900e8af (spi: sunxi: Add Allwinner A31 SPI controller driver) Signed-off-by: Mirko Vogt Signed-off-by: Ralf Schlatterbeck Link: https://lore.kernel.org/r/20210614144507.y3udezjfbko7eavv@runtux.com Signed-off-by: Mark Brown --- drivers/spi/spi-sun6i.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index cc8401980125..23ad052528db 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -379,6 +379,10 @@ static int sun6i_spi_transfer_one(struct spi_master *master, } sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg); + /* Finally enable the bus - doing so before might raise SCK to HIGH */ + reg = sun6i_spi_read(sspi, SUN6I_GBL_CTL_REG); + reg |= SUN6I_GBL_CTL_BUS_ENABLE; + sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, reg); /* Setup the transfer now... */ if (sspi->tx_buf) @@ -504,7 +508,7 @@ static int sun6i_spi_runtime_resume(struct device *dev) } sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, - SUN6I_GBL_CTL_BUS_ENABLE | SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP); + SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP); return 0; From 0f4f58b847b23d79185ad20ecf629c9f913f4f41 Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Mon, 21 Jun 2021 18:47:56 +0800 Subject: [PATCH 76/86] spi: rockchip: add compatible string for rv1126 Add compatible string for rv1126 for potential applications. Signed-off-by: Jon Lin Link: https://lore.kernel.org/r/20210621104800.19088-3-jon.lin@rock-chips.com Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 52d6259d96ed..bbeed3ae4ee1 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -922,6 +922,7 @@ static const struct of_device_id rockchip_spi_dt_match[] = { { .compatible = "rockchip,rk3368-spi", }, { .compatible = "rockchip,rk3399-spi", }, { .compatible = "rockchip,rv1108-spi", }, + { .compatible = "rockchip,rv1126-spi", }, { }, }; MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match); From 4a47fcdb5f8b220a396e896a4efed51c13e27d8b Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Mon, 21 Jun 2021 18:47:57 +0800 Subject: [PATCH 77/86] spi: rockchip: Set rx_fifo interrupt waterline base on transfer item The error here is to calculate the width as 8 bits. In fact, 16 bits should be considered. Signed-off-by: Jon Lin Link: https://lore.kernel.org/r/20210621104800.19088-4-jon.lin@rock-chips.com Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index bbeed3ae4ee1..0887b19ef3ad 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -540,8 +540,8 @@ static int rockchip_spi_config(struct rockchip_spi *rs, * interrupt exactly when the fifo is full doesn't seem to work, * so we need the strict inequality here */ - if (xfer->len < rs->fifo_len) - writel_relaxed(xfer->len - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); + if ((xfer->len / rs->n_bytes) < rs->fifo_len) + writel_relaxed(xfer->len / rs->n_bytes - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); else writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); From 2758bd093ac35ca5b62dbecfd30dab60e8b59790 Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Mon, 21 Jun 2021 18:47:58 +0800 Subject: [PATCH 78/86] spi: rockchip: Wait for STB status in slave mode tx_xfer After ROCKCHIP_SPI_VER2_TYPE2, SR->STB is a more accurate judgment bit for spi slave transmition. Signed-off-by: Jon Lin Link: https://lore.kernel.org/r/20210621104800.19088-5-jon.lin@rock-chips.com Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 0887b19ef3ad..950d3bce443b 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -116,13 +116,14 @@ #define BAUDR_SCKDV_MIN 2 #define BAUDR_SCKDV_MAX 65534 -/* Bit fields in SR, 5bit */ -#define SR_MASK 0x1f +/* Bit fields in SR, 6bit */ +#define SR_MASK 0x3f #define SR_BUSY (1 << 0) #define SR_TF_FULL (1 << 1) #define SR_TF_EMPTY (1 << 2) #define SR_RF_EMPTY (1 << 3) #define SR_RF_FULL (1 << 4) +#define SR_SLAVE_TX_BUSY (1 << 5) /* Bit fields in ISR, IMR, ISR, RISR, 5bit */ #define INT_MASK 0x1f @@ -197,13 +198,19 @@ static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable) writel_relaxed((enable ? 1U : 0U), rs->regs + ROCKCHIP_SPI_SSIENR); } -static inline void wait_for_idle(struct rockchip_spi *rs) +static inline void wait_for_tx_idle(struct rockchip_spi *rs, bool slave_mode) { unsigned long timeout = jiffies + msecs_to_jiffies(5); do { - if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY)) - return; + if (slave_mode) { + if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_SLAVE_TX_BUSY) && + !((readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY))) + return; + } else { + if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY)) + return; + } } while (!time_after(jiffies, timeout)); dev_warn(rs->dev, "spi controller is in busy state!\n"); @@ -383,7 +390,7 @@ static void rockchip_spi_dma_txcb(void *data) return; /* Wait until the FIFO data completely. */ - wait_for_idle(rs); + wait_for_tx_idle(rs, ctlr->slave); spi_enable_chip(rs, false); spi_finalize_current_transfer(ctlr); @@ -545,7 +552,7 @@ static int rockchip_spi_config(struct rockchip_spi *rs, else writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); - writel_relaxed(rs->fifo_len / 2, rs->regs + ROCKCHIP_SPI_DMATDLR); + writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR); writel_relaxed(rockchip_spi_calc_burst_size(xfer->len / rs->n_bytes) - 1, rs->regs + ROCKCHIP_SPI_DMARDLR); writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR); From b8d423711d1870c5e1280d5bbb0639fe6638a60e Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Mon, 21 Jun 2021 18:48:47 +0800 Subject: [PATCH 79/86] spi: rockchip: Support cs-gpio 1.Add standard cs-gpio support 2.Refer to spi-controller.yaml for details Signed-off-by: Jon Lin Link: https://lore.kernel.org/r/20210621104848.19539-1-jon.lin@rock-chips.com Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 950d3bce443b..fbd750b1d28e 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -157,7 +157,8 @@ */ #define ROCKCHIP_SPI_MAX_TRANLEN 0xffff -#define ROCKCHIP_SPI_MAX_CS_NUM 2 +/* 2 for native cs, 2 for cs-gpio */ +#define ROCKCHIP_SPI_MAX_CS_NUM 4 #define ROCKCHIP_SPI_VER2_TYPE1 0x05EC0002 #define ROCKCHIP_SPI_VER2_TYPE2 0x00110002 @@ -245,11 +246,15 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) /* Keep things powered as long as CS is asserted */ pm_runtime_get_sync(rs->dev); - ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, - BIT(spi->chip_select)); + if (spi->cs_gpiod) + ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, 1); + else + ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select)); } else { - ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, - BIT(spi->chip_select)); + if (spi->cs_gpiod) + ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, 1); + else + ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select)); /* Drop reference from when we first asserted CS */ pm_runtime_put(rs->dev); From 736b81e075172f1e6cd7a8bc1a1374a2dee9e4dc Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Mon, 21 Jun 2021 18:48:48 +0800 Subject: [PATCH 80/86] spi: rockchip: Support SPI_CS_HIGH 1.Add standard spi-cs-high support 2.Refer to spi-controller.yaml for details Signed-off-by: Jon Lin Link: https://lore.kernel.org/r/20210621104848.19539-2-jon.lin@rock-chips.com Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index fbd750b1d28e..540861ca2ba3 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -107,6 +107,8 @@ #define CR0_OPM_MASTER 0x0 #define CR0_OPM_SLAVE 0x1 +#define CR0_SOI_OFFSET 23 + #define CR0_MTM_OFFSET 0x21 /* Bit fields in SER, 2bit */ @@ -236,7 +238,7 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) { struct spi_controller *ctlr = spi->controller; struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); - bool cs_asserted = !enable; + bool cs_asserted = spi->mode & SPI_CS_HIGH ? enable : !enable; /* Return immediately for no-op */ if (cs_asserted == rs->cs_asserted[spi->chip_select]) @@ -507,6 +509,8 @@ static int rockchip_spi_config(struct rockchip_spi *rs, cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET; if (spi->mode & SPI_LSB_FIRST) cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET; + if (spi->mode & SPI_CS_HIGH) + cr0 |= BIT(spi->chip_select) << CR0_SOI_OFFSET; if (xfer->rx_buf && xfer->tx_buf) cr0 |= CR0_XFM_TR << CR0_XFM_OFFSET; @@ -795,6 +799,14 @@ static int rockchip_spi_probe(struct platform_device *pdev) ctlr->can_dma = rockchip_spi_can_dma; } + switch (readl_relaxed(rs->regs + ROCKCHIP_SPI_VERSION)) { + case ROCKCHIP_SPI_VER2_TYPE2: + ctlr->mode_bits |= SPI_CS_HIGH; + break; + default: + break; + } + ret = devm_spi_register_controller(&pdev->dev, ctlr); if (ret < 0) { dev_err(&pdev->dev, "Failed to register controller\n"); From c58c7e9bf55ced301fdd9c8c1841361cc5fc8458 Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Mon, 21 Jun 2021 18:47:55 +0800 Subject: [PATCH 81/86] spi: spi-rockchip: add description for rv1126 The description below will be used for rv1126.dtsi or compatible one in the future Signed-off-by: Jon Lin Link: https://lore.kernel.org/r/20210621104800.19088-2-jon.lin@rock-chips.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-rockchip.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.yaml b/Documentation/devicetree/bindings/spi/spi-rockchip.yaml index 1e6cf29e6388..7f987e79337c 100644 --- a/Documentation/devicetree/bindings/spi/spi-rockchip.yaml +++ b/Documentation/devicetree/bindings/spi/spi-rockchip.yaml @@ -33,6 +33,7 @@ properties: - rockchip,rk3328-spi - rockchip,rk3368-spi - rockchip,rk3399-spi + - rockchip,rv1126-spi - const: rockchip,rk3066-spi reg: From 29176edd6e7ad7333d0bb19a309b2104fa4f4341 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 23 Jun 2021 11:58:42 +0200 Subject: [PATCH 82/86] spi: spi-rspi: : use proper DMAENGINE API for termination dmaengine_terminate_all() is deprecated in favor of explicitly saying if it should be sync or async. Here, we want dmaengine_terminate_sync() because there is no other synchronization code in the driver to handle an async case. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20210623095843.3228-2-wsa+renesas@sang-engineering.com Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index e39fd38f5180..d16ed88802d3 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -618,9 +618,9 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx, ret = -ETIMEDOUT; } if (tx) - dmaengine_terminate_all(rspi->ctlr->dma_tx); + dmaengine_terminate_sync(rspi->ctlr->dma_tx); if (rx) - dmaengine_terminate_all(rspi->ctlr->dma_rx); + dmaengine_terminate_sync(rspi->ctlr->dma_rx); } rspi_disable_irq(rspi, irq_mask); @@ -634,7 +634,7 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx, no_dma_tx: if (rx) - dmaengine_terminate_all(rspi->ctlr->dma_rx); + dmaengine_terminate_sync(rspi->ctlr->dma_rx); no_dma_rx: if (ret == -EAGAIN) { dev_warn_once(&rspi->ctlr->dev, From a26dee29ec04a3f6779684852c36a2a71fd68fd8 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 23 Jun 2021 11:58:43 +0200 Subject: [PATCH 83/86] spi: spi-sh-msiof: : use proper DMAENGINE API for termination dmaengine_terminate_all() is deprecated in favor of explicitly saying if it should be sync or async. Here, we want dmaengine_terminate_sync() because there is no other synchronization code in the driver to handle an async case. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20210623095843.3228-3-wsa+renesas@sang-engineering.com Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 41ed9ff8fad0..f88d9acd20d9 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -853,10 +853,10 @@ stop_reset: sh_msiof_spi_stop(p, rx); stop_dma: if (tx) - dmaengine_terminate_all(p->ctlr->dma_tx); + dmaengine_terminate_sync(p->ctlr->dma_tx); no_dma_tx: if (rx) - dmaengine_terminate_all(p->ctlr->dma_rx); + dmaengine_terminate_sync(p->ctlr->dma_rx); sh_msiof_write(p, SIIER, 0); return ret; } From b01d550663fa5fd40a1785b0f1211fb657892edf Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 23 Jun 2021 18:23:00 +0100 Subject: [PATCH 84/86] spi: Fix self assignment issue with ancillary->mode There is an assignment of ancillary->mode to itself which looks dubious since the proceeding comment states that the speed and mode is taken over from the SPI main device, indicating that ancillary->mode should assigned using the value spi->mode. Fix this. Addresses-Coverity: ("Self assignment") Fixes: 0c79378c0199 ("spi: add ancillary device support") Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20210623172300.161484-1-colin.king@canonical.com Signed-off-by: Mark Brown --- drivers/spi/spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 572ad95c1d4f..c296f08b36c1 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2183,7 +2183,7 @@ struct spi_device *spi_new_ancillary_device(struct spi_device *spi, /* Take over SPI mode/speed from SPI main device */ ancillary->max_speed_hz = spi->max_speed_hz; - ancillary->mode = ancillary->mode; + ancillary->mode = spi->mode; /* Register the new device */ rc = spi_add_device_locked(ancillary); From c58db2abb19fd2bf23fb25bb3630a9f540df6042 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Mon, 14 Jun 2021 06:43:17 +0900 Subject: [PATCH 85/86] spi: convert Xilinx Zynq UltraScale+ MPSoC GQSPI bindings to YAML Convert spi for Xilinx Zynq UltraScale+ MPSoC GQSPI bindings documentation to YAML. Signed-off-by: Nobuhiro Iwamatsu Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210613214317.296667-1-iwamatsu@nigauri.org Signed-off-by: Mark Brown --- .../bindings/spi/spi-zynqmp-qspi.txt | 25 --------- .../bindings/spi/spi-zynqmp-qspi.yaml | 51 +++++++++++++++++++ 2 files changed, 51 insertions(+), 25 deletions(-) delete mode 100644 Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.txt create mode 100644 Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml diff --git a/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.txt b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.txt deleted file mode 100644 index 0f6d37ff541c..000000000000 --- a/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.txt +++ /dev/null @@ -1,25 +0,0 @@ -Xilinx Zynq UltraScale+ MPSoC GQSPI controller Device Tree Bindings -------------------------------------------------------------------- - -Required properties: -- compatible : Should be "xlnx,zynqmp-qspi-1.0". -- reg : Physical base address and size of GQSPI registers map. -- interrupts : Property with a value describing the interrupt - number. -- clock-names : List of input clock names - "ref_clk", "pclk" - (See clock bindings for details). -- clocks : Clock phandles (see clock bindings for details). - -Optional properties: -- num-cs : Number of chip selects used. - -Example: - qspi: spi@ff0f0000 { - compatible = "xlnx,zynqmp-qspi-1.0"; - clock-names = "ref_clk", "pclk"; - clocks = <&misc_clk &misc_clk>; - interrupts = <0 15 4>; - interrupt-parent = <&gic>; - num-cs = <1>; - reg = <0x0 0xff0f0000 0x1000>,<0x0 0xc0000000 0x8000000>; - }; diff --git a/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml new file mode 100644 index 000000000000..ea72c8001256 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/spi-zynqmp-qspi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xilinx Zynq UltraScale+ MPSoC GQSPI controller Device Tree Bindings + +maintainers: + - Michal Simek + +allOf: + - $ref: "spi-controller.yaml#" + +properties: + compatible: + const: xlnx,zynqmp-qspi-1.0 + + reg: + maxItems: 2 + + interrupts: + maxItems: 1 + + clock-names: + items: + - const: ref_clk + - const: pclk + + clocks: + maxItems: 2 + +unevaluatedProperties: false + +examples: + - | + #include + soc { + #address-cells = <2>; + #size-cells = <2>; + + qspi: spi@ff0f0000 { + compatible = "xlnx,zynqmp-qspi-1.0"; + clocks = <&zynqmp_clk QSPI_REF>, <&zynqmp_clk LPD_LSBUS>; + clock-names = "ref_clk", "pclk"; + interrupts = <0 15 4>; + interrupt-parent = <&gic>; + reg = <0x0 0xff0f0000 0x0 0x1000>, + <0x0 0xc0000000 0x0 0x8000000>; + }; + }; From b470e10eb43f19e08245cd87dd3192a8141cfbb5 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 25 Jun 2021 10:52:11 +0530 Subject: [PATCH 86/86] spi: core: add dma_map_dev for dma device Some controllers like qcom geni need the parent device to be used for dma mapping, so add a dma_map_dev field and let drivers fill this to be used as mapping device Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20210625052213.32260-4-vkoul@kernel.org Signed-off-by: Mark Brown --- drivers/spi/spi.c | 4 ++++ include/linux/spi/spi.h | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index c296f08b36c1..35928d0843d9 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -993,11 +993,15 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) if (ctlr->dma_tx) tx_dev = ctlr->dma_tx->device->dev; + else if (ctlr->dma_map_dev) + tx_dev = ctlr->dma_map_dev; else tx_dev = ctlr->dev.parent; if (ctlr->dma_rx) rx_dev = ctlr->dma_rx->device->dev; + else if (ctlr->dma_map_dev) + rx_dev = ctlr->dma_map_dev; else rx_dev = ctlr->dev.parent; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 3ada36175e5f..97b8d12b5f2b 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -588,6 +588,7 @@ struct spi_controller { bool (*can_dma)(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *xfer); + struct device *dma_map_dev; /* * These hooks are for drivers that want to use the generic