diff mbox

[9/9] omap34xxcam: Add camera driver

Message ID 1236074816-30018-9-git-send-email-sakari.ailus@maxwell.research.nokia.com (mailing list archive)
State Awaiting Upstream, archived
Headers show

Commit Message

Sakari Ailus March 3, 2009, 10:06 a.m. UTC
This is the camera driver for the OMAP 3 camera ISP and v4l2-int-device
sensors, lenses and (led) flashes. There are a few connections to OMAP
3 left but after those have been broken this is hardware independent.
Namely, the OMAP 3 ISP must offer a standard interface through
v4l2_subdev (or v4l2-int-device) first.

This driver has originated from the omap24xxcam camera driver written
specifically for OMAP 2.

TODO:

- Convert to use v4l2_subdev instead of v4l2-int-device.

Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
---
 drivers/media/video/Kconfig       |    9 +
 drivers/media/video/Makefile      |    2 +
 drivers/media/video/omap34xxcam.c | 1962 +++++++++++++++++++++++++++++++++++++
 drivers/media/video/omap34xxcam.h |  207 ++++
 4 files changed, 2180 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/omap34xxcam.c
 create mode 100644 drivers/media/video/omap34xxcam.h

Comments

Alexey Klimov March 3, 2009, 5:31 p.m. UTC | #1
On Tue, 2009-03-03 at 12:06 +0200, Sakari Ailus wrote:
> This is the camera driver for the OMAP 3 camera ISP and v4l2-int-device
> sensors, lenses and (led) flashes. There are a few connections to OMAP
> 3 left but after those have been broken this is hardware independent.
> Namely, the OMAP 3 ISP must offer a standard interface through
> v4l2_subdev (or v4l2-int-device) first.
> 
> This driver has originated from the omap24xxcam camera driver written
> specifically for OMAP 2.
> 
> TODO:
> 
> - Convert to use v4l2_subdev instead of v4l2-int-device.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
> ---
>  drivers/media/video/Kconfig       |    9 +
>  drivers/media/video/Makefile      |    2 +
>  drivers/media/video/omap34xxcam.c | 1962 +++++++++++++++++++++++++++++++++++++
>  drivers/media/video/omap34xxcam.h |  207 ++++
>  4 files changed, 2180 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/media/video/omap34xxcam.c
>  create mode 100644 drivers/media/video/omap34xxcam.h
> 
> diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
> index 19cf3b8..3cdb5a4 100644
> --- a/drivers/media/video/Kconfig
> +++ b/drivers/media/video/Kconfig
> @@ -711,6 +711,15 @@ 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
> +	select OMAP_IOMMU
> +	depends on VIDEO_V4L2 && ARCH_OMAP34XX
> +	---help---
> +	  Driver for an OMAP 3 camera controller.
> +
>  config SOC_CAMERA
>  	tristate "SoC camera support"
>  	depends on VIDEO_V4L2 && HAS_DMA
> diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
> index e654270..74a684e 100644
> --- a/drivers/media/video/Makefile
> +++ b/drivers/media/video/Makefile
> @@ -108,6 +108,8 @@ obj-$(CONFIG_VIDEO_OV7670) 	+= ov7670.o
>  
>  obj-y				+= isp/
>  
> +obj-$(CONFIG_VIDEO_OMAP3) += omap34xxcam.o
> +
>  obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
>  
>  obj-$(CONFIG_USB_DABUSB)        += dabusb.o
> diff --git a/drivers/media/video/omap34xxcam.c b/drivers/media/video/omap34xxcam.c
> new file mode 100644
> index 0000000..4d75b6f
> --- /dev/null
> +++ b/drivers/media/video/omap34xxcam.c
> @@ -0,0 +1,1962 @@
> +/*
> + * omap34xxcam.c
> + *
> + * Copyright (C) 2006--2009 Nokia Corporation
> + * Copyright (C) 2007--2009 Texas Instruments
> + *
> + * Contact: Sakari Ailus <sakari.ailus@nokia.com>
> + *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *
> + * Originally based on the OMAP 2 camera driver.
> + *
> + * Written by Sakari Ailus <sakari.ailus@nokia.com>
> + *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *            Sergio Aguirre <saaguirre@ti.com>
> + *            Mohit Jalori
> + *            Sameer Venkatraman
> + *            Leonides Martinez
> + *
> + * This program 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 program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#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 <media/v4l2-ioctl.h>
> +
> +#include "omap34xxcam.h"
> +#include "isp/isp.h"
> +#include "isp/ispmmu.h"
> +#include "isp/ispreg.h"
> +#include "isp/ispccdc.h"
> +#include "isp/isph3a.h"
> +#include "isp/isp_af.h"
> +#include "isp/isphist.h"
> +#include "isp/isppreview.h"
> +#include "isp/ispresizer.h"
> +
> +#define OMAP34XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
> +
> +/* global variables */
> +static struct omap34xxcam_device *omap34xxcam;
> +
> +/*
> + *
> + * Sensor handling.
> + *
> + */
> +
> +/**
> + * omap34xxcam_slave_power_set - set slave power state
> + * @vdev: per-video device data structure
> + * @power: new power state
> + */
> +static int omap34xxcam_slave_power_set(struct omap34xxcam_videodev *vdev,
> +				       enum v4l2_power power,
> +				       int mask)
> +{
> +	int rval = 0, i = 0;
> +
> +	BUG_ON(!mutex_is_locked(&vdev->mutex));
> +
> +#ifdef OMAP34XXCAM_POWEROFF_DELAY
> +	vdev->power_state_wish = -1;
> +#endif
> +
> +	for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +		if (vdev->slave[i] == v4l2_int_device_dummy())
> +			continue;
> +
> +		if (!(mask & (1 << i))
> +		    || power == vdev->power_state[i])
> +			continue;
> +
> +		rval = vidioc_int_s_power(vdev->slave[i], power);
> +
> +		if (rval && power != V4L2_POWER_OFF) {
> +			power = V4L2_POWER_OFF;
> +			goto out;
> +		}
> +
> +		vdev->power_state[i] = power;
> +	}
> +
> +	return 0;
> +
> +out:
> +	for (i--; i >= 0; i--) {
> +		if (vdev->slave[i] == v4l2_int_device_dummy())
> +			continue;
> +
> +		if (!(mask & (1 << i)))
> +			continue;
> +
> +		vidioc_int_s_power(vdev->slave[i], power);
> +		vdev->power_state[i] = power;
> +	}
> +
> +	return rval;
> +}
> +
> +#ifdef OMAP34XXCAM_POWEROFF_DELAY
> +static void omap34xxcam_slave_power_work(struct work_struct *work)
> +{
> +	struct omap34xxcam_videodev *vdev =
> +		container_of(work, struct omap34xxcam_videodev, poweroff_work);
> +
> +	mutex_lock(&vdev->mutex);
> +
> +	if (vdev->power_state_wish != -1)
> +		omap34xxcam_slave_power_set(vdev, vdev->power_state_wish,
> +					    vdev->power_state_mask);
> +
> +	mutex_unlock(&vdev->mutex);
> +}
> +
> +static void omap34xxcam_slave_power_timer(unsigned long ptr)
> +{
> +	struct omap34xxcam_videodev *vdev = (void *)ptr;
> +
> +	schedule_work(&vdev->poweroff_work);
> +}
> +
> +/**
> + * omap34xxcam_slave_power_suggest - delayed power state change
> + *
> + * @vdev: per-video device data structure
> + * @power: new power state
> + */
> +static void omap34xxcam_slave_power_suggest(struct omap34xxcam_videodev *vdev,
> +					    enum v4l2_power power,
> +					    int mask)
> +{
> +	BUG_ON(!mutex_is_locked(&vdev->mutex));
> +
> +	del_timer(&vdev->poweroff_timer);
> +
> +	vdev->power_state_wish = power;
> +	vdev->power_state_mask = mask;
> +
> +	mod_timer(&vdev->poweroff_timer, jiffies + OMAP34XXCAM_POWEROFF_DELAY);
> +}
> +#else /* OMAP34XXCAM_POWEROFF_DELAY */
> +#define omap34xxcam_slave_power_suggest(a, b, c) do {} while(0)
> +#endif /* OMAP34XXCAM_POWEROFF_DELAY */
> +
> +/**
> + * 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.
> + */
> +void omap34xxcam_vbq_complete(struct videobuf_buffer *vb, void *priv)
> +{
> +	struct omap34xxcam_fh *fh = priv;
> +
> +	do_gettimeofday(&vb->ts);
> +	vb->field_count = atomic_add_return(2, &fh->field_count);
> +
> +	wake_up(&vb->done);
> +}
> +
> +/**
> + * 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 omap34xxcam_videodev *vdev = fh->vdev;
> +
> +	if (*cnt <= 0)
> +		*cnt = VIDEO_MAX_FRAME;	/* supply a default number of buffers */
> +
> +	if (*cnt > VIDEO_MAX_FRAME)
> +		*cnt = VIDEO_MAX_FRAME;
> +
> +	*size = vdev->pix.sizeimage;
> +
> +	while (*size * *cnt > fh->vdev->vdev_sensor_config.capture_mem)
> +		(*cnt)--;
> +
> +	return isp_vbq_setup(vbq, cnt, size);
> +}
> +
> +/**
> + * 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 omap34xxcam_fh *fh = vbq->priv_data;
> +	struct omap34xxcam_videodev *vdev = fh->vdev;
> +	int err = 0;
> +
> +	/*
> +	 * 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 (vdev->pix.sizeimage > vb->bsize)
> +			/* The buffer isn't big enough. */
> +			return -EINVAL;
> +	} else {
> +		if (vb->state != VIDEOBUF_NEEDS_INIT
> +		    && vdev->pix.sizeimage > vb->bsize)
> +			/*
> +			 * We have a kernel bounce buffer that has
> +			 * already been allocated.
> +			 */
> +			omap34xxcam_vbq_release(vbq, vb);
> +	}
> +
> +	vb->size = vdev->pix.bytesperline * vdev->pix.height;
> +	vb->width = vdev->pix.width;
> +	vb->height = vdev->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;
> +
> +	vb->state = VIDEOBUF_ACTIVE;
> +
> +	isp_buf_queue(vb, omap34xxcam_vbq_complete, (void *)fh);
> +}
> +
> +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_SHORT_NAME, sizeof(cap->driver));
> +	strlcpy(cap->card, vdev->vfd->name, sizeof(cap->card));
> +	cap->version = OMAP34XXCAM_VERSION;
> +	if (vdev->vdev_sensor != v4l2_int_device_dummy())
> +		cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
> +
> +	return 0;
> +}
> +
> +/**
> + * vidioc_enum_fmt_vid_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_vid_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 == v4l2_int_device_dummy())
> +		return -EINVAL;
> +
> +	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_vid_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_vid_cap(struct file *file, void *fh,
> +				struct v4l2_format *f)
> +{
> +	struct omap34xxcam_fh *ofh = fh;
> +	struct omap34xxcam_videodev *vdev = ofh->vdev;
> +
> +	if (vdev->vdev_sensor == v4l2_int_device_dummy())
> +		return -EINVAL;
> +
> +	mutex_lock(&vdev->mutex);
> +	f->fmt.pix = vdev->pix;
> +	mutex_unlock(&vdev->mutex);

Hmmmm, you are using mutex_lock to lock reading from vdev structure..
Well, i don't if this is right approach. I am used to that mutex_lock is
used to prevent _changing_ of members in structure..


> +
> +	return 0;
> +}
> +
> +static int try_pix_parm(struct omap34xxcam_videodev *vdev,
> +			struct v4l2_pix_format *best_pix_in,
> +			struct v4l2_pix_format *wanted_pix_out,
> +			struct v4l2_fract *best_ival)
> +{
> +	int fps;
> +	int fmtd_index;
> +	int rval;
> +	struct v4l2_pix_format best_pix_out;
> +
> +	if (best_ival->numerator == 0
> +	    || best_ival->denominator == 0)
> +		*best_ival = vdev->vdev_sensor_config.ival_default;
> +
> +	fps = best_ival->denominator / best_ival->numerator;
> +
> +	best_ival->denominator = 0;
> +	best_pix_out.height = INT_MAX >> 1;
> +	best_pix_out.width = best_pix_out.height;
> +
> +	for (fmtd_index = 0; ; fmtd_index++) {
> +		int size_index;
> +		struct v4l2_fmtdesc fmtd;
> +
> +		fmtd.index = fmtd_index;
> +		fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +		rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, &fmtd);
> +		if (rval)
> +			break;
> +		dev_info(&vdev->vfd->dev, "trying fmt %8.8x (%d)\n",
> +			 fmtd.pixelformat, fmtd_index);
> +		/*
> +		 * Get supported resolutions.
> +		 */
> +		for (size_index = 0; ; size_index++) {
> +			struct v4l2_frmsizeenum frms;
> +			struct v4l2_pix_format pix_tmp_in, pix_tmp_out;
> +			int ival_index;
> +
> +			frms.index = size_index;
> +			frms.pixel_format = fmtd.pixelformat;
> +
> +			rval = vidioc_int_enum_framesizes(vdev->vdev_sensor,
> +							  &frms);
> +			if (rval)
> +				break;
> +
> +			pix_tmp_in.pixelformat = frms.pixel_format;
> +			pix_tmp_in.width = frms.discrete.width;
> +			pix_tmp_in.height = frms.discrete.height;
> +			pix_tmp_out = *wanted_pix_out;
> +			/* Don't do upscaling. */
> +			if (pix_tmp_out.width > pix_tmp_in.width)
> +				pix_tmp_out.width = pix_tmp_in.width;
> +			if (pix_tmp_out.height > pix_tmp_in.height)
> +				pix_tmp_out.height = pix_tmp_in.height;
> +			rval = isp_try_fmt_cap(&pix_tmp_in, &pix_tmp_out);
> +			if (rval)
> +				return rval;
> +
> +			dev_info(&vdev->vfd->dev, "this w %d\th %d\tfmt %8.8x\t"
> +				 "-> w %d\th %d\t fmt %8.8x"
> +				 "\twanted w %d\th %d\t fmt %8.8x\n",
> +				 pix_tmp_in.width, pix_tmp_in.height,
> +				 pix_tmp_in.pixelformat,
> +				 pix_tmp_out.width, pix_tmp_out.height,
> +				 pix_tmp_out.pixelformat,
> +				 wanted_pix_out->width, wanted_pix_out->height,
> +				 wanted_pix_out->pixelformat);
> +
> +#define IS_SMALLER_OR_EQUAL(pix1, pix2)				\
> +			((pix1)->width + (pix1)->height		\
> +			 < (pix2)->width + (pix2)->height)
> +#define SIZE_DIFF(pix1, pix2)						\
> +			(abs((pix1)->width - (pix2)->width)		\
> +			 + abs((pix1)->height - (pix2)->height))
> +
> +			/*
> +			 * Don't use modes that are farther from wanted size
> +			 * that what we already got.
> +			 */
> +			if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
> +			    > SIZE_DIFF(&best_pix_out, wanted_pix_out)) {
> +				dev_info(&vdev->vfd->dev, "size diff bigger: "
> +					 "w %d\th %d\tw %d\th %d\n",
> +					 pix_tmp_out.width, pix_tmp_out.height,
> +					 best_pix_out.width,
> +					 best_pix_out.height);
> +				continue;
> +			}
> +
> +			/*
> +			 * There's an input mode that can provide output
> +			 * closer to wanted.
> +			 */
> +			if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
> +			    < SIZE_DIFF(&best_pix_out, wanted_pix_out)) {
> +				/* Force renegotation of fps etc. */
> +				best_ival->denominator = 0;
> +				dev_info(&vdev->vfd->dev, "renegotiate: "
> +					 "w %d\th %d\tw %d\th %d\n",
> +					 pix_tmp_out.width, pix_tmp_out.height,
> +					 best_pix_out.width,
> +					 best_pix_out.height);
> +			}
> +
> +			for (ival_index = 0; ; ival_index++) {
> +				struct v4l2_frmivalenum frmi;
> +
> +				frmi.index = ival_index;
> +				frmi.pixel_format = frms.pixel_format;
> +				frmi.width = frms.discrete.width;
> +				frmi.height = frms.discrete.height;
> +				/* FIXME: try to fix standard... */
> +				frmi.reserved[0] = 0xdeafbeef;
> +
> +				rval = vidioc_int_enum_frameintervals(
> +					vdev->vdev_sensor, &frmi);
> +				if (rval)
> +					break;
> +
> +				dev_info(&vdev->vfd->dev, "fps %d\n",
> +					 frmi.discrete.denominator
> +					 / frmi.discrete.numerator);
> +
> +				if (best_ival->denominator == 0)
> +					goto do_it_now;
> +
> +				/*
> +				 * We aim to use maximum resolution
> +				 * from the sensor, provided that the
> +				 * fps is at least as close as on the
> +				 * current mode.
> +				 */
> +#define FPS_ABS_DIFF(fps, ival) abs(fps - (ival).denominator / (ival).numerator)
> +
> +				/* Select mode with closest fps. */
> +				if (FPS_ABS_DIFF(fps, frmi.discrete)
> +				    < FPS_ABS_DIFF(fps, *best_ival)) {
> +					dev_info(&vdev->vfd->dev, "closer fps: "
> +						 "fps %d\t fps %d\n",
> +						 FPS_ABS_DIFF(fps, frmi.discrete),
> +						 FPS_ABS_DIFF(fps, *best_ival));
> +					goto do_it_now;
> +				}
> +
> +				/*
> +				 * Select bigger resolution if it's available
> +				 * at same fps.
> +				 */
> +				if (frmi.width + frmi.height
> +				    > best_pix_in->width + best_pix_in->height
> +				    && FPS_ABS_DIFF(fps, frmi.discrete)
> +				    <= FPS_ABS_DIFF(fps, *best_ival)) {
> +					dev_info(&vdev->vfd->dev, "bigger res, "
> +						 "same fps: "
> +						 "w %d\th %d\tw %d\th %d\n",
> +						 frmi.width, frmi.height,
> +						 best_pix_in->width,
> +						 best_pix_in->height);
> +					goto do_it_now;
> +				}
> +
> +				dev_info(&vdev->vfd->dev, "falling through\n");
> +
> +				continue;
> +
> +			do_it_now:
> +				*best_ival = frmi.discrete;
> +				best_pix_out = pix_tmp_out;
> +				best_pix_in->width = frmi.width;
> +				best_pix_in->height = frmi.height;
> +				best_pix_in->pixelformat = frmi.pixel_format;
> +
> +				dev_info(&vdev->vfd->dev,
> +					 "best_pix_in: w %d\th %d\tfmt %8.8x"
> +					 "\tival %d/%d\n",
> +					 best_pix_in->width,
> +					 best_pix_in->height,
> +					 best_pix_in->pixelformat,
> +					 best_ival->numerator,
> +					 best_ival->denominator);
> +			}
> +		}
> +	}
> +
> +	if (best_ival->denominator == 0)
> +		return -EINVAL;
> +
> +	*wanted_pix_out = best_pix_out;
> +
> +	dev_info(&vdev->vfd->dev, "w %d, h %d, fmt %8.8x -> w %d, h %d\n",
> +		 best_pix_in->width, best_pix_in->height,
> +		 best_pix_in->pixelformat,
> +		 best_pix_out.width, best_pix_out.height);
> +
> +	return isp_try_fmt_cap(best_pix_in, wanted_pix_out);
> +}
> +
> +static int s_pix_parm(struct omap34xxcam_videodev *vdev,
> +		      struct v4l2_pix_format *best_pix,
> +		      struct v4l2_pix_format *pix,
> +		      struct v4l2_fract *best_ival)
> +{
> +	struct v4l2_streamparm a;
> +	struct v4l2_format fmt;
> +	int rval;
> +
> +	rval = try_pix_parm(vdev, best_pix, pix, best_ival);
> +	if (rval)
> +		return rval;
> +
> +	rval = isp_s_fmt_cap(best_pix, pix);
> +	if (rval)
> +		return rval;
> +
> +	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +	fmt.fmt.pix = *best_pix;
> +	rval = vidioc_int_s_fmt_cap(vdev->vdev_sensor, &fmt);
> +	if (rval)
> +		return rval;
> +
> +	a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +	a.parm.capture.timeperframe = *best_ival;
> +	rval = vidioc_int_s_parm(vdev->vdev_sensor, &a);
> +
> +	return rval;
> +}
> +
> +/**
> + * vidioc_s_fmt_vid_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_vid_cap().
> + */
> +static int vidioc_s_fmt_vid_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_tmp;
> +	struct v4l2_fract timeperframe;
> +	int rval;
> +
> +	if (vdev->vdev_sensor == v4l2_int_device_dummy())
> +		return -EINVAL;
> +
> +	mutex_lock(&vdev->mutex);
> +	if (vdev->streaming) {
> +		rval = -EBUSY;
> +		goto out;
> +	}

