diff options
Diffstat (limited to 'drivers/media/video/mt9m111.c')
-rw-r--r-- | drivers/media/video/mt9m111.c | 112 |
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 | ||
398 | static 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 | |||
398 | static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 421 | static 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 | ||
437 | static 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 | |||
448 | static 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 | |||
462 | static 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 | |||
415 | static int mt9m111_set_pixfmt(struct i2c_client *client, u32 pixfmt) | 477 | static 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) | |||
489 | static int mt9m111_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 551 | static 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 | ||
907 | static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { | 985 | static 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 | ||
913 | static struct v4l2_subdev_ops mt9m111_subdev_ops = { | 994 | static 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; |