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