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> | |
17 | ||
18 | #include <mach/dma.h> | |
19 | ||
20 | static inline bool pl330_filter(struct dma_chan *chan, void *param) | |
21 | { | |
22 | struct dma_pl330_peri *peri = chan->private; | |
23 | return peri->peri_id == (unsigned)param; | |
24 | } | |
25 | ||
26 | static unsigned samsung_dmadev_request(enum dma_ch dma_ch, | |
27 | struct samsung_dma_info *info) | |
28 | { | |
29 | struct dma_chan *chan; | |
30 | dma_cap_mask_t mask; | |
31 | struct dma_slave_config slave_config; | |
32 | ||
33 | dma_cap_zero(mask); | |
34 | dma_cap_set(info->cap, mask); | |
35 | ||
36 | chan = dma_request_channel(mask, pl330_filter, (void *)dma_ch); | |
37 | ||
38 | if (info->direction == DMA_FROM_DEVICE) { | |
39 | memset(&slave_config, 0, sizeof(struct dma_slave_config)); | |
40 | slave_config.direction = info->direction; | |
41 | slave_config.src_addr = info->fifo; | |
42 | slave_config.src_addr_width = info->width; | |
43 | slave_config.src_maxburst = 1; | |
44 | dmaengine_slave_config(chan, &slave_config); | |
45 | } else if (info->direction == DMA_TO_DEVICE) { | |
46 | memset(&slave_config, 0, sizeof(struct dma_slave_config)); | |
47 | slave_config.direction = info->direction; | |
48 | slave_config.dst_addr = info->fifo; | |
49 | slave_config.dst_addr_width = info->width; | |
50 | slave_config.dst_maxburst = 1; | |
51 | dmaengine_slave_config(chan, &slave_config); | |
52 | } | |
53 | ||
54 | return (unsigned)chan; | |
55 | } | |
56 | ||
57 | static int samsung_dmadev_release(unsigned ch, | |
58 | struct s3c2410_dma_client *client) | |
59 | { | |
60 | dma_release_channel((struct dma_chan *)ch); | |
61 | ||
62 | return 0; | |
63 | } | |
64 | ||
65 | static int samsung_dmadev_prepare(unsigned ch, | |
66 | struct samsung_dma_prep_info *info) | |
67 | { | |
68 | struct scatterlist sg; | |
69 | struct dma_chan *chan = (struct dma_chan *)ch; | |
70 | struct dma_async_tx_descriptor *desc; | |
71 | ||
72 | switch (info->cap) { | |
73 | case DMA_SLAVE: | |
74 | sg_init_table(&sg, 1); | |
75 | sg_dma_len(&sg) = info->len; | |
76 | sg_set_page(&sg, pfn_to_page(PFN_DOWN(info->buf)), | |
77 | info->len, offset_in_page(info->buf)); | |
78 | sg_dma_address(&sg) = info->buf; | |
79 | ||
80 | desc = chan->device->device_prep_slave_sg(chan, | |
81 | &sg, 1, info->direction, DMA_PREP_INTERRUPT); | |
82 | break; | |
83 | case DMA_CYCLIC: | |
84 | desc = chan->device->device_prep_dma_cyclic(chan, | |
85 | info->buf, info->len, info->period, info->direction); | |
86 | break; | |
87 | default: | |
88 | dev_err(&chan->dev->device, "unsupported format\n"); | |
89 | return -EFAULT; | |
90 | } | |
91 | ||
92 | if (!desc) { | |
93 | dev_err(&chan->dev->device, "cannot prepare cyclic dma\n"); | |
94 | return -EFAULT; | |
95 | } | |
96 | ||
97 | desc->callback = info->fp; | |
98 | desc->callback_param = info->fp_param; | |
99 | ||
100 | dmaengine_submit((struct dma_async_tx_descriptor *)desc); | |
101 | ||
102 | return 0; | |
103 | } | |
104 | ||
105 | static inline int samsung_dmadev_trigger(unsigned ch) | |
106 | { | |
107 | dma_async_issue_pending((struct dma_chan *)ch); | |
108 | ||
109 | return 0; | |
110 | } | |
111 | ||
112 | static inline int samsung_dmadev_flush(unsigned ch) | |
113 | { | |
114 | return dmaengine_terminate_all((struct dma_chan *)ch); | |
115 | } | |
116 | ||
117 | struct samsung_dma_ops dmadev_ops = { | |
118 | .request = samsung_dmadev_request, | |
119 | .release = samsung_dmadev_release, | |
120 | .prepare = samsung_dmadev_prepare, | |
121 | .trigger = samsung_dmadev_trigger, | |
122 | .started = NULL, | |
123 | .flush = samsung_dmadev_flush, | |
124 | .stop = samsung_dmadev_flush, | |
125 | }; | |
126 | ||
127 | void *samsung_dmadev_get_ops(void) | |
128 | { | |
129 | return &dmadev_ops; | |
130 | } | |
131 | EXPORT_SYMBOL(samsung_dmadev_get_ops); |