s3c2440 spi驱动DMA模式

来源:互联网 发布:淘宝中老年女秋装 编辑:程序博客网 时间:2024/05/24 05:38
#include <linux/irq.h>
#include<linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include<linux/interrupt.h>
#include<mach/regs-gpio.h>
#include <mach/hardware.h>
#include <mach/dma.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include<linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/gpio.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include<linux/semaphore.h>
#include <asm/uaccess.h>
#include<linux/dma-mapping.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#include<linux/spinlock.h>
#include <linux/clk.h>
#include <asm/system.h>
#include <asm/signal.h>
#include <asm/io.h>
#include <asm/dma.h>
#define DEVICE_NAME "tq2440_spi"
#define DBG(msg...) do{ \
if(debug)\
printk(KERN_INFO msg);\
}while(0)
static int debug=1;
static int spi_major=0;
module_param(spi_major,int,S_IRUGO);
static struct class *spi_class;
static struct semaphore sem;                                           
struct cdev spiCdev;
static int spi_open(struct inode *,struct file *);
static int spi_release(struct inode *,struct file *);
static ssize_t spi_write(struct file *filp,const char*buf,size_t count,loff_t *f_ops);
static ssize_t spi_read(struct file *filp,char *buf,size_tcount,loff_t *f_ops);
static ssize_t spi_ioctl(struct inode *inode,struct file*filp,unsigned int cmd,unsigned long data);
static void config_write(void);
static void config_read(void);

typedef struct {
int size;
char *start;
dma_addr_t dma_addr;
struct semaphore sem;
}spi_buff_t;

static spi_buff_t output_buff;
static spi_buff_t input_buff;
volatile unsigned long *s3c2440_clkcon;
volatile unsigned long *spi_spcon1;//SPI Part define
volatile unsigned long *spi_spsta1;
volatile unsigned long *spi_sppin1;
volatile unsigned long *spi_sppre1;
volatile unsigned long *spi_sptdat1;
volatile unsigned long *spi_sprdat1;
static struct s3c2410_dma_client spi_dma_client={
.name="SPI",
};
static const struct file_operations spi_fops= 
{
.owner=THIS_MODULE,
.open=spi_open,
.read=spi_read,
.ioctl=spi_ioctl,
.release=spi_release,
.write=spi_write,
};

static void spi_clear_buf(spi_buff_t *s)
{
DBG("spi_clear_buf\n");
s3c2410_dma_ctrl(DMACH_SPI1,S3C2410_DMAOP_FLUSH);
dma_free_coherent(NULL,s->size,s->start,s->dma_addr);
}
static int spi_open(struct inode *inode,struct file*filp)
{
DBG("spi_open\n");
if(down_interruptible(&sem))
return -ERESTARTSYS;
filp->private_data=&spiCdev;
return 0;
}
static int spi_release(struct inode *inode,struct file*filp)
{
up(&sem);
DBG("release\n");
return 0;
}
static int spi_setup_buf(spi_buff_t *s)
{
char *dmabuf=0;
dma_addr_t dmaphys=0;
int dmasize=s->size;
DBG("spi_setup_buf\n");
dmabuf=dma_alloc_coherent(NULL,dmasize,&dmaphys,GFP_KERNEL|GFP_DMA);
if(!dmabuf)
goto err;
s->start=dmabuf;
s->dma_addr=dmaphys;
init_MUTEX(&s->sem);
DBG("buf start %p dma%d\n",s->start,s->dma_addr);
return 0;
err:
printk(KERN_ERR "unable to allocate spi menmory\n");
return -ENOMEM;
}
static ssize_t spi_read(struct file *filp,char __user*buf,size_t count,loff_t *f_ops)
{
spi_buff_t *s=&input_buff;
DBG("spi read!\n");
config_read();
s->size=count;
if(spi_setup_buf(s))
return -ENOMEM;
down(&s->sem);
s3c2410_dma_enqueue(DMACH_SPI1,(void*)s,s->dma_addr,s->size);
if(copy_to_user(buf,s->start,s->size)){
printk("copy_to_user error\n");
up(&s->sem);
}
return s->size;
}

static ssize_t spi_write(struct file *filp,const char __user*buf,size_t count,loff_t *f_ops)
{
int ret=0;
spi_buff_t *s=&output_buff;
DBG("spi_write:start count=%d\n",count);
config_write();
s->size=count;
if(spi_setup_buf(s)){
printk("err no mem\n");
return -ENOMEM;
}
if(down_interruptible(&s->sem)){
printk("down interruptible error\n");
}
if(copy_from_user(s->start,buf,count)){
printk("copy_from_user error\n");
up(&s->sem);
return -EFAULT;
}
if((ret=s3c2410_dma_enqueue(DMACH_SPI1,(void*)s,s->dma_addr,s->size))){
printk("dma enqueue failed.\n");
return ret;
}
return count;
}

