aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/mt9v022.c
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2009-08-25 10:50:46 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-18 23:19:17 -0400
commit6a6c8786725c0b3d143674effa8b772f47b1c189 (patch)
tree8bb76c5dcbd579f13e876bd1a0bb56bee4bcebdd /drivers/media/video/mt9v022.c
parent0166b74374cae3fa8bff0caef726a3d960a9a50a (diff)
V4L/DVB (12534): soc-camera: V4L2 API compliant scaling (S_FMT) and cropping (S_CROP)
The initial soc-camera scaling and cropping implementation turned out to be incompliant with the V4L2 API, e.g., it expected the user to specify cropping in output window pixels, instead of input window pixels. This patch converts the soc-camera core and all drivers to comply with the standard. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/mt9v022.c')
-rw-r--r--drivers/media/video/mt9v022.c131
1 files changed, 104 insertions, 27 deletions
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index ab1965425289..35ea0ddd0715 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -55,6 +55,13 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
55/* Progressive scan, master, defaults */ 55/* Progressive scan, master, defaults */
56#define MT9V022_CHIP_CONTROL_DEFAULT 0x188 56#define MT9V022_CHIP_CONTROL_DEFAULT 0x188
57 57
58#define MT9V022_MAX_WIDTH 752
59#define MT9V022_MAX_HEIGHT 480
60#define MT9V022_MIN_WIDTH 48
61#define MT9V022_MIN_HEIGHT 32
62#define MT9V022_COLUMN_SKIP 1
63#define MT9V022_ROW_SKIP 4
64
58static const struct soc_camera_data_format mt9v022_colour_formats[] = { 65static const struct soc_camera_data_format mt9v022_colour_formats[] = {
59 /* Order important: first natively supported, 66 /* Order important: first natively supported,
60 * second supported with a GPIO extender */ 67 * second supported with a GPIO extender */
@@ -86,6 +93,8 @@ static const struct soc_camera_data_format mt9v022_monochrome_formats[] = {
86 93
87struct mt9v022 { 94struct mt9v022 {
88 struct v4l2_subdev subdev; 95 struct v4l2_subdev subdev;
96 struct v4l2_rect rect; /* Sensor window */
97 __u32 fourcc;
89 int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ 98 int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
90 u16 chip_control; 99 u16 chip_control;
91}; 100};
@@ -250,44 +259,101 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
250 259
251static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) 260static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
252{ 261{
253 struct v4l2_rect *rect = &a->c;
254 struct i2c_client *client = sd->priv; 262 struct i2c_client *client = sd->priv;
263 struct mt9v022 *mt9v022 = to_mt9v022(client);
264 struct v4l2_rect rect = a->c;
255 struct soc_camera_device *icd = client->dev.platform_data; 265 struct soc_camera_device *icd = client->dev.platform_data;
256 int ret; 266 int ret;
257 267
268 /* Bayer format - even size lengths */
269 if (mt9v022->fourcc == V4L2_PIX_FMT_SBGGR8 ||
270 mt9v022->fourcc == V4L2_PIX_FMT_SBGGR16) {
271 rect.width = ALIGN(rect.width, 2);
272 rect.height = ALIGN(rect.height, 2);
273 /* Let the user play with the starting pixel */
274 }
275
276 soc_camera_limit_side(&rect.left, &rect.width,
277 MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH);
278
279 soc_camera_limit_side(&rect.top, &rect.height,
280 MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT);
281
258 /* Like in example app. Contradicts the datasheet though */ 282 /* Like in example app. Contradicts the datasheet though */
259 ret = reg_read(client, MT9V022_AEC_AGC_ENABLE); 283 ret = reg_read(client, MT9V022_AEC_AGC_ENABLE);
260 if (ret >= 0) { 284 if (ret >= 0) {
261 if (ret & 1) /* Autoexposure */ 285 if (ret & 1) /* Autoexposure */
262 ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 286 ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
263 rect->height + icd->y_skip_top + 43); 287 rect.height + icd->y_skip_top + 43);
264 else 288 else
265 ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 289 ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
266 rect->height + icd->y_skip_top + 43); 290 rect.height + icd->y_skip_top + 43);
267 } 291 }
268 /* Setup frame format: defaults apart from width and height */ 292 /* Setup frame format: defaults apart from width and height */
269 if (!ret) 293 if (!ret)
270 ret = reg_write(client, MT9V022_COLUMN_START, rect->left); 294 ret = reg_write(client, MT9V022_COLUMN_START, rect.left);
271 if (!ret) 295 if (!ret)
272 ret = reg_write(client, MT9V022_ROW_START, rect->top); 296 ret = reg_write(client, MT9V022_ROW_START, rect.top);
273 if (!ret) 297 if (!ret)
274 /* Default 94, Phytec driver says: 298 /* Default 94, Phytec driver says:
275 * "width + horizontal blank >= 660" */ 299 * "width + horizontal blank >= 660" */
276 ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, 300 ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING,
277 rect->width > 660 - 43 ? 43 : 301 rect.width > 660 - 43 ? 43 :
278 660 - rect->width); 302 660 - rect.width);
279 if (!ret) 303 if (!ret)
280 ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45); 304 ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45);
281 if (!ret) 305 if (!ret)
282 ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect->width); 306 ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width);
283 if (!ret) 307 if (!ret)
284 ret = reg_write(client, MT9V022_WINDOW_HEIGHT, 308 ret = reg_write(client, MT9V022_WINDOW_HEIGHT,
285 rect->height + icd->y_skip_top); 309 rect.height + icd->y_skip_top);
286 310
287 if (ret < 0) 311 if (ret < 0)
288 return ret; 312 return ret;
289 313
290 dev_dbg(&client->dev, "Frame %ux%u pixel\n", rect->width, rect->height); 314 dev_dbg(&client->dev, "Frame %ux%u pixel\n", rect.width, rect.height);
315
316 mt9v022->rect = rect;
317
318 return 0;
319}
320
321static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
322{
323 struct i2c_client *client = sd->priv;
324 struct mt9v022 *mt9v022 = to_mt9v022(client);
325
326 a->c = mt9v022->rect;
327 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
328
329 return 0;
330}
331
332static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
333{
334 a->bounds.left = MT9V022_COLUMN_SKIP;
335 a->bounds.top = MT9V022_ROW_SKIP;
336 a->bounds.width = MT9V022_MAX_WIDTH;
337 a->bounds.height = MT9V022_MAX_HEIGHT;
338 a->defrect = a->bounds;
339 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
340 a->pixelaspect.numerator = 1;
341 a->pixelaspect.denominator = 1;
342
343 return 0;
344}
345
346static int mt9v022_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
347{
348 struct i2c_client *client = sd->priv;
349 struct mt9v022 *mt9v022 = to_mt9v022(client);
350 struct v4l2_pix_format *pix = &f->fmt.pix;
351
352 pix->width = mt9v022->rect.width;
353 pix->height = mt9v022->rect.height;
354 pix->pixelformat = mt9v022->fourcc;
355 pix->field = V4L2_FIELD_NONE;
356 pix->colorspace = V4L2_COLORSPACE_SRGB;
291 357
292 return 0; 358 return 0;
293} 359}
@@ -296,16 +362,16 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
296{ 362{
297 struct i2c_client *client = sd->priv; 363 struct i2c_client *client = sd->priv;
298 struct mt9v022 *mt9v022 = to_mt9v022(client); 364 struct mt9v022 *mt9v022 = to_mt9v022(client);
299 struct soc_camera_device *icd = client->dev.platform_data;
300 struct v4l2_pix_format *pix = &f->fmt.pix; 365 struct v4l2_pix_format *pix = &f->fmt.pix;
301 struct v4l2_crop a = { 366 struct v4l2_crop a = {
302 .c = { 367 .c = {
303 .left = icd->rect_current.left, 368 .left = mt9v022->rect.left,
304 .top = icd->rect_current.top, 369 .top = mt9v022->rect.top,
305 .width = pix->width, 370 .width = pix->width,
306 .height = pix->height, 371 .height = pix->height,
307 }, 372 },
308 }; 373 };
374 int ret;
309 375
310 /* The caller provides a supported format, as verified per call to 376 /* The caller provides a supported format, as verified per call to
311 * icd->try_fmt(), datawidth is from our supported format list */ 377 * icd->try_fmt(), datawidth is from our supported format list */
@@ -328,7 +394,14 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
328 } 394 }
329 395
330 /* No support for scaling on this camera, just crop. */ 396 /* No support for scaling on this camera, just crop. */
331 return mt9v022_s_crop(sd, &a); 397 ret = mt9v022_s_crop(sd, &a);
398 if (!ret) {
399 pix->width = mt9v022->rect.width;
400 pix->height = mt9v022->rect.height;
401 mt9v022->fourcc = pix->pixelformat;
402 }
403
404 return ret;
332} 405}
333 406
334static int mt9v022_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) 407static int mt9v022_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
@@ -336,10 +409,13 @@ static int mt9v022_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
336 struct i2c_client *client = sd->priv; 409 struct i2c_client *client = sd->priv;
337 struct soc_camera_device *icd = client->dev.platform_data; 410 struct soc_camera_device *icd = client->dev.platform_data;
338 struct v4l2_pix_format *pix = &f->fmt.pix; 411 struct v4l2_pix_format *pix = &f->fmt.pix;
412 int align = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 ||
413 pix->pixelformat == V4L2_PIX_FMT_SBGGR16;
339 414
340 v4l_bound_align_image(&pix->width, 48, 752, 2 /* ? */, 415 v4l_bound_align_image(&pix->width, MT9V022_MIN_WIDTH,
341 &pix->height, 32 + icd->y_skip_top, 416 MT9V022_MAX_WIDTH, align,
342 480 + icd->y_skip_top, 0, 0); 417 &pix->height, MT9V022_MIN_HEIGHT + icd->y_skip_top,
418 MT9V022_MAX_HEIGHT + icd->y_skip_top, align, 0);
343 419
344 return 0; 420 return 0;
345} 421}
@@ -669,6 +745,8 @@ static int mt9v022_video_probe(struct soc_camera_device *icd,
669 if (flags & SOCAM_DATAWIDTH_8) 745 if (flags & SOCAM_DATAWIDTH_8)
670 icd->num_formats++; 746 icd->num_formats++;
671 747
748 mt9v022->fourcc = icd->formats->fourcc;
749
672 dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", 750 dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
673 data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? 751 data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
674 "monochrome" : "colour"); 752 "monochrome" : "colour");
@@ -679,10 +757,9 @@ ei2c:
679 757
680static void mt9v022_video_remove(struct soc_camera_device *icd) 758static void mt9v022_video_remove(struct soc_camera_device *icd)
681{ 759{
682 struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
683 struct soc_camera_link *icl = to_soc_camera_link(icd); 760 struct soc_camera_link *icl = to_soc_camera_link(icd);
684 761
685 dev_dbg(&client->dev, "Video %x removed: %p, %p\n", client->addr, 762 dev_dbg(&icd->dev, "Video removed: %p, %p\n",
686 icd->dev.parent, icd->vdev); 763 icd->dev.parent, icd->vdev);
687 if (icl->free_bus) 764 if (icl->free_bus)
688 icl->free_bus(icl); 765 icl->free_bus(icl);
@@ -701,8 +778,11 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
701static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { 778static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
702 .s_stream = mt9v022_s_stream, 779 .s_stream = mt9v022_s_stream,
703 .s_fmt = mt9v022_s_fmt, 780 .s_fmt = mt9v022_s_fmt,
781 .g_fmt = mt9v022_g_fmt,
704 .try_fmt = mt9v022_try_fmt, 782 .try_fmt = mt9v022_try_fmt,
705 .s_crop = mt9v022_s_crop, 783 .s_crop = mt9v022_s_crop,
784 .g_crop = mt9v022_g_crop,
785 .cropcap = mt9v022_cropcap,
706}; 786};
707 787
708static struct v4l2_subdev_ops mt9v022_subdev_ops = { 788static struct v4l2_subdev_ops mt9v022_subdev_ops = {
@@ -745,16 +825,13 @@ static int mt9v022_probe(struct i2c_client *client,
745 mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; 825 mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
746 826
747 icd->ops = &mt9v022_ops; 827 icd->ops = &mt9v022_ops;
748 icd->rect_max.left = 1;
749 icd->rect_max.top = 4;
750 icd->rect_max.width = 752;
751 icd->rect_max.height = 480;
752 icd->rect_current.left = 1;
753 icd->rect_current.top = 4;
754 icd->width_min = 48;
755 icd->height_min = 32;
756 icd->y_skip_top = 1; 828 icd->y_skip_top = 1;
757 829
830 mt9v022->rect.left = MT9V022_COLUMN_SKIP;
831 mt9v022->rect.top = MT9V022_ROW_SKIP;
832 mt9v022->rect.width = MT9V022_MAX_WIDTH;
833 mt9v022->rect.height = MT9V022_MAX_HEIGHT;
834
758 ret = mt9v022_video_probe(icd, client); 835 ret = mt9v022_video_probe(icd, client);
759 if (ret) { 836 if (ret) {
760 icd->ops = NULL; 837 icd->ops = NULL;