📄 omap24xxcam.c
字号:
/* * drivers/media/video/omap/omap24xxcam.c * * Video-for-Linux (Version 2) camera capture driver for * the OMAP24xx camera controller. * * Author: Andy Lowe (source@mvista.com) * * Copyright (C) 2004 MontaVista Software, Inc. * Copyright (C) 2004 Texas Instruments. * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */#include <linux/config.h>#include <linux/init.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/vmalloc.h>#include <linux/slab.h>#include <linux/sched.h>#include <linux/smp_lock.h>#include <linux/interrupt.h>#include <linux/kdev_t.h>#include <linux/types.h>#include <linux/wait.h>#include <linux/i2c.h>#include <linux/videodev.h>#include <linux/pci.h> /* needed for videobufs */#include <media/video-buf.h>#include <linux/dma-mapping.h>#include <linux/device.h>#include <linux/input.h>#include <asm/io.h>#include <asm/byteorder.h>#include <asm/scatterlist.h>#include <asm/irq.h>#include <asm/semaphore.h>#include <asm/processor.h>#include <asm/arch/bus.h>#include "omap24xxcam.h"#define CAMERA_OV9640#ifdef CAMERA_OV9640#include "ov9640.h"#endif#include "sensor_if.h"/* configuration macros */#define CAM_NAME "omap24xxcam"#define CONFIG_H4extern struct camera_sensor camera_sensor_if;void omap24xxcam_cleanup(void);/* global variables */static struct omap24xxcam_device *saved_cam;/* module parameters */static int video_nr = -1; /* video device minor (-1 ==> auto assign) *//* Maximum amount of memory to use for capture buffers. * Default is 4800KB, enough to double-buffer SXGA. */static int capture_mem = 1280*960*2*2;/* Size of video overlay framebuffer. This determines the maximum image size * that can be previewed. Default is 600KB, enough for VGA. */static int overlay_mem = 640*480*2;/* Size of video2_mem framebuffer. This determines the maximum image size which * video2_layer can support. Default is 300 KB. Size of LCD or 320*240.*/static int video2_mem = 320*240*2;/* -------------------------------------------------------------------------- *//* Set the value of the CC_CTRL register in cam->cc_ctrl that is required to * support the currently selected capture format in cam->pix. The CC_CTRL bits * which must be configured are: NOBT_SYNCHRO, BT_CORRECT, PAR_ORDERCAM, * PAR_CLK_POL, NOBT_HS_POL, NOBT_VS_POL, PAR_MODE, and CCP_MODE. The CC_RST, * CC_FRAME_TRIG, and CC_EN bits are actively managed by the driver and should * be set to zero by this routine. */static voidomap24xxcam_sensor_cc_ctrl(struct omap24xxcam_device *cam){ struct v4l2_pix_format *pix = &cam->pix; cam->cc_ctrl = CC_CTRL_NOBT_SYNCHRO | CC_CTRL_NOBT_VS_POL | CC_CTRL_PAR_MODE_NOBT8; switch (pix->pixelformat) { case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB555: default: /* These formats need a 16-bit byte swap */ cam->cc_ctrl |= CC_CTRL_PAR_ORDERCAM; case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_RGB565X: case V4L2_PIX_FMT_RGB555X: /* These formats don't need a 16-bit byte swap */ break; }}/* * camera core register I/O routines */static __inline__ u32 cc_reg_in(const struct omap24xxcam_device *cam, u32 offset){ return readl(cam->cam_mmio_base + CC_REG_OFFSET + offset);}static __inline__ u32 cc_reg_out(const struct omap24xxcam_device *cam, u32 offset, u32 val){ writel(val, cam->cam_mmio_base + CC_REG_OFFSET + offset); return val;}static __inline__ u32 cc_reg_merge(const struct omap24xxcam_device *cam, u32 offset, u32 val, u32 mask){ u32 addr = cam->cam_mmio_base + CC_REG_OFFSET + offset; u32 new_val = (readl(addr) & ~mask) | (val & mask); writel(new_val, addr); return new_val;}voidcc_init(const struct omap24xxcam_device *cam){ /* Setting the camera core AUTOIDLE bit causes problems with frame * synchronization, so we will clear the AUTOIDLE bit instead. */ //cc_reg_out(cam, CC_SYSCONFIG, 0); cc_reg_out(cam, CC_SYSCONFIG, CC_SYSCONFIG_AUTOIDLE);}/* * camera DMA register I/O routines */static __inline__ u32 camdma_reg_in(const struct omap24xxcam_device *cam, u32 offset){ return readl(cam->cam_mmio_base + CAMDMA_REG_OFFSET + offset);}static __inline__ u32 camdma_reg_out(const struct omap24xxcam_device *cam, u32 offset, u32 val){ writel(val, cam->cam_mmio_base + CAMDMA_REG_OFFSET + offset); return val;}static __inline__ u32 camdma_reg_merge(const struct omap24xxcam_device *cam, u32 offset, u32 val, u32 mask){ u32 addr = cam->cam_mmio_base + CAMDMA_REG_OFFSET + offset; u32 new_val = (readl(addr) & ~mask) | (val & mask); writel(new_val, addr); return new_val;}voidcamdma_init(const struct omap24xxcam_device *cam){ camdma_reg_out(cam, CAMDMA_OCP_SYSCONFIG, CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE | CAMDMA_OCP_SYSCONFIG_AUTOIDLE); camdma_reg_merge(cam, CAMDMA_GCR, 0x10, CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH);}/* * camera MMU register I/O routines */static __inline__ u32 cammmu_reg_in(const struct omap24xxcam_device *cam, u32 offset){ return readl(cam->cam_mmio_base + CAMMMU_REG_OFFSET + offset);}static __inline__ u32 cammmu_reg_out(const struct omap24xxcam_device *cam, u32 offset, u32 val){ writel(val, cam->cam_mmio_base + CAMMMU_REG_OFFSET + offset); return val;}static __inline__ u32 cammmu_reg_merge(const struct omap24xxcam_device *cam, u32 offset, u32 val, u32 mask){ u32 addr = cam->cam_mmio_base + CAMMMU_REG_OFFSET + offset; u32 new_val = (readl(addr) & ~mask) | (val & mask); writel(new_val, addr); return new_val;}voidcammmu_init(const struct omap24xxcam_device *cam){ /* set the camera MMU autoidle bit */ cammmu_reg_out(cam, CAMMMU_SYSCONFIG, CAMMMU_SYSCONFIG_AUTOIDLE);}/* * camera subsystem register I/O routines */static __inline__ u32 cam_reg_in(const struct omap24xxcam_device *cam, u32 offset){ return readl(cam->cam_mmio_base + offset);}static __inline__ u32 cam_reg_out(const struct omap24xxcam_device *cam, u32 offset, u32 val){ writel(val, cam->cam_mmio_base + offset); return val;}static __inline__ u32 cam_reg_merge(const struct omap24xxcam_device *cam, u32 offset, u32 val, u32 mask){ u32 addr = cam->cam_mmio_base + offset; u32 new_val = (readl(addr) & ~mask) | (val & mask); writel(new_val, addr); return new_val;}/* Reset the camera subsystem (camera core, camera DMA, and camera MMU) */static voidcam_reset(const struct omap24xxcam_device *cam, unsigned long timeout_ticks){ unsigned long timeout; cam_reg_out(cam, CAM_SYSCONFIG, CAM_SYSCONFIG_SOFTRESET); /* wait for reset to complete */ timeout = jiffies + timeout_ticks; while (!(cam_reg_in(cam, CAM_SYSSTATUS) & CAM_SYSSTATUS_RESETDONE) && time_before(jiffies, timeout)) { if (!in_atomic()) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } else udelay(10); } if (!(cam_reg_in(cam, CAM_SYSSTATUS) & CAM_SYSSTATUS_RESETDONE)) { printk(KERN_WARNING CAM_NAME ": timeout waiting for camera subsystem reset\n"); } return;}/* Initialize the camera subsystem (camera core, camera DMA, and camera MMU) */voidcam_init(const struct omap24xxcam_device *cam){ /* reset the camera subsystem with a timeout of 200ms */ cam_reset(cam, HZ/5); /* set the camera subsystem autoidle bit */ cam_reg_out(cam, CAM_SYSCONFIG, CAM_SYSCONFIG_AUTOIDLE); /* initialize the camera MMU */ cammmu_init(cam); /* initialize the camera DMA controller */ camdma_init(cam); /* initialize the camera core module */ cc_init(cam);}/* * display controller register I/O routines */static __inline__ u32 dispc_reg_in(const struct omap24xxcam_device *cam, u32 offset){ return readl(cam->dispc_mmio_base + DISPC_REG_OFFSET + offset);}static __inline__ u32 dispc_reg_out(const struct omap24xxcam_device *cam, u32 offset, u32 val){ writel(val, cam->dispc_mmio_base + DISPC_REG_OFFSET + offset); return val;}static __inline__ u32 dispc_reg_merge(const struct omap24xxcam_device *cam, u32 offset, u32 val, u32 mask){ u32 addr = cam->dispc_mmio_base + DISPC_REG_OFFSET + offset; u32 new_val = (readl(addr) & ~mask) | (val & mask); writel(new_val, addr); return new_val;}/* -------------------------------------------------------------------------- *//* Turn off the video overlay window. */static voidomap24xxcam_disable_vlayer(struct omap24xxcam_device *cam, int v){ unsigned long vid_attributes; vid_attributes = dispc_reg_merge(cam, DISPC_VID_ATTRIBUTES(v), 0, DISPC_VID_ATTRIBUTES_ENABLE); if (vid_attributes & DISPC_VID_ATTRIBUTES_VIDCHANNELOUT) { /* digital output */ dispc_reg_merge(cam, DISPC_CONTROL, DISPC_CONTROL_GODIGITAL, DISPC_CONTROL_GODIGITAL); } else { /* LCD */ dispc_reg_merge(cam, DISPC_CONTROL, DISPC_CONTROL_GOLCD, DISPC_CONTROL_GOLCD); }}/* Flip the video overlay framebuffer. The video overlay window may initially * be either enabled or disabled. The overlay window will be enabled by this * routine. fb_base_phys is the physical base address of the framebuffer for * the video overlay. The address programmed into the base address register of * the video overlay window is calculated based on the cropped size and the full * size of the overlay framebuffer. */static voidomap24xxcam_flip_overlay(struct omap24xxcam_device *cam, unsigned long fb_base_phys){ unsigned long vid_attributes; int v = cam->vid1; unsigned long cropped_base_phys; struct v4l2_rect *crop = &cam->crop; struct v4l2_pix_format *pix = &cam->pix; cropped_base_phys = fb_base_phys + pix->bytesperline*crop->top + crop->left*2; dispc_reg_out(cam, DISPC_VID_BA0(v), cropped_base_phys); dispc_reg_out(cam, DISPC_VID_BA1(v), cropped_base_phys); vid_attributes = dispc_reg_merge(cam, DISPC_VID_ATTRIBUTES(v), DISPC_VID_ATTRIBUTES_ENABLE, DISPC_VID_ATTRIBUTES_ENABLE); if (vid_attributes & DISPC_VID_ATTRIBUTES_VIDCHANNELOUT) { /* digital output */ dispc_reg_merge(cam, DISPC_CONTROL, DISPC_CONTROL_GODIGITAL, DISPC_CONTROL_GODIGITAL); } else { /* LCD */ dispc_reg_merge(cam, DISPC_CONTROL, DISPC_CONTROL_GOLCD, DISPC_CONTROL_GOLCD); }}/* Get the framebuffer parameters by reading the display controller registers * for the graphics window. */static voidomap24xxcam_g_fbuf(struct omap24xxcam_device *cam){ struct v4l2_framebuffer *fbuf = &cam->fbuf; unsigned long gfx_size, gfx_position; /* This routine makes some assumptions about the framebuffer driver. * First, the entire contents of the graphics framebuffer must be * displayed, i.e. a configuration in which part of the graphics * framebuffer is offscreen is not supported. The graphics * window must not be resized or repositioned while capture preview is * active. The rotation capabilities of the display controller must * not be used to rotate the graphics window. */ fbuf->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY; gfx_size = dispc_reg_in(cam, DISPC_GFX_SIZE); fbuf->fmt.width = 1 + ((gfx_size & DISPC_GFX_SIZE_GFXSIZEX) >> DISPC_GFX_SIZE_GFXSIZEX_SHIFT); fbuf->fmt.height = 1 + ((gfx_size & DISPC_GFX_SIZE_GFXSIZEY) >> DISPC_GFX_SIZE_GFXSIZEY_SHIFT); gfx_position = dispc_reg_in(cam, DISPC_GFX_POSITION); cam->gfx_position_x = (gfx_position & DISPC_GFX_POSITION_GFXPOSX) >> DISPC_GFX_POSITION_GFXPOSX_SHIFT; cam->gfx_position_y = (gfx_position & DISPC_GFX_POSITION_GFXPOSY) >> DISPC_GFX_POSITION_GFXPOSY_SHIFT; cam->gfx_attributes = dispc_reg_in(cam, DISPC_GFX_ATTRIBUTES);}/* Return the default overlay cropping rectangle in crop given the image capture * size in cam->pix and the video display size in cam->fbuf. The default * cropping rectangle is the largest rectangle no larger than the capture size * that will fit on the display. The default cropping rectangle is centered in * the captured image. All dimensions and offsets are rounded down to even * numbers. */static voidomap24xxcam_default_crop_rect(struct omap24xxcam_device *cam, struct v4l2_rect *crop){ struct v4l2_pix_format *pix = &cam->pix; struct v4l2_framebuffer *fbuf = &cam->fbuf; crop->width = (pix->width < fbuf->fmt.width) ? pix->width : fbuf->fmt.width; crop->height = (pix->height < fbuf->fmt.height) ? pix->height : fbuf->fmt.height; crop->width &= ~1; crop->height &= ~1; crop->left = ((pix->width - crop->width) >> 1) & ~1; crop->top = ((pix->height - crop->height) >> 1) & ~1;}/* Given a new cropping rectangle in new_crop, adjust the cropping rectangle to * the nearest supported configuration. The image preview window cam->win will * also be adjusted if necessary. The preview window is adjusted such that the * horizontal and vertical rescaling ratios stay constant. If the preview * window would fall outside the display boundaries, the cropping rectangle will
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -