From 7b5b08d99d5362e9c36fd7d42d6c06c2a848266c Mon Sep 17 00:00:00 2001 From: Kurt Mahan Date: Sun, 9 Dec 2007 02:21:19 -0700 Subject: [PATCH] Update EDMA. LTIBName: m5445x-edma-update Signed-off-by: Kurt Mahan --- drivers/spi/coldfire_edma.c | 261 +++++++++++++++++++++++--------------- include/asm-m68k/coldfire_edma.h | 9 +- include/asm-m68k/mcf5445x_edma.h | 28 +++- 3 files changed, 188 insertions(+), 110 deletions(-) --- a/drivers/spi/coldfire_edma.c +++ b/drivers/spi/coldfire_edma.c @@ -20,76 +20,91 @@ #include #include #include +#ifdef CONFIG_M54455 #include #include +#endif /* CONFIG_M54455 */ #include - -/* callback handler data for each TCD */ +/* + * Callback handler data for each TCD + */ struct edma_isr_record { - edma_irq_handler irq_handler; /* interrupt handler */ - edma_error_handler error_handler; /* error interrupt handler */ - void* dev; /* device used for the channel */ - int allocated; /* busy flag */ - spinlock_t *lock; /* spin lock (if needs to be locked in interrupt) */ - const char* device_id; /* device id string, used in proc file system */ + edma_irq_handler irq_handler; /* interrupt handler */ + edma_error_handler error_handler; /* error interrupt handler */ + void *arg; /* argument to pass back */ + int allocated; /* busy flag */ + spinlock_t *lock; /* spin lock (optional) */ + const char *device_id; /* dev id string, used in procfs */ }; -/* device structure */ +/* + * Device structure + */ struct coldfire_edma_dev { - struct cdev cdev; /* character device */ - struct edma_isr_record dma_interrupt_handlers[EDMA_CHANNELS]; /* channel handlers */ + struct cdev cdev; /* character device */ + struct edma_isr_record dma_interrupt_handlers[EDMA_CHANNELS]; }; /* allocated major device number */ static int coldfire_dma_major; + /* device driver structure */ -static struct coldfire_edma_dev* devp = NULL; +static struct coldfire_edma_dev *devp = NULL; /* device driver file operations */ struct file_operations coldfire_edma_fops = { .owner = THIS_MODULE, }; -/* eDMA channel interrupt handler */ +/** + * dmaisr - eDMA channel interrupt handler + * @irq: interrupt number + * @dev_id: argument + */ static int dmaisr(int irq, void *dev_id) { int channel = irq - EDMA_INT_CONTROLLER_BASE - EDMA_INT_CHANNEL_BASE; int result = IRQ_HANDLED; - if (devp!=NULL && devp->dma_interrupt_handlers[channel].lock) { - spin_lock(devp->dma_interrupt_handlers[channel].lock); - } + if ((devp != NULL) && + (devp->dma_interrupt_handlers[channel].irq_handler)) { + /* call user irq handler */ + if (devp->dma_interrupt_handlers[channel].lock) + spin_lock(devp->dma_interrupt_handlers[channel].lock); + + result = devp->dma_interrupt_handlers[channel].irq_handler( + channel, devp->dma_interrupt_handlers[channel].arg); - if (devp!=NULL && devp->dma_interrupt_handlers[channel].irq_handler) { - result = devp->dma_interrupt_handlers[channel].irq_handler(channel, - devp->dma_interrupt_handlers[channel].dev); + if (devp->dma_interrupt_handlers[channel].lock) + spin_unlock(devp->dma_interrupt_handlers[channel].lock); } else { + /* no irq handler so just ack it */ confirm_edma_interrupt_handled(channel); - printk(EDMA_DRIVER_NAME ": No handler for DMA channel %d\n", channel); - } - - if (devp!=NULL && devp->dma_interrupt_handlers[channel].lock) { - spin_unlock(devp->dma_interrupt_handlers[channel].lock); + printk(EDMA_DRIVER_NAME ": No handler for DMA channel %d\n", + channel); } return result; } -/* eDMA error interrupt handler */ +/** + * dma_error_isr - eDMA error interrupt handler + * @irq: interrupt number + * @dev_id: argument + */ static int dma_error_isr(int irq, void* dev_id) { u16 err; int i; err = MCF_EDMA_ERR; - for (i=0;idma_interrupt_handlers[i].error_handler) { - devp->dma_interrupt_handlers[i].error_handler(i, devp->dma_interrupt_handlers[i].dev); - } else { + if (devp!=NULL && devp->dma_interrupt_handlers[i].error_handler) + devp->dma_interrupt_handlers[i].error_handler(i, devp->dma_interrupt_handlers[i].arg); + else printk(KERN_WARNING EDMA_DRIVER_NAME ": DMA error on channel %d\n", i); - } } } @@ -97,11 +112,26 @@ static int dma_error_isr(int irq, void* return IRQ_HANDLED; } -/* sets channel parameters */ +/** + * set_edma_params - Set transfer control descriptor (TCD) + * @channel: channel number + * @source: source address + * @dest: destination address + * @attr: attributes + * @soff: source offset + * @nbytes: number of bytes to be transfered in minor loop + * @slast: last source address adjustment + * @citer: major loop count + * @biter: beginning minor loop count + * @doff: destination offset + * @dlast_sga: last destination address adjustment + * @major_int: generate interrupt after each major loop + * @disable_req: disable DMA request after major loop + */ void set_edma_params(int channel, u32 source, u32 dest, - u32 attr, u32 soff, u32 nbytes, u32 slast, - u32 citer, u32 biter, u32 doff, u32 dlast_sga, - int major_int, int disable_req) + u32 attr, u32 soff, u32 nbytes, u32 slast, + u32 citer, u32 biter, u32 doff, u32 dlast_sga, + int major_int, int disable_req) { if (channel<0 || channel>EDMA_CHANNELS) @@ -117,45 +147,56 @@ void set_edma_params(int channel, u32 so MCF_EDMA_TCD_BITER(channel)=MCF_EDMA_TCD_BITER_BITER(biter); MCF_EDMA_TCD_DOFF(channel) = MCF_EDMA_TCD_DOFF_DOFF(doff); MCF_EDMA_TCD_DLAST_SGA(channel) = MCF_EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga); + /* interrupt at the end of major loop */ - if (major_int) { + if (major_int) MCF_EDMA_TCD_CSR(channel) |= MCF_EDMA_TCD_CSR_INT_MAJOR; - } else { + else MCF_EDMA_TCD_CSR(channel) &= ~MCF_EDMA_TCD_CSR_INT_MAJOR; - } + /* disable request at the end of major loop of transfer or not*/ - if (disable_req) { + if (disable_req) MCF_EDMA_TCD_CSR(channel) |= MCF_EDMA_TCD_CSR_D_REQ; - } else { + else MCF_EDMA_TCD_CSR(channel) &= ~MCF_EDMA_TCD_CSR_D_REQ; - } - } EXPORT_SYMBOL(set_edma_params); -/* init eDMA controller */ +/** + * init_edma - Initialize the eDMA controller + */ void init_edma(void) { MCF_EDMA_CR = 0; } EXPORT_SYMBOL(init_edma); -/* request eDMA channel */ +/** + * request_edma_channel - Request an eDMA channel + * @channel: channel number + * @handler: dma handler + * @error_handler: dma error handler + * @arg: argument to pass back + * @lock: optional spinlock to hold over interrupt + * @device_id: device id + * + * Returns 0 if success or a negative value if failure + */ int request_edma_channel(int channel, - edma_irq_handler handler, - edma_error_handler error_handler, - void* dev, - spinlock_t *lock, - const char* device_id ) + edma_irq_handler handler, + edma_error_handler error_handler, + void *arg, + spinlock_t *lock, + const char *device_id ) { if (devp!=NULL && channel>=0 && channel<=EDMA_CHANNELS) { - if (devp->dma_interrupt_handlers[channel].allocated) { + if (devp->dma_interrupt_handlers[channel].allocated) return -EBUSY; - } + devp->dma_interrupt_handlers[channel].allocated = 1; devp->dma_interrupt_handlers[channel].irq_handler = handler; devp->dma_interrupt_handlers[channel].error_handler = error_handler; - devp->dma_interrupt_handlers[channel].dev = dev; + devp->dma_interrupt_handlers[channel].arg = arg; devp->dma_interrupt_handlers[channel].lock = lock; devp->dma_interrupt_handlers[channel].device_id = device_id; return 0; @@ -164,16 +205,22 @@ int request_edma_channel(int channel, } EXPORT_SYMBOL(request_edma_channel); -/* free eDMA channel */ -int free_edma_channel(int channel, void* dev) +/** + * free_edma_channel - Free the edma channel + * @channel: channel number + * @arg: argument created with + * + * Returns 0 if success or a negative value if failure + */ +int free_edma_channel(int channel, void *arg) { if (devp!=NULL && channel>=0 && channel<=EDMA_CHANNELS) { if (devp->dma_interrupt_handlers[channel].allocated) { - if (devp->dma_interrupt_handlers[channel].dev != dev) { + if (devp->dma_interrupt_handlers[channel].arg != arg) return -EBUSY; - } + devp->dma_interrupt_handlers[channel].allocated = 0; - devp->dma_interrupt_handlers[channel].dev = NULL; + devp->dma_interrupt_handlers[channel].arg = NULL; devp->dma_interrupt_handlers[channel].irq_handler = NULL; devp->dma_interrupt_handlers[channel].error_handler = NULL; devp->dma_interrupt_handlers[channel].lock = NULL; @@ -184,7 +231,9 @@ int free_edma_channel(int channel, void* } EXPORT_SYMBOL(free_edma_channel); -/* clean-up device driver allocated resources */ +/** + * coldfire_edma_cleanup - cleanup driver allocated resources + */ static void coldfire_edma_cleanup(void) { dev_t devno; @@ -192,13 +241,10 @@ static void coldfire_edma_cleanup(void) /* free interrupts/memory */ if (devp) { - for (i=0;icdev); kfree(devp); } @@ -209,30 +255,42 @@ static void coldfire_edma_cleanup(void) } #ifdef CONFIG_PROC_FS -/* proc file system support */ +/* + * proc file system support + */ #define FREE_CHANNEL "free" #define DEVICE_UNKNOWN "device unknown" +/** + * proc_edma_show - print out proc info + * @m: seq_file + * @v: + */ static int proc_edma_show(struct seq_file *m, void *v) { int i; - if (devp==NULL) return 0; + if (devp == NULL) + return 0; for (i = 0 ; i < EDMA_CHANNELS ; i++) { if (devp->dma_interrupt_handlers[i].allocated) { if (devp->dma_interrupt_handlers[i].device_id) - seq_printf(m, "%2d: %s\n", i, devp->dma_interrupt_handlers[i].device_id); + seq_printf(m, "%2d: %s\n", i, devp->dma_interrupt_handlers[i].device_id); else seq_printf(m, "%2d: %s\n", i, DEVICE_UNKNOWN); - } else { + } else seq_printf(m, "%2d: %s\n", i, FREE_CHANNEL); - } } return 0; } +/** + * proc_edma_open - open the proc file + * @inode: inode ptr + * @file: file ptr + */ static int proc_edma_open(struct inode *inode, struct file *file) { return single_open(file, proc_edma_show, NULL); @@ -245,6 +303,9 @@ static const struct file_operations proc .release = single_release, }; +/** + * proc_edma_init - initialize proc filesystem + */ static int __init proc_edma_init(void) { struct proc_dir_entry *e; @@ -258,7 +319,9 @@ static int __init proc_edma_init(void) #endif -/* initializes device driver */ +/** + * coldfire_edma_init - eDMA module init + */ static int __init coldfire_edma_init(void) { dev_t dev; @@ -267,8 +330,9 @@ static int __init coldfire_edma_init(voi /* allocate free major number */ result = alloc_chrdev_region(&dev, DMA_DEV_MINOR, 1, EDMA_DRIVER_NAME); - if (result<0) { - printk(KERN_WARNING EDMA_DRIVER_NAME": can't get major %d\n", result); + if (result < 0) { + printk(KERN_WARNING EDMA_DRIVER_NAME": can't get major %d\n", + result); return result; } coldfire_dma_major = MAJOR(dev); @@ -280,71 +344,68 @@ static int __init coldfire_edma_init(voi goto fail; } - /* init handlers (no handlers for beggining) */ - for (i=0;idma_interrupt_handlers[i].irq_handler = NULL; devp->dma_interrupt_handlers[i].error_handler = NULL; - devp->dma_interrupt_handlers[i].dev = NULL; + devp->dma_interrupt_handlers[i].arg = NULL; devp->dma_interrupt_handlers[i].allocated = 0; devp->dma_interrupt_handlers[i].lock = NULL; devp->dma_interrupt_handlers[i].device_id = NULL; } - /* register char device */ + /* register char device */ cdev_init(&devp->cdev, &coldfire_edma_fops); devp->cdev.owner = THIS_MODULE; devp->cdev.ops = &coldfire_edma_fops; result = cdev_add(&devp->cdev, dev, 1); if (result) { - printk(KERN_NOTICE EDMA_DRIVER_NAME": Error %d adding coldfire-dma device\n", result); + printk(KERN_NOTICE EDMA_DRIVER_NAME + ": Error %d adding coldfire-dma device\n", result); result = -ENODEV; goto fail; } /* request/enable irq for each eDMA channel */ - for (i=0;i