diff options
Diffstat (limited to 'arch/arm/mach-spear/pl080.c')
| -rw-r--r-- | arch/arm/mach-spear/pl080.c | 78 | 
1 files changed, 78 insertions, 0 deletions
| diff --git a/arch/arm/mach-spear/pl080.c b/arch/arm/mach-spear/pl080.c new file mode 100644 index 00000000000..cfa1199d0f4 --- /dev/null +++ b/arch/arm/mach-spear/pl080.c @@ -0,0 +1,78 @@ +/* + * arch/arm/plat-spear/pl080.c + * + * DMAC pl080 definitions for SPEAr platform + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.linux@gmail.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/amba/pl08x.h> +#include <linux/amba/bus.h> +#include <linux/bug.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/spinlock_types.h> +#include <mach/spear.h> +#include <mach/misc_regs.h> + +static spinlock_t lock = __SPIN_LOCK_UNLOCKED(x); + +struct { +	unsigned char busy; +	unsigned char val; +} signals[16] = {{0, 0}, }; + +int pl080_get_signal(const struct pl08x_channel_data *cd) +{ +	unsigned int signal = cd->min_signal, val; +	unsigned long flags; + +	spin_lock_irqsave(&lock, flags); + +	/* Return if signal is already acquired by somebody else */ +	if (signals[signal].busy && +			(signals[signal].val != cd->muxval)) { +		spin_unlock_irqrestore(&lock, flags); +		return -EBUSY; +	} + +	/* If acquiring for the first time, configure it */ +	if (!signals[signal].busy) { +		val = readl(DMA_CHN_CFG); + +		/* +		 * Each request line has two bits in DMA_CHN_CFG register. To +		 * goto the bits of current request line, do left shift of +		 * value by 2 * signal number. +		 */ +		val &= ~(0x3 << (signal * 2)); +		val |= cd->muxval << (signal * 2); +		writel(val, DMA_CHN_CFG); +	} + +	signals[signal].busy++; +	signals[signal].val = cd->muxval; +	spin_unlock_irqrestore(&lock, flags); + +	return signal; +} + +void pl080_put_signal(const struct pl08x_channel_data *cd, int signal) +{ +	unsigned long flags; + +	spin_lock_irqsave(&lock, flags); + +	/* if signal is not used */ +	if (!signals[signal].busy) +		BUG(); + +	signals[signal].busy--; + +	spin_unlock_irqrestore(&lock, flags); +} |