From a2c8c68cca3dbb0c87f5034ab8ea29350174ec4a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 1 Dec 2008 09:44:53 -0300 Subject: V4L/DVB (9785): soc-camera: merge .try_bus_param() into .try_fmt_cap() .try_bus_param() method from struct soc_camera_host_ops is only called at one location immediately before .try_fmt_cap(), there is no value in keeping these two methods separate, merge them. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pxa_camera.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/media/video/pxa_camera.c') diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index eb6be5802928..2a811f8584b5 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -913,6 +913,11 @@ static int pxa_camera_set_fmt_cap(struct soc_camera_device *icd, static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd, struct v4l2_format *f) { + int ret = pxa_camera_try_bus_param(icd, f->fmt.pix.pixelformat); + + if (ret < 0) + return ret; + /* limit to pxa hardware capabilities */ if (f->fmt.pix.height < 32) f->fmt.pix.height = 32; @@ -1039,7 +1044,6 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = { .reqbufs = pxa_camera_reqbufs, .poll = pxa_camera_poll, .querycap = pxa_camera_querycap, - .try_bus_param = pxa_camera_try_bus_param, .set_bus_param = pxa_camera_set_bus_param, }; -- cgit v1.2.3-59-g8ed1b From 25c4d74ea6f07f2aaa3df537619680ba967043f5 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 1 Dec 2008 09:44:59 -0300 Subject: V4L/DVB (9787): soc-camera: let camera host drivers decide upon pixel format Pixel format requested by the user is not necessarily the same, as what a sensor driver provides. There are situations, when a camera host driver provides the required format, but requires a different format from the sensor. Further, the list of formats, supported by sensors is pretty static and can be pretty good described with a constant list of structures. Whereas decisions, made by camera host drivers to support requested formats can be quite complex, therefore it is better to let the host driver do the work. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pxa_camera.c | 32 ++++++++++++++++- drivers/media/video/sh_mobile_ceu_camera.c | 32 ++++++++++++++++- drivers/media/video/soc_camera.c | 58 ++++++++++++------------------ include/media/soc_camera.h | 3 ++ 4 files changed, 87 insertions(+), 38 deletions(-) (limited to 'drivers/media/video/pxa_camera.c') diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 2a811f8584b5..a375872b1342 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -907,17 +907,43 @@ static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt) static int pxa_camera_set_fmt_cap(struct soc_camera_device *icd, __u32 pixfmt, struct v4l2_rect *rect) { - return icd->ops->set_fmt_cap(icd, pixfmt, rect); + const struct soc_camera_data_format *cam_fmt; + int ret; + + /* + * TODO: find a suitable supported by the SoC output format, check + * whether the sensor supports one of acceptable input formats. + */ + if (pixfmt) { + cam_fmt = soc_camera_format_by_fourcc(icd, pixfmt); + if (!cam_fmt) + return -EINVAL; + } + + ret = icd->ops->set_fmt_cap(icd, pixfmt, rect); + if (pixfmt && !ret) + icd->current_fmt = cam_fmt; + + return ret; } static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd, struct v4l2_format *f) { + const struct soc_camera_data_format *cam_fmt; int ret = pxa_camera_try_bus_param(icd, f->fmt.pix.pixelformat); if (ret < 0) return ret; + /* + * TODO: find a suitable supported by the SoC output format, check + * whether the sensor supports one of acceptable input formats. + */ + cam_fmt = soc_camera_format_by_fourcc(icd, f->fmt.pix.pixelformat); + if (!cam_fmt) + return -EINVAL; + /* limit to pxa hardware capabilities */ if (f->fmt.pix.height < 32) f->fmt.pix.height = 32; @@ -929,6 +955,10 @@ static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd, f->fmt.pix.width = 2048; f->fmt.pix.width &= ~0x01; + f->fmt.pix.bytesperline = f->fmt.pix.width * + DIV_ROUND_UP(cam_fmt->depth, 8); + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + /* limit to sensor capabilities */ return icd->ops->try_fmt_cap(icd, f); } diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 87d0f3075811..02f846d1908b 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -453,17 +453,43 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, static int sh_mobile_ceu_set_fmt_cap(struct soc_camera_device *icd, __u32 pixfmt, struct v4l2_rect *rect) { - return icd->ops->set_fmt_cap(icd, pixfmt, rect); + const struct soc_camera_data_format *cam_fmt; + int ret; + + /* + * TODO: find a suitable supported by the SoC output format, check + * whether the sensor supports one of acceptable input formats. + */ + if (pixfmt) { + cam_fmt = soc_camera_format_by_fourcc(icd, pixfmt); + if (!cam_fmt) + return -EINVAL; + } + + ret = icd->ops->set_fmt_cap(icd, pixfmt, rect); + if (pixfmt && !ret) + icd->current_fmt = cam_fmt; + + return ret; } static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd, struct v4l2_format *f) { + const struct soc_camera_data_format *cam_fmt; int ret = sh_mobile_ceu_try_bus_param(icd, f->fmt.pix.pixelformat); if (ret < 0) return ret; + /* + * TODO: find a suitable supported by the SoC output format, check + * whether the sensor supports one of acceptable input formats. + */ + cam_fmt = soc_camera_format_by_fourcc(icd, f->fmt.pix.pixelformat); + if (!cam_fmt) + return -EINVAL; + /* FIXME: calculate using depth and bus width */ if (f->fmt.pix.height < 4) @@ -477,6 +503,10 @@ static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd, f->fmt.pix.width &= ~0x01; f->fmt.pix.height &= ~0x03; + f->fmt.pix.bytesperline = f->fmt.pix.width * + DIV_ROUND_UP(cam_fmt->depth, 8); + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + /* limit to sensor capabilities */ return icd->ops->try_fmt_cap(icd, f); } diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 7217de21e76b..01c33841d1c6 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -35,7 +35,7 @@ static LIST_HEAD(devices); static DEFINE_MUTEX(list_lock); static DEFINE_MUTEX(video_lock); -const static struct soc_camera_data_format *format_by_fourcc( +const struct soc_camera_data_format *soc_camera_format_by_fourcc( struct soc_camera_device *icd, unsigned int fourcc) { unsigned int i; @@ -45,6 +45,7 @@ const static struct soc_camera_data_format *format_by_fourcc( return icd->formats + i; return NULL; } +EXPORT_SYMBOL(soc_camera_format_by_fourcc); static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) @@ -54,25 +55,19 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); enum v4l2_field field; - const struct soc_camera_data_format *fmt; int ret; WARN_ON(priv != file->private_data); - fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat); - if (!fmt) { - dev_dbg(&icd->dev, "invalid format 0x%08x\n", - f->fmt.pix.pixelformat); - return -EINVAL; - } - - dev_dbg(&icd->dev, "fmt: 0x%08x\n", fmt->fourcc); - + /* + * TODO: this might also have to migrate to host-drivers, if anyone + * wishes to support other fields + */ field = f->fmt.pix.field; if (field == V4L2_FIELD_ANY) { - field = V4L2_FIELD_NONE; - } else if (V4L2_FIELD_NONE != field) { + f->fmt.pix.field = V4L2_FIELD_NONE; + } else if (field != V4L2_FIELD_NONE) { dev_err(&icd->dev, "Field type invalid.\n"); return -EINVAL; } @@ -80,13 +75,6 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, /* limit format to hardware capabilities */ ret = ici->ops->try_fmt_cap(icd, f); - /* calculate missing fields */ - f->fmt.pix.field = field; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - return ret; } @@ -325,18 +313,10 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, to_soc_camera_host(icd->dev.parent); int ret; struct v4l2_rect rect; - const static struct soc_camera_data_format *data_fmt; WARN_ON(priv != file->private_data); - data_fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat); - if (!data_fmt) - return -EINVAL; - - /* buswidth may be further adjusted by the ici */ - icd->buswidth = data_fmt->depth; - - ret = soc_camera_try_fmt_vid_cap(file, icf, f); + ret = soc_camera_try_fmt_vid_cap(file, priv, f); if (ret < 0) return ret; @@ -345,14 +325,21 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, rect.width = f->fmt.pix.width; rect.height = f->fmt.pix.height; ret = ici->ops->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect); - if (ret < 0) + if (ret < 0) { return ret; + } else if (!icd->current_fmt || + icd->current_fmt->fourcc != f->fmt.pix.pixelformat) { + dev_err(&ici->dev, "Host driver hasn't set up current " + "format correctly!\n"); + return -EINVAL; + } - icd->current_fmt = data_fmt; + /* buswidth may be further adjusted by the ici */ + icd->buswidth = icd->current_fmt->depth; icd->width = rect.width; icd->height = rect.height; icf->vb_vidq.field = f->fmt.pix.field; - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type) + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", f->type); @@ -394,10 +381,9 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.height = icd->height; f->fmt.pix.field = icf->vb_vidq.field; f->fmt.pix.pixelformat = icd->current_fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * icd->current_fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.bytesperline = f->fmt.pix.width * + DIV_ROUND_UP(icd->current_fmt->depth, 8); + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n", icd->current_fmt->fourcc); return 0; diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index ee0e6b4bed33..8e8fcb75dacb 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -105,6 +105,9 @@ extern void soc_camera_device_unregister(struct soc_camera_device *icd); extern int soc_camera_video_start(struct soc_camera_device *icd); extern void soc_camera_video_stop(struct soc_camera_device *icd); +extern const struct soc_camera_data_format *soc_camera_format_by_fourcc( + struct soc_camera_device *icd, unsigned int fourcc); + struct soc_camera_data_format { const char *name; unsigned int depth; -- cgit v1.2.3-59-g8ed1b From d8fac217c58f0101a351b9c8c80f1665bd9efef9 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 1 Dec 2008 09:45:21 -0300 Subject: V4L/DVB (9788): soc-camera: simplify naming We anyway don't follow the s_fmt_vid_cap / g_fmt_vid_cap / try_fmt_vid_cap naming, and soc-camera is so far only about video capture, let's simplify operation names a bit further. set_fmt_cap / try_fmt_cap wasn't a very good choice too. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9m001.c | 14 +++++++------- drivers/media/video/mt9m111.c | 12 ++++++------ drivers/media/video/mt9v022.c | 14 +++++++------- drivers/media/video/ov772x.c | 14 +++++++------- drivers/media/video/pxa_camera.c | 16 ++++++++-------- drivers/media/video/sh_mobile_ceu_camera.c | 16 ++++++++-------- drivers/media/video/soc_camera.c | 6 +++--- drivers/media/video/soc_camera_platform.c | 12 ++++++------ include/media/soc_camera.h | 10 ++++------ 9 files changed, 56 insertions(+), 58 deletions(-) (limited to 'drivers/media/video/pxa_camera.c') diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 0c524376b67e..0bcfef7b1c17 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -285,8 +285,8 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) width_flag; } -static int mt9m001_set_fmt_cap(struct soc_camera_device *icd, - __u32 pixfmt, struct v4l2_rect *rect) +static int mt9m001_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) { struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); int ret; @@ -298,7 +298,7 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd, ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank); /* The caller provides a supported format, as verified per - * call to icd->try_fmt_cap() */ + * call to icd->try_fmt() */ if (!ret) ret = reg_write(icd, MT9M001_COLUMN_START, rect->left); if (!ret) @@ -325,8 +325,8 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd, return ret; } -static int mt9m001_try_fmt_cap(struct soc_camera_device *icd, - struct v4l2_format *f) +static int mt9m001_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) { if (f->fmt.pix.height < 32 + icd->y_skip_top) f->fmt.pix.height = 32 + icd->y_skip_top; @@ -447,8 +447,8 @@ static struct soc_camera_ops mt9m001_ops = { .release = mt9m001_release, .start_capture = mt9m001_start_capture, .stop_capture = mt9m001_stop_capture, - .set_fmt_cap = mt9m001_set_fmt_cap, - .try_fmt_cap = mt9m001_try_fmt_cap, + .set_fmt = mt9m001_set_fmt, + .try_fmt = mt9m001_try_fmt, .set_bus_param = mt9m001_set_bus_param, .query_bus_param = mt9m001_query_bus_param, .controls = mt9m001_controls, diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index da0b2d553fd0..63c52c0b3e72 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -452,8 +452,8 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt) return ret; } -static int mt9m111_set_fmt_cap(struct soc_camera_device *icd, - __u32 pixfmt, struct v4l2_rect *rect) +static int mt9m111_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) { struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); int ret; @@ -473,8 +473,8 @@ static int mt9m111_set_fmt_cap(struct soc_camera_device *icd, return ret; } -static int mt9m111_try_fmt_cap(struct soc_camera_device *icd, - struct v4l2_format *f) +static int mt9m111_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) { if (f->fmt.pix.height > MT9M111_MAX_HEIGHT) f->fmt.pix.height = MT9M111_MAX_HEIGHT; @@ -597,8 +597,8 @@ static struct soc_camera_ops mt9m111_ops = { .release = mt9m111_release, .start_capture = mt9m111_start_capture, .stop_capture = mt9m111_stop_capture, - .set_fmt_cap = mt9m111_set_fmt_cap, - .try_fmt_cap = mt9m111_try_fmt_cap, + .set_fmt = mt9m111_set_fmt, + .try_fmt = mt9m111_try_fmt, .query_bus_param = mt9m111_query_bus_param, .set_bus_param = mt9m111_set_bus_param, .controls = mt9m111_controls, diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 2584201059d8..3a39f0288599 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -337,14 +337,14 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) width_flag; } -static int mt9v022_set_fmt_cap(struct soc_camera_device *icd, - __u32 pixfmt, struct v4l2_rect *rect) +static int mt9v022_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) { struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); int ret; /* The caller provides a supported format, as verified per call to - * icd->try_fmt_cap(), datawidth is from our supported format list */ + * icd->try_fmt(), datawidth is from our supported format list */ switch (pixfmt) { case V4L2_PIX_FMT_GREY: case V4L2_PIX_FMT_Y16: @@ -400,8 +400,8 @@ static int mt9v022_set_fmt_cap(struct soc_camera_device *icd, return 0; } -static int mt9v022_try_fmt_cap(struct soc_camera_device *icd, - struct v4l2_format *f) +static int mt9v022_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) { if (f->fmt.pix.height < 32 + icd->y_skip_top) f->fmt.pix.height = 32 + icd->y_skip_top; @@ -538,8 +538,8 @@ static struct soc_camera_ops mt9v022_ops = { .release = mt9v022_release, .start_capture = mt9v022_start_capture, .stop_capture = mt9v022_stop_capture, - .set_fmt_cap = mt9v022_set_fmt_cap, - .try_fmt_cap = mt9v022_try_fmt_cap, + .set_fmt = mt9v022_set_fmt, + .try_fmt = mt9v022_try_fmt, .set_bus_param = mt9v022_set_bus_param, .query_bus_param = mt9v022_query_bus_param, .controls = mt9v022_controls, diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 96964b79afac..76f296642db6 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -755,9 +755,9 @@ static int ov772x_set_register(struct soc_camera_device *icd, } #endif -static int ov772x_set_fmt_cap(struct soc_camera_device *icd, - __u32 pixfmt, - struct v4l2_rect *rect) +static int ov772x_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, + struct v4l2_rect *rect) { struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); int ret = -EINVAL; @@ -778,8 +778,8 @@ static int ov772x_set_fmt_cap(struct soc_camera_device *icd, return ret; } -static int ov772x_try_fmt_cap(struct soc_camera_device *icd, - struct v4l2_format *f) +static int ov772x_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) { struct v4l2_pix_format *pix = &f->fmt.pix; struct ov772x_priv *priv; @@ -868,8 +868,8 @@ static struct soc_camera_ops ov772x_ops = { .release = ov772x_release, .start_capture = ov772x_start_capture, .stop_capture = ov772x_stop_capture, - .set_fmt_cap = ov772x_set_fmt_cap, - .try_fmt_cap = ov772x_try_fmt_cap, + .set_fmt = ov772x_set_fmt, + .try_fmt = ov772x_try_fmt, .set_bus_param = ov772x_set_bus_param, .query_bus_param = ov772x_query_bus_param, .get_chip_id = ov772x_get_chip_id, diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index a375872b1342..665eef236f5b 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -904,8 +904,8 @@ static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt) return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL; } -static int pxa_camera_set_fmt_cap(struct soc_camera_device *icd, - __u32 pixfmt, struct v4l2_rect *rect) +static int pxa_camera_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) { const struct soc_camera_data_format *cam_fmt; int ret; @@ -920,15 +920,15 @@ static int pxa_camera_set_fmt_cap(struct soc_camera_device *icd, return -EINVAL; } - ret = icd->ops->set_fmt_cap(icd, pixfmt, rect); + ret = icd->ops->set_fmt(icd, pixfmt, rect); if (pixfmt && !ret) icd->current_fmt = cam_fmt; return ret; } -static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd, - struct v4l2_format *f) +static int pxa_camera_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) { const struct soc_camera_data_format *cam_fmt; int ret = pxa_camera_try_bus_param(icd, f->fmt.pix.pixelformat); @@ -960,7 +960,7 @@ static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd, f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; /* limit to sensor capabilities */ - return icd->ops->try_fmt_cap(icd, f); + return icd->ops->try_fmt(icd, f); } static int pxa_camera_reqbufs(struct soc_camera_file *icf, @@ -1068,8 +1068,8 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = { .remove = pxa_camera_remove_device, .suspend = pxa_camera_suspend, .resume = pxa_camera_resume, - .set_fmt_cap = pxa_camera_set_fmt_cap, - .try_fmt_cap = pxa_camera_try_fmt_cap, + .set_fmt = pxa_camera_set_fmt, + .try_fmt = pxa_camera_try_fmt, .init_videobuf = pxa_camera_init_videobuf, .reqbufs = pxa_camera_reqbufs, .poll = pxa_camera_poll, diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 02f846d1908b..d284d5d1dd01 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -450,8 +450,8 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, return 0; } -static int sh_mobile_ceu_set_fmt_cap(struct soc_camera_device *icd, - __u32 pixfmt, struct v4l2_rect *rect) +static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) { const struct soc_camera_data_format *cam_fmt; int ret; @@ -466,15 +466,15 @@ static int sh_mobile_ceu_set_fmt_cap(struct soc_camera_device *icd, return -EINVAL; } - ret = icd->ops->set_fmt_cap(icd, pixfmt, rect); + ret = icd->ops->set_fmt(icd, pixfmt, rect); if (pixfmt && !ret) icd->current_fmt = cam_fmt; return ret; } -static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd, - struct v4l2_format *f) +static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) { const struct soc_camera_data_format *cam_fmt; int ret = sh_mobile_ceu_try_bus_param(icd, f->fmt.pix.pixelformat); @@ -508,7 +508,7 @@ static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd, f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; /* limit to sensor capabilities */ - return icd->ops->try_fmt_cap(icd, f); + return icd->ops->try_fmt(icd, f); } static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf, @@ -576,8 +576,8 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { .owner = THIS_MODULE, .add = sh_mobile_ceu_add_device, .remove = sh_mobile_ceu_remove_device, - .set_fmt_cap = sh_mobile_ceu_set_fmt_cap, - .try_fmt_cap = sh_mobile_ceu_try_fmt_cap, + .set_fmt = sh_mobile_ceu_set_fmt, + .try_fmt = sh_mobile_ceu_try_fmt, .reqbufs = sh_mobile_ceu_reqbufs, .poll = sh_mobile_ceu_poll, .querycap = sh_mobile_ceu_querycap, diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 01c33841d1c6..9db66a4fd1a3 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -73,7 +73,7 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, } /* limit format to hardware capabilities */ - ret = ici->ops->try_fmt_cap(icd, f); + ret = ici->ops->try_fmt(icd, f); return ret; } @@ -324,7 +324,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, rect.top = icd->y_current; rect.width = f->fmt.pix.width; rect.height = f->fmt.pix.height; - ret = ici->ops->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect); + ret = ici->ops->set_fmt(icd, f->fmt.pix.pixelformat, &rect); if (ret < 0) { return ret; } else if (!icd->current_fmt || @@ -553,7 +553,7 @@ static int soc_camera_s_crop(struct file *file, void *fh, if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - ret = ici->ops->set_fmt_cap(icd, 0, &a->c); + ret = ici->ops->set_fmt(icd, 0, &a->c); if (!ret) { icd->width = a->c.width; icd->height = a->c.height; diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index bb7a9d480e8f..c23871e4c1e6 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c @@ -79,14 +79,14 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd) return p->bus_param; } -static int soc_camera_platform_set_fmt_cap(struct soc_camera_device *icd, - __u32 pixfmt, struct v4l2_rect *rect) +static int soc_camera_platform_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) { return 0; } -static int soc_camera_platform_try_fmt_cap(struct soc_camera_device *icd, - struct v4l2_format *f) +static int soc_camera_platform_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) { struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd); @@ -124,8 +124,8 @@ static struct soc_camera_ops soc_camera_platform_ops = { .release = soc_camera_platform_release, .start_capture = soc_camera_platform_start_capture, .stop_capture = soc_camera_platform_stop_capture, - .set_fmt_cap = soc_camera_platform_set_fmt_cap, - .try_fmt_cap = soc_camera_platform_try_fmt_cap, + .set_fmt = soc_camera_platform_set_fmt, + .try_fmt = soc_camera_platform_try_fmt, .set_bus_param = soc_camera_platform_set_bus_param, .query_bus_param = soc_camera_platform_query_bus_param, }; diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 8e8fcb75dacb..b14f6ddc9e18 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -66,9 +66,8 @@ struct soc_camera_host_ops { void (*remove)(struct soc_camera_device *); int (*suspend)(struct soc_camera_device *, pm_message_t state); int (*resume)(struct soc_camera_device *); - int (*set_fmt_cap)(struct soc_camera_device *, __u32, - struct v4l2_rect *); - int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *); + int (*set_fmt)(struct soc_camera_device *, __u32, struct v4l2_rect *); + int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *); void (*init_videobuf)(struct videobuf_queue *, struct soc_camera_device *); int (*reqbufs)(struct soc_camera_file *, struct v4l2_requestbuffers *); @@ -125,9 +124,8 @@ struct soc_camera_ops { int (*release)(struct soc_camera_device *); int (*start_capture)(struct soc_camera_device *); int (*stop_capture)(struct soc_camera_device *); - int (*set_fmt_cap)(struct soc_camera_device *, __u32, - struct v4l2_rect *); - int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *); + int (*set_fmt)(struct soc_camera_device *, __u32, struct v4l2_rect *); + int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *); unsigned long (*query_bus_param)(struct soc_camera_device *); int (*set_bus_param)(struct soc_camera_device *, unsigned long); int (*get_chip_id)(struct soc_camera_device *, -- cgit v1.2.3-59-g8ed1b From 2a48fc739df213b8f98b4effd95ce5ec93bca3da Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Mon, 1 Dec 2008 09:45:35 -0300 Subject: V4L/DVB (9791): pxa-camera: pixel format negotiation Use the new format-negotiation infrastructure, support all four YUV422 packed and the planar formats. The new translation structure enables to build the format list with buswidth, depth, host format and camera format checked, so that it's not done anymore on try_fmt nor set_fmt. Signed-off-by: Robert Jarzmik Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pxa_camera.c | 207 +++++++++++++++++++++++++++++++-------- 1 file changed, 165 insertions(+), 42 deletions(-) (limited to 'drivers/media/video/pxa_camera.c') diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 665eef236f5b..97923e1bd06d 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -765,6 +765,9 @@ static int test_platform_param(struct pxa_camera_dev *pcdev, if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8)) return -EINVAL; *flags |= SOCAM_DATAWIDTH_8; + break; + default: + return -EINVAL; } return 0; @@ -823,12 +826,10 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) * We fix bit-per-pixel equal to data-width... */ switch (common_flags & SOCAM_DATAWIDTH_MASK) { case SOCAM_DATAWIDTH_10: - icd->buswidth = 10; dw = 4; bpp = 0x40; break; case SOCAM_DATAWIDTH_9: - icd->buswidth = 9; dw = 3; bpp = 0x20; break; @@ -836,7 +837,6 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) /* Actually it can only be 8 now, * default is just to silence compiler warnings */ case SOCAM_DATAWIDTH_8: - icd->buswidth = 8; dw = 2; bpp = 0; } @@ -862,7 +862,17 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) case V4L2_PIX_FMT_YUV422P: pcdev->channels = 3; cicr1 |= CICR1_YCBCR_F; + /* + * Normally, pxa bus wants as input UYVY format. We allow all + * reorderings of the YUV422 format, as no processing is done, + * and the YUV stream is just passed through without any + * transformation. Note that UYVY is the only format that + * should be used if pxa framebuffer Overlay2 is used. + */ + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: cicr1 |= CICR1_COLOR_SP_VAL(2); break; case V4L2_PIX_FMT_RGB555: @@ -888,13 +898,14 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) return 0; } -static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt) +static int pxa_camera_try_bus_param(struct soc_camera_device *icd, + unsigned char buswidth) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; unsigned long bus_flags, camera_flags; - int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags); + int ret = test_platform_param(pcdev, buswidth, &bus_flags); if (ret < 0) return ret; @@ -904,25 +915,139 @@ static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt) return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL; } +static const struct soc_camera_data_format pxa_camera_formats[] = { + { + .name = "Planar YUV422 16 bit", + .depth = 16, + .fourcc = V4L2_PIX_FMT_YUV422P, + .colorspace = V4L2_COLORSPACE_JPEG, + }, +}; + +static bool buswidth_supported(struct soc_camera_device *icd, int depth) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct pxa_camera_dev *pcdev = ici->priv; + + switch (depth) { + case 8: + return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8); + case 9: + return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9); + case 10: + return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10); + } + return false; +} + +static int required_buswidth(const struct soc_camera_data_format *fmt) +{ + switch (fmt->fourcc) { + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB555: + return 8; + default: + return fmt->depth; + } +} + +static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, + struct soc_camera_format_xlate *xlate) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + int formats = 0, buswidth, ret; + + buswidth = required_buswidth(icd->formats + idx); + + if (!buswidth_supported(icd, buswidth)) + return 0; + + ret = pxa_camera_try_bus_param(icd, buswidth); + if (ret < 0) + return 0; + + switch (icd->formats[idx].fourcc) { + case V4L2_PIX_FMT_UYVY: + formats++; + if (xlate) { + xlate->host_fmt = &pxa_camera_formats[0]; + xlate->cam_fmt = icd->formats + idx; + xlate->buswidth = buswidth; + xlate++; + dev_dbg(&ici->dev, "Providing format %s using %s\n", + pxa_camera_formats[0].name, + icd->formats[idx].name); + } + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB555: + formats++; + if (xlate) { + xlate->host_fmt = icd->formats + idx; + xlate->cam_fmt = icd->formats + idx; + xlate->buswidth = buswidth; + xlate++; + dev_dbg(&ici->dev, "Providing format %s packed\n", + icd->formats[idx].name); + } + break; + default: + /* Generic pass-through */ + formats++; + if (xlate) { + xlate->host_fmt = icd->formats + idx; + xlate->cam_fmt = icd->formats + idx; + xlate->buswidth = icd->formats[idx].depth; + xlate++; + dev_dbg(&ici->dev, + "Providing format %s in pass-through mode\n", + icd->formats[idx].name); + } + } + + return formats; +} + static int pxa_camera_set_fmt(struct soc_camera_device *icd, __u32 pixfmt, struct v4l2_rect *rect) { - const struct soc_camera_data_format *cam_fmt; - int ret; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + const struct soc_camera_data_format *host_fmt, *cam_fmt = NULL; + const struct soc_camera_format_xlate *xlate; + int ret, buswidth; - /* - * TODO: find a suitable supported by the SoC output format, check - * whether the sensor supports one of acceptable input formats. - */ - if (pixfmt) { - cam_fmt = soc_camera_format_by_fourcc(icd, pixfmt); - if (!cam_fmt) - return -EINVAL; + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (!xlate) { + dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + return -EINVAL; } - ret = icd->ops->set_fmt(icd, pixfmt, rect); - if (pixfmt && !ret) - icd->current_fmt = cam_fmt; + buswidth = xlate->buswidth; + host_fmt = xlate->host_fmt; + cam_fmt = xlate->cam_fmt; + + switch (pixfmt) { + case 0: /* Only geometry change */ + ret = icd->ops->set_fmt(icd, pixfmt, rect); + break; + default: + ret = icd->ops->set_fmt(icd, cam_fmt->fourcc, rect); + } + + if (ret < 0) + dev_warn(&ici->dev, "Failed to configure for format %x\n", + pixfmt); + + if (pixfmt && !ret) { + icd->buswidth = buswidth; + icd->current_fmt = host_fmt; + } return ret; } @@ -930,34 +1055,31 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, static int pxa_camera_try_fmt(struct soc_camera_device *icd, struct v4l2_format *f) { - const struct soc_camera_data_format *cam_fmt; - int ret = pxa_camera_try_bus_param(icd, f->fmt.pix.pixelformat); - - if (ret < 0) - return ret; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + __u32 pixfmt = pix->pixelformat; - /* - * TODO: find a suitable supported by the SoC output format, check - * whether the sensor supports one of acceptable input formats. - */ - cam_fmt = soc_camera_format_by_fourcc(icd, f->fmt.pix.pixelformat); - if (!cam_fmt) + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (!xlate) { + dev_warn(&ici->dev, "Format %x not found\n", pixfmt); return -EINVAL; + } /* limit to pxa hardware capabilities */ - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.height > 2048) - f->fmt.pix.height = 2048; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.width > 2048) - f->fmt.pix.width = 2048; - f->fmt.pix.width &= ~0x01; - - f->fmt.pix.bytesperline = f->fmt.pix.width * - DIV_ROUND_UP(cam_fmt->depth, 8); - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + if (pix->height < 32) + pix->height = 32; + if (pix->height > 2048) + pix->height = 2048; + if (pix->width < 48) + pix->width = 48; + if (pix->width > 2048) + pix->width = 2048; + pix->width &= ~0x01; + + pix->bytesperline = pix->width * + DIV_ROUND_UP(xlate->host_fmt->depth, 8); + pix->sizeimage = pix->height * pix->bytesperline; /* limit to sensor capabilities */ return icd->ops->try_fmt(icd, f); @@ -1068,6 +1190,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = { .remove = pxa_camera_remove_device, .suspend = pxa_camera_suspend, .resume = pxa_camera_resume, + .get_formats = pxa_camera_get_formats, .set_fmt = pxa_camera_set_fmt, .try_fmt = pxa_camera_try_fmt, .init_videobuf = pxa_camera_init_videobuf, -- cgit v1.2.3-59-g8ed1b From 5ca11fa3e0025864df930d6d97470b87c35919ed Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Thu, 18 Dec 2008 11:15:50 -0300 Subject: V4L/DVB: pxa-camera: use memory mapped IO access for camera (QCI) registers Signed-off-by: Eric Miao Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pxa_camera.c | 202 +++++++++++++++++++++++++++++++-------- 1 file changed, 162 insertions(+), 40 deletions(-) (limited to 'drivers/media/video/pxa_camera.c') diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 97923e1bd06d..45040f99031d 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -42,6 +42,101 @@ #define PXA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5) #define PXA_CAM_DRV_NAME "pxa27x-camera" +/* Camera Interface */ +#define CICR0 0x0000 +#define CICR1 0x0004 +#define CICR2 0x0008 +#define CICR3 0x000C +#define CICR4 0x0010 +#define CISR 0x0014 +#define CIFR 0x0018 +#define CITOR 0x001C +#define CIBR0 0x0028 +#define CIBR1 0x0030 +#define CIBR2 0x0038 + +#define CICR0_DMAEN (1 << 31) /* DMA request enable */ +#define CICR0_PAR_EN (1 << 30) /* Parity enable */ +#define CICR0_SL_CAP_EN (1 << 29) /* Capture enable for slave mode */ +#define CICR0_ENB (1 << 28) /* Camera interface enable */ +#define CICR0_DIS (1 << 27) /* Camera interface disable */ +#define CICR0_SIM (0x7 << 24) /* Sensor interface mode mask */ +#define CICR0_TOM (1 << 9) /* Time-out mask */ +#define CICR0_RDAVM (1 << 8) /* Receive-data-available mask */ +#define CICR0_FEM (1 << 7) /* FIFO-empty mask */ +#define CICR0_EOLM (1 << 6) /* End-of-line mask */ +#define CICR0_PERRM (1 << 5) /* Parity-error mask */ +#define CICR0_QDM (1 << 4) /* Quick-disable mask */ +#define CICR0_CDM (1 << 3) /* Disable-done mask */ +#define CICR0_SOFM (1 << 2) /* Start-of-frame mask */ +#define CICR0_EOFM (1 << 1) /* End-of-frame mask */ +#define CICR0_FOM (1 << 0) /* FIFO-overrun mask */ + +#define CICR1_TBIT (1 << 31) /* Transparency bit */ +#define CICR1_RGBT_CONV (0x3 << 29) /* RGBT conversion mask */ +#define CICR1_PPL (0x7ff << 15) /* Pixels per line mask */ +#define CICR1_RGB_CONV (0x7 << 12) /* RGB conversion mask */ +#define CICR1_RGB_F (1 << 11) /* RGB format */ +#define CICR1_YCBCR_F (1 << 10) /* YCbCr format */ +#define CICR1_RGB_BPP (0x7 << 7) /* RGB bis per pixel mask */ +#define CICR1_RAW_BPP (0x3 << 5) /* Raw bis per pixel mask */ +#define CICR1_COLOR_SP (0x3 << 3) /* Color space mask */ +#define CICR1_DW (0x7 << 0) /* Data width mask */ + +#define CICR2_BLW (0xff << 24) /* Beginning-of-line pixel clock + wait count mask */ +#define CICR2_ELW (0xff << 16) /* End-of-line pixel clock + wait count mask */ +#define CICR2_HSW (0x3f << 10) /* Horizontal sync pulse width mask */ +#define CICR2_BFPW (0x3f << 3) /* Beginning-of-frame pixel clock + wait count mask */ +#define CICR2_FSW (0x7 << 0) /* Frame stabilization + wait count mask */ + +#define CICR3_BFW (0xff << 24) /* Beginning-of-frame line clock + wait count mask */ +#define CICR3_EFW (0xff << 16) /* End-of-frame line clock + wait count mask */ +#define CICR3_VSW (0x3f << 10) /* Vertical sync pulse width mask */ +#define CICR3_BFPW (0x3f << 3) /* Beginning-of-frame pixel clock + wait count mask */ +#define CICR3_LPF (0x7ff << 0) /* Lines per frame mask */ + +#define CICR4_MCLK_DLY (0x3 << 24) /* MCLK Data Capture Delay mask */ +#define CICR4_PCLK_EN (1 << 23) /* Pixel clock enable */ +#define CICR4_PCP (1 << 22) /* Pixel clock polarity */ +#define CICR4_HSP (1 << 21) /* Horizontal sync polarity */ +#define CICR4_VSP (1 << 20) /* Vertical sync polarity */ +#define CICR4_MCLK_EN (1 << 19) /* MCLK enable */ +#define CICR4_FR_RATE (0x7 << 8) /* Frame rate mask */ +#define CICR4_DIV (0xff << 0) /* Clock divisor mask */ + +#define CISR_FTO (1 << 15) /* FIFO time-out */ +#define CISR_RDAV_2 (1 << 14) /* Channel 2 receive data available */ +#define CISR_RDAV_1 (1 << 13) /* Channel 1 receive data available */ +#define CISR_RDAV_0 (1 << 12) /* Channel 0 receive data available */ +#define CISR_FEMPTY_2 (1 << 11) /* Channel 2 FIFO empty */ +#define CISR_FEMPTY_1 (1 << 10) /* Channel 1 FIFO empty */ +#define CISR_FEMPTY_0 (1 << 9) /* Channel 0 FIFO empty */ +#define CISR_EOL (1 << 8) /* End of line */ +#define CISR_PAR_ERR (1 << 7) /* Parity error */ +#define CISR_CQD (1 << 6) /* Camera interface quick disable */ +#define CISR_CDD (1 << 5) /* Camera interface disable done */ +#define CISR_SOF (1 << 4) /* Start of frame */ +#define CISR_EOF (1 << 3) /* End of frame */ +#define CISR_IFO_2 (1 << 2) /* FIFO overrun for Channel 2 */ +#define CISR_IFO_1 (1 << 1) /* FIFO overrun for Channel 1 */ +#define CISR_IFO_0 (1 << 0) /* FIFO overrun for Channel 0 */ + +#define CIFR_FLVL2 (0x7f << 23) /* FIFO 2 level mask */ +#define CIFR_FLVL1 (0x7f << 16) /* FIFO 1 level mask */ +#define CIFR_FLVL0 (0xff << 8) /* FIFO 0 level mask */ +#define CIFR_THL_0 (0x3 << 4) /* Threshold Level for Channel 0 FIFO */ +#define CIFR_RESET_F (1 << 3) /* Reset input FIFOs */ +#define CIFR_FEN2 (1 << 2) /* FIFO enable for channel 2 */ +#define CIFR_FEN1 (1 << 1) /* FIFO enable for channel 1 */ +#define CIFR_FEN0 (1 << 0) /* FIFO enable for channel 0 */ + #define CICR0_SIM_MP (0 << 24) #define CICR0_SIM_SP (1 << 24) #define CICR0_SIM_MS (2 << 24) @@ -385,7 +480,10 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq, active = pcdev->active; if (!active) { - CIFR |= CIFR_RESET_F; + unsigned long cifr, cicr0; + + cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F; + __raw_writel(cifr, pcdev->base + CIFR); for (i = 0; i < pcdev->channels; i++) { DDADR(pcdev->dma_chans[i]) = buf->dmas[i].sg_dma; @@ -394,7 +492,9 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq, } pcdev->active = buf; - CICR0 |= CICR0_ENB; + + cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_ENB; + __raw_writel(cicr0, pcdev->base + CICR0); } else { struct pxa_cam_dma *buf_dma; struct pxa_cam_dma *act_dma; @@ -478,6 +578,8 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, struct videobuf_buffer *vb, struct pxa_buffer *buf) { + unsigned long cicr0; + /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ list_del_init(&vb->queue); vb->state = VIDEOBUF_DONE; @@ -490,7 +592,9 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, DCSR(pcdev->dma_chans[0]) = 0; DCSR(pcdev->dma_chans[1]) = 0; DCSR(pcdev->dma_chans[2]) = 0; - CICR0 &= ~CICR0_ENB; + + cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB; + __raw_writel(cicr0, pcdev->base + CICR0); return; } @@ -505,6 +609,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, unsigned long flags; u32 status, camera_status, overrun; struct videobuf_buffer *vb; + unsigned long cifr, cicr0; spin_lock_irqsave(&pcdev->lock, flags); @@ -527,22 +632,26 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, goto out; } - camera_status = CISR; + camera_status = __raw_readl(pcdev->base + CISR); overrun = CISR_IFO_0; if (pcdev->channels == 3) overrun |= CISR_IFO_1 | CISR_IFO_2; if (camera_status & overrun) { dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n", camera_status); /* Stop the Capture Interface */ - CICR0 &= ~CICR0_ENB; + cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB; + __raw_writel(cicr0, pcdev->base + CICR0); + /* Stop DMA */ DCSR(channel) = 0; /* Reset the FIFOs */ - CIFR |= CIFR_RESET_F; + cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F; + __raw_writel(cifr, pcdev->base + CIFR); /* Enable End-Of-Frame Interrupt */ - CICR0 &= ~CICR0_EOFM; + cicr0 &= ~CICR0_EOFM; + __raw_writel(cicr0, pcdev->base + CICR0); /* Restart the Capture Interface */ - CICR0 |= CICR0_ENB; + __raw_writel(cicr0 | CICR0_ENB, pcdev->base + CICR0); goto out; } @@ -629,7 +738,8 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev) pdata->init(pcdev->dev); } - CICR0 = 0x3FF; /* disable all interrupts */ + /* disable all interrupts */ + __raw_writel(0x3ff, pcdev->base + CICR0); if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) cicr4 |= CICR4_PCLK_EN; @@ -642,7 +752,8 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev) if (pcdev->platform_flags & PXA_CAMERA_VSP) cicr4 |= CICR4_VSP; - CICR4 = mclk_get_divisor(pcdev) | cicr4; + cicr4 |= mclk_get_divisor(pcdev); + __raw_writel(cicr4, pcdev->base + CICR4); clk_enable(pcdev->clk); } @@ -655,14 +766,15 @@ static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev) static irqreturn_t pxa_camera_irq(int irq, void *data) { struct pxa_camera_dev *pcdev = data; - unsigned int status = CISR; + unsigned long status, cicr0; - dev_dbg(pcdev->dev, "Camera interrupt status 0x%x\n", status); + status = __raw_readl(pcdev->base + CISR); + dev_dbg(pcdev->dev, "Camera interrupt status 0x%lx\n", status); if (!status) return IRQ_NONE; - CISR = status; + __raw_writel(status, pcdev->base + CISR); if (status & CISR_EOF) { int i; @@ -671,7 +783,8 @@ static irqreturn_t pxa_camera_irq(int irq, void *data) pcdev->active->dmas[i].sg_dma; DCSR(pcdev->dma_chans[i]) = DCSR_RUN; } - CICR0 |= CICR0_EOFM; + cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM; + __raw_writel(cicr0, pcdev->base + CICR0); } return IRQ_HANDLED; @@ -718,7 +831,7 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd) icd->devnum); /* disable capture, disable interrupts */ - CICR0 = 0x3ff; + __raw_writel(0x3ff, pcdev->base + CICR0); /* Stop DMA engine */ DCSR(pcdev->dma_chans[0]) = 0; @@ -779,7 +892,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; unsigned long dw, bpp, bus_flags, camera_flags, common_flags; - u32 cicr0, cicr1, cicr4 = 0; + u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0; int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags); if (ret < 0) @@ -852,9 +965,9 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) cicr4 |= CICR4_VSP; - cicr0 = CICR0; + cicr0 = __raw_readl(pcdev->base + CICR0); if (cicr0 & CICR0_ENB) - CICR0 = cicr0 & ~CICR0_ENB; + __raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0); cicr1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw; @@ -884,16 +997,21 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) break; } - CICR1 = cicr1; - CICR2 = 0; - CICR3 = CICR3_LPF_VAL(icd->height - 1) | + cicr2 = 0; + cicr3 = CICR3_LPF_VAL(icd->height - 1) | CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top)); - CICR4 = mclk_get_divisor(pcdev) | cicr4; + cicr4 |= mclk_get_divisor(pcdev); + + __raw_writel(cicr1, pcdev->base + CICR1); + __raw_writel(cicr2, pcdev->base + CICR2); + __raw_writel(cicr3, pcdev->base + CICR3); + __raw_writel(cicr4, pcdev->base + CICR4); /* CIF interrupts are not used, only DMA */ - CICR0 = (pcdev->platform_flags & PXA_CAMERA_MASTER ? - CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP)) | - CICR0_DMAEN | CICR0_IRQ_MASK | (cicr0 & CICR0_ENB); + cicr0 = (cicr0 & CICR0_ENB) | (pcdev->platform_flags & PXA_CAMERA_MASTER ? + CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP)); + cicr0 |= CICR0_DMAEN | CICR0_IRQ_MASK; + __raw_writel(cicr0, pcdev->base + CICR0); return 0; } @@ -1139,11 +1257,11 @@ static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state) struct pxa_camera_dev *pcdev = ici->priv; int i = 0, ret = 0; - pcdev->save_cicr[i++] = CICR0; - pcdev->save_cicr[i++] = CICR1; - pcdev->save_cicr[i++] = CICR2; - pcdev->save_cicr[i++] = CICR3; - pcdev->save_cicr[i++] = CICR4; + pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR0); + pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR1); + pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR2); + pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3); + pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4); if ((pcdev->icd) && (pcdev->icd->ops->suspend)) ret = pcdev->icd->ops->suspend(pcdev->icd, state); @@ -1162,23 +1280,27 @@ static int pxa_camera_resume(struct soc_camera_device *icd) DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD; DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD; - CICR0 = pcdev->save_cicr[i++] & ~CICR0_ENB; - CICR1 = pcdev->save_cicr[i++]; - CICR2 = pcdev->save_cicr[i++]; - CICR3 = pcdev->save_cicr[i++]; - CICR4 = pcdev->save_cicr[i++]; + __raw_writel(pcdev->save_cicr[i++] & ~CICR0_ENB, pcdev->base + CICR0); + __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR1); + __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR2); + __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR3); + __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4); if ((pcdev->icd) && (pcdev->icd->ops->resume)) ret = pcdev->icd->ops->resume(pcdev->icd); /* Restart frame capture if active buffer exists */ if (!ret && pcdev->active) { + unsigned long cifr, cicr0; + /* Reset the FIFOs */ - CIFR |= CIFR_RESET_F; - /* Enable End-Of-Frame Interrupt */ - CICR0 &= ~CICR0_EOFM; - /* Restart the Capture Interface */ - CICR0 |= CICR0_ENB; + cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F; + __raw_writel(cifr, pcdev->base + CIFR); + + cicr0 = __raw_readl(pcdev->base + CICR0); + cicr0 &= ~CICR0_EOFM; /* Enable End-Of-Frame Interrupt */ + cicr0 |= CICR0_ENB; /* Restart the Capture Interface */ + __raw_writel(cicr0, pcdev->base + CICR0); } return ret; -- cgit v1.2.3-59-g8ed1b From cf34cba78d0e0a7244bd7f11addb4d971293fb30 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 18 Dec 2008 11:38:03 -0300 Subject: V4L/DVB (10075): pxa-camera: setup the FIFO inactivity time-out register Using PXA270's FIFO inactivity time-out register (CITOR) reduces FIFO overruns. The time-out is calculated in CICLK / LCDCLK ticks and has to be longer than one pixel time. For this we have to know the pixel clock frequency, which usually is provided by the camera. We use the struct soc_camera_sense to request PCLK frequency from the camera driver upon each data format change. Tested-by: Robert Jarzmik Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pxa_camera.c | 90 ++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 21 deletions(-) (limited to 'drivers/media/video/pxa_camera.c') diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 45040f99031d..28ea13f7b2b0 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -215,7 +215,9 @@ struct pxa_camera_dev { struct pxacamera_platform_data *pdata; struct resource *res; unsigned long platform_flags; - unsigned long platform_mclk_10khz; + unsigned long ciclk; + unsigned long mclk; + u32 mclk_divisor; struct list_head capture; @@ -707,24 +709,43 @@ static void pxa_camera_init_videobuf(struct videobuf_queue *q, sizeof(struct pxa_buffer), icd); } -static int mclk_get_divisor(struct pxa_camera_dev *pcdev) +static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev) { - unsigned int mclk_10khz = pcdev->platform_mclk_10khz; - unsigned long div; + unsigned long mclk = pcdev->mclk; + u32 div; unsigned long lcdclk; - lcdclk = clk_get_rate(pcdev->clk) / 10000; + lcdclk = clk_get_rate(pcdev->clk); + pcdev->ciclk = lcdclk; - /* We verify platform_mclk_10khz != 0, so if anyone breaks it, here - * they get a nice Oops */ - div = (lcdclk + 2 * mclk_10khz - 1) / (2 * mclk_10khz) - 1; + /* mclk <= ciclk / 4 (27.4.2) */ + if (mclk > lcdclk / 4) { + mclk = lcdclk / 4; + dev_warn(pcdev->dev, "Limiting master clock to %lu\n", mclk); + } + + /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */ + div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1; + + /* If we're not supplying MCLK, leave it at 0 */ + if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) + pcdev->mclk = lcdclk / (2 * (div + 1)); - dev_dbg(pcdev->dev, "LCD clock %lukHz, target freq %dkHz, " - "divisor %lu\n", lcdclk * 10, mclk_10khz * 10, div); + dev_dbg(pcdev->dev, "LCD clock %luHz, target freq %luHz, " + "divisor %u\n", lcdclk, mclk, div); return div; } +static void recalculate_fifo_timeout(struct pxa_camera_dev *pcdev, + unsigned long pclk) +{ + /* We want a timeout > 1 pixel time, not ">=" */ + u32 ciclk_per_pixel = pcdev->ciclk / pclk + 1; + + __raw_writel(ciclk_per_pixel, pcdev->base + CITOR); +} + static void pxa_camera_activate(struct pxa_camera_dev *pcdev) { struct pxacamera_platform_data *pdata = pcdev->pdata; @@ -752,8 +773,14 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev) if (pcdev->platform_flags & PXA_CAMERA_VSP) cicr4 |= CICR4_VSP; - cicr4 |= mclk_get_divisor(pcdev); - __raw_writel(cicr4, pcdev->base + CICR4); + __raw_writel(pcdev->mclk_divisor | cicr4, pcdev->base + CICR4); + + if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) + /* Initialise the timeout under the assumption pclk = mclk */ + recalculate_fifo_timeout(pcdev, pcdev->mclk); + else + /* "Safe default" - 13MHz */ + recalculate_fifo_timeout(pcdev, 13000000); clk_enable(pcdev->clk); } @@ -1000,7 +1027,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) cicr2 = 0; cicr3 = CICR3_LPF_VAL(icd->height - 1) | CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top)); - cicr4 |= mclk_get_divisor(pcdev); + cicr4 |= pcdev->mclk_divisor; __raw_writel(cicr1, pcdev->base + CICR1); __raw_writel(cicr2, pcdev->base + CICR2); @@ -1019,8 +1046,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) static int pxa_camera_try_bus_param(struct soc_camera_device *icd, unsigned char buswidth) { - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; unsigned long bus_flags, camera_flags; int ret = test_platform_param(pcdev, buswidth, &bus_flags); @@ -1136,8 +1162,13 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, __u32 pixfmt, struct v4l2_rect *rect) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct pxa_camera_dev *pcdev = ici->priv; const struct soc_camera_data_format *host_fmt, *cam_fmt = NULL; const struct soc_camera_format_xlate *xlate; + struct soc_camera_sense sense = { + .master_clock = pcdev->mclk, + .pixel_clock_max = pcdev->ciclk / 4, + }; int ret, buswidth; xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); @@ -1150,6 +1181,10 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, host_fmt = xlate->host_fmt; cam_fmt = xlate->cam_fmt; + /* If PCLK is used to latch data from the sensor, check sense */ + if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) + icd->sense = &sense; + switch (pixfmt) { case 0: /* Only geometry change */ ret = icd->ops->set_fmt(icd, pixfmt, rect); @@ -1158,9 +1193,20 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, ret = icd->ops->set_fmt(icd, cam_fmt->fourcc, rect); } - if (ret < 0) + icd->sense = NULL; + + if (ret < 0) { dev_warn(&ici->dev, "Failed to configure for format %x\n", pixfmt); + } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { + if (sense.pixel_clock > sense.pixel_clock_max) { + dev_err(&ici->dev, + "pixel clock %lu set by the camera too high!", + sense.pixel_clock); + return -EIO; + } + recalculate_fifo_timeout(pcdev, sense.pixel_clock); + } if (pixfmt && !ret) { icd->buswidth = buswidth; @@ -1369,14 +1415,17 @@ static int pxa_camera_probe(struct platform_device *pdev) "data widths, using default 10 bit\n"); pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; } - pcdev->platform_mclk_10khz = pcdev->pdata->mclk_10khz; - if (!pcdev->platform_mclk_10khz) { + pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; + if (!pcdev->mclk) { dev_warn(&pdev->dev, - "mclk_10khz == 0! Please, fix your platform data. " + "mclk == 0! Please, fix your platform data. " "Using default 20MHz\n"); - pcdev->platform_mclk_10khz = 2000; + pcdev->mclk = 20000000; } + pcdev->dev = &pdev->dev; + pcdev->mclk_divisor = mclk_get_divisor(pcdev); + INIT_LIST_HEAD(&pcdev->capture); spin_lock_init(&pcdev->lock); @@ -1396,7 +1445,6 @@ static int pxa_camera_probe(struct platform_device *pdev) } pcdev->irq = irq; pcdev->base = base; - pcdev->dev = &pdev->dev; /* request dma */ err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH, -- cgit v1.2.3-59-g8ed1b From 64f5905ee74906643e22657bd20e2f11443053f0 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 18 Dec 2008 11:51:55 -0300 Subject: V4L/DVB (10080): soc-camera: readability improvements, more strict operations checks Simplify multiple drivers by replacing f->fmt.pix.* with a single pointer dereference, merge some needlessly broken lines, verify host and camera operations pointers on registration. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9m001.c | 20 +++++---- drivers/media/video/mt9m111.c | 10 +++-- drivers/media/video/mt9v022.c | 20 +++++---- drivers/media/video/pxa_camera.c | 21 +++------ drivers/media/video/soc_camera.c | 74 ++++++++++++++++++------------- drivers/media/video/soc_camera_platform.c | 5 ++- 6 files changed, 81 insertions(+), 69 deletions(-) (limited to 'drivers/media/video/pxa_camera.c') diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index b58f0f85e30f..e81b3247f79e 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -327,15 +327,17 @@ static int mt9m001_set_fmt(struct soc_camera_device *icd, static int mt9m001_try_fmt(struct soc_camera_device *icd, struct v4l2_format *f) { - if (f->fmt.pix.height < 32 + icd->y_skip_top) - f->fmt.pix.height = 32 + icd->y_skip_top; - if (f->fmt.pix.height > 1024 + icd->y_skip_top) - f->fmt.pix.height = 1024 + icd->y_skip_top; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.width > 1280) - f->fmt.pix.width = 1280; - f->fmt.pix.width &= ~0x01; /* has to be even, unsure why was ~3 */ + struct v4l2_pix_format *pix = &f->fmt.pix; + + if (pix->height < 32 + icd->y_skip_top) + pix->height = 32 + icd->y_skip_top; + if (pix->height > 1024 + icd->y_skip_top) + pix->height = 1024 + icd->y_skip_top; + if (pix->width < 48) + pix->width = 48; + if (pix->width > 1280) + pix->width = 1280; + pix->width &= ~0x01; /* has to be even, unsure why was ~3 */ return 0; } diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 3dfeea4e94b1..c89ea41fe259 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -503,10 +503,12 @@ static int mt9m111_set_fmt(struct soc_camera_device *icd, static int mt9m111_try_fmt(struct soc_camera_device *icd, struct v4l2_format *f) { - if (f->fmt.pix.height > MT9M111_MAX_HEIGHT) - f->fmt.pix.height = MT9M111_MAX_HEIGHT; - if (f->fmt.pix.width > MT9M111_MAX_WIDTH) - f->fmt.pix.width = MT9M111_MAX_WIDTH; + struct v4l2_pix_format *pix = &f->fmt.pix; + + if (pix->height > MT9M111_MAX_HEIGHT) + pix->height = MT9M111_MAX_HEIGHT; + if (pix->width > MT9M111_MAX_WIDTH) + pix->width = MT9M111_MAX_WIDTH; return 0; } diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 3b3a6a027b1d..be20747b8138 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -406,15 +406,17 @@ static int mt9v022_set_fmt(struct soc_camera_device *icd, static int mt9v022_try_fmt(struct soc_camera_device *icd, struct v4l2_format *f) { - if (f->fmt.pix.height < 32 + icd->y_skip_top) - f->fmt.pix.height = 32 + icd->y_skip_top; - if (f->fmt.pix.height > 480 + icd->y_skip_top) - f->fmt.pix.height = 480 + icd->y_skip_top; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.width > 752) - f->fmt.pix.width = 752; - f->fmt.pix.width &= ~0x03; /* ? */ + struct v4l2_pix_format *pix = &f->fmt.pix; + + if (pix->height < 32 + icd->y_skip_top) + pix->height = 32 + icd->y_skip_top; + if (pix->height > 480 + icd->y_skip_top) + pix->height = 480 + icd->y_skip_top; + if (pix->width < 48) + pix->width = 48; + if (pix->width > 752) + pix->width = 752; + pix->width &= ~0x03; /* ? */ return 0; } diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 28ea13f7b2b0..f6919a0e2ac2 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -240,8 +240,7 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) { struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); @@ -267,8 +266,7 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) { struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); int i; @@ -344,8 +342,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field) { struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); int ret; @@ -464,8 +461,7 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { struct soc_camera_device *icd = vq->priv_data; - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); struct pxa_buffer *active; @@ -915,8 +911,7 @@ static int test_platform_param(struct pxa_camera_dev *pcdev, static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) { - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; unsigned long dw, bpp, bus_flags, camera_flags, common_flags; u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0; @@ -1298,8 +1293,7 @@ static int pxa_camera_querycap(struct soc_camera_host *ici, static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state) { - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; int i = 0, ret = 0; @@ -1317,8 +1311,7 @@ static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state) static int pxa_camera_resume(struct soc_camera_device *icd) { - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; int i = 0, ret = 0; diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 176017501055..d5613cdd93a6 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -98,8 +98,7 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); enum v4l2_field field; int ret; @@ -163,8 +162,7 @@ static int soc_camera_reqbufs(struct file *file, void *priv, int ret; struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); WARN_ON(priv != file->private_data); @@ -388,8 +386,7 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt) { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); if (list_empty(&icf->vb_vidq.stream)) { dev_err(&icd->dev, "Trying to poll with no queued buffers!\n"); @@ -415,9 +412,9 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); - __u32 pixfmt = f->fmt.pix.pixelformat; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct v4l2_pix_format *pix = &f->fmt.pix; + __u32 pixfmt = pix->pixelformat; int ret; struct v4l2_rect rect; @@ -429,9 +426,9 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, rect.left = icd->x_current; rect.top = icd->y_current; - rect.width = f->fmt.pix.width; - rect.height = f->fmt.pix.height; - ret = ici->ops->set_fmt(icd, f->fmt.pix.pixelformat, &rect); + rect.width = pix->width; + rect.height = pix->height; + ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect); if (ret < 0) { return ret; } else if (!icd->current_fmt || @@ -443,7 +440,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, icd->width = rect.width; icd->height = rect.height; - icf->vb_vidq.field = f->fmt.pix.field; + icf->vb_vidq.field = pix->field; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", f->type); @@ -479,16 +476,17 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; + struct v4l2_pix_format *pix = &f->fmt.pix; WARN_ON(priv != file->private_data); - f->fmt.pix.width = icd->width; - f->fmt.pix.height = icd->height; - f->fmt.pix.field = icf->vb_vidq.field; - f->fmt.pix.pixelformat = icd->current_fmt->fourcc; - f->fmt.pix.bytesperline = f->fmt.pix.width * + pix->width = icd->width; + pix->height = icd->height; + pix->field = icf->vb_vidq.field; + pix->pixelformat = icd->current_fmt->fourcc; + pix->bytesperline = pix->width * DIV_ROUND_UP(icd->current_fmt->depth, 8); - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + pix->sizeimage = pix->height * pix->bytesperline; dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n", icd->current_fmt->fourcc); return 0; @@ -499,8 +497,7 @@ static int soc_camera_querycap(struct file *file, void *priv, { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); WARN_ON(priv != file->private_data); @@ -651,8 +648,7 @@ static int soc_camera_s_crop(struct file *file, void *fh, { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); int ret; if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -776,13 +772,9 @@ static int scan_add_device(struct soc_camera_device *icd) static int soc_camera_probe(struct device *dev) { struct soc_camera_device *icd = to_soc_camera_dev(dev); - struct soc_camera_host *ici = - to_soc_camera_host(icd->dev.parent); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); int ret; - if (!icd->ops->probe) - return -ENODEV; - /* We only call ->add() here to activate and probe the camera. * We shall ->remove() and deactivate it immediately afterwards. */ ret = ici->ops->add(icd); @@ -863,7 +855,16 @@ int soc_camera_host_register(struct soc_camera_host *ici) int ret; struct soc_camera_host *ix; - if (!ici->ops->init_videobuf || !ici->ops->add || !ici->ops->remove) + if (!ici || !ici->ops || + !ici->ops->try_fmt || + !ici->ops->set_fmt || + !ici->ops->set_bus_param || + !ici->ops->querycap || + !ici->ops->init_videobuf || + !ici->ops->reqbufs || + !ici->ops->add || + !ici->ops->remove || + !ici->ops->poll) return -EINVAL; /* Number might be equal to the platform device ID */ @@ -931,7 +932,16 @@ int soc_camera_device_register(struct soc_camera_device *icd) struct soc_camera_device *ix; int num = -1, i; - if (!icd) + if (!icd || !icd->ops || + !icd->ops->probe || + !icd->ops->init || + !icd->ops->release || + !icd->ops->start_capture || + !icd->ops->stop_capture || + !icd->ops->set_fmt || + !icd->ops->try_fmt || + !icd->ops->query_bus_param || + !icd->ops->set_bus_param) return -EINVAL; for (i = 0; i < 256 && num < 0; i++) { @@ -953,7 +963,9 @@ int soc_camera_device_register(struct soc_camera_device *icd) icd->dev.bus = &soc_camera_bus_type; dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum); - icd->dev.release = dummy_release; + icd->dev.release = dummy_release; + icd->use_count = 0; + icd->host_priv = NULL; return scan_add_device(icd); } diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index c23871e4c1e6..013ab06e3180 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c @@ -89,9 +89,10 @@ static int soc_camera_platform_try_fmt(struct soc_camera_device *icd, struct v4l2_format *f) { struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd); + struct v4l2_pix_format *pix = &f->fmt.pix; - f->fmt.pix.width = p->format.width; - f->fmt.pix.height = p->format.height; + pix->width = p->format.width; + pix->height = p->format.height; return 0; } -- cgit v1.2.3-59-g8ed1b From bf507158eb27ea94aca300b28ecee60fdbb40007 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 18 Dec 2008 11:53:51 -0300 Subject: V4L/DVB (10081): pxa-camera: call try_fmt() camera device method with correct pixel format With the introduction of the format conversion support in soc-camera, we now also have to take care to pass the correct pixel format to the camera driver when calling its try_fmt() method. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pxa_camera.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/media/video/pxa_camera.c') diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index f6919a0e2ac2..aa7efc45d364 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -1218,6 +1218,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; __u32 pixfmt = pix->pixelformat; + int ret; xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { @@ -1240,8 +1241,13 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, DIV_ROUND_UP(xlate->host_fmt->depth, 8); pix->sizeimage = pix->height * pix->bytesperline; + /* camera has to see its format, but the user the original one */ + pix->pixelformat = xlate->cam_fmt->fourcc; /* limit to sensor capabilities */ - return icd->ops->try_fmt(icd, f); + ret = icd->ops->try_fmt(icd, f); + pix->pixelformat = xlate->host_fmt->fourcc; + + return ret; } static int pxa_camera_reqbufs(struct soc_camera_file *icf, -- cgit v1.2.3-59-g8ed1b From 1c3bb7431d16f7486a8523d54380bad89c485dc8 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 18 Dec 2008 12:28:54 -0300 Subject: V4L/DVB (10083): soc-camera: unify locking, play nicer with videobuf locking Move mutex from host drivers to camera device object, take into account videobuf locking. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pxa_camera.c | 15 ++--- drivers/media/video/sh_mobile_ceu_camera.c | 9 +-- drivers/media/video/soc_camera.c | 99 +++++++++++++++++++++++++----- include/media/soc_camera.h | 8 ++- 4 files changed, 96 insertions(+), 35 deletions(-) (limited to 'drivers/media/video/pxa_camera.c') diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index aa7efc45d364..c3c50de0aa50 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -164,8 +163,6 @@ CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \ CICR0_EOFM | CICR0_FOM) -static DEFINE_MUTEX(camera_lock); - /* * Structures */ @@ -813,16 +810,17 @@ static irqreturn_t pxa_camera_irq(int irq, void *data) return IRQ_HANDLED; } -/* The following two functions absolutely depend on the fact, that - * there can be only one camera on PXA quick capture interface */ +/* + * The following two functions absolutely depend on the fact, that + * there can be only one camera on PXA quick capture interface + * Called with .video_lock held + */ static int pxa_camera_add_device(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; int ret; - mutex_lock(&camera_lock); - if (pcdev->icd) { ret = -EBUSY; goto ebusy; @@ -838,11 +836,10 @@ static int pxa_camera_add_device(struct soc_camera_device *icd) pcdev->icd = icd; ebusy: - mutex_unlock(&camera_lock); - return ret; } +/* Called with .video_lock held */ static void pxa_camera_remove_device(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index a49bec1509f4..47ffa441c869 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -75,8 +74,6 @@ #define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */ #define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */ -static DEFINE_MUTEX(camera_lock); - /* per video frame buffer */ struct sh_mobile_ceu_buffer { struct videobuf_buffer vb; /* v4l buffer must be first */ @@ -292,14 +289,13 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data) return IRQ_HANDLED; } +/* Called with .video_lock held */ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; int ret = -EBUSY; - mutex_lock(&camera_lock); - if (pcdev->icd) goto err; @@ -319,11 +315,10 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) pcdev->icd = icd; err: - mutex_unlock(&camera_lock); - return ret; } +/* Called with .video_lock held */ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index d5613cdd93a6..e869670dbae5 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -33,7 +33,6 @@ static LIST_HEAD(hosts); static LIST_HEAD(devices); static DEFINE_MUTEX(list_lock); -static DEFINE_MUTEX(video_lock); const struct soc_camera_data_format *soc_camera_format_by_fourcc( struct soc_camera_device *icd, unsigned int fourcc) @@ -270,8 +269,10 @@ static int soc_camera_open(struct inode *inode, struct file *file) if (!icf) return -ENOMEM; - /* Protect against icd->remove() until we module_get() both drivers. */ - mutex_lock(&video_lock); + /* + * It is safe to dereference these pointers now as long as a user has + * the video device open - we are protected by the held cdev reference. + */ vdev = video_devdata(file); icd = container_of(vdev->parent, struct soc_camera_device, dev); @@ -289,6 +290,9 @@ static int soc_camera_open(struct inode *inode, struct file *file) goto emgi; } + /* Protect against icd->remove() until we module_get() both drivers. */ + mutex_lock(&icd->video_lock); + icf->icd = icd; icd->use_count++; @@ -304,7 +308,7 @@ static int soc_camera_open(struct inode *inode, struct file *file) } } - mutex_unlock(&video_lock); + mutex_unlock(&icd->video_lock); file->private_data = icf; dev_dbg(&icd->dev, "camera device open\n"); @@ -313,16 +317,16 @@ static int soc_camera_open(struct inode *inode, struct file *file) return 0; - /* All errors are entered with the video_lock held */ + /* First two errors are entered with the .video_lock held */ eiciadd: soc_camera_free_user_formats(icd); eiufmt: icd->use_count--; + mutex_unlock(&icd->video_lock); module_put(ici->ops->owner); emgi: module_put(icd->ops->owner); emgd: - mutex_unlock(&video_lock); vfree(icf); return ret; } @@ -334,15 +338,16 @@ static int soc_camera_close(struct inode *inode, struct file *file) struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct video_device *vdev = icd->vdev; - mutex_lock(&video_lock); + mutex_lock(&icd->video_lock); icd->use_count--; if (!icd->use_count) { ici->ops->remove(icd); soc_camera_free_user_formats(icd); } + mutex_unlock(&icd->video_lock); + module_put(icd->ops->owner); module_put(ici->ops->owner); - mutex_unlock(&video_lock); vfree(icf); @@ -424,18 +429,27 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, if (ret < 0) return ret; + mutex_lock(&icf->vb_vidq.vb_lock); + + if (videobuf_queue_is_busy(&icf->vb_vidq)) { + dev_err(&icd->dev, "S_FMT denied: queue busy\n"); + ret = -EBUSY; + goto unlock; + } + rect.left = icd->x_current; rect.top = icd->y_current; rect.width = pix->width; rect.height = pix->height; ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect); if (ret < 0) { - return ret; + goto unlock; } else if (!icd->current_fmt || icd->current_fmt->fourcc != pixfmt) { dev_err(&ici->dev, "Host driver hasn't set up current format correctly!\n"); - return -EINVAL; + ret = -EINVAL; + goto unlock; } icd->width = rect.width; @@ -449,7 +463,12 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, icd->width, icd->height); /* set physical bus parameters */ - return ici->ops->set_bus_param(icd, pixfmt); + ret = ici->ops->set_bus_param(icd, pixfmt); + +unlock: + mutex_unlock(&icf->vb_vidq.vb_lock); + + return ret; } static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, @@ -510,6 +529,7 @@ static int soc_camera_streamon(struct file *file, void *priv, { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; + int ret; WARN_ON(priv != file->private_data); @@ -518,10 +538,16 @@ static int soc_camera_streamon(struct file *file, void *priv, if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; + mutex_lock(&icd->video_lock); + icd->ops->start_capture(icd); /* This calls buf_queue from host driver's videobuf_queue_ops */ - return videobuf_streamon(&icf->vb_vidq); + ret = videobuf_streamon(&icf->vb_vidq); + + mutex_unlock(&icd->video_lock); + + return ret; } static int soc_camera_streamoff(struct file *file, void *priv, @@ -537,12 +563,16 @@ static int soc_camera_streamoff(struct file *file, void *priv, if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; + mutex_lock(&icd->video_lock); + /* This calls buf_release from host driver's videobuf_queue_ops for all * remaining buffers. When the last buffer is freed, stop capture */ videobuf_streamoff(&icf->vb_vidq); icd->ops->stop_capture(icd); + mutex_unlock(&icd->video_lock); + return 0; } @@ -654,6 +684,9 @@ static int soc_camera_s_crop(struct file *file, void *fh, if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; + /* Cropping is allowed during a running capture, guard consistency */ + mutex_lock(&icf->vb_vidq.vb_lock); + ret = ici->ops->set_fmt(icd, 0, &a->c); if (!ret) { icd->width = a->c.width; @@ -662,6 +695,8 @@ static int soc_camera_s_crop(struct file *file, void *fh, icd->y_current = a->c.top; } + mutex_unlock(&icf->vb_vidq.vb_lock); + return ret; } @@ -775,11 +810,32 @@ static int soc_camera_probe(struct device *dev) struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); int ret; + /* + * Possible race scenario: + * modprobe triggers __func__ + * at this moment respective gets rmmod'ed + * to protect take module references. + */ + + if (!try_module_get(icd->ops->owner)) { + dev_err(&icd->dev, "Couldn't lock sensor driver.\n"); + ret = -EINVAL; + goto emgd; + } + + if (!try_module_get(ici->ops->owner)) { + dev_err(&icd->dev, "Couldn't lock capture bus driver.\n"); + ret = -EINVAL; + goto emgi; + } + + mutex_lock(&icd->video_lock); + /* We only call ->add() here to activate and probe the camera. * We shall ->remove() and deactivate it immediately afterwards. */ ret = ici->ops->add(icd); if (ret < 0) - return ret; + goto eiadd; ret = icd->ops->probe(icd); if (ret >= 0) { @@ -793,6 +849,12 @@ static int soc_camera_probe(struct device *dev) } ici->ops->remove(icd); +eiadd: + mutex_unlock(&icd->video_lock); + module_put(ici->ops->owner); +emgi: + module_put(icd->ops->owner); +emgd: return ret; } @@ -966,6 +1028,7 @@ int soc_camera_device_register(struct soc_camera_device *icd) icd->dev.release = dummy_release; icd->use_count = 0; icd->host_priv = NULL; + mutex_init(&icd->video_lock); return scan_add_device(icd); } @@ -1012,6 +1075,10 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { #endif }; +/* + * Usually called from the struct soc_camera_ops .probe() method, i.e., from + * soc_camera_probe() above with .video_lock held + */ int soc_camera_video_start(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); @@ -1027,7 +1094,7 @@ int soc_camera_video_start(struct soc_camera_device *icd) dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev); strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); - /* Maybe better &ici->dev */ + vdev->parent = &icd->dev; vdev->current_norm = V4L2_STD_UNKNOWN; vdev->fops = &soc_camera_fops; @@ -1061,10 +1128,10 @@ void soc_camera_video_stop(struct soc_camera_device *icd) if (!icd->dev.parent || !vdev) return; - mutex_lock(&video_lock); + mutex_lock(&icd->video_lock); video_unregister_device(vdev); icd->vdev = NULL; - mutex_unlock(&video_lock); + mutex_unlock(&icd->video_lock); } EXPORT_SYMBOL(soc_camera_video_stop); diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 38b826c608be..8bae9a359d93 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -12,9 +12,10 @@ #ifndef SOC_CAMERA_H #define SOC_CAMERA_H +#include +#include #include #include -#include struct soc_camera_device { struct list_head list; @@ -45,9 +46,10 @@ struct soc_camera_device { struct soc_camera_format_xlate *user_formats; int num_user_formats; struct module *owner; - void *host_priv; /* per-device host private data */ - /* soc_camera.c private count. Only accessed with video_lock held */ + void *host_priv; /* Per-device host private data */ + /* soc_camera.c private count. Only accessed with .video_lock held */ int use_count; + struct mutex video_lock; /* Protects device data */ }; struct soc_camera_file { -- cgit v1.2.3-59-g8ed1b From 06daa1af4d207e93c9a8a3e54adef8635ba81c94 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 18 Dec 2008 12:52:08 -0300 Subject: V4L/DVB (10090): soc-camera: let drivers decide upon supported field values sh_mobile_ceu_camera.c is already prepared to support interlaced format, this patch moves the choice of a field type down to host and / or camera drivers. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pxa_camera.c | 10 ++++++++++ drivers/media/video/soc_camera.c | 19 +------------------ 2 files changed, 11 insertions(+), 18 deletions(-) (limited to 'drivers/media/video/pxa_camera.c') diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index c3c50de0aa50..b2d9fe5dfd61 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -1215,6 +1215,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; __u32 pixfmt = pix->pixelformat; + enum v4l2_field field; int ret; xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); @@ -1244,6 +1245,15 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, ret = icd->ops->try_fmt(icd, f); pix->pixelformat = xlate->host_fmt->fourcc; + field = pix->field; + + if (field == V4L2_FIELD_ANY) { + pix->field = V4L2_FIELD_NONE; + } else if (field != V4L2_FIELD_NONE) { + dev_err(&icd->dev, "Field type %d unsupported.\n", field); + return -EINVAL; + } + return ret; } diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index e86e6bda1b7f..90077cb4fe66 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -98,28 +98,11 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - enum v4l2_field field; - int ret; WARN_ON(priv != file->private_data); - /* - * TODO: this might also have to migrate to host-drivers, if anyone - * wishes to support other fields - */ - field = f->fmt.pix.field; - - if (field == V4L2_FIELD_ANY) { - f->fmt.pix.field = V4L2_FIELD_NONE; - } else if (field != V4L2_FIELD_NONE) { - dev_err(&icd->dev, "Field type invalid.\n"); - return -EINVAL; - } - /* limit format to hardware capabilities */ - ret = ici->ops->try_fmt(icd, f); - - return ret; + return ici->ops->try_fmt(icd, f); } static int soc_camera_enum_input(struct file *file, void *priv, -- cgit v1.2.3-59-g8ed1b