⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s3c2440a_camif.c

📁 linux下cmos摄像头驱动模块
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Camera interface on S3C2440A *   * $Revision: 1.0 $ * * april 2008 PHT * *  飞 凌 嵌 入 式 * www.witech.com.cn */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/version.h>#include <linux/wait.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/completion.h>#include <linux/videodev.h>#include <linux/dma-mapping.h>#include <asm/io.h>#include <asm/hardware.h>#include <asm/semaphore.h>#include <asm/uaccess.h>#include <asm/arch/regs-gpio.h>#include <asm/arch/regs-gpioj.h>#include <asm/arch/regs-clock.h>#include <asm/arch/regs-irq.h>#include "s3c2440a_camif.h"#define DEBUG 	0#if DEBUG#define DPRINTK(x...) printk(x)#else#define DPRINTK(x...) /* !!!! */#endif#ifndef __user#define	__user#endif#define	VIDIOCSYCbCr		_IOW('v',200, int)			#define	CAMERA_STOP_QUICKLY#define	SKIP_FIRST_FRAME#define	RGB_YUV_MUTEXstatic struct img_buf_t yuv_buf[4];static struct img_buf_t rgb_buf[4];#define YUV_TUPLE_SIZE (640*480*2)//(1024*768*2) // maximum#define YUV_IMG_BUF_SIZE PAGE_ALIGN(YUV_TUPLE_SIZE + PAGE_SIZE - 1)static unsigned char *camif_yuv_buf = NULL;static dma_addr_t camif_yuv_buf_dma = 0;#define RGB_TUPLE_SIZE (640*480*2) // maximum RGB24#define RGB_IMG_BUF_SIZE PAGE_ALIGN(RGB_TUPLE_SIZE + PAGE_SIZE - 1)static unsigned char *camif_rgb_buf = NULL;static dma_addr_t camif_rgb_buf_dma = 0;static struct s3c2440_camif camif; // v4l devstatic struct s3c2440_camif_cfg_t s3c2440_camif_cfg;static int	v4l_cam_open(struct inode *inode, struct file *file);static void	v4l_cam_release (struct inode *, struct file *);static int	v4l_cam_ioctl(struct inode *, struct file *, unsigned int, unsigned long);static int	v4l_cam_mmap(struct file *v, struct vm_area_struct *vma);static ssize_t	v4l_cam_read(struct file *, char __user *, size_t, loff_t *);static unsigned int	v4l_cam_poll(struct file *, struct poll_table_struct *);static __u16 power_lvl = 0;static __u16 reset_lvl = 1;static struct file_operations  cam_ops =
{
	.open     = v4l_cam_open,	.release    = v4l_cam_release,	.read     = v4l_cam_read,	.ioctl    = v4l_cam_ioctl,	.poll     = v4l_cam_poll,	.mmap     = v4l_cam_mmap,};//power on/offstatic __inline void camera_power(int mode){		if(mode) {	//power on		if(power_lvl)			s3c2410_gpio_setpin(S3C2410_GPG12,1);		else			s3c2410_gpio_setpin(S3C2410_GPG12,0);	} else {		if(power_lvl)			s3c2410_gpio_setpin(S3C2410_GPG12,0);		else			s3c2410_gpio_setpin(S3C2410_GPG12,1);	}}//external resetstatic __inline void camera_reset(int mode){		if(mode) {	//do reset		if(reset_lvl)			__raw_writel(__raw_readl(rCIGCTRL)|(1<<30),rCIGCTRL);		else			__raw_writel(__raw_readl(rCIGCTRL) & ~(1<<30),rCIGCTRL);		} else {		if(reset_lvl)			__raw_writel(__raw_readl(rCIGCTRL) & ~(1<<30),rCIGCTRL);		else			__raw_writel(__raw_readl(rCIGCTRL) | (1<<30),rCIGCTRL);	}	}//software reset#define CAMERA_RESET() 		\	{__raw_writel(__raw_readl(rCIGCTRL) | (1<<31),rCIGCTRL);	\	camera_reset(1);		\	mdelay(50); 			\	__raw_writel(__raw_readl(rCIGCTRL) & ~(1<<31),rCIGCTRL);	\	camera_reset(0);		\	mdelay(50);}/*  *   CAMCLK_DIV =  UPLL / ( CAMCLK * 2)  - 1 ; */static void cam_gpio_init(void){	DPRINTK("%s():\n", __FUNCTION__);	/*		s3c2410_gpio_cfgpin(S3C2440_GPJ0 , 2);	s3c2410_gpio_cfgpin(S3C2440_GPJ1 , 2);	s3c2410_gpio_cfgpin(S3C2440_GPJ2 , 2);	s3c2410_gpio_cfgpin(S3C2440_GPJ3 , 2);	s3c2410_gpio_cfgpin(S3C2440_GPJ4 , 2);	s3c2410_gpio_cfgpin(S3C2440_GPJ5 , 2);	s3c2410_gpio_cfgpin(S3C2440_GPJ6 , 2);	s3c2410_gpio_cfgpin(S3C2440_GPJ7 , 2);	s3c2410_gpio_cfgpin(S3C2440_GPJ8 , 2);	s3c2410_gpio_cfgpin(S3C2440_GPJ9 , 2);	s3c2410_gpio_cfgpin(S3C2440_GPJ10 , 2);	s3c2410_gpio_cfgpin(S3C2440_GPJ11 , 2);	s3c2410_gpio_cfgpin(S3C2440_GPJ12 , 2);*/	__raw_writel(0x2aaaaaa , S3C2440_GPJCON);	__raw_writel(0x0 , S3C2440_GPJDAT);	__raw_writel(0x0 , S3C2440_GPJUP);}static void inline s3c2440_camif_init(void){	DPRINTK("%s():\n", __FUNCTION__);		cam_gpio_init();	// Camera clock enable	__raw_writel(__raw_readl(S3C2410_CLKCON) | S3C2440_CLKCON_CAMERA,S3C2410_CLKCON);	//set CAMDIVN;  CAMCLK_DIV=upll /( camclk * 2) -1;	0:24M, 1:12M, 2:8M, 3:6M, 5:4M, 11:2M	__raw_writel(S3C2440_CAMDIVN_CAMCLK_SEL|(CAM_CLK_DIV & S3C2440_CAMDIVN_CAMCLK_MASK),S3C2440_CAMDIVN);		printk("camera power level %d, reset level %d\n", power_lvl, reset_lvl);		__raw_writel((1<<29),rCIGCTRL);	//bit 29 must be 1	CAMERA_RESET();	}static void s3c2440_camif_deinit(void){	DPRINTK("%s():\n", __FUNCTION__);	// Camera clock disable	__raw_writel(__raw_readl(S3C2410_CLKCON) & ~S3C2440_CLKCON_CAMERA,S3C2410_CLKCON);	__raw_writel(0,rCIIMGCPT);	mdelay(5);}/******************************************************** CalculateBurstSize - Calculate the busrt lengths  Description:	 - dstHSize: the number of the byte of H Size. */void __inline CalculateBurstSize(u32 hSize, u32 *mainBurstSize, u32 *remainedBurstSize){	__u32 tmp = (hSize/4)%16;	switch(tmp) {		case 0:			*mainBurstSize = 16;			*remainedBurstSize = 16;			break;		case 4:			*mainBurstSize = 16;			*remainedBurstSize = 4;			break;		case 8:			*mainBurstSize=16;			*remainedBurstSize = 8;			break;		default: 			tmp=(hSize/4)%8;			switch(tmp) {				case 0:					*mainBurstSize = 8;					*remainedBurstSize = 8;					break;				case 4:					*mainBurstSize = 8;					*remainedBurstSize = 4;				default:					*mainBurstSize = 4;					tmp = (hSize/4)%4;					*remainedBurstSize = (tmp)?tmp:4;					break;			}			break;	}}/******************************************************** CalculatePrescalerRatioShift - none  Description:	 - none */void __inline CalculatePrescalerRatioShift(u32 SrcSize, u32 DstSize, u32 *ratio, u32 *shift){	if(SrcSize>=64*DstSize) {		printk(KERN_ERR "Error: out of the prescaler range: SrcSize/DstSize = %d(< 64)\n",				SrcSize/DstSize);		panic("camera set error!\n");	} else if(SrcSize>=32*DstSize) {		*ratio=32;		*shift=5;	} else if(SrcSize>=16*DstSize) {		*ratio=16;		*shift=4;	} else if(SrcSize>=8*DstSize) {		*ratio=8;		*shift=3;	} else if(SrcSize>=4*DstSize) {		*ratio=4;		*shift=2;	} else if(SrcSize>=2*DstSize) {		*ratio=2;		*shift=1;	} else {		*ratio=1;		*shift=0;	}    	}static void s3c2440_camif_configure(struct s3c2440_camif_cfg_t *cfg){	int i;	unsigned int ysize, csize;	unsigned int burst_y, burst_c, remain_burst_y, remain_burst_c;	unsigned int hsft, vsft, hratio, vratio, mhratio, mvratio;	unsigned int hscale, vscale;		DPRINTK("%s():\n", __FUNCTION__);		cfg->pre_x = cfg->dst_x;	cfg->pre_y = cfg->dst_y;	switch(cfg->dev->mode) {	case 0:		cfg->dev->size = cfg->dst_x*cfg->dst_y*2;		cfg->pre_fmt = 0;	//RGB16		break;	case 1:		cfg->dev->size = cfg->dst_x*cfg->dst_y*3;		cfg->pre_fmt = 1;	//RGB24		break;	case 2:		cfg->dev->size = (cfg->dst_x*cfg->dst_y*3)/2;		cfg->dst_fmt = 0;	//YCbCr4:2:0		break;	case 3:		cfg->dev->size = cfg->dst_x*cfg->dst_y*2;		cfg->dst_fmt = 1;	//YCbCr4:2:2		break;	}	DPRINTK("CAMIF: src = (%dx%d), co dst = (%dx%d), pre dst = (%dx%d)\n",			cfg->src_x, cfg->src_y,			cfg->dst_x, cfg->dst_y,			cfg->pre_x, cfg->pre_y);	////////////////// common control setting	// ITU601,UVOffset=0,YCbYCr	__raw_writel((1<<31)|(0<<30)|(0<<29)|(cfg->src_x<<16)|(cfg->ycbcr<<14)|(cfg->src_y),rCISRCFMT);	// clear overflow, disable window offset	__raw_writel((1<<30)|(0xf<<12),rCIWDOFST);	__raw_writel(0,rCIWDOFST);	// clear test pattern,  normal PCLK, VSYNC, HREF	__raw_writel(__raw_readl(rCIGCTRL) & ~((3<<27)|(7<<24)),rCIGCTRL);	ysize = cfg->dst_x * cfg->dst_y;	if(cfg->dst_fmt)	//YCbCr4:2:2		csize =  ysize / 2;	else				//YCbCr4:2:0		csize =  ysize / 4;	for (i = 0; i < 4; i++) {		yuv_buf[i].buf = camif_yuv_buf;		yuv_buf[i].phys_addr = (unsigned int)camif_yuv_buf_dma;		rgb_buf[i].buf = camif_rgb_buf;		rgb_buf[i].phys_addr = (unsigned int)camif_rgb_buf_dma;				DPRINTK("yuv_buf[%d] : virt=0x%08lx, phys = 0x%08lx\n",				i, (unsigned long)yuv_buf[i].buf, (unsigned long)yuv_buf[i].phys_addr);		DPRINTK("rgb_buf[%d] : virt=0x%08lx, phys = 0x%08lx\n",				i, (unsigned long)rgb_buf[i].buf, (unsigned long)rgb_buf[i].phys_addr);		__raw_writel(yuv_buf[i].phys_addr,CICOSTAY(i));		__raw_writel(yuv_buf[i].phys_addr + ysize,CICOSTACb(i));		__raw_writel(yuv_buf[i].phys_addr + ysize + csize,CICOSTACr(i));		__raw_writel(rgb_buf[i].phys_addr,CIPRSTARGB(i));		DPRINTK("STAY%d  = 0x%08x\n", i, yuv_buf[i].phys_addr);		DPRINTK("STACB%d = 0x%08x\n", i, yuv_buf[i].phys_addr + ysize);		DPRINTK("STACR%d = 0x%08x\n", i, yuv_buf[i].phys_addr + ysize + csize);	}	////////////////// codec port setting	// YCbCr4:2:2 input, YCbCr4:2:2/YCbCr4:2:0 output, normal	__raw_writel((1<<31)|((cfg->dst_fmt?1:0)<<30)|(cfg->dst_x<<16)|(0<<14)|(cfg->dst_y),rCICOTRGFMT);	CalculateBurstSize(cfg->dst_x, &burst_y, &remain_burst_y);	CalculateBurstSize(cfg->dst_x/2, &burst_c, &remain_burst_c);	__raw_writel((burst_y<<19)|(remain_burst_y<<14)|(burst_c<<9)|(remain_burst_c<<4),rCICOCTRL);	CalculatePrescalerRatioShift(cfg->src_x, cfg->dst_x, &hratio, &hsft);	CalculatePrescalerRatioShift(cfg->src_y, cfg->dst_y, &vratio, &vsft);	mhratio = (cfg->src_x<<8)/(cfg->dst_x<<hsft);	mvratio = (cfg->src_y<<8)/(cfg->dst_y<<vsft);	__raw_writel(((10-hsft-vsft)<<28)|(hratio<<16)|(vratio),rCICOSCPRERATIO);	__raw_writel(((cfg->src_x/hratio)<<16)|(cfg->src_y/vratio),rCICOSCPREDST);	if(cfg->dev->mode==2||cfg->dev->mode==3)		cfg->bypass = (cfg->src_x==cfg->dst_x&&cfg->src_y==cfg->dst_y)?1:0;	hscale = (cfg->src_x>cfg->dst_x)?0:1;	vscale = (cfg->src_y>cfg->dst_y)?0:1;	__raw_writel((0<<31)|(hscale<<30)|(vscale<<29)|(mhratio<<16)|(mvratio),rCICOSCCTRL);	__raw_writel(cfg->dst_x*cfg->dst_y,rCICOTAREA);	///////////////// preview port setting	__raw_writel((cfg->pre_x<<16)|(0<<14)|(cfg->pre_y),rCIPRTRGFMT);	if (cfg->pre_fmt)	//RGB24B		CalculateBurstSize(cfg->pre_x*4, &burst_y, &remain_burst_y);	else 				// RGB16B		CalculateBurstSize(cfg->pre_x*2, &burst_y, &remain_burst_y);	__raw_writel((burst_y<<19)|(remain_burst_y<<14),rCIPRCTRL);		CalculatePrescalerRatioShift(cfg->src_x, cfg->pre_x, &hratio, &hsft);	CalculatePrescalerRatioShift(cfg->src_y, cfg->pre_y, &vratio, &vsft);	mhratio = (cfg->src_x<<8)/(cfg->pre_x<<hsft);	mvratio = (cfg->src_y<<8)/(cfg->pre_y<<vsft);	__raw_writel(((10-hsft-vsft)<<28)|(hratio<<16)|(vratio),rCIPRSCPRERATIO);	__raw_writel(((cfg->src_x/hratio)<<16)|(cfg->src_y/vratio),rCIPRSCPREDST);	hscale = (cfg->src_x>cfg->pre_x)?0:1;	vscale = (cfg->src_y>cfg->pre_y)?0:1;	__raw_writel((1<<31)|((cfg->pre_fmt?1:0)<<30)|(hscale<<29)|(vscale<<28)|(mhratio<<16)|(mvratio),rCIPRSCCTRL);	__raw_writel(cfg->pre_x*cfg->pre_y,rCIPRTAREA);		}static __inline void start_capture(struct s3c2440_camif *dev){	switch(dev->mode) {	case 0:	case 1:		__raw_writel(__raw_readl(rCIPRSCCTRL) | (1<<15),rCIPRSCCTRL);		__raw_writel(__raw_readl(rCIIMGCPT) | (5<<29),rCIIMGCPT);		break;	case 2:	case 3:		__raw_writel(__raw_readl(rCICOSCCTRL) | (1<<15)|(s3c2440_camif_cfg.bypass?(1<<31):0),rCICOSCCTRL);		__raw_writel(__raw_readl(rCIIMGCPT) | (6<<29),rCIIMGCPT);		break;	}}static __inline void stop_capture(struct s3c2440_camif *dev){	switch(dev->mode) {	case 0:	case 1:		__raw_writel(__raw_readl(rCIPRSCCTRL) & ~(1<<15),rCIPRSCCTRL);		__raw_writel(__raw_readl(rCIIMGCPT) & ~(7<<29),rCIIMGCPT);#ifndef CAMERA_STOP_QUICKLY		__raw_writel(__raw_readl(rCIPRCTRL) | (1<<2),rCIPRCTRL);		//NOTE:LastIrqEn bit should be set after clearing CAPTURE_ENABLE_BIT & SCALER_START_BIT		dev->flag |= 0x200;#endif		break;	case 2:	case 3:		__raw_writel(__raw_readl(rCICOSCCTRL) & ~(1<<15),rCICOSCCTRL);		__raw_writel(__raw_readl(rCIIMGCPT) & ~(7<<29),rCIIMGCPT);#ifndef CAMERA_STOP_QUICKLY		__raw_writel(__raw_readl(rCICOCTRL) | (1<<2),rCICOCTRL);		//NOTE:LastIrqEn bit should be set after clearing CAPTURE_ENABLE_BIT & SCALER_START_BIT		dev->flag |= 0x200;#endif		break;	}}// run in irq disabled statestatic irqreturn_t s3c2440_camif_isr_c(int irq, void *dev_id, struct pt_regs *regs){	struct s3c2440_camif *dev = (struct s3c2440_camif*)dev_id;		DPRINTK("%s():\n", __FUNCTION__);		if(__raw_readl(S3C2410_SUBSRCPND) & (0x1<<11))
	{		__raw_writel(__raw_readl(S3C2410_SUBSRCPND) | (1<<11),S3C2410_SUBSRCPND);		__raw_writel(__raw_readl(S3C2410_SRCPND) | (1<<6),S3C2410_SRCPND);		__raw_writel(__raw_readl(S3C2410_INTPND) | (1<<6),S3C2410_INTPND);
	}
	else 	if(__raw_readl(S3C2410_SUBSRCPND) & (0x1<<12))
	{		__raw_writel(__raw_readl(S3C2410_SUBSRCPND) | (2<<11),S3C2410_SUBSRCPND);		__raw_writel(__raw_readl(S3C2410_SRCPND) | (1<<6),S3C2410_SRCPND);		__raw_writel(__raw_readl(S3C2410_INTPND) | (1<<6),S3C2410_INTPND);
	}			//GPFDAT ^= 1<<4;	//LED0	if(dev->flag&1) {		if(dev->flag&0x200) {			dev->flag = 0;			complete(&dev->stop);		} else if(dev->flag&0x100) {			stop_capture(dev);#ifdef CAMERA_STOP_QUICKLY			dev->flag = 0;			complete(&dev->stop);#endif		} else#ifdef SKIP_FIRST_FRAME		if(dev->flag&4)#endif		{			if(!(dev->flag&2)) {				stop_capture(dev);#ifdef CAMERA_STOP_QUICKLY				dev->flag = 0;#endif			}			dev->rdy = 1;			wake_up_interruptible(&dev->wait);		}		dev->flag |= 4;	} else {		printk(KERN_ERR "flag is 0x%08x\n", dev->flag);		dev->flag = 1;	//error state, must not happen		stop_capture(dev);		printk(KERN_ERR "%s.%d: camera BUG!\n", __FILE__, __LINE__);	}	return IRQ_HANDLED;}#define	s3c2440_camif_isr_p	s3c2440_camif_isr_cstatic int v4l_cam_open(struct inode *inode, struct file *file){	unsigned long flags;	struct s3c2440_camif *dev =&camif;	//dev = container_of(camif.dev,struct s3c2440_camif, video_device);	file->private_data = dev;	DPRINTK("%s():\n", __FUNCTION__);	spin_lock_irqsave(&dev->lock, flags);	if(dev->open_count) {		spin_unlock_irqrestore(&dev->lock, flags);		return -EBUSY;	}	dev->open_count++;	spin_unlock_irqrestore(&dev->lock, flags);	DPRINTK("open(): dev->opencount = %d\n", dev->open_count);		camera_power(1);	//s3c2440_camif_init();		dev->set_chg = 1;	dev->mode = 0;	//RGB image	dev->flag = 0;	//not run, not ready	s3c2440_camif_cfg.dev   = dev;	s3c2440_camif_cfg.src_x = 640;	s3c2440_camif_cfg.src_y = 480;	s3c2440_camif_cfg.dst_x = 240;	s3c2440_camif_cfg.dst_y = 180;	s3c2440_camif_cfg.pre_x = 240;	s3c2440_camif_cfg.pre_y = 180;	s3c2440_camif_cfg.dst_fmt = 1;	s3c2440_camif_cfg.pre_fmt = 0;	s3c2440_camif_cfg.ycbcr   = 0;	//YCbCr

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -