aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/mt9m111.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-11-04 10:58:25 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-11-04 10:58:25 -0400
commit1046a2c428bedd64c960dcfd0c57cc69a82fea2f (patch)
treed34b83e0ac61b51305cece031f7ff49579e3fe76 /drivers/media/video/mt9m111.c
parent46e85f5f1c2a1d106c1ec0fa2a06280276b8e052 (diff)
parentb3f4e1eba45eda5d1213810ef3bc53e5247df2df (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.c260
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
178struct mt9m111 { 180struct 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
197static struct mt9m111 *to_mt9m111(const struct i2c_client *client) 196static 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
366static 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
376static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
377{
378 return 0;
379}
380
381static int mt9m111_make_rect(struct mt9m111 *mt9m111, 365static 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
663static 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
700static 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
707static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask) 647static 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)
758static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on) 697static 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
774static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on) 706static 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
790static 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
833static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 715static 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
870static int mt9m111_suspend(struct mt9m111 *mt9m111) 738static 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
889static int mt9m111_resume(struct mt9m111 *mt9m111) 753static 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 */
925static int mt9m111_video_probe(struct soc_camera_device *icd, 787static 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)
963ei2c: 814 return ret;
964 return ret; 815 return v4l2_ctrl_handler_setup(&mt9m111->hdl);
965} 816}
966 817
967static int mt9m111_s_power(struct v4l2_subdev *sd, int on) 818static 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
852static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
853 .s_ctrl = mt9m111_s_ctrl,
854};
855
1001static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { 856static 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
875static 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
1022static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { 890static 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
1032static struct v4l2_subdev_ops mt9m111_subdev_ops = { 901static 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,
1087static int mt9m111_remove(struct i2c_client *client) 967static 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;