From fcf0af445bfdb617993af352ee442471aeca1073 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 29 Aug 2014 12:41:39 +0300 Subject: [PATCH 01/21] spi: dw-pci: move info message at the end of probe Let's print info message when controller is found and properly initialized. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw-pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 3f3dc1226edf..0ac86a58dd27 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -40,9 +40,6 @@ static int spi_pci_probe(struct pci_dev *pdev, int pci_bar = 0; int ret; - dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n", - pdev->vendor, pdev->device); - ret = pcim_enable_device(pdev); if (ret) return ret; @@ -83,6 +80,9 @@ static int spi_pci_probe(struct pci_dev *pdev, /* PCI hook and SPI hook use the same drv data */ pci_set_drvdata(pdev, dwpci); + dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n", + pdev->vendor, pdev->device); + return 0; } From ceb86de9d6dae58b66ae10e7533ff2d3d8c7bbae Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 29 Aug 2014 12:41:40 +0300 Subject: [PATCH 02/21] spi: dw-pci: apply pci_bar and re-use pci_name Nevertheless pci_bar is 0 let's explicitly use it when map IO regions. While here, use pci_name instead of dev_name. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 0ac86a58dd27..e203d8fc0ce6 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -55,7 +55,7 @@ static int spi_pci_probe(struct pci_dev *pdev, /* Get basic io resource and map it */ dws->paddr = pci_resource_start(pdev, pci_bar); - ret = pcim_iomap_regions(pdev, 1, dev_name(&pdev->dev)); + ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev)); if (ret) return ret; From 35f2d4136477ce2cd684b03e7f1b802963750394 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 29 Aug 2014 12:41:41 +0300 Subject: [PATCH 03/21] spi: dw-pci: convert to use dev_pm_ops Convert system PM callbacks to use dev_pm_ops. In addition remove the PCI calls related to a power state since the bus code cares about this already. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw-pci.c | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index e203d8fc0ce6..9e8d18cac03f 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -93,38 +93,26 @@ static void spi_pci_remove(struct pci_dev *pdev) dw_spi_remove_host(&dwpci->dws); } -#ifdef CONFIG_PM -static int spi_suspend(struct pci_dev *pdev, pm_message_t state) +#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); - int ret; - ret = dw_spi_suspend_host(&dwpci->dws); - if (ret) - return ret; - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return ret; + return dw_spi_suspend_host(&dwpci->dws); } -static int spi_resume(struct pci_dev *pdev) +static int spi_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); - int ret; - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - ret = pci_enable_device(pdev); - if (ret) - return ret; return dw_spi_resume_host(&dwpci->dws); } -#else -#define spi_suspend NULL -#define spi_resume NULL #endif +static SIMPLE_DEV_PM_OPS(dw_spi_pm_ops, spi_suspend, spi_resume); + static const struct pci_device_id pci_ids[] = { /* Intel MID platform SPI controller 0 */ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) }, @@ -136,8 +124,9 @@ static struct pci_driver dw_spi_driver = { .id_table = pci_ids, .probe = spi_pci_probe, .remove = spi_pci_remove, - .suspend = spi_suspend, - .resume = spi_resume, + .driver = { + .pm = &dw_spi_pm_ops, + }, }; module_pci_driver(dw_spi_driver); From c95791b6a5c5f18addb41530d1c27c8f5d612d65 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 29 Aug 2014 12:41:42 +0300 Subject: [PATCH 04/21] spi: dw-pci: provide platform specific data via driver_data Instead of checking for device and vendor IDs inside probe function let's provide a helper function via driver_data. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw-pci.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 9e8d18cac03f..958bc4600877 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -32,11 +32,19 @@ struct dw_spi_pci { struct dw_spi dws; }; -static int spi_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) +struct spi_pci_desc { + int (*setup)(struct dw_spi *); +}; + +static struct spi_pci_desc spi_pci_mid_desc = { + .setup = dw_spi_mid_init, +}; + +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; int ret; @@ -64,11 +72,11 @@ static int spi_pci_probe(struct pci_dev *pdev, dws->irq = pdev->irq; /* - * Specific handling for Intel MID paltforms, like dma setup, + * Specific handling for paltforms, like dma setup, * clock rate, FIFO depth. */ - if (pdev->device == 0x0800) { - ret = dw_spi_mid_init(dws); + if (desc && desc->setup) { + ret = desc->setup(dws); if (ret) return ret; } @@ -115,7 +123,7 @@ static SIMPLE_DEV_PM_OPS(dw_spi_pm_ops, spi_suspend, spi_resume); static const struct pci_device_id pci_ids[] = { /* Intel MID platform SPI controller 0 */ - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) }, + { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc}, {}, }; From 5dc23c442101d254246d88766c4423696b9aa9bd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 29 Aug 2014 12:41:43 +0300 Subject: [PATCH 05/21] spi: dw-pci: remove FSF address and update copyright The FSF address is subject to change, thus remove it from the file. While here, update a copyright line. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw-pci.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 958bc4600877..c90a45009b9b 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -1,7 +1,7 @@ /* * PCI interface driver for DW SPI Core * - * Copyright (c) 2009, Intel Corporation. + * Copyright (c) 2009, 2014 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -11,10 +11,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ #include From 05ed2aee3e97c9cfb737388706b439264e27eb0c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 12 Sep 2014 15:11:57 +0300 Subject: [PATCH 06/21] spi: dw: remove FSF address There is no need to keep FSF address in the head of the file. While here, fix few typos in the header. There is no functional change. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 4 ---- drivers/spi/spi-dw.h | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 29f33143b795..6e55334c239a 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -11,10 +11,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ #include diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 6d2acad34f64..fcd12b6b4697 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -217,11 +217,11 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask) * Each SPI slave device to work with dw_api controller should * has such a structure claiming its working mode (PIO/DMA etc), * which can be save in the "controller_data" member of the - * struct spi_device + * struct spi_device. */ struct dw_spi_chip { - u8 poll_mode; /* 0 for contoller polling mode */ - u8 type; /* SPI/SSP/Micrwire */ + u8 poll_mode; /* 1 for controller polling mode */ + u8 type; /* SPI/SSP/MicroWire */ u8 enable_dma; void (*cs_control)(u32 command); }; From fb57862ead652454ceeb659617404c5f13bc34b5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 12 Sep 2014 15:11:58 +0300 Subject: [PATCH 07/21] spi: dw-mid: check that DMA was inited before exit If the driver was compiled with DMA support, but DMA channels weren't acquired by some reason, mid_spi_dma_exit() will crash the kernel. Fixes: 7063c0d942a1 (spi/dw_spi: add DMA support) Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw-mid.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index 6d207afec8cb..0d88e4aab73e 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -89,6 +89,8 @@ err_exit: static void mid_spi_dma_exit(struct dw_spi *dws) { + if (!dws->dma_inited) + return; dma_release_channel(dws->txchan); dma_release_channel(dws->rxchan); } From ea092455d713d28c0b74a2ebe022524025d97491 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 12 Sep 2014 15:11:59 +0300 Subject: [PATCH 08/21] spi: dw-mid: remove Moorestown support The support of the Moorestown was removed [1] from kernel long time ago. This is just a follow up of that change. [1] http://www.spinics.net/lists/platform-driver-x86/msg02948.html Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- drivers/spi/spi-dw-mid.c | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 62e2242ad7e0..6343df87afb3 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -591,7 +591,7 @@ config SPI_DW_PCI depends on SPI_DESIGNWARE && PCI config SPI_DW_MID_DMA - bool "DMA support for DW SPI controller on Intel Moorestown platform" + bool "DMA support for DW SPI controller on Intel MID platform" depends on SPI_DW_PCI && INTEL_MID_DMAC config SPI_DW_MMIO diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index 0d88e4aab73e..deba3c459d68 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -50,11 +50,9 @@ static int mid_spi_dma_init(struct dw_spi *dws) /* * Get pci device for DMA controller, currently it could only - * be the DMA controller of either Moorestown or Medfield + * be the DMA controller of Medfield */ - dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0813, NULL); - if (!dws->dmac) - dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL); + dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL); dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); @@ -192,7 +190,7 @@ static struct dw_spi_dma_ops mid_dma_ops = { }; #endif -/* Some specific info for SPI0 controller on Moorestown */ +/* Some specific info for SPI0 controller on Intel MID */ /* HW info for MRST CLk Control Unit, one 32b reg */ #define MRST_SPI_CLK_BASE 100000000 /* 100m */ From b89e9c87dd3b118f0b953d349e5bede1505e3bc5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 12 Sep 2014 15:12:00 +0300 Subject: [PATCH 09/21] spi: dw-mid: remove redundant dmac member Instead of using that member we prefer to use dma_dev which represents actual struct device of the DMA device. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw-mid.c | 12 ++++++++---- drivers/spi/spi-dw.h | 1 - 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index deba3c459d68..9ae2eaa228fd 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -39,12 +39,13 @@ static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param) { struct dw_spi *dws = param; - return dws->dmac && (&dws->dmac->dev == chan->device->dev); + return dws->dma_dev == chan->device->dev; } static int mid_spi_dma_init(struct dw_spi *dws) { struct mid_dma *dw_dma = dws->dma_priv; + struct pci_dev *dma_dev; struct intel_mid_dma_slave *rxs, *txs; dma_cap_mask_t mask; @@ -52,7 +53,11 @@ static int mid_spi_dma_init(struct dw_spi *dws) * Get pci device for DMA controller, currently it could only * be the DMA controller of Medfield */ - dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL); + dma_dev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL); + if (!dma_dev) + return -ENODEV; + + dws->dma_dev = &dma_dev->dev; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); @@ -81,8 +86,7 @@ static int mid_spi_dma_init(struct dw_spi *dws) free_rxchan: dma_release_channel(dws->rxchan); err_exit: - return -1; - + return -EBUSY; } static void mid_spi_dma_exit(struct dw_spi *dws) diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index fcd12b6b4697..089fc4ba3ace 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -140,7 +140,6 @@ struct dw_spi { dma_addr_t dma_addr; /* phy address of the Data register */ struct dw_spi_dma_ops *dma_ops; void *dma_priv; /* platform relate info */ - struct pci_dev *dmac; /* Bus interface info */ void *priv; From 197e96b4d80554a66aff34df5406b4c2d26f0111 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 12 Sep 2014 15:12:01 +0300 Subject: [PATCH 10/21] spi: dw-mid: remove FSF address and update copyright The FSF address is subject to change, thus remove it from the file. While here, update a copyright line. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw-mid.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index 9ae2eaa228fd..c4b9f6497d5b 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -1,7 +1,7 @@ /* * Special handling for DW core on Intel MID platform * - * Copyright (c) 2009, Intel Corporation. + * Copyright (c) 2009, 2014 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -11,10 +11,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ #include From 53288fe9bdc7e8a0265bbe9074f71f1a6c478008 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 12 Sep 2014 15:11:56 +0300 Subject: [PATCH 11/21] spi: dw: don't use mrst prefix anymore Since driver is used on other platforms and debugfs stuff would be useful there as well let's substitute mrst_ by dw_ where it suits. Additionally let's use SPI master device name when print registers dump. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index fdb5a6d1c8c6..e2f7c5c0f4ba 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -55,22 +55,20 @@ struct chip_data { #ifdef CONFIG_DEBUG_FS #define SPI_REGS_BUFSIZE 1024 -static ssize_t spi_show_regs(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t dw_spi_show_regs(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { - struct dw_spi *dws; + struct dw_spi *dws = file->private_data; char *buf; u32 len = 0; ssize_t ret; - dws = file->private_data; - buf = kzalloc(SPI_REGS_BUFSIZE, GFP_KERNEL); if (!buf) return 0; len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, - "MRST SPI0 registers:\n"); + "%s registers:\n", dev_name(&dws->master->dev)); len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, "=================================\n"); len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, @@ -106,41 +104,41 @@ static ssize_t spi_show_regs(struct file *file, char __user *user_buf, len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, "=================================\n"); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); kfree(buf); return ret; } -static const struct file_operations mrst_spi_regs_ops = { +static const struct file_operations dw_spi_regs_ops = { .owner = THIS_MODULE, .open = simple_open, - .read = spi_show_regs, + .read = dw_spi_show_regs, .llseek = default_llseek, }; -static int mrst_spi_debugfs_init(struct dw_spi *dws) +static int dw_spi_debugfs_init(struct dw_spi *dws) { - dws->debugfs = debugfs_create_dir("mrst_spi", NULL); + dws->debugfs = debugfs_create_dir("dw_spi", NULL); if (!dws->debugfs) return -ENOMEM; debugfs_create_file("registers", S_IFREG | S_IRUGO, - dws->debugfs, (void *)dws, &mrst_spi_regs_ops); + dws->debugfs, (void *)dws, &dw_spi_regs_ops); return 0; } -static void mrst_spi_debugfs_remove(struct dw_spi *dws) +static void dw_spi_debugfs_remove(struct dw_spi *dws) { debugfs_remove_recursive(dws->debugfs); } #else -static inline int mrst_spi_debugfs_init(struct dw_spi *dws) +static inline int dw_spi_debugfs_init(struct dw_spi *dws) { return 0; } -static inline void mrst_spi_debugfs_remove(struct dw_spi *dws) +static inline void dw_spi_debugfs_remove(struct dw_spi *dws) { } #endif /* CONFIG_DEBUG_FS */ @@ -682,7 +680,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) goto err_dma_exit; } - mrst_spi_debugfs_init(dws); + dw_spi_debugfs_init(dws); return 0; err_dma_exit: @@ -699,7 +697,7 @@ void dw_spi_remove_host(struct dw_spi *dws) { if (!dws) return; - mrst_spi_debugfs_remove(dws); + dw_spi_debugfs_remove(dws); if (dws->dma_ops && dws->dma_ops->dma_exit) dws->dma_ops->dma_exit(dws); From 2be01d29f8555d5afe0c7c4bea6b306b0c31f17f Mon Sep 17 00:00:00 2001 From: Oscar Utbult Date: Tue, 16 Sep 2014 12:52:13 +0200 Subject: [PATCH 12/21] spi-summary: documentation mistake Contributors are not listed in alphabetical order as claimed by documentation. Signed-off-by: Oscar Utbult Signed-off-by: Mark Brown --- Documentation/spi/spi-summary | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary index 7982bcc4d151..d29734bff28c 100644 --- a/Documentation/spi/spi-summary +++ b/Documentation/spi/spi-summary @@ -601,13 +601,13 @@ THANKS TO Contributors to Linux-SPI discussions include (in alphabetical order, by last name): +Mark Brown David Brownell Russell King +Grant Likely Dmitry Pervushin Stephen Street Mark Underwood Andrew Victor -Vitaly Wool -Grant Likely -Mark Brown Linus Walleij +Vitaly Wool From 365a7bb32e097a8501a6a70b9225abcb09924f8c Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Tue, 16 Sep 2014 14:25:05 +0300 Subject: [PATCH 13/21] spi: davinci: add support for adding delay between word's transmissions This patch adds ability to configure delay between transmission of words over SPI bus if it's required by SPI slave devices. New optional SPI slave property: - ti,spi-word-delay : delay between transmission of words (SPIFMTn.WDELAY, SPIDAT1.WDEL) Signed-off-by: Murali Karicheri Signed-off-by: Grygorii Strashko Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-davinci.txt | 30 ++++++++++ drivers/spi/spi-davinci.c | 55 ++++++++++++++++--- 2 files changed, 78 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/spi-davinci.txt b/Documentation/devicetree/bindings/spi/spi-davinci.txt index f80887bca0d6..12ecfe9e3599 100644 --- a/Documentation/devicetree/bindings/spi/spi-davinci.txt +++ b/Documentation/devicetree/bindings/spi/spi-davinci.txt @@ -1,5 +1,10 @@ Davinci SPI controller device bindings +Links on DM: +Keystone 2 - http://www.ti.com/lit/ug/sprugp2a/sprugp2a.pdf +dm644x - http://www.ti.com/lit/ug/sprue32a/sprue32a.pdf +OMAP-L138/da830 - http://www.ti.com/lit/ug/spruh77a/spruh77a.pdf + Required properties: - #address-cells: number of cells required to define a chip select address on the SPI bus. Should be set to 1. @@ -24,6 +29,30 @@ Optional: cs-gpios = <0>, <0>, <0>, <&gpio1 30 0>, <&gpio1 31 0>; where first three are internal CS and last two are GPIO CS. +Optional properties for slave devices: +SPI slave nodes can contain the following properties. +Not all SPI Peripherals from Texas Instruments support this. +Please check SPI peripheral documentation for a device before using these. + +- ti,spi-wdelay : delay between transmission of words + (SPIFMTn.WDELAY, SPIDAT1.WDEL) must be specified in number of SPI module + clock periods. + + delay = WDELAY * SPI_module_clock_period + 2 * SPI_module_clock_period + +Below is timing diagram which shows functional meaning of +"ti,spi-wdelay" parameter. + + +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +SPI_CLK | | | | | | | | | | | | | | | | + +----------+ +-+ +-+ +-+ +-+ +---------------------------+ +-+ +-+ +- + +SPI_SOMI/SIMO+-----------------+ +----------- + +----------+ word1 +---------------------------+word2 + +-----------------+ +----------- + WDELAY + <--------------------------> + Example of a NOR flash slave device (n25q032) connected to DaVinci SPI controller device over the SPI bus. @@ -43,6 +72,7 @@ spi0:spi@20BF0000 { compatible = "st,m25p32"; spi-max-frequency = <25000000>; reg = <0>; + ti,spi-wdelay = <8>; partition@0 { label = "u-boot-spl"; diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 84a9fb1ab984..25886d8a84ba 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -65,6 +65,7 @@ /* SPIDAT1 (upper 16 bit defines) */ #define SPIDAT1_CSHOLD_MASK BIT(12) +#define SPIDAT1_WDEL BIT(10) /* SPIGCR1 */ #define SPIGCR1_CLKMOD_MASK BIT(1) @@ -209,6 +210,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) { struct davinci_spi *dspi; struct davinci_spi_platform_data *pdata; + struct davinci_spi_config *spicfg = spi->controller_data; u8 chip_sel = spi->chip_select; u16 spidat1 = CS_DEFAULT; bool gpio_chipsel = false; @@ -223,6 +225,10 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) gpio = spi->cs_gpio; } + /* program delay transfers if tx_delay is non zero */ + if (spicfg->wdelay) + spidat1 |= SPIDAT1_WDEL; + /* * Board specific chip select logic decides the polarity and cs * line for the controller @@ -237,9 +243,9 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) spidat1 |= SPIDAT1_CSHOLD_MASK; spidat1 &= ~(0x1 << chip_sel); } - - iowrite16(spidat1, dspi->base + SPIDAT1 + 2); } + + iowrite16(spidat1, dspi->base + SPIDAT1 + 2); } /** @@ -285,7 +291,7 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, int prescale; dspi = spi_master_get_devdata(spi->master); - spicfg = (struct davinci_spi_config *)spi->controller_data; + spicfg = spi->controller_data; if (!spicfg) spicfg = &davinci_spi_default_cfg; @@ -332,6 +338,14 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, if (!(spi->mode & SPI_CPHA)) spifmt |= SPIFMT_PHASE_MASK; + /* + * Assume wdelay is used only on SPI peripherals that has this field + * in SPIFMTn register and when it's configured from board file or DT. + */ + if (spicfg->wdelay) + spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT) + & SPIFMT_WDELAY_MASK); + /* * Version 1 hardware supports two basic SPI modes: * - Standard SPI mode uses 4 pins, with chipselect @@ -349,9 +363,6 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, u32 delay = 0; - spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT) - & SPIFMT_WDELAY_MASK); - if (spicfg->odd_parity) spifmt |= SPIFMT_ODD_PARITY_MASK; @@ -383,6 +394,26 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, return 0; } +static int davinci_spi_of_setup(struct spi_device *spi) +{ + struct davinci_spi_config *spicfg = spi->controller_data; + struct device_node *np = spi->dev.of_node; + u32 prop; + + if (spicfg == NULL && np) { + spicfg = kzalloc(sizeof(*spicfg), GFP_KERNEL); + if (!spicfg) + return -ENOMEM; + *spicfg = davinci_spi_default_cfg; + /* override with dt configured values */ + if (!of_property_read_u32(np, "ti,spi-wdelay", &prop)) + spicfg->wdelay = (u8)prop; + spi->controller_data = spicfg; + } + + return 0; +} + /** * davinci_spi_setup - This functions will set default transfer method * @spi: spi device on which data transfer to be done @@ -433,7 +464,16 @@ static int davinci_spi_setup(struct spi_device *spi) else clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK); - return retval; + return davinci_spi_of_setup(spi); +} + +static void davinci_spi_cleanup(struct spi_device *spi) +{ + struct davinci_spi_config *spicfg = spi->controller_data; + + spi->controller_data = NULL; + if (spi->dev.of_node) + kfree(spicfg); } static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status) @@ -947,6 +987,7 @@ static int davinci_spi_probe(struct platform_device *pdev) master->num_chipselect = pdata->num_chipselect; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16); master->setup = davinci_spi_setup; + master->cleanup = davinci_spi_cleanup; dspi->bitbang.chipselect = davinci_spi_chipselect; dspi->bitbang.setup_transfer = davinci_spi_setup_transfer; From b41583e7299046abdc578c33f25ed83ee95b9b31 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 18 Sep 2014 20:08:51 +0300 Subject: [PATCH 14/21] spi: dw-mid: respect 8 bit mode In case of 8 bit mode and DMA usage we end up with every second byte written as 0. We have to respect bits_per_word settings what this patch actually does. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-dw-mid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index c4b9f6497d5b..f7f0ad285ae6 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -136,7 +136,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) txconf.dst_addr = dws->dma_addr; txconf.dst_maxburst = LNW_DMA_MSIZE_16; txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + txconf.dst_addr_width = dws->dma_width; txconf.device_fc = false; txchan->device->device_control(txchan, DMA_SLAVE_CONFIG, @@ -159,7 +159,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) rxconf.src_addr = dws->dma_addr; rxconf.src_maxburst = LNW_DMA_MSIZE_16; rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + rxconf.src_addr_width = dws->dma_width; rxconf.device_fc = false; rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG, From 8e45ef682cb31fda62ed4eeede5d9745a0a1b1e2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 18 Sep 2014 20:08:53 +0300 Subject: [PATCH 15/21] spi: dw-mid: terminate ongoing transfers at exit Do full clean up at exit, means terminate all ongoing DMA transfers. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-dw-mid.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index f7f0ad285ae6..ecae30fe28af 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -89,7 +89,11 @@ static void mid_spi_dma_exit(struct dw_spi *dws) { if (!dws->dma_inited) return; + + dmaengine_terminate_all(dws->txchan); dma_release_channel(dws->txchan); + + dmaengine_terminate_all(dws->rxchan); dma_release_channel(dws->rxchan); } From c3ce15bf2ae5cde3392944ad043b80f123510cde Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 18 Sep 2014 20:08:56 +0300 Subject: [PATCH 16/21] spi: dw: introduce support of loopback mode For testing purposes it's good to have a loopback mode enabled. The patch adds necessary bits for that. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index e2f7c5c0f4ba..7064cd008539 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -591,6 +591,9 @@ static int dw_spi_setup(struct spi_device *spi) | (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, !(spi->mode & SPI_CS_HIGH)); @@ -652,7 +655,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) goto err_free_master; } - master->mode_bits = SPI_CPOL | SPI_CPHA; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP; master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); master->bus_num = dws->bus_num; master->num_chipselect = dws->num_cs; From c3c6e231d860774037e7001ff3d536e5644fe2da Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 18 Sep 2014 20:08:57 +0300 Subject: [PATCH 17/21] spi: dw: fix style of code in few places Make comments be surrounded by spaces and move part of code to one line where it suits 80 characters. There is no functional changes. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 7064cd008539..6bb484919e58 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -390,7 +390,7 @@ static void pump_transfers(unsigned long data) goto early_exit; } - /* Delay if requested at end of transfer*/ + /* Delay if requested at end of transfer */ if (message->state == RUNNING_STATE) { previous = list_entry(transfer->transfer_list.prev, struct spi_transfer, @@ -519,7 +519,7 @@ static int dw_spi_transfer_one_message(struct spi_master *master, struct dw_spi *dws = spi_master_get_devdata(master); dws->cur_msg = msg; - /* Initial message state*/ + /* Initial message state */ dws->cur_msg->state = START_STATE; dws->cur_transfer = list_entry(dws->cur_msg->transfers.next, struct spi_transfer, @@ -645,8 +645,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) dws->prev_chip = NULL; dws->dma_inited = 0; dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60); - snprintf(dws->name, sizeof(dws->name), "dw_spi%d", - dws->bus_num); + 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, dws); From a31083600476ac11b656bbc70784767f231469ff Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Mon, 29 Sep 2014 10:57:06 +0800 Subject: [PATCH 18/21] spi: fsl: Sort include headers alphabetically Sort all the include headers alphabetically for the freescale spi drivers. If the inlcude headers sorted out of order, maybe the best logical choice is to append new ones after the exist ones, while this may create a lot of potential for duplicates and conflicts for each diffenent changes will add new headers in the same location. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-cpm.c | 14 +++++++------- drivers/spi/spi-fsl-dspi.c | 24 ++++++++++++------------ drivers/spi/spi-fsl-espi.c | 12 ++++++------ drivers/spi/spi-fsl-lib.c | 6 +++--- drivers/spi/spi-fsl-spi.c | 22 +++++++++++----------- 5 files changed, 39 insertions(+), 39 deletions(-) diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c index 54b06376f03c..c5dd20beee22 100644 --- a/drivers/spi/spi-fsl-cpm.c +++ b/drivers/spi/spi-fsl-cpm.c @@ -15,17 +15,17 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include -#include "spi-fsl-lib.h" #include "spi-fsl-cpm.h" +#include "spi-fsl-lib.h" #include "spi-fsl-spi.h" /* CPM1 and CPM2 are mutually exclusive. */ diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 5021ddf03f60..63c3859d24cf 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -13,22 +13,22 @@ * */ +#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include #define DRIVER_NAME "fsl-dspi" diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 8ebd724e4c59..68b4254069c0 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -8,19 +8,19 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ -#include #include -#include -#include -#include +#include #include +#include +#include +#include #include #include #include #include #include -#include -#include +#include +#include #include #include "spi-fsl-lib.h" diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c index e0b773fc29cb..5ddb5b098e4e 100644 --- a/drivers/spi/spi-fsl-lib.c +++ b/drivers/spi/spi-fsl-lib.c @@ -16,10 +16,10 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ -#include -#include -#include #include +#include +#include +#include #include #include #include diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 9452f6740997..c15a34ba71f5 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -19,25 +19,25 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ -#include -#include -#include -#include #include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include #include +#include #include #include -#include #include #include -#include #include +#include +#include +#include +#include +#include #include "spi-fsl-lib.h" #include "spi-fsl-cpm.h" From 15ee3be78b017ee9d697fe59d45cdfbb35d9fdeb Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 2 Oct 2014 16:31:07 +0300 Subject: [PATCH 19/21] spi: dw-mid: change magic numbers to the constants Instead of using magic numbers in the code we create a bit map definition of the DMACR register and use it. There is no functional change. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw-mid.c | 4 ++-- drivers/spi/spi-dw.h | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index ecae30fe28af..7bdf93747e5f 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -124,9 +124,9 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) dw_writew(dws, DW_SPI_DMARDLR, 0xf); dw_writew(dws, DW_SPI_DMATDLR, 0x10); if (dws->tx_dma) - dma_ctrl |= 0x2; + dma_ctrl |= SPI_DMA_TDMAE; if (dws->rx_dma) - dma_ctrl |= 0x1; + dma_ctrl |= SPI_DMA_RDMAE; dw_writew(dws, DW_SPI_DMACR, dma_ctrl); spi_enable_chip(dws, 1); } diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 089fc4ba3ace..83a103a76481 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -74,6 +74,10 @@ #define SPI_INT_RXFI (1 << 4) #define SPI_INT_MSTI (1 << 5) +/* Bit fields in DMACR */ +#define SPI_DMA_RDMAE (1 << 0) +#define SPI_DMA_TDMAE (1 << 1) + /* TX RX interrupt level threshold, max can be 256 */ #define SPI_INT_THRESHOLD 32 From 2a285299446cccbaf9ba47403e8f2ce578cd1ad1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 2 Oct 2014 16:31:08 +0300 Subject: [PATCH 20/21] spi: dw-mid: convert to use DMAengine wrappers Instead of direct dereference to dmaengine callbacks we are going to use DMAengine wrappers. Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw-mid.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index 7bdf93747e5f..a507add6231e 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -113,8 +113,7 @@ static void dw_spi_dma_done(void *arg) static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) { - struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL; - struct dma_chan *txchan, *rxchan; + struct dma_async_tx_descriptor *txdesc, *rxdesc; struct dma_slave_config txconf, rxconf; u16 dma_ctrl = 0; @@ -132,8 +131,6 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) } dws->dma_chan_done = 0; - txchan = dws->txchan; - rxchan = dws->rxchan; /* 2. Prepare the TX dma transfer */ txconf.direction = DMA_MEM_TO_DEV; @@ -143,14 +140,13 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) txconf.dst_addr_width = dws->dma_width; txconf.device_fc = false; - txchan->device->device_control(txchan, DMA_SLAVE_CONFIG, - (unsigned long) &txconf); + dmaengine_slave_config(dws->txchan, &txconf); memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl)); dws->tx_sgl.dma_address = dws->tx_dma; dws->tx_sgl.length = dws->len; - txdesc = dmaengine_prep_slave_sg(txchan, + txdesc = dmaengine_prep_slave_sg(dws->txchan, &dws->tx_sgl, 1, DMA_MEM_TO_DEV, @@ -166,14 +162,13 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) rxconf.src_addr_width = dws->dma_width; rxconf.device_fc = false; - rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG, - (unsigned long) &rxconf); + dmaengine_slave_config(dws->rxchan, &rxconf); memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl)); dws->rx_sgl.dma_address = dws->rx_dma; dws->rx_sgl.length = dws->len; - rxdesc = dmaengine_prep_slave_sg(rxchan, + rxdesc = dmaengine_prep_slave_sg(dws->rxchan, &dws->rx_sgl, 1, DMA_DEV_TO_MEM, @@ -182,8 +177,8 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) rxdesc->callback_param = dws; /* rx must be started before tx due to spi instinct */ - rxdesc->tx_submit(rxdesc); - txdesc->tx_submit(txdesc); + dmaengine_submit(rxdesc); + dmaengine_submit(txdesc); return 0; } From f7477c2be8689ee8355db345f107744c9bd7f112 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 2 Oct 2014 16:31:09 +0300 Subject: [PATCH 21/21] spi: dw-mid: follow new DMAengine workflow Though intel-mid-dma does not follow a new DMA workflow (*) let's prepare SPI DW driver for that. (*) The client is obliged to call dma_async_issue_pending() which starts the actual transfers. Old DMA drivers do not follow this, since requirement was introduced in the discussion of [1]. [1] http://www.spinics.net/lists/arm-kernel/msg125987.html Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw-mid.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index a507add6231e..46c6d58e1fda 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -150,7 +150,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) &dws->tx_sgl, 1, DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT); + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); txdesc->callback = dw_spi_dma_done; txdesc->callback_param = dws; @@ -172,13 +172,17 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) &dws->rx_sgl, 1, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT); + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); rxdesc->callback = dw_spi_dma_done; rxdesc->callback_param = dws; /* rx must be started before tx due to spi instinct */ dmaengine_submit(rxdesc); + dma_async_issue_pending(dws->rxchan); + dmaengine_submit(txdesc); + dma_async_issue_pending(dws->txchan); + return 0; }