| .. | .. |
|---|
| 50 | 50 | |
|---|
| 51 | 51 | #define SC031GS_REG_COARSE_AGAIN 0x3e08 |
|---|
| 52 | 52 | #define SC031GS_REG_FINE_AGAIN 0x3e09 |
|---|
| 53 | | -#define ANALOG_GAIN_MIN 0x01 |
|---|
| 54 | | -#define ANALOG_GAIN_MAX 0xF8 |
|---|
| 53 | +#define ANALOG_GAIN_MIN 0x10 |
|---|
| 54 | +#define ANALOG_GAIN_MAX 0x7c0 // 124x |
|---|
| 55 | 55 | #define ANALOG_GAIN_STEP 1 |
|---|
| 56 | 56 | #define ANALOG_GAIN_DEFAULT 0x1f |
|---|
| 57 | 57 | |
|---|
| .. | .. |
|---|
| 117 | 117 | struct v4l2_ctrl *vblank; |
|---|
| 118 | 118 | struct v4l2_ctrl *test_pattern; |
|---|
| 119 | 119 | struct mutex mutex; |
|---|
| 120 | + struct v4l2_fract cur_fps; |
|---|
| 121 | + u32 cur_vts; |
|---|
| 120 | 122 | bool streaming; |
|---|
| 121 | 123 | bool power_on; |
|---|
| 122 | 124 | const struct sc031gs_mode *cur_mode; |
|---|
| .. | .. |
|---|
| 296 | 298 | {0x3d08, 0x01}, |
|---|
| 297 | 299 | {0x3e01, 0x14}, |
|---|
| 298 | 300 | {0x3e02, 0x80}, |
|---|
| 299 | | - {0x3e06, 0x0c}, |
|---|
| 301 | + {0x3e06, 0x00}, |
|---|
| 300 | 302 | {0x4500, 0x59}, |
|---|
| 301 | 303 | {0x4501, 0xc4}, |
|---|
| 302 | 304 | {0x4603, 0x00}, |
|---|
| .. | .. |
|---|
| 477 | 479 | __v4l2_ctrl_modify_range(sc031gs->vblank, vblank_def, |
|---|
| 478 | 480 | SC031GS_VTS_MAX - mode->height, |
|---|
| 479 | 481 | 1, vblank_def); |
|---|
| 482 | + sc031gs->cur_fps = mode->max_fps; |
|---|
| 483 | + sc031gs->cur_vts = mode->vts_def; |
|---|
| 480 | 484 | } |
|---|
| 481 | 485 | |
|---|
| 482 | 486 | mutex_unlock(&sc031gs->mutex); |
|---|
| .. | .. |
|---|
| 611 | 615 | |
|---|
| 612 | 616 | ret = sc031gs_ioctl(sd, cmd, inf); |
|---|
| 613 | 617 | if (!ret) |
|---|
| 614 | | - ret = copy_to_user(up, inf, sizeof(*inf)); |
|---|
| 618 | + if (copy_to_user(up, inf, sizeof(*inf))) { |
|---|
| 619 | + kfree(inf); |
|---|
| 620 | + return -EFAULT; |
|---|
| 621 | + } |
|---|
| 615 | 622 | kfree(inf); |
|---|
| 616 | 623 | break; |
|---|
| 617 | 624 | case RKMODULE_AWB_CFG: |
|---|
| .. | .. |
|---|
| 620 | 627 | ret = -ENOMEM; |
|---|
| 621 | 628 | return ret; |
|---|
| 622 | 629 | } |
|---|
| 623 | | - |
|---|
| 624 | | - ret = copy_from_user(cfg, up, sizeof(*cfg)); |
|---|
| 625 | | - if (!ret) |
|---|
| 626 | | - ret = sc031gs_ioctl(sd, cmd, cfg); |
|---|
| 630 | + if (copy_from_user(cfg, up, sizeof(*cfg))) { |
|---|
| 631 | + kfree(cfg); |
|---|
| 632 | + return -EFAULT; |
|---|
| 633 | + } |
|---|
| 634 | + ret = sc031gs_ioctl(sd, cmd, cfg); |
|---|
| 627 | 635 | kfree(cfg); |
|---|
| 628 | 636 | break; |
|---|
| 629 | 637 | case RKMODULE_SET_QUICK_STREAM: |
|---|
| 630 | | - ret = copy_from_user(&stream, up, sizeof(u32)); |
|---|
| 631 | | - if (!ret) |
|---|
| 632 | | - ret = sc031gs_ioctl(sd, cmd, &stream); |
|---|
| 638 | + if (copy_from_user(&stream, up, sizeof(u32))) |
|---|
| 639 | + return -EFAULT; |
|---|
| 640 | + ret = sc031gs_ioctl(sd, cmd, &stream); |
|---|
| 633 | 641 | break; |
|---|
| 634 | 642 | default: |
|---|
| 635 | 643 | ret = -ENOIOCTLCMD; |
|---|
| .. | .. |
|---|
| 643 | 651 | static int sc031gs_set_ctrl_gain(struct sc031gs *sc031gs, u32 a_gain) |
|---|
| 644 | 652 | { |
|---|
| 645 | 653 | int ret = 0; |
|---|
| 646 | | - u32 coarse_again, fine_again, fine_again_reg, coarse_again_reg; |
|---|
| 654 | + u32 coarse_again, fine_again, fine_again_reg, coarse_again_reg, digital_gain_reg; |
|---|
| 647 | 655 | |
|---|
| 648 | 656 | if (a_gain < 0x20) { /*1x ~ 2x*/ |
|---|
| 649 | 657 | fine_again = a_gain - 16; |
|---|
| .. | .. |
|---|
| 651 | 659 | fine_again_reg = ((0x01 << 4) & 0x10) | |
|---|
| 652 | 660 | (fine_again & 0x0f); |
|---|
| 653 | 661 | coarse_again_reg = coarse_again & 0x1F; |
|---|
| 662 | + digital_gain_reg = 0x80; |
|---|
| 654 | 663 | } else if (a_gain < 0x40) { /*2x ~ 4x*/ |
|---|
| 655 | 664 | fine_again = (a_gain >> 1) - 16; |
|---|
| 656 | 665 | coarse_again = 0x7; |
|---|
| 657 | 666 | fine_again_reg = ((0x01 << 4) & 0x10) | |
|---|
| 658 | 667 | (fine_again & 0x0f); |
|---|
| 659 | 668 | coarse_again_reg = coarse_again & 0x1F; |
|---|
| 669 | + digital_gain_reg = 0x80; |
|---|
| 660 | 670 | } else if (a_gain < 0x80) { /*4x ~ 8x*/ |
|---|
| 661 | 671 | fine_again = (a_gain >> 2) - 16; |
|---|
| 662 | 672 | coarse_again = 0xf; |
|---|
| 663 | 673 | fine_again_reg = ((0x01 << 4) & 0x10) | |
|---|
| 664 | 674 | (fine_again & 0x0f); |
|---|
| 665 | 675 | coarse_again_reg = coarse_again & 0x1F; |
|---|
| 666 | | - } else { /*8x ~ 16x*/ |
|---|
| 676 | + digital_gain_reg = 0x80; |
|---|
| 677 | + } else if (a_gain < 0x100) { /*8x ~ 16x*/ |
|---|
| 667 | 678 | fine_again = (a_gain >> 3) - 16; |
|---|
| 668 | 679 | coarse_again = 0x1f; |
|---|
| 669 | 680 | fine_again_reg = ((0x01 << 4) & 0x10) | |
|---|
| 670 | 681 | (fine_again & 0x0f); |
|---|
| 671 | 682 | coarse_again_reg = coarse_again & 0x1F; |
|---|
| 683 | + digital_gain_reg = 0x80; |
|---|
| 684 | + } else if (a_gain < 0x200) { /*16x ~ 32x*/ |
|---|
| 685 | + fine_again_reg = 0x1f; |
|---|
| 686 | + coarse_again_reg = 0x1f; |
|---|
| 687 | + digital_gain_reg = (a_gain * 0x80 / 0x100) & 0xf8; |
|---|
| 688 | + } else if (a_gain < 0x400) { /*32x ~ 64x*/ |
|---|
| 689 | + fine_again_reg = 0x1f; |
|---|
| 690 | + coarse_again_reg = 0x1f; |
|---|
| 691 | + digital_gain_reg = (a_gain * 0x80 / 0x200) & 0x1f8; |
|---|
| 692 | + } else { /*64x ~ 124*/ |
|---|
| 693 | + fine_again_reg = 0x1f; |
|---|
| 694 | + coarse_again_reg = 0x1f; |
|---|
| 695 | + digital_gain_reg = (a_gain * 0x80 / 0x400) & 0x3f8; |
|---|
| 672 | 696 | } |
|---|
| 673 | 697 | |
|---|
| 674 | 698 | if (a_gain < 0x20) { |
|---|
| .. | .. |
|---|
| 690 | 714 | SC031GS_REG_FINE_AGAIN, |
|---|
| 691 | 715 | SC031GS_REG_VALUE_08BIT, |
|---|
| 692 | 716 | fine_again_reg); |
|---|
| 717 | + |
|---|
| 718 | + ret |= sc031gs_write_reg(sc031gs->client, 0x3e06, |
|---|
| 719 | + SC031GS_REG_VALUE_16BIT, digital_gain_reg); |
|---|
| 693 | 720 | |
|---|
| 694 | 721 | return ret; |
|---|
| 695 | 722 | } |
|---|
| .. | .. |
|---|
| 765 | 792 | struct sc031gs *sc031gs = to_sc031gs(sd); |
|---|
| 766 | 793 | const struct sc031gs_mode *mode = sc031gs->cur_mode; |
|---|
| 767 | 794 | |
|---|
| 768 | | - mutex_lock(&sc031gs->mutex); |
|---|
| 769 | | - fi->interval = mode->max_fps; |
|---|
| 770 | | - mutex_unlock(&sc031gs->mutex); |
|---|
| 795 | + if (sc031gs->streaming) |
|---|
| 796 | + fi->interval = sc031gs->cur_fps; |
|---|
| 797 | + else |
|---|
| 798 | + fi->interval = mode->max_fps; |
|---|
| 771 | 799 | |
|---|
| 772 | 800 | return 0; |
|---|
| 773 | 801 | } |
|---|
| .. | .. |
|---|
| 917 | 945 | if (fie->index >= ARRAY_SIZE(supported_modes)) |
|---|
| 918 | 946 | return -EINVAL; |
|---|
| 919 | 947 | |
|---|
| 920 | | - if (fie->code != PIX_FORMAT) |
|---|
| 921 | | - return -EINVAL; |
|---|
| 948 | + fie->code = PIX_FORMAT; |
|---|
| 922 | 949 | |
|---|
| 923 | 950 | fie->width = supported_modes[fie->index].width; |
|---|
| 924 | 951 | fie->height = supported_modes[fie->index].height; |
|---|
| .. | .. |
|---|
| 967 | 994 | .pad = &sc031gs_pad_ops, |
|---|
| 968 | 995 | }; |
|---|
| 969 | 996 | |
|---|
| 997 | +static void sc031gs_modify_fps_info(struct sc031gs *sc031gs) |
|---|
| 998 | +{ |
|---|
| 999 | + const struct sc031gs_mode *mode = sc031gs->cur_mode; |
|---|
| 1000 | + |
|---|
| 1001 | + sc031gs->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / |
|---|
| 1002 | + sc031gs->cur_vts; |
|---|
| 1003 | +} |
|---|
| 1004 | + |
|---|
| 970 | 1005 | static int sc031gs_set_ctrl(struct v4l2_ctrl *ctrl) |
|---|
| 971 | 1006 | { |
|---|
| 972 | 1007 | struct sc031gs *sc031gs = container_of(ctrl->handler, |
|---|
| .. | .. |
|---|
| 1003 | 1038 | ret = sc031gs_write_reg(sc031gs->client, SC031GS_REG_VTS, |
|---|
| 1004 | 1039 | SC031GS_REG_VALUE_16BIT, |
|---|
| 1005 | 1040 | ctrl->val + sc031gs->cur_mode->height); |
|---|
| 1041 | + if (!ret) |
|---|
| 1042 | + sc031gs->cur_vts = ctrl->val + sc031gs->cur_mode->height; |
|---|
| 1043 | + sc031gs_modify_fps_info(sc031gs); |
|---|
| 1006 | 1044 | break; |
|---|
| 1007 | 1045 | case V4L2_CID_TEST_PATTERN: |
|---|
| 1008 | 1046 | ret = sc031gs_enable_test_pattern(sc031gs, ctrl->val); |
|---|
| .. | .. |
|---|
| 1053 | 1091 | sc031gs->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
|---|
| 1054 | 1092 | |
|---|
| 1055 | 1093 | vblank_def = mode->vts_def - mode->height; |
|---|
| 1094 | + sc031gs->cur_vts = mode->vts_def; |
|---|
| 1056 | 1095 | sc031gs->vblank = v4l2_ctrl_new_std(handler, &sc031gs_ctrl_ops, |
|---|
| 1057 | 1096 | V4L2_CID_VBLANK, vblank_def, |
|---|
| 1058 | 1097 | SC031GS_VTS_MAX - mode->height, |
|---|
| .. | .. |
|---|
| 1082 | 1121 | } |
|---|
| 1083 | 1122 | |
|---|
| 1084 | 1123 | sc031gs->subdev.ctrl_handler = handler; |
|---|
| 1124 | + sc031gs->cur_fps = mode->max_fps; |
|---|
| 1085 | 1125 | |
|---|
| 1086 | 1126 | return 0; |
|---|
| 1087 | 1127 | |
|---|