Well, why don't remove goto, place return -EBUSY, and move mutex after
if (vdev->streaming) check ?

> +
> +	vdev->want_pix = f->fmt.pix;
> +
> +	timeperframe = vdev->want_timeperframe;
> +
> +	rval = s_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe);
> +	if (!rval)
> +		vdev->pix = f->fmt.pix;
> +
> +out:
> +	mutex_unlock(&vdev->mutex);
> +
> +	return rval;
> +}
> +
> +/**
> + * vidioc_try_fmt_vid_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_vid_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_tmp;
> +	struct v4l2_fract timeperframe;
> +	int rval;
> +
> +	if (vdev->vdev_sensor == v4l2_int_device_dummy())
> +		return -EINVAL;
> +
> +	mutex_lock(&vdev->mutex);
> +
> +	timeperframe = vdev->want_timeperframe;
> +
> +	rval = try_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe);
> +
> +	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;
> +
> +	if (vdev->vdev_sensor == v4l2_int_device_dummy())
> +		return -EINVAL;
> +
> +	mutex_lock(&vdev->mutex);
> +	if (vdev->streaming) {
> +		mutex_unlock(&vdev->mutex);
> +		return -EBUSY;
> +	}

If i'm doing this i prefer to place mutex_lock after this
if(vdev->streaming) check.

> +
> +	rval = videobuf_reqbufs(&ofh->vbq, b);
> +
> +	mutex_unlock(&vdev->mutex);
> +
> +	/*
> +	 * 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;
> +	int rval;
> +
> +videobuf_dqbuf_again:
> +	rval = videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
> +
> +	/*
> +	 * This is a hack. We don't want to show -EIO to the user
> +	 * space. Requeue the buffer and try again if we're not doing
> +	 * this in non-blocking mode.
> +	 */
> +	if (rval == -EIO) {
> +		videobuf_qbuf(&ofh->vbq, b);
> +		if (!(file->f_flags & O_NONBLOCK))
> +			goto videobuf_dqbuf_again;
> +		/*
> +		 * We don't have a videobuf_buffer now --- maybe next
> +		 * time...
> +		 */
> +		rval = -EAGAIN;
> +	}
> +
> +	return rval;
> +}
> +
> +/**
> + * 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;
> +	int rval;
> +
> +	if (vdev->vdev_sensor == v4l2_int_device_dummy())
> +		return -EINVAL;
> +
> +	mutex_lock(&vdev->mutex);
> +	if (vdev->streaming) {
> +		rval = -EBUSY;
> +		goto out;
> +	}
> +
> +	rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +					   OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS);
> +	if (rval) {
> +		dev_dbg(&vdev->vfd->dev, "omap34xxcam_slave_power_set failed\n");
> +		goto out;
> +	}
> +
> +	rval = videobuf_streamon(&ofh->vbq);
> +	if (rval)
> +		omap34xxcam_slave_power_set(
> +			vdev, V4L2_POWER_OFF,
> +			OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS);
> +	else
> +		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;
> +
> +	mutex_lock(&vdev->mutex);
> +
> +	if (vdev->streaming == file)
> +		isp_stop();
> +
> +	rval = videobuf_streamoff(q);
> +	if (!rval) {
> +		vdev->streaming = NULL;
> +
> +		omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY,
> +					    OMAP34XXCAM_SLAVE_POWER_SENSOR);
> +		omap34xxcam_slave_power_suggest(vdev, V4L2_POWER_STANDBY,
> +						OMAP34XXCAM_SLAVE_POWER_LENS);
> +	}
> +
> +	mutex_unlock(&vdev->mutex);
> +
> +	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;
> +	struct v4l2_queryctrl a_tmp;
> +	int best_slave = -1;
> +	u32 best_ctrl = (u32)-1;
> +	int i;
> +
> +	if (vdev->vdev_sensor_config.sensor_isp)
> +		return vidioc_int_queryctrl(vdev->vdev_sensor, a);
> +
> +	/* No next flags: try slaves directly. */
> +	if (!(a->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
> +		for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +			if (!vidioc_int_queryctrl(vdev->slave[i], a))
> +				return 0;
> +		}
> +		return isp_queryctrl(a);
> +	}
> +
> +	/* Find slave with smallest next control id. */
> +	for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +		a_tmp = *a;
> +
> +		if (vidioc_int_queryctrl(vdev->slave[i], &a_tmp))
> +			continue;
> +
> +		if (a_tmp.id < best_ctrl) {
> +			best_slave = i;
> +			best_ctrl = a_tmp.id;
> +		}
> +	}
> +
> +	a_tmp = *a;
> +	if (!isp_queryctrl(&a_tmp)) {
> +		if (a_tmp.id < best_ctrl) {
> +			*a = a_tmp;
> +
> +			return 0;
> +		}
> +	}
> +
> +	if (best_slave == -1)
> +		return -EINVAL;
> +
> +	a->id = best_ctrl;
> +	return vidioc_int_queryctrl(vdev->slave[best_slave], a);
> +}
> +
> +/**
> + * vidioc_querymenu - V4L2 query menu IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @a: standard V4L2 query menu ioctl structure
> + *
> + * If the requested control is supported, returns the menu information
> + * in the v4l2_querymenu structure.  Otherwise, returns -EINVAL if the
> + * control is not supported or is not a menu.  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
> + * menu control, the request is forwarded to the "raw" sensor driver to
> + * see if it supports it.
> + */
> +static int vidioc_querymenu(struct file *file, void *fh,
> +			    struct v4l2_querymenu *a)
> +{
> +	struct omap34xxcam_fh *ofh = fh;
> +	struct omap34xxcam_videodev *vdev = ofh->vdev;
> +	int i;
> +
> +	if (vdev->vdev_sensor_config.sensor_isp)
> +		return vidioc_int_querymenu(vdev->vdev_sensor, a);
> +
> +	/* Try slaves directly. */
> +	for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +		if (!vidioc_int_querymenu(vdev->slave[i], a))
> +			return 0;
> +	}
> +	return isp_querymenu(a);
> +}
> +
> +static int vidioc_g_ext_ctrls(struct file *file, void *fh,
> +			      struct v4l2_ext_controls *a)
> +{
> +	struct omap34xxcam_fh *ofh = fh;
> +	struct omap34xxcam_videodev *vdev = ofh->vdev;
> +	int i, ctrl_idx, rval = 0;
> +
> +	mutex_lock(&vdev->mutex);
> +
> +	for (ctrl_idx = 0; ctrl_idx < a->count; ctrl_idx++) {
> +		struct v4l2_control ctrl;
> +
> +		ctrl.id = a->controls[ctrl_idx].id;
> +
> +		if (vdev->vdev_sensor_config.sensor_isp) {
> +			rval = vidioc_int_g_ctrl(vdev->vdev_sensor, &ctrl);
> +		} else {
> +			for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +				rval = vidioc_int_g_ctrl(vdev->slave[i], &ctrl);
> +				if (!rval)
> +					break;
> +			}
> +		}
> +
> +		if (rval)
> +			rval = isp_g_ctrl(&ctrl);
> +
> +		if (rval) {
> +			a->error_idx = ctrl_idx;
> +			break;
> +		}
> +
> +		a->controls[ctrl_idx].value = ctrl.value;
> +	}
> +
> +	mutex_unlock(&vdev->mutex);
> +
> +	return rval;
> +}
> +
> +static int vidioc_s_ext_ctrls(struct file *file, void *fh,
> +			      struct v4l2_ext_controls *a)
> +{
> +	struct omap34xxcam_fh *ofh = fh;
> +	struct omap34xxcam_videodev *vdev = ofh->vdev;
> +	int i, ctrl_idx, rval = 0;
> +
> +	mutex_lock(&vdev->mutex);
> +
> +	for (ctrl_idx = 0; ctrl_idx < a->count; ctrl_idx++) {
> +		struct v4l2_control ctrl;
> +
> +		ctrl.id = a->controls[ctrl_idx].id;
> +		ctrl.value = a->controls[ctrl_idx].value;
> +
> +		if (vdev->vdev_sensor_config.sensor_isp) {
> +			rval = vidioc_int_s_ctrl(vdev->vdev_sensor, &ctrl);
> +		} else {
> +			for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +				rval = vidioc_int_s_ctrl(vdev->slave[i], &ctrl);
> +				if (!rval)
> +					break;
> +			}
> +		}
> +
> +		if (rval)
> +			rval = isp_s_ctrl(&ctrl);
> +
> +		if (rval) {
> +			a->error_idx = ctrl_idx;
> +			break;
> +		}
> +
> +		a->controls[ctrl_idx].value = ctrl.value;
> +	}
> +
> +	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_pix_format pix_tmp_sensor, pix_tmp;
> +	int rval;
> +
> +	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
> +		return -EINVAL;
> +
> +	if (vdev->vdev_sensor == v4l2_int_device_dummy())
> +		return -EINVAL;
> +
> +	mutex_lock(&vdev->mutex);
> +	if (vdev->streaming) {
> +		rval = -EBUSY;
> +		goto out;
> +	}
> +
> +	vdev->want_timeperframe = a->parm.capture.timeperframe;
> +
> +	pix_tmp = vdev->want_pix;
> +
> +	rval = s_pix_parm(vdev, &pix_tmp_sensor, &pix_tmp,
> +			  &a->parm.capture.timeperframe);
> +
> +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 == v4l2_int_device_dummy())
> +		return -EINVAL;
> +
> +	mutex_lock(&vdev->mutex);
> +
> +	rval = vidioc_int_cropcap(vdev->vdev_sensor, a);
> +
> +	if (rval && !vdev->vdev_sensor_config.sensor_isp) {
> +		struct v4l2_format f;
> +
> +		/* cropcap failed, try to do this via g_fmt_cap */
> +		rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &f);
> +		if (!rval) {
> +			cropcap->bounds.top = 0;
> +			cropcap->bounds.left = 0;
> +			cropcap->bounds.width = f.fmt.pix.width;
> +			cropcap->bounds.height = f.fmt.pix.height;
> +			cropcap->defrect = cropcap->bounds;
> +			cropcap->pixelaspect.numerator = 1;
> +			cropcap->pixelaspect.denominator = 1;
> +		}
> +	}
> +
> +	mutex_unlock(&vdev->mutex);
> +
> +	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 == v4l2_int_device_dummy())
> +		return -EINVAL;
> +
> +	mutex_lock(&vdev->mutex);
> +
> +	if (vdev->vdev_sensor_config.sensor_isp)
> +		rval = vidioc_int_g_crop(vdev->vdev_sensor, a);
> +	else
> +		rval = isp_g_crop(a);
> +
> +	mutex_unlock(&vdev->mutex);
> +
> +	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;
> +	int rval = 0;
> +
> +	if (vdev->vdev_sensor == v4l2_int_device_dummy())
> +		return -EINVAL;
> +
> +	mutex_lock(&vdev->mutex);
> +
> +	if (vdev->vdev_sensor_config.sensor_isp)
> +		rval = vidioc_int_s_crop(vdev->vdev_sensor, a);
> +	else
> +		rval = isp_s_crop(a, &vdev->pix);
> +
> +	mutex_unlock(&vdev->mutex);
> +
> +	return rval;
> +}
> +
> +static int vidioc_enum_framesizes(struct file *file, void *fh,
> +				  struct v4l2_frmsizeenum *frms)
> +{
> +	struct omap34xxcam_fh *ofh = fh;
> +	struct omap34xxcam_videodev *vdev = ofh->vdev;
> +	u32 pixel_format;
> +	int rval;
> +
> +	mutex_lock(&vdev->mutex);
> +
> +	if (vdev->vdev_sensor_config.sensor_isp) {
> +		rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
> +	} else {
> +		pixel_format = frms->pixel_format;
> +		frms->pixel_format = -1;	/* ISP does format conversion */
> +		rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
> +		frms->pixel_format = pixel_format;
> +	}
> +
> +	mutex_unlock(&vdev->mutex);
> +	return rval;
> +}
> +
> +static int vidioc_enum_frameintervals(struct file *file, void *fh,
> +				      struct v4l2_frmivalenum *frmi)
> +{
> +	struct omap34xxcam_fh *ofh = fh;
> +	struct omap34xxcam_videodev *vdev = ofh->vdev;
> +	u32 pixel_format;
> +	int rval;
> +
> +	mutex_lock(&vdev->mutex);
> +
> +	if (vdev->vdev_sensor_config.sensor_isp) {
> +		rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
> +	} else {
> +		pixel_format = frmi->pixel_format;
> +		frmi->pixel_format = -1;	/* ISP does format conversion */
> +		rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
> +		frmi->pixel_format = pixel_format;
> +	}
> +
> +	mutex_unlock(&vdev->mutex);
> +	return rval;
> +}
> +
> +/**
> + * vidioc_default - private IOCTL handler
> + * @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 long vidioc_default(struct file *file, void *fh, int cmd, void *arg)
> +{
> +	struct omap34xxcam_fh *ofh = file->private_data;
> +	struct omap34xxcam_videodev *vdev = ofh->vdev;
> +	int rval;
> +
> +	if (vdev->vdev_sensor_config.sensor_isp) {
> +		rval = -EINVAL;
> +	} else {
> +		switch (cmd) {
> +		case VIDIOC_PRIVATE_ISP_AEWB_REQ:
> +		{
> +			/* Need to update sensor first */
> +			struct isph3a_aewb_data *data;
> +			struct v4l2_control vc;
> +
> +			data = (struct isph3a_aewb_data *) arg;
> +			if (data->update & SET_EXPOSURE) {
> +				dev_info(&vdev->vfd->dev, "using "
> +					 "VIDIOC_PRIVATE_ISP_AEWB_REQ to set "
> +					 "exposure is deprecated!\n");
> +				vc.id = V4L2_CID_EXPOSURE;
> +				vc.value = data->shutter;
> +				mutex_lock(&vdev->mutex);
> +				rval = vidioc_int_s_ctrl(vdev->vdev_sensor,
> +							 &vc);
> +				mutex_unlock(&vdev->mutex);
> +				if (rval)
> +					goto out;
> +			}
> +			if (data->update & SET_ANALOG_GAIN) {
> +				dev_info(&vdev->vfd->dev, "using "
> +					 "VIDIOC_PRIVATE_ISP_AEWB_REQ to set "
> +					 "gain is deprecated!\n");
> +				vc.id = V4L2_CID_GAIN;
> +				vc.value = data->gain;
> +				mutex_lock(&vdev->mutex);
> +				rval = vidioc_int_s_ctrl(vdev->vdev_sensor,
> +							 &vc);
> +				mutex_unlock(&vdev->mutex);
> +				if (rval)
> +					goto out;
> +			}
> +		}
> +		break;
> +		case VIDIOC_PRIVATE_ISP_AF_REQ: {
> +			/* Need to update lens first */
> +			struct isp_af_data *data;
> +			struct v4l2_control vc;
> +
> +			if (!vdev->vdev_lens) {
> +				rval = -EINVAL;
> +				goto out;
> +			}
> +			data = (struct isp_af_data *) arg;
> +			if (data->update & LENS_DESIRED_POSITION) {
> +				dev_info(&vdev->vfd->dev, "using "
> +					 "VIDIOC_PRIVATE_ISP_AF_REQ to set "
> +					 "lens position is deprecated!\n");
> +				vc.id = V4L2_CID_FOCUS_ABSOLUTE;
> +				vc.value = data->desired_lens_direction;
> +				mutex_lock(&vdev->mutex);
> +				rval = vidioc_int_s_ctrl(vdev->vdev_lens, &vc);
> +				mutex_unlock(&vdev->mutex);
> +				if (rval)
> +					goto out;
> +			}
> +		}
> +			break;
> +		}
> +
> +		mutex_lock(&vdev->mutex);
> +		rval = isp_handle_private(cmd, arg);
> +		mutex_unlock(&vdev->mutex);
> +	}
> +out:
> +	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 file *file)
> +{
> +	int rval = 0;
> +	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(file->f_dentry->d_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] != v4l2_int_device_dummy()
> +		    && !try_module_get(vdev->slave[i]->module)) {
> +			mutex_unlock(&vdev->mutex);
> +			dev_err(&vdev->vfd->dev, "can't try_module_get %s\n",
> +				vdev->slave[i]->name);
> +			rval = -ENODEV;
> +			goto out_try_module_get;
> +		}
> +	}
> +
> +	if (atomic_inc_return(&vdev->users) == 1) {
> +		rval = isp_get();
> +		if (rval < 0) {
> +			dev_err(&vdev->vfd->dev, "can't get isp\n");
> +			goto out_isp_get;
> +		}
> +		if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +						OMAP34XXCAM_SLAVE_POWER_ALL)) {
> +			dev_err(&vdev->vfd->dev, "can't power up slaves\n");
> +			rval = -EBUSY;
> +			goto out_slave_power_set_standby;
> +		}
> +		omap34xxcam_slave_power_set(
> +			vdev, V4L2_POWER_STANDBY,
> +			OMAP34XXCAM_SLAVE_POWER_SENSOR);
> +		omap34xxcam_slave_power_suggest(
> +			vdev, V4L2_POWER_STANDBY,
> +			OMAP34XXCAM_SLAVE_POWER_LENS);
> +	}
> +
> +	fh->vdev = vdev;
> +
> +	if (!vdev->pix.width
> +	    && vdev->vdev_sensor != v4l2_int_device_dummy()) {
> +		memset(&format, 0, sizeof(format));
> +		if (vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format)) {
> +			dev_err(&vdev->vfd->dev,
> +				"can't get current pix from sensor!\n");
> +			goto out_vidioc_int_g_fmt_cap;
> +		}
> +		if (!vdev->vdev_sensor_config.sensor_isp) {
> +			struct v4l2_pix_format pix = format.fmt.pix;
> +			if (isp_s_fmt_cap(&pix, &format.fmt.pix)) {
> +				dev_err(&vdev->vfd->dev,
> +					"isp doesn't like the sensor!\n");
> +				goto out_isp_s_fmt_cap;
> +			}
> +		}
> +		vdev->pix = format.fmt.pix;
> +	}
> +
> +	mutex_unlock(&vdev->mutex);
> +
> +	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_isp_s_fmt_cap:
> +out_vidioc_int_g_fmt_cap:
> +	omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
> +				    OMAP34XXCAM_SLAVE_POWER_ALL);
> +out_slave_power_set_standby:
> +	isp_put();
> +
> +out_isp_get:
> +	atomic_dec(&vdev->users);
> +	mutex_unlock(&vdev->mutex);
> +
> +out_try_module_get:
> +	for (i--; i >= 0; i--)
> +		if (vdev->slave[i] != v4l2_int_device_dummy())
> +			module_put(vdev->slave[i]->module);
> +
> +	kfree(fh);
> +
> +	return rval;
> +}
> +
> +/**
> + * 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 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,
> +			OMAP34XXCAM_SLAVE_POWER_SENSOR);
> +		omap34xxcam_slave_power_suggest(
> +			vdev, V4L2_POWER_STANDBY,
> +			OMAP34XXCAM_SLAVE_POWER_LENS);
> +		vdev->streaming = NULL;
> +	}
> +
> +	if (atomic_dec_return(&vdev->users) == 0) {
> +		omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
> +					    OMAP34XXCAM_SLAVE_POWER_ALL);
> +		isp_put();
> +	}
> +	mutex_unlock(&vdev->mutex);
> +
> +	file->private_data = NULL;
> +
> +	for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++)
> +		if (vdev->slave[i] != v4l2_int_device_dummy())
> +			module_put(vdev->slave[i]->module);
> +
> +	kfree(fh);
> +
> +	return 0;
> +}
> +
> +static struct v4l2_file_operations omap34xxcam_fops = {
> +	.owner = THIS_MODULE,
> +	.unlocked_ioctl = video_ioctl2,
> +	.poll = omap34xxcam_poll,
> +	.mmap = omap34xxcam_mmap,
> +	.open = omap34xxcam_open,
> +	.release = omap34xxcam_release,
> +};
> +
> +static void omap34xxcam_vfd_name_update(struct omap34xxcam_videodev *vdev)
> +{
> +	struct video_device *vfd = vdev->vfd;
> +	int i;
> +
> +	strlcpy(vfd->name, CAM_SHORT_NAME, sizeof(vfd->name));
> +	for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +		strlcat(vfd->name, "/", sizeof(vfd->name));
> +		if (vdev->slave[i] == v4l2_int_device_dummy())
> +			continue;
> +		strlcat(vfd->name, vdev->slave[i]->name, sizeof(vfd->name));
> +	}
> +	dev_info(&vdev->vfd->dev, "video%d is now %s\n", vfd->num, vfd->name);
> +}
> +
> +/**
> + * 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);
> +
> +	mutex_lock(&vdev->mutex);
> +
> +	if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy()) {
> +		vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
> +		vdev->slaves--;
> +		omap34xxcam_vfd_name_update(vdev);
> +	}
> +
> +	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;
> +	}
> +
> +	mutex_unlock(&vdev->mutex);
> +}
> +
> +static const struct v4l2_ioctl_ops omap34xxcam_ioctl_ops = {
> +	.vidioc_querycap		= vidioc_querycap,
> +	.vidioc_enum_fmt_vid_cap	= vidioc_enum_fmt_vid_cap,
> +	.vidioc_g_fmt_vid_cap		= vidioc_g_fmt_vid_cap,
> +	.vidioc_s_fmt_vid_cap		= vidioc_s_fmt_vid_cap,
> +	.vidioc_try_fmt_vid_cap		= vidioc_try_fmt_vid_cap,
> +	.vidioc_reqbufs			= vidioc_reqbufs,
> +	.vidioc_querybuf		= vidioc_querybuf,
> +	.vidioc_qbuf			= vidioc_qbuf,
> +	.vidioc_dqbuf			= vidioc_dqbuf,
> +	.vidioc_streamon		= vidioc_streamon,
> +	.vidioc_streamoff		= vidioc_streamoff,
> +	.vidioc_enum_input		= vidioc_enum_input,
> +	.vidioc_g_input			= vidioc_g_input,
> +	.vidioc_s_input			= vidioc_s_input,
> +	.vidioc_queryctrl		= vidioc_queryctrl,
> +	.vidioc_querymenu		= vidioc_querymenu,
> +	.vidioc_g_ext_ctrls		= vidioc_g_ext_ctrls,
> +	.vidioc_s_ext_ctrls		= vidioc_s_ext_ctrls,
> +	.vidioc_g_parm			= vidioc_g_parm,
> +	.vidioc_s_parm			= vidioc_s_parm,
> +	.vidioc_cropcap			= vidioc_cropcap,
> +	.vidioc_g_crop			= vidioc_g_crop,
> +	.vidioc_s_crop			= vidioc_s_crop,
> +	.vidioc_enum_framesizes		= vidioc_enum_framesizes,
> +	.vidioc_enum_frameintervals	= vidioc_enum_frameintervals,
> +	.vidioc_default			= vidioc_default,
> +};
> +
> +/**
> + * 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_hw_config hwc;
> +	int rval;
> +
> +	/* We need to check rval just once. The place is here. */

