📄 s3c2440a_camif.c
字号:
/* * 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 + -