static ssize_t spi_ioctl(struct inode *inode,struct file*filp,unsigned int cmd,unsigned long data)
{
return 0;
}
static void spi_dmain_done_callback(struct s3c2410_dma_chan*ch,void *buf,int size,
enum s3c2410_dma_buffresult result)
{
spi_buff_t *b=(spi_buff_t *)buf;
DBG("spi_dmain_done_callback\n");
b->size=size;
up(&b->sem);
}
static void spi_dmaout_done_callback(struct s3c2410_dma_chan*ch,void *buf,int size,
enum s3c2410_dma_buffresult result)
{
spi_buff_t *b=(spi_buff_t *)buf;
DBG("spi_dmaout_done_callback\n");
up(&b->sem);
}
static void config_write(void)
{
enum s3c2410_dmasrc source;
int hwcfg;
unsigned long devaddr;
int dcon;
unsigned int flags=0;
DBG("spi config_dma\n");
source=S3C2410_DMASRC_MEM;
hwcfg=3;
devaddr=0x59000030;
dcon=0X2a800000;
flags=S3C2410_DMAF_AUTOSTART;
s3c2410_dma_devconfig(DMACH_SPI1, source, hwcfg,devaddr); 
s3c2410_dma_config(DMACH_SPI1, 1,dcon); 
s3c2410_dma_set_buffdone_fn(DMACH_SPI1,spi_dmaout_done_callback); 
s3c2410_dma_setflags(DMACH_SPI1,flags); 
}
static void config_read(void)
{
enum s3c2410_dmasrc source;
int hwcfg;
unsigned long devaddr;
int dcon;
unsigned int flags=0;
DBG("spi config_read\n");
source=S3C2410_DMASRC_HW;
hwcfg=3;
devaddr=0x59000034;
dcon=0X2a800000;
flags=S3C2410_DMAF_AUTOSTART;
s3c2410_dma_devconfig(DMACH_SPI1, source, hwcfg,devaddr); 
s3c2410_dma_config(DMACH_SPI1, 1,dcon); 
s3c2410_dma_set_buffdone_fn(DMACH_SPI1,spi_dmain_done_callback); 
s3c2410_dma_setflags(DMACH_SPI1,flags); 
}
static int spi_init_dma(spi_buff_t *s,char *desc)
{
int ret;
DBG("spi init dma\n");
ret=!s3c2410_dma_request(DMACH_SPI1,&spi_dma_client,NULL);
if(ret){
spi_clear_buf(s);
printk(KERN_ERR "failed to get dma channel\n");
}
return ret;
}
static int spi_clear_dma(spi_buff_t *s,structs3c2410_dma_client *client)
{
DBG("spi_clear_dma\n");
s3c2410_dma_set_buffdone_fn(DMACH_SPI1,NULL);
s3c2410_dma_free(DMACH_SPI1,client);
return 0;
}
static void config_spi(void)
{
s3c2410_gpio_cfgpin(S3C2410_GPG5,S3C2410_GPG5_SPIMISO1);
s3c2410_gpio_cfgpin(S3C2410_GPG6,S3C2410_GPG6_SPIMOSI1);
s3c2410_gpio_cfgpin(S3C2410_GPG7,S3C2410_GPG7_SPICLK1);
s3c2410_gpio_cfgpin(S3C2410_GPG3,S3C2410_GPG3_nSS1);
s3c2410_gpio_pullup(S3C2410_GPG5,1);
s3c2410_gpio_pullup(S3C2410_GPG6,1);
s3c2410_gpio_pullup(S3C2410_GPG7,1);
/
*s3c2440_clkcon |=0x40000;
ioremap_spi();
config_spi();
if(spi_init_dma(&output_buff,"spiout")){
spi_clear_dma(&output_buff,&spi_dma_client);
printk(KERN_ERR "SPI_OUT"":unable to get DMAchannel\n");
return -EBUSY;
}
spi_class=class_create(THIS_MODULE,DEVICE_NAME);
if(IS_ERR(spi_class))
{
printk("Err:failed in spi class.\n");
return -1;
}
device_create(spi_class,NULL,devno,NULL,DEVICE_NAME);
printk("Init spi success!\n");  
return result;
}


static void __exit spi_exit(void)
{
cdev_del(&spiCdev);
unregister_chrdev_region(MKDEV(spi_major, 0), 1);
device_destroy(spi_class ,MKDEV(spi_major,0));
class_destroy(spi_class);
spi_clear_dma(&output_buff,&spi_dma_client);
iounmap_spi();
printk("spi_exit!\n");
}

module_init(spi_init);
module_exit(spi_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("syw");
MODULE_DESCRIPTION("SPI driver for S3C2440");

0 1
原创粉丝点击