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 | ||
c4e16625 | 21 | static unsigned samsung_dmadev_request(enum dma_ch dma_ch, |
e7ba5f1d PV |
22 | struct samsung_dma_req *param, |
23 | struct device *dev, char *ch_name) | |
c4e16625 | 24 | { |
c4e16625 | 25 | dma_cap_mask_t mask; |
4972a80e | 26 | void *filter_param; |
c4e16625 BK |
27 | |
28 | dma_cap_zero(mask); | |
fbb20e81 | 29 | dma_cap_set(param->cap, mask); |
c4e16625 | 30 | |
4972a80e TA |
31 | /* |
32 | * If a dma channel property of a device node from device tree is | |
33 | * specified, use that as the fliter parameter. | |
34 | */ | |
fbb20e81 BK |
35 | filter_param = (dma_ch == DMACH_DT_PROP) ? |
36 | (void *)param->dt_dmach_prop : (void *)dma_ch; | |
e7ba5f1d PV |
37 | |
38 | if (dev->of_node) | |
39 | return (unsigned)dma_request_slave_channel(dev, ch_name); | |
40 | else | |
41 | return (unsigned)dma_request_channel(mask, pl330_filter, | |
42 | filter_param); | |
fbb20e81 | 43 | } |
c4e16625 | 44 | |
3688be49 | 45 | static int samsung_dmadev_release(unsigned ch, void *param) |
fbb20e81 BK |
46 | { |
47 | dma_release_channel((struct dma_chan *)ch); | |
48 | ||
49 | return 0; | |
50 | } | |
51 | ||
52 | static int samsung_dmadev_config(unsigned ch, | |
53 | struct samsung_dma_config *param) | |
54 | { | |
55 | struct dma_chan *chan = (struct dma_chan *)ch; | |
56 | struct dma_slave_config slave_config; | |
57 | ||
58 | if (param->direction == DMA_DEV_TO_MEM) { | |
c4e16625 | 59 | memset(&slave_config, 0, sizeof(struct dma_slave_config)); |
fbb20e81 BK |
60 | slave_config.direction = param->direction; |
61 | slave_config.src_addr = param->fifo; | |
62 | slave_config.src_addr_width = param->width; | |
c4e16625 BK |
63 | slave_config.src_maxburst = 1; |
64 | dmaengine_slave_config(chan, &slave_config); | |
fbb20e81 | 65 | } else if (param->direction == DMA_MEM_TO_DEV) { |
c4e16625 | 66 | memset(&slave_config, 0, sizeof(struct dma_slave_config)); |
fbb20e81 BK |
67 | slave_config.direction = param->direction; |
68 | slave_config.dst_addr = param->fifo; | |
69 | slave_config.dst_addr_width = param->width; | |
c4e16625 BK |
70 | slave_config.dst_maxburst = 1; |
71 | dmaengine_slave_config(chan, &slave_config); | |
fbb20e81 BK |
72 | } else { |
73 | pr_warn("unsupported direction\n"); | |
74 | return -EINVAL; | |
c4e16625 BK |
75 | } |
76 | ||
c4e16625 BK |
77 | return 0; |
78 | } | |
79 | ||
80 | static int samsung_dmadev_prepare(unsigned ch, | |
fbb20e81 | 81 | struct samsung_dma_prep *param) |
c4e16625 BK |
82 | { |
83 | struct scatterlist sg; | |
84 | struct dma_chan *chan = (struct dma_chan *)ch; | |
85 | struct dma_async_tx_descriptor *desc; | |
86 | ||
fbb20e81 | 87 | switch (param->cap) { |
c4e16625 BK |
88 | case DMA_SLAVE: |
89 | sg_init_table(&sg, 1); | |
fbb20e81 BK |
90 | sg_dma_len(&sg) = param->len; |
91 | sg_set_page(&sg, pfn_to_page(PFN_DOWN(param->buf)), | |
92 | param->len, offset_in_page(param->buf)); | |
93 | sg_dma_address(&sg) = param->buf; | |
c4e16625 | 94 | |
16052827 | 95 | desc = dmaengine_prep_slave_sg(chan, |
fbb20e81 | 96 | &sg, 1, param->direction, DMA_PREP_INTERRUPT); |
c4e16625 BK |
97 | break; |
98 | case DMA_CYCLIC: | |
fbb20e81 | 99 | desc = dmaengine_prep_dma_cyclic(chan, param->buf, |
b7ef37d0 PU |
100 | param->len, param->period, param->direction, |
101 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | |
c4e16625 BK |
102 | break; |
103 | default: | |
104 | dev_err(&chan->dev->device, "unsupported format\n"); | |
105 | return -EFAULT; | |
106 | } | |
107 | ||
108 | if (!desc) { | |
109 | dev_err(&chan->dev->device, "cannot prepare cyclic dma\n"); | |
110 | return -EFAULT; | |
111 | } | |
112 | ||
fbb20e81 BK |
113 | desc->callback = param->fp; |
114 | desc->callback_param = param->fp_param; | |
c4e16625 BK |
115 | |
116 | dmaengine_submit((struct dma_async_tx_descriptor *)desc); | |
117 | ||
118 | return 0; | |
119 | } | |
120 | ||
121 | static inline int samsung_dmadev_trigger(unsigned ch) | |
122 | { | |
123 | dma_async_issue_pending((struct dma_chan *)ch); | |
124 | ||
125 | return 0; | |
126 | } | |
127 | ||
128 | static inline int samsung_dmadev_flush(unsigned ch) | |
129 | { | |
130 | return dmaengine_terminate_all((struct dma_chan *)ch); | |
131 | } | |
132 | ||
6d259a25 | 133 | static struct samsung_dma_ops dmadev_ops = { |
c4e16625 BK |
134 | .request = samsung_dmadev_request, |
135 | .release = samsung_dmadev_release, | |
fbb20e81 | 136 | .config = samsung_dmadev_config, |
c4e16625 BK |
137 | .prepare = samsung_dmadev_prepare, |
138 | .trigger = samsung_dmadev_trigger, | |
139 | .started = NULL, | |
140 | .flush = samsung_dmadev_flush, | |
141 | .stop = samsung_dmadev_flush, | |
142 | }; | |
143 | ||
144 | void *samsung_dmadev_get_ops(void) | |
145 | { | |
146 | return &dmadev_ops; | |
147 | } | |
148 | EXPORT_SYMBOL(samsung_dmadev_get_ops); |