?? pxa_camera-hzh.c
字號(hào):
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);}//設(shè)置mclk頻率和mclk及pclk是否由CPU產(chǎn)生(ciclk=104M,mclk=24M由CPU產(chǎn)生,pclk由sensor產(chǎn)生)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; }//設(shè)置采樣有效邊緣和同步信號(hào)有效極性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; }//設(shè)置超時(shí)參數(shù)和FIFO啟動(dòng)DMA的閥值和使能/禁止FIFO1,FIFO2(FIFO現(xiàn)已可自動(dòng)使能)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;}//設(shè)置中斷掩碼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;}//讀中斷狀態(tài)unsigned int ci_get_int_status(void){ int value; value = CISR; return value;}//寫(xiě)和讀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; }//關(guān)閉camera,有快速和等待當(dāng)前禎采樣完畢兩種模式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通道結(jié)束才做具體操作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; } } //當(dāng)尾塊索引(讀取數(shù)據(jù)時(shí)修改)與頭塊索引(DMA結(jié)束時(shí)修改)只差1時(shí),在尾塊前一塊重復(fù)DMA以防止覆蓋數(shù)據(jù) 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; } //如前面有重復(fù)一塊DMA操作,在條件滿(mǎn)足時(shí)(數(shù)據(jù)已被讀出,尾塊已變)恢復(fù)DMA循環(huán)操作 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目的地址并啟動(dòng)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 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");
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -