From 0ed36990a93b23c4873c77cdc1423429e40ed469 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 15 Sep 2015 16:26:23 +0300 Subject: [PATCH 01/14] spi: dw: Remove needless if statements SPI core validates both bits_per_word and speed_hz transfer parameters and defaults to spi->bits_per_word and spi->max_speed_hz in case these per transfer parameters are not set. This allows to remove related if statements as they evaluate always to true and reduce indentation. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 4fbfcdc5cb24..2b5d736465c9 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -309,34 +309,29 @@ static int dw_spi_transfer_one(struct spi_master *master, cr0 = chip->cr0; /* Handle per transfer options for bpw and speed */ - if (transfer->speed_hz) { - speed = chip->speed_hz; + speed = chip->speed_hz; + if ((transfer->speed_hz != speed) || !chip->clk_div) { + speed = transfer->speed_hz; - if ((transfer->speed_hz != speed) || !chip->clk_div) { - speed = transfer->speed_hz; + /* clk_div doesn't support odd number */ + clk_div = (dws->max_freq / speed + 1) & 0xfffe; - /* clk_div doesn't support odd number */ - clk_div = (dws->max_freq / speed + 1) & 0xfffe; + chip->speed_hz = speed; + chip->clk_div = clk_div; - chip->speed_hz = speed; - chip->clk_div = clk_div; - - spi_set_clk(dws, chip->clk_div); - } + spi_set_clk(dws, chip->clk_div); } - if (transfer->bits_per_word) { - if (transfer->bits_per_word == 8) { - dws->n_bytes = 1; - dws->dma_width = 1; - } else if (transfer->bits_per_word == 16) { - dws->n_bytes = 2; - dws->dma_width = 2; - } - cr0 = (transfer->bits_per_word - 1) - | (chip->type << SPI_FRF_OFFSET) - | (spi->mode << SPI_MODE_OFFSET) - | (chip->tmode << SPI_TMOD_OFFSET); + if (transfer->bits_per_word == 8) { + dws->n_bytes = 1; + dws->dma_width = 1; + } else if (transfer->bits_per_word == 16) { + dws->n_bytes = 2; + dws->dma_width = 2; } + cr0 = (transfer->bits_per_word - 1) + | (chip->type << SPI_FRF_OFFSET) + | (spi->mode << SPI_MODE_OFFSET) + | (chip->tmode << SPI_TMOD_OFFSET); /* * Adjust transfer mode if necessary. Requires platform dependent From 55f9a0706f60df4639010c91d6f28ce6b2351179 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 15 Sep 2015 16:26:24 +0300 Subject: [PATCH 02/14] spi: dw: Remove test for non-zero spi->max_speed_hz Test for non-zero spi->max_speed_hz in dw_spi_setup() looks needless as spi_setup() defaults to master->max_speed_hz in case it is not set. This drivers sets the master->max_speed_hz based on max_freq data passed to it via dw_spi_add_host() call. I suppose things have already fallen apart if dw_spi_mmio_probe() or spi_pci_probe() ever passes zero max_freq. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 2b5d736465c9..1153d36ec8a6 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -448,11 +448,6 @@ static int dw_spi_setup(struct spi_device *spi) } chip->bits_per_word = spi->bits_per_word; - if (!spi->max_speed_hz) { - dev_err(&spi->dev, "No max speed HZ parameter\n"); - return -EINVAL; - } - chip->tmode = 0; /* Tx & Rx */ /* Default SPI mode is SCPOL = 0, SCPH = 0 */ chip->cr0 = (chip->bits_per_word - 1) From f9b841af4c1c3c3b7ce3552ab5ee5d9c430e9c29 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 9 Oct 2015 10:39:27 +0100 Subject: [PATCH 03/14] spi: spi-coldfire-qspi: enable RuntimePM before registering to the core The core may register clients attached to this master which may use funtionality from the master. So, RuntimePM must be enabled before, otherwise this will fail. Signed-off-by: Wolfram Sang Signed-off-by: Mark Brown --- drivers/spi/spi-coldfire-qspi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index 688956ff5095..23f6fffd75e1 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -420,19 +420,20 @@ static int mcfqspi_probe(struct platform_device *pdev) master->auto_runtime_pm = true; platform_set_drvdata(pdev, master); + pm_runtime_enable(&pdev->dev); status = devm_spi_register_master(&pdev->dev, master); if (status) { dev_dbg(&pdev->dev, "spi_register_master failed\n"); goto fail2; } - pm_runtime_enable(&pdev->dev); dev_info(&pdev->dev, "Coldfire QSPI bus driver\n"); return 0; fail2: + pm_runtime_disable(&pdev->dev); mcfqspi_cs_teardown(mcfqspi); fail1: clk_disable(mcfqspi->clk); From 5f0966e61f0a65bef26b9fedbc1a4ab22a6f918b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Oct 2015 23:12:17 +0300 Subject: [PATCH 04/14] spi: dw: use plain struct device * at earlier ->probe() The name of the master device is set during registrationg which happens after we issue the error message. Change it to plain struct device * to see which device registration failed. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 1153d36ec8a6..749a831f26ce 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -520,7 +520,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) ret = devm_request_irq(dev, dws->irq, dw_spi_irq, IRQF_SHARED, dws->name, master); if (ret < 0) { - dev_err(&master->dev, "can not get IRQ\n"); + dev_err(dev, "can not get IRQ\n"); goto err_free_master; } From 4adb1f8f880081ee9921ebd399786387e0cd6f52 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Oct 2015 23:12:18 +0300 Subject: [PATCH 05/14] spi: dw: remove unneeded cr0 member of struct chip_data Since we recalculate cr0 each time we start a transfer the chip_data->cr0 becomes redundant. Remove it and related pieces. This is a follow up to commit 0ed36990a93b (spi: dw: Remove needless if statements). Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 749a831f26ce..c769c2a5da16 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -30,7 +30,6 @@ /* Slave spi_dev related */ struct chip_data { - u16 cr0; u8 cs; /* chip select pin */ u8 n_bytes; /* current is a 1/2/4 byte op */ u8 tmode; /* TR/TO/RO/EEPROM */ @@ -291,7 +290,7 @@ static int dw_spi_transfer_one(struct spi_master *master, u16 txlevel = 0; u16 clk_div = 0; u32 speed = 0; - u32 cr0 = 0; + u32 cr0; int ret; dws->dma_mapped = 0; @@ -306,8 +305,6 @@ static int dw_spi_transfer_one(struct spi_master *master, spi_enable_chip(dws, 0); - cr0 = chip->cr0; - /* Handle per transfer options for bpw and speed */ speed = chip->speed_hz; if ((transfer->speed_hz != speed) || !chip->clk_div) { @@ -328,6 +325,7 @@ static int dw_spi_transfer_one(struct spi_master *master, dws->n_bytes = 2; dws->dma_width = 2; } + /* Default SPI mode is SCPOL = 0, SCPH = 0 */ cr0 = (transfer->bits_per_word - 1) | (chip->type << SPI_FRF_OFFSET) | (spi->mode << SPI_MODE_OFFSET) @@ -449,14 +447,6 @@ static int dw_spi_setup(struct spi_device *spi) chip->bits_per_word = spi->bits_per_word; chip->tmode = 0; /* Tx & Rx */ - /* Default SPI mode is SCPOL = 0, SCPH = 0 */ - chip->cr0 = (chip->bits_per_word - 1) - | (chip->type << SPI_FRF_OFFSET) - | (spi->mode << SPI_MODE_OFFSET) - | (chip->tmode << SPI_TMOD_OFFSET); - - if (spi->mode & SPI_LOOP) - chip->cr0 |= 1 << SPI_SRL_OFFSET; if (gpio_is_valid(spi->cs_gpio)) { ret = gpio_direction_output(spi->cs_gpio, From 863cb2f72e636c8721482fd88e256facb59c5737 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Oct 2015 23:12:20 +0300 Subject: [PATCH 06/14] spi: dw: remove bits_per_word member of struct chip_data There is no need to carry over spi->bits_per_word and Co from ->setup() in struct chip_data since ->transfer_one() will anyway take the transfer parameters from struct spi_transfer. This is since SPI core validates both bits_per_word transfer parameter and defaults to spi->bits_per_word in case that per transfer parameter is not set. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index c769c2a5da16..c8f7f161213d 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -31,17 +31,14 @@ /* Slave spi_dev related */ struct chip_data { u8 cs; /* chip select pin */ - u8 n_bytes; /* current is a 1/2/4 byte op */ u8 tmode; /* TR/TO/RO/EEPROM */ u8 type; /* SPI/SSP/MicroWire */ u8 poll_mode; /* 1 means use poll mode */ - u32 dma_width; u32 rx_threshold; u32 tx_threshold; u8 enable_dma; - u8 bits_per_word; u16 clk_div; /* baud rate divider */ u32 speed_hz; /* baud rate */ void (*cs_control)(u32 command); @@ -294,8 +291,6 @@ static int dw_spi_transfer_one(struct spi_master *master, int ret; dws->dma_mapped = 0; - dws->n_bytes = chip->n_bytes; - dws->dma_width = chip->dma_width; dws->tx = (void *)transfer->tx_buf; dws->tx_end = dws->tx + transfer->len; @@ -324,6 +319,8 @@ static int dw_spi_transfer_one(struct spi_master *master, } else if (transfer->bits_per_word == 16) { dws->n_bytes = 2; dws->dma_width = 2; + } else { + return -EINVAL; } /* Default SPI mode is SCPOL = 0, SCPH = 0 */ cr0 = (transfer->bits_per_word - 1) @@ -437,15 +434,6 @@ static int dw_spi_setup(struct spi_device *spi) chip->tx_threshold = 0; } - if (spi->bits_per_word == 8) { - chip->n_bytes = 1; - chip->dma_width = 1; - } else if (spi->bits_per_word == 16) { - chip->n_bytes = 2; - chip->dma_width = 2; - } - chip->bits_per_word = spi->bits_per_word; - chip->tmode = 0; /* Tx & Rx */ if (gpio_is_valid(spi->cs_gpio)) { From de6feda884b0079f5f232a41d94da23d198ff230 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Oct 2015 23:12:21 +0300 Subject: [PATCH 07/14] spi: dw: eliminate speed variable in ->transfer_one() There is no point to have a separate variable for speed in ->transfer_one(). While here, remove !chip->clk_div from a condition since it is assigned simultaneously with chip->speed_hz. We can do this safely because a) transfer speed can't be higher than max_freq and therefore chip->clk_div can be 0 only when chip->speed_hz is 0, and b) transfer speed can't be 0, otherwise we will get division by zero exception. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index c8f7f161213d..a6fd7cfa1b40 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -285,8 +285,7 @@ static int dw_spi_transfer_one(struct spi_master *master, struct chip_data *chip = spi_get_ctldata(spi); u8 imask = 0; u16 txlevel = 0; - u16 clk_div = 0; - u32 speed = 0; + u16 clk_div; u32 cr0; int ret; @@ -301,14 +300,11 @@ static int dw_spi_transfer_one(struct spi_master *master, spi_enable_chip(dws, 0); /* Handle per transfer options for bpw and speed */ - speed = chip->speed_hz; - if ((transfer->speed_hz != speed) || !chip->clk_div) { - speed = transfer->speed_hz; - + if (transfer->speed_hz != chip->speed_hz) { /* clk_div doesn't support odd number */ - clk_div = (dws->max_freq / speed + 1) & 0xfffe; + clk_div = (dws->max_freq / transfer->speed_hz + 1) & 0xfffe; - chip->speed_hz = speed; + chip->speed_hz = transfer->speed_hz; chip->clk_div = clk_div; spi_set_clk(dws, chip->clk_div); From d53c0ef319eb5ceb5a089ff3050a2e6808c9adb9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Oct 2015 23:12:22 +0300 Subject: [PATCH 08/14] spi: dw: eliminate unused threshold variables The tx_threshold and rx_threshold variables are not used anywhere. Remove them. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index a6fd7cfa1b40..c8e7715097e7 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -36,8 +36,6 @@ struct chip_data { u8 poll_mode; /* 1 means use poll mode */ - u32 rx_threshold; - u32 tx_threshold; u8 enable_dma; u16 clk_div; /* baud rate divider */ u32 speed_hz; /* baud rate */ @@ -425,9 +423,6 @@ static int dw_spi_setup(struct spi_device *spi) chip->poll_mode = chip_info->poll_mode; chip->type = chip_info->type; - - chip->rx_threshold = 0; - chip->tx_threshold = 0; } chip->tmode = 0; /* Tx & Rx */ From 1cc3f141f0cb5a822cdef30fb1d92ae6f4176bfa Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Oct 2015 23:12:23 +0300 Subject: [PATCH 09/14] spi: dw: introduce spi_shutdown_chip() This helper disables SPI controller and sets clock to 0. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 13 ++++++------- drivers/spi/spi-dw.h | 6 ++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index c8e7715097e7..a730c353d3bf 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -546,22 +546,21 @@ void dw_spi_remove_host(struct dw_spi *dws) if (dws->dma_ops && dws->dma_ops->dma_exit) dws->dma_ops->dma_exit(dws); - spi_enable_chip(dws, 0); - /* Disable clk */ - spi_set_clk(dws, 0); + + spi_shutdown_chip(dws); } EXPORT_SYMBOL_GPL(dw_spi_remove_host); int dw_spi_suspend_host(struct dw_spi *dws) { - int ret = 0; + int ret; ret = spi_master_suspend(dws->master); if (ret) return ret; - spi_enable_chip(dws, 0); - spi_set_clk(dws, 0); - return ret; + + spi_shutdown_chip(dws); + return 0; } EXPORT_SYMBOL_GPL(dw_spi_suspend_host); diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index b75ed327d5a2..35589a270468 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -225,6 +225,12 @@ static inline void spi_reset_chip(struct dw_spi *dws) spi_enable_chip(dws, 1); } +static inline void spi_shutdown_chip(struct dw_spi *dws) +{ + spi_enable_chip(dws, 0); + spi_set_clk(dws, 0); +} + /* * Each SPI slave device to work with dw_api controller should * has such a structure claiming its working mode (poll or PIO/DMA), From 1c2df965387f9a5a657a644bab5a1b5b535365b2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Oct 2015 23:12:24 +0300 Subject: [PATCH 10/14] spi: dw-pci: remove unused pdev member from struct dw_spi_pci The pdev member is not used anywhere, thus remove it. Moreover struct dw_spi_pci becomes an equivalent of struct dw_spi and therefore remove entire struct dw_spi_pci. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw-pci.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 6d331e0db331..332ccb0539a7 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -23,11 +23,6 @@ #define DRIVER_NAME "dw_spi_pci" -struct dw_spi_pci { - struct pci_dev *pdev; - struct dw_spi dws; -}; - struct spi_pci_desc { int (*setup)(struct dw_spi *); u16 num_cs; @@ -48,7 +43,6 @@ static struct spi_pci_desc spi_pci_mid_desc_2 = { static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct dw_spi_pci *dwpci; struct dw_spi *dws; struct spi_pci_desc *desc = (struct spi_pci_desc *)ent->driver_data; int pci_bar = 0; @@ -58,14 +52,10 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) return ret; - dwpci = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_pci), - GFP_KERNEL); - if (!dwpci) + dws = devm_kzalloc(&pdev->dev, sizeof(*dws), GFP_KERNEL); + if (!dws) return -ENOMEM; - dwpci->pdev = pdev; - dws = &dwpci->dws; - /* Get basic io resource and map it */ dws->paddr = pci_resource_start(pdev, pci_bar); @@ -74,7 +64,6 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return ret; dws->regs = pcim_iomap_table(pdev)[pci_bar]; - dws->irq = pdev->irq; /* @@ -99,7 +88,7 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return ret; /* PCI hook and SPI hook use the same drv data */ - pci_set_drvdata(pdev, dwpci); + pci_set_drvdata(pdev, dws); dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n", pdev->vendor, pdev->device); @@ -109,26 +98,26 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static void spi_pci_remove(struct pci_dev *pdev) { - struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); + struct dw_spi *dws = pci_get_drvdata(pdev); - dw_spi_remove_host(&dwpci->dws); + dw_spi_remove_host(dws); } #ifdef CONFIG_PM_SLEEP static int spi_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); - struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); + struct dw_spi *dws = pci_get_drvdata(pdev); - return dw_spi_suspend_host(&dwpci->dws); + return dw_spi_suspend_host(dws); } static int spi_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); - struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); + struct dw_spi *dws = pci_get_drvdata(pdev); - return dw_spi_resume_host(&dwpci->dws); + return dw_spi_resume_host(dws); } #endif From 9899995e98a4bc670a07e28ff91e3d0dbe08bea9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Oct 2015 23:12:25 +0300 Subject: [PATCH 11/14] spi: dw-mmio: convert to unified device property API Convert the driver to use unfied device property API instead of OF one. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw-mmio.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 7edede6e024b..a6d7029a85ac 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "spi-dw.h" @@ -74,13 +75,11 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) dws->max_freq = clk_get_rate(dwsmmio->clk); - of_property_read_u32(pdev->dev.of_node, "reg-io-width", - &dws->reg_io_width); + device_property_read_u32(&pdev->dev, "reg-io-width", &dws->reg_io_width); num_cs = 4; - if (pdev->dev.of_node) - of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs); + device_property_read_u32(&pdev->dev, "num-cs", &num_cs); dws->num_cs = num_cs; From 02f20387e1bca550639c37b1945f20cd32ddfcce Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Oct 2015 12:11:40 +0300 Subject: [PATCH 12/14] spi: dw: explicitly free IRQ handler in dw_spi_remove_host() The following warning occurs when DW SPI is compiled as a module and it's a PCI device. On the removal stage pcibios_free_irq() is called earlier than free_irq() due to the latter is called at managed resources free strage. ------------[ cut here ]------------ WARNING: CPU: 1 PID: 1003 at /home/andy/prj/linux/fs/proc/generic.c:575 remove_proc_entry+0x118/0x150() remove_proc_entry: removing non-empty directory 'irq/38', leaking at least 'dw_spi1' Modules linked in: spi_dw_midpci(-) spi_dw [last unloaded: dw_dmac_core] CPU: 1 PID: 1003 Comm: modprobe Not tainted 4.3.0-rc5-next-20151013+ #32 00000000 00000000 f5535d70 c12dc220 f5535db0 f5535da0 c104e912 c198a6bc f5535dcc 000003eb c198a638 0000023f c11b4098 c11b4098 f54f1ec8 f54f1ea0 f642ba20 f5535db8 c104e96e 00000009 f5535db0 c198a6bc f5535dcc f5535df0 Call Trace: [] dump_stack+0x41/0x61 [] warn_slowpath_common+0x82/0xb0 [] ? remove_proc_entry+0x118/0x150 [] ? remove_proc_entry+0x118/0x150 [] warn_slowpath_fmt+0x2e/0x30 [] remove_proc_entry+0x118/0x150 [] unregister_irq_proc+0xaa/0xc0 [] free_desc+0x1e/0x60 [] irq_free_descs+0x32/0x70 [] irq_domain_free_irqs+0x120/0x150 [] mp_unmap_irq+0x5c/0x60 [] intel_mid_pci_irq_disable+0x20/0x40 [] pcibios_free_irq+0xf/0x20 [] pci_device_remove+0x52/0xb0 [] __device_release_driver+0x77/0x100 [] driver_detach+0x87/0x90 [] bus_remove_driver+0x4a/0xc0 [] ? selinux_capable+0xd/0x10 [] driver_unregister+0x23/0x60 [] ? find_module_all+0x5a/0x80 [] pci_unregister_driver+0x13/0x60 [] dw_spi_driver_exit+0xd/0xf [spi_dw_midpci] [] SyS_delete_module+0x17a/0x210 Explicitly call free_irq() at removal stage of the DW SPI driver. Fixes: 04f421e7b0b1 (spi: dw: use managed resources) Cc: stable@vger.kernel.org Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index a730c353d3bf..221ff97557a3 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -486,8 +486,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60); snprintf(dws->name, sizeof(dws->name), "dw_spi%d", dws->bus_num); - ret = devm_request_irq(dev, dws->irq, dw_spi_irq, IRQF_SHARED, - dws->name, master); + ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dws->name, master); if (ret < 0) { dev_err(dev, "can not get IRQ\n"); goto err_free_master; @@ -532,6 +531,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) if (dws->dma_ops && dws->dma_ops->dma_exit) dws->dma_ops->dma_exit(dws); spi_enable_chip(dws, 0); + free_irq(dws->irq, master); err_free_master: spi_master_put(master); return ret; @@ -548,6 +548,8 @@ void dw_spi_remove_host(struct dw_spi *dws) dws->dma_ops->dma_exit(dws); spi_shutdown_chip(dws); + + free_irq(dws->irq, dws->master); } EXPORT_SYMBOL_GPL(dw_spi_remove_host); From f4aaa1c8a5c0e0a3fc565360df83965f3918c874 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Oct 2015 12:11:41 +0300 Subject: [PATCH 13/14] spi: dw: remove a NULL check when call ->remove() Currently all users aware about calling dw_spi_remove_host() with properly set parameter. Remove unneeded check. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 221ff97557a3..cc2e98037afd 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -540,8 +540,6 @@ EXPORT_SYMBOL_GPL(dw_spi_add_host); void dw_spi_remove_host(struct dw_spi *dws) { - if (!dws) - return; dw_spi_debugfs_remove(dws); if (dws->dma_ops && dws->dma_ops->dma_exit) From d7ef54ca1219ddf99d56a0f7cf40912ab4c4bb0b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 27 Oct 2015 17:48:16 +0200 Subject: [PATCH 14/14] spi: dw: replace magic constant by DW_SPI_DR The offset 0x60 is the offset of the data register defined as DW_SPI_DR in the header file. Use it. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index cc2e98037afd..882cd6618cd5 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -483,7 +483,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) dws->master = master; dws->type = SSI_MOTO_SPI; dws->dma_inited = 0; - dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60); + dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR); snprintf(dws->name, sizeof(dws->name), "dw_spi%d", dws->bus_num); ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dws->name, master);