aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/mt9p031.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/mt9p031.c')
-rw-r--r--drivers/media/video/mt9p031.c118
1 files changed, 111 insertions, 7 deletions
diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c
index 3a9363118e83..8f061d9ac443 100644
--- a/drivers/media/video/mt9p031.c
+++ b/drivers/media/video/mt9p031.c
@@ -91,7 +91,14 @@
91#define MT9P031_GLOBAL_GAIN_MAX 1024 91#define MT9P031_GLOBAL_GAIN_MAX 1024
92#define MT9P031_GLOBAL_GAIN_DEF 8 92#define MT9P031_GLOBAL_GAIN_DEF 8
93#define MT9P031_GLOBAL_GAIN_MULT (1 << 6) 93#define MT9P031_GLOBAL_GAIN_MULT (1 << 6)
94#define MT9P031_ROW_BLACK_TARGET 0x49
94#define MT9P031_ROW_BLACK_DEF_OFFSET 0x4b 95#define MT9P031_ROW_BLACK_DEF_OFFSET 0x4b
96#define MT9P031_GREEN1_OFFSET 0x60
97#define MT9P031_GREEN2_OFFSET 0x61
98#define MT9P031_BLACK_LEVEL_CALIBRATION 0x62
99#define MT9P031_BLC_MANUAL_BLC (1 << 0)
100#define MT9P031_RED_OFFSET 0x63
101#define MT9P031_BLUE_OFFSET 0x64
95#define MT9P031_TEST_PATTERN 0xa0 102#define MT9P031_TEST_PATTERN 0xa0
96#define MT9P031_TEST_PATTERN_SHIFT 3 103#define MT9P031_TEST_PATTERN_SHIFT 3
97#define MT9P031_TEST_PATTERN_ENABLE (1 << 0) 104#define MT9P031_TEST_PATTERN_ENABLE (1 << 0)
@@ -110,7 +117,6 @@ struct mt9p031 {
110 struct media_pad pad; 117 struct media_pad pad;
111 struct v4l2_rect crop; /* Sensor window */ 118 struct v4l2_rect crop; /* Sensor window */
112 struct v4l2_mbus_framefmt format; 119 struct v4l2_mbus_framefmt format;
113 struct v4l2_ctrl_handler ctrls;
114 struct mt9p031_platform_data *pdata; 120 struct mt9p031_platform_data *pdata;
115 struct mutex power_lock; /* lock to protect power_count */ 121 struct mutex power_lock; /* lock to protect power_count */
116 int power_count; 122 int power_count;
@@ -119,6 +125,10 @@ struct mt9p031 {
119 struct aptina_pll pll; 125 struct aptina_pll pll;
120 int reset; 126 int reset;
121 127
128 struct v4l2_ctrl_handler ctrls;
129 struct v4l2_ctrl *blc_auto;
130 struct v4l2_ctrl *blc_offset;
131
122 /* Registers cache */ 132 /* Registers cache */
123 u16 output_control; 133 u16 output_control;
124 u16 mode2; 134 u16 mode2;
@@ -565,6 +575,10 @@ static int mt9p031_set_crop(struct v4l2_subdev *subdev,
565 */ 575 */
566 576
567#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001) 577#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001)
578#define V4L2_CID_BLC_AUTO (V4L2_CID_USER_BASE | 0x1002)
579#define V4L2_CID_BLC_TARGET_LEVEL (V4L2_CID_USER_BASE | 0x1003)
580#define V4L2_CID_BLC_ANALOG_OFFSET (V4L2_CID_USER_BASE | 0x1004)
581#define V4L2_CID_BLC_DIGITAL_OFFSET (V4L2_CID_USER_BASE | 0x1005)
568 582
569static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl) 583static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
570{ 584{
@@ -629,11 +643,17 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
629 643
630 case V4L2_CID_TEST_PATTERN: 644 case V4L2_CID_TEST_PATTERN:
631 if (!ctrl->val) { 645 if (!ctrl->val) {
632 ret = mt9p031_set_mode2(mt9p031, 646 /* Restore the black level compensation settings. */
633 0, MT9P031_READ_MODE_2_ROW_BLC); 647 if (mt9p031->blc_auto->cur.val != 0) {
634 if (ret < 0) 648 ret = mt9p031_s_ctrl(mt9p031->blc_auto);
635 return ret; 649 if (ret < 0)
636 650 return ret;
651 }
652 if (mt9p031->blc_offset->cur.val != 0) {
653 ret = mt9p031_s_ctrl(mt9p031->blc_offset);
654 if (ret < 0)
655 return ret;
656 }
637 return mt9p031_write(client, MT9P031_TEST_PATTERN, 657 return mt9p031_write(client, MT9P031_TEST_PATTERN,
638 MT9P031_TEST_PATTERN_DISABLE); 658 MT9P031_TEST_PATTERN_DISABLE);
639 } 659 }
@@ -648,10 +668,14 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
648 if (ret < 0) 668 if (ret < 0)
649 return ret; 669 return ret;
650 670
671 /* Disable digital black level compensation when using a test
672 * pattern.
673 */
651 ret = mt9p031_set_mode2(mt9p031, MT9P031_READ_MODE_2_ROW_BLC, 674 ret = mt9p031_set_mode2(mt9p031, MT9P031_READ_MODE_2_ROW_BLC,
652 0); 675 0);
653 if (ret < 0) 676 if (ret < 0)
654 return ret; 677 return ret;
678
655 ret = mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET, 0); 679 ret = mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET, 0);
656 if (ret < 0) 680 if (ret < 0)
657 return ret; 681 return ret;
@@ -659,7 +683,40 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
659 return mt9p031_write(client, MT9P031_TEST_PATTERN, 683 return mt9p031_write(client, MT9P031_TEST_PATTERN,
660 ((ctrl->val - 1) << MT9P031_TEST_PATTERN_SHIFT) 684 ((ctrl->val - 1) << MT9P031_TEST_PATTERN_SHIFT)
661 | MT9P031_TEST_PATTERN_ENABLE); 685 | MT9P031_TEST_PATTERN_ENABLE);
686
687 case V4L2_CID_BLC_AUTO:
688 ret = mt9p031_set_mode2(mt9p031,
689 ctrl->val ? 0 : MT9P031_READ_MODE_2_ROW_BLC,
690 ctrl->val ? MT9P031_READ_MODE_2_ROW_BLC : 0);
691 if (ret < 0)
692 return ret;
693
694 return mt9p031_write(client, MT9P031_BLACK_LEVEL_CALIBRATION,
695 ctrl->val ? 0 : MT9P031_BLC_MANUAL_BLC);
696
697 case V4L2_CID_BLC_TARGET_LEVEL:
698 return mt9p031_write(client, MT9P031_ROW_BLACK_TARGET,
699 ctrl->val);
700
701 case V4L2_CID_BLC_ANALOG_OFFSET:
702 data = ctrl->val & ((1 << 9) - 1);
703
704 ret = mt9p031_write(client, MT9P031_GREEN1_OFFSET, data);
705 if (ret < 0)
706 return ret;
707 ret = mt9p031_write(client, MT9P031_GREEN2_OFFSET, data);
708 if (ret < 0)
709 return ret;
710 ret = mt9p031_write(client, MT9P031_RED_OFFSET, data);
711 if (ret < 0)
712 return ret;
713 return mt9p031_write(client, MT9P031_BLUE_OFFSET, data);
714
715 case V4L2_CID_BLC_DIGITAL_OFFSET:
716 return mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET,
717 ctrl->val & ((1 << 12) - 1));
662 } 718 }
719
663 return 0; 720 return 0;
664} 721}
665 722
@@ -693,6 +750,46 @@ static const struct v4l2_ctrl_config mt9p031_ctrls[] = {
693 .flags = 0, 750 .flags = 0,
694 .menu_skip_mask = 0, 751 .menu_skip_mask = 0,
695 .qmenu = mt9p031_test_pattern_menu, 752 .qmenu = mt9p031_test_pattern_menu,
753 }, {
754 .ops = &mt9p031_ctrl_ops,
755 .id = V4L2_CID_BLC_AUTO,
756 .type = V4L2_CTRL_TYPE_BOOLEAN,
757 .name = "BLC, Auto",
758 .min = 0,
759 .max = 1,
760 .step = 1,
761 .def = 1,
762 .flags = 0,
763 }, {
764 .ops = &mt9p031_ctrl_ops,
765 .id = V4L2_CID_BLC_TARGET_LEVEL,
766 .type = V4L2_CTRL_TYPE_INTEGER,
767 .name = "BLC Target Level",
768 .min = 0,
769 .max = 4095,
770 .step = 1,
771 .def = 168,
772 .flags = 0,
773 }, {
774 .ops = &mt9p031_ctrl_ops,
775 .id = V4L2_CID_BLC_ANALOG_OFFSET,
776 .type = V4L2_CTRL_TYPE_INTEGER,
777 .name = "BLC Analog Offset",
778 .min = -255,
779 .max = 255,
780 .step = 1,
781 .def = 32,
782 .flags = 0,
783 }, {
784 .ops = &mt9p031_ctrl_ops,
785 .id = V4L2_CID_BLC_DIGITAL_OFFSET,
786 .type = V4L2_CTRL_TYPE_INTEGER,
787 .name = "BLC Digital Offset",
788 .min = -2048,
789 .max = 2047,
790 .step = 1,
791 .def = 40,
792 .flags = 0,
696 } 793 }
697}; 794};
698 795
@@ -872,9 +969,16 @@ static int mt9p031_probe(struct i2c_client *client,
872 969
873 mt9p031->subdev.ctrl_handler = &mt9p031->ctrls; 970 mt9p031->subdev.ctrl_handler = &mt9p031->ctrls;
874 971
875 if (mt9p031->ctrls.error) 972 if (mt9p031->ctrls.error) {
876 printk(KERN_INFO "%s: control initialization error %d\n", 973 printk(KERN_INFO "%s: control initialization error %d\n",
877 __func__, mt9p031->ctrls.error); 974 __func__, mt9p031->ctrls.error);
975 ret = mt9p031->ctrls.error;
976 goto done;
977 }
978
979 mt9p031->blc_auto = v4l2_ctrl_find(&mt9p031->ctrls, V4L2_CID_BLC_AUTO);
980 mt9p031->blc_offset = v4l2_ctrl_find(&mt9p031->ctrls,
981 V4L2_CID_BLC_DIGITAL_OFFSET);
878 982
879 mutex_init(&mt9p031->power_lock); 983 mutex_init(&mt9p031->power_lock);
880 v4l2_i2c_subdev_init(&mt9p031->subdev, client, &mt9p031_subdev_ops); 984 v4l2_i2c_subdev_init(&mt9p031->subdev, client, &mt9p031_subdev_ops);