aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/mt9m111.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/mt9m111.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/mt9m111.c')
-rw-r--r--drivers/media/video/mt9m111.c112
1 files changed, 95 insertions, 17 deletions
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index 3637376da755..920dd53c4cfa 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -194,7 +194,7 @@ static int mt9m111_reg_read(struct i2c_client *client, const u16 reg)
194 194
195 ret = reg_page_map_set(client, reg); 195 ret = reg_page_map_set(client, reg);
196 if (!ret) 196 if (!ret)
197 ret = swab16(i2c_smbus_read_word_data(client, (reg & 0xff))); 197 ret = swab16(i2c_smbus_read_word_data(client, reg & 0xff));
198 198
199 dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret); 199 dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret);
200 return ret; 200 return ret;
@@ -257,8 +257,8 @@ static int mt9m111_setup_rect(struct i2c_client *client,
257 int width = rect->width; 257 int width = rect->width;
258 int height = rect->height; 258 int height = rect->height;
259 259
260 if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8) 260 if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 ||
261 || (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16)) 261 mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16)
262 is_raw_format = 1; 262 is_raw_format = 1;
263 else 263 else
264 is_raw_format = 0; 264 is_raw_format = 0;
@@ -395,23 +395,85 @@ static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
395 return 0; 395 return 0;
396} 396}
397 397
398static int mt9m111_make_rect(struct i2c_client *client,
399 struct v4l2_rect *rect)
400{
401 struct mt9m111 *mt9m111 = to_mt9m111(client);
402
403 if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 ||
404 mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16) {
405 /* Bayer format - even size lengths */
406 rect->width = ALIGN(rect->width, 2);
407 rect->height = ALIGN(rect->height, 2);
408 /* Let the user play with the starting pixel */
409 }
410
411 /* FIXME: the datasheet doesn't specify minimum sizes */
412 soc_camera_limit_side(&rect->left, &rect->width,
413 MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH);
414
415 soc_camera_limit_side(&rect->top, &rect->height,
416 MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT);
417
418 return mt9m111_setup_rect(client, rect);
419}
420
398static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) 421static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
399{ 422{
400 struct v4l2_rect *rect = &a->c; 423 struct v4l2_rect rect = a->c;
401 struct i2c_client *client = sd->priv; 424 struct i2c_client *client = sd->priv;
402 struct mt9m111 *mt9m111 = to_mt9m111(client); 425 struct mt9m111 *mt9m111 = to_mt9m111(client);
403 int ret; 426 int ret;
404 427
405 dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n", 428 dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
406 __func__, rect->left, rect->top, rect->width, 429 __func__, rect.left, rect.top, rect.width, rect.height);
407 rect->height);
408 430
409 ret = mt9m111_setup_rect(client, rect); 431 ret = mt9m111_make_rect(client, &rect);
410 if (!ret) 432 if (!ret)
411 mt9m111->rect = *rect; 433 mt9m111->rect = rect;
412 return ret; 434 return ret;
413} 435}
414 436
437static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
438{
439 struct i2c_client *client = sd->priv;
440 struct mt9m111 *mt9m111 = to_mt9m111(client);
441
442 a->c = mt9m111->rect;
443 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
444
445 return 0;
446}
447
448static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
449{
450 a->bounds.left = MT9M111_MIN_DARK_COLS;
451 a->bounds.top = MT9M111_MIN_DARK_ROWS;
452 a->bounds.width = MT9M111_MAX_WIDTH;
453 a->bounds.height = MT9M111_MAX_HEIGHT;
454 a->defrect = a->bounds;
455 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
456 a->pixelaspect.numerator = 1;
457 a->pixelaspect.denominator = 1;
458
459 return 0;
460}
461
462static int mt9m111_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
463{
464 struct i2c_client *client = sd->priv;
465 struct mt9m111 *mt9m111 = to_mt9m111(client);
466 struct v4l2_pix_format *pix = &f->fmt.pix;
467
468 pix->width = mt9m111->rect.width;
469 pix->height = mt9m111->rect.height;
470 pix->pixelformat = mt9m111->pixfmt;
471 pix->field = V4L2_FIELD_NONE;
472 pix->colorspace = V4L2_COLORSPACE_SRGB;
473
474 return 0;
475}
476
415static int mt9m111_set_pixfmt(struct i2c_client *client, u32 pixfmt) 477static int mt9m111_set_pixfmt(struct i2c_client *client, u32 pixfmt)
416{ 478{
417 struct mt9m111 *mt9m111 = to_mt9m111(client); 479 struct mt9m111 *mt9m111 = to_mt9m111(client);
@@ -478,7 +540,7 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
478 __func__, pix->pixelformat, rect.left, rect.top, rect.width, 540 __func__, pix->pixelformat, rect.left, rect.top, rect.width,
479 rect.height); 541 rect.height);
480 542
481 ret = mt9m111_setup_rect(client, &rect); 543 ret = mt9m111_make_rect(client, &rect);
482 if (!ret) 544 if (!ret)
483 ret = mt9m111_set_pixfmt(client, pix->pixelformat); 545 ret = mt9m111_set_pixfmt(client, pix->pixelformat);
484 if (!ret) 546 if (!ret)
@@ -489,11 +551,27 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
489static int mt9m111_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) 551static int mt9m111_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
490{ 552{
491 struct v4l2_pix_format *pix = &f->fmt.pix; 553 struct v4l2_pix_format *pix = &f->fmt.pix;
554 bool bayer = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 ||
555 pix->pixelformat == V4L2_PIX_FMT_SBGGR16;
556
557 /*
558 * With Bayer format enforce even side lengths, but let the user play
559 * with the starting pixel
560 */
492 561
493 if (pix->height > MT9M111_MAX_HEIGHT) 562 if (pix->height > MT9M111_MAX_HEIGHT)
494 pix->height = MT9M111_MAX_HEIGHT; 563 pix->height = MT9M111_MAX_HEIGHT;
564 else if (pix->height < 2)
565 pix->height = 2;
566 else if (bayer)
567 pix->height = ALIGN(pix->height, 2);
568
495 if (pix->width > MT9M111_MAX_WIDTH) 569 if (pix->width > MT9M111_MAX_WIDTH)
496 pix->width = MT9M111_MAX_WIDTH; 570 pix->width = MT9M111_MAX_WIDTH;
571 else if (pix->width < 2)
572 pix->width = 2;
573 else if (bayer)
574 pix->width = ALIGN(pix->width, 2);
497 575
498 return 0; 576 return 0;
499} 577}
@@ -906,8 +984,11 @@ static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
906 984
907static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { 985static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
908 .s_fmt = mt9m111_s_fmt, 986 .s_fmt = mt9m111_s_fmt,
987 .g_fmt = mt9m111_g_fmt,
909 .try_fmt = mt9m111_try_fmt, 988 .try_fmt = mt9m111_try_fmt,
910 .s_crop = mt9m111_s_crop, 989 .s_crop = mt9m111_s_crop,
990 .g_crop = mt9m111_g_crop,
991 .cropcap = mt9m111_cropcap,
911}; 992};
912 993
913static struct v4l2_subdev_ops mt9m111_subdev_ops = { 994static struct v4l2_subdev_ops mt9m111_subdev_ops = {
@@ -949,16 +1030,13 @@ static int mt9m111_probe(struct i2c_client *client,
949 1030
950 /* Second stage probe - when a capture adapter is there */ 1031 /* Second stage probe - when a capture adapter is there */
951 icd->ops = &mt9m111_ops; 1032 icd->ops = &mt9m111_ops;
952 icd->rect_max.left = MT9M111_MIN_DARK_COLS;
953 icd->rect_max.top = MT9M111_MIN_DARK_ROWS;
954 icd->rect_max.width = MT9M111_MAX_WIDTH;
955 icd->rect_max.height = MT9M111_MAX_HEIGHT;
956 icd->rect_current.left = icd->rect_max.left;
957 icd->rect_current.top = icd->rect_max.top;
958 icd->width_min = MT9M111_MIN_DARK_ROWS;
959 icd->height_min = MT9M111_MIN_DARK_COLS;
960 icd->y_skip_top = 0; 1033 icd->y_skip_top = 0;
961 1034
1035 mt9m111->rect.left = MT9M111_MIN_DARK_COLS;
1036 mt9m111->rect.top = MT9M111_MIN_DARK_ROWS;
1037 mt9m111->rect.width = MT9M111_MAX_WIDTH;
1038 mt9m111->rect.height = MT9M111_MAX_HEIGHT;
1039
962 ret = mt9m111_video_probe(icd, client); 1040 ret = mt9m111_video_probe(icd, client);
963 if (ret) { 1041 if (ret) {
964 icd->ops = NULL; 1042 icd->ops = NULL;