.. | .. |
---|
6 | 6 | * V0.0X01.0X00 first version. |
---|
7 | 7 | * V0.0X01.0X01 fix if plugin_gpio was not used. |
---|
8 | 8 | * V0.0X01.0X02 modify driver init level to late_initcall. |
---|
| 9 | + * V0.0X01.0X03 add 4K60 dual mipi support |
---|
| 10 | + * |
---|
9 | 11 | */ |
---|
10 | 12 | |
---|
11 | 13 | #include <linux/clk.h> |
---|
.. | .. |
---|
34 | 36 | #include <media/v4l2-fwnode.h> |
---|
35 | 37 | #include "lt6911uxc.h" |
---|
36 | 38 | |
---|
37 | | -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x2) |
---|
| 39 | +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x3) |
---|
38 | 40 | #define LT6911UXC_NAME "LT6911UXC" |
---|
39 | 41 | |
---|
40 | | -#define LT6911UXC_LINK_FREQ_HIGH 400000000 |
---|
41 | | -#define LT6911UXC_LINK_FREQ_LOW 200000000 |
---|
42 | | -#define LT6911UXC_PIXEL_RATE 400000000 |
---|
| 42 | +#define LT6911UXC_LINK_FREQ_650M 650000000 |
---|
| 43 | +#define LT6911UXC_LINK_FREQ_400M 400000000 |
---|
| 44 | +#define LT6911UXC_LINK_FREQ_300M 300000000 |
---|
| 45 | +#define LT6911UXC_LINK_FREQ_200M 200000000 |
---|
| 46 | +#define LT6911UXC_LINK_FREQ_100M 100000000 |
---|
| 47 | +#define LT6911UXC_LINK_FREQ_60M 60000000 |
---|
| 48 | +#define LT6911UXC_PIXEL_RATE 600000000 |
---|
43 | 49 | |
---|
44 | 50 | #define I2C_MAX_XFER_SIZE 128 |
---|
45 | 51 | |
---|
.. | .. |
---|
54 | 60 | MODULE_PARM_DESC(debug, "debug level (0-2)"); |
---|
55 | 61 | |
---|
56 | 62 | static const s64 link_freq_menu_items[] = { |
---|
57 | | - LT6911UXC_LINK_FREQ_HIGH, |
---|
58 | | - LT6911UXC_LINK_FREQ_LOW, |
---|
| 63 | + LT6911UXC_LINK_FREQ_650M, |
---|
| 64 | + LT6911UXC_LINK_FREQ_400M, |
---|
| 65 | + LT6911UXC_LINK_FREQ_300M, |
---|
| 66 | + LT6911UXC_LINK_FREQ_200M, |
---|
| 67 | + LT6911UXC_LINK_FREQ_100M, |
---|
| 68 | + LT6911UXC_LINK_FREQ_60M, |
---|
59 | 69 | }; |
---|
60 | 70 | |
---|
61 | 71 | struct lt6911uxc { |
---|
.. | .. |
---|
78 | 88 | struct v4l2_dv_timings timings; |
---|
79 | 89 | struct v4l2_fwnode_bus_mipi_csi2 bus; |
---|
80 | 90 | struct v4l2_subdev sd; |
---|
| 91 | + struct rkmodule_multi_dev_info multi_dev_info; |
---|
81 | 92 | const char *len_name; |
---|
82 | 93 | const char *module_facing; |
---|
83 | 94 | const char *module_name; |
---|
.. | .. |
---|
100 | 111 | u32 hts_def; |
---|
101 | 112 | u32 vts_def; |
---|
102 | 113 | u32 exp_def; |
---|
| 114 | + u32 mipi_freq_idx; |
---|
| 115 | +}; |
---|
| 116 | + |
---|
| 117 | +static struct rkmodule_csi_dphy_param rk3588_dcphy_param = { |
---|
| 118 | + .vendor = PHY_VENDOR_SAMSUNG, |
---|
| 119 | + .lp_vol_ref = 3, |
---|
| 120 | + .lp_hys_sw = {3, 0, 3, 0}, |
---|
| 121 | + .lp_escclk_pol_sel = {1, 1, 0, 0}, |
---|
| 122 | + .skew_data_cal_clk = {0, 0, 0, 0}, |
---|
| 123 | + .clk_hs_term_sel = 2, |
---|
| 124 | + .data_hs_term_sel = {2, 2, 2, 2}, |
---|
| 125 | + .reserved = {0}, |
---|
103 | 126 | }; |
---|
104 | 127 | |
---|
105 | 128 | static const struct v4l2_dv_timings_cap lt6911uxc_timings_cap = { |
---|
106 | 129 | .type = V4L2_DV_BT_656_1120, |
---|
107 | 130 | /* keep this initialization for compatibility with GCC < 4.4.6 */ |
---|
108 | 131 | .reserved = { 0 }, |
---|
109 | | - V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 400000000, |
---|
| 132 | + V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 600000000, |
---|
110 | 133 | V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | |
---|
111 | 134 | V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, |
---|
112 | 135 | V4L2_DV_BT_CAP_PROGRESSIVE | |
---|
.. | .. |
---|
121 | 144 | .height = 2160, |
---|
122 | 145 | .max_fps = { |
---|
123 | 146 | .numerator = 10000, |
---|
| 147 | + .denominator = 600000, |
---|
| 148 | + }, |
---|
| 149 | + .hts_def = 4400, |
---|
| 150 | + .vts_def = 2250, |
---|
| 151 | + .mipi_freq_idx = 0, |
---|
| 152 | + }, { |
---|
| 153 | + .width = 3840, |
---|
| 154 | + .height = 2160, |
---|
| 155 | + .max_fps = { |
---|
| 156 | + .numerator = 10000, |
---|
124 | 157 | .denominator = 300000, |
---|
125 | 158 | }, |
---|
126 | 159 | .hts_def = 4400, |
---|
127 | 160 | .vts_def = 2250, |
---|
| 161 | + .mipi_freq_idx = 0, |
---|
128 | 162 | }, { |
---|
129 | 163 | .width = 1920, |
---|
130 | 164 | .height = 1080, |
---|
.. | .. |
---|
134 | 168 | }, |
---|
135 | 169 | .hts_def = 2200, |
---|
136 | 170 | .vts_def = 1125, |
---|
| 171 | + .mipi_freq_idx = 2, |
---|
137 | 172 | }, { |
---|
138 | 173 | .width = 1920, |
---|
139 | 174 | .height = 540, |
---|
.. | .. |
---|
141 | 176 | .numerator = 10000, |
---|
142 | 177 | .denominator = 600000, |
---|
143 | 178 | }, |
---|
| 179 | + .mipi_freq_idx = 3, |
---|
144 | 180 | }, { |
---|
145 | 181 | .width = 1440, |
---|
146 | 182 | .height = 240, |
---|
.. | .. |
---|
148 | 184 | .numerator = 10000, |
---|
149 | 185 | .denominator = 600000, |
---|
150 | 186 | }, |
---|
| 187 | + .mipi_freq_idx = 4, |
---|
151 | 188 | }, { |
---|
152 | 189 | .width = 1440, |
---|
153 | 190 | .height = 288, |
---|
.. | .. |
---|
155 | 192 | .numerator = 10000, |
---|
156 | 193 | .denominator = 500000, |
---|
157 | 194 | }, |
---|
| 195 | + .mipi_freq_idx = 4, |
---|
158 | 196 | }, { |
---|
159 | 197 | .width = 1280, |
---|
160 | 198 | .height = 720, |
---|
.. | .. |
---|
164 | 202 | }, |
---|
165 | 203 | .hts_def = 1650, |
---|
166 | 204 | .vts_def = 750, |
---|
| 205 | + .mipi_freq_idx = 3, |
---|
167 | 206 | }, { |
---|
168 | 207 | .width = 720, |
---|
169 | 208 | .height = 576, |
---|
.. | .. |
---|
173 | 212 | }, |
---|
174 | 213 | .hts_def = 864, |
---|
175 | 214 | .vts_def = 625, |
---|
| 215 | + .mipi_freq_idx = 5, |
---|
176 | 216 | }, { |
---|
177 | 217 | .width = 720, |
---|
178 | 218 | .height = 480, |
---|
.. | .. |
---|
182 | 222 | }, |
---|
183 | 223 | .hts_def = 858, |
---|
184 | 224 | .vts_def = 525, |
---|
| 225 | + .mipi_freq_idx = 5, |
---|
185 | 226 | }, |
---|
186 | 227 | }; |
---|
187 | 228 | |
---|
.. | .. |
---|
390 | 431 | u8 value, val_h, val_l; |
---|
391 | 432 | u32 fw_ver, mipi_byte_clk, mipi_bitrate; |
---|
392 | 433 | u8 fw_a, fw_b, fw_c, fw_d, lanes; |
---|
| 434 | + u8 video_fmt; |
---|
393 | 435 | int ret; |
---|
394 | 436 | |
---|
395 | 437 | memset(timings, 0, sizeof(struct v4l2_dv_timings)); |
---|
.. | .. |
---|
421 | 463 | |
---|
422 | 464 | i2c_rd8(sd, MIPI_LANES, &lanes); |
---|
423 | 465 | lt6911uxc->csi_lanes_in_use = lanes; |
---|
| 466 | + if (lt6911uxc->csi_lanes_in_use == 8) |
---|
| 467 | + v4l2_info(sd, "get 8 lane in use, set dual mipi mode\n"); |
---|
424 | 468 | i2c_wr8(sd, FM1_DET_CLK_SRC_SEL, AD_LMTX_WRITE_CLK); |
---|
425 | 469 | i2c_rd8(sd, FREQ_METER_H, &clk_h); |
---|
426 | 470 | i2c_rd8(sd, FREQ_METER_M, &clk_m); |
---|
427 | 471 | i2c_rd8(sd, FREQ_METER_L, &clk_l); |
---|
428 | 472 | mipi_byte_clk = (((clk_h & 0xf) << 16) | (clk_m << 8) | clk_l); |
---|
429 | 473 | mipi_bitrate = mipi_byte_clk * 8 / 1000; |
---|
430 | | - v4l2_info(sd, "MIPI Byte clk: %dKHz, MIPI bitrate: %dMbps, lanes:%d\n", |
---|
| 474 | + v4l2_info(sd, "MIPI Byte clk: %uKHz, MIPI bitrate: %uMbps, lanes:%d\n", |
---|
431 | 475 | mipi_byte_clk, mipi_bitrate, lanes); |
---|
432 | 476 | |
---|
433 | 477 | i2c_rd8(sd, HTOTAL_H, &val_h); |
---|
.. | .. |
---|
457 | 501 | hbp = ((val_h << 8) | val_l) * 2; |
---|
458 | 502 | i2c_rd8(sd, VBP, &value); |
---|
459 | 503 | vbp = value; |
---|
| 504 | + i2c_rd8(sd, COLOR_FMT_STATUS, &video_fmt); |
---|
| 505 | + video_fmt = (video_fmt & GENMASK(6, 5)) >> 5; |
---|
460 | 506 | lt6911uxc_i2c_disable(sd); |
---|
| 507 | + |
---|
| 508 | + if (video_fmt == 0x3) { |
---|
| 509 | + lt6911uxc->nosignal = true; |
---|
| 510 | + v4l2_err(sd, "%s ERROR: HDMI input YUV420, don't support YUV420!\n", __func__); |
---|
| 511 | + return -EINVAL; |
---|
| 512 | + } |
---|
461 | 513 | |
---|
462 | 514 | if (!lt6911uxc_rcv_supported_res(sd, hact, vact)) { |
---|
463 | 515 | lt6911uxc->nosignal = true; |
---|
.. | .. |
---|
694 | 746 | } |
---|
695 | 747 | |
---|
696 | 748 | lt6911uxc->timings = *timings; |
---|
697 | | - |
---|
698 | 749 | enable_stream(sd, false); |
---|
699 | 750 | |
---|
700 | 751 | return 0; |
---|
.. | .. |
---|
771 | 822 | case 4: |
---|
772 | 823 | cfg->flags |= V4L2_MBUS_CSI2_4_LANE; |
---|
773 | 824 | break; |
---|
774 | | - |
---|
| 825 | + case 8: |
---|
| 826 | + cfg->flags |= V4L2_MBUS_CSI2_4_LANE; |
---|
| 827 | + break; |
---|
775 | 828 | default: |
---|
776 | 829 | return -EINVAL; |
---|
777 | 830 | } |
---|
.. | .. |
---|
836 | 889 | return 0; |
---|
837 | 890 | } |
---|
838 | 891 | |
---|
| 892 | +static int lt6911uxc_get_reso_dist(const struct lt6911uxc_mode *mode, |
---|
| 893 | + struct v4l2_dv_timings *timings) |
---|
| 894 | +{ |
---|
| 895 | + struct v4l2_bt_timings *bt = &timings->bt; |
---|
| 896 | + u32 cur_fps, dist_fps; |
---|
| 897 | + |
---|
| 898 | + cur_fps = fps_calc(bt); |
---|
| 899 | + dist_fps = DIV_ROUND_CLOSEST(mode->max_fps.denominator, mode->max_fps.numerator); |
---|
| 900 | + |
---|
| 901 | + return abs(mode->width - bt->width) + |
---|
| 902 | + abs(mode->height - bt->height) + abs(dist_fps - cur_fps); |
---|
| 903 | +} |
---|
| 904 | + |
---|
| 905 | +static const struct lt6911uxc_mode * |
---|
| 906 | +lt6911uxc_find_best_fit(struct lt6911uxc *lt6911uxc) |
---|
| 907 | +{ |
---|
| 908 | + int dist; |
---|
| 909 | + int cur_best_fit = 0; |
---|
| 910 | + int cur_best_fit_dist = -1; |
---|
| 911 | + unsigned int i; |
---|
| 912 | + |
---|
| 913 | + for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { |
---|
| 914 | + dist = lt6911uxc_get_reso_dist(&supported_modes[i], <6911uxc->timings); |
---|
| 915 | + if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { |
---|
| 916 | + cur_best_fit_dist = dist; |
---|
| 917 | + cur_best_fit = i; |
---|
| 918 | + } |
---|
| 919 | + } |
---|
| 920 | + dev_info(<6911uxc->i2c_client->dev, |
---|
| 921 | + "find current mode: support_mode[%d], %dx%d@%dfps\n", |
---|
| 922 | + cur_best_fit, supported_modes[cur_best_fit].width, |
---|
| 923 | + supported_modes[cur_best_fit].height, |
---|
| 924 | + DIV_ROUND_CLOSEST(supported_modes[cur_best_fit].max_fps.denominator, |
---|
| 925 | + supported_modes[cur_best_fit].max_fps.numerator)); |
---|
| 926 | + |
---|
| 927 | + return &supported_modes[cur_best_fit]; |
---|
| 928 | +} |
---|
| 929 | + |
---|
839 | 930 | static int lt6911uxc_get_fmt(struct v4l2_subdev *sd, |
---|
840 | 931 | struct v4l2_subdev_pad_config *cfg, |
---|
841 | 932 | struct v4l2_subdev_format *format) |
---|
842 | 933 | { |
---|
843 | 934 | struct lt6911uxc *lt6911uxc = to_state(sd); |
---|
| 935 | + const struct lt6911uxc_mode *mode; |
---|
844 | 936 | |
---|
845 | 937 | mutex_lock(<6911uxc->confctl_mutex); |
---|
846 | 938 | format->format.code = lt6911uxc->mbus_fmt_code; |
---|
.. | .. |
---|
850 | 942 | lt6911uxc->timings.bt.interlaced ? |
---|
851 | 943 | V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE; |
---|
852 | 944 | format->format.colorspace = V4L2_COLORSPACE_SRGB; |
---|
| 945 | + |
---|
| 946 | + mode = lt6911uxc_find_best_fit(lt6911uxc); |
---|
| 947 | + lt6911uxc->cur_mode = mode; |
---|
| 948 | + __v4l2_ctrl_s_ctrl_int64(lt6911uxc->pixel_rate, |
---|
| 949 | + LT6911UXC_PIXEL_RATE); |
---|
| 950 | + __v4l2_ctrl_s_ctrl(lt6911uxc->link_freq, |
---|
| 951 | + mode->mipi_freq_idx); |
---|
| 952 | + |
---|
853 | 953 | mutex_unlock(<6911uxc->confctl_mutex); |
---|
854 | 954 | |
---|
855 | 955 | v4l2_dbg(1, debug, sd, "%s: fmt code:%d, w:%d, h:%d, field mode:%s\n", |
---|
.. | .. |
---|
859 | 959 | return 0; |
---|
860 | 960 | } |
---|
861 | 961 | |
---|
862 | | -static int lt6911uxc_get_reso_dist(const struct lt6911uxc_mode *mode, |
---|
863 | | - struct v4l2_mbus_framefmt *framefmt) |
---|
864 | | -{ |
---|
865 | | - return abs(mode->width - framefmt->width) + |
---|
866 | | - abs(mode->height - framefmt->height); |
---|
867 | | -} |
---|
868 | | - |
---|
869 | | -static const struct lt6911uxc_mode * |
---|
870 | | -lt6911uxc_find_best_fit(struct v4l2_subdev_format *fmt) |
---|
871 | | -{ |
---|
872 | | - struct v4l2_mbus_framefmt *framefmt = &fmt->format; |
---|
873 | | - int dist; |
---|
874 | | - int cur_best_fit = 0; |
---|
875 | | - int cur_best_fit_dist = -1; |
---|
876 | | - unsigned int i; |
---|
877 | | - |
---|
878 | | - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { |
---|
879 | | - dist = lt6911uxc_get_reso_dist(&supported_modes[i], framefmt); |
---|
880 | | - if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { |
---|
881 | | - cur_best_fit_dist = dist; |
---|
882 | | - cur_best_fit = i; |
---|
883 | | - } |
---|
884 | | - } |
---|
885 | | - |
---|
886 | | - return &supported_modes[cur_best_fit]; |
---|
887 | | -} |
---|
888 | | - |
---|
889 | 962 | static int lt6911uxc_set_fmt(struct v4l2_subdev *sd, |
---|
890 | 963 | struct v4l2_subdev_pad_config *cfg, |
---|
891 | 964 | struct v4l2_subdev_format *format) |
---|
892 | 965 | { |
---|
893 | 966 | struct lt6911uxc *lt6911uxc = to_state(sd); |
---|
894 | 967 | const struct lt6911uxc_mode *mode; |
---|
895 | | - int index; |
---|
896 | 968 | |
---|
897 | 969 | /* is overwritten by get_fmt */ |
---|
898 | 970 | u32 code = format->format.code; |
---|
.. | .. |
---|
915 | 987 | return 0; |
---|
916 | 988 | |
---|
917 | 989 | lt6911uxc->mbus_fmt_code = format->format.code; |
---|
918 | | - mode = lt6911uxc_find_best_fit(format); |
---|
| 990 | + mode = lt6911uxc_find_best_fit(lt6911uxc); |
---|
919 | 991 | lt6911uxc->cur_mode = mode; |
---|
920 | 992 | enable_stream(sd, false); |
---|
921 | | - |
---|
922 | | - if (((mode->width == 720) && (mode->height == 576)) || |
---|
923 | | - ((mode->width == 720) && (mode->height == 480))) |
---|
924 | | - index = 1; |
---|
925 | | - else |
---|
926 | | - index = 0; |
---|
927 | | - |
---|
928 | | - __v4l2_ctrl_s_ctrl(lt6911uxc->link_freq, index); |
---|
929 | | - v4l2_dbg(1, debug, sd, "%s res wxh:%dx%d, link freq:%llu", __func__, |
---|
930 | | - mode->width, mode->height, link_freq_menu_items[index]); |
---|
931 | 993 | |
---|
932 | 994 | return 0; |
---|
933 | 995 | } |
---|
.. | .. |
---|
957 | 1019 | static long lt6911uxc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) |
---|
958 | 1020 | { |
---|
959 | 1021 | struct lt6911uxc *lt6911uxc = to_state(sd); |
---|
| 1022 | + struct device *dev = <6911uxc->i2c_client->dev; |
---|
960 | 1023 | long ret = 0; |
---|
| 1024 | + struct rkmodule_csi_dphy_param *dphy_param; |
---|
| 1025 | + struct rkmodule_capture_info *capture_info; |
---|
961 | 1026 | |
---|
962 | 1027 | switch (cmd) { |
---|
963 | 1028 | case RKMODULE_GET_MODULE_INFO: |
---|
.. | .. |
---|
965 | 1030 | break; |
---|
966 | 1031 | case RKMODULE_GET_HDMI_MODE: |
---|
967 | 1032 | *(int *)arg = RKMODULE_HDMIIN_MODE; |
---|
| 1033 | + break; |
---|
| 1034 | + case RKMODULE_SET_CSI_DPHY_PARAM: |
---|
| 1035 | + dphy_param = (struct rkmodule_csi_dphy_param *)arg; |
---|
| 1036 | + if (dphy_param->vendor == PHY_VENDOR_SAMSUNG) |
---|
| 1037 | + rk3588_dcphy_param = *dphy_param; |
---|
| 1038 | + dev_dbg(<6911uxc->i2c_client->dev, |
---|
| 1039 | + "sensor set dphy param\n"); |
---|
| 1040 | + break; |
---|
| 1041 | + case RKMODULE_GET_CSI_DPHY_PARAM: |
---|
| 1042 | + dphy_param = (struct rkmodule_csi_dphy_param *)arg; |
---|
| 1043 | + *dphy_param = rk3588_dcphy_param; |
---|
| 1044 | + dev_dbg(<6911uxc->i2c_client->dev, |
---|
| 1045 | + "sensor get dphy param\n"); |
---|
| 1046 | + break; |
---|
| 1047 | + case RKMODULE_GET_CAPTURE_MODE: |
---|
| 1048 | + capture_info = (struct rkmodule_capture_info *)arg; |
---|
| 1049 | + if (lt6911uxc->csi_lanes_in_use == 8) { |
---|
| 1050 | + dev_info(dev, "8 lanes in use, set dual mipi mode\n"); |
---|
| 1051 | + capture_info->mode = RKMODULE_MULTI_DEV_COMBINE_ONE; |
---|
| 1052 | + capture_info->multi_dev = lt6911uxc->multi_dev_info; |
---|
| 1053 | + } else { |
---|
| 1054 | + capture_info->mode = 0; |
---|
| 1055 | + } |
---|
968 | 1056 | break; |
---|
969 | 1057 | default: |
---|
970 | 1058 | ret = -ENOIOCTLCMD; |
---|
.. | .. |
---|
982 | 1070 | struct rkmodule_inf *inf; |
---|
983 | 1071 | long ret; |
---|
984 | 1072 | int *seq; |
---|
| 1073 | + struct rkmodule_csi_dphy_param *dphy_param; |
---|
| 1074 | + struct rkmodule_capture_info *capture_info; |
---|
985 | 1075 | |
---|
986 | 1076 | switch (cmd) { |
---|
987 | 1077 | case RKMODULE_GET_MODULE_INFO: |
---|
.. | .. |
---|
1013 | 1103 | ret = -EFAULT; |
---|
1014 | 1104 | } |
---|
1015 | 1105 | kfree(seq); |
---|
| 1106 | + break; |
---|
| 1107 | + case RKMODULE_SET_CSI_DPHY_PARAM: |
---|
| 1108 | + dphy_param = kzalloc(sizeof(*dphy_param), GFP_KERNEL); |
---|
| 1109 | + if (!dphy_param) { |
---|
| 1110 | + ret = -ENOMEM; |
---|
| 1111 | + return ret; |
---|
| 1112 | + } |
---|
| 1113 | + |
---|
| 1114 | + ret = copy_from_user(dphy_param, up, sizeof(*dphy_param)); |
---|
| 1115 | + if (!ret) |
---|
| 1116 | + ret = lt6911uxc_ioctl(sd, cmd, dphy_param); |
---|
| 1117 | + else |
---|
| 1118 | + ret = -EFAULT; |
---|
| 1119 | + kfree(dphy_param); |
---|
| 1120 | + break; |
---|
| 1121 | + case RKMODULE_GET_CSI_DPHY_PARAM: |
---|
| 1122 | + dphy_param = kzalloc(sizeof(*dphy_param), GFP_KERNEL); |
---|
| 1123 | + if (!dphy_param) { |
---|
| 1124 | + ret = -ENOMEM; |
---|
| 1125 | + return ret; |
---|
| 1126 | + } |
---|
| 1127 | + |
---|
| 1128 | + ret = lt6911uxc_ioctl(sd, cmd, dphy_param); |
---|
| 1129 | + if (!ret) { |
---|
| 1130 | + ret = copy_to_user(up, dphy_param, sizeof(*dphy_param)); |
---|
| 1131 | + if (ret) |
---|
| 1132 | + ret = -EFAULT; |
---|
| 1133 | + } |
---|
| 1134 | + kfree(dphy_param); |
---|
| 1135 | + break; |
---|
| 1136 | + case RKMODULE_GET_CAPTURE_MODE: |
---|
| 1137 | + capture_info = kzalloc(sizeof(*capture_info), GFP_KERNEL); |
---|
| 1138 | + if (!capture_info) { |
---|
| 1139 | + ret = -ENOMEM; |
---|
| 1140 | + return ret; |
---|
| 1141 | + } |
---|
| 1142 | + |
---|
| 1143 | + ret = lt6911uxc_ioctl(sd, cmd, capture_info); |
---|
| 1144 | + if (!ret) { |
---|
| 1145 | + ret = copy_to_user(up, capture_info, sizeof(*capture_info)); |
---|
| 1146 | + if (ret) |
---|
| 1147 | + ret = -EFAULT; |
---|
| 1148 | + } |
---|
| 1149 | + kfree(capture_info); |
---|
1016 | 1150 | break; |
---|
1017 | 1151 | default: |
---|
1018 | 1152 | ret = -ENOIOCTLCMD; |
---|
.. | .. |
---|
1093 | 1227 | |
---|
1094 | 1228 | static int lt6911uxc_init_v4l2_ctrls(struct lt6911uxc *lt6911uxc) |
---|
1095 | 1229 | { |
---|
| 1230 | + const struct lt6911uxc_mode *mode; |
---|
1096 | 1231 | struct v4l2_subdev *sd; |
---|
1097 | 1232 | int ret; |
---|
1098 | 1233 | |
---|
| 1234 | + mode = lt6911uxc->cur_mode; |
---|
1099 | 1235 | sd = <6911uxc->sd; |
---|
1100 | 1236 | ret = v4l2_ctrl_handler_init(<6911uxc->hdl, 5); |
---|
1101 | 1237 | if (ret) |
---|
.. | .. |
---|
1105 | 1241 | V4L2_CID_LINK_FREQ, |
---|
1106 | 1242 | ARRAY_SIZE(link_freq_menu_items) - 1, 0, |
---|
1107 | 1243 | link_freq_menu_items); |
---|
1108 | | - v4l2_ctrl_new_std(<6911uxc->hdl, NULL, V4L2_CID_PIXEL_RATE, |
---|
1109 | | - 0, LT6911UXC_PIXEL_RATE, 1, LT6911UXC_PIXEL_RATE); |
---|
| 1244 | + lt6911uxc->pixel_rate = v4l2_ctrl_new_std(<6911uxc->hdl, NULL, |
---|
| 1245 | + V4L2_CID_PIXEL_RATE, |
---|
| 1246 | + 0, LT6911UXC_PIXEL_RATE, 1, LT6911UXC_PIXEL_RATE); |
---|
1110 | 1247 | |
---|
1111 | 1248 | lt6911uxc->detect_tx_5v_ctrl = v4l2_ctrl_new_std(<6911uxc->hdl, |
---|
1112 | 1249 | NULL, V4L2_CID_DV_RX_POWER_PRESENT, |
---|
.. | .. |
---|
1124 | 1261 | v4l2_err(sd, "cfg v4l2 ctrls failed! ret:%d\n", ret); |
---|
1125 | 1262 | return ret; |
---|
1126 | 1263 | } |
---|
| 1264 | + |
---|
| 1265 | + __v4l2_ctrl_s_ctrl(lt6911uxc->link_freq, mode->mipi_freq_idx); |
---|
| 1266 | + __v4l2_ctrl_s_ctrl_int64(lt6911uxc->pixel_rate, LT6911UXC_PIXEL_RATE); |
---|
1127 | 1267 | |
---|
1128 | 1268 | if (lt6911uxc_update_controls(sd)) { |
---|
1129 | 1269 | ret = -ENODEV; |
---|
.. | .. |
---|
1309 | 1449 | }; |
---|
1310 | 1450 | ATTRIBUTE_GROUPS(lt6911); |
---|
1311 | 1451 | |
---|
| 1452 | +static int lt6911uxc_get_multi_dev_info(struct lt6911uxc *lt6911uxc) |
---|
| 1453 | +{ |
---|
| 1454 | + struct device *dev = <6911uxc->i2c_client->dev; |
---|
| 1455 | + struct device_node *node = dev->of_node; |
---|
| 1456 | + struct device_node *multi_info_np; |
---|
| 1457 | + |
---|
| 1458 | + multi_info_np = of_get_child_by_name(node, "multi-dev-info"); |
---|
| 1459 | + if (!multi_info_np) { |
---|
| 1460 | + dev_info(dev, "failed to get multi dev info\n"); |
---|
| 1461 | + return -EINVAL; |
---|
| 1462 | + } |
---|
| 1463 | + |
---|
| 1464 | + of_property_read_u32(multi_info_np, "dev-idx-l", |
---|
| 1465 | + <6911uxc->multi_dev_info.dev_idx[0]); |
---|
| 1466 | + of_property_read_u32(multi_info_np, "dev-idx-r", |
---|
| 1467 | + <6911uxc->multi_dev_info.dev_idx[1]); |
---|
| 1468 | + of_property_read_u32(multi_info_np, "combine-idx", |
---|
| 1469 | + <6911uxc->multi_dev_info.combine_idx[0]); |
---|
| 1470 | + of_property_read_u32(multi_info_np, "pixel-offset", |
---|
| 1471 | + <6911uxc->multi_dev_info.pixel_offset); |
---|
| 1472 | + of_property_read_u32(multi_info_np, "dev-num", |
---|
| 1473 | + <6911uxc->multi_dev_info.dev_num); |
---|
| 1474 | + dev_info(dev, |
---|
| 1475 | + "multi dev left: mipi%d, multi dev right: mipi%d, combile mipi%d, dev num: %d\n", |
---|
| 1476 | + lt6911uxc->multi_dev_info.dev_idx[0], lt6911uxc->multi_dev_info.dev_idx[1], |
---|
| 1477 | + lt6911uxc->multi_dev_info.combine_idx[0], lt6911uxc->multi_dev_info.dev_num); |
---|
| 1478 | + |
---|
| 1479 | + return 0; |
---|
| 1480 | +} |
---|
| 1481 | + |
---|
1312 | 1482 | static int lt6911uxc_probe(struct i2c_client *client, |
---|
1313 | 1483 | const struct i2c_device_id *id) |
---|
1314 | 1484 | { |
---|
.. | .. |
---|
1340 | 1510 | v4l2_err(sd, "lt6911uxc_parse_of failed! err:%d\n", err); |
---|
1341 | 1511 | return err; |
---|
1342 | 1512 | } |
---|
| 1513 | + |
---|
| 1514 | + err = lt6911uxc_get_multi_dev_info(lt6911uxc); |
---|
| 1515 | + if (err) |
---|
| 1516 | + v4l2_info(sd, "get multi dev info failed, not use dual mipi mode\n"); |
---|
1343 | 1517 | |
---|
1344 | 1518 | err = lt6911uxc_check_chip_id(lt6911uxc); |
---|
1345 | 1519 | if (err < 0) |
---|
.. | .. |
---|
1497 | 1671 | i2c_del_driver(<6911uxc_driver); |
---|
1498 | 1672 | } |
---|
1499 | 1673 | |
---|
1500 | | -late_initcall(lt6911uxc_driver_init); |
---|
| 1674 | +device_initcall_sync(lt6911uxc_driver_init); |
---|
1501 | 1675 | module_exit(lt6911uxc_driver_exit); |
---|
1502 | 1676 | |
---|
1503 | 1677 | MODULE_DESCRIPTION("Lontium LT6911UXC HDMI to MIPI CSI-2 bridge driver"); |
---|
1504 | 1678 | MODULE_AUTHOR("Dingxian Wen <shawn.wen@rock-chips.com>"); |
---|
| 1679 | +MODULE_AUTHOR("Jianwei Fan <jianwei.fan@rock-chips.com>"); |
---|
1505 | 1680 | MODULE_LICENSE("GPL v2"); |
---|