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