]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
dma: dw: split driver to library part and platform code
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Wed, 5 Jun 2013 12:26:45 +0000 (15:26 +0300)
committerVinod Koul <vinod.koul@intel.com>
Wed, 12 Jun 2013 13:17:45 +0000 (18:47 +0530)
To simplify the driver development let's split driver to library and platform
code parts. It helps us to add PCI driver in future.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
[Fixed compile error and few checkpatch issues]
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
drivers/dma/Makefile
drivers/dma/dw/Kconfig
drivers/dma/dw/Makefile
drivers/dma/dw/core.c [moved from drivers/dma/dw/dw_dmac.c with 85% similarity]
drivers/dma/dw/internal.h [new file with mode: 0644]
drivers/dma/dw/platform.c [new file with mode: 0644]
drivers/dma/dw/regs.h [moved from drivers/dma/dw/dw_dmac_regs.h with 99% similarity]

index ac44ca0d468aecb1fffd4cd8a7183080c8cd509c..6e2a521fbbe37e663658328c48cdb091bbb55c56 100644 (file)
@@ -15,7 +15,7 @@ obj-$(CONFIG_FSL_DMA) += fsldma.o
 obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o
 obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
 obj-$(CONFIG_MV_XOR) += mv_xor.o
-obj-$(CONFIG_DW_DMAC) += dw/
+obj-$(CONFIG_DW_DMAC_CORE) += dw/
 obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
 obj-$(CONFIG_MX3_IPU) += ipu/
 obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
index 38a215af5cccef476f48cd0df28b1a22c4378de7..efd9e02a58eb398f7155734eb9f1af4776098185 100644 (file)
@@ -2,10 +2,14 @@
 # DMA engine configuration for dw
 #
 
-config DW_DMAC
+config DW_DMAC_CORE
        tristate "Synopsys DesignWare AHB DMA support"
        depends on GENERIC_HARDIRQS
        select DMA_ENGINE
+
+config DW_DMAC
+       tristate "Synopsys DesignWare AHB DMA platform driver"
+       select DW_DMAC_CORE
        default y if CPU_AT32AP7000
        help
          Support the Synopsys DesignWare AHB DMA controller. This
@@ -14,7 +18,7 @@ config DW_DMAC
 config DW_DMAC_BIG_ENDIAN_IO
        bool "Use big endian I/O register access"
        default y if AVR32
-       depends on DW_DMAC
+       depends on DW_DMAC_CORE
        help
          Say yes here to use big endian I/O access when reading and writing
          to the DMA controller registers. This is needed on some platforms,
index dd8d9936beef551c1075dc7676cb2e9dc4ffb160..47f36746c55987381335fc51c56b0b2bf6e1dbf0 100644 (file)
@@ -1 +1,5 @@
-obj-$(CONFIG_DW_DMAC) += dw_dmac.o
+obj-$(CONFIG_DW_DMAC_CORE)     += dw_dmac_core.o
+dw_dmac_core-objs      := core.o
+
+obj-$(CONFIG_DW_DMAC)          += dw_dmac.o
+dw_dmac-objs           := platform.o
similarity index 85%
rename from drivers/dma/dw/dw_dmac.c
rename to drivers/dma/dw/core.c
index 15f3f4f79c1098bb8256465b5cdefccac032a389..eea479c121736e20c6e52f71059df1b4e14a364b 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2007-2008 Atmel Corporation
  * Copyright (C) 2010-2011 ST Microelectronics
+ * Copyright (C) 2013 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_dma.h>
 #include <linux/mm.h>
 #include <linux/module.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/acpi.h>
-#include <linux/acpi_dma.h>
 
 #include "../dmaengine.h"
-#include "dw_dmac_regs.h"
+#include "internal.h"
 
 /*
  * This supports the Synopsys "DesignWare AHB Central DMA Controller",
  * which does not support descriptor writeback.
  */
 
-static inline unsigned int dwc_get_dms(struct dw_dma_slave *slave)
-{
-       return slave ? slave->dst_master : 0;
-}
-
-static inline unsigned int dwc_get_sms(struct dw_dma_slave *slave)
-{
-       return slave ? slave->src_master : 1;
-}
-
 static inline void dwc_set_masters(struct dw_dma_chan *dwc)
 {
        struct dw_dma *dw = to_dw_dma(dwc->chan.device);
@@ -1225,99 +1211,6 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
        dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
 }
 
