* [PATCH] Re: omap24xxcam status (Was: v4l2 camera test app)
2006-03-20 16:27 omap24xxcam status (Was: v4l2 camera test app) Zhang, Jian
2006-03-20 17:36 ` David Cohen
@ 2006-03-20 21:20 ` David Cohen
2006-03-21 12:56 ` Komal Shah
1 sibling, 1 reply; 8+ messages in thread
From: David Cohen @ 2006-03-20 21:20 UTC (permalink / raw)
To: ext Zhang, Jian; +Cc: Linux-omap-open-source
[-- Attachment #1: Type: text/plain, Size: 2730 bytes --]
Hi,
I am sending a new patch with support for the new sensor interface
(kernel 2.6.10 TI already did it). I have made also some updates
according to Komal comments. :)
Regards,
David Cohen
ext Zhang, Jian wrote:
> David,
>
> I don't see the new sensor interface incorporated in your patch. It is
> likely that Micron 2MP camera MT9D111 will be used by more people. The
> new sensor interface supports double-context which is an advanced
> feature of micron camera.
>
> Regards,
> Jian
>
> -----Original Message-----
> From: David Cohen [mailto:david.cohen@indt.org.br]
> Sent: Monday, March 20, 2006 10:10 AM
> To: ext Komal Shah
> Cc: Ola Helm; Linux-omap-open-source@linux.omap.com; Zhang, Jian
> Subject: Re: omap24xxcam status (Was: v4l2 camera test app)
>
> Hi,
>
> I just sent a code that should be compilable and working. I guess the
> mainly target is to apply this patch to the public tree. After that, as
> Komal said, could be interesting to update the dma code to the omap api
> to be easier future reviews.
>
> Regards,
>
> David Cohen
>
> ext Komal Shah wrote:
>
>
>> --- Ola Helm <ola.hel@gmail.com> wrote:
>>
>>
>>
>>
>>> Hi,
>>>
>>> Have you got some idea what's the situation of the 24xx camera driver
>>> at the
>>> moment? AFAIK the patch David sent in last month is not included to
>>> tree,
>>> propably since there were some opposite opinions about the way of
>>> implementation and at least I did not have one file mentioned in
>>> patch (I
>>> think you mentioned about the same issue)
>>>
>>>
>>>
>> 24xx camera driver is now in David's hand. I just review the code now,
>> as not able to work on camera stuff anymore.
>>
>> Following strategy can work out meanwhile as I had offline discussion
>> with David :)
>>
>> o Separate 24xx CamDMA code from omap24xxcam.c to new file as
>> exported apis (Suggested by David)
>>
>> o Keep the old omap24xxcam driver interface(2.6.8 TI kernel days),
>> having video out code part of the camera driver itself. As new
>> separated video out code depends upon the common display controller
>> library, which requires to change fb driver in git tree to adopt
>> that interface, so that video out, and fb driver can
>> utilize the same code. But video out patches submitted by me didn't
>> generated any discussion on the list in that direction.
>>
>> o So, to have 24xx camera code in git tree, we can use the old camera
>> driver interface as of now, if everyone agrees.
>>
>> ---Komal Shah
>> http://komalshah.blogspot.com/
>>
>> __________________________________________________
>> Do You Yahoo!?
>> Tired of spam? Yahoo! Mail has the best spam protection around
>> http://mail.yahoo.com
>>
>>
>>
>
>
[-- Attachment #2: diff_omap24xxcam_v2.patch --]
[-- Type: text/plain, Size: 134326 bytes --]
diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile
index c4c5a81..3027af6 100644
--- a/drivers/media/video/omap/Makefile
+++ b/drivers/media/video/omap/Makefile
@@ -3,9 +3,8 @@
obj-$(CONFIG_VIDEO_OMAP_CAMERA) += omapcamera.o
obj-$(CONFIG_VIDEO_CAMERA_SENSOR_OV9640) += sensor_ov9640.o
-objs-yy := camera_core.o
-
-objs-y$(CONFIG_ARCH_OMAP16XX) += omap16xxcam.o
+objs-y$(CONFIG_ARCH_OMAP16XX) += camera_core.o omap16xxcam.o
+objs-y$(CONFIG_ARCH_OMAP24XX) += omap24xxcam.o
objs-y$(CONFIG_MACH_OMAP_H3) += h3_sensor_power.o
omapcamera-objs := $(objs-yy)
diff --git a/drivers/media/video/omap/omap24xxcam.c b/drivers/media/video/omap/omap24xxcam.c
new file mode 100644
index 0000000..e46ce15
--- /dev/null
+++ b/drivers/media/video/omap/omap24xxcam.c
@@ -0,0 +1,3381 @@
+/*
+ * 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.
+ *
+ * History:
+ * 2006/mar - David Cohen <david.cohen@indt.org.br>
+ * * Updated the driver for the Linux Device Model
+ * * Updated some obsolete functions of V4L2
+ * * Some others small fixes
+ */
+
+#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 <linux/version.h>
+#include <linux/platform_device.h>
+#include <linux/clk.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/clock.h>
+
+#include "omap24xxcam.h"
+#include "sensor_if.h"
+
+/* configuration macros */
+#define CAM_NAME "omap24xxcam"
+
+/* Should be moved from here */
+#define INT_CAM_MPU_IRQ 24
+
+//#define DEBUG_CAM
+
+#ifdef DEBUG_CAM
+#define DBG printk(KERN_INFO CAM_NAME ": %s\n", __FUNCTION__)
+#define DBG_END printk(KERN_INFO CAM_NAME ": %s END!\n", __FUNCTION__)
+#define DBG_MID(x) printk(KERN_INFO CAM_NAME ": %s - %d\n", __FUNCTION__, x)
+#else
+#define DBG
+#define DBG_END
+#define DBG_MID(x)
+#endif
+
+extern 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;
+
+static struct clk *cam_fck;
+static struct clk *cam_ick;
+
+/* -------------------------------------------------------------------------- */
+
+/* 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 void omap24xxcam_sensor_cc_ctrl(struct omap24xxcam_device *cam)
+{
+ struct v4l2_pix_format *pix = &cam->pix;
+ struct camera_sensor *sensor = cam->cam_sensor;
+
+ /* basic mode */
+ cam->cc_ctrl = sensor->parallel_mode << CC_CTRL_PAR_MODE_SHIFT;
+ /* sync polarity */
+ cam->cc_ctrl |= (sensor->hs_polarity << CC_CTRL_NOBT_HS_POL_SHIFT);
+ cam->cc_ctrl |= (sensor->vs_polarity << CC_CTRL_NOBT_VS_POL_SHIFT);
+ /* swap */
+ cam->cc_ctrl |= (sensor->image_swap ? CC_CTRL_PAR_ORDERCAM : 0);
+ /* based on BT or NOBT */
+ if ((sensor->parallel_mode == PAR_MODE_BT8) ||
+ (sensor->parallel_mode == PAR_MODE_BT10)) {
+ /* BT correction enable */
+ cam->cc_ctrl |= (sensor->bt_correction ? CC_CTRL_BT_CORRECT : 0);
+ cam->cc_ctrl |= ((sensor->parallel_mode == PAR_MODE_BT8) ? CC_CTRL_PAR_MODE_BT8 : CC_CTRL_PAR_MODE_BT10);
+ }
+ else
+ /* always use the rising edger to trigger the acquisition
+ in NOBT modes. This is recommended */
+ cam->cc_ctrl |= CC_CTRL_NOBT_SYNCHRO;
+
+ 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;
+}
+
+void cc_init(const struct omap24xxcam_device *cam)
+{
+ DBG;
+ /* 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 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;
+}
+
+void cammmu_init(const struct omap24xxcam_device *cam)
+{
+ DBG;
+ /* set the camera MMU autoidle bit */
+ cammmu_reg_out(cam, CAMMMU_SYSCONFIG, CAMMMU_SYSCONFIG_AUTOIDLE);
+}
+
+/*
+ * camera DMA register I/O routines
+ */
+
+__inline__ u32
+camdma_reg_in(const struct omap24xxcam_device *cam, u32 offset)
+{
+ return readl(cam->cam_mmio_base + CAMDMA_REG_OFFSET + offset);
+}
+
+__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;
+}
+
+__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;
+}
+
+void
+camdma_init(const struct omap24xxcam_device *cam)
+{
+ DBG;
+ camdma_reg_out(cam, CAMDMA_OCP_SYSCONFIG,
+ CAMDMA_OCP_SYSCONFIG_MIDLEMODE_NSTANDBY
+ | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE
+ | CAMDMA_OCP_SYSCONFIG_AUTOIDLE);
+
+ camdma_reg_merge(cam, CAMDMA_GCR, 0x10,
+ CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH);
+}
+
+/*
+ * 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 void
+cam_reset(const struct omap24xxcam_device *cam, unsigned long timeout_ticks)
+{
+ unsigned long timeout;
+
+ DBG;
+
+ 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) */
+void cam_init(const struct omap24xxcam_device *cam)
+{
+ DBG;
+ /* 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 void omap24xxcam_disable_vlayer(struct omap24xxcam_device *cam, int v)
+{
+ unsigned long vid_attributes;
+
+ DBG;
+
+ 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 void
+omap24xxcam_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;
+
+ DBG;
+
+ 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 void omap24xxcam_g_fbuf(struct omap24xxcam_device *cam)
+{
+ struct v4l2_framebuffer *fbuf = &cam->fbuf;
+ unsigned long gfx_size, gfx_position;
+
+ DBG;
+
+ /* 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 void
+omap24xxcam_default_crop_rect(struct omap24xxcam_device *cam,
+ struct v4l2_rect *crop)
+{
+ struct v4l2_pix_format *pix = &cam->pix;
+ struct v4l2_framebuffer *fbuf = &cam->fbuf;
+
+ DBG;
+
+ 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
+ * also be adjusted to maintain the rescaling ratios. If successful, cam->crop
+ * and cam->win are updated.
+ * Returns zero if succesful, or -EINVAL if the requested cropping rectangle is
+ * impossible and cannot reasonably be adjusted.
+ */
+static int
+omap24xxcam_new_crop_rect(struct omap24xxcam_device *cam,
+ const struct v4l2_rect *new_crop)
+{
+ struct v4l2_pix_format *pix = &cam->pix;
+ struct v4l2_window *win = &cam->win;
+ struct v4l2_framebuffer *fbuf = &cam->fbuf;
+ struct v4l2_rect *crop = &cam->crop;
+ struct v4l2_rect try_crop;
+ unsigned long vresize, hresize;
+
+ DBG;
+
+ /* make a working copy of the new_crop rectangle */
+ try_crop = *new_crop;
+
+ /* adjust the cropping rectangle so it fits in the image */
+ if (try_crop.left < 0) {
+ try_crop.width += try_crop.left;
+ try_crop.left = 0;
+ }
+ if (try_crop.top < 0) {
+ try_crop.height += try_crop.top;
+ try_crop.top = 0;
+ }
+ try_crop.width = (try_crop.width < pix->width) ?
+ try_crop.width : pix->width;
+ try_crop.height = (try_crop.height < pix->height) ?
+ try_crop.height : pix->height;
+ if (try_crop.left + try_crop.width > pix->width)
+ try_crop.width = pix->width - try_crop.left;
+ if (try_crop.top + try_crop.height > pix->height)
+ try_crop.height = pix->height - try_crop.top;
+ try_crop.width &= ~1;
+ try_crop.height &= ~1;
+ if (try_crop.width <= 0 || try_crop.height <= 0)
+ return -EINVAL;
+
+ if (crop->height != win->w.height) {
+ /* If we're resizing vertically, we can't support a crop width
+ * wider than 768 pixels.
+ */
+ if (try_crop.width > 768)
+ try_crop.width = 768;
+ }
+ /* vertical resizing */
+ vresize = (1024 * crop->height) / win->w.height;
+ if (vresize > 2048)
+ vresize = 2048;
+ else if (vresize == 0)
+ vresize = 1;
+ win->w.height = ((1024 * try_crop.height) / vresize) & ~1;
+ if (win->w.height == 0)
+ win->w.height = 2;
+ if (win->w.height + win->w.top > fbuf->fmt.height) {
+ /* We made the preview window extend below the bottom of the
+ * display, so clip it to the display boundary and resize the
+ * cropping height to maintain the vertical resizing ratio.
+ */
+ win->w.height = (fbuf->fmt.height - win->w.top) & ~1;
+ try_crop.height = ((vresize * win->w.height) / 1024) & ~1;
+ if (try_crop.height == 0)
+ try_crop.height = 2;
+ }
+ /* horizontal resizing */
+ hresize = (1024 * crop->width) / win->w.width;
+ if (hresize > 2048)
+ hresize = 2048;
+ else if (hresize == 0)
+ hresize = 1;
+ win->w.width = ((1024 * try_crop.width) / hresize) & ~1;
+ if (win->w.width == 0)
+ win->w.width = 2;
+ if (win->w.width + win->w.left > fbuf->fmt.width) {
+ /* We made the preview window extend past the right side of the
+ * display, so clip it to the display boundary and resize the
+ * cropping width to maintain the horizontal resizing ratio.
+ */
+ win->w.width = (fbuf->fmt.width - win->w.left) & ~1;
+ try_crop.width = ((hresize * win->w.width) / 1024) & ~1;
+ if (try_crop.width == 0)
+ try_crop.width = 2;
+ }
+ /* update our cropping rectangle and we're done */
+ *crop = try_crop;
+ return 0;
+}
+
+/* Given a new preview window in new_win, adjust the preview window to the
+ * nearest supported configuration. The adjusted preview window parameters are
+ * returned in new_win.
+ * Returns zero if succesful, or -EINVAL if the requested preview window is
+ * impossible and cannot reasonably be adjusted.
+ */
+static int
+omap24xxcam_try_preview_window(struct omap24xxcam_device *cam,
+ struct v4l2_window *new_win)
+{
+ struct v4l2_framebuffer *fbuf = &cam->fbuf;
+ struct v4l2_rect try_win;
+
+ DBG;
+
+ /* make a working copy of the new_win rectangle */
+ try_win = new_win->w;
+
+ /* adjust the preview window so it fits on the display by clipping any
+ * offscreen areas
+ */
+ if (try_win.left < 0) {
+ try_win.width += try_win.left;
+ try_win.left = 0;
+ }
+ if (try_win.top < 0) {
+ try_win.height += try_win.top;
+ try_win.top = 0;
+ }
+ try_win.width = (try_win.width < fbuf->fmt.width) ?
+ try_win.width : fbuf->fmt.width;
+ try_win.height = (try_win.height < fbuf->fmt.height) ?
+ try_win.height : fbuf->fmt.height;
+ if (try_win.left + try_win.width > fbuf->fmt.width)
+ try_win.width = fbuf->fmt.width - try_win.left;
+ if (try_win.top + try_win.height > fbuf->fmt.height)
+ try_win.height = fbuf->fmt.height - try_win.top;
+ try_win.width &= ~1;
+ try_win.height &= ~1;
+ if (try_win.width <= 0 || try_win.height <= 0)
+ return -EINVAL;
+
+ /* We now have a valid preview window, so go with it */
+ new_win->w = try_win;
+ new_win->field = V4L2_FIELD_NONE;
+ return 0;
+}
+
+/* Given a new preview window in new_win, adjust the preview window to the
+ * nearest supported configuration. The image cropping window cam->crop
+ * will also be adjusted if necessary. Preference is given to keeping the
+ * preview window as close to the requested configuration as possible. If
+ * successful, new_win, cam->win, and cam->crop are updated.
+ * Returns zero if succesful, or -EINVAL if the requested preview window is
+ * impossible and cannot reasonably be adjusted.
+ */
+static int
+omap24xxcam_new_preview_window(struct omap24xxcam_device *cam,
+ struct v4l2_window *new_win)
+{
+ struct v4l2_window *win = &cam->win;
+ struct v4l2_rect *crop = &cam->crop;
+ int err;
+
+ DBG;
+
+ err = omap24xxcam_try_preview_window(cam, new_win);
+ if (err)
+ return err;
+
+ /* update our preview window */
+ win->w = new_win->w;
+ win->field = new_win->field;
+ win->chromakey = new_win->chromakey;
+
+ /* adjust the cropping window to allow for resizing limitations */
+ if (crop->height / win->w.height >= 2) {
+ /* The maximum vertical downsizing ratio is 2:1 */
+ crop->height = win->w.height * 2;
+ }
+ if (crop->width / win->w.width >= 2) {
+ /* The maximum horizontal downsizing ratio is 2:1 */
+ crop->width = win->w.width * 2;
+ }
+ if (crop->width > 768) {
+ /* The OMAP2420 vertical resizing line buffer is 768 pixels
+ * wide. If the cropped image is wider than 768 pixels then it
+ * cannot be vertically resized.
+ */
+ if (crop->height != win->w.height)
+ crop->width = 768;
+ }
+ return 0;
+}
+
+/* Given a capture format in cam->pix, the cam->crop, cam->win, and cam->fbuf
+ * structures are initialized to default values. cam->fbuf is initialized by
+ * reading the display controller registers for the graphics window. cam->crop
+ * is initialized to the largest window size that will fit on the display. The
+ * crop window is centered in the captured image. cam->win is initialized to
+ * the same size as cam->crop and is centered on the display.
+ * All sizes and offsets are constrained to be even numbers.
+ */
+static void omap24xxcam_new_capture_format(struct omap24xxcam_device *cam)
+{
+ struct v4l2_rect *crop = &cam->crop;
+ struct v4l2_window *win = &cam->win;
+ struct v4l2_framebuffer *fbuf = &cam->fbuf;
+
+ DBG;
+
+ /* get the framebuffer parameters */
+ omap24xxcam_g_fbuf(cam);
+
+ /* crop defines the preview source window in the image capture
+ * buffer
+ */
+ omap24xxcam_default_crop_rect(cam, crop);
+
+ /* win defines the preview target window on the display */
+ win->w.width = crop->width;
+ win->w.height = crop->height;
+ win->w.left = ((fbuf->fmt.width - win->w.width) >> 1) & ~1;
+ win->w.top = ((fbuf->fmt.height - win->w.height) >> 1) & ~1;
+}
+
+/* Program the camera interface xclk for the frequency cam->xclk based on
+ * the functional clock frequency cam->mclk. If the specifed cam->xclk
+ * frequency is not possible based on the value of cam->mclk, then the
+ * closest xclk frequency lower than the specified xclk will be selected.
+ * The actual xclk frequency is returned in cam->xclk. If cam->xclk is zero,
+ * then xclk is turned off (stable low value).
+ */
+static void omap24xxcam_set_xclk(struct omap24xxcam_device *cam)
+{
+ unsigned long divisor;
+
+ DBG;
+
+ if (cam->mclk == 0)
+ cam->mclk = 96000000; /* supply a default mclk */
+
+ if (cam->xclk == 0) {
+ cc_reg_out(cam, CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW);
+ return;
+ }
+
+ if (cam->xclk > cam->mclk)
+ cam->xclk = cam->mclk;
+
+ divisor = cam->mclk / cam->xclk;
+ if (cam->xclk * divisor < cam->mclk)
+ divisor += 1;
+ if (divisor > 30)
+ divisor = 30;
+ cam->xclk = cam->mclk / divisor;
+ if (divisor == 1)
+ cc_reg_out(cam, CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_BYPASS);
+ else
+ cc_reg_out(cam, CC_CTRL_XCLK, divisor);
+}
+
+/* Write the color space conversion coefficients to the display controller
+ * registers. Each coefficient is a signed 11-bit integer in the range
+ * [-1024, 1023]. The matrix coefficients are:
+ * [ RY RCr RCb ]
+ * [ GY GCr GCb ]
+ * [ BY BCr BCb ]
+ */
+static void
+omap24xxcam_set_colorconv(struct omap24xxcam_device *cam,
+ const short int mtx[3][3], int v)
+{
+ unsigned long ccreg;
+
+ DBG;
+
+ ccreg = (mtx[0][0] & 0x7ff) | ((mtx[0][1] & 0x7ff) << 16);
+ dispc_reg_out(cam, DISPC_VID_CONV_COEF0(v), ccreg);
+ ccreg = (mtx[0][2] & 0x7ff) | ((mtx[1][0] & 0x7ff) << 16);
+ dispc_reg_out(cam, DISPC_VID_CONV_COEF1(v), ccreg);
+ ccreg = (mtx[1][1] & 0x7ff) | ((mtx[1][2] & 0x7ff) << 16);
+ dispc_reg_out(cam, DISPC_VID_CONV_COEF2(v), ccreg);
+ ccreg = (mtx[2][0] & 0x7ff) | ((mtx[2][1] & 0x7ff) << 16);
+ dispc_reg_out(cam, DISPC_VID_CONV_COEF3(v), ccreg);
+ ccreg = mtx[2][2] & 0x7ff;
+ dispc_reg_out(cam, DISPC_VID_CONV_COEF4(v), ccreg);
+}
+
+/* Write the horizontal and vertical resizing coefficients to the display
+ * controller registers. Each coefficient is a signed 8-bit integer in the
+ * range [-128, 127] except for the middle coefficient (vc[1][i] and hc[3][i])
+ * which is an unsigned 8-bit integer in the range [0, 255]. The first index of
+ * the matrix is the coefficient number (0 to 2 vertical or 0 to 4 horizontal)
+ * and the second index is the phase (0 to 7).
+ */
+static void
+omap24xxcam_set_resize(struct omap24xxcam_device *cam,
+ const short int vc[3][8], const short int hc[5][8],
+ int v)
+{
+ int i;
+ unsigned long reg;
+
+ DBG;
+
+ for (i = 0; i < 8; i++) {
+ reg = (hc[0][i] & 0xff) | ((hc[1][i] & 0xff) << 8)
+ | ((hc[2][i] & 0xff) << 16) | ((hc[3][i] & 0xff) << 24);
+ dispc_reg_out(cam, DISPC_VID_FIR_COEF_H(v, i), reg);
+ reg = (hc[4][i] & 0xff) | ((vc[0][i] & 0xff) << 8)
+ | ((vc[1][i] & 0xff) << 16) | ((vc[2][i] & 0xff) << 24);
+ dispc_reg_out(cam, DISPC_VID_FIR_COEF_HV(v, i), reg);
+ }
+}
+
+static void
+omap24xxcam_configure_overlay(struct omap24xxcam_device *cam,
+ struct omap24xx_vid2_format *vid2_format)
+{
+ int v;
+ struct v4l2_window *win = &cam->win;
+ struct v4l2_rect *crop = &cam->crop;
+ struct v4l2_pix_format *pix;
+ struct v4l2_framebuffer *fbuf = &cam->fbuf;
+ int vid_position_x, vid_position_y;
+ unsigned long vid_position, vid_size, vid_picture_size;
+ unsigned long vid_attributes;
+ unsigned long firvinc, firhinc;
+ /* color space conversion matrices */
+ const static short int cc_bt601[3][3] = {
+ {298, 409, 0},
+ {298, -208, -100},
+ {298, 0, 517}
+ };
+ const static short int cc_bt709[3][3] = {
+ {298, 459, 0},
+ {298, -137, -55},
+ {298, 0, 541}
+ };
+ const static short int cc_bt601_full[3][3] = {
+ {256, 351, 0},
+ {256, -179, -86},
+ {256, 0, 443}
+ };
+ /* vertical resizing matrix */
+ const static short int vc[3][8] = {
+ {0, 3, 12, 32, 0, 7, 5, 2},
+ {128, 123, 111, 89, 64, 89, 111, 123},
+ {0, 2, 5, 7, 64, 32, 12, 3}
+ };
+ /* horizontal resizing matrix */
+ const static short int hc[5][8] = {
+ {0, -1, -2, -5, 0, -2, -1, 0},
+ {0, 13, 30, 51, -9, -11, -11, -8},
+ {128, 124, 112, 95, 73, 95, 112, 124},
+ {0, -8, -11, -11, 73, 51, 30, 13},
+ {0, 0, -1, -2, -9, -5, -2, -1}
+ };
+
+ DBG;
+
+ if (vid2_format) {
+ pix = &vid2_format->pix;
+ v = cam->vid2;
+ } else {
+ pix = &cam->pix;
+ v = cam->vid1;
+ }
+ /* make sure the video overlay is disabled before we reconfigure it */
+ omap24xxcam_disable_vlayer(cam, v);
+
+ /* configure the video attributes register */
+ vid_attributes = 0;
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDFORMAT_YUV2;
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDCOLORCONVENABLE;
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDFORMAT_UYVY;
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDCOLORCONVENABLE;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ default:
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDFORMAT_RGB16;
+ vid_attributes |= ((cam->gfx_attributes &
+ DISPC_GFX_ATTRIBUTES_GFXREPLICATIONENABLE)
+ << 5);
+ break;
+ case V4L2_PIX_FMT_RGB565X:
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDFORMAT_RGB16;
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDENDIANNESS;
+ vid_attributes |= ((cam->gfx_attributes &
+ DISPC_GFX_ATTRIBUTES_GFXREPLICATIONENABLE)
+ << 5);
+ break;
+ }
+ if (cam->gfx_attributes & DISPC_GFX_ATTRIBUTES_GFXCHANNELOUT)
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDCHANNELOUT;
+ vid_attributes |= ((cam->gfx_attributes
+ & DISPC_GFX_ATTRIBUTES_GFXBURSTSIZE) << 8);
+ switch (pix->colorspace) {
+ case V4L2_COLORSPACE_SMPTE170M:
+ case V4L2_COLORSPACE_SMPTE240M:
+ case V4L2_COLORSPACE_BT878:
+ case V4L2_COLORSPACE_470_SYSTEM_M:
+ case V4L2_COLORSPACE_470_SYSTEM_BG:
+ /* luma (Y) range lower limit is 16, BT.601 standard */
+ omap24xxcam_set_colorconv(cam, cc_bt601, v);
+ break;
+ case V4L2_COLORSPACE_REC709:
+ /* luma (Y) range lower limit is 16, BT.709 standard */
+ omap24xxcam_set_colorconv(cam, cc_bt709, v);
+ break;
+ case V4L2_COLORSPACE_JPEG:
+ case V4L2_COLORSPACE_SRGB:
+ /* full luma (Y) range, assume BT.601 standard */
+ vid_attributes |= DISPC_VID_ATTRIBUTES_VIDFULLRANGE;
+ omap24xxcam_set_colorconv(cam, cc_bt601_full, v);
+ break;
+ }
+ if (!vid2_format) { /* use win and crop if it is for overlay */
+ if (win->w.width != crop->width) {
+ vid_attributes |=
+ DISPC_VID_ATTRIBUTES_VIDRESIZEENABLE_HRESIZE;
+ if (win->w.width < crop->width)
+ vid_attributes |=
+ DISPC_VID_ATTRIBUTES_VIDHRESIZECONF;
+ }
+ if (win->w.height != crop->height) {
+ vid_attributes |=
+ DISPC_VID_ATTRIBUTES_VIDRESIZEENABLE_VRESIZE;
+ if (win->w.height < crop->height)
+ vid_attributes |=
+ DISPC_VID_ATTRIBUTES_VIDVRESIZECONF;
+ }
+ }
+ dispc_reg_out(cam, DISPC_VID_ATTRIBUTES(v), vid_attributes);
+
+ /* configure transparency color key */
+ if (fbuf->flags & V4L2_FBUF_FLAG_CHROMAKEY) {
+ /* enable chromakey */
+ if (vid_attributes & DISPC_VID_ATTRIBUTES_VIDCHANNELOUT) {
+ /* digital output channel */
+ dispc_reg_out(cam, DISPC_TRANS_COLOR1, win->chromakey);
+ dispc_reg_merge(cam, DISPC_CONFIG,
+ DISPC_CONFIG_TCKDIGENABLE,
+ DISPC_CONFIG_TCKDIGSELECTION
+ | DISPC_CONFIG_TCKDIGENABLE);
+ } else {
+ /* LCD */
+ dispc_reg_out(cam, DISPC_TRANS_COLOR0, win->chromakey);
+ dispc_reg_merge(cam, DISPC_CONFIG,
+ DISPC_CONFIG_TCKLCDENABLE,
+ DISPC_CONFIG_TCKLCDSELECTION
+ | DISPC_CONFIG_TCKLCDENABLE);
+ }
+ } else {
+ /* disable chromakey */
+ if (vid_attributes & DISPC_VID_ATTRIBUTES_VIDCHANNELOUT) {
+ /* digital output channel */
+ dispc_reg_merge(cam, DISPC_CONFIG, 0,
+ DISPC_CONFIG_TCKDIGSELECTION
+ | DISPC_CONFIG_TCKDIGENABLE);
+ } else {
+ /* LCD */
+ dispc_reg_merge(cam, DISPC_CONFIG, 0,
+ DISPC_CONFIG_TCKLCDSELECTION
+ | DISPC_CONFIG_TCKLCDENABLE);
+ }
+ }
+
+ /* initialize the resizing filter */
+ omap24xxcam_set_resize(cam, vc, hc, v);
+
+ if (!vid2_format) { /* use win and crop if it is for overlay */
+ dispc_reg_out(cam, DISPC_VID_ACCU0(v), 0);
+ dispc_reg_out(cam, DISPC_VID_ACCU1(v), 0);
+ firhinc = (1024 * (crop->width - 1)) / (win->w.width - 1);
+ if (firhinc < 1)
+ firhinc = 1;
+ else if (firhinc > 2047)
+ firhinc = 2047;
+ firvinc = (1024 * (crop->height - 1)) / (win->w.height - 1);
+ if (firvinc < 1)
+ firvinc = 1;
+ else if (firvinc > 2047)
+ firvinc = 2047;
+ dispc_reg_out(cam, DISPC_VID_FIR(v), firhinc | (firvinc << 16));
+
+ /* configure the target window on the display */
+ vid_position_x = cam->gfx_position_x + win->w.left;
+ vid_position_y = cam->gfx_position_y + win->w.top;
+ vid_size =
+ (((win->w.width - 1) << DISPC_VID_SIZE_VIDSIZEX_SHIFT)
+ & DISPC_VID_SIZE_VIDSIZEX)
+ | (((win->w.height - 1) << DISPC_VID_SIZE_VIDSIZEY_SHIFT)
+ & DISPC_VID_SIZE_VIDSIZEY);
+
+ /* configure the source window in the framebuffer */
+ vid_picture_size =
+ (((crop->width -
+ 1) << DISPC_VID_PICTURE_SIZE_VIDORGSIZEX_SHIFT)
+ & DISPC_VID_PICTURE_SIZE_VIDORGSIZEX)
+ |
+ (((crop->height -
+ 1) << DISPC_VID_PICTURE_SIZE_VIDORGSIZEY_SHIFT)
+ & DISPC_VID_PICTURE_SIZE_VIDORGSIZEY);
+ dispc_reg_out(cam, DISPC_VID_ROW_INC(v),
+ 1 + pix->bytesperline - crop->width * 2);
+ } else { /* video 2 layer configuration */
+ struct v4l2_framebuffer *fbuf = &cam->fbuf;
+ int row_inc;
+ /* in video2 layer we won't be down or up scaling */
+ dispc_reg_out(cam, DISPC_VID_FIR(v), 0x400 | (0x400 << 16));
+ if (pix->width + vid2_format->left > fbuf->fmt.width) {
+ vid_position_x = fbuf->fmt.width < pix->width ? 0 :
+ cam->gfx_position_x + fbuf->fmt.width - pix->width;
+ } else {
+ vid_position_x = cam->gfx_position_x +
+ vid2_format->left;
+
+ }
+
+ if (pix->height + vid2_format->top > fbuf->fmt.height) {
+ vid_position_y = fbuf->fmt.height < pix->height ? 0 :
+ cam->gfx_position_y +
+ fbuf->fmt.height - pix->height;
+ } else {
+ vid_position_y = cam->gfx_position_y + vid2_format->top;
+ }
+
+ vid_size = ((((pix->width > fbuf->fmt.width ? fbuf->fmt.width
+ : pix->width) - 1)
+ << DISPC_VID_SIZE_VIDSIZEX_SHIFT)
+ & DISPC_VID_SIZE_VIDSIZEX)
+ | ((((pix->height > fbuf->fmt.height ? fbuf->fmt.height
+ : pix->height) - 1) << DISPC_VID_SIZE_VIDSIZEY_SHIFT)
+ & DISPC_VID_SIZE_VIDSIZEY);
+ vid_picture_size = vid_size;
+ row_inc = ((pix->width -
+ ((vid_size >> DISPC_VID_SIZE_VIDSIZEX_SHIFT)
+ & DISPC_VID_SIZE_VIDSIZEX)) * 2)
+ - 1;
+ /* we are subtracting 1 instead of adding because vid_size
+ ** is 1 less than the pix width
+ */
+ dispc_reg_out(cam, DISPC_VID_ROW_INC(v), row_inc);
+ }
+ vid_position = ((vid_position_x << DISPC_VID_POSITION_VIDPOSX_SHIFT)
+ & DISPC_VID_POSITION_VIDPOSX)
+ | ((vid_position_y << DISPC_VID_POSITION_VIDPOSY_SHIFT)
+ & DISPC_VID_POSITION_VIDPOSY);
+ dispc_reg_out(cam, DISPC_VID_POSITION(v), vid_position);
+ dispc_reg_out(cam, DISPC_VID_SIZE(v), vid_size);
+ dispc_reg_out(cam, DISPC_VID_PICTURE_SIZE(v), vid_picture_size);
+ dispc_reg_out(cam, DISPC_VID_PIXEL_INC(v), 1);
+
+ if (vid2_format) {
+ unsigned long vid2_base_phys;
+ vid2_base_phys = cam->video2_base_phys;
+ //+ pix->bytesperline*crop->top + crop->left*2;
+ dispc_reg_out(cam, DISPC_VID_BA0(v), vid2_base_phys);
+ dispc_reg_out(cam, DISPC_VID_BA1(v), vid2_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);
+ }
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Start a DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully started, or non-zero if all
+ * DMA channels are already in use or starting is currently inhibited.
+ */
+int
+omap24xxcam_dma_start(struct omap24xxcam_device *cam, dma_addr_t start,
+ unsigned long len, dma_callback_t callback, void *arg)
+{
+ unsigned long irqflags;
+ int dmach;
+ void (*dma_notify)(struct omap24xxcam_device *cam);
+
+ DBG;
+
+ spin_lock_irqsave(&cam->dma_lock, irqflags);
+
+ if (!cam->free_dmach || cam->dma_stop) {
+ spin_unlock_irqrestore(&cam->dma_lock, irqflags);
+ DBG_MID(3);
+ return -EBUSY;
+ }
+
+ dmach = cam->next_dmach;
+
+ cam->camdma[dmach].callback = callback;
+ cam->camdma[dmach].arg = arg;
+
+ camdma_reg_out(cam, CAMDMA_CCR(dmach),
+ CAMDMA_CCR_SEL_SRC_DST_SYNC
+ | CAMDMA_CCR_BS
+ | CAMDMA_CCR_DST_AMODE_POST_INC
+ | CAMDMA_CCR_SRC_AMODE_POST_INC
+ | CAMDMA_CCR_FS
+ | CAMDMA_CCR_WR_ACTIVE
+ | CAMDMA_CCR_RD_ACTIVE
+ | CAMDMA_CCR_SYNCHRO_CAMERA);
+ camdma_reg_out(cam, CAMDMA_CLNK_CTRL(dmach), 0);
+ camdma_reg_out(cam, CAMDMA_CEN(dmach), len);
+ camdma_reg_out(cam, CAMDMA_CFN(dmach), 1);
+ camdma_reg_out(cam, CAMDMA_CSDP(dmach),
+ CAMDMA_CSDP_WRITE_MODE_POSTED
+ | CAMDMA_CSDP_DST_BURST_EN_64
+ | CAMDMA_CSDP_DST_PACKED
+ | CAMDMA_CSDP_SRC_BURST_EN_64
+ | CAMDMA_CSDP_SRC_PACKED
+ | CAMDMA_CSDP_DATA_TYPE_8BITS);
+ camdma_reg_out(cam, CAMDMA_CSSA(dmach), 0);
+ camdma_reg_out(cam, CAMDMA_CDSA(dmach), start);
+ camdma_reg_out(cam, CAMDMA_CSEI(dmach), 0);
+ camdma_reg_out(cam, CAMDMA_CSFI(dmach), DMA_THRESHOLD);
+ camdma_reg_out(cam, CAMDMA_CDEI(dmach), 0);
+ camdma_reg_out(cam, CAMDMA_CDFI(dmach), 0);
+ camdma_reg_out(cam, CAMDMA_CSR(dmach),
+ CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR
+ | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR
+ | CAMDMA_CSR_BLOCK
+ | CAMDMA_CSR_DROP);
+ camdma_reg_out(cam, CAMDMA_CICR(dmach),
+ CAMDMA_CICR_MISALIGNED_ERR_IE
+ | CAMDMA_CICR_SUPERVISOR_ERR_IE
+ | CAMDMA_CICR_SECURE_ERR_IE
+ | CAMDMA_CICR_TRANS_ERR_IE
+ | CAMDMA_CICR_BLOCK_IE
+ | CAMDMA_CICR_DROP_IE);
+
+ /* We're ready to start the DMA transfer. */
+
+ if (cam->free_dmach < NUM_CAMDMA_CHANNELS) {
+ /* A transfer is already in progress, so try to chain to it. */
+ int prev_dmach, ch;
+
+ if (dmach == 0)
+ prev_dmach = NUM_CAMDMA_CHANNELS - 1;
+ else
+ prev_dmach = dmach - 1;
+ camdma_reg_out(cam, CAMDMA_CLNK_CTRL(prev_dmach),
+ CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach);
+ /* Did we chain the DMA transfer before the previous one
+ * finished?
+ */
+ ch = (dmach + cam->free_dmach) % NUM_CAMDMA_CHANNELS;
+ DBG_MID(1);
+ while (!(camdma_reg_in(cam, CAMDMA_CCR(ch))
+ & CAMDMA_CCR_ENABLE))
+ {
+ if (ch == dmach) {
+ /* The previous transfer has ended and this one
+ * hasn't started, so we must not have chained
+ * to the previous one in time. We'll have to
+ * start it now.
+ */
+ camdma_reg_out(cam, CAMDMA_CCR(dmach),
+ CAMDMA_CCR_SEL_SRC_DST_SYNC
+ | CAMDMA_CCR_BS
+ | CAMDMA_CCR_DST_AMODE_POST_INC
+ | CAMDMA_CCR_SRC_AMODE_POST_INC
+ | CAMDMA_CCR_ENABLE
+ | CAMDMA_CCR_FS
+ | CAMDMA_CCR_SYNCHRO_CAMERA);
+ break;
+ } else
+ ch = (ch + 1) % NUM_CAMDMA_CHANNELS;
+ }
+ DBG_MID(2);
+ }
+ else {
+ /* No transfer is in progress, so we'll just start this one
+ * now.
+ */
+ camdma_reg_out(cam, CAMDMA_CCR(dmach),
+ CAMDMA_CCR_SEL_SRC_DST_SYNC
+ | CAMDMA_CCR_BS
+ | CAMDMA_CCR_DST_AMODE_POST_INC
+ | CAMDMA_CCR_SRC_AMODE_POST_INC
+ | CAMDMA_CCR_ENABLE
+ | CAMDMA_CCR_FS
+ | CAMDMA_CCR_SYNCHRO_CAMERA);
+ }
+
+ cam->next_dmach = (cam->next_dmach + 1) % NUM_CAMDMA_CHANNELS;
+ cam->free_dmach--;
+
+ dma_notify = cam->dma_notify;
+ cam->dma_notify = NULL;
+
+ spin_unlock_irqrestore(&cam->dma_lock, irqflags);
+
+ if (dma_notify)
+ (*dma_notify)(cam);
+
+ DBG_END;
+
+ return 0;
+}
+
+/* DMA completion routine for the scatter-gather DMA fragments. */
+static void
+omap24xxcam_sg_dma_callback(struct omap24xxcam_device *cam, unsigned long csr,
+ void *arg)
+{
+ int sgslot = (int)arg;
+ struct sgdma_state *sgdma;
+ const unsigned long csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ DBG;
+
+ spin_lock(&cam->sg_lock);
+
+ sgdma = cam->sgdma + sgslot;
+ if (!sgdma->queued_sglist) {
+ spin_unlock(&cam->sg_lock);
+ printk(KERN_DEBUG CAM_NAME
+ ": sgdma completed when none queued!\n");
+ return;
+ }
+
+ sgdma->csr |= csr;
+ if (!--sgdma->queued_sglist) {
+ /* Queue for this sglist is empty, so check to see if we're
+ * done.
+ */
+ if ((sgdma->next_sglist == sgdma->sglen)
+ || (sgdma->csr & csr_error)) {
+ dma_callback_t callback = sgdma->callback;
+ void *arg = sgdma->arg;
+ unsigned long sg_csr = sgdma->csr;
+ /* All done with this sglist */
+ cam->free_sgdma++;
+ if (callback) {
+ spin_unlock(&cam->sg_lock);
+ (*callback) (cam, sg_csr, arg);
+ return;
+ }
+ }
+ }
+
+ spin_unlock(&cam->sg_lock);
+}
+
+/* Process the scatter-gather DMA queue by starting queued transfers. */
+static void omap24xxcam_sg_dma_process(struct omap24xxcam_device *cam)
+{
+ unsigned long irqflags;
+ int queued_sgdma, sgslot;
+ struct sgdma_state *sgdma;
+ const unsigned long csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ DBG;
+
+ spin_lock_irqsave(&cam->sg_lock, irqflags);
+
+ queued_sgdma = NUM_SG_DMA - cam->free_sgdma;
+ sgslot = (cam->next_sgdma + cam->free_sgdma) % NUM_SG_DMA;
+ while (queued_sgdma > 0) {
+ sgdma = cam->sgdma + sgslot;
+ while ((sgdma->next_sglist < sgdma->sglen) &&
+ !(sgdma->csr & csr_error)) {
+ const struct scatterlist *sglist;
+
+ sglist = sgdma->sglist + sgdma->next_sglist;
+ /* try to start the next DMA transfer */
+ if (omap24xxcam_dma_start(cam, sg_dma_address(sglist),
+ sg_dma_len(sglist),
+ omap24xxcam_sg_dma_callback,
+ (void *)sgslot)) {
+ /* DMA start failed */
+ spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+ return;
+ } else {
+ /* DMA start was successful */
+ sgdma->next_sglist++;
+ sgdma->queued_sglist++;
+ }
+ }
+ queued_sgdma--;
+ sgslot = (sgslot + 1) % NUM_SG_DMA;
+ }
+
+ spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+ DBG_END;
+}
+
+/* Queue a scatter-gather DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully queued, or
+ * non-zero if all of the scatter-gather slots are already in use.
+ */
+static int
+omap24xxcam_sg_dma_queue(struct omap24xxcam_device *cam,
+ const struct scatterlist *sglist, int sglen,
+ dma_callback_t callback, void *arg)
+{
+ unsigned long irqflags;
+ struct sgdma_state *sgdma;
+
+ DBG;
+
+ if ((sglen < 0) || ((sglen > 0) & !sglist))
+ return -EINVAL;
+
+ spin_lock_irqsave(&cam->sg_lock, irqflags);
+
+ if (!cam->free_sgdma) {
+ spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+ return -EBUSY;
+ }
+
+ sgdma = cam->sgdma + cam->next_sgdma;
+
+ sgdma->sglist = sglist;
+ sgdma->sglen = sglen;
+ sgdma->next_sglist = 0;
+ sgdma->queued_sglist = 0;
+ sgdma->csr = 0;
+ sgdma->callback = callback;
+ sgdma->arg = arg;
+
+ cam->next_sgdma = (cam->next_sgdma + 1) % NUM_SG_DMA;
+ cam->free_sgdma--;
+
+ spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+
+ omap24xxcam_sg_dma_process(cam);
+
+ return 0;
+}
+
+/* Abort all chained DMA transfers. After all transfers have been aborted and
+ * the DMA controller is idle, the completion routines for any aborted transfers
+ * will be called in sequence. The DMA controller may not be idle after this
+ * routine completes, because the completion routines might start new transfers.
+ */
+static void
+omap24xxcam_dma_abort(struct omap24xxcam_device *cam, unsigned long csr)
+{
+ unsigned long irqflags;
+ int dmach, i, free_dmach;
+ dma_callback_t callback;
+ void *arg;
+
+ DBG;
+
+ spin_lock_irqsave(&cam->dma_lock, irqflags);
+
+ /* stop any DMA transfers in progress */
+ dmach = (cam->next_dmach + cam->free_dmach) % NUM_CAMDMA_CHANNELS;
+ for (i = 0; i < NUM_CAMDMA_CHANNELS; i++) {
+ /* mask all interrupts from this channel */
+ camdma_reg_out(cam, CAMDMA_CICR(dmach), 0);
+ /* unlink this channel */
+ camdma_reg_merge(cam, CAMDMA_CLNK_CTRL(dmach), 0,
+ CAMDMA_CLNK_CTRL_ENABLE_LNK);
+ /* disable this channel */
+ camdma_reg_merge(cam, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE);
+ dmach = (dmach + 1) % NUM_CAMDMA_CHANNELS;
+ }
+
+ /* We have to be careful here because the callback routine might start
+ * a new DMA transfer, and we only want to abort transfers that were
+ * started before this routine was called.
+ */
+ free_dmach = cam->free_dmach;
+ while ((cam->free_dmach < NUM_CAMDMA_CHANNELS) &&
+ (free_dmach < NUM_CAMDMA_CHANNELS)) {
+ dmach = (cam->next_dmach + cam->free_dmach)
+ % NUM_CAMDMA_CHANNELS;
+ callback = cam->camdma[dmach].callback;
+ arg = cam->camdma[dmach].arg;
+ cam->free_dmach++;
+ free_dmach++;
+ if (callback) {
+ /* leave interrupts disabled during callback */
+ spin_unlock(&cam->dma_lock);
+ (*callback) (cam, csr, arg);
+ spin_lock(&cam->dma_lock);
+ }
+ }
+
+ spin_unlock_irqrestore(&cam->dma_lock, irqflags);
+}
+
+/* Abort all chained DMA transfers. After all transfers have been aborted and
+ * the DMA controller is idle, the completion routines for any aborted transfers
+ * will be called in sequence. If the completion routines attempt to start a
+ * new DMA transfer it will fail, so the DMA controller will be idle after this
+ * routine completes.
+ */
+static void
+omap24xxcam_dma_stop(struct omap24xxcam_device *cam, unsigned long csr)
+{
+ unsigned long irqflags;
+
+ DBG;
+
+ spin_lock_irqsave(&cam->dma_lock, irqflags);
+ cam->dma_stop++;
+ spin_unlock_irqrestore(&cam->dma_lock, irqflags);
+ omap24xxcam_dma_abort(cam, csr);
+ spin_lock_irqsave(&cam->dma_lock, irqflags);
+ cam->dma_stop--;
+ spin_unlock_irqrestore(&cam->dma_lock, irqflags);
+}
+
+/* Sync scatter-gather DMA by aborting any DMA transfers currently in progress.
+ * Any queued scatter-gather DMA transactions that have not yet been started
+ * will remain queued. The DMA controller will be idle after this routine
+ * completes. When the scatter-gather queue is restarted, the next
+ * scatter-gather DMA transfer will begin at the start of a new transaction.
+ */
+static void
+omap24xxcam_sg_dma_sync(struct omap24xxcam_device *cam, unsigned long csr)
+{
+ unsigned long irqflags;
+ int sgslot;
+ struct sgdma_state *sgdma;
+
+ DBG;
+
+ /* stop any DMA transfers in progress */
+ omap24xxcam_dma_stop(cam, csr);
+
+ spin_lock_irqsave(&cam->sg_lock, irqflags);
+
+ if (cam->free_sgdma < NUM_SG_DMA) {
+ sgslot = (cam->next_sgdma + cam->free_sgdma) % NUM_SG_DMA;
+ sgdma = cam->sgdma + sgslot;
+ if (sgdma->next_sglist != 0) {
+ /* This DMA transfer was in progress, so abort it. */
+ dma_callback_t callback = sgdma->callback;
+ void *arg = sgdma->arg;
+ cam->free_sgdma++;
+ if (callback) {
+ /* leave interrupts masked */
+ spin_unlock(&cam->sg_lock);
+ (*callback) (cam, csr, arg);
+ spin_lock(&cam->sg_lock);
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+}
+
+/* This routine is not needed at the moment, but we'll keep it around just in
+ * case.
+ */
+#if 0
+/* Stop the DMA controller, aborting any DMA transfers in progress. Any queued
+ * scatter-gather DMA transactions are cancelled. The DMA controller will be
+ * idle after this routine completes, and the scatter-gather DMA queue will
+ * be empty. csr is the completion status passed to the completion routines
+ * for any DMA transfers that are aborted. It should have at least one error
+ * bit set.
+ */
+static void
+omap24xxcam_sg_dma_stop(struct omap24xxcam_device *cam, unsigned long csr)
+{
+ unsigned long irqflags;
+ int queued_sgdma, sgslot;
+ struct sgdma_state *sgdma;
+ dma_callback_t callback;
+ void *arg;
+
+ /* stop any DMA transfers in progress */
+ omap24xxcam_dma_stop(cam, csr);
+
+ spin_lock_irqsave(&cam->sg_lock, irqflags);
+
+ queued_sgdma = NUM_SG_DMA - cam->free_sgdma;
+ sgslot = (cam->next_sgdma + cam->free_sgdma) % NUM_SG_DMA;
+ while (queued_sgdma > 0) {
+ sgdma = cam->sgdma + sgslot;
+ callback = sgdma->callback;
+ arg = sgdma->arg;
+ cam->free_sgdma++;
+ sgdma->queued_sglist = 0;
+ if (callback) {
+ /* leave interrupts masked */
+ spin_unlock(&cam->sg_lock);
+ (*callback) (cam, csr, arg);
+ spin_lock(&cam->sg_lock);
+ }
+ queued_sgdma--;
+ sgslot = (sgslot + 1) % NUM_SG_DMA;
+ }
+
+ spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+}
+#endif /* if 0 */
+
+/* Register a routine to be called once immediately after a DMA transfer is
+ * started. The purpose of this is to allow the camera interface to be
+ * started only after a DMA transaction has been queued in order to avoid
+ * DMA overruns. The registered callback routine will only be called one
+ * time and then discarded. Only one callback routine may be registered at a
+ * time.
+ * Returns zero if successful, or a non-zero error code if a different callback
+ * routine has already been registered.
+ */
+static int
+omap24xxcam_dma_notify(struct omap24xxcam_device *cam,
+ void (*callback) (struct omap24xxcam_device * cam))
+{
+ unsigned long irqflags;
+
+ DBG;
+
+ spin_lock_irqsave(&cam->dma_lock, irqflags);
+
+ if (cam->dma_notify && (cam->dma_notify != callback)) {
+ spin_unlock_irqrestore(&cam->dma_lock, irqflags);
+ return -EBUSY;
+ }
+
+ cam->dma_notify = callback;
+
+ spin_unlock_irqrestore(&cam->dma_lock, irqflags);
+
+ return 0;
+}
+
+/* Camera DMA interrupt service routine. */
+static void omap24xxcam_dma_isr(struct omap24xxcam_device *cam)
+{
+ int dmach, i;
+ dma_callback_t callback;
+ void *arg;
+ unsigned long csr;
+ const unsigned long csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ spin_lock(&cam->dma_lock);
+
+ if (cam->free_dmach == NUM_CAMDMA_CHANNELS) {
+ /* A camera DMA interrupt occurred while all channels are idle,
+ * so we'll acknowledge the interrupt in the IRQSTATUS register
+ * and exit.
+ */
+ for (i = 0; i< 4; ++i) {
+ csr = camdma_reg_in(cam, CAMDMA_CSR(i));
+ /* ack interrupt in CSR */
+ camdma_reg_out(cam, CAMDMA_CSR(i), csr);
+ }
+ camdma_reg_out(cam, CAMDMA_IRQSTATUS_L0, 0xffffffff);
+ spin_unlock(&cam->dma_lock);
+ return;
+ }
+
+ while (cam->free_dmach < NUM_CAMDMA_CHANNELS) {
+ dmach = (cam->next_dmach + cam->free_dmach)
+ % NUM_CAMDMA_CHANNELS;
+ if (camdma_reg_in(cam, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE) {
+ /* This buffer hasn't finished yet, so we're done. */
+ break;
+ }
+ csr = camdma_reg_in(cam, CAMDMA_CSR(dmach));
+ /* ack interrupt in CSR */
+ camdma_reg_out(cam, CAMDMA_CSR(dmach), csr);
+ /* ack interrupt in IRQSTATUS */
+ camdma_reg_out(cam, CAMDMA_IRQSTATUS_L0, (1 << dmach));
+ if (csr & csr_error) {
+ /* A DMA error occurred, so stop all DMA transfers in
+ * progress.
+ */
+ spin_unlock(&cam->dma_lock);
+ omap24xxcam_dma_stop(cam, csr);
+ return;
+ } else {
+ callback = cam->camdma[dmach].callback;
+ arg = cam->camdma[dmach].arg;
+ cam->free_dmach++;
+ if (callback) {
+ spin_unlock(&cam->dma_lock);
+ (*callback) (cam, csr, arg);
+ spin_lock(&cam->dma_lock);
+ }
+ }
+ }
+
+ spin_unlock(&cam->dma_lock);
+
+ omap24xxcam_sg_dma_process(cam);
+}
+
+/* Shutdown the camera DMA driver and controller. */
+static void omap24xxcam_dma_exit(struct omap24xxcam_device *cam)
+{
+ int ch;
+
+ DBG;
+
+ /* Mask all DMA interrupts */
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L0, 0);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L1, 0);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L2, 0);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L3, 0);
+
+ /* disable all DMA channels */
+ for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++)
+ camdma_reg_out(cam, CAMDMA_CCR(ch), 0);
+}
+
+/* Initialize the camera DMA driver. */
+static void omap24xxcam_dma_init(struct omap24xxcam_device *cam)
+{
+ int ch, sg;
+
+ DBG;
+
+ /* group all channels on DMA IRQ0 and unmask irq */
+
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L0, 0xffffffff);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L1, 0);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L2, 0);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L3, 0);
+
+ spin_lock_init(&cam->dma_lock);
+ cam->free_dmach = NUM_CAMDMA_CHANNELS;
+ cam->next_dmach = 0;
+ for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++) {
+ cam->camdma[ch].callback = NULL;
+ cam->camdma[ch].arg = NULL;
+ }
+
+ spin_lock_init(&cam->sg_lock);
+ cam->free_sgdma = NUM_SG_DMA;
+ cam->next_sgdma = 0;
+ for (sg = 0; sg < NUM_SG_DMA; sg++) {
+ cam->sgdma[sg].sglen = 0;
+ cam->sgdma[sg].next_sglist = 0;
+ cam->sgdma[sg].queued_sglist = 0;
+ cam->sgdma[sg].csr = 0;
+ cam->sgdma[sg].callback = NULL;
+ cam->sgdma[sg].arg = NULL;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Callback routine for overlay DMA completion. We just start another DMA
+ * transfer unless overlay has been turned off.
+ */
+static void
+omap24xxcam_overlay_callback(struct omap24xxcam_device *cam, unsigned long csr,
+ void *arg)
+{
+ int err;
+ unsigned long irqflags;
+ const unsigned long csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ DBG;
+
+ spin_lock_irqsave(&cam->overlay_lock, irqflags);
+
+ if (cam->overlay_cnt > 0)
+ --cam->overlay_cnt;
+
+ if (!cam->previewing || (csr & csr_error)) {
+ printk(KERN_INFO CAM_NAME
+ ": overlay_callback error. csr = 0x%08x\n", (u16)csr);
+ spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
+ return;
+ }
+
+ sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;
+ sg_dma_len(&cam->overlay_sglist) = cam->pix.sizeimage;
+
+ while (cam->overlay_cnt < 2) {
+ err = omap24xxcam_sg_dma_queue(cam, &cam->overlay_sglist, 1,
+ omap24xxcam_overlay_callback,
+ NULL);
+ if (err)
+ break;
+ ++cam->overlay_cnt;
+ }
+
+ spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
+}
+
+/* Begin DMA'ing into the camera overlay framebuffer. We queue up two DMA
+ * transfers so that all frames will be captured.
+ */
+static void omap24xxcam_start_overlay_dma(struct omap24xxcam_device *cam)
+{
+ int err;
+ unsigned long irqflags;
+
+ DBG;
+
+ if (!cam->previewing)
+ return;
+
+ if (cam->pix.sizeimage > cam->overlay_size)
+ return;
+
+ spin_lock_irqsave(&cam->overlay_lock, irqflags);
+
+ sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;
+ sg_dma_len(&cam->overlay_sglist) = cam->pix.sizeimage;
+
+ while (cam->overlay_cnt < 2) {
+ err = omap24xxcam_sg_dma_queue(cam, &cam->overlay_sglist, 1,
+ omap24xxcam_overlay_callback,
+ NULL);
+ if (err)
+ break;
+ ++cam->overlay_cnt;
+ }
+
+ spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
+}
+
+/* Enable the camera core interface. */
+static void omap24xxcam_cc_enable(struct omap24xxcam_device *cam)
+{
+ DBG;
+ /* Get the CC_CTRL register value for the current capture format. */
+ omap24xxcam_sensor_cc_ctrl(cam);
+
+ /* program the camera interface DMA packet size */
+ cc_reg_out(cam, CC_CTRL_DMA, CC_CTRL_DMA_EN | (DMA_THRESHOLD / 4 - 1));
+
+ /* enable camera core error interrupts */
+ cc_reg_out(cam, CC_IRQENABLE, CC_IRQENABLE_FW_ERR_IRQ
+ | CC_IRQENABLE_FSC_ERR_IRQ | CC_IRQENABLE_SSC_ERR_IRQ
+ | CC_IRQENABLE_FIFO_OF_IRQ /*| CC_IRQENABLE_FIFO_FULL_IRQ */
+ );
+
+ /* enable the camera interface */
+ cc_reg_out(cam, CC_CTRL, cam->cc_ctrl | CC_CTRL_CC_EN);
+}
+
+/* Error recovery for DMA errors and camera interface errors. */
+static void omap24xxcam_error_handler(struct omap24xxcam_device *cam)
+{
+ DBG;
+ /* Get the CC_CTRL register value for the current capture format. */
+ omap24xxcam_sensor_cc_ctrl(cam);
+
+ /* Disable and reset the camera interface. */
+ cc_reg_out(cam, CC_CTRL,
+ cam->cc_ctrl & ~(CC_CTRL_CC_EN | CC_CTRL_CC_FRAME_TRIG));
+ cc_reg_out(cam, CC_CTRL, (cam->cc_ctrl | CC_CTRL_CC_RST)
+ & ~(CC_CTRL_CC_EN | CC_CTRL_CC_FRAME_TRIG));
+
+ /* Stop the DMA controller and frame sync scatter-gather DMA. */
+ omap24xxcam_sg_dma_sync(cam, CAMDMA_CSR_TRANS_ERR);
+
+#if 1
+ /* Reset and re-initialize the entire camera subsystem.
+ * Resetting the camera FIFO via the CC_RST bit in the CC_CTRL
+ * register is supposed to be sufficient to recover from a
+ * camera interface error, but it doesn't seem to be enough. If
+ * we only do that then subsequent image captures are out of sync
+ * by either one or two times DMA_THRESHOLD bytes. Resetting and
+ * re-initializing the entire camera subsystem prevents the problem
+ * with frame synchronization. Calling cam_init() from an ISR is
+ * undesirable since it waits an indeterminate amount of time for the
+ * camera subsystem reset to complete. If we ever figure out exactly
+ * what needs to be reset to recover from a camera interface error,
+ * maybe we can replace this global reset with something less drastic.
+ */
+ cam_init(cam);
+ omap24xxcam_set_xclk(cam);
+ /* group all channels on DMA IRQ0 and unmask irq */
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L0, 0xffffffff);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L1, 0);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L2, 0);
+ camdma_reg_out(cam, CAMDMA_IRQENABLE_L3, 0);
+#endif
+
+ if (cam->previewing || cam->streaming) {
+ /* Preview or capture is in progress, so we need to register
+ * our routine to restart the camera interface the next time a
+ * DMA transfer is queued.
+ */
+ omap24xxcam_dma_notify(cam, omap24xxcam_cc_enable);
+ }
+
+ /* Restart overlay DMA if preview is enabled. */
+ omap24xxcam_start_overlay_dma(cam);
+
+ /* Restart the scatter-gather DMA queue. */
+ omap24xxcam_sg_dma_process(cam);
+}
+
+/* Interrupt service routine for camera core interrupts. */
+static void omap24xxcam_cc_isr(struct omap24xxcam_device *cam)
+{
+ unsigned long cc_irqstatus;
+ const unsigned long cc_irqstatus_err = CC_IRQSTATUS_FW_ERR_IRQ
+ | CC_IRQSTATUS_FSC_ERR_IRQ | CC_IRQSTATUS_SSC_ERR_IRQ
+ | CC_IRQSTATUS_FIFO_OF_IRQ;
+
+ cc_irqstatus = cc_reg_in(cam, CC_IRQSTATUS);
+ cc_reg_out(cam, CC_IRQSTATUS, cc_irqstatus);
+
+ if (cc_irqstatus & cc_irqstatus_err)
+ omap24xxcam_error_handler(cam);
+}
+
+static irqreturn_t omap24xxcam_isr(int irq, void *arg, struct pt_regs *regs)
+{
+ struct omap24xxcam_device *cam = (struct omap24xxcam_device *)arg;
+ unsigned long irqstatus;
+ unsigned int irqhandled = 0;
+
+ irqstatus = cam_reg_in(cam, CAM_IRQSTATUS);
+ if (irqstatus &
+ (CAM_IRQSTATUS_DMA_IRQ2 | CAM_IRQSTATUS_DMA_IRQ1
+ | CAM_IRQSTATUS_DMA_IRQ0)) {
+ omap24xxcam_dma_isr(cam);
+ irqhandled = 1;
+ }
+ if (irqstatus & CAM_IRQSTATUS_CC_IRQ) {
+ omap24xxcam_cc_isr(cam);
+ irqhandled = 1;
+ }
+ if (irqstatus & CAM_IRQSTATUS_MMU_IRQ)
+ printk(KERN_ERR CAM_NAME ": Unhandled camera MMU interrupt!\n");
+
+ return IRQ_RETVAL(irqhandled);
+}
+
+static void omap24xxcam_adjust_xclk(struct omap24xxcam_device *cam)
+{
+ unsigned long divisor;
+
+ DBG;
+
+ if (cam->xclk > cam->mclk)
+ cam->xclk = cam->mclk;
+ divisor = cam->mclk / cam->xclk;
+ if (cam->xclk * divisor < cam->mclk)
+ divisor += 1;
+ if (divisor > 30)
+ divisor = 30;
+
+ cam->xclk = cam->mclk / divisor;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* This routine is called from interrupt context when a scatter-gather DMA
+ * transfer of a videobuf_buffer completes.
+ */
+static void
+omap24xxcam_vbq_complete(struct omap24xxcam_device *cam, unsigned long csr,
+ void *arg)
+{
+ struct videobuf_buffer *vb = (struct videobuf_buffer *)arg;
+ const unsigned long csr_error = CAMDMA_CSR_MISALIGNED_ERR
+ | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+ | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+ DBG;
+
+ spin_lock(&cam->vbq_lock);
+
+ do_gettimeofday(&vb->ts);
+ vb->field_count = cam->field_count;
+ cam->field_count += 2;
+ if (csr & csr_error) {
+ vb->state = STATE_ERROR;
+ omap24xxcam_error_handler(cam);
+ } else
+ vb->state = STATE_DONE;
+ wake_up(&vb->done);
+ spin_unlock(&cam->vbq_lock);
+}
+
+static void
+omap24xxcam_vbq_release(struct videobuf_queue *vbq, struct videobuf_buffer *vb)
+{
+ DBG;
+
+ videobuf_waiton(vb, 0, 0);
+ videobuf_dma_pci_unmap(NULL, &vb->dma);
+ videobuf_dma_free(&vb->dma);
+
+ vb->state = STATE_NEEDS_INIT;
+}
+
+/* Limit the number of available kernel image capture buffers based on the
+ * number requested, the currently selected image size, and the maximum
+ * amount of memory permitted for kernel capture buffers.
+ */
+static int
+omap24xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
+ unsigned int *size)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+ struct omap24xxcam_device *cam = fh->cam;
+
+ DBG;
+
+ if (*cnt <= 0)
+ *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
+
+ if (*cnt > VIDEO_MAX_FRAME)
+ *cnt = VIDEO_MAX_FRAME;
+
+ spin_lock(&cam->img_lock);
+
+ if (cam->still_capture && cam->cam_sensor->try_format_still_capture)
+ *size = cam->pix2.sizeimage;
+ else
+ *size = cam->pix.sizeimage;
+
+ spin_unlock(&cam->img_lock);
+
+ while (*size * *cnt > capture_mem)
+ (*cnt)--;
+
+ return 0;
+}
+
+static int
+omap24xxcam_vbq_prepare(struct videobuf_queue *vbq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ int err = 0;
+ unsigned int size;
+
+ DBG;
+
+ spin_lock(&cam->img_lock);
+ if (cam->still_capture && cam->cam_sensor->try_format_still_capture)
+ size = cam->pix2.sizeimage;
+ else
+ size = cam->pix.sizeimage;
+
+ if (vb->baddr) {
+ /* This is a userspace buffer. */
+ if (size > vb->bsize) {
+ /* The buffer isn't big enough. */
+ err = -EINVAL;
+ } else
+ vb->size = size;
+ } else if (!vb->baddr) {
+ if (vb->state != STATE_NEEDS_INIT) {
+ /* We have a kernel bounce buffer that has already been
+ * allocated.
+ */
+ if (size > vb->size) {
+ /* The image size has been changed to a larger
+ * size since this buffer was allocated, so we
+ * need to free and reallocate it.
+ */
+ spin_unlock(&cam->img_lock);
+ omap24xxcam_vbq_release(vbq, vb);
+ spin_lock(&cam->img_lock);
+ vb->size = size;
+ }
+ } else {
+ /* We need to allocate a new kernel bounce buffer. */
+ vb->size = size;
+ }
+ }
+ if (cam->still_capture && cam->cam_sensor->try_format_still_capture) {
+ vb->width = cam->pix2.width;
+ vb->height = cam->pix2.height;
+ }
+ else {
+ vb->width = cam->pix.width;
+ vb->height = cam->pix.height;
+ }
+ vb->field = field;
+
+ spin_unlock(&cam->img_lock);
+
+ if (err)
+ return err;
+
+ if (vb->state == STATE_NEEDS_INIT)
+ err = videobuf_iolock(NULL, vb, NULL);
+
+ if (!err)
+ vb->state = STATE_PREPARED;
+ else
+ omap24xxcam_vbq_release(vbq, vb);
+
+ return err;
+}
+
+static void
+omap24xxcam_vbq_queue(struct videobuf_queue *vbq, struct videobuf_buffer *vb)
+{
+ struct omap24xxcam_fh *fh = vbq->priv_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ enum videobuf_state state = vb->state;
+ int err;
+
+ DBG;
+
+ vb->state = STATE_QUEUED;
+ err = omap24xxcam_sg_dma_queue(cam, vb->dma.sglist, vb->dma.sglen,
+ omap24xxcam_vbq_complete, vb);
+ if (err) {
+ /* Oops. We're not supposed to get any errors here. The only
+ * way we could get an error is if we ran out of scatter-gather
+ * DMA slots, but we are supposed to have at least as many
+ * scatter-gather DMA slots as video buffers so that can't
+ * happen.
+ */
+ printk(KERN_DEBUG CAM_NAME
+ ": Failed to queue a video buffer for DMA!\n");
+ vb->state = state;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int
+omap24xxcam_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ void *arg)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ int err;
+
+ DBG;
+
+ switch (cmd) {
+ /* for time being below IOCTL cmd is here */
+
+ case VIDIOC_ENUMINPUT:
+ {
+ /* default handler assumes 1 video input (the camera) */
+ struct v4l2_input *input = (struct v4l2_input *)arg;
+ int index = input->index;
+
+ memset(input, 0, sizeof(*input));
+ input->index = index;
+
+ if (index > 0)
+ return -EINVAL;
+
+ strlcpy(input->name, "camera", sizeof(input->name));
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+
+ return 0;
+ }
+
+ case VIDIOC_G_INPUT:
+ {
+ unsigned int *input = arg;
+ *input = 0;
+
+ return 0;
+ }
+
+ case VIDIOC_S_INPUT:
+ {
+ unsigned int *input = arg;
+
+ if (*input > 0)
+ return -EINVAL;
+
+ return 0;
+ }
+
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap =
+ (struct v4l2_capability *)arg;
+
+ memset(cap, 0, sizeof(*cap));
+ strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
+ cap->bus_info[0] = '\0';
+ cap->version = KERNEL_VERSION(0, 0, 0);
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_VIDEO_OVERLAY |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ return 0;
+ }
+
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_STILL_CAPTURE:
+ {
+ if (cam->cam_sensor->try_format_still_capture){
+ struct v4l2_pix_format *pix =
+ &f->fmt.pix;
+ memset(pix, 0, sizeof (*pix));
+ spin_lock(&cam->img_lock);
+ *pix = cam->pix2;
+ spin_unlock(&cam->img_lock);
+ return 0;
+ }
+ /* else fall through */
+ }
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ {
+ struct v4l2_pix_format *pix =
+ &f->fmt.pix;
+ memset(pix, 0, sizeof(*pix));
+ spin_lock(&cam->img_lock);
+ *pix = cam->pix;
+ spin_unlock(&cam->img_lock);
+ return 0;
+ }
+
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ {
+ struct v4l2_window *win = &f->fmt.win;
+ memset(win, 0, sizeof(*win));
+ /* The API has a bit of a problem here.
+ * We're returning a v4l2_window
+ * structure, but that structure
+ * contains pointers to variable-sized
+ * objects for clipping rectangles and
+ * clipping bitmaps. We will just
+ * return NULLs for those pointers.
+ */
+ spin_lock(&cam->img_lock);
+ win->w = cam->win.w;
+ win->field = cam->win.field;
+ win->chromakey = cam->win.chromakey;
+ spin_unlock(&cam->img_lock);
+ return 0;
+ }
+
+ default:
+ {
+ return -EINVAL;
+ }
+ }
+ }
+
+ case VIDIOC_TRY_FMT:
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ {
+ struct v4l2_window *win = &f->fmt.win;
+
+ spin_lock(&cam->img_lock);
+ err =
+ omap24xxcam_try_preview_window(cam,
+ win);
+ spin_unlock(&cam->img_lock);
+ return err;
+ }
+
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ {
+ return cam->cam_sensor->try_format(&f->
+ fmt.
+ pix,
+ cam->
+ sensor);
+ }
+
+ default:
+ {
+ return -EINVAL;
+ }
+ }
+ }
+
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ {
+ struct v4l2_window *win = &f->fmt.win;
+
+ spin_lock(&cam->img_lock);
+ if (cam->previewing) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ }
+ err =
+ omap24xxcam_new_preview_window(cam,
+ win);
+ spin_unlock(&cam->img_lock);
+ return err;
+ }
+
+ case V4L2_BUF_TYPE_STILL_CAPTURE:
+ {
+ if (cam->cam_sensor->try_format_still_capture &&
+ cam->cam_sensor->configure_still_capture) {
+ spin_lock(&cam->img_lock);
+ cam->cam_sensor->try_format_still_capture(&f->fmt.pix,
+ cam->
+ sensor);
+ /* set the new capture format */
+ cam->pix2 = f->fmt.pix;
+ spin_unlock(&cam->img_lock);
+ err =
+ cam->cam_sensor->configure_still_capture
+ (&cam->
+ pix2,
+ cam->
+ xclk,
+ &cam->
+ cparm.
+ timeperframe,
+ cam->
+ sensor);
+ return err;
+ }
+ /* else fall through */
+ }
+
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ {
+ spin_lock(&cam->img_lock);
+ if (cam->streaming || cam->previewing) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ }
+ cam->cam_sensor->try_format(&f->fmt.pix,
+ cam->
+ sensor);
+ /* set the new capture format */
+ cam->pix = f->fmt.pix;
+ /* adjust the capture frame rate */
+ cam->xclk =
+ cam->cam_sensor->calc_xclk(&cam->
+ pix,
+ &cam->
+ nominal_timeperframe,
+ cam->
+ sensor);
+ omap24xxcam_adjust_xclk(cam);
+ cam->cparm.timeperframe =
+ cam->nominal_timeperframe;
+ /* intialize the preview parameters */
+ omap24xxcam_new_capture_format(cam);
+ spin_unlock(&cam->img_lock);
+ /* program xclk */
+ omap24xxcam_set_xclk(cam);
+ /* program the sensor */
+ err =
+ cam->cam_sensor->configure(&cam->
+ pix,
+ cam->
+ xclk,
+ &cam->
+ cparm.
+ timeperframe,
+ cam->
+ sensor);
+ return err;
+ }
+
+ default:
+ {
+ return -EINVAL;
+ }
+ }
+ }
+
+ case VIDIOC_G_FBUF:
+ {
+ struct v4l2_framebuffer *fbuf =
+ (struct v4l2_framebuffer *)arg;
+
+ spin_lock(&cam->img_lock);
+ *fbuf = cam->fbuf;
+ spin_unlock(&cam->img_lock);
+ return 0;
+ }
+
+ case VIDIOC_S_FBUF:
+ {
+ struct v4l2_framebuffer *fbuf =
+ (struct v4l2_framebuffer *)arg;
+ unsigned int flags = fbuf->flags;
+
+ /* The only field the user is allowed to change is
+ * fbuf->flags.
+ */
+ spin_lock(&cam->img_lock);
+ if (cam->previewing) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ }
+ if (flags & V4L2_FBUF_FLAG_CHROMAKEY)
+ cam->fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+ else
+ cam->fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY;
+ spin_unlock(&cam->img_lock);
+ return 0;
+ }
+
+ case VIDIOC_CROPCAP:
+ {
+ struct v4l2_cropcap *cropcap =
+ (struct v4l2_cropcap *)arg;
+ enum v4l2_buf_type type = cropcap->type;
+
+ memset(cropcap, 0, sizeof(*cropcap));
+ cropcap->type = type;
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ {
+ struct v4l2_pix_format *pix = &cam->pix;
+
+ spin_lock(&cam->img_lock);
+ cropcap->bounds.width = pix->width & ~1;
+ cropcap->bounds.height =
+ pix->height & ~1;
+ omap24xxcam_default_crop_rect(cam,
+ &cropcap->
+ defrect);
+ spin_unlock(&cam->img_lock);
+ cropcap->pixelaspect.numerator = 1;
+ cropcap->pixelaspect.denominator = 1;
+ return 0;
+ }
+
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ {
+ /* We're required to support the CROPCAP
+ * ioctl even though the G_CROP/S_CROP
+ * ioctls are optional, which seems a
+ * little strange. We don't support
+ * cropping of captured images.
+ */
+ spin_lock(&cam->img_lock);
+ cropcap->bounds.width = cam->pix.width;
+ cropcap->bounds.height =
+ cam->pix.height;
+ spin_unlock(&cam->img_lock);
+ cropcap->defrect.width =
+ cropcap->bounds.width;
+ cropcap->defrect.height =
+ cropcap->bounds.height;
+ cropcap->pixelaspect.numerator = 1;
+ cropcap->pixelaspect.denominator = 1;
+ return 0;
+ }
+
+ default:
+ {
+ return -EINVAL;
+ }
+ }
+ }
+
+ case VIDIOC_G_CROP:
+ {
+ struct v4l2_crop *crop = (struct v4l2_crop *)arg;
+
+ switch (crop->type) {
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ {
+ spin_lock(&cam->img_lock);
+ crop->c = cam->crop;
+ spin_unlock(&cam->img_lock);
+ return 0;
+ }
+
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ {
+ /* We don't support cropping of captured
+ * images.
+ */
+ return -EINVAL;
+ }
+
+ default:
+ {
+ return -EINVAL;
+ }
+ }
+ }
+
+ case VIDIOC_S_CROP:
+ {
+ struct v4l2_crop *crop = (struct v4l2_crop *)arg;
+
+ switch (crop->type) {
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ {
+ spin_lock(&cam->img_lock);
+ if (cam->previewing) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ }
+ err = omap24xxcam_new_crop_rect(cam,
+ &crop->
+ c);
+ spin_unlock(&cam->img_lock);
+ return err;
+ }
+
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ {
+ /* We don't support cropping of captured
+ * images.
+ */
+ return -EINVAL;
+ }
+
+ default:
+ {
+ return -EINVAL;
+ }
+ }
+ }
+
+ case VIDIOC_G_PARM:
+ {
+ struct v4l2_streamparm *parm =
+ (struct v4l2_streamparm *)arg;
+ enum v4l2_buf_type type = parm->type;
+
+ memset(parm, 0, sizeof(*parm));
+ parm->type = type;
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ spin_lock(&cam->img_lock);
+ parm->parm.capture = cam->cparm;
+ spin_unlock(&cam->img_lock);
+ return 0;
+ }
+
+ case VIDIOC_S_PARM:
+ {
+ struct v4l2_streamparm *parm =
+ (struct v4l2_streamparm *)arg;
+ struct v4l2_captureparm *cparm = &parm->parm.capture;
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ spin_lock(&cam->img_lock);
+ if (cam->streaming || cam->previewing) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ }
+ cam->cparm.capturemode = cparm->capturemode;
+ if (cparm->timeperframe.numerator
+ && cparm->timeperframe.denominator) {
+ cam->nominal_timeperframe = cparm->timeperframe;
+ /* adjust the capture frame rate */
+ cam->xclk =
+ cam->cam_sensor->calc_xclk(&cam->pix,
+ &cam->
+ nominal_timeperframe,
+ cam->sensor);
+ omap24xxcam_adjust_xclk(cam);
+ cam->cparm.timeperframe =
+ cam->nominal_timeperframe;
+ spin_unlock(&cam->img_lock);
+ /* program xclk */
+ omap24xxcam_set_xclk(cam);
+ /* program the sensor */
+ err =
+ cam->cam_sensor->configure(&cam->pix,
+ cam->xclk,
+ &cam->cparm.
+ timeperframe,
+ cam->sensor);
+ } else {
+ spin_unlock(&cam->img_lock);
+ }
+ return 0;
+ }
+
+ case VIDIOC_OVERLAY:
+ {
+ int *on = arg;
+
+ spin_lock(&cam->img_lock);
+
+ if (!cam->previewing && *on) {
+ if (cam->pix.sizeimage <= cam->overlay_size) {
+ /* Turn on the overlay window */
+ omap24xxcam_configure_overlay(cam,
+ NULL);
+ omap24xxcam_flip_overlay(cam,
+ cam->
+ overlay_base_phys);
+ cam->previewing = fh;
+ spin_unlock(&cam->img_lock);
+ /* start the camera interface */
+ omap24xxcam_dma_notify(cam,
+ omap24xxcam_cc_enable);
+ omap24xxcam_start_overlay_dma(cam);
+ } else {
+ /* Image size is bigger than overlay
+ * buffer.
+ */
+ omap24xxcam_disable_vlayer(cam,
+ cam->vid1);
+ spin_unlock(&cam->img_lock);
+ return -EINVAL;
+ }
+ } else if (!*on) {
+ /* turn overlay off */
+ omap24xxcam_disable_vlayer(cam, cam->vid1);
+ cam->previewing = NULL;
+ spin_unlock(&cam->img_lock);
+ } else
+ spin_unlock(&cam->img_lock);
+
+ return 0;
+ }
+
+ case VIDIOC_REQBUFS:
+ return videobuf_reqbufs(&fh->vbq, arg);
+
+ case VIDIOC_QUERYBUF:
+ return videobuf_querybuf(&fh->vbq, arg);
+
+ case VIDIOC_QBUF:
+ return videobuf_qbuf(&fh->vbq, arg);
+
+ case VIDIOC_DQBUF:
+ return videobuf_dqbuf(&fh->vbq, arg,
+ file->f_flags & O_NONBLOCK);
+
+ case VIDIOC_STREAMON:
+ {
+ spin_lock(&cam->img_lock);
+ if (cam->streaming) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ } else
+ cam->streaming = fh;
+ spin_unlock(&cam->img_lock);
+
+ omap24xxcam_dma_notify(cam, omap24xxcam_cc_enable);
+ return videobuf_streamon(&fh->vbq);
+ }
+
+ case VIDIOC_STREAMOFF:
+ {
+ struct videobuf_queue *q = &fh->vbq;
+ int i;
+
+ /* video-buf lib has trouble to turn off streaming while
+ any buffer is still in QUEUED state. Let's wait until
+ all queued buffers are filled.
+ */
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (NULL == q->bufs[i])
+ continue;
+ while (q->bufs[i]->state == STATE_QUEUED) ;
+ }
+
+ err = videobuf_streamoff(q);
+ if (err < 0)
+ return err;
+
+ spin_lock(&cam->img_lock);
+ if (cam->streaming == fh)
+ cam->streaming = NULL;
+ spin_unlock(&cam->img_lock);
+ return 0;
+ }
+
+ case VIDIOC_G_CTRL:
+ case VIDIOC_S_CTRL:
+ case VIDIOC_QUERYCTRL:
+ case VIDIOC_QUERYMENU:
+ {
+ /* no controls have been implemented yet */
+ return -EINVAL;
+ }
+
+ case VIDIOC_ENUMSTD:
+ case VIDIOC_G_STD:
+ case VIDIOC_S_STD:
+ case VIDIOC_QUERYSTD:
+ {
+ /* Digital cameras don't have an analog video standard,
+ * so we don't need to implement these ioctls.
+ */
+ return -EINVAL;
+ }
+
+ case VIDIOC_G_AUDIO:
+ case VIDIOC_S_AUDIO:
+ case VIDIOC_G_AUDOUT:
+ case VIDIOC_S_AUDOUT:
+ {
+ /* we don't have any audio inputs or outputs */
+ return -EINVAL;
+ }
+
+ case VIDIOC_G_JPEGCOMP:
+ case VIDIOC_S_JPEGCOMP:
+ {
+ /* JPEG compression is not supported */
+ return -EINVAL;
+ }
+
+ case VIDIOC_G_TUNER:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_G_MODULATOR:
+ case VIDIOC_S_MODULATOR:
+ case VIDIOC_G_FREQUENCY:
+ case VIDIOC_S_FREQUENCY:
+ {
+ /* we don't have a tuner or modulator */
+ return -EINVAL;
+ }
+
+ case VIDIOC_ENUMOUTPUT:
+ case VIDIOC_G_OUTPUT:
+ case VIDIOC_S_OUTPUT:
+ {
+ /* we don't have any video outputs */
+ return -EINVAL;
+ }
+
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *fmt = arg;
+ return cam->cam_sensor->enum_pixformat(fmt,
+ cam->sensor);
+ }
+ case VIDIOC_S_VID2:
+ {
+ /* this api will set the parameters of video layer 2
+ ** of DISPC to display to use video 2 layer pipeline
+ ** to use hardware color conversion block to display
+ ** YUV422 format data on LCD
+ **/
+ struct omap24xx_vid2_format *vid2_format =
+ (struct omap24xx_vid2_format *)arg;
+
+ omap24xxcam_configure_overlay(cam, vid2_format);
+ return 0;
+ }
+
+ case VIDIOC_S_VID2_DISABLE:
+ {
+ omap24xxcam_disable_vlayer(cam, cam->vid2);
+ return 0;
+ }
+
+ default:
+ {
+ /* unrecognized ioctl */
+ return -ENOIOCTLCMD;
+ }
+ }
+
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+ /*
+ * file operations
+ */
+
+static unsigned
+int omap24xxcam_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ struct videobuf_buffer *vb;
+ enum v4l2_field field;
+
+ DBG;
+
+ spin_lock(&cam->img_lock);
+
+ if (cam->streaming == fh) {
+ spin_unlock(&cam->img_lock);
+ /* streaming capture */
+ if (list_empty(&fh->vbq.stream))
+ return POLLERR;
+ vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer,
+ stream);
+ } else if (cam->streaming) {
+ /* streaming I/O is in progress on another file descriptor */
+ spin_unlock(&cam->img_lock);
+ return POLLERR;
+ } else {
+ /* read() capture */
+ spin_unlock(&cam->img_lock);
+ down(&fh->vbq.lock);
+ if (fh->vbq.read_buf == NULL) {
+ /* need to capture a new image */
+ fh->vbq.read_buf = videobuf_alloc(fh->vbq.msize);
+ if (fh->vbq.read_buf == NULL) {
+ up(&fh->vbq.lock);
+ return POLLERR;
+ }
+ fh->vbq.read_buf->memory = V4L2_MEMORY_USERPTR;
+ field = videobuf_next_field(&fh->vbq);
+ if (fh->vbq.ops->buf_prepare(&fh->vbq, fh->vbq.read_buf,
+ field) != 0) {
+ up(&fh->vbq.lock);
+ return POLLERR;
+ }
+ omap24xxcam_dma_notify(cam, omap24xxcam_cc_enable);
+ fh->vbq.ops->buf_queue(&fh->vbq, fh->vbq.read_buf);
+ fh->vbq.read_off = 0;
+ }
+ up(&fh->vbq.lock);
+ vb = (struct videobuf_buffer *)fh->vbq.read_buf;
+ }
+
+ omap24xxcam_dma_notify(cam, omap24xxcam_cc_enable);
+ poll_wait(file, &vb->done, wait);
+ if (vb->state == STATE_DONE || vb->state == STATE_ERROR)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static ssize_t
+omap24xxcam_read(struct file *file, char *data, size_t count, loff_t * ppos)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+ int err;
+
+ DBG;
+
+ spin_lock(&cam->img_lock);
+ if (cam->streaming) {
+ spin_unlock(&cam->img_lock);
+ return -EBUSY;
+ }
+ cam->still_capture = 1;
+ spin_unlock(&cam->img_lock);
+
+ if (cam->cam_sensor->enter_still_capture)
+ cam->cam_sensor->enter_still_capture(16, cam->sensor);
+ omap24xxcam_dma_notify(cam, omap24xxcam_cc_enable);
+
+ /* **HACK**for some strange reason, dma'ing directly to user
+ ** buffer gives syncing error, we will use kernel bounce buffer
+ ** to capture the image pretending that we want to read one pixel
+ ** less than the actual image size.
+ */
+ err =
+ videobuf_read_one(&fh->vbq, data, count - 2, ppos,
+ file->f_flags & O_NONBLOCK);
+
+ spin_lock(&cam->img_lock);
+ cam->still_capture = 0;
+ spin_unlock(&cam->img_lock);
+
+ if (cam->cam_sensor->exit_still_capture)
+ cam->cam_sensor->exit_still_capture(cam->sensor);
+
+ DBG_END;
+
+ return err;
+}
+static ssize_t
+omap24xxcam_write(struct file *file, const char *data, size_t count,
+ loff_t * ppos)
+{
+ unsigned long vid_attributes;
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+
+ DBG;
+
+ vid_attributes = dispc_reg_merge(cam, DISPC_VID_ATTRIBUTES(1),
+ 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);
+ }
+ if (copy_from_user((void *)cam->video2_base, data, count)) {
+ printk("error in copying data");
+ }
+ return count;
+}
+
+static int omap24xxcam_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+
+ return videobuf_mmap_mapper(&fh->vbq, vma);
+}
+
+static int
+omap24xxcam_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return video_usercopy(inode, file, cmd, arg, omap24xxcam_do_ioctl);
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and
+ * turn codec audio on
+ */
+int omap24xxcam_clock_on(void)
+{
+
+ clk_enable(cam_fck);
+ clk_enable(cam_ick);
+
+ printk(KERN_DEBUG
+ "FCLK = %d [%d], usecount = %d\n",
+ (uint) clk_get_rate(cam_fck), CAM_CLOCK,
+ clk_get_usecount(cam_fck));
+
+ return 0;
+}
+
+/*
+ * Do some sanity check, turn clock off and then turn
+ * codec audio off
+ */
+int omap24xxcam_clock_off(void)
+{
+ if (clk_get_usecount(cam_fck) > 0) {
+ if (clk_get_rate(cam_fck) != CAM_CLOCK) {
+ printk(KERN_WARNING
+ "FCLK for camera should be %d Hz. But is %d Hz\n",
+ (uint) clk_get_rate(cam_fck), CAM_CLOCK);
+ }
+
+ clk_disable(cam_fck);
+ clk_disable(cam_ick);
+ }
+
+ return 0;
+}
+
+static int omap24xxcam_release(struct inode *inode, struct file *file)
+{
+ struct omap24xxcam_fh *fh = file->private_data;
+ struct omap24xxcam_device *cam = fh->cam;
+
+ DBG;
+
+ spin_lock(&cam->img_lock);
+ /* turn off overlay */
+ if (cam->previewing == fh) {
+ cam->previewing = NULL;
+ spin_unlock(&cam->img_lock);
+ omap24xxcam_disable_vlayer(cam, cam->vid1);
+ spin_lock(&cam->img_lock);
+ }
+
+ /* stop streaming capture */
+ if (cam->streaming == fh) {
+ cam->streaming = NULL;
+ spin_unlock(&cam->img_lock);
+ videobuf_streamoff(&fh->vbq);
+ spin_lock(&cam->img_lock);
+ }
+ spin_unlock(&cam->img_lock);
+
+ /* release read_buf videobuf_buffer struct */
+ if (fh->vbq.read_buf) {
+ omap24xxcam_vbq_release(&fh->vbq, fh->vbq.read_buf);
+ kfree(fh->vbq.read_buf);
+ }
+
+ file->private_data = NULL;
+ kfree(fh);
+
+ return 0;
+}
+
+static int omap24xxcam_open(struct inode *inode, struct file *file)
+{
+ int minor = iminor(inode);
+ struct omap24xxcam_device *cam = saved_cam;
+ struct omap24xxcam_fh *fh;
+
+ DBG;
+
+ if (!cam || !cam->vfd || (cam->vfd->minor != minor))
+ return -ENODEV;
+
+ /* allocate per-filehandle data */
+ fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+ if (NULL == fh)
+ return -ENOMEM;
+ file->private_data = fh;
+ fh->cam = cam;
+ fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ videobuf_queue_init(&fh->vbq, &cam->vbq_ops, NULL, &cam->vbq_lock,
+ fh->type, V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), fh);
+
+ return 0;
+}
+
+static struct file_operations omap24xxcam_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = omap24xxcam_read,
+ .write = omap24xxcam_write,
+ .poll = omap24xxcam_poll,
+ .ioctl = omap24xxcam_ioctl,
+ .mmap = omap24xxcam_mmap,
+ .open = omap24xxcam_open,
+ .release = omap24xxcam_release,
+};
+
+/* -------------------------------------------------------------------------- */
+static int omap24xxcam_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ DBG;
+
+ /* disable previewing */
+ spin_lock(&cam->img_lock);
+ if (cam->previewing) {
+ /* turn overlay off */
+ omap24xxcam_disable_vlayer(cam, cam->vid1);
+ cam->previewing = NULL;
+ }
+ spin_unlock(&cam->img_lock);
+
+ /* Get the CC_CTRL register value for the current capture format. */
+ omap24xxcam_sensor_cc_ctrl(cam);
+
+ /* Disable the camera interface. */
+ cc_reg_out(cam, CC_CTRL,
+ cam->cc_ctrl & ~(CC_CTRL_CC_EN | CC_CTRL_CC_FRAME_TRIG));
+
+ /* Stop the DMA controller and frame sync scatter-gather DMA. */
+ omap24xxcam_sg_dma_sync(cam, CAMDMA_CSR_TRANS_ERR);
+
+ /* stop XCLK */
+ cc_reg_out(cam, CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW);
+
+ /* power down the sensor */
+ cam->cam_sensor->power_off(cam->sensor);
+
+ return 0;
+}
+static int omap24xxcam_resume(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+ DBG;
+
+ /* power up the sensor */
+ cam->cam_sensor->power_on(cam->sensor);
+
+ /* set XCLK */
+ omap24xxcam_set_xclk(cam);
+
+ if (cam->streaming) {
+ /* capture was in progress, so we need to register
+ * our routine to restart the camera interface the next time a
+ * DMA transfer is queued.
+ */
+ omap24xxcam_dma_notify(cam, omap24xxcam_cc_enable);
+ }
+
+ /* Restart the scatter-gather DMA queue. */
+ omap24xxcam_sg_dma_process(cam);
+
+ /* camera interface will be enabled through dma_notify function
+ ** automatically when new dma starts
+ */
+
+ return 0;
+}
+
+static int omap24xxcam_probe(struct platform_device *pdev)
+{
+ struct omap24xxcam_device *cam;
+ struct video_device *vfd;
+
+ DBG;
+
+ cam = kzalloc(sizeof(struct omap24xxcam_device), GFP_KERNEL);
+ if (!cam) {
+ printk(KERN_ERR CAM_NAME ": could not allocate memory\n");
+ goto init_error;
+ }
+ saved_cam = cam;
+
+ /* initialize the video_device struct */
+ vfd = cam->vfd = video_device_alloc();
+ if (!vfd) {
+ printk(KERN_ERR CAM_NAME
+ ": could not allocate video device struct\n");
+ goto init_error;
+ }
+ vfd->release = video_device_release;
+#ifdef FIXME_FIXME
+/* If the dev fields are not initlized (parent and such) sysfs will crash you
+ * when it tries to set you up....most drivers seem to chain in the info their
+ * parent bus gave them. Getting this associated right is likely necessary for power
+ * mangement.
+ */
+ vfd->dev = &cam->dev;
+#endif
+ strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
+ vfd->type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CHROMAKEY;
+ /* need to register for a VID_HARDWARE_* ID in videodev.h */
+ vfd->hardware = 0;
+ vfd->fops = &omap24xxcam_fops;
+ video_set_drvdata(vfd, cam);
+ vfd->minor = -1;
+
+ /* initialize the videobuf queue ops */
+ cam->vbq_ops.buf_setup = omap24xxcam_vbq_setup;
+ cam->vbq_ops.buf_prepare = omap24xxcam_vbq_prepare;
+ cam->vbq_ops.buf_queue = omap24xxcam_vbq_queue;
+ cam->vbq_ops.buf_release = omap24xxcam_vbq_release;
+ spin_lock_init(&cam->vbq_lock);
+
+ /* Impose a lower limit on the amount of memory allocated for capture.
+ * We require at least enough memory to double-buffer QVGA (300KB).
+ */
+ if (capture_mem < 320 * 240 * 2 * 2)
+ capture_mem = 320 * 240 * 2 * 2;
+
+ /* request the mem region for the camera registers */
+ if (!request_mem_region(CAM_REG_BASE, CAM_REG_SIZE, vfd->name)) {
+ printk(KERN_ERR CAM_NAME
+ ": cannot reserve camera register I/O region\n");
+ goto init_error;
+ }
+ cam->cam_mmio_base_phys = CAM_REG_BASE;
+ cam->cam_mmio_size = CAM_REG_SIZE;
+
+ /* map the region */
+ cam->cam_mmio_base = (unsigned long)
+ ioremap(cam->cam_mmio_base_phys, cam->cam_mmio_size);
+ if (!cam->cam_mmio_base) {
+ printk(KERN_ERR CAM_NAME
+ ": cannot map camera register I/O region\n");
+ goto init_error;
+ }
+
+ /* Map the display controller registers.
+ * Note that we do not request the memory region first, because the
+ * framebuffer driver will already have claimed this region and the
+ * request would fail.
+ */
+ cam->dispc_mmio_base_phys = DSS_REG_BASE;
+ cam->dispc_mmio_size = DSS_REG_SIZE;
+ cam->dispc_mmio_base = (unsigned long)
+ ioremap(cam->dispc_mmio_base_phys, cam->dispc_mmio_size);
+ if (!cam->dispc_mmio_base) {
+ printk(KERN_ERR CAM_NAME
+ ": cannot map display controller register I/O region\n");
+ goto init_error;
+ }
+
+ /* allocate coherent memory for the overlay framebuffer */
+ cam->overlay_size = overlay_mem;
+ if (cam->overlay_size > 0) {
+ cam->overlay_base = (unsigned long)dma_alloc_coherent(NULL,
+ cam->
+ overlay_size,
+ (dma_addr_t
+ *) &
+ cam->
+ overlay_base_phys,
+ GFP_KERNEL
+ |
+ GFP_DMA);
+ if (!cam->overlay_base) {
+ printk(KERN_ERR CAM_NAME
+ ": cannot allocate overlay framebuffer\n");
+ goto init_error;
+ }
+ }
+ memset((void *)cam->overlay_base, 0, cam->overlay_size);
+
+ cam->video2_size = video2_mem;
+ if (cam->video2_size > 0) {
+ cam->video2_base = (unsigned long)dma_alloc_coherent(NULL,
+ cam->
+ video2_size,
+ (dma_addr_t
+ *) & cam->
+ video2_base_phys,
+ GFP_KERNEL
+ | GFP_DMA);
+ if (!cam->video2_base) {
+ printk(KERN_ERR CAM_NAME
+ ": cannot allocate video2 layer memory\n");
+ goto init_error;
+
+ }
+ }
+ memset((void *)cam->video2_base, 0, cam->video2_size);
+
+ /* initialize the overlay spinlock */
+ spin_lock_init(&cam->overlay_lock);
+
+ /* initialize the camera interface */
+ cam_init(cam);
+
+ /* initialize the spinlock used to serialize access to the image
+ * parameters
+ */
+ spin_lock_init(&cam->img_lock);
+ cam->cam_sensor = &camera_sensor_if;
+
+ /* initialize the camera interface functional clock frequency */
+ cam->mclk = 96000000; /* 96MHz */
+ cam_fck = clk_get(0, "cam_fck");
+ cam_ick = clk_get(0, "cam_ick");
+ omap24xxcam_clock_on();
+
+ /* initialize the streaming capture parameters */
+ cam->cparm.readbuffers = 1;
+ cam->cparm.capability = V4L2_CAP_TIMEPERFRAME;
+
+ /* Enable the xclk output. The sensor may (and does, in the case of
+ * the OV9640) require an xclk input in order for its initialization
+ * routine to work.
+ */
+ cam->xclk = 12000000; /* choose an arbitrary xclk frequency */
+ omap24xxcam_set_xclk(cam);
+
+ /* get the framebuffer parameters in case the sensor init routine
+ * needs them
+ */
+ omap24xxcam_g_fbuf(cam);
+
+ /* select an arbitrary default capture frame rate of 5fps */
+ cam->nominal_timeperframe.numerator = 1;
+ cam->nominal_timeperframe.denominator = 15;
+
+ /* initialize the sensor and define a default capture format cam->pix */
+ cam->sensor = cam->cam_sensor->init(&cam->pix, &cam->pix2);
+ if (!cam->sensor) {
+ printk(KERN_ERR CAM_NAME ": cannot initialize sensor\n");
+ goto init_error;
+ }
+ printk(KERN_INFO "Sensor is %s\n", cam->cam_sensor->name);
+
+ /* calculate xclk based on the default capture format and default
+ * frame rate
+ */
+ cam->xclk = cam->cam_sensor->calc_xclk(&cam->pix,
+ &cam->nominal_timeperframe,
+ cam->sensor);
+ omap24xxcam_adjust_xclk(cam);
+ cam->cparm.timeperframe = cam->nominal_timeperframe;
+
+ /* program the camera interface to generate the new xclk frequency */
+ omap24xxcam_set_xclk(cam);
+
+ /* initialize the image preview parameters based on the default capture
+ * format
+ */
+ omap24xxcam_new_capture_format(cam);
+
+ /* program the sensor for the default capture format and rate */
+ cam->cam_sensor->configure(&cam->pix, cam->xclk,
+ &cam->cparm.timeperframe, cam->sensor);
+ if (cam->cam_sensor->configure_still_capture)
+ cam->cam_sensor->configure_still_capture(&cam->pix2, cam->xclk,
+ &cam->cparm.timeperframe, cam->sensor);
+
+ /* use display controller video window 0 for preview */
+ cam->vid1 = 0;
+ cam->vid2 = 1;
+
+ /* initialize the DMA driver */
+ omap24xxcam_dma_init(cam);
+
+ /* install the interrupt service routine */
+ if (request_irq(INT_CAM_MPU_IRQ, omap24xxcam_isr, 0, CAM_NAME, cam)) {
+ printk(KERN_ERR CAM_NAME
+ ": could not install interrupt service routine\n");
+ goto init_error;
+ }
+ cam->irq = INT_CAM_MPU_IRQ;
+
+ if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
+ printk(KERN_ERR CAM_NAME
+ ": could not register Video for Linux device\n");
+ vfd->minor = -1;
+ goto init_error;
+ }
+ /* set driver specific data to use in power management functions */
+ platform_set_drvdata(pdev, cam);
+
+ printk(KERN_INFO CAM_NAME
+ ": registered device video%d [v4l2]\n", vfd->minor);
+
+#undef CAMERA_TEST
+//#define CAMERA_TEST
+#ifdef CAMERA_TEST
+ if (cam->pix.sizeimage <= cam->overlay_size) {
+ printk(KERN_INFO CAM_NAME ": Camera test--enabling overlay\n");
+ /* turn on the video overlay */
+ omap24xxcam_configure_overlay(cam, NULL);
+ omap24xxcam_flip_overlay(cam, cam->overlay_base_phys);
+ cam->previewing = (struct omap24xxcam_fh *)1;
+ /* start the camera interface */
+ omap24xxcam_dma_notify(cam, omap24xxcam_cc_enable);
+ omap24xxcam_start_overlay_dma(cam);
+ } else {
+ printk(KERN_INFO CAM_NAME
+ ": Can't start camera test--overlay buffer too"
+ " small\n");
+ }
+#endif
+
+ return 0;
+
+ init_error:
+ omap24xxcam_cleanup();
+ return -ENODEV;
+}
+
+static int omap24xxcam_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver omap24xxcam_driver = {
+ .probe = omap24xxcam_probe,
+ .remove = omap24xxcam_remove,
+#ifdef CONFIG_PM
+ .suspend = omap24xxcam_suspend,
+ .resume = omap24xxcam_resume,
+#else
+ .suspend = NULL,
+ .resume = NULL,
+#endif
+ .shutdown = NULL,
+ .driver {
+ .name = CAM_NAME,
+ },
+};
+
+static struct platform_device omap24xxcam_dev = {
+ .name = CAM_NAME,
+ .dev = {
+ .release = NULL,
+ },
+ .id = 0,
+};
+
+int __init omap24xxcam_init(void)
+{
+ int ret;
+
+ DBG;
+
+ ret = platform_driver_register(&omap24xxcam_driver);
+ if (ret != 0)
+ return ret;
+ ret = platform_device_register(&omap24xxcam_dev);
+ if (ret != 0) {
+ platform_driver_unregister(&omap24xxcam_driver);
+ return ret;
+ }
+
+ return 0;
+}
+
+void omap24xxcam_cleanup(void)
+{
+ struct omap24xxcam_device *cam = saved_cam;
+ struct video_device *vfd;
+
+ DBG;
+
+ if (!cam)
+ return;
+ vfd = cam->vfd;
+
+ if (vfd) {
+ if (vfd->minor == -1) {
+ /* The device was never registered, so release the
+ * video_device struct directly.
+ */
+ video_device_release(vfd);
+ } else {
+ /* The unregister function will release the video_device
+ * struct as well as unregistering it.
+ */
+ video_unregister_device(vfd);
+ }
+ cam->vfd = NULL;
+ }
+
+ if (cam->irq) {
+ free_irq(cam->irq, cam);
+ cam->irq = 0;
+ }
+
+ omap24xxcam_dma_exit(cam);
+ cam->cam_sensor->cleanup(cam->sensor);
+ /* sensor allocated private data is gone */
+ cam->sensor = NULL;
+
+ if (cam->video2_base) {
+ dma_free_coherent(NULL, cam->video2_size,
+ (void *)cam->video2_base,
+ cam->video2_base_phys);
+ cam->video2_base = 0;
+ }
+ cam->video2_base_phys = 0;
+
+ if (cam->overlay_base) {
+ dma_free_coherent(NULL, cam->overlay_size,
+ (void *)cam->overlay_base,
+ cam->overlay_base_phys);
+ cam->overlay_base = 0;
+ }
+ cam->overlay_base_phys = 0;
+
+ if (cam->dispc_mmio_base) {
+ iounmap((void *)cam->dispc_mmio_base);
+ cam->dispc_mmio_base = 0;
+ }
+ cam->dispc_mmio_base_phys = 0;
+
+ if (cam->cam_mmio_base) {
+ iounmap((void *)cam->cam_mmio_base);
+ cam->cam_mmio_base = 0;
+ }
+ if (cam->cam_mmio_base_phys) {
+ release_mem_region(cam->cam_mmio_base_phys, cam->cam_mmio_size);
+ cam->cam_mmio_base_phys = 0;
+ }
+
+ platform_device_unregister(&omap24xxcam_dev);
+ platform_driver_unregister(&omap24xxcam_driver);
+
+ kfree(cam);
+ saved_cam = NULL;
+}
+
+MODULE_AUTHOR("MontaVista Software, Inc.");
+MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr,
+ "Minor number for video device (-1 ==> auto assign)");
+module_param(capture_mem, int, 0);
+MODULE_PARM_DESC(capture_mem,
+ "Maximum amount of memory for capture buffers (default 4800KB)");
+module_param(overlay_mem, int, 0);
+MODULE_PARM_DESC(overlay_mem,
+ "Preview overlay framebuffer size (default 600KB)");
+
+module_init(omap24xxcam_init);
+module_exit(omap24xxcam_cleanup);
diff --git a/drivers/media/video/omap/omap24xxcam.h b/drivers/media/video/omap/omap24xxcam.h
new file mode 100644
index 0000000..85c10e6
--- /dev/null
+++ b/drivers/media/video/omap/omap24xxcam.h
@@ -0,0 +1,869 @@
+/*
+ * drivers/media/video/omap24xxcam.h
+ *
+ * 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.
+ */
+
+#ifndef OMAP24XXCAM_H
+#define OMAP24XXCAM_H
+
+#define CAM_CLOCK 96000000
+
+/* physical memory map definitions */
+ /* camera subsystem */
+#define CAM_REG_BASE 0x48052000
+#define CAM_REG_SIZE 0x00001000
+ /* camera core */
+#define CC_REG_OFFSET 0x00000400
+ /* camera DMA */
+#define CAMDMA_REG_OFFSET 0x00000800
+ /* camera MMU */
+#define CAMMMU_REG_OFFSET 0x00000C00
+
+/* define camera subsystem register offsets */
+#define CAM_REVISION 0x000
+#define CAM_SYSCONFIG 0x010
+#define CAM_SYSSTATUS 0x014
+#define CAM_IRQSTATUS 0x018
+#define CAM_GPO 0x040
+#define CAM_GPI 0x050
+
+/* define camera core register offsets */
+#define CC_REVISION 0x000
+#define CC_SYSCONFIG 0x010
+#define CC_SYSSTATUS 0x014
+#define CC_IRQSTATUS 0x018
+#define CC_IRQENABLE 0x01C
+#define CC_CTRL 0x040
+#define CC_CTRL_DMA 0x044
+#define CC_CTRL_XCLK 0x048
+#define CC_FIFODATA 0x04C
+#define CC_TEST 0x050
+#define CC_GENPAR 0x054
+#define CC_CCPFSCR 0x058
+#define CC_CCPFECR 0x05C
+#define CC_CCPLSCR 0x060
+#define CC_CCPLECR 0x064
+#define CC_CCPDFR 0x068
+
+/* define camera dma register offsets */
+#define CAMDMA_REVISION 0x000
+#define CAMDMA_IRQSTATUS_L0 0x008
+#define CAMDMA_IRQSTATUS_L1 0x00C
+#define CAMDMA_IRQSTATUS_L2 0x010
+#define CAMDMA_IRQSTATUS_L3 0x014
+#define CAMDMA_IRQENABLE_L0 0x018
+#define CAMDMA_IRQENABLE_L1 0x01C
+#define CAMDMA_IRQENABLE_L2 0x020
+#define CAMDMA_IRQENABLE_L3 0x024
+#define CAMDMA_SYSSTATUS 0x028
+#define CAMDMA_OCP_SYSCONFIG 0x02C
+#define CAMDMA_CAPS_0 0x064
+#define CAMDMA_CAPS_2 0x06C
+#define CAMDMA_CAPS_3 0x070
+#define CAMDMA_CAPS_4 0x074
+#define CAMDMA_GCR 0x078
+#define CAMDMA_CCR(n) (0x080 + (n)*0x60)
+#define CAMDMA_CLNK_CTRL(n) (0x084 + (n)*0x60)
+#define CAMDMA_CICR(n) (0x088 + (n)*0x60)
+#define CAMDMA_CSR(n) (0x08C + (n)*0x60)
+#define CAMDMA_CSDP(n) (0x090 + (n)*0x60)
+#define CAMDMA_CEN(n) (0x094 + (n)*0x60)
+#define CAMDMA_CFN(n) (0x098 + (n)*0x60)
+#define CAMDMA_CSSA(n) (0x09C + (n)*0x60)
+#define CAMDMA_CDSA(n) (0x0A0 + (n)*0x60)
+#define CAMDMA_CSEI(n) (0x0A4 + (n)*0x60)
+#define CAMDMA_CSFI(n) (0x0A8 + (n)*0x60)
+#define CAMDMA_CDEI(n) (0x0AC + (n)*0x60)
+#define CAMDMA_CDFI(n) (0x0B0 + (n)*0x60)
+#define CAMDMA_CSAC(n) (0x0B4 + (n)*0x60)
+#define CAMDMA_CDAC(n) (0x0B8 + (n)*0x60)
+#define CAMDMA_CCEN(n) (0x0BC + (n)*0x60)
+#define CAMDMA_CCFN(n) (0x0C0 + (n)*0x60)
+#define CAMDMA_COLOR(n) (0x0C4 + (n)*0x60)
+
+/* define camera mmu register offsets */
+#define CAMMMU_REVISION 0x000
+#define CAMMMU_SYSCONFIG 0x010
+#define CAMMMU_SYSSTATUS 0x014
+#define CAMMMU_IRQSTATUS 0x018
+#define CAMMMU_IRQENABLE 0x01C
+#define CAMMMU_WALKING_ST 0x040
+#define CAMMMU_CNTL 0x044
+#define CAMMMU_FAULT_AD 0x048
+#define CAMMMU_TTB 0x04C
+#define CAMMMU_LOCK 0x050
+#define CAMMMU_LD_TLB 0x054
+#define CAMMMU_CAM 0x058
+#define CAMMMU_RAM 0x05C
+#define CAMMMU_GFLUSH 0x060
+#define CAMMMU_FLUSH_ENTRY 0x064
+#define CAMMMU_READ_CAM 0x068
+#define CAMMMU_READ_RAM 0x06C
+#define CAMMMU_EMU_FAULT_AD 0x070
+
+/* Define bit fields within selected registers */
+#define CAM_REVISION_MAJOR (15 << 4)
+#define CAM_REVISION_MAJOR_SHIFT 4
+#define CAM_REVISION_MINOR (15 << 0)
+#define CAM_REVISION_MINOR_SHIFT 0
+
+#define CAM_SYSCONFIG_SOFTRESET (1 << 1)
+#define CAM_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define CAM_SYSSTATUS_RESETDONE (1 << 0)
+
+#define CAM_IRQSTATUS_CC_IRQ (1 << 4)
+#define CAM_IRQSTATUS_MMU_IRQ (1 << 3)
+#define CAM_IRQSTATUS_DMA_IRQ2 (1 << 2)
+#define CAM_IRQSTATUS_DMA_IRQ1 (1 << 1)
+#define CAM_IRQSTATUS_DMA_IRQ0 (1 << 0)
+
+#define CAM_GPO_CAM_S_P_EN (1 << 1)
+#define CAM_GPO_CAM_CCP_MODE (1 << 0)
+
+#define CAM_GPI_CC_DMA_REQ1 (1 << 24)
+#define CAP_GPI_CC_DMA_REQ0 (1 << 23)
+#define CAP_GPI_CAM_MSTANDBY (1 << 21)
+#define CAP_GPI_CAM_WAIT (1 << 20)
+#define CAP_GPI_CAM_S_DATA (1 << 17)
+#define CAP_GPI_CAM_S_CLK (1 << 16)
+#define CAP_GPI_CAM_P_DATA (0xFFF << 3)
+#define CAP_GPI_CAM_P_DATA_SHIFT 3
+#define CAP_GPI_CAM_P_VS (1 << 2)
+#define CAP_GPI_CAM_P_HS (1 << 1)
+#define CAP_GPI_CAM_P_CLK (1 << 0)
+
+#define CC_REVISION_MAJOR (15 << 4)
+#define CC_REVISION_MAJOR_SHIFT 4
+#define CC_REVISION_MINOR (15 << 0)
+#define CC_REVISION_MINOR_SHIFT 0
+
+#define CC_SYSCONFIG_SIDLEMODE (3 << 3)
+#define CC_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
+#define CC_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
+#define CC_SYSCONFIG_SOFTRESET (1 << 1)
+#define CC_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define CC_SYSSTATUS_RESETDONE (1 << 0)
+
+#define CC_IRQSTATUS_FS_IRQ (1 << 19)
+#define CC_IRQSTATUS_LE_IRQ (1 << 18)
+#define CC_IRQSTATUS_LS_IRQ (1 << 17)
+#define CC_IRQSTATUS_FE_IRQ (1 << 16)
+#define CC_IRQSTATUS_FW_ERR_IRQ (1 << 10)
+#define CC_IRQSTATUS_FSC_ERR_IRQ (1 << 9)
+#define CC_IRQSTATUS_SSC_ERR_IRQ (1 << 8)
+#define CC_IRQSTATUS_FIFO_NOEMPTY_IRQ (1 << 4)
+#define CC_IRQSTATUS_FIFO_FULL_IRQ (1 << 3)
+#define CC_IRQSTATUS_FIFO_THR_IRQ (1 << 2)
+#define CC_IRQSTATUS_FIFO_OF_IRQ (1 << 1)
+#define CC_IRQSTATUS_FIFO_UF_IRQ (1 << 0)
+
+#define CC_IRQENABLE_FS_IRQ (1 << 19)
+#define CC_IRQENABLE_LE_IRQ (1 << 18)
+#define CC_IRQENABLE_LS_IRQ (1 << 17)
+#define CC_IRQENABLE_FE_IRQ (1 << 16)
+#define CC_IRQENABLE_FW_ERR_IRQ (1 << 10)
+#define CC_IRQENABLE_FSC_ERR_IRQ (1 << 9)
+#define CC_IRQENABLE_SSC_ERR_IRQ (1 << 8)
+#define CC_IRQENABLE_FIFO_NOEMPTY_IRQ (1 << 4)
+#define CC_IRQENABLE_FIFO_FULL_IRQ (1 << 3)
+#define CC_IRQENABLE_FIFO_THR_IRQ (1 << 2)
+#define CC_IRQENABLE_FIFO_OF_IRQ (1 << 1)
+#define CC_IRQENABLE_FIFO_UF_IRQ (1 << 0)
+
+#define CC_CTRL_CC_ONE_SHOT (1 << 20)
+#define CC_CTRL_CC_IF_SYNCHRO (1 << 19)
+#define CC_CTRL_CC_RST (1 << 18)
+#define CC_CTRL_CC_FRAME_TRIG (1 << 17)
+#define CC_CTRL_CC_EN (1 << 16)
+#define CC_CTRL_NOBT_SYNCHRO (1 << 13)
+#define CC_CTRL_BT_CORRECT (1 << 12)
+#define CC_CTRL_PAR_ORDERCAM (1 << 11)
+#define CC_CTRL_PAR_CLK_POL (1 << 10)
+#define CC_CTRL_NOBT_HS_POL_SHIFT 9
+#define CC_CTRL_NOBT_HS_POL (1 << 9)
+#define CC_CTRL_NOBT_VS_POL_SHIFT 8
+#define CC_CTRL_NOBT_VS_POL (1 << 8)
+#define CC_CTRL_PAR_MODE (7 << 1)
+#define CC_CTRL_PAR_MODE_SHIFT 1
+#define CC_CTRL_PAR_MODE_NOBT8 (0 << 1)
+#define CC_CTRL_PAR_MODE_NOBT10 (1 << 1)
+#define CC_CTRL_PAR_MODE_NOBT12 (2 << 1)
+#define CC_CTRL_PAR_MODE_BT8 (4 << 1)
+#define CC_CTRL_PAR_MODE_BT10 (5 << 1)
+#define CC_CTRL_PAR_MODE_FIFOTEST (7 << 1)
+#define CC_CTRL_CCP_MODE (1 << 0)
+
+#define CC_CTRL_DMA_EN (1 << 8)
+#define CC_CTRL_DMA_FIFO_THRESHOLD (0x7F << 0)
+#define CC_CTRL_DMA_FIFO_THRESHOLD_SHIFT 0
+
+#define CC_CTRL_XCLK_DIV (0x1F << 0)
+#define CC_CTRL_XCLK_DIV_SHIFT 0
+#define CC_CTRL_XCLK_DIV_STABLE_LOW (0 << 0)
+#define CC_CTRL_XCLK_DIV_STABLE_HIGH (1 << 0)
+#define CC_CTRL_XCLK_DIV_BYPASS (31 << 0)
+
+#define CC_TEST_FIFO_RD_POINTER (0xFF << 24)
+#define CC_TEST_FIFO_RD_POINTER_SHIFT 24
+#define CC_TEST_FIFO_WR_POINTER (0xFF << 16)
+#define CC_TEST_FIFO_WR_POINTER_SHIFT 16
+#define CC_TEST_FIFO_LEVEL (0xFF << 8)
+#define CC_TEST_FIFO_LEVEL_SHIFT 8
+#define CC_TEST_FIFO_LEVEL_PEAK (0xFF << 0)
+#define CC_TEST_FIFO_LEVEL_PEAK_SHIFT 0
+
+#define CC_GENPAR_FIFO_DEPTH (7 << 0)
+#define CC_GENPAR_FIFO_DEPTH_SHIFT 0
+
+#define CC_CCPDFR_ALPHA (0xFF << 8)
+#define CC_CCPDFR_ALPHA_SHIFT 8
+#define CC_CCPDFR_DATAFORMAT (15 << 0)
+#define CC_CCPDFR_DATAFORMAT_SHIFT 0
+#define CC_CCPDFR_DATAFORMAT_YUV422BE ( 0 << 0)
+#define CC_CCPDFR_DATAFORMAT_YUV422 ( 1 << 0)
+#define CC_CCPDFR_DATAFORMAT_YUV420 ( 2 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB444 ( 4 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB565 ( 5 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB888NDE ( 6 << 0)
+#define CC_CCPDFR_DATAFORMAT_RGB888 ( 7 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW8NDE ( 8 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW8 ( 9 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW10NDE (10 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW10 (11 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW12NDE (12 << 0)
+#define CC_CCPDFR_DATAFORMAT_RAW12 (13 << 0)
+#define CC_CCPDFR_DATAFORMAT_JPEG8 (15 << 0)
+
+#define CAMDMA_REVISION_MAJOR (15 << 4)
+#define CAMDMA_REVISION_MAJOR_SHIFT 4
+#define CAMDMA_REVISION_MINOR (15 << 0)
+#define CAMDMA_REVISION_MINOR_SHIFT 0
+
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE (3 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY (0 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_NSTANDBY (1 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_SSTANDBY (2 << 12)
+#define CAMDMA_OCP_SYSCONFIG_FUNC_CLOCK (1 << 9)
+#define CAMDMA_OCP_SYSCONFIG_OCP_CLOCK (1 << 8)
+#define CAMDMA_OCP_SYSCONFIG_EMUFREE (1 << 5)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE (3 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_SIDLE (2 << 3)
+#define CAMDMA_OCP_SYSCONFIG_SOFTRESET (1 << 1)
+#define CAMDMA_OCP_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define CAMDMA_SYSSTATUS_RESETDONE (1 << 0)
+
+#define CAMDMA_GCR_ARBITRATION_RATE (0xFF << 16)
+#define CAMDMA_GCR_ARBITRATION_RATE_SHIFT 16
+#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH (0xFF << 0)
+#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH_SHIFT 0
+
+#define CAMDMA_CCR_SEL_SRC_DST_SYNC (1 << 24)
+#define CAMDMA_CCR_PREFETCH (1 << 23)
+#define CAMDMA_CCR_SUPERVISOR (1 << 22)
+#define CAMDMA_CCR_SECURE (1 << 21)
+#define CAMDMA_CCR_BS (1 << 18)
+#define CAMDMA_CCR_TRANSPARENT_COPY_ENABLE (1 << 17)
+#define CAMDMA_CCR_CONSTANT_FILL_ENABLE (1 << 16)
+#define CAMDMA_CCR_DST_AMODE (3 << 14)
+#define CAMDMA_CCR_DST_AMODE_CONST_ADDR (0 << 14)
+#define CAMDMA_CCR_DST_AMODE_POST_INC (1 << 14)
+#define CAMDMA_CCR_DST_AMODE_SGL_IDX (2 << 14)
+#define CAMDMA_CCR_DST_AMODE_DBL_IDX (3 << 14)
+#define CAMDMA_CCR_SRC_AMODE (3 << 12)
+#define CAMDMA_CCR_SRC_AMODE_CONST_ADDR (0 << 12)
+#define CAMDMA_CCR_SRC_AMODE_POST_INC (1 << 12)
+#define CAMDMA_CCR_SRC_AMODE_SGL_IDX (2 << 12)
+#define CAMDMA_CCR_SRC_AMODE_DBL_IDX (3 << 12)
+#define CAMDMA_CCR_WR_ACTIVE (1 << 10)
+#define CAMDMA_CCR_RD_ACTIVE (1 << 9)
+#define CAMDMA_CCR_SUSPEND_SENSITIVE (1 << 8)
+#define CAMDMA_CCR_ENABLE (1 << 7)
+#define CAMDMA_CCR_PRIO (1 << 6)
+#define CAMDMA_CCR_FS (1 << 5)
+#define CAMDMA_CCR_SYNCHRO ((3 << 19) | (31 << 0))
+#define CAMDMA_CCR_SYNCHRO_CAMERA 0x01
+
+#define CAMDMA_CLNK_CTRL_ENABLE_LNK (1 << 15)
+#define CAMDMA_CLNK_CTRL_NEXTLCH_ID (0x1F << 0)
+#define CAMDMA_CLNK_CTRL_NEXTLCH_ID_SHIFT 0
+
+#define CAMDMA_CICR_MISALIGNED_ERR_IE (1 << 11)
+#define CAMDMA_CICR_SUPERVISOR_ERR_IE (1 << 10)
+#define CAMDMA_CICR_SECURE_ERR_IE (1 << 9)
+#define CAMDMA_CICR_TRANS_ERR_IE (1 << 8)
+#define CAMDMA_CICR_PACKET_IE (1 << 7)
+#define CAMDMA_CICR_BLOCK_IE (1 << 5)
+#define CAMDMA_CICR_LAST_IE (1 << 4)
+#define CAMDMA_CICR_FRAME_IE (1 << 3)
+#define CAMDMA_CICR_HALF_IE (1 << 2)
+#define CAMDMA_CICR_DROP_IE (1 << 1)
+
+#define CAMDMA_CSR_MISALIGNED_ERR (1 << 11)
+#define CAMDMA_CSR_SUPERVISOR_ERR (1 << 10)
+#define CAMDMA_CSR_SECURE_ERR (1 << 9)
+#define CAMDMA_CSR_TRANS_ERR (1 << 8)
+#define CAMDMA_CSR_PACKET (1 << 7)
+#define CAMDMA_CSR_SYNC (1 << 6)
+#define CAMDMA_CSR_BLOCK (1 << 5)
+#define CAMDMA_CSR_LAST (1 << 4)
+#define CAMDMA_CSR_FRAME (1 << 3)
+#define CAMDMA_CSR_HALF (1 << 2)
+#define CAMDMA_CSR_DROP (1 << 1)
+
+#define CAMDMA_CSDP_SRC_ENDIANNESS (1 << 21)
+#define CAMDMA_CSDP_SRC_ENDIANNESS_LOCK (1 << 20)
+#define CAMDMA_CSDP_DST_ENDIANNESS (1 << 19)
+#define CAMDMA_CSDP_DST_ENDIANNESS_LOCK (1 << 18)
+#define CAMDMA_CSDP_WRITE_MODE (3 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_WRNP (0 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_POSTED (1 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_POSTED_LAST_WRNP (2 << 16)
+#define CAMDMA_CSDP_DST_BURST_EN (3 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_1 (0 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_16 (1 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_32 (2 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_64 (3 << 14)
+#define CAMDMA_CSDP_DST_PACKED (1 << 13)
+#define CAMDMA_CSDP_WR_ADD_TRSLT (15 << 9)
+#define CAMDMA_CSDP_WR_ADD_TRSLT_ENABLE_MREQADD (3 << 9)
+#define CAMDMA_CSDP_SRC_BURST_EN (3 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_1 (0 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_16 (1 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_32 (2 << 7)
+#define CAMDMA_CSDP_SRC_BURST_EN_64 (3 << 7)
+#define CAMDMA_CSDP_SRC_PACKED (1 << 6)
+#define CAMDMA_CSDP_RD_ADD_TRSLT (15 << 2)
+#define CAMDMA_CSDP_RD_ADD_TRSLT_ENABLE_MREQADD (3 << 2)
+#define CAMDMA_CSDP_DATA_TYPE (3 << 0)
+#define CAMDMA_CSDP_DATA_TYPE_8BITS (0 << 0)
+#define CAMDMA_CSDP_DATA_TYPE_16BITS (1 << 0)
+#define CAMDMA_CSDP_DATA_TYPE_32BITS (2 << 0)
+
+#define CAMMMU_SYSCONFIG_AUTOIDLE (1 << 0)
+
+struct omap24xx_cc_regs {
+ u32 revision; /* 0x000 */
+ u32 res1[3];
+ u32 sysconfig; /* 0x010 */
+ u32 sysstatus; /* 0x014 */
+ u32 irqstatus; /* 0x018 */
+ u32 irqenable; /* 0x01C */
+ u32 res2[8];
+ u32 ctrl; /* 0x040 */
+ u32 ctrl_dma; /* 0x044 */
+ u32 ctrl_xclk; /* 0x048 */
+ u32 fifodata; /* 0x04C */
+ u32 test; /* 0x050 */
+ u32 genpar; /* 0x054 */
+ u32 ccpfscr; /* 0x058 */
+ u32 ccpfecr; /* 0x05C */
+ u32 ccplscr; /* 0x060 */
+ u32 ccplecr; /* 0x064 */
+ u32 ccpdfr; /* 0x068 */
+};
+struct omap24xx_vid2_format {
+ struct v4l2_pix_format pix;
+ __s32 left; /* following two members are defined to */
+ __s32 top; /* position the video2 layer on the lcd */
+
+};
+
+/* forward declarations */
+struct omap24xxcam_fh;
+struct omap24xxcam_device;
+
+/* camera DMA definitions */
+#define DMA_THRESHOLD 32 /* number of bytes transferred per DMA request */
+/* NUM_CAMDMA_CHANNELS is the number of logical channels provided by the camera
+ * DMA controller.
+ */
+#define NUM_CAMDMA_CHANNELS 4
+/* NUM_SG_DMA is the number of scatter-gather DMA transfers that can be queued.
+ * We need it to be 2 greater than the maximum number of video frames so that
+ * we can use 2 slots for overlay while still having VIDEO_MAX_FRAME slots left
+ * for streaming.
+ */
+#define NUM_SG_DMA (VIDEO_MAX_FRAME+2)
+
+typedef void (*dma_callback_t) (struct omap24xxcam_device * cam,
+ unsigned long status, void *arg);
+
+struct camdma_state {
+ dma_callback_t callback;
+ void *arg;
+};
+struct sgdma_state {
+ const struct scatterlist *sglist;
+ int sglen; /* number of sglist entries */
+ int next_sglist; /* index of next sglist entry to process */
+ int queued_sglist; /* number of sglist entries queued for DMA */
+ unsigned long csr; /* DMA return code */
+ dma_callback_t callback;
+ void *arg;
+};
+
+/* per-device data structure */
+struct omap24xxcam_device {
+ unsigned int irq;
+
+ unsigned long cam_mmio_base;
+ unsigned long cam_mmio_base_phys;
+ unsigned long cam_mmio_size;
+
+ unsigned long dispc_mmio_base;
+ unsigned long dispc_mmio_base_phys;
+ unsigned long dispc_mmio_size;
+
+ unsigned long overlay_base;
+ unsigned long overlay_base_phys;
+ unsigned long overlay_size;
+
+ /* camera DMA management */
+ spinlock_t dma_lock;
+ /* While dma_stop!=0, an attempt to start a new DMA transfer will
+ * fail.
+ */
+ int dma_stop;
+ int free_dmach; /* number of dma channels free */
+ int next_dmach; /* index of next dma channel to use */
+ struct camdma_state camdma[NUM_CAMDMA_CHANNELS];
+ /* dma_notify is a pointer to a callback routine for notification when
+ * a DMA transfer has been started.
+ */
+ void (*dma_notify) (struct omap24xxcam_device * cam);
+
+ /* frequncy (in Hz) of camera interface functional clock (MCLK) */
+ unsigned long mclk;
+
+ struct device dev;
+ struct video_device *vfd;
+
+ spinlock_t overlay_lock; /* spinlock for overlay DMA counter */
+ int overlay_cnt; /* count of queued overlay DMA xfers */
+ struct scatterlist overlay_sglist;
+
+ spinlock_t vbq_lock; /* spinlock for videobuf queues */
+ struct videobuf_queue_ops vbq_ops; /* videobuf queue operations */
+ unsigned long field_count; /* field counter for videobuf_buffer */
+
+ /* scatter-gather DMA management */
+ spinlock_t sg_lock;
+ int free_sgdma; /* number of free sg dma slots */
+ int next_sgdma; /* index of next sg dma slot to use */
+ struct sgdma_state sgdma[NUM_SG_DMA];
+
+ /* The img_lock is used to serialize access to the image parameters for
+ * overlay and capture.
+ */
+ spinlock_t img_lock;
+
+ /* Access to everything below here is locked by img_lock */
+
+ /* We allow streaming from at most one filehandle at a time.
+ * non-NULL means streaming is in progress.
+ */
+ struct omap24xxcam_fh *streaming;
+ /* We allow previewing from at most one filehandle at a time.
+ * non-NULL means previewing is in progress.
+ */
+ struct omap24xxcam_fh *previewing;
+
+ /* capture parameters (frame rate, number of buffers) */
+ struct v4l2_captureparm cparm;
+
+ /* This is the frame period actually requested by the user. */
+ struct v4l2_fract nominal_timeperframe;
+
+ /* frequency (in Hz) of camera interface xclk output */
+ unsigned long xclk;
+
+ /* pointer to camera sensor interface interface */
+ struct camera_sensor *cam_sensor;
+ /* blind pointer to private data structure for sensor */
+ void *sensor;
+
+ /* pix defines the size and pixel format of the image captured by the
+ * sensor. This also defines the size of the framebuffers. The
+ * same pool of framebuffers is used for video capture and video
+ * overlay. These parameters are set/queried by the
+ * VIDIOC_S_FMT/VIDIOC_G_FMT ioctls with a CAPTURE buffer type.
+ */
+ struct v4l2_pix_format pix;
+ struct v4l2_pix_format pix2;
+ int still_capture;
+
+ /* crop defines the size and offset of the video overlay source window
+ * within the framebuffer. These parameters are set/queried by the
+ * VIDIOC_S_CROP/VIDIOC_G_CROP ioctls with an OVERLAY buffer type.
+ * The cropping rectangle allows a subset of the captured image to be
+ * previewed. It only affects the portion of the image previewed, not
+ * captured; the entire camera image is always captured.
+ */
+ struct v4l2_rect crop;
+
+ /* win defines the size and offset of the video overlay target window
+ * within the video display. These parameters are set/queried by the
+ * VIDIOC_S_FMT/VIDIOC_G_FMT ioctls with an OVERLAY buffer type.
+ */
+ struct v4l2_window win;
+
+ /* fbuf reflects the size of the video display. It is queried with the
+ * VIDIOC_G_FBUF ioctl. The size of the video display cannot be
+ * changed with the VIDIOC_S_FBUF ioctl.
+ */
+ struct v4l2_framebuffer fbuf;
+
+ /* value of CC_CTRL register required to support current capture
+ * format
+ */
+ unsigned long cc_ctrl;
+
+ /* display controller video window (0 or 1) to use for capture
+ * preview
+ */
+ int vid1;
+
+ /* gfx_position x and y are the offset of the display controller
+ * graphics window with respect to the display
+ */
+ int gfx_position_x;
+ int gfx_position_y;
+ /* value of GFX_ATTRIBUTES register from display controller */
+ unsigned long gfx_attributes;
+
+ /* video 2 layer of the display controller is also configured through
+ ** it */
+ int vid2;
+ unsigned long video2_base;
+ unsigned long video2_base_phys;
+ unsigned long video2_size;
+};
+
+/* per-filehandle data structure */
+struct omap24xxcam_fh {
+ struct omap24xxcam_device *cam;
+ enum v4l2_buf_type type;
+ struct videobuf_queue vbq;
+};
+
+/* Selected register definitions from the framebuffer driver for the
+ * OMAP2420 display controller are repeated here.
+ */
+#ifndef OMAP24XXFB_H
+
+/* physical memory map definitions */
+ /* display subsystem */
+#define DSS_REG_BASE 0x48050000
+#define DSS_REG_SIZE 0x00001000
+ /* display controller */
+#define DISPC_REG_OFFSET 0x00000400
+
+/* define display controller register offsets */
+#define DISPC_REVISION 0x000
+#define DISPC_SYSCONFIG 0x010
+#define DISPC_SYSSTATUS 0x014
+#define DISPC_IRQSTATUS 0x018
+#define DISPC_IRQENABLE 0x01C
+#define DISPC_CONTROL 0x040
+#define DISPC_CONFIG 0x044
+#define DISPC_CAPABLE 0x048
+#define DISPC_DEFAULT_COLOR0 0x04C
+#define DISPC_DEFAULT_COLOR1 0x050
+#define DISPC_TRANS_COLOR0 0x054
+#define DISPC_TRANS_COLOR1 0x058
+#define DISPC_LINE_STATUS 0x05C
+#define DISPC_LINE_NUMBER 0x060
+#define DISPC_TIMING_H 0x064
+#define DISPC_TIMING_V 0x068
+#define DISPC_POL_FREQ 0x06C
+#define DISPC_DIVISOR 0x070
+#define DISPC_SIZE_DIG 0x078
+#define DISPC_SIZE_LCD 0x07C
+#define DISPC_GFX_BA0 0x080
+#define DISPC_GFX_BA1 0x084
+#define DISPC_GFX_POSITION 0x088
+#define DISPC_GFX_SIZE 0x08C
+#define DISPC_GFX_ATTRIBUTES 0x0A0
+#define DISPC_GFX_FIFO_THRESHOLD 0x0A4
+#define DISPC_GFX_FIFO_SIZE 0x0A8
+#define DISPC_GFX_ROW_INC 0x0AC
+#define DISPC_GFX_PIXEL_INC 0x0B0
+#define DISPC_GFX_WINDOW_SKIP 0x0B4
+#define DISPC_GFX_TABLE_BA 0x0B8
+
+/* The registers for the video pipelines are parameterized by the video pipeline
+ * index: n=0 for VID1 and n=1 for VID2.
+ */
+#define DISPC_VID_BA0(n) (0x0BC + (n)*0x90)
+#define DISPC_VID_BA1(n) (0x0C0 + (n)*0x90)
+#define DISPC_VID_POSITION(n) (0x0C4 + (n)*0x90)
+#define DISPC_VID_SIZE(n) (0x0C8 + (n)*0x90)
+#define DISPC_VID_ATTRIBUTES(n) (0x0CC + (n)*0x90)
+#define DISPC_VID_FIFO_THRESHOLD(n) (0x0D0 + (n)*0x90)
+#define DISPC_VID_FIFO_SIZE(n) (0x0D4 + (n)*0x90)
+#define DISPC_VID_ROW_INC(n) (0x0D8 + (n)*0x90)
+#define DISPC_VID_PIXEL_INC(n) (0x0DC + (n)*0x90)
+#define DISPC_VID_FIR(n) (0x0E0 + (n)*0x90)
+#define DISPC_VID_PICTURE_SIZE(n) (0x0E4 + (n)*0x90)
+#define DISPC_VID_ACCU0(n) (0x0E8 + (n)*0x90)
+#define DISPC_VID_ACCU1(n) (0x0EC + (n)*0x90)
+/* The FIR coefficients are parameterized by the video pipeline index n = {0, 1}
+ * and the coefficient index i = {0, 1, 2, 3, 4, 5, 6, 7}.
+ */
+#define DISPC_VID_FIR_COEF_H(n, i) (0x0F0 + (i)*0x8 + (n)*0x90)
+#define DISPC_VID_FIR_COEF_HV(n, i) (0x0F4 + (i)*0x8 + (n)*0x90)
+#define DISPC_VID_CONV_COEF0(n) (0x130 + (n)*0x90)
+#define DISPC_VID_CONV_COEF1(n) (0x134 + (n)*0x90)
+#define DISPC_VID_CONV_COEF2(n) (0x138 + (n)*0x90)
+#define DISPC_VID_CONV_COEF3(n) (0x13C + (n)*0x90)
+#define DISPC_VID_CONV_COEF4(n) (0x140 + (n)*0x90)
+
+/* Define bit fields within selected registers */
+#define DISPC_REVISION_MAJOR (15 << 4)
+#define DISPC_REVISION_MAJOR_SHIFT 4
+#define DISPC_REVISION_MINOR (15 << 0)
+#define DISPC_REVISION_MINOR_SHIFT 0
+
+#define DISPC_SYSCONFIG_MIDLEMODE (3 << 12)
+#define DISPC_SYSCONFIG_MIDLEMODE_FSTANDBY (0 << 12)
+#define DISPC_SYSCONFIG_MIDLEMODE_NSTANDBY (1 << 12)
+#define DISPC_SYSCONFIG_MIDLEMODE_SSTANDBY (2 << 12)
+#define DISPC_SYSCONFIG_SIDLEMODE (3 << 3)
+#define DISPC_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
+#define DISPC_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
+#define DISPC_SYSCONFIG_SIDLEMODE_SIDLE (2 << 3)
+#define DISPC_SYSCONFIG_SOFTRESET (1 << 1)
+#define DISPC_SYSCONFIG_AUTOIDLE (1 << 0)
+
+#define DISPC_SYSSTATUS_RESETDONE (1 << 0)
+
+#define DISPC_IRQSTATUS_SYNCLOST (1 << 14)
+#define DISPC_IRQSTATUS_VID2ENDWINDOW (1 << 13)
+#define DISPC_IRQSTATUS_VID2FIFOUNDERFLOW (1 << 12)
+#define DISPC_IRQSTATUS_VID1ENDWINDOW (1 << 11)
+#define DISPC_IRQSTATUS_VID1FIFOUNDERFLOW (1 << 10)
+#define DISPC_IRQSTATUS_OCPERROR (1 << 9)
+#define DISPC_IRQSTATUS_PALETTEGAMMALOADING (1 << 8)
+#define DISPC_IRQSTATUS_GFXENDWINDOW (1 << 7)
+#define DISPC_IRQSTATUS_GFXFIFOUNDERFLOW (1 << 6)
+#define DISPC_IRQSTATUS_PROGRAMMEDLINENUMBER (1 << 5)
+#define DISPC_IRQSTATUS_ACBIASCOUNTSTATUS (1 << 4)
+#define DISPC_IRQSTATUS_EVSYNC_ODD (1 << 3)
+#define DISPC_IRQSTATUS_EVSYNC_EVEN (1 << 2)
+#define DISPC_IRQSTATUS_VSYNC (1 << 1)
+#define DISPC_IRQSTATUS_FRAMEDONE (1 << 0)
+
+#define DISPC_IRQENABLE_SYNCLOST (1 << 14)
+#define DISPC_IRQENABLE_VID2ENDWINDOW (1 << 13)
+#define DISPC_IRQENABLE_VID2FIFOUNDERFLOW (1 << 12)
+#define DISPC_IRQENABLE_VID1ENDWINDOW (1 << 11)
+#define DISPC_IRQENABLE_VID1FIFOUNDERFLOW (1 << 10)
+#define DISPC_IRQENABLE_OCPERROR (1 << 9)
+#define DISPC_IRQENABLE_PALETTEGAMMALOADING (1 << 8)
+#define DISPC_IRQENABLE_GFXENDWINDOW (1 << 7)
+#define DISPC_IRQENABLE_GFXFIFOUNDERFLOW (1 << 6)
+#define DISPC_IRQENABLE_PROGRAMMEDLINENUMBER (1 << 5)
+#define DISPC_IRQENABLE_ACBIASCOUNTSTATUS (1 << 4)
+#define DISPC_IRQENABLE_EVSYNC_ODD (1 << 3)
+#define DISPC_IRQENABLE_EVSYNC_EVEN (1 << 2)
+#define DISPC_IRQENABLE_VSYNC (1 << 1)
+#define DISPC_IRQENABLE_FRAMEDONE (1 << 0)
+
+#define DISPC_CONTROL_TDMUNUSEDBITS (3 << 25)
+#define DISPC_CONTROL_TDMUNUSEDBITS_LOWLEVEL (0 << 25)
+#define DISPC_CONTROL_TDMUNUSEDBITS_HIGHLEVEL (1 << 25)
+#define DISPC_CONTROL_TDMUNUSEDBITS_UNCHANGED (2 << 25)
+#define DISPC_CONTROL_TDMCYCLEFORMAT (3 << 23)
+#define DISPC_CONTROL_TDMCYCLEFORMAT_1CYCPERPIX (0 << 23)
+#define DISPC_CONTROL_TDMCYCLEFORMAT_2CYCPERPIX (1 << 23)
+#define DISPC_CONTROL_TDMCYCLEFORMAT_3CYCPERPIX (2 << 23)
+#define DISPC_CONTROL_TDMCYCLEFORMAT_3CYCPER2PIX (3 << 23)
+#define DISPC_CONTROL_TDMPARALLELMODE (3 << 21)
+#define DISPC_CONTROL_TDMPARALLELMODE_8BPARAINT (0 << 21)
+#define DISPC_CONTROL_TDMPARALLELMODE_9BPARAINT (1 << 21)
+#define DISPC_CONTROL_TDMPARALLELMODE_12BPARAINT (2 << 21)
+#define DISPC_CONTROL_TDMPARALLELMODE_16BPARAINT (3 << 21)
+#define DISPC_CONTROL_TDMENABLE (1 << 20)
+#define DISPC_CONTROL_HT (7 << 17)
+#define DISPC_CONTROL_HT_SHIFT 17
+#define DISPC_CONTROL_GPOUT1 (1 << 16)
+#define DISPC_CONTROL_GPOUT0 (1 << 15)
+#define DISPC_CONTROL_GPIN1 (1 << 14)
+#define DISPC_CONTROL_GPIN0 (1 << 13)
+#define DISPC_CONTROL_OVERLAYOPTIMIZATION (1 << 12)
+#define DISPC_CONTROL_RFBIMODE (1 << 11)
+#define DISPC_CONTROL_SECURE (1 << 10)
+#define DISPC_CONTROL_TFTDATALINES (3 << 8)
+#define DISPC_CONTROL_TFTDATALINES_OALSB12B (0 << 8)
+#define DISPC_CONTROL_TFTDATALINES_OALSB16B (1 << 8)
+#define DISPC_CONTROL_TFTDATALINES_OALSB18B (2 << 8)
+#define DISPC_CONTROL_TFTDATALINES_OALSB24B (3 << 8)
+#define DISPC_CONTROL_TFTDITHERENABLE (1 << 7)
+#define DISPC_CONTROL_GODIGITAL (1 << 6)
+#define DISPC_CONTROL_GOLCD (1 << 5)
+#define DISPC_CONTROL_M8B (1 << 4)
+#define DISPC_CONTROL_STNTFT (1 << 3)
+#define DISPC_CONTROL_MONOCOLOR (1 << 2)
+#define DISPC_CONTROL_DIGITALENABLE (1 << 1)
+#define DISPC_CONTROL_LCDENABLE (1 << 0)
+
+#define DISPC_CONFIG_TCKDIGSELECTION (1 << 13)
+#define DISPC_CONFIG_TCKDIGENABLE (1 << 12)
+#define DISPC_CONFIG_TCKLCDSELECTION (1 << 11)
+#define DISPC_CONFIG_TCKLCDENABLE (1 << 10)
+#define DISPC_CONFIG_FUNCGATED (1 << 9)
+#define DISPC_CONFIG_ACBIASGATED (1 << 8)
+#define DISPC_CONFIG_VSYNCGATED (1 << 7)
+#define DISPC_CONFIG_HSYNCGATED (1 << 6)
+#define DISPC_CONFIG_PIXELCLOCKGATED (1 << 5)
+#define DISPC_CONFIG_PIXELDATAGATED (1 << 4)
+#define DISPC_CONFIG_PALETTEGAMMATABLE (1 << 3)
+#define DISPC_CONFIG_LOADMODE_FRDATLEFR (1 << 2)
+#define DISPC_CONFIG_LOADMODE_PGTABUSETB (1 << 1)
+#define DISPC_CONFIG_PIXELGATED (1 << 0)
+
+#define DISPC_CAPABLE_GFXGAMMATABLECAPABLE (1 << 9)
+#define DISPC_CAPABLE_GFXLAYERCAPABLE (1 << 8)
+#define DISPC_CAPABLE_GFXTRANSDSTCAPABLE (1 << 7)
+#define DISPC_CAPABLE_STNDITHERINGCAPABLE (1 << 6)
+#define DISPC_CAPABLE_TFTDITHERINGCAPABLE (1 << 5)
+#define DISPC_CAPABLE_VIDTRANSSRCCAPABLE (1 << 4)
+#define DISPC_CAPABLE_VIDLAYERCAPABLE (1 << 3)
+#define DISPC_CAPABLE_VIDVERTFIRCAPABLE (1 << 2)
+#define DISPC_CAPABLE_VIDHORFIRCAPABLE (1 << 1)
+#define DISPC_CAPABLE_VIDCAPABLE (1 << 0)
+
+#define DISPC_POL_FREQ_ONOFF (1 << 17)
+#define DISPC_POL_FREQ_RF (1 << 16)
+#define DISPC_POL_FREQ_IEO (1 << 15)
+#define DISPC_POL_FREQ_IPC (1 << 14)
+#define DISPC_POL_FREQ_IHS (1 << 13)
+#define DISPC_POL_FREQ_IVS (1 << 12)
+#define DISPC_POL_FREQ_ACBI (15 << 8)
+#define DISPC_POL_FREQ_ACBI_SHIFT 8
+#define DISPC_POL_FREQ_ACB 0xFF
+#define DISPC_POL_FREQ_ACB_SHIFT 0
+
+#define DISPC_TIMING_H_HBP (0xFF << 20)
+#define DISPC_TIMING_H_HBP_SHIFT 20
+#define DISPC_TIMING_H_HFP (0xFF << 8)
+#define DISPC_TIMING_H_HFP_SHIFT 8
+#define DISPC_TIMING_H_HSW (0x3F << 0)
+#define DISPC_TIMING_H_HSW_SHIFT 0
+
+#define DISPC_TIMING_V_VBP (0xFF << 20)
+#define DISPC_TIMING_V_VBP_SHIFT 20
+#define DISPC_TIMING_V_VFP (0xFF << 8)
+#define DISPC_TIMING_V_VFP_SHIFT 8
+#define DISPC_TIMING_V_VSW (0x3F << 0)
+#define DISPC_TIMING_V_VSW_SHIFT 0
+
+#define DISPC_DIVISOR_LCD (0xFF << 16)
+#define DISPC_DIVISOR_LCD_SHIFT 16
+#define DISPC_DIVISOR_PCD 0xFF
+#define DISPC_DIVISOR_PCD_SHIFT 0
+
+#define DISPC_SIZE_LCD_LPP (0x7FF << 16)
+#define DISPC_SIZE_LCD_LPP_SHIFT 16
+#define DISPC_SIZE_LCD_PPL 0x7FF
+#define DISPC_SIZE_LCD_PPL_SHIFT 0
+
+#define DISPC_SIZE_DIG_LPP (0x7FF << 16)
+#define DISPC_SIZE_DIG_LPP_SHIFT 16
+#define DISPC_SIZE_DIG_PPL 0x7FF
+#define DISPC_SIZE_DIG_PPL_SHIFT 0
+
+#define DISPC_GFX_POSITION_GFXPOSY (0x7FF << 16)
+#define DISPC_GFX_POSITION_GFXPOSY_SHIFT 16
+#define DISPC_GFX_POSITION_GFXPOSX 0x7FF
+#define DISPC_GFX_POSITION_GFXPOSX_SHIFT 0
+
+#define DISPC_GFX_SIZE_GFXSIZEY (0x7FF << 16)
+#define DISPC_GFX_SIZE_GFXSIZEY_SHIFT 16
+#define DISPC_GFX_SIZE_GFXSIZEX 0x7FF
+#define DISPC_GFX_SIZE_GFXSIZEX_SHIFT 0
+
+#define DISPC_GFX_ATTRIBUTES_GFXENDIANNESS (1 << 10)
+#define DISPC_GFX_ATTRIBUTES_GFXNIBBLEMODE (1 << 9)
+#define DISPC_GFX_ATTRIBUTES_GFXCHANNELOUT (1 << 8)
+#define DISPC_GFX_ATTRIBUTES_GFXBURSTSIZE (3 << 6)
+#define DISPC_GFX_ATTRIBUTES_GFXBURSTSIZE_BURST4X32 (0 << 6)
+#define DISPC_GFX_ATTRIBUTES_GFXBURSTSIZE_BURST8X32 (1 << 6)
+#define DISPC_GFX_ATTRIBUTES_GFXBURSTSIZE_BURST16X32 (2 << 6)
+#define DISPC_GFX_ATTRIBUTES_GFXREPLICATIONENABLE (1 << 5)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT (15 << 1)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT_BITMAP1 (0 << 1)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT_BITMAP2 (1 << 1)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT_BITMAP4 (2 << 1)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT_BITMAP8 (3 << 1)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT_RGB12 (4 << 1)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT_RGB16 (6 << 1)
+#define DISPC_GFX_ATTRIBUTES_GFXFORMAT_RGB24 (8 << 1)
+#define DISPC_GFX_ATTRIBUTES_ENABLE (1 << 0)
+
+#define DISPC_GFX_FIFO_THRESHOLD_HIGH (0x1FF << 16)
+#define DISPC_GFX_FIFO_THRESHOLD_HIGH_SHIFT 16
+#define DISPC_GFX_FIFO_THRESHOLD_LOW 0x1FF
+#define DISPC_GFX_FIFO_THRESHOLD_LOW_SHIFT 0
+
+#define DISPC_VID_POSITION_VIDPOSY (0x7FF << 16)
+#define DISPC_VID_POSITION_VIDPOSY_SHIFT 16
+#define DISPC_VID_POSITION_VIDPOSX 0x7FF
+#define DISPC_VID_POSITION_VIDPOSX_SHIFT 0
+
+#define DISPC_VID_SIZE_VIDSIZEY (0x7FF << 16)
+#define DISPC_VID_SIZE_VIDSIZEY_SHIFT 16
+#define DISPC_VID_SIZE_VIDSIZEX 0x7FF
+#define DISPC_VID_SIZE_VIDSIZEX_SHIFT 0
+
+#define DISPC_VID_ATTRIBUTES_VIDROWREPEATENABLE (1 << 18)
+#define DISPC_VID_ATTRIBUTES_VIDENDIANNESS (1 << 17)
+#define DISPC_VID_ATTRIBUTES_VIDCHANNELOUT (1 << 16)
+#define DISPC_VID_ATTRIBUTES_VIDBURSTSIZE (3 << 14)
+#define DISPC_VID_ATTRIBUTES_VIDBURSTSIZE_BURST4X32 (0 << 14)
+#define DISPC_VID_ATTRIBUTES_VIDBURSTSIZE_BURST8X32 (1 << 14)
+#define DISPC_VID_ATTRIBUTES_VIDBURSTSIZE_BURST16X32 (2 << 14)
+#define DISPC_VID_ATTRIBUTES_VIDROTATION (3 << 12)
+#define DISPC_VID_ATTRIBUTES_VIDROTATION_NOROT (0 << 12)
+#define DISPC_VID_ATTRIBUTES_VIDROTATION_ROT90 (1 << 12)
+#define DISPC_VID_ATTRIBUTES_VIDROTATION_ROT180 (2 << 12)
+#define DISPC_VID_ATTRIBUTES_VIDROTATION_ROT270 (3 << 12)
+#define DISPC_VID_ATTRIBUTES_VIDFULLRANGE (1 << 11)
+#define DISPC_VID_ATTRIBUTES_VIDREPLICATIONENABLE (1 << 10)
+#define DISPC_VID_ATTRIBUTES_VIDCOLORCONVENABLE (1 << 9)
+#define DISPC_VID_ATTRIBUTES_VIDVRESIZECONF (1 << 8)
+#define DISPC_VID_ATTRIBUTES_VIDHRESIZECONF (1 << 7)
+#define DISPC_VID_ATTRIBUTES_VIDRESIZEENABLE_VRESIZE (1 << 6)
+#define DISPC_VID_ATTRIBUTES_VIDRESIZEENABLE_HRESIZE (1 << 5)
+#define DISPC_VID_ATTRIBUTES_VIDFORMAT (15 << 1)
+#define DISPC_VID_ATTRIBUTES_VIDFORMAT_RGB16 (6 << 1)
+#define DISPC_VID_ATTRIBUTES_VIDFORMAT_YUV2 (10 << 1)
+#define DISPC_VID_ATTRIBUTES_VIDFORMAT_UYVY (11 << 1)
+#define DISPC_VID_ATTRIBUTES_ENABLE (1 << 0)
+
+#define DISPC_VID_PICTURE_SIZE_VIDORGSIZEY (0x7FF << 16)
+#define DISPC_VID_PICTURE_SIZE_VIDORGSIZEY_SHIFT 16
+#define DISPC_VID_PICTURE_SIZE_VIDORGSIZEX 0x7FF
+#define DISPC_VID_PICTURE_SIZE_VIDORGSIZEX_SHIFT 0
+#define VIDIOC_S_VID2 _IOWR ('V', 90, struct omap24xx_vid2_format)
+#define VIDIOC_S_VID2_DISABLE _IOWR ('V', 91, int)
+
+#endif /* ifndef OMAP24XXFB_H */
+
+#endif /* ifndef OMAP24XXCAM_H */
diff --git a/drivers/media/video/omap/sensor_if.h b/drivers/media/video/omap/sensor_if.h
index 984ba55..e595ccf 100644
--- a/drivers/media/video/omap/sensor_if.h
+++ b/drivers/media/video/omap/sensor_if.h
@@ -2,7 +2,7 @@
/*
* drivers/media/video/omap/sensor_if.h
*
- * Copyright (C) 2004 Texas Instruments, Inc.
+ * Copyright (C) 2004-2005 Texas Instruments, Inc.
*
* Sensor interface to OMAP camera capture drivers
* Sensor driver should implement this interface
@@ -21,29 +21,68 @@
#define LEN_SENSOR_NAME 31
+#define PAR_MODE_NOBT8 0
+#define PAR_MODE_NOBT10 1
+#define PAR_MODE_NOBT12 2
+#define PAR_MODE_BT8 4
+#define PAR_MODE_BT10 5
+
+#define SYNC_ACTIVE_HIGH 0
+#define SYNC_ACTIVE_LOW 1
+
+#define V4L2_BUF_TYPE_STILL_CAPTURE V4L2_BUF_TYPE_PRIVATE
+
struct camera_sensor {
unsigned int version;
char name[LEN_SENSOR_NAME + 1];
- void *(*init)(struct v4l2_pix_format *);
+ int parallel_mode; /* parallel I/F mode */
+ int hs_polarity; /* horizontal sync polarity */
+ int vs_polarity; /* vertical sync polarity */
+ int image_swap; /* image swap or not */
+ int bt_correction; /* BT correction enabled or not */
+
+ /* init the sensor with the passed pix format. A none zero private
+ pointer must be returned on success. The same pointer is passed
+ back for all other functions. This gives a sensor driver the
+ chance to handle multiple sensor. */
+ void *(*init)(struct v4l2_pix_format *, struct v4l2_pix_format *);
+ /* clean up the sensor */
int (*cleanup)(void *);
+ /* These are for power management */
int (*power_on)(void *);
int (*power_off)(void *);
+ /* Handle V4L2 fmt IOCTLs */
int (*enum_pixformat)(struct v4l2_fmtdesc *, void *);
int (*try_format) (struct v4l2_pix_format *, void *);
+ /* Calculated the needed xclk for the pix format passed and the
+ desired capture rate. */
unsigned long (*calc_xclk) (struct v4l2_pix_format *,
struct v4l2_fract *, void *);
+ /* Configure the sensor to generate the passed pix format at the
+ passed capture rate with the passed xclk */
int (*configure) (struct v4l2_pix_format *, unsigned long,
struct v4l2_fract *, void *);
-
+ /* These handle V4L2 control IOCTLs */
int (*query_control) (struct v4l2_queryctrl *, void *);
int (*get_control) (struct v4l2_control *, void *);
int (*set_control) (struct v4l2_control *, void *);
+ /* These are only for those sensors that use a different sensor context
+ for still image capture. A simple sensor driver doesn't have to
+ implement them. */
+ int (*try_format_still_capture) (struct v4l2_pix_format *, void *);
+ int (*configure_still_capture) (struct v4l2_pix_format *, unsigned long,
+ struct v4l2_fract *, void *);
+ unsigned long (*calc_xclk_still_capture) (struct v4l2_pix_format *,
+ struct v4l2_fract *, void *);
+ int (*enter_still_capture) (int, void *);
+ int (*exit_still_capture) (void *);
+
};
#endif
[-- Attachment #3: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply related [flat|nested] 8+ messages in thread