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>
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
)
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) {
33 priv
->irq_handler
= NULL
;
34 priv
->irq_handler_param
= NULL
;
36 priv
->req_no
= req_no
;
38 case APB_DMA_SD_REQ_NO
:
39 *(unsigned int *) (IO_ADDRESS(MOXART_PMU_BASE
)
43 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
45 "MOXART APB DMA: apb_dma_alloc uses DMA channel %d\n"
50 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
54 void apb_dma_release(struct apb_dma_priv
*priv
)
58 spin_lock_irqsave(&apb_dma_lock
, flags
);
60 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
65 priv
->irq_handler
= NULL
;
66 priv
->irq_handler_param
= NULL
;
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
)
77 spin_lock_irqsave(&apb_dma_lock
, flags
);
79 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
82 priv
->irq_handler
= func
;
83 priv
->irq_handler_param
= param
;
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
)
96 spin_lock_irqsave(&apb_dma_lock
, flags
);
98 spin_unlock_irqrestore(&apb_dma_lock
, flags
);
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
)
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
);
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
);
129 writel(PHY_ADDRESS(param
->dest_addr
), &priv
->reg
->dest_addr
);
132 switch (param
->data_width
) {
133 case APB_DMAB_DATA_WIDTH_1
:
135 case APB_DMAB_DATA_WIDTH_2
:
138 case APB_DMAB_DATA_WIDTH_4
:
144 if (param
->burst_mode
)
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;
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;
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
);
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
)
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
)
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
)
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
);
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
)
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");
260 static int moxart_dma_remove(struct platform_device
*pdev
)
265 static struct platform_driver moxart_dma_driver
= {
266 .probe
= moxart_dma_probe
,
267 .remove
= __devexit_p(moxart_dma_remove
),
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
);