Commit | Line | Data |
---|---|---|
c4e16625 BK |
1 | /* linux/arch/arm/plat-samsung/dma-ops.c |
2 | * | |
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | |
4 | * http://www.samsung.com | |
5 | * | |
6 | * Samsung DMA Operations | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | */ | |
12 | ||
13 | #include <linux/kernel.h> | |
14 | #include <linux/errno.h> | |
15 | #include <linux/amba/pl330.h> | |
16 | #include <linux/scatterlist.h> | |
0c073e35 | 17 | #include <linux/export.h> |
c4e16625 BK |
18 | |
19 | #include <mach/dma.h> | |
20 | ||
21 | static inline bool pl330_filter(struct dma_chan *chan, void *param) | |
22 | { | |
23 | struct dma_pl330_peri *peri = chan->private; | |
24 | return peri->peri_id == (unsigned)param; | |
25 | } | |
26 | ||
27 | static unsigned samsung_dmadev_request(enum dma_ch dma_ch, | |
28 | struct samsung_dma_info *info) | |
29 | { | |
30 | struct dma_chan *chan; | |
31 | dma_cap_mask_t mask; | |
32 | struct dma_slave_config slave_config; | |
33 | ||
34 | dma_cap_zero(mask); | |
35 | dma_cap_set(info->cap, mask); | |
36 | ||
37 | chan = dma_request_channel(mask, pl330_filter, (void *)dma_ch); | |
38 | ||
39 | if (info->direction == DMA_FROM_DEVICE) { | |
40 | memset(&slave_config, 0, sizeof(struct dma_slave_config)); | |
41 | slave_config.direction = info->direction; | |
42 | slave_config.src_addr = info->fifo; | |
43 | slave_config.src_addr_width = info->width; | |
44 | slave_config.src_maxburst = 1; | |
45 | dmaengine_slave_config(chan, &slave_config); | |
46 | } else if (info->direction == DMA_TO_DEVICE) { | |
47 | memset(&slave_config, 0, sizeof(struct dma_slave_config)); | |
48 | slave_config.direction = info->direction; | |
49 | slave_config.dst_addr = info->fifo; | |
50 | slave_config.dst_addr_width = info->width; | |
51 | slave_config.dst_maxburst = 1; | |
52 | dmaengine_slave_config(chan, &slave_config); | |
53 | } | |
54 | ||
55 | return (unsigned)chan; | |
56 | } | |
57 | ||
58 | static int samsung_dmadev_release(unsigned ch, | |
59 | struct s3c2410_dma_client *client) | |
60 | { | |
61 | dma_release_channel((struct dma_chan *)ch); | |
62 | ||
63 | return 0; | |
64 | } | |
65 | ||
66 | static int samsung_dmadev_prepare(unsigned ch, | |
67 | struct samsung_dma_prep_info *info) | |
68 | { | |
69 | struct scatterlist sg; | |
70 | struct dma_chan *chan = (struct dma_chan *)ch; | |
71 | struct dma_async_tx_descriptor *desc; | |
72 | ||
73 | switch (info->cap) { | |
74 | case DMA_SLAVE: | |
75 | sg_init_table(&sg, 1); | |
76 | sg_dma_len(&sg) = info->len; | |
77 | sg_set_page(&sg, pfn_to_page(PFN_DOWN(info->buf)), | |
78 | info->len, offset_in_page(info->buf)); | |
79 | sg_dma_address(&sg) = info->buf; | |
80 | ||
81 | desc = chan->device->device_prep_slave_sg(chan, | |
82 | &sg, 1, info->direction, DMA_PREP_INTERRUPT); | |
83 | break; | |
84 | case DMA_CYCLIC: | |
85 | desc = chan->device->device_prep_dma_cyclic(chan, | |
86 | info->buf, info->len, info->period, info->direction); | |
87 | break; | |
88 | default: | |
89 | dev_err(&chan->dev->device, "unsupported format\n"); | |
90 | return -EFAULT; | |
91 | } | |
92 | ||
93 | if (!desc) { | |
94 | dev_err(&chan->dev->device, "cannot prepare cyclic dma\n"); | |
95 | return -EFAULT; | |
96 | } | |
97 | ||
98 | desc->callback = info->fp; | |
99 | desc->callback_param = info->fp_param; | |
100 | ||
101 | dmaengine_submit((struct dma_async_tx_descriptor *)desc); | |
102 | ||
103 | return 0; | |
104 | } | |
105 | ||
106 | static inline int samsung_dmadev_trigger(unsigned ch) | |
107 | { | |
108 | dma_async_issue_pending((struct dma_chan *)ch); | |
109 | ||
110 | return 0; | |
111 | } | |
112 | ||
113 | static inline int samsung_dmadev_flush(unsigned ch) | |
114 | { | |
115 | return dmaengine_terminate_all((struct dma_chan *)ch); | |
116 | } | |
117 | ||
118 | struct samsung_dma_ops dmadev_ops = { | |
119 | .request = samsung_dmadev_request, | |
120 | .release = samsung_dmadev_release, | |
121 | .prepare = samsung_dmadev_prepare, | |
122 | .trigger = samsung_dmadev_trigger, | |
123 | .started = NULL, | |
124 | .flush = samsung_dmadev_flush, | |
125 | .stop = samsung_dmadev_flush, | |
126 | }; | |
127 | ||
128 | void *samsung_dmadev_get_ops(void) | |
129 | { | |
130 | return &dmadev_ops; | |
131 | } | |
132 | EXPORT_SYMBOL(samsung_dmadev_get_ops); |