📄 s3c2440_ov7620.c
字号:
}#endif#if DEBUG_WORK_STANDALONE CAPTURE_PORT_A();#endif}static void cam_to_rgb32_sw(int frame, struct s3c2440_camif_cfg_t *cfg){ int i; for (i = 0; i < cfg->dst_y; i++) yuv_convert_rgb32(yuv_buf[frame].buf + i * cfg->dst_x, yuv_buf[frame].buf + cfg->dst_x*cfg->dst_y + (i/2) * cfg->dst_x / 2, yuv_buf[frame].buf + cfg->dst_x*cfg->dst_y/2*3 + (i/2) * cfg->dst_x / 2, rgb_buf[frame].buf + i * cfg->dst_x * 4, cfg->dst_x); frame_to_user = frame;#if DEBUG_WORK_STANDALONE CAPTURE_PORT_A();#endif}static void cam_to_yuv420(int frame, struct s3c2440_camif_cfg_t *cfg){ int i; /* Y */ memcpy(rgb_buf[frame].buf, yuv_buf[frame].buf, cfg->dst_x * cfg->dst_y); /* U */ for (i = 0; i < cfg->dst_y * 2; i++) memcpy( rgb_buf[frame].buf + cfg->dst_x * cfg->dst_y + i * cfg->dst_x / 2 , yuv_buf[frame].buf + cfg->dst_x * cfg->dst_y + (i/2) * cfg->dst_x / 2 , cfg->dst_x / 2); /* V */ for (i = 0; i < cfg->dst_y * 2; i++) memcpy( rgb_buf[frame].buf + cfg->dst_x * cfg->dst_y / 2 * 3 + i * cfg->dst_x / 2 , yuv_buf[frame].buf + cfg->dst_x * cfg->dst_y / 2 * 3 + (i/2) * cfg->dst_x / 2 , cfg->dst_x / 2); frame_to_user = frame;#if DEBUG_WORK_STANDALONE CAPTURE_PORT_A();#endif}static void s3c2440_camif_config(struct s3c2440_camif_cfg_t *cfg){ int i; unsigned long adist, awidth; unsigned long hratio, vratio; int mburst, rburst;// unsigned long frame_offset_yuv = PAGE_ALIGN(YUV_TUPLE_SIZE);// unsigned long frame_offset_rgb = PAGE_ALIGN(RGB_TUPLE_SIZE); for (i = 0; i < 4; i++) { yuv_buf[i].buf = camif_yuv_buf; yuv_buf[i].phys_addr = (unsigned int)camif_yuv_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); rgb_buf[i].buf = camif_rgb_buf; rgb_buf[i].phys_addr = (unsigned int)camif_rgb_buf_dma; 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); CAM_STAY(i) = yuv_buf[i].phys_addr; DPRINTK2("STAY%d = 0x%08x\n", i, yuv_buf[i].phys_addr); CAM_STACB(i) = yuv_buf[i].phys_addr + cfg->dst_x*cfg->dst_y; DPRINTK2("STACB%d = 0x%08x\n", i, yuv_buf[i].phys_addr + cfg->dst_x*cfg->dst_y); CAM_STACR(i) = yuv_buf[i].phys_addr + cfg->dst_x*cfg->dst_y / 2 * 3; DPRINTK2("STACR%d = 0x%08x\n", i, yuv_buf[i].phys_addr + cfg->dst_x*cfg->dst_y / 2 * 3); } CAM_ASIZE = CAM_SIZE_H(cfg->dst_x) | CAM_SIZE_V(cfg->dst_y);#if 1 mburst = 4; rburst = (cfg->dst_x / 4) % mburst;#endif#if 1 rburst = rburst ? rburst : mburst;#endif#if 0 mburst = 16; rburst = ((cfg->dst_x / 4) + mburst) % mburst;#endif CAM_AYBURST = CAM_BURST_M(mburst) | CAM_BURST_R(rburst); DPRINTK2("YBURST = %d,%d = 0x%08lx\n", mburst, rburst , CAM_BURST_M(mburst) | CAM_BURST_R(rburst));#if 1 mburst = 4; rburst = (cfg->dst_x / 2 / 4) % mburst;#endif#if 1 rburst = rburst ? rburst : mburst;#endif CAM_ACBBURST = CAM_BURST_M(mburst) | CAM_BURST_R(rburst); CAM_ACRBURST = CAM_BURST_M(mburst) | CAM_BURST_R(rburst); DPRINTK2("CBBURST = %d,%d = 0x%08lx\n", mburst, rburst , CAM_BURST_M(mburst) | CAM_BURST_R(rburst)); /* * Adist = ( MemoryBusClk/CameraClk ) * 3 * Width * CameraClk = UPLL / [(CAMCLK_DIV + 1) * 2] * by SW.LEE */ adist = ( s3c2440_get_bus_clk(GET_HCLK) * 3 * cfg->src_x ) / get_camera_clk(); awidth = adist; CAM_ADISTWIDTH = CAM_DISTWIDTH_D(adist) | CAM_DISTWIDTH_W(awidth); DPRINTK2("HCLK = %ld, pixel_clock = %ld, adist = %ld\n" , s3c2440_get_bus_clk(GET_HCLK) , get_camera_clk() , adist ); DPRINTK2("CAM_ADISTWIDTH = 0x%08lx\n" , CAM_DISTWIDTH_D(adist) | CAM_DISTWIDTH_W(awidth)); hratio = (cfg->src_x * 4096) / cfg->dst_x; vratio = (cfg->src_y * 4096) / cfg->dst_y; CAM_YRATIO = CAM_RATIO_H(hratio) | CAM_RATIO_V(vratio); DPRINTK2("YRATIO = %ld,%ld = 0x%08lx\n", hratio, vratio , CAM_RATIO_H(hratio) | CAM_RATIO_V(vratio)); hratio = ((cfg->src_x/2) * 4096) / (cfg->dst_x/2); vratio = (cfg->src_y * 4096) / (cfg->dst_y/2); CAM_CRATIO = CAM_RATIO_H(hratio) | CAM_RATIO_V(vratio); DPRINTK2("CRATIO = %ld,%ld = 0x%08lx\n", hratio, vratio , CAM_RATIO_H(hratio) | CAM_RATIO_V(vratio)); CAM_YORIGINAL = CAM_ORIGINAL_H(cfg->src_x) | CAM_ORIGINAL_V(cfg->src_y); DPRINTK2("YORIGINAL = 0x%08lx\n", CAM_ORIGINAL_H(cfg->src_x) | CAM_ORIGINAL_V(cfg->src_y)); CAM_CORIGINAL = CAM_ORIGINAL_H((cfg->src_x/2)) | CAM_ORIGINAL_V(cfg->src_y); DPRINTK2("CORIGINAL = 0x%08lx\n", CAM_ORIGINAL_H((cfg->src_x/2)) | CAM_ORIGINAL_V(cfg->src_y)); switch (cfg->dst_type) { case CAMIF_TYPE_RGB16 : cfg->camif_frame_handler = cam_to_rgb16_sw; break; case CAMIF_TYPE_RGB32 : cfg->camif_frame_handler = cam_to_rgb32_sw; break; case CAMIF_TYPE_YUV420 : cfg->camif_frame_handler = cam_to_yuv420; break; panic("unknown destination type.\n"); } if (!cfg->camif_frame_handler) panic("unknown dst_type.\n");}static void s3c2440_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);}/* * $\> SW.LEE * * OV7620_CLK is 12Mhz or 24Mhz * * CAMCLK = OV7620_CLK; * CAMCLK_DIV = UPLL / ( CAMCLK * 2) - 1 ; */ void inline s3c2440_camif_init(void){ unsigned int upll, uclk, camclk,camclk_div; camclk = get_camera_clk(); CLKCON |= CLKCON_CAMIF;/* Supposed that you must set UPLL at first */ UPLLCON = FInsrt(0x38, fPLL_MDIV) | FInsrt(0x02, fPLL_PDIV) | 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 ) ;}void inline s3c2440_camif_deinit(void){ CLKCON &= ~CLKCON_CAMIF; CAM_CTRL = 0; mdelay(5);}static void cam_s_task_handler(void * data){ struct s3c2440_camif_cfg_t *cfg = (struct s3c2440_camif_cfg_t *)data; int frame = (CAM_STAT_FRAME(CAM_RDSTAT) ); // + 3) % 4;// CAM_CTRL &= ~(1<<18); DPRINTK("frame = %d\n", frame); cfg->camif_frame_handler(frame, cfg);#if MORE_STABLE_BUT_SLOW DPRINTK2("wait for stable\n"); interruptible_sleep_on_timeout(&cam_wait, 8); DPRINTK2("wait done\n"); if (signal_pending(current)) goto out; memcpy(camif_user_buf, rgb_buf[frame_to_user].buf, USER_TUPLE_SIZE);out:#endif wake_up_interruptible(&camdev_wait); UNSET_CAM(CAM_CAPTURING);}static void s3c2440_camif_isr_s(int irq, void *dev_id, struct pt_regs *regs){ schedule_task(&cam_s_task);}/*************** end of CAMIF ******************//*********** start of device interface *********/static int camdev_open_count = 0;int inline cam_init(void){ enable_irq(IRQ_CAM_S); return 0;}void inline cam_deinit(void){ disable_irq(IRQ_CAM_S);}int inline cam_setparam(struct s3c2440_camif_cfg_t *param){ s3c2440_camif_cfg.dst_x = param->dst_x; s3c2440_camif_cfg.dst_y = param->dst_y; s3c2440_camif_cfg.dst_type = param->dst_type; /* * ToDo * lock & unlock */ if ( 1 == camdev_open_count) s3c2440_camif_config(&s3c2440_camif_cfg); return 0;}static int cam_open(struct inode *inode, struct file *file){ DPRINTK("open_count = %d\n", camdev_open_count); /* * ToDo * lock & unlock */ if (0 == camdev_open_count) { if (cam_init() < 0) return -EIO; SET_CAM(CAM_OPENED); } camdev_open_count ++; return 0;}static int cam_release(struct inode *inode, struct file *file){ camdev_open_count --; /* * ToDo * lock & unlock */ if (!camdev_open_count) { disable_irq(IRQ_CAM_S); flush_scheduled_tasks(); cam_deinit(); UNSET_CAM(CAM_CAPTURING); UNSET_CAM(CAM_OPENED); } return 0;}static ssize_t cam_read(struct file *f, char *buf, size_t count, loff_t *pos){ size_t end; if (IS_CAM(CAM_CAPTURING)) { interruptible_sleep_on(&camdev_wait); if (signal_pending(current)) { return -EIO; } }#if 0 if (!(f->f_flags & O_NONBLOCK)) { return -EPERM; }#endif#if MORE_STABLE_BUT_SLOW end = min_t(size_t, USER_TUPLE_SIZE, count); if (copy_to_user(buf, camif_user_buf, end)) return -EFAULT;#else end = min_t(size_t, RGB_TUPLE_SIZE, count); if (copy_to_user(buf, rgb_buf[frame_to_user].buf, end)) return -EFAULT;#endif return end;}static ssize_t cam_write(struct file *f, const char *b, size_t c, loff_t *pos){ if (IS_CAM(CAM_CAPTURING)) { printk("already capturing...\n"); return c; } SET_CAM(CAM_CAPTURING); CAPTURE_PORT_A(); return c;}static int cam_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct s3c2440_camif_cfg_t tmp_caminfo; int ret = 0; switch(cmd) { case 0x10: if (copy_from_user(&tmp_caminfo, (struct s3c2440_camif_cfg_t*)arg, sizeof(struct s3c2440_camif_cfg_t))) return -EFAULT; ret = cam_setparam(&tmp_caminfo); break; default: return -EINVAL; } return ret;}static struct file_operations cam_fops = { owner : THIS_MODULE, llseek : no_llseek, open : cam_open, read : cam_read, write : cam_write, ioctl : cam_ioctl, release : cam_release,};static struct miscdevice cam_dev = { minor : MISC_DYNAMIC_MINOR, name : "cam", fops : &cam_fops};/************* end of device interface *********/int __init init_s3c2440_ov7620(void){ int ret = 0; printk("Starting S3C2440 Camera \n"); DPRINTK("camif_dst_x = %d, camif_dst_y = %d\n", camif_dst_x, camif_dst_y); camif_yuv_buf = consistent_alloc(GFP_KERNEL, YUV_IMG_BUF_SIZE, &camif_yuv_buf_dma); if (!camif_yuv_buf) printk(" Faile YUV_IMG_BUF \n"); camif_rgb_buf = consistent_alloc(GFP_KERNEL, RGB_IMG_BUF_SIZE, &camif_rgb_buf_dma); if (!camif_rgb_buf) printk(" Faile RGB_IMG_BUF \n");#if MORE_STABLE_BUT_SLOW camif_user_buf = (unsigned char *)vmalloc(USER_TUPLE_SIZE);#endif if (!camif_yuv_buf || !camif_rgb_buf #if MORE_STABLE_BUT_SLOW || !camif_user_buf#endif ) { printk(" CAMERA Memory allocation failed \n"); ret = -ENOMEM; goto mem_err; } memset(camif_yuv_buf, 0, YUV_IMG_BUF_SIZE); memset(camif_rgb_buf, 0, RGB_IMG_BUF_SIZE); init_yuvtable(); INIT_TQUEUE(&cam_s_task, cam_s_task_handler, (void*)&s3c2440_camif_cfg); s3c2440_cam_gpio_init(); s3c2440_camif_init(); /* default config */ s3c2440_camif_cfg.src_x = CAM_SRC_X; s3c2440_camif_cfg.src_y = CAM_SRC_Y; s3c2440_camif_cfg.dst_x = camif_dst_x; s3c2440_camif_cfg.dst_y = camif_dst_y; s3c2440_camif_cfg.dst_type = CAMIF_DEFAULT_FMT; s3c2440_camif_config(&s3c2440_camif_cfg); ov7620_init(); if ((ret != check_ov7620())) if ((ret = check_ov7620())) goto err_not_det; ov7620_config(); printk("OV7620 [0x12] = 0x%02x\n", ov7620_sccb_receivebyte(0x12)); if ((ret = request_irq(IRQ_CAM_S, s3c2440_camif_isr_s, SA_INTERRUPT, "CAM_S", NULL))) { printk("request_irq(CAM_S) failed.\n"); goto err_irq_s; } disable_irq(IRQ_CAM_S); flush_scheduled_tasks();#if DEBUG_WORK_STANDALONE /* capture A port */ enable_irq(IRQ_CAM_S); CAPTURE_PORT_A();#else misc_register(&cam_dev);#endif return 0;err_irq_s: free_irq(IRQ_CAM_S, NULL);err_not_det: ov7620_deinit(); s3c2440_camif_deinit();mem_err: if (camif_yuv_buf) consistent_free(camif_yuv_buf, YUV_IMG_BUF_SIZE , camif_yuv_buf_dma); if (camif_rgb_buf) consistent_free(camif_rgb_buf, RGB_IMG_BUF_SIZE , camif_rgb_buf_dma); return ret;}void __exit exit_s3c2440_ov7620(void){ disable_irq(IRQ_CAM_S); flush_scheduled_tasks(); s3c2440_camif_deinit(); free_irq(IRQ_CAM_S, NULL); ov7620_deinit(); DPRINTK(" CAMEAR: Free Consistent Memory \n"); if (camif_yuv_buf) consistent_free(camif_yuv_buf, YUV_IMG_BUF_SIZE , camif_yuv_buf_dma); if (camif_rgb_buf) consistent_free(camif_rgb_buf, RGB_IMG_BUF_SIZE , camif_rgb_buf_dma);#if MORE_STABLE_BUT_SLOW if (camif_user_buf) vfree(camif_user_buf);#endif#if DEBUG_WORK_STANDALONE /* do nothing */#else misc_deregister(&cam_dev);#endif}module_init(init_s3c2440_ov7620);module_exit(exit_s3c2440_ov7620);MODULE_PARM(camif_dst_x, "i");MODULE_PARM_DESC(camif_dst_x, "S3C2440 CAMIF, width of destination image");MODULE_PARM(camif_dst_y, "i");MODULE_PARM_DESC(camif_dst_y, "S3C2440 CAMIF, height of destination image");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -