.. | .. |
---|
3 | 3 | * Copyright (c) 2021 Rockchip Electronics Co. Ltd. |
---|
4 | 4 | * |
---|
5 | 5 | * Author: Dingxian Wen <shawn.wen@rock-chips.com> |
---|
| 6 | + * V0.0X01.0X00 first version. |
---|
| 7 | + * V0.0X01.0X01 fix if plugin_gpio was not used. |
---|
| 8 | + * V0.0X01.0X02 modify driver init level to late_initcall. |
---|
| 9 | + * V0.0X01.0X03 add 4K60 dual mipi support |
---|
| 10 | + * |
---|
6 | 11 | */ |
---|
7 | 12 | |
---|
8 | 13 | #include <linux/clk.h> |
---|
.. | .. |
---|
15 | 20 | #include <linux/module.h> |
---|
16 | 21 | #include <linux/of_graph.h> |
---|
17 | 22 | #include <linux/rk-camera-module.h> |
---|
| 23 | +#include <linux/rk_hdmirx_class.h> |
---|
18 | 24 | #include <linux/slab.h> |
---|
19 | 25 | #include <linux/timer.h> |
---|
20 | 26 | #include <linux/v4l2-dv-timings.h> |
---|
21 | 27 | #include <linux/version.h> |
---|
22 | 28 | #include <linux/videodev2.h> |
---|
23 | 29 | #include <linux/workqueue.h> |
---|
| 30 | +#include <linux/compat.h> |
---|
24 | 31 | #include <media/v4l2-controls_rockchip.h> |
---|
25 | 32 | #include <media/v4l2-ctrls.h> |
---|
26 | 33 | #include <media/v4l2-device.h> |
---|
.. | .. |
---|
29 | 36 | #include <media/v4l2-fwnode.h> |
---|
30 | 37 | #include "lt6911uxc.h" |
---|
31 | 38 | |
---|
32 | | -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x0) |
---|
| 39 | +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x3) |
---|
33 | 40 | #define LT6911UXC_NAME "LT6911UXC" |
---|
34 | 41 | |
---|
35 | | -#define LT6911UXC_LINK_FREQ_HIGH 400000000 |
---|
36 | | -#define LT6911UXC_LINK_FREQ_LOW 200000000 |
---|
37 | | -#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 |
---|
38 | 49 | |
---|
39 | 50 | #define I2C_MAX_XFER_SIZE 128 |
---|
| 51 | + |
---|
| 52 | +#ifdef LT6911UXC_OUT_RGB |
---|
| 53 | +#define LT6911UXC_MEDIA_BUS_FMT MEDIA_BUS_FMT_BGR888_1X24 |
---|
| 54 | +#else |
---|
| 55 | +#define LT6911UXC_MEDIA_BUS_FMT MEDIA_BUS_FMT_UYVY8_2X8 |
---|
| 56 | +#endif |
---|
40 | 57 | |
---|
41 | 58 | static int debug; |
---|
42 | 59 | module_param(debug, int, 0644); |
---|
43 | 60 | MODULE_PARM_DESC(debug, "debug level (0-2)"); |
---|
44 | 61 | |
---|
45 | 62 | static const s64 link_freq_menu_items[] = { |
---|
46 | | - LT6911UXC_LINK_FREQ_HIGH, |
---|
47 | | - 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, |
---|
48 | 69 | }; |
---|
49 | 70 | |
---|
50 | 71 | struct lt6911uxc { |
---|
.. | .. |
---|
67 | 88 | struct v4l2_dv_timings timings; |
---|
68 | 89 | struct v4l2_fwnode_bus_mipi_csi2 bus; |
---|
69 | 90 | struct v4l2_subdev sd; |
---|
| 91 | + struct rkmodule_multi_dev_info multi_dev_info; |
---|
70 | 92 | const char *len_name; |
---|
71 | 93 | const char *module_facing; |
---|
72 | 94 | const char *module_name; |
---|
.. | .. |
---|
79 | 101 | u32 module_index; |
---|
80 | 102 | u32 csi_lanes_in_use; |
---|
81 | 103 | u32 audio_sampling_rate; |
---|
| 104 | + struct device *classdev; |
---|
82 | 105 | }; |
---|
83 | 106 | |
---|
84 | 107 | struct lt6911uxc_mode { |
---|
.. | .. |
---|
88 | 111 | u32 hts_def; |
---|
89 | 112 | u32 vts_def; |
---|
90 | 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}, |
---|
91 | 126 | }; |
---|
92 | 127 | |
---|
93 | 128 | static const struct v4l2_dv_timings_cap lt6911uxc_timings_cap = { |
---|
94 | 129 | .type = V4L2_DV_BT_656_1120, |
---|
95 | 130 | /* keep this initialization for compatibility with GCC < 4.4.6 */ |
---|
96 | 131 | .reserved = { 0 }, |
---|
97 | | - V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 400000000, |
---|
| 132 | + V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 600000000, |
---|
98 | 133 | V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | |
---|
99 | 134 | V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, |
---|
100 | 135 | V4L2_DV_BT_CAP_PROGRESSIVE | |
---|
.. | .. |
---|
109 | 144 | .height = 2160, |
---|
110 | 145 | .max_fps = { |
---|
111 | 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, |
---|
112 | 157 | .denominator = 300000, |
---|
113 | 158 | }, |
---|
114 | 159 | .hts_def = 4400, |
---|
115 | 160 | .vts_def = 2250, |
---|
| 161 | + .mipi_freq_idx = 0, |
---|
116 | 162 | }, { |
---|
117 | 163 | .width = 1920, |
---|
118 | 164 | .height = 1080, |
---|
.. | .. |
---|
122 | 168 | }, |
---|
123 | 169 | .hts_def = 2200, |
---|
124 | 170 | .vts_def = 1125, |
---|
| 171 | + .mipi_freq_idx = 2, |
---|
125 | 172 | }, { |
---|
126 | 173 | .width = 1920, |
---|
127 | 174 | .height = 540, |
---|
.. | .. |
---|
129 | 176 | .numerator = 10000, |
---|
130 | 177 | .denominator = 600000, |
---|
131 | 178 | }, |
---|
| 179 | + .mipi_freq_idx = 3, |
---|
132 | 180 | }, { |
---|
133 | 181 | .width = 1440, |
---|
134 | 182 | .height = 240, |
---|
.. | .. |
---|
136 | 184 | .numerator = 10000, |
---|
137 | 185 | .denominator = 600000, |
---|
138 | 186 | }, |
---|
| 187 | + .mipi_freq_idx = 4, |
---|
139 | 188 | }, { |
---|
140 | 189 | .width = 1440, |
---|
141 | 190 | .height = 288, |
---|
.. | .. |
---|
143 | 192 | .numerator = 10000, |
---|
144 | 193 | .denominator = 500000, |
---|
145 | 194 | }, |
---|
| 195 | + .mipi_freq_idx = 4, |
---|
146 | 196 | }, { |
---|
147 | 197 | .width = 1280, |
---|
148 | 198 | .height = 720, |
---|
.. | .. |
---|
152 | 202 | }, |
---|
153 | 203 | .hts_def = 1650, |
---|
154 | 204 | .vts_def = 750, |
---|
| 205 | + .mipi_freq_idx = 3, |
---|
155 | 206 | }, { |
---|
156 | 207 | .width = 720, |
---|
157 | 208 | .height = 576, |
---|
.. | .. |
---|
161 | 212 | }, |
---|
162 | 213 | .hts_def = 864, |
---|
163 | 214 | .vts_def = 625, |
---|
| 215 | + .mipi_freq_idx = 5, |
---|
164 | 216 | }, { |
---|
165 | 217 | .width = 720, |
---|
166 | 218 | .height = 480, |
---|
.. | .. |
---|
170 | 222 | }, |
---|
171 | 223 | .hts_def = 858, |
---|
172 | 224 | .vts_def = 525, |
---|
| 225 | + .mipi_freq_idx = 5, |
---|
173 | 226 | }, |
---|
174 | 227 | }; |
---|
175 | 228 | |
---|
.. | .. |
---|
286 | 339 | |
---|
287 | 340 | static inline bool tx_5v_power_present(struct v4l2_subdev *sd) |
---|
288 | 341 | { |
---|
289 | | - int val; |
---|
| 342 | + bool ret; |
---|
| 343 | + int val, i, cnt; |
---|
290 | 344 | struct lt6911uxc *lt6911uxc = to_state(sd); |
---|
291 | 345 | |
---|
292 | | - val = gpiod_get_value(lt6911uxc->plugin_det_gpio); |
---|
293 | | - v4l2_dbg(1, debug, sd, "%s plug det: %s!\n", __func__, |
---|
294 | | - (val > 0) ? "int" : "out"); |
---|
| 346 | + /* if not use plugin det gpio */ |
---|
| 347 | + if (!lt6911uxc->plugin_det_gpio) |
---|
| 348 | + return true; |
---|
295 | 349 | |
---|
296 | | - return (val > 0); |
---|
| 350 | + cnt = 0; |
---|
| 351 | + for (i = 0; i < 5; i++) { |
---|
| 352 | + val = gpiod_get_value(lt6911uxc->plugin_det_gpio); |
---|
| 353 | + |
---|
| 354 | + if (val > 0) |
---|
| 355 | + cnt++; |
---|
| 356 | + usleep_range(500, 600); |
---|
| 357 | + } |
---|
| 358 | + |
---|
| 359 | + ret = (cnt >= 3) ? true : false; |
---|
| 360 | + v4l2_dbg(1, debug, sd, "%s: %d\n", __func__, ret); |
---|
| 361 | + |
---|
| 362 | + return ret; |
---|
297 | 363 | } |
---|
298 | 364 | |
---|
299 | 365 | static inline bool no_signal(struct v4l2_subdev *sd) |
---|
.. | .. |
---|
365 | 431 | u8 value, val_h, val_l; |
---|
366 | 432 | u32 fw_ver, mipi_byte_clk, mipi_bitrate; |
---|
367 | 433 | u8 fw_a, fw_b, fw_c, fw_d, lanes; |
---|
| 434 | + u8 video_fmt; |
---|
368 | 435 | int ret; |
---|
369 | 436 | |
---|
370 | 437 | memset(timings, 0, sizeof(struct v4l2_dv_timings)); |
---|
.. | .. |
---|
396 | 463 | |
---|
397 | 464 | i2c_rd8(sd, MIPI_LANES, &lanes); |
---|
398 | 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"); |
---|
399 | 468 | i2c_wr8(sd, FM1_DET_CLK_SRC_SEL, AD_LMTX_WRITE_CLK); |
---|
400 | 469 | i2c_rd8(sd, FREQ_METER_H, &clk_h); |
---|
401 | 470 | i2c_rd8(sd, FREQ_METER_M, &clk_m); |
---|
402 | 471 | i2c_rd8(sd, FREQ_METER_L, &clk_l); |
---|
403 | 472 | mipi_byte_clk = (((clk_h & 0xf) << 16) | (clk_m << 8) | clk_l); |
---|
404 | 473 | mipi_bitrate = mipi_byte_clk * 8 / 1000; |
---|
405 | | - 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", |
---|
406 | 475 | mipi_byte_clk, mipi_bitrate, lanes); |
---|
407 | 476 | |
---|
408 | 477 | i2c_rd8(sd, HTOTAL_H, &val_h); |
---|
.. | .. |
---|
432 | 501 | hbp = ((val_h << 8) | val_l) * 2; |
---|
433 | 502 | i2c_rd8(sd, VBP, &value); |
---|
434 | 503 | vbp = value; |
---|
| 504 | + i2c_rd8(sd, COLOR_FMT_STATUS, &video_fmt); |
---|
| 505 | + video_fmt = (video_fmt & GENMASK(6, 5)) >> 5; |
---|
435 | 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 | + } |
---|
436 | 513 | |
---|
437 | 514 | if (!lt6911uxc_rcv_supported_res(sd, hact, vact)) { |
---|
438 | 515 | lt6911uxc->nosignal = true; |
---|
.. | .. |
---|
505 | 582 | struct v4l2_subdev *sd = <6911uxc->sd; |
---|
506 | 583 | |
---|
507 | 584 | v4l2_dbg(2, debug, sd, "%s:\n", __func__); |
---|
| 585 | + |
---|
| 586 | + v4l2_ctrl_s_ctrl(lt6911uxc->detect_tx_5v_ctrl, tx_5v_power_present(sd)); |
---|
508 | 587 | lt6911uxc_config_hpd(sd); |
---|
509 | 588 | } |
---|
510 | 589 | |
---|
.. | .. |
---|
589 | 668 | v4l2_subdev_notify_event(sd, <6911uxc_ev_fmt); |
---|
590 | 669 | } |
---|
591 | 670 | |
---|
592 | | -static int lt6911uxc_get_ctrl(struct v4l2_ctrl *ctrl) |
---|
593 | | -{ |
---|
594 | | - int ret = -1; |
---|
595 | | - struct lt6911uxc *lt6911uxc = container_of(ctrl->handler, |
---|
596 | | - struct lt6911uxc, hdl); |
---|
597 | | - struct v4l2_subdev *sd = &(lt6911uxc->sd); |
---|
598 | | - |
---|
599 | | - if (ctrl->id == V4L2_CID_DV_RX_POWER_PRESENT) { |
---|
600 | | - ret = tx_5v_power_present(sd); |
---|
601 | | - *ctrl->p_new.p_s32 = ret; |
---|
602 | | - } |
---|
603 | | - |
---|
604 | | - return ret; |
---|
605 | | -} |
---|
606 | | - |
---|
607 | 671 | static int lt6911uxc_isr(struct v4l2_subdev *sd, u32 status, bool *handled) |
---|
608 | 672 | { |
---|
609 | 673 | struct lt6911uxc *lt6911uxc = to_state(sd); |
---|
.. | .. |
---|
682 | 746 | } |
---|
683 | 747 | |
---|
684 | 748 | lt6911uxc->timings = *timings; |
---|
685 | | - |
---|
686 | 749 | enable_stream(sd, false); |
---|
687 | 750 | |
---|
688 | 751 | return 0; |
---|
.. | .. |
---|
738 | 801 | return 0; |
---|
739 | 802 | } |
---|
740 | 803 | |
---|
741 | | -static int lt6911uxc_g_mbus_config(struct v4l2_subdev *sd, |
---|
| 804 | +static int lt6911uxc_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad, |
---|
742 | 805 | struct v4l2_mbus_config *cfg) |
---|
743 | 806 | { |
---|
744 | 807 | struct lt6911uxc *lt6911uxc = to_state(sd); |
---|
745 | 808 | |
---|
746 | | - cfg->type = V4L2_MBUS_CSI2; |
---|
| 809 | + cfg->type = V4L2_MBUS_CSI2_DPHY; |
---|
747 | 810 | cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | V4L2_MBUS_CSI2_CHANNEL_0; |
---|
748 | 811 | |
---|
749 | 812 | switch (lt6911uxc->csi_lanes_in_use) { |
---|
.. | .. |
---|
759 | 822 | case 4: |
---|
760 | 823 | cfg->flags |= V4L2_MBUS_CSI2_4_LANE; |
---|
761 | 824 | break; |
---|
762 | | - |
---|
| 825 | + case 8: |
---|
| 826 | + cfg->flags |= V4L2_MBUS_CSI2_4_LANE; |
---|
| 827 | + break; |
---|
763 | 828 | default: |
---|
764 | 829 | return -EINVAL; |
---|
765 | 830 | } |
---|
.. | .. |
---|
780 | 845 | { |
---|
781 | 846 | switch (code->index) { |
---|
782 | 847 | case 0: |
---|
783 | | - code->code = MEDIA_BUS_FMT_UYVY8_2X8; |
---|
| 848 | + code->code = LT6911UXC_MEDIA_BUS_FMT; |
---|
784 | 849 | break; |
---|
785 | 850 | |
---|
786 | 851 | default: |
---|
.. | .. |
---|
797 | 862 | if (fse->index >= ARRAY_SIZE(supported_modes)) |
---|
798 | 863 | return -EINVAL; |
---|
799 | 864 | |
---|
800 | | - if (fse->code != MEDIA_BUS_FMT_UYVY8_2X8) |
---|
| 865 | + if (fse->code != LT6911UXC_MEDIA_BUS_FMT) |
---|
801 | 866 | return -EINVAL; |
---|
802 | 867 | |
---|
803 | 868 | fse->min_width = supported_modes[fse->index].width; |
---|
.. | .. |
---|
815 | 880 | if (fie->index >= ARRAY_SIZE(supported_modes)) |
---|
816 | 881 | return -EINVAL; |
---|
817 | 882 | |
---|
818 | | - if (fie->code != MEDIA_BUS_FMT_UYVY8_2X8) |
---|
819 | | - return -EINVAL; |
---|
| 883 | + fie->code = LT6911UXC_MEDIA_BUS_FMT; |
---|
820 | 884 | |
---|
821 | 885 | fie->width = supported_modes[fie->index].width; |
---|
822 | 886 | fie->height = supported_modes[fie->index].height; |
---|
.. | .. |
---|
825 | 889 | return 0; |
---|
826 | 890 | } |
---|
827 | 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 | + |
---|
828 | 930 | static int lt6911uxc_get_fmt(struct v4l2_subdev *sd, |
---|
829 | 931 | struct v4l2_subdev_pad_config *cfg, |
---|
830 | 932 | struct v4l2_subdev_format *format) |
---|
831 | 933 | { |
---|
832 | 934 | struct lt6911uxc *lt6911uxc = to_state(sd); |
---|
| 935 | + const struct lt6911uxc_mode *mode; |
---|
833 | 936 | |
---|
834 | 937 | mutex_lock(<6911uxc->confctl_mutex); |
---|
835 | 938 | format->format.code = lt6911uxc->mbus_fmt_code; |
---|
.. | .. |
---|
839 | 942 | lt6911uxc->timings.bt.interlaced ? |
---|
840 | 943 | V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE; |
---|
841 | 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 | + |
---|
842 | 953 | mutex_unlock(<6911uxc->confctl_mutex); |
---|
843 | 954 | |
---|
844 | 955 | v4l2_dbg(1, debug, sd, "%s: fmt code:%d, w:%d, h:%d, field mode:%s\n", |
---|
.. | .. |
---|
848 | 959 | return 0; |
---|
849 | 960 | } |
---|
850 | 961 | |
---|
851 | | -static int lt6911uxc_get_reso_dist(const struct lt6911uxc_mode *mode, |
---|
852 | | - struct v4l2_mbus_framefmt *framefmt) |
---|
853 | | -{ |
---|
854 | | - return abs(mode->width - framefmt->width) + |
---|
855 | | - abs(mode->height - framefmt->height); |
---|
856 | | -} |
---|
857 | | - |
---|
858 | | -static const struct lt6911uxc_mode * |
---|
859 | | -lt6911uxc_find_best_fit(struct v4l2_subdev_format *fmt) |
---|
860 | | -{ |
---|
861 | | - struct v4l2_mbus_framefmt *framefmt = &fmt->format; |
---|
862 | | - int dist; |
---|
863 | | - int cur_best_fit = 0; |
---|
864 | | - int cur_best_fit_dist = -1; |
---|
865 | | - unsigned int i; |
---|
866 | | - |
---|
867 | | - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { |
---|
868 | | - dist = lt6911uxc_get_reso_dist(&supported_modes[i], framefmt); |
---|
869 | | - if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { |
---|
870 | | - cur_best_fit_dist = dist; |
---|
871 | | - cur_best_fit = i; |
---|
872 | | - } |
---|
873 | | - } |
---|
874 | | - |
---|
875 | | - return &supported_modes[cur_best_fit]; |
---|
876 | | -} |
---|
877 | | - |
---|
878 | 962 | static int lt6911uxc_set_fmt(struct v4l2_subdev *sd, |
---|
879 | 963 | struct v4l2_subdev_pad_config *cfg, |
---|
880 | 964 | struct v4l2_subdev_format *format) |
---|
881 | 965 | { |
---|
882 | 966 | struct lt6911uxc *lt6911uxc = to_state(sd); |
---|
883 | 967 | const struct lt6911uxc_mode *mode; |
---|
884 | | - int index; |
---|
885 | 968 | |
---|
886 | 969 | /* is overwritten by get_fmt */ |
---|
887 | 970 | u32 code = format->format.code; |
---|
.. | .. |
---|
893 | 976 | return ret; |
---|
894 | 977 | |
---|
895 | 978 | switch (code) { |
---|
896 | | - case MEDIA_BUS_FMT_UYVY8_2X8: |
---|
| 979 | + case LT6911UXC_MEDIA_BUS_FMT: |
---|
897 | 980 | break; |
---|
898 | 981 | |
---|
899 | 982 | default: |
---|
.. | .. |
---|
904 | 987 | return 0; |
---|
905 | 988 | |
---|
906 | 989 | lt6911uxc->mbus_fmt_code = format->format.code; |
---|
907 | | - mode = lt6911uxc_find_best_fit(format); |
---|
| 990 | + mode = lt6911uxc_find_best_fit(lt6911uxc); |
---|
908 | 991 | lt6911uxc->cur_mode = mode; |
---|
909 | 992 | enable_stream(sd, false); |
---|
910 | | - |
---|
911 | | - if (((mode->width == 720) && (mode->height == 576)) || |
---|
912 | | - ((mode->width == 720) && (mode->height == 480))) |
---|
913 | | - index = 1; |
---|
914 | | - else |
---|
915 | | - index = 0; |
---|
916 | | - |
---|
917 | | - __v4l2_ctrl_s_ctrl(lt6911uxc->link_freq, index); |
---|
918 | | - v4l2_dbg(1, debug, sd, "%s res wxh:%dx%d, link freq:%llu", __func__, |
---|
919 | | - mode->width, mode->height, link_freq_menu_items[index]); |
---|
920 | 993 | |
---|
921 | 994 | return 0; |
---|
922 | 995 | } |
---|
.. | .. |
---|
946 | 1019 | static long lt6911uxc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) |
---|
947 | 1020 | { |
---|
948 | 1021 | struct lt6911uxc *lt6911uxc = to_state(sd); |
---|
| 1022 | + struct device *dev = <6911uxc->i2c_client->dev; |
---|
949 | 1023 | long ret = 0; |
---|
| 1024 | + struct rkmodule_csi_dphy_param *dphy_param; |
---|
| 1025 | + struct rkmodule_capture_info *capture_info; |
---|
950 | 1026 | |
---|
951 | 1027 | switch (cmd) { |
---|
952 | 1028 | case RKMODULE_GET_MODULE_INFO: |
---|
953 | 1029 | lt6911uxc_get_module_inf(lt6911uxc, (struct rkmodule_inf *)arg); |
---|
| 1030 | + break; |
---|
| 1031 | + case RKMODULE_GET_HDMI_MODE: |
---|
| 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 | + } |
---|
954 | 1056 | break; |
---|
955 | 1057 | default: |
---|
956 | 1058 | ret = -ENOIOCTLCMD; |
---|
.. | .. |
---|
967 | 1069 | void __user *up = compat_ptr(arg); |
---|
968 | 1070 | struct rkmodule_inf *inf; |
---|
969 | 1071 | long ret; |
---|
| 1072 | + int *seq; |
---|
| 1073 | + struct rkmodule_csi_dphy_param *dphy_param; |
---|
| 1074 | + struct rkmodule_capture_info *capture_info; |
---|
970 | 1075 | |
---|
971 | 1076 | switch (cmd) { |
---|
972 | 1077 | case RKMODULE_GET_MODULE_INFO: |
---|
.. | .. |
---|
984 | 1089 | } |
---|
985 | 1090 | kfree(inf); |
---|
986 | 1091 | break; |
---|
| 1092 | + case RKMODULE_GET_HDMI_MODE: |
---|
| 1093 | + seq = kzalloc(sizeof(*seq), GFP_KERNEL); |
---|
| 1094 | + if (!seq) { |
---|
| 1095 | + ret = -ENOMEM; |
---|
| 1096 | + return ret; |
---|
| 1097 | + } |
---|
987 | 1098 | |
---|
| 1099 | + ret = lt6911uxc_ioctl(sd, cmd, seq); |
---|
| 1100 | + if (!ret) { |
---|
| 1101 | + ret = copy_to_user(up, seq, sizeof(*seq)); |
---|
| 1102 | + if (ret) |
---|
| 1103 | + ret = -EFAULT; |
---|
| 1104 | + } |
---|
| 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); |
---|
| 1150 | + break; |
---|
988 | 1151 | default: |
---|
989 | 1152 | ret = -ENOIOCTLCMD; |
---|
990 | 1153 | break; |
---|
.. | .. |
---|
993 | 1156 | return ret; |
---|
994 | 1157 | } |
---|
995 | 1158 | #endif |
---|
996 | | - |
---|
997 | | -static const struct v4l2_ctrl_ops lt6911uxc_ctrl_ops = { |
---|
998 | | - .g_volatile_ctrl = lt6911uxc_get_ctrl, |
---|
999 | | -}; |
---|
1000 | 1159 | |
---|
1001 | 1160 | static const struct v4l2_subdev_core_ops lt6911uxc_core_ops = { |
---|
1002 | 1161 | .interrupt_service_routine = lt6911uxc_isr, |
---|
.. | .. |
---|
1013 | 1172 | .s_dv_timings = lt6911uxc_s_dv_timings, |
---|
1014 | 1173 | .g_dv_timings = lt6911uxc_g_dv_timings, |
---|
1015 | 1174 | .query_dv_timings = lt6911uxc_query_dv_timings, |
---|
1016 | | - .g_mbus_config = lt6911uxc_g_mbus_config, |
---|
1017 | 1175 | .s_stream = lt6911uxc_s_stream, |
---|
1018 | 1176 | .g_frame_interval = lt6911uxc_g_frame_interval, |
---|
1019 | 1177 | }; |
---|
.. | .. |
---|
1026 | 1184 | .get_fmt = lt6911uxc_get_fmt, |
---|
1027 | 1185 | .enum_dv_timings = lt6911uxc_enum_dv_timings, |
---|
1028 | 1186 | .dv_timings_cap = lt6911uxc_dv_timings_cap, |
---|
| 1187 | + .get_mbus_config = lt6911uxc_g_mbus_config, |
---|
1029 | 1188 | }; |
---|
1030 | 1189 | |
---|
1031 | 1190 | static const struct v4l2_subdev_ops lt6911uxc_ops = { |
---|
.. | .. |
---|
1068 | 1227 | |
---|
1069 | 1228 | static int lt6911uxc_init_v4l2_ctrls(struct lt6911uxc *lt6911uxc) |
---|
1070 | 1229 | { |
---|
| 1230 | + const struct lt6911uxc_mode *mode; |
---|
1071 | 1231 | struct v4l2_subdev *sd; |
---|
1072 | 1232 | int ret; |
---|
1073 | 1233 | |
---|
| 1234 | + mode = lt6911uxc->cur_mode; |
---|
1074 | 1235 | sd = <6911uxc->sd; |
---|
1075 | 1236 | ret = v4l2_ctrl_handler_init(<6911uxc->hdl, 5); |
---|
1076 | 1237 | if (ret) |
---|
.. | .. |
---|
1080 | 1241 | V4L2_CID_LINK_FREQ, |
---|
1081 | 1242 | ARRAY_SIZE(link_freq_menu_items) - 1, 0, |
---|
1082 | 1243 | link_freq_menu_items); |
---|
1083 | | - v4l2_ctrl_new_std(<6911uxc->hdl, NULL, V4L2_CID_PIXEL_RATE, |
---|
1084 | | - 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); |
---|
1085 | 1247 | |
---|
1086 | 1248 | lt6911uxc->detect_tx_5v_ctrl = v4l2_ctrl_new_std(<6911uxc->hdl, |
---|
1087 | | - <6911uxc_ctrl_ops, V4L2_CID_DV_RX_POWER_PRESENT, |
---|
| 1249 | + NULL, V4L2_CID_DV_RX_POWER_PRESENT, |
---|
1088 | 1250 | 0, 1, 0, 0); |
---|
1089 | | - if (lt6911uxc->detect_tx_5v_ctrl) |
---|
1090 | | - lt6911uxc->detect_tx_5v_ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; |
---|
1091 | 1251 | |
---|
1092 | 1252 | lt6911uxc->audio_sampling_rate_ctrl = |
---|
1093 | 1253 | v4l2_ctrl_new_custom(<6911uxc->hdl, |
---|
.. | .. |
---|
1101 | 1261 | v4l2_err(sd, "cfg v4l2 ctrls failed! ret:%d\n", ret); |
---|
1102 | 1262 | return ret; |
---|
1103 | 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); |
---|
1104 | 1267 | |
---|
1105 | 1268 | if (lt6911uxc_update_controls(sd)) { |
---|
1106 | 1269 | ret = -ENODEV; |
---|
.. | .. |
---|
1153 | 1316 | { |
---|
1154 | 1317 | struct device *dev = <6911uxc->i2c_client->dev; |
---|
1155 | 1318 | struct device_node *node = dev->of_node; |
---|
1156 | | - struct v4l2_fwnode_endpoint *endpoint; |
---|
| 1319 | + struct v4l2_fwnode_endpoint endpoint = { .bus_type = 0 }; |
---|
1157 | 1320 | struct device_node *ep; |
---|
1158 | 1321 | int ret; |
---|
1159 | 1322 | |
---|
.. | .. |
---|
1209 | 1372 | return ret; |
---|
1210 | 1373 | } |
---|
1211 | 1374 | |
---|
1212 | | - endpoint = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep)); |
---|
1213 | | - if (IS_ERR(endpoint)) { |
---|
| 1375 | + ret = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep), &endpoint); |
---|
| 1376 | + if (ret) { |
---|
1214 | 1377 | dev_err(dev, "failed to parse endpoint\n"); |
---|
1215 | | - ret = PTR_ERR(endpoint); |
---|
1216 | | - return ret; |
---|
| 1378 | + goto put_node; |
---|
1217 | 1379 | } |
---|
1218 | 1380 | |
---|
1219 | | - if (endpoint->bus_type != V4L2_MBUS_CSI2 || |
---|
1220 | | - endpoint->bus.mipi_csi2.num_data_lanes == 0) { |
---|
| 1381 | + if (endpoint.bus_type != V4L2_MBUS_CSI2_DPHY || |
---|
| 1382 | + endpoint.bus.mipi_csi2.num_data_lanes == 0) { |
---|
1221 | 1383 | dev_err(dev, "missing CSI-2 properties in endpoint\n"); |
---|
1222 | 1384 | ret = -EINVAL; |
---|
1223 | 1385 | goto free_endpoint; |
---|
.. | .. |
---|
1236 | 1398 | goto free_endpoint; |
---|
1237 | 1399 | } |
---|
1238 | 1400 | |
---|
1239 | | - lt6911uxc->csi_lanes_in_use = endpoint->bus.mipi_csi2.num_data_lanes; |
---|
1240 | | - lt6911uxc->bus = endpoint->bus.mipi_csi2; |
---|
| 1401 | + lt6911uxc->csi_lanes_in_use = endpoint.bus.mipi_csi2.num_data_lanes; |
---|
| 1402 | + lt6911uxc->bus = endpoint.bus.mipi_csi2; |
---|
1241 | 1403 | lt6911uxc->enable_hdcp = false; |
---|
1242 | 1404 | |
---|
1243 | 1405 | gpiod_set_value(lt6911uxc->hpd_ctl_gpio, 0); |
---|
.. | .. |
---|
1247 | 1409 | ret = 0; |
---|
1248 | 1410 | |
---|
1249 | 1411 | free_endpoint: |
---|
1250 | | - v4l2_fwnode_endpoint_free(endpoint); |
---|
| 1412 | + v4l2_fwnode_endpoint_free(&endpoint); |
---|
| 1413 | +put_node: |
---|
| 1414 | + of_node_put(ep); |
---|
1251 | 1415 | return ret; |
---|
1252 | 1416 | } |
---|
1253 | 1417 | #else |
---|
.. | .. |
---|
1257 | 1421 | } |
---|
1258 | 1422 | #endif |
---|
1259 | 1423 | |
---|
| 1424 | +static ssize_t audio_rate_show(struct device *dev, |
---|
| 1425 | + struct device_attribute *attr, char *buf) |
---|
| 1426 | +{ |
---|
| 1427 | + struct lt6911uxc *lt6911uxc = dev_get_drvdata(dev); |
---|
| 1428 | + |
---|
| 1429 | + return snprintf(buf, PAGE_SIZE, "%d", lt6911uxc->audio_sampling_rate); |
---|
| 1430 | +} |
---|
| 1431 | + |
---|
| 1432 | +static ssize_t audio_present_show(struct device *dev, |
---|
| 1433 | + struct device_attribute *attr, char *buf) |
---|
| 1434 | +{ |
---|
| 1435 | + struct lt6911uxc *lt6911uxc = dev_get_drvdata(dev); |
---|
| 1436 | + |
---|
| 1437 | + return snprintf(buf, PAGE_SIZE, "%d", |
---|
| 1438 | + tx_5v_power_present(<6911uxc->sd) ? |
---|
| 1439 | + lt6911uxc->is_audio_present : 0); |
---|
| 1440 | +} |
---|
| 1441 | + |
---|
| 1442 | +static DEVICE_ATTR_RO(audio_rate); |
---|
| 1443 | +static DEVICE_ATTR_RO(audio_present); |
---|
| 1444 | + |
---|
| 1445 | +static struct attribute *lt6911_attrs[] = { |
---|
| 1446 | + &dev_attr_audio_rate.attr, |
---|
| 1447 | + &dev_attr_audio_present.attr, |
---|
| 1448 | + NULL |
---|
| 1449 | +}; |
---|
| 1450 | +ATTRIBUTE_GROUPS(lt6911); |
---|
| 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 | + |
---|
1260 | 1482 | static int lt6911uxc_probe(struct i2c_client *client, |
---|
1261 | 1483 | const struct i2c_device_id *id) |
---|
1262 | 1484 | { |
---|
| 1485 | + struct v4l2_dv_timings default_timing = |
---|
| 1486 | + V4L2_DV_BT_CEA_640X480P59_94; |
---|
1263 | 1487 | struct lt6911uxc *lt6911uxc; |
---|
1264 | 1488 | struct v4l2_subdev *sd; |
---|
1265 | 1489 | struct device *dev = &client->dev; |
---|
.. | .. |
---|
1277 | 1501 | |
---|
1278 | 1502 | sd = <6911uxc->sd; |
---|
1279 | 1503 | lt6911uxc->i2c_client = client; |
---|
| 1504 | + lt6911uxc->timings = default_timing; |
---|
1280 | 1505 | lt6911uxc->cur_mode = &supported_modes[0]; |
---|
1281 | | - lt6911uxc->mbus_fmt_code = MEDIA_BUS_FMT_UYVY8_2X8; |
---|
| 1506 | + lt6911uxc->mbus_fmt_code = LT6911UXC_MEDIA_BUS_FMT; |
---|
1282 | 1507 | |
---|
1283 | 1508 | err = lt6911uxc_parse_of(lt6911uxc); |
---|
1284 | 1509 | if (err) { |
---|
1285 | 1510 | v4l2_err(sd, "lt6911uxc_parse_of failed! err:%d\n", err); |
---|
1286 | 1511 | return err; |
---|
1287 | 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"); |
---|
1288 | 1517 | |
---|
1289 | 1518 | err = lt6911uxc_check_chip_id(lt6911uxc); |
---|
1290 | 1519 | if (err < 0) |
---|
.. | .. |
---|
1330 | 1559 | goto err_clean_entity; |
---|
1331 | 1560 | } |
---|
1332 | 1561 | |
---|
| 1562 | + lt6911uxc->classdev = device_create_with_groups(rk_hdmirx_class(), |
---|
| 1563 | + dev, MKDEV(0, 0), |
---|
| 1564 | + lt6911uxc, |
---|
| 1565 | + lt6911_groups, |
---|
| 1566 | + "lt6911"); |
---|
| 1567 | + if (IS_ERR(lt6911uxc->classdev)) |
---|
| 1568 | + goto err_clean_entity; |
---|
| 1569 | + |
---|
1333 | 1570 | INIT_DELAYED_WORK(<6911uxc->delayed_work_enable_hotplug, |
---|
1334 | 1571 | lt6911uxc_delayed_work_enable_hotplug); |
---|
1335 | 1572 | INIT_DELAYED_WORK(<6911uxc->delayed_work_res_change, |
---|
.. | .. |
---|
1353 | 1590 | } |
---|
1354 | 1591 | |
---|
1355 | 1592 | lt6911uxc->plugin_irq = gpiod_to_irq(lt6911uxc->plugin_det_gpio); |
---|
1356 | | - if (lt6911uxc->plugin_irq < 0) { |
---|
1357 | | - dev_err(dev, "failed to get plugin det irq\n"); |
---|
1358 | | - err = lt6911uxc->plugin_irq; |
---|
1359 | | - goto err_work_queues; |
---|
1360 | | - } |
---|
| 1593 | + if (lt6911uxc->plugin_irq < 0) |
---|
| 1594 | + dev_err(dev, "failed to get plugin det irq, maybe no use\n"); |
---|
1361 | 1595 | |
---|
1362 | 1596 | err = devm_request_threaded_irq(dev, lt6911uxc->plugin_irq, NULL, |
---|
1363 | 1597 | plugin_detect_irq_handler, IRQF_TRIGGER_FALLING | |
---|
1364 | 1598 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "lt6911uxc", |
---|
1365 | 1599 | lt6911uxc); |
---|
1366 | | - if (err) { |
---|
1367 | | - dev_err(dev, "failed to register plugin det irq (%d)\n", err); |
---|
1368 | | - goto err_work_queues; |
---|
1369 | | - } |
---|
| 1600 | + if (err) |
---|
| 1601 | + dev_err(dev, "failed to register plugin det irq (%d), maybe no use\n", err); |
---|
1370 | 1602 | |
---|
1371 | 1603 | err = v4l2_ctrl_handler_setup(sd->ctrl_handler); |
---|
1372 | 1604 | if (err) { |
---|
.. | .. |
---|
1444 | 1676 | |
---|
1445 | 1677 | MODULE_DESCRIPTION("Lontium LT6911UXC HDMI to MIPI CSI-2 bridge driver"); |
---|
1446 | 1678 | MODULE_AUTHOR("Dingxian Wen <shawn.wen@rock-chips.com>"); |
---|
| 1679 | +MODULE_AUTHOR("Jianwei Fan <jianwei.fan@rock-chips.com>"); |
---|
1447 | 1680 | MODULE_LICENSE("GPL v2"); |
---|