2011-09-02 09:44:35 +09:00
/* linux/arch/arm/plat-samsung/s3c-dma-ops.c
*
* Copyright ( c ) 2011 Samsung Electronics Co . , Ltd .
* http : //www.samsung.com
*
* Samsung S3C - DMA Operations
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <linux/types.h>
2011-10-08 23:24:48 -04:00
# include <linux/export.h>
2011-09-02 09:44:35 +09:00
# include <mach/dma.h>
struct cb_data {
void ( * fp ) ( void * ) ;
void * fp_param ;
unsigned ch ;
struct list_head node ;
} ;
static LIST_HEAD ( dma_list ) ;
static void s3c_dma_cb ( struct s3c2410_dma_chan * channel , void * param ,
int size , enum s3c2410_dma_buffresult res )
{
struct cb_data * data = param ;
data - > fp ( data - > fp_param ) ;
}
static unsigned s3c_dma_request ( enum dma_ch dma_ch ,
2013-01-18 17:17:02 +05:30
struct samsung_dma_req * param ,
struct device * dev , char * ch_name )
2011-09-02 09:44:35 +09:00
{
struct cb_data * data ;
2012-06-19 13:26:53 +09:00
if ( s3c2410_dma_request ( dma_ch , param - > client , NULL ) < 0 ) {
s3c2410_dma_free ( dma_ch , param - > client ) ;
2011-09-02 09:44:35 +09:00
return 0 ;
}
2012-06-19 13:26:53 +09:00
if ( param - > cap = = DMA_CYCLIC )
s3c2410_dma_setflags ( dma_ch , S3C2410_DMAF_CIRCULAR ) ;
2011-09-02 09:44:35 +09:00
data = kzalloc ( sizeof ( struct cb_data ) , GFP_KERNEL ) ;
data - > ch = dma_ch ;
list_add_tail ( & data - > node , & dma_list ) ;
return ( unsigned ) dma_ch ;
}
2012-06-19 13:26:53 +09:00
static int s3c_dma_release ( unsigned ch , void * param )
2011-09-02 09:44:35 +09:00
{
struct cb_data * data ;
list_for_each_entry ( data , & dma_list , node )
if ( data - > ch = = ch )
break ;
list_del ( & data - > node ) ;
2012-06-19 13:26:53 +09:00
s3c2410_dma_free ( ch , param ) ;
2011-09-02 09:44:35 +09:00
kfree ( data ) ;
return 0 ;
}
2012-06-19 13:26:53 +09:00
static int s3c_dma_config ( unsigned ch , struct samsung_dma_config * param )
{
s3c2410_dma_devconfig ( ch , param - > direction , param - > fifo ) ;
s3c2410_dma_config ( ch , param - > width ) ;
return 0 ;
}
static int s3c_dma_prepare ( unsigned ch , struct samsung_dma_prep * param )
2011-09-02 09:44:35 +09:00
{
struct cb_data * data ;
2012-06-19 13:26:53 +09:00
int len = ( param - > cap = = DMA_CYCLIC ) ? param - > period : param - > len ;
2011-09-02 09:44:35 +09:00
list_for_each_entry ( data , & dma_list , node )
if ( data - > ch = = ch )
break ;
if ( ! data - > fp ) {
s3c2410_dma_set_buffdone_fn ( ch , s3c_dma_cb ) ;
2012-06-19 13:26:53 +09:00
data - > fp = param - > fp ;
data - > fp_param = param - > fp_param ;
2011-09-02 09:44:35 +09:00
}
2012-06-19 13:26:53 +09:00
s3c2410_dma_enqueue ( ch , ( void * ) data , param - > buf , len ) ;
2011-09-02 09:44:35 +09:00
return 0 ;
}
static inline int s3c_dma_trigger ( unsigned ch )
{
return s3c2410_dma_ctrl ( ch , S3C2410_DMAOP_START ) ;
}
static inline int s3c_dma_started ( unsigned ch )
{
return s3c2410_dma_ctrl ( ch , S3C2410_DMAOP_STARTED ) ;
}
static inline int s3c_dma_flush ( unsigned ch )
{
return s3c2410_dma_ctrl ( ch , S3C2410_DMAOP_FLUSH ) ;
}
static inline int s3c_dma_stop ( unsigned ch )
{
return s3c2410_dma_ctrl ( ch , S3C2410_DMAOP_STOP ) ;
}
static struct samsung_dma_ops s3c_dma_ops = {
. request = s3c_dma_request ,
. release = s3c_dma_release ,
2012-06-19 13:26:53 +09:00
. config = s3c_dma_config ,
2011-09-02 09:44:35 +09:00
. prepare = s3c_dma_prepare ,
. trigger = s3c_dma_trigger ,
. started = s3c_dma_started ,
. flush = s3c_dma_flush ,
. stop = s3c_dma_stop ,
} ;
void * s3c_dma_get_ops ( void )
{
return & s3c_dma_ops ;
}
EXPORT_SYMBOL ( s3c_dma_get_ops ) ;