18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * arch/arm/plat-spear/pl080.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * DMAC pl080 definitions for SPEAr platform
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2012 ST Microelectronics
78c2ecf20Sopenharmony_ci * Viresh Kumar <vireshk@kernel.org>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public
108c2ecf20Sopenharmony_ci * License version 2. This program is licensed "as is" without any
118c2ecf20Sopenharmony_ci * warranty of any kind, whether express or implied.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/amba/pl08x.h>
158c2ecf20Sopenharmony_ci#include <linux/amba/bus.h>
168c2ecf20Sopenharmony_ci#include <linux/bug.h>
178c2ecf20Sopenharmony_ci#include <linux/err.h>
188c2ecf20Sopenharmony_ci#include <linux/io.h>
198c2ecf20Sopenharmony_ci#include <linux/spinlock_types.h>
208c2ecf20Sopenharmony_ci#include <mach/spear.h>
218c2ecf20Sopenharmony_ci#include <mach/misc_regs.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic spinlock_t lock = __SPIN_LOCK_UNLOCKED(x);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistruct {
268c2ecf20Sopenharmony_ci	unsigned char busy;
278c2ecf20Sopenharmony_ci	unsigned char val;
288c2ecf20Sopenharmony_ci} signals[16] = {{0, 0}, };
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ciint pl080_get_signal(const struct pl08x_channel_data *cd)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	unsigned int signal = cd->min_signal, val;
338c2ecf20Sopenharmony_ci	unsigned long flags;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	spin_lock_irqsave(&lock, flags);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	/* Return if signal is already acquired by somebody else */
388c2ecf20Sopenharmony_ci	if (signals[signal].busy &&
398c2ecf20Sopenharmony_ci			(signals[signal].val != cd->muxval)) {
408c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&lock, flags);
418c2ecf20Sopenharmony_ci		return -EBUSY;
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	/* If acquiring for the first time, configure it */
458c2ecf20Sopenharmony_ci	if (!signals[signal].busy) {
468c2ecf20Sopenharmony_ci		val = readl(DMA_CHN_CFG);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci		/*
498c2ecf20Sopenharmony_ci		 * Each request line has two bits in DMA_CHN_CFG register. To
508c2ecf20Sopenharmony_ci		 * goto the bits of current request line, do left shift of
518c2ecf20Sopenharmony_ci		 * value by 2 * signal number.
528c2ecf20Sopenharmony_ci		 */
538c2ecf20Sopenharmony_ci		val &= ~(0x3 << (signal * 2));
548c2ecf20Sopenharmony_ci		val |= cd->muxval << (signal * 2);
558c2ecf20Sopenharmony_ci		writel(val, DMA_CHN_CFG);
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	signals[signal].busy++;
598c2ecf20Sopenharmony_ci	signals[signal].val = cd->muxval;
608c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&lock, flags);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	return signal;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_civoid pl080_put_signal(const struct pl08x_channel_data *cd, int signal)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	unsigned long flags;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	spin_lock_irqsave(&lock, flags);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	/* if signal is not used */
728c2ecf20Sopenharmony_ci	if (!signals[signal].busy)
738c2ecf20Sopenharmony_ci		BUG();
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	signals[signal].busy--;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&lock, flags);
788c2ecf20Sopenharmony_ci}
79