1/* 2 * linux/arch/arm/mach-pxa/dma.c 3 * 4 * PXA DMA registration and IRQ dispatching 5 * 6 * Author: Nicolas Pitre 7 * Created: Nov 15, 2001 8 * Copyright: MontaVista Software Inc. 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 15#include <linux/module.h> 16#include <linux/init.h> 17#include <linux/kernel.h> 18#include <linux/interrupt.h> 19#include <linux/errno.h> 20 21#include <asm/system.h> 22#include <asm/irq.h> 23#include <asm/hardware.h> 24#include <asm/dma.h> 25 26#include <asm/arch/pxa-regs.h> 27 28static struct dma_channel { 29 char *name; 30 void (*irq_handler)(int, void *); 31 void *data; 32} dma_channels[PXA_DMA_CHANNELS]; 33 34 35int pxa_request_dma (char *name, pxa_dma_prio prio, 36 void (*irq_handler)(int, void *), 37 void *data) 38{ 39 unsigned long flags; 40 int i, found = 0; 41 42 /* basic sanity checks */ 43 if (!name || !irq_handler) 44 return -EINVAL; 45 46 local_irq_save(flags); 47 48 do { 49 /* try grabbing a DMA channel with the requested priority */ 50 pxa_for_each_dma_prio (i, prio) { 51 if (!dma_channels[i].name) { 52 found = 1; 53 break; 54 } 55 } 56 /* if requested prio group is full, try a hier priority */ 57 } while (!found && prio--); 58 59 if (found) { 60 DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; 61 dma_channels[i].name = name; 62 dma_channels[i].irq_handler = irq_handler; 63 dma_channels[i].data = data; 64 } else { 65 printk (KERN_WARNING "No more available DMA channels for %s\n", name); 66 i = -ENODEV; 67 } 68 69 local_irq_restore(flags); 70 return i; 71} 72 73void pxa_free_dma (int dma_ch) 74{ 75 unsigned long flags; 76 77 if (!dma_channels[dma_ch].name) { 78 printk (KERN_CRIT 79 "%s: trying to free channel %d which is already freed\n", 80 __FUNCTION__, dma_ch); 81 return; 82 } 83 84 local_irq_save(flags); 85 DCSR(dma_ch) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; 86 dma_channels[dma_ch].name = NULL; 87 local_irq_restore(flags); 88} 89 90static irqreturn_t dma_irq_handler(int irq, void *dev_id) 91{ 92 int i, dint = DINT; 93 94 for (i = 0; i < PXA_DMA_CHANNELS; i++) { 95 if (dint & (1 << i)) { 96 struct dma_channel *channel = &dma_channels[i]; 97 if (channel->name && channel->irq_handler) { 98 channel->irq_handler(i, channel->data); 99 } else { 100 /* 101 * IRQ for an unregistered DMA channel: 102 * let's clear the interrupts and disable it. 103 */ 104 printk (KERN_WARNING "spurious IRQ for DMA channel %d\n", i); 105 DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; 106 } 107 } 108 } 109 return IRQ_HANDLED; 110} 111 112static int __init pxa_dma_init (void) 113{ 114 int ret; 115 116 ret = request_irq (IRQ_DMA, dma_irq_handler, 0, "DMA", NULL); 117 if (ret) 118 printk (KERN_CRIT "Wow! Can't register IRQ for DMA\n"); 119 return ret; 120} 121 122arch_initcall(pxa_dma_init); 123 124EXPORT_SYMBOL(pxa_request_dma); 125EXPORT_SYMBOL(pxa_free_dma); 126