aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/dw/platform.c
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2013-06-05 08:26:45 -0400
committerVinod Koul <vinod.koul@intel.com>2013-07-05 02:10:44 -0400
commit9cade1a46c77dfc96d57a3ea6354e95b2a7fcf61 (patch)
tree52340617645937017301473d5333abb47c4b33cd /drivers/dma/dw/platform.c
parent61a7649620d54a037c612f9a713abe5178cddc65 (diff)
dma: dw: split driver to library part and platform code
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>
Diffstat (limited to 'drivers/dma/dw/platform.c')
-rw-r--r--drivers/dma/dw/platform.c317
1 files changed, 317 insertions, 0 deletions
diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c
new file mode 100644
index 000000000000..6c9449cffae8
--- /dev/null
+++ b/drivers/dma/dw/platform.c
@@ -0,0 +1,317 @@
1/*
2 * Platform driver for the Synopsys DesignWare DMA Controller
3 *
4 * Copyright (C) 2007-2008 Atmel Corporation
5 * Copyright (C) 2010-2011 ST Microelectronics
6 * Copyright (C) 2013 Intel Corporation
7 *
8 * Some parts of this driver are derived from the original dw_dmac.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/module.h>
16#include <linux/device.h>
17#include <linux/clk.h>
18#include <linux/platform_device.h>
19#include <linux/dmaengine.h>
20#include <linux/dma-mapping.h>
21#include <linux/of.h>
22#include <linux/of_dma.h>
23#include <linux/acpi.h>
24#include <linux/acpi_dma.h>
25
26#include "internal.h"
27
28struct dw_dma_of_filter_args {
29 struct dw_dma *dw;
30 unsigned int req;
31 unsigned int src;
32 unsigned int dst;
33};
34
35static bool dw_dma_of_filter(struct dma_chan *chan, void *param)
36{
37 struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
38 struct dw_dma_of_filter_args *fargs = param;
39
40 /* Ensure the device matches our channel */
41 if (chan->device != &fargs->dw->dma)
42 return false;
43
44 dwc->request_line = fargs->req;
45 dwc->src_master = fargs->src;
46 dwc->dst_master = fargs->dst;
47
48 return true;
49}
50
51static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
52 struct of_dma *ofdma)
53{
54 struct dw_dma *dw = ofdma->of_dma_data;
55 struct dw_dma_of_filter_args fargs = {
56 .dw = dw,
57 };
58 dma_cap_mask_t cap;
59
60 if (dma_spec->args_count != 3)
61 return NULL;
62
63 fargs.req = dma_spec->args[0];
64 fargs.src = dma_spec->args[1];
65 fargs.dst = dma_spec->args[2];
66
67 if (WARN_ON(fargs.req >= DW_DMA_MAX_NR_REQUESTS ||
68 fargs.src >= dw->nr_masters ||
69 fargs.dst >= dw->nr_masters))
70 return NULL;
71
72 dma_cap_zero(cap);
73 dma_cap_set(DMA_SLAVE, cap);
74
75 /* TODO: there should be a simpler way to do this */
76 return dma_request_channel(cap, dw_dma_of_filter, &fargs);
77}
78
79#ifdef CONFIG_ACPI
80static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param)
81{
82 struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
83 struct acpi_dma_spec *dma_spec = param;
84
85 if (chan->device->dev != dma_spec->dev ||
86 chan->chan_id != dma_spec->chan_id)
87 return false;
88
89 dwc->request_line = dma_spec->slave_id;
90 dwc->src_master = dwc_get_sms(NULL);
91 dwc->dst_master = dwc_get_dms(NULL);
92
93 return true;
94}
95
96static void dw_dma_acpi_controller_register(struct dw_dma *dw)
97{
98 struct device *dev = dw->dma.dev;
99 struct acpi_dma_filter_info *info;
100 int ret;
101
102 info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
103 if (!info)
104 return;
105
106 dma_cap_zero(info->dma_cap);
107 dma_cap_set(DMA_SLAVE, info->dma_cap);
108 info->filter_fn = dw_dma_acpi_filter;
109
110 ret = devm_acpi_dma_controller_register(dev, acpi_dma_simple_xlate,
111 info);
112 if (ret)
113 dev_err(dev, "could not register acpi_dma_controller\n");
114}
115#else /* !CONFIG_ACPI */
116static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {}
117#endif /* !CONFIG_ACPI */
118
119#ifdef CONFIG_OF
120static struct dw_dma_platform_data *
121dw_dma_parse_dt(struct platform_device *pdev)
122{
123 struct device_node *np = pdev->dev.of_node;
124 struct dw_dma_platform_data *pdata;
125 u32 tmp, arr[4];
126
127 if (!np) {
128 dev_err(&pdev->dev, "Missing DT data\n");
129 return NULL;
130 }
131
132 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
133 if (!pdata)
134 return NULL;
135
136 if (of_property_read_u32(np, "dma-channels", &pdata->nr_channels))
137 return NULL;
138
139 if (of_property_read_bool(np, "is_private"))
140 pdata->is_private = true;
141
142 if (!of_property_read_u32(np, "chan_allocation_order", &tmp))
143 pdata->chan_allocation_order = (unsigned char)tmp;
144
145 if (!of_property_read_u32(np, "chan_priority", &tmp))
146 pdata->chan_priority = tmp;
147
148 if (!of_property_read_u32(np, "block_size", &tmp))
149 pdata->block_size = tmp;
150
151 if (!of_property_read_u32(np, "dma-masters", &tmp)) {
152 if (tmp > 4)
153 return NULL;
154
155 pdata->nr_masters = tmp;
156 }
157
158 if (!of_property_read_u32_array(np, "data_width", arr,
159 pdata->nr_masters))
160 for (tmp = 0; tmp < pdata->nr_masters; tmp++)
161 pdata->data_width[tmp] = arr[tmp];
162
163 return pdata;
164}
165#else
166static inline struct dw_dma_platform_data *
167dw_dma_parse_dt(struct platform_device *pdev)
168{
169 return NULL;
170}
171#endif
172
173static int dw_probe(struct platform_device *pdev)
174{
175 struct dw_dma_chip *chip;
176 struct device *dev = &pdev->dev;
177 struct resource *mem;
178 struct dw_dma_platform_data *pdata;
179 int err;
180
181 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
182 if (!chip)
183 return -ENOMEM;
184
185 chip->irq = platform_get_irq(pdev, 0);
186 if (chip->irq < 0)
187 return chip->irq;
188
189 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
190 chip->regs = devm_ioremap_resource(dev, mem);
191 if (IS_ERR(chip->regs))
192 return PTR_ERR(chip->regs);
193
194 /* Apply default dma_mask if needed */
195 if (!dev->dma_mask) {
196 dev->dma_mask = &dev->coherent_dma_mask;
197 dev->coherent_dma_mask = DMA_BIT_MASK(32);
198 }
199
200 pdata = dev_get_platdata(dev);
201 if (!pdata)
202 pdata = dw_dma_parse_dt(pdev);
203
204 chip->dev = dev;
205
206 err = dw_dma_probe(chip, pdata);
207 if (err)
208 return err;
209
210 platform_set_drvdata(pdev, chip);
211
212 if (pdev->dev.of_node) {
213 err = of_dma_controller_register(pdev->dev.of_node,
214 dw_dma_of_xlate, chip->dw);
215 if (err)
216 dev_err(&pdev->dev,
217 "could not register of_dma_controller\n");
218 }
219
220 if (ACPI_HANDLE(&pdev->dev))
221 dw_dma_acpi_controller_register(chip->dw);
222
223 return 0;
224}
225
226static int dw_remove(struct platform_device *pdev)
227{
228 struct dw_dma_chip *chip = platform_get_drvdata(pdev);
229
230 if (pdev->dev.of_node)
231 of_dma_controller_free(pdev->dev.of_node);
232
233 return dw_dma_remove(chip);
234}
235
236static void dw_shutdown(struct platform_device *pdev)
237{
238 struct dw_dma_chip *chip = platform_get_drvdata(pdev);
239
240 dw_dma_shutdown(chip);
241}
242
243#ifdef CONFIG_OF
244static const struct of_device_id dw_dma_of_id_table[] = {
245 { .compatible = "snps,dma-spear1340" },
246 {}
247};
248MODULE_DEVICE_TABLE(of, dw_dma_of_id_table);
249#endif
250
251#ifdef CONFIG_ACPI
252static const struct acpi_device_id dw_dma_acpi_id_table[] = {
253 { "INTL9C60", 0 },
254 { }
255};
256#endif
257
258#ifdef CONFIG_PM_SLEEP
259
260static int dw_suspend_noirq(struct device *dev)
261{
262 struct platform_device *pdev = to_platform_device(dev);
263 struct dw_dma_chip *chip = platform_get_drvdata(pdev);
264
265 return dw_dma_suspend(chip);
266}
267
268static int dw_resume_noirq(struct device *dev)
269{
270 struct platform_device *pdev = to_platform_device(dev);
271 struct dw_dma_chip *chip = platform_get_drvdata(pdev);
272
273 return dw_dma_resume(chip);
274}
275
276#else /* !CONFIG_PM_SLEEP */
277
278#define dw_suspend_noirq NULL
279#define dw_resume_noirq NULL
280
281#endif /* !CONFIG_PM_SLEEP */
282
283static const struct dev_pm_ops dw_dev_pm_ops = {
284 .suspend_noirq = dw_suspend_noirq,
285 .resume_noirq = dw_resume_noirq,
286 .freeze_noirq = dw_suspend_noirq,
287 .thaw_noirq = dw_resume_noirq,
288 .restore_noirq = dw_resume_noirq,
289 .poweroff_noirq = dw_suspend_noirq,
290};
291
292static struct platform_driver dw_driver = {
293 .probe = dw_probe,
294 .remove = dw_remove,
295 .shutdown = dw_shutdown,
296 .driver = {
297 .name = "dw_dmac",
298 .pm = &dw_dev_pm_ops,
299 .of_match_table = of_match_ptr(dw_dma_of_id_table),
300 .acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table),
301 },
302};
303
304static int __init dw_init(void)
305{
306 return platform_driver_register(&dw_driver);
307}
308subsys_initcall(dw_init);
309
310static void __exit dw_exit(void)
311{
312 platform_driver_unregister(&dw_driver);
313}
314module_exit(dw_exit);
315
316MODULE_LICENSE("GPL v2");
317MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller platform driver");