📄 pxa_camera-hzh.c
字号:
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);}//设置mclk频率和mclk及pclk是否由CPU产生(ciclk=104M,mclk=24M由CPU产生,pclk由sensor产生)void ci_set_clock(unsigned int clk_regs_base, int pclk_enable, int mclk_enable, unsigned int mclk_khz){ unsigned int ciclk = 0, value, div, cccr_l; // determine the LCLK frequency programmed into the CCCR. cccr_l = (CCCR & 0x0000001F); if (cccr_l < 8) // L = [2 - 7] ciclk = (13 * cccr_l) * 100; else if (cccr_l < 17) // L = [8 - 16] ciclk = ((13 * cccr_l) * 100) >> 1; else if (cccr_l < 32) // L = [17 - 31] ciclk = ((13 * cccr_l) * 100) >> 2; // want a divisor that gives us a clock rate as close to, but not more than the given mclk. div = (ciclk / (2 * mclk_khz)); div = div - 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; return; }//设置超时参数和FIFO启动DMA的阀值和使能/禁止FIFO1,FIFO2(FIFO现已可自动使能)void ci_set_fifo(unsigned int timeout, CI_FIFO_THRESHOLD threshold, int fifo1_enable, int fifo2_enable){ unsigned int value; // write citor CITOR = timeout; // write cifr: always enable fifo 0! also reset input fifo value = CIFR; value &= ~(CI_CIFR_FEN0 | CI_CIFR_FEN1 | CI_CIFR_FEN2 | CI_CIFR_RESETF | CI_CIFR_THL_0_SMASK<<CI_CIFR_THL_0_SHIFT); value |= (unsigned int)threshold << CI_CIFR_THL_0_SHIFT; value |= (fifo1_enable) ? CI_CIFR_FEN1 : 0; value |= (fifo2_enable) ? CI_CIFR_FEN2 : 0; value |= CI_CIFR_RESETF | CI_CIFR_FEN0; CIFR = value; return; }void ci_reset_fifo(void){ unsigned int value; value = CIFR; value |= CI_CIFR_RESETF; CIFR = value;}//设置中断掩码void ci_set_int_mask(unsigned int mask){ unsigned int value; // write mask in cicr0 value = CICR0; value &= ~CI_CICR0_INTERRUPT_MASK; value |= (mask & CI_CICR0_INTERRUPT_MASK); CICR0 = value; return; }//获取中断掩码unsigned int ci_get_int_mask(void){ unsigned int value; // write mask in cicr0 value = CICR0; return (value & CI_CICR0_INTERRUPT_MASK);}//清除中断void ci_clear_int_status(unsigned int status){ // write 1 to clear CISR = status;}//读中断状态unsigned int ci_get_int_status(void){ int value; value = CISR; return value;}//写和读camera控制寄存器void ci_set_reg_value(unsigned int reg_offset, unsigned int value){ CI_REG((u32)(ci_regs_base) + reg_offset) = value;}int ci_get_reg_value(unsigned int reg_offset){ int value; value = CI_REG((u32)(ci_regs_base) + reg_offset); return value;}//-------------------------------------------------------------------------------------------------------// Control APIs//-------------------------------------------------------------------------------------------------------int ci_init(void){ int cken_val; (unsigned long*)ci_regs_base = (unsigned long*)ioremap(CI_REGS_PHYS, CI_REG_SIZE); if(!ci_regs_base) { printk ("ci regs base apply failed \n"); return -1; } // clear all CI registers CICR0 = 0x3FF; // disable all interrupts CICR1 = 0; CICR2 = 0; CICR3 = 0; CICR4 = 0; CISR = ~0; CIFR = 0; CITOR = 0; // enable CI clock cken_val = CKEN; cken_val |= CKEN24_CAMERA; CKEN = cken_val; return 0;}void ci_deinit(){ // disable CI clock CKEN &= ~CKEN24_CAMERA;}void ci_enable(int dma_en){ unsigned int value; // write mask in cicr0 value = CICR0; value |= CI_CICR0_ENB; if (dma_en) { value |= CI_CICR0_DMA_EN; } CICR0 = value; return; }//关闭camera,有快速和等待当前祯采样完毕两种模式int ci_disable(int quick){ volatile unsigned int value, mask; int retry; // write control bit in cicr0 value = CICR0; if (quick) { value &= ~CI_CICR0_ENB; mask = CI_CISR_CQD; } else { value |= CI_CICR0_DIS; mask = CI_CISR_CDD; } CICR0 = value; // wait shutdown complete retry = 50; while ( retry-- > 0 ) { value = CISR; if ( value & mask ) { CISR = mask; return 0; } mdelay(10); } return -1; }void ci_slave_capture_enable(){ unsigned int value; // write mask in cicr0 value = CICR0; value |= CI_CICR0_SL_CAP_EN; CICR0 = value; return; }void ci_slave_capture_disable(){ unsigned int value; // write mask in cicr0 value = CICR0; value &= ~CI_CICR0_SL_CAP_EN; CICR0 = value; return; }//DMA中断处理程序,只在Y通道结束才做具体操作void pxa_ci_dma_irq_y(int channel, void *data, struct pt_regs *regs){ int dcsr; static int dma_repeated=0; camera_context_t *cam_ctx = g_camera_context; dcsr = DCSR(channel); DCSR(channel) = dcsr & ~DCSR_STOPIRQEN; if (still_image_mode == 1) { if (task_waiting == 1) { wake_up_interruptible (&camera_wait_q); task_waiting = 0; } else { still_image_rdy = 1; } } //当尾块索引(读取数据时修改)与头块索引(DMA结束时修改)只差1时,在尾块前一块重复DMA以防止覆盖数据 else if (dma_repeated == 0 && (cam_ctx->block_tail == ((cam_ctx->block_header + 2) % cam_ctx->block_number))) { dma_repeated = 1; pxa_dma_repeat(cam_ctx); cam_ctx->block_header = (cam_ctx->block_header + 1) % cam_ctx->block_number; } //如前面有重复一块DMA操作,在条件满足时(数据已被读出,尾块已变)恢复DMA循环操作 else if (dma_repeated == 1 && (cam_ctx->block_tail != ((cam_ctx->block_header + 1) % cam_ctx->block_number)) && (cam_ctx->block_tail != ((cam_ctx->block_header + 2) % cam_ctx->block_number))) { pxa_dma_continue(cam_ctx); dma_repeated = 0; } else if (dma_repeated == 0) { cam_ctx->block_header = (cam_ctx->block_header + 1) % cam_ctx->block_number; } if (task_waiting == 1 && !(cam_ctx->block_header == cam_ctx->block_tail)) { wake_up_interruptible (&camera_wait_q); task_waiting = 0; } return;}void pxa_ci_dma_irq_cb(int channel, void *data, struct pt_regs *regs){ return;}void pxa_ci_dma_irq_cr(int channel, void *data, struct pt_regs *regs){ return;} inline static void pxa_ci_dma_stop(camera_context_t *cam_ctx){ int ch0, ch1, ch2; ch0 = cam_ctx->dma_channels[0]; ch1 = cam_ctx->dma_channels[1]; ch2 = cam_ctx->dma_channels[2]; DCSR(ch0) &= ~DCSR_RUN; DCSR(ch1) &= ~DCSR_RUN; DCSR(ch2) &= ~DCSR_RUN;} //填充DMA目的地址并启动DMA操作void pxa_dma_start(camera_context_t *cam_ctx){ unsigned char cnt_blk; pxa_dma_desc *cnt_desc; cam_ctx->block_header = (cam_ctx->block_header + 1) % cam_ctx->block_number; cnt_blk = (unsigned char)cam_ctx->block_header; cnt_desc = (pxa_dma_desc *)cam_ctx->fifo0_descriptors_physical + cnt_blk * cam_ctx->fifo0_num_descriptors; DDADR(cam_ctx->dma_channels[0]) = (int) cnt_desc; DCSR(cam_ctx->dma_channels[0]) |= DCSR_RUN; if (cam_ctx->fifo1_num_descriptors) { cnt_desc = (pxa_dma_desc *)cam_ctx->fifo1_descriptors_physical + cnt_blk * cam_ctx->fifo1_num_descriptors; DDADR(cam_ctx->dma_channels[1]) = (int) cnt_desc; DCSR(cam_ctx->dma_channels[1]) |= DCSR_RUN; } if (cam_ctx->fifo2_num_descriptors) { cnt_desc = (pxa_dma_desc *)cam_ctx->fifo2_descriptors_physical + cnt_blk * cam_ctx->fifo2_num_descriptors; DDADR(cam_ctx->dma_channels[2]) = (int) cnt_desc; DCSR(cam_ctx->dma_channels[2]) |= DCSR_RUN; } return;}irqreturn_t pxa_camera_irq(int irq, void *dev_id, struct pt_regs *regs) { int cisr; static int dma_started=0; disable_irq(IRQ_CAMERA); cisr = CISR; if (cisr & CI_CISR_SOF) { if (dma_started == 0) { dma_started = 1; } CISR |= CI_CISR_SOF; } if (cisr & CI_CISR_EOF) { CISR |= CI_CISR_EOF; } enable_irq(IRQ_CAMERA); return IRQ_HANDLED; }void pxa_dma_repeat(camera_context_t *cam_ctx){ pxa_dma_desc *cnt_head, *cnt_tail; int cnt_block; cnt_block = (cam_ctx->block_header + 1) % cam_ctx->block_number;// FIFO0 (pxa_dma_desc *)cnt_head = (pxa_dma_desc *)cam_ctx->fifo0_descriptors_virtual + cnt_block * cam_ctx->fifo0_num_descriptors; cnt_tail = cnt_head + cam_ctx->fifo0_num_descriptors - 1; cnt_tail->ddadr = cnt_head->ddadr - sizeof(pxa_dma_desc);// FIFO1 if (cam_ctx->fifo1_transfer_size) { cnt_head = (pxa_dma_desc *)cam_ctx->fifo1_descriptors_virtual + cnt_block * cam_ctx->fifo1_num_descriptors; cnt_tail = cnt_head + cam_ctx->fifo1_num_descriptors - 1; cnt_tail->ddadr = cnt_head->ddadr - sizeof(pxa_dma_desc); }// FIFO2 if (cam_ctx->fifo2_transfer_size) { cnt_head = (pxa_dma_desc *)cam_ctx->fifo2_descriptors_virtual + cnt_block * cam_ctx->fifo2_num_descriptors; cnt_tail = cnt_head + cam_ctx->fifo2_num_descriptors - 1; cnt_tail->ddadr = cnt_head->ddadr - sizeof(pxa_dma_desc); } return;}void pxa_dma_continue(camera_context_t *cam_ctx){ pxa_dma_desc *cnt_head, *cnt_tail; pxa_dma_desc *next_head; int cnt_block, next_block; cnt_block = cam_ctx->block_header; next_block = (cnt_block + 1) % cam_ctx->block_number;// FIFO0 cnt_head = (pxa_dma_desc *)cam_ctx->fifo0_descriptors_virtual + cnt_block * cam_ctx->fifo0_num_descriptors; cnt_tail = cnt_head + cam_ctx->fifo0_num_descriptors - 1; next_head = (pxa_dma_desc *)cam_ctx->fifo0_descriptors_virtual + next_block * cam_ctx->fifo0_num_descriptors; cnt_tail->ddadr = next_head->ddadr - sizeof(pxa_dma_desc);// FIFO1 if (cam_ctx->fifo1_transfer_size) { cnt_head = (pxa_dma_desc *)cam_ctx->fifo1_descriptors_virtual + cnt_block * cam_ctx->fifo1_num_descriptors; cnt_tail = cnt_head + cam_ctx->fifo1_num_descriptors - 1; next_head = (pxa_dma_desc *)cam_ctx->fifo1_descriptors_virtual + next_block * cam_ctx->fifo1_num_descriptors; cnt_tail->ddadr = next_head->ddadr - sizeof(pxa_dma_desc); }// FIFO2 if (cam_ctx->fifo2_transfer_size) { cnt_head = (pxa_dma_desc *)cam_ctx->fifo2_descriptors_virtual + cnt_block * cam_ctx->fifo2_num_descriptors; cnt_tail = cnt_head + cam_ctx->fifo2_num_descriptors - 1; next_head = (pxa_dma_desc *)cam_ctx->fifo2_descriptors_virtual + next_block * cam_ctx->fifo2_num_descriptors; cnt_tail->ddadr = next_head->ddadr - sizeof(pxa_dma_desc); } return;}module_init(pxa_camera_init);module_exit(pxa_camera_exit);MODULE_DESCRIPTION("Bulverde Camera Interface driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -