Re: [PULL] soc-camera and mediabus

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 14 Dec 2009, Jonathan Cameron wrote:

> Hi All,
> 
> >> 3) it would be interesting to patch the other sensor drivers to be compatible
> >>    with soc_camera (mt9v011/ov7670);
> > 
> > Well, this could be done, yes, but does it make sense to do this blindly 
> > without any hardware to test? I would rather add such conversions on a 
> > one-by-one basis as need arises.
> > 
> I'm working on the ov7670. I've added the media bus stuff to what I've
> previously posted but I haven't tested as yet.  For reference, a quick and dirty
> cut of the patch is below.  Some thought is needed on how to deal with the sections
> that currently need to be different for the soc-camera and non soc camera uses.
> (mainly the registration code in probe).

Look at my patch for mt9t031. First you do not have to fail if 
client->dev.platform_data == NULL. You have to look at the bridge driver, 
that's currently working with ov7670. If it is not setting platform_data, 
you can use it to detect whether you're in soc-camera environment or not. 
Otherwise, if the bridge driver were also using that pointer, we would 
have to come up with a ov7670-specific struct to be linked from that 
pointer. I was actually thinking about a way to pass soc-camera data to 
client drivers in a way, that would not imped non soc-camera use. So, how 
about:


	I soc-camera environment

1. platform defines a

static struct ov7670_platform_data ov7670 = {
	.link = &ov7670_link,
};

2. and a

static struct soc_camera_link ov7670_link = {
	.client_data = &ov7670,
};

3. soc-camera core gets &ov7670_link in its probe, same as this is done 
now, then it does

	icl->icd = icd;
	icl->board_info->platform_data = icl->client_data;

	subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
				icl->module_name, icl->board_info, NULL);

4. ov7670 probe is called with client platform data pointing to its own 
data:

static int ov7670_probe(struct i2c_client *client,
			const struct i2c_device_id *did)
{
	struct ov7670_platform_data *pdata = client->dev.platform_data;
	struct soc_camera_link *icl = pdata->link;
	struct soc_camera_device *icd;

	if (icl)
		icd = icl->icd;


	II Non soc-camera environment

1. the bridge driver fills in sensor data and does

	struct ov7670_platform_data *ov7670_pdata = kzalloc(sizeof(*pdata));

	ov7670_pdata->... = ...;
	board_info->platform_data = ov7670_pdata;

	subdev = v4l2_i2c_new_subdev_board(v4l2_dev, adap,
				module_name, board_info, NULL);

2. ov7670_probe() gets called and finds its data as above, but without an 
soc-camera link this time.


The advantage of the above is, that each client driver is free to define 
its own platform data struct, and for soc-camera it only has to provide 
one pointer in it. The ugly side is the cross-referencing between I.1. and 
I.2. above.

Alternatively we could agree, that all client drivers get in their i2c 
client platform data a standard struct with only pointers in it to client 
data and to various bridging models:

struct v4l2_client {
	void *client;
	struct soc_camera_link *icl;
	struct int_device_link *int;
	...
};

or a bit more hidden

struct v4l2_client {
	void *client;
	void *bridge_data;
	enum V4L2_BRIDGE_TYPE bridge_type;
};

> On another note, does anyone have an objection to making the set_bus_param
> function optional?   At the moment we are adding null functions for those
> devices that can't actually change anything which seems a little pointless.

Yes, it can.

> 
> Jonathan
> 
> 
> diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
> index 0e2184e..e57c3b5 100644
> --- a/drivers/media/video/ov7670.c
> +++ b/drivers/media/video/ov7670.c
> @@ -18,6 +18,7 @@
>  #include <media/v4l2-device.h>
>  #include <media/v4l2-chip-ident.h>
>  #include <media/v4l2-i2c-drv.h>
> +#include <media/soc_camera.h>
>  
>  
>  MODULE_AUTHOR("Jonathan Corbet <corbet@xxxxxxx>");
> @@ -545,7 +546,7 @@ static struct ov7670_format_struct {
>  		.bpp		= 1
>  	},
>  };
> -#define N_OV7670_FMTS ARRAY_SIZE(ov7670_formats)
> +
>  
>  
>  /*
> @@ -668,52 +669,37 @@ static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop,
>  	return ret;
>  }
>  
> +static enum v4l2_mbus_pixelcode ov7670_codes[] = {
> +	V4L2_MBUS_FMT_YUYV8_2X8,
> +	V4L2_MBUS_FMT_RGB565_2X8_LE,
> +};
>  
> -static int ov7670_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
> +static int ov7670_enum_fmt(struct v4l2_subdev *sd, int index, enum v4l2_mbus_pixelcode *code)
>  {
> -	struct ov7670_format_struct *ofmt;
> -
> -	if (fmt->index >= N_OV7670_FMTS)
> +	if (index >= ARRAY_SIZE(ov7670_codes))
>  		return -EINVAL;
>  
> -	ofmt = ov7670_formats + fmt->index;
> -	fmt->flags = 0;
> -	strcpy(fmt->description, ofmt->desc);
> -	fmt->pixelformat = ofmt->pixelformat;
> +	*code = ov7670_codes[index];
>  	return 0;
>  }
>  
>  
>  static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
> -		struct v4l2_format *fmt,
> -		struct ov7670_format_struct **ret_fmt,
> -		struct ov7670_win_size **ret_wsize)
> +				   struct v4l2_mbus_framefmt *mf,
> +				   struct ov7670_format_struct **ret_fmt,
> +				   struct ov7670_win_size **ret_wsize)
>  {
>  	int index;
>  	struct ov7670_win_size *wsize;
> -	struct v4l2_pix_format *pix = &fmt->fmt.pix;
>  
> -	for (index = 0; index < N_OV7670_FMTS; index++)
> -		if (ov7670_formats[index].pixelformat == pix->pixelformat)
> -			break;
> -	if (index >= N_OV7670_FMTS) {
> -		/* default to first format */
> -		index = 0;
> -		pix->pixelformat = ov7670_formats[0].pixelformat;
> -	}
> -	if (ret_fmt != NULL)
> -		*ret_fmt = ov7670_formats + index;
> -	/*
> -	 * Fields: the OV devices claim to be progressive.
> -	 */
> -	pix->field = V4L2_FIELD_NONE;
> +	mf->field = V4L2_FIELD_NONE;
>  	/*
>  	 * Round requested image size down to the nearest
>  	 * we support, but not below the smallest.
>  	 */
>  	for (wsize = ov7670_win_sizes; wsize < ov7670_win_sizes + N_WIN_SIZES;
>  	     wsize++)
> -		if (pix->width >= wsize->width && pix->height >= wsize->height)
> +		if ( mf->width >= wsize->width && mf->height >= wsize->height)
>  			break;
>  	if (wsize >= ov7670_win_sizes + N_WIN_SIZES)
>  		wsize--;   /* Take the smallest one */
> @@ -722,22 +708,34 @@ static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
>  	/*
>  	 * Note the size we'll actually handle.
>  	 */
> -	pix->width = wsize->width;
> -	pix->height = wsize->height;
> -	pix->bytesperline = pix->width*ov7670_formats[index].bpp;
> -	pix->sizeimage = pix->height*pix->bytesperline;
> +	mf->width = wsize->width;
> +	mf->height = wsize->height;
> +	switch (mf->code) {
> +	case V4L2_MBUS_FMT_RGB565_2X8_LE:
> +		mf->colorspace = V4L2_COLORSPACE_SRGB;
> +		if (ret_fmt != NULL)
> +			*ret_fmt = ov7670_formats + 2;
> +		break;
> +	default:
> +		mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
> +	case V4L2_MBUS_FMT_YUYV8_2X8:
> +		mf->colorspace = V4L2_COLORSPACE_JPEG;
> +		if (ret_fmt != NULL)
> +			*ret_fmt = ov7670_formats;
> +		break;
> +	}
>  	return 0;
>  }
>  
> -static int ov7670_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
> +static int ov7670_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
>  {
> -	return ov7670_try_fmt_internal(sd, fmt, NULL, NULL);
> +	return ov7670_try_fmt_internal(sd, mf, NULL, NULL);
>  }
>  
>  /*
>   * Set a format.
>   */
> -static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
> +static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
>  {
>  	int ret;
>  	struct ov7670_format_struct *ovfmt;
> @@ -745,7 +743,11 @@ static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
>  	struct ov7670_info *info = to_state(sd);
>  	unsigned char com7, clkrc = 0;
>  
> -	ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize);
> +	ret = ov7670_init(sd, 0);
> +	if (ret)
> +		return ret;
> +
> +	ret = ov7670_try_fmt_internal(sd, mf, &ovfmt, &wsize);
>  	if (ret)
>  		return ret;
>  	/*
> @@ -753,7 +755,7 @@ static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
>  	 * CLKRC.  If we're *not*, however, then rewriting clkrc hoses
>  	 * the colors.
>  	 */
> -	if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) {
> +	if (mf->code == V4L2_MBUS_FMT_RGB565_2X8_LE) {
>  		ret = ov7670_read(sd, REG_CLKRC, &clkrc);
>  		if (ret)
>  			return ret;
> @@ -778,7 +780,7 @@ static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
>  		ret = ov7670_write_array(sd, wsize->regs);
>  	info->fmt = ovfmt;
>  
> -	if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 && ret == 0)
> +	if (mf->code == V4L2_MBUS_FMT_RGB565_2X8_LE && ret == 0)
>  		ret = ov7670_write(sd, REG_CLKRC, clkrc);
>  	return ret;
>  }
> @@ -1226,11 +1228,11 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = {
>  };
>  
>  static const struct v4l2_subdev_video_ops ov7670_video_ops = {
> -	.enum_fmt = ov7670_enum_fmt,
> -	.try_fmt = ov7670_try_fmt,
> -	.s_fmt = ov7670_s_fmt,
>  	.s_parm = ov7670_s_parm,
>  	.g_parm = ov7670_g_parm,
> +	.s_mbus_fmt = ov7670_s_fmt,
> +	.try_mbus_fmt = ov7670_try_fmt,
> +	.enum_mbus_fmt = ov7670_enum_fmt,
>  };
>  
>  static const struct v4l2_subdev_ops ov7670_ops = {
> @@ -1239,6 +1241,28 @@ static const struct v4l2_subdev_ops ov7670_ops = {
>  };
>  
>  /* ----------------------------------------------------------------------- */
> +static unsigned long ov7670_soc_query_bus_param(struct soc_camera_device *icd)
> +{
> +	struct soc_camera_link *icl = to_soc_camera_link(icd);
> +
> +	unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
> +		SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
> +		SOCAM_DATAWIDTH_8 | SOCAM_DATA_ACTIVE_HIGH;
> +
> +	return soc_camera_apply_sensor_flags(icl, flags);
> +}
> +
> +/* This device only supports one bus option */
> +static int ov7670_soc_set_bus_param(struct soc_camera_device *icd,
> +				    unsigned long flags)
> +{
> +	return 0;
> +}
> +
> +static struct soc_camera_ops ov7670_soc_ops = {
> +	.set_bus_param = ov7670_soc_set_bus_param,
> +	.query_bus_param = ov7670_soc_query_bus_param,
> +};
>  
>  static int ov7670_probe(struct i2c_client *client,
>  			const struct i2c_device_id *id)
> @@ -1246,6 +1270,12 @@ static int ov7670_probe(struct i2c_client *client,
>  	struct v4l2_subdev *sd;
>  	struct ov7670_info *info;
>  	int ret;
> +	struct soc_camera_device *icd = client->dev.platform_data;
> +	if (!icd) {
> +		dev_err(&client->dev, "OV7670: missing soc-camera data!\n");
> +		return -EINVAL;
> +	}
> +	icd->ops = &ov7670_soc_ops;
>  
>  	info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL);
>  	if (info == NULL)
> 

---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux