📄 s3c2410_fpga0301.c
字号:
/** Filename: s3c2410_fpga.c* Function: driver for FPGA on the s3c2410 board**/#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h> /* printk() */#include <linux/init.h>#include <linux/ioport.h>#include <linux/miscdevice.h>#include <linux/sched.h>#include <linux/delay.h> /* udelay */#include <linux/poll.h>#include <linux/spinlock.h>#include <linux/irq.h>#include <asm/hardware.h>#include <asm/io.h> /* for outb(), inl(),etc. */#include <asm/irq.h> /* for IRQ_EINT1 */#include <asm/signal.h>#include <asm/arch/S3C2410.h>//#include "s3c2410_fpga-01.h"/* There are something differences between kernel-2.6 and kernel-2.4(MIZI provided). * For kernel 2.6, there are no need to do these macro definitions. *//* Just for kernel-2.4(MIZI) */#define S3C2410_SRCPND SRCPND#define S3C2410_INTMSK INTMSK#define S3C2410_INTMOD INTMOD#define S3C2410_EXTINT0 EXTINT0/*#ifdef __FPGA_ADDR_V#define FPGA_ADDR_V io_p2v(0x10000000)#else#define FPGA_ADDR_P (0x10000000) //request_men_region() use physical memery address#endif*/#define FPGA_ADDR (0x10000000)#define DEVICE_NAME "fpga"static volatile unsigned char *FPGA_BASE;static int fpga_major = 0;#define MEN_SZ (0x100)unsigned char *kbuffer = 0;unsigned int length = 0;static int ready = 0; #define FPGA_CONFIG (0X00)#define FPGA_DATA (0X01)static int status = FPGA_DATA; /* 0=FPGA_CONFIG; 1=FPGA_DATA */ #define FPGA_DEBUG#undef Jdebug#ifdef FPGA_DEBUG# ifdef __KERNEL__# define Jdebug(fmt,args...) printk(KERN_EMERG fmt,## args)# else # define Jdebug(fmt, args...) fprintf(stderr, fmt, ## args)# endif#else# define Jdebug(fmt, args...) /* not debugging: nothing */#endif //////////////////////////////////////////////////////////////////////////////////////////// This is equal to using init_waitqueue_head(&fpga_wait)static DECLARE_WAIT_QUEUE_HEAD(fpga_wait); //ȴᅣ17//* FPGA �жϷ���/static void fpga_irq(int irq, void *dev_id, struct pt_regs *regs){ int i; Jdebug("fpga_irq:entering irq processing.\n"); if (irq != IRQ_EINT1) { printk("bad irq %d in fpga \n",irq); return; } S3C2410_SRCPND = (0x1 << 1); if (ready) return 1; memset(kbuffer, 0, MEM_SZ); length = readb(FPGA_BASE)+ readb(FPGA_BASE+1)<<8; for (i=0; i<length; i++) { *(kbuffer+i) = readb(FPGA_BASE+i); udelay(5); } ready = 1; wake_up_interruptible(&fpga_wait); //���}ᅣ17}static int fpga_read(struct file *file, char *buffer, size_t count, loff_t *ppos){ int ret; if (status != FPGA_DATA) { printk("FPGA's status is CONFIG,no data to read!\n"); return 0; } if(!ready) //not ready yet ? return 0; if (length == 0) return 0; if (count == -1) { count = length; ret = copy_to_user(buffer, kbuffer,count); } else ret = copy_to_user(buffer, kbuffer,count); if (ret) return -EINVAL; ready = 0; return count;}static int fpga_ioctl(struct inode *inode, struct file *file, unsigned int cmd,unsigned long arg){ int i; switch(cmd) { case FPGA_CONFIG: /* ARM FPGA | GPBCON GPB10 -----> nCONFIG |[21,20]01:Output GPB9 <----- nSTATUS |[19,18]00:input GPB8 <----- CONF_DONE |[17,16]00:input */ Jdebug("doing fpga config...\n"); status = FPGA_CONFIG; GPBCON &= 0X10 << 16; /*01,0000*/ Jdebug("GPBCON = 0X%0X!\n",GPBCON); /* GPBUP = 0; */ GPBDAT &= 0X0 << 10; /* draw low */ for (i=0;i<1000;i++); /* wait more than 40us,100MIPS,1000enought */ GPBDAT &= 0X1 << 10; /* pull up */ Jdebug("GPBDAT is OK!\n"); while ( !(GPBDAT&(0x1<<9)) ); /* wait GPB9(nSTATUS) high */ printk("FPGA is ready to write data!\n"); break; case FPGA_DATA: status = FPGA_DATA ; default: printk("two options: FPGA_DATA(1) or FPGA_CONFIG(0)\n"); break; } return 0;}static int fpga_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){ int i, len; len = 1; /* len = (buffer[1]<<8)+buffer[0]; printk("writing len is %d\n",len); if (len != count) return -EINVAL; */ //printk("writing %c\n", buffer[0]); memset(kbuffer, 0, 256); copy_from_user(kbuffer, buffer, len); printk("entering while...\n"); while(1) { //writeb(0x33, FPGA_BASE); *FPGA_BASE = 0X33; printk("write 0x33 to fpga\n"); for (i=0; i<10000; i++); //delay(1); //*FPGA_BASE = 0X34; // writeb(0x34, FPGA_BASE); // printk("write 0x34 to fpga\n"); // delay(1); // for (i=0; i<10000; i++); //writeb(0x34, FPGA_BASE); } //printk("write finished.\n"); return count;}static int fpga_release(struct inode *inode, struct file *file){ kfree(kbuffer); Jdebug("fpga: release() done!\n"); return 0;}static int fpga_open(struct inode *inode, struct file *file){ int i; BWSCON &= ~(0x03 << 8); BWSCON |= (0X00 << 8); // set bank2 to 8bit GPHCON &= ~(0xF << 18); GPHCON |= (0xA << 18); // set gpio to the clkout mode MISCCR &= ~(0x7 << 8 ); MISCCR |= (0x4 << 8); // set clkout1 to pclk MISCCR &= ~(0x7 << 4 ); MISCCR |= (0x3 << 4); // set clkout0 to hclk printk("BWSCON = 0x%0x\n",BWSCON ); printk("MISCCR = 0x%0x\n",MISCCR ); printk("GPHCON = 0x%0x\n",GPHCON); kbuffer = (unsigned char *)kmalloc(256, GFP_KERNEL); if(!kbuffer) { printk("failed assigned small mem for buffer1 ! \n"); return -ENOMEM; } Jdebug("fpga: open() done!\n"); return 0;}static int fpga_mmap(struct file *filp, struct vm_area_struct *vma){ unsigned long off = vma->vm_pgoff << PAGE_SHIFT; unsigned long physical = FPGA_ADDR + off; unsigned long vsize = vma->vm_end - vma->vm_start; unsigned long psize = MEM_SZ - off; if (vsize > psize) return -EINVAL; // spans too high vma->vm_flags |= VM_IO | VM_RESERVED; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); remap_page_range(vma, vma->vm_start, physical, vsize, vma->vm_page_prot); return 0;}/*�ϵͳӿڶ�*/static struct file_operations fpga_fops = {owner: THIS_MODULE,open: fpga_open,read: fpga_read,ioctl: fpga_ioctl,write: fpga_write,release: fpga_release,mmap: fpga_mmap,};#ifdef CONFIG_DEVFS_FSstatic devfs_handle_t devfs_handle;#endif/* FPGA ��*/static int __init fpga_init(void){ int ret; ready = 0; /*ע�豸*/ ret = register_chrdev(fpga_major, DEVICE_NAME, &fpga_fops ); if(ret<0) { printk(DEVICE_NAME "can't register fpga major number \n" ); return ret; } if (fpga_major == 0) fpga_major = ret;// use not only int1, but also 2,4,5,6, should be set! Jdebug("original INTMSK= 0x%x\n", S3C2410_INTMSK); S3C2410_INTMSK &= ~(0x1 << 1); /* open INT1 interrupt, othets not change*/ Jdebug("new INTMSK = 0x%x\n",S3C2410_INTMSK);/* temp = inl(S3C2410_INTMOD); printk("original value of INTMOD is 0x%x", temp); temp |= 0x1 << 1; outl(temp,S3C2410_INTMOD); //INT1 using FIQ(fast interrupt) printk("Value changed of INTMOD using outl() is 0x%x", temp);*/ // __raw_writel((__raw_readl(S3C2410_INTMSK)&~(0x1<<1)), S3C2410_INTMSK); // set 0 to INT1 of INTMSK// __raw_writel((__raw_readl(S3C2410_INTMOD)| (0x1<<1), S3C2410_INTMOD); // set 1 to INT1 of INTMOD init_waitqueue_head(&fpga_wait); if( request_irq(IRQ_EINT1, &fpga_irq, 0/*SA_INTERRUPT*/, DEVICE_NAME, NULL)) { unregister_chrdev( fpga_major, DEVICE_NAME ); printk( DEVICE_NAME "can't request irq \n" ); return (-1); } Jdebug( DEVICE_NAME" assigned IRQ %d\n", IRQ_EINT1);#ifdef CONFIG_DEVFS_FS devfs_handle = devfs_register(NULL, DEVICE_NAME, DEVFS_FL_DEFAULT, fpga_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, &fpga_fops, NULL );#endif FPGA_BASE = ioremap(FPGA_ADDR,0X100); if (!FPGA_BASE) { prink("ioremap fpga base address failed!\n"); return -EINVAL; } if (check_mem_region(FPGA_BASE, 0x100)) { printk("fpga: memory already in use.\n"); return -EBUSY; } request_mem_region(FPGA_BASE,0X100,DEVICE_NAME); printk("CLKDIVN = 0X%0x\n",CLKDIVN); CLKDIVN = 3;// CLKDIVN = 1; printk("CLKDIVN = 0X%0x\n",CLKDIVN); Jdebug("fpga: init() done!\n"); return 0;}static void __exit fpga_exit(void){ release_mem_region(FPGA_BASE,0X100); iounmap(FPGA_BASE); #ifdef CONFIG_DEVFS_FS devfs_unregister(devfs_handle);#endif free_irq( IRQ_EINT1, fpga_irq); unregister_chrdev(fpga_major, DEVICE_NAME); Jdebug("fpga: exit() done!\n");}module_init(fpga_init);module_exit(fpga_exit);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -