code style scripts/checkpatch.pl (linux-3.9-rc1) formatting
[linux-2.6.32.60-moxart.git] / arch / arm / mach-moxart / apb_dma.c
blob9f4c5eaadefaee165601dafe0472ca747cd5321a
1 /* Copyright (C) 2013 Jonas Jensen <jonas.jensen@gmail.com>
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the License,
5 * or (at your option) any later version. */
7 #include <linux/init.h>
8 #include <linux/kernel.h>
9 #include <linux/io.h>
10 #include <linux/irq.h>
11 #include <linux/platform_device.h>
12 #include <linux/interrupt.h>
14 #include <asm/cacheflush.h>
16 #include <mach/hardware.h>
17 #include <mach/irqs.h>
18 #include <mach/apb_dma.h>
20 static struct apb_dma_priv apb_dma_channel[APB_DMA_MAX_CHANNEL];
21 static spinlock_t apb_dma_lock;
23 struct apb_dma_priv *apb_dma_alloc(int req_no)
25 int i;
26 unsigned long flags;
27 struct apb_dma_priv *priv = apb_dma_channel;
29 spin_lock_irqsave(&apb_dma_lock, flags);
30 for (i = 0; i < APB_DMA_MAX_CHANNEL; i++, priv++) {
31 if (priv->used_flag == 0) {
32 priv->used_flag = 1;
33 priv->irq_handler = NULL;
34 priv->irq_handler_param = NULL;
35 priv->error_flag = 0;
36 priv->req_no = req_no;
37 switch (req_no) {
38 case APB_DMA_SD_REQ_NO:
39 *(unsigned int *) (IO_ADDRESS(MOXART_PMU_BASE)
40 + 0xB8) = 0;
41 break;
43 spin_unlock_irqrestore(&apb_dma_lock, flags);
44 dbg_printk(KERN_INFO
45 "MOXART APB DMA: apb_dma_alloc uses DMA channel %d\n"
46 , i);
47 return priv;
50 spin_unlock_irqrestore(&apb_dma_lock, flags);
51 return NULL;
54 void apb_dma_release(struct apb_dma_priv *priv)
56 unsigned long flags;
58 spin_lock_irqsave(&apb_dma_lock, flags);
59 if (priv == NULL) {
60 spin_unlock_irqrestore(&apb_dma_lock, flags);
61 return;
63 priv->used_flag = 0;
64 priv->error_flag = 0;
65 priv->irq_handler = NULL;
66 priv->irq_handler_param = NULL;
67 priv->req_no = 0;
68 spin_unlock_irqrestore(&apb_dma_lock, flags);
71 void apb_dma_set_irq(struct apb_dma_priv *priv,
72 void (*func)(void *param), void *param)
74 unsigned long flags;
75 unsigned int cmd;
77 spin_lock_irqsave(&apb_dma_lock, flags);
78 if (priv == NULL) {
79 spin_unlock_irqrestore(&apb_dma_lock, flags);
80 return;
82 priv->irq_handler = func;
83 priv->irq_handler_param = param;
84 priv->error_flag = 0;
85 cmd = readl(&priv->reg->command.ul);
86 cmd |= (APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN);
87 writel(cmd, &priv->reg->command.ul);
88 spin_unlock_irqrestore(&apb_dma_lock, flags);
91 void apb_dma_release_irq(struct apb_dma_priv *priv)
93 unsigned long flags;
94 unsigned int cmd;
96 spin_lock_irqsave(&apb_dma_lock, flags);
97 if (priv == NULL) {
98 spin_unlock_irqrestore(&apb_dma_lock, flags);
99 return;
101 cmd = readl(&priv->reg->command.ul);
102 cmd &= ~(APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN);
103 writel(cmd, &priv->reg->command.ul);
104 priv->irq_handler = NULL;
105 priv->irq_handler_param = NULL;
106 priv->error_flag = 0;
107 spin_unlock_irqrestore(&apb_dma_lock, flags);
110 void apb_dma_conf(struct apb_dma_priv *priv, struct apb_dma_conf_param *param)
112 unsigned long flags;
113 union _command cmd;
114 unsigned int size;
116 spin_lock_irqsave(&apb_dma_lock, flags);
118 if (param->source_sel == APB_DMAB_SOURCE_AHB) {
119 writel(virt_to_phys((void *)param->source_addr),
120 &priv->reg->source_addr);
121 } else
122 writel(PHY_ADDRESS(param->source_addr),
123 &priv->reg->source_addr);
125 if (param->dest_sel == APB_DMAB_DEST_AHB) {
126 writel(virt_to_phys((void *)param->dest_addr),
127 &priv->reg->dest_addr);
128 } else
129 writel(PHY_ADDRESS(param->dest_addr), &priv->reg->dest_addr);
131 size = param->size;
132 switch (param->data_width) {
133 case APB_DMAB_DATA_WIDTH_1:
134 break;
135 case APB_DMAB_DATA_WIDTH_2:
136 size >>= 1;
137 break;
138 case APB_DMAB_DATA_WIDTH_4:
139 default:
140 size >>= 2;
141 break;
144 if (param->burst_mode)
145 size >>= 2;
147 writel(size, &priv->reg->cycles);
148 cmd.ul = readl(&priv->reg->command.ul);
149 cmd.bits.data_width = param->data_width;
150 if (param->dest_sel) { /* AHB */
151 dmac_inv_range((void *)param->dest_addr,
152 (void *)param->dest_addr + param->size);
153 cmd.bits.dest_req_no = 0;
154 } else { /* APB */
155 cmd.bits.dest_req_no = priv->req_no;
157 cmd.bits.dest_sel = param->dest_sel;
158 if (param->source_sel) { /* AHB */
159 dmac_flush_range((void *)param->source_addr,
160 (void *)param->source_addr + param->size);
161 cmd.bits.source_req_no = 0;
162 } else { /* APB */
163 cmd.bits.source_req_no = priv->req_no;
165 cmd.bits.source_sel = param->source_sel;
166 cmd.bits.burst = param->burst_mode;
167 cmd.bits.dest_inc = param->dest_inc;
168 cmd.bits.source_inc = param->source_inc;
169 writel(cmd.ul, &priv->reg->command.ul);
171 cmd.ul = readl(&priv->reg->command.ul);
172 dbg_printk(KERN_INFO
173 "apb_dma_conf: cmd.ul=%x read from &priv->reg->command.ul=%x\n"
174 , cmd.ul, (unsigned int)&priv->reg->command.ul);
176 spin_unlock_irqrestore(&apb_dma_lock, flags);
179 void apb_dma_enable(struct apb_dma_priv *priv)
181 unsigned long flags;
182 unsigned int cmd;
184 spin_lock_irqsave(&apb_dma_lock, flags);
185 cmd = readl(&priv->reg->command.ul);
186 /* dbg_printk(KERN_INFO "apb_dma_enable: cmd=%x read from
187 "&priv->reg->command.ul=%x\n", cmd,
188 (unsigned int)&priv->reg->command.ul);*/
189 cmd |= APB_DMA_ENABLE;
190 writel(cmd, &priv->reg->command.ul);
191 cmd = readl(&priv->reg->command.ul);
192 /* dbg_printk(KERN_INFO "apb_dma_enable: readback:"
193 "(cmd | APB_DMA_ENABLE)=%x\n", cmd);*/
194 spin_unlock_irqrestore(&apb_dma_lock, flags);
197 void apb_dma_disable(struct apb_dma_priv *priv)
199 unsigned long flags;
200 unsigned int cmd;
202 spin_lock_irqsave(&apb_dma_lock, flags);
203 cmd = readl(&priv->reg->command.ul);
204 cmd &= ~APB_DMA_ENABLE;
205 writel(cmd, &priv->reg->command.ul);
206 spin_unlock_irqrestore(&apb_dma_lock, flags);
209 static irqreturn_t moxart_dma_interrupt(int irq, void *devid)
211 int i;
212 unsigned int cmd;
213 struct apb_dma_priv *priv = apb_dma_channel;
215 /* dbg_printk(KERN_INFO "moxart_dma_interrupt\n"); */
216 for (i = 0; i < APB_DMA_MAX_CHANNEL; i++, priv++) {
217 cmd = readl(&priv->reg->command.ul);
218 if (cmd & APB_DMA_FIN_INT_STS)
219 cmd &= ~APB_DMA_FIN_INT_STS;
220 if (cmd & APB_DMA_ERR_INT_STS) {
221 cmd &= ~APB_DMA_ERR_INT_STS;
222 priv->error_flag = 1;
224 if (priv->used_flag && priv->irq_handler)
225 priv->irq_handler(priv->irq_handler_param);
226 priv->error_flag = 0;
227 writel(cmd, &priv->reg->command.ul);
230 return IRQ_HANDLED;
233 static struct irqaction moxart_dma_irq = {
234 .name = "MOXART APB DMA",
235 .flags = IRQF_DISABLED,
236 .handler = moxart_dma_interrupt,
239 static int moxart_dma_probe(struct platform_device *pdev)
241 int i;
242 struct apb_dma_priv *priv = apb_dma_channel;
244 memset(apb_dma_channel, 0, sizeof(apb_dma_channel));
245 spin_lock_init(&apb_dma_lock);
247 for (i = 0; i < APB_DMA_MAX_CHANNEL; i++)
248 priv[i].reg = (struct apb_dma_reg *)
249 (IO_ADDRESS(MOXART_APB_DMA_BASE)
250 + 0x80 + i*sizeof(struct apb_dma_reg));
252 moxart_int_set_irq(IRQ_APB_DMA, EDGE, H_ACTIVE);
253 setup_irq(IRQ_APB_DMA, &moxart_dma_irq);
255 dev_info(&pdev->dev, "MOXART APB DMA: finished moxart_dma_probe\n");
257 return 0;
260 static int moxart_dma_remove(struct platform_device *pdev)
262 return 0;
265 static struct platform_driver moxart_dma_driver = {
266 .probe = moxart_dma_probe,
267 .remove = __devexit_p(moxart_dma_remove),
268 .driver = {
269 .name = "MOXART_APB_DMA",
270 .owner = THIS_MODULE,
274 static __init int moxart_init(void)
276 return platform_driver_register(&moxart_dma_driver);
279 static __exit void moxart_exit(void)
281 platform_driver_unregister(&moxart_dma_driver);
284 module_init(moxart_init);
285 module_exit(moxart_exit);
287 MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>");
288 MODULE_DESCRIPTION("MOXART APB DMA driver");
289 MODULE_LICENSE("GPL");
290 MODULE_VERSION(DRV_VERSION);