Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dma-ops.c
Go to the documentation of this file.
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 #include <linux/export.h>
18 
19 #include <mach/dma.h>
20 
21 static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
22  struct samsung_dma_req *param)
23 {
25  void *filter_param;
26 
27  dma_cap_zero(mask);
28  dma_cap_set(param->cap, mask);
29 
30  /*
31  * If a dma channel property of a device node from device tree is
32  * specified, use that as the fliter parameter.
33  */
34  filter_param = (dma_ch == DMACH_DT_PROP) ?
35  (void *)param->dt_dmach_prop : (void *)dma_ch;
36  return (unsigned)dma_request_channel(mask, pl330_filter, filter_param);
37 }
38 
39 static int samsung_dmadev_release(unsigned ch, void *param)
40 {
41  dma_release_channel((struct dma_chan *)ch);
42 
43  return 0;
44 }
45 
46 static int samsung_dmadev_config(unsigned ch,
47  struct samsung_dma_config *param)
48 {
49  struct dma_chan *chan = (struct dma_chan *)ch;
51 
52  if (param->direction == DMA_DEV_TO_MEM) {
53  memset(&slave_config, 0, sizeof(struct dma_slave_config));
54  slave_config.direction = param->direction;
55  slave_config.src_addr = param->fifo;
56  slave_config.src_addr_width = param->width;
57  slave_config.src_maxburst = 1;
58  dmaengine_slave_config(chan, &slave_config);
59  } else if (param->direction == DMA_MEM_TO_DEV) {
60  memset(&slave_config, 0, sizeof(struct dma_slave_config));
61  slave_config.direction = param->direction;
62  slave_config.dst_addr = param->fifo;
63  slave_config.dst_addr_width = param->width;
64  slave_config.dst_maxburst = 1;
65  dmaengine_slave_config(chan, &slave_config);
66  } else {
67  pr_warn("unsupported direction\n");
68  return -EINVAL;
69  }
70 
71  return 0;
72 }
73 
74 static int samsung_dmadev_prepare(unsigned ch,
75  struct samsung_dma_prep *param)
76 {
77  struct scatterlist sg;
78  struct dma_chan *chan = (struct dma_chan *)ch;
80 
81  switch (param->cap) {
82  case DMA_SLAVE:
83  sg_init_table(&sg, 1);
84  sg_dma_len(&sg) = param->len;
85  sg_set_page(&sg, pfn_to_page(PFN_DOWN(param->buf)),
86  param->len, offset_in_page(param->buf));
87  sg_dma_address(&sg) = param->buf;
88 
89  desc = dmaengine_prep_slave_sg(chan,
90  &sg, 1, param->direction, DMA_PREP_INTERRUPT);
91  break;
92  case DMA_CYCLIC:
93  desc = dmaengine_prep_dma_cyclic(chan, param->buf,
94  param->len, param->period, param->direction,
96  break;
97  default:
98  dev_err(&chan->dev->device, "unsupported format\n");
99  return -EFAULT;
100  }
101 
102  if (!desc) {
103  dev_err(&chan->dev->device, "cannot prepare cyclic dma\n");
104  return -EFAULT;
105  }
106 
107  desc->callback = param->fp;
108  desc->callback_param = param->fp_param;
109 
110  dmaengine_submit((struct dma_async_tx_descriptor *)desc);
111 
112  return 0;
113 }
114 
115 static inline int samsung_dmadev_trigger(unsigned ch)
116 {
117  dma_async_issue_pending((struct dma_chan *)ch);
118 
119  return 0;
120 }
121 
122 static inline int samsung_dmadev_flush(unsigned ch)
123 {
124  return dmaengine_terminate_all((struct dma_chan *)ch);
125 }
126 
127 static struct samsung_dma_ops dmadev_ops = {
128  .request = samsung_dmadev_request,
129  .release = samsung_dmadev_release,
130  .config = samsung_dmadev_config,
131  .prepare = samsung_dmadev_prepare,
132  .trigger = samsung_dmadev_trigger,
133  .started = NULL,
134  .flush = samsung_dmadev_flush,
135  .stop = samsung_dmadev_flush,
136 };
137 
139 {
140  return &dmadev_ops;
141 }