diff mbox

[1/3,-,v0] V4L: vpfe capture driver - adding support for camera capture

Message ID 1246053885-8302-1-git-send-email-m-karicheri2@ti.com (mailing list archive)
State Not Applicable
Headers show

Commit Message

Murali Karicheri June 26, 2009, 10:04 p.m. UTC
From: Muralidharan Karicheri <m-karicheri2@ti.com>

Re-sending adding Hans to CC

Following updates to vpfe capture driver :-
	1) Adding support for camera capture using mt9t031 driver
	   (A patch for mt9t031 is already sent for review)
	2) Use v4l2_i2c_new_subdev_board() for loading sub devices
	3) Fixed a bug in s_input and g_input handler
	4) removed g_std() since it is already taken care by
	   v4l2 framework based on current_norm
	5) return proper error code from ccdc register function

Mandatory Reviewers: Hans Verkuil <hverkuil@xs4all.nl>

NOTE: Requires support for v4l2_i2c_new_subdev_board() which was recently
added to v4l2 framework by Hans Verkuil.

Signed-off-by: Muralidharan Karicheri <m-karicheri2@ti.com>
---
Applies to v4l-dvb repository

 drivers/media/video/davinci/vpfe_capture.c |  356 ++++++++++++++++++++--------
 include/media/davinci/vpfe_capture.h       |   16 ++
 2 files changed, 271 insertions(+), 101 deletions(-)

Comments

