MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / arch / arm / mach-moxart / apb_dma.c
blobb700308a3fdc9d7baa00744303623ecec76009ba
2 /*
3 * Copyright (C) 2005 Moxa Group All Rights Reserved.
5 * History:
6 * Date Author Comment
7 * 12-01-2005 Victor Yu. Create it.
8 */
9 #include <linux/version.h>
10 #include <linux/config.h>
11 #include <asm/arch/moxa.h>
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/interrupt.h>
15 #include <linux/mm.h>
16 #include <linux/slab.h>
17 #include <asm/arch/cpe_int.h>
18 #include <asm/arch/dma.h>
19 #include <asm/cacheflush.h>
20 #include <asm/irq.h>
22 //#define MOXA_DEBUG
23 #ifdef MOXA_DEBUG
24 #define DBG(x...) printk(x)
25 #else
26 #define DBG(x...)
27 #endif
29 static apb_dma_priv apb_dma_channel[APB_DMA_MAX_CHANNEL];
30 static spinlock_t apb_dma_lock;
32 apb_dma_priv *apb_dma_alloc(int req_no)
34 int i;
35 unsigned long flags;
36 apb_dma_priv *priv=apb_dma_channel;
38 spin_lock_irqsave(&apb_dma_lock, flags);
39 for ( i=0; i<APB_DMA_MAX_CHANNEL; i++, priv++ ) {
40 if ( priv->used_flag == 0 ) {
41 priv->used_flag = 1;
42 priv->irq_handler = NULL;
43 priv->irq_handler_param = NULL;
44 priv->error_flag = 0;
45 priv->req_no = req_no;
46 switch ( req_no ) {
47 case APB_DMA_SPI_TX_REQ_NO :
48 *(unsigned int *)(CPE_PMU_BASE+0xA0) = 0;
49 break;
50 case APB_DMA_SPI_RX_REQ_NO :
51 *(unsigned int *)(CPE_PMU_BASE+0xA4) = 0;
52 break;
53 case APB_DMA_SD_REQ_NO :
54 *(unsigned int *)(CPE_PMU_BASE+0xB8) = 0;
55 break;
56 case APB_DMA_AC97_TX_REQ_NO :
57 *(unsigned int *)(CPE_PMU_BASE+0xBC) = 0;
58 break;
59 case APB_DMA_AC97_RX_REQ_NO :
60 *(unsigned int *)(CPE_PMU_BASE+0xC0) = 0;
61 break;
62 case APB_DMA_USB_DEVICE_REQ_NO :
63 *(unsigned int *)(CPE_PMU_BASE+0xCC) = 0;
64 break;
66 spin_unlock_irqrestore(&apb_dma_lock, flags);
67 DBG("apb_dma_alloc uses DMA channel %d\n", i);
68 return priv;
71 spin_unlock_irqrestore(&apb_dma_lock, flags);
72 return NULL;
74 EXPORT_SYMBOL(apb_dma_alloc);
76 void apb_dma_release(apb_dma_priv *priv)
78 unsigned long flags;
80 spin_lock_irqsave(&apb_dma_lock, flags);
81 if ( priv == NULL ) {
82 spin_unlock_irqrestore(&apb_dma_lock, flags);
83 return;
85 priv->used_flag = 0;
86 priv->error_flag = 0;
87 priv->irq_handler = NULL;
88 priv->irq_handler_param = NULL;
89 priv->req_no = 0;
90 spin_unlock_irqrestore(&apb_dma_lock, flags);
92 EXPORT_SYMBOL(apb_dma_release);
94 void apb_dma_set_irq(apb_dma_priv *priv, void (*func)(void *param), void *param)
96 unsigned long flags;
97 unsigned int cmd;
99 spin_lock_irqsave(&apb_dma_lock, flags);
100 if ( priv == NULL ) {
101 spin_unlock_irqrestore(&apb_dma_lock, flags);
102 return;
104 priv->irq_handler = func;
105 priv->irq_handler_param = param;
106 priv->error_flag = 0;
107 cmd = readl(&priv->reg->command.ul);
108 cmd |= (APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN);
109 writel(cmd, &priv->reg->command.ul);
110 spin_unlock_irqrestore(&apb_dma_lock, flags);
112 EXPORT_SYMBOL(apb_dma_set_irq);
114 void apb_dma_release_irq(apb_dma_priv *priv)
116 unsigned long flags;
117 unsigned int cmd;
119 spin_lock_irqsave(&apb_dma_lock, flags);
120 if ( priv == NULL ) {
121 spin_unlock_irqrestore(&apb_dma_lock, flags);
122 return;
124 cmd = readl(&priv->reg->command.ul);
125 cmd &= ~(APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN);
126 writel(cmd, &priv->reg->command.ul);
127 priv->irq_handler = NULL;
128 priv->irq_handler_param = NULL;
129 priv->error_flag = 0;
130 spin_unlock_irqrestore(&apb_dma_lock, flags);
132 EXPORT_SYMBOL(apb_dma_release_irq);
134 void apb_dma_conf(apb_dma_priv *priv, apb_dma_conf_param *param)
136 unsigned long flags;
137 union _command cmd;
138 unsigned int size;
140 spin_lock_irqsave(&apb_dma_lock, flags);
141 writel(param->source_addr, &priv->reg->source_addr);
142 writel(param->dest_addr, &priv->reg->dest_addr);
143 size = param->size;
144 switch ( param->data_width ) {
145 case APB_DMAB_DATA_WIDTH_1 :
146 break;
147 case APB_DMAB_DATA_WIDTH_2 :
148 size >>= 1;
149 break;
150 case APB_DMAB_DATA_WIDTH_4 :
151 default :
152 size >>= 2;
153 break;
155 if ( param->burst_mode )
156 size >>= 2;
157 writel(size, &priv->reg->cycles);
158 cmd.ul = readl(&priv->reg->command.ul);
159 cmd.bits.data_width = param->data_width;
160 if ( param->dest_sel ) { // AHB
161 #if 1 // add by Victor Yu. 07-12-2007
162 dmac_inv_range(param->dest_addr, param->dest_addr+param->size);
163 #endif
164 cmd.bits.dest_req_no = 0;
165 } else { // APB
166 cmd.bits.dest_req_no = priv->req_no;
168 cmd.bits.dest_sel = param->dest_sel;
169 if ( param->source_sel ) { // AHB
170 #if 1 // add by Victor Yu. 07-12-2007
171 dmac_flush_range(param->source_addr, param->source_addr+param->size);
172 #endif
173 cmd.bits.source_req_no = 0;
174 } else { // APB
175 cmd.bits.source_req_no = priv->req_no;
177 cmd.bits.source_sel = param->source_sel;
178 cmd.bits.burst = param->burst_mode;
179 cmd.bits.dest_inc = param->dest_inc;
180 cmd.bits.source_inc = param->source_inc;
181 writel(cmd.ul, &priv->reg->command.ul);
182 spin_unlock_irqrestore(&apb_dma_lock, flags);
184 EXPORT_SYMBOL(apb_dma_conf);
186 void apb_dma_enable(apb_dma_priv *priv)
188 unsigned long flags;
189 unsigned int cmd;
191 spin_lock_irqsave(&apb_dma_lock, flags);
192 cmd = readl(&priv->reg->command.ul);
193 cmd |= APB_DMA_ENABLE;
194 writel(cmd, &priv->reg->command.ul);
195 spin_unlock_irqrestore(&apb_dma_lock, flags);
197 EXPORT_SYMBOL(apb_dma_enable);
198 EXPORT_SYMBOL(apb_dma_disable);
199 void apb_dma_disable(apb_dma_priv *priv)
201 unsigned long flags;
202 unsigned int cmd;
204 spin_lock_irqsave(&apb_dma_lock, flags);
205 cmd = readl(&priv->reg->command.ul);
206 cmd &= ~APB_DMA_ENABLE;
207 writel(cmd, &priv->reg->command.ul);
208 spin_unlock_irqrestore(&apb_dma_lock, flags);
211 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-08-2007
212 static irqreturn_t apb_dma_irq(int irq, void *devid)
213 #else
214 static irqreturn_t apb_dma_irq(int irq, void *devid, struct pt_regs *regs)
215 #endif // LINUX_VERSION_CODE
217 int i;
218 unsigned int cmd;
219 apb_dma_priv *priv=apb_dma_channel;
221 DBG("apb_dma_irq test01\n");
222 for ( i=0; i<APB_DMA_MAX_CHANNEL; i++, priv++ ) {
223 cmd = readl(&priv->reg->command.ul);
224 if ( cmd & APB_DMA_FIN_INT_STS ) {
225 DBG("apb_dma_irq finish interrupt channel [%d]\n", i);
226 cmd &= ~APB_DMA_FIN_INT_STS;
228 if ( cmd & APB_DMA_ERR_INT_STS ) {
229 DBG("apb_dma_irq error interrupt channel [%d]\n", i);
230 cmd &= ~APB_DMA_ERR_INT_STS;
231 priv->error_flag = 1;
233 if ( priv->used_flag && priv->irq_handler ) {
234 priv->irq_handler(priv->irq_handler_param);
236 priv->error_flag = 0;
237 writel(cmd, &priv->reg->command.ul);
240 return IRQ_HANDLED;
243 static int __init apb_dma_init(void)
245 int ret, i;
246 apb_dma_priv *priv=apb_dma_channel;
248 printk("Moxa CPU APB DMA Device Driver V1.0 load ");
250 memset(apb_dma_channel, 0, sizeof(apb_dma_channel));
251 spin_lock_init(&apb_dma_lock);
253 for ( i=0; i<APB_DMA_MAX_CHANNEL; i++, priv++ ) {
254 priv->reg = (apb_dma_reg *)(CPE_APBDMA_BASE+0x80+i*sizeof(apb_dma_reg));
257 cpe_int_set_irq(IRQ_APBDMA, EDGE, H_ACTIVE);
258 ret = request_irq(IRQ_APBDMA, apb_dma_irq, SA_INTERRUPT, "APB DMA", NULL);
259 if ( ret )
260 printk("fail !\n");
261 else
262 printk("OK.\n");
264 return ret;
267 module_init(apb_dma_init);