-/*----------------------------------------------------------------------*/
-
-struct dw_dma_of_filter_args {
-       struct dw_dma *dw;
-       unsigned int req;
-       unsigned int src;
-       unsigned int dst;
-};
-
-static bool dw_dma_of_filter(struct dma_chan *chan, void *param)
-{
-       struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
-       struct dw_dma_of_filter_args *fargs = param;
-
-       /* Ensure the device matches our channel */
-        if (chan->device != &fargs->dw->dma)
-                return false;
-
-       dwc->request_line = fargs->req;
-       dwc->src_master = fargs->src;
-       dwc->dst_master = fargs->dst;
-
-       return true;
-}
-
-static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
-                                       struct of_dma *ofdma)
-{
-       struct dw_dma *dw = ofdma->of_dma_data;
-       struct dw_dma_of_filter_args fargs = {
-               .dw = dw,
-       };
-       dma_cap_mask_t cap;
-
-       if (dma_spec->args_count != 3)
-               return NULL;
-
-       fargs.req = dma_spec->args[0];
-       fargs.src = dma_spec->args[1];
-       fargs.dst = dma_spec->args[2];
-
-       if (WARN_ON(fargs.req >= DW_DMA_MAX_NR_REQUESTS ||
-                   fargs.src >= dw->nr_masters ||
-                   fargs.dst >= dw->nr_masters))
-               return NULL;
-
-       dma_cap_zero(cap);
-       dma_cap_set(DMA_SLAVE, cap);
-
-       /* TODO: there should be a simpler way to do this */
-       return dma_request_channel(cap, dw_dma_of_filter, &fargs);
-}
-
-#ifdef CONFIG_ACPI
-static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param)
-{
-       struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
-       struct acpi_dma_spec *dma_spec = param;
-
-       if (chan->device->dev != dma_spec->dev ||
-           chan->chan_id != dma_spec->chan_id)
-               return false;
-
-       dwc->request_line = dma_spec->slave_id;
-       dwc->src_master = dwc_get_sms(NULL);
-       dwc->dst_master = dwc_get_dms(NULL);
-
-       return true;
-}
-
-static void dw_dma_acpi_controller_register(struct dw_dma *dw)
-{
-       struct device *dev = dw->dma.dev;
-       struct acpi_dma_filter_info *info;
-       int ret;
-
-       info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return;
-
-       dma_cap_zero(info->dma_cap);
-       dma_cap_set(DMA_SLAVE, info->dma_cap);
-       info->filter_fn = dw_dma_acpi_filter;
-
-       ret = devm_acpi_dma_controller_register(dev, acpi_dma_simple_xlate,
-                                               info);
-       if (ret)
-               dev_err(dev, "could not register acpi_dma_controller\n");
-}
-#else /* !CONFIG_ACPI */
-static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {}
-#endif /* !CONFIG_ACPI */
-
 /* --------------------- Cyclic DMA API extensions -------------------- */
 
 /**
@@ -1598,101 +1491,24 @@ static void dw_dma_off(struct dw_dma *dw)
                dw->chan[i].initialized = false;
 }
 
-#ifdef CONFIG_OF
-static struct dw_dma_platform_data *
-dw_dma_parse_dt(struct platform_device *pdev)
-{
-       struct device_node *np = pdev->dev.of_node;
-       struct dw_dma_platform_data *pdata;
-       u32 tmp, arr[4];
-
-       if (!np) {
-               dev_err(&pdev->dev, "Missing DT data\n");
-               return NULL;
-       }
-
-       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-       if (!pdata)
-               return NULL;
-
-       if (of_property_read_u32(np, "dma-channels", &pdata->nr_channels))
-               return NULL;
-
-       if (of_property_read_bool(np, "is_private"))
-               pdata->is_private = true;
-
-       if (!of_property_read_u32(np, "chan_allocation_order", &tmp))
-               pdata->chan_allocation_order = (unsigned char)tmp;
-
-       if (!of_property_read_u32(np, "chan_priority", &tmp))
-               pdata->chan_priority = tmp;
-
-       if (!of_property_read_u32(np, "block_size", &tmp))
-               pdata->block_size = tmp;
-
-       if (!of_property_read_u32(np, "dma-masters", &tmp)) {
-               if (tmp > 4)
-                       return NULL;
-
-               pdata->nr_masters = tmp;
-       }
-
-       if (!of_property_read_u32_array(np, "data_width", arr,
-                               pdata->nr_masters))
-               for (tmp = 0; tmp < pdata->nr_masters; tmp++)
-                       pdata->data_width[tmp] = arr[tmp];
-
-       return pdata;
-}
-#else
-static inline struct dw_dma_platform_data *
-dw_dma_parse_dt(struct platform_device *pdev)
+int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
 {
-       return NULL;
-}
-#endif
-
-static int dw_probe(struct platform_device *pdev)
-{
-       struct dw_dma_platform_data *pdata;
-       struct resource         *io;
        struct dw_dma           *dw;
        size_t                  size;
-       void __iomem            *regs;
        bool                    autocfg;
        unsigned int            dw_params;
        unsigned int            nr_channels;
        unsigned int            max_blk_size = 0;
-       int                     irq;
        int                     err;
        int                     i;
 
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
-
-       io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       regs = devm_ioremap_resource(&pdev->dev, io);
-       if (IS_ERR(regs))
-               return PTR_ERR(regs);
-
-       /* Apply default dma_mask if needed */
-       if (!pdev->dev.dma_mask) {
-               pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
-               pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-       }
-
-       dw_params = dma_read_byaddr(regs, DW_PARAMS);
+       dw_params = dma_read_byaddr(chip->regs, DW_PARAMS);
        autocfg = dw_params >> DW_PARAMS_EN & 0x1;
 
-       dev_dbg(&pdev->dev, "DW_PARAMS: 0x%08x\n", dw_params);
-
-       pdata = dev_get_platdata(&pdev->dev);
-       if (!pdata)
-               pdata = dw_dma_parse_dt(pdev);
+       dev_dbg(chip->dev, "DW_PARAMS: 0x%08x\n", dw_params);
 
        if (!pdata && autocfg) {
-               pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+               pdata = devm_kzalloc(chip->dev, sizeof(*pdata), GFP_KERNEL);
                if (!pdata)
                        return -ENOMEM;
 
@@ -1709,16 +1525,17 @@ static int dw_probe(struct platform_device *pdev)
                nr_channels = pdata->nr_channels;
 
        size = sizeof(struct dw_dma) + nr_channels * sizeof(struct dw_dma_chan);
-       dw = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+       dw = devm_kzalloc(chip->dev, size, GFP_KERNEL);
        if (!dw)
                return -ENOMEM;
 
-       dw->clk = devm_clk_get(&pdev->dev, "hclk");
+       dw->clk = devm_clk_get(chip->dev, "hclk");
        if (IS_ERR(dw->clk))
                return PTR_ERR(dw->clk);
        clk_prepare_enable(dw->clk);
 
-       dw->regs = regs;
+       dw->regs = chip->regs;
+       chip->dw = dw;
 
        /* Get hardware configuration parameters */
        if (autocfg) {
@@ -1743,18 +1560,16 @@ static int dw_probe(struct platform_device *pdev)
        /* Disable BLOCK interrupts as well */
        channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
 
-       err = devm_request_irq(&pdev->dev, irq, dw_dma_interrupt, 0,
+       err = devm_request_irq(chip->dev, chip->irq, dw_dma_interrupt, 0,
                               "dw_dmac", dw);
        if (err)
                return err;
 
-       platform_set_drvdata(pdev, dw);
-
        /* Create a pool of consistent memory blocks for hardware descriptors */
-       dw->desc_pool = dmam_pool_create("dw_dmac_desc_pool", &pdev->dev,
+       dw->desc_pool = dmam_pool_create("dw_dmac_desc_pool", chip->dev,
                                         sizeof(struct dw_desc), 4, 0);
        if (!dw->desc_pool) {
-               dev_err(&pdev->dev, "No memory for descriptors dma pool\n");
+               dev_err(chip->dev, "No memory for descriptors dma pool\n");
                return -ENOMEM;
        }
 
@@ -1795,12 +1610,12 @@ static int dw_probe(struct platform_device *pdev)
                /* Hardware configuration */
                if (autocfg) {
                        unsigned int dwc_params;
+                       void __iomem *addr = chip->regs + r * sizeof(u32);
 
-                       dwc_params = dma_read_byaddr(regs + r * sizeof(u32),
-                                                    DWC_PARAMS);
+                       dwc_params = dma_read_byaddr(addr, DWC_PARAMS);
 
-                       dev_dbg(&pdev->dev, "DWC_PARAMS[%d]: 0x%08x\n", i,
-                                           dwc_params);
+                       dev_dbg(chip->dev, "DWC_PARAMS[%d]: 0x%08x\n", i,
+                                          dwc_params);
 
                        /* Decode maximum block size for given channel. The
                         * stored 4 bit value represents blocks from 0x00 for 3
@@ -1831,7 +1646,7 @@ static int dw_probe(struct platform_device *pdev)
        dma_cap_set(DMA_SLAVE, dw->dma.cap_mask);
        if (pdata->is_private)
                dma_cap_set(DMA_PRIVATE, dw->dma.cap_mask);
-       dw->dma.dev = &pdev->dev;
+       dw->dma.dev = chip->dev;
        dw->dma.device_alloc_chan_resources = dwc_alloc_chan_resources;
        dw->dma.device_free_chan_resources = dwc_free_chan_resources;
 
@@ -1845,32 +1660,20 @@ static int dw_probe(struct platform_device *pdev)
 
        dma_writel(dw, CFG, DW_CFG_DMA_EN);
 
-       dev_info(&pdev->dev, "DesignWare DMA Controller, %d channels\n",
+       dev_info(chip->dev, "DesignWare DMA Controller, %d channels\n",
                 nr_channels);
 
        dma_async_device_register(&dw->dma);
 
-       if (pdev->dev.of_node) {
-               err = of_dma_controller_register(pdev->dev.of_node,
-                                                dw_dma_of_xlate, dw);
-               if (err)
-                       dev_err(&pdev->dev,
-                               "could not register of_dma_controller\n");
-       }
-
-       if (ACPI_HANDLE(&pdev->dev))
-               dw_dma_acpi_controller_register(dw);
-
        return 0;
 }
+EXPORT_SYMBOL_GPL(dw_dma_probe);
 
-static int dw_remove(struct platform_device *pdev)
+int dw_dma_remove(struct dw_dma_chip *chip)
 {
-       struct dw_dma           *dw = platform_get_drvdata(pdev);
+       struct dw_dma           *dw = chip->dw;
        struct dw_dma_chan      *dwc, *_dwc;
 
-       if (pdev->dev.of_node)
-               of_dma_controller_free(pdev->dev.of_node);
        dw_dma_off(dw);
        dma_async_device_unregister(&dw->dma);
 
@@ -1884,86 +1687,44 @@ static int dw_remove(struct platform_device *pdev)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(dw_dma_remove);
 
-static void dw_shutdown(struct platform_device *pdev)
+void dw_dma_shutdown(struct dw_dma_chip *chip)
 {
-       struct dw_dma   *dw = platform_get_drvdata(pdev);
+       struct dw_dma *dw = chip->dw;
 
        dw_dma_off(dw);
        clk_disable_unprepare(dw->clk);
 }
+EXPORT_SYMBOL_GPL(dw_dma_shutdown);
 
-static int dw_suspend_noirq(struct device *dev)
+#ifdef CONFIG_PM_SLEEP
+
+int dw_dma_suspend(struct dw_dma_chip *chip)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct dw_dma   *dw = platform_get_drvdata(pdev);
+       struct dw_dma *dw = chip->dw;
 
        dw_dma_off(dw);
        clk_disable_unprepare(dw->clk);
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(dw_dma_suspend);
 
-static int dw_resume_noirq(struct device *dev)
+int dw_dma_resume(struct dw_dma_chip *chip)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct dw_dma   *dw = platform_get_drvdata(pdev);
+       struct dw_dma *dw = chip->dw;
 
        clk_prepare_enable(dw->clk);
        dma_writel(dw, CFG, DW_CFG_DMA_EN);
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(dw_dma_resume);
 
-static const struct dev_pm_ops dw_dev_pm_ops = {
-       .suspend_noirq = dw_suspend_noirq,
-       .resume_noirq = dw_resume_noirq,
-       .freeze_noirq = dw_suspend_noirq,
-       .thaw_noirq = dw_resume_noirq,
-       .restore_noirq = dw_resume_noirq,
-       .poweroff_noirq = dw_suspend_noirq,
-};
-
-#ifdef CONFIG_OF
-static const struct of_device_id dw_dma_of_id_table[] = {
-       { .compatible = "snps,dma-spear1340" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, dw_dma_of_id_table);
-#endif
-
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id dw_dma_acpi_id_table[] = {
-       { "INTL9C60", 0 },
-       { }
-};
-#endif
-
-static struct platform_driver dw_driver = {
-       .probe          = dw_probe,
-       .remove         = dw_remove,
-       .shutdown       = dw_shutdown,
-       .driver = {
-               .name   = "dw_dmac",
-               .pm     = &dw_dev_pm_ops,
-               .of_match_table = of_match_ptr(dw_dma_of_id_table),
-               .acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table),
-       },
-};
-
-static int __init dw_init(void)
-{
-       return platform_driver_register(&dw_driver);
-}
-subsys_initcall(dw_init);
-
-static void __exit dw_exit(void)
-{
-       platform_driver_unregister(&dw_driver);
-}
-module_exit(dw_exit);
+#endif /* CONFIG_PM_SLEEP */
 
 MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller driver");
+MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller core driver");
 MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
 MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h
new file mode 100644 (file)
index 0000000..32667f9
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Driver for the Synopsys DesignWare DMA Controller
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _DW_DMAC_INTERNAL_H
+#define _DW_DMAC_INTERNAL_H
+
+#include <linux/device.h>
+#include <linux/dw_dmac.h>
+
+#include "regs.h"
+
+/**
+ * struct dw_dma_chip - representation of DesignWare DMA controller hardware
+ * @dev:               struct device of the DMA controller
+ * @irq:               irq line
+ * @regs:              memory mapped I/O space
+ * @dw:                        struct dw_dma that is filed by dw_dma_probe()
+ */
+struct dw_dma_chip {
+       struct device   *dev;
+       int             irq;
+       void __iomem    *regs;
+       struct dw_dma   *dw;
+};
+
+/* Export to the platform drivers */
+int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata);
+int dw_dma_remove(struct dw_dma_chip *chip);
+
+void dw_dma_shutdown(struct dw_dma_chip *chip);
+
+#ifdef CONFIG_PM_SLEEP
+
+int dw_dma_suspend(struct dw_dma_chip *chip);
+int dw_dma_resume(struct dw_dma_chip *chip);
+
+#endif /* CONFIG_PM_SLEEP */
+
+/**
+ * dwc_get_dms - get destination master
+ * @slave:     pointer to the custom slave configuration
+ *
+ * Returns destination master in the custom slave configuration if defined, or
+ * default value otherwise.
+ */
+static inline unsigned int dwc_get_dms(struct dw_dma_slave *slave)
+{
+       return slave ? slave->dst_master : 0;
+}
+
+/**
+ * dwc_get_sms - get source master
+ * @slave:     pointer to the custom slave configuration
+ *
+ * Returns source master in the custom slave configuration if defined, or
+ * default value otherwise.
+ */
+static inline unsigned int dwc_get_sms(struct dw_dma_slave *slave)
+{
+       return slave ? slave->src_master : 1;
+}
+
+#endif /* _DW_DMAC_INTERNAL_H */
diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c
new file mode 100644 (file)
index 0000000..6c9449c
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * Platform driver for the Synopsys DesignWare DMA Controller
+ *
+ * Copyright (C) 2007-2008 Atmel Corporation
+ * Copyright (C) 2010-2011 ST Microelectronics
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Some parts of this driver are derived from the original dw_dmac.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_dma.h>
+#include <linux/acpi.h>
+#include <linux/acpi_dma.h>
+
+#include "internal.h"
+
+struct dw_dma_of_filter_args {
+       struct dw_dma *dw;
+       unsigned int req;
+       unsigned int src;
+       unsigned int dst;
+};
+
+static bool dw_dma_of_filter(struct dma_chan *chan, void *param)
+{
+       struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+       struct dw_dma_of_filter_args *fargs = param;
+
+       /* Ensure the device matches our channel */
+       if (chan->device != &fargs->dw->dma)
+               return false;
+
+       dwc->request_line = fargs->req;
+       dwc->src_master = fargs->src;
+       dwc->dst_master = fargs->dst;
+
+       return true;
+}
+
+static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
+                                       struct of_dma *ofdma)
+{
+       struct dw_dma *dw = ofdma->of_dma_data;
+       struct dw_dma_of_filter_args fargs = {
+               .dw = dw,
+       };
+       dma_cap_mask_t cap;
+
+       if (dma_spec->args_count != 3)
+               return NULL;
+
+       fargs.req = dma_spec->args[0];
+       fargs.src = dma_spec->args[1];
+       fargs.dst = dma_spec->args[2];
+
+       if (WARN_ON(fargs.req >= DW_DMA_MAX_NR_REQUESTS ||
+                   fargs.src >= dw->nr_masters ||
+                   fargs.dst >= dw->nr_masters))
+               return NULL;
+
+       dma_cap_zero(cap);
+       dma_cap_set(DMA_SLAVE, cap);
+
+       /* TODO: there should be a simpler way to do this */
+       return dma_request_channel(cap, dw_dma_of_filter, &fargs);
+}
+
+#ifdef CONFIG_ACPI
+static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param)
+{
+       struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+       struct acpi_dma_spec *dma_spec = param;
+
+       if (chan->device->dev != dma_spec->dev ||
+           chan->chan_id != dma_spec->chan_id)
+               return false;
+
+       dwc->request_line = dma_spec->slave_id;
+       dwc->src_master = dwc_get_sms(NULL);
+       dwc->dst_master = dwc_get_dms(NULL);
+
+       return true;
+}
+
+static void dw_dma_acpi_controller_register(struct dw_dma *dw)
+{
+       struct device *dev = dw->dma.dev;
+       struct acpi_dma_filter_info *info;
+       int ret;
+
+       info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return;
+
+       dma_cap_zero(info->dma_cap);
+       dma_cap_set(DMA_SLAVE, info->dma_cap);
+       info->filter_fn = dw_dma_acpi_filter;
+
+       ret = devm_acpi_dma_controller_register(dev, acpi_dma_simple_xlate,
+                                               info);
+       if (ret)
+               dev_err(dev, "could not register acpi_dma_controller\n");
+}
+#else /* !CONFIG_ACPI */
+static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {}
+#endif /* !CONFIG_ACPI */
+
+#ifdef CONFIG_OF
+static struct dw_dma_platform_data *
+dw_dma_parse_dt(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct dw_dma_platform_data *pdata;
+       u32 tmp, arr[4];
+
+       if (!np) {
+               dev_err(&pdev->dev, "Missing DT data\n");
+               return NULL;
+       }
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return NULL;
+
+       if (of_property_read_u32(np, "dma-channels", &pdata->nr_channels))
+               return NULL;
+
+       if (of_property_read_bool(np, "is_private"))
+               pdata->is_private = true;
+
+       if (!of_property_read_u32(np, "chan_allocation_order", &tmp))
+               pdata->chan_allocation_order = (unsigned char)tmp;
+
+       if (!of_property_read_u32(np, "chan_priority", &tmp))
+               pdata->chan_priority = tmp;
+
+       if (!of_property_read_u32(np, "block_size", &tmp))
+               pdata->block_size = tmp;
+
+       if (!of_property_read_u32(np, "dma-masters", &tmp)) {
+               if (tmp > 4)
+                       return NULL;
+
+               pdata->nr_masters = tmp;
+       }
+
+       if (!of_property_read_u32_array(np, "data_width", arr,
+                               pdata->nr_masters))
+               for (tmp = 0; tmp < pdata->nr_masters; tmp++)
+                       pdata->data_width[tmp] = arr[tmp];
+
+       return pdata;
+}
+#else
+static inline struct dw_dma_platform_data *
+dw_dma_parse_dt(struct platform_device *pdev)
+{
+       return NULL;
+}
+#endif
+
+static int dw_probe(struct platform_device *pdev)
+{
+       struct dw_dma_chip *chip;
+       struct device *dev = &pdev->dev;
+       struct resource *mem;
+       struct dw_dma_platform_data *pdata;
+       int err;
+
+       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->irq = platform_get_irq(pdev, 0);
+       if (chip->irq < 0)
+               return chip->irq;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       chip->regs = devm_ioremap_resource(dev, mem);
+       if (IS_ERR(chip->regs))
+               return PTR_ERR(chip->regs);
+
+       /* Apply default dma_mask if needed */
+       if (!dev->dma_mask) {
+               dev->dma_mask = &dev->coherent_dma_mask;
+               dev->coherent_dma_mask = DMA_BIT_MASK(32);
+       }
+
+       pdata = dev_get_platdata(dev);
+       if (!pdata)
+               pdata = dw_dma_parse_dt(pdev);
+
+       chip->dev = dev;
+
+       err = dw_dma_probe(chip, pdata);
+       if (err)
+               return err;
+
+       platform_set_drvdata(pdev, chip);
+
+       if (pdev->dev.of_node) {
+               err = of_dma_controller_register(pdev->dev.of_node,
+                                                dw_dma_of_xlate, chip->dw);
+               if (err)
+                       dev_err(&pdev->dev,
+                               "could not register of_dma_controller\n");
+       }
+
+       if (ACPI_HANDLE(&pdev->dev))
+               dw_dma_acpi_controller_register(chip->dw);
+
+       return 0;
+}
+
+static int dw_remove(struct platform_device *pdev)
+{
+       struct dw_dma_chip *chip = platform_get_drvdata(pdev);
+
+       if (pdev->dev.of_node)
+               of_dma_controller_free(pdev->dev.of_node);
+
+       return dw_dma_remove(chip);
+}
+
+static void dw_shutdown(struct platform_device *pdev)
+{
+       struct dw_dma_chip *chip = platform_get_drvdata(pdev);
+
+       dw_dma_shutdown(chip);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id dw_dma_of_id_table[] = {
+       { .compatible = "snps,dma-spear1340" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, dw_dma_of_id_table);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id dw_dma_acpi_id_table[] = {
+       { "INTL9C60", 0 },
+       { }
+};
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+
+static int dw_suspend_noirq(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct dw_dma_chip *chip = platform_get_drvdata(pdev);
+
+       return dw_dma_suspend(chip);
+}
+
+static int dw_resume_noirq(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct dw_dma_chip *chip = platform_get_drvdata(pdev);
+
+       return dw_dma_resume(chip);
+}
+
+#else /* !CONFIG_PM_SLEEP */
+
+#define dw_suspend_noirq       NULL
+#define dw_resume_noirq                NULL
+
+#endif /* !CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops dw_dev_pm_ops = {
+       .suspend_noirq = dw_suspend_noirq,
+       .resume_noirq = dw_resume_noirq,
+       .freeze_noirq = dw_suspend_noirq,
+       .thaw_noirq = dw_resume_noirq,
+       .restore_noirq = dw_resume_noirq,
+       .poweroff_noirq = dw_suspend_noirq,
+};
+
+static struct platform_driver dw_driver = {
+       .probe          = dw_probe,
+       .remove         = dw_remove,
+       .shutdown       = dw_shutdown,
+       .driver = {
+               .name   = "dw_dmac",
+               .pm     = &dw_dev_pm_ops,
+               .of_match_table = of_match_ptr(dw_dma_of_id_table),
+               .acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table),
+       },
+};
+
+static int __init dw_init(void)
+{
+       return platform_driver_register(&dw_driver);
+}
+subsys_initcall(dw_init);
+
+static void __exit dw_exit(void)
+{
+       platform_driver_unregister(&dw_driver);
+}
+module_exit(dw_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller platform driver");
similarity index 99%
rename from drivers/dma/dw/dw_dmac_regs.h
rename to drivers/dma/dw/regs.h
index 9d417200bd57f714b5493a589da7703252458658..07c5a6ecb52b9182ae0ad9bdb0c9158417bda7a8 100644 (file)
@@ -9,6 +9,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/interrupt.h>
 #include <linux/dmaengine.h>
 #include <linux/dw_dmac.h>