博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
s3c2440 spi驱动DMA模式
阅读量:4052 次
发布时间:2019-05-25

本文共 7204 字,大约阅读时间需要 24 分钟。

#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");

转载地址:http://wipci.baihongyu.com/

你可能感兴趣的文章
MySQL数据库的高可用方案总结
查看>>
常用排序算法总结(一) 比较算法总结
查看>>
SSH原理与运用
查看>>
SIGN UP BEC2
查看>>
S3C2440中对LED驱动电路的理解
查看>>
《天亮了》韩红
查看>>
Windows CE下USB摄像头驱动开发(以OV511为例,附带全部源代码以及讲解) [转]
查看>>
出现( linker command failed with exit code 1)错误总结
查看>>
iOS开发中一些常见的并行处理
查看>>
iOS获取手机的Mac地址
查看>>
ios7.1发布企业证书测试包的问题
查看>>
如何自定义iOS中的控件
查看>>
iOS 开发百问
查看>>
Mac环境下svn的使用
查看>>
github简单使用教程
查看>>
如何高效利用GitHub
查看>>
新手看过来:VC对话框控件属性的修改
查看>>
实现MAVROS与px4的自定义通讯功能(一)
查看>>
BUUCTF笔记之Web系列部分WriteUp(四)
查看>>
使用fastcoll生成字符串MD5碰撞
查看>>