📄 pxa_camera.c
字号:
{ 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 = 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; }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;}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; iounmap((void *)ci_regs_base); //hzh, unmap and reset ci_regs_base ci_regs_base = 0;}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; }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; }#ifdef CONFIG_ARCH_FS_PXA27X //hzh#include <asm/leds.h>static int led_dma_done;#define LED_DMA_DONE() leds_event(((led_dma_done++)&1)?led_red_on:led_red_off)#else#define LED_DMA_DONE()#endifvoid 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; LED_DMA_DONE(); //hzh dcsr = DCSR(channel); DCSR(channel) = dcsr & ~DCSR_STOPIRQEN; if (still_image_mode == 1) { if (task_waiting == 1) { still_image_rdy = 1; //add by hzh wake_up_interruptible (&camera_wait_q); task_waiting = 0; } else { still_image_rdy = 1; wake_up_interruptible (&camera_wait_q); //add by hzh, wakeup process } } 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; } 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;} 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) { 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 + -