1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Intersil ISL7998x analog to MIPI CSI-2 or BT.656 decoder driver. |
4 | * |
5 | * Copyright (C) 2018-2019 Marek Vasut <marex@denx.de> |
6 | * Copyright (C) 2021 Michael Tretter <kernel@pengutronix.de> |
7 | */ |
8 | |
9 | #include <linux/bitfield.h> |
10 | #include <linux/delay.h> |
11 | #include <linux/gpio/consumer.h> |
12 | #include <linux/i2c.h> |
13 | #include <linux/module.h> |
14 | #include <linux/of_graph.h> |
15 | #include <linux/pm_runtime.h> |
16 | #include <linux/regmap.h> |
17 | #include <linux/slab.h> |
18 | #include <linux/v4l2-mediabus.h> |
19 | #include <linux/videodev2.h> |
20 | |
21 | #include <media/v4l2-async.h> |
22 | #include <media/v4l2-common.h> |
23 | #include <media/v4l2-ctrls.h> |
24 | #include <media/v4l2-device.h> |
25 | #include <media/v4l2-fwnode.h> |
26 | #include <media/v4l2-ioctl.h> |
27 | |
28 | /* |
29 | * This control allows to activate and deactivate the test pattern on |
30 | * selected output channels. |
31 | * This value is ISL7998x specific. |
32 | */ |
33 | #define V4L2_CID_TEST_PATTERN_CHANNELS (V4L2_CID_USER_ISL7998X_BASE + 0) |
34 | |
35 | /* |
36 | * This control allows to specify the color of the test pattern. |
37 | * This value is ISL7998x specific. |
38 | */ |
39 | #define V4L2_CID_TEST_PATTERN_COLOR (V4L2_CID_USER_ISL7998X_BASE + 1) |
40 | |
41 | /* |
42 | * This control allows to specify the bar pattern in the test pattern. |
43 | * This value is ISL7998x specific. |
44 | */ |
45 | #define V4L2_CID_TEST_PATTERN_BARS (V4L2_CID_USER_ISL7998X_BASE + 2) |
46 | |
47 | #define ISL7998X_INPUTS 4 |
48 | |
49 | #define ISL7998X_REG(page, reg) (((page) << 8) | (reg)) |
50 | |
51 | #define ISL7998X_REG_PN_SIZE 256 |
52 | #define ISL7998X_REG_PN_BASE(n) ((n) * ISL7998X_REG_PN_SIZE) |
53 | |
54 | #define ISL7998X_REG_PX_DEC_PAGE(page) ISL7998X_REG((page), 0xff) |
55 | #define ISL7998X_REG_PX_DEC_PAGE_MASK 0xf |
56 | #define ISL7998X_REG_P0_PRODUCT_ID_CODE ISL7998X_REG(0, 0x00) |
57 | #define ISL7998X_REG_P0_PRODUCT_REV_CODE ISL7998X_REG(0, 0x01) |
58 | #define ISL7998X_REG_P0_SW_RESET_CTL ISL7998X_REG(0, 0x02) |
59 | #define ISL7998X_REG_P0_IO_BUFFER_CTL ISL7998X_REG(0, 0x03) |
60 | #define ISL7998X_REG_P0_IO_BUFFER_CTL_1_1 ISL7998X_REG(0, 0x04) |
61 | #define ISL7998X_REG_P0_IO_PAD_PULL_EN_CTL ISL7998X_REG(0, 0x05) |
62 | #define ISL7998X_REG_P0_IO_BUFFER_CTL_1_2 ISL7998X_REG(0, 0x06) |
63 | #define ISL7998X_REG_P0_VIDEO_IN_CHAN_CTL ISL7998X_REG(0, 0x07) |
64 | #define ISL7998X_REG_P0_CLK_CTL_1 ISL7998X_REG(0, 0x08) |
65 | #define ISL7998X_REG_P0_CLK_CTL_2 ISL7998X_REG(0, 0x09) |
66 | #define ISL7998X_REG_P0_CLK_CTL_3 ISL7998X_REG(0, 0x0a) |
67 | #define ISL7998X_REG_P0_CLK_CTL_4 ISL7998X_REG(0, 0x0b) |
68 | #define ISL7998X_REG_P0_MPP1_SYNC_CTL ISL7998X_REG(0, 0x0c) |
69 | #define ISL7998X_REG_P0_MPP2_SYNC_CTL ISL7998X_REG(0, 0x0d) |
70 | #define ISL7998X_REG_P0_IRQ_SYNC_CTL ISL7998X_REG(0, 0x0e) |
71 | #define ISL7998X_REG_P0_INTERRUPT_STATUS ISL7998X_REG(0, 0x10) |
72 | #define ISL7998X_REG_P0_CHAN_1_IRQ ISL7998X_REG(0, 0x11) |
73 | #define ISL7998X_REG_P0_CHAN_2_IRQ ISL7998X_REG(0, 0x12) |
74 | #define ISL7998X_REG_P0_CHAN_3_IRQ ISL7998X_REG(0, 0x13) |
75 | #define ISL7998X_REG_P0_CHAN_4_IRQ ISL7998X_REG(0, 0x14) |
76 | #define ISL7998X_REG_P0_SHORT_DIAG_IRQ ISL7998X_REG(0, 0x15) |
77 | #define ISL7998X_REG_P0_CHAN_1_IRQ_EN ISL7998X_REG(0, 0x16) |
78 | #define ISL7998X_REG_P0_CHAN_2_IRQ_EN ISL7998X_REG(0, 0x17) |
79 | #define ISL7998X_REG_P0_CHAN_3_IRQ_EN ISL7998X_REG(0, 0x18) |
80 | #define ISL7998X_REG_P0_CHAN_4_IRQ_EN ISL7998X_REG(0, 0x19) |
81 | #define ISL7998X_REG_P0_SHORT_DIAG_IRQ_EN ISL7998X_REG(0, 0x1a) |
82 | #define ISL7998X_REG_P0_CHAN_1_STATUS ISL7998X_REG(0, 0x1b) |
83 | #define ISL7998X_REG_P0_CHAN_2_STATUS ISL7998X_REG(0, 0x1c) |
84 | #define ISL7998X_REG_P0_CHAN_3_STATUS ISL7998X_REG(0, 0x1d) |
85 | #define ISL7998X_REG_P0_CHAN_4_STATUS ISL7998X_REG(0, 0x1e) |
86 | #define ISL7998X_REG_P0_SHORT_DIAG_STATUS ISL7998X_REG(0, 0x1f) |
87 | #define ISL7998X_REG_P0_CLOCK_DELAY ISL7998X_REG(0, 0x20) |
88 | |
89 | #define ISL7998X_REG_PX_DEC_INPUT_FMT(pg) ISL7998X_REG((pg), 0x02) |
90 | #define ISL7998X_REG_PX_DEC_STATUS_1(pg) ISL7998X_REG((pg), 0x03) |
91 | #define ISL7998X_REG_PX_DEC_STATUS_1_VDLOSS BIT(7) |
92 | #define ISL7998X_REG_PX_DEC_STATUS_1_HLOCK BIT(6) |
93 | #define ISL7998X_REG_PX_DEC_STATUS_1_VLOCK BIT(3) |
94 | #define ISL7998X_REG_PX_DEC_HS_DELAY_CTL(pg) ISL7998X_REG((pg), 0x04) |
95 | #define ISL7998X_REG_PX_DEC_ANCTL(pg) ISL7998X_REG((pg), 0x06) |
96 | #define ISL7998X_REG_PX_DEC_CROP_HI(pg) ISL7998X_REG((pg), 0x07) |
97 | #define ISL7998X_REG_PX_DEC_VDELAY_LO(pg) ISL7998X_REG((pg), 0x08) |
98 | #define ISL7998X_REG_PX_DEC_VACTIVE_LO(pg) ISL7998X_REG((pg), 0x09) |
99 | #define ISL7998X_REG_PX_DEC_HDELAY_LO(pg) ISL7998X_REG((pg), 0x0a) |
100 | #define ISL7998X_REG_PX_DEC_HACTIVE_LO(pg) ISL7998X_REG((pg), 0x0b) |
101 | #define ISL7998X_REG_PX_DEC_CNTRL1(pg) ISL7998X_REG((pg), 0x0c) |
102 | #define ISL7998X_REG_PX_DEC_CSC_CTL(pg) ISL7998X_REG((pg), 0x0d) |
103 | #define ISL7998X_REG_PX_DEC_BRIGHT(pg) ISL7998X_REG((pg), 0x10) |
104 | #define ISL7998X_REG_PX_DEC_CONTRAST(pg) ISL7998X_REG((pg), 0x11) |
105 | #define ISL7998X_REG_PX_DEC_SHARPNESS(pg) ISL7998X_REG((pg), 0x12) |
106 | #define ISL7998X_REG_PX_DEC_SAT_U(pg) ISL7998X_REG((pg), 0x13) |
107 | #define ISL7998X_REG_PX_DEC_SAT_V(pg) ISL7998X_REG((pg), 0x14) |
108 | #define ISL7998X_REG_PX_DEC_HUE(pg) ISL7998X_REG((pg), 0x15) |
109 | #define ISL7998X_REG_PX_DEC_VERT_PEAK(pg) ISL7998X_REG((pg), 0x17) |
110 | #define ISL7998X_REG_PX_DEC_CORING(pg) ISL7998X_REG((pg), 0x18) |
111 | #define ISL7998X_REG_PX_DEC_SDT(pg) ISL7998X_REG((pg), 0x1c) |
112 | #define ISL7998X_REG_PX_DEC_SDT_DET BIT(7) |
113 | #define ISL7998X_REG_PX_DEC_SDT_NOW GENMASK(6, 4) |
114 | #define ISL7998X_REG_PX_DEC_SDT_STANDARD GENMASK(2, 0) |
115 | #define ISL7998X_REG_PX_DEC_SDT_STANDARD_NTSC_M 0 |
116 | #define ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL 1 |
117 | #define ISL7998X_REG_PX_DEC_SDT_STANDARD_SECAM 2 |
118 | #define ISL7998X_REG_PX_DEC_SDT_STANDARD_NTSC_443 3 |
119 | #define ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL_M 4 |
120 | #define ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL_CN 5 |
121 | #define ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL_60 6 |
122 | #define ISL7998X_REG_PX_DEC_SDT_STANDARD_UNKNOWN 7 |
123 | #define ISL7998X_REG_PX_DEC_SDTR(pg) ISL7998X_REG((pg), 0x1d) |
124 | #define ISL7998X_REG_PX_DEC_SDTR_ATSTART BIT(7) |
125 | #define ISL7998X_REG_PX_DEC_CLMPG(pg) ISL7998X_REG((pg), 0x20) |
126 | #define ISL7998X_REG_PX_DEC_IAGC(pg) ISL7998X_REG((pg), 0x21) |
127 | #define ISL7998X_REG_PX_DEC_AGCGAIN(pg) ISL7998X_REG((pg), 0x22) |
128 | #define ISL7998X_REG_PX_DEC_PEAKWT(pg) ISL7998X_REG((pg), 0x23) |
129 | #define ISL7998X_REG_PX_DEC_CLMPL(pg) ISL7998X_REG((pg), 0x24) |
130 | #define ISL7998X_REG_PX_DEC_SYNCT(pg) ISL7998X_REG((pg), 0x25) |
131 | #define ISL7998X_REG_PX_DEC_MISSCNT(pg) ISL7998X_REG((pg), 0x26) |
132 | #define ISL7998X_REG_PX_DEC_PCLAMP(pg) ISL7998X_REG((pg), 0x27) |
133 | #define ISL7998X_REG_PX_DEC_VERT_CTL_1(pg) ISL7998X_REG((pg), 0x28) |
134 | #define ISL7998X_REG_PX_DEC_VERT_CTL_2(pg) ISL7998X_REG((pg), 0x29) |
135 | #define ISL7998X_REG_PX_DEC_CLR_KILL_LVL(pg) ISL7998X_REG((pg), 0x2a) |
136 | #define ISL7998X_REG_PX_DEC_COMB_FILTER_CTL(pg) ISL7998X_REG((pg), 0x2b) |
137 | #define ISL7998X_REG_PX_DEC_LUMA_DELAY(pg) ISL7998X_REG((pg), 0x2c) |
138 | #define ISL7998X_REG_PX_DEC_MISC1(pg) ISL7998X_REG((pg), 0x2d) |
139 | #define ISL7998X_REG_PX_DEC_MISC2(pg) ISL7998X_REG((pg), 0x2e) |
140 | #define ISL7998X_REG_PX_DEC_MISC3(pg) ISL7998X_REG((pg), 0x2f) |
141 | #define ISL7998X_REG_PX_DEC_MVSN(pg) ISL7998X_REG((pg), 0x30) |
142 | #define ISL7998X_REG_PX_DEC_CSTATUS2(pg) ISL7998X_REG((pg), 0x31) |
143 | #define ISL7998X_REG_PX_DEC_HFREF(pg) ISL7998X_REG((pg), 0x32) |
144 | #define ISL7998X_REG_PX_DEC_CLMD(pg) ISL7998X_REG((pg), 0x33) |
145 | #define ISL7998X_REG_PX_DEC_ID_DET_CTL(pg) ISL7998X_REG((pg), 0x34) |
146 | #define ISL7998X_REG_PX_DEC_CLCNTL(pg) ISL7998X_REG((pg), 0x35) |
147 | #define ISL7998X_REG_PX_DEC_DIFF_CLMP_CTL_1(pg) ISL7998X_REG((pg), 0x36) |
148 | #define ISL7998X_REG_PX_DEC_DIFF_CLMP_CTL_2(pg) ISL7998X_REG((pg), 0x37) |
149 | #define ISL7998X_REG_PX_DEC_DIFF_CLMP_CTL_3(pg) ISL7998X_REG((pg), 0x38) |
150 | #define ISL7998X_REG_PX_DEC_DIFF_CLMP_CTL_4(pg) ISL7998X_REG((pg), 0x39) |
151 | #define ISL7998X_REG_PX_DEC_SHORT_DET_CTL(pg) ISL7998X_REG((pg), 0x3a) |
152 | #define ISL7998X_REG_PX_DEC_SHORT_DET_CTL_1(pg) ISL7998X_REG((pg), 0x3b) |
153 | #define ISL7998X_REG_PX_DEC_AFE_TST_MUX_CTL(pg) ISL7998X_REG((pg), 0x3c) |
154 | #define ISL7998X_REG_PX_DEC_DATA_CONV(pg) ISL7998X_REG((pg), 0x3d) |
155 | #define ISL7998X_REG_PX_DEC_INTERNAL_TEST(pg) ISL7998X_REG((pg), 0x3f) |
156 | #define ISL7998X_REG_PX_DEC_H_DELAY_CTL(pg) ISL7998X_REG((pg), 0x43) |
157 | #define ISL7998X_REG_PX_DEC_H_DELAY_II_HI(pg) ISL7998X_REG((pg), 0x44) |
158 | #define ISL7998X_REG_PX_DEC_H_DELAY_II_LOW(pg) ISL7998X_REG((pg), 0x45) |
159 | |
160 | #define ISL7998X_REG_PX_ACA_CTL_1(pg) ISL7998X_REG((pg), 0x80) |
161 | #define ISL7998X_REG_PX_ACA_GAIN_CTL(pg) ISL7998X_REG((pg), 0x81) |
162 | #define ISL7998X_REG_PX_ACA_Y_AVG_HI_LIMIT(pg) ISL7998X_REG((pg), 0x82) |
163 | #define ISL7998X_REG_PX_ACA_Y_AVG_LO_LIMIT(pg) ISL7998X_REG((pg), 0x83) |
164 | #define ISL7998X_REG_PX_ACA_Y_DET_THRESHOLD(pg) ISL7998X_REG((pg), 0x84) |
165 | #define ISL7998X_REG_PX_ACA_BLACK_LVL(pg) ISL7998X_REG((pg), 0x85) |
166 | #define ISL7998X_REG_PX_ACA_CENTER_LVL(pg) ISL7998X_REG((pg), 0x86) |
167 | #define ISL7998X_REG_PX_ACA_WHITE_LVL(pg) ISL7998X_REG((pg), 0x87) |
168 | #define ISL7998X_REG_PX_ACA_MEAN_OFF_LIMIT(pg) ISL7998X_REG((pg), 0x88) |
169 | #define ISL7998X_REG_PX_ACA_MEAN_OFF_UPGAIN(pg) ISL7998X_REG((pg), 0x89) |
170 | #define ISL7998X_REG_PX_ACA_MEAN_OFF_SLOPE(pg) ISL7998X_REG((pg), 0x8a) |
171 | #define ISL7998X_REG_PX_ACA_MEAN_OFF_DNGAIN(pg) ISL7998X_REG((pg), 0x8b) |
172 | #define ISL7998X_REG_PX_ACA_DELTA_CO_THRES(pg) ISL7998X_REG((pg), 0x8c) |
173 | #define ISL7998X_REG_PX_ACA_DELTA_SLOPE(pg) ISL7998X_REG((pg), 0x8d) |
174 | #define ISL7998X_REG_PX_ACA_LO_HI_AVG_THRES(pg) ISL7998X_REG((pg), 0x8e) |
175 | #define ISL7998X_REG_PX_ACA_LO_MAX_LVL_CTL(pg) ISL7998X_REG((pg), 0x8f) |
176 | #define ISL7998X_REG_PX_ACA_HI_MAX_LVL_CTL(pg) ISL7998X_REG((pg), 0x90) |
177 | #define ISL7998X_REG_PX_ACA_LO_UPGAIN_CTL(pg) ISL7998X_REG((pg), 0x91) |
178 | #define ISL7998X_REG_PX_ACA_LO_DNGAIN_CTL(pg) ISL7998X_REG((pg), 0x92) |
179 | #define ISL7998X_REG_PX_ACA_HI_UPGAIN_CTL(pg) ISL7998X_REG((pg), 0x93) |
180 | #define ISL7998X_REG_PX_ACA_HI_DNGAIN_CTL(pg) ISL7998X_REG((pg), 0x94) |
181 | #define ISL7998X_REG_PX_ACA_LOPASS_FLT_COEF(pg) ISL7998X_REG((pg), 0x95) |
182 | #define ISL7998X_REG_PX_ACA_PDF_INDEX(pg) ISL7998X_REG((pg), 0x96) |
183 | #define ISL7998X_REG_PX_ACA_HIST_WIN_H_STT(pg) ISL7998X_REG((pg), 0x97) |
184 | #define ISL7998X_REG_PX_ACA_HIST_WIN_H_SZ1(pg) ISL7998X_REG((pg), 0x98) |
185 | #define ISL7998X_REG_PX_ACA_HIST_WIN_H_SZ2(pg) ISL7998X_REG((pg), 0x99) |
186 | #define ISL7998X_REG_PX_ACA_HIST_WIN_V_STT(pg) ISL7998X_REG((pg), 0x9a) |
187 | #define ISL7998X_REG_PX_ACA_HIST_WIN_V_SZ1(pg) ISL7998X_REG((pg), 0x9b) |
188 | #define ISL7998X_REG_PX_ACA_HIST_WIN_V_SZ2(pg) ISL7998X_REG((pg), 0x9c) |
189 | #define ISL7998X_REG_PX_ACA_Y_AVG(pg) ISL7998X_REG((pg), 0xa0) |
190 | #define ISL7998X_REG_PX_ACA_Y_AVG_LIM(pg) ISL7998X_REG((pg), 0xa1) |
191 | #define ISL7998X_REG_PX_ACA_LO_AVG(pg) ISL7998X_REG((pg), 0xa2) |
192 | #define ISL7998X_REG_PX_ACA_HI_AVG(pg) ISL7998X_REG((pg), 0xa3) |
193 | #define ISL7998X_REG_PX_ACA_Y_MAX(pg) ISL7998X_REG((pg), 0xa4) |
194 | #define ISL7998X_REG_PX_ACA_Y_MIN(pg) ISL7998X_REG((pg), 0xa5) |
195 | #define ISL7998X_REG_PX_ACA_MOFFSET(pg) ISL7998X_REG((pg), 0xa6) |
196 | #define ISL7998X_REG_PX_ACA_LO_GAIN(pg) ISL7998X_REG((pg), 0xa7) |
197 | #define ISL7998X_REG_PX_ACA_HI_GAIN(pg) ISL7998X_REG((pg), 0xa8) |
198 | #define ISL7998X_REG_PX_ACA_LL_SLOPE(pg) ISL7998X_REG((pg), 0xa9) |
199 | #define ISL7998X_REG_PX_ACA_LH_SLOPE(pg) ISL7998X_REG((pg), 0xaa) |
200 | #define ISL7998X_REG_PX_ACA_HL_SLOPE(pg) ISL7998X_REG((pg), 0xab) |
201 | #define ISL7998X_REG_PX_ACA_HH_SLOPE(pg) ISL7998X_REG((pg), 0xac) |
202 | #define ISL7998X_REG_PX_ACA_X_LOW(pg) ISL7998X_REG((pg), 0xad) |
203 | #define ISL7998X_REG_PX_ACA_X_MEAN(pg) ISL7998X_REG((pg), 0xae) |
204 | #define ISL7998X_REG_PX_ACA_X_HIGH(pg) ISL7998X_REG((pg), 0xaf) |
205 | #define ISL7998X_REG_PX_ACA_Y_LOW(pg) ISL7998X_REG((pg), 0xb0) |
206 | #define ISL7998X_REG_PX_ACA_Y_MEAN(pg) ISL7998X_REG((pg), 0xb1) |
207 | #define ISL7998X_REG_PX_ACA_Y_HIGH(pg) ISL7998X_REG((pg), 0xb2) |
208 | #define ISL7998X_REG_PX_ACA_CTL_2(pg) ISL7998X_REG((pg), 0xb3) |
209 | #define ISL7998X_REG_PX_ACA_CTL_3(pg) ISL7998X_REG((pg), 0xb4) |
210 | #define ISL7998X_REG_PX_ACA_CTL_4(pg) ISL7998X_REG((pg), 0xb5) |
211 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_HIST(pg) ISL7998X_REG((pg), 0xc0) |
212 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_TL_H(pg) ISL7998X_REG((pg), 0xc1) |
213 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_TL_L(pg) ISL7998X_REG((pg), 0xc2) |
214 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_TL_H(pg) ISL7998X_REG((pg), 0xc3) |
215 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_TL_L(pg) ISL7998X_REG((pg), 0xc4) |
216 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_TR_H(pg) ISL7998X_REG((pg), 0xc5) |
217 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_TR_L(pg) ISL7998X_REG((pg), 0xc6) |
218 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_TR_H(pg) ISL7998X_REG((pg), 0xc7) |
219 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_TR_L(pg) ISL7998X_REG((pg), 0xc8) |
220 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_BL_H(pg) ISL7998X_REG((pg), 0xc9) |
221 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_BL_L(pg) ISL7998X_REG((pg), 0xca) |
222 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_BL_H(pg) ISL7998X_REG((pg), 0xcb) |
223 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_BL_L(pg) ISL7998X_REG((pg), 0xcc) |
224 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_BR_H(pg) ISL7998X_REG((pg), 0xcd) |
225 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_BR_L(pg) ISL7998X_REG((pg), 0xce) |
226 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_BR_H(pg) ISL7998X_REG((pg), 0xcf) |
227 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_BR_L(pg) ISL7998X_REG((pg), 0xd0) |
228 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_LM_H(pg) ISL7998X_REG((pg), 0xd1) |
229 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_LM_L(pg) ISL7998X_REG((pg), 0xd2) |
230 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_LM_H(pg) ISL7998X_REG((pg), 0xd3) |
231 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_LM_L(pg) ISL7998X_REG((pg), 0xd4) |
232 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_TM_H(pg) ISL7998X_REG((pg), 0xd5) |
233 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_TM_L(pg) ISL7998X_REG((pg), 0xd6) |
234 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_TM_H(pg) ISL7998X_REG((pg), 0xd7) |
235 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_TM_L(pg) ISL7998X_REG((pg), 0xd8) |
236 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_BM_H(pg) ISL7998X_REG((pg), 0xd9) |
237 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_BM_L(pg) ISL7998X_REG((pg), 0xda) |
238 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_BM_H(pg) ISL7998X_REG((pg), 0xdb) |
239 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_BM_L(pg) ISL7998X_REG((pg), 0xdc) |
240 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_RM_H(pg) ISL7998X_REG((pg), 0xdd) |
241 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_X_RM_L(pg) ISL7998X_REG((pg), 0xde) |
242 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_RM_H(pg) ISL7998X_REG((pg), 0xdf) |
243 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_RM_L(pg) ISL7998X_REG((pg), 0xe0) |
244 | #define ISL7998X_REG_PX_ACA_HIST_DATA_LO(pg) ISL7998X_REG((pg), 0xe1) |
245 | #define ISL7998X_REG_PX_ACA_HIST_DATA_MID(pg) ISL7998X_REG((pg), 0xe2) |
246 | #define ISL7998X_REG_PX_ACA_HIST_DATA_HI(pg) ISL7998X_REG((pg), 0xe3) |
247 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_CLR(pg) ISL7998X_REG((pg), 0xe4) |
248 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_CB_CLR(pg) ISL7998X_REG((pg), 0xe5) |
249 | #define ISL7998X_REG_PX_ACA_FLEX_WIN_CR_CLR(pg) ISL7998X_REG((pg), 0xe6) |
250 | #define ISL7998X_REG_PX_ACA_XFER_HIST_HOST(pg) ISL7998X_REG((pg), 0xe7) |
251 | |
252 | #define ISL7998X_REG_P5_LI_ENGINE_CTL ISL7998X_REG(5, 0x00) |
253 | #define ISL7998X_REG_P5_LI_ENGINE_LINE_CTL ISL7998X_REG(5, 0x01) |
254 | #define ISL7998X_REG_P5_LI_ENGINE_PIC_WIDTH ISL7998X_REG(5, 0x02) |
255 | #define ISL7998X_REG_P5_LI_ENGINE_SYNC_CTL ISL7998X_REG(5, 0x03) |
256 | #define ISL7998X_REG_P5_LI_ENGINE_VC_ASSIGNMENT ISL7998X_REG(5, 0x04) |
257 | #define ISL7998X_REG_P5_LI_ENGINE_TYPE_CTL ISL7998X_REG(5, 0x05) |
258 | #define ISL7998X_REG_P5_LI_ENGINE_FIFO_CTL ISL7998X_REG(5, 0x06) |
259 | #define ISL7998X_REG_P5_MIPI_READ_START_CTL ISL7998X_REG(5, 0x07) |
260 | #define ISL7998X_REG_P5_PSEUDO_FRM_FIELD_CTL ISL7998X_REG(5, 0x08) |
261 | #define ISL7998X_REG_P5_ONE_FIELD_MODE_CTL ISL7998X_REG(5, 0x09) |
262 | #define ISL7998X_REG_P5_MIPI_INT_HW_TST_CTR ISL7998X_REG(5, 0x0a) |
263 | #define ISL7998X_REG_P5_TP_GEN_BAR_PATTERN ISL7998X_REG(5, 0x0b) |
264 | #define ISL7998X_REG_P5_MIPI_PCNT_PSFRM ISL7998X_REG(5, 0x0c) |
265 | #define ISL7998X_REG_P5_LI_ENGINE_TP_GEN_CTL ISL7998X_REG(5, 0x0d) |
266 | #define ISL7998X_REG_P5_MIPI_VBLANK_PSFRM ISL7998X_REG(5, 0x0e) |
267 | #define ISL7998X_REG_P5_LI_ENGINE_CTL_2 ISL7998X_REG(5, 0x0f) |
268 | #define ISL7998X_REG_P5_MIPI_WCNT_1 ISL7998X_REG(5, 0x10) |
269 | #define ISL7998X_REG_P5_MIPI_WCNT_2 ISL7998X_REG(5, 0x11) |
270 | #define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_1 ISL7998X_REG(5, 0x12) |
271 | #define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_2 ISL7998X_REG(5, 0x13) |
272 | #define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_3 ISL7998X_REG(5, 0x14) |
273 | #define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_4 ISL7998X_REG(5, 0x15) |
274 | #define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_5 ISL7998X_REG(5, 0x16) |
275 | #define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_6 ISL7998X_REG(5, 0x17) |
276 | #define ISL7998X_REG_P5_MIPI_DPHY_PARAMS_1 ISL7998X_REG(5, 0x18) |
277 | #define ISL7998X_REG_P5_MIPI_DPHY_SOT_PERIOD ISL7998X_REG(5, 0x19) |
278 | #define ISL7998X_REG_P5_MIPI_DPHY_EOT_PERIOD ISL7998X_REG(5, 0x1a) |
279 | #define ISL7998X_REG_P5_MIPI_DPHY_PARAMS_2 ISL7998X_REG(5, 0x1b) |
280 | #define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_7 ISL7998X_REG(5, 0x1c) |
281 | #define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_8 ISL7998X_REG(5, 0x1d) |
282 | #define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_9 ISL7998X_REG(5, 0x1e) |
283 | #define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_10 ISL7998X_REG(5, 0x1f) |
284 | #define ISL7998X_REG_P5_TP_GEN_MIPI ISL7998X_REG(5, 0x20) |
285 | #define ISL7998X_REG_P5_ESC_MODE_TIME_CTL ISL7998X_REG(5, 0x21) |
286 | #define ISL7998X_REG_P5_AUTO_TEST_ERR_DET ISL7998X_REG(5, 0x22) |
287 | #define ISL7998X_REG_P5_MIPI_TIMING ISL7998X_REG(5, 0x23) |
288 | #define ISL7998X_REG_P5_PIC_HEIGHT_HIGH ISL7998X_REG(5, 0x24) |
289 | #define ISL7998X_REG_P5_PIC_HEIGHT_LOW ISL7998X_REG(5, 0x25) |
290 | #define ISL7998X_REG_P5_MIPI_SP_HS_TRL_CTL ISL7998X_REG(5, 0x26) |
291 | #define ISL7998X_REG_P5_FIFO_THRSH_CNT_1 ISL7998X_REG(5, 0x28) |
292 | #define ISL7998X_REG_P5_FIFO_THRSH_CNT_2 ISL7998X_REG(5, 0x29) |
293 | #define ISL7998X_REG_P5_TP_GEN_RND_SYNC_CTL_1 ISL7998X_REG(5, 0x2a) |
294 | #define ISL7998X_REG_P5_TP_GEN_RND_SYNC_CTL_2 ISL7998X_REG(5, 0x2b) |
295 | #define ISL7998X_REG_P5_PSF_FIELD_END_CTL_1 ISL7998X_REG(5, 0x2c) |
296 | #define ISL7998X_REG_P5_PSF_FIELD_END_CTL_2 ISL7998X_REG(5, 0x2d) |
297 | #define ISL7998X_REG_P5_PSF_FIELD_END_CTL_3 ISL7998X_REG(5, 0x2e) |
298 | #define ISL7998X_REG_P5_PSF_FIELD_END_CTL_4 ISL7998X_REG(5, 0x2f) |
299 | #define ISL7998X_REG_P5_MIPI_ANA_DATA_CTL_1 ISL7998X_REG(5, 0x30) |
300 | #define ISL7998X_REG_P5_MIPI_ANA_DATA_CTL_2 ISL7998X_REG(5, 0x31) |
301 | #define ISL7998X_REG_P5_MIPI_ANA_CLK_CTL ISL7998X_REG(5, 0x32) |
302 | #define ISL7998X_REG_P5_PLL_ANA_STATUS ISL7998X_REG(5, 0x33) |
303 | #define ISL7998X_REG_P5_PLL_ANA_MISC_CTL ISL7998X_REG(5, 0x34) |
304 | #define ISL7998X_REG_P5_MIPI_ANA ISL7998X_REG(5, 0x35) |
305 | #define ISL7998X_REG_P5_PLL_ANA ISL7998X_REG(5, 0x36) |
306 | #define ISL7998X_REG_P5_TOTAL_PF_LINE_CNT_1 ISL7998X_REG(5, 0x38) |
307 | #define ISL7998X_REG_P5_TOTAL_PF_LINE_CNT_2 ISL7998X_REG(5, 0x39) |
308 | #define ISL7998X_REG_P5_H_LINE_CNT_1 ISL7998X_REG(5, 0x3a) |
309 | #define ISL7998X_REG_P5_H_LINE_CNT_2 ISL7998X_REG(5, 0x3b) |
310 | #define ISL7998X_REG_P5_HIST_LINE_CNT_1 ISL7998X_REG(5, 0x3c) |
311 | #define ISL7998X_REG_P5_HIST_LINE_CNT_2 ISL7998X_REG(5, 0x3d) |
312 | |
313 | static const struct reg_sequence isl7998x_init_seq_1[] = { |
314 | { ISL7998X_REG_P0_SHORT_DIAG_IRQ_EN, 0xff }, |
315 | { ISL7998X_REG_PX_DEC_SDT(0x1), 0x00 }, |
316 | { ISL7998X_REG_PX_DEC_SHORT_DET_CTL_1(0x1), 0x03 }, |
317 | { ISL7998X_REG_PX_DEC_SDT(0x2), 0x00 }, |
318 | { ISL7998X_REG_PX_DEC_SHORT_DET_CTL_1(0x2), 0x03 }, |
319 | { ISL7998X_REG_PX_DEC_SDT(0x3), 0x00 }, |
320 | { ISL7998X_REG_PX_DEC_SHORT_DET_CTL_1(0x3), 0x03 }, |
321 | { ISL7998X_REG_PX_DEC_SDT(0x4), 0x00 }, |
322 | { ISL7998X_REG_PX_DEC_SHORT_DET_CTL_1(0x4), 0x03 }, |
323 | { ISL7998X_REG_P5_LI_ENGINE_CTL, 0x00 }, |
324 | { ISL7998X_REG_P0_SW_RESET_CTL, 0x1f, 10 }, |
325 | { ISL7998X_REG_P0_IO_BUFFER_CTL, 0x00 }, |
326 | { ISL7998X_REG_P0_MPP2_SYNC_CTL, 0xc9 }, |
327 | { ISL7998X_REG_P0_IRQ_SYNC_CTL, 0xc9 }, |
328 | { ISL7998X_REG_P0_CHAN_1_IRQ, 0x03 }, |
329 | { ISL7998X_REG_P0_CHAN_2_IRQ, 0x00 }, |
330 | { ISL7998X_REG_P0_CHAN_3_IRQ, 0x00 }, |
331 | { ISL7998X_REG_P0_CHAN_4_IRQ, 0x00 }, |
332 | { ISL7998X_REG_P5_LI_ENGINE_CTL, 0x02 }, |
333 | { ISL7998X_REG_P5_LI_ENGINE_LINE_CTL, 0x85 }, |
334 | { ISL7998X_REG_P5_LI_ENGINE_PIC_WIDTH, 0xa0 }, |
335 | { ISL7998X_REG_P5_LI_ENGINE_SYNC_CTL, 0x18 }, |
336 | { ISL7998X_REG_P5_LI_ENGINE_TYPE_CTL, 0x40 }, |
337 | { ISL7998X_REG_P5_LI_ENGINE_FIFO_CTL, 0x40 }, |
338 | { ISL7998X_REG_P5_MIPI_WCNT_1, 0x05 }, |
339 | { ISL7998X_REG_P5_MIPI_WCNT_2, 0xa0 }, |
340 | { ISL7998X_REG_P5_TP_GEN_MIPI, 0x00 }, |
341 | { ISL7998X_REG_P5_ESC_MODE_TIME_CTL, 0x0c }, |
342 | { ISL7998X_REG_P5_MIPI_SP_HS_TRL_CTL, 0x00 }, |
343 | { ISL7998X_REG_P5_TP_GEN_RND_SYNC_CTL_1, 0x00 }, |
344 | { ISL7998X_REG_P5_TP_GEN_RND_SYNC_CTL_2, 0x19 }, |
345 | { ISL7998X_REG_P5_PSF_FIELD_END_CTL_1, 0x18 }, |
346 | { ISL7998X_REG_P5_PSF_FIELD_END_CTL_2, 0xf1 }, |
347 | { ISL7998X_REG_P5_PSF_FIELD_END_CTL_3, 0x00 }, |
348 | { ISL7998X_REG_P5_PSF_FIELD_END_CTL_4, 0xf1 }, |
349 | { ISL7998X_REG_P5_MIPI_ANA_DATA_CTL_1, 0x00 }, |
350 | { ISL7998X_REG_P5_MIPI_ANA_DATA_CTL_2, 0x00 }, |
351 | { ISL7998X_REG_P5_MIPI_ANA_CLK_CTL, 0x00 }, |
352 | { ISL7998X_REG_P5_PLL_ANA_STATUS, 0xc0 }, |
353 | { ISL7998X_REG_P5_PLL_ANA_MISC_CTL, 0x18 }, |
354 | { ISL7998X_REG_P5_PLL_ANA, 0x00 }, |
355 | { ISL7998X_REG_P0_SW_RESET_CTL, 0x10, 10 }, |
356 | /* Page 0xf means write to all of pages 1,2,3,4 */ |
357 | { ISL7998X_REG_PX_DEC_VDELAY_LO(0xf), 0x14 }, |
358 | { ISL7998X_REG_PX_DEC_MISC3(0xf), 0xe6 }, |
359 | { ISL7998X_REG_PX_DEC_CLMD(0xf), 0x85 }, |
360 | { ISL7998X_REG_PX_DEC_H_DELAY_II_LOW(0xf), 0x11 }, |
361 | { ISL7998X_REG_PX_ACA_XFER_HIST_HOST(0xf), 0x00 }, |
362 | { ISL7998X_REG_P0_CLK_CTL_1, 0x1f }, |
363 | { ISL7998X_REG_P0_CLK_CTL_2, 0x43 }, |
364 | { ISL7998X_REG_P0_CLK_CTL_3, 0x4f }, |
365 | }; |
366 | |
367 | static const struct reg_sequence isl7998x_init_seq_2[] = { |
368 | { ISL7998X_REG_P5_LI_ENGINE_SYNC_CTL, 0x10 }, |
369 | { ISL7998X_REG_P5_LI_ENGINE_VC_ASSIGNMENT, 0xe4 }, |
370 | { ISL7998X_REG_P5_LI_ENGINE_TYPE_CTL, 0x00 }, |
371 | { ISL7998X_REG_P5_LI_ENGINE_FIFO_CTL, 0x60 }, |
372 | { ISL7998X_REG_P5_MIPI_READ_START_CTL, 0x2b }, |
373 | { ISL7998X_REG_P5_PSEUDO_FRM_FIELD_CTL, 0x02 }, |
374 | { ISL7998X_REG_P5_ONE_FIELD_MODE_CTL, 0x00 }, |
375 | { ISL7998X_REG_P5_MIPI_INT_HW_TST_CTR, 0x62 }, |
376 | { ISL7998X_REG_P5_TP_GEN_BAR_PATTERN, 0x02 }, |
377 | { ISL7998X_REG_P5_MIPI_PCNT_PSFRM, 0x36 }, |
378 | { ISL7998X_REG_P5_LI_ENGINE_TP_GEN_CTL, 0x00 }, |
379 | { ISL7998X_REG_P5_MIPI_VBLANK_PSFRM, 0x6c }, |
380 | { ISL7998X_REG_P5_LI_ENGINE_CTL_2, 0x00 }, |
381 | { ISL7998X_REG_P5_MIPI_WCNT_1, 0x05 }, |
382 | { ISL7998X_REG_P5_MIPI_WCNT_2, 0xa0 }, |
383 | { ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_1, 0x77 }, |
384 | { ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_2, 0x17 }, |
385 | { ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_3, 0x08 }, |
386 | { ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_4, 0x38 }, |
387 | { ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_5, 0x14 }, |
388 | { ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_6, 0xf6 }, |
389 | { ISL7998X_REG_P5_MIPI_DPHY_PARAMS_1, 0x00 }, |
390 | { ISL7998X_REG_P5_MIPI_DPHY_SOT_PERIOD, 0x17 }, |
391 | { ISL7998X_REG_P5_MIPI_DPHY_EOT_PERIOD, 0x0a }, |
392 | { ISL7998X_REG_P5_MIPI_DPHY_PARAMS_2, 0x71 }, |
393 | { ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_7, 0x7a }, |
394 | { ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_8, 0x0f }, |
395 | { ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_9, 0x8c }, |
396 | { ISL7998X_REG_P5_MIPI_SP_HS_TRL_CTL, 0x08 }, |
397 | { ISL7998X_REG_P5_FIFO_THRSH_CNT_1, 0x01 }, |
398 | { ISL7998X_REG_P5_FIFO_THRSH_CNT_2, 0x0e }, |
399 | { ISL7998X_REG_P5_TP_GEN_RND_SYNC_CTL_1, 0x00 }, |
400 | { ISL7998X_REG_P5_TP_GEN_RND_SYNC_CTL_2, 0x00 }, |
401 | { ISL7998X_REG_P5_TOTAL_PF_LINE_CNT_1, 0x03 }, |
402 | { ISL7998X_REG_P5_TOTAL_PF_LINE_CNT_2, 0xc0 }, |
403 | { ISL7998X_REG_P5_H_LINE_CNT_1, 0x06 }, |
404 | { ISL7998X_REG_P5_H_LINE_CNT_2, 0xb3 }, |
405 | { ISL7998X_REG_P5_HIST_LINE_CNT_1, 0x00 }, |
406 | { ISL7998X_REG_P5_HIST_LINE_CNT_2, 0xf1 }, |
407 | { ISL7998X_REG_P5_LI_ENGINE_FIFO_CTL, 0x00 }, |
408 | { ISL7998X_REG_P5_MIPI_ANA, 0x00 }, |
409 | /* |
410 | * Wait a bit after reset so that the chip can capture a frame |
411 | * and update internal line counters. |
412 | */ |
413 | { ISL7998X_REG_P0_SW_RESET_CTL, 0x00, 50 }, |
414 | }; |
415 | |
416 | enum isl7998x_pads { |
417 | ISL7998X_PAD_OUT, |
418 | ISL7998X_PAD_VIN1, |
419 | ISL7998X_PAD_VIN2, |
420 | ISL7998X_PAD_VIN3, |
421 | ISL7998X_PAD_VIN4, |
422 | ISL7998X_NUM_PADS |
423 | }; |
424 | |
425 | struct isl7998x_datafmt { |
426 | u32 code; |
427 | enum v4l2_colorspace colorspace; |
428 | }; |
429 | |
430 | static const struct isl7998x_datafmt isl7998x_colour_fmts[] = { |
431 | { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB }, |
432 | }; |
433 | |
434 | /* Menu items for LINK_FREQ V4L2 control */ |
435 | static const s64 [] = { |
436 | /* 1 channel, 1 lane or 2 channels, 2 lanes */ |
437 | 108000000, |
438 | /* 2 channels, 1 lane or 4 channels, 2 lanes */ |
439 | 216000000, |
440 | /* 4 channels, 1 lane */ |
441 | 432000000, |
442 | }; |
443 | |
444 | /* Menu items for TEST_PATTERN V4L2 control */ |
445 | static const char * const [] = { |
446 | "Disabled" , |
447 | "Enabled" , |
448 | }; |
449 | |
450 | static const char * const isl7998x_test_pattern_bars[] = { |
451 | "bbbbwb" , "bbbwwb" , "bbwbwb" , "bbwwwb" , |
452 | }; |
453 | |
454 | static const char * const isl7998x_test_pattern_colors[] = { |
455 | "Yellow" , "Blue" , "Green" , "Pink" , |
456 | }; |
457 | |
458 | struct isl7998x_mode { |
459 | unsigned int width; |
460 | unsigned int height; |
461 | enum v4l2_field field; |
462 | }; |
463 | |
464 | static const struct isl7998x_mode supported_modes[] = { |
465 | { |
466 | .width = 720, |
467 | .height = 576, |
468 | .field = V4L2_FIELD_SEQ_TB, |
469 | }, |
470 | { |
471 | .width = 720, |
472 | .height = 480, |
473 | .field = V4L2_FIELD_SEQ_BT, |
474 | }, |
475 | }; |
476 | |
477 | static const struct isl7998x_video_std { |
478 | const v4l2_std_id norm; |
479 | unsigned int id; |
480 | const struct isl7998x_mode *mode; |
481 | } isl7998x_std_res[] = { |
482 | { V4L2_STD_NTSC_443, |
483 | ISL7998X_REG_PX_DEC_SDT_STANDARD_NTSC_443, |
484 | &supported_modes[1] }, |
485 | { V4L2_STD_PAL_M, |
486 | ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL_M, |
487 | &supported_modes[1] }, |
488 | { V4L2_STD_PAL_Nc, |
489 | ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL_CN, |
490 | &supported_modes[0] }, |
491 | { V4L2_STD_PAL_N, |
492 | ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL, |
493 | &supported_modes[0] }, |
494 | { V4L2_STD_PAL_60, |
495 | ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL_60, |
496 | &supported_modes[1] }, |
497 | { V4L2_STD_NTSC, |
498 | ISL7998X_REG_PX_DEC_SDT_STANDARD_NTSC_M, |
499 | &supported_modes[1] }, |
500 | { V4L2_STD_PAL, |
501 | ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL, |
502 | &supported_modes[0] }, |
503 | { V4L2_STD_SECAM, |
504 | ISL7998X_REG_PX_DEC_SDT_STANDARD_SECAM, |
505 | &supported_modes[0] }, |
506 | { V4L2_STD_UNKNOWN, |
507 | ISL7998X_REG_PX_DEC_SDT_STANDARD_UNKNOWN, |
508 | &supported_modes[1] }, |
509 | }; |
510 | |
511 | struct isl7998x { |
512 | struct v4l2_subdev subdev; |
513 | struct regmap *regmap; |
514 | struct gpio_desc *pd_gpio; |
515 | struct gpio_desc *rstb_gpio; |
516 | unsigned int nr_mipi_lanes; |
517 | u32 nr_inputs; |
518 | |
519 | const struct isl7998x_datafmt *fmt; |
520 | v4l2_std_id norm; |
521 | struct media_pad pads[ISL7998X_NUM_PADS]; |
522 | |
523 | int enabled; |
524 | |
525 | /* protect fmt, norm, enabled */ |
526 | struct mutex lock; |
527 | |
528 | struct v4l2_ctrl_handler ctrl_handler; |
529 | /* protect ctrl_handler */ |
530 | struct mutex ctrl_mutex; |
531 | |
532 | /* V4L2 Controls */ |
533 | struct v4l2_ctrl *link_freq; |
534 | u8 test_pattern; |
535 | u8 test_pattern_bars; |
536 | u8 test_pattern_chans; |
537 | u8 test_pattern_color; |
538 | }; |
539 | |
540 | static struct isl7998x *sd_to_isl7998x(struct v4l2_subdev *sd) |
541 | { |
542 | return container_of(sd, struct isl7998x, subdev); |
543 | } |
544 | |
545 | static struct isl7998x *i2c_to_isl7998x(const struct i2c_client *client) |
546 | { |
547 | return sd_to_isl7998x(sd: i2c_get_clientdata(client)); |
548 | } |
549 | |
550 | static unsigned int isl7998x_norm_to_val(v4l2_std_id norm) |
551 | { |
552 | unsigned int i; |
553 | |
554 | for (i = 0; i < ARRAY_SIZE(isl7998x_std_res); i++) |
555 | if (isl7998x_std_res[i].norm & norm) |
556 | break; |
557 | if (i == ARRAY_SIZE(isl7998x_std_res)) |
558 | return ISL7998X_REG_PX_DEC_SDT_STANDARD_UNKNOWN; |
559 | |
560 | return isl7998x_std_res[i].id; |
561 | } |
562 | |
563 | static const struct isl7998x_mode *isl7998x_norm_to_mode(v4l2_std_id norm) |
564 | { |
565 | unsigned int i; |
566 | |
567 | for (i = 0; i < ARRAY_SIZE(isl7998x_std_res); i++) |
568 | if (isl7998x_std_res[i].norm & norm) |
569 | break; |
570 | /* Use NTSC default resolution during standard detection */ |
571 | if (i == ARRAY_SIZE(isl7998x_std_res)) |
572 | return &supported_modes[1]; |
573 | |
574 | return isl7998x_std_res[i].mode; |
575 | } |
576 | |
577 | static int isl7998x_get_nr_inputs(struct device_node *of_node) |
578 | { |
579 | struct device_node *port; |
580 | unsigned int inputs = 0; |
581 | unsigned int i; |
582 | |
583 | if (of_graph_get_endpoint_count(np: of_node) > ISL7998X_NUM_PADS) |
584 | return -EINVAL; |
585 | |
586 | /* |
587 | * The driver does not provide means to remap the input ports. It |
588 | * always configures input ports to start from VID1. Ensure that the |
589 | * device tree is correct. |
590 | */ |
591 | for (i = ISL7998X_PAD_VIN1; i <= ISL7998X_PAD_VIN4; i++) { |
592 | port = of_graph_get_port_by_id(node: of_node, id: i); |
593 | if (!port) |
594 | continue; |
595 | |
596 | inputs |= BIT(i); |
597 | of_node_put(node: port); |
598 | } |
599 | |
600 | switch (inputs) { |
601 | case BIT(ISL7998X_PAD_VIN1): |
602 | return 1; |
603 | case BIT(ISL7998X_PAD_VIN1) | BIT(ISL7998X_PAD_VIN2): |
604 | return 2; |
605 | case BIT(ISL7998X_PAD_VIN1) | BIT(ISL7998X_PAD_VIN2) | |
606 | BIT(ISL7998X_PAD_VIN3) | BIT(ISL7998X_PAD_VIN4): |
607 | return 4; |
608 | default: |
609 | return -EINVAL; |
610 | } |
611 | } |
612 | |
613 | static int isl7998x_wait_power_on(struct isl7998x *isl7998x) |
614 | { |
615 | struct device *dev = isl7998x->subdev.dev; |
616 | u32 chip_id; |
617 | int ret; |
618 | int err; |
619 | |
620 | ret = read_poll_timeout(regmap_read, err, !err, 2000, 20000, false, |
621 | isl7998x->regmap, |
622 | ISL7998X_REG_P0_PRODUCT_ID_CODE, &chip_id); |
623 | if (ret) { |
624 | dev_err(dev, "timeout while waiting for ISL7998X\n" ); |
625 | return ret; |
626 | } |
627 | |
628 | dev_dbg(dev, "Found ISL799%x\n" , chip_id); |
629 | |
630 | return ret; |
631 | } |
632 | |
633 | static int isl7998x_set_standard(struct isl7998x *isl7998x, v4l2_std_id norm) |
634 | { |
635 | const struct isl7998x_mode *mode = isl7998x_norm_to_mode(norm); |
636 | unsigned int val = isl7998x_norm_to_val(norm); |
637 | unsigned int width = mode->width; |
638 | unsigned int i; |
639 | int ret; |
640 | |
641 | for (i = 0; i < ISL7998X_INPUTS; i++) { |
642 | ret = regmap_write_bits(map: isl7998x->regmap, |
643 | ISL7998X_REG_PX_DEC_SDT(i + 1), |
644 | ISL7998X_REG_PX_DEC_SDT_STANDARD, |
645 | val); |
646 | if (ret) |
647 | return ret; |
648 | } |
649 | |
650 | ret = regmap_write(map: isl7998x->regmap, |
651 | ISL7998X_REG_P5_LI_ENGINE_LINE_CTL, |
652 | val: 0x20 | ((width >> 7) & 0x1f)); |
653 | if (ret) |
654 | return ret; |
655 | |
656 | ret = regmap_write(map: isl7998x->regmap, |
657 | ISL7998X_REG_P5_LI_ENGINE_PIC_WIDTH, |
658 | val: (width << 1) & 0xff); |
659 | if (ret) |
660 | return ret; |
661 | |
662 | return 0; |
663 | } |
664 | |
665 | static int isl7998x_init(struct isl7998x *isl7998x) |
666 | { |
667 | const unsigned int lanes = isl7998x->nr_mipi_lanes; |
668 | static const u32 isl7998x_video_in_chan_map[] = { 0x00, 0x11, 0x02, 0x02 }; |
669 | const struct reg_sequence isl7998x_init_seq_custom[] = { |
670 | { ISL7998X_REG_P0_VIDEO_IN_CHAN_CTL, |
671 | isl7998x_video_in_chan_map[isl7998x->nr_inputs - 1] }, |
672 | { ISL7998X_REG_P0_CLK_CTL_4, |
673 | (lanes == 1) ? 0x40 : 0x41 }, |
674 | { ISL7998X_REG_P5_LI_ENGINE_CTL, |
675 | (lanes == 1) ? 0x01 : 0x02 }, |
676 | }; |
677 | struct device *dev = isl7998x->subdev.dev; |
678 | struct regmap *regmap = isl7998x->regmap; |
679 | int ret; |
680 | |
681 | dev_dbg(dev, "configuring %d lanes for %d inputs (norm %s)\n" , |
682 | isl7998x->nr_mipi_lanes, isl7998x->nr_inputs, |
683 | v4l2_norm_to_name(isl7998x->norm)); |
684 | |
685 | ret = regmap_register_patch(map: regmap, regs: isl7998x_init_seq_1, |
686 | ARRAY_SIZE(isl7998x_init_seq_1)); |
687 | if (ret) |
688 | return ret; |
689 | |
690 | mutex_lock(&isl7998x->lock); |
691 | ret = isl7998x_set_standard(isl7998x, norm: isl7998x->norm); |
692 | mutex_unlock(lock: &isl7998x->lock); |
693 | if (ret) |
694 | return ret; |
695 | |
696 | ret = regmap_register_patch(map: regmap, regs: isl7998x_init_seq_custom, |
697 | ARRAY_SIZE(isl7998x_init_seq_custom)); |
698 | if (ret) |
699 | return ret; |
700 | |
701 | return regmap_register_patch(map: regmap, regs: isl7998x_init_seq_2, |
702 | ARRAY_SIZE(isl7998x_init_seq_2)); |
703 | } |
704 | |
705 | static int isl7998x_set_test_pattern(struct isl7998x *isl7998x) |
706 | { |
707 | const struct reg_sequence isl7998x_init_seq_tpg_off[] = { |
708 | { ISL7998X_REG_P5_LI_ENGINE_TP_GEN_CTL, 0 }, |
709 | { ISL7998X_REG_P5_LI_ENGINE_CTL_2, 0 } |
710 | }; |
711 | const struct reg_sequence isl7998x_init_seq_tpg_on[] = { |
712 | { ISL7998X_REG_P5_TP_GEN_BAR_PATTERN, |
713 | isl7998x->test_pattern_bars << 6 }, |
714 | { ISL7998X_REG_P5_LI_ENGINE_CTL_2, |
715 | isl7998x->norm & V4L2_STD_PAL ? BIT(2) : 0 }, |
716 | { ISL7998X_REG_P5_LI_ENGINE_TP_GEN_CTL, |
717 | (isl7998x->test_pattern_chans << 4) | |
718 | (isl7998x->test_pattern_color << 2) } |
719 | }; |
720 | struct device *dev = isl7998x->subdev.dev; |
721 | struct regmap *regmap = isl7998x->regmap; |
722 | int ret; |
723 | |
724 | if (pm_runtime_get_if_in_use(dev) <= 0) |
725 | return 0; |
726 | |
727 | if (isl7998x->test_pattern != 0) { |
728 | dev_dbg(dev, "enabling test pattern: channels 0x%x, %s, %s\n" , |
729 | isl7998x->test_pattern_chans, |
730 | isl7998x_test_pattern_bars[isl7998x->test_pattern_bars], |
731 | isl7998x_test_pattern_colors[isl7998x->test_pattern_color]); |
732 | ret = regmap_register_patch(map: regmap, regs: isl7998x_init_seq_tpg_on, |
733 | ARRAY_SIZE(isl7998x_init_seq_tpg_on)); |
734 | } else { |
735 | ret = regmap_register_patch(map: regmap, regs: isl7998x_init_seq_tpg_off, |
736 | ARRAY_SIZE(isl7998x_init_seq_tpg_off)); |
737 | } |
738 | |
739 | pm_runtime_put(dev); |
740 | |
741 | return ret; |
742 | } |
743 | |
744 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
745 | static int isl7998x_g_register(struct v4l2_subdev *sd, |
746 | struct v4l2_dbg_register *reg) |
747 | { |
748 | struct isl7998x *isl7998x = sd_to_isl7998x(sd); |
749 | int ret; |
750 | u32 val; |
751 | |
752 | ret = regmap_read(map: isl7998x->regmap, reg: reg->reg, val: &val); |
753 | if (ret) |
754 | return ret; |
755 | |
756 | reg->size = 1; |
757 | reg->val = val; |
758 | |
759 | return 0; |
760 | } |
761 | |
762 | static int isl7998x_s_register(struct v4l2_subdev *sd, |
763 | const struct v4l2_dbg_register *reg) |
764 | { |
765 | struct isl7998x *isl7998x = sd_to_isl7998x(sd); |
766 | |
767 | return regmap_write(map: isl7998x->regmap, reg: reg->reg, val: reg->val); |
768 | } |
769 | #endif |
770 | |
771 | static int isl7998x_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) |
772 | { |
773 | struct isl7998x *isl7998x = sd_to_isl7998x(sd); |
774 | |
775 | mutex_lock(&isl7998x->lock); |
776 | *norm = isl7998x->norm; |
777 | mutex_unlock(lock: &isl7998x->lock); |
778 | |
779 | return 0; |
780 | } |
781 | |
782 | static int isl7998x_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) |
783 | { |
784 | struct isl7998x *isl7998x = sd_to_isl7998x(sd); |
785 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
786 | struct device *dev = &client->dev; |
787 | int ret = 0; |
788 | |
789 | mutex_lock(&isl7998x->lock); |
790 | if (isl7998x->enabled) { |
791 | ret = -EBUSY; |
792 | mutex_unlock(lock: &isl7998x->lock); |
793 | return ret; |
794 | } |
795 | isl7998x->norm = norm; |
796 | mutex_unlock(lock: &isl7998x->lock); |
797 | |
798 | if (pm_runtime_get_if_in_use(dev) <= 0) |
799 | return ret; |
800 | |
801 | ret = isl7998x_set_standard(isl7998x, norm); |
802 | |
803 | pm_runtime_put(dev); |
804 | |
805 | return ret; |
806 | } |
807 | |
808 | static int isl7998x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) |
809 | { |
810 | struct isl7998x *isl7998x = sd_to_isl7998x(sd); |
811 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
812 | struct device *dev = &client->dev; |
813 | unsigned int std_id[ISL7998X_INPUTS]; |
814 | unsigned int i; |
815 | int ret; |
816 | u32 reg; |
817 | |
818 | ret = pm_runtime_resume_and_get(dev); |
819 | if (ret) |
820 | return ret; |
821 | |
822 | dev_dbg(dev, "starting video standard detection\n" ); |
823 | |
824 | mutex_lock(&isl7998x->lock); |
825 | if (isl7998x->enabled) { |
826 | ret = -EBUSY; |
827 | goto out_unlock; |
828 | } |
829 | |
830 | ret = isl7998x_set_standard(isl7998x, V4L2_STD_UNKNOWN); |
831 | if (ret) |
832 | goto out_unlock; |
833 | |
834 | for (i = 0; i < ISL7998X_INPUTS; i++) { |
835 | ret = regmap_write(map: isl7998x->regmap, |
836 | ISL7998X_REG_PX_DEC_SDTR(i + 1), |
837 | ISL7998X_REG_PX_DEC_SDTR_ATSTART); |
838 | if (ret) |
839 | goto out_reset_std; |
840 | } |
841 | |
842 | for (i = 0; i < ISL7998X_INPUTS; i++) { |
843 | ret = regmap_read_poll_timeout(isl7998x->regmap, |
844 | ISL7998X_REG_PX_DEC_SDT(i + 1), |
845 | reg, |
846 | !(reg & ISL7998X_REG_PX_DEC_SDT_DET), |
847 | 2000, 500 * USEC_PER_MSEC); |
848 | if (ret) |
849 | goto out_reset_std; |
850 | std_id[i] = FIELD_GET(ISL7998X_REG_PX_DEC_SDT_NOW, reg); |
851 | } |
852 | |
853 | /* |
854 | * According to Renesas FAE, all input cameras must have the |
855 | * same standard on this chip. |
856 | */ |
857 | for (i = 0; i < isl7998x->nr_inputs; i++) { |
858 | dev_dbg(dev, "input %d: detected %s\n" , |
859 | i, v4l2_norm_to_name(isl7998x_std_res[std_id[i]].norm)); |
860 | if (std_id[0] != std_id[i]) |
861 | dev_warn(dev, |
862 | "incompatible standards: %s on input %d (expected %s)\n" , |
863 | v4l2_norm_to_name(isl7998x_std_res[std_id[i]].norm), i, |
864 | v4l2_norm_to_name(isl7998x_std_res[std_id[0]].norm)); |
865 | } |
866 | |
867 | *std = isl7998x_std_res[std_id[0]].norm; |
868 | |
869 | out_reset_std: |
870 | isl7998x_set_standard(isl7998x, norm: isl7998x->norm); |
871 | out_unlock: |
872 | mutex_unlock(lock: &isl7998x->lock); |
873 | pm_runtime_put(dev); |
874 | |
875 | return ret; |
876 | } |
877 | |
878 | static int isl7998x_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *std) |
879 | { |
880 | *std = V4L2_STD_ALL; |
881 | |
882 | return 0; |
883 | } |
884 | |
885 | static int isl7998x_g_input_status(struct v4l2_subdev *sd, u32 *status) |
886 | { |
887 | struct isl7998x *isl7998x = sd_to_isl7998x(sd); |
888 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
889 | struct device *dev = &client->dev; |
890 | unsigned int i; |
891 | int ret = 0; |
892 | u32 reg; |
893 | |
894 | if (!pm_runtime_active(dev)) { |
895 | *status |= V4L2_IN_ST_NO_POWER; |
896 | return 0; |
897 | } |
898 | |
899 | for (i = 0; i < isl7998x->nr_inputs; i++) { |
900 | ret = regmap_read(map: isl7998x->regmap, |
901 | ISL7998X_REG_PX_DEC_STATUS_1(i + 1), val: ®); |
902 | if (!ret) { |
903 | if (reg & ISL7998X_REG_PX_DEC_STATUS_1_VDLOSS) |
904 | *status |= V4L2_IN_ST_NO_SIGNAL; |
905 | if (!(reg & ISL7998X_REG_PX_DEC_STATUS_1_HLOCK)) |
906 | *status |= V4L2_IN_ST_NO_H_LOCK; |
907 | if (!(reg & ISL7998X_REG_PX_DEC_STATUS_1_VLOCK)) |
908 | *status |= V4L2_IN_ST_NO_V_LOCK; |
909 | } |
910 | } |
911 | |
912 | return ret; |
913 | } |
914 | |
915 | static int isl7998x_s_stream(struct v4l2_subdev *sd, int enable) |
916 | { |
917 | struct isl7998x *isl7998x = sd_to_isl7998x(sd); |
918 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
919 | struct device *dev = &client->dev; |
920 | int ret = 0; |
921 | u32 reg; |
922 | |
923 | dev_dbg(dev, "stream %s\n" , enable ? "ON" : "OFF" ); |
924 | |
925 | mutex_lock(&isl7998x->lock); |
926 | if (isl7998x->enabled == enable) |
927 | goto out; |
928 | isl7998x->enabled = enable; |
929 | |
930 | if (enable) { |
931 | ret = isl7998x_set_test_pattern(isl7998x); |
932 | if (ret) |
933 | goto out; |
934 | } |
935 | |
936 | regmap_read(map: isl7998x->regmap, |
937 | ISL7998X_REG_P5_LI_ENGINE_CTL, val: ®); |
938 | if (enable) |
939 | reg &= ~BIT(7); |
940 | else |
941 | reg |= BIT(7); |
942 | ret = regmap_write(map: isl7998x->regmap, |
943 | ISL7998X_REG_P5_LI_ENGINE_CTL, val: reg); |
944 | |
945 | out: |
946 | mutex_unlock(lock: &isl7998x->lock); |
947 | |
948 | return ret; |
949 | } |
950 | |
951 | static int isl7998x_pre_streamon(struct v4l2_subdev *sd, u32 flags) |
952 | { |
953 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
954 | struct device *dev = &client->dev; |
955 | |
956 | return pm_runtime_resume_and_get(dev); |
957 | } |
958 | |
959 | static int isl7998x_post_streamoff(struct v4l2_subdev *sd) |
960 | { |
961 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
962 | struct device *dev = &client->dev; |
963 | |
964 | pm_runtime_put(dev); |
965 | |
966 | return 0; |
967 | } |
968 | |
969 | static int isl7998x_enum_mbus_code(struct v4l2_subdev *sd, |
970 | struct v4l2_subdev_state *sd_state, |
971 | struct v4l2_subdev_mbus_code_enum *code) |
972 | { |
973 | if (code->index >= ARRAY_SIZE(isl7998x_colour_fmts)) |
974 | return -EINVAL; |
975 | |
976 | code->code = isl7998x_colour_fmts[code->index].code; |
977 | |
978 | return 0; |
979 | } |
980 | |
981 | static int isl7998x_enum_frame_size(struct v4l2_subdev *sd, |
982 | struct v4l2_subdev_state *sd_state, |
983 | struct v4l2_subdev_frame_size_enum *fse) |
984 | { |
985 | if (fse->index >= ARRAY_SIZE(supported_modes)) |
986 | return -EINVAL; |
987 | |
988 | if (fse->code != isl7998x_colour_fmts[0].code) |
989 | return -EINVAL; |
990 | |
991 | fse->min_width = supported_modes[fse->index].width; |
992 | fse->max_width = fse->min_width; |
993 | fse->min_height = supported_modes[fse->index].height; |
994 | fse->max_height = fse->min_height; |
995 | |
996 | return 0; |
997 | } |
998 | |
999 | static int isl7998x_get_fmt(struct v4l2_subdev *sd, |
1000 | struct v4l2_subdev_state *sd_state, |
1001 | struct v4l2_subdev_format *format) |
1002 | { |
1003 | struct isl7998x *isl7998x = sd_to_isl7998x(sd); |
1004 | struct v4l2_mbus_framefmt *mf = &format->format; |
1005 | const struct isl7998x_mode *mode; |
1006 | |
1007 | mutex_lock(&isl7998x->lock); |
1008 | |
1009 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) { |
1010 | format->format = *v4l2_subdev_state_get_format(sd_state, |
1011 | format->pad); |
1012 | goto out; |
1013 | } |
1014 | |
1015 | mode = isl7998x_norm_to_mode(norm: isl7998x->norm); |
1016 | |
1017 | mf->width = mode->width; |
1018 | mf->height = mode->height; |
1019 | mf->code = isl7998x->fmt->code; |
1020 | mf->field = mode->field; |
1021 | mf->colorspace = 0; |
1022 | |
1023 | out: |
1024 | mutex_unlock(lock: &isl7998x->lock); |
1025 | |
1026 | return 0; |
1027 | } |
1028 | |
1029 | static int isl7998x_set_fmt(struct v4l2_subdev *sd, |
1030 | struct v4l2_subdev_state *sd_state, |
1031 | struct v4l2_subdev_format *format) |
1032 | { |
1033 | struct isl7998x *isl7998x = sd_to_isl7998x(sd); |
1034 | struct v4l2_mbus_framefmt *mf = &format->format; |
1035 | const struct isl7998x_mode *mode; |
1036 | |
1037 | mutex_lock(&isl7998x->lock); |
1038 | |
1039 | mode = isl7998x_norm_to_mode(norm: isl7998x->norm); |
1040 | |
1041 | mf->width = mode->width; |
1042 | mf->height = mode->height; |
1043 | mf->code = isl7998x->fmt->code; |
1044 | mf->field = mode->field; |
1045 | |
1046 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) |
1047 | *v4l2_subdev_state_get_format(sd_state, format->pad) = format->format; |
1048 | |
1049 | mutex_unlock(lock: &isl7998x->lock); |
1050 | |
1051 | return 0; |
1052 | } |
1053 | |
1054 | static int isl7998x_set_ctrl(struct v4l2_ctrl *ctrl) |
1055 | { |
1056 | struct isl7998x *isl7998x = container_of(ctrl->handler, |
1057 | struct isl7998x, ctrl_handler); |
1058 | int ret = 0; |
1059 | |
1060 | switch (ctrl->id) { |
1061 | case V4L2_CID_TEST_PATTERN_BARS: |
1062 | mutex_lock(&isl7998x->lock); |
1063 | isl7998x->test_pattern_bars = ctrl->val & 0x3; |
1064 | ret = isl7998x_set_test_pattern(isl7998x); |
1065 | mutex_unlock(lock: &isl7998x->lock); |
1066 | break; |
1067 | case V4L2_CID_TEST_PATTERN_CHANNELS: |
1068 | mutex_lock(&isl7998x->lock); |
1069 | isl7998x->test_pattern_chans = ctrl->val & 0xf; |
1070 | ret = isl7998x_set_test_pattern(isl7998x); |
1071 | mutex_unlock(lock: &isl7998x->lock); |
1072 | break; |
1073 | case V4L2_CID_TEST_PATTERN_COLOR: |
1074 | mutex_lock(&isl7998x->lock); |
1075 | isl7998x->test_pattern_color = ctrl->val & 0x3; |
1076 | ret = isl7998x_set_test_pattern(isl7998x); |
1077 | mutex_unlock(lock: &isl7998x->lock); |
1078 | break; |
1079 | case V4L2_CID_TEST_PATTERN: |
1080 | mutex_lock(&isl7998x->lock); |
1081 | isl7998x->test_pattern = ctrl->val; |
1082 | ret = isl7998x_set_test_pattern(isl7998x); |
1083 | mutex_unlock(lock: &isl7998x->lock); |
1084 | break; |
1085 | } |
1086 | |
1087 | return ret; |
1088 | } |
1089 | |
1090 | static const struct v4l2_subdev_core_ops isl7998x_subdev_core_ops = { |
1091 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1092 | .g_register = isl7998x_g_register, |
1093 | .s_register = isl7998x_s_register, |
1094 | #endif |
1095 | }; |
1096 | |
1097 | static const struct v4l2_subdev_video_ops isl7998x_subdev_video_ops = { |
1098 | .g_std = isl7998x_g_std, |
1099 | .s_std = isl7998x_s_std, |
1100 | .querystd = isl7998x_querystd, |
1101 | .g_tvnorms = isl7998x_g_tvnorms, |
1102 | .g_input_status = isl7998x_g_input_status, |
1103 | .s_stream = isl7998x_s_stream, |
1104 | .pre_streamon = isl7998x_pre_streamon, |
1105 | .post_streamoff = isl7998x_post_streamoff, |
1106 | }; |
1107 | |
1108 | static const struct v4l2_subdev_pad_ops isl7998x_subdev_pad_ops = { |
1109 | .enum_mbus_code = isl7998x_enum_mbus_code, |
1110 | .enum_frame_size = isl7998x_enum_frame_size, |
1111 | .get_fmt = isl7998x_get_fmt, |
1112 | .set_fmt = isl7998x_set_fmt, |
1113 | }; |
1114 | |
1115 | static const struct v4l2_subdev_ops isl7998x_subdev_ops = { |
1116 | .core = &isl7998x_subdev_core_ops, |
1117 | .video = &isl7998x_subdev_video_ops, |
1118 | .pad = &isl7998x_subdev_pad_ops, |
1119 | }; |
1120 | |
1121 | static const struct media_entity_operations isl7998x_entity_ops = { |
1122 | .link_validate = v4l2_subdev_link_validate, |
1123 | }; |
1124 | |
1125 | static const struct v4l2_ctrl_ops isl7998x_ctrl_ops = { |
1126 | .s_ctrl = isl7998x_set_ctrl, |
1127 | }; |
1128 | |
1129 | static const struct v4l2_ctrl_config isl7998x_ctrls[] = { |
1130 | { |
1131 | .ops = &isl7998x_ctrl_ops, |
1132 | .id = V4L2_CID_TEST_PATTERN_BARS, |
1133 | .type = V4L2_CTRL_TYPE_MENU, |
1134 | .name = "Test Pattern Bars" , |
1135 | .max = ARRAY_SIZE(isl7998x_test_pattern_bars) - 1, |
1136 | .def = 0, |
1137 | .qmenu = isl7998x_test_pattern_bars, |
1138 | }, { |
1139 | .ops = &isl7998x_ctrl_ops, |
1140 | .id = V4L2_CID_TEST_PATTERN_CHANNELS, |
1141 | .type = V4L2_CTRL_TYPE_INTEGER, |
1142 | .name = "Test Pattern Channels" , |
1143 | .min = 0, |
1144 | .max = 0xf, |
1145 | .step = 1, |
1146 | .def = 0xf, |
1147 | .flags = 0, |
1148 | }, { |
1149 | .ops = &isl7998x_ctrl_ops, |
1150 | .id = V4L2_CID_TEST_PATTERN_COLOR, |
1151 | .type = V4L2_CTRL_TYPE_MENU, |
1152 | .name = "Test Pattern Color" , |
1153 | .max = ARRAY_SIZE(isl7998x_test_pattern_colors) - 1, |
1154 | .def = 0, |
1155 | .qmenu = isl7998x_test_pattern_colors, |
1156 | }, |
1157 | }; |
1158 | |
1159 | #define ISL7998X_REG_DECODER_ACA_READABLE_RANGE(page) \ |
1160 | /* Decoder range */ \ |
1161 | regmap_reg_range(ISL7998X_REG_PX_DEC_INPUT_FMT(page), \ |
1162 | ISL7998X_REG_PX_DEC_HS_DELAY_CTL(page)), \ |
1163 | regmap_reg_range(ISL7998X_REG_PX_DEC_ANCTL(page), \ |
1164 | ISL7998X_REG_PX_DEC_CSC_CTL(page)), \ |
1165 | regmap_reg_range(ISL7998X_REG_PX_DEC_BRIGHT(page), \ |
1166 | ISL7998X_REG_PX_DEC_HUE(page)), \ |
1167 | regmap_reg_range(ISL7998X_REG_PX_DEC_VERT_PEAK(page), \ |
1168 | ISL7998X_REG_PX_DEC_CORING(page)), \ |
1169 | regmap_reg_range(ISL7998X_REG_PX_DEC_SDT(page), \ |
1170 | ISL7998X_REG_PX_DEC_SDTR(page)), \ |
1171 | regmap_reg_range(ISL7998X_REG_PX_DEC_CLMPG(page), \ |
1172 | ISL7998X_REG_PX_DEC_DATA_CONV(page)), \ |
1173 | regmap_reg_range(ISL7998X_REG_PX_DEC_INTERNAL_TEST(page), \ |
1174 | ISL7998X_REG_PX_DEC_INTERNAL_TEST(page)), \ |
1175 | regmap_reg_range(ISL7998X_REG_PX_DEC_H_DELAY_CTL(page), \ |
1176 | ISL7998X_REG_PX_DEC_H_DELAY_II_LOW(page)), \ |
1177 | /* ACA range */ \ |
1178 | regmap_reg_range(ISL7998X_REG_PX_ACA_CTL_1(page), \ |
1179 | ISL7998X_REG_PX_ACA_HIST_WIN_V_SZ2(page)), \ |
1180 | regmap_reg_range(ISL7998X_REG_PX_ACA_Y_AVG(page), \ |
1181 | ISL7998X_REG_PX_ACA_CTL_4(page)), \ |
1182 | regmap_reg_range(ISL7998X_REG_PX_ACA_FLEX_WIN_HIST(page), \ |
1183 | ISL7998X_REG_PX_ACA_XFER_HIST_HOST(page)), \ |
1184 | regmap_reg_range(ISL7998X_REG_PX_DEC_PAGE(page), \ |
1185 | ISL7998X_REG_PX_DEC_PAGE(page)) |
1186 | |
1187 | #define ISL7998X_REG_DECODER_ACA_WRITEABLE_RANGE(page) \ |
1188 | /* Decoder range */ \ |
1189 | regmap_reg_range(ISL7998X_REG_PX_DEC_INPUT_FMT(page), \ |
1190 | ISL7998X_REG_PX_DEC_INPUT_FMT(page)), \ |
1191 | regmap_reg_range(ISL7998X_REG_PX_DEC_HS_DELAY_CTL(page), \ |
1192 | ISL7998X_REG_PX_DEC_HS_DELAY_CTL(page)), \ |
1193 | regmap_reg_range(ISL7998X_REG_PX_DEC_ANCTL(page), \ |
1194 | ISL7998X_REG_PX_DEC_CSC_CTL(page)), \ |
1195 | regmap_reg_range(ISL7998X_REG_PX_DEC_BRIGHT(page), \ |
1196 | ISL7998X_REG_PX_DEC_HUE(page)), \ |
1197 | regmap_reg_range(ISL7998X_REG_PX_DEC_VERT_PEAK(page), \ |
1198 | ISL7998X_REG_PX_DEC_CORING(page)), \ |
1199 | regmap_reg_range(ISL7998X_REG_PX_DEC_SDT(page), \ |
1200 | ISL7998X_REG_PX_DEC_SDTR(page)), \ |
1201 | regmap_reg_range(ISL7998X_REG_PX_DEC_CLMPG(page), \ |
1202 | ISL7998X_REG_PX_DEC_MISC3(page)), \ |
1203 | regmap_reg_range(ISL7998X_REG_PX_DEC_CLMD(page), \ |
1204 | ISL7998X_REG_PX_DEC_DATA_CONV(page)), \ |
1205 | regmap_reg_range(ISL7998X_REG_PX_DEC_INTERNAL_TEST(page), \ |
1206 | ISL7998X_REG_PX_DEC_INTERNAL_TEST(page)), \ |
1207 | regmap_reg_range(ISL7998X_REG_PX_DEC_H_DELAY_CTL(page), \ |
1208 | ISL7998X_REG_PX_DEC_H_DELAY_II_LOW(page)), \ |
1209 | /* ACA range */ \ |
1210 | regmap_reg_range(ISL7998X_REG_PX_ACA_CTL_1(page), \ |
1211 | ISL7998X_REG_PX_ACA_HIST_WIN_V_SZ2(page)), \ |
1212 | regmap_reg_range(ISL7998X_REG_PX_ACA_CTL_2(page), \ |
1213 | ISL7998X_REG_PX_ACA_CTL_4(page)), \ |
1214 | regmap_reg_range(ISL7998X_REG_PX_ACA_FLEX_WIN_HIST(page), \ |
1215 | ISL7998X_REG_PX_ACA_HIST_DATA_LO(page)), \ |
1216 | regmap_reg_range(ISL7998X_REG_PX_ACA_XFER_HIST_HOST(page), \ |
1217 | ISL7998X_REG_PX_ACA_XFER_HIST_HOST(page)), \ |
1218 | regmap_reg_range(ISL7998X_REG_PX_DEC_PAGE(page), \ |
1219 | ISL7998X_REG_PX_DEC_PAGE(page)) |
1220 | |
1221 | #define ISL7998X_REG_DECODER_ACA_VOLATILE_RANGE(page) \ |
1222 | /* Decoder range */ \ |
1223 | regmap_reg_range(ISL7998X_REG_PX_DEC_STATUS_1(page), \ |
1224 | ISL7998X_REG_PX_DEC_STATUS_1(page)), \ |
1225 | regmap_reg_range(ISL7998X_REG_PX_DEC_SDT(page), \ |
1226 | ISL7998X_REG_PX_DEC_SDT(page)), \ |
1227 | regmap_reg_range(ISL7998X_REG_PX_DEC_MVSN(page), \ |
1228 | ISL7998X_REG_PX_DEC_HFREF(page)), \ |
1229 | /* ACA range */ \ |
1230 | regmap_reg_range(ISL7998X_REG_PX_ACA_Y_AVG(page), \ |
1231 | ISL7998X_REG_PX_ACA_Y_HIGH(page)), \ |
1232 | regmap_reg_range(ISL7998X_REG_PX_ACA_HIST_DATA_LO(page), \ |
1233 | ISL7998X_REG_PX_ACA_FLEX_WIN_CR_CLR(page)) |
1234 | |
1235 | static const struct regmap_range isl7998x_readable_ranges[] = { |
1236 | regmap_reg_range(ISL7998X_REG_P0_PRODUCT_ID_CODE, |
1237 | ISL7998X_REG_P0_IRQ_SYNC_CTL), |
1238 | regmap_reg_range(ISL7998X_REG_P0_INTERRUPT_STATUS, |
1239 | ISL7998X_REG_P0_CLOCK_DELAY), |
1240 | regmap_reg_range(ISL7998X_REG_PX_DEC_PAGE(0), |
1241 | ISL7998X_REG_PX_DEC_PAGE(0)), |
1242 | |
1243 | ISL7998X_REG_DECODER_ACA_READABLE_RANGE(1), |
1244 | ISL7998X_REG_DECODER_ACA_READABLE_RANGE(2), |
1245 | ISL7998X_REG_DECODER_ACA_READABLE_RANGE(3), |
1246 | ISL7998X_REG_DECODER_ACA_READABLE_RANGE(4), |
1247 | |
1248 | regmap_reg_range(ISL7998X_REG_P5_LI_ENGINE_CTL, |
1249 | ISL7998X_REG_P5_MIPI_SP_HS_TRL_CTL), |
1250 | regmap_reg_range(ISL7998X_REG_P5_FIFO_THRSH_CNT_1, |
1251 | ISL7998X_REG_P5_PLL_ANA), |
1252 | regmap_reg_range(ISL7998X_REG_P5_TOTAL_PF_LINE_CNT_1, |
1253 | ISL7998X_REG_P5_HIST_LINE_CNT_2), |
1254 | regmap_reg_range(ISL7998X_REG_PX_DEC_PAGE(5), |
1255 | ISL7998X_REG_PX_DEC_PAGE(5)), |
1256 | }; |
1257 | |
1258 | static const struct regmap_range isl7998x_writeable_ranges[] = { |
1259 | regmap_reg_range(ISL7998X_REG_P0_SW_RESET_CTL, |
1260 | ISL7998X_REG_P0_IRQ_SYNC_CTL), |
1261 | regmap_reg_range(ISL7998X_REG_P0_CHAN_1_IRQ, |
1262 | ISL7998X_REG_P0_SHORT_DIAG_IRQ_EN), |
1263 | regmap_reg_range(ISL7998X_REG_P0_CLOCK_DELAY, |
1264 | ISL7998X_REG_P0_CLOCK_DELAY), |
1265 | regmap_reg_range(ISL7998X_REG_PX_DEC_PAGE(0), |
1266 | ISL7998X_REG_PX_DEC_PAGE(0)), |
1267 | |
1268 | ISL7998X_REG_DECODER_ACA_WRITEABLE_RANGE(1), |
1269 | ISL7998X_REG_DECODER_ACA_WRITEABLE_RANGE(2), |
1270 | ISL7998X_REG_DECODER_ACA_WRITEABLE_RANGE(3), |
1271 | ISL7998X_REG_DECODER_ACA_WRITEABLE_RANGE(4), |
1272 | |
1273 | regmap_reg_range(ISL7998X_REG_P5_LI_ENGINE_CTL, |
1274 | ISL7998X_REG_P5_ESC_MODE_TIME_CTL), |
1275 | regmap_reg_range(ISL7998X_REG_P5_MIPI_SP_HS_TRL_CTL, |
1276 | ISL7998X_REG_P5_PLL_ANA), |
1277 | regmap_reg_range(ISL7998X_REG_P5_TOTAL_PF_LINE_CNT_1, |
1278 | ISL7998X_REG_P5_HIST_LINE_CNT_2), |
1279 | regmap_reg_range(ISL7998X_REG_PX_DEC_PAGE(5), |
1280 | ISL7998X_REG_PX_DEC_PAGE(5)), |
1281 | |
1282 | ISL7998X_REG_DECODER_ACA_WRITEABLE_RANGE(0xf), |
1283 | }; |
1284 | |
1285 | static const struct regmap_range isl7998x_volatile_ranges[] = { |
1286 | /* Product id code register is used to check availability */ |
1287 | regmap_reg_range(ISL7998X_REG_P0_PRODUCT_ID_CODE, |
1288 | ISL7998X_REG_P0_PRODUCT_ID_CODE), |
1289 | regmap_reg_range(ISL7998X_REG_P0_MPP1_SYNC_CTL, |
1290 | ISL7998X_REG_P0_IRQ_SYNC_CTL), |
1291 | regmap_reg_range(ISL7998X_REG_P0_INTERRUPT_STATUS, |
1292 | ISL7998X_REG_P0_INTERRUPT_STATUS), |
1293 | regmap_reg_range(ISL7998X_REG_P0_CHAN_1_STATUS, |
1294 | ISL7998X_REG_P0_SHORT_DIAG_STATUS), |
1295 | |
1296 | ISL7998X_REG_DECODER_ACA_VOLATILE_RANGE(1), |
1297 | ISL7998X_REG_DECODER_ACA_VOLATILE_RANGE(2), |
1298 | ISL7998X_REG_DECODER_ACA_VOLATILE_RANGE(3), |
1299 | ISL7998X_REG_DECODER_ACA_VOLATILE_RANGE(4), |
1300 | |
1301 | regmap_reg_range(ISL7998X_REG_P5_AUTO_TEST_ERR_DET, |
1302 | ISL7998X_REG_P5_PIC_HEIGHT_LOW), |
1303 | }; |
1304 | |
1305 | static const struct regmap_access_table isl7998x_readable_table = { |
1306 | .yes_ranges = isl7998x_readable_ranges, |
1307 | .n_yes_ranges = ARRAY_SIZE(isl7998x_readable_ranges), |
1308 | }; |
1309 | |
1310 | static const struct regmap_access_table isl7998x_writeable_table = { |
1311 | .yes_ranges = isl7998x_writeable_ranges, |
1312 | .n_yes_ranges = ARRAY_SIZE(isl7998x_writeable_ranges), |
1313 | }; |
1314 | |
1315 | static const struct regmap_access_table isl7998x_volatile_table = { |
1316 | .yes_ranges = isl7998x_volatile_ranges, |
1317 | .n_yes_ranges = ARRAY_SIZE(isl7998x_volatile_ranges), |
1318 | }; |
1319 | |
1320 | static const struct regmap_range_cfg isl7998x_ranges[] = { |
1321 | { |
1322 | .range_min = ISL7998X_REG_PN_BASE(0), |
1323 | .range_max = ISL7998X_REG_PX_ACA_XFER_HIST_HOST(0xf), |
1324 | .selector_reg = ISL7998X_REG_PX_DEC_PAGE(0), |
1325 | .selector_mask = ISL7998X_REG_PX_DEC_PAGE_MASK, |
1326 | .window_start = 0, |
1327 | .window_len = 256, |
1328 | } |
1329 | }; |
1330 | |
1331 | static const struct regmap_config isl7998x_regmap = { |
1332 | .reg_bits = 8, |
1333 | .val_bits = 8, |
1334 | .max_register = ISL7998X_REG_PX_ACA_XFER_HIST_HOST(0xf), |
1335 | .ranges = isl7998x_ranges, |
1336 | .num_ranges = ARRAY_SIZE(isl7998x_ranges), |
1337 | .rd_table = &isl7998x_readable_table, |
1338 | .wr_table = &isl7998x_writeable_table, |
1339 | .volatile_table = &isl7998x_volatile_table, |
1340 | .cache_type = REGCACHE_MAPLE, |
1341 | }; |
1342 | |
1343 | static int isl7998x_mc_init(struct isl7998x *isl7998x) |
1344 | { |
1345 | unsigned int i; |
1346 | |
1347 | isl7998x->subdev.entity.ops = &isl7998x_entity_ops; |
1348 | isl7998x->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; |
1349 | |
1350 | isl7998x->pads[ISL7998X_PAD_OUT].flags = MEDIA_PAD_FL_SOURCE; |
1351 | for (i = ISL7998X_PAD_VIN1; i < ISL7998X_NUM_PADS; i++) |
1352 | isl7998x->pads[i].flags = MEDIA_PAD_FL_SINK; |
1353 | |
1354 | return media_entity_pads_init(entity: &isl7998x->subdev.entity, |
1355 | num_pads: ISL7998X_NUM_PADS, |
1356 | pads: isl7998x->pads); |
1357 | } |
1358 | |
1359 | static int (unsigned int lanes, |
1360 | unsigned int inputs) |
1361 | { |
1362 | int ret = -EINVAL; |
1363 | |
1364 | switch (lanes) { |
1365 | case 1: |
1366 | if (inputs == 1) |
1367 | ret = 0; |
1368 | if (inputs == 2) |
1369 | ret = 1; |
1370 | if (inputs == 4) |
1371 | ret = 2; |
1372 | break; |
1373 | case 2: |
1374 | if (inputs == 2) |
1375 | ret = 0; |
1376 | if (inputs == 4) |
1377 | ret = 1; |
1378 | break; |
1379 | default: |
1380 | break; |
1381 | } |
1382 | |
1383 | return ret; |
1384 | } |
1385 | |
1386 | static void isl7998x_remove_controls(struct isl7998x *isl7998x) |
1387 | { |
1388 | v4l2_ctrl_handler_free(hdl: &isl7998x->ctrl_handler); |
1389 | mutex_destroy(lock: &isl7998x->ctrl_mutex); |
1390 | } |
1391 | |
1392 | static int isl7998x_init_controls(struct isl7998x *isl7998x) |
1393 | { |
1394 | struct v4l2_subdev *sd = &isl7998x->subdev; |
1395 | int link_freq_index; |
1396 | unsigned int i; |
1397 | int ret; |
1398 | |
1399 | ret = v4l2_ctrl_handler_init(&isl7998x->ctrl_handler, |
1400 | 2 + ARRAY_SIZE(isl7998x_ctrls)); |
1401 | if (ret) |
1402 | return ret; |
1403 | |
1404 | mutex_init(&isl7998x->ctrl_mutex); |
1405 | isl7998x->ctrl_handler.lock = &isl7998x->ctrl_mutex; |
1406 | link_freq_index = get_link_freq_menu_index(lanes: isl7998x->nr_mipi_lanes, |
1407 | inputs: isl7998x->nr_inputs); |
1408 | if (link_freq_index < 0 || |
1409 | link_freq_index >= ARRAY_SIZE(link_freq_menu_items)) { |
1410 | dev_err(sd->dev, |
1411 | "failed to find MIPI link freq: %d lanes, %d inputs\n" , |
1412 | isl7998x->nr_mipi_lanes, isl7998x->nr_inputs); |
1413 | ret = -EINVAL; |
1414 | goto err; |
1415 | } |
1416 | |
1417 | isl7998x->link_freq = v4l2_ctrl_new_int_menu(hdl: &isl7998x->ctrl_handler, |
1418 | ops: &isl7998x_ctrl_ops, |
1419 | V4L2_CID_LINK_FREQ, |
1420 | ARRAY_SIZE(link_freq_menu_items) - 1, |
1421 | def: link_freq_index, |
1422 | qmenu_int: link_freq_menu_items); |
1423 | if (isl7998x->link_freq) |
1424 | isl7998x->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
1425 | |
1426 | for (i = 0; i < ARRAY_SIZE(isl7998x_ctrls); i++) |
1427 | v4l2_ctrl_new_custom(hdl: &isl7998x->ctrl_handler, |
1428 | cfg: &isl7998x_ctrls[i], NULL); |
1429 | |
1430 | v4l2_ctrl_new_std_menu_items(hdl: &isl7998x->ctrl_handler, |
1431 | ops: &isl7998x_ctrl_ops, |
1432 | V4L2_CID_TEST_PATTERN, |
1433 | ARRAY_SIZE(isl7998x_test_pattern_menu) - 1, |
1434 | mask: 0, def: 0, qmenu: isl7998x_test_pattern_menu); |
1435 | |
1436 | ret = isl7998x->ctrl_handler.error; |
1437 | if (ret) |
1438 | goto err; |
1439 | |
1440 | isl7998x->subdev.ctrl_handler = &isl7998x->ctrl_handler; |
1441 | v4l2_ctrl_handler_setup(hdl: &isl7998x->ctrl_handler); |
1442 | |
1443 | return 0; |
1444 | |
1445 | err: |
1446 | isl7998x_remove_controls(isl7998x); |
1447 | |
1448 | return ret; |
1449 | } |
1450 | |
1451 | static int isl7998x_probe(struct i2c_client *client) |
1452 | { |
1453 | struct device *dev = &client->dev; |
1454 | struct v4l2_fwnode_endpoint endpoint = { |
1455 | .bus_type = V4L2_MBUS_CSI2_DPHY, |
1456 | }; |
1457 | struct fwnode_handle *ep; |
1458 | struct isl7998x *isl7998x; |
1459 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
1460 | int nr_inputs; |
1461 | int ret; |
1462 | |
1463 | ret = i2c_check_functionality(adap: adapter, I2C_FUNC_SMBUS_WORD_DATA); |
1464 | if (!ret) { |
1465 | dev_warn(&adapter->dev, |
1466 | "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n" ); |
1467 | return -EIO; |
1468 | } |
1469 | |
1470 | isl7998x = devm_kzalloc(dev, size: sizeof(*isl7998x), GFP_KERNEL); |
1471 | if (!isl7998x) |
1472 | return -ENOMEM; |
1473 | |
1474 | isl7998x->pd_gpio = devm_gpiod_get_optional(dev, con_id: "powerdown" , |
1475 | flags: GPIOD_OUT_HIGH); |
1476 | if (IS_ERR(ptr: isl7998x->pd_gpio)) |
1477 | return dev_err_probe(dev, err: PTR_ERR(ptr: isl7998x->pd_gpio), |
1478 | fmt: "Failed to retrieve/request PD GPIO\n" ); |
1479 | |
1480 | isl7998x->rstb_gpio = devm_gpiod_get_optional(dev, con_id: "reset" , |
1481 | flags: GPIOD_OUT_HIGH); |
1482 | if (IS_ERR(ptr: isl7998x->rstb_gpio)) |
1483 | return dev_err_probe(dev, err: PTR_ERR(ptr: isl7998x->rstb_gpio), |
1484 | fmt: "Failed to retrieve/request RSTB GPIO\n" ); |
1485 | |
1486 | isl7998x->regmap = devm_regmap_init_i2c(client, &isl7998x_regmap); |
1487 | if (IS_ERR(ptr: isl7998x->regmap)) |
1488 | return dev_err_probe(dev, err: PTR_ERR(ptr: isl7998x->regmap), |
1489 | fmt: "Failed to allocate register map\n" ); |
1490 | |
1491 | ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), |
1492 | port: ISL7998X_PAD_OUT, endpoint: 0, flags: 0); |
1493 | if (!ep) |
1494 | return dev_err_probe(dev, err: -EINVAL, fmt: "Missing endpoint node\n" ); |
1495 | |
1496 | ret = v4l2_fwnode_endpoint_parse(fwnode: ep, vep: &endpoint); |
1497 | fwnode_handle_put(fwnode: ep); |
1498 | if (ret) |
1499 | return dev_err_probe(dev, err: ret, fmt: "Failed to parse endpoint\n" ); |
1500 | |
1501 | if (endpoint.bus.mipi_csi2.num_data_lanes == 0 || |
1502 | endpoint.bus.mipi_csi2.num_data_lanes > 2) |
1503 | return dev_err_probe(dev, err: -EINVAL, |
1504 | fmt: "Invalid number of MIPI lanes\n" ); |
1505 | |
1506 | isl7998x->nr_mipi_lanes = endpoint.bus.mipi_csi2.num_data_lanes; |
1507 | |
1508 | nr_inputs = isl7998x_get_nr_inputs(of_node: dev->of_node); |
1509 | if (nr_inputs < 0) |
1510 | return dev_err_probe(dev, err: nr_inputs, |
1511 | fmt: "Invalid number of input ports\n" ); |
1512 | isl7998x->nr_inputs = nr_inputs; |
1513 | |
1514 | v4l2_i2c_subdev_init(sd: &isl7998x->subdev, client, ops: &isl7998x_subdev_ops); |
1515 | isl7998x->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
1516 | |
1517 | ret = isl7998x_mc_init(isl7998x); |
1518 | if (ret < 0) |
1519 | return ret; |
1520 | |
1521 | isl7998x->fmt = &isl7998x_colour_fmts[0]; |
1522 | isl7998x->norm = V4L2_STD_NTSC; |
1523 | isl7998x->enabled = 0; |
1524 | |
1525 | mutex_init(&isl7998x->lock); |
1526 | |
1527 | ret = isl7998x_init_controls(isl7998x); |
1528 | if (ret) |
1529 | goto err_entity_cleanup; |
1530 | |
1531 | ret = v4l2_async_register_subdev(sd: &isl7998x->subdev); |
1532 | if (ret < 0) |
1533 | goto err_controls_cleanup; |
1534 | |
1535 | pm_runtime_enable(dev); |
1536 | |
1537 | return 0; |
1538 | |
1539 | err_controls_cleanup: |
1540 | isl7998x_remove_controls(isl7998x); |
1541 | err_entity_cleanup: |
1542 | media_entity_cleanup(entity: &isl7998x->subdev.entity); |
1543 | |
1544 | return ret; |
1545 | } |
1546 | |
1547 | static void isl7998x_remove(struct i2c_client *client) |
1548 | { |
1549 | struct isl7998x *isl7998x = i2c_to_isl7998x(client); |
1550 | |
1551 | pm_runtime_disable(dev: &client->dev); |
1552 | v4l2_async_unregister_subdev(sd: &isl7998x->subdev); |
1553 | isl7998x_remove_controls(isl7998x); |
1554 | media_entity_cleanup(entity: &isl7998x->subdev.entity); |
1555 | } |
1556 | |
1557 | static const struct of_device_id isl7998x_of_match[] = { |
1558 | { .compatible = "isil,isl79987" , }, |
1559 | { /* sentinel */ }, |
1560 | }; |
1561 | MODULE_DEVICE_TABLE(of, isl7998x_of_match); |
1562 | |
1563 | static const struct i2c_device_id isl7998x_id[] = { |
1564 | { "isl79987" , 0 }, |
1565 | { /* sentinel */ }, |
1566 | }; |
1567 | MODULE_DEVICE_TABLE(i2c, isl7998x_id); |
1568 | |
1569 | static int __maybe_unused isl7998x_runtime_resume(struct device *dev) |
1570 | { |
1571 | struct v4l2_subdev *sd = dev_get_drvdata(dev); |
1572 | struct isl7998x *isl7998x = sd_to_isl7998x(sd); |
1573 | int ret; |
1574 | |
1575 | gpiod_set_value(desc: isl7998x->rstb_gpio, value: 1); |
1576 | gpiod_set_value(desc: isl7998x->pd_gpio, value: 0); |
1577 | gpiod_set_value(desc: isl7998x->rstb_gpio, value: 0); |
1578 | |
1579 | ret = isl7998x_wait_power_on(isl7998x); |
1580 | if (ret) |
1581 | goto err; |
1582 | |
1583 | ret = isl7998x_init(isl7998x); |
1584 | if (ret) |
1585 | goto err; |
1586 | |
1587 | return 0; |
1588 | |
1589 | err: |
1590 | gpiod_set_value(desc: isl7998x->pd_gpio, value: 1); |
1591 | |
1592 | return ret; |
1593 | } |
1594 | |
1595 | static int __maybe_unused isl7998x_runtime_suspend(struct device *dev) |
1596 | { |
1597 | struct v4l2_subdev *sd = dev_get_drvdata(dev); |
1598 | struct isl7998x *isl7998x = sd_to_isl7998x(sd); |
1599 | |
1600 | gpiod_set_value(desc: isl7998x->pd_gpio, value: 1); |
1601 | |
1602 | return 0; |
1603 | } |
1604 | |
1605 | static const struct dev_pm_ops isl7998x_pm_ops = { |
1606 | SET_RUNTIME_PM_OPS(isl7998x_runtime_suspend, |
1607 | isl7998x_runtime_resume, |
1608 | NULL) |
1609 | }; |
1610 | |
1611 | static struct i2c_driver isl7998x_i2c_driver = { |
1612 | .driver = { |
1613 | .name = "isl7998x" , |
1614 | .of_match_table = isl7998x_of_match, |
1615 | .pm = &isl7998x_pm_ops, |
1616 | }, |
1617 | .probe = isl7998x_probe, |
1618 | .remove = isl7998x_remove, |
1619 | .id_table = isl7998x_id, |
1620 | }; |
1621 | |
1622 | module_i2c_driver(isl7998x_i2c_driver); |
1623 | |
1624 | MODULE_DESCRIPTION("Intersil ISL7998x Analog to MIPI CSI-2/BT656 decoder" ); |
1625 | MODULE_AUTHOR("Marek Vasut <marex@denx.de>" ); |
1626 | MODULE_LICENSE("GPL v2" ); |
1627 | |