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

📄 s3c2440a_camif.c

📁 2440mmc-and-camera-linux-driver 2440mmc-and-camera-linux-driver
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Camera interface on S3C2440A * * 8-12-2005 : * ported by antiscle <hzh12@tom.com>, IIC initialize is done in user program */#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/irq.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/locks.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/completion.h>#include <linux/videodev.h>#include <asm/io.h>#include <asm/hardware.h>#include <asm/semaphore.h>#include <asm/uaccess.h>#include <asm/arch/cpu_s3c2440.h>#include "s3c2440a_camif.h"#if DEBUG#define DPRINTK(x...) printk(x)#else#define DPRINTK(x...) /* !!!! */#endif#ifndef __user#define	__user#endif#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 (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 (800*600*3) // 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 video_device *v, int mode);static void v4l_cam_close(struct video_device *v);static int v4l_cam_ioctl(struct video_device *v, unsigned int cmd, void *arg);static int v4l_cam_mmap(struct video_device *v, const char *adr, unsigned long size);static long v4l_cam_read(struct video_device *v, char *buf, unsigned long count, int noblock);//static long v4l_cam_write(struct video_device *v, const char *buf, unsigned long count, int noblock);static unsigned int v4l_cam_poll(struct video_device *v, struct file *file, poll_table *table);static int v4l_cam_initdone (struct video_device *v);static __u16 power_lvl = 0;static __u16 reset_lvl = 1;//power on/offstatic __inline void camera_power(int mode){	if(mode) {	//power on		if(power_lvl)			GPGDAT |= 1<<12;		else			GPGDAT &= ~(1<<12);	} else {		if(power_lvl)			GPGDAT &= ~(1<<12);		else			GPGDAT |= 1<<12;	}}//external resetstatic __inline void camera_reset(int mode){	if(mode) {	//do reset		if(reset_lvl)			rCIGCTRL |= 1<<30;		//GPJDAT |= 1<<12;		else			rCIGCTRL &= ~(1<<30);	//GPJDAT &= ~(1<<12);	} else {		if(reset_lvl)			rCIGCTRL &= ~(1<<30);	//GPJDAT &= ~(1<<12);		else			rCIGCTRL |= 1<<30;		//GPJDAT |= 1<<12;	}}//software reset#define CAMERA_RESET() 		\	{rCIGCTRL |= (1<<31);	\	camera_reset(1);		\	mdelay(50); 			\	rCIGCTRL &=  ~(1<<31);	\	camera_reset(0);		\	mdelay(50);}/*  *   CAMCLK_DIV =  UPLL / ( CAMCLK * 2)  - 1 ; */static __inline unsigned int get_camera_clk(void){        return 24000000;}static void cam_gpio_init(void){	set_gpio_ctrl(GPIO_CAMDATA0);	set_gpio_ctrl(GPIO_CAMDATA1);	set_gpio_ctrl(GPIO_CAMDATA2);	set_gpio_ctrl(GPIO_CAMDATA3);	set_gpio_ctrl(GPIO_CAMDATA4);	set_gpio_ctrl(GPIO_CAMDATA5);	set_gpio_ctrl(GPIO_CAMDATA6);	set_gpio_ctrl(GPIO_CAMDATA7);	set_gpio_ctrl(GPIO_CAMPCLKIN);	set_gpio_ctrl(GPIO_CAMVSYNC);	set_gpio_ctrl(GPIO_CAMHREF);	set_gpio_ctrl(GPIO_CAMPCLKOUT);	set_gpio_ctrl(GPIO_CAMRESET);	//set_gpio_ctrl(GPIO_J12|GPIO_MODE_OUT|GPIO_PULLUP_DIS);	//reset	set_gpio_ctrl(GPIO_G12|GPIO_MODE_OUT|GPIO_PULLUP_DIS);	//power pin}static void inline s3c2440_camif_init(void){	unsigned int upll, uclk, camclk,camclk_div;	cam_gpio_init();	camclk = get_camera_clk();	CLKCON |= CLKCON_CAMIF;	/* Supposed that you must set UPLL at first */	//UPLLCON = FInsrt(0x38, fPLL_MDIV) | FInsrt(0x02, fPLL_PDIV)	//don't set UPLL here	//	| FInsrt(0x02, fPLL_SDIV);	upll = s3c2440_get_bus_clk(GET_UPLL);	uclk = (CLKDIVN & DIVN_UPLL_EN) ? upll/2 : upll;	printk("CAMERA : UPLL %08d  UCLK %08d CAMCLK %08d \n",upll, uclk, camclk);	camclk_div = upll /( camclk * 2) -1 ;	CAMDIVN = CAMCLK_SET_DIV | (camclk_div & 0xf );		printk("camera power level %d, reset level %d\n", power_lvl, reset_lvl);	rCIGCTRL = 1<<29;	//bit 29 must be 1	CAMERA_RESET();}static void s3c2440_camif_deinit(void){	CLKCON &= ~CLKCON_CAMIF;	rCIIMGCPT = 0;	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;		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	rCISRCFMT = (1<<31)|(0<<30)|(0<<29)|(cfg->src_x<<16)|(cfg->ycbcr<<14)|(cfg->src_y);	// clear overflow, disable window offset	rCIWDOFST = (1<<30)|(0xf<<12); 	rCIWDOFST = 0;	// clear test pattern,  normal PCLK, VSYNC, HREF	rCIGCTRL &= ~((3<<27)|(7<<24));	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);				CICOSTAY(i) = yuv_buf[i].phys_addr;		CICOSTACb(i) = yuv_buf[i].phys_addr + ysize;		CICOSTACr(i) = yuv_buf[i].phys_addr + ysize + csize;		CIPRSTARGB(i) = rgb_buf[i].phys_addr;		DPRINTK("STAY%d  = 0x%08x\n", i, yuv_buf[i].phys_addr);		DPRINTK("STACB%d = 0x%08x\n", i, yuv_buf[i].phys_addr + yszie);		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	rCICOTRGFMT = (1<<31)|((cfg->dst_fmt?1:0)<<30)|(cfg->dst_x<<16)|(0<<14)|(cfg->dst_y);	CalculateBurstSize(cfg->dst_x, &burst_y, &remain_burst_y);	CalculateBurstSize(cfg->dst_x/2, &burst_c, &remain_burst_c);	rCICOCTRL = (burst_y<<19)|(remain_burst_y<<14)|(burst_c<<9)|(remain_burst_c<<4);	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);	rCICOSCPRERATIO = ((10-hsft-vsft)<<28)|(hratio<<16)|(vratio);	rCICOSCPREDST = ((cfg->src_x/hratio)<<16)|(cfg->src_y/vratio); 	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;	rCICOSCCTRL = (0<<31)|(hscale<<30)|(vscale<<29)|(mhratio<<16)|(mvratio);	rCICOTAREA = cfg->dst_x*cfg->dst_y;	///////////////// preview port setting	rCIPRTRGFMT = (cfg->pre_x<<16)|(0<<14)|(cfg->pre_y);	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);   	rCIPRCTRL = (burst_y<<19)|(remain_burst_y<<14);	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);	rCIPRSCPRERATIO = ((10-hsft-vsft)<<28)|(hratio<<16)|(vratio);	rCIPRSCPREDST = ((cfg->src_x/hratio)<<16)|(cfg->src_y/vratio);	hscale = (cfg->src_x>cfg->pre_x)?0:1;	vscale = (cfg->src_y>cfg->pre_y)?0:1;	rCIPRSCCTRL = (1<<31)|((cfg->pre_fmt?1:0)<<30)|(hscale<<29)|(vscale<<28)|(mhratio<<16)|(mvratio);	rCIPRTAREA= cfg->pre_x*cfg->pre_y;}static __inline void start_capture(struct s3c2440_camif *dev){	switch(dev->mode) {	case 0:	case 1:		rCIPRSCCTRL |= 1<<15;		rCIIMGCPT |= 5<<29;		break;	case 2:	case 3:		rCICOSCCTRL |= (1<<15)|(s3c2440_camif_cfg.bypass?(1<<31):0);		rCIIMGCPT |= 6<<29;		break;	}}static __inline void stop_capture(struct s3c2440_camif *dev){	switch(dev->mode) {	case 0:	case 1:		rCIPRSCCTRL &= ~(1<<15);	//stop preview scaler.		rCIIMGCPT   &= ~(7<<29);	//stop capturing for preview and codec scaler.#ifndef CAMERA_STOP_QUICKLY		rCIPRCTRL |= (1<<2);		//Enable last IRQ at the end of frame capture.		//NOTE:LastIrqEn bit should be set after clearing CAPTURE_ENABLE_BIT & SCALER_START_BIT		dev->flag |= 0x200;#endif		break;	case 2:	case 3:		rCICOSCCTRL &= ~(1<<15);	//stop codec scaler.		rCIIMGCPT   &= ~(7<<29);	//stop capturing for preview and codec scaler.#ifndef CAMERA_STOP_QUICKLY		rCICOCTRL |= (1<<2);		//Enable last IRQ at the end of frame capture.		//NOTE:LastIrqEn bit should be set after clearing CAPTURE_ENABLE_BIT & SCALER_START_BIT		dev->flag |= 0x200;#endif		break;	}}// run in irq disabled statestatic void s3c2440_camif_isr_c(int irq, void *dev_id, struct pt_regs *regs){	struct s3c2440_camif *dev = (struct s3c2440_camif*)dev_id;		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__);	}}#define	s3c2440_camif_isr_p	s3c2440_camif_isr_cstatic int v4l_cam_open(struct video_device *v, int mode){	unsigned long flags;	struct s3c2440_camif *dev = (struct s3c2440_camif *)v->priv;	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);	MOD_INC_USE_COUNT;	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	//s3c2440_camif_configure(&s3c2440_camif_cfg);	return 0;}static void v4l_cam_close(struct video_device *v){	unsigned long flags;	struct s3c2440_camif *dev = (struct s3c2440_camif *)(v->priv);

⌨️ 快捷键说明

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