Hans Verkuil June 27, 2009, 12:08 p.m. UTC | #1
On Saturday 27 June 2009 00:04:45 m-karicheri2@ti.com wrote:
> From: Muralidharan Karicheri <m-karicheri2@ti.com>
> 
> Re-sending adding Hans to CC
> 
> Following updates to vpfe capture driver :-
> 	1) Adding support for camera capture using mt9t031 driver
> 	   (A patch for mt9t031 is already sent for review)
> 	2) Use v4l2_i2c_new_subdev_board() for loading sub devices
> 	3) Fixed a bug in s_input and g_input handler
> 	4) removed g_std() since it is already taken care by
> 	   v4l2 framework based on current_norm
> 	5) return proper error code from ccdc register function
> 
> Mandatory Reviewers: Hans Verkuil <hverkuil@xs4all.nl>
> 
> NOTE: Requires support for v4l2_i2c_new_subdev_board() which was recently
> added to v4l2 framework by Hans Verkuil.
> 
> Signed-off-by: Muralidharan Karicheri <m-karicheri2@ti.com>
> ---
> Applies to v4l-dvb repository
> 
>  drivers/media/video/davinci/vpfe_capture.c |  356 ++++++++++++++++++++--------
>  include/media/davinci/vpfe_capture.h       |   16 ++
>  2 files changed, 271 insertions(+), 101 deletions(-)
> 
> diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
> index a4cbe2a..414a7b4 100644
> --- a/drivers/media/video/davinci/vpfe_capture.c
> +++ b/drivers/media/video/davinci/vpfe_capture.c
> @@ -59,7 +59,6 @@
>   *    TODO list
>   *		- Support multiple REQBUF after open
>   *		- Support for de-allocating buffers through REQBUF
> - *		- Support for Raw Bayer RGB capture
>   *		- Support for chaining Image Processor
>   *		- Support for static allocation of buffers
>   *		- Support for USERPTR IO
> @@ -74,18 +73,29 @@
>  #include <media/v4l2-common.h>
>  #include <linux/io.h>
>  #include <media/davinci/vpfe_capture.h>
> -#include <media/tvp514x.h>
> -#include <linux/i2c.h>
>  #include "ccdc_hw_device.h"
>  
>  static int debug;
>  static u32 numbuffers = 3;
>  static u32 bufsize = (720 * 576 * 2);
> +static int interface;
>  
> +module_param(interface, bool, S_IRUGO);
>  module_param(numbuffers, uint, S_IRUGO);
>  module_param(bufsize, uint, S_IRUGO);
> -module_param(debug, int, 0644);
> -
> +module_param(debug, bool, 0644);
> +
> +/**
> + * VPFE capture can be used for capturing video such as from TVP5146 or TVP7002
> + * and for capture raw bayer data from camera sensors such as MT9T031. At this
> + * point there is problem in co-existence of mt9t031 and tvp5146 due to i2c
> + * address collision. So set the variable below from bootargs to do either video
> + * capture or camera capture.
> + * interface = 0 - video capture (from TVP514x or such),
> + * interface = 1 - Camera capture (from MT9T031 or such)
> + * Re-visit this when we fix the co-existence issue
> + */
> +MODULE_PARM_DESC(interface, "interface 0-1 (default:0)");
>  MODULE_PARM_DESC(numbuffers, "buffer count (default:3)");
>  MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)");
>  MODULE_PARM_DESC(debug, "Debug level 0-1");
> @@ -145,6 +155,7 @@ static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
>  			.pixelformat = V4L2_PIX_FMT_SBGGR8,
>  		},
>  		.bpp = 1,
> +		.subdev_pix_fmt = V4L2_PIX_FMT_SGRBG10,
>  	},
>  	{
>  		.fmtdesc = {
> @@ -154,6 +165,7 @@ static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
>  			.pixelformat = V4L2_PIX_FMT_SBGGR16,
>  		},
>  		.bpp = 2,
> +		.subdev_pix_fmt = V4L2_PIX_FMT_SGRBG10,
>  	},
>  	{
>  		.fmtdesc = {
> @@ -163,6 +175,7 @@ static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
>  			.pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
>  		},
>  		.bpp = 1,
> +		.subdev_pix_fmt = V4L2_PIX_FMT_SGRBG10,
>  	},
>  	{
>  		.fmtdesc = {
> @@ -172,6 +185,7 @@ static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
>  			.pixelformat = V4L2_PIX_FMT_UYVY,
>  		},
>  		.bpp = 2,
> +		.subdev_pix_fmt = V4L2_PIX_FMT_UYVY,
>  	},
>  	{
>  		.fmtdesc = {
> @@ -181,6 +195,7 @@ static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
>  			.pixelformat = V4L2_PIX_FMT_YUYV,
>  		},
>  		.bpp = 2,
> +		.subdev_pix_fmt = V4L2_PIX_FMT_UYVY,
>  	},
>  	{
>  		.fmtdesc = {
> @@ -190,12 +205,15 @@ static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
>  			.pixelformat = V4L2_PIX_FMT_NV12,
>  		},
>  		.bpp = 1,
> +		.subdev_pix_fmt = V4L2_PIX_FMT_UYVY,
>  	},
>  };
>  
> -/*
> - * vpfe_lookup_pix_format()
> - * lookup an entry in the vpfe pix format table based on pix_format
> +/**
> + * vpfe_lookup_pix_format() - lookup an entry in the vpfe pix format table
> + * @pix_format: v4l pix format
> + * This function lookup an entry in the vpfe pix format table based on
> + * pix_format
>   */
>  static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format)
>  {
> @@ -243,19 +261,19 @@ int vpfe_register_ccdc_device(struct ccdc_hw_device *dev)
>  		 * walk through it during vpfe probe
>  		 */
>  		printk(KERN_ERR "vpfe capture not initialized\n");
> -		ret = -1;
> +		ret = -EFAULT;
>  		goto unlock;
>  	}
>  
>  	if (strcmp(dev->name, ccdc_cfg->name)) {
>  		/* ignore this ccdc */
> -		ret = -1;
> +		ret = -EINVAL;
>  		goto unlock;
>  	}
>  
>  	if (ccdc_dev) {
>  		printk(KERN_ERR "ccdc already registered\n");
> -		ret = -1;
> +		ret = -EINVAL;
>  		goto unlock;
>  	}
>  
> @@ -295,6 +313,41 @@ void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev)
>  EXPORT_SYMBOL(vpfe_unregister_ccdc_device);
>  
>  /*
> + * vpfe_get_camera_frame_params()
> + * Get the image parameters such as max height and width, frame format
> + * etc and update the stdinfo accordingly. This is a work around to get
> + * the maximum width, height and frame format since camera driver doesn't
> + * support s_std.
> + */
> +static int vpfe_get_camera_frame_params(struct vpfe_device *vpfe_dev)
> +{
> +	struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev;
> +	struct v4l2_format sd_fmt;
> +	int ret;
> +
> +	/*
> +	 * Get the limits of width and height using try format
> +	 */
> +	memset(&sd_fmt, 0, sizeof(sd_fmt));
> +	sd_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +	/* hard code it to match that of mt9t031 sensor */
> +	sd_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SGRBG10;

I assume that this is a temporary solution? Since the pixel format will
depend on the sensor that is used. If it is temporary then it should be
marked with a TODO or FIXME.

> +	/* use a value big enough */
> +	sd_fmt.fmt.pix.width = 1 << 31;
> +	sd_fmt.fmt.pix.height = 1 << 31;
> +	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
> +			sdinfo->grp_id, video, try_fmt, &sd_fmt);
> +
> +	if (!ret) {
> +		vpfe_dev->std_info.active_pixels = sd_fmt.fmt.pix.width;
> +		vpfe_dev->std_info.active_lines = sd_fmt.fmt.pix.height;
> +		/* hard code the frame format to be progressive always.  */
> +		vpfe_dev->std_info.frame_format = 0;
> +	}
> +	return ret;
> +}
> +
> +/*
>   * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings
>   */
>  static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev,
> @@ -304,9 +357,13 @@ static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev,
>  	enum ccdc_buftype buf_type;
>  	enum ccdc_frmfmt frm_fmt;
>  
> +	vpfe_dev->crop.top = 0;
> +	vpfe_dev->crop.left = 0;
>  	memset(f, 0, sizeof(*f));
>  	f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
>  	ccdc_dev->hw_ops.get_image_window(&image_win);
> +	vpfe_dev->crop.width = image_win.width;
> +	vpfe_dev->crop.height = image_win.height;
>  	f->fmt.pix.width = image_win.width;
>  	f->fmt.pix.height = image_win.height;
>  	f->fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length();
> @@ -388,8 +445,10 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
>  				    const v4l2_std_id *std_id)
>  {
>  	struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev;
> +	struct v4l2_format sd_fmt;
>  	int i, ret = 0;
>  
> +	/* configure the ccdc based on standard */
>  	for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) {
>  		if (vpfe_standards[i].std_id & *std_id) {
>  			vpfe_dev->std_info.active_pixels =
> @@ -426,16 +485,17 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
>  		vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
>  	}
>  
> +	sd_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
>  	/* if sub device supports g_fmt, override the defaults */
>  	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
> -			sdinfo->grp_id, video, g_fmt, &vpfe_dev->fmt);
> +			sdinfo->grp_id, video, g_fmt, &sd_fmt);
>  
>  	if (ret && ret != -ENOIOCTLCMD) {
>  		v4l2_err(&vpfe_dev->v4l2_dev,
>  			"error in getting g_fmt from sub device\n");
>  		return ret;
>  	}
> -
> +	vpfe_dev->fmt = sd_fmt;
>  	/* Sets the values in CCDC */
>  	ret = vpfe_config_ccdc_image_format(vpfe_dev);
>  	if (ret)
> @@ -458,13 +518,29 @@ static int vpfe_initialize_device(struct vpfe_device *vpfe_dev)
>  
>  	/* set first input of current subdevice as the current input */
>  	vpfe_dev->current_input = 0;
> +	/*
> +	 * set default standard. For camera device, we cannot set standard.
> +	 * So we set it to -1. Otherwise, first entry in the standard is the
> +	 * is the default
> +	 */
> +	if (vpfe_dev->current_subdev->camera) {
> +		vpfe_dev->std_index = -1;
> +		/*
> +		 * Configure the vpfe default format information based on ccdc
> +		 * defaults
> +		 */
> +		ret = vpfe_get_ccdc_image_format(vpfe_dev, &vpfe_dev->fmt);
> +		/* Get max width and height available for capture from camera */
> +		if (!ret)
> +			ret = vpfe_get_camera_frame_params(vpfe_dev);
>  
> -	/* set default standard */
> -	vpfe_dev->std_index = 0;
> -
> -	/* Configure the default format information */
> -	ret = vpfe_config_image_format(vpfe_dev,
> +	} else {
> +		vpfe_dev->std_index = 0;
> +		/* Configure the default format information */
> +		ret = vpfe_config_image_format(vpfe_dev,
>  				&vpfe_standards[vpfe_dev->std_index].std_id);
> +	}
> +
>  	if (ret)
>  		return ret;
>  
> @@ -962,6 +1038,8 @@ static int vpfe_s_fmt_vid_cap(struct file *file, void *priv,
>  {
>  	struct vpfe_device *vpfe_dev = video_drvdata(file);
>  	const struct vpfe_pixel_format *pix_fmts;
> +	struct vpfe_subdev_info *sdinfo;
> +	struct v4l2_format sd_fmt;
>  	int ret = 0;
>  
>  	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n");
> @@ -983,11 +1061,30 @@ static int vpfe_s_fmt_vid_cap(struct file *file, void *priv,
>  	if (ret)
>  		return ret;
>  
> -	/* First detach any IRQ if currently attached */
> -	vpfe_detach_irq(vpfe_dev);
> -	vpfe_dev->fmt = *fmt;
> -	/* set image capture parameters in the ccdc */
> -	ret = vpfe_config_ccdc_image_format(vpfe_dev);
> +	sdinfo = vpfe_dev->current_subdev;
> +	if (sdinfo->camera) {
> +		/*
> +		 * Current implementation of camera sub device calculates
> +		 * sensor timing values based on S_FMT. So we need to
> +		 * explicitely call S_FMT first and make sure it succeeds before
> +		 * setting capture parameters in ccdc
> +		 */
> +		sd_fmt = *fmt;
> +		sd_fmt.fmt.pix.pixelformat = pix_fmts->subdev_pix_fmt;
> +		ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
> +						 sdinfo->grp_id,
> +						 video, s_fmt, &sd_fmt);
> +
> +		vpfe_dev->crop.width = fmt->fmt.pix.width;
> +		vpfe_dev->crop.height = fmt->fmt.pix.height;

Shouldn't these two assignments depend on whether the s_fmt call above was
successful?

> +	}
> +
> +	if (!ret) {
> +		/* First detach any IRQ if currently attached */
> +		vpfe_dev->fmt = *fmt;
> +		/* set image capture parameters in the ccdc */
> +		ret = vpfe_config_ccdc_image_format(vpfe_dev);
> +	}
>  	mutex_unlock(&vpfe_dev->lock);
>  	return ret;
>  }
> @@ -1047,7 +1144,7 @@ static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev,
>  		sdinfo = &cfg->sub_devs[i];
>  		if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) {
>  			if (vpfe_dev->current_input >= sdinfo->num_inputs)
> -				return -1;
> +				return -EINVAL;
>  			*app_input_index = j + vpfe_dev->current_input;
>  			return 0;
>  		}
> @@ -1061,10 +1158,11 @@ static int vpfe_enum_input(struct file *file, void *priv,
>  {
>  	struct vpfe_device *vpfe_dev = video_drvdata(file);
>  	struct vpfe_subdev_info *sdinfo;
> -	int subdev, index ;
> +	int subdev, index, temp_index;
>  
>  	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n");
>  
> +	temp_index = inp->index;
>  	if (vpfe_get_subdev_input_index(vpfe_dev,
>  					&subdev,
>  					&index,
> @@ -1075,6 +1173,7 @@ static int vpfe_enum_input(struct file *file, void *priv,
>  	}
>  	sdinfo = &vpfe_dev->cfg->sub_devs[subdev];
>  	memcpy(inp, &sdinfo->inputs[index], sizeof(struct v4l2_input));
> +	inp->index = temp_index;
>  	return 0;
>  }
>  
> @@ -1092,7 +1191,7 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
>  {
>  	struct vpfe_device *vpfe_dev = video_drvdata(file);
>  	struct vpfe_subdev_info *sdinfo;
> -	int subdev_index, inp_index;
> +	int subdev_index, subdev_inp_index;
>  	struct vpfe_route *route;
>  	u32 input = 0, output = 0;
>  	int ret = -EINVAL;
> @@ -1115,31 +1214,47 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
>  
>  	if (vpfe_get_subdev_input_index(vpfe_dev,
>  					&subdev_index,
> -					&inp_index,
> +					&subdev_inp_index,
>  					index) < 0) {
>  		v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n");
>  		goto unlock_out;
>  	}
>  
>  	sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index];
> -	route = &sdinfo->routes[inp_index];
> +
> +	if (!sdinfo->registered) {
> +		ret = -EINVAL;
> +		goto unlock_out;
> +	}
> +
> +	if (vpfe_dev->cfg->setup_input) {
> +		if (vpfe_dev->cfg->setup_input(sdinfo->grp_id) < 0) {
> +			ret = -EFAULT;
> +			v4l2_info(&vpfe_dev->v4l2_dev, "couldn't setup input"
> +				  " for %s\n", sdinfo->name);
> +			goto unlock_out;
> +		}
> +	}
> +
> +	route = &sdinfo->routes[subdev_inp_index];
>  	if (route && sdinfo->can_route) {
>  		input = route->input;
>  		output = route->output;
> -	}
> +		ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
> +						 sdinfo->grp_id, video,
> +						 s_routing, input, output, 0);
>  
> -	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
> -					 video, s_routing, input, output, 0);
> -
> -	if (ret) {
> -		v4l2_err(&vpfe_dev->v4l2_dev,
> -			"vpfe_doioctl:error in setting input in decoder \n");
> -		ret = -EINVAL;
> -		goto unlock_out;
> +		if (ret) {
> +			v4l2_err(&vpfe_dev->v4l2_dev,
> +				"vpfe_doioctl:error in setting input in"
> +				" decoder \n");
> +			ret = -EINVAL;
> +			goto unlock_out;
> +		}
>  	}
> +
>  	vpfe_dev->current_subdev = sdinfo;
> -	vpfe_dev->current_input = index;
> -	vpfe_dev->std_index = 0;
> +	vpfe_dev->current_input = subdev_inp_index;
>  
>  	/* set the bus/interface parameter for the sub device in ccdc */
>  	ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params);
> @@ -1147,8 +1262,22 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
>  		goto unlock_out;
>  
>  	/* set the default image parameters in the device */
> -	ret = vpfe_config_image_format(vpfe_dev,
> +	if (vpfe_dev->current_subdev->camera)
> +		vpfe_dev->std_index = -1;
> +		/* for camera, use ccdc default parameters */
> +		ret = vpfe_get_ccdc_image_format(vpfe_dev, &vpfe_dev->fmt);
> +		/* Get max width and height available for capture from camera */
> +		if (!ret)
> +			ret = vpfe_get_camera_frame_params(vpfe_dev);
> +	else {
> +		vpfe_dev->std_index = 0;
> +		/*
> +		 * For non-camera sub device, use standard to configure vpfe
> +		 * default
> +		 */
> +		ret = vpfe_config_image_format(vpfe_dev,
>  				&vpfe_standards[vpfe_dev->std_index].std_id);
> +	}
>  unlock_out:
>  	mutex_unlock(&vpfe_dev->lock);
>  	return ret;
> @@ -1207,15 +1336,6 @@ unlock_out:
>  	return ret;
>  }
>  
> -static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id)
> -{
> -	struct vpfe_device *vpfe_dev = video_drvdata(file);
> -
> -	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n");
> -
> -	*std_id = vpfe_standards[vpfe_dev->std_index].std_id;
> -	return 0;
> -}

