📄 iic.c
字号:
ioctl: pxa_camera_ioctl, mmap: pxa_camera_mmap, initialize: pxa_camera_video_init, minor: -1,};static int __init pxa_camera_init(void){ camera_context_t *cam_ctx = NULL; int err; /* 1. mapping CI registers, so that we can access the CI */ if ((err = request_irq(IRQ_CAMERA, pxa_camera_irq, 0, "PXA Camera", &vd))) { printk(KERN_WARNING PREFIX "camera interrupt register failed, error %d\n", err); return -ENXIO; } ci_dma_y = pxa_request_dma("CI_Y",DMA_PRIO_HIGH, pxa_ci_dma_irq_y, &vd); if (ci_dma_y < 0) { printk(KERN_WARNING PREFIX "can't request DMA for Y\n"); goto error; } ci_dma_cb = pxa_request_dma("CI_Cb",DMA_PRIO_HIGH, pxa_ci_dma_irq_cb, &vd); if (ci_dma_cb < 0) { printk(KERN_WARNING PREFIX "can't request DMA for Cb\n"); goto error; } ci_dma_cr = pxa_request_dma("CI_Cr",DMA_PRIO_HIGH, pxa_ci_dma_irq_cr, &vd); if (ci_dma_cr < 0) { printk(KERN_WARNING PREFIX "can't request DMA for Cr\n"); goto error; } DRCMR68 = ci_dma_y | DRCMR_MAPVLD; DRCMR69 = ci_dma_cb | DRCMR_MAPVLD; DRCMR70 = ci_dma_cr | DRCMR_MAPVLD; (unsigned long*)ci_regs_base = (unsigned long*)ioremap(CI_REGS_PHYS, CI_REG_SIZE); if(!ci_regs_base) { printk(KERN_ERR PREFIX "can't remap I/O registers at %x\n", CI_REGS_PHYS); return -1; } cam_ctx = (camera_context_t *) kmalloc(sizeof(struct camera_context_s), GFP_KERNEL); if (cam_ctx == NULL) { printk(KERN_WARNING PREFIX "can't allocate buffer for camera control structure\n"); goto error; } else { g_camera_context = cam_ctx; atomic_set(&cam_ctx->refcount, 0);#ifdef CONFIG_DPM cam_ctx->dma_started = 0;#endif } cam_ctx->dma_descriptors_virtual = consistent_alloc( GFP_KERNEL, MAX_DESC_NUM * sizeof(pxa_dma_desc), (void *)&cam_ctx->dma_descriptors_physical); if (cam_ctx->dma_descriptors_virtual == NULL) { printk(KERN_WARNING PREFIX "memory allocation for DMA descriptors (%ld bytes) failed\n", (long)(MAX_DESC_NUM * sizeof (pxa_dma_desc))); goto error; } cam_ctx->buf_size = BUF_SIZE_DEFT; cam_ctx->buffer_virtual = consistent_alloc( GFP_KERNEL, cam_ctx->buf_size, (void *)&cam_ctx->buffer_physical); if (!cam_ctx->buffer_virtual) goto error; cam_ctx->dma_descriptors_size = MAX_DESC_NUM; if (video_register_device(&vd, VFL_TYPE_GRABBER, minor) < 0) { printk(KERN_WARNING PREFIX "can't register video device\n"); goto error; }#ifdef CONFIG_DPM pxa_camera_ldm_register();#endif printk(KERN_NOTICE PREFIX "video device registered, use device /dev/video%d \n",minor); printk("manual call pxa_camera_open...\n"); pxa_camera_open(&vd,0); return 0;error: free_irq(IRQ_CAMERA, &vd); if (ci_dma_y >= 0) pxa_free_dma(ci_dma_y); if (ci_dma_cb >= 0) pxa_free_dma(ci_dma_cb); if (ci_dma_cr >= 0) pxa_free_dma(ci_dma_cr); DRCMR68 = 0; DRCMR69 = 0; DRCMR70 = 0; if(ci_regs_base) iounmap((unsigned long*)ci_regs_base); if (g_camera_context) { if (cam_ctx->dma_descriptors_virtual) { consistent_free (cam_ctx->dma_descriptors_virtual, MAX_DESC_NUM * sizeof (pxa_dma_desc), (int)cam_ctx->dma_descriptors_physical); } if (cam_ctx->buffer_virtual) { consistent_free (cam_ctx->buffer_virtual, cam_ctx->buf_size, (int)cam_ctx->dma_descriptors_physical); } kfree(g_camera_context); } return -ENXIO;}static void __exit pxa_camera_exit(void){ camera_context_t *cam_ctx = g_camera_context;#ifdef CONFIG_DPM pxa_camera_ldm_unregister();#endif video_unregister_device(&vd); free_irq(IRQ_CAMERA, &vd); if (ci_dma_y >= 0) pxa_free_dma(ci_dma_y); if (ci_dma_cb >= 0) pxa_free_dma(ci_dma_cb); if (ci_dma_cr >= 0) pxa_free_dma(ci_dma_cr); DRCMR68 = 0; DRCMR69 = 0; DRCMR70 = 0; if(ci_regs_base) iounmap((unsigned long*)ci_regs_base); if (cam_ctx->dma_descriptors_virtual) { consistent_free (cam_ctx->dma_descriptors_virtual, MAX_DESC_NUM * sizeof (pxa_dma_desc), (int)cam_ctx->dma_descriptors_physical); } if (cam_ctx->buffer_virtual) consistent_free (cam_ctx->buffer_virtual, cam_ctx->buf_size, (int)cam_ctx->buffer_physical); kfree(g_camera_context);}//-------------------------------------------------------------------------------------------------------// Configuration APIs//-------------------------------------------------------------------------------------------------------void ci_set_frame_rate(CI_FRAME_CAPTURE_RATE frate){ unsigned int value; // write cicr4 value = CICR4; value &= ~(CI_CICR4_FR_RATE_SMASK << CI_CICR4_FR_RATE_SHIFT); value |= (unsigned)frate << CI_CICR4_FR_RATE_SHIFT; CICR4 = value;}CI_FRAME_CAPTURE_RATE ci_get_frame_rate(void){ unsigned int value; value = CICR4; return (CI_FRAME_CAPTURE_RATE)((value >> CI_CICR4_FR_RATE_SHIFT) & CI_CICR4_FR_RATE_SMASK);}void ci_set_image_format(CI_IMAGE_FORMAT input_format, CI_IMAGE_FORMAT output_format){ unsigned int value, tbit, rgbt_conv, rgb_conv, rgb_f, ycbcr_f, rgb_bpp, raw_bpp, cspace; // write cicr1: preserve ppl value and data width value value = CICR1; value &= ( (CI_CICR1_PPL_SMASK << CI_CICR1_PPL_SHIFT) | ((CI_CICR1_DW_SMASK) << CI_CICR1_DW_SHIFT)); tbit = rgbt_conv = rgb_conv = rgb_f = ycbcr_f = rgb_bpp = raw_bpp = cspace = 0; switch(input_format) { case CI_RAW8: cspace = 0; raw_bpp = 0; break; case CI_RAW9: cspace = 0; raw_bpp = 1; break; case CI_RAW10: cspace = 0; raw_bpp = 2; break; case CI_YCBCR422: case CI_YCBCR422_PLANAR: cspace = 2; if (output_format == CI_YCBCR422_PLANAR) { ycbcr_f = 1; } break; case CI_RGB444: cspace = 1; rgb_bpp = 0; break; case CI_RGB555: cspace = 1; rgb_bpp = 1; if (output_format == CI_RGBT555_0) { rgbt_conv = 2; tbit = 0; } else if (output_format == CI_RGBT555_1) { rgbt_conv = 2; tbit = 1; } break; case CI_RGB565: cspace = 1; rgb_bpp = 2; rgb_f = 1; break; case CI_RGB666: cspace = 1; rgb_bpp = 3; if (output_format == CI_RGB666_PACKED) { rgb_f = 1; } break; case CI_RGB888: case CI_RGB888_PACKED: cspace = 1; rgb_bpp = 4; switch(output_format) { case CI_RGB888_PACKED: rgb_f = 1; break; case CI_RGBT888_0: rgbt_conv = 1; tbit = 0; break; case CI_RGBT888_1: rgbt_conv = 1; tbit = 1; break; case CI_RGB666: rgb_conv = 1; break;// RGB666 PACKED - JamesL case CI_RGB666_PACKED: rgb_conv = 1; rgb_f = 1; break;// end case CI_RGB565: rgb_conv = 2; break; case CI_RGB555: rgb_conv = 3; break; case CI_RGB444: rgb_conv = 4; break; default: break; } break; default: break; } value |= (tbit==1) ? CI_CICR1_TBIT : 0; value |= rgbt_conv << CI_CICR1_RGBT_CONV_SHIFT; value |= rgb_conv << CI_CICR1_RGB_CONV_SHIFT; value |= (rgb_f==1) ? CI_CICR1_RBG_F : 0; value |= (ycbcr_f==1) ? CI_CICR1_YCBCR_F : 0; value |= rgb_bpp << CI_CICR1_RGB_BPP_SHIFT; value |= raw_bpp << CI_CICR1_RAW_BPP_SHIFT; value |= cspace << CI_CICR1_COLOR_SP_SHIFT; CICR1 = value; return; }void ci_set_mode(CI_MODE mode, CI_DATA_WIDTH data_width){ unsigned int value; // write mode field in cicr0 value = CICR0; value &= ~(CI_CICR0_SIM_SMASK << CI_CICR0_SIM_SHIFT); value |= (unsigned int)mode << CI_CICR0_SIM_SHIFT; CICR0 = value; // write data width cicr1 value = CICR1; value &= ~(CI_CICR1_DW_SMASK << CI_CICR1_DW_SHIFT); value |= ((unsigned)data_width) << CI_CICR1_DW_SHIFT; CICR1 = value; return; }void ci_configure_mp(unsigned int ppl, unsigned int lpf, CI_MP_TIMING* timing){ unsigned int value; // write ppl field in cicr1 value = CICR1; value &= ~(CI_CICR1_PPL_SMASK << CI_CICR1_PPL_SHIFT); value |= (ppl & CI_CICR1_PPL_SMASK) << CI_CICR1_PPL_SHIFT; CICR1 = value; // write BLW, ELW in cicr2 value = CICR2; value &= ~(CI_CICR2_BLW_SMASK << CI_CICR2_BLW_SHIFT | CI_CICR2_ELW_SMASK << CI_CICR2_ELW_SHIFT ); value |= (timing->BLW & CI_CICR2_BLW_SMASK) << CI_CICR2_BLW_SHIFT; CICR2 = value; // write BFW, LPF in cicr3 value = CICR3; value &= ~(CI_CICR3_BFW_SMASK << CI_CICR3_BFW_SHIFT | CI_CICR3_LPF_SMASK << CI_CICR3_LPF_SHIFT ); value |= (timing->BFW & CI_CICR3_BFW_SMASK) << CI_CICR3_BFW_SHIFT; value |= (lpf & CI_CICR3_LPF_SMASK) << CI_CICR3_LPF_SHIFT; CICR3 = value; return;}void ci_configure_sp(unsigned int ppl, unsigned int lpf, CI_SP_TIMING* timing){ unsigned int value; // write ppl field in cicr1 value = CICR1; value &= ~(CI_CICR1_PPL_SMASK << CI_CICR1_PPL_SHIFT); value |= (ppl & CI_CICR1_PPL_SMASK) << CI_CICR1_PPL_SHIFT; CICR1 = value; // write cicr2 value = CICR2; value |= (timing->BLW & CI_CICR2_BLW_SMASK) << CI_CICR2_BLW_SHIFT; value |= (timing->ELW & CI_CICR2_ELW_SMASK) << CI_CICR2_ELW_SHIFT; value |= (timing->HSW & CI_CICR2_HSW_SMASK) << CI_CICR2_HSW_SHIFT; value |= (timing->BFPW & CI_CICR2_BFPW_SMASK) << CI_CICR2_BFPW_SHIFT; value |= (timing->FSW & CI_CICR2_FSW_SMASK) << CI_CICR2_FSW_SHIFT; CICR2 = value; // write cicr3 value = CICR3; value |= (timing->BFW & CI_CICR3_BFW_SMASK) << CI_CICR3_BFW_SHIFT; value |= (timing->EFW & CI_CICR3_EFW_SMASK) << CI_CICR3_EFW_SHIFT; value |= (timing->VSW & CI_CICR3_VSW_SMASK) << CI_CICR3_VSW_SHIFT; value |= (lpf & CI_CICR3_LPF_SMASK) << CI_CICR3_LPF_SHIFT; CICR3 = value; return;}void ci_configure_ms(unsigned int ppl, unsigned int lpf, CI_MS_TIMING* timing){ // the operation is same as Master-Parallel ci_configure_mp(ppl, lpf, (CI_MP_TIMING*)timing);}void ci_configure_ep(int parity_check){ unsigned int value; // write parity_enable field in cicr0 value = CICR0; if (parity_check) { value |= CI_CICR0_PAR_EN; } else { value &= ~CI_CICR0_PAR_EN; } CICR0 = value; return; }void ci_configure_es(int parity_check){ // the operationi is same as Embedded-Parallel ci_configure_ep(parity_check);}void ci_set_clock(unsigned int clk_regs_base, int pclk_enable, int mclk_enable, unsigned int mclk_khz){ unsigned int ciclk, value, div, cccr_l, K; // determine the LCLK frequency programmed into the CCCR. cccr_l = (CCCR & 0x0000001F); if (cccr_l < 8) K = 1; else if (cccr_l < 17) K = 2; else K = 3; ciclk = (13 * cccr_l) / K; div = ciclk / ( 2 * mclk_khz ) - 1 ; // write cicr4 value = CICR4; value &= ~(CI_CICR4_PCLK_EN | CI_CICR4_MCLK_EN | CI_CICR4_DIV_SMASK<<CI_CICR4_DIV_SHIFT); value |= (pclk_enable) ? CI_CICR4_PCLK_EN : 0; value |= (mclk_enable) ? CI_CICR4_MCLK_EN : 0; value |= div << CI_CICR4_DIV_SHIFT; CICR4 = value; return; }void ci_set_polarity(int pclk_sample_falling, int hsync_active_low, int vsync_active_low){ unsigned int value; // write cicr4 value = CICR4; value &= ~(CI_CICR4_PCP | CI_CICR4_HSP | CI_CICR4_VSP); value |= (pclk_sample_falling)? CI_CICR4_PCP : 0; value |= (hsync_active_low) ? CI_CICR4_HSP : 0; value |= (vsync_active_low) ? CI_CICR4_VSP : 0; CICR4 = value;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -