diff options
Diffstat (limited to 'drivers/media/video/mt9v022.c')
-rw-r--r-- | drivers/media/video/mt9v022.c | 46 |
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 = { | |||
540 | static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 544 | static 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; |