[1/3,-,v0] V4L: vpfe capture driver - adding support for camera capture
Commit Message
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
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
@@ -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)
@@ -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 {