aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/mt9v022.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/mt9v022.c')
-rw-r--r--drivers/media/video/mt9v022.c46
1 files changed, 35 insertions, 11 deletions
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index 5c47b55823c8..995607f9d3ba 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -45,7 +45,7 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
45#define MT9V022_PIXEL_OPERATION_MODE 0x0f 45#define MT9V022_PIXEL_OPERATION_MODE 0x0f
46#define MT9V022_LED_OUT_CONTROL 0x1b 46#define MT9V022_LED_OUT_CONTROL 0x1b
47#define MT9V022_ADC_MODE_CONTROL 0x1c 47#define MT9V022_ADC_MODE_CONTROL 0x1c
48#define MT9V022_ANALOG_GAIN 0x34 48#define MT9V022_ANALOG_GAIN 0x35
49#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47 49#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47
50#define MT9V022_PIXCLK_FV_LV 0x74 50#define MT9V022_PIXCLK_FV_LV 0x74
51#define MT9V022_DIGITAL_TEST_PATTERN 0x7f 51#define MT9V022_DIGITAL_TEST_PATTERN 0x7f
@@ -156,6 +156,10 @@ static int mt9v022_init(struct i2c_client *client)
156 /* AEC, AGC on */ 156 /* AEC, AGC on */
157 ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3); 157 ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3);
158 if (!ret) 158 if (!ret)
159 ret = reg_write(client, MT9V022_ANALOG_GAIN, 16);
160 if (!ret)
161 ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480);
162 if (!ret)
159 ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480); 163 ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480);
160 if (!ret) 164 if (!ret)
161 /* default - auto */ 165 /* default - auto */
@@ -540,8 +544,12 @@ static struct soc_camera_ops mt9v022_ops = {
540static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 544static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
541{ 545{
542 struct i2c_client *client = sd->priv; 546 struct i2c_client *client = sd->priv;
547 const struct v4l2_queryctrl *qctrl;
548 unsigned long range;
543 int data; 549 int data;
544 550
551 qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
552
545 switch (ctrl->id) { 553 switch (ctrl->id) {
546 case V4L2_CID_VFLIP: 554 case V4L2_CID_VFLIP:
547 data = reg_read(client, MT9V022_READ_MODE); 555 data = reg_read(client, MT9V022_READ_MODE);
@@ -567,6 +575,24 @@ static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
567 return -EIO; 575 return -EIO;
568 ctrl->value = !!(data & 0x2); 576 ctrl->value = !!(data & 0x2);
569 break; 577 break;
578 case V4L2_CID_GAIN:
579 data = reg_read(client, MT9V022_ANALOG_GAIN);
580 if (data < 0)
581 return -EIO;
582
583 range = qctrl->maximum - qctrl->minimum;
584 ctrl->value = ((data - 16) * range + 24) / 48 + qctrl->minimum;
585
586 break;
587 case V4L2_CID_EXPOSURE:
588 data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH);
589 if (data < 0)
590 return -EIO;
591
592 range = qctrl->maximum - qctrl->minimum;
593 ctrl->value = ((data - 1) * range + 239) / 479 + qctrl->minimum;
594
595 break;
570 } 596 }
571 return 0; 597 return 0;
572} 598}
@@ -575,7 +601,6 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
575{ 601{
576 int data; 602 int data;
577 struct i2c_client *client = sd->priv; 603 struct i2c_client *client = sd->priv;
578 struct soc_camera_device *icd = client->dev.platform_data;
579 const struct v4l2_queryctrl *qctrl; 604 const struct v4l2_queryctrl *qctrl;
580 605
581 qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); 606 qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
@@ -605,12 +630,9 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
605 return -EINVAL; 630 return -EINVAL;
606 else { 631 else {
607 unsigned long range = qctrl->maximum - qctrl->minimum; 632 unsigned long range = qctrl->maximum - qctrl->minimum;
608 /* Datasheet says 16 to 64. autogain only works properly 633 /* Valid values 16 to 64, 32 to 64 must be even. */
609 * after setting gain to maximum 14. Larger values
610 * produce "white fly" noise effect. On the whole,
611 * manually setting analog gain does no good. */
612 unsigned long gain = ((ctrl->value - qctrl->minimum) * 634 unsigned long gain = ((ctrl->value - qctrl->minimum) *
613 10 + range / 2) / range + 4; 635 48 + range / 2) / range + 16;
614 if (gain >= 32) 636 if (gain >= 32)
615 gain &= ~1; 637 gain &= ~1;
616 /* The user wants to set gain manually, hope, she 638 /* The user wants to set gain manually, hope, she
@@ -619,11 +641,10 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
619 if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) 641 if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
620 return -EIO; 642 return -EIO;
621 643
622 dev_info(&client->dev, "Setting gain from %d to %lu\n", 644 dev_dbg(&client->dev, "Setting gain from %d to %lu\n",
623 reg_read(client, MT9V022_ANALOG_GAIN), gain); 645 reg_read(client, MT9V022_ANALOG_GAIN), gain);
624 if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) 646 if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0)
625 return -EIO; 647 return -EIO;
626 icd->gain = ctrl->value;
627 } 648 }
628 break; 649 break;
629 case V4L2_CID_EXPOSURE: 650 case V4L2_CID_EXPOSURE:
@@ -646,7 +667,6 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
646 if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 667 if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
647 shutter) < 0) 668 shutter) < 0)
648 return -EIO; 669 return -EIO;
649 icd->exposure = ctrl->value;
650 } 670 }
651 break; 671 break;
652 case V4L2_CID_AUTOGAIN: 672 case V4L2_CID_AUTOGAIN:
@@ -827,6 +847,10 @@ static int mt9v022_probe(struct i2c_client *client,
827 mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; 847 mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
828 848
829 icd->ops = &mt9v022_ops; 849 icd->ops = &mt9v022_ops;
850 /*
851 * MT9V022 _really_ corrupts the first read out line.
852 * TODO: verify on i.MX31
853 */
830 icd->y_skip_top = 1; 854 icd->y_skip_top = 1;
831 855
832 mt9v022->rect.left = MT9V022_COLUMN_SKIP; 856 mt9v022->rect.left = MT9V022_COLUMN_SKIP;