xref: /openbmc/linux/arch/arm/mach-spear/pl080.c (revision 3a35093a)
1 /*
2  * arch/arm/plat-spear/pl080.c
3  *
4  * DMAC pl080 definitions for SPEAr platform
5  *
6  * Copyright (C) 2012 ST Microelectronics
7  * Viresh Kumar <vireshk@kernel.org>
8  *
9  * This file is licensed under the terms of the GNU General Public
10  * License version 2. This program is licensed "as is" without any
11  * warranty of any kind, whether express or implied.
12  */
13 
14 #include <linux/amba/pl08x.h>
15 #include <linux/amba/bus.h>
16 #include <linux/bug.h>
17 #include <linux/err.h>
18 #include <linux/io.h>
19 #include <linux/spinlock_types.h>
20 #include <mach/spear.h>
21 #include <mach/misc_regs.h>
22 
23 static spinlock_t lock = __SPIN_LOCK_UNLOCKED(x);
24 
25 struct {
26 	unsigned char busy;
27 	unsigned char val;
28 } signals[16] = {{0, 0}, };
29 
30 int pl080_get_signal(const struct pl08x_channel_data *cd)
31 {
32 	unsigned int signal = cd->min_signal, val;
33 	unsigned long flags;
34 
35 	spin_lock_irqsave(&lock, flags);
36 
37 	/* Return if signal is already acquired by somebody else */
38 	if (signals[signal].busy &&
39 			(signals[signal].val != cd->muxval)) {
40 		spin_unlock_irqrestore(&lock, flags);
41 		return -EBUSY;
42 	}
43 
44 	/* If acquiring for the first time, configure it */
45 	if (!signals[signal].busy) {
46 		val = readl(DMA_CHN_CFG);
47 
48 		/*
49 		 * Each request line has two bits in DMA_CHN_CFG register. To
50 		 * goto the bits of current request line, do left shift of
51 		 * value by 2 * signal number.
52 		 */
53 		val &= ~(0x3 << (signal * 2));
54 		val |= cd->muxval << (signal * 2);
55 		writel(val, DMA_CHN_CFG);
56 	}
57 
58 	signals[signal].busy++;
59 	signals[signal].val = cd->muxval;
60 	spin_unlock_irqrestore(&lock, flags);
61 
62 	return signal;
63 }
64 
65 void pl080_put_signal(const struct pl08x_channel_data *cd, int signal)
66 {
67 	unsigned long flags;
68 
69 	spin_lock_irqsave(&lock, flags);
70 
71 	/* if signal is not used */
72 	if (!signals[signal].busy)
73 		BUG();
74 
75 	signals[signal].busy--;
76 
77 	spin_unlock_irqrestore(&lock, flags);
78 }
79