📄 camif_mx2ads.c
字号:
minmod = mod = (*mclk) * (*hclk); /* This is very rough estimation , but it should works */ for (div2 = 1; div2 <= 64; div2++ ) { for (div1 = 2; div1 <= 32; div1 +=2) { mod = MOD(div1 * div2, sysclk/cam_clock); if (mod < minmod) { minmod = mod; *mclk = div1; *hclk = div2; if (!mod) break; } } } ret_freq = CLK_MPLL / (*hclk) / (*mclk); *hclk = *hclk - 1; *mclk = (*mclk - 1) >> 1; return ret_freq;}static intcamif_open(int channel){ int ret; unsigned int hclk, mclk; unsigned int reg_val; int i, initilized = 0; if (channel >= CAMIF_CHANNELS_NUM) return -EINVAL; if (!this->camera) return 0; for (i = 0; i < CAMIF_CHANNELS_NUM; i++) { if (chan_stat[i].opened) initilized = 1; } chan_stat[channel].opened = 1; init_waitqueue_head(&chan_stat[channel].abortqueue); if (initilized) return 0;#ifdef CONFIG_MX2TO1 mx_module_clk_open(HCLK_MODULE_CSI);#else camera_clk = camera_set_csi_clock(camera_clk, &hclk, &mclk); dbg("Set camera Master clock to %ld Hz\n", camera_clk); CRM_PCDR1 = (CRM_PCDR1 & ~PCDR1_PERDIV4) | ((hclk << PCDR1_PERDIV4_SHIFT) & PCDR1_PERDIV4); mx_module_clk_open(HCLK_MODULE_CSI); mx_module_clk_open(IPG_MODULE_PERCLK4); mx_module_clk_open(HCLK_MODULE_EMMA); mx_module_clk_open(IPG_MODULE_EMMA); CSI_REG_READ(CSICR1, reg_val); /* Clear register */ reg_val &= ~(CSICR1_MCLKDIV); reg_val |= (mclk << CSICR1_MCLKDIV_SHIFT) & CSICR1_MCLKDIV; CSI_REG_WRITE(CSICR1, reg_val); /* Clear register */#endif /* Reset eMMa */ PRP_CNTL = PRP2_CNTL_RST; mdelay(5); if (PRP_CNTL & PRP2_CNTL_RST) { err("prp: reset timeout\n"); return -EIO; } PRP_CNTL = PRP2_CNTL_IN_RGB16 | PRP2_CNTL_CSI | PRP2_CNTL_UNCHAIN; PRP_INTRSTATUS = 0x0; /* change irq to named constatnt*/ if (request_irq(INT_EMMAPRP, emma_prp_isr, SA_INTERRUPT, "eMMA prp", NULL)) { err("eMMa interrupt requesting error\n"); camif_close(channel); return -1; } if ((ret = this->camera->open())) { err("Camera open error\n"); camif_close(channel); return ret; } camif_start(); return 0;}/* * Deallocate CSI-related resources */static intcamif_close(int channel){ int i; if (channel >= CAMIF_CHANNELS_NUM) return -EINVAL; camif_abort(channel); chan_stat[channel].opened = 0; for (i = 0; i < CAMIF_CHANNELS_NUM; i++) { if (chan_stat[i].opened) { /* Other channel opened we can't stop now */ return 0; } } free_irq(INT_EMMAPRP, NULL); camif_stop(); this->camera->close();#ifdef CONFIG_MX2TO1 mx_module_clk_close(HCLK_MODULE_CSI);#else /* disable CSI PerClock 4 and HCLK */ mx_module_clk_close(HCLK_MODULE_CSI); mx_module_clk_close(IPG_MODULE_PERCLK4); mx_module_clk_close(HCLK_MODULE_EMMA); mx_module_clk_close(IPG_MODULE_EMMA);#endif return 0;}static intcamif_inithw(void){ uint32_t reg_val = 0; unsigned int hclk = 0, mclk = 0; /* * Before access to CSI registers, CSI clock control should be * configured */#ifdef CONFIG_MX2TO1 mx_module_clk_open(HCLK_MODULE_CSI); mclk = CSICR1_MCLKDIV_4 >> CSICR1_MCLKDIV_SHIFT;#else /* adjust CSI PerClock 4 */ /* enable CSI PerClock 4 and HCLK */ camera_set_csi_clock(camera_clk, &hclk, &mclk); CRM_PCDR1 = (CRM_PCDR1 & ~PCDR1_PERDIV4) | ((hclk << PCDR1_PERDIV4_SHIFT) & PCDR1_PERDIV4); mx_module_clk_open(HCLK_MODULE_CSI); mx_module_clk_open(IPG_MODULE_PERCLK4); mx_module_clk_open(HCLK_MODULE_EMMA); mx_module_clk_open(IPG_MODULE_EMMA);#endif reg_val = 0; reg_val |= (mclk << CSICR1_MCLKDIV_SHIFT) & CSICR1_MCLKDIV; reg_val |= CSICR1_SOF_POL_RISE; reg_val |= CSICR1_SOF_INTEN; reg_val |= CSICR1_REDGE; reg_val |= CSICR1_GCLK_MODE; reg_val |= CSICR1_HSYNC_POL_HIGH; reg_val |= CSICR1_FCC_SCLR ; reg_val |= CSICR1_RXFF_LEVEL_16; reg_val |= CSICR1_SWAP16_EN; reg_val |= CSICR1_PRP_IFEN; CSI_REG_WRITE(CSICR1, reg_val); return 0;}static intcamif_ioctl(unsigned int cmd, void *arg){ return -ENOIOCTLCMD;}/* * Cannel specific initialization */static intcamif_chan_init(unsigned int chan, void (*callback)(void *), void* data){ if (chan >= CAMIF_CHANNELS_NUM) return -EINVAL; chan_stat[chan].capture_callback = callback; chan_stat[chan].callback_data = data; return 0;}#define CSI_REG_REQUESTED (1)#define PRP_REG_REQUESTED (2)/* * Initialise CSI for first use (set gpios, reserve memory) */static intcamif_init(void){ this = &camif_mx2ads; memset(&chan_stat, 0, sizeof(chan_stat)); /* * reserve virtual addresses for CSI registers physical address */ if (!request_mem_region(CSI_BASE, CSI_IO_SIZE, "MX21.CSI registers")) { err("MX2 Camera: CSI memory region is already in use\n"); dbg("Address=0x%08x, size=0x%x\n", CSI_BASE, CSI_IO_SIZE); return -1; } mem_region_reserved |= CSI_REG_REQUESTED; if (!request_mem_region(EMMA_PRP_BASE, EMMA_PRP_IO_SIZE, "MX21.EMMA PRP registers")) { err("MX2 Camera: MX21.EMMA PRP memory region is already in " "use\n"); dbg("Address=0x%08x, size=0x%x\n", EMMA_PRP_BASE, EMMA_PRP_IO_SIZE); return -1; } mem_region_reserved |= PRP_REG_REQUESTED; /* * Enable CSI GPIOs */ if (mx2_register_gpios(PORT_B, CSI_GPIO_MASK, PRIMARY)) { err("MX2 Camera: CSI GPIO pins are already in use\n"); return -1; } if (camif_inithw()) { return -1; } camera_module_present = 1; return 0;}static voidcamif_cleanup(void) { info("Unloading camera interface \n"); if (this->camera) this->camera->cleanup(); if (mem_region_reserved & CSI_REG_REQUESTED) { release_mem_region(CSI_BASE, CSI_IO_SIZE); } if (mem_region_reserved & PRP_REG_REQUESTED) { release_mem_region(EMMA_PRP_BASE, EMMA_PRP_IO_SIZE); } mx2_unregister_gpios(PORT_B, CSI_GPIO_MASK);#ifdef CONFIG_MX2TO1 mx_module_clk_close(HCLK_MODULE_CSI);#else /* disable CSI PerClock 4 and HCLK */ mx_module_clk_close(HCLK_MODULE_CSI); mx_module_clk_close(IPG_MODULE_PERCLK4);#endif}typedef struct cam_dev_tag { char *cam_name; struct camera* camera_if; struct camera_serial_bus * sbus; unsigned long camera_clk;} cam_dev_t;cam_dev_t camera_devs[] = {#ifdef CONFIG_VIDEO_MX2ADS_OV9640 { .cam_name = "OV9640", .camera_if = &camera_ov9640, .sbus = &camera_mx2ads_omnivision_i2c, .camera_clk = CAMERA_OV9640_WORK_FREQ, },#endif /* CONFIG_VIDEO_MX2ADS_OV9640 */#ifdef CONFIG_VIDEO_MX2ADS_MISOC0343 { .cam_name = "MI-SOC-0343", .camera_if = &camera_misoc0343, .sbus = &camera_mx2ads_generic_i2c, .camera_clk = CAMERA_MISOC0343_WORK_FREQ, },#endif /* CONFIG_VIDEO_MX2ADS_MISOC0343 */#ifdef CONFIG_VIDEO_MX2ADS_MT9V111 { .cam_name = "MT9V111", .camera_if = &camera_mt9v111, .sbus = &camera_mx2ads_generic_i2c, .camera_clk = CAMERA_MT9V111_WORK_FREQ, },#endif /* CONFIG_VIDEO_MX2ADS_MT9V111 */ { .cam_name = NULL, .camera_if = NULL, .sbus = NULL, .camera_clk = 0, }};/**************************** * Routine: Description: ***************************/static struct camera * camif_camera_detect(void){ cam_dev_t *devices = camera_devs; ENTRY(); this->camera = NULL; if (!camera_module_present) return NULL; camif_start(); while (devices->camera_if) { int ret; char *name = devices->cam_name; struct camera * cam = devices->camera_if; cam->camif = this; camera_clk = devices->camera_clk; this->sbus = devices->sbus; devices++; info("Trying to detect %s camera\n", name); if ((ret = cam->detect())) { info("%s camera not detected\n", name); if (ret == -ENODEV) continue; else break; } else { info("%s camera detected\n", name); this->camera = cam; this->camera->init(); break; } info("%s camera not detected\n", name); } if (!this->camera) { info("No camera devices detected\n"); /*TODO: the camif has ability ro read stream indirect from * memeoty, So we can use this V4l2 module even if no camera * modules present. In this cae the write primitive should be * defined. */ } camif_stop(); return this->camera;}struct camera_interface camif_mx2ads = { .camera_detect = camif_camera_detect, .init = camif_init, .init_chan = camif_chan_init, .cleanup = camif_cleanup, .open = camif_open, .close = camif_close, .snapshot = camif_snapshot, .start_streaming = camif_start_streaming, .abort = camif_abort, .set_frame_period = camif_set_fp, .ioctl = camif_ioctl, .set_format = camif_set_format, .convert_image = camif_convert_image,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -