s3c2440 spi驱动DMA模式

#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_t count,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,struct s3c2410_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,"spi out")){
spi_clear_dma(&output_buff,&spi_dma_client);
printk(KERN_ERR "SPI_OUT"":unable to get DMA channel\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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值