lists.zerezo.com
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Patch 10/16] OMAP3 camera driver ISP basic blocks
- Date: Mon, 30 Jun 2008 23:07:21 -0500
- From: Mohit Jalori <mjalori@xxxxxx>
- Subject: [Patch 10/16] OMAP3 camera driver ISP basic blocks
From: Mohit Jalori <mjalori@xxxxxx>
ARM: OMAP: OMAP34XXCAM: Camera Driver.
Adding OMAP 3 Camera Driver with basic ISP blocks.
Signed-off-by: Mohit Jalori <mjalori@xxxxxx>
---
drivers/media/video/Kconfig | 10
drivers/media/video/Makefile | 2
drivers/media/video/omap34xxcam.c | 1605 +++++++++++++++++++++++++++++++
drivers/media/video/omap34xxcam.h | 189 +++
drivers/media/video/isp/Makefile | 4
drivers/media/video/isp/Kconfig | 1
drivers/media/video/isp/isp.c | 1802 +++++++++++++++++++++++++++++++++++
drivers/media/video/isp/isp.h | 326 ++++++
drivers/media/video/isp/ispccdc.c | 1296 +++++++++++++++++++++++++
drivers/media/video/isp/ispccdc.h | 202 +++
drivers/media/video/isp/ispmmu.c | 742 ++++++++++++++
drivers/media/video/isp/ispmmu.h | 117 ++
drivers/media/video/isp/ispreg.h | 1281 ++++++++++++++++++++++++
include/asm-arm/arch-omap/isp_user.h | 151 ++
14 files changed, 7728 insertions(+)
--- a/drivers/media/video/Kconfig 2008-06-29 17:44:21.000000000 -0500
+++ b/drivers/media/video/Kconfig 2008-06-29 16:57:48.000000000 -0500
@@ -792,6 +792,16 @@ config VIDEO_CAFE_CCIC
CMOS camera controller. This is the controller found on first-
generation OLPC systems.
+config VIDEO_OMAP3
+ tristate "OMAP 3 Camera support"
+ select VIDEOBUF_GEN
+ select VIDEOBUF_DMA_SG
+ depends on VIDEO_V4L2 && ARCH_OMAP34XX
+ ---help---
+ Driver for an OMAP 3 camera controller.
+
+source "drivers/media/video/isp/Kconfig"
+
config VIDEO_OMAP2
tristate "OMAP 2 Camera support (EXPERIMENTAL)"
select VIDEOBUF_GEN
--- a/drivers/media/video/Makefile 2008-06-29 17:44:21.000000000 -0500
+++ b/drivers/media/video/Makefile 2008-06-29 16:57:48.000000000 -0500
@@ -105,6 +105,8 @@ obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_cc
obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
obj-$(CONFIG_VIDEO_OMAP2) += omap24xxcam.o omap24xxcam-dma.o
+obj-$(CONFIG_VIDEO_OMAP3) += omap34xxcam.o isp/
+
obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
obj-$(CONFIG_VIDEO_OV9640) += ov9640.o
--- /dev/null 2004-06-24 13:05:26.000000000 -0500
+++ b/drivers/media/video/omap34xxcam.c 2008-06-29 17:07:06.000000000 -0500
@@ -0,0 +1,1605 @@
+/*
+ * drivers/media/video/omap34xxcam.c
+ *
+ * Video-for-Linux (Version 2) Camera capture driver for OMAP34xx ISP.
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ * Copyright (C) 2008 Nokia.
+ *
+ * Contributors:
+ * Sameer Venkatraman <sameerv@xxxxxx>
+ * Mohit Jalori <mjalori@xxxxxx>
+ * Sakari Ailus <sakari.ailus@xxxxxxxxx>
+ * Tuukka Toivonen <tuukka.o.toivonen@xxxxxxxxx>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/pci.h> /* needed for videobufs */
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-common.h>
+
+#include "omap34xxcam.h"
+#include "isp/isp.h"
+#include "isp/ispmmu.h"
+#include "isp/ispreg.h"
+#include "isp/ispccdc.h"
+
+#define OMAP34XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
+
+/* global variables */
+static struct omap34xxcam_device *omap34xxcam;
+
+/* module parameters */
+static int capture_mem = 2592 * 1944 * 2 * 2;
+static int omap34xxcam_device_register(struct v4l2_int_device *s);
+static void omap34xxcam_device_unregister(struct v4l2_int_device *s);
+static int omap34xxcam_remove(struct platform_device *pdev);
+struct omap34xxcam_fh *camfh_saved;
+
+/*
+ *
+ * Sensor handling.
+ *
+ */
+
+/**
+ * omap34xxcam_slave_enable - Enable all slaves on device
+ * @vdev: per-video device data structure
+ *
+ * Power-up and configure camera sensor and sensor interface. On
+ * successful return (0), it's ready for capturing now.
+ */
+static int omap34xxcam_slave_power_set(struct omap34xxcam_videodev *vdev,
+ enum v4l2_power power)
+{
+ int rval = 0, i = OMAP34XXCAM_SLAVE_FLASH + 1;
+
+ if (power == V4L2_POWER_OFF)
+ goto out;
+
+ for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+ if (!vdev->slave[i])
+ continue;
+
+ rval = vidioc_int_s_power(vdev->slave[i], power);
+
+ if (rval) {
+ power = V4L2_POWER_OFF;
+ goto out;
+ }
+ }
+
+ return 0;
+
+out:
+ for (i--; i >= 0; i--) {
+ if (!vdev->slave[i])
+ continue;
+
+ vidioc_int_s_power(vdev->slave[i], power);
+ }
+
+ return rval;
+}
+
+/**
+ * omap34xxcam_update_vbq - Updates VBQ with completed input buffer
+ * @vb: ptr. to standard V4L2 video buffer structure
+ *
+ * Updates video buffer queue with completed buffer passed as
+ * input parameter. Also updates ISP H3A timestamp and field count
+ * statistics.
+ */
+int omap34xxcam_update_vbq(struct videobuf_buffer *vb)
+{
+ struct omap34xxcam_fh *fh = camfh_saved;
+ struct omap34xxcam_videodev *vdev = fh->vdev;
+ int rval = 0;
+
+ do_gettimeofday(&vb->ts);
+ vb->field_count = atomic_add_return(2, &fh->field_count);
+ vb->state = VIDEOBUF_DONE;
+
+ if (vdev->streaming)
+ rval = 1;
+
+ wake_up(&vb->done);
+
+ return rval;
+}
+
+/**
+ * omap34xxcam_vbq_setup - Calcs size and num of buffs allowed in queue
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @cnt: ptr to location to hold the count of buffers to be in the queue
+ * @size: ptr to location to hold the size of a frame
+ *
+ * Calculates the number of buffers of current image size that can be
+ * supported by the available capture memory.
+ */
+static int omap34xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
+ unsigned int *size)
+{
+ struct omap34xxcam_fh *fh = vbq->priv_data;
+ struct v4l2_format format;
+
+ if (*cnt <= 0)
+ *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
+
+ if (*cnt > VIDEO_MAX_FRAME)
+ *cnt = VIDEO_MAX_FRAME;
+
+ isp_g_fmt_cap(&format);
+ *size = format.fmt.pix.sizeimage;
+
+ /* accessing fh->cam->capture_mem is ok, it's constant */
+ while (*size * *cnt > fh->vdev->capture_mem)
+ (*cnt)--;
+
+ return 0;
+}
+
+/**
+ * omap34xxcam_vbq_release - Free resources for input VBQ and VB
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @vb: ptr to standard V4L2 video buffer structure
+ *
+ * Unmap and free all memory associated with input VBQ and VB, also
+ * unmap the address in ISP MMU. Reset the VB state.
+ */
+static void omap34xxcam_vbq_release(struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb)
+{
+ if (!vbq->streaming) {
+ isp_vbq_release(vbq, vb);
+ videobuf_dma_unmap(vbq, videobuf_to_dma(vb));
+ videobuf_dma_free(videobuf_to_dma(vb));
+ vb->state = VIDEOBUF_NEEDS_INIT;
+ }
+ return;
+}
+
+/**
+ * omap34xxcam_vbq_prepare - V4L2 video ops buf_prepare handler
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @vb: ptr to standard V4L2 video buffer structure
+ * @field: standard V4L2 field enum
+ *
+ * Verifies there is sufficient locked memory for the requested
+ * buffer, or if there is not, allocates, locks and initializes
+ * it.
+ */
+static int omap34xxcam_vbq_prepare(struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct v4l2_format format;
+ unsigned int size;
+ int err = 0;
+
+ isp_g_fmt_cap(&format);
+ size = format.fmt.pix.sizeimage;
+ /*
+ * Accessing pix here is okay since it's constant while
+ * streaming is on (and we only get called then).
+ */
+ if (vb->baddr) {
+ /* This is a userspace buffer. */
+ if (size > vb->bsize)
+ /* The buffer isn't big enough. */
+ err = -EINVAL;
+ else {
+ vb->size = size;
+ vb->bsize = vb->size;
+ }
+ } else {
+ if (vb->state != VIDEOBUF_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.
+ */
+ omap34xxcam_vbq_release(vbq, vb);
+ vb->size = size;
+ }
+ } else {
+ /* We need to allocate a new kernel bounce buffer. */
+ vb->size = size;
+ }
+ }
+
+ if (err)
+ return err;
+
+ vb->width = format.fmt.pix.width;
+ vb->height = format.fmt.pix.height;
+ vb->field = field;
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ err = videobuf_iolock(vbq, vb, NULL);
+ if (!err) {
+ /* isp_addr will be stored locally inside isp code */
+ err = isp_vbq_prepare(vbq, vb, field);
+ }
+ }
+
+ if (!err)
+ vb->state = VIDEOBUF_PREPARED;
+ else
+ omap34xxcam_vbq_release(vbq, vb);
+
+ return err;
+
+}
+
+/**
+ * omap34xxcam_vbq_queue - V4L2 video ops buf_queue handler
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @vb: ptr to standard V4L2 video buffer structure
+ *
+ * Maps the video buffer to sgdma and through the isp, sets
+ * the isp buffer done callback and sets the video buffer state
+ * to active.
+ */
+static void omap34xxcam_vbq_queue(struct videobuf_queue *vbq,
+ struct videobuf_buffer *vb)
+{
+ struct omap34xxcam_fh *fh = vbq->priv_data;
+ struct omap34xxcam_videodev *vdev = fh->vdev;
+ enum videobuf_state state = vb->state;
+ isp_vbq_callback_ptr func_ptr;
+ int err = 0;
+
+ camfh_saved = fh;
+
+ func_ptr = omap34xxcam_update_vbq;
+ vb->state = VIDEOBUF_ACTIVE;
+
+ err = isp_sgdma_queue(videobuf_to_dma(vb),
+ vb, 0, &vdev->cam->dma_notify, func_ptr);
+ if (err) {
+ dev_dbg(vdev->cam->dev, "vbq queue failed\n");
+ vb->state = state;
+ }
+
+}
+
+static struct videobuf_queue_ops omap34xxcam_vbq_ops = {
+ .buf_setup = omap34xxcam_vbq_setup,
+ .buf_prepare = omap34xxcam_vbq_prepare,
+ .buf_queue = omap34xxcam_vbq_queue,
+ .buf_release = omap34xxcam_vbq_release,
+};
+
+/*
+ *
+ * IOCTL interface.
+ *
+ */
+
+/**
+ * vidioc_querycap - V4L2 query capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @cap: ptr to standard V4L2 capability structure
+ *
+ * Fill in the V4L2 capabliity structure for the camera device
+ */
+static int vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+
+ strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, vdev->vfd->name, sizeof(cap->card));
+ cap->version = OMAP34XXCAM_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+/**
+ * vidioc_enum_fmt_cap - V4L2 enumerate format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format description structure
+ *
+ * Fills in enumerate format capabilities information for sensor (if SOC
+ * sensor attached) or ISP (if raw sensor attached).
+ */
+static int vidioc_enum_fmt_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ int rval;
+
+ if (vdev->vdev_sensor_config.sensor_isp)
+ rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, f);
+ else
+ rval = isp_enum_fmt_cap(f);
+
+ return rval;
+}
+
+/**
+ * vidioc_g_fmt_cap - V4L2 get format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format structure
+ *
+ * Fills in format capabilities for sensor (if SOC sensor attached) or ISP
+ * (if raw sensor attached).
+ */
+static int vidioc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+
+ mutex_lock(&vdev->mutex);
+ f->fmt.pix = ofh->pix;
+ mutex_unlock(&vdev->mutex);
+
+ return 0;
+}
+
+/**
+ * vidioc_s_fmt_cap - V4L2 set format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format structure
+ *
+ * Attempts to set input format with the sensor driver (first) and then the
+ * ISP. Returns the return code from vidioc_g_fmt_cap().
+ */
+static int vidioc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_pix_format pix_tmp;
+ int rval;
+
+ mutex_lock(&vdev->mutex);
+ if (vdev->streaming) {
+ rval = -EBUSY;
+ goto out;
+ }
+
+ pix_tmp.width = f->fmt.pix.width;
+ pix_tmp.height = f->fmt.pix.height;
+ pix_tmp.pixelformat = f->fmt.pix.pixelformat;
+ /* Always negotiate with the sensor first */
+ rval = vidioc_int_s_fmt_cap(vdev->vdev_sensor, f);
+ if (rval)
+ goto out;
+
+ /* Negotiate with OMAP3 ISP */
+ rval = isp_s_fmt_cap(pix, &pix_tmp);
+out:
+ mutex_unlock(&vdev->mutex);
+
+ if (!rval) {
+ mutex_lock(&ofh->vbq.vb_lock);
+ *pix = ofh->pix = pix_tmp;
+ mutex_unlock(&ofh->vbq.vb_lock);
+ }
+
+ return rval;
+}
+
+/**
+ * vidioc_try_fmt_cap - V4L2 try format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format structure
+ *
+ * Checks if the given format is supported by the sensor driver and
+ * by the ISP.
+ */
+static int vidioc_try_fmt_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_pix_format pix_tmp;
+ int rval;
+
+ mutex_lock(&vdev->mutex);
+ pix_tmp.width = f->fmt.pix.width;
+ pix_tmp.height = f->fmt.pix.height;
+ pix_tmp.pixelformat = f->fmt.pix.pixelformat;
+ rval = vidioc_int_try_fmt_cap(vdev->vdev_sensor, f);
+ if (rval)
+ goto out;
+
+ rval = isp_try_fmt_cap(pix, &pix_tmp);
+ *pix = pix_tmp;
+
+out:
+ mutex_unlock(&vdev->mutex);
+ return rval;
+}
+
+/**
+ * vidioc_reqbufs - V4L2 request buffers IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 request buffers structure
+ *
+ * Attempts to get a buffer from the buffer queue associated with the
+ * fh through the video buffer library API.
+ */
+static int vidioc_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *b)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ int rval;
+
+ mutex_lock(&vdev->mutex);
+ if (vdev->streaming) {
+ mutex_unlock(&vdev->mutex);
+ return -EBUSY;
+ }
+
+ mutex_unlock(&vdev->mutex);
+
+ rval = videobuf_reqbufs(&ofh->vbq, b);
+
+ /*
+ * Either videobuf_reqbufs failed or the buffers are not
+ * memory-mapped (which would need special attention).
+ */
+ if (rval < 0 || b->memory != V4L2_MEMORY_MMAP)
+ goto out;
+
+out:
+ return rval;
+}
+
+/**
+ * vidioc_querybuf - V4L2 query buffer IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 buffer structure
+ *
+ * Attempts to fill in the v4l2_buffer structure for the buffer queue
+ * associated with the fh through the video buffer library API.
+ */
+static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct omap34xxcam_fh *ofh = fh;
+
+ return videobuf_querybuf(&ofh->vbq, b);
+}
+
+/**
+ * vidioc_qbuf - V4L2 queue buffer IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 buffer structure
+ *
+ * Attempts to queue the v4l2_buffer on the buffer queue
+ * associated with the fh through the video buffer library API.
+ */
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct omap34xxcam_fh *ofh = fh;
+
+ return videobuf_qbuf(&ofh->vbq, b);
+}
+
+/**
+ * vidioc_dqbuf - V4L2 dequeue buffer IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 buffer structure
+ *
+ * Attempts to dequeue the v4l2_buffer from the buffer queue
+ * associated with the fh through the video buffer library API. If the
+ * buffer is a user space buffer, then this function will also requeue it,
+ * as user does not expect to do this.
+ */
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct omap34xxcam_fh *ofh = fh;
+
+ return videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
+}
+
+/**
+ * vidioc_streamon - V4L2 streamon IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: V4L2 buffer type
+ *
+ * Attempts to start streaming by enabling the sensor interface and turning
+ * on video buffer streaming through the video buffer library API. Upon
+ * success the function returns 0, otherwise an error code is returned.
+ */
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct omap34xxcam_device *cam = vdev->cam;
+ int rval;
+
+ mutex_lock(&vdev->mutex);
+ if (vdev->streaming) {
+ rval = -EBUSY;
+ goto out;
+ }
+
+ rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_RESUME);
+ if (rval) {
+ dev_dbg(vdev->cam->dev, "omap34xxcam_slave_power_set failed\n");
+ goto out;
+ }
+ /* Configure sensor and start streaming */
+ rval = vidioc_int_init(vdev->vdev_sensor);
+ if (rval) {
+ dev_dbg(vdev->cam->dev, "vidioc_int_init failed\n");
+ goto out;
+ }
+
+ cam->dma_notify = 1;
+ isp_sgdma_init();
+ rval = videobuf_streamon(&ofh->vbq);
+ if (!rval)
+ vdev->streaming = file;
+
+out:
+ mutex_unlock(&vdev->mutex);
+
+ return rval;
+}
+
+/**
+ * vidioc_streamoff - V4L2 streamoff IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: V4L2 buffer type
+ *
+ * Attempts to stop streaming by flushing all scheduled work, waiting on
+ * any queued buffers to complete and then stopping the ISP and turning
+ * off video buffer streaming through the video buffer library API. Upon
+ * success the function returns 0, otherwise an error code is returned.
+ */
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct videobuf_queue *q = &ofh->vbq;
+ int rval;
+
+ isp_stop();
+ rval = videobuf_streamoff(q);
+ if (!rval) {
+ mutex_lock(&vdev->mutex);
+ vdev->streaming = NULL;
+ mutex_unlock(&vdev->mutex);
+ }
+
+ omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY);
+
+ return rval;
+}
+
+/**
+ * vidioc_enum_input - V4L2 enumerate input IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @inp: V4L2 input type information structure
+ *
+ * Fills in v4l2_input structure. Returns 0.
+ */
+static int vidioc_enum_input(struct file *file, void *fh,
+ struct v4l2_input *inp)
+{
+ if (inp->index > 0)
+ return -EINVAL;
+
+ strlcpy(inp->name, "camera", sizeof(inp->name));
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+ return 0;
+}
+
+/**
+ * vidioc_g_input - V4L2 get input IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: address to hold index of input supported
+ *
+ * Sets index to 0.
+ */
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+ *i = 0;
+
+ return 0;
+}
+
+/**
+ * vidioc_s_input - V4L2 set input IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: index of input selected
+ *
+ * 0 is only index supported.
+ */
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * vidioc_queryctrl - V4L2 query control IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 query control ioctl structure
+ *
+ * If the requested control is supported, returns the control information
+ * in the v4l2_queryctrl structure. Otherwise, returns -EINVAL if the
+ * control is not supported. If the sensor being used is a "smart sensor",
+ * this request is passed to the sensor driver, otherwise the ISP is
+ * queried and if it does not support the requested control, the request
+ * is forwarded to the "raw" sensor driver to see if it supports it.
+ */
+static int vidioc_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *a)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ int rval;
+
+ mutex_lock(&vdev->mutex);
+ if (vdev->vdev_sensor_config.sensor_isp) {
+ rval = vidioc_int_queryctrl(vdev->vdev_sensor, a);
+ } else {
+ rval = isp_queryctrl(a);
+ if (rval) {
+ /* ISP does not support, check sensor */
+ rval = vidioc_int_queryctrl(vdev->vdev_sensor, a);
+ }
+ }
+ mutex_unlock(&vdev->mutex);
+
+ return rval;
+}
+
+/**
+ * vidioc_g_ctrl - V4L2 get control IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 control structure
+ *
+ * If the sensor being used is a "smart sensor",
+ * this request is passed to the sensor driver, otherwise the ISP is
+ * queried and if it does not support the requested control, the request
+ * is forwarded to the "raw" sensor driver to see if it supports it.
+ * If one of these supports the control, the current value of the control
+ * is returned in the v4l2_control structure. Otherwise, -EINVAL is
+ * returned if the control is not supported.
+ */
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *a)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ int rval;
+
+ mutex_lock(&vdev->mutex);
+ if (vdev->vdev_sensor_config.sensor_isp) {
+ rval = vidioc_int_g_ctrl(vdev->vdev_sensor, a);
+ } else {
+ rval = isp_g_ctrl(a);
+ /* If control not supported on ISP, try sensor */
+ if (rval)
+ rval = vidioc_int_g_ctrl(vdev->vdev_sensor, a);
+ }
+ mutex_unlock(&vdev->mutex);
+
+ return rval;
+}
+
+/**
+ * vidioc_s_ctrl - V4L2 set control IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 control structure
+ *
+ * If the sensor being used is a "smart sensor", this request is passed to
+ * the sensor driver. Otherwise, the ISP is queried and if it does not
+ * support the requested control, the request is forwarded to the "raw"
+ * sensor driver to see if it supports it.
+ * If one of these supports the control, the current value of the control
+ * is returned in the v4l2_control structure. Otherwise, -EINVAL is
+ * returned if the control is not supported.
+ */
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ int rval;
+
+ mutex_lock(&vdev->mutex);
+ if (vdev->vdev_sensor_config.sensor_isp) {
+ rval = vidioc_int_s_ctrl(vdev->vdev_sensor, a);
+ } else {
+ rval = isp_s_ctrl(a);
+ /* If control not supported on ISP, try sensor */
+ if (rval)
+ rval = vidioc_int_s_ctrl(vdev->vdev_sensor, a);
+ }
+ mutex_unlock(&vdev->mutex);
+
+ return rval;
+}
+
+/**
+ * vidioc_g_parm - V4L2 get parameters IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 stream parameters structure
+ *
+ * If request is for video capture buffer type, handles request by
+ * forwarding to sensor driver.
+ */
+static int vidioc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ int rval;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ mutex_lock(&vdev->mutex);
+ rval = vidioc_int_g_parm(vdev->vdev_sensor, a);
+ mutex_unlock(&vdev->mutex);
+
+ return rval;
+}
+
+/**
+ * vidioc_s_parm - V4L2 set parameters IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 stream parameters structure
+ *
+ * If request is for video capture buffer type, handles request by
+ * first getting current stream parameters from sensor, then forwarding
+ * request to set new parameters to sensor driver. It then attempts to
+ * enable the sensor interface with the new parameters. If this fails, it
+ * reverts back to the previous parameters.
+ */
+static int vidioc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct v4l2_streamparm old_streamparm;
+ int rval;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ mutex_lock(&vdev->mutex);
+ if (vdev->streaming) {
+ rval = -EBUSY;
+ goto out;
+ }
+
+ old_streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ rval = vidioc_int_g_parm(vdev->vdev_sensor, &old_streamparm);
+ if (rval)
+ goto out;
+
+ rval = vidioc_int_s_parm(vdev->vdev_sensor, a);
+ if (rval)
+ goto out;
+
+out:
+ mutex_unlock(&vdev->mutex);
+
+ return rval;
+}
+
+/**
+ * vidioc_cropcap - V4L2 crop capture IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 crop capture structure
+ *
+ * If using a "smart" sensor, just forwards request to the sensor driver,
+ * otherwise fills in the v4l2_cropcap values locally.
+ */
+static int vidioc_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct v4l2_cropcap *cropcap = a;
+ int rval;
+
+ if (vdev->vdev_sensor_config.sensor_isp) {
+ rval = vidioc_int_cropcap(vdev->vdev_sensor, a);
+ } else {
+ cropcap->bounds.left = cropcap->bounds.top = 0;
+ cropcap->bounds.width = ofh->pix.width;
+ cropcap->bounds.height = ofh->pix.height;
+ cropcap->defrect = cropcap->bounds;
+ cropcap->pixelaspect.numerator = 1;
+ cropcap->pixelaspect.denominator = 1;
+ rval = 0;
+ }
+ return rval;
+}
+
+/**
+ * vidioc_g_crop - V4L2 get capture crop IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 crop structure
+ *
+ * If using a "smart" sensor, just forwards request to the sensor driver,
+ * otherwise calls the isp functions to fill in current crop values.
+ */
+static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ int rval = 0;
+
+ if (vdev->vdev_sensor_config.sensor_isp)
+ rval = vidioc_int_g_crop(vdev->vdev_sensor, a);
+ else
+ rval = isp_g_crop(a);
+
+ return rval;
+}
+
+/**
+ * vidioc_s_crop - V4L2 set capture crop IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 crop structure
+ *
+ * If using a "smart" sensor, just forwards request to the sensor driver,
+ * otherwise calls the isp functions to set the current crop values.
+ */
+static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+ struct omap34xxcam_fh *ofh = fh;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ struct v4l2_pix_format *pix = &ofh->pix;
+ int rval = 0;
+
+ if (vdev->vdev_sensor_config.sensor_isp)
+ rval = vidioc_int_s_crop(vdev->vdev_sensor, a);
+ else
+ rval = isp_s_crop(a, pix);
+
+ return rval;
+}
+
+/*
+ *
+ * File operations.
+ *
+ */
+
+/**
+ * omap34xxcam_poll - file operations poll handler
+ * @file: ptr. to system file structure
+ * @wait: system poll table structure
+ *
+ */
+static unsigned int omap34xxcam_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct omap34xxcam_fh *fh = file->private_data;
+ struct omap34xxcam_videodev *vdev = fh->vdev;
+ struct videobuf_buffer *vb;
+
+ mutex_lock(&vdev->mutex);
+ if (vdev->streaming != file) {
+ mutex_unlock(&vdev->mutex);
+ return POLLERR;
+ }
+ mutex_unlock(&vdev->mutex);
+
+ mutex_lock(&fh->vbq.vb_lock);
+ if (list_empty(&fh->vbq.stream)) {
+ mutex_unlock(&fh->vbq.vb_lock);
+ return POLLERR;
+ }
+ vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
+ mutex_unlock(&fh->vbq.vb_lock);
+
+ poll_wait(file, &vb->done, wait);
+
+ if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+/**
+ * omap34xxcam_mmap - file operations mmap handler
+ * @file: ptr. to system file structure
+ * @vma: system virt. mem. area structure
+ *
+ * Maps a virtual memory area via the video buffer API
+ */
+static int omap34xxcam_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct omap34xxcam_fh *fh = file->private_data;
+
+ return videobuf_mmap_mapper(&fh->vbq, vma);
+}
+
+/**
+ * omap34xxcam_open - file operations open handler
+ * @inode: ptr. to system inode structure
+ * @file: ptr. to system file structure
+ *
+ * Allocates and initializes the per-filehandle data (omap34xxcam_fh),
+ * enables the sensor, opens/initializes the ISP interface and the
+ * video buffer queue. Note that this function will allow multiple
+ * file handles to be open simultaneously, however only the first
+ * handle opened will initialize the ISP. It is the application
+ * responsibility to only use one handle for streaming and the others
+ * for control only.
+ * This function returns 0 upon success and -ENODEV upon error.
+ */
+static int omap34xxcam_open(struct inode *inode, struct file *file)
+{
+ struct omap34xxcam_videodev *vdev = NULL;
+ struct omap34xxcam_device *cam = omap34xxcam;
+ struct omap34xxcam_fh *fh;
+ struct v4l2_format format;
+ int i;
+
+ for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
+ if (cam->vdevs[i].vfd
+ && cam->vdevs[i].vfd->minor == iminor(inode)) {
+ vdev = &cam->vdevs[i];
+ break;
+ }
+ }
+
+ if (!vdev || !vdev->vfd)
+ return -ENODEV;
+
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (fh == NULL)
+ return -ENOMEM;
+
+ mutex_lock(&vdev->mutex);
+ for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+ if (vdev->slave[i]
+ && !try_module_get(vdev->slave[i]->module)) {
+ mutex_unlock(&vdev->mutex);
+ goto out_try_module_get;
+ }
+ }
+
+ if (atomic_inc_return(&vdev->users) == 1) {
+ isp_get();
+ isp_open();
+ if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON)) {
+ mutex_unlock(&vdev->mutex);
+ goto out_try_module_get;
+ }
+ if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY)) {
+ mutex_unlock(&vdev->mutex);
+ goto out_try_module_get;
+ }
+ }
+
+ mutex_unlock(&vdev->mutex);
+ fh->vdev = vdev;
+ mutex_lock(&vdev->mutex);
+
+ /* FIXME: Check that we have sensor now... */
+ if (vdev->vdev_sensor_config.sensor_isp)
+ vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
+ else
+ isp_g_fmt_cap(&format);
+
+ mutex_unlock(&vdev->mutex);
+ /* FIXME: how about fh->pix when there are more users? */
+ fh->pix = format.fmt.pix;
+
+ file->private_data = fh;
+
+ spin_lock_init(&fh->vbq_lock);
+
+ videobuf_queue_sg_init(&fh->vbq, &omap34xxcam_vbq_ops, NULL,
+ &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), fh);
+
+ return 0;
+
+out_try_module_get:
+ for (i--; i >= 0; i--)
+ if (vdev->slave[i])
+ module_put(vdev->slave[i]->module);
+
+ isp_close();
+ isp_put();
+ kfree(fh);
+
+ return -ENODEV;
+}
+
+/**
+ * omap34xxcam_release - file operations release handler
+ * @inode: ptr. to system inode structure
+ * @file: ptr. to system file structure
+ *
+ * Complement of omap34xxcam_open. This function will flush any scheduled
+ * work, disable the sensor, close the ISP interface, stop the
+ * video buffer queue from streaming and free the per-filehandle data
+ * (omap34xxcam_fh). Note that because multiple open file handles
+ * are allowed, this function will only close the ISP and disable the
+ * sensor when the last open file handle (by count) is closed.
+ * This function returns 0.
+ */
+static int omap34xxcam_release(struct inode *inode, struct file *file)
+{
+ struct omap34xxcam_fh *fh = file->private_data;
+ struct omap34xxcam_videodev *vdev = fh->vdev;
+ int i;
+
+ mutex_lock(&vdev->mutex);
+ if (vdev->streaming == file) {
+ isp_stop();
+ videobuf_streamoff(&fh->vbq);
+ omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY);
+ vdev->streaming = NULL;
+ }
+
+ if (atomic_dec_return(&vdev->users) == 0) {
+ omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF);
+ isp_close();
+ isp_put();
+ }
+ mutex_unlock(&vdev->mutex);
+
+ file->private_data = NULL;
+
+ for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++)
+ if (vdev->slave[i])
+ module_put(vdev->slave[i]->module);
+
+ kfree(fh);
+
+ return 0;
+}
+
+/**
+ * omap34xxcam_handle_private - private IOCTL handler
+ * @inode: ptr. to system inode structure
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @cmd: ioctl cmd value
+ * @arg: ioctl arg value
+ *
+ * If the sensor being used is a "smart sensor", this request is returned to
+ * caller with -EINVAL err code. Otherwise if the control id is the private
+ * VIDIOC_PRIVATE_ISP_AEWB_REQ to update the analog gain or exposure,
+ * then this request is forwared directly to the sensor to incorporate the
+ * feedback. The request is then passed on to the ISP private IOCTL handler,
+ * isp_handle_private()
+ */
+static int omap34xxcam_handle_private(struct file *file, void *fh,
+ int cmd, void *arg)
+{
+ struct omap34xxcam_fh *ofh = file->private_data;
+ struct omap34xxcam_videodev *vdev = ofh->vdev;
+ int rval;
+
+ mutex_lock(&vdev->mutex);
+
+ if (vdev->vdev_sensor_config.sensor_isp) {
+ rval = -EINVAL;
+ } else {
+ switch (cmd) {
+ default:
+ rval = isp_handle_private(cmd, arg);
+ }
+ }
+
+ mutex_unlock(&vdev->mutex);
+ return rval;
+}
+
+/**
+ * omap34xxcam_unlocked_ioctl - unlocked (unserialized) IOCTL handler
+ * @file: ptr. to system file structure
+ * @cmd: ioctl cmd value
+ * @arg: ioctl arg value
+ *
+ * Unlocked (unserialized) ioctl handler for the camera driver.
+ * Checks if the IOCTL is in the private ioctl range, and if so
+ * calls the local private ioctl handler omap34xxcam_handle_private(),
+ * otherwise it calls the V4L2 provided ioctl handler (video_ioctl2).
+ */
+static long omap34xxcam_unlocked_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return (long)video_ioctl2(file->f_dentry->d_inode, file, cmd, arg);
+}
+
+static struct file_operations omap34xxcam_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .unlocked_ioctl = omap34xxcam_unlocked_ioctl,
+ .poll = omap34xxcam_poll,
+ .mmap = omap34xxcam_mmap,
+ .open = omap34xxcam_open,
+ .release = omap34xxcam_release,
+};
+
+/**
+ * omap34xxcam_device_unregister - V4L2 detach handler
+ * @s: ptr. to standard V4L2 device information structure
+ *
+ * Detach sensor and unregister and release the video device.
+ */
+static void omap34xxcam_device_unregister(struct v4l2_int_device *s)
+{
+ struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+ struct omap34xxcam_hw_config hwc;
+
+ BUG_ON(vidioc_int_g_priv(s, &hwc) < 0);
+
+ if (vdev->slave[hwc.dev_type]) {
+ vdev->slave[hwc.dev_type] = NULL;
+ vdev->slaves--;
+ }
+
+ if (vdev->slaves == 0 && vdev->vfd) {
+ if (vdev->vfd->minor == -1) {
+ /*
+ * The device was never registered, so release the
+ * video_device struct directly.
+ */
+ video_device_release(vdev->vfd);
+ } else {
+ /*
+ * The unregister function will release the
+ * video_device struct as well as
+ * unregistering it.
+ */
+ video_unregister_device(vdev->vfd);
+ }
+ vdev->vfd = NULL;
+ }
+
+}
+
+/**
+ * omap34xxcam_device_register - V4L2 attach handler
+ * @s: ptr. to standard V4L2 device information structure
+ *
+ * Allocates and initializes the V4L2 video_device structure, initializes
+ * the sensor, and finally registers the device with V4L2 based on the
+ * video_device structure.
+ *
+ * Returns 0 on success, otherwise an appropriate error code on
+ * failure.
+ */
+static int omap34xxcam_device_register(struct v4l2_int_device *s)
+{
+ struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+ struct omap34xxcam_device *cam = vdev->cam;
+ struct omap34xxcam_hw_config hwc;
+ struct video_device *vfd;
+ int rval, i;
+
+ /* We need to check rval just once. The place is here. */
+ if (vidioc_int_g_priv(s, &hwc))
+ return -ENODEV;
+
+ dev_info(cam->dev, "vdev index %d, slave index %d\n",
+ vdev->index, hwc.dev_index);
+
+ if (vdev->index != hwc.dev_index)
+ return -ENODEV;
+
+ if (hwc.dev_type < 0 || hwc.dev_type > OMAP34XXCAM_SLAVE_FLASH)
+ return -EINVAL;
+
+ if (vdev->slave[hwc.dev_type])
+ return -EBUSY;
+
+ mutex_lock(&vdev->mutex);
+ if (atomic_read(&vdev->users)) {
+ dev_info(cam->dev, "we're open (%d), can't register\n",
+ atomic_read(&vdev->users));
+ mutex_unlock(&vdev->mutex);
+ return -EBUSY;
+ }
+
+ /* Are we the first slave? */
+ if (vdev->slaves == 0) {
+
+ /* initialize the video_device struct */
+ vfd = vdev->vfd = video_device_alloc();
+ if (!vfd) {
+ dev_err(cam->dev,
+ "could not allocate video device struct\n");
+ return -ENOMEM;
+ }
+ vfd->release = video_device_release;
+
+ vfd->dev = cam->dev;
+
+ vfd->type = VID_TYPE_CAPTURE;
+ vfd->fops = &omap34xxcam_fops;
+ vfd->priv = vdev;
+
+ vfd->vidioc_querycap = vidioc_querycap;
+ vfd->vidioc_enum_fmt_cap = vidioc_enum_fmt_cap;
+ vfd->vidioc_g_fmt_cap = vidioc_g_fmt_cap;
+ vfd->vidioc_s_fmt_cap = vidioc_s_fmt_cap;
+ vfd->vidioc_try_fmt_cap = vidioc_try_fmt_cap;
+ vfd->vidioc_reqbufs = vidioc_reqbufs;
+ vfd->vidioc_querybuf = vidioc_querybuf;
+ vfd->vidioc_qbuf = vidioc_qbuf;
+ vfd->vidioc_dqbuf = vidioc_dqbuf;
+ vfd->vidioc_streamon = vidioc_streamon;
+ vfd->vidioc_streamoff = vidioc_streamoff;
+ vfd->vidioc_enum_input = vidioc_enum_input;
+ vfd->vidioc_g_input = vidioc_g_input;
+ vfd->vidioc_s_input = vidioc_s_input;
+ vfd->vidioc_queryctrl = vidioc_queryctrl;
+ vfd->vidioc_g_ctrl = vidioc_g_ctrl;
+ vfd->vidioc_s_ctrl = vidioc_s_ctrl;
+ vfd->vidioc_g_parm = vidioc_g_parm;
+ vfd->vidioc_s_parm = vidioc_s_parm;
+ vfd->vidioc_cropcap = vidioc_cropcap;
+ vfd->vidioc_g_crop = vidioc_g_crop;
+ vfd->vidioc_s_crop = vidioc_s_crop;
+ vfd->vidioc_default = omap34xxcam_handle_private;
+
+ if (video_register_device(vfd, VFL_TYPE_GRABBER,
+ hwc.dev_minor) < 0) {
+ dev_err(cam->dev,
+ "could not register V4L device\n");
+ vfd->minor = -1;
+ rval = -EBUSY;
+ goto err;
+ }
+ dev_info(cam->dev,
+ "registered device video%d\n", vfd->minor);
+ } else {
+ vfd = vdev->vfd;
+ }
+
+ vdev->slaves++;
+ vdev->slave[hwc.dev_type] = s;
+ vdev->slave_config[hwc.dev_type] = hwc;
+ dev_info(cam->dev, "registering device %s (%d) to video%d\n",
+ s->name, hwc.dev_type, vfd->minor);
+
+ isp_get();
+ rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON);
+ omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF);
+ isp_put();
+
+ if (rval)
+ goto err;
+ strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
+ for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+ strlcat(vfd->name, "/", sizeof(vfd->name));
+ if (!vdev->slave[i])
+ continue;
+ strlcat(vfd->name, vdev->slave[i]->name, sizeof(vfd->name));
+ }
+
+ mutex_unlock(&vdev->mutex);
+
+ dev_info(cam->dev, "video%d is now %s\n", vfd->minor, vfd->name);
+ return 0;
+
+err:
+ if (s == vdev->slave[hwc.dev_type]) {
+ vdev->slave[hwc.dev_type] = NULL;
+ vdev->slaves--;
+ }
+
+ mutex_unlock(&vdev->mutex);
+ omap34xxcam_device_unregister(s);
+
+ return rval;
+}
+
+static struct v4l2_int_master omap34xxcam_master = {
+ .attach = omap34xxcam_device_register,
+ .detach = omap34xxcam_device_unregister,
+};
+
+/*
+ *
+ * Driver Suspend/Resume
+ *
+ */
+
+#ifdef CONFIG_PM
+/**
+ * omap34xxcam_suspend - platform driver PM suspend handler
+ * @pdev: ptr. to platform level device information structure
+ * @state: power state
+ *
+ * If applicable, stop capture and disable sensor.
+ *
+ * Returns 0 always
+ */
+static int omap34xxcam_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct omap34xxcam_videodev *vdev = platform_get_drvdata(pdev);
+
+ if (atomic_read(&vdev->users) == 0)
+ return 0;
+
+ if (vdev->streaming) {
+ isp_stop();
+ omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF);
+ }
+
+ return 0;
+}
+
+/**
+ * omap34xxcam_resume - platform driver PM resume handler
+ * @pdev: ptr. to platform level device information structure
+ *
+ * If applicable, resume capture and enable sensor.
+ *
+ * Returns 0 always
+ */
+static int omap34xxcam_resume(struct platform_device *pdev)
+{
+ struct omap34xxcam_videodev *vdev = platform_get_drvdata(pdev);
+
+ if (atomic_read(&vdev->users) == 0)
+ return 0;
+
+ if (vdev->streaming) {
+ omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON);
+ isp_start();
+ }
+
+ return 0;
+}
+#endif
+
+/*
+ *
+ * Driver initialisation and deinitialisation.
+ *
+ */
+
+/**
+ * omap34xxcam_probe - platform driver probe handler
+ * @pdev: ptr. to platform level device information structure
+ *
+ * Allocates and initializes camera device information structure
+ * (omap34xxcam_device), maps the device registers and gets the
+ * device IRQ. Registers the device as a V4L2 client.
+ *
+ * Returns 0 on success or -ENODEV on failure.
+ */
+static int omap34xxcam_probe(struct platform_device *pdev)
+{
+ struct omap34xxcam_device *cam;
+ struct resource *mem;
+ struct isp_sysc isp_sysconfig;
+ int irq;
+ int i;
+
+ cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+ if (!cam) {
+ dev_err(&pdev->dev, "could not allocate memory\n");
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, cam);
+
+ cam->dev = &pdev->dev;
+ /*
+ * 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 */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(cam->dev, "no mem resource?\n");
+ goto err;
+ }
+
+ if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,
+ pdev->name)) {
+ dev_err(cam->dev,
+ "cannot reserve camera register I/O region\n");
+ goto err;
+
+ }
+ cam->mmio_base_phys = mem->start;
+ cam->mmio_size = (mem->end - mem->start) + 1;
+
+ /* map the region */
+ cam->mmio_base = (unsigned long)
+ ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
+ if (!cam->mmio_base) {
+ dev_err(cam->dev, "cannot map camera register I/O region\n");
+ goto err;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(cam->dev, "no irq for camera?\n");
+ goto err;
+ }
+
+ isp_get();
+ isp_sysconfig.reset = 0;
+ isp_sysconfig.idle_mode = 1;
+ isp_power_settings(isp_sysconfig);
+
+ for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
+ struct omap34xxcam_videodev *vdev = &cam->vdevs[i];
+ struct v4l2_int_device *m = &vdev->master;
+
+ m->module = THIS_MODULE;
+ strlcpy(m->name, CAM_NAME, sizeof(m->name));
+ m->type = v4l2_int_type_master;
+ m->u.master = &omap34xxcam_master;
+ m->priv = vdev;
+
+ if (v4l2_int_device_register(m))
+ goto err;
+
+ mutex_init(&vdev->mutex);
+ vdev->index = i;
+ vdev->cam = cam;
+ vdev->capture_mem = capture_mem;
+ }
+
+ omap34xxcam = cam;
+ isp_put();
+
+ return 0;
+
+err:
+ omap34xxcam_remove(pdev);
+ isp_put();
+ return -ENODEV;
+}
+
+/**
+ * omap34xxcam_remove - platform driver remove handler
+ * @pdev: ptr. to platform level device information structure
+ *
+ * Unregister device with V4L2, unmap camera registers, and
+ * free camera device information structure (omap34xxcam_device).
+ *
+ * Returns 0 always.
+ */
+static int omap34xxcam_remove(struct platform_device *pdev)
+{
+ struct omap34xxcam_device *cam = platform_get_drvdata(pdev);
+ int i;
+
+ if (!cam)
+ return 0;
+
+ omap34xxcam = NULL;
+
+ isp_put();
+
+ for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
+ if (cam->vdevs[i].cam == NULL)
+ continue;
+
+ v4l2_int_device_unregister(&cam->vdevs[i].master);
+ cam->vdevs[i].cam = NULL;
+ }
+
+ if (cam->mmio_base) {
+ iounmap((void *)cam->mmio_base);
+ cam->mmio_base = 0;
+ }
+
+ if (cam->mmio_base_phys) {
+ release_mem_region(cam->mmio_base_phys, cam->mmio_size);
+ cam->mmio_base_phys = 0;
+ }
+
+ kfree(cam);
+
+ return 0;
+}
+
+static struct platform_driver omap34xxcam_driver = {
+ .probe = omap34xxcam_probe,
+ .remove = omap34xxcam_remove,
+#ifdef CONFIG_PM
+ .suspend = omap34xxcam_suspend,
+ .resume = omap34xxcam_resume,
+#endif
+ .driver = {
+ .name = CAM_NAME,
+ },
+};
+
+/*
+ *
+ * Module initialisation and deinitialisation
+ *
+ */
+
+/**
+ * omap34xxcam_init - module_init function
+ *
+ * Calls platfrom driver to register probe, remove,
+ * suspend and resume functions.
+ *
+ */
+static int __init omap34xxcam_init(void)
+{
+ return platform_driver_register(&omap34xxcam_driver);
+}
+
+/**
+ * omap34xxcam_cleanup - module_exit function
+ *
+ * Calls platfrom driver to unregister probe, remove,
+ * suspend and resume functions.
+ *
+ */
+static void __exit omap34xxcam_cleanup(void)
+{
+ platform_driver_unregister(&omap34xxcam_driver);
+}
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("OMAP34xx Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+
+late_initcall(omap34xxcam_init);
+module_exit(omap34xxcam_cleanup);
--- /dev/null 2004-06-24 13:05:26.000000000 -0500
+++ b/drivers/media/video/omap34xxcam.h 2008-06-29 16:57:48.000000000 -0500
@@ -0,0 +1,189 @@
+/*
+ * drivers/media/video/omap34xxcam.h
+ *
+ * Video-for-Linux (Version 2) Camera capture driver for OMAP34xx ISP.
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ * Copyright (C) 2008 Nokia.
+ *
+ * Contributors:
+ * Sameer Venkatraman <sameerv@xxxxxx>
+ * Mohit Jalori <mjalori@xxxxxx>
+ * Sakari Ailus <sakari.ailus@xxxxxxxxx>
+ * Tuukka Toivonen <tuukka.o.toivonen@xxxxxxxxx>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef OMAP34XXCAM_H
+#define OMAP34XXCAM_H
+
+#include <media/v4l2-int-device.h>
+#include "isp/isp.h"
+
+#define CAM_NAME "omap34xxcam"
+
+#define OMAP_ISP_AF (1 << 4)
+#define OMAP_ISP_HIST (1 << 5)
+#define OMAP34XXCAM_XCLK_NONE -1
+#define OMAP34XXCAM_XCLK_A 0
+#define OMAP34XXCAM_XCLK_B 1
+
+#define OMAP34XXCAM_SLAVE_SENSOR 0
+#define OMAP34XXCAM_SLAVE_LENS 1
+#define OMAP34XXCAM_SLAVE_FLASH 2 /* This is the last slave! */
+
+#define OMAP34XXCAM_VIDEODEVS 4
+
+struct omap34xxcam_device;
+struct omap34xxcam_videodev;
+
+struct omap34xxcam_sensor_config {
+ int xclk;
+ int sensor_isp;
+};
+
+struct omap34xxcam_lens_config {
+};
+
+struct omap34xxcam_flash_config {
+};
+
+/**
+ * struct omap34xxcam_hw_config - struct for vidioc_int_g_priv ioctl
+ * @xclk: OMAP34XXCAM_XCLK_A or OMAP34XXCAM_XCLK_B
+ * @sensor_isp: Is sensor smart/SOC or raw
+ * @s_pix_sparm: Access function to set pix and sparm.
+ * Pix will override sparm
+ */
+struct omap34xxcam_hw_config {
+ int dev_index; /* Index in omap34xxcam_sensors */
+ int dev_minor; /* Video device minor number */
+ int dev_type; /* OMAP34XXCAM_SLAVE_* */
+ union {
+ struct omap34xxcam_sensor_config sensor;
+ struct omap34xxcam_lens_config lens;
+ struct omap34xxcam_flash_config flash;
+ } u;
+};
+
+/**
+ * struct omap34xxcam_videodev - per /dev/video* structure
+ * @mutex: serialises access to this structure
+ * @cam: pointer to cam hw structure
+ * @master: we are v4l2_int_device master
+ * @sensor: sensor device
+ * @lens: lens device
+ * @flash: flash device
+ * @slaves: how many slaves we have at the moment
+ * @vfd: our video device
+ * @capture_mem: maximum kernel-allocated capture memory
+ * @if_u: sensor interface stuff
+ * @index: index of this structure in cam->vdevs
+ * @users: how many users we have
+ * @sensor_config: ISP-speicific sensor configuration
+ * @lens_config: ISP-speicific lens configuration
+ * @flash_config: ISP-speicific flash configuration
+ * @streaming: streaming file handle, if streaming is enabled
+ */
+struct omap34xxcam_videodev {
+ struct mutex mutex;
+
+ struct omap34xxcam_device *cam;
+ struct v4l2_int_device master;
+
+#define vdev_sensor slave[OMAP34XXCAM_SLAVE_SENSOR]
+#define vdev_lens slave[OMAP34XXCAM_SLAVE_LENS]
+#define vdev_flash slave[OMAP34XXCAM_SLAVE_FLASH]
+ struct v4l2_int_device *slave[OMAP34XXCAM_SLAVE_FLASH + 1];
+
+ /* number of slaves attached */
+ int slaves;
+
+ /*** video device parameters ***/
+ struct video_device *vfd;
+ int capture_mem;
+
+ /*** general driver state information ***/
+ /*
+ * Sensor interface parameters: interface type, CC_CTRL
+ * register value and interface specific data.
+ */
+ u32 xclk;
+ /* index to omap34xxcam_videodevs of this structure */
+ int index;
+ atomic_t users;
+
+#define vdev_sensor_config slave_config[OMAP34XXCAM_SLAVE_SENSOR].u.sensor
+#define vdev_lens_config slave_config[OMAP34XXCAM_SLAVE_LENS].u.lens
+#define vdev_flash_config slave_config[OMAP34XXCAM_SLAVE_FLASH].u.flash
+ struct omap34xxcam_hw_config slave_config[OMAP34XXCAM_SLAVE_FLASH + 1];
+
+ /*** capture data ***/
+ /* file handle, if streaming is on */
+ struct file *streaming;
+};
+
+/**
+ * struct omap34xxcam_device - per-device data structure
+ * @mutex: mutex serialises access to this structure
+ * @sgdma_in_queue: Number or sgdma requests in scatter-gather queue,
+ * protected by the lock above.
+ * @sgdma: ISP sgdma subsystem information structure
+ * @dma_notify: DMA notify flag
+ * @irq: irq number platform HW resource
+ * @mmio_base: register map memory base (platform HW resource)
+ * @mmio_base_phys: register map memory base physical address
+ * @mmio_size: register map memory size
+ * @dev: device structure
+ * @vdevs: /dev/video specific structures
+ * @fck: camera module fck clock information
+ * @ick: camera module ick clock information
+ */
+struct omap34xxcam_device {
+ struct mutex mutex;
+ int sgdma_in_queue;
+ struct isp_sgdma sgdma;
+ int dma_notify;
+
+ /*** platform HW resource ***/
+ unsigned int irq;
+ unsigned long mmio_base;
+ unsigned long mmio_base_phys;
+ unsigned long mmio_size;
+
+ /*** interfaces and device ***/
+ struct device *dev;
+ struct omap34xxcam_videodev vdevs[OMAP34XXCAM_VIDEODEVS];
+
+ /*** camera module clocks ***/
+ struct clk *fck;
+ struct clk *ick;
+ bool sensor_if_enabled;
+};
+
+/**
+ * struct omap34xxcam_fh - per-filehandle data structure
+ * @vbq_lock: spinlock for the videobuf queue
+ * @vbq: V4L2 video buffer queue structure
+ * @pix: V4L2 pixel format structure (serialise pix by vbq->lock)
+ * @field_count: field counter for videobuf_buffer
+ * @vdev: our /dev/video specific structure
+ */
+struct omap34xxcam_fh {
+ spinlock_t vbq_lock;
+ struct videobuf_queue vbq;
+ struct v4l2_pix_format pix;
+ atomic_t field_count;
+ /* accessing cam here doesn't need serialisation: it's constant */
+ struct omap34xxcam_videodev *vdev;
+};
+
+#endif /* ifndef OMAP34XXCAM_H */
--- /dev/null 2004-06-24 13:05:26.000000000 -0500
+++ b/drivers/media/video/isp/Makefile 2008-06-29 17:44:40.000000000 -0500
@@ -0,0 +1,4 @@
+# Makefile for OMAP3 ISP driver
+
+obj-$(CONFIG_VIDEO_OMAP3) += \
+ isp.o ispccdc.o ispmmu.o \
--- /dev/null 2004-06-24 13:05:26.000000000 -0500
+++ b/drivers/media/video/isp/Kconfig 2008-06-29 17:07:00.000000000 -0500
@@ -0,0 +1 @@
+# Kconfig for OMAP3 ISP driver
--- /dev/null 2004-06-24 13:05:26.000000000 -0500
+++ b/drivers/media/video/isp/isp.c 2008-06-29 17:44:57.000000000 -0500
@@ -0,0 +1,1802 @@
+/*
+ * drivers/media/video/isp/isp.c
+ *
+ * Driver Library for ISP Control module in TI's OMAP3430 Camera ISP
+ * ISP interface and IRQ related APIs are defined here.
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ * Copyright (C) 2008 Nokia.
+ *
+ * Contributors:
+ * Sameer Venkatraman <sameerv@xxxxxx>
+ * Mohit Jalori <mjalori@xxxxxx>
+ * Sakari Ailus <sakari.ailus@xxxxxxxxx>
+ * Tuukka Toivonen <tuukka.o.toivonen@xxxxxxxxx>
+ * Toni Leinonen <toni.leinonen@xxxxxxxxx>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <asm/irq.h>
+#include <linux/bitops.h>
+#include <linux/scatterlist.h>
+#include <asm/mach-types.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/io.h>
+#include <linux/device.h>
+#include <linux/videodev2.h>
+
+#include "isp.h"
+#include "ispmmu.h"
+#include "ispreg.h"
+#include "ispccdc.h"
+
+/* List of image formats supported via OMAP ISP */
+const static struct v4l2_fmtdesc isp_formats[] = {
+ {
+ .description = "UYVY, packed",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ },
+ {
+ .description = "YUYV (YUV 4:2:2), packed",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .description = "Bayer10 (GrR/BGb)",
+ .pixelformat = V4L2_PIX_FMT_SGRBG10,
+ },
+};
+
+/* ISP Crop capabilities */
+static struct v4l2_rect ispcroprect;
+static struct v4l2_rect cur_rect;
+
+/**
+ * struct vcontrol - Video control structure.
+ * @qc: V4L2 Query control structure.
+ * @current_value: Current value of the control.
+ */
+static struct vcontrol {
+ struct v4l2_queryctrl qc;
+ int current_value;
+} video_control[] = { };
+
+/**
+ * struct ispirq - Structure for containing callbacks to be called in ISP ISR.
+ * @isp_callbk: Array which stores callback functions, indexed by the type of
+ * callback (8 possible types).
+ * @isp_callbk_arg1: Pointer to array containing pointers to the first argument
+ * to be passed to the requested callback function.
+ * @isp_callbk_arg2: Pointer to array containing pointers to the second
+ * argument to be passed to the requested callback function.
+ *
+ * This structure is used to contain all the callback functions related for
+ * each callback type (CBK_CCDC_VD0, CBK_CCDC_VD1, CBK_PREV_DONE,
+ * CBK_RESZ_DONE, CBK_MMU_ERR, CBK_H3A_AWB_DONE, CBK_HIST_DONE, CBK_HS_VS,
+ * CBK_LSC_ISR).
+ */
+static struct ispirq {
+ isp_callback_t isp_callbk[9];
+ isp_vbq_callback_ptr isp_callbk_arg1[9];
+ void *isp_callbk_arg2[9];
+} ispirq_obj;
+
+/**
+ * struct isp - Structure for storing ISP Control module information
+ * @lock: Spinlock to sync between isr and processes.
+ * @isp_temp_buf_lock: Temporary spinlock for buffer control.
+ * @isp_mutex: Semaphore used to get access to the ISP.
+ * @if_status: Type of interface used in ISP.
+ * @interfacetype: (Not used).
+ * @ref_count: Reference counter.
+ * @cam_ick: Pointer to ISP Interface clock.
+ * @cam_fck: Pointer to ISP Functional clock.
+ *
+ * This structure is used to store the OMAP ISP Control Information.
+ */
+static struct isp {
+ spinlock_t lock;
+ spinlock_t isp_temp_buf_lock;
+ struct mutex isp_mutex;
+ u8 if_status;
+ u8 interfacetype;
+ int ref_count;
+ struct clk *cam_ick;
+ struct clk *cam_mclk;
+} isp_obj;
+
+struct isp_sgdma ispsg;
+
+/**
+ * struct ispmodule - Structure for storing ISP sub-module information.
+ * @isp_pipeline: Bit mask for submodules enabled within the ISP.
+ * @isp_temp_state: State of current buffers.
+ * @applyCrop: Flag to do a crop operation when video buffer queue ISR is done
+ * @pix: Structure containing the format and layout of the output image.
+ * @ccdc_input_width: ISP CCDC module input image width.
+ * @ccdc_input_height: ISP CCDC module input image height.
+ * @ccdc_output_width: ISP CCDC module output image width.
+ * @ccdc_output_height: ISP CCDC module output image height.
+ * @preview_input_width: ISP Preview module input image width.
+ * @preview_input_height: ISP Preview module input image height.
+ * @preview_output_width: ISP Preview module output image width.
+ * @preview_output_height: ISP Preview module output image height.
+ * @resizer_input_width: ISP Resizer module input image width.
+ * @resizer_input_height: ISP Resizer module input image height.
+ * @resizer_output_width: ISP Resizer module output image width.
+ * @resizer_output_height: ISP Resizer module output image height.
+ */
+struct ispmodule {
+ unsigned int isp_pipeline;
+ int isp_temp_state;
+ int applyCrop;
+ struct v4l2_pix_format pix;
+ unsigned int ccdc_input_width;
+ unsigned int ccdc_input_height;
+ unsigned int ccdc_output_width;
+ unsigned int ccdc_output_height;
+ unsigned int preview_input_width;
+ unsigned int preview_input_height;
+ unsigned int preview_output_width;
+ unsigned int preview_output_height;
+ unsigned int resizer_input_width;
+ unsigned int resizer_input_height;
+ unsigned int resizer_output_width;
+ unsigned int resizer_output_height;
+};
+
+static struct ispmodule ispmodule_obj = {
+ .isp_pipeline = OMAP_ISP_CCDC,
+ .isp_temp_state = ISP_BUF_INIT,
+ .applyCrop = 0,
+ .pix = {
+ .width = ISP_OUTPUT_WIDTH_DEFAULT,
+ .height = ISP_OUTPUT_HEIGHT_DEFAULT,
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .field = V4L2_FIELD_NONE,
+ .bytesperline = ISP_OUTPUT_WIDTH_DEFAULT * ISP_BYTES_PER_PIXEL,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0,
+ },
+};
+
+/* Structure for saving/restoring ISP module registers */
+static struct isp_reg isp_reg_list[] = {
+ {ISP_SYSCONFIG, 0},
+ {ISP_IRQ0ENABLE, 0},
+ {ISP_IRQ1ENABLE, 0},
+ {ISP_TCTRL_GRESET_LENGTH, 0},
+ {ISP_TCTRL_PSTRB_REPLAY, 0},
+ {ISP_CTRL, 0},
+ {ISP_TCTRL_CTRL, 0},
+ {ISP_TCTRL_FRAME, 0},
+ {ISP_TCTRL_PSTRB_DELAY, 0},
+ {ISP_TCTRL_STRB_DELAY, 0},
+ {ISP_TCTRL_SHUT_DELAY, 0},
+ {ISP_TCTRL_PSTRB_LENGTH, 0},
+ {ISP_TCTRL_STRB_LENGTH, 0},
+ {ISP_TCTRL_SHUT_LENGTH, 0},
+ {ISP_CBUFF_SYSCONFIG, 0},
+ {ISP_CBUFF_IRQENABLE, 0},
+ {ISP_CBUFF0_CTRL, 0},
+ {ISP_CBUFF1_CTRL, 0},
+ {ISP_CBUFF0_START, 0},
+ {ISP_CBUFF1_START, 0},
+ {ISP_CBUFF0_END, 0},
+ {ISP_CBUFF1_END, 0},
+ {ISP_CBUFF0_WINDOWSIZE, 0},
+ {ISP_CBUFF1_WINDOWSIZE, 0},
+ {ISP_CBUFF0_THRESHOLD, 0},
+ {ISP_CBUFF1_THRESHOLD, 0},
+ {ISP_TOK_TERM, 0}
+};
+
+/*
+ *
+ * V4L2 Handling
+ *
+ */
+
+/**
+ * find_vctrl - Returns the index of the ctrl array of the requested ctrl ID.
+ * @id: Requested control ID.
+ *
+ * Returns 0 if successful, -EINVAL if not found, or -EDOM if its out of
+ * domain.
+ **/
+static int find_vctrl(int id)
+{
+ int i;
+
+ if (id < V4L2_CID_BASE)
+ return -EDOM;
+
+ for (i = (ARRAY_SIZE(video_control) - 1); i >= 0; i--)
+ if (video_control[i].qc.id == id)
+ break;
+
+ if (i < 0)
+ i = -EINVAL;
+
+ return i;
+}
+
+/**
+ * isp_open - Reserve ISP submodules for operation
+ **/
+void isp_open(void)
+{
+ ispccdc_request();
+ return;
+}
+EXPORT_SYMBOL(isp_open);
+
+/**
+ * isp_close - Free ISP submodules
+ **/
+void isp_close(void)
+{
+ ispccdc_free();
+ return;
+}
+EXPORT_SYMBOL(isp_close);
+
+/* Flag to check first time of isp_get */
+static int off_mode;
+
+/**
+ * isp_set_sgdma_callback - Set Scatter-Gather DMA Callback.
+ * @sgdma_state: Pointer to structure with the SGDMA state for each videobuffer
+ * @func_ptr: Callback function pointer for SG-DMA management
+ **/
+static int isp_set_sgdma_callback(struct isp_sgdma_state *sgdma_state,
+ isp_vbq_callback_ptr func_ptr)
+{
+ if (ispmodule_obj.isp_pipeline & OMAP_ISP_CCDC) {
+ isp_set_callback(CBK_CCDC_VD0, sgdma_state->callback, func_ptr,
+ sgdma_state->arg);
+ isp_set_callback(CBK_CCDC_VD1, sgdma_state->callback, func_ptr,
+ sgdma_state->arg);
+ isp_set_callback(CBK_LSC_ISR, NULL, NULL, NULL);
+ }
+
+ isp_set_callback(CBK_HS_VS, sgdma_state->callback, func_ptr,
+ sgdma_state->arg);
+ return 0;
+}
+
+/**
+ * isp_set_callback - Sets the callback for the ISP module done events.
+ * @type: Type of the event for which callback is requested.
+ * @callback: Method to be called as callback in the ISR context.
+ * @arg1: First argument to be passed when callback is called in ISR.
+ * @arg2: Second argument to be passed when callback is called in ISR.
+ *
+ * This function sets a callback function for a done event in the ISP
+ * module, and enables the corresponding interrupt.
+ **/
+int isp_set_callback(enum isp_callback_type type, isp_callback_t callback,
+ isp_vbq_callback_ptr arg1,
+ void *arg2)
+{
+ unsigned long irqflags = 0;
+
+ if (callback == NULL) {
+ DPRINTK_ISPCTRL("ISP_ERR : Null Callback\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&isp_obj.lock, irqflags);
+ ispirq_obj.isp_callbk[type] = callback;
+ ispirq_obj.isp_callbk_arg1[type] = arg1;
+ ispirq_obj.isp_callbk_arg2[type] = arg2;
+ spin_unlock_irqrestore(&isp_obj.lock, irqflags);
+
+ switch (type) {
+ case CBK_HS_VS:
+ omap_writel(IRQ0ENABLE_HS_VS_IRQ, ISP_IRQ0STATUS);
+ omap_writel(omap_readl(ISP_IRQ0ENABLE) | IRQ0ENABLE_HS_VS_IRQ,
+ ISP_IRQ0ENABLE);
+ break;
+ case CBK_MMU_ERR:
+ omap_writel(omap_readl(ISP_IRQ0ENABLE) |
+ IRQ0ENABLE_MMU_ERR_IRQ,
+ ISP_IRQ0ENABLE);
+
+ omap_writel(omap_readl(ISPMMU_IRQENABLE) |
+ IRQENABLE_MULTIHITFAULT |
+ IRQENABLE_TWFAULT |
+ IRQENABLE_EMUMISS |
+ IRQENABLE_TRANSLNFAULT |
+ IRQENABLE_TLBMISS,
+ ISPMMU_IRQENABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(isp_set_callback);
+
+/**
+ * isp_unset_callback - Clears the callback for the ISP module done events.
+ * @type: Type of the event for which callback to be cleared.
+ *
+ * This function clears a callback function for a done event in the ISP
+ * module, and disables the corresponding interrupt.
+ **/
+int isp_unset_callback(enum isp_callback_type type)
+{
+ unsigned long irqflags = 0;
+
+ spin_lock_irqsave(&isp_obj.lock, irqflags);
+ ispirq_obj.isp_callbk[type] = NULL;
+ ispirq_obj.isp_callbk_arg1[type] = NULL;
+ ispirq_obj.isp_callbk_arg2[type] = NULL;
+ spin_unlock_irqrestore(&isp_obj.lock, irqflags);
+
+ switch (type) {
+ case CBK_CCDC_VD0:
+ omap_writel((omap_readl(ISP_IRQ0ENABLE)) &
+ ~IRQ0ENABLE_CCDC_VD0_IRQ,
+ ISP_IRQ0ENABLE);
+ break;
+ case CBK_CCDC_VD1:
+ omap_writel((omap_readl(ISP_IRQ0ENABLE)) &
+ ~IRQ0ENABLE_CCDC_VD1_IRQ,
+ ISP_IRQ0ENABLE);
+ break;
+ case CBK_MMU_ERR:
+ omap_writel(omap_readl(ISPMMU_IRQENABLE) &
+ ~(IRQENABLE_MULTIHITFAULT |
+ IRQENABLE_TWFAULT |
+ IRQENABLE_EMUMISS |
+ IRQENABLE_TRANSLNFAULT |
+ IRQENABLE_TLBMISS),
+ ISPMMU_IRQENABLE);
+ break;
+ case CBK_HS_VS:
+ omap_writel((omap_readl(ISP_IRQ0ENABLE)) &
+ ~IRQ0ENABLE_HS_VS_IRQ,
+ ISP_IRQ0ENABLE);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(isp_unset_callback);
+
+/**
+ * isp_request_interface - Requests an ISP interface type (parallel or serial).
+ * @if_t: Type of requested ISP interface (parallel or serial).
+ *
+ * This function requests for allocation of an ISP interface type.
+ **/
+int isp_request_interface(enum isp_interface_type if_t)
+{
+ if (isp_obj.if_status & if_t) {
+ DPRINTK_ISPCTRL("ISP_ERR : Requested Interface already \
+ allocated\n");
+ goto err_ebusy;
+ }
+ if ((isp_obj.if_status == (ISP_PARLL | ISP_CSIA))
+ || isp_obj.if_status == (ISP_CSIA | ISP_CSIB)) {
+ DPRINTK_ISPCTRL("ISP_ERR : No Free interface now\n");
+ goto err_ebusy;
+ }
+
+ if (((isp_obj.if_status == ISP_PARLL) && (if_t == ISP_CSIA)) ||
+ ((isp_obj.if_status == ISP_CSIA) &&
+ (if_t == ISP_PARLL)) ||
+ ((isp_obj.if_status == ISP_CSIA) &&
+ (if_t == ISP_CSIB)) ||
+ ((isp_obj.if_status == ISP_CSIB) &&
+ (if_t == ISP_CSIA)) ||
+ (isp_obj.if_status == 0)) {
+ isp_obj.if_status |= if_t;
+ return 0;
+ } else {
+ DPRINTK_ISPCTRL("ISP_ERR : Invalid Combination Serial- \
+ Parallel interface\n");
+ return -EINVAL;
+ }
+
+err_ebusy:
+ return -EBUSY;
+}
+EXPORT_SYMBOL(isp_request_interface);
+
+/**
+ * isp_free_interface - Frees an ISP interface type (parallel or serial).
+ * @if_t: Type of ISP interface to be freed (parallel or serial).
+ *
+ * This function frees the allocation of an ISP interface type.
+ **/
+int isp_free_interface(enum isp_interface_type if_t)
+{
+ isp_obj.if_status &= ~if_t;
+ return 0;
+}
+EXPORT_SYMBOL(isp_free_interface);
+
+/**
+ * isp_set_xclk - Configures the specified cam_xclk to the desired frequency.
+ * @xclk: Desired frequency of the clock in Hz.
+ * @xclksel: XCLK to configure (0 = A, 1 = B).
+ *
+ * Configures the specified MCLK divisor in the ISP timing control register
+ * (TCTRL_CTRL) to generate the desired xclk clock value.
+ *
+ * Divisor = CM_CAM_MCLK_HZ / xclk
+ *
+ * Returns the final frequency that is actually being generated
+ **/
+u32 isp_set_xclk(u32 xclk, u8 xclksel)
+{
+ u32 divisor;
+ u32 currentxclk;
+
+ if (xclk >= CM_CAM_MCLK_HZ) {
+ divisor = ISPTCTRL_CTRL_DIV_BYPASS;
+ currentxclk = CM_CAM_MCLK_HZ;
+ } else if (xclk >= 2) {
+ divisor = CM_CAM_MCLK_HZ / xclk;
+ if (divisor >= ISPTCTRL_CTRL_DIV_BYPASS)
+ divisor = ISPTCTRL_CTRL_DIV_BYPASS - 1;
+ currentxclk = CM_CAM_MCLK_HZ / divisor;
+ } else {
+ divisor = xclk;
+ currentxclk = 0;
+ }
+
+ switch (xclksel) {
+ case 0:
+ omap_writel((omap_readl(ISP_TCTRL_CTRL) &
+ ~ISPTCTRL_CTRL_DIVA_MASK) |
+ (divisor << ISPTCTRL_CTRL_DIVA_SHIFT),
+ ISP_TCTRL_CTRL);
+ DPRINTK_ISPCTRL("isp_set_xclk(): cam_xclka set to %d Hz\n",
+ currentxclk);
+ break;
+ case 1:
+ omap_writel((omap_readl(ISP_TCTRL_CTRL) &
+ ~ISPTCTRL_CTRL_DIVB_MASK) |
+ (divisor << ISPTCTRL_CTRL_DIVB_SHIFT),
+ ISP_TCTRL_CTRL);
+ DPRINTK_ISPCTRL("isp_set_xclk(): cam_xclkb set to %d Hz\n",
+ currentxclk);
+ break;
+ default:
+ DPRINTK_ISPCTRL("ISP_ERR: isp_set_xclk(): Invalid requested "
+ "xclk. Must be 0 (A) or 1 (B)."
+ "\n");
+ return -EINVAL;
+ }
+
+ return currentxclk;
+}
+EXPORT_SYMBOL(isp_set_xclk);
+
+/**
+ * isp_get_xclk - Returns the frequency in Hz of the desired cam_xclk.
+ * @xclksel: XCLK to retrieve (0 = A, 1 = B).
+ *
+ * This function returns the External Clock (XCLKA or XCLKB) value generated
+ * by the ISP.
+ **/
+u32 isp_get_xclk(u8 xclksel)
+{
+ u32 xclkdiv;
+ u32 xclk;
+
+ switch (xclksel) {
+ case 0:
+ xclkdiv = omap_readl(ISP_TCTRL_CTRL) & ISPTCTRL_CTRL_DIVA_MASK;
+ xclkdiv = xclkdiv >> ISPTCTRL_CTRL_DIVA_SHIFT;
+ break;
+ case 1:
+ xclkdiv = omap_readl(ISP_TCTRL_CTRL) & ISPTCTRL_CTRL_DIVB_MASK;
+ xclkdiv = xclkdiv >> ISPTCTRL_CTRL_DIVB_SHIFT;
+ break;
+ default:
+ DPRINTK_ISPCTRL("ISP_ERR: isp_get_xclk(): Invalid requested "
+ "xclk. Must be 0 (A) or 1 (B)."
+ "\n");
+ return -EINVAL;
+ }
+
+ switch (xclkdiv) {
+ case 0:
+ case 1:
+ xclk = 0;
+ break;
+ case 0x1f:
+ xclk = CM_CAM_MCLK_HZ;
+ break;
+ default:
+ xclk = CM_CAM_MCLK_HZ / xclkdiv;
+ break;
+ }
+
+ return xclk;
+}
+EXPORT_SYMBOL(isp_get_xclk);
+
+/**
+ * isp_power_settings - Sysconfig settings, for Power Management.
+ * @isp_sysconfig: Structure containing the power settings for ISP to configure
+ *
+ * Sets the power settings for the ISP, and SBL bus.
+ **/
+void isp_power_settings(struct isp_sysc isp_sysconfig)
+{
+ if (isp_sysconfig.idle_mode) {
+ omap_writel(ISP_SYSCONFIG_AUTOIDLE |
+ (ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY <<
+ ISP_SYSCONFIG_MIDLEMODE_SHIFT),
+ ISP_SYSCONFIG);
+
+ omap_writel(ISPMMU_AUTOIDLE | (ISPMMU_SIDLEMODE_SMARTIDLE <<
+ ISPMMU_SIDLEMODE_SHIFT),
+ ISPMMU_SYSCONFIG);
+ if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0)) {
+ omap_writel(ISPCSI1_AUTOIDLE |
+ (ISPCSI1_MIDLEMODE_SMARTSTANDBY <<
+ ISPCSI1_MIDLEMODE_SHIFT),
+ ISP_CSIA_SYSCONFIG);
+ omap_writel(ISPCSI1_AUTOIDLE |
+ (ISPCSI1_MIDLEMODE_SMARTSTANDBY <<
+ ISPCSI1_MIDLEMODE_SHIFT),
+ ISP_CSIB_SYSCONFIG);
+ }
+ omap_writel(ISPCTRL_SBL_AUTOIDLE, ISP_CTRL);
+
+ } else {
+ omap_writel(ISP_SYSCONFIG_AUTOIDLE |
+ (ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY <<
+ ISP_SYSCONFIG_MIDLEMODE_SHIFT),
+ ISP_SYSCONFIG);
+
+ omap_writel(ISPMMU_AUTOIDLE |
+ (ISPMMU_SIDLEMODE_NOIDLE << ISPMMU_SIDLEMODE_SHIFT),
+ ISPMMU_SYSCONFIG);
+ if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0)) {
+ omap_writel(ISPCSI1_AUTOIDLE |
+ (ISPCSI1_MIDLEMODE_FORCESTANDBY <<
+ ISPCSI1_MIDLEMODE_SHIFT),
+ ISP_CSIA_SYSCONFIG);
+
+ omap_writel(ISPCSI1_AUTOIDLE |
+ (ISPCSI1_MIDLEMODE_FORCESTANDBY <<
+ ISPCSI1_MIDLEMODE_SHIFT),
+ ISP_CSIB_SYSCONFIG);
+ }
+
+ omap_writel(ISPCTRL_SBL_AUTOIDLE, ISP_CTRL);
+ }
+}
+EXPORT_SYMBOL(isp_power_settings);
+
+#define BIT_SET(var, shift, mask, val) \
+ do { \
+ var = (var & ~(mask << shift)) \
+ | (val << shift); \
+ } while (0)
+
+static int isp_init_csi(struct isp_interface_config *config)
+{
+ u32 i = 0, val, reg;
+ int format;
+
+ switch (config->u.csi.format) {
+ case V4L2_PIX_FMT_SGRBG10:
+ format = 0x16; /* RAW10+VP */
+ break;
+ case V4L2_PIX_FMT_SGRBG10DPCM8:
+ format = 0x12; /* RAW8+DPCM10+VP */
+ break;
+ default:
+ printk(KERN_ERR "isp_init_csi: bad csi format\n");
+ return -EINVAL;
+ }
+
+ /* Reset the CSI and wait for reset to complete */
+ omap_writel(omap_readl(ISPCSI1_SYSCONFIG) | BIT(1), ISPCSI1_SYSCONFIG);
+ while (!(omap_readl(ISPCSI1_SYSSTATUS) & BIT(0))) {
+ udelay(10);
+ if (i++ > 10)
+ break;
+ }
+ if (!(omap_readl(ISPCSI1_SYSSTATUS) & BIT(0))) {
+ printk(KERN_WARNING
+ "omap3_isp: timeout waiting for csi reset\n");
+ }
+
+ /* CONTROL_CSIRXFE */
+ omap_writel(
+ /* CSIb receiver data/clock or data/strobe mode */
+ (config->u.csi.signalling << 10)
+ | BIT(12) /* Enable differential transceiver */
+ | BIT(13) /* Disable reset */
+#ifdef TERM_RESISTOR
+ | BIT(8) /* Enable internal CSIb resistor (no effect) */
+#endif
+/* | BIT(7) */ /* Strobe/clock inversion (no effect) */
+ , CONTROL_CSIRXFE);
+
+#ifdef TERM_RESISTOR
+ /* Set CONTROL_CSI */
+ val = omap_readl(CONTROL_CSI);
+ val &= ~(0x1F<<16);
+ val |= BIT(31) | (TERM_RESISTOR<<16);
+ omap_writel(val, CONTROL_CSI);
+#endif
+
+ /* ISPCSI1_CTRL */
+ val = omap_readl(ISPCSI1_CTRL);
+ val &= ~BIT(11); /* Enable VP only off ->
+ extract embedded data to interconnect */
+ BIT_SET(val, 8, 0x3, config->u.csi.vpclk); /* Video port clock */
+/* val |= BIT(3); */ /* Wait for FEC before disabling interface */
+ val |= BIT(2); /* I/O cell output is parallel
+ (no effect, but errata says should be enabled
+ for class 1/2) */
+ val |= BIT(12); /* VP clock polarity to falling edge
+ (needed or bad picture!) */
+
+ /* Data/strobe physical layer */
+ BIT_SET(val, 1, 1, config->u.csi.signalling);
+ BIT_SET(val, 10, 1, config->u.csi.strobe_clock_inv);
+ val |= BIT(4); /* Magic bit to enable CSI1 and strobe mode */
+ omap_writel(val, ISPCSI1_CTRL);
+
+ /* ISPCSI1_LCx_CTRL logical channel #0 */
+ reg = ISPCSI1_LCx_CTRL(0); /* reg = ISPCSI1_CTRL1; */
+ val = omap_readl(reg);
+ /* Format = RAW10+VP or RAW8+DPCM10+VP*/
+ BIT_SET(val, 3, 0x1f, format);
+ /* Enable setting of frame regions of interest */
+ BIT_SET(val, 1, 1, 1);
+ BIT_SET(val, 2, 1, config->u.csi.crc);
+ omap_writel(val, reg);
+
+ /* ISPCSI1_DAT_START for logical channel #0 */
+ reg = ISPCSI1_LCx_DAT_START(0); /* reg = ISPCSI1_DAT_START; */
+ val = omap_readl(reg);
+ BIT_SET(val, 16, 0xfff, config->u.csi.data_start);
+ omap_writel(val, reg);
+
+ /* ISPCSI1_DAT_SIZE for logical channel #0 */
+ reg = ISPCSI1_LCx_DAT_SIZE(0); /* reg = ISPCSI1_DAT_SIZE; */
+ val = omap_readl(reg);
+ BIT_SET(val, 16, 0xfff, config->u.csi.data_size);
+ omap_writel(val, reg);
+
+ /* Clear status bits for logical channel #0 */
+ omap_writel(0xFFF & ~BIT(6), ISPCSI1_LC01_IRQSTATUS);
+
+ /* Enable CSI1 */
+ val = omap_readl(ISPCSI1_CTRL);
+ val |= BIT(0) | BIT(4);
+ omap_writel(val, ISPCSI1_CTRL);
+
+ if (!(omap_readl(ISPCSI1_CTRL) & BIT(4))) {
+ printk(KERN_WARNING "OMAP3 CSI1 bus not available\n");
+ if (config->u.csi.signalling) /* Strobe mode requires CSI1 */
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * isp_configure_interface - Configures ISP Control I/F related parameters.
+ * @config: Pointer to structure containing the desired configuration for the
+ * ISP.
+ *
+ * Configures ISP control register (ISP_CTRL) with the values specified inside
+ * the config structure. Controls:
+ * - Selection of parallel or serial input to the preview hardware.
+ * - Data lane shifter.
+ * - Pixel clock polarity.
+ * - 8 to 16-bit bridge at the input of CCDC module.
+ * - HS or VS synchronization signal detection
+ **/
+int isp_configure_interface(struct isp_interface_config *config)
+{
+ u32 ispctrl_val = omap_readl(ISP_CTRL);
+ u32 ispccdc_vdint_val;
+ int r;
+
+ ispctrl_val &= ISPCTRL_SHIFT_MASK;
+ ispctrl_val |= (config->dataline_shift << ISPCTRL_SHIFT_SHIFT);
+ ispctrl_val &= ~ISPCTRL_PAR_CLK_POL_INV;
+
+ ispctrl_val &= (ISPCTRL_PAR_SER_CLK_SEL_MASK);
+ switch (config->ccdc_par_ser) {
+ case ISP_PARLL:
+ ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL;
+ ispctrl_val |= (config->u.par.par_clk_pol
+ << ISPCTRL_PAR_CLK_POL_SHIFT);
+ ispctrl_val &= ~ISPCTRL_PAR_BRIDGE_BENDIAN;
+ ispctrl_val |= (config->u.par.par_bridge
+ << ISPCTRL_PAR_BRIDGE_SHIFT);
+ break;
+ case ISP_CSIB:
+ ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIB;
+ r = isp_init_csi(config);
+ if (r)
+ return r;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ispctrl_val &= ~(ISPCTRL_SYNC_DETECT_VSRISE);
+ ispctrl_val |= (config->hsvs_syncdetect);
+
+ omap_writel(ispctrl_val, ISP_CTRL);
+
+ ispccdc_vdint_val = omap_readl(ISPCCDC_VDINT);
+ ispccdc_vdint_val &= ~(ISPCCDC_VDINT_0_MASK << ISPCCDC_VDINT_0_SHIFT);
+ ispccdc_vdint_val &= ~(ISPCCDC_VDINT_1_MASK << ISPCCDC_VDINT_1_SHIFT);
+ omap_writel((config->vdint0_timing << ISPCCDC_VDINT_0_SHIFT) |
+ (config->vdint1_timing <<
+ ISPCCDC_VDINT_1_SHIFT),
+ ISPCCDC_VDINT);
+
+ return 0;
+}
+EXPORT_SYMBOL(isp_configure_interface);
+
+/**
+ * isp_CCDC_VD01_enable - Enables VD0 and VD1 IRQs.
+ *
+ * Sets VD0 and VD1 bits in IRQ0STATUS to reset the flag, and sets them in
+ * IRQ0ENABLE to enable the corresponding IRQs.
+ **/
+void isp_CCDC_VD01_enable(void)
+{
+ omap_writel(IRQ0STATUS_CCDC_VD0_IRQ | IRQ0STATUS_CCDC_VD1_IRQ,
+ ISP_IRQ0STATUS);
+ omap_writel(omap_readl(ISP_IRQ0ENABLE) | IRQ0ENABLE_CCDC_VD0_IRQ |
+ IRQ0ENABLE_CCDC_VD1_IRQ,
+ ISP_IRQ0ENABLE);
+}
+
+/**
+ * isp_CCDC_VD01_disable - Disables VD0 and VD1 IRQs.
+ *
+ * Clears VD0 and VD1 bits in IRQ0ENABLE register.
+ **/
+void isp_CCDC_VD01_disable(void)
+{
+ omap_writel(omap_readl(ISP_IRQ0ENABLE) & ~(IRQ0ENABLE_CCDC_VD0_IRQ |
+ IRQ0ENABLE_CCDC_VD1_IRQ),
+ ISP_IRQ0ENABLE);
+}
+
+/**
+ * omap34xx_isp_isr - Interrupt Service Routine for Camera ISP module.
+ * @irq: Not used currently.
+ * @ispirq_disp: Pointer to the object that is passed while request_irq is
+ * called. This is the ispirq_obj object containing info on the
+ * callback.
+ *
+ * Handles the corresponding callback if plugged in.
+ *
+ * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the
+ * IRQ wasn't handled.
+ **/
+static irqreturn_t omap34xx_isp_isr(int irq, void *ispirq_disp)
+{
+ struct ispirq *irqdis = (struct ispirq *)ispirq_disp;
+ u32 irqstatus = 0;
+ unsigned long irqflags = 0;
+ u8 is_irqhandled = 0;
+
+ irqstatus = omap_readl(ISP_IRQ0STATUS);
+
+ spin_lock_irqsave(&isp_obj.lock, irqflags);
+
+ if ((irqstatus & MMU_ERR) == MMU_ERR) {
+ if (irqdis->isp_callbk[CBK_MMU_ERR])
+ irqdis->isp_callbk[CBK_MMU_ERR](irqstatus,
+ irqdis->isp_callbk_arg1[CBK_MMU_ERR],
+ irqdis->isp_callbk_arg2[CBK_MMU_ERR]);
+ is_irqhandled = 1;
+ goto out;
+ }
+
+ if ((irqstatus & CCDC_VD1) == CCDC_VD1) {
+ if (irqdis->isp_callbk[CBK_CCDC_VD1])
+ irqdis->isp_callbk[CBK_CCDC_VD1](CCDC_VD1,
+ irqdis->isp_callbk_arg1[CBK_CCDC_VD1],
+ irqdis->isp_callbk_arg2[CBK_CCDC_VD1]);
+ is_irqhandled = 1;
+ }
+
+ if ((irqstatus & CCDC_VD0) == CCDC_VD0) {
+ if (irqdis->isp_callbk[CBK_CCDC_VD0])
+ irqdis->isp_callbk[CBK_CCDC_VD0](CCDC_VD0,
+ irqdis->isp_callbk_arg1[CBK_CCDC_VD0],
+ irqdis->isp_callbk_arg2[CBK_CCDC_VD0]);
+ is_irqhandled = 1;
+ }
+
+ if ((irqstatus & HS_VS) == HS_VS) {
+ if (irqdis->isp_callbk[CBK_HS_VS])
+ irqdis->isp_callbk[CBK_HS_VS](HS_VS,
+ irqdis->isp_callbk_arg1[CBK_HS_VS],
+ irqdis->isp_callbk_arg2[CBK_HS_VS]);
+ is_irqhandled = 1;
+ }
+
+ if (irqstatus & IRQ0STATUS_CSIB_IRQ) {
+ u32 ispcsi1_irqstatus;
+
+ ispcsi1_irqstatus = omap_readl(ISPCSI1_LC01_IRQSTATUS);
+ DPRINTK_ISPCTRL("%x\n", ispcsi1_irqstatus);
+ }
+
+out:
+ omap_writel(irqstatus, ISP_IRQ0STATUS);
+ spin_unlock_irqrestore(&isp_obj.lock, irqflags);
+
+ if (is_irqhandled)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
+}
+/* Device name, needed for resource tracking layer */
+struct device_driver camera_drv = {
+ .name = "camera"
+};
+
+struct device camera_dev = {
+ .driver = &camera_drv,
+};
+
+/**
+ * isp_set_pipeline - Set bit mask for submodules enabled within the ISP.
+ * @soc_type: Sensor to use: 1 - Smart sensor, 0 - Raw sensor.
+ *
+ * Sets Previewer and Resizer in the bit mask only if its a Raw sensor.
+ **/
+void isp_set_pipeline(int soc_type)
+{
+ ispmodule_obj.isp_pipeline |= OMAP_ISP_CCDC;
+
+ if (!soc_type)
+ ispmodule_obj.isp_pipeline |= (OMAP_ISP_PREVIEW |
+ OMAP_ISP_RESIZER);
+
+ return;
+}
+
+/**
+ * omapisp_unset_callback - Unsets all the callbacks associated with ISP module
+ **/
+void omapisp_unset_callback()
+{
+ isp_unset_callback(CBK_HS_VS);
+
+ if (ispmodule_obj.isp_pipeline & OMAP_ISP_CCDC) {
+ isp_unset_callback(CBK_CCDC_VD0);
+ isp_unset_callback(CBK_CCDC_VD1);
+ isp_unset_callback(CBK_LSC_ISR);
+ }
+ omap_writel(omap_readl(ISP_IRQ0STATUS) | ISP_INT_CLR, ISP_IRQ0STATUS);
+}
+
+/**
+ * isp_start - Starts ISP submodule
+ *
+ * Start the needed isp components assuming these components
+ * are configured correctly.
+ **/
+void isp_start(void)
+{
+ return;
+}
+
+/**
+ * isp_stop - Stops isp submodules
+ **/
+void isp_stop()
+{
+ int timeout;
+
+ spin_lock(&isp_obj.isp_temp_buf_lock);
+ ispmodule_obj.isp_temp_state = ISP_FREE_RUNNING;
+ spin_unlock(&isp_obj.isp_temp_buf_lock);
+ omapisp_unset_callback();
+
+ if (ispmodule_obj.isp_pipeline & OMAP_ISP_CCDC) {
+ ispccdc_enable(0);
+ timeout = 0;
+ while (ispccdc_busy() && (timeout < 20)) {
+ timeout++;
+ mdelay(10);
+ }
+ }
+ if (ispccdc_busy()) {
+ isp_save_ctx();
+ omap_writel(omap_readl(ISP_SYSCONFIG) |
+ ISP_SYSCONFIG_SOFTRESET, ISP_SYSCONFIG);
+ timeout = 0;
+ while ((!(omap_readl(ISP_SYSSTATUS) & 0x1)) && timeout < 20) {
+ timeout++;
+ mdelay(1);
+ }
+ isp_restore_ctx();
+ }
+}
+
+/**
+ * isp_set_buf - Sets output address for submodules.
+ * @sgdma_state: Pointer to structure with the SGDMA state for each videobuffer
+ **/
+void isp_set_buf(struct isp_sgdma_state *sgdma_state)
+{
+ if (ispmodule_obj.isp_pipeline & OMAP_ISP_CCDC)
+ ispccdc_set_outaddr(sgdma_state->isp_addr);
+
+}
+
+/**
+ * isp_calc_pipeline - Sets pipeline depending of input and output pixel format
+ * @pix_input: Pointer to V4L2 pixel format structure for input image.
+ * @pix_output: Pointer to V4L2 pixel format structure for output image.
+ **/
+void isp_calc_pipeline(struct v4l2_pix_format *pix_input,
+ struct v4l2_pix_format *pix_output)
+{
+ ispmodule_obj.isp_pipeline = OMAP_ISP_CCDC;
+ if ((pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10) &&
+ (pix_output->pixelformat != V4L2_PIX_FMT_SGRBG10)) {
+ ispmodule_obj.isp_pipeline |= (OMAP_ISP_PREVIEW |
+ OMAP_ISP_RESIZER);
+ ispccdc_config_datapath(CCDC_RAW, CCDC_OTHERS_VP);
+ } else {
+ if (pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10)
+ ispccdc_config_datapath(CCDC_RAW, CCDC_OTHERS_MEM);
+ else
+ ispccdc_config_datapath(CCDC_YUV_SYNC,
+ CCDC_OTHERS_MEM);
+ }
+ return;
+}
+
+/**
+ * isp_config_pipeline - Configures the image size and ycpos for ISP submodules
+ * @pix_input: Pointer to V4L2 pixel format structure for input image.
+ * @pix_output: Pointer to V4L2 pixel format structure for output image.
+ *
+ * The configuration of ycpos depends on the output pixel format for both the
+ * Preview and Resizer submodules.
+ **/
+void isp_config_pipeline(struct v4l2_pix_format *pix_input,
+ struct v4l2_pix_format *pix_output)
+{
+ ispccdc_config_size(ispmodule_obj.ccdc_input_width,
+ ispmodule_obj.ccdc_input_height,
+ ispmodule_obj.ccdc_output_width,
+ ispmodule_obj.ccdc_output_height);
+
+ return;
+}
+
+/**
+ * isp_vbq_done - Callback for interrupt completion
+ * @status: IRQ0STATUS register value. Passed by the ISR, or the caller.
+ * @arg1: Pointer to callback function for SG-DMA management.
+ * @arg2: Pointer to videobuffer structure managed by ISP.
+ **/
+void isp_vbq_done(unsigned long status, isp_vbq_callback_ptr arg1, void *arg2)
+{
+ struct videobuf_buffer *vb = (struct videobuf_buffer *) arg2;
+ int notify = 0;
+ int rval = 0;
+ unsigned long flags;
+
+ switch (status) {
+ case CCDC_VD0:
+ ispccdc_config_shadow_registers();
+ if ((ispmodule_obj.isp_pipeline & OMAP_ISP_RESIZER) ||
+ (ispmodule_obj.isp_pipeline & OMAP_ISP_PREVIEW))
+ return;
+ else {
+ spin_lock(&isp_obj.isp_temp_buf_lock);
+ if (ispmodule_obj.isp_temp_state != ISP_BUF_INIT) {
+ spin_unlock(&isp_obj.isp_temp_buf_lock);
+ return;
+
+ } else {
+ spin_unlock(&isp_obj.isp_temp_buf_lock);
+ break;
+ }
+ }
+ break;
+ case CCDC_VD1:
+ if ((ispmodule_obj.isp_pipeline & OMAP_ISP_RESIZER) ||
+ (ispmodule_obj.isp_pipeline & OMAP_ISP_PREVIEW))
+ return;
+ spin_lock(&isp_obj.isp_temp_buf_lock);
+ if (ispmodule_obj.isp_temp_state == ISP_BUF_INIT) {
+ spin_unlock(&isp_obj.isp_temp_buf_lock);
+ ispccdc_enable(0);
+ return;
+ }
+ spin_unlock(&isp_obj.isp_temp_buf_lock);
+ return;
+ break;
+ case HS_VS:
+ spin_lock(&isp_obj.isp_temp_buf_lock);
+ if (ispmodule_obj.isp_temp_state == ISP_BUF_TRAN) {
+ isp_CCDC_VD01_enable();
+ ispmodule_obj.isp_temp_state = ISP_BUF_INIT;
+ }
+ spin_unlock(&isp_obj.isp_temp_buf_lock);
+ return;
+ default:
+ break;
+ }
+
+ spin_lock_irqsave(&ispsg.lock, flags);
+ ispsg.free_sgdma++;
+ if (ispsg.free_sgdma > NUM_SG_DMA)
+ ispsg.free_sgdma = NUM_SG_DMA;
+ spin_unlock_irqrestore(&ispsg.lock, flags);
+
+ rval = arg1(vb);
+
+ if (rval)
+ isp_sgdma_process(&ispsg, 1, ¬ify, arg1);
+
+ return;
+}
+
+/**
+ * isp_sgdma_init - Initializes Scatter Gather DMA status and operations.
+ **/
+void isp_sgdma_init()
+{
+ int sg;
+
+ ispsg.free_sgdma = NUM_SG_DMA;
+ ispsg.next_sgdma = 0;
+ for (sg = 0; sg < NUM_SG_DMA; sg++) {
+ ispsg.sg_state[sg].status = 0;
+ ispsg.sg_state[sg].callback = NULL;
+ ispsg.sg_state[sg].arg = NULL;
+ }
+}
+
+/**
+ * isp_sgdma_process - Sets operations and config for specified SG DMA
+ * @sgdma: SG-DMA function to work on.
+ * @irq: Flag to specify if an IRQ is associated with the DMA completion.
+ * @dma_notify: Pointer to flag that says when the ISP has to be started.
+ * @func_ptr: Callback function pointer for SG-DMA setup.
+ **/
+void isp_sgdma_process(struct isp_sgdma *sgdma, int irq, int *dma_notify,
+ isp_vbq_callback_ptr func_ptr)
+{
+ struct isp_sgdma_state *sgdma_state;
+ unsigned long flags;
+ spin_lock_irqsave(&sgdma->lock, flags);
+
+ if (NUM_SG_DMA > sgdma->free_sgdma) {
+ sgdma_state = sgdma->sg_state +
+ (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
+ if (!irq) {
+ if (*dma_notify) {
+ isp_set_sgdma_callback(sgdma_state, func_ptr);
+ isp_set_buf(sgdma_state);
+ ispccdc_enable(1);
+ isp_start();
+ *dma_notify = 0;
+ ispmodule_obj.isp_temp_state = ISP_BUF_TRAN;
+ } else {
+ if (ispmodule_obj.isp_temp_state ==
+ ISP_FREE_RUNNING) {
+ isp_set_sgdma_callback(sgdma_state,
+ func_ptr);
+ isp_set_buf(sgdma_state);
+ ispccdc_enable(1);
+ ispmodule_obj.isp_temp_state =
+ ISP_BUF_TRAN;
+ }
+ }
+ } else {
+ isp_set_sgdma_callback(sgdma_state, func_ptr);
+ isp_set_buf(sgdma_state);
+ ispccdc_enable(1);
+ ispmodule_obj.isp_temp_state = ISP_BUF_INIT;
+
+ if (*dma_notify) {
+ isp_start();
+ *dma_notify = 0;
+ }
+ }
+ } else {
+ spin_lock(&isp_obj.isp_temp_buf_lock);
+ isp_CCDC_VD01_disable();
+ ispmodule_obj.isp_temp_state = ISP_FREE_RUNNING;
+ spin_unlock(&isp_obj.isp_temp_buf_lock);
+ }
+ spin_unlock_irqrestore(&sgdma->lock, flags);
+ return;
+}
+
+/**
+ * isp_sgdma_queue - Queues a Scatter-Gather DMA videobuffer.
+ * @vdma: Pointer to structure containing the desired DMA video buffer
+ * transfer parameters.
+ * @vb: Pointer to structure containing the target videobuffer.
+ * @irq: Flag to specify if an IRQ is associated with the DMA completion.
+ * @dma_notify: Pointer to flag that says when the ISP has to be started.
+ * @func_ptr: Callback function pointer for SG-DMA setup.
+ *
+ * Returns 0 if successful, -EINVAL if invalid SG linked list setup, or -EBUSY
+ * if the ISP SG-DMA is not free.
+ **/
+int isp_sgdma_queue(struct videobuf_dmabuf *vdma, struct videobuf_buffer *vb,
+ int irq, int *dma_notify,
+ isp_vbq_callback_ptr func_ptr)
+{
+ unsigned long flags;
+ struct isp_sgdma_state *sg_state;
+ const struct scatterlist *sglist = vdma->sglist;
+ int sglen = vdma->sglen;
+
+ if ((sglen < 0) || ((sglen > 0) & !sglist))
+ return -EINVAL;
+
+ spin_lock_irqsave(&ispsg.lock, flags);
+
+ if (!ispsg.free_sgdma) {
+ spin_unlock_irqrestore(&ispsg.lock, flags);
+ return -EBUSY;
+ }
+
+ sg_state = ispsg.sg_state + ispsg.next_sgdma;
+ sg_state->isp_addr = ispsg.isp_addr_capture[vb->i];
+ sg_state->status = 0;
+ sg_state->callback = isp_vbq_done;
+ sg_state->arg = vb;
+
+ ispsg.next_sgdma = (ispsg.next_sgdma + 1) % NUM_SG_DMA;
+ ispsg.free_sgdma--;
+
+ spin_unlock_irqrestore(&ispsg.lock, flags);
+
+ isp_sgdma_process(&ispsg, irq, dma_notify, func_ptr);
+
+ return 0;
+}
+
+/**
+ * isp_vbq_prepare - Videobuffer queue prepare.
+ * @vbq: Pointer to videobuf_queue structure.
+ * @vb: Pointer to videobuf_buffer structure.
+ * @field: Requested Field order for the videobuffer.
+ *
+ * Returns 0 if successful, or -EIO if the ispmmu was unable to map a
+ * scatter-gather linked list data space.
+ **/
+int isp_vbq_prepare(struct videobuf_queue *vbq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ unsigned int isp_addr;
+ struct videobuf_dmabuf *vdma;
+
+ int err = 0;
+
+ vdma = videobuf_to_dma(vb);
+
+ isp_addr = ispmmu_map_sg(vdma->sglist, vdma->sglen);
+
+ if (!isp_addr)
+ err = -EIO;
+ else
+ ispsg.isp_addr_capture[vb->i] = isp_addr;
+
+ return err;
+}
+
+/**
+ * isp_vbq_release - Videobuffer queue release.
+ * @vbq: Pointer to videobuf_queue structure.
+ * @vb: Pointer to videobuf_buffer structure.
+ **/
+void isp_vbq_release(struct videobuf_queue *vbq, struct videobuf_buffer *vb)
+{
+ ispmmu_unmap(ispsg.isp_addr_capture[vb->i]);
+ ispsg.isp_addr_capture[vb->i] = (dma_addr_t) NULL;
+ return;
+}
+
+/**
+ * isp_queryctrl - Query V4L2 control from existing controls in ISP.
+ * @a: Pointer to v4l2_queryctrl structure. It only needs the id field filled.
+ *
+ * Returns 0 if successful, or -EINVAL if not found in ISP.
+ **/
+int isp_queryctrl(struct v4l2_queryctrl *a)
+{
+ int i;
+
+ i = find_vctrl(a->id);
+ if (i == -EINVAL)
+ a->flags = V4L2_CTRL_FLAG_DISABLED;
+
+ if (i < 0)
+ return -EINVAL;
+
+ *a = video_control[i].qc;
+ return 0;
+}
+
+/**
+ * isp_g_ctrl - Gets value of the desired V4L2 control.
+ * @a: V4L2 control to read actual value from.
+ *
+ * Return 0 if successful, or -EINVAL if chosen control is not found.
+ **/
+int isp_g_ctrl(struct v4l2_control *a)
+{
+ int rval = 0;
+
+ switch (a->id) {
+ default:
+ rval = -EINVAL;
+ break;
+ }
+
+ return rval;
+}
+
+/**
+ * isp_s_ctrl - Sets value of the desired V4L2 control.
+ * @a: V4L2 control to read actual value from.
+ *
+ * Return 0 if successful, -EINVAL if chosen control is not found or value
+ * is out of bounds, -EFAULT if copy_from_user or copy_to_user operation fails
+ * from camera abstraction layer related controls or the transfered user space
+ * pointer via the value field is not set properly.
+ **/
+int isp_s_ctrl(struct v4l2_control *a)
+{
+ int rval = 0;
+
+ switch (a->id) {
+ default:
+ rval = -EINVAL;
+ break;
+ }
+
+ return rval;
+}
+
+/**
+ * isp_handle_private - Handle all private ioctls for isp module.
+ * @cmd: ioctl cmd value
+ * @arg: ioctl arg value
+ *
+ * Return 0 if successful, -EINVAL if chosen cmd value is not handled or value
+ * is out of bounds, -EFAULT if ioctl arg value is not valid.
+ * Function simply routes the input ioctl cmd id to the appropriate handler in
+ * the isp module.
+ **/
+int isp_handle_private(int cmd, void *arg)
+{
+ int rval = 0;
+
+ switch (cmd) {
+ default:
+ rval = -EINVAL;
+ break;
+ }
+
+ return rval;
+}
+
+/**
+ * isp_enum_fmt_cap - Gets more information of chosen format index and type
+ * @f: Pointer to structure containing index and type of format to read from.
+ *
+ * Returns 0 if successful, or -EINVAL if format index or format type is
+ * invalid.
+ **/
+int isp_enum_fmt_cap(struct v4l2_fmtdesc *f)
+{
+ int index = f->index;
+ enum v4l2_buf_type type = f->type;
+ int rval = -EINVAL;
+
+ if (index >= NUM_ISP_CAPTURE_FORMATS)
+ goto err;
+
+ memset(f, 0, sizeof(*f));
+ f->index = index;
+ f->type = type;
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ rval = 0;
+ break;
+ default:
+ goto err;
+ }
+
+ f->flags = isp_formats[index].flags;
+ strncpy(f->description, isp_formats[index].description,
+ sizeof(f->description));
+ f->pixelformat = isp_formats[index].pixelformat;
+err:
+ return rval;
+}
+EXPORT_SYMBOL(isp_enum_fmt_cap);
+
+/**
+ * isp_g_fmt_cap - Gets current output image format.
+ * @f: Pointer to V4L2 format structure to be filled with current output format
+ **/
+void isp_g_fmt_cap(struct v4l2_format *f)
+{
+ f->fmt.pix = ispmodule_obj.pix;
+ return;
+}
+
+/**
+ * isp_s_fmt_cap - Sets I/O formats and crop and configures pipeline in ISP
+ * @f: Pointer to V4L2 format structure to be filled with current output format
+ *
+ * Returns 0 if successful, or return value of either isp_try_size or
+ * isp_try_fmt if there is an error.
+ **/
+int isp_s_fmt_cap(struct v4l2_pix_format *pix_input,
+ struct v4l2_pix_format *pix_output)
+{
+ int crop_scaling_w, crop_scaling_h = 0;
+ int rval = 0;
+
+ isp_calc_pipeline(pix_input, pix_output);
+ rval = isp_try_size(pix_input, pix_output);
+
+ if (rval)
+ goto out;
+
+ rval = isp_try_fmt(pix_input, pix_output);
+ if (rval)
+ goto out;
+
+ if (ispcroprect.width != pix_output->width) {
+ crop_scaling_w = 1;
+ ispcroprect.left = 0;
+ ispcroprect.width = pix_output->width;
+ }
+
+ if (ispcroprect.height != pix_output->height) {
+ crop_scaling_h = 1;
+ ispcroprect.top = 0;
+ ispcroprect.height = pix_output->height;
+ }
+
+ isp_config_pipeline(pix_input, pix_output);
+
+ if (crop_scaling_h || crop_scaling_w)
+ isp_config_crop(pix_output);
+
+out:
+ return rval;
+}
+EXPORT_SYMBOL(isp_s_fmt_cap);
+
+/**
+ * isp_config_crop - Configures crop parameters in isp resizer.
+ * @croppix: Pointer to V4L2 pixel format structure containing crop parameters
+ **/
+void isp_config_crop(struct v4l2_pix_format *croppix)
+{
+ u8 crop_scaling_w;
+ u8 crop_scaling_h;
+ struct v4l2_pix_format *pix = croppix;
+
+ crop_scaling_w = (ispmodule_obj.preview_output_width * 10) /
+ pix->width;
+ crop_scaling_h = (ispmodule_obj.preview_output_height * 10) /
+ pix->height;
+
+ cur_rect.left = (ispcroprect.left * crop_scaling_w) / 10;
+ cur_rect.top = (ispcroprect.top * crop_scaling_h) / 10;
+ cur_rect.width = (ispcroprect.width * crop_scaling_w) / 10;
+ cur_rect.height = (ispcroprect.height * crop_scaling_h) / 10;
+
+ return;
+}
+
+/**
+ * isp_g_crop - Gets crop rectangle size and position.
+ * @a: Pointer to V4L2 crop structure to be filled.
+ *
+ * Always returns 0.
+ **/
+int isp_g_crop(struct v4l2_crop *a)
+{
+ struct v4l2_crop *crop = a;
+
+ crop->c = ispcroprect;
+ return 0;
+}
+
+/**
+ * isp_s_crop - Sets crop rectangle size and position and queues crop operation
+ * @a: Pointer to V4L2 crop structure with desired parameters.
+ * @pix: Pointer to V4L2 pixel format structure with desired parameters.
+ *
+ * Returns 0 if successful, or -EINVAL if crop parameters are out of bounds.
+ **/
+int isp_s_crop(struct v4l2_crop *a, struct v4l2_pix_format *pix)
+{
+ struct v4l2_crop *crop = a;
+ int rval = 0;
+
+ if ((crop->c.left + crop->c.width) > pix->width) {
+ rval = -EINVAL;
+ goto out;
+ }
+
+ if ((crop->c.top + crop->c.height) > pix->height) {
+ rval = -EINVAL;
+ goto out;
+ }
+
+ ispcroprect.left = crop->c.left;
+ ispcroprect.top = crop->c.top;
+ ispcroprect.width = crop->c.width;
+ ispcroprect.height = crop->c.height;
+
+ isp_config_crop(pix);
+
+ ispmodule_obj.applyCrop = 1;
+out:
+ return rval;
+}
+
+/**
+ * isp_try_fmt_cap - Tries desired input/output image formats
+ * @pix_input: Pointer to V4L2 pixel format structure for input image.
+ * @pix_output: Pointer to V4L2 pixel format structure for output image.
+ *
+ * Returns 0 if successful, or return value of either isp_try_size or
+ * isp_try_fmt if there is an error.
+ **/
+int isp_try_fmt_cap(struct v4l2_pix_format *pix_input,
+ struct v4l2_pix_format *pix_output)
+{
+ int rval = 0;
+
+ isp_calc_pipeline(pix_input, pix_output);
+ rval = isp_try_size(pix_input, pix_output);
+
+ if (rval)
+ goto out;
+
+ rval = isp_try_fmt(pix_input, pix_output);
+
+ if (rval)
+ goto out;
+
+out:
+ return rval;
+}
+EXPORT_SYMBOL(isp_try_fmt_cap);
+
+/**
+ * isp_try_size - Tries size configuration for I/O images of each ISP submodule
+ * @pix_input: Pointer to V4L2 pixel format structure for input image.
+ * @pix_output: Pointer to V4L2 pixel format structure for output image.
+ *
+ * Returns 0 if successful, or return value of ispccdc_try_size,
+ * isppreview_try_size, or ispresizer_try_size (depending on the pipeline
+ * configuration) if there is an error.
+ **/
+int isp_try_size(struct v4l2_pix_format *pix_input,
+ struct v4l2_pix_format *pix_output)
+{
+ int rval = 0;
+ ispmodule_obj.ccdc_input_width = pix_input->width;
+ ispmodule_obj.ccdc_input_height = pix_input->height;
+ ispmodule_obj.resizer_output_width = pix_output->width;
+ ispmodule_obj.resizer_output_height = pix_output->height;
+
+ if (ispmodule_obj.isp_pipeline & OMAP_ISP_CCDC) {
+ rval = ispccdc_try_size(ispmodule_obj.ccdc_input_width,
+ ispmodule_obj.ccdc_input_height,
+ &ispmodule_obj.ccdc_output_width,
+ &ispmodule_obj.ccdc_output_height);
+ pix_output->width = ispmodule_obj.ccdc_output_width;
+ pix_output->height = ispmodule_obj.ccdc_output_height;
+ }
+
+ return rval;
+}
+EXPORT_SYMBOL(isp_try_size);
+
+/**
+ * isp_try_fmt - Validates input/output format parameters.
+ * @pix_input: Pointer to V4L2 pixel format structure for input image.
+ * @pix_output: Pointer to V4L2 pixel format structure for output image.
+ *
+ * Always returns 0.
+ **/
+int isp_try_fmt(struct v4l2_pix_format *pix_input,
+ struct v4l2_pix_format *pix_output)
+{
+ int ifmt;
+
+ for (ifmt = 0; ifmt < NUM_ISP_CAPTURE_FORMATS; ifmt++) {
+ if (pix_output->pixelformat == isp_formats[ifmt].pixelformat)
+ break;
+ }
+ if (ifmt == NUM_ISP_CAPTURE_FORMATS)
+ ifmt = 1;
+ pix_output->pixelformat = isp_formats[ifmt].pixelformat;
+ pix_output->field = V4L2_FIELD_NONE;
+ pix_output->bytesperline = pix_output->width * ISP_BYTES_PER_PIXEL;
+ pix_output->sizeimage = pix_output->bytesperline * pix_output->height;
+ pix_output->priv = 0;
+ switch (pix_output->pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ pix_output->colorspace = V4L2_COLORSPACE_JPEG;
+ break;
+ default:
+ pix_output->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ }
+
+ ispmodule_obj.pix.pixelformat = pix_output->pixelformat;
+ ispmodule_obj.pix.width = pix_output->width;
+ ispmodule_obj.pix.height = pix_output->height;
+ ispmodule_obj.pix.field = pix_output->field;
+ ispmodule_obj.pix.bytesperline = pix_output->bytesperline;
+ ispmodule_obj.pix.sizeimage = pix_output->sizeimage;
+ ispmodule_obj.pix.priv = pix_output->priv;
+ ispmodule_obj.pix.colorspace = pix_output->colorspace;
+
+ return 0;
+}
+/**
+ * isp_save_ctx - Saves ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
+ *
+ * Routine for saving the context of each module in the ISP.
+ * CCDC, HIST, H3A, PREV, RESZ and MMU.
+ **/
+void isp_save_ctx(void)
+{
+ isp_save_context(isp_reg_list);
+ ispccdc_save_context();
+ ispmmu_save_context();
+}
+EXPORT_SYMBOL(isp_save_ctx);
+
+/**
+ * isp_restore_ctx - Restores ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
+ *
+ * Routine for restoring the context of each module in the ISP.
+ * CCDC, HIST, H3A, PREV, RESZ and MMU.
+ **/
+void isp_restore_ctx(void)
+{
+ isp_restore_context(isp_reg_list);
+ ispccdc_restore_context();
+ ispmmu_restore_context();
+}
+EXPORT_SYMBOL(isp_restore_ctx);
+
+/**
+ * isp_get - Adquires the ISP resource.
+ *
+ * Initializes the clocks for the first acquire.
+ **/
+int isp_get(void)
+{
+ int ret_err = 0;
+ DPRINTK_ISPCTRL("isp_get: old %d\n", isp_obj.ref_count);
+ mutex_lock(&(isp_obj.isp_mutex));
+ if (isp_obj.ref_count == 0) {
+ isp_obj.cam_ick = clk_get(&camera_dev, "cam_ick");
+ if (IS_ERR(isp_obj.cam_ick)) {
+ DPRINTK_ISPCTRL("ISP_ERR: clk_get for "
+ "cam_ick failed\n");
+ ret_err = PTR_ERR(isp_obj.cam_ick);
+ goto out_clk_get_ick;
+ }
+ isp_obj.cam_mclk = clk_get(&camera_dev, "cam_mclk");
+ if (IS_ERR(isp_obj.cam_mclk)) {
+ DPRINTK_ISPCTRL("ISP_ERR: clk_get for "
+ "cam_mclk failed\n");
+ ret_err = PTR_ERR(isp_obj.cam_mclk);
+ goto out_clk_get_mclk;
+ }
+ ret_err = clk_enable(isp_obj.cam_ick);
+ if (ret_err) {
+ DPRINTK_ISPCTRL("ISP_ERR: clk_en for ick failed\n");
+ goto out_clk_enable_ick;
+ }
+ ret_err = clk_enable(isp_obj.cam_mclk);
+ if (ret_err) {
+ DPRINTK_ISPCTRL("ISP_ERR: clk_en for mclk failed\n");
+ goto out_clk_enable_mclk;
+ }
+ if (off_mode == 1)
+ isp_restore_ctx();
+ }
+ isp_obj.ref_count++;
+ mutex_unlock(&(isp_obj.isp_mutex));
+
+
+ DPRINTK_ISPCTRL("isp_get: new %d\n", isp_obj.ref_count);
+ return isp_obj.ref_count;
+
+out_clk_enable_mclk:
+ clk_disable(isp_obj.cam_ick);
+out_clk_enable_ick:
+ clk_put(isp_obj.cam_mclk);
+out_clk_get_mclk:
+ clk_put(isp_obj.cam_ick);
+out_clk_get_ick:
+
+ mutex_unlock(&(isp_obj.isp_mutex));
+
+ return ret_err;
+}
+EXPORT_SYMBOL(isp_get);
+
+/**
+ * isp_put - Releases the ISP resource.
+ *
+ * Releases the clocks also for the last release.
+ **/
+int isp_put(void)
+{
+ DPRINTK_ISPCTRL("isp_put: old %d\n", isp_obj.ref_count);
+ mutex_lock(&(isp_obj.isp_mutex));
+ if (isp_obj.ref_count)
+ if (--isp_obj.ref_count == 0) {
+ isp_save_ctx();
+ off_mode = 1;
+
+ clk_disable(isp_obj.cam_ick);
+ clk_disable(isp_obj.cam_mclk);
+ clk_put(isp_obj.cam_ick);
+ clk_put(isp_obj.cam_mclk);
+ }
+ mutex_unlock(&(isp_obj.isp_mutex));
+ DPRINTK_ISPCTRL("isp_put: new %d\n", isp_obj.ref_count);
+ return isp_obj.ref_count;
+}
+EXPORT_SYMBOL(isp_put);
+
+/**
+ * isp_save_context - Saves the values of the ISP module registers.
+ * @reg_list: Structure containing pairs of register address and value to
+ * modify on OMAP.
+ **/
+void isp_save_context(struct isp_reg *reg_list)
+{
+ struct isp_reg *next = reg_list;
+
+ for (; next->reg != ISP_TOK_TERM; next++)
+ next->val = omap_readl(next->reg);
+}
+EXPORT_SYMBOL(isp_save_context);
+
+/**
+ * isp_restore_context - Restores the values of the ISP module registers.
+ * @reg_list: Structure containing pairs of register address and value to
+ * modify on OMAP.
+ **/
+void isp_restore_context(struct isp_reg *reg_list)
+{
+ struct isp_reg *next = reg_list;
+
+ for (; next->reg != ISP_TOK_TERM; next++)
+ omap_writel(next->val, next->reg);
+}
+EXPORT_SYMBOL(isp_restore_context);
+
+/**
+ * isp_init - ISP module initialization.
+ **/
+static int __init isp_init(void)
+{
+ DPRINTK_ISPCTRL("+isp_init for Omap 3430 Camera ISP\n");
+ isp_obj.ref_count = 0;
+
+ mutex_init(&(isp_obj.isp_mutex));
+ spin_lock_init(&isp_obj.isp_temp_buf_lock);
+
+ if (request_irq(INT_34XX_CAM_IRQ, omap34xx_isp_isr, IRQF_SHARED,
+ "Omap 34xx Camera ISP", &ispirq_obj)) {
+ DPRINTK_ISPCTRL("Could not install ISR\n");
+ return -EINVAL;
+ } else {
+ spin_lock_init(&isp_obj.lock);
+ DPRINTK_ISPCTRL("-isp_init for Omap 3430 Camera ISP\n");
+ return 0;
+ }
+}
+
+/**
+ * isp_cleanup - ISP module cleanup.
+ **/
+static void __exit isp_cleanup(void)
+{
+ free_irq(INT_34XX_CAM_IRQ, &ispirq_obj);
+}
+
+/**
+ * isp_print_status - Prints the values of the ISP Control Module registers
+ *
+ * Also prints other debug information stored in the ISP module structure.
+ **/
+void isp_print_status(void)
+{
+ if (!is_ispctrl_debug_enabled())
+ return;
+
+ DPRINTK_ISPCTRL("###CM_FCLKEN_CAM=0x%x\n", omap_readl(CM_FCLKEN_CAM));
+ DPRINTK_ISPCTRL("###CM_ICLKEN_CAM=0x%x\n", omap_readl(CM_ICLKEN_CAM));
+ DPRINTK_ISPCTRL("###CM_CLKSEL_CAM=0x%x\n", omap_readl(CM_CLKSEL_CAM));
+ DPRINTK_ISPCTRL("###CM_AUTOIDLE_CAM=0x%x\n",
+ omap_readl(CM_AUTOIDLE_CAM));
+ DPRINTK_ISPCTRL("###CM_CLKEN_PLL[18:16] should be 0x7, = 0x%x\n",
+ omap_readl(CM_CLKEN_PLL));
+ DPRINTK_ISPCTRL("###CM_CLKSEL2_PLL[18:8] should be 0x2D, [6:0] should "
+ "be 1 = 0x%x\n", omap_readl(CM_CLKSEL2_PLL));
+ DPRINTK_ISPCTRL("###CTRL_PADCONF_CAM_HS=0x%x\n",
+ omap_readl(CTRL_PADCONF_CAM_HS));
+ DPRINTK_ISPCTRL("###CTRL_PADCONF_CAM_XCLKA=0x%x\n",
+ omap_readl(CTRL_PADCONF_CAM_XCLKA));
+ DPRINTK_ISPCTRL("###CTRL_PADCONF_CAM_D1=0x%x\n",
+ omap_readl(CTRL_PADCONF_CAM_D1));
+ DPRINTK_ISPCTRL("###CTRL_PADCONF_CAM_D3=0x%x\n",
+ omap_readl(CTRL_PADCONF_CAM_D3));
+ DPRINTK_ISPCTRL("###CTRL_PADCONF_CAM_D5=0x%x\n",
+ omap_readl(CTRL_PADCONF_CAM_D5));
+ DPRINTK_ISPCTRL("###CTRL_PADCONF_CAM_D7=0x%x\n",
+ omap_readl(CTRL_PADCONF_CAM_D7));
+ DPRINTK_ISPCTRL("###CTRL_PADCONF_CAM_D9=0x%x\n",
+ omap_readl(CTRL_PADCONF_CAM_D9));
+ DPRINTK_ISPCTRL("###CTRL_PADCONF_CAM_D11=0x%x\n",
+ omap_readl(CTRL_PADCONF_CAM_D11));
+}
+EXPORT_SYMBOL(isp_print_status);
+
+module_init(isp_init);
+module_exit(isp_cleanup);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("ISP Control Module Library");
+MODULE_LICENSE("GPL");
--- /dev/null 2004-06-24 13:05:26.000000000 -0500
+++ b/drivers/media/video/isp/isp.h 2008-06-29 16:57:48.000000000 -0500
@@ -0,0 +1,326 @@
+/*
+ * drivers/media/video/isp/isp.h
+ *
+ * Top level public header file for ISP Control module in
+ * TI's OMAP3430 Camera ISP
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ * Copyright (C) 2008 Nokia.
+ *
+ * Contributors:
+ * Sameer Venkatraman <sameerv@xxxxxx>
+ * Mohit Jalori <mjalori@xxxxxx>
+ * Sakari Ailus <sakari.ailus@xxxxxxxxx>
+ * Tuukka Toivonen <tuukka.o.toivonen@xxxxxxxxx>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef OMAP_ISP_TOP_H
+#define OMAP_ISP_TOP_H
+#include <media/videobuf-dma-sg.h>
+#include <linux/videodev2.h>
+#define OMAP_ISP_CCDC (1 << 0)
+#define OMAP_ISP_PREVIEW (1 << 1)
+#define OMAP_ISP_RESIZER (1 << 2)
+#define OMAP_ISP_AEWB (1 << 3)
+#define OMAP_ISP_AF (1 << 4)
+#define OMAP_ISP_HIST (1 << 5)
+
+/* Our ISP specific controls */
+#define V4L2_CID_PRIVATE_ISP_COLOR_FX (V4L2_CID_PRIVATE_BASE + 0)
+
+/* ISP Private IOCTLs */
+#define VIDIOC_PRIVATE_ISP_CCDC_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct ispccdc_update_config)
+#define VIDIOC_PRIVATE_ISP_PRV_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct ispprv_update_config)
+#define VIDIOC_PRIVATE_ISP_AEWB_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct isph3a_aewb_config)
+#define VIDIOC_PRIVATE_ISP_AEWB_REQ \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct isph3a_aewb_data)
+#define VIDIOC_PRIVATE_ISP_HIST_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct isp_hist_config)
+#define VIDIOC_PRIVATE_ISP_HIST_REQ \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct isp_hist_data)
+#define VIDIOC_PRIVATE_ISP_AF_CFG \
+ _IO('V', BASE_VIDIOC_PRIVATE + 8)
+#define VIDIOC_PRIVATE_ISP_AF_REQ \
+ _IO('V', BASE_VIDIOC_PRIVATE + 9)
+
+#define ISP_TOK_TERM 0xFFFFFFFF /*
+ * terminating token for ISP
+ * modules reg list
+ */
+#define NUM_SG_DMA (VIDEO_MAX_FRAME + 2)
+
+#define ISP_BUF_INIT 0
+#define ISP_FREE_RUNNING 1
+#define ISP_BUF_TRAN 2
+
+#ifndef CONFIG_ARCH_OMAP3410
+#define USE_ISP_PREVIEW
+#define USE_ISP_RESZ
+#define is_isppreview_enabled() 1
+#define is_ispresizer_enabled() 1
+#else
+#define is_isppreview_enabled() 0
+#define is_ispresizer_enabled() 0
+#endif
+
+#ifdef OMAP_ISPCTRL_DEBUG
+#define is_ispctrl_debug_enabled() 1
+#else
+#define is_ispctrl_debug_enabled() 0
+#endif
+
+#define ISP_XCLKA_DEFAULT 0x12
+#define ISP_OUTPUT_WIDTH_DEFAULT 176
+#define ISP_OUTPUT_HEIGHT_DEFAULT 144
+#define ISP_BYTES_PER_PIXEL 2
+#define NUM_ISP_CAPTURE_FORMATS (sizeof(isp_formats) /\
+ sizeof(isp_formats[0]))
+
+typedef int (*isp_vbq_callback_ptr) (struct videobuf_buffer *vb);
+typedef void (*isp_callback_t) (unsigned long status,
+ isp_vbq_callback_ptr arg1, void *arg2);
+
+enum isp_interface_type {
+ ISP_PARLL = 1,
+ ISP_CSIA = 2,
+ ISP_CSIB = 4
+};
+
+enum isp_irqevents {
+ CCDC_VD0 = 0x100,
+ CCDC_VD1 = 0x200,
+ CCDC_VD2 = 0x400,
+ CCDC_ERR = 0x800,
+ H3A_AWB_DONE = 0x2000,
+ HIST_DONE = 0x10000,
+ PREV_DONE = 0x100000,
+ LSC_DONE = 0x20000,
+ LSC_PRE_COMP = 0x40000,
+ LSC_PRE_ERR = 0x80000,
+ RESZ_DONE = 0x1000000,
+ SBL_OVF = 0x2000000,
+ MMU_ERR = 0x10000000,
+ OCP_ERR = 0x20000000,
+ HS_VS = 0x80000000
+};
+
+enum isp_callback_type {
+ CBK_CCDC_VD0,
+ CBK_CCDC_VD1,
+ CBK_PREV_DONE,
+ CBK_RESZ_DONE,
+ CBK_MMU_ERR,
+ CBK_H3A_AWB_DONE,
+ CBK_HIST_DONE,
+ CBK_HS_VS,
+ CBK_LSC_ISR
+};
+
+/**
+ * struct isp_reg - Structure for ISP register values.
+ * @reg: 32-bit Register address.
+ * @val: 32-bit Register value.
+ */
+struct isp_reg {
+ u32 reg;
+ u32 val;
+};
+
+/**
+ * struct isp_sgdma_state - SG-DMA state for each videobuffer + 2 overlays
+ * @isp_addr: ISP space address mapped by ISP MMU.
+ * @status: DMA return code mapped by ISP MMU.
+ * @callback: Pointer to ISP callback function.
+ * @arg: Pointer to argument passed to the specified callback function.
+ */
+struct isp_sgdma_state {
+ dma_addr_t isp_addr;
+ u32 status;
+ isp_callback_t callback;
+ void *arg;
+};
+
+/**
+ * struct isp_sgdma - ISP Scatter Gather DMA status.
+ * @isp_addr_capture: Array of ISP space addresses mapped by the ISP MMU.
+ * @lock: Spinlock used to check free_sgdma field.
+ * @free_sgdma: Number of free SG-DMA slots.
+ * @next_sgdma: Index of next SG-DMA slot to use.
+ */
+struct isp_sgdma {
+ dma_addr_t isp_addr_capture[VIDEO_MAX_FRAME];
+ spinlock_t lock;
+ int free_sgdma;
+ int next_sgdma;
+ struct isp_sgdma_state sg_state[NUM_SG_DMA];
+};
+
+/**
+ * struct isp_interface_config - ISP interface configuration.
+ * @ccdc_par_ser: ISP interface type. 0 - Parallel, 1 - CSIA, 2 - CSIB to CCDC.
+ * @par_bridge: CCDC Bridge input control. Parallel interface.
+ * 0 - Disable, 1 - Enable, first byte->cam_d(bits 7 to 0)
+ * 2 - Enable, first byte -> cam_d(bits 15 to 8)
+ * @par_clk_pol: Pixel clock polarity on the parallel interface.
+ * 0 - Non Inverted, 1 - Inverted
+ * @dataline_shift: Data lane shifter.
+ * 0 - No Shift, 1 - CAMEXT[13 to 2]->CAM[11 to 0]
+ * 2 - CAMEXT[13 to 4]->CAM[9 to 0]
+ * 3 - CAMEXT[13 to 6]->CAM[7 to 0]
+ * @hsvs_syncdetect: HS or VS synchronization signal detection.
+ * 0 - HS Falling, 1 - HS rising
+ * 2 - VS falling, 3 - VS rising
+ * @vdint0_timing: VD0 Interrupt timing.
+ * @vdint1_timing: VD1 Interrupt timing.
+ * @strobe: Strobe related parameter.
+ * @prestrobe: PreStrobe related parameter.
+ * @shutter: Shutter related parameter.
+ */
+struct isp_interface_config {
+ enum isp_interface_type ccdc_par_ser;
+ u8 dataline_shift;
+ u32 hsvs_syncdetect;
+ u16 vdint0_timing;
+ u16 vdint1_timing;
+ int strobe;
+ int prestrobe;
+ int shutter;
+ union {
+ struct par {
+ unsigned par_bridge:2;
+ unsigned par_clk_pol:1;
+ } par;
+ struct csi {
+ unsigned crc:1;
+ unsigned mode:1;
+ unsigned edge:1;
+ unsigned signalling:1;
+ unsigned strobe_clock_inv:1;
+ unsigned vs_edge:1;
+ unsigned channel:3;
+ unsigned vpclk:2; /* Video port output clock */
+ unsigned int data_start;
+ unsigned int data_size;
+ u32 format; /* V4L2_PIX_FMT_* */
+ } csi;
+ } u;
+};
+
+/**
+ * struct isp_sysc - ISP Power switches to set.
+ * @reset: Flag for setting ISP reset.
+ * @idle_mode: Flag for setting ISP idle mode.
+ */
+struct isp_sysc {
+ char reset;
+ char idle_mode;
+};
+
+void isp_open(void);
+
+void isp_close(void);
+
+void isp_start(void);
+
+void isp_stop(void);
+
+void isp_sgdma_init(void);
+
+void isp_vbq_done(unsigned long status, isp_vbq_callback_ptr arg1, void *arg2);
+
+void isp_sgdma_process(struct isp_sgdma *sgdma, int irq, int *dma_notify,
+ isp_vbq_callback_ptr func_ptr);
+
+int isp_sgdma_queue(struct videobuf_dmabuf *vdma, struct videobuf_buffer *vb,
+ int irq, int *dma_notify,
+ isp_vbq_callback_ptr func_ptr);
+
+int isp_vbq_prepare(struct videobuf_queue *vbq, struct videobuf_buffer *vb,
+ enum v4l2_field field);
+
+void isp_vbq_release(struct videobuf_queue *vbq, struct videobuf_buffer *vb);
+
+int isp_set_callback(enum isp_callback_type type, isp_callback_t callback,
+ isp_vbq_callback_ptr arg1, void *arg2);
+
+void omapisp_unset_callback(void);
+
+int isp_unset_callback(enum isp_callback_type type);
+
+u32 isp_set_xclk(u32 xclk, u8 xclksel);
+
+u32 isp_get_xclk(u8 xclksel);
+
+int isp_request_interface(enum isp_interface_type if_t);
+
+int isp_free_interface(enum isp_interface_type if_t);
+
+void isp_power_settings(struct isp_sysc);
+
+int isp_configure_interface(struct isp_interface_config *config);
+
+void isp_CCDC_VD01_disable(void);
+
+void isp_CCDC_VD01_enable(void);
+
+int isp_get(void);
+
+int isp_put(void);
+
+void isp_set_pipeline(int soc_type);
+
+void isp_config_pipeline(struct v4l2_pix_format *pix_input,
+ struct v4l2_pix_format *pix_output);
+
+int isp_queryctrl(struct v4l2_queryctrl *a);
+
+int isp_g_ctrl(struct v4l2_control *a);
+
+int isp_s_ctrl(struct v4l2_control *a);
+
+int isp_enum_fmt_cap(struct v4l2_fmtdesc *f);
+
+int isp_try_fmt_cap(struct v4l2_pix_format *pix_input,
+ struct v4l2_pix_format *pix_output);
+
+void isp_g_fmt_cap(struct v4l2_format *f);
+
+int isp_s_fmt_cap(struct v4l2_pix_format *pix_input,
+ struct v4l2_pix_format *pix_output);
+
+int isp_g_crop(struct v4l2_crop *a);
+
+int isp_s_crop(struct v4l2_crop *a, struct v4l2_pix_format *pix);
+
+void isp_config_crop(struct v4l2_pix_format *pix);
+
+int isp_try_size(struct v4l2_pix_format *pix_input,
+ struct v4l2_pix_format *pix_output);
+
+int isp_try_fmt(struct v4l2_pix_format *pix_input,
+ struct v4l2_pix_format *pix_output);
+
+int isp_handle_private(int cmd, void *arg);
+
+void isp_save_context(struct isp_reg *);
+
+void isp_restore_context(struct isp_reg *);
+
+void isp_save_ctx(void);
+
+void isp_restore_ctx(void);
+
+void isp_print_status(void);
+
+#endif /* OMAP_ISP_TOP_H */
--- /dev/null 2004-06-24 13:05:26.000000000 -0500
+++ b/drivers/media/video/isp/ispccdc.c 2008-06-29 17:44:57.000000000 -0500
@@ -0,0 +1,1296 @@
+/*
+ * drivers/media/video/isp/ispccdc.c
+ *
+ * Driver Library for CCDC module in TI's OMAP3430 Camera ISP
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * Contributors:
+ * Senthilvadivu Guruswamy <svadivu@xxxxxx>
+ * Pallavi Kulkarni <p-kulkarni@xxxxxx>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <asm/mach-types.h>
+#include <asm/arch/clock.h>
+#include <linux/io.h>
+#include <linux/scatterlist.h>
+#include <linux/uaccess.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispccdc.h"
+#include "ispmmu.h"
+
+static u32 *fpc_table_add;
+static unsigned long fpc_table_add_m;
+
+/**
+ * struct isp_ccdc - Structure for the CCDC module to store its own information
+ * @ccdc_inuse: Flag to determine if CCDC has been reserved or not (0 or 1).
+ * @ccdcout_w: CCDC output width.
+ * @ccdcout_h: CCDC output height.
+ * @ccdcin_w: CCDC input width.
+ * @ccdcin_h: CCDC input height.
+ * @ccdcin_woffset: CCDC input horizontal offset.
+ * @ccdcin_hoffset: CCDC input vertical offset.
+ * @crop_w: Crop width.
+ * @crop_h: Crop weight.
+ * @ccdc_inpfmt: CCDC input format.
+ * @ccdc_outfmt: CCDC output format.
+ * @vpout_en: Video port output enable.
+ * @wen: Data write enable.
+ * @exwen: External data write enable.
+ * @refmt_en: Reformatter enable.
+ * @ccdcslave: CCDC slave mode enable.
+ * @syncif_ipmod: Image
+ * @obclamp_en: Data input format.
+ * @mutexlock: Mutex used to get access to the CCDC.
+ */
+static struct isp_ccdc {
+ u8 ccdc_inuse;
+ u32 ccdcout_w;
+ u32 ccdcout_h;
+ u32 ccdcin_w;
+ u32 ccdcin_h;
+ u32 ccdcin_woffset;
+ u32 ccdcin_hoffset;
+ u32 crop_w;
+ u32 crop_h;
+ u8 ccdc_inpfmt;
+ u8 ccdc_outfmt;
+ u8 vpout_en;
+ u8 wen;
+ u8 exwen;
+ u8 refmt_en;
+ u8 ccdcslave;
+ u8 syncif_ipmod;
+ u8 obclamp_en;
+ u8 lsc_en;
+ struct mutex mutexlock;
+} ispccdc_obj;
+
+/* Structure for saving/restoring CCDC module registers*/
+static struct isp_reg ispccdc_reg_list[] = {
+ {ISPCCDC_SYN_MODE, 0},
+ {ISPCCDC_HD_VD_WID, 0},
+ {ISPCCDC_PIX_LINES, 0},
+ {ISPCCDC_HORZ_INFO, 0},
+ {ISPCCDC_VERT_START, 0},
+ {ISPCCDC_VERT_LINES, 0},
+ {ISPCCDC_CULLING, 0},
+ {ISPCCDC_HSIZE_OFF, 0},
+ {ISPCCDC_SDOFST, 0},
+ {ISPCCDC_SDR_ADDR, 0},
+ {ISPCCDC_CLAMP, 0},
+ {ISPCCDC_DCSUB, 0},
+ {ISPCCDC_COLPTN, 0},
+ {ISPCCDC_BLKCMP, 0},
+ {ISPCCDC_FPC, 0},
+ {ISPCCDC_FPC_ADDR, 0},
+ {ISPCCDC_VDINT, 0},
+ {ISPCCDC_ALAW, 0},
+ {ISPCCDC_REC656IF, 0},
+ {ISPCCDC_CFG, 0},
+ {ISPCCDC_FMTCFG, 0},
+ {ISPCCDC_FMT_HORZ, 0},
+ {ISPCCDC_FMT_VERT, 0},
+ {ISPCCDC_FMT_ADDR0, 0},
+ {ISPCCDC_FMT_ADDR1, 0},
+ {ISPCCDC_FMT_ADDR2, 0},
+ {ISPCCDC_FMT_ADDR3, 0},
+ {ISPCCDC_FMT_ADDR4, 0},
+ {ISPCCDC_FMT_ADDR5, 0},
+ {ISPCCDC_FMT_ADDR6, 0},
+ {ISPCCDC_FMT_ADDR7, 0},
+ {ISPCCDC_PRGEVEN0, 0},
+ {ISPCCDC_PRGEVEN1, 0},
+ {ISPCCDC_PRGODD0, 0},
+ {ISPCCDC_PRGODD1, 0},
+ {ISPCCDC_VP_OUT, 0},
+ {ISPCCDC_LSC_CONFIG, 0},
+ {ISPCCDC_LSC_INITIAL, 0},
+ {ISPCCDC_LSC_TABLE_BASE, 0},
+ {ISPCCDC_LSC_TABLE_OFFSET, 0},
+ {ISP_TOK_TERM, 0}
+};
+
+/**
+ * omap34xx_isp_ccdc_config - Sets CCDC configuration from userspace
+ * @userspace_add: Structure containing CCDC configuration sent from userspace.
+ *
+ * Returns 0 if successful, -EINVAL if the pointer to the configuration
+ * structure is null, or the copy_from_user function fails to copy user space
+ * memory to kernel space memory.
+ **/
+int omap34xx_isp_ccdc_config(void *userspace_add)
+{
+ struct ispccdc_bclamp bclamp_t;
+ struct ispccdc_blcomp blcomp_t;
+ struct ispccdc_fpc fpc_t;
+ struct ispccdc_culling cull_t;
+ struct ispccdc_update_config *ccdc_struct;
+
+ if (userspace_add == NULL)
+ return -EINVAL;
+
+ ccdc_struct = (struct ispccdc_update_config *) userspace_add;
+
+ if ((ISP_ABS_CCDC_ALAW & ccdc_struct->flag) == ISP_ABS_CCDC_ALAW) {
+ if ((ISP_ABS_CCDC_ALAW & ccdc_struct->update) ==
+ ISP_ABS_CCDC_ALAW)
+ ispccdc_config_alaw(ccdc_struct->alawip);
+ ispccdc_enable_alaw(1);
+ } else if ((ISP_ABS_CCDC_ALAW & ccdc_struct->update) ==
+ ISP_ABS_CCDC_ALAW)
+ ispccdc_enable_alaw(0);
+
+ if ((ISP_ABS_CCDC_LPF & ccdc_struct->flag) == ISP_ABS_CCDC_LPF)
+ ispccdc_enable_lpf(1);
+ else
+ ispccdc_enable_lpf(0);
+
+ if ((ISP_ABS_CCDC_BLCLAMP & ccdc_struct->flag) ==
+ ISP_ABS_CCDC_BLCLAMP) {
+ if ((ISP_ABS_CCDC_BLCLAMP & ccdc_struct->update) ==
+ ISP_ABS_CCDC_BLCLAMP) {
+ if (copy_from_user(&bclamp_t, (struct ispccdc_bclamp *)
+ (ccdc_struct->bclamp),
+ sizeof(struct ispccdc_bclamp)))
+ goto copy_from_user_err;
+
+ ispccdc_config_black_clamp(bclamp_t);
+ }
+ ispccdc_enable_black_clamp(1);
+ } else if ((ISP_ABS_CCDC_BLCLAMP & ccdc_struct->update) ==
+ ISP_ABS_CCDC_BLCLAMP)
+ ispccdc_enable_black_clamp(0);
+
+ if ((ISP_ABS_CCDC_BCOMP & ccdc_struct->update) == ISP_ABS_CCDC_BCOMP) {
+ if (copy_from_user(&blcomp_t, (struct ispccdc_blcomp *)
+ (ccdc_struct->blcomp),
+ sizeof(blcomp_t)))
+ goto copy_from_user_err;
+
+ ispccdc_config_black_comp(blcomp_t);
+ }
+
+ if ((ISP_ABS_CCDC_FPC & ccdc_struct->flag) == ISP_ABS_CCDC_FPC) {
+ if ((ISP_ABS_CCDC_FPC & ccdc_struct->update) ==
+ ISP_ABS_CCDC_FPC) {
+ if (copy_from_user(&fpc_t, (struct ispccdc_fpc *)
+ (ccdc_struct->fpc),
+ sizeof(fpc_t)))
+ goto copy_from_user_err;
+ fpc_table_add = kmalloc((64 + (fpc_t.fpnum * 4)),
+ GFP_KERNEL | GFP_DMA);
+ if (!fpc_table_add) {
+ printk(KERN_ERR "Cannot allocate memory for"
+ " FPC table");
+ return -ENOMEM;
+ }
+ while (((int)fpc_table_add & 0xFFFFFFC0) !=
+ (int)fpc_table_add)
+ fpc_table_add++;
+
+ fpc_table_add_m = ispmmu_map(virt_to_phys
+ (fpc_table_add),
+ (fpc_t.fpnum) * 4);
+
+ if (copy_from_user(fpc_table_add, (u32 *)fpc_t.fpcaddr,
+ fpc_t.fpnum * 4))
+ goto copy_from_user_err;
+
+ fpc_t.fpcaddr = fpc_table_add_m;
+ ispccdc_config_fpc(fpc_t);
+ }
+ ispccdc_enable_fpc(1);
+ } else if ((ISP_ABS_CCDC_FPC & ccdc_struct->update) ==
+ ISP_ABS_CCDC_FPC)
+ ispccdc_enable_fpc(0);
+
+ if ((ISP_ABS_CCDC_CULL & ccdc_struct->update) == ISP_ABS_CCDC_CULL) {
+ if (copy_from_user(&cull_t, (struct ispccdc_culling *)
+ (ccdc_struct->cull),
+ sizeof(cull_t)))
+ goto copy_from_user_err;
+ ispccdc_config_culling(cull_t);
+ }
+
+ if ((ISP_ABS_CCDC_COLPTN & ccdc_struct->update) == ISP_ABS_CCDC_COLPTN)
+ ispccdc_config_imgattr(ccdc_struct->colptn);
+
+ return 0;
+
+copy_from_user_err:
+ printk(KERN_ERR "CCDC Config:Copy From User Error");
+ return -EINVAL ;
+}
+
+/**
+ * ispccdc_request - Reserves the CCDC module.
+ *
+ * Reserves the CCDC module and assures that is used only once at a time.
+ *
+ * Returns 0 if successful, or -EBUSY if CCDC module is busy.
+ **/
+int ispccdc_request(void)
+{
+ mutex_lock(&ispccdc_obj.mutexlock);
+ if (ispccdc_obj.ccdc_inuse) {
+ mutex_unlock(&ispccdc_obj.mutexlock);
+ DPRINTK_ISPCCDC("ISP_ERR : CCDC Module Busy");
+ return -EBUSY;
+ }
+
+ ispccdc_obj.ccdc_inuse = 1;
+ mutex_unlock(&ispccdc_obj.mutexlock);
+ omap_writel((omap_readl(ISP_CTRL)) | ISPCTRL_CCDC_RAM_EN |
+ ISPCTRL_CCDC_CLK_EN |
+ ISPCTRL_SBL_WR1_RAM_EN,
+ ISP_CTRL);
+ omap_writel((omap_readl(ISPCCDC_CFG)) | ISPCCDC_CFG_VDLC, ISPCCDC_CFG);
+ return 0;
+}
+EXPORT_SYMBOL(ispccdc_request);
+
+/**
+ * ispccdc_free - Frees the CCDC module.
+ *
+ * Frees the CCDC module so it can be used by another process.
+ *
+ * Returns 0 if successful, or -EINVAL if module has been already freed.
+ **/
+int ispccdc_free(void)
+{
+ mutex_lock(&ispccdc_obj.mutexlock);
+ if (!ispccdc_obj.ccdc_inuse) {
+ mutex_unlock(&ispccdc_obj.mutexlock);
+ DPRINTK_ISPCCDC("ISP_ERR: CCDC Module already freed\n");
+ return -EINVAL;
+ }
+
+ ispccdc_obj.ccdc_inuse = 0;
+ mutex_unlock(&ispccdc_obj.mutexlock);
+ omap_writel((omap_readl(ISP_CTRL)) & ~(ISPCTRL_CCDC_CLK_EN |
+ ISPCTRL_CCDC_RAM_EN |
+ ISPCTRL_SBL_WR1_RAM_EN),
+ ISP_CTRL);
+ return 0;
+}
+EXPORT_SYMBOL(ispccdc_free);
+
+/**
+ * ispccdc_config_crop - Configures crop parameters for the ISP CCDC.
+ * @left: Left offset of the crop area.
+ * @top: Top offset of the crop area.
+ * @height: Height of the crop area.
+ * @width: Width of the crop area.
+ *
+ * The following restrictions are applied for the crop settings. If incoming
+ * values do not follow these restrictions then we map the settings to the
+ * closest acceptable crop value.
+ * 1) Left offset is always odd. This can be avoided if we enable byte swap
+ * option for incoming data into CCDC.
+ * 2) Top offset is always even.
+ * 3) Crop height is always even.
+ * 4) Crop width is always a multiple of 16 pixels
+ **/
+void ispccdc_config_crop(u32 left, u32 top, u32 height, u32 width)
+{
+ ispccdc_obj.ccdcin_woffset = left + ((left + 1) % 2);
+ ispccdc_obj.ccdcin_hoffset = top + (top % 2);
+
+ ispccdc_obj.crop_w = width - (width % 16);
+ ispccdc_obj.crop_h = height + (height % 2);
+
+ DPRINTK_ISPCCDC("\n\tOffsets L %d T %d W %d H %d\n",
+ ispccdc_obj.ccdcin_woffset,
+ ispccdc_obj.ccdcin_hoffset,
+ ispccdc_obj.crop_w,
+ ispccdc_obj.crop_h);
+}
+
+/**
+ * ispccdc_config_datapath - Specifies the input and output modules for CCDC.
+ * @input: Indicates the module that inputs the image to the CCDC.
+ * @output: Indicates the module to which the CCDC outputs the image.
+ *
+ * Configures the default configuration for the CCDC to work with.
+ *
+ * The valid values for the input are CCDC_RAW (0), CCDC_YUV_SYNC (1),
+ * CCDC_YUV_BT (2), and CCDC_OTHERS (3).
+ *
+ * The valid values for the output are CCDC_YUV_RSZ (0), CCDC_YUV_MEM_RSZ (1),
+ * CCDC_OTHERS_VP (2), CCDC_OTHERS_MEM (3), CCDC_OTHERS_VP_MEM (4).
+ *
+ * Returns 0 if successful, or -EINVAL if wrong I/O combination or wrong input
+ * or output values.
+ **/
+int ispccdc_config_datapath(enum ccdc_input input, enum ccdc_output output)
+{
+ u32 syn_mode = 0;
+ struct ispccdc_vp vpcfg;
+ struct ispccdc_syncif syncif;
+ struct ispccdc_bclamp blkcfg;
+
+ u32 colptn = (ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT) |
+ (ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC1_SHIFT) |
+ (ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT) |
+ (ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC3_SHIFT) |
+ (ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC0_SHIFT) |
+ (ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC1_SHIFT) |
+ (ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC2_SHIFT) |
+ (ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC3_SHIFT) |
+ (ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT) |
+ (ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC1_SHIFT) |
+ (ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT) |
+ (ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC3_SHIFT) |
+ (ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC0_SHIFT) |
+ (ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC1_SHIFT) |
+ (ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC2_SHIFT) |
+ (ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC3_SHIFT);
+
+ /* CCDC does not convert the image format */
+ if (((input == CCDC_RAW) || (input == CCDC_OTHERS)) &&
+ (output == CCDC_YUV_R