.. | .. |
---|
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, |
---|