diff options
Diffstat (limited to 'drivers/media/video/mt9v022.c')
-rw-r--r-- | drivers/media/video/mt9v022.c | 228 |
1 files changed, 144 insertions, 84 deletions
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 995607f9d3ba..91df7ec91fb6 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c | |||
@@ -18,9 +18,11 @@ | |||
18 | #include <media/v4l2-chip-ident.h> | 18 | #include <media/v4l2-chip-ident.h> |
19 | #include <media/soc_camera.h> | 19 | #include <media/soc_camera.h> |
20 | 20 | ||
21 | /* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c | 21 | /* |
22 | * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c | ||
22 | * The platform has to define ctruct i2c_board_info objects and link to them | 23 | * The platform has to define ctruct i2c_board_info objects and link to them |
23 | * from struct soc_camera_link */ | 24 | * from struct soc_camera_link |
25 | */ | ||
24 | 26 | ||
25 | static char *sensor_type; | 27 | static char *sensor_type; |
26 | module_param(sensor_type, charp, S_IRUGO); | 28 | module_param(sensor_type, charp, S_IRUGO); |
@@ -62,41 +64,49 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); | |||
62 | #define MT9V022_COLUMN_SKIP 1 | 64 | #define MT9V022_COLUMN_SKIP 1 |
63 | #define MT9V022_ROW_SKIP 4 | 65 | #define MT9V022_ROW_SKIP 4 |
64 | 66 | ||
65 | static const struct soc_camera_data_format mt9v022_colour_formats[] = { | 67 | /* MT9V022 has only one fixed colorspace per pixelcode */ |
66 | /* Order important: first natively supported, | 68 | struct mt9v022_datafmt { |
67 | * second supported with a GPIO extender */ | 69 | enum v4l2_mbus_pixelcode code; |
68 | { | 70 | enum v4l2_colorspace colorspace; |
69 | .name = "Bayer (sRGB) 10 bit", | 71 | }; |
70 | .depth = 10, | 72 | |
71 | .fourcc = V4L2_PIX_FMT_SBGGR16, | 73 | /* Find a data format by a pixel code in an array */ |
72 | .colorspace = V4L2_COLORSPACE_SRGB, | 74 | static const struct mt9v022_datafmt *mt9v022_find_datafmt( |
73 | }, { | 75 | enum v4l2_mbus_pixelcode code, const struct mt9v022_datafmt *fmt, |
74 | .name = "Bayer (sRGB) 8 bit", | 76 | int n) |
75 | .depth = 8, | 77 | { |
76 | .fourcc = V4L2_PIX_FMT_SBGGR8, | 78 | int i; |
77 | .colorspace = V4L2_COLORSPACE_SRGB, | 79 | for (i = 0; i < n; i++) |
78 | } | 80 | if (fmt[i].code == code) |
81 | return fmt + i; | ||
82 | |||
83 | return NULL; | ||
84 | } | ||
85 | |||
86 | static const struct mt9v022_datafmt mt9v022_colour_fmts[] = { | ||
87 | /* | ||
88 | * Order important: first natively supported, | ||
89 | * second supported with a GPIO extender | ||
90 | */ | ||
91 | {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, | ||
92 | {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, | ||
79 | }; | 93 | }; |
80 | 94 | ||
81 | static const struct soc_camera_data_format mt9v022_monochrome_formats[] = { | 95 | static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = { |
82 | /* Order important - see above */ | 96 | /* Order important - see above */ |
83 | { | 97 | {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG}, |
84 | .name = "Monochrome 10 bit", | 98 | {V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG}, |
85 | .depth = 10, | ||
86 | .fourcc = V4L2_PIX_FMT_Y16, | ||
87 | }, { | ||
88 | .name = "Monochrome 8 bit", | ||
89 | .depth = 8, | ||
90 | .fourcc = V4L2_PIX_FMT_GREY, | ||
91 | }, | ||
92 | }; | 99 | }; |
93 | 100 | ||
94 | struct mt9v022 { | 101 | struct mt9v022 { |
95 | struct v4l2_subdev subdev; | 102 | struct v4l2_subdev subdev; |
96 | struct v4l2_rect rect; /* Sensor window */ | 103 | struct v4l2_rect rect; /* Sensor window */ |
97 | __u32 fourcc; | 104 | const struct mt9v022_datafmt *fmt; |
105 | const struct mt9v022_datafmt *fmts; | ||
106 | int num_fmts; | ||
98 | int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ | 107 | int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ |
99 | u16 chip_control; | 108 | u16 chip_control; |
109 | unsigned short y_skip_top; /* Lines to skip at the top */ | ||
100 | }; | 110 | }; |
101 | 111 | ||
102 | static struct mt9v022 *to_mt9v022(const struct i2c_client *client) | 112 | static struct mt9v022 *to_mt9v022(const struct i2c_client *client) |
@@ -143,9 +153,11 @@ static int mt9v022_init(struct i2c_client *client) | |||
143 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 153 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
144 | int ret; | 154 | int ret; |
145 | 155 | ||
146 | /* Almost the default mode: master, parallel, simultaneous, and an | 156 | /* |
157 | * Almost the default mode: master, parallel, simultaneous, and an | ||
147 | * undocumented bit 0x200, which is present in table 7, but not in 8, | 158 | * undocumented bit 0x200, which is present in table 7, but not in 8, |
148 | * plus snapshot mode to disable scan for now */ | 159 | * plus snapshot mode to disable scan for now |
160 | */ | ||
149 | mt9v022->chip_control |= 0x10; | 161 | mt9v022->chip_control |= 0x10; |
150 | ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); | 162 | ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); |
151 | if (!ret) | 163 | if (!ret) |
@@ -265,12 +277,10 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
265 | struct i2c_client *client = sd->priv; | 277 | struct i2c_client *client = sd->priv; |
266 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 278 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
267 | struct v4l2_rect rect = a->c; | 279 | struct v4l2_rect rect = a->c; |
268 | struct soc_camera_device *icd = client->dev.platform_data; | ||
269 | int ret; | 280 | int ret; |
270 | 281 | ||
271 | /* Bayer format - even size lengths */ | 282 | /* Bayer format - even size lengths */ |
272 | if (mt9v022->fourcc == V4L2_PIX_FMT_SBGGR8 || | 283 | if (mt9v022->fmts == mt9v022_colour_fmts) { |
273 | mt9v022->fourcc == V4L2_PIX_FMT_SBGGR16) { | ||
274 | rect.width = ALIGN(rect.width, 2); | 284 | rect.width = ALIGN(rect.width, 2); |
275 | rect.height = ALIGN(rect.height, 2); | 285 | rect.height = ALIGN(rect.height, 2); |
276 | /* Let the user play with the starting pixel */ | 286 | /* Let the user play with the starting pixel */ |
@@ -287,10 +297,10 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
287 | if (ret >= 0) { | 297 | if (ret >= 0) { |
288 | if (ret & 1) /* Autoexposure */ | 298 | if (ret & 1) /* Autoexposure */ |
289 | ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, | 299 | ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, |
290 | rect.height + icd->y_skip_top + 43); | 300 | rect.height + mt9v022->y_skip_top + 43); |
291 | else | 301 | else |
292 | ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, | 302 | ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, |
293 | rect.height + icd->y_skip_top + 43); | 303 | rect.height + mt9v022->y_skip_top + 43); |
294 | } | 304 | } |
295 | /* Setup frame format: defaults apart from width and height */ | 305 | /* Setup frame format: defaults apart from width and height */ |
296 | if (!ret) | 306 | if (!ret) |
@@ -298,8 +308,10 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
298 | if (!ret) | 308 | if (!ret) |
299 | ret = reg_write(client, MT9V022_ROW_START, rect.top); | 309 | ret = reg_write(client, MT9V022_ROW_START, rect.top); |
300 | if (!ret) | 310 | if (!ret) |
301 | /* Default 94, Phytec driver says: | 311 | /* |
302 | * "width + horizontal blank >= 660" */ | 312 | * Default 94, Phytec driver says: |
313 | * "width + horizontal blank >= 660" | ||
314 | */ | ||
303 | ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, | 315 | ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, |
304 | rect.width > 660 - 43 ? 43 : | 316 | rect.width > 660 - 43 ? 43 : |
305 | 660 - rect.width); | 317 | 660 - rect.width); |
@@ -309,7 +321,7 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
309 | ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width); | 321 | ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width); |
310 | if (!ret) | 322 | if (!ret) |
311 | ret = reg_write(client, MT9V022_WINDOW_HEIGHT, | 323 | ret = reg_write(client, MT9V022_WINDOW_HEIGHT, |
312 | rect.height + icd->y_skip_top); | 324 | rect.height + mt9v022->y_skip_top); |
313 | 325 | ||
314 | if (ret < 0) | 326 | if (ret < 0) |
315 | return ret; | 327 | return ret; |
@@ -346,46 +358,48 @@ static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
346 | return 0; | 358 | return 0; |
347 | } | 359 | } |
348 | 360 | ||
349 | static int mt9v022_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 361 | static int mt9v022_g_fmt(struct v4l2_subdev *sd, |
362 | struct v4l2_mbus_framefmt *mf) | ||
350 | { | 363 | { |
351 | struct i2c_client *client = sd->priv; | 364 | struct i2c_client *client = sd->priv; |
352 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 365 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
353 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
354 | 366 | ||
355 | pix->width = mt9v022->rect.width; | 367 | mf->width = mt9v022->rect.width; |
356 | pix->height = mt9v022->rect.height; | 368 | mf->height = mt9v022->rect.height; |
357 | pix->pixelformat = mt9v022->fourcc; | 369 | mf->code = mt9v022->fmt->code; |
358 | pix->field = V4L2_FIELD_NONE; | 370 | mf->colorspace = mt9v022->fmt->colorspace; |
359 | pix->colorspace = V4L2_COLORSPACE_SRGB; | 371 | mf->field = V4L2_FIELD_NONE; |
360 | 372 | ||
361 | return 0; | 373 | return 0; |
362 | } | 374 | } |
363 | 375 | ||
364 | static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 376 | static int mt9v022_s_fmt(struct v4l2_subdev *sd, |
377 | struct v4l2_mbus_framefmt *mf) | ||
365 | { | 378 | { |
366 | struct i2c_client *client = sd->priv; | 379 | struct i2c_client *client = sd->priv; |
367 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 380 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
368 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
369 | struct v4l2_crop a = { | 381 | struct v4l2_crop a = { |
370 | .c = { | 382 | .c = { |
371 | .left = mt9v022->rect.left, | 383 | .left = mt9v022->rect.left, |
372 | .top = mt9v022->rect.top, | 384 | .top = mt9v022->rect.top, |
373 | .width = pix->width, | 385 | .width = mf->width, |
374 | .height = pix->height, | 386 | .height = mf->height, |
375 | }, | 387 | }, |
376 | }; | 388 | }; |
377 | int ret; | 389 | int ret; |
378 | 390 | ||
379 | /* The caller provides a supported format, as verified per call to | 391 | /* |
380 | * icd->try_fmt(), datawidth is from our supported format list */ | 392 | * The caller provides a supported format, as verified per call to |
381 | switch (pix->pixelformat) { | 393 | * icd->try_fmt(), datawidth is from our supported format list |
382 | case V4L2_PIX_FMT_GREY: | 394 | */ |
383 | case V4L2_PIX_FMT_Y16: | 395 | switch (mf->code) { |
396 | case V4L2_MBUS_FMT_GREY8_1X8: | ||
397 | case V4L2_MBUS_FMT_Y10_1X10: | ||
384 | if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM) | 398 | if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM) |
385 | return -EINVAL; | 399 | return -EINVAL; |
386 | break; | 400 | break; |
387 | case V4L2_PIX_FMT_SBGGR8: | 401 | case V4L2_MBUS_FMT_SBGGR8_1X8: |
388 | case V4L2_PIX_FMT_SBGGR16: | 402 | case V4L2_MBUS_FMT_SBGGR10_1X10: |
389 | if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC) | 403 | if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC) |
390 | return -EINVAL; | 404 | return -EINVAL; |
391 | break; | 405 | break; |
@@ -399,26 +413,38 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | |||
399 | /* No support for scaling on this camera, just crop. */ | 413 | /* No support for scaling on this camera, just crop. */ |
400 | ret = mt9v022_s_crop(sd, &a); | 414 | ret = mt9v022_s_crop(sd, &a); |
401 | if (!ret) { | 415 | if (!ret) { |
402 | pix->width = mt9v022->rect.width; | 416 | mf->width = mt9v022->rect.width; |
403 | pix->height = mt9v022->rect.height; | 417 | mf->height = mt9v022->rect.height; |
404 | mt9v022->fourcc = pix->pixelformat; | 418 | mt9v022->fmt = mt9v022_find_datafmt(mf->code, |
419 | mt9v022->fmts, mt9v022->num_fmts); | ||
420 | mf->colorspace = mt9v022->fmt->colorspace; | ||
405 | } | 421 | } |
406 | 422 | ||
407 | return ret; | 423 | return ret; |
408 | } | 424 | } |
409 | 425 | ||
410 | static int mt9v022_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | 426 | static int mt9v022_try_fmt(struct v4l2_subdev *sd, |
427 | struct v4l2_mbus_framefmt *mf) | ||
411 | { | 428 | { |
412 | struct i2c_client *client = sd->priv; | 429 | struct i2c_client *client = sd->priv; |
413 | struct soc_camera_device *icd = client->dev.platform_data; | 430 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
414 | struct v4l2_pix_format *pix = &f->fmt.pix; | 431 | const struct mt9v022_datafmt *fmt; |
415 | int align = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 || | 432 | int align = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 || |
416 | pix->pixelformat == V4L2_PIX_FMT_SBGGR16; | 433 | mf->code == V4L2_MBUS_FMT_SBGGR10_1X10; |
417 | 434 | ||
418 | v4l_bound_align_image(&pix->width, MT9V022_MIN_WIDTH, | 435 | v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH, |
419 | MT9V022_MAX_WIDTH, align, | 436 | MT9V022_MAX_WIDTH, align, |
420 | &pix->height, MT9V022_MIN_HEIGHT + icd->y_skip_top, | 437 | &mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top, |
421 | MT9V022_MAX_HEIGHT + icd->y_skip_top, align, 0); | 438 | MT9V022_MAX_HEIGHT + mt9v022->y_skip_top, align, 0); |
439 | |||
440 | fmt = mt9v022_find_datafmt(mf->code, mt9v022->fmts, | ||
441 | mt9v022->num_fmts); | ||
442 | if (!fmt) { | ||
443 | fmt = mt9v022->fmt; | ||
444 | mf->code = fmt->code; | ||
445 | } | ||
446 | |||
447 | mf->colorspace = fmt->colorspace; | ||
422 | 448 | ||
423 | return 0; | 449 | return 0; |
424 | } | 450 | } |
@@ -635,8 +661,10 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
635 | 48 + range / 2) / range + 16; | 661 | 48 + range / 2) / range + 16; |
636 | if (gain >= 32) | 662 | if (gain >= 32) |
637 | gain &= ~1; | 663 | gain &= ~1; |
638 | /* The user wants to set gain manually, hope, she | 664 | /* |
639 | * knows, what she's doing... Switch AGC off. */ | 665 | * The user wants to set gain manually, hope, she |
666 | * knows, what she's doing... Switch AGC off. | ||
667 | */ | ||
640 | 668 | ||
641 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) | 669 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) |
642 | return -EIO; | 670 | return -EIO; |
@@ -655,8 +683,10 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
655 | unsigned long range = qctrl->maximum - qctrl->minimum; | 683 | unsigned long range = qctrl->maximum - qctrl->minimum; |
656 | unsigned long shutter = ((ctrl->value - qctrl->minimum) * | 684 | unsigned long shutter = ((ctrl->value - qctrl->minimum) * |
657 | 479 + range / 2) / range + 1; | 685 | 479 + range / 2) / range + 1; |
658 | /* The user wants to set shutter width manually, hope, | 686 | /* |
659 | * she knows, what she's doing... Switch AEC off. */ | 687 | * The user wants to set shutter width manually, hope, |
688 | * she knows, what she's doing... Switch AEC off. | ||
689 | */ | ||
660 | 690 | ||
661 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) | 691 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) |
662 | return -EIO; | 692 | return -EIO; |
@@ -689,8 +719,10 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
689 | return 0; | 719 | return 0; |
690 | } | 720 | } |
691 | 721 | ||
692 | /* Interface active, can use i2c. If it fails, it can indeed mean, that | 722 | /* |
693 | * this wasn't our capture interface, so, we wait for the right one */ | 723 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
724 | * this wasn't our capture interface, so, we wait for the right one | ||
725 | */ | ||
694 | static int mt9v022_video_probe(struct soc_camera_device *icd, | 726 | static int mt9v022_video_probe(struct soc_camera_device *icd, |
695 | struct i2c_client *client) | 727 | struct i2c_client *client) |
696 | { | 728 | { |
@@ -733,17 +765,17 @@ static int mt9v022_video_probe(struct soc_camera_device *icd, | |||
733 | !strcmp("color", sensor_type))) { | 765 | !strcmp("color", sensor_type))) { |
734 | ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11); | 766 | ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11); |
735 | mt9v022->model = V4L2_IDENT_MT9V022IX7ATC; | 767 | mt9v022->model = V4L2_IDENT_MT9V022IX7ATC; |
736 | icd->formats = mt9v022_colour_formats; | 768 | mt9v022->fmts = mt9v022_colour_fmts; |
737 | } else { | 769 | } else { |
738 | ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11); | 770 | ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11); |
739 | mt9v022->model = V4L2_IDENT_MT9V022IX7ATM; | 771 | mt9v022->model = V4L2_IDENT_MT9V022IX7ATM; |
740 | icd->formats = mt9v022_monochrome_formats; | 772 | mt9v022->fmts = mt9v022_monochrome_fmts; |
741 | } | 773 | } |
742 | 774 | ||
743 | if (ret < 0) | 775 | if (ret < 0) |
744 | goto ei2c; | 776 | goto ei2c; |
745 | 777 | ||
746 | icd->num_formats = 0; | 778 | mt9v022->num_fmts = 0; |
747 | 779 | ||
748 | /* | 780 | /* |
749 | * This is a 10bit sensor, so by default we only allow 10bit. | 781 | * This is a 10bit sensor, so by default we only allow 10bit. |
@@ -756,14 +788,14 @@ static int mt9v022_video_probe(struct soc_camera_device *icd, | |||
756 | flags = SOCAM_DATAWIDTH_10; | 788 | flags = SOCAM_DATAWIDTH_10; |
757 | 789 | ||
758 | if (flags & SOCAM_DATAWIDTH_10) | 790 | if (flags & SOCAM_DATAWIDTH_10) |
759 | icd->num_formats++; | 791 | mt9v022->num_fmts++; |
760 | else | 792 | else |
761 | icd->formats++; | 793 | mt9v022->fmts++; |
762 | 794 | ||
763 | if (flags & SOCAM_DATAWIDTH_8) | 795 | if (flags & SOCAM_DATAWIDTH_8) |
764 | icd->num_formats++; | 796 | mt9v022->num_fmts++; |
765 | 797 | ||
766 | mt9v022->fourcc = icd->formats->fourcc; | 798 | mt9v022->fmt = &mt9v022->fmts[0]; |
767 | 799 | ||
768 | dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", | 800 | dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", |
769 | data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? | 801 | data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? |
@@ -787,6 +819,16 @@ static void mt9v022_video_remove(struct soc_camera_device *icd) | |||
787 | icl->free_bus(icl); | 819 | icl->free_bus(icl); |
788 | } | 820 | } |
789 | 821 | ||
822 | static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | ||
823 | { | ||
824 | struct i2c_client *client = sd->priv; | ||
825 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
826 | |||
827 | *lines = mt9v022->y_skip_top; | ||
828 | |||
829 | return 0; | ||
830 | } | ||
831 | |||
790 | static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { | 832 | static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { |
791 | .g_ctrl = mt9v022_g_ctrl, | 833 | .g_ctrl = mt9v022_g_ctrl, |
792 | .s_ctrl = mt9v022_s_ctrl, | 834 | .s_ctrl = mt9v022_s_ctrl, |
@@ -797,19 +839,38 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { | |||
797 | #endif | 839 | #endif |
798 | }; | 840 | }; |
799 | 841 | ||
842 | static int mt9v022_enum_fmt(struct v4l2_subdev *sd, int index, | ||
843 | enum v4l2_mbus_pixelcode *code) | ||
844 | { | ||
845 | struct i2c_client *client = sd->priv; | ||
846 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
847 | |||
848 | if ((unsigned int)index >= mt9v022->num_fmts) | ||
849 | return -EINVAL; | ||
850 | |||
851 | *code = mt9v022->fmts[index].code; | ||
852 | return 0; | ||
853 | } | ||
854 | |||
800 | static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { | 855 | static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { |
801 | .s_stream = mt9v022_s_stream, | 856 | .s_stream = mt9v022_s_stream, |
802 | .s_fmt = mt9v022_s_fmt, | 857 | .s_mbus_fmt = mt9v022_s_fmt, |
803 | .g_fmt = mt9v022_g_fmt, | 858 | .g_mbus_fmt = mt9v022_g_fmt, |
804 | .try_fmt = mt9v022_try_fmt, | 859 | .try_mbus_fmt = mt9v022_try_fmt, |
805 | .s_crop = mt9v022_s_crop, | 860 | .s_crop = mt9v022_s_crop, |
806 | .g_crop = mt9v022_g_crop, | 861 | .g_crop = mt9v022_g_crop, |
807 | .cropcap = mt9v022_cropcap, | 862 | .cropcap = mt9v022_cropcap, |
863 | .enum_mbus_fmt = mt9v022_enum_fmt, | ||
864 | }; | ||
865 | |||
866 | static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { | ||
867 | .g_skip_top_lines = mt9v022_g_skip_top_lines, | ||
808 | }; | 868 | }; |
809 | 869 | ||
810 | static struct v4l2_subdev_ops mt9v022_subdev_ops = { | 870 | static struct v4l2_subdev_ops mt9v022_subdev_ops = { |
811 | .core = &mt9v022_subdev_core_ops, | 871 | .core = &mt9v022_subdev_core_ops, |
812 | .video = &mt9v022_subdev_video_ops, | 872 | .video = &mt9v022_subdev_video_ops, |
873 | .sensor = &mt9v022_subdev_sensor_ops, | ||
813 | }; | 874 | }; |
814 | 875 | ||
815 | static int mt9v022_probe(struct i2c_client *client, | 876 | static int mt9v022_probe(struct i2c_client *client, |
@@ -851,8 +912,7 @@ static int mt9v022_probe(struct i2c_client *client, | |||
851 | * MT9V022 _really_ corrupts the first read out line. | 912 | * MT9V022 _really_ corrupts the first read out line. |
852 | * TODO: verify on i.MX31 | 913 | * TODO: verify on i.MX31 |
853 | */ | 914 | */ |
854 | icd->y_skip_top = 1; | 915 | mt9v022->y_skip_top = 1; |
855 | |||
856 | mt9v022->rect.left = MT9V022_COLUMN_SKIP; | 916 | mt9v022->rect.left = MT9V022_COLUMN_SKIP; |
857 | mt9v022->rect.top = MT9V022_ROW_SKIP; | 917 | mt9v022->rect.top = MT9V022_ROW_SKIP; |
858 | mt9v022->rect.width = MT9V022_MAX_WIDTH; | 918 | mt9v022->rect.width = MT9V022_MAX_WIDTH; |