| .. | .. |
|---|
| 123 | 123 | |
|---|
| 124 | 124 | #define sc500ai_NUM_SUPPLIES ARRAY_SIZE(sc500ai_supply_names) |
|---|
| 125 | 125 | |
|---|
| 126 | | -enum sc500ai_max_pad { |
|---|
| 127 | | - PAD0, /* link to isp */ |
|---|
| 128 | | - PAD1, /* link to csi wr0 | hdr x2:L x3:M */ |
|---|
| 129 | | - PAD2, /* link to csi wr1 | hdr x3:L */ |
|---|
| 130 | | - PAD3, /* link to csi wr2 | hdr x2:M x3:S */ |
|---|
| 131 | | - PAD_MAX, |
|---|
| 132 | | -}; |
|---|
| 133 | | - |
|---|
| 134 | 126 | struct regval { |
|---|
| 135 | 127 | u16 addr; |
|---|
| 136 | 128 | u8 val; |
|---|
| .. | .. |
|---|
| 173 | 165 | struct v4l2_ctrl *pixel_rate; |
|---|
| 174 | 166 | struct v4l2_ctrl *link_freq; |
|---|
| 175 | 167 | struct mutex mutex; |
|---|
| 168 | + struct v4l2_fract cur_fps; |
|---|
| 176 | 169 | bool streaming; |
|---|
| 177 | 170 | bool power_on; |
|---|
| 178 | 171 | const struct sc500ai_mode *cur_mode; |
|---|
| .. | .. |
|---|
| 277 | 270 | {0x3e17, 0x80}, |
|---|
| 278 | 271 | {0x4500, 0x88}, |
|---|
| 279 | 272 | {0x4509, 0x20}, |
|---|
| 273 | + {0x4800, 0x04}, |
|---|
| 280 | 274 | {0x5799, 0x00}, |
|---|
| 281 | 275 | {0x59e0, 0x60}, |
|---|
| 282 | 276 | {0x59e1, 0x08}, |
|---|
| .. | .. |
|---|
| 596 | 590 | __v4l2_ctrl_s_ctrl(sc500ai->link_freq, mode->mipi_freq_idx); |
|---|
| 597 | 591 | pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / mode->bpp * 2 * SC500AI_LANES; |
|---|
| 598 | 592 | __v4l2_ctrl_s_ctrl_int64(sc500ai->pixel_rate, pixel_rate); |
|---|
| 593 | + sc500ai->cur_fps = mode->max_fps; |
|---|
| 594 | + sc500ai->cur_vts = mode->vts_def; |
|---|
| 599 | 595 | } |
|---|
| 600 | 596 | |
|---|
| 601 | 597 | mutex_unlock(&sc500ai->mutex); |
|---|
| .. | .. |
|---|
| 671 | 667 | struct sc500ai *sc500ai = to_sc500ai(sd); |
|---|
| 672 | 668 | const struct sc500ai_mode *mode = sc500ai->cur_mode; |
|---|
| 673 | 669 | |
|---|
| 674 | | - mutex_lock(&sc500ai->mutex); |
|---|
| 675 | | - fi->interval = mode->max_fps; |
|---|
| 676 | | - mutex_unlock(&sc500ai->mutex); |
|---|
| 670 | + if (sc500ai->streaming) |
|---|
| 671 | + fi->interval = sc500ai->cur_fps; |
|---|
| 672 | + else |
|---|
| 673 | + fi->interval = mode->max_fps; |
|---|
| 677 | 674 | |
|---|
| 678 | 675 | return 0; |
|---|
| 679 | 676 | } |
|---|
| 680 | 677 | |
|---|
| 681 | | -static int sc500ai_g_mbus_config(struct v4l2_subdev *sd, |
|---|
| 678 | +static int sc500ai_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad, |
|---|
| 682 | 679 | struct v4l2_mbus_config *config) |
|---|
| 683 | 680 | { |
|---|
| 684 | 681 | struct sc500ai *sc500ai = to_sc500ai(sd); |
|---|
| .. | .. |
|---|
| 692 | 689 | if (mode->hdr_mode == HDR_X3) |
|---|
| 693 | 690 | val |= V4L2_MBUS_CSI2_CHANNEL_2; |
|---|
| 694 | 691 | |
|---|
| 695 | | - config->type = V4L2_MBUS_CSI2; |
|---|
| 692 | + config->type = V4L2_MBUS_CSI2_DPHY; |
|---|
| 696 | 693 | config->flags = val; |
|---|
| 697 | 694 | |
|---|
| 698 | 695 | return 0; |
|---|
| .. | .. |
|---|
| 911 | 908 | return ret; |
|---|
| 912 | 909 | } |
|---|
| 913 | 910 | |
|---|
| 911 | +static int sc500ai_get_channel_info(struct sc500ai *sc500ai, struct rkmodule_channel_info *ch_info) |
|---|
| 912 | +{ |
|---|
| 913 | + if (ch_info->index < PAD0 || ch_info->index >= PAD_MAX) |
|---|
| 914 | + return -EINVAL; |
|---|
| 915 | + ch_info->vc = sc500ai->cur_mode->vc[ch_info->index]; |
|---|
| 916 | + ch_info->width = sc500ai->cur_mode->width; |
|---|
| 917 | + ch_info->height = sc500ai->cur_mode->height; |
|---|
| 918 | + ch_info->bus_fmt = sc500ai->cur_mode->bus_fmt; |
|---|
| 919 | + return 0; |
|---|
| 920 | +} |
|---|
| 921 | + |
|---|
| 914 | 922 | static long sc500ai_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) |
|---|
| 915 | 923 | { |
|---|
| 916 | 924 | struct sc500ai *sc500ai = to_sc500ai(sd); |
|---|
| 917 | 925 | struct rkmodule_hdr_cfg *hdr; |
|---|
| 918 | 926 | const struct sc500ai_mode *mode; |
|---|
| 927 | + struct rkmodule_channel_info *ch_info; |
|---|
| 919 | 928 | |
|---|
| 920 | 929 | long ret = 0; |
|---|
| 921 | 930 | u32 i, h, w; |
|---|
| .. | .. |
|---|
| 959 | 968 | __v4l2_ctrl_s_ctrl(sc500ai->link_freq, mode->mipi_freq_idx); |
|---|
| 960 | 969 | pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / mode->bpp * 2 * SC500AI_LANES; |
|---|
| 961 | 970 | __v4l2_ctrl_s_ctrl_int64(sc500ai->pixel_rate, pixel_rate); |
|---|
| 962 | | - |
|---|
| 971 | + sc500ai->cur_fps = mode->max_fps; |
|---|
| 972 | + sc500ai->cur_vts = mode->vts_def; |
|---|
| 963 | 973 | dev_info(&sc500ai->client->dev, "sensor mode: %d\n", sc500ai->cur_mode->hdr_mode); |
|---|
| 964 | 974 | } |
|---|
| 965 | 975 | break; |
|---|
| .. | .. |
|---|
| 976 | 986 | ret = sc500ai_write_reg(sc500ai->client, SC500AI_REG_CTRL_MODE, |
|---|
| 977 | 987 | SC500AI_REG_VALUE_08BIT, SC500AI_MODE_SW_STANDBY); |
|---|
| 978 | 988 | break; |
|---|
| 989 | + case RKMODULE_GET_CHANNEL_INFO: |
|---|
| 990 | + ch_info = (struct rkmodule_channel_info *)arg; |
|---|
| 991 | + ret = sc500ai_get_channel_info(sc500ai, ch_info); |
|---|
| 992 | + break; |
|---|
| 979 | 993 | default: |
|---|
| 980 | 994 | ret = -ENOIOCTLCMD; |
|---|
| 981 | 995 | break; |
|---|
| .. | .. |
|---|
| 990 | 1004 | { |
|---|
| 991 | 1005 | void __user *up = compat_ptr(arg); |
|---|
| 992 | 1006 | struct rkmodule_inf *inf; |
|---|
| 993 | | - struct rkmodule_awb_cfg *cfg; |
|---|
| 994 | 1007 | struct rkmodule_hdr_cfg *hdr; |
|---|
| 995 | 1008 | struct preisp_hdrae_exp_s *hdrae; |
|---|
| 1009 | + struct rkmodule_channel_info *ch_info; |
|---|
| 996 | 1010 | long ret = 0; |
|---|
| 997 | 1011 | u32 stream = 0; |
|---|
| 998 | 1012 | |
|---|
| .. | .. |
|---|
| 1005 | 1019 | } |
|---|
| 1006 | 1020 | |
|---|
| 1007 | 1021 | ret = sc500ai_ioctl(sd, cmd, inf); |
|---|
| 1008 | | - if (!ret) |
|---|
| 1022 | + if (!ret) { |
|---|
| 1009 | 1023 | ret = copy_to_user(up, inf, sizeof(*inf)); |
|---|
| 1010 | | - kfree(inf); |
|---|
| 1011 | | - break; |
|---|
| 1012 | | - case RKMODULE_AWB_CFG: |
|---|
| 1013 | | - cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); |
|---|
| 1014 | | - if (!cfg) { |
|---|
| 1015 | | - ret = -ENOMEM; |
|---|
| 1016 | | - return ret; |
|---|
| 1024 | + if (ret) |
|---|
| 1025 | + ret = -EFAULT; |
|---|
| 1017 | 1026 | } |
|---|
| 1018 | | - |
|---|
| 1019 | | - ret = copy_from_user(cfg, up, sizeof(*cfg)); |
|---|
| 1020 | | - if (!ret) |
|---|
| 1021 | | - ret = sc500ai_ioctl(sd, cmd, cfg); |
|---|
| 1022 | | - kfree(cfg); |
|---|
| 1027 | + kfree(inf); |
|---|
| 1023 | 1028 | break; |
|---|
| 1024 | 1029 | case RKMODULE_GET_HDR_CFG: |
|---|
| 1025 | 1030 | hdr = kzalloc(sizeof(*hdr), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 1029 | 1034 | } |
|---|
| 1030 | 1035 | |
|---|
| 1031 | 1036 | ret = sc500ai_ioctl(sd, cmd, hdr); |
|---|
| 1032 | | - if (!ret) |
|---|
| 1037 | + if (!ret) { |
|---|
| 1033 | 1038 | ret = copy_to_user(up, hdr, sizeof(*hdr)); |
|---|
| 1039 | + if (ret) |
|---|
| 1040 | + ret = -EFAULT; |
|---|
| 1041 | + } |
|---|
| 1034 | 1042 | kfree(hdr); |
|---|
| 1035 | 1043 | break; |
|---|
| 1036 | 1044 | case RKMODULE_SET_HDR_CFG: |
|---|
| .. | .. |
|---|
| 1040 | 1048 | return ret; |
|---|
| 1041 | 1049 | } |
|---|
| 1042 | 1050 | |
|---|
| 1043 | | - ret = copy_from_user(hdr, up, sizeof(*hdr)); |
|---|
| 1044 | | - if (!ret) |
|---|
| 1045 | | - ret = sc500ai_ioctl(sd, cmd, hdr); |
|---|
| 1051 | + if (copy_from_user(hdr, up, sizeof(*hdr))) |
|---|
| 1052 | + return -EFAULT; |
|---|
| 1053 | + |
|---|
| 1054 | + ret = sc500ai_ioctl(sd, cmd, hdr); |
|---|
| 1046 | 1055 | kfree(hdr); |
|---|
| 1047 | 1056 | break; |
|---|
| 1048 | 1057 | case PREISP_CMD_SET_HDRAE_EXP: |
|---|
| .. | .. |
|---|
| 1052 | 1061 | return ret; |
|---|
| 1053 | 1062 | } |
|---|
| 1054 | 1063 | |
|---|
| 1055 | | - ret = copy_from_user(hdrae, up, sizeof(*hdrae)); |
|---|
| 1056 | | - if (!ret) |
|---|
| 1057 | | - ret = sc500ai_ioctl(sd, cmd, hdrae); |
|---|
| 1064 | + if (copy_from_user(hdrae, up, sizeof(*hdrae))) |
|---|
| 1065 | + return -EFAULT; |
|---|
| 1066 | + |
|---|
| 1067 | + ret = sc500ai_ioctl(sd, cmd, hdrae); |
|---|
| 1058 | 1068 | kfree(hdrae); |
|---|
| 1059 | 1069 | break; |
|---|
| 1060 | 1070 | case RKMODULE_SET_QUICK_STREAM: |
|---|
| 1061 | | - ret = copy_from_user(&stream, up, sizeof(u32)); |
|---|
| 1062 | | - if (!ret) |
|---|
| 1063 | | - ret = sc500ai_ioctl(sd, cmd, &stream); |
|---|
| 1071 | + if (copy_from_user(&stream, up, sizeof(u32))) |
|---|
| 1072 | + return -EFAULT; |
|---|
| 1073 | + |
|---|
| 1074 | + ret = sc500ai_ioctl(sd, cmd, &stream); |
|---|
| 1075 | + break; |
|---|
| 1076 | + case RKMODULE_GET_CHANNEL_INFO: |
|---|
| 1077 | + ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL); |
|---|
| 1078 | + if (!ch_info) { |
|---|
| 1079 | + ret = -ENOMEM; |
|---|
| 1080 | + return ret; |
|---|
| 1081 | + } |
|---|
| 1082 | + |
|---|
| 1083 | + ret = sc500ai_ioctl(sd, cmd, ch_info); |
|---|
| 1084 | + if (!ret) { |
|---|
| 1085 | + ret = copy_to_user(up, ch_info, sizeof(*ch_info)); |
|---|
| 1086 | + if (ret) |
|---|
| 1087 | + ret = -EFAULT; |
|---|
| 1088 | + } |
|---|
| 1089 | + kfree(ch_info); |
|---|
| 1064 | 1090 | break; |
|---|
| 1065 | 1091 | default: |
|---|
| 1066 | 1092 | ret = -ENOIOCTLCMD; |
|---|
| .. | .. |
|---|
| 1348 | 1374 | static const struct v4l2_subdev_video_ops sc500ai_video_ops = { |
|---|
| 1349 | 1375 | .s_stream = sc500ai_s_stream, |
|---|
| 1350 | 1376 | .g_frame_interval = sc500ai_g_frame_interval, |
|---|
| 1351 | | - .g_mbus_config = sc500ai_g_mbus_config, |
|---|
| 1352 | 1377 | }; |
|---|
| 1353 | 1378 | |
|---|
| 1354 | 1379 | static const struct v4l2_subdev_pad_ops sc500ai_pad_ops = { |
|---|
| .. | .. |
|---|
| 1358 | 1383 | .get_fmt = sc500ai_get_fmt, |
|---|
| 1359 | 1384 | .set_fmt = sc500ai_set_fmt, |
|---|
| 1360 | 1385 | .get_selection = sc500ai_get_selection, |
|---|
| 1386 | + .get_mbus_config = sc500ai_g_mbus_config, |
|---|
| 1361 | 1387 | }; |
|---|
| 1362 | 1388 | |
|---|
| 1363 | 1389 | static const struct v4l2_subdev_ops sc500ai_subdev_ops = { |
|---|
| .. | .. |
|---|
| 1365 | 1391 | .video = &sc500ai_video_ops, |
|---|
| 1366 | 1392 | .pad = &sc500ai_pad_ops, |
|---|
| 1367 | 1393 | }; |
|---|
| 1394 | + |
|---|
| 1395 | +static void sc500ai_modify_fps_info(struct sc500ai *sc500ai) |
|---|
| 1396 | +{ |
|---|
| 1397 | + const struct sc500ai_mode *mode = sc500ai->cur_mode; |
|---|
| 1398 | + |
|---|
| 1399 | + sc500ai->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / |
|---|
| 1400 | + sc500ai->cur_vts; |
|---|
| 1401 | +} |
|---|
| 1368 | 1402 | |
|---|
| 1369 | 1403 | static int sc500ai_set_ctrl(struct v4l2_ctrl *ctrl) |
|---|
| 1370 | 1404 | { |
|---|
| .. | .. |
|---|
| 1399 | 1433 | switch (ctrl->id) { |
|---|
| 1400 | 1434 | case V4L2_CID_EXPOSURE: |
|---|
| 1401 | 1435 | if (sc500ai->cur_mode->hdr_mode != NO_HDR) |
|---|
| 1402 | | - return ret; |
|---|
| 1436 | + goto ctrl_end; |
|---|
| 1403 | 1437 | val = ctrl->val << 1; |
|---|
| 1404 | 1438 | ret = sc500ai_write_reg(sc500ai->client, |
|---|
| 1405 | 1439 | SC500AI_REG_EXPOSURE_H, |
|---|
| .. | .. |
|---|
| 1418 | 1452 | break; |
|---|
| 1419 | 1453 | case V4L2_CID_ANALOGUE_GAIN: |
|---|
| 1420 | 1454 | if (sc500ai->cur_mode->hdr_mode != NO_HDR) |
|---|
| 1421 | | - return ret; |
|---|
| 1455 | + goto ctrl_end; |
|---|
| 1422 | 1456 | |
|---|
| 1423 | 1457 | sc500ai_get_gain_reg(ctrl->val, &again, &again_fine, &dgain, &dgain_fine); |
|---|
| 1424 | 1458 | ret = sc500ai_write_reg(sc500ai->client, |
|---|
| .. | .. |
|---|
| 1453 | 1487 | SC500AI_REG_VTS_L, |
|---|
| 1454 | 1488 | SC500AI_REG_VALUE_08BIT, |
|---|
| 1455 | 1489 | vts & 0xff); |
|---|
| 1456 | | - sc500ai->cur_vts = vts; |
|---|
| 1490 | + if (!ret) |
|---|
| 1491 | + sc500ai->cur_vts = vts; |
|---|
| 1492 | + sc500ai_modify_fps_info(sc500ai); |
|---|
| 1457 | 1493 | break; |
|---|
| 1458 | 1494 | case V4L2_CID_HFLIP: |
|---|
| 1459 | 1495 | ret = sc500ai_read_reg(sc500ai->client, SC500AI_FLIP_MIRROR_REG, |
|---|
| .. | .. |
|---|
| 1520 | 1556 | break; |
|---|
| 1521 | 1557 | } |
|---|
| 1522 | 1558 | |
|---|
| 1559 | +ctrl_end: |
|---|
| 1523 | 1560 | pm_runtime_put(&client->dev); |
|---|
| 1524 | 1561 | |
|---|
| 1525 | 1562 | return ret; |
|---|
| .. | .. |
|---|
| 1565 | 1602 | |
|---|
| 1566 | 1603 | vblank_def = mode->vts_def - mode->height; |
|---|
| 1567 | 1604 | sc500ai->cur_vts = mode->vts_def; |
|---|
| 1605 | + sc500ai->cur_fps = mode->max_fps; |
|---|
| 1568 | 1606 | sc500ai->vblank = v4l2_ctrl_new_std(handler, &sc500ai_ctrl_ops, |
|---|
| 1569 | 1607 | V4L2_CID_VBLANK, vblank_def, |
|---|
| 1570 | 1608 | SC500AI_VTS_MAX - mode->height, |
|---|