Please take note that the g_std in the framework is done on a per-device node
basis. So if you register multiple device nodes that all share the same
standard, then you need to create your own g_std implementation.

A common example of this is when both a video and a vbi device node is created:
in that case both nodes share the same standard.

So depending on whether a vbi node will be created in the future, you will
probably be better off keeping this g_std function.

>  /*
>   *  Videobuf operations
>   */
> @@ -1576,6 +1696,7 @@ static int vpfe_cropcap(struct file *file, void *priv,
>  			      struct v4l2_cropcap *crop)
>  {
>  	struct vpfe_device *vpfe_dev = video_drvdata(file);
> +	struct vpfe_subdev_info *sdinfo;
>  
>  	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n");
>  
> @@ -1584,11 +1705,25 @@ static int vpfe_cropcap(struct file *file, void *priv,
>  
>  	memset(crop, 0, sizeof(struct v4l2_cropcap));
>  	crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> -	crop->bounds.width = crop->defrect.width =
> -		vpfe_standards[vpfe_dev->std_index].width;
> -	crop->bounds.height = crop->defrect.height =
> -		vpfe_standards[vpfe_dev->std_index].height;
> -	crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect;
> +	sdinfo = vpfe_dev->current_subdev;
> +
> +	if (!sdinfo->camera) {
> +		crop->bounds.width = vpfe_standards[vpfe_dev->std_index].width;
> +		crop->defrect.width = crop->bounds.width;
> +		crop->bounds.height =
> +			vpfe_standards[vpfe_dev->std_index].height;
> +		crop->defrect.height = crop->bounds.height;
> +		crop->pixelaspect =
> +			vpfe_standards[vpfe_dev->std_index].pixelaspect;
> +	} else {
> +		/* camera interface */
> +		crop->bounds.width = vpfe_dev->std_info.active_pixels;
> +		crop->defrect.width = crop->bounds.width;
> +		crop->bounds.height = vpfe_dev->std_info.active_lines;
> +		crop->defrect.height = crop->bounds.height;
> +		crop->pixelaspect.numerator = 1;
> +		crop->pixelaspect.denominator = 1;
> +	}
>  	return 0;
>  }
>  
> @@ -1710,7 +1845,6 @@ static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
>  	.vidioc_s_input		 = vpfe_s_input,
>  	.vidioc_querystd	 = vpfe_querystd,
>  	.vidioc_s_std		 = vpfe_s_std,
> -	.vidioc_g_std		 = vpfe_g_std,
>  	.vidioc_reqbufs		 = vpfe_reqbufs,
>  	.vidioc_querybuf	 = vpfe_querybuf,
>  	.vidioc_qbuf		 = vpfe_qbuf,
> @@ -1806,18 +1940,20 @@ out:
>  	return -1;
>  }
>  
> -/*
> - * vpfe_probe : This function creates device entries by register
> - * itself to the V4L2 driver and initializes fields of each
> - * device objects
> +/**
> + * vpfe_probe : vpfe probe function
> + * @pdev: platform device pointer
> + *
> + * This function creates device entries by register itself to the V4L2 driver
> + * and initializes fields of each device objects
>   */
>  static __init int vpfe_probe(struct platform_device *pdev)
>  {
> +	struct vpfe_subdev_info *sdinfo;
>  	struct vpfe_config *vpfe_cfg;
>  	struct resource *res1;
>  	struct vpfe_device *vpfe_dev;
>  	struct i2c_adapter *i2c_adap;
> -	struct i2c_client *client;
>  	struct video_device *vfd;
>  	int ret = -ENOMEM, i, j;
>  	int num_subdevs = 0;
> @@ -1919,7 +2055,7 @@ static __init int vpfe_probe(struct platform_device *pdev)
>  	/* Allocate memory for video device */
>  	vfd = video_device_alloc();
>  	if (NULL == vfd) {
> -		ret = ENOMEM;
> +		ret = -ENOMEM;
>  		v4l2_err(pdev->dev.driver,
>  			"Unable to alloc video device\n");
>  		goto probe_out_release_irq;
> @@ -1927,12 +2063,11 @@ static __init int vpfe_probe(struct platform_device *pdev)
>  
>  	/* Initialize field of video device */
>  	vfd->release		= video_device_release;
> -	vfd->current_norm	= V4L2_STD_UNKNOWN;
>  	vfd->fops		= &vpfe_fops;
>  	vfd->ioctl_ops		= &vpfe_ioctl_ops;
>  	vfd->minor		= -1;
>  	vfd->tvnorms		= 0;
> -	vfd->current_norm	= V4L2_STD_PAL;
> +	vfd->current_norm	= V4L2_STD_NTSC;
>  	vfd->v4l2_dev 		= &vpfe_dev->v4l2_dev;
>  	snprintf(vfd->name, sizeof(vfd->name),
>  		 "%s_V%d.%d.%d",
> @@ -1992,62 +2127,81 @@ static __init int vpfe_probe(struct platform_device *pdev)
>  	}
>  
>  	for (i = 0; i < num_subdevs; i++) {
> -		struct vpfe_subdev_info *sdinfo = &vpfe_cfg->sub_devs[i];
>  		struct v4l2_input *inps;
>  
> -		list_for_each_entry(client, &i2c_adap->clients, list) {
> -			if (!strcmp(client->name, sdinfo->name))
> -				break;
> -		}
> +		sdinfo = &vpfe_cfg->sub_devs[i];
> +		/**
> +		 * register subdevices based on interface setting. Currently
> +		 * tvp5146 and mt9t031 cannot co-exists due to i2c address
> +		 * conflicts. So only one of them is registered. Re-visit this
> +		 * once we have support for i2c switch handling in i2c driver
> +		 * framework
> +		 */
> +		if (interface == sdinfo->camera) {
> +			/* setup input path */
> +			if (vpfe_cfg->setup_input) {
> +				if (vpfe_cfg->setup_input(sdinfo->grp_id) < 0) {
> +					ret = -EFAULT;
> +					v4l2_info(&vpfe_dev->v4l2_dev, "could"
> +						  " not setup input for %s\n",
> +						  sdinfo->name);
> +					goto probe_sd_out;
> +				}
> +			}
> +			/* Load up the subdevice */
> +			vpfe_dev->sd[i] =
> +				v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
> +							  i2c_adap,
> +							  sdinfo->name,
> +							  &sdinfo->board_info,
> +							  0);

The last arg is a pointer, so you NULL rather than 0. You might want to rename
sdinfo->name to sdinfo->modname or sdinfo->module_name, since just 'name'
suggests that it is the i2c device name rather than the module name.
Just a suggestion.

> +			if (vpfe_dev->sd[i])
> +				v4l2_info(&vpfe_dev->v4l2_dev,
> +					  "v4l2 sub device %s registered\n",
> +					  sdinfo->name);
> +			else {
> +				v4l2_info(&vpfe_dev->v4l2_dev,
> +					  "v4l2 sub device %s register fails\n",
> +					  sdinfo->name);
> +			}
> +			vpfe_dev->sd[i]->grp_id = sdinfo->grp_id;
>  
> -		if (NULL == client) {
> -			v4l2_err(&vpfe_dev->v4l2_dev, "No Subdevice found\n");
> -			ret =  -ENODEV;
> -			goto probe_sd_out;
> +			/* update tvnorms from the sub devices */
> +			for (j = 0; j < sdinfo->num_inputs; j++) {
> +				inps = &sdinfo->inputs[j];
> +				vfd->tvnorms |= inps->std;
> +			}
> +			sdinfo->registered = 1;
>  		}
> +	}
>  
> -		/* Get subdevice data from the client */
> -		vpfe_dev->sd[i] = i2c_get_clientdata(client);
> -		if (NULL == vpfe_dev->sd[i]) {
> -			v4l2_err(&vpfe_dev->v4l2_dev,
> -				"No Subdevice data\n");
> -			ret =  -ENODEV;
> -			goto probe_sd_out;
> +	/* We need atleast one sub device to do capture */

atleast -> at least

> +	for (i = 0; i < num_subdevs; i++) {
> +		sdinfo = &vpfe_cfg->sub_devs[i];
> +		if (sdinfo->registered) {
> +			/* set this as the current sub device */
> +			vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[i];
> +			break;
>  		}
> +	}
>  
> -		vpfe_dev->sd[i]->grp_id = sdinfo->grp_id;
> -		ret = v4l2_device_register_subdev(&vpfe_dev->v4l2_dev,
> -						  vpfe_dev->sd[i]);
> -		if (ret) {
> -			ret =  -ENODEV;
> -			v4l2_err(&vpfe_dev->v4l2_dev,
> -				"Error registering v4l2 sub-device\n");
> -			goto probe_sd_out;
> -		}
> -		v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 sub device %s"
> -			  " registered\n", client->name);
> +	/* if we don't have any sub device registered, return error */
> +	if (i == num_subdevs)
> +		goto probe_sd_out;
>  
> -		/* update tvnorms from the sub devices */
> -		for (j = 0; j < sdinfo->num_inputs; j++) {
> -			inps = &sdinfo->inputs[j];
> -			vfd->tvnorms |= inps->std;
> -		}
> -	}
>  	/* We have at least one sub device to work with */
> -	vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0];
>  	mutex_unlock(&ccdc_lock);
>  	return 0;
>  
>  probe_sd_out:
> -	for (j = i; j >= 0; j--)
> -		v4l2_device_unregister_subdev(vpfe_dev->sd[j]);
>  	kfree(vpfe_dev->sd);
>  probe_out_video_unregister:
>  	video_unregister_device(vpfe_dev->video_dev);
>  probe_out_v4l2_unregister:
>  	v4l2_device_unregister(&vpfe_dev->v4l2_dev);
>  probe_out_video_release:
> -	video_device_release(vpfe_dev->video_dev);
> +	if (vpfe_dev->video_dev->minor == -1)
> +		video_device_release(vpfe_dev->video_dev);
>  probe_out_release_irq:
>  	free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
>  probe_out_unmap1:
> @@ -2124,7 +2278,7 @@ static __init int vpfe_init(void)
>  	return platform_driver_register(&vpfe_driver);
>  }
>  
> -/*
> +/**
>   * vpfe_cleanup : This function un-registers device driver
>   */
>  static void vpfe_cleanup(void)
> diff --git a/include/media/davinci/vpfe_capture.h b/include/media/davinci/vpfe_capture.h
> index 8259257..2aad7d7 100644
> --- a/include/media/davinci/vpfe_capture.h
> +++ b/include/media/davinci/vpfe_capture.h
> @@ -25,6 +25,7 @@
>  #include <media/v4l2-dev.h>
>  #include <linux/videodev2.h>
>  #include <linux/clk.h>
> +#include <linux/i2c.h>
>  #include <media/v4l2-ioctl.h>
>  #include <media/v4l2-device.h>
>  #include <media/videobuf-dma-contig.h>
> @@ -46,6 +47,8 @@ struct vpfe_pixel_format {
>  	struct v4l2_fmtdesc fmtdesc;
>  	/* bytes per pixel */
>  	int bpp;
> +	/* decoder format */
> +	u32 subdev_pix_fmt;
>  };
>  
>  struct vpfe_std_info {
> @@ -60,9 +63,16 @@ struct vpfe_route {
>  	u32 output;
>  };
>  
> +enum vpfe_subdev_id {
> +	VPFE_SUBDEV_TVP5146 = 1,
> +	VPFE_SUBDEV_MT9T031 = 2
> +};
> +
>  struct vpfe_subdev_info {
>  	/* Sub device name */
>  	char name[32];
> +	/* Is this a camera sub device ? */
> +	int camera;

Suggest renaming to is_camera.

>  	/* Sub device group id */
>  	int grp_id;
>  	/* Number of inputs supported */
> @@ -75,6 +85,10 @@ struct vpfe_subdev_info {
>  	int can_route;
>  	/* ccdc bus/interface configuration */
>  	struct vpfe_hw_if_param ccdc_if_params;
> +	/* i2c subdevice board info */
> +	struct i2c_board_info board_info;
> +	/* registered ? */
> +	int registered;

Suggest grouping the bool-type fields into bitfields.

>  };
>  
>  struct vpfe_config {
> @@ -89,6 +103,8 @@ struct vpfe_config {
>  	/* vpfe clock */
>  	struct clk *vpssclk;
>  	struct clk *slaveclk;
> +	/* setup function for the input path */
> +	int (*setup_input)(seenum vpfe_subdev_id id);
>  };
>  
>  struct vpfe_device {

Regards,

          Hans
diff mbox

Patch

diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
index a4cbe2a..414a7b4 100644
--- a/drivers/media/video/davinci/vpfe_capture.c
+++ b/drivers/media/video/davinci/vpfe_capture.c
@@ -59,7 +59,6 @@ 
  *    TODO list
  *		- Support multiple REQBUF after open
  *		- Support for de-allocating buffers through REQBUF
- *		- Support for Raw Bayer RGB capture
  *		- Support for chaining Image Processor
  *		- Support for static allocation of buffers
  *		- Support for USERPTR IO
@@ -74,18 +73,29 @@ 
 #include <media/v4l2-common.h>
 #include <linux/io.h>
 #include <media/davinci/vpfe_capture.h>
-#include <media/tvp514x.h>
-#include <linux/i2c.h>
 #include "ccdc_hw_device.h"
 
 static int debug;
 static u32 numbuffers = 3;
 static u32 bufsize = (720 * 576 * 2);
+static int interface;
 
+module_param(interface, bool, S_IRUGO);
 module_param(numbuffers, uint, S_IRUGO);
 module_param(bufsize, uint, S_IRUGO);
-module_param(debug, int, 0644);
-
+module_param(debug, bool, 0644);
+
+/**
+ * VPFE capture can be used for capturing video such as from TVP5146 or TVP7002
+ * and for capture raw bayer data from camera sensors such as MT9T031. At this
+ * point there is problem in co-existence of mt9t031 and tvp5146 due to i2c
+ * address collision. So set the variable below from bootargs to do either video
+ * capture or camera capture.
+ * interface = 0 - video capture (from TVP514x or such),
+ * interface = 1 - Camera capture (from MT9T031 or such)
+ * Re-visit this when we fix the co-existence issue
+ */
+MODULE_PARM_DESC(interface, "interface 0-1 (default:0)");
 MODULE_PARM_DESC(numbuffers, "buffer count (default:3)");
 MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)");
 MODULE_PARM_DESC(debug, "Debug level 0-1");
@@ -145,6 +155,7 @@  static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
 			.pixelformat = V4L2_PIX_FMT_SBGGR8,
 		},
 		.bpp = 1,
+		.subdev_pix_fmt = V4L2_PIX_FMT_SGRBG10,
 	},
 	{
 		.fmtdesc = {
@@ -154,6 +165,7 @@  static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
 			.pixelformat = V4L2_PIX_FMT_SBGGR16,
 		},
 		.bpp = 2,
+		.subdev_pix_fmt = V4L2_PIX_FMT_SGRBG10,
 	},
 	{
 		.fmtdesc = {
@@ -163,6 +175,7 @@  static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
 			.pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
 		},
 		.bpp = 1,
+		.subdev_pix_fmt = V4L2_PIX_FMT_SGRBG10,
 	},
 	{
 		.fmtdesc = {
@@ -172,6 +185,7 @@  static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
 			.pixelformat = V4L2_PIX_FMT_UYVY,
 		},
 		.bpp = 2,
+		.subdev_pix_fmt = V4L2_PIX_FMT_UYVY,
 	},
 	{
 		.fmtdesc = {
@@ -181,6 +195,7 @@  static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
 			.pixelformat = V4L2_PIX_FMT_YUYV,
 		},
 		.bpp = 2,
+		.subdev_pix_fmt = V4L2_PIX_FMT_UYVY,
 	},
 	{
 		.fmtdesc = {
@@ -190,12 +205,15 @@  static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
 			.pixelformat = V4L2_PIX_FMT_NV12,
 		},
 		.bpp = 1,
+		.subdev_pix_fmt = V4L2_PIX_FMT_UYVY,
 	},
 };
 