I didn't understand this comment. You doing nothin in next few lines
with int variable rval(which introduced in this function). Is comment
talking about struct v4l2_int_device *s ?

> +	if (vidioc_int_g_priv(s, &hwc))
> +		return -ENODEV;
> +
> +	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] != v4l2_int_device_dummy())
> +		return -EBUSY;
> +
> +	mutex_lock(&vdev->mutex);
> +	if (atomic_read(&vdev->users)) {
> +		dev_err(&vdev->vfd->dev, "we're open (%d), can't register\n",
> +			atomic_read(&vdev->users));
> +		mutex_unlock(&vdev->mutex);
> +		return -EBUSY;
> +	}
> +
> +	vdev->slaves++;
> +	vdev->slave[hwc.dev_type] = s;
> +	vdev->slave_config[hwc.dev_type] = hwc;
> +
> +	if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
> +		rval = isp_get();
> +		if (rval < 0) {
> +			dev_err(&vdev->vfd->dev,
> +				"can't get ISP, sensor init failed\n");
> +			goto err;
> +		}
> +	}
> +	rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +					   1 << hwc.dev_type);
> +	if (rval)
> +		goto err_omap34xxcam_slave_power_set;
> +	if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
> +		struct v4l2_format format;
> +
> +		format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +		rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
> +		if (rval)
> +			rval = -EBUSY;
> +
> +		vdev->want_pix = format.fmt.pix;
> +	}
> +	omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF, 1 << hwc.dev_type);
> +	if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
> +		isp_put();
> +
> +	if (rval)
> +		goto err;
> +
> +	/* Are we the first slave? */
> +	if (vdev->slaves == 1) {
> +		/* initialize the video_device struct */
> +		vdev->vfd = video_device_alloc();
> +		if (!vdev->vfd) {
> +			dev_err(&vdev->vfd->dev,
> +				"could not allocate video device struct\n");

Do i understand you code in right way ?
You call video_device_alloc() to get vdev->vfd. Then if vdev->vfd is
null(empty) you make message dev_err which based on vdev->vfd->dev but
dev->vfd allocating is failed.. If i'm not wrong you message will
provide kernel oops.
One more point here is that you use dev_err(&vdev->vfd->dev before call
to video_device_alloc() in this function.


> +			return -ENOMEM;
> +		}
> +		vdev->vfd->release	= video_device_release;
> +		vdev->vfd->minor	= -1;
> +		vdev->vfd->fops		= &omap34xxcam_fops;
> +		vdev->vfd->ioctl_ops	= &omap34xxcam_ioctl_ops;
> +		video_set_drvdata(vdev->vfd, vdev);
> +
> +		if (video_register_device(vdev->vfd, VFL_TYPE_GRABBER,
> +					  hwc.dev_minor) < 0) {
> +			dev_err(&vdev->vfd->dev,
> +				"could not register V4L device\n");
> +			vdev->vfd->minor = -1;
> +			rval = -EBUSY;
> +			goto err;
> +		}
> +	}
> +
> +	omap34xxcam_vfd_name_update(vdev);
> +
> +	mutex_unlock(&vdev->mutex);
> +
> +	return 0;
> +
> +err_omap34xxcam_slave_power_set:
> +	if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
> +		isp_put();
> +
> +err:
> +	if (s == vdev->slave[hwc.dev_type]) {
> +		vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
> +		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,
> +};
> +
> +/*
> + *
> + * Module initialisation and deinitialisation
> + *
> + */
> +
> +static void omap34xxcam_exit(void)
> +{
> +	struct omap34xxcam_device *cam = omap34xxcam;
> +	int i;
> +
> +	if (!cam)
> +		return;
> +
> +	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;
> +	}
> +
> +	omap34xxcam = NULL;
> +
> +	kfree(cam);
> +}
> +
> +static int __init omap34xxcam_init(void)
> +{
> +	struct omap34xxcam_device *cam;
> +	int i;
> +
> +	cam = kzalloc(sizeof(*cam), GFP_KERNEL);
> +	if (!cam) {
> +		printk(KERN_ERR "%s: could not allocate memory\n", __func__);
> +		goto err;

If kzalloc failed you return -ENODEV; but this is ENOMEM error.


> +	}
> +
> +	omap34xxcam = cam;
> +
> +	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;
> +
> +		mutex_init(&vdev->mutex);
> +		vdev->index             = i;
> +		vdev->cam               = cam;
> +		vdev->vdev_sensor =
> +			vdev->vdev_lens =
> +			vdev->vdev_flash = v4l2_int_device_dummy();
> +#ifdef OMAP34XXCAM_POWEROFF_DELAY
> +		setup_timer(&vdev->poweroff_timer,
> +			    omap34xxcam_slave_power_timer, (unsigned long)vdev);
> +		INIT_WORK(&vdev->poweroff_work, omap34xxcam_slave_power_work);
> +#endif /* OMAP34XXCAM_POWEROFF_DELAY */
> +
> +		if (v4l2_int_device_register(m))
> +			goto err;
> +	}
> +
> +	return 0;
> +
> +err:
> +	omap34xxcam_exit();
> +	return -ENODEV;
> +}
> +
> +MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
> +MODULE_DESCRIPTION("OMAP34xx Video for Linux camera driver");
> +MODULE_LICENSE("GPL");
> +
> +late_initcall(omap34xxcam_init);
> +module_exit(omap34xxcam_exit);
> diff --git a/drivers/media/video/omap34xxcam.h b/drivers/media/video/omap34xxcam.h
> new file mode 100644
> index 0000000..9859d15
> --- /dev/null
> +++ b/drivers/media/video/omap34xxcam.h
> @@ -0,0 +1,207 @@
> +/*
> + * omap34xxcam.h
> + *
> + * Copyright (C) 2006--2009 Nokia Corporation
> + * Copyright (C) 2007--2009 Texas Instruments
> + *
> + * Contact: Sakari Ailus <sakari.ailus@nokia.com>
> + *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *
> + * Originally based on the OMAP 2 camera driver.
> + *
> + * Written by Sakari Ailus <sakari.ailus@nokia.com>
> + *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *            Sergio Aguirre <saaguirre@ti.com>
> + *            Mohit Jalori
> + *            Sameer Venkatraman
> + *            Leonides Martinez
> + *
> + * This program 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 program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#ifndef OMAP34XXCAM_H
> +#define OMAP34XXCAM_H
> +
> +#include <media/v4l2-int-device.h>
> +#include "isp/isp.h"
> +
> +#define CAM_NAME			"omap34xxcam"
> +#define CAM_SHORT_NAME			"omap3"
> +
> +#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! */
> +
> +/* mask for omap34xxcam_slave_power_set */
> +#define OMAP34XXCAM_SLAVE_POWER_SENSOR	(1 << OMAP34XXCAM_SLAVE_SENSOR)
> +#define OMAP34XXCAM_SLAVE_POWER_LENS	(1 << OMAP34XXCAM_SLAVE_LENS)
> +#define OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS \
> +	(OMAP34XXCAM_SLAVE_POWER_SENSOR | OMAP34XXCAM_SLAVE_POWER_LENS)
> +#define OMAP34XXCAM_SLAVE_POWER_FLASH	(1 << OMAP34XXCAM_SLAVE_FLASH)
> +#define OMAP34XXCAM_SLAVE_POWER_ALL	-1
> +
> +#define OMAP34XXCAM_VIDEODEVS		4
> +
> +/* #define OMAP34XXCAM_POWEROFF_DELAY (2 * HZ) */
> +
> +struct omap34xxcam_device;
> +struct omap34xxcam_videodev;
> +
> +struct omap34xxcam_sensor_config {
> +	int xclk;
> +	int sensor_isp;
> +	u32 capture_mem;
> +	struct v4l2_fract ival_default;
> +};
> +
> +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
> + * @power_state: Current power state
> + * @power_state_wish: New power state when poweroff_timer expires
> + * @power_state_mask: Bitmask of devices to set the new power state
> + * @poweroff_timer: Timer for dispatching poweroff_work
> + * @poweroff_work: Work for slave power state change
> + * @sensor_config: ISP-speicific sensor configuration
> + * @lens_config: ISP-speicific lens configuration
> + * @flash_config: ISP-speicific flash configuration
> + * @want_timeperframe: Desired timeperframe
> + * @want_pix: Desired pix
> + * @pix: Current pix
> + * @streaming: streaming file handle, if streaming is enabled
> + */
> +struct omap34xxcam_videodev {
> +	struct mutex mutex; /* serialises access to this structure */
> +
> +	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 ***/
> +	int index;
> +	atomic_t users;
> +	enum v4l2_power power_state[OMAP34XXCAM_SLAVE_FLASH + 1];
> +#ifdef OMAP34XXCAM_POWEROFF_DELAY
> +	enum v4l2_power power_state_wish;
> +	int power_state_mask;
> +	struct timer_list poweroff_timer;
> +	struct work_struct poweroff_work;
> +#endif /* OMAP34XXCAM_POWEROFF_DELAY */
> +
> +#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 ***/
> +	struct file *streaming;
> +	struct v4l2_fract want_timeperframe;
> +	struct v4l2_pix_format want_pix;
> +	spinlock_t pix_lock;
> +	struct v4l2_pix_format pix;
> +};
> +
> +/**
> + * 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
> + * @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; /* serialises access to this structure */
> +
> +	/*** interfaces and device ***/
> +	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
> + * @field_count: field counter for videobuf_buffer
> + * @vdev: our /dev/video specific structure
> + */
> +struct omap34xxcam_fh {
> +	spinlock_t vbq_lock; /* spinlock for the videobuf queue */
> +	struct videobuf_queue vbq;
> +	atomic_t field_count;
> +	struct omap34xxcam_videodev *vdev;
> +};
> +
> +#endif /* ifndef OMAP34XXCAM_H */
Sakari Ailus March 5, 2009, 2:09 p.m. UTC | #2
Alexey Klimov wrote:
>> +static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
>> +				struct v4l2_format *f)
>> +{
>> +	struct omap34xxcam_fh *ofh = fh;
>> +	struct omap34xxcam_videodev *vdev = ofh->vdev;
>> +
>> +	if (vdev->vdev_sensor == v4l2_int_device_dummy())
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&vdev->mutex);
>> +	f->fmt.pix = vdev->pix;
>> +	mutex_unlock(&vdev->mutex);
> 
> Hmmmm, you are using mutex_lock to lock reading from vdev structure..
> Well, i don't if this is right approach. I am used to that mutex_lock is
> used to prevent _changing_ of members in structure..

The vdev->mutex is acquired since we want to prevent concurrent access 
to vdev->pix. Otherwise it might change while we are reading it, right?

>> +static int vidioc_s_fmt_vid_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_tmp;
>> +	struct v4l2_fract timeperframe;
>> +	int rval;
>> +
>> +	if (vdev->vdev_sensor == v4l2_int_device_dummy())
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&vdev->mutex);
>> +	if (vdev->streaming) {
>> +		rval = -EBUSY;
>> +		goto out;
>> +	}
> 
> Well, why don't remove goto, place return -EBUSY, and move mutex after
> if (vdev->streaming) check ?

The streaming state may change in the meantime. See vidioc_streamon. 
It's not very likely but possible as far as I understand.

>> +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;
>> +
>> +	if (vdev->vdev_sensor == v4l2_int_device_dummy())
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&vdev->mutex);
>> +	if (vdev->streaming) {
>> +		mutex_unlock(&vdev->mutex);
>> +		return -EBUSY;
>> +	}
> 
> If i'm doing this i prefer to place mutex_lock after this
> if(vdev->streaming) check.

Same here.

>> +static int omap34xxcam_device_register(struct v4l2_int_device *s)
>> +{
>> +	struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
>> +	struct omap34xxcam_hw_config hwc;
>> +	int rval;
>> +
>> +	/* We need to check rval just once. The place is here. */
> 
> I didn't understand this comment. You doing nothin in next few lines
> with int variable rval(which introduced in this function). Is comment
> talking about struct v4l2_int_device *s ?

Yes. If the g_priv() succeeds now it will succeed in future, too. This 
comes from the platform data through the slave device.

>> +	/* Are we the first slave? */
>> +	if (vdev->slaves == 1) {
>> +		/* initialize the video_device struct */
>> +		vdev->vfd = video_device_alloc();
>> +		if (!vdev->vfd) {
>> +			dev_err(&vdev->vfd->dev,
>> +				"could not allocate video device struct\n");
> 
> Do i understand you code in right way ?
> You call video_device_alloc() to get vdev->vfd. Then if vdev->vfd is
> null(empty) you make message dev_err which based on vdev->vfd->dev but
> dev->vfd allocating is failed.. If i'm not wrong you message will
> provide kernel oops.
> One more point here is that you use dev_err(&vdev->vfd->dev before call
> to video_device_alloc() in this function.

Indeed. Others hit this already. Thanks.

>> +static int __init omap34xxcam_init(void)
>> +{
>> +	struct omap34xxcam_device *cam;
>> +	int i;
>> +
>> +	cam = kzalloc(sizeof(*cam), GFP_KERNEL);
>> +	if (!cam) {
>> +		printk(KERN_ERR "%s: could not allocate memory\n", __func__);
>> +		goto err;
> 
> If kzalloc failed you return -ENODEV; but this is ENOMEM error.

Yes. Will fix.

Thanks again for the comments.
Alexey Klimov March 7, 2009, 2:38 p.m. UTC | #3
Hello, Sakari Ailus

On Thu, 2009-03-05 at 16:09 +0200, Sakari Ailus wrote:
> Alexey Klimov wrote:
> >> +static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
> >> +				struct v4l2_format *f)
> >> +{
> >> +	struct omap34xxcam_fh *ofh = fh;
> >> +	struct omap34xxcam_videodev *vdev = ofh->vdev;
> >> +
> >> +	if (vdev->vdev_sensor == v4l2_int_device_dummy())
> >> +		return -EINVAL;
> >> +
> >> +	mutex_lock(&vdev->mutex);
> >> +	f->fmt.pix = vdev->pix;
> >> +	mutex_unlock(&vdev->mutex);
> > 
> > Hmmmm, you are using mutex_lock to lock reading from vdev structure..
> > Well, i don't if this is right approach. I am used to that mutex_lock is
> > used to prevent _changing_ of members in structure..
> 
> The vdev->mutex is acquired since we want to prevent concurrent access 
> to vdev->pix. Otherwise it might change while we are reading it, right?

I thought more about this and looks like that i was wrong. You are
right. You are reading structure, and i wasn't able to notice that first
time. Sorry for bothering about this.

<snip>

> >> +static int omap34xxcam_device_register(struct v4l2_int_device *s)
> >> +{
> >> +	struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
> >> +	struct omap34xxcam_hw_config hwc;
> >> +	int rval;
> >> +
> >> +	/* We need to check rval just once. The place is here. */
> > 
> > I didn't understand this comment. You doing nothin in next few lines
> > with int variable rval(which introduced in this function). Is comment
> > talking about struct v4l2_int_device *s ?
> 
> Yes. If the g_priv() succeeds now it will succeed in future, too. This 
> comes from the platform data through the slave device.

Well, okay. I mean that for me this comment looks ambiguous. Please, if
you don't mind it's better not to use word "rval" because it  creates
confusion with int rval;.
diff mbox

Patch

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 19cf3b8..3cdb5a4 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -711,6 +711,15 @@  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
+	select OMAP_IOMMU
+	depends on VIDEO_V4L2 && ARCH_OMAP34XX
+	---help---
+	  Driver for an OMAP 3 camera controller.
+
 config SOC_CAMERA
 	tristate "SoC camera support"
 	depends on VIDEO_V4L2 && HAS_DMA
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index e654270..74a684e 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -108,6 +108,8 @@  obj-$(CONFIG_VIDEO_OV7670) 	+= ov7670.o
 
 obj-y				+= isp/
 
+obj-$(CONFIG_VIDEO_OMAP3) += omap34xxcam.o
+
 obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
 
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
diff --git a/drivers/media/video/omap34xxcam.c b/drivers/media/video/omap34xxcam.c
new file mode 100644
index 0000000..4d75b6f
--- /dev/null
+++ b/drivers/media/video/omap34xxcam.c
@@ -0,0 +1,1962 @@ 
+/*
+ * omap34xxcam.c
+ *
+ * Copyright (C) 2006--2009 Nokia Corporation
+ * Copyright (C) 2007--2009 Texas Instruments
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *
+ * Originally based on the OMAP 2 camera driver.
+ *
+ * Written by Sakari Ailus <sakari.ailus@nokia.com>
+ *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *            Sergio Aguirre <saaguirre@ti.com>
+ *            Mohit Jalori
+ *            Sameer Venkatraman
+ *            Leonides Martinez
+ *
+ * This program 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 program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#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 <media/v4l2-ioctl.h>
+
+#include "omap34xxcam.h"
+#include "isp/isp.h"
+#include "isp/ispmmu.h"
+#include "isp/ispreg.h"
+#include "isp/ispccdc.h"
+#include "isp/isph3a.h"
+#include "isp/isp_af.h"
+#include "isp/isphist.h"
+#include "isp/isppreview.h"
+#include "isp/ispresizer.h"
+
+#define OMAP34XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
+
+/* global variables */
+static struct omap34xxcam_device *omap34xxcam;
+
+/*
+ *
+ * Sensor handling.
+ *
+ */
+
+/**
+ * omap34xxcam_slave_power_set - set slave power state
+ * @vdev: per-video device data structure
+ * @power: new power state
+ */
+static int omap34xxcam_slave_power_set(struct omap34xxcam_videodev *vdev,
+				       enum v4l2_power power,
+				       int mask)
+{
+	int rval = 0, i = 0;
+
+	BUG_ON(!mutex_is_locked(&vdev->mutex));
+
+#ifdef OMAP34XXCAM_POWEROFF_DELAY
+	vdev->power_state_wish = -1;
+#endif
+
+	for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+		if (vdev->slave[i] == v4l2_int_device_dummy())
+			continue;
+
+		if (!(mask & (1 << i))
+		    || power == vdev->power_state[i])
+			continue;
+
+		rval = vidioc_int_s_power(vdev->slave[i], power);
+
+		if (rval && power != V4L2_POWER_OFF) {
+			power = V4L2_POWER_OFF;
+			goto out;
+		}
+
+		vdev->power_state[i] = power;
+	}
+
+	return 0;
+
+out:
+	for (i--; i >= 0; i--) {
+		if (vdev->slave[i] == v4l2_int_device_dummy())
+			continue;
+
+		if (!(mask & (1 << i)))
+			continue;
+
+		vidioc_int_s_power(vdev->slave[i], power);
+		vdev->power_state[i] = power;
+	}
+
+	return rval;
+}
+
+#ifdef OMAP34XXCAM_POWEROFF_DELAY
+static void omap34xxcam_slave_power_work(struct work_struct *work)
+{
+	struct omap34xxcam_videodev *vdev =
+		container_of(work, struct omap34xxcam_videodev, poweroff_work);
+
+	mutex_lock(&vdev->mutex);
+
+	if (vdev->power_state_wish != -1)
+		omap34xxcam_slave_power_set(vdev, vdev->power_state_wish,
+					    vdev->power_state_mask);
+
+	mutex_unlock(&vdev->mutex);
+}
+
+static void omap34xxcam_slave_power_timer(unsigned long ptr)
+{
+	struct omap34xxcam_videodev *vdev = (void *)ptr;
+
+	schedule_work(&vdev->poweroff_work);
+}
+
+/**
+ * omap34xxcam_slave_power_suggest - delayed power state change
+ *
+ * @vdev: per-video device data structure
+ * @power: new power state
+ */
+static void omap34xxcam_slave_power_suggest(struct omap34xxcam_videodev *vdev,
+					    enum v4l2_power power,
+					    int mask)
+{
+	BUG_ON(!mutex_is_locked(&vdev->mutex));
+
+	del_timer(&vdev->poweroff_timer);
+
+	vdev->power_state_wish = power;
+	vdev->power_state_mask = mask;
+
+	mod_timer(&vdev->poweroff_timer, jiffies + OMAP34XXCAM_POWEROFF_DELAY);
+}
+#else /* OMAP34XXCAM_POWEROFF_DELAY */
+#define omap34xxcam_slave_power_suggest(a, b, c) do {} while(0)
+#endif /* OMAP34XXCAM_POWEROFF_DELAY */
+
+/**
+ * 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.
+ */
+void omap34xxcam_vbq_complete(struct videobuf_buffer *vb, void *priv)
+{
+	struct omap34xxcam_fh *fh = priv;
+
+	do_gettimeofday(&vb->ts);
+	vb->field_count = atomic_add_return(2, &fh->field_count);
+
+	wake_up(&vb->done);
+}
+
+/**
+ * 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 omap34xxcam_videodev *vdev = fh->vdev;
+
+	if (*cnt <= 0)
+		*cnt = VIDEO_MAX_FRAME;	/* supply a default number of buffers */
+
+	if (*cnt > VIDEO_MAX_FRAME)
+		*cnt = VIDEO_MAX_FRAME;
+
+	*size = vdev->pix.sizeimage;
+
+	while (*size * *cnt > fh->vdev->vdev_sensor_config.capture_mem)
+		(*cnt)--;
+
+	return isp_vbq_setup(vbq, cnt, size);
+}
+
+/**
+ * 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 omap34xxcam_fh *fh = vbq->priv_data;
+	struct omap34xxcam_videodev *vdev = fh->vdev;
+	int err = 0;
+
+	/*
+	 * 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 (vdev->pix.sizeimage > vb->bsize)
+			/* The buffer isn't big enough. */
+			return -EINVAL;
+	} else {
+		if (vb->state != VIDEOBUF_NEEDS_INIT
+		    && vdev->pix.sizeimage > vb->bsize)
+			/*
+			 * We have a kernel bounce buffer that has
+			 * already been allocated.
+			 */
+			omap34xxcam_vbq_release(vbq, vb);
+	}
+
+	vb->size = vdev->pix.bytesperline * vdev->pix.height;
+	vb->width = vdev->pix.width;
+	vb->height = vdev->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;
+
+	vb->state = VIDEOBUF_ACTIVE;
+
+	isp_buf_queue(vb, omap34xxcam_vbq_complete, (void *)fh);
+}
+
+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_SHORT_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, vdev->vfd->name, sizeof(cap->card));
+	cap->version = OMAP34XXCAM_VERSION;
+	if (vdev->vdev_sensor != v4l2_int_device_dummy())
+		cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+/**
+ * vidioc_enum_fmt_vid_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_vid_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 == v4l2_int_device_dummy())
+		return -EINVAL;
+
+	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_vid_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_vid_cap(struct file *file, void *fh,
+				struct v4l2_format *f)
+{
+	struct omap34xxcam_fh *ofh = fh;
+	struct omap34xxcam_videodev *vdev = ofh->vdev;
+
+	if (vdev->vdev_sensor == v4l2_int_device_dummy())
+		return -EINVAL;
+
+	mutex_lock(&vdev->mutex);
+	f->fmt.pix = vdev->pix;
+	mutex_unlock(&vdev->mutex);
+
+	return 0;
+}
+
+static int try_pix_parm(struct omap34xxcam_videodev *vdev,
+			struct v4l2_pix_format *best_pix_in,
+			struct v4l2_pix_format *wanted_pix_out,
+			struct v4l2_fract *best_ival)
+{
+	int fps;
+	int fmtd_index;
+	int rval;
+	struct v4l2_pix_format best_pix_out;
+
+	if (best_ival->numerator == 0
+	    || best_ival->denominator == 0)
+		*best_ival = vdev->vdev_sensor_config.ival_default;
+
+	fps = best_ival->denominator / best_ival->numerator;
+
+	best_ival->denominator = 0;
+	best_pix_out.height = INT_MAX >> 1;
+	best_pix_out.width = best_pix_out.height;
+
+	for (fmtd_index = 0; ; fmtd_index++) {
+		int size_index;
+		struct v4l2_fmtdesc fmtd;
+
+		fmtd.index = fmtd_index;
+		fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, &fmtd);
+		if (rval)
+			break;
+		dev_info(&vdev->vfd->dev, "trying fmt %8.8x (%d)\n",
+			 fmtd.pixelformat, fmtd_index);
+		/*
+		 * Get supported resolutions.
+		 */
+		for (size_index = 0; ; size_index++) {
+			struct v4l2_frmsizeenum frms;
+			struct v4l2_pix_format pix_tmp_in, pix_tmp_out;
+			int ival_index;
+
+			frms.index = size_index;
+			frms.pixel_format = fmtd.pixelformat;
+
+			rval = vidioc_int_enum_framesizes(vdev->vdev_sensor,
+							  &frms);
+			if (rval)
+				break;
+
+			pix_tmp_in.pixelformat = frms.pixel_format;
+			pix_tmp_in.width = frms.discrete.width;
+			pix_tmp_in.height = frms.discrete.height;
+			pix_tmp_out = *wanted_pix_out;
+			/* Don't do upscaling. */
+			if (pix_tmp_out.width > pix_tmp_in.width)
+				pix_tmp_out.width = pix_tmp_in.width;
+			if (pix_tmp_out.height > pix_tmp_in.height)
+				pix_tmp_out.height = pix_tmp_in.height;
+			rval = isp_try_fmt_cap(&pix_tmp_in, &pix_tmp_out);
+			if (rval)
+				return rval;
+
+			dev_info(&vdev->vfd->dev, "this w %d\th %d\tfmt %8.8x\t"
+				 "-> w %d\th %d\t fmt %8.8x"
+				 "\twanted w %d\th %d\t fmt %8.8x\n",
+				 pix_tmp_in.width, pix_tmp_in.height,
+				 pix_tmp_in.pixelformat,
+				 pix_tmp_out.width, pix_tmp_out.height,
+				 pix_tmp_out.pixelformat,
+				 wanted_pix_out->width, wanted_pix_out->height,
+				 wanted_pix_out->pixelformat);
+
+#define IS_SMALLER_OR_EQUAL(pix1, pix2)				\
+			((pix1)->width + (pix1)->height		\
+			 < (pix2)->width + (pix2)->height)
+#define SIZE_DIFF(pix1, pix2)						\
+			(abs((pix1)->width - (pix2)->width)		\
+			 + abs((pix1)->height - (pix2)->height))
+
+			/*
+			 * Don't use modes that are farther from wanted size
+			 * that what we already got.
+			 */
+			if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
+			    > SIZE_DIFF(&best_pix_out, wanted_pix_out)) {
+				dev_info(&vdev->vfd->dev, "size diff bigger: "
+					 "w %d\th %d\tw %d\th %d\n",
+					 pix_tmp_out.width, pix_tmp_out.height,
+					 best_pix_out.width,
+					 best_pix_out.height);
+				continue;
+			}
+
+			/*
+			 * There's an input mode that can provide output
+			 * closer to wanted.
+			 */
+			if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
+			    < SIZE_DIFF(&best_pix_out, wanted_pix_out)) {
+				/* Force renegotation of fps etc. */
+				best_ival->denominator = 0;
+				dev_info(&vdev->vfd->dev, "renegotiate: "
+					 "w %d\th %d\tw %d\th %d\n",
+					 pix_tmp_out.width, pix_tmp_out.height,
+					 best_pix_out.width,
+					 best_pix_out.height);
+			}
+
+			for (ival_index = 0; ; ival_index++) {
+				struct v4l2_frmivalenum frmi;
+
+				frmi.index = ival_index;
+				frmi.pixel_format = frms.pixel_format;
+				frmi.width = frms.discrete.width;
+				frmi.height = frms.discrete.height;
+				/* FIXME: try to fix standard... */
+				frmi.reserved[0] = 0xdeafbeef;
+
+				rval = vidioc_int_enum_frameintervals(
+					vdev->vdev_sensor, &frmi);
+				if (rval)
+					break;
+
+				dev_info(&vdev->vfd->dev, "fps %d\n",
+					 frmi.discrete.denominator
+					 / frmi.discrete.numerator);
+
+				if (best_ival->denominator == 0)
+					goto do_it_now;
+
+				/*
+				 * We aim to use maximum resolution
+				 * from the sensor, provided that the
+				 * fps is at least as close as on the
+				 * current mode.
+				 */
+#define FPS_ABS_DIFF(fps, ival) abs(fps - (ival).denominator / (ival).numerator)
+
+				/* Select mode with closest fps. */
+				if (FPS_ABS_DIFF(fps, frmi.discrete)
+				    < FPS_ABS_DIFF(fps, *best_ival)) {
+					dev_info(&vdev->vfd->dev, "closer fps: "
+						 "fps %d\t fps %d\n",
+						 FPS_ABS_DIFF(fps, frmi.discrete),
+						 FPS_ABS_DIFF(fps, *best_ival));
+					goto do_it_now;
+				}
+
+				/*
+				 * Select bigger resolution if it's available
+				 * at same fps.
+				 */
+				if (frmi.width + frmi.height
+				    > best_pix_in->width + best_pix_in->height
+				    && FPS_ABS_DIFF(fps, frmi.discrete)
+				    <= FPS_ABS_DIFF(fps, *best_ival)) {
+					dev_info(&vdev->vfd->dev, "bigger res, "
+						 "same fps: "
+						 "w %d\th %d\tw %d\th %d\n",
+						 frmi.width, frmi.height,
+						 best_pix_in->width,
+						 best_pix_in->height);
+					goto do_it_now;
+				}
+
+				dev_info(&vdev->vfd->dev, "falling through\n");
+
+				continue;
+
+			do_it_now:
+				*best_ival = frmi.discrete;
+				best_pix_out = pix_tmp_out;
+				best_pix_in->width = frmi.width;
+				best_pix_in->height = frmi.height;
+				best_pix_in->pixelformat = frmi.pixel_format;
+
+				dev_info(&vdev->vfd->dev,
+					 "best_pix_in: w %d\th %d\tfmt %8.8x"
+					 "\tival %d/%d\n",
+					 best_pix_in->width,
+					 best_pix_in->height,
+					 best_pix_in->pixelformat,
+					 best_ival->numerator,
+					 best_ival->denominator);
+			}
+		}
+	}
+
+	if (best_ival->denominator == 0)
+		return -EINVAL;
+
+	*wanted_pix_out = best_pix_out;
+
+	dev_info(&vdev->vfd->dev, "w %d, h %d, fmt %8.8x -> w %d, h %d\n",
+		 best_pix_in->width, best_pix_in->height,
+		 best_pix_in->pixelformat,
+		 best_pix_out.width, best_pix_out.height);
+
+	return isp_try_fmt_cap(best_pix_in, wanted_pix_out);
+}
+
+static int s_pix_parm(struct omap34xxcam_videodev *vdev,
+		      struct v4l2_pix_format *best_pix,
+		      struct v4l2_pix_format *pix,
+		      struct v4l2_fract *best_ival)
+{
+	struct v4l2_streamparm a;
+	struct v4l2_format fmt;
+	int rval;
+
+	rval = try_pix_parm(vdev, best_pix, pix, best_ival);
+	if (rval)
+		return rval;
+
+	rval = isp_s_fmt_cap(best_pix, pix);
+	if (rval)
+		return rval;
+
+	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	fmt.fmt.pix = *best_pix;
+	rval = vidioc_int_s_fmt_cap(vdev->vdev_sensor, &fmt);
+	if (rval)
+		return rval;
+
+	a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a.parm.capture.timeperframe = *best_ival;
+	rval = vidioc_int_s_parm(vdev->vdev_sensor, &a);
+
+	return rval;
+}
+
+/**
+ * vidioc_s_fmt_vid_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_vid_cap().
+ */
+static int vidioc_s_fmt_vid_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_tmp;
+	struct v4l2_fract timeperframe;
+	int rval;
+
+	if (vdev->vdev_sensor == v4l2_int_device_dummy())
+		return -EINVAL;
+
+	mutex_lock(&vdev->mutex);
+	if (vdev->streaming) {
+		rval = -EBUSY;
+		goto out;
+	}
+
+	vdev->want_pix = f->fmt.pix;
+
+	timeperframe = vdev->want_timeperframe;
+
+	rval = s_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe);
+	if (!rval)
+		vdev->pix = f->fmt.pix;
+
+out:
+	mutex_unlock(&vdev->mutex);
+
+	return rval;
+}
+
+/**
+ * vidioc_try_fmt_vid_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_vid_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_tmp;
+	struct v4l2_fract timeperframe;
+	int rval;
+
+	if (vdev->vdev_sensor == v4l2_int_device_dummy())
+		return -EINVAL;
+
+	mutex_lock(&vdev->mutex);
+
+	timeperframe = vdev->want_timeperframe;
+
+	rval = try_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe);
+
+	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;
+
+	if (vdev->vdev_sensor == v4l2_int_device_dummy())
+		return -EINVAL;
+
+	mutex_lock(&vdev->mutex);
+	if (vdev->streaming) {
+		mutex_unlock(&vdev->mutex);
+		return -EBUSY;
+	}
+
+	rval = videobuf_reqbufs(&ofh->vbq, b);
+
+	mutex_unlock(&vdev->mutex);
+
+	/*
+	 * 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;
+	int rval;
+
+videobuf_dqbuf_again:
+	rval = videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
+
+	/*
+	 * This is a hack. We don't want to show -EIO to the user
+	 * space. Requeue the buffer and try again if we're not doing
+	 * this in non-blocking mode.
+	 */
+	if (rval == -EIO) {
+		videobuf_qbuf(&ofh->vbq, b);
+		if (!(file->f_flags & O_NONBLOCK))
+			goto videobuf_dqbuf_again;
+		/*
+		 * We don't have a videobuf_buffer now --- maybe next
+		 * time...
+		 */
+		rval = -EAGAIN;
+	}
+
+	return rval;
+}
+
+/**
+ * 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;
+	int rval;
+
+	if (vdev->vdev_sensor == v4l2_int_device_dummy())
+		return -EINVAL;
+
+	mutex_lock(&vdev->mutex);
+	if (vdev->streaming) {
+		rval = -EBUSY;
+		goto out;
+	}
+
+	rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+					   OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS);
+	if (rval) {
+		dev_dbg(&vdev->vfd->dev, "omap34xxcam_slave_power_set failed\n");
+		goto out;
+	}
+
+	rval = videobuf_streamon(&ofh->vbq);
+	if (rval)
+		omap34xxcam_slave_power_set(
+			vdev, V4L2_POWER_OFF,
+			OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS);
+	else
+		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;
+
+	mutex_lock(&vdev->mutex);
+
+	if (vdev->streaming == file)
+		isp_stop();
+
+	rval = videobuf_streamoff(q);
+	if (!rval) {
+		vdev->streaming = NULL;
+
+		omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY,
+					    OMAP34XXCAM_SLAVE_POWER_SENSOR);
+		omap34xxcam_slave_power_suggest(vdev, V4L2_POWER_STANDBY,
+						OMAP34XXCAM_SLAVE_POWER_LENS);
+	}
+
+	mutex_unlock(&vdev->mutex);
+
+	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;
+	struct v4l2_queryctrl a_tmp;
+	int best_slave = -1;
+	u32 best_ctrl = (u32)-1;
+	int i;
+
+	if (vdev->vdev_sensor_config.sensor_isp)
+		return vidioc_int_queryctrl(vdev->vdev_sensor, a);
+
+	/* No next flags: try slaves directly. */
+	if (!(a->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
+		for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+			if (!vidioc_int_queryctrl(vdev->slave[i], a))
+				return 0;
+		}
+		return isp_queryctrl(a);
+	}
+
+	/* Find slave with smallest next control id. */
+	for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+		a_tmp = *a;
+
+		if (vidioc_int_queryctrl(vdev->slave[i], &a_tmp))
+			continue;
+
+		if (a_tmp.id < best_ctrl) {
+			best_slave = i;
+			best_ctrl = a_tmp.id;
+		}
+	}
+
+	a_tmp = *a;
+	if (!isp_queryctrl(&a_tmp)) {
+		if (a_tmp.id < best_ctrl) {
+			*a = a_tmp;
+
+			return 0;
+		}
+	}
+
+	if (best_slave == -1)
+		return -EINVAL;
+
+	a->id = best_ctrl;
+	return vidioc_int_queryctrl(vdev->slave[best_slave], a);
+}
+
+/**
+ * vidioc_querymenu - V4L2 query menu IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 query menu ioctl structure
+ *
+ * If the requested control is supported, returns the menu information
+ * in the v4l2_querymenu structure.  Otherwise, returns -EINVAL if the
+ * control is not supported or is not a menu.  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
+ * menu control, the request is forwarded to the "raw" sensor driver to
+ * see if it supports it.
+ */
+static int vidioc_querymenu(struct file *file, void *fh,
+			    struct v4l2_querymenu *a)
+{
+	struct omap34xxcam_fh *ofh = fh;
+	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	int i;
+
+	if (vdev->vdev_sensor_config.sensor_isp)
+		return vidioc_int_querymenu(vdev->vdev_sensor, a);
+
+	/* Try slaves directly. */
+	for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+		if (!vidioc_int_querymenu(vdev->slave[i], a))
+			return 0;
+	}
+	return isp_querymenu(a);
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *fh,
+			      struct v4l2_ext_controls *a)
+{
+	struct omap34xxcam_fh *ofh = fh;
+	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	int i, ctrl_idx, rval = 0;
+
+	mutex_lock(&vdev->mutex);
+
+	for (ctrl_idx = 0; ctrl_idx < a->count; ctrl_idx++) {
+		struct v4l2_control ctrl;
+
+		ctrl.id = a->controls[ctrl_idx].id;
+
+		if (vdev->vdev_sensor_config.sensor_isp) {
+			rval = vidioc_int_g_ctrl(vdev->vdev_sensor, &ctrl);
+		} else {
+			for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+				rval = vidioc_int_g_ctrl(vdev->slave[i], &ctrl);
+				if (!rval)
+					break;
+			}
+		}
+
+		if (rval)
+			rval = isp_g_ctrl(&ctrl);
+
+		if (rval) {
+			a->error_idx = ctrl_idx;
+			break;
+		}
+
+		a->controls[ctrl_idx].value = ctrl.value;
+	}
+
+	mutex_unlock(&vdev->mutex);
+
+	return rval;
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *fh,
+			      struct v4l2_ext_controls *a)
+{
+	struct omap34xxcam_fh *ofh = fh;
+	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	int i, ctrl_idx, rval = 0;
+
+	mutex_lock(&vdev->mutex);
+
+	for (ctrl_idx = 0; ctrl_idx < a->count; ctrl_idx++) {
+		struct v4l2_control ctrl;
+
+		ctrl.id = a->controls[ctrl_idx].id;
+		ctrl.value = a->controls[ctrl_idx].value;
+
+		if (vdev->vdev_sensor_config.sensor_isp) {
+			rval = vidioc_int_s_ctrl(vdev->vdev_sensor, &ctrl);
+		} else {
+			for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+				rval = vidioc_int_s_ctrl(vdev->slave[i], &ctrl);
+				if (!rval)
+					break;
+			}
+		}
+
+		if (rval)
+			rval = isp_s_ctrl(&ctrl);
+
+		if (rval) {
+			a->error_idx = ctrl_idx;
+			break;
+		}
+
+		a->controls[ctrl_idx].value = ctrl.value;
+	}
+
+	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_pix_format pix_tmp_sensor, pix_tmp;
+	int rval;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (vdev->vdev_sensor == v4l2_int_device_dummy())
+		return -EINVAL;
+
+	mutex_lock(&vdev->mutex);
+	if (vdev->streaming) {
+		rval = -EBUSY;
+		goto out;
+	}
+
+	vdev->want_timeperframe = a->parm.capture.timeperframe;
+
+	pix_tmp = vdev->want_pix;
+
+	rval = s_pix_parm(vdev, &pix_tmp_sensor, &pix_tmp,
+			  &a->parm.capture.timeperframe);
+
+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 == v4l2_int_device_dummy())
+		return -EINVAL;
+
+	mutex_lock(&vdev->mutex);
+
+	rval = vidioc_int_cropcap(vdev->vdev_sensor, a);
+
+	if (rval && !vdev->vdev_sensor_config.sensor_isp) {
+		struct v4l2_format f;
+
+		/* cropcap failed, try to do this via g_fmt_cap */
+		rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &f);
+		if (!rval) {
+			cropcap->bounds.top = 0;
+			cropcap->bounds.left = 0;
+			cropcap->bounds.width = f.fmt.pix.width;
+			cropcap->bounds.height = f.fmt.pix.height;
+			cropcap->defrect = cropcap->bounds;
+			cropcap->pixelaspect.numerator = 1;
+			cropcap->pixelaspect.denominator = 1;
+		}
+	}
+
+	mutex_unlock(&vdev->mutex);
+
+	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 == v4l2_int_device_dummy())
+		return -EINVAL;
+
+	mutex_lock(&vdev->mutex);
+
+	if (vdev->vdev_sensor_config.sensor_isp)
+		rval = vidioc_int_g_crop(vdev->vdev_sensor, a);
+	else
+		rval = isp_g_crop(a);
+
+	mutex_unlock(&vdev->mutex);
+
+	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;
+	int rval = 0;
+
+	if (vdev->vdev_sensor == v4l2_int_device_dummy())
+		return -EINVAL;
+
+	mutex_lock(&vdev->mutex);
+
+	if (vdev->vdev_sensor_config.sensor_isp)
+		rval = vidioc_int_s_crop(vdev->vdev_sensor, a);
+	else
+		rval = isp_s_crop(a, &vdev->pix);
+
+	mutex_unlock(&vdev->mutex);
+
+	return rval;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *fh,
+				  struct v4l2_frmsizeenum *frms)
+{
+	struct omap34xxcam_fh *ofh = fh;
+	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	u32 pixel_format;
+	int rval;
+
+	mutex_lock(&vdev->mutex);
+
+	if (vdev->vdev_sensor_config.sensor_isp) {
+		rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
+	} else {
+		pixel_format = frms->pixel_format;
+		frms->pixel_format = -1;	/* ISP does format conversion */
+		rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
+		frms->pixel_format = pixel_format;
+	}
+
+	mutex_unlock(&vdev->mutex);
+	return rval;
+}
+
+static int vidioc_enum_frameintervals(struct file *file, void *fh,
+				      struct v4l2_frmivalenum *frmi)
+{
+	struct omap34xxcam_fh *ofh = fh;
+	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	u32 pixel_format;
+	int rval;
+
+	mutex_lock(&vdev->mutex);
+
+	if (vdev->vdev_sensor_config.sensor_isp) {
+		rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
+	} else {
+		pixel_format = frmi->pixel_format;
+		frmi->pixel_format = -1;	/* ISP does format conversion */
+		rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
+		frmi->pixel_format = pixel_format;
+	}
+
+	mutex_unlock(&vdev->mutex);
+	return rval;
+}
+
+/**
+ * vidioc_default - private IOCTL handler
+ * @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 long vidioc_default(struct file *file, void *fh, int cmd, void *arg)
+{
+	struct omap34xxcam_fh *ofh = file->private_data;
+	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	int rval;
+
+	if (vdev->vdev_sensor_config.sensor_isp) {
+		rval = -EINVAL;
+	} else {
+		switch (cmd) {
+		case VIDIOC_PRIVATE_ISP_AEWB_REQ:
+		{
+			/* Need to update sensor first */
+			struct isph3a_aewb_data *data;
+			struct v4l2_control vc;
+
+			data = (struct isph3a_aewb_data *) arg;
+			if (data->update & SET_EXPOSURE) {
+				dev_info(&vdev->vfd->dev, "using "
+					 "VIDIOC_PRIVATE_ISP_AEWB_REQ to set "
+					 "exposure is deprecated!\n");
+				vc.id = V4L2_CID_EXPOSURE;
+				vc.value = data->shutter;
+				mutex_lock(&vdev->mutex);
+				rval = vidioc_int_s_ctrl(vdev->vdev_sensor,
+							 &vc);
+				mutex_unlock(&vdev->mutex);
+				if (rval)
+					goto out;
+			}
+			if (data->update & SET_ANALOG_GAIN) {
+				dev_info(&vdev->vfd->dev, "using "
+					 "VIDIOC_PRIVATE_ISP_AEWB_REQ to set "
+					 "gain is deprecated!\n");
+				vc.id = V4L2_CID_GAIN;
+				vc.value = data->gain;
+				mutex_lock(&vdev->mutex);
+				rval = vidioc_int_s_ctrl(vdev->vdev_sensor,
+							 &vc);
+				mutex_unlock(&vdev->mutex);
+				if (rval)
+					goto out;
+			}
+		}
+		break;
+		case VIDIOC_PRIVATE_ISP_AF_REQ: {
+			/* Need to update lens first */
+			struct isp_af_data *data;
+			struct v4l2_control vc;
+
+			if (!vdev->vdev_lens) {
+				rval = -EINVAL;
+				goto out;
+			}
+			data = (struct isp_af_data *) arg;
+			if (data->update & LENS_DESIRED_POSITION) {
+				dev_info(&vdev->vfd->dev, "using "
+					 "VIDIOC_PRIVATE_ISP_AF_REQ to set "
+					 "lens position is deprecated!\n");
+				vc.id = V4L2_CID_FOCUS_ABSOLUTE;
+				vc.value = data->desired_lens_direction;
+				mutex_lock(&vdev->mutex);
+				rval = vidioc_int_s_ctrl(vdev->vdev_lens, &vc);
+				mutex_unlock(&vdev->mutex);
+				if (rval)
+					goto out;
+			}
+		}
+			break;
+		}
+
+		mutex_lock(&vdev->mutex);
+		rval = isp_handle_private(cmd, arg);
+		mutex_unlock(&vdev->mutex);
+	}
+out:
+	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 file *file)
+{
+	int rval = 0;
+	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(file->f_dentry->d_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] != v4l2_int_device_dummy()
+		    && !try_module_get(vdev->slave[i]->module)) {
+			mutex_unlock(&vdev->mutex);
+			dev_err(&vdev->vfd->dev, "can't try_module_get %s\n",
+				vdev->slave[i]->name);
+			rval = -ENODEV;
+			goto out_try_module_get;
+		}
+	}
+
+	if (atomic_inc_return(&vdev->users) == 1) {
+		rval = isp_get();
+		if (rval < 0) {
+			dev_err(&vdev->vfd->dev, "can't get isp\n");
+			goto out_isp_get;
+		}
+		if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+						OMAP34XXCAM_SLAVE_POWER_ALL)) {
+			dev_err(&vdev->vfd->dev, "can't power up slaves\n");
+			rval = -EBUSY;
+			goto out_slave_power_set_standby;
+		}
+		omap34xxcam_slave_power_set(
+			vdev, V4L2_POWER_STANDBY,
+			OMAP34XXCAM_SLAVE_POWER_SENSOR);
+		omap34xxcam_slave_power_suggest(
+			vdev, V4L2_POWER_STANDBY,
+			OMAP34XXCAM_SLAVE_POWER_LENS);
+	}
+
+	fh->vdev = vdev;
+
+	if (!vdev->pix.width
+	    && vdev->vdev_sensor != v4l2_int_device_dummy()) {
+		memset(&format, 0, sizeof(format));
+		if (vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format)) {
+			dev_err(&vdev->vfd->dev,
+				"can't get current pix from sensor!\n");
+			goto out_vidioc_int_g_fmt_cap;
+		}
+		if (!vdev->vdev_sensor_config.sensor_isp) {
+			struct v4l2_pix_format pix = format.fmt.pix;
+			if (isp_s_fmt_cap(&pix, &format.fmt.pix)) {
+				dev_err(&vdev->vfd->dev,
+					"isp doesn't like the sensor!\n");
+				goto out_isp_s_fmt_cap;
+			}
+		}
+		vdev->pix = format.fmt.pix;
+	}
+
+	mutex_unlock(&vdev->mutex);
+
+	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_isp_s_fmt_cap:
+out_vidioc_int_g_fmt_cap:
+	omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
+				    OMAP34XXCAM_SLAVE_POWER_ALL);
+out_slave_power_set_standby:
+	isp_put();
+
+out_isp_get:
+	atomic_dec(&vdev->users);
+	mutex_unlock(&vdev->mutex);
+
+out_try_module_get:
+	for (i--; i >= 0; i--)
+		if (vdev->slave[i] != v4l2_int_device_dummy())
+			module_put(vdev->slave[i]->module);
+
+	kfree(fh);
+
+	return rval;
+}
+
+/**
+ * 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 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,
+			OMAP34XXCAM_SLAVE_POWER_SENSOR);
+		omap34xxcam_slave_power_suggest(
+			vdev, V4L2_POWER_STANDBY,
+			OMAP34XXCAM_SLAVE_POWER_LENS);
+		vdev->streaming = NULL;
+	}
+
+	if (atomic_dec_return(&vdev->users) == 0) {
+		omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
+					    OMAP34XXCAM_SLAVE_POWER_ALL);
+		isp_put();
+	}
+	mutex_unlock(&vdev->mutex);
+
+	file->private_data = NULL;
+
+	for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++)
+		if (vdev->slave[i] != v4l2_int_device_dummy())
+			module_put(vdev->slave[i]->module);
+
+	kfree(fh);
+
+	return 0;
+}
+
+static struct v4l2_file_operations omap34xxcam_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = video_ioctl2,
+	.poll = omap34xxcam_poll,
+	.mmap = omap34xxcam_mmap,
+	.open = omap34xxcam_open,
+	.release = omap34xxcam_release,
+};
+
+static void omap34xxcam_vfd_name_update(struct omap34xxcam_videodev *vdev)
+{
+	struct video_device *vfd = vdev->vfd;
+	int i;
+
+	strlcpy(vfd->name, CAM_SHORT_NAME, sizeof(vfd->name));
+	for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+		strlcat(vfd->name, "/", sizeof(vfd->name));
+		if (vdev->slave[i] == v4l2_int_device_dummy())
+			continue;
+		strlcat(vfd->name, vdev->slave[i]->name, sizeof(vfd->name));
+	}
+	dev_info(&vdev->vfd->dev, "video%d is now %s\n", vfd->num, vfd->name);
+}
+
+/**
+ * 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);
+
+	mutex_lock(&vdev->mutex);
+
+	if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy()) {
+		vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
+		vdev->slaves--;
+		omap34xxcam_vfd_name_update(vdev);
+	}
+
+	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;
+	}
+
+	mutex_unlock(&vdev->mutex);
+}
+
+static const struct v4l2_ioctl_ops omap34xxcam_ioctl_ops = {
+	.vidioc_querycap		= vidioc_querycap,
+	.vidioc_enum_fmt_vid_cap	= vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap		= vidioc_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap		= vidioc_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap		= vidioc_try_fmt_vid_cap,
+	.vidioc_reqbufs			= vidioc_reqbufs,
+	.vidioc_querybuf		= vidioc_querybuf,
+	.vidioc_qbuf			= vidioc_qbuf,
+	.vidioc_dqbuf			= vidioc_dqbuf,
+	.vidioc_streamon		= vidioc_streamon,
+	.vidioc_streamoff		= vidioc_streamoff,
+	.vidioc_enum_input		= vidioc_enum_input,
+	.vidioc_g_input			= vidioc_g_input,
+	.vidioc_s_input			= vidioc_s_input,
+	.vidioc_queryctrl		= vidioc_queryctrl,
+	.vidioc_querymenu		= vidioc_querymenu,
+	.vidioc_g_ext_ctrls		= vidioc_g_ext_ctrls,
+	.vidioc_s_ext_ctrls		= vidioc_s_ext_ctrls,
+	.vidioc_g_parm			= vidioc_g_parm,
+	.vidioc_s_parm			= vidioc_s_parm,
+	.vidioc_cropcap			= vidioc_cropcap,
+	.vidioc_g_crop			= vidioc_g_crop,
+	.vidioc_s_crop			= vidioc_s_crop,
+	.vidioc_enum_framesizes		= vidioc_enum_framesizes,
+	.vidioc_enum_frameintervals	= vidioc_enum_frameintervals,
+	.vidioc_default			= vidioc_default,
+};
+
+/**
+ * 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_hw_config hwc;
+	int rval;
+
+	/* We need to check rval just once. The place is here. */
+	if (vidioc_int_g_priv(s, &hwc))
+		return -ENODEV;
+
+	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] != v4l2_int_device_dummy())
+		return -EBUSY;
+
+	mutex_lock(&vdev->mutex);
+	if (atomic_read(&vdev->users)) {
+		dev_err(&vdev->vfd->dev, "we're open (%d), can't register\n",
+			atomic_read(&vdev->users));
+		mutex_unlock(&vdev->mutex);
+		return -EBUSY;
+	}
+
+	vdev->slaves++;
+	vdev->slave[hwc.dev_type] = s;
+	vdev->slave_config[hwc.dev_type] = hwc;
+
+	if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
+		rval = isp_get();
+		if (rval < 0) {
+			dev_err(&vdev->vfd->dev,
+				"can't get ISP, sensor init failed\n");
+			goto err;
+		}
+	}
+	rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+					   1 << hwc.dev_type);
+	if (rval)
+		goto err_omap34xxcam_slave_power_set;
+	if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
+		struct v4l2_format format;
+
+		format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
+		if (rval)
+			rval = -EBUSY;
+
+		vdev->want_pix = format.fmt.pix;
+	}
+	omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF, 1 << hwc.dev_type);
+	if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
+		isp_put();
+
+	if (rval)
+		goto err;
+
+	/* Are we the first slave? */
+	if (vdev->slaves == 1) {
+		/* initialize the video_device struct */
+		vdev->vfd = video_device_alloc();
+		if (!vdev->vfd) {
+			dev_err(&vdev->vfd->dev,
+				"could not allocate video device struct\n");
+			return -ENOMEM;
+		}
+		vdev->vfd->release	= video_device_release;
+		vdev->vfd->minor	= -1;
+		vdev->vfd->fops		= &omap34xxcam_fops;
+		vdev->vfd->ioctl_ops	= &omap34xxcam_ioctl_ops;
+		video_set_drvdata(vdev->vfd, vdev);
+
+		if (video_register_device(vdev->vfd, VFL_TYPE_GRABBER,
+					  hwc.dev_minor) < 0) {
+			dev_err(&vdev->vfd->dev,
+				"could not register V4L device\n");
+			vdev->vfd->minor = -1;
+			rval = -EBUSY;
+			goto err;
+		}
+	}
+
+	omap34xxcam_vfd_name_update(vdev);
+
+	mutex_unlock(&vdev->mutex);
+
+	return 0;
+
+err_omap34xxcam_slave_power_set:
+	if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
+		isp_put();
+
+err:
+	if (s == vdev->slave[hwc.dev_type]) {
+		vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
+		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,
+};
+
+/*
+ *
+ * Module initialisation and deinitialisation
+ *
+ */
+
+static void omap34xxcam_exit(void)
+{
+	struct omap34xxcam_device *cam = omap34xxcam;
+	int i;
+
+	if (!cam)
+		return;
+
+	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;
+	}
+
+	omap34xxcam = NULL;
+
+	kfree(cam);
+}
+
+static int __init omap34xxcam_init(void)
+{
+	struct omap34xxcam_device *cam;
+	int i;
+
+	cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+	if (!cam) {
+		printk(KERN_ERR "%s: could not allocate memory\n", __func__);
+		goto err;
+	}
+
+	omap34xxcam = cam;
+
+	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;
+
+		mutex_init(&vdev->mutex);
+		vdev->index             = i;
+		vdev->cam               = cam;
+		vdev->vdev_sensor =
+			vdev->vdev_lens =
+			vdev->vdev_flash = v4l2_int_device_dummy();
+#ifdef OMAP34XXCAM_POWEROFF_DELAY
+		setup_timer(&vdev->poweroff_timer,
+			    omap34xxcam_slave_power_timer, (unsigned long)vdev);
+		INIT_WORK(&vdev->poweroff_work, omap34xxcam_slave_power_work);
+#endif /* OMAP34XXCAM_POWEROFF_DELAY */
+
+		if (v4l2_int_device_register(m))
+			goto err;
+	}
+
+	return 0;
+
+err:
+	omap34xxcam_exit();
+	return -ENODEV;
+}
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("OMAP34xx Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+
+late_initcall(omap34xxcam_init);
+module_exit(omap34xxcam_exit);
diff --git a/drivers/media/video/omap34xxcam.h b/drivers/media/video/omap34xxcam.h
new file mode 100644
index 0000000..9859d15
--- /dev/null
+++ b/drivers/media/video/omap34xxcam.h
@@ -0,0 +1,207 @@ 
+/*
+ * omap34xxcam.h
+ *
+ * Copyright (C) 2006--2009 Nokia Corporation
+ * Copyright (C) 2007--2009 Texas Instruments
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *
+ * Originally based on the OMAP 2 camera driver.
+ *
+ * Written by Sakari Ailus <sakari.ailus@nokia.com>
+ *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *            Sergio Aguirre <saaguirre@ti.com>
+ *            Mohit Jalori
+ *            Sameer Venkatraman
+ *            Leonides Martinez
+ *
+ * This program 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 program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef OMAP34XXCAM_H
+#define OMAP34XXCAM_H
+
+#include <media/v4l2-int-device.h>
+#include "isp/isp.h"
+
+#define CAM_NAME			"omap34xxcam"
+#define CAM_SHORT_NAME			"omap3"
+
+#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! */
+
+/* mask for omap34xxcam_slave_power_set */
+#define OMAP34XXCAM_SLAVE_POWER_SENSOR	(1 << OMAP34XXCAM_SLAVE_SENSOR)
+#define OMAP34XXCAM_SLAVE_POWER_LENS	(1 << OMAP34XXCAM_SLAVE_LENS)
+#define OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS \
+	(OMAP34XXCAM_SLAVE_POWER_SENSOR | OMAP34XXCAM_SLAVE_POWER_LENS)
+#define OMAP34XXCAM_SLAVE_POWER_FLASH	(1 << OMAP34XXCAM_SLAVE_FLASH)
+#define OMAP34XXCAM_SLAVE_POWER_ALL	-1
+
+#define OMAP34XXCAM_VIDEODEVS		4
+
+/* #define OMAP34XXCAM_POWEROFF_DELAY (2 * HZ) */
+
+struct omap34xxcam_device;
+struct omap34xxcam_videodev;
+
+struct omap34xxcam_sensor_config {
+	int xclk;
+	int sensor_isp;
+	u32 capture_mem;
+	struct v4l2_fract ival_default;
+};
+
+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
+ * @power_state: Current power state
+ * @power_state_wish: New power state when poweroff_timer expires
+ * @power_state_mask: Bitmask of devices to set the new power state
+ * @poweroff_timer: Timer for dispatching poweroff_work
+ * @poweroff_work: Work for slave power state change
+ * @sensor_config: ISP-speicific sensor configuration
+ * @lens_config: ISP-speicific lens configuration
+ * @flash_config: ISP-speicific flash configuration
+ * @want_timeperframe: Desired timeperframe
+ * @want_pix: Desired pix
+ * @pix: Current pix
+ * @streaming: streaming file handle, if streaming is enabled
+ */
+struct omap34xxcam_videodev {
+	struct mutex mutex; /* serialises access to this structure */
+
+	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 ***/
+	int index;
+	atomic_t users;
+	enum v4l2_power power_state[OMAP34XXCAM_SLAVE_FLASH + 1];
+#ifdef OMAP34XXCAM_POWEROFF_DELAY
+	enum v4l2_power power_state_wish;
+	int power_state_mask;
+	struct timer_list poweroff_timer;
+	struct work_struct poweroff_work;
+#endif /* OMAP34XXCAM_POWEROFF_DELAY */
+
+#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 ***/
+	struct file *streaming;
+	struct v4l2_fract want_timeperframe;
+	struct v4l2_pix_format want_pix;
+	spinlock_t pix_lock;
+	struct v4l2_pix_format pix;
+};
+
+/**
+ * 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
+ * @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; /* serialises access to this structure */
+
+	/*** interfaces and device ***/
+	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
+ * @field_count: field counter for videobuf_buffer
+ * @vdev: our /dev/video specific structure
+ */
+struct omap34xxcam_fh {
+	spinlock_t vbq_lock; /* spinlock for the videobuf queue */
+	struct videobuf_queue vbq;
+	atomic_t field_count;
+	struct omap34xxcam_videodev *vdev;
+};
+
+#endif /* ifndef OMAP34XXCAM_H */