diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-04 10:58:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-04 10:58:25 -0400 |
commit | 1046a2c428bedd64c960dcfd0c57cc69a82fea2f (patch) | |
tree | d34b83e0ac61b51305cece031f7ff49579e3fe76 /drivers/media/video/mt9m111.c | |
parent | 46e85f5f1c2a1d106c1ec0fa2a06280276b8e052 (diff) | |
parent | b3f4e1eba45eda5d1213810ef3bc53e5247df2df (diff) |
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (144 commits)
[media] saa7134.h: Suppress compiler warnings when CONFIG_VIDEO_SAA7134_RC is not set
[media] it913x [VER 1.07] Support for single ITE 9135 devices
[media] Support for Terratec G1
[media] cx25821: off by one in cx25821_vidioc_s_input()
[media] media: tea5764: reconcile Kconfig symbol and macro
[media] omap_vout: Add poll() support
[media] omap3isp: preview: Add crop support on the sink pad
[media] omap3isp: preview: Rename min/max input/output sizes defines
[media] omap3isp: preview: Remove horizontal averager support
[media] omap3isp: Report the ISP revision through the media controller API
[media] omap3isp: ccdc: remove redundant operation
[media] omap3isp: Fix memory leaks in initialization error paths
[media] omap3isp: Add missing mutex_destroy() calls
[media] omap3isp: Move *_init_entities() functions to the init/cleanup section
[media] omap3isp: Move media_entity_cleanup() from unregister() to cleanup()
[media] MFC: Change MFC firmware binary name
[media] vb2: add vb2_get_unmapped_area in vb2 core
[media] v4l: Add v4l2 subdev driver for S5K6AAFX sensor
[media] v4l: Add AUTO option for the V4L2_CID_POWER_LINE_FREQUENCY control
[media] media: ov6650: stylistic improvements
...
Diffstat (limited to 'drivers/media/video/mt9m111.c')
-rw-r--r-- | drivers/media/video/mt9m111.c | 260 |
1 files changed, 70 insertions, 190 deletions
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 07af26e6beb..f023cc092c2 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c | |||
@@ -13,10 +13,12 @@ | |||
13 | #include <linux/log2.h> | 13 | #include <linux/log2.h> |
14 | #include <linux/gpio.h> | 14 | #include <linux/gpio.h> |
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/v4l2-mediabus.h> | ||
16 | 17 | ||
18 | #include <media/soc_camera.h> | ||
17 | #include <media/v4l2-common.h> | 19 | #include <media/v4l2-common.h> |
20 | #include <media/v4l2-ctrls.h> | ||
18 | #include <media/v4l2-chip-ident.h> | 21 | #include <media/v4l2-chip-ident.h> |
19 | #include <media/soc_camera.h> | ||
20 | 22 | ||
21 | /* | 23 | /* |
22 | * MT9M111, MT9M112 and MT9M131: | 24 | * MT9M111, MT9M112 and MT9M131: |
@@ -177,6 +179,8 @@ enum mt9m111_context { | |||
177 | 179 | ||
178 | struct mt9m111 { | 180 | struct mt9m111 { |
179 | struct v4l2_subdev subdev; | 181 | struct v4l2_subdev subdev; |
182 | struct v4l2_ctrl_handler hdl; | ||
183 | struct v4l2_ctrl *gain; | ||
180 | int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code | 184 | int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code |
181 | * from v4l2-chip-ident.h */ | 185 | * from v4l2-chip-ident.h */ |
182 | enum mt9m111_context context; | 186 | enum mt9m111_context context; |
@@ -185,13 +189,8 @@ struct mt9m111 { | |||
185 | int power_count; | 189 | int power_count; |
186 | const struct mt9m111_datafmt *fmt; | 190 | const struct mt9m111_datafmt *fmt; |
187 | int lastpage; /* PageMap cache value */ | 191 | int lastpage; /* PageMap cache value */ |
188 | unsigned int gain; | ||
189 | unsigned char autoexposure; | ||
190 | unsigned char datawidth; | 192 | unsigned char datawidth; |
191 | unsigned int powered:1; | 193 | unsigned int powered:1; |
192 | unsigned int hflip:1; | ||
193 | unsigned int vflip:1; | ||
194 | unsigned int autowhitebalance:1; | ||
195 | }; | 194 | }; |
196 | 195 | ||
197 | static struct mt9m111 *to_mt9m111(const struct i2c_client *client) | 196 | static struct mt9m111 *to_mt9m111(const struct i2c_client *client) |
@@ -363,21 +362,6 @@ static int mt9m111_reset(struct mt9m111 *mt9m111) | |||
363 | return ret; | 362 | return ret; |
364 | } | 363 | } |
365 | 364 | ||
366 | static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd) | ||
367 | { | ||
368 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
369 | unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING | | ||
370 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | | ||
371 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; | ||
372 | |||
373 | return soc_camera_apply_sensor_flags(icl, flags); | ||
374 | } | ||
375 | |||
376 | static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f) | ||
377 | { | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | static int mt9m111_make_rect(struct mt9m111 *mt9m111, | 365 | static int mt9m111_make_rect(struct mt9m111 *mt9m111, |
382 | struct v4l2_rect *rect) | 366 | struct v4l2_rect *rect) |
383 | { | 367 | { |
@@ -660,50 +644,6 @@ static int mt9m111_s_register(struct v4l2_subdev *sd, | |||
660 | } | 644 | } |
661 | #endif | 645 | #endif |
662 | 646 | ||
663 | static const struct v4l2_queryctrl mt9m111_controls[] = { | ||
664 | { | ||
665 | .id = V4L2_CID_VFLIP, | ||
666 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
667 | .name = "Flip Verticaly", | ||
668 | .minimum = 0, | ||
669 | .maximum = 1, | ||
670 | .step = 1, | ||
671 | .default_value = 0, | ||
672 | }, { | ||
673 | .id = V4L2_CID_HFLIP, | ||
674 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
675 | .name = "Flip Horizontaly", | ||
676 | .minimum = 0, | ||
677 | .maximum = 1, | ||
678 | .step = 1, | ||
679 | .default_value = 0, | ||
680 | }, { /* gain = 1/32*val (=>gain=1 if val==32) */ | ||
681 | .id = V4L2_CID_GAIN, | ||
682 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
683 | .name = "Gain", | ||
684 | .minimum = 0, | ||
685 | .maximum = 63 * 2 * 2, | ||
686 | .step = 1, | ||
687 | .default_value = 32, | ||
688 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
689 | }, { | ||
690 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
691 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
692 | .name = "Auto Exposure", | ||
693 | .minimum = 0, | ||
694 | .maximum = 1, | ||
695 | .step = 1, | ||
696 | .default_value = 1, | ||
697 | } | ||
698 | }; | ||
699 | |||
700 | static struct soc_camera_ops mt9m111_ops = { | ||
701 | .query_bus_param = mt9m111_query_bus_param, | ||
702 | .set_bus_param = mt9m111_set_bus_param, | ||
703 | .controls = mt9m111_controls, | ||
704 | .num_controls = ARRAY_SIZE(mt9m111_controls), | ||
705 | }; | ||
706 | |||
707 | static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask) | 647 | static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask) |
708 | { | 648 | { |
709 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); | 649 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); |
@@ -744,7 +684,6 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain) | |||
744 | if (gain > 63 * 2 * 2) | 684 | if (gain > 63 * 2 * 2) |
745 | return -EINVAL; | 685 | return -EINVAL; |
746 | 686 | ||
747 | mt9m111->gain = gain; | ||
748 | if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) | 687 | if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) |
749 | val = (1 << 10) | (1 << 9) | (gain / 4); | 688 | val = (1 << 10) | (1 << 9) | (gain / 4); |
750 | else if ((gain >= 64) && (gain < 64 * 2)) | 689 | else if ((gain >= 64) && (gain < 64 * 2)) |
@@ -758,118 +697,47 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain) | |||
758 | static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on) | 697 | static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on) |
759 | { | 698 | { |
760 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); | 699 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); |
761 | int ret; | ||
762 | 700 | ||
763 | if (on) | 701 | if (on) |
764 | ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); | 702 | return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); |
765 | else | 703 | return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); |
766 | ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); | ||
767 | |||
768 | if (!ret) | ||
769 | mt9m111->autoexposure = on; | ||
770 | |||
771 | return ret; | ||
772 | } | 704 | } |
773 | 705 | ||
774 | static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on) | 706 | static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on) |
775 | { | 707 | { |
776 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); | 708 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); |
777 | int ret; | ||
778 | 709 | ||
779 | if (on) | 710 | if (on) |
780 | ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); | 711 | return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); |
781 | else | 712 | return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); |
782 | ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); | ||
783 | |||
784 | if (!ret) | ||
785 | mt9m111->autowhitebalance = on; | ||
786 | |||
787 | return ret; | ||
788 | } | ||
789 | |||
790 | static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
791 | { | ||
792 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
793 | struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); | ||
794 | int data; | ||
795 | |||
796 | switch (ctrl->id) { | ||
797 | case V4L2_CID_VFLIP: | ||
798 | if (mt9m111->context == HIGHPOWER) | ||
799 | data = reg_read(READ_MODE_B); | ||
800 | else | ||
801 | data = reg_read(READ_MODE_A); | ||
802 | |||
803 | if (data < 0) | ||
804 | return -EIO; | ||
805 | ctrl->value = !!(data & MT9M111_RMB_MIRROR_ROWS); | ||
806 | break; | ||
807 | case V4L2_CID_HFLIP: | ||
808 | if (mt9m111->context == HIGHPOWER) | ||
809 | data = reg_read(READ_MODE_B); | ||
810 | else | ||
811 | data = reg_read(READ_MODE_A); | ||
812 | |||
813 | if (data < 0) | ||
814 | return -EIO; | ||
815 | ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS); | ||
816 | break; | ||
817 | case V4L2_CID_GAIN: | ||
818 | data = mt9m111_get_global_gain(mt9m111); | ||
819 | if (data < 0) | ||
820 | return data; | ||
821 | ctrl->value = data; | ||
822 | break; | ||
823 | case V4L2_CID_EXPOSURE_AUTO: | ||
824 | ctrl->value = mt9m111->autoexposure; | ||
825 | break; | ||
826 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
827 | ctrl->value = mt9m111->autowhitebalance; | ||
828 | break; | ||
829 | } | ||
830 | return 0; | ||
831 | } | 713 | } |
832 | 714 | ||
833 | static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 715 | static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl) |
834 | { | 716 | { |
835 | struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); | 717 | struct mt9m111 *mt9m111 = container_of(ctrl->handler, |
836 | const struct v4l2_queryctrl *qctrl; | 718 | struct mt9m111, hdl); |
837 | int ret; | ||
838 | |||
839 | qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id); | ||
840 | if (!qctrl) | ||
841 | return -EINVAL; | ||
842 | 719 | ||
843 | switch (ctrl->id) { | 720 | switch (ctrl->id) { |
844 | case V4L2_CID_VFLIP: | 721 | case V4L2_CID_VFLIP: |
845 | mt9m111->vflip = ctrl->value; | 722 | return mt9m111_set_flip(mt9m111, ctrl->val, |
846 | ret = mt9m111_set_flip(mt9m111, ctrl->value, | ||
847 | MT9M111_RMB_MIRROR_ROWS); | 723 | MT9M111_RMB_MIRROR_ROWS); |
848 | break; | ||
849 | case V4L2_CID_HFLIP: | 724 | case V4L2_CID_HFLIP: |
850 | mt9m111->hflip = ctrl->value; | 725 | return mt9m111_set_flip(mt9m111, ctrl->val, |
851 | ret = mt9m111_set_flip(mt9m111, ctrl->value, | ||
852 | MT9M111_RMB_MIRROR_COLS); | 726 | MT9M111_RMB_MIRROR_COLS); |
853 | break; | ||
854 | case V4L2_CID_GAIN: | 727 | case V4L2_CID_GAIN: |
855 | ret = mt9m111_set_global_gain(mt9m111, ctrl->value); | 728 | return mt9m111_set_global_gain(mt9m111, ctrl->val); |
856 | break; | ||
857 | case V4L2_CID_EXPOSURE_AUTO: | 729 | case V4L2_CID_EXPOSURE_AUTO: |
858 | ret = mt9m111_set_autoexposure(mt9m111, ctrl->value); | 730 | return mt9m111_set_autoexposure(mt9m111, ctrl->val); |
859 | break; | ||
860 | case V4L2_CID_AUTO_WHITE_BALANCE: | 731 | case V4L2_CID_AUTO_WHITE_BALANCE: |
861 | ret = mt9m111_set_autowhitebalance(mt9m111, ctrl->value); | 732 | return mt9m111_set_autowhitebalance(mt9m111, ctrl->val); |
862 | break; | ||
863 | default: | ||
864 | ret = -EINVAL; | ||
865 | } | 733 | } |
866 | 734 | ||
867 | return ret; | 735 | return -EINVAL; |
868 | } | 736 | } |
869 | 737 | ||
870 | static int mt9m111_suspend(struct mt9m111 *mt9m111) | 738 | static int mt9m111_suspend(struct mt9m111 *mt9m111) |
871 | { | 739 | { |
872 | mt9m111->gain = mt9m111_get_global_gain(mt9m111); | 740 | v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(mt9m111)); |
873 | 741 | ||
874 | return 0; | 742 | return 0; |
875 | } | 743 | } |
@@ -879,11 +747,7 @@ static void mt9m111_restore_state(struct mt9m111 *mt9m111) | |||
879 | mt9m111_set_context(mt9m111, mt9m111->context); | 747 | mt9m111_set_context(mt9m111, mt9m111->context); |
880 | mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code); | 748 | mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code); |
881 | mt9m111_setup_rect(mt9m111, &mt9m111->rect); | 749 | mt9m111_setup_rect(mt9m111, &mt9m111->rect); |
882 | mt9m111_set_flip(mt9m111, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); | 750 | v4l2_ctrl_handler_setup(&mt9m111->hdl); |
883 | mt9m111_set_flip(mt9m111, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); | ||
884 | mt9m111_set_global_gain(mt9m111, mt9m111->gain); | ||
885 | mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure); | ||
886 | mt9m111_set_autowhitebalance(mt9m111, mt9m111->autowhitebalance); | ||
887 | } | 751 | } |
888 | 752 | ||
889 | static int mt9m111_resume(struct mt9m111 *mt9m111) | 753 | static int mt9m111_resume(struct mt9m111 *mt9m111) |
@@ -911,8 +775,6 @@ static int mt9m111_init(struct mt9m111 *mt9m111) | |||
911 | ret = mt9m111_reset(mt9m111); | 775 | ret = mt9m111_reset(mt9m111); |
912 | if (!ret) | 776 | if (!ret) |
913 | ret = mt9m111_set_context(mt9m111, mt9m111->context); | 777 | ret = mt9m111_set_context(mt9m111, mt9m111->context); |
914 | if (!ret) | ||
915 | ret = mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure); | ||
916 | if (ret) | 778 | if (ret) |
917 | dev_err(&client->dev, "mt9m111 init failed: %d\n", ret); | 779 | dev_err(&client->dev, "mt9m111 init failed: %d\n", ret); |
918 | return ret; | 780 | return ret; |
@@ -922,22 +784,12 @@ static int mt9m111_init(struct mt9m111 *mt9m111) | |||
922 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 784 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
923 | * this wasn't our capture interface, so, we wait for the right one | 785 | * this wasn't our capture interface, so, we wait for the right one |
924 | */ | 786 | */ |
925 | static int mt9m111_video_probe(struct soc_camera_device *icd, | 787 | static int mt9m111_video_probe(struct i2c_client *client) |
926 | struct i2c_client *client) | ||
927 | { | 788 | { |
928 | struct mt9m111 *mt9m111 = to_mt9m111(client); | 789 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
929 | s32 data; | 790 | s32 data; |
930 | int ret; | 791 | int ret; |
931 | 792 | ||
932 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
933 | BUG_ON(!icd->parent || | ||
934 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
935 | |||
936 | mt9m111->lastpage = -1; | ||
937 | |||
938 | mt9m111->autoexposure = 1; | ||
939 | mt9m111->autowhitebalance = 1; | ||
940 | |||
941 | data = reg_read(CHIP_VERSION); | 793 | data = reg_read(CHIP_VERSION); |
942 | 794 | ||
943 | switch (data) { | 795 | switch (data) { |
@@ -951,17 +803,16 @@ static int mt9m111_video_probe(struct soc_camera_device *icd, | |||
951 | dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data); | 803 | dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data); |
952 | break; | 804 | break; |
953 | default: | 805 | default: |
954 | ret = -ENODEV; | ||
955 | dev_err(&client->dev, | 806 | dev_err(&client->dev, |
956 | "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n", | 807 | "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n", |
957 | data); | 808 | data); |
958 | goto ei2c; | 809 | return -ENODEV; |
959 | } | 810 | } |
960 | 811 | ||
961 | ret = mt9m111_init(mt9m111); | 812 | ret = mt9m111_init(mt9m111); |
962 | 813 | if (ret) | |
963 | ei2c: | 814 | return ret; |
964 | return ret; | 815 | return v4l2_ctrl_handler_setup(&mt9m111->hdl); |
965 | } | 816 | } |
966 | 817 | ||
967 | static int mt9m111_s_power(struct v4l2_subdev *sd, int on) | 818 | static int mt9m111_s_power(struct v4l2_subdev *sd, int on) |
@@ -998,9 +849,11 @@ out: | |||
998 | return ret; | 849 | return ret; |
999 | } | 850 | } |
1000 | 851 | ||
852 | static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = { | ||
853 | .s_ctrl = mt9m111_s_ctrl, | ||
854 | }; | ||
855 | |||
1001 | static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { | 856 | static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { |
1002 | .g_ctrl = mt9m111_g_ctrl, | ||
1003 | .s_ctrl = mt9m111_s_ctrl, | ||
1004 | .g_chip_ident = mt9m111_g_chip_ident, | 857 | .g_chip_ident = mt9m111_g_chip_ident, |
1005 | .s_power = mt9m111_s_power, | 858 | .s_power = mt9m111_s_power, |
1006 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 859 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
@@ -1019,6 +872,21 @@ static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
1019 | return 0; | 872 | return 0; |
1020 | } | 873 | } |
1021 | 874 | ||
875 | static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, | ||
876 | struct v4l2_mbus_config *cfg) | ||
877 | { | ||
878 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
879 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
880 | |||
881 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
882 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
883 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
884 | cfg->type = V4L2_MBUS_PARALLEL; | ||
885 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
886 | |||
887 | return 0; | ||
888 | } | ||
889 | |||
1022 | static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { | 890 | static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { |
1023 | .s_mbus_fmt = mt9m111_s_fmt, | 891 | .s_mbus_fmt = mt9m111_s_fmt, |
1024 | .g_mbus_fmt = mt9m111_g_fmt, | 892 | .g_mbus_fmt = mt9m111_g_fmt, |
@@ -1027,6 +895,7 @@ static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { | |||
1027 | .g_crop = mt9m111_g_crop, | 895 | .g_crop = mt9m111_g_crop, |
1028 | .cropcap = mt9m111_cropcap, | 896 | .cropcap = mt9m111_cropcap, |
1029 | .enum_mbus_fmt = mt9m111_enum_fmt, | 897 | .enum_mbus_fmt = mt9m111_enum_fmt, |
898 | .g_mbus_config = mt9m111_g_mbus_config, | ||
1030 | }; | 899 | }; |
1031 | 900 | ||
1032 | static struct v4l2_subdev_ops mt9m111_subdev_ops = { | 901 | static struct v4l2_subdev_ops mt9m111_subdev_ops = { |
@@ -1038,17 +907,10 @@ static int mt9m111_probe(struct i2c_client *client, | |||
1038 | const struct i2c_device_id *did) | 907 | const struct i2c_device_id *did) |
1039 | { | 908 | { |
1040 | struct mt9m111 *mt9m111; | 909 | struct mt9m111 *mt9m111; |
1041 | struct soc_camera_device *icd = client->dev.platform_data; | ||
1042 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 910 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
1043 | struct soc_camera_link *icl; | 911 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
1044 | int ret; | 912 | int ret; |
1045 | 913 | ||
1046 | if (!icd) { | ||
1047 | dev_err(&client->dev, "mt9m111: soc-camera data missing!\n"); | ||
1048 | return -EINVAL; | ||
1049 | } | ||
1050 | |||
1051 | icl = to_soc_camera_link(icd); | ||
1052 | if (!icl) { | 914 | if (!icl) { |
1053 | dev_err(&client->dev, "mt9m111: driver needs platform data\n"); | 915 | dev_err(&client->dev, "mt9m111: driver needs platform data\n"); |
1054 | return -EINVAL; | 916 | return -EINVAL; |
@@ -1065,19 +927,37 @@ static int mt9m111_probe(struct i2c_client *client, | |||
1065 | return -ENOMEM; | 927 | return -ENOMEM; |
1066 | 928 | ||
1067 | v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); | 929 | v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); |
930 | v4l2_ctrl_handler_init(&mt9m111->hdl, 5); | ||
931 | v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, | ||
932 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
933 | v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, | ||
934 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
935 | v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, | ||
936 | V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); | ||
937 | mt9m111->gain = v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, | ||
938 | V4L2_CID_GAIN, 0, 63 * 2 * 2, 1, 32); | ||
939 | v4l2_ctrl_new_std_menu(&mt9m111->hdl, | ||
940 | &mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, | ||
941 | V4L2_EXPOSURE_AUTO); | ||
942 | mt9m111->subdev.ctrl_handler = &mt9m111->hdl; | ||
943 | if (mt9m111->hdl.error) { | ||
944 | int err = mt9m111->hdl.error; | ||
1068 | 945 | ||
1069 | /* Second stage probe - when a capture adapter is there */ | 946 | kfree(mt9m111); |
1070 | icd->ops = &mt9m111_ops; | 947 | return err; |
948 | } | ||
1071 | 949 | ||
950 | /* Second stage probe - when a capture adapter is there */ | ||
1072 | mt9m111->rect.left = MT9M111_MIN_DARK_COLS; | 951 | mt9m111->rect.left = MT9M111_MIN_DARK_COLS; |
1073 | mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; | 952 | mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; |
1074 | mt9m111->rect.width = MT9M111_MAX_WIDTH; | 953 | mt9m111->rect.width = MT9M111_MAX_WIDTH; |
1075 | mt9m111->rect.height = MT9M111_MAX_HEIGHT; | 954 | mt9m111->rect.height = MT9M111_MAX_HEIGHT; |
1076 | mt9m111->fmt = &mt9m111_colour_fmts[0]; | 955 | mt9m111->fmt = &mt9m111_colour_fmts[0]; |
956 | mt9m111->lastpage = -1; | ||
1077 | 957 | ||
1078 | ret = mt9m111_video_probe(icd, client); | 958 | ret = mt9m111_video_probe(client); |
1079 | if (ret) { | 959 | if (ret) { |
1080 | icd->ops = NULL; | 960 | v4l2_ctrl_handler_free(&mt9m111->hdl); |
1081 | kfree(mt9m111); | 961 | kfree(mt9m111); |
1082 | } | 962 | } |
1083 | 963 | ||
@@ -1087,9 +967,9 @@ static int mt9m111_probe(struct i2c_client *client, | |||
1087 | static int mt9m111_remove(struct i2c_client *client) | 967 | static int mt9m111_remove(struct i2c_client *client) |
1088 | { | 968 | { |
1089 | struct mt9m111 *mt9m111 = to_mt9m111(client); | 969 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
1090 | struct soc_camera_device *icd = client->dev.platform_data; | ||
1091 | 970 | ||
1092 | icd->ops = NULL; | 971 | v4l2_device_unregister_subdev(&mt9m111->subdev); |
972 | v4l2_ctrl_handler_free(&mt9m111->hdl); | ||
1093 | kfree(mt9m111); | 973 | kfree(mt9m111); |
1094 | 974 | ||
1095 | return 0; | 975 | return 0; |