diff options
Diffstat (limited to 'drivers/media/video/mt9m111.c')
-rw-r--r-- | drivers/media/video/mt9m111.c | 121 |
1 files changed, 88 insertions, 33 deletions
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index da0b2d553fd0..c89ea41fe259 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for MT9M111 CMOS Image Sensor from Micron | 2 | * Driver for MT9M111/MT9M112 CMOS Image Sensor from Micron |
3 | * | 3 | * |
4 | * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr> | 4 | * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr> |
5 | * | 5 | * |
@@ -19,7 +19,7 @@ | |||
19 | #include <media/soc_camera.h> | 19 | #include <media/soc_camera.h> |
20 | 20 | ||
21 | /* | 21 | /* |
22 | * mt9m111 i2c address is 0x5d or 0x48 (depending on SAddr pin) | 22 | * mt9m111 and mt9m112 i2c address is 0x5d or 0x48 (depending on SAddr pin) |
23 | * The platform has to define i2c_board_info and call i2c_register_board_info() | 23 | * The platform has to define i2c_board_info and call i2c_register_board_info() |
24 | */ | 24 | */ |
25 | 25 | ||
@@ -90,7 +90,7 @@ | |||
90 | #define MT9M111_OUTPUT_FORMAT_CTRL2_B 0x19b | 90 | #define MT9M111_OUTPUT_FORMAT_CTRL2_B 0x19b |
91 | 91 | ||
92 | #define MT9M111_OPMODE_AUTOEXPO_EN (1 << 14) | 92 | #define MT9M111_OPMODE_AUTOEXPO_EN (1 << 14) |
93 | 93 | #define MT9M111_OPMODE_AUTOWHITEBAL_EN (1 << 1) | |
94 | 94 | ||
95 | #define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14) | 95 | #define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14) |
96 | #define MT9M111_OUTFMT_BYPASS_IFP (1 << 10) | 96 | #define MT9M111_OUTFMT_BYPASS_IFP (1 << 10) |
@@ -128,9 +128,14 @@ | |||
128 | .colorspace = _colorspace } | 128 | .colorspace = _colorspace } |
129 | #define RGB_FMT(_name, _depth, _fourcc) \ | 129 | #define RGB_FMT(_name, _depth, _fourcc) \ |
130 | COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_SRGB) | 130 | COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_SRGB) |
131 | #define JPG_FMT(_name, _depth, _fourcc) \ | ||
132 | COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_JPEG) | ||
131 | 133 | ||
132 | static const struct soc_camera_data_format mt9m111_colour_formats[] = { | 134 | static const struct soc_camera_data_format mt9m111_colour_formats[] = { |
133 | COL_FMT("YCrYCb 8 bit", 8, V4L2_PIX_FMT_YUYV, V4L2_COLORSPACE_JPEG), | 135 | JPG_FMT("CbYCrY 16 bit", 16, V4L2_PIX_FMT_UYVY), |
136 | JPG_FMT("CrYCbY 16 bit", 16, V4L2_PIX_FMT_VYUY), | ||
137 | JPG_FMT("YCbYCr 16 bit", 16, V4L2_PIX_FMT_YUYV), | ||
138 | JPG_FMT("YCrYCb 16 bit", 16, V4L2_PIX_FMT_YVYU), | ||
134 | RGB_FMT("RGB 565", 16, V4L2_PIX_FMT_RGB565), | 139 | RGB_FMT("RGB 565", 16, V4L2_PIX_FMT_RGB565), |
135 | RGB_FMT("RGB 555", 16, V4L2_PIX_FMT_RGB555), | 140 | RGB_FMT("RGB 555", 16, V4L2_PIX_FMT_RGB555), |
136 | RGB_FMT("Bayer (sRGB) 10 bit", 10, V4L2_PIX_FMT_SBGGR16), | 141 | RGB_FMT("Bayer (sRGB) 10 bit", 10, V4L2_PIX_FMT_SBGGR16), |
@@ -145,7 +150,7 @@ enum mt9m111_context { | |||
145 | struct mt9m111 { | 150 | struct mt9m111 { |
146 | struct i2c_client *client; | 151 | struct i2c_client *client; |
147 | struct soc_camera_device icd; | 152 | struct soc_camera_device icd; |
148 | int model; /* V4L2_IDENT_MT9M111* codes from v4l2-chip-ident.h */ | 153 | int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */ |
149 | enum mt9m111_context context; | 154 | enum mt9m111_context context; |
150 | unsigned int left, top, width, height; | 155 | unsigned int left, top, width, height; |
151 | u32 pixfmt; | 156 | u32 pixfmt; |
@@ -158,6 +163,7 @@ struct mt9m111 { | |||
158 | unsigned int swap_rgb_red_blue:1; | 163 | unsigned int swap_rgb_red_blue:1; |
159 | unsigned int swap_yuv_y_chromas:1; | 164 | unsigned int swap_yuv_y_chromas:1; |
160 | unsigned int swap_yuv_cb_cr:1; | 165 | unsigned int swap_yuv_cb_cr:1; |
166 | unsigned int autowhitebalance:1; | ||
161 | }; | 167 | }; |
162 | 168 | ||
163 | static int reg_page_map_set(struct i2c_client *client, const u16 reg) | 169 | static int reg_page_map_set(struct i2c_client *client, const u16 reg) |
@@ -410,9 +416,13 @@ static int mt9m111_stop_capture(struct soc_camera_device *icd) | |||
410 | 416 | ||
411 | static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd) | 417 | static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd) |
412 | { | 418 | { |
413 | return SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING | | 419 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); |
420 | struct soc_camera_link *icl = mt9m111->client->dev.platform_data; | ||
421 | unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING | | ||
414 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | | 422 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | |
415 | SOCAM_DATAWIDTH_8; | 423 | SOCAM_DATAWIDTH_8; |
424 | |||
425 | return soc_camera_apply_sensor_flags(icl, flags); | ||
416 | } | 426 | } |
417 | 427 | ||
418 | static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f) | 428 | static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f) |
@@ -438,7 +448,24 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt) | |||
438 | case V4L2_PIX_FMT_RGB565: | 448 | case V4L2_PIX_FMT_RGB565: |
439 | ret = mt9m111_setfmt_rgb565(icd); | 449 | ret = mt9m111_setfmt_rgb565(icd); |
440 | break; | 450 | break; |
451 | case V4L2_PIX_FMT_UYVY: | ||
452 | mt9m111->swap_yuv_y_chromas = 0; | ||
453 | mt9m111->swap_yuv_cb_cr = 0; | ||
454 | ret = mt9m111_setfmt_yuv(icd); | ||
455 | break; | ||
456 | case V4L2_PIX_FMT_VYUY: | ||
457 | mt9m111->swap_yuv_y_chromas = 0; | ||
458 | mt9m111->swap_yuv_cb_cr = 1; | ||
459 | ret = mt9m111_setfmt_yuv(icd); | ||
460 | break; | ||
441 | case V4L2_PIX_FMT_YUYV: | 461 | case V4L2_PIX_FMT_YUYV: |
462 | mt9m111->swap_yuv_y_chromas = 1; | ||
463 | mt9m111->swap_yuv_cb_cr = 0; | ||
464 | ret = mt9m111_setfmt_yuv(icd); | ||
465 | break; | ||
466 | case V4L2_PIX_FMT_YVYU: | ||
467 | mt9m111->swap_yuv_y_chromas = 1; | ||
468 | mt9m111->swap_yuv_cb_cr = 1; | ||
442 | ret = mt9m111_setfmt_yuv(icd); | 469 | ret = mt9m111_setfmt_yuv(icd); |
443 | break; | 470 | break; |
444 | default: | 471 | default: |
@@ -452,8 +479,8 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt) | |||
452 | return ret; | 479 | return ret; |
453 | } | 480 | } |
454 | 481 | ||
455 | static int mt9m111_set_fmt_cap(struct soc_camera_device *icd, | 482 | static int mt9m111_set_fmt(struct soc_camera_device *icd, |
456 | __u32 pixfmt, struct v4l2_rect *rect) | 483 | __u32 pixfmt, struct v4l2_rect *rect) |
457 | { | 484 | { |
458 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | 485 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); |
459 | int ret; | 486 | int ret; |
@@ -473,13 +500,15 @@ static int mt9m111_set_fmt_cap(struct soc_camera_device *icd, | |||
473 | return ret; | 500 | return ret; |
474 | } | 501 | } |
475 | 502 | ||
476 | static int mt9m111_try_fmt_cap(struct soc_camera_device *icd, | 503 | static int mt9m111_try_fmt(struct soc_camera_device *icd, |
477 | struct v4l2_format *f) | 504 | struct v4l2_format *f) |
478 | { | 505 | { |
479 | if (f->fmt.pix.height > MT9M111_MAX_HEIGHT) | 506 | struct v4l2_pix_format *pix = &f->fmt.pix; |
480 | f->fmt.pix.height = MT9M111_MAX_HEIGHT; | 507 | |
481 | if (f->fmt.pix.width > MT9M111_MAX_WIDTH) | 508 | if (pix->height > MT9M111_MAX_HEIGHT) |
482 | f->fmt.pix.width = MT9M111_MAX_WIDTH; | 509 | pix->height = MT9M111_MAX_HEIGHT; |
510 | if (pix->width > MT9M111_MAX_WIDTH) | ||
511 | pix->width = MT9M111_MAX_WIDTH; | ||
483 | 512 | ||
484 | return 0; | 513 | return 0; |
485 | } | 514 | } |
@@ -597,8 +626,8 @@ static struct soc_camera_ops mt9m111_ops = { | |||
597 | .release = mt9m111_release, | 626 | .release = mt9m111_release, |
598 | .start_capture = mt9m111_start_capture, | 627 | .start_capture = mt9m111_start_capture, |
599 | .stop_capture = mt9m111_stop_capture, | 628 | .stop_capture = mt9m111_stop_capture, |
600 | .set_fmt_cap = mt9m111_set_fmt_cap, | 629 | .set_fmt = mt9m111_set_fmt, |
601 | .try_fmt_cap = mt9m111_try_fmt_cap, | 630 | .try_fmt = mt9m111_try_fmt, |
602 | .query_bus_param = mt9m111_query_bus_param, | 631 | .query_bus_param = mt9m111_query_bus_param, |
603 | .set_bus_param = mt9m111_set_bus_param, | 632 | .set_bus_param = mt9m111_set_bus_param, |
604 | .controls = mt9m111_controls, | 633 | .controls = mt9m111_controls, |
@@ -634,18 +663,15 @@ static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask) | |||
634 | 663 | ||
635 | static int mt9m111_get_global_gain(struct soc_camera_device *icd) | 664 | static int mt9m111_get_global_gain(struct soc_camera_device *icd) |
636 | { | 665 | { |
637 | unsigned int data, gain; | 666 | int data; |
638 | 667 | ||
639 | data = reg_read(GLOBAL_GAIN); | 668 | data = reg_read(GLOBAL_GAIN); |
640 | if (data >= 0) | 669 | if (data >= 0) |
641 | gain = ((data & (1 << 10)) * 2) | 670 | return (data & 0x2f) * (1 << ((data >> 10) & 1)) * |
642 | | ((data & (1 << 9)) * 2) | 671 | (1 << ((data >> 9) & 1)); |
643 | | (data & 0x2f); | 672 | return data; |
644 | else | ||
645 | gain = data; | ||
646 | |||
647 | return gain; | ||
648 | } | 673 | } |
674 | |||
649 | static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain) | 675 | static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain) |
650 | { | 676 | { |
651 | u16 val; | 677 | u16 val; |
@@ -679,6 +705,23 @@ static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on) | |||
679 | 705 | ||
680 | return ret; | 706 | return ret; |
681 | } | 707 | } |
708 | |||
709 | static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on) | ||
710 | { | ||
711 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
712 | int ret; | ||
713 | |||
714 | if (on) | ||
715 | ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); | ||
716 | else | ||
717 | ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); | ||
718 | |||
719 | if (!ret) | ||
720 | mt9m111->autowhitebalance = on; | ||
721 | |||
722 | return ret; | ||
723 | } | ||
724 | |||
682 | static int mt9m111_get_control(struct soc_camera_device *icd, | 725 | static int mt9m111_get_control(struct soc_camera_device *icd, |
683 | struct v4l2_control *ctrl) | 726 | struct v4l2_control *ctrl) |
684 | { | 727 | { |
@@ -715,6 +758,9 @@ static int mt9m111_get_control(struct soc_camera_device *icd, | |||
715 | case V4L2_CID_EXPOSURE_AUTO: | 758 | case V4L2_CID_EXPOSURE_AUTO: |
716 | ctrl->value = mt9m111->autoexposure; | 759 | ctrl->value = mt9m111->autoexposure; |
717 | break; | 760 | break; |
761 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
762 | ctrl->value = mt9m111->autowhitebalance; | ||
763 | break; | ||
718 | } | 764 | } |
719 | return 0; | 765 | return 0; |
720 | } | 766 | } |
@@ -748,6 +794,9 @@ static int mt9m111_set_control(struct soc_camera_device *icd, | |||
748 | case V4L2_CID_EXPOSURE_AUTO: | 794 | case V4L2_CID_EXPOSURE_AUTO: |
749 | ret = mt9m111_set_autoexposure(icd, ctrl->value); | 795 | ret = mt9m111_set_autoexposure(icd, ctrl->value); |
750 | break; | 796 | break; |
797 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
798 | ret = mt9m111_set_autowhitebalance(icd, ctrl->value); | ||
799 | break; | ||
751 | default: | 800 | default: |
752 | ret = -EINVAL; | 801 | ret = -EINVAL; |
753 | } | 802 | } |
@@ -766,6 +815,7 @@ static int mt9m111_restore_state(struct soc_camera_device *icd) | |||
766 | mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); | 815 | mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); |
767 | mt9m111_set_global_gain(icd, icd->gain); | 816 | mt9m111_set_global_gain(icd, icd->gain); |
768 | mt9m111_set_autoexposure(icd, mt9m111->autoexposure); | 817 | mt9m111_set_autoexposure(icd, mt9m111->autoexposure); |
818 | mt9m111_set_autowhitebalance(icd, mt9m111->autowhitebalance); | ||
769 | return 0; | 819 | return 0; |
770 | } | 820 | } |
771 | 821 | ||
@@ -798,7 +848,7 @@ static int mt9m111_init(struct soc_camera_device *icd) | |||
798 | if (!ret) | 848 | if (!ret) |
799 | ret = mt9m111_set_autoexposure(icd, mt9m111->autoexposure); | 849 | ret = mt9m111_set_autoexposure(icd, mt9m111->autoexposure); |
800 | if (ret) | 850 | if (ret) |
801 | dev_err(&icd->dev, "mt9m111 init failed: %d\n", ret); | 851 | dev_err(&icd->dev, "mt9m11x init failed: %d\n", ret); |
802 | return ret; | 852 | return ret; |
803 | } | 853 | } |
804 | 854 | ||
@@ -808,7 +858,7 @@ static int mt9m111_release(struct soc_camera_device *icd) | |||
808 | 858 | ||
809 | ret = mt9m111_disable(icd); | 859 | ret = mt9m111_disable(icd); |
810 | if (ret < 0) | 860 | if (ret < 0) |
811 | dev_err(&icd->dev, "mt9m111 release failed: %d\n", ret); | 861 | dev_err(&icd->dev, "mt9m11x release failed: %d\n", ret); |
812 | 862 | ||
813 | return ret; | 863 | return ret; |
814 | } | 864 | } |
@@ -841,25 +891,30 @@ static int mt9m111_video_probe(struct soc_camera_device *icd) | |||
841 | data = reg_read(CHIP_VERSION); | 891 | data = reg_read(CHIP_VERSION); |
842 | 892 | ||
843 | switch (data) { | 893 | switch (data) { |
844 | case 0x143a: | 894 | case 0x143a: /* MT9M111 */ |
845 | mt9m111->model = V4L2_IDENT_MT9M111; | 895 | mt9m111->model = V4L2_IDENT_MT9M111; |
846 | icd->formats = mt9m111_colour_formats; | 896 | break; |
847 | icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats); | 897 | case 0x148c: /* MT9M112 */ |
898 | mt9m111->model = V4L2_IDENT_MT9M112; | ||
848 | break; | 899 | break; |
849 | default: | 900 | default: |
850 | ret = -ENODEV; | 901 | ret = -ENODEV; |
851 | dev_err(&icd->dev, | 902 | dev_err(&icd->dev, |
852 | "No MT9M111 chip detected, register read %x\n", data); | 903 | "No MT9M11x chip detected, register read %x\n", data); |
853 | goto ei2c; | 904 | goto ei2c; |
854 | } | 905 | } |
855 | 906 | ||
856 | dev_info(&icd->dev, "Detected a MT9M111 chip ID 0x143a\n"); | 907 | icd->formats = mt9m111_colour_formats; |
908 | icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats); | ||
909 | |||
910 | dev_info(&icd->dev, "Detected a MT9M11x chip ID %x\n", data); | ||
857 | 911 | ||
858 | ret = soc_camera_video_start(icd); | 912 | ret = soc_camera_video_start(icd); |
859 | if (ret) | 913 | if (ret) |
860 | goto eisis; | 914 | goto eisis; |
861 | 915 | ||
862 | mt9m111->autoexposure = 1; | 916 | mt9m111->autoexposure = 1; |
917 | mt9m111->autowhitebalance = 1; | ||
863 | 918 | ||
864 | mt9m111->swap_rgb_even_odd = 1; | 919 | mt9m111->swap_rgb_even_odd = 1; |
865 | mt9m111->swap_rgb_red_blue = 1; | 920 | mt9m111->swap_rgb_red_blue = 1; |
@@ -889,7 +944,7 @@ static int mt9m111_probe(struct i2c_client *client, | |||
889 | int ret; | 944 | int ret; |
890 | 945 | ||
891 | if (!icl) { | 946 | if (!icl) { |
892 | dev_err(&client->dev, "MT9M111 driver needs platform data\n"); | 947 | dev_err(&client->dev, "MT9M11x driver needs platform data\n"); |
893 | return -EINVAL; | 948 | return -EINVAL; |
894 | } | 949 | } |
895 | 950 | ||
@@ -968,6 +1023,6 @@ static void __exit mt9m111_mod_exit(void) | |||
968 | module_init(mt9m111_mod_init); | 1023 | module_init(mt9m111_mod_init); |
969 | module_exit(mt9m111_mod_exit); | 1024 | module_exit(mt9m111_mod_exit); |
970 | 1025 | ||
971 | MODULE_DESCRIPTION("Micron MT9M111 Camera driver"); | 1026 | MODULE_DESCRIPTION("Micron MT9M111/MT9M112 Camera driver"); |
972 | MODULE_AUTHOR("Robert Jarzmik"); | 1027 | MODULE_AUTHOR("Robert Jarzmik"); |
973 | MODULE_LICENSE("GPL"); | 1028 | MODULE_LICENSE("GPL"); |