-/*
- * vpfe_lookup_pix_format()
- * lookup an entry in the vpfe pix format table based on pix_format
+/**
+ * vpfe_lookup_pix_format() - lookup an entry in the vpfe pix format table
+ * @pix_format: v4l pix format
+ * This function lookup an entry in the vpfe pix format table based on
+ * pix_format
  */
 static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format)
 {
@@ -243,19 +261,19 @@  int vpfe_register_ccdc_device(struct ccdc_hw_device *dev)
 		 * walk through it during vpfe probe
 		 */
 		printk(KERN_ERR "vpfe capture not initialized\n");
-		ret = -1;
+		ret = -EFAULT;
 		goto unlock;
 	}
 
 	if (strcmp(dev->name, ccdc_cfg->name)) {
 		/* ignore this ccdc */
-		ret = -1;
+		ret = -EINVAL;
 		goto unlock;
 	}
 
 	if (ccdc_dev) {
 		printk(KERN_ERR "ccdc already registered\n");
-		ret = -1;
+		ret = -EINVAL;
 		goto unlock;
 	}
 
@@ -295,6 +313,41 @@  void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev)
 EXPORT_SYMBOL(vpfe_unregister_ccdc_device);
 
 /*
+ * vpfe_get_camera_frame_params()
+ * Get the image parameters such as max height and width, frame format
+ * etc and update the stdinfo accordingly. This is a work around to get
+ * the maximum width, height and frame format since camera driver doesn't
+ * support s_std.
+ */
+static int vpfe_get_camera_frame_params(struct vpfe_device *vpfe_dev)
+{
+	struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev;
+	struct v4l2_format sd_fmt;
+	int ret;
+
+	/*
+	 * Get the limits of width and height using try format
+	 */
+	memset(&sd_fmt, 0, sizeof(sd_fmt));
+	sd_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	/* hard code it to match that of mt9t031 sensor */
+	sd_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SGRBG10;
+	/* use a value big enough */
+	sd_fmt.fmt.pix.width = 1 << 31;
+	sd_fmt.fmt.pix.height = 1 << 31;
+	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
+			sdinfo->grp_id, video, try_fmt, &sd_fmt);
+
+	if (!ret) {
+		vpfe_dev->std_info.active_pixels = sd_fmt.fmt.pix.width;
+		vpfe_dev->std_info.active_lines = sd_fmt.fmt.pix.height;
+		/* hard code the frame format to be progressive always.  */
+		vpfe_dev->std_info.frame_format = 0;
+	}
+	return ret;
+}
+
+/*
  * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings
  */
 static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev,
@@ -304,9 +357,13 @@  static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev,
 	enum ccdc_buftype buf_type;
 	enum ccdc_frmfmt frm_fmt;
 
+	vpfe_dev->crop.top = 0;
+	vpfe_dev->crop.left = 0;
 	memset(f, 0, sizeof(*f));
 	f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
 	ccdc_dev->hw_ops.get_image_window(&image_win);
+	vpfe_dev->crop.width = image_win.width;
+	vpfe_dev->crop.height = image_win.height;
 	f->fmt.pix.width = image_win.width;
 	f->fmt.pix.height = image_win.height;
 	f->fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length();
@@ -388,8 +445,10 @@  static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
 				    const v4l2_std_id *std_id)
 {
 	struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev;
+	struct v4l2_format sd_fmt;
 	int i, ret = 0;
 
+	/* configure the ccdc based on standard */
 	for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) {
 		if (vpfe_standards[i].std_id & *std_id) {
 			vpfe_dev->std_info.active_pixels =
@@ -426,16 +485,17 @@  static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
 		vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
 	}
 
+	sd_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	/* if sub device supports g_fmt, override the defaults */
 	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
-			sdinfo->grp_id, video, g_fmt, &vpfe_dev->fmt);
+			sdinfo->grp_id, video, g_fmt, &sd_fmt);
 
 	if (ret && ret != -ENOIOCTLCMD) {
 		v4l2_err(&vpfe_dev->v4l2_dev,
 			"error in getting g_fmt from sub device\n");
 		return ret;
 	}
-
+	vpfe_dev->fmt = sd_fmt;
 	/* Sets the values in CCDC */
 	ret = vpfe_config_ccdc_image_format(vpfe_dev);
 	if (ret)
@@ -458,13 +518,29 @@  static int vpfe_initialize_device(struct vpfe_device *vpfe_dev)
 
 	/* set first input of current subdevice as the current input */
 	vpfe_dev->current_input = 0;
+	/*
+	 * set default standard. For camera device, we cannot set standard.
+	 * So we set it to -1. Otherwise, first entry in the standard is the
+	 * is the default
+	 */
+	if (vpfe_dev->current_subdev->camera) {
+		vpfe_dev->std_index = -1;
+		/*
+		 * Configure the vpfe default format information based on ccdc
+		 * defaults
+		 */
+		ret = vpfe_get_ccdc_image_format(vpfe_dev, &vpfe_dev->fmt);
+		/* Get max width and height available for capture from camera */
+		if (!ret)
+			ret = vpfe_get_camera_frame_params(vpfe_dev);
 
-	/* set default standard */
-	vpfe_dev->std_index = 0;
-
-	/* Configure the default format information */
-	ret = vpfe_config_image_format(vpfe_dev,
+	} else {
+		vpfe_dev->std_index = 0;
+		/* Configure the default format information */
+		ret = vpfe_config_image_format(vpfe_dev,
 				&vpfe_standards[vpfe_dev->std_index].std_id);
+	}
+
 	if (ret)
 		return ret;
 
@@ -962,6 +1038,8 @@  static int vpfe_s_fmt_vid_cap(struct file *file, void *priv,
 {
 	struct vpfe_device *vpfe_dev = video_drvdata(file);
 	const struct vpfe_pixel_format *pix_fmts;
+	struct vpfe_subdev_info *sdinfo;
+	struct v4l2_format sd_fmt;
 	int ret = 0;
 
 	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n");
@@ -983,11 +1061,30 @@  static int vpfe_s_fmt_vid_cap(struct file *file, void *priv,
 	if (ret)
 		return ret;
 
-	/* First detach any IRQ if currently attached */
-	vpfe_detach_irq(vpfe_dev);
-	vpfe_dev->fmt = *fmt;
-	/* set image capture parameters in the ccdc */
-	ret = vpfe_config_ccdc_image_format(vpfe_dev);
+	sdinfo = vpfe_dev->current_subdev;
+	if (sdinfo->camera) {
+		/*
+		 * Current implementation of camera sub device calculates
+		 * sensor timing values based on S_FMT. So we need to
+		 * explicitely call S_FMT first and make sure it succeeds before
+		 * setting capture parameters in ccdc
+		 */
+		sd_fmt = *fmt;
+		sd_fmt.fmt.pix.pixelformat = pix_fmts->subdev_pix_fmt;
+		ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
+						 sdinfo->grp_id,
+						 video, s_fmt, &sd_fmt);
+
+		vpfe_dev->crop.width = fmt->fmt.pix.width;
+		vpfe_dev->crop.height = fmt->fmt.pix.height;
+	}
+
+	if (!ret) {
+		/* First detach any IRQ if currently attached */
+		vpfe_dev->fmt = *fmt;
+		/* set image capture parameters in the ccdc */
+		ret = vpfe_config_ccdc_image_format(vpfe_dev);
+	}
 	mutex_unlock(&vpfe_dev->lock);
 	return ret;
 }
@@ -1047,7 +1144,7 @@  static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev,
 		sdinfo = &cfg->sub_devs[i];
 		if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) {
 			if (vpfe_dev->current_input >= sdinfo->num_inputs)
-				return -1;
+				return -EINVAL;
 			*app_input_index = j + vpfe_dev->current_input;
 			return 0;
 		}
@@ -1061,10 +1158,11 @@  static int vpfe_enum_input(struct file *file, void *priv,
 {
 	struct vpfe_device *vpfe_dev = video_drvdata(file);
 	struct vpfe_subdev_info *sdinfo;
-	int subdev, index ;
+	int subdev, index, temp_index;
 
 	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n");
 
+	temp_index = inp->index;
 	if (vpfe_get_subdev_input_index(vpfe_dev,
 					&subdev,
 					&index,
@@ -1075,6 +1173,7 @@  static int vpfe_enum_input(struct file *file, void *priv,
 	}
 	sdinfo = &vpfe_dev->cfg->sub_devs[subdev];
 	memcpy(inp, &sdinfo->inputs[index], sizeof(struct v4l2_input));
+	inp->index = temp_index;
 	return 0;
 }
 
@@ -1092,7 +1191,7 @@  static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
 {
 	struct vpfe_device *vpfe_dev = video_drvdata(file);
 	struct vpfe_subdev_info *sdinfo;
-	int subdev_index, inp_index;
+	int subdev_index, subdev_inp_index;
 	struct vpfe_route *route;
 	u32 input = 0, output = 0;
 	int ret = -EINVAL;
@@ -1115,31 +1214,47 @@  static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
 
 	if (vpfe_get_subdev_input_index(vpfe_dev,
 					&subdev_index,
-					&inp_index,
+					&subdev_inp_index,
 					index) < 0) {
 		v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n");
 		goto unlock_out;
 	}
 
 	sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index];
-	route = &sdinfo->routes[inp_index];
+
+	if (!sdinfo->registered) {
+		ret = -EINVAL;
+		goto unlock_out;
+	}
+
+	if (vpfe_dev->cfg->setup_input) {
+		if (vpfe_dev->cfg->setup_input(sdinfo->grp_id) < 0) {
+			ret = -EFAULT;
+			v4l2_info(&vpfe_dev->v4l2_dev, "couldn't setup input"
+				  " for %s\n", sdinfo->name);
+			goto unlock_out;
+		}
+	}
+
+	route = &sdinfo->routes[subdev_inp_index];
 	if (route && sdinfo->can_route) {
 		input = route->input;
 		output = route->output;
-	}
+		ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
+						 sdinfo->grp_id, video,
+						 s_routing, input, output, 0);
 
-	ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
-					 video, s_routing, input, output, 0);
-
-	if (ret) {
-		v4l2_err(&vpfe_dev->v4l2_dev,
-			"vpfe_doioctl:error in setting input in decoder \n");
-		ret = -EINVAL;
-		goto unlock_out;
+		if (ret) {
+			v4l2_err(&vpfe_dev->v4l2_dev,
+				"vpfe_doioctl:error in setting input in"
+				" decoder \n");
+			ret = -EINVAL;
+			goto unlock_out;
+		}
 	}
+
 	vpfe_dev->current_subdev = sdinfo;
-	vpfe_dev->current_input = index;
-	vpfe_dev->std_index = 0;
+	vpfe_dev->current_input = subdev_inp_index;
 
 	/* set the bus/interface parameter for the sub device in ccdc */
 	ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params);
@@ -1147,8 +1262,22 @@  static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
 		goto unlock_out;
 
 	/* set the default image parameters in the device */
-	ret = vpfe_config_image_format(vpfe_dev,
+	if (vpfe_dev->current_subdev->camera)
+		vpfe_dev->std_index = -1;
+		/* for camera, use ccdc default parameters */
+		ret = vpfe_get_ccdc_image_format(vpfe_dev, &vpfe_dev->fmt);
+		/* Get max width and height available for capture from camera */
+		if (!ret)
+			ret = vpfe_get_camera_frame_params(vpfe_dev);
+	else {
+		vpfe_dev->std_index = 0;
+		/*
+		 * For non-camera sub device, use standard to configure vpfe
+		 * default
+		 */
+		ret = vpfe_config_image_format(vpfe_dev,
 				&vpfe_standards[vpfe_dev->std_index].std_id);
+	}
 unlock_out:
 	mutex_unlock(&vpfe_dev->lock);
 	return ret;
@@ -1207,15 +1336,6 @@  unlock_out:
 	return ret;
 }
 
-static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id)
-{
-	struct vpfe_device *vpfe_dev = video_drvdata(file);
-
-	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n");
-
-	*std_id = vpfe_standards[vpfe_dev->std_index].std_id;
-	return 0;
-}
 /*
  *  Videobuf operations
  */
@@ -1576,6 +1696,7 @@  static int vpfe_cropcap(struct file *file, void *priv,
 			      struct v4l2_cropcap *crop)
 {
 	struct vpfe_device *vpfe_dev = video_drvdata(file);
+	struct vpfe_subdev_info *sdinfo;
 
 	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n");
 
@@ -1584,11 +1705,25 @@  static int vpfe_cropcap(struct file *file, void *priv,
 
 	memset(crop, 0, sizeof(struct v4l2_cropcap));
 	crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	crop->bounds.width = crop->defrect.width =
-		vpfe_standards[vpfe_dev->std_index].width;
-	crop->bounds.height = crop->defrect.height =
-		vpfe_standards[vpfe_dev->std_index].height;
-	crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect;
+	sdinfo = vpfe_dev->current_subdev;
+
+	if (!sdinfo->camera) {
+		crop->bounds.width = vpfe_standards[vpfe_dev->std_index].width;
+		crop->defrect.width = crop->bounds.width;
+		crop->bounds.height =
+			vpfe_standards[vpfe_dev->std_index].height;
+		crop->defrect.height = crop->bounds.height;
+		crop->pixelaspect =
+			vpfe_standards[vpfe_dev->std_index].pixelaspect;
+	} else {
+		/* camera interface */
+		crop->bounds.width = vpfe_dev->std_info.active_pixels;
+		crop->defrect.width = crop->bounds.width;
+		crop->bounds.height = vpfe_dev->std_info.active_lines;
+		crop->defrect.height = crop->bounds.height;
+		crop->pixelaspect.numerator = 1;
+		crop->pixelaspect.denominator = 1;
+	}
 	return 0;
 }
 
@@ -1710,7 +1845,6 @@  static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
 	.vidioc_s_input		 = vpfe_s_input,
 	.vidioc_querystd	 = vpfe_querystd,
 	.vidioc_s_std		 = vpfe_s_std,
-	.vidioc_g_std		 = vpfe_g_std,
 	.vidioc_reqbufs		 = vpfe_reqbufs,
 	.vidioc_querybuf	 = vpfe_querybuf,
 	.vidioc_qbuf		 = vpfe_qbuf,
@@ -1806,18 +1940,20 @@  out:
 	return -1;
 }
 
-/*
- * vpfe_probe : This function creates device entries by register
- * itself to the V4L2 driver and initializes fields of each
- * device objects
+/**
+ * vpfe_probe : vpfe probe function
+ * @pdev: platform device pointer
+ *
+ * This function creates device entries by register itself to the V4L2 driver
+ * and initializes fields of each device objects
  */
 static __init int vpfe_probe(struct platform_device *pdev)
 {
+	struct vpfe_subdev_info *sdinfo;
 	struct vpfe_config *vpfe_cfg;
 	struct resource *res1;
 	struct vpfe_device *vpfe_dev;
 	struct i2c_adapter *i2c_adap;
-	struct i2c_client *client;
 	struct video_device *vfd;
 	int ret = -ENOMEM, i, j;
 	int num_subdevs = 0;
@@ -1919,7 +2055,7 @@  static __init int vpfe_probe(struct platform_device *pdev)
 	/* Allocate memory for video device */
 	vfd = video_device_alloc();
 	if (NULL == vfd) {
-		ret = ENOMEM;
+		ret = -ENOMEM;
 		v4l2_err(pdev->dev.driver,
 			"Unable to alloc video device\n");
 		goto probe_out_release_irq;
@@ -1927,12 +2063,11 @@  static __init int vpfe_probe(struct platform_device *pdev)
 
 	/* Initialize field of video device */
 	vfd->release		= video_device_release;
-	vfd->current_norm	= V4L2_STD_UNKNOWN;
 	vfd->fops		= &vpfe_fops;
 	vfd->ioctl_ops		= &vpfe_ioctl_ops;
 	vfd->minor		= -1;
 	vfd->tvnorms		= 0;
-	vfd->current_norm	= V4L2_STD_PAL;
+	vfd->current_norm	= V4L2_STD_NTSC;
 	vfd->v4l2_dev 		= &vpfe_dev->v4l2_dev;
 	snprintf(vfd->name, sizeof(vfd->name),
 		 "%s_V%d.%d.%d",
@@ -1992,62 +2127,81 @@  static __init int vpfe_probe(struct platform_device *pdev)
 	}
 
 	for (i = 0; i < num_subdevs; i++) {
-		struct vpfe_subdev_info *sdinfo = &vpfe_cfg->sub_devs[i];
 		struct v4l2_input *inps;
 
-		list_for_each_entry(client, &i2c_adap->clients, list) {
-			if (!strcmp(client->name, sdinfo->name))
-				break;
-		}
+		sdinfo = &vpfe_cfg->sub_devs[i];
+		/**
+		 * register subdevices based on interface setting. Currently
+		 * tvp5146 and mt9t031 cannot co-exists due to i2c address
+		 * conflicts. So only one of them is registered. Re-visit this
+		 * once we have support for i2c switch handling in i2c driver
+		 * framework
+		 */
+		if (interface == sdinfo->camera) {
+			/* setup input path */
+			if (vpfe_cfg->setup_input) {
+				if (vpfe_cfg->setup_input(sdinfo->grp_id) < 0) {
+					ret = -EFAULT;
+					v4l2_info(&vpfe_dev->v4l2_dev, "could"
+						  " not setup input for %s\n",
+						  sdinfo->name);
+					goto probe_sd_out;
+				}
+			}
+			/* Load up the subdevice */
+			vpfe_dev->sd[i] =
+				v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
+							  i2c_adap,
+							  sdinfo->name,
+							  &sdinfo->board_info,
+							  0);
+			if (vpfe_dev->sd[i])
+				v4l2_info(&vpfe_dev->v4l2_dev,
+					  "v4l2 sub device %s registered\n",
+					  sdinfo->name);
+			else {
+				v4l2_info(&vpfe_dev->v4l2_dev,
+					  "v4l2 sub device %s register fails\n",
+					  sdinfo->name);
+			}
+			vpfe_dev->sd[i]->grp_id = sdinfo->grp_id;
 
-		if (NULL == client) {
-			v4l2_err(&vpfe_dev->v4l2_dev, "No Subdevice found\n");
-			ret =  -ENODEV;
-			goto probe_sd_out;
+			/* update tvnorms from the sub devices */
+			for (j = 0; j < sdinfo->num_inputs; j++) {
+				inps = &sdinfo->inputs[j];
+				vfd->tvnorms |= inps->std;
+			}
+			sdinfo->registered = 1;
 		}
+	}
 
-		/* Get subdevice data from the client */
-		vpfe_dev->sd[i] = i2c_get_clientdata(client);
-		if (NULL == vpfe_dev->sd[i]) {
-			v4l2_err(&vpfe_dev->v4l2_dev,
-				"No Subdevice data\n");
-			ret =  -ENODEV;
-			goto probe_sd_out;
+	/* We need atleast one sub device to do capture */
+	for (i = 0; i < num_subdevs; i++) {
+		sdinfo = &vpfe_cfg->sub_devs[i];
+		if (sdinfo->registered) {
+			/* set this as the current sub device */
+			vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[i];
+			break;
 		}
+	}
 
-		vpfe_dev->sd[i]->grp_id = sdinfo->grp_id;
-		ret = v4l2_device_register_subdev(&vpfe_dev->v4l2_dev,
-						  vpfe_dev->sd[i]);
-		if (ret) {
-			ret =  -ENODEV;
-			v4l2_err(&vpfe_dev->v4l2_dev,
-				"Error registering v4l2 sub-device\n");
-			goto probe_sd_out;
-		}
-		v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 sub device %s"
-			  " registered\n", client->name);
+	/* if we don't have any sub device registered, return error */
+	if (i == num_subdevs)
+		goto probe_sd_out;
 
-		/* update tvnorms from the sub devices */
-		for (j = 0; j < sdinfo->num_inputs; j++) {
-			inps = &sdinfo->inputs[j];
-			vfd->tvnorms |= inps->std;
-		}
-	}
 	/* We have at least one sub device to work with */
-	vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0];
 	mutex_unlock(&ccdc_lock);
 	return 0;
 
 probe_sd_out:
-	for (j = i; j >= 0; j--)
-		v4l2_device_unregister_subdev(vpfe_dev->sd[j]);
 	kfree(vpfe_dev->sd);
 probe_out_video_unregister:
 	video_unregister_device(vpfe_dev->video_dev);
 probe_out_v4l2_unregister:
 	v4l2_device_unregister(&vpfe_dev->v4l2_dev);
 probe_out_video_release:
-	video_device_release(vpfe_dev->video_dev);
+	if (vpfe_dev->video_dev->minor == -1)
+		video_device_release(vpfe_dev->video_dev);
 probe_out_release_irq:
 	free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
 probe_out_unmap1:
@@ -2124,7 +2278,7 @@  static __init int vpfe_init(void)
 	return platform_driver_register(&vpfe_driver);
 }
 
-/*
+/**
  * vpfe_cleanup : This function un-registers device driver
  */
 static void vpfe_cleanup(void)
diff --git a/include/media/davinci/vpfe_capture.h b/include/media/davinci/vpfe_capture.h
index 8259257..2aad7d7 100644
--- a/include/media/davinci/vpfe_capture.h
+++ b/include/media/davinci/vpfe_capture.h
@@ -25,6 +25,7 @@ 
 #include <media/v4l2-dev.h>
 #include <linux/videodev2.h>
 #include <linux/clk.h>
+#include <linux/i2c.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 #include <media/videobuf-dma-contig.h>
@@ -46,6 +47,8 @@  struct vpfe_pixel_format {
 	struct v4l2_fmtdesc fmtdesc;
 	/* bytes per pixel */
 	int bpp;
+	/* decoder format */
+	u32 subdev_pix_fmt;
 };
 
 struct vpfe_std_info {
@@ -60,9 +63,16 @@  struct vpfe_route {
 	u32 output;
 };
 
+enum vpfe_subdev_id {
+	VPFE_SUBDEV_TVP5146 = 1,
+	VPFE_SUBDEV_MT9T031 = 2
+};
+
 struct vpfe_subdev_info {
 	/* Sub device name */
 	char name[32];
+	/* Is this a camera sub device ? */
+	int camera;
 	/* Sub device group id */
 	int grp_id;
 	/* Number of inputs supported */
@@ -75,6 +85,10 @@  struct vpfe_subdev_info {
 	int can_route;
 	/* ccdc bus/interface configuration */
 	struct vpfe_hw_if_param ccdc_if_params;
+	/* i2c subdevice board info */
+	struct i2c_board_info board_info;
+	/* registered ? */
+	int registered;
 };
 
 struct vpfe_config {
@@ -89,6 +103,8 @@  struct vpfe_config {
 	/* vpfe clock */
 	struct clk *vpssclk;
 	struct clk *slaveclk;
+	/* setup function for the input path */
+	int (*setup_input)(enum vpfe_subdev_id id);
 };
 
 struct vpfe_device {