Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
unicore32
kernel
dma.c
Go to the documentation of this file.
1
/*
2
* linux/arch/unicore32/kernel/dma.c
3
*
4
* Code specific to PKUnity SoC and UniCore ISA
5
*
6
* Maintained by GUAN Xue-tao <
[email protected]
>
7
* Copyright (C) 2001-2010 Guan Xuetao
8
*
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License version 2 as
11
* published by the Free Software Foundation.
12
*/
13
14
#include <linux/module.h>
15
#include <
linux/init.h
>
16
#include <linux/kernel.h>
17
#include <
linux/interrupt.h
>
18
#include <linux/errno.h>
19
#include <
linux/io.h
>
20
21
#include <asm/irq.h>
22
#include <mach/hardware.h>
23
#include <mach/dma.h>
24
25
struct
dma_channel
{
26
char
*
name
;
27
puv3_dma_prio
prio
;
28
void
(*
irq_handler
)(
int
,
void
*);
29
void
(*
err_handler
)(
int
,
void
*);
30
void
*
data
;
31
};
32
33
static
struct
dma_channel
dma_channels[
MAX_DMA_CHANNELS
];
34
35
int
puv3_request_dma
(
char
*
name
,
puv3_dma_prio
prio
,
36
void
(*
irq_handler
)(
int
,
void
*),
37
void
(*
err_handler
)(
int
,
void
*),
38
void
*
data
)
39
{
40
unsigned
long
flags
;
41
int
i
, found = 0;
42
43
/* basic sanity checks */
44
if
(!name)
45
return
-
EINVAL
;
46
47
local_irq_save
(flags);
48
49
do
{
50
/* try grabbing a DMA channel with the requested priority */
51
for
(i = 0; i <
MAX_DMA_CHANNELS
; i++) {
52
if
((dma_channels[i].prio == prio) &&
53
!dma_channels[i].name) {
54
found = 1;
55
break
;
56
}
57
}
58
/* if requested prio group is full, try a hier priority */
59
}
while
(!found && prio--);
60
61
if
(found) {
62
dma_channels[
i
].name =
name
;
63
dma_channels[
i
].irq_handler =
irq_handler
;
64
dma_channels[
i
].err_handler =
err_handler
;
65
dma_channels[
i
].data =
data
;
66
}
else
{
67
printk
(
KERN_WARNING
"No more available DMA channels for %s\n"
,
68
name);
69
i = -
ENODEV
;
70
}
71
72
local_irq_restore
(flags);
73
return
i
;
74
}
75
EXPORT_SYMBOL
(
puv3_request_dma
);
76
77
void
puv3_free_dma
(
int
dma_ch
)
78
{
79
unsigned
long
flags
;
80
81
if
(!dma_channels[dma_ch].name) {
82
printk
(
KERN_CRIT
83
"%s: trying to free channel %d which is already freed\n"
,
84
__func__, dma_ch);
85
return
;
86
}
87
88
local_irq_save
(flags);
89
dma_channels[
dma_ch
].name =
NULL
;
90
dma_channels[
dma_ch
].err_handler =
NULL
;
91
local_irq_restore
(flags);
92
}
93
EXPORT_SYMBOL
(
puv3_free_dma
);
94
95
static
irqreturn_t
dma_irq_handler(
int
irq
,
void
*
dev_id
)
96
{
97
int
i
,
dint
;
98
99
dint =
readl
(
DMAC_ITCSR
);
100
for
(i = 0; i <
MAX_DMA_CHANNELS
; i++) {
101
if
(dint &
DMAC_CHANNEL
(i)) {
102
struct
dma_channel
*
channel
= &dma_channels[
i
];
103
104
/* Clear TC interrupt of channel i */
105
writel
(
DMAC_CHANNEL
(i),
DMAC_ITCCR
);
106
writel
(0,
DMAC_ITCCR
);
107
108
if
(channel->
name
&& channel->
irq_handler
) {
109
channel->
irq_handler
(i, channel->
data
);
110
}
else
{
111
/*
112
* IRQ for an unregistered DMA channel:
113
* let's clear the interrupts and disable it.
114
*/
115
printk
(
KERN_WARNING
"spurious IRQ for"
116
" DMA channel %d\n"
, i);
117
}
118
}
119
}
120
return
IRQ_HANDLED
;
121
}
122
123
static
irqreturn_t
dma_err_handler(
int
irq,
void
*dev_id)
124
{
125
int
i
, dint;
126
127
dint =
readl
(
DMAC_IESR
);
128
for
(i = 0; i <
MAX_DMA_CHANNELS
; i++) {
129
if
(dint &
DMAC_CHANNEL
(i)) {
130
struct
dma_channel
*channel = &dma_channels[
i
];
131
132
/* Clear Err interrupt of channel i */
133
writel
(
DMAC_CHANNEL
(i),
DMAC_IECR
);
134
writel
(0,
DMAC_IECR
);
135
136
if
(channel->
name
&& channel->
err_handler
) {
137
channel->
err_handler
(i, channel->
data
);
138
}
else
{
139
/*
140
* IRQ for an unregistered DMA channel:
141
* let's clear the interrupts and disable it.
142
*/
143
printk
(
KERN_WARNING
"spurious IRQ for"
144
" DMA channel %d\n"
, i);
145
}
146
}
147
}
148
return
IRQ_HANDLED
;
149
}
150
151
int
__init
puv3_init_dma
(
void
)
152
{
153
int
i
,
ret
;
154
155
/* dma channel priorities on v8 processors:
156
* ch 0 - 1 <--> (0) DMA_PRIO_HIGH
157
* ch 2 - 3 <--> (1) DMA_PRIO_MEDIUM
158
* ch 4 - 5 <--> (2) DMA_PRIO_LOW
159
*/
160
for
(i = 0; i <
MAX_DMA_CHANNELS
; i++) {
161
puv3_stop_dma(i);
162
dma_channels[
i
].name =
NULL
;
163
dma_channels[
i
].prio =
min
((i & 0x7) >> 1,
DMA_PRIO_LOW
);
164
}
165
166
ret =
request_irq
(
IRQ_DMA
, dma_irq_handler, 0,
"DMA"
,
NULL
);
167
if
(ret) {
168
printk
(
KERN_CRIT
"Can't register IRQ for DMA\n"
);
169
return
ret
;
170
}
171
172
ret =
request_irq
(
IRQ_DMAERR
, dma_err_handler, 0,
"DMAERR"
,
NULL
);
173
if
(ret) {
174
printk
(
KERN_CRIT
"Can't register IRQ for DMAERR\n"
);
175
free_irq
(
IRQ_DMA
,
"DMA"
);
176
return
ret
;
177
}
178
179
return
0;
180
}
181
182
postcore_initcall
(
puv3_init_dma
);
Generated on Thu Jan 10 2013 12:55:52 for Linux Kernel by
1.8.2