.. | .. |
---|
8 | 8 | * V0.0X01.0X01 fix set vflip/hflip failed bug. |
---|
9 | 9 | */ |
---|
10 | 10 | |
---|
| 11 | +//#define DEBUG |
---|
11 | 12 | #include <linux/clk.h> |
---|
12 | 13 | #include <linux/device.h> |
---|
13 | 14 | #include <linux/delay.h> |
---|
.. | .. |
---|
59 | 60 | |
---|
60 | 61 | #define SC530AI_XVCLK_FREQ 27000000 |
---|
61 | 62 | |
---|
62 | | -#define SC530AI_CHIP_ID 0x9e39 |
---|
| 63 | +#define SC530AI_CHIP_ID 0x8e39 |
---|
63 | 64 | #define SC530AI_REG_CHIP_ID 0x3107 |
---|
64 | 65 | |
---|
65 | 66 | #define SC530AI_REG_CTRL_MODE 0x0100 |
---|
.. | .. |
---|
77 | 78 | #define SC530AI_REG_DIG_FINE_GAIN 0x3e07 |
---|
78 | 79 | #define SC530AI_REG_ANA_GAIN 0x3e09 |
---|
79 | 80 | |
---|
80 | | -#define SC530AI_GAIN_MIN 0x800 |
---|
81 | | -#define SC530AI_GAIN_MAX 0xa3300 |
---|
| 81 | +#define SC530AI_GAIN_MIN 0x20 |
---|
| 82 | +#define SC530AI_GAIN_MAX (32 * 326) |
---|
82 | 83 | #define SC530AI_GAIN_STEP 1 |
---|
83 | | -#define SC530AI_GAIN_DEFAULT 0x800 |
---|
| 84 | +#define SC530AI_GAIN_DEFAULT 0x20 |
---|
84 | 85 | |
---|
85 | 86 | #define SC530AI_REG_VTS_H 0x320e |
---|
86 | 87 | #define SC530AI_REG_VTS_L 0x320f |
---|
.. | .. |
---|
139 | 140 | |
---|
140 | 141 | #define sc530ai_NUM_SUPPLIES ARRAY_SIZE(sc530ai_supply_names) |
---|
141 | 142 | |
---|
142 | | -enum sc530ai_max_pad { |
---|
143 | | - PAD0, /* link to isp */ |
---|
144 | | - PAD1, /* link to csi wr0 | hdr x2:L x3:M */ |
---|
145 | | - PAD2, /* link to csi wr1 | hdr x3:L */ |
---|
146 | | - PAD3, /* link to csi wr2 | hdr x2:M x3:S */ |
---|
147 | | - PAD_MAX, |
---|
148 | | -}; |
---|
149 | | - |
---|
150 | 143 | struct regval { |
---|
151 | 144 | u16 addr; |
---|
152 | 145 | u8 val; |
---|
.. | .. |
---|
177 | 170 | struct pinctrl *pinctrl; |
---|
178 | 171 | struct pinctrl_state *pins_default; |
---|
179 | 172 | struct pinctrl_state *pins_sleep; |
---|
180 | | - |
---|
| 173 | + struct v4l2_fract cur_fps; |
---|
| 174 | + u32 cur_vts; |
---|
181 | 175 | struct v4l2_subdev subdev; |
---|
182 | 176 | struct media_pad pad; |
---|
183 | 177 | struct v4l2_ctrl_handler ctrl_handler; |
---|
.. | .. |
---|
191 | 185 | struct mutex mutex; |
---|
192 | 186 | bool streaming; |
---|
193 | 187 | bool power_on; |
---|
| 188 | + const struct sc530ai_mode *support_modes; |
---|
194 | 189 | const struct sc530ai_mode *cur_mode; |
---|
| 190 | + u32 support_modes_num; |
---|
195 | 191 | unsigned int lane_num; |
---|
196 | 192 | u32 module_index; |
---|
197 | 193 | const char *module_facing; |
---|
.. | .. |
---|
208 | 204 | * max_framerate 30fps |
---|
209 | 205 | * mipi_datarate per lane 1008Mbps, 4lane |
---|
210 | 206 | */ |
---|
211 | | -static const struct regval sc530ai_linear_10_30fps_2880x1620_regs[] = { |
---|
| 207 | +static const struct regval sc530ai_linear_10_30fps_2880x1620_4lane_regs[] = { |
---|
212 | 208 | {0x0103, 0x01}, |
---|
213 | 209 | {0x0100, 0x00}, |
---|
214 | 210 | {0x36e9, 0x80}, |
---|
.. | .. |
---|
317 | 313 | {0x3e02, 0xa0}, |
---|
318 | 314 | {0x440e, 0x02}, |
---|
319 | 315 | {0x4509, 0x20}, |
---|
| 316 | + {0x4800, 0x04}, |
---|
320 | 317 | {0x4837, 0x28}, |
---|
321 | 318 | {0x5010, 0x10}, |
---|
322 | 319 | {0x5799, 0x06}, |
---|
.. | .. |
---|
356 | 353 | {REG_NULL, 0x00}, |
---|
357 | 354 | }; |
---|
358 | 355 | |
---|
359 | | -static const struct regval sc530ai_hdr_10_30fps_2880x1620_regs[] = { |
---|
| 356 | +static const struct regval sc530ai_hdr_10_30fps_2880x1620_4lane_regs[] = { |
---|
360 | 357 | {0x0103, 0x01}, |
---|
361 | 358 | {0x0100, 0x00}, |
---|
362 | 359 | {0x36e9, 0x80}, |
---|
.. | .. |
---|
471 | 468 | {0x3e24, 0xc8}, |
---|
472 | 469 | {0x440e, 0x02}, |
---|
473 | 470 | {0x4509, 0x20}, |
---|
| 471 | + {0x4800, 0x04}, |
---|
474 | 472 | {0x4816, 0x11}, |
---|
475 | 473 | {0x5010, 0x10}, |
---|
476 | 474 | {0x5799, 0x06}, |
---|
.. | .. |
---|
626 | 624 | {0x3e02, 0xa0}, |
---|
627 | 625 | {0x440e, 0x02}, |
---|
628 | 626 | {0x4509, 0x20}, |
---|
| 627 | + {0x4800, 0x04}, |
---|
629 | 628 | {0x4837, 0x14}, |
---|
630 | 629 | {0x5010, 0x10}, |
---|
631 | 630 | {0x5799, 0x06}, |
---|
.. | .. |
---|
664 | 663 | {REG_NULL, 0x00}, |
---|
665 | 664 | }; |
---|
666 | 665 | |
---|
667 | | -static const struct sc530ai_mode supported_modes[] = { |
---|
| 666 | +static const struct sc530ai_mode supported_modes_4lane[] = { |
---|
668 | 667 | { |
---|
669 | 668 | .width = 2880, |
---|
670 | 669 | .height = 1620, |
---|
.. | .. |
---|
676 | 675 | .hts_def = 0xb40, |
---|
677 | 676 | .vts_def = 0x0672, |
---|
678 | 677 | .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, |
---|
679 | | - .reg_list = sc530ai_linear_10_30fps_2880x1620_regs, |
---|
| 678 | + .reg_list = sc530ai_linear_10_30fps_2880x1620_4lane_regs, |
---|
680 | 679 | .mipi_freq_idx = 0, |
---|
681 | 680 | .bpp = 10, |
---|
682 | 681 | .hdr_mode = NO_HDR, |
---|
.. | .. |
---|
693 | 692 | .hts_def = 0xb40, |
---|
694 | 693 | .vts_def = 0x0ce4, |
---|
695 | 694 | .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, |
---|
696 | | - .reg_list = sc530ai_hdr_10_30fps_2880x1620_regs, |
---|
| 695 | + .reg_list = sc530ai_hdr_10_30fps_2880x1620_4lane_regs, |
---|
697 | 696 | .mipi_freq_idx = 1, |
---|
698 | 697 | .bpp = 10, |
---|
699 | 698 | .hdr_mode = HDR_X2, |
---|
.. | .. |
---|
702 | 701 | .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_1, |
---|
703 | 702 | .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_1,//M->csi wr2 |
---|
704 | 703 | }, |
---|
705 | | - { |
---|
| 704 | +}; |
---|
| 705 | + |
---|
| 706 | +static const struct sc530ai_mode supported_modes_2lane[] = { |
---|
| 707 | +{ |
---|
706 | 708 | .width = 2880, |
---|
707 | 709 | .height = 1620, |
---|
708 | 710 | .max_fps = { |
---|
.. | .. |
---|
812 | 814 | } |
---|
813 | 815 | |
---|
814 | 816 | static const struct sc530ai_mode * |
---|
815 | | -sc530ai_find_best_fit(struct v4l2_subdev_format *fmt) |
---|
| 817 | +sc530ai_find_best_fit(struct sc530ai *sc530ai, struct v4l2_subdev_format *fmt) |
---|
816 | 818 | { |
---|
817 | 819 | struct v4l2_mbus_framefmt *framefmt = &fmt->format; |
---|
818 | 820 | int dist; |
---|
.. | .. |
---|
820 | 822 | int cur_best_fit_dist = -1; |
---|
821 | 823 | unsigned int i; |
---|
822 | 824 | |
---|
823 | | - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { |
---|
824 | | - dist = sc530ai_get_reso_dist(&supported_modes[i], framefmt); |
---|
| 825 | + for (i = 0; i < sc530ai->support_modes_num; i++) { |
---|
| 826 | + dist = sc530ai_get_reso_dist(&sc530ai->support_modes[i], framefmt); |
---|
825 | 827 | if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { |
---|
826 | 828 | cur_best_fit_dist = dist; |
---|
827 | 829 | cur_best_fit = i; |
---|
828 | 830 | } |
---|
829 | 831 | } |
---|
830 | 832 | |
---|
831 | | - return &supported_modes[cur_best_fit]; |
---|
| 833 | + return &sc530ai->support_modes[cur_best_fit]; |
---|
832 | 834 | } |
---|
833 | 835 | |
---|
834 | 836 | static int sc530ai_set_fmt(struct v4l2_subdev *sd, |
---|
.. | .. |
---|
842 | 844 | |
---|
843 | 845 | mutex_lock(&sc530ai->mutex); |
---|
844 | 846 | |
---|
845 | | - mode = sc530ai_find_best_fit(fmt); |
---|
| 847 | + mode = sc530ai_find_best_fit(sc530ai, fmt); |
---|
846 | 848 | fmt->format.code = mode->bus_fmt; |
---|
847 | 849 | fmt->format.width = mode->width; |
---|
848 | 850 | fmt->format.height = mode->height; |
---|
.. | .. |
---|
869 | 871 | pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / |
---|
870 | 872 | mode->bpp * 2 * sc530ai->lane_num; |
---|
871 | 873 | __v4l2_ctrl_s_ctrl_int64(sc530ai->pixel_rate, pixel_rate); |
---|
| 874 | + sc530ai->cur_vts = mode->vts_def; |
---|
| 875 | + sc530ai->cur_fps = mode->max_fps; |
---|
872 | 876 | } |
---|
873 | 877 | |
---|
874 | 878 | mutex_unlock(&sc530ai->mutex); |
---|
.. | .. |
---|
924 | 928 | struct v4l2_subdev_pad_config *cfg, |
---|
925 | 929 | struct v4l2_subdev_frame_size_enum *fse) |
---|
926 | 930 | { |
---|
927 | | - if (fse->index >= ARRAY_SIZE(supported_modes)) |
---|
| 931 | + struct sc530ai *sc530ai = to_sc530ai(sd); |
---|
| 932 | + |
---|
| 933 | + if (fse->index >= sc530ai->support_modes_num) |
---|
928 | 934 | return -EINVAL; |
---|
929 | 935 | |
---|
930 | | - if (fse->code != supported_modes[0].bus_fmt) |
---|
| 936 | + if (fse->code != sc530ai->support_modes[fse->index].bus_fmt) |
---|
931 | 937 | return -EINVAL; |
---|
932 | 938 | |
---|
933 | | - fse->min_width = supported_modes[fse->index].width; |
---|
934 | | - fse->max_width = supported_modes[fse->index].width; |
---|
935 | | - fse->max_height = supported_modes[fse->index].height; |
---|
936 | | - fse->min_height = supported_modes[fse->index].height; |
---|
| 939 | + fse->min_width = sc530ai->support_modes[fse->index].width; |
---|
| 940 | + fse->max_width = sc530ai->support_modes[fse->index].width; |
---|
| 941 | + fse->max_height = sc530ai->support_modes[fse->index].height; |
---|
| 942 | + fse->min_height = sc530ai->support_modes[fse->index].height; |
---|
937 | 943 | |
---|
938 | 944 | return 0; |
---|
939 | 945 | } |
---|
.. | .. |
---|
944 | 950 | struct sc530ai *sc530ai = to_sc530ai(sd); |
---|
945 | 951 | const struct sc530ai_mode *mode = sc530ai->cur_mode; |
---|
946 | 952 | |
---|
947 | | - mutex_lock(&sc530ai->mutex); |
---|
948 | | - fi->interval = mode->max_fps; |
---|
949 | | - mutex_unlock(&sc530ai->mutex); |
---|
| 953 | + if (sc530ai->streaming) |
---|
| 954 | + fi->interval = sc530ai->cur_fps; |
---|
| 955 | + else |
---|
| 956 | + fi->interval = mode->max_fps; |
---|
950 | 957 | |
---|
951 | 958 | return 0; |
---|
952 | 959 | } |
---|
953 | 960 | |
---|
954 | | -static int sc530ai_g_mbus_config(struct v4l2_subdev *sd, |
---|
| 961 | +static int sc530ai_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, |
---|
955 | 962 | struct v4l2_mbus_config *config) |
---|
956 | 963 | { |
---|
957 | 964 | struct sc530ai *sc530ai = to_sc530ai(sd); |
---|
.. | .. |
---|
965 | 972 | if (mode->hdr_mode == HDR_X3) |
---|
966 | 973 | val |= V4L2_MBUS_CSI2_CHANNEL_2; |
---|
967 | 974 | |
---|
968 | | - config->type = V4L2_MBUS_CSI2; |
---|
| 975 | + config->type = V4L2_MBUS_CSI2_DPHY; |
---|
969 | 976 | config->flags = val; |
---|
970 | 977 | |
---|
971 | 978 | return 0; |
---|
.. | .. |
---|
984 | 991 | static void sc530ai_get_gain_reg(u32 total_gain, u32 *again, u32 *dgain, |
---|
985 | 992 | u32 *dgain_fine) |
---|
986 | 993 | { |
---|
987 | | - if (total_gain < 0x1000) { /* 1 - 2x gain */ |
---|
| 994 | + u32 gain_factor = 0; |
---|
| 995 | + |
---|
| 996 | + if (total_gain < SC530AI_GAIN_MIN) |
---|
| 997 | + total_gain = SC530AI_GAIN_MIN; |
---|
| 998 | + else if (total_gain > SC530AI_GAIN_MAX) |
---|
| 999 | + total_gain = SC530AI_GAIN_MAX; |
---|
| 1000 | + |
---|
| 1001 | + gain_factor = total_gain * 1000 / 32; |
---|
| 1002 | + if (gain_factor < 2000) { /* 1 - 2x gain */ |
---|
988 | 1003 | *again = 0x00; |
---|
989 | 1004 | *dgain = 0x00; |
---|
990 | | - *dgain_fine = total_gain >> 4; |
---|
991 | | - } else if (total_gain < 0x1466) { /* 2x - 2.55x gain */ |
---|
| 1005 | + *dgain_fine = gain_factor * 128 / 1000; |
---|
| 1006 | + } else if (gain_factor < 2550) { /* 2x - 2.55x gain */ |
---|
992 | 1007 | *again = 0x01; |
---|
993 | 1008 | *dgain = 0x00; |
---|
994 | | - *dgain_fine = total_gain >> 5; |
---|
995 | | - } else if (total_gain < 0x28cc) { /* 2.55x - 5.1x gain */ |
---|
| 1009 | + *dgain_fine = gain_factor * 128 / 2000; |
---|
| 1010 | + } else if (gain_factor < 2550 * 2) { /* 2.55x - 5.1x gain */ |
---|
996 | 1011 | *again = 0x40; |
---|
997 | 1012 | *dgain = 0x00; |
---|
998 | | - *dgain_fine = total_gain * 0x80 / 0x1466; |
---|
999 | | - } else if (total_gain < 0x5198) { /* 5.1x - 10.2x gain */ |
---|
| 1013 | + *dgain_fine = gain_factor * 128 / 2550; |
---|
| 1014 | + } else if (gain_factor < 2550 * 4) { /* 5.1x - 10.2x gain */ |
---|
1000 | 1015 | *again = 0x48; |
---|
1001 | 1016 | *dgain = 0x00; |
---|
1002 | | - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 1; |
---|
1003 | | - } else if (total_gain < 0xa330) { /* 10.2x - 20.4x gain */ |
---|
| 1017 | + *dgain_fine = gain_factor * 128 / 5110; |
---|
| 1018 | + } else if (gain_factor < 2550 * 8) { /* 10.2x - 20.4x gain */ |
---|
1004 | 1019 | *again = 0x49; |
---|
1005 | 1020 | *dgain = 0x00; |
---|
1006 | | - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 2; |
---|
1007 | | - } else if (total_gain < 0x14660) { /* 20.4x - 40.8x gain */ |
---|
| 1021 | + *dgain_fine = gain_factor * 128 / 10200; |
---|
| 1022 | + } else if (gain_factor < 2550 * 16) { /* 20.4x - 40.8x gain */ |
---|
1008 | 1023 | *again = 0x4B; |
---|
1009 | 1024 | *dgain = 0x00; |
---|
1010 | | - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 3; |
---|
1011 | | - } else if (total_gain < 0x28cc0) { /* 40.8x - 81.6x gain */ |
---|
| 1025 | + *dgain_fine = gain_factor * 128 / 20400; |
---|
| 1026 | + } else if (gain_factor < 2550 * 32) { /* 40.8x - 81.6x gain */ |
---|
1012 | 1027 | *again = 0x4f; |
---|
1013 | 1028 | *dgain = 0x00; |
---|
1014 | | - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 4; |
---|
1015 | | - } else if (total_gain < 0x51980) { /* 81.6x - 163.2x gain */ |
---|
| 1029 | + *dgain_fine = gain_factor * 128 / 40800; |
---|
| 1030 | + } else if (gain_factor < 2550 * 64) { /* 81.6x - 163.2x gain */ |
---|
1016 | 1031 | *again = 0x5f; |
---|
1017 | 1032 | *dgain = 0x00; |
---|
1018 | | - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 5; |
---|
1019 | | - } else if (total_gain < 0xa3300) { /* 163.2x - 326.4x gain */ |
---|
| 1033 | + *dgain_fine = gain_factor * 128 / 40800 / 2; |
---|
| 1034 | + } else if (gain_factor < 2550 * 128) { /* 163.2x - 326.4x gain */ |
---|
1020 | 1035 | *again = 0x5f; |
---|
1021 | 1036 | *dgain = 0x01; |
---|
1022 | | - *dgain_fine = (total_gain * 0x80 / 0x1466) >> 6; |
---|
| 1037 | + *dgain_fine = gain_factor * 128 / 40800 / 4; |
---|
1023 | 1038 | } |
---|
1024 | 1039 | } |
---|
1025 | 1040 | |
---|
.. | .. |
---|
1114 | 1129 | return ret; |
---|
1115 | 1130 | } |
---|
1116 | 1131 | |
---|
| 1132 | +static int sc530ai_get_channel_info(struct sc530ai *sc530ai, struct rkmodule_channel_info *ch_info) |
---|
| 1133 | +{ |
---|
| 1134 | + if (ch_info->index < PAD0 || ch_info->index >= PAD_MAX) |
---|
| 1135 | + return -EINVAL; |
---|
| 1136 | + ch_info->vc = sc530ai->cur_mode->vc[ch_info->index]; |
---|
| 1137 | + ch_info->width = sc530ai->cur_mode->width; |
---|
| 1138 | + ch_info->height = sc530ai->cur_mode->height; |
---|
| 1139 | + ch_info->bus_fmt = sc530ai->cur_mode->bus_fmt; |
---|
| 1140 | + return 0; |
---|
| 1141 | +} |
---|
| 1142 | + |
---|
1117 | 1143 | static long sc530ai_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) |
---|
1118 | 1144 | { |
---|
1119 | 1145 | struct sc530ai *sc530ai = to_sc530ai(sd); |
---|
1120 | 1146 | struct rkmodule_hdr_cfg *hdr; |
---|
1121 | 1147 | const struct sc530ai_mode *mode; |
---|
| 1148 | + struct rkmodule_channel_info *ch_info; |
---|
1122 | 1149 | |
---|
1123 | 1150 | long ret = 0; |
---|
1124 | 1151 | u32 i, h = 0, w; |
---|
.. | .. |
---|
1136 | 1163 | break; |
---|
1137 | 1164 | case RKMODULE_SET_HDR_CFG: |
---|
1138 | 1165 | hdr = (struct rkmodule_hdr_cfg *)arg; |
---|
1139 | | - w = sc530ai->cur_mode->mipi_freq_idx; |
---|
1140 | | - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { |
---|
1141 | | - if (w == supported_modes[i].mipi_freq_idx && |
---|
1142 | | - supported_modes[i].hdr_mode == hdr->hdr_mode) { |
---|
1143 | | - sc530ai->cur_mode = &supported_modes[i]; |
---|
| 1166 | + w = sc530ai->cur_mode->width; |
---|
| 1167 | + h = sc530ai->cur_mode->height; |
---|
| 1168 | + for (i = 0; i < sc530ai->support_modes_num; i++) { |
---|
| 1169 | + if (w == sc530ai->support_modes[i].width && |
---|
| 1170 | + h == sc530ai->support_modes[i].height && |
---|
| 1171 | + sc530ai->support_modes[i].hdr_mode == hdr->hdr_mode) { |
---|
| 1172 | + sc530ai->cur_mode = &sc530ai->support_modes[i]; |
---|
1144 | 1173 | break; |
---|
1145 | 1174 | } |
---|
1146 | 1175 | } |
---|
1147 | | - if (i == ARRAY_SIZE(supported_modes)) { |
---|
| 1176 | + if (i == sc530ai->support_modes_num) { |
---|
1148 | 1177 | dev_err(&sc530ai->client->dev, |
---|
1149 | 1178 | "not find hdr mode:%d %dx%d config\n", |
---|
1150 | 1179 | hdr->hdr_mode, w, h); |
---|
.. | .. |
---|
1169 | 1198 | |
---|
1170 | 1199 | __v4l2_ctrl_s_ctrl_int64(sc530ai->pixel_rate, |
---|
1171 | 1200 | pixel_rate); |
---|
1172 | | - |
---|
| 1201 | + sc530ai->cur_vts = mode->vts_def; |
---|
| 1202 | + sc530ai->cur_fps = mode->max_fps; |
---|
1173 | 1203 | dev_info(&sc530ai->client->dev, "sensor mode: %d\n", |
---|
1174 | 1204 | sc530ai->cur_mode->hdr_mode); |
---|
1175 | 1205 | } |
---|
.. | .. |
---|
1191 | 1221 | SC530AI_REG_VALUE_08BIT, |
---|
1192 | 1222 | SC530AI_MODE_SW_STANDBY); |
---|
1193 | 1223 | break; |
---|
| 1224 | + case RKMODULE_GET_CHANNEL_INFO: |
---|
| 1225 | + ch_info = (struct rkmodule_channel_info *)arg; |
---|
| 1226 | + ret = sc530ai_get_channel_info(sc530ai, ch_info); |
---|
| 1227 | + break; |
---|
1194 | 1228 | default: |
---|
1195 | 1229 | ret = -ENOIOCTLCMD; |
---|
1196 | 1230 | break; |
---|
.. | .. |
---|
1207 | 1241 | struct rkmodule_inf *inf; |
---|
1208 | 1242 | struct rkmodule_hdr_cfg *hdr; |
---|
1209 | 1243 | struct preisp_hdrae_exp_s *hdrae; |
---|
| 1244 | + struct rkmodule_channel_info *ch_info; |
---|
1210 | 1245 | long ret = 0; |
---|
1211 | 1246 | u32 stream = 0; |
---|
1212 | 1247 | |
---|
.. | .. |
---|
1276 | 1311 | return -EFAULT; |
---|
1277 | 1312 | |
---|
1278 | 1313 | ret = sc530ai_ioctl(sd, cmd, &stream); |
---|
| 1314 | + break; |
---|
| 1315 | + case RKMODULE_GET_CHANNEL_INFO: |
---|
| 1316 | + ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL); |
---|
| 1317 | + if (!ch_info) { |
---|
| 1318 | + ret = -ENOMEM; |
---|
| 1319 | + return ret; |
---|
| 1320 | + } |
---|
| 1321 | + |
---|
| 1322 | + ret = sc530ai_ioctl(sd, cmd, ch_info); |
---|
| 1323 | + if (!ret) { |
---|
| 1324 | + ret = copy_to_user(up, ch_info, sizeof(*ch_info)); |
---|
| 1325 | + if (ret) |
---|
| 1326 | + ret = -EFAULT; |
---|
| 1327 | + } |
---|
| 1328 | + kfree(ch_info); |
---|
1279 | 1329 | break; |
---|
1280 | 1330 | default: |
---|
1281 | 1331 | ret = -ENOIOCTLCMD; |
---|
.. | .. |
---|
1457 | 1507 | regulator_bulk_disable(sc530ai_NUM_SUPPLIES, sc530ai->supplies); |
---|
1458 | 1508 | } |
---|
1459 | 1509 | |
---|
1460 | | -static int sc530ai_runtime_resume(struct device *dev) |
---|
| 1510 | +static int __maybe_unused sc530ai_runtime_resume(struct device *dev) |
---|
1461 | 1511 | { |
---|
1462 | 1512 | struct i2c_client *client = to_i2c_client(dev); |
---|
1463 | 1513 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
---|
.. | .. |
---|
1466 | 1516 | return __sc530ai_power_on(sc530ai); |
---|
1467 | 1517 | } |
---|
1468 | 1518 | |
---|
1469 | | -static int sc530ai_runtime_suspend(struct device *dev) |
---|
| 1519 | +static int __maybe_unused sc530ai_runtime_suspend(struct device *dev) |
---|
1470 | 1520 | { |
---|
1471 | 1521 | struct i2c_client *client = to_i2c_client(dev); |
---|
1472 | 1522 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
---|
.. | .. |
---|
1483 | 1533 | struct sc530ai *sc530ai = to_sc530ai(sd); |
---|
1484 | 1534 | struct v4l2_mbus_framefmt *try_fmt = |
---|
1485 | 1535 | v4l2_subdev_get_try_format(sd, fh->pad, 0); |
---|
1486 | | - const struct sc530ai_mode *def_mode = &supported_modes[0]; |
---|
| 1536 | + const struct sc530ai_mode *def_mode = &sc530ai->support_modes[0]; |
---|
1487 | 1537 | |
---|
1488 | 1538 | mutex_lock(&sc530ai->mutex); |
---|
1489 | 1539 | /* Initialize try_fmt */ |
---|
.. | .. |
---|
1529 | 1579 | struct v4l2_subdev_pad_config *cfg, |
---|
1530 | 1580 | struct v4l2_subdev_frame_interval_enum *fie) |
---|
1531 | 1581 | { |
---|
1532 | | - if (fie->index >= ARRAY_SIZE(supported_modes)) |
---|
| 1582 | + struct sc530ai *sc530ai = to_sc530ai(sd); |
---|
| 1583 | + |
---|
| 1584 | + if (fie->index >= sc530ai->support_modes_num) |
---|
1533 | 1585 | return -EINVAL; |
---|
1534 | 1586 | |
---|
1535 | | - fie->code = supported_modes[fie->index].bus_fmt; |
---|
1536 | | - fie->width = supported_modes[fie->index].width; |
---|
1537 | | - fie->height = supported_modes[fie->index].height; |
---|
1538 | | - fie->interval = supported_modes[fie->index].max_fps; |
---|
1539 | | - fie->reserved[0] = supported_modes[fie->index].hdr_mode; |
---|
| 1587 | + fie->code = sc530ai->support_modes[fie->index].bus_fmt; |
---|
| 1588 | + fie->width = sc530ai->support_modes[fie->index].width; |
---|
| 1589 | + fie->height = sc530ai->support_modes[fie->index].height; |
---|
| 1590 | + fie->interval = sc530ai->support_modes[fie->index].max_fps; |
---|
| 1591 | + fie->reserved[0] = sc530ai->support_modes[fie->index].hdr_mode; |
---|
1540 | 1592 | return 0; |
---|
1541 | 1593 | } |
---|
1542 | 1594 | |
---|
.. | .. |
---|
1562 | 1614 | static const struct v4l2_subdev_video_ops sc530ai_video_ops = { |
---|
1563 | 1615 | .s_stream = sc530ai_s_stream, |
---|
1564 | 1616 | .g_frame_interval = sc530ai_g_frame_interval, |
---|
1565 | | - .g_mbus_config = sc530ai_g_mbus_config, |
---|
1566 | 1617 | }; |
---|
1567 | 1618 | |
---|
1568 | 1619 | static const struct v4l2_subdev_pad_ops sc530ai_pad_ops = { |
---|
.. | .. |
---|
1572 | 1623 | .get_fmt = sc530ai_get_fmt, |
---|
1573 | 1624 | .set_fmt = sc530ai_set_fmt, |
---|
1574 | 1625 | .get_selection = sc530ai_get_selection, |
---|
| 1626 | + .get_mbus_config = sc530ai_g_mbus_config, |
---|
1575 | 1627 | }; |
---|
1576 | 1628 | |
---|
1577 | 1629 | static const struct v4l2_subdev_ops sc530ai_subdev_ops = { |
---|
.. | .. |
---|
1579 | 1631 | .video = &sc530ai_video_ops, |
---|
1580 | 1632 | .pad = &sc530ai_pad_ops, |
---|
1581 | 1633 | }; |
---|
| 1634 | + |
---|
| 1635 | +static void sc530ai_modify_fps_info(struct sc530ai *sc5330ai) |
---|
| 1636 | +{ |
---|
| 1637 | + const struct sc530ai_mode *mode = sc5330ai->cur_mode; |
---|
| 1638 | + |
---|
| 1639 | + sc5330ai->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / |
---|
| 1640 | + sc5330ai->cur_vts; |
---|
| 1641 | +} |
---|
1582 | 1642 | |
---|
1583 | 1643 | static int sc530ai_set_ctrl(struct v4l2_ctrl *ctrl) |
---|
1584 | 1644 | { |
---|
.. | .. |
---|
1608 | 1668 | switch (ctrl->id) { |
---|
1609 | 1669 | case V4L2_CID_EXPOSURE: |
---|
1610 | 1670 | if (sc530ai->cur_mode->hdr_mode != NO_HDR) |
---|
1611 | | - return ret; |
---|
| 1671 | + goto ctrl_end; |
---|
1612 | 1672 | val = ctrl->val << 1; |
---|
1613 | 1673 | ret = sc530ai_write_reg(sc530ai->client, |
---|
1614 | 1674 | SC530AI_REG_EXPOSURE_H, |
---|
.. | .. |
---|
1627 | 1687 | break; |
---|
1628 | 1688 | case V4L2_CID_ANALOGUE_GAIN: |
---|
1629 | 1689 | if (sc530ai->cur_mode->hdr_mode != NO_HDR) |
---|
1630 | | - return ret; |
---|
| 1690 | + goto ctrl_end; |
---|
1631 | 1691 | |
---|
1632 | 1692 | sc530ai_get_gain_reg(ctrl->val, &again, &dgain, &dgain_fine); |
---|
1633 | 1693 | ret = sc530ai_write_reg(sc530ai->client, |
---|
.. | .. |
---|
1642 | 1702 | SC530AI_REG_ANA_GAIN, |
---|
1643 | 1703 | SC530AI_REG_VALUE_08BIT, |
---|
1644 | 1704 | again); |
---|
1645 | | - |
---|
| 1705 | + dev_dbg(&client->dev, "set gain 0x%x\n", ctrl->val); |
---|
1646 | 1706 | break; |
---|
1647 | 1707 | case V4L2_CID_VBLANK: |
---|
1648 | 1708 | vts = ctrl->val + sc530ai->cur_mode->height; |
---|
.. | .. |
---|
1654 | 1714 | SC530AI_REG_VTS_L, |
---|
1655 | 1715 | SC530AI_REG_VALUE_08BIT, |
---|
1656 | 1716 | vts & 0xff); |
---|
| 1717 | + if (!ret) |
---|
| 1718 | + sc530ai->cur_vts = vts; |
---|
| 1719 | + if (sc530ai->cur_vts != sc530ai->cur_mode->vts_def) |
---|
| 1720 | + sc530ai_modify_fps_info(sc530ai); |
---|
| 1721 | + dev_dbg(&client->dev, "set vblank 0x%x\n", ctrl->val); |
---|
1657 | 1722 | break; |
---|
1658 | 1723 | case V4L2_CID_HFLIP: |
---|
1659 | 1724 | ret = sc530ai_read_reg(sc530ai->client, SC530AI_FLIP_MIRROR_REG, |
---|
.. | .. |
---|
1691 | 1756 | break; |
---|
1692 | 1757 | } |
---|
1693 | 1758 | |
---|
| 1759 | +ctrl_end: |
---|
1694 | 1760 | pm_runtime_put(&client->dev); |
---|
1695 | 1761 | |
---|
1696 | 1762 | return ret; |
---|
.. | .. |
---|
1715 | 1781 | fwnode = of_fwnode_handle(endpoint); |
---|
1716 | 1782 | rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0); |
---|
1717 | 1783 | if (rval <= 0) { |
---|
1718 | | - dev_warn(dev, " Get mipi lane num failed!\n"); |
---|
1719 | | - return -1; |
---|
| 1784 | + dev_err(dev, " Get mipi lane num failed!\n"); |
---|
| 1785 | + return -EINVAL; |
---|
1720 | 1786 | } |
---|
1721 | 1787 | |
---|
1722 | 1788 | sc530ai->lane_num = rval; |
---|
| 1789 | + dev_info(dev, "lane_num = %d\n", sc530ai->lane_num); |
---|
1723 | 1790 | |
---|
1724 | 1791 | if (sc530ai->lane_num == 2) { |
---|
1725 | | - sc530ai->cur_mode = &supported_modes[2]; |
---|
1726 | | - dev_info(dev, "lane_num(%d)\n", sc530ai->lane_num); |
---|
1727 | | - } else if (sc530ai->lane_num == 2) { |
---|
1728 | | - sc530ai->cur_mode = &supported_modes[0]; |
---|
1729 | | - dev_info(dev, "lane_num(%d)\n", sc530ai->lane_num); |
---|
1730 | | - } else { |
---|
1731 | | - dev_err(dev, "unsupported lane_num(%d)\n", sc530ai->lane_num); |
---|
1732 | | - return -1; |
---|
| 1792 | + sc530ai->support_modes = supported_modes_2lane; |
---|
| 1793 | + sc530ai->support_modes_num = ARRAY_SIZE(supported_modes_2lane); |
---|
| 1794 | + } else if (sc530ai->lane_num == 4) { |
---|
| 1795 | + sc530ai->support_modes = supported_modes_4lane; |
---|
| 1796 | + sc530ai->support_modes_num = ARRAY_SIZE(supported_modes_4lane); |
---|
1733 | 1797 | } |
---|
| 1798 | + |
---|
| 1799 | + sc530ai->cur_mode = &sc530ai->support_modes[0]; |
---|
| 1800 | + |
---|
1734 | 1801 | return 0; |
---|
1735 | 1802 | } |
---|
1736 | 1803 | |
---|
.. | .. |
---|
1809 | 1876 | } |
---|
1810 | 1877 | sc530ai->subdev.ctrl_handler = handler; |
---|
1811 | 1878 | sc530ai->has_init_exp = false; |
---|
| 1879 | + sc530ai->cur_vts = mode->vts_def; |
---|
| 1880 | + sc530ai->cur_fps = mode->max_fps; |
---|
1812 | 1881 | |
---|
1813 | 1882 | return 0; |
---|
1814 | 1883 | |
---|
.. | .. |
---|
1857 | 1926 | struct v4l2_subdev *sd; |
---|
1858 | 1927 | char facing[2]; |
---|
1859 | 1928 | int ret; |
---|
1860 | | - u32 i, hdr_mode = 0; |
---|
| 1929 | + u32 hdr_mode = 0; |
---|
1861 | 1930 | |
---|
1862 | 1931 | dev_info(dev, "driver version: %02x.%02x.%02x", |
---|
1863 | 1932 | DRIVER_VERSION >> 16, |
---|
.. | .. |
---|
1883 | 1952 | } |
---|
1884 | 1953 | |
---|
1885 | 1954 | sc530ai->client = client; |
---|
1886 | | - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { |
---|
1887 | | - if (hdr_mode == supported_modes[i].hdr_mode) { |
---|
1888 | | - sc530ai->cur_mode = &supported_modes[i]; |
---|
1889 | | - break; |
---|
1890 | | - } |
---|
1891 | | - } |
---|
1892 | | - if (i == ARRAY_SIZE(supported_modes)) |
---|
1893 | | - sc530ai->cur_mode = &supported_modes[0]; |
---|
| 1955 | + |
---|
| 1956 | + ret = sc530ai_parse_of(sc530ai); |
---|
| 1957 | + if (ret) |
---|
| 1958 | + return -EINVAL; |
---|
1894 | 1959 | |
---|
1895 | 1960 | sc530ai->xvclk = devm_clk_get(dev, "xvclk"); |
---|
1896 | 1961 | if (IS_ERR(sc530ai->xvclk)) { |
---|
.. | .. |
---|
1928 | 1993 | dev_err(dev, "Failed to get power regulators\n"); |
---|
1929 | 1994 | return ret; |
---|
1930 | 1995 | } |
---|
1931 | | - |
---|
1932 | | - ret = sc530ai_parse_of(sc530ai); |
---|
1933 | | - if (ret != 0) |
---|
1934 | | - return -EINVAL; |
---|
1935 | 1996 | |
---|
1936 | 1997 | mutex_init(&sc530ai->mutex); |
---|
1937 | 1998 | |
---|