📄 cafe_ccic.c
字号:
i2c_del_adapter(&cam->i2c_adapter);}/* ------------------------------------------------------------------- *//* * Deal with the controller. *//* * Do everything we think we need to have the interface operating * according to the desired format. */static void cafe_ctlr_dma(struct cafe_camera *cam){ /* * Store the first two Y buffers (we aren't supporting * planar formats for now, so no UV bufs). Then either * set the third if it exists, or tell the controller * to just use two. */ cafe_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]); cafe_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]); if (cam->nbufs > 2) { cafe_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]); cafe_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS); } else cafe_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS); cafe_reg_write(cam, REG_UBAR, 0); /* 32 bits only for now */}static void cafe_ctlr_image(struct cafe_camera *cam){ int imgsz; struct v4l2_pix_format *fmt = &cam->pix_format; imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) | (fmt->bytesperline & IMGSZ_H_MASK); cafe_reg_write(cam, REG_IMGSIZE, imgsz); cafe_reg_write(cam, REG_IMGOFFSET, 0); /* YPITCH just drops the last two bits */ cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline, IMGP_YP_MASK); /* * Tell the controller about the image format we are using. */ switch (cam->pix_format.pixelformat) { case V4L2_PIX_FMT_YUYV: cafe_reg_write_mask(cam, REG_CTRL0, C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV, C0_DF_MASK); break; case V4L2_PIX_FMT_RGB444: cafe_reg_write_mask(cam, REG_CTRL0, C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB, C0_DF_MASK); /* Alpha value? */ break; case V4L2_PIX_FMT_RGB565: cafe_reg_write_mask(cam, REG_CTRL0, C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR, C0_DF_MASK); break; default: cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat); break; } /* * Make sure it knows we want to use hsync/vsync. */ cafe_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, C0_SIFM_MASK);}/* * Configure the controller for operation; caller holds the * device mutex. */static int cafe_ctlr_configure(struct cafe_camera *cam){ unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); cafe_ctlr_dma(cam); cafe_ctlr_image(cam); cafe_set_config_needed(cam, 0); spin_unlock_irqrestore(&cam->dev_lock, flags); return 0;}static void cafe_ctlr_irq_enable(struct cafe_camera *cam){ /* * Clear any pending interrupts, since we do not * expect to have I/O active prior to enabling. */ cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); cafe_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS);}static void cafe_ctlr_irq_disable(struct cafe_camera *cam){ cafe_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS);}/* * Make the controller start grabbing images. Everything must * be set up before doing this. */static void cafe_ctlr_start(struct cafe_camera *cam){ /* set_bit performs a read, so no other barrier should be needed here */ cafe_reg_set_bit(cam, REG_CTRL0, C0_ENABLE);}static void cafe_ctlr_stop(struct cafe_camera *cam){ cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);}static void cafe_ctlr_init(struct cafe_camera *cam){ unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); /* * Added magic to bring up the hardware on the B-Test board */ cafe_reg_write(cam, 0x3038, 0x8); cafe_reg_write(cam, 0x315c, 0x80008); /* * Go through the dance needed to wake the device up. * Note that these registers are global and shared * with the NAND and SD devices. Interaction between the * three still needs to be examined. */ cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */ cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC); cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS); /* * Here we must wait a bit for the controller to come around. */ spin_unlock_irqrestore(&cam->dev_lock, flags); msleep(5); spin_lock_irqsave(&cam->dev_lock, flags); cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN); /* * Make sure it's not powered down. */ cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); /* * Turn off the enable bit. It sure should be off anyway, * but it's good to be sure. */ cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); /* * Mask all interrupts. */ cafe_reg_write(cam, REG_IRQMASK, 0); /* * Clock the sensor appropriately. Controller clock should * be 48MHz, sensor "typical" value is half that. */ cafe_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK); spin_unlock_irqrestore(&cam->dev_lock, flags);}/* * Stop the controller, and don't return until we're really sure that no * further DMA is going on. */static void cafe_ctlr_stop_dma(struct cafe_camera *cam){ unsigned long flags; /* * Theory: stop the camera controller (whether it is operating * or not). Delay briefly just in case we race with the SOF * interrupt, then wait until no DMA is active. */ spin_lock_irqsave(&cam->dev_lock, flags); cafe_ctlr_stop(cam); spin_unlock_irqrestore(&cam->dev_lock, flags); mdelay(1); wait_event_timeout(cam->iowait, !test_bit(CF_DMA_ACTIVE, &cam->flags), HZ); if (test_bit(CF_DMA_ACTIVE, &cam->flags)) cam_err(cam, "Timeout waiting for DMA to end\n"); /* This would be bad news - what now? */ spin_lock_irqsave(&cam->dev_lock, flags); cam->state = S_IDLE; cafe_ctlr_irq_disable(cam); spin_unlock_irqrestore(&cam->dev_lock, flags);}/* * Power up and down. */static void cafe_ctlr_power_up(struct cafe_camera *cam){ unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); /* * Part one of the sensor dance: turn the global * GPIO signal on. */ cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON); cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT|GGPIO_VAL); /* * Put the sensor into operational mode (assumes OLPC-style * wiring). Control 0 is reset - set to 1 to operate. * Control 1 is power down, set to 0 to operate. */ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */// mdelay(1); /* Marvell says 1ms will do it */ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);// mdelay(1); /* Enough? */ spin_unlock_irqrestore(&cam->dev_lock, flags); msleep(5); /* Just to be sure */}static void cafe_ctlr_power_down(struct cafe_camera *cam){ unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1); cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON); cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT); cafe_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN); spin_unlock_irqrestore(&cam->dev_lock, flags);}/* -------------------------------------------------------------------- *//* * Communications with the sensor. */static int __cafe_cam_cmd(struct cafe_camera *cam, int cmd, void *arg){ struct i2c_client *sc = cam->sensor; int ret; if (sc == NULL || sc->driver == NULL || sc->driver->command == NULL) return -EINVAL; ret = sc->driver->command(sc, cmd, arg); if (ret == -EPERM) /* Unsupported command */ return 0; return ret;}static int __cafe_cam_reset(struct cafe_camera *cam){ int zero = 0; return __cafe_cam_cmd(cam, VIDIOC_INT_RESET, &zero);}/* * We have found the sensor on the i2c. Let's try to have a * conversation. */static int cafe_cam_init(struct cafe_camera *cam){ struct v4l2_chip_ident chip = { V4L2_CHIP_MATCH_I2C_ADDR, 0, 0, 0 }; int ret; mutex_lock(&cam->s_mutex); if (cam->state != S_NOTREADY) cam_warn(cam, "Cam init with device in funky state %d", cam->state); ret = __cafe_cam_reset(cam); if (ret) goto out; chip.match_chip = cam->sensor->addr; ret = __cafe_cam_cmd(cam, VIDIOC_G_CHIP_IDENT, &chip); if (ret) goto out; cam->sensor_type = chip.ident;// if (cam->sensor->addr != OV7xx0_SID) { if (cam->sensor_type != V4L2_IDENT_OV7670) { cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr); ret = -EINVAL; goto out; }/* Get/set parameters? */ ret = 0; cam->state = S_IDLE; out: cafe_ctlr_power_down(cam); mutex_unlock(&cam->s_mutex); return ret;}/* * Configure the sensor to match the parameters we have. Caller should * hold s_mutex */static int cafe_cam_set_flip(struct cafe_camera *cam){ struct v4l2_control ctrl; memset(&ctrl, 0, sizeof(ctrl)); ctrl.id = V4L2_CID_VFLIP; ctrl.value = flip; return __cafe_cam_cmd(cam, VIDIOC_S_CTRL, &ctrl);}static int cafe_cam_configure(struct cafe_camera *cam){ struct v4l2_format fmt; int ret, zero = 0; if (cam->state != S_IDLE) return -EINVAL; fmt.fmt.pix = cam->pix_format; ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero); if (ret == 0) ret = __cafe_cam_cmd(cam, VIDIOC_S_FMT, &fmt); /* * OV7670 does weird things if flip is set *before* format... */ ret += cafe_cam_set_flip(cam); return ret;}/* -------------------------------------------------------------------- *//* * DMA buffer management. These functions need s_mutex held. *//* FIXME: this is inefficient as hell, since dma_alloc_coherent just * does a get_free_pages() call, and we waste a good chunk of an orderN * allocation. Should try to allocate the whole set in one chunk. */static int cafe_alloc_dma_bufs(struct cafe_camera *cam, int loadtime){ int i; cafe_set_config_needed(cam, 1); if (loadtime) cam->dma_buf_size = dma_buf_size; else cam->dma_buf_size = cam->pix_format.sizeimage; if (n_dma_bufs > 3) n_dma_bufs = 3; cam->nbufs = 0; for (i = 0; i < n_dma_bufs; i++) { cam->dma_bufs[i] = dma_alloc_coherent(&cam->pdev->dev, cam->dma_buf_size, cam->dma_handles + i, GFP_KERNEL); if (cam->dma_bufs[i] == NULL) { cam_warn(cam, "Failed to allocate DMA buffer\n"); break; } /* For debug, remove eventually */ memset(cam->dma_bufs[i], 0xcc, cam->dma_buf_size); (cam->nbufs)++; } switch (cam->nbufs) { case 1: dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size, cam->dma_bufs[0], cam->dma_handles[0]); cam->nbufs = 0; case 0: cam_err(cam, "Insufficient DMA buffers, cannot operate\n"); return -ENOMEM; case 2: if (n_dma_bufs > 2) cam_warn(cam, "Will limp along with only 2 buffers\n"); break; } return 0;}static void cafe_free_dma_bufs(struct cafe_camera *cam){ int i; for (i = 0; i < cam->nbufs; i++) { dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size, cam->dma_bufs[i], cam->dma_handles[i]); cam->dma_bufs[i] = NULL; } cam->nbufs = 0;}/* ----------------------------------------------------------------------- *//* * Here starts the V4L2 interface code. *//* * Read an image from the device. */static ssize_t cafe_deliver_buffer(struct cafe_camera *cam, char __user *buffer, size_t len, loff_t *pos){ int bufno; unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); if (cam->next_buf < 0) { cam_err(cam, "deliver_buffer: No next buffer\n"); spin_unlock_irqrestore(&cam->dev_lock, flags); return -EIO; } bufno = cam->next_buf; clear_bit(bufno, &cam->flags); if (++(cam->next_buf) >= cam->nbufs) cam->next_buf = 0; if (! test_bit(cam->next_buf, &cam->flags)) cam->next_buf = -1; cam->specframes = 0; spin_unlock_irqrestore(&cam->dev_lock, flags); if (len > cam->pix_format.sizeimage) len = cam->pix_format.sizeimage; if (copy_to_user(buffer, cam->dma_bufs[bufno], len)) return -EFAULT; (*pos) += len; return len;}/* * Get everything ready, and start grabbing frames. */static int cafe_read_setup(struct cafe_camera *cam, enum cafe_state state){ int ret; unsigned long flags; /* * Configuration. If we still don't have DMA buffers, * make one last, desperate attempt. */ if (cam->nbufs == 0) if (cafe_alloc_dma_bufs(cam, 0)) return -ENOMEM; if (cafe_needs_config(cam)) { cafe_cam_configure(cam); ret = cafe_ctlr_configure(cam); if (ret) return ret; } /* * Turn it loose. */ spin_lock_irqsave(&cam->dev_lock, flags); cafe_reset_buffers(cam); cafe_ctlr_irq_enable(cam); cam->state = state; cafe_ctlr_start(cam); spin_unlock_irqrestore(&cam->dev_lock, flags); return 0;}static ssize_t cafe_v4l_read(struct file *filp, char __user *buffer, size_t len, loff_t *pos){ struct cafe_camera *cam = filp->private_data; int ret = 0; /* * Perhaps we're in speculative read mode and already * have data? */ mutex_lock(&cam->s_mutex); if (cam->state == S_SPECREAD) { if (cam->next_buf >= 0) { ret = cafe_deliver_buffer(cam, buffer, len, pos); if (ret != 0) goto out_unlock; } } else if (cam->state == S_FLAKED || cam->state == S_NOTREADY) { ret = -EIO; goto out_unlock; } else if (cam->state != S_IDLE) { ret = -EBUSY; goto out_unlock; } /* * v4l2: multiple processes can open the device, but only * one gets to grab data from it. */ if (cam->owner && cam->owner != filp) { ret = -EBUSY; goto out_unlock; } cam->owner = filp; /* * Do setup if need be. */ if (cam->state != S_SPECREAD) { ret = cafe_read_setup(cam, S_SINGLEREAD); if (ret) goto out_unlock; } /* * Wait for something to happen. This should probably * be interruptible (FIXME). */ wait_event_timeout(cam->iowait, cam->next_buf >= 0, HZ); if (cam->next_buf < 0) { cam_err(cam, "read() operation timed out\n"); cafe_ctlr_stop_dma(cam); ret = -EIO; goto out_unlock; } /* * Give them their data and we should be done. */ ret = cafe_deliver_buffer(cam, buffer, len, pos); out_unlock: mutex_unlock(&cam->s_mutex); return ret;}/* * Streaming I/O support. */static int cafe_vidioc_streamon(struct file *filp, void *priv, enum v4l2_buf_type type){ struct cafe_camera *cam = filp->private_data; int ret = -EINVAL; if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) goto out; mutex_lock(&cam->s_mutex); if (cam->state != S_IDLE || cam->n_sbufs == 0) goto out_unlock; cam->sequence = 0; ret = cafe_read_setup(cam, S_STREAMING); out_unlock: mutex_unlock(&cam->s_mutex); out: return ret;}static int cafe_vidioc_streamoff(struct file *filp, void *priv, enum v4l2_buf_type type){ struct cafe_camera *cam = filp->private_data; int ret = -EINVAL; if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) goto out;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -