| .. | .. |
|---|
| 89 | 89 | #define to_sc210iot(sd) container_of(sd, struct sc210iot, subdev) |
|---|
| 90 | 90 | |
|---|
| 91 | 91 | enum { |
|---|
| 92 | | - PAD0, |
|---|
| 93 | | - PAD1, |
|---|
| 94 | | - PAD2, |
|---|
| 95 | | - PAD3, |
|---|
| 96 | | - PAD_MAX, |
|---|
| 97 | | -}; |
|---|
| 98 | | - |
|---|
| 99 | | -enum { |
|---|
| 100 | 92 | LINK_FREQ_INDEX, |
|---|
| 101 | 93 | }; |
|---|
| 102 | 94 | |
|---|
| .. | .. |
|---|
| 148 | 140 | struct v4l2_ctrl *link_freq; |
|---|
| 149 | 141 | struct v4l2_ctrl *pixel_rate; |
|---|
| 150 | 142 | struct mutex lock; |
|---|
| 143 | + struct v4l2_fract cur_fps; |
|---|
| 144 | + u32 cur_vts; |
|---|
| 151 | 145 | bool streaming; |
|---|
| 152 | 146 | bool power_on; |
|---|
| 153 | 147 | bool is_thunderboot; |
|---|
| .. | .. |
|---|
| 371 | 365 | return ret; |
|---|
| 372 | 366 | } |
|---|
| 373 | 367 | |
|---|
| 368 | +static void sc210iot_modify_fps_info(struct sc210iot *sc210iot) |
|---|
| 369 | +{ |
|---|
| 370 | + const struct sc210iot_mode *mode = sc210iot->cur_mode; |
|---|
| 371 | + |
|---|
| 372 | + sc210iot->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / |
|---|
| 373 | + sc210iot->cur_vts; |
|---|
| 374 | +} |
|---|
| 375 | + |
|---|
| 374 | 376 | static int sc210iot_set_ctrl(struct v4l2_ctrl *ctrl) |
|---|
| 375 | 377 | { |
|---|
| 376 | 378 | struct sc210iot *sc210iot = container_of(ctrl->handler, |
|---|
| .. | .. |
|---|
| 402 | 404 | dev_dbg(sc210iot->dev, "set vblank 0x%x\n", ctrl->val); |
|---|
| 403 | 405 | ret = sc210iot_write_reg(sc210iot, SC210IOT_REG_VTS_H, |
|---|
| 404 | 406 | (ctrl->val + sc210iot->cur_mode->height) >> 8); |
|---|
| 405 | | - ret = sc210iot_write_reg(sc210iot, SC210IOT_REG_VTS_L, |
|---|
| 407 | + ret |= sc210iot_write_reg(sc210iot, SC210IOT_REG_VTS_L, |
|---|
| 406 | 408 | (ctrl->val + sc210iot->cur_mode->height) & 0xff); |
|---|
| 409 | + if (!ret) |
|---|
| 410 | + sc210iot->cur_vts = ctrl->val + sc210iot->cur_mode->height; |
|---|
| 411 | + if (sc210iot->cur_vts != sc210iot->cur_mode->vts_def) |
|---|
| 412 | + sc210iot_modify_fps_info(sc210iot); |
|---|
| 407 | 413 | break; |
|---|
| 408 | 414 | case V4L2_CID_HFLIP: |
|---|
| 409 | 415 | regmap_update_bits(sc210iot->regmap, SC210IOT_REG_MIRROR_FLIP, |
|---|
| .. | .. |
|---|
| 487 | 493 | } |
|---|
| 488 | 494 | sc210iot->subdev.ctrl_handler = handler; |
|---|
| 489 | 495 | sc210iot->has_init_exp = false; |
|---|
| 496 | + sc210iot->cur_fps = mode->max_fps; |
|---|
| 497 | + sc210iot->cur_vts = mode->vts_def; |
|---|
| 490 | 498 | return 0; |
|---|
| 491 | 499 | err_free_handler: |
|---|
| 492 | 500 | v4l2_ctrl_handler_free(handler); |
|---|
| .. | .. |
|---|
| 687 | 695 | return ret; |
|---|
| 688 | 696 | } |
|---|
| 689 | 697 | ret = sc210iot_ioctl(sd, cmd, inf); |
|---|
| 690 | | - if (!ret) |
|---|
| 698 | + if (!ret) { |
|---|
| 691 | 699 | ret = copy_to_user(up, inf, sizeof(*inf)); |
|---|
| 700 | + if (ret) |
|---|
| 701 | + ret = -EFAULT; |
|---|
| 702 | + } |
|---|
| 692 | 703 | kfree(inf); |
|---|
| 693 | 704 | break; |
|---|
| 694 | 705 | case RKMODULE_GET_HDR_CFG: |
|---|
| .. | .. |
|---|
| 698 | 709 | return ret; |
|---|
| 699 | 710 | } |
|---|
| 700 | 711 | ret = sc210iot_ioctl(sd, cmd, hdr); |
|---|
| 701 | | - if (!ret) |
|---|
| 712 | + if (!ret) { |
|---|
| 702 | 713 | ret = copy_to_user(up, hdr, sizeof(*hdr)); |
|---|
| 714 | + if (ret) |
|---|
| 715 | + ret = -EFAULT; |
|---|
| 716 | + } |
|---|
| 703 | 717 | kfree(hdr); |
|---|
| 704 | | - break; |
|---|
| 705 | | - case RKMODULE_SET_HDR_CFG: |
|---|
| 706 | 718 | break; |
|---|
| 707 | 719 | case RKMODULE_SET_QUICK_STREAM: |
|---|
| 708 | 720 | ret = copy_from_user(&stream, up, sizeof(u32)); |
|---|
| 709 | 721 | if (!ret) |
|---|
| 710 | 722 | ret = sc210iot_ioctl(sd, cmd, &stream); |
|---|
| 723 | + else |
|---|
| 724 | + ret = -EFAULT; |
|---|
| 711 | 725 | break; |
|---|
| 712 | 726 | default: |
|---|
| 713 | 727 | ret = -ENOIOCTLCMD; |
|---|
| .. | .. |
|---|
| 758 | 772 | struct sc210iot *sc210iot = to_sc210iot(sd); |
|---|
| 759 | 773 | const struct sc210iot_mode *mode = sc210iot->cur_mode; |
|---|
| 760 | 774 | |
|---|
| 761 | | - mutex_lock(&sc210iot->lock); |
|---|
| 762 | | - fi->interval = mode->max_fps; |
|---|
| 763 | | - mutex_unlock(&sc210iot->lock); |
|---|
| 775 | + if (sc210iot->streaming) |
|---|
| 776 | + fi->interval = sc210iot->cur_fps; |
|---|
| 777 | + else |
|---|
| 778 | + fi->interval = mode->max_fps; |
|---|
| 764 | 779 | return 0; |
|---|
| 765 | 780 | } |
|---|
| 766 | 781 | |
|---|
| 767 | | -static int sc210iot_g_mbus_config(struct v4l2_subdev *sd, |
|---|
| 782 | +static int sc210iot_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, |
|---|
| 768 | 783 | struct v4l2_mbus_config *config) |
|---|
| 769 | 784 | { |
|---|
| 770 | 785 | struct sc210iot *sc210iot = to_sc210iot(sd); |
|---|
| 771 | 786 | |
|---|
| 772 | 787 | u32 val = 1 << (SC210IOT_LANES - 1) | V4L2_MBUS_CSI2_CHANNEL_0 | |
|---|
| 773 | 788 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; |
|---|
| 774 | | - config->type = V4L2_MBUS_CSI2; |
|---|
| 789 | + config->type = V4L2_MBUS_CSI2_DPHY; |
|---|
| 775 | 790 | config->flags = (sc210iot->cur_mode->hdr_mode == NO_HDR) ? |
|---|
| 776 | 791 | val : (val | V4L2_MBUS_CSI2_CHANNEL_1); |
|---|
| 777 | 792 | return 0; |
|---|
| .. | .. |
|---|
| 856 | 871 | __v4l2_ctrl_modify_range(sc210iot->vblank, vblank_def, |
|---|
| 857 | 872 | SC210IOT_VTS_MAX - mode->height, |
|---|
| 858 | 873 | 1, vblank_def); |
|---|
| 874 | + sc210iot->cur_fps = mode->max_fps; |
|---|
| 875 | + sc210iot->cur_vts = mode->vts_def; |
|---|
| 859 | 876 | } |
|---|
| 860 | 877 | mutex_unlock(&sc210iot->lock); |
|---|
| 861 | 878 | return 0; |
|---|
| .. | .. |
|---|
| 951 | 968 | static const struct v4l2_subdev_video_ops sc210iot_video_ops = { |
|---|
| 952 | 969 | .s_stream = sc210iot_s_stream, |
|---|
| 953 | 970 | .g_frame_interval = sc210iot_g_frame_interval, |
|---|
| 954 | | - .g_mbus_config = sc210iot_g_mbus_config, |
|---|
| 955 | 971 | }; |
|---|
| 956 | 972 | |
|---|
| 957 | 973 | static const struct v4l2_subdev_pad_ops sc210iot_pad_ops = { |
|---|
| .. | .. |
|---|
| 960 | 976 | .enum_frame_interval = sc210iot_enum_frame_interval, |
|---|
| 961 | 977 | .get_fmt = sc210iot_get_fmt, |
|---|
| 962 | 978 | .set_fmt = sc210iot_set_fmt, |
|---|
| 979 | + .get_mbus_config = sc210iot_g_mbus_config, |
|---|
| 963 | 980 | }; |
|---|
| 964 | 981 | |
|---|
| 965 | 982 | static const struct v4l2_subdev_ops sc210iot_subdev_ops = { |
|---|