1e8c08826SMartin Kepplinger // SPDX-License-Identifier: GPL-2.0
2e8c08826SMartin Kepplinger // Copyright (c) 2021 Purism SPC
3e8c08826SMartin Kepplinger
4e8c08826SMartin Kepplinger #include <asm/unaligned.h>
5e8c08826SMartin Kepplinger #include <linux/clk.h>
6e8c08826SMartin Kepplinger #include <linux/delay.h>
7e8c08826SMartin Kepplinger #include <linux/gpio/consumer.h>
8e8c08826SMartin Kepplinger #include <linux/i2c.h>
9e8c08826SMartin Kepplinger #include <linux/module.h>
10e8c08826SMartin Kepplinger #include <linux/pm_runtime.h>
11e8c08826SMartin Kepplinger #include <linux/pm.h>
12e7cc3e09SMartin Kepplinger #include <linux/property.h>
13e8c08826SMartin Kepplinger #include <linux/regulator/consumer.h>
14e8c08826SMartin Kepplinger #include <media/v4l2-ctrls.h>
15e8c08826SMartin Kepplinger #include <media/v4l2-device.h>
16e8c08826SMartin Kepplinger #include <media/v4l2-fwnode.h>
17e8c08826SMartin Kepplinger
18e8c08826SMartin Kepplinger #define HI846_MEDIA_BUS_FORMAT MEDIA_BUS_FMT_SGBRG10_1X10
19e8c08826SMartin Kepplinger #define HI846_RGB_DEPTH 10
20e8c08826SMartin Kepplinger
21e8c08826SMartin Kepplinger /* Frame length lines / vertical timings */
22e8c08826SMartin Kepplinger #define HI846_REG_FLL 0x0006
23e8c08826SMartin Kepplinger #define HI846_FLL_MAX 0xffff
24e8c08826SMartin Kepplinger
25e8c08826SMartin Kepplinger /* Horizontal timing */
26e8c08826SMartin Kepplinger #define HI846_REG_LLP 0x0008
27e8c08826SMartin Kepplinger #define HI846_LINE_LENGTH 3800
28e8c08826SMartin Kepplinger
29e8c08826SMartin Kepplinger #define HI846_REG_BINNING_MODE 0x000c
30e8c08826SMartin Kepplinger
31e8c08826SMartin Kepplinger #define HI846_REG_IMAGE_ORIENTATION 0x000e
32e8c08826SMartin Kepplinger
33e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0022 0x0022
34e8c08826SMartin Kepplinger
35e8c08826SMartin Kepplinger #define HI846_REG_Y_ADDR_START_VACT_H 0x0026
36e8c08826SMartin Kepplinger #define HI846_REG_Y_ADDR_START_VACT_L 0x0027
37e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0028 0x0028
38e8c08826SMartin Kepplinger
39e8c08826SMartin Kepplinger #define HI846_REG_Y_ADDR_END_VACT_H 0x002c
40e8c08826SMartin Kepplinger #define HI846_REG_Y_ADDR_END_VACT_L 0x002d
41e8c08826SMartin Kepplinger
42e8c08826SMartin Kepplinger #define HI846_REG_Y_ODD_INC_FOBP 0x002e
43e8c08826SMartin Kepplinger #define HI846_REG_Y_EVEN_INC_FOBP 0x002f
44e8c08826SMartin Kepplinger
45e8c08826SMartin Kepplinger #define HI846_REG_Y_ODD_INC_VACT 0x0032
46e8c08826SMartin Kepplinger #define HI846_REG_Y_EVEN_INC_VACT 0x0033
47e8c08826SMartin Kepplinger
48e8c08826SMartin Kepplinger #define HI846_REG_GROUPED_PARA_HOLD 0x0046
49e8c08826SMartin Kepplinger
50e8c08826SMartin Kepplinger #define HI846_REG_TG_ENABLE 0x004c
51e8c08826SMartin Kepplinger
52e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_005C 0x005c
53e8c08826SMartin Kepplinger
54e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_006A 0x006a
55e8c08826SMartin Kepplinger
56e8c08826SMartin Kepplinger /*
57e8c08826SMartin Kepplinger * Long exposure time. Actually, exposure is a 20 bit value that
58e8c08826SMartin Kepplinger * includes the lower 4 bits of 0x0073 too. Only 16 bits are used
59e8c08826SMartin Kepplinger * right now
60e8c08826SMartin Kepplinger */
61e8c08826SMartin Kepplinger #define HI846_REG_EXPOSURE 0x0074
62e8c08826SMartin Kepplinger #define HI846_EXPOSURE_MIN 6
63e8c08826SMartin Kepplinger #define HI846_EXPOSURE_MAX_MARGIN 2
64e8c08826SMartin Kepplinger #define HI846_EXPOSURE_STEP 1
65e8c08826SMartin Kepplinger
66e8c08826SMartin Kepplinger /* Analog gain controls from sensor */
67e8c08826SMartin Kepplinger #define HI846_REG_ANALOG_GAIN 0x0077
68e8c08826SMartin Kepplinger #define HI846_ANAL_GAIN_MIN 0
69e8c08826SMartin Kepplinger #define HI846_ANAL_GAIN_MAX 240
70e8c08826SMartin Kepplinger #define HI846_ANAL_GAIN_STEP 8
71e8c08826SMartin Kepplinger
72e8c08826SMartin Kepplinger /* Digital gain controls from sensor */
73e8c08826SMartin Kepplinger #define HI846_REG_MWB_GR_GAIN_H 0x0078
74e8c08826SMartin Kepplinger #define HI846_REG_MWB_GR_GAIN_L 0x0079
75e8c08826SMartin Kepplinger #define HI846_REG_MWB_GB_GAIN_H 0x007a
76e8c08826SMartin Kepplinger #define HI846_REG_MWB_GB_GAIN_L 0x007b
77e8c08826SMartin Kepplinger #define HI846_REG_MWB_R_GAIN_H 0x007c
78e8c08826SMartin Kepplinger #define HI846_REG_MWB_R_GAIN_L 0x007d
79e8c08826SMartin Kepplinger #define HI846_REG_MWB_B_GAIN_H 0x007e
80e8c08826SMartin Kepplinger #define HI846_REG_MWB_B_GAIN_L 0x007f
81e8c08826SMartin Kepplinger #define HI846_DGTL_GAIN_MIN 512
82e8c08826SMartin Kepplinger #define HI846_DGTL_GAIN_MAX 8191
83e8c08826SMartin Kepplinger #define HI846_DGTL_GAIN_STEP 1
84e8c08826SMartin Kepplinger #define HI846_DGTL_GAIN_DEFAULT 512
85e8c08826SMartin Kepplinger
86e8c08826SMartin Kepplinger #define HI846_REG_X_ADDR_START_HACT_H 0x0120
87e8c08826SMartin Kepplinger #define HI846_REG_X_ADDR_END_HACT_H 0x0122
88e8c08826SMartin Kepplinger
89e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_012A 0x012a
90e8c08826SMartin Kepplinger
91e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0200 0x0200
92e8c08826SMartin Kepplinger
93e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_021C 0x021c
94e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_021E 0x021e
95e8c08826SMartin Kepplinger
96e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0402 0x0402
97e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0404 0x0404
98e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0408 0x0408
99e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0410 0x0410
100e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0412 0x0412
101e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0414 0x0414
102e8c08826SMartin Kepplinger
103e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0418 0x0418
104e8c08826SMartin Kepplinger
105e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_051E 0x051e
106e8c08826SMartin Kepplinger
107e8c08826SMartin Kepplinger /* Formatter */
108e8c08826SMartin Kepplinger #define HI846_REG_X_START_H 0x0804
109e8c08826SMartin Kepplinger #define HI846_REG_X_START_L 0x0805
110e8c08826SMartin Kepplinger
111e8c08826SMartin Kepplinger /* MIPI */
112e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0900 0x0900
113e8c08826SMartin Kepplinger #define HI846_REG_MIPI_TX_OP_EN 0x0901
114e8c08826SMartin Kepplinger #define HI846_REG_MIPI_TX_OP_MODE 0x0902
115e8c08826SMartin Kepplinger #define HI846_RAW8 BIT(5)
116e8c08826SMartin Kepplinger
117e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_090C 0x090c
118e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_090E 0x090e
119e8c08826SMartin Kepplinger
120e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0914 0x0914
121e8c08826SMartin Kepplinger #define HI846_REG_TLPX 0x0915
122e8c08826SMartin Kepplinger #define HI846_REG_TCLK_PREPARE 0x0916
123e8c08826SMartin Kepplinger #define HI846_REG_TCLK_ZERO 0x0917
124e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0918 0x0918
125e8c08826SMartin Kepplinger #define HI846_REG_THS_PREPARE 0x0919
126e8c08826SMartin Kepplinger #define HI846_REG_THS_ZERO 0x091a
127e8c08826SMartin Kepplinger #define HI846_REG_THS_TRAIL 0x091b
128e8c08826SMartin Kepplinger #define HI846_REG_TCLK_POST 0x091c
129e8c08826SMartin Kepplinger #define HI846_REG_TCLK_TRAIL_MIN 0x091d
130e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_091E 0x091e
131e8c08826SMartin Kepplinger
132e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0954 0x0954
133e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0956 0x0956
134e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0958 0x0958
135e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_095A 0x095a
136e8c08826SMartin Kepplinger
137e8c08826SMartin Kepplinger /* ISP Common */
138e8c08826SMartin Kepplinger #define HI846_REG_MODE_SELECT 0x0a00
139e8c08826SMartin Kepplinger #define HI846_MODE_STANDBY 0x00
140e8c08826SMartin Kepplinger #define HI846_MODE_STREAMING 0x01
141e8c08826SMartin Kepplinger #define HI846_REG_FAST_STANDBY_MODE 0x0a02
142e8c08826SMartin Kepplinger #define HI846_REG_ISP_EN_H 0x0a04
143e8c08826SMartin Kepplinger
144e8c08826SMartin Kepplinger /* Test Pattern Control */
145e8c08826SMartin Kepplinger #define HI846_REG_ISP 0x0a05
146e8c08826SMartin Kepplinger #define HI846_REG_ISP_TPG_EN 0x01
147e8c08826SMartin Kepplinger #define HI846_REG_TEST_PATTERN 0x020a /* 1-9 */
148e8c08826SMartin Kepplinger
149e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0A0C 0x0a0c
150e8c08826SMartin Kepplinger
151e8c08826SMartin Kepplinger /* Windowing */
152e8c08826SMartin Kepplinger #define HI846_REG_X_OUTPUT_SIZE_H 0x0a12
153e8c08826SMartin Kepplinger #define HI846_REG_X_OUTPUT_SIZE_L 0x0a13
154e8c08826SMartin Kepplinger #define HI846_REG_Y_OUTPUT_SIZE_H 0x0a14
155e8c08826SMartin Kepplinger #define HI846_REG_Y_OUTPUT_SIZE_L 0x0a15
156e8c08826SMartin Kepplinger
157e8c08826SMartin Kepplinger /* ISP Common */
158e8c08826SMartin Kepplinger #define HI846_REG_PEDESTAL_EN 0x0a1a
159e8c08826SMartin Kepplinger
160e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0A1E 0x0a1e
161e8c08826SMartin Kepplinger
162e8c08826SMartin Kepplinger /* Horizontal Binning Mode */
163e8c08826SMartin Kepplinger #define HI846_REG_HBIN_MODE 0x0a22
164e8c08826SMartin Kepplinger
165e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0A24 0x0a24
166e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0B02 0x0b02
167e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0B10 0x0b10
168e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0B12 0x0b12
169e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0B14 0x0b14
170e8c08826SMartin Kepplinger
171e8c08826SMartin Kepplinger /* BLC (Black Level Calibration) */
172e8c08826SMartin Kepplinger #define HI846_REG_BLC_CTL0 0x0c00
173e8c08826SMartin Kepplinger
174e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0C06 0x0c06
175e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0C10 0x0c10
176e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0C12 0x0c12
177e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0C14 0x0c14
178e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0C16 0x0c16
179e8c08826SMartin Kepplinger
180e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0E04 0x0e04
181e8c08826SMartin Kepplinger
182e8c08826SMartin Kepplinger #define HI846_REG_CHIP_ID_L 0x0f16
183e8c08826SMartin Kepplinger #define HI846_REG_CHIP_ID_H 0x0f17
184e8c08826SMartin Kepplinger #define HI846_CHIP_ID_L 0x46
185e8c08826SMartin Kepplinger #define HI846_CHIP_ID_H 0x08
186e8c08826SMartin Kepplinger
187e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0F04 0x0f04
188e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0F08 0x0f08
189e8c08826SMartin Kepplinger
190e8c08826SMartin Kepplinger /* PLL */
191e8c08826SMartin Kepplinger #define HI846_REG_PLL_CFG_MIPI2_H 0x0f2a
192e8c08826SMartin Kepplinger #define HI846_REG_PLL_CFG_MIPI2_L 0x0f2b
193e8c08826SMartin Kepplinger
194e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0F30 0x0f30
195e8c08826SMartin Kepplinger #define HI846_REG_PLL_CFG_RAMP1_H 0x0f32
196e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_0F36 0x0f36
197e8c08826SMartin Kepplinger #define HI846_REG_PLL_CFG_MIPI1_H 0x0f38
198e8c08826SMartin Kepplinger
199e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_2008 0x2008
200e8c08826SMartin Kepplinger #define HI846_REG_UNKNOWN_326E 0x326e
201e8c08826SMartin Kepplinger
202e8c08826SMartin Kepplinger struct hi846_reg {
203e8c08826SMartin Kepplinger u16 address;
204e8c08826SMartin Kepplinger u16 val;
205e8c08826SMartin Kepplinger };
206e8c08826SMartin Kepplinger
207e8c08826SMartin Kepplinger struct hi846_reg_list {
208e8c08826SMartin Kepplinger u32 num_of_regs;
209e8c08826SMartin Kepplinger const struct hi846_reg *regs;
210e8c08826SMartin Kepplinger };
211e8c08826SMartin Kepplinger
212e8c08826SMartin Kepplinger struct hi846_mode {
213e8c08826SMartin Kepplinger /* Frame width in pixels */
214e8c08826SMartin Kepplinger u32 width;
215e8c08826SMartin Kepplinger
216e8c08826SMartin Kepplinger /* Frame height in pixels */
217e8c08826SMartin Kepplinger u32 height;
218e8c08826SMartin Kepplinger
219e8c08826SMartin Kepplinger /* Horizontal timing size */
220e8c08826SMartin Kepplinger u32 llp;
221e8c08826SMartin Kepplinger
222e8c08826SMartin Kepplinger /* Link frequency needed for this resolution */
223e8c08826SMartin Kepplinger u8 link_freq_index;
224e8c08826SMartin Kepplinger
225e8c08826SMartin Kepplinger u16 fps;
226e8c08826SMartin Kepplinger
227e8c08826SMartin Kepplinger /* Vertical timining size */
228e8c08826SMartin Kepplinger u16 frame_len;
229e8c08826SMartin Kepplinger
230e8c08826SMartin Kepplinger const struct hi846_reg_list reg_list_config;
231e8c08826SMartin Kepplinger const struct hi846_reg_list reg_list_2lane;
232e8c08826SMartin Kepplinger const struct hi846_reg_list reg_list_4lane;
233e8c08826SMartin Kepplinger
234e8c08826SMartin Kepplinger /* Position inside of the 3264x2448 pixel array */
235e8c08826SMartin Kepplinger struct v4l2_rect crop;
236e8c08826SMartin Kepplinger };
237e8c08826SMartin Kepplinger
238e8c08826SMartin Kepplinger static const struct hi846_reg hi846_init_2lane[] = {
239e8c08826SMartin Kepplinger {HI846_REG_MODE_SELECT, 0x0000},
240e8c08826SMartin Kepplinger /* regs below are unknown */
241e8c08826SMartin Kepplinger {0x2000, 0x100a},
242e8c08826SMartin Kepplinger {0x2002, 0x00ff},
243e8c08826SMartin Kepplinger {0x2004, 0x0007},
244e8c08826SMartin Kepplinger {0x2006, 0x3fff},
245e8c08826SMartin Kepplinger {0x2008, 0x3fff},
246e8c08826SMartin Kepplinger {0x200a, 0xc216},
247e8c08826SMartin Kepplinger {0x200c, 0x1292},
248e8c08826SMartin Kepplinger {0x200e, 0xc01a},
249e8c08826SMartin Kepplinger {0x2010, 0x403d},
250e8c08826SMartin Kepplinger {0x2012, 0x000e},
251e8c08826SMartin Kepplinger {0x2014, 0x403e},
252e8c08826SMartin Kepplinger {0x2016, 0x0b80},
253e8c08826SMartin Kepplinger {0x2018, 0x403f},
254e8c08826SMartin Kepplinger {0x201a, 0x82ae},
255e8c08826SMartin Kepplinger {0x201c, 0x1292},
256e8c08826SMartin Kepplinger {0x201e, 0xc00c},
257e8c08826SMartin Kepplinger {0x2020, 0x4130},
258e8c08826SMartin Kepplinger {0x2022, 0x43e2},
259e8c08826SMartin Kepplinger {0x2024, 0x0180},
260e8c08826SMartin Kepplinger {0x2026, 0x4130},
261e8c08826SMartin Kepplinger {0x2028, 0x7400},
262e8c08826SMartin Kepplinger {0x202a, 0x5000},
263e8c08826SMartin Kepplinger {0x202c, 0x0253},
264e8c08826SMartin Kepplinger {0x202e, 0x0ad1},
265e8c08826SMartin Kepplinger {0x2030, 0x2360},
266e8c08826SMartin Kepplinger {0x2032, 0x0009},
267e8c08826SMartin Kepplinger {0x2034, 0x5020},
268e8c08826SMartin Kepplinger {0x2036, 0x000b},
269e8c08826SMartin Kepplinger {0x2038, 0x0002},
270e8c08826SMartin Kepplinger {0x203a, 0x0044},
271e8c08826SMartin Kepplinger {0x203c, 0x0016},
272e8c08826SMartin Kepplinger {0x203e, 0x1792},
273e8c08826SMartin Kepplinger {0x2040, 0x7002},
274e8c08826SMartin Kepplinger {0x2042, 0x154f},
275e8c08826SMartin Kepplinger {0x2044, 0x00d5},
276e8c08826SMartin Kepplinger {0x2046, 0x000b},
277e8c08826SMartin Kepplinger {0x2048, 0x0019},
278e8c08826SMartin Kepplinger {0x204a, 0x1698},
279e8c08826SMartin Kepplinger {0x204c, 0x000e},
280e8c08826SMartin Kepplinger {0x204e, 0x099a},
281e8c08826SMartin Kepplinger {0x2050, 0x0058},
282e8c08826SMartin Kepplinger {0x2052, 0x7000},
283e8c08826SMartin Kepplinger {0x2054, 0x1799},
284e8c08826SMartin Kepplinger {0x2056, 0x0310},
285e8c08826SMartin Kepplinger {0x2058, 0x03c3},
286e8c08826SMartin Kepplinger {0x205a, 0x004c},
287e8c08826SMartin Kepplinger {0x205c, 0x064a},
288e8c08826SMartin Kepplinger {0x205e, 0x0001},
289e8c08826SMartin Kepplinger {0x2060, 0x0007},
290e8c08826SMartin Kepplinger {0x2062, 0x0bc7},
291e8c08826SMartin Kepplinger {0x2064, 0x0055},
292e8c08826SMartin Kepplinger {0x2066, 0x7000},
293e8c08826SMartin Kepplinger {0x2068, 0x1550},
294e8c08826SMartin Kepplinger {0x206a, 0x158a},
295e8c08826SMartin Kepplinger {0x206c, 0x0004},
296e8c08826SMartin Kepplinger {0x206e, 0x1488},
297e8c08826SMartin Kepplinger {0x2070, 0x7010},
298e8c08826SMartin Kepplinger {0x2072, 0x1508},
299e8c08826SMartin Kepplinger {0x2074, 0x0004},
300e8c08826SMartin Kepplinger {0x2076, 0x0016},
301e8c08826SMartin Kepplinger {0x2078, 0x03d5},
302e8c08826SMartin Kepplinger {0x207a, 0x0055},
303e8c08826SMartin Kepplinger {0x207c, 0x08ca},
304e8c08826SMartin Kepplinger {0x207e, 0x2019},
305e8c08826SMartin Kepplinger {0x2080, 0x0007},
306e8c08826SMartin Kepplinger {0x2082, 0x7057},
307e8c08826SMartin Kepplinger {0x2084, 0x0fc7},
308e8c08826SMartin Kepplinger {0x2086, 0x5041},
309e8c08826SMartin Kepplinger {0x2088, 0x12c8},
310e8c08826SMartin Kepplinger {0x208a, 0x5060},
311e8c08826SMartin Kepplinger {0x208c, 0x5080},
312e8c08826SMartin Kepplinger {0x208e, 0x2084},
313e8c08826SMartin Kepplinger {0x2090, 0x12c8},
314e8c08826SMartin Kepplinger {0x2092, 0x7800},
315e8c08826SMartin Kepplinger {0x2094, 0x0802},
316e8c08826SMartin Kepplinger {0x2096, 0x040f},
317e8c08826SMartin Kepplinger {0x2098, 0x1007},
318e8c08826SMartin Kepplinger {0x209a, 0x0803},
319e8c08826SMartin Kepplinger {0x209c, 0x080b},
320e8c08826SMartin Kepplinger {0x209e, 0x3803},
321e8c08826SMartin Kepplinger {0x20a0, 0x0807},
322e8c08826SMartin Kepplinger {0x20a2, 0x0404},
323e8c08826SMartin Kepplinger {0x20a4, 0x0400},
324e8c08826SMartin Kepplinger {0x20a6, 0xffff},
325e8c08826SMartin Kepplinger {0x20a8, 0xf0b2},
326e8c08826SMartin Kepplinger {0x20aa, 0xffef},
327e8c08826SMartin Kepplinger {0x20ac, 0x0a84},
328e8c08826SMartin Kepplinger {0x20ae, 0x1292},
329e8c08826SMartin Kepplinger {0x20b0, 0xc02e},
330e8c08826SMartin Kepplinger {0x20b2, 0x4130},
331e8c08826SMartin Kepplinger {0x23fe, 0xc056},
332e8c08826SMartin Kepplinger {0x3232, 0xfc0c},
333e8c08826SMartin Kepplinger {0x3236, 0xfc22},
334e8c08826SMartin Kepplinger {0x3248, 0xfca8},
335e8c08826SMartin Kepplinger {0x326a, 0x8302},
336e8c08826SMartin Kepplinger {0x326c, 0x830a},
337e8c08826SMartin Kepplinger {0x326e, 0x0000},
338e8c08826SMartin Kepplinger {0x32ca, 0xfc28},
339e8c08826SMartin Kepplinger {0x32cc, 0xc3bc},
340e8c08826SMartin Kepplinger {0x32ce, 0xc34c},
341e8c08826SMartin Kepplinger {0x32d0, 0xc35a},
342e8c08826SMartin Kepplinger {0x32d2, 0xc368},
343e8c08826SMartin Kepplinger {0x32d4, 0xc376},
344e8c08826SMartin Kepplinger {0x32d6, 0xc3c2},
345e8c08826SMartin Kepplinger {0x32d8, 0xc3e6},
346e8c08826SMartin Kepplinger {0x32da, 0x0003},
347e8c08826SMartin Kepplinger {0x32dc, 0x0003},
348e8c08826SMartin Kepplinger {0x32de, 0x00c7},
349e8c08826SMartin Kepplinger {0x32e0, 0x0031},
350e8c08826SMartin Kepplinger {0x32e2, 0x0031},
351e8c08826SMartin Kepplinger {0x32e4, 0x0031},
352e8c08826SMartin Kepplinger {0x32e6, 0xfc28},
353e8c08826SMartin Kepplinger {0x32e8, 0xc3bc},
354e8c08826SMartin Kepplinger {0x32ea, 0xc384},
355e8c08826SMartin Kepplinger {0x32ec, 0xc392},
356e8c08826SMartin Kepplinger {0x32ee, 0xc3a0},
357e8c08826SMartin Kepplinger {0x32f0, 0xc3ae},
358e8c08826SMartin Kepplinger {0x32f2, 0xc3c4},
359e8c08826SMartin Kepplinger {0x32f4, 0xc3e6},
360e8c08826SMartin Kepplinger {0x32f6, 0x0003},
361e8c08826SMartin Kepplinger {0x32f8, 0x0003},
362e8c08826SMartin Kepplinger {0x32fa, 0x00c7},
363e8c08826SMartin Kepplinger {0x32fc, 0x0031},
364e8c08826SMartin Kepplinger {0x32fe, 0x0031},
365e8c08826SMartin Kepplinger {0x3300, 0x0031},
366e8c08826SMartin Kepplinger {0x3302, 0x82ca},
367e8c08826SMartin Kepplinger {0x3304, 0xc164},
368e8c08826SMartin Kepplinger {0x3306, 0x82e6},
369e8c08826SMartin Kepplinger {0x3308, 0xc19c},
370e8c08826SMartin Kepplinger {0x330a, 0x001f},
371e8c08826SMartin Kepplinger {0x330c, 0x001a},
372e8c08826SMartin Kepplinger {0x330e, 0x0034},
373e8c08826SMartin Kepplinger {0x3310, 0x0000},
374e8c08826SMartin Kepplinger {0x3312, 0x0000},
375e8c08826SMartin Kepplinger {0x3314, 0xfc94},
376e8c08826SMartin Kepplinger {0x3316, 0xc3d8},
377e8c08826SMartin Kepplinger /* regs above are unknown */
378e8c08826SMartin Kepplinger {HI846_REG_MODE_SELECT, 0x0000},
379e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0E04, 0x0012},
380e8c08826SMartin Kepplinger {HI846_REG_Y_ODD_INC_FOBP, 0x1111},
381e8c08826SMartin Kepplinger {HI846_REG_Y_ODD_INC_VACT, 0x1111},
382e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0022, 0x0008},
383e8c08826SMartin Kepplinger {HI846_REG_Y_ADDR_START_VACT_H, 0x0040},
384e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0028, 0x0017},
385e8c08826SMartin Kepplinger {HI846_REG_Y_ADDR_END_VACT_H, 0x09cf},
386e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_005C, 0x2101},
387e8c08826SMartin Kepplinger {HI846_REG_FLL, 0x09de},
388e8c08826SMartin Kepplinger {HI846_REG_LLP, 0x0ed8},
389e8c08826SMartin Kepplinger {HI846_REG_IMAGE_ORIENTATION, 0x0100},
390e8c08826SMartin Kepplinger {HI846_REG_BINNING_MODE, 0x0022},
391e8c08826SMartin Kepplinger {HI846_REG_HBIN_MODE, 0x0000},
392e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0A24, 0x0000},
393e8c08826SMartin Kepplinger {HI846_REG_X_START_H, 0x0000},
394e8c08826SMartin Kepplinger {HI846_REG_X_OUTPUT_SIZE_H, 0x0cc0},
395e8c08826SMartin Kepplinger {HI846_REG_Y_OUTPUT_SIZE_H, 0x0990},
396e8c08826SMartin Kepplinger {HI846_REG_EXPOSURE, 0x09d8},
397e8c08826SMartin Kepplinger {HI846_REG_ANALOG_GAIN, 0x0000},
398e8c08826SMartin Kepplinger {HI846_REG_GROUPED_PARA_HOLD, 0x0000},
399e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_051E, 0x0000},
400e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0200, 0x0400},
401e8c08826SMartin Kepplinger {HI846_REG_PEDESTAL_EN, 0x0c00},
402e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0A0C, 0x0010},
403e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0A1E, 0x0ccf},
404e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0402, 0x0110},
405e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0404, 0x00f4},
406e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0408, 0x0000},
407e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0410, 0x008d},
408e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0412, 0x011a},
409e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0414, 0x864c},
410e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_021C, 0x0003},
411e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_021E, 0x0235},
412e8c08826SMartin Kepplinger {HI846_REG_BLC_CTL0, 0x9150},
413e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0C06, 0x0021},
414e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0C10, 0x0040},
415e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0C12, 0x0040},
416e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0C14, 0x0040},
417e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0C16, 0x0040},
418e8c08826SMartin Kepplinger {HI846_REG_FAST_STANDBY_MODE, 0x0100},
419e8c08826SMartin Kepplinger {HI846_REG_ISP_EN_H, 0x014a},
420e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0418, 0x0000},
421e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_012A, 0x03b4},
422e8c08826SMartin Kepplinger {HI846_REG_X_ADDR_START_HACT_H, 0x0046},
423e8c08826SMartin Kepplinger {HI846_REG_X_ADDR_END_HACT_H, 0x0376},
424e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B02, 0xe04d},
425e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B10, 0x6821},
426e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B12, 0x0120},
427e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B14, 0x0001},
428e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_2008, 0x38fd},
429e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_326E, 0x0000},
430e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0900, 0x0320},
431e8c08826SMartin Kepplinger {HI846_REG_MIPI_TX_OP_MODE, 0xc31a},
432e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0914, 0xc109},
433e8c08826SMartin Kepplinger {HI846_REG_TCLK_PREPARE, 0x061a},
434e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0918, 0x0306},
435e8c08826SMartin Kepplinger {HI846_REG_THS_ZERO, 0x0b09},
436e8c08826SMartin Kepplinger {HI846_REG_TCLK_POST, 0x0c07},
437e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_091E, 0x0a00},
438e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_090C, 0x042a},
439e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_090E, 0x006b},
440e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0954, 0x0089},
441e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0956, 0x0000},
442e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0958, 0xca00},
443e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_095A, 0x9240},
444e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0F08, 0x2f04},
445e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0F30, 0x001f},
446e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0F36, 0x001f},
447e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0F04, 0x3a00},
448e8c08826SMartin Kepplinger {HI846_REG_PLL_CFG_RAMP1_H, 0x025a},
449e8c08826SMartin Kepplinger {HI846_REG_PLL_CFG_MIPI1_H, 0x025a},
450e8c08826SMartin Kepplinger {HI846_REG_PLL_CFG_MIPI2_H, 0x0024},
451e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_006A, 0x0100},
452e8c08826SMartin Kepplinger {HI846_REG_TG_ENABLE, 0x0100},
453e8c08826SMartin Kepplinger };
454e8c08826SMartin Kepplinger
455e8c08826SMartin Kepplinger static const struct hi846_reg hi846_init_4lane[] = {
456e8c08826SMartin Kepplinger {0x2000, 0x987a},
457e8c08826SMartin Kepplinger {0x2002, 0x00ff},
458e8c08826SMartin Kepplinger {0x2004, 0x0047},
459e8c08826SMartin Kepplinger {0x2006, 0x3fff},
460e8c08826SMartin Kepplinger {0x2008, 0x3fff},
461e8c08826SMartin Kepplinger {0x200a, 0xc216},
462e8c08826SMartin Kepplinger {0x200c, 0x1292},
463e8c08826SMartin Kepplinger {0x200e, 0xc01a},
464e8c08826SMartin Kepplinger {0x2010, 0x403d},
465e8c08826SMartin Kepplinger {0x2012, 0x000e},
466e8c08826SMartin Kepplinger {0x2014, 0x403e},
467e8c08826SMartin Kepplinger {0x2016, 0x0b80},
468e8c08826SMartin Kepplinger {0x2018, 0x403f},
469e8c08826SMartin Kepplinger {0x201a, 0x82ae},
470e8c08826SMartin Kepplinger {0x201c, 0x1292},
471e8c08826SMartin Kepplinger {0x201e, 0xc00c},
472e8c08826SMartin Kepplinger {0x2020, 0x4130},
473e8c08826SMartin Kepplinger {0x2022, 0x43e2},
474e8c08826SMartin Kepplinger {0x2024, 0x0180},
475e8c08826SMartin Kepplinger {0x2026, 0x4130},
476e8c08826SMartin Kepplinger {0x2028, 0x7400},
477e8c08826SMartin Kepplinger {0x202a, 0x5000},
478e8c08826SMartin Kepplinger {0x202c, 0x0253},
479e8c08826SMartin Kepplinger {0x202e, 0x0ad1},
480e8c08826SMartin Kepplinger {0x2030, 0x2360},
481e8c08826SMartin Kepplinger {0x2032, 0x0009},
482e8c08826SMartin Kepplinger {0x2034, 0x5020},
483e8c08826SMartin Kepplinger {0x2036, 0x000b},
484e8c08826SMartin Kepplinger {0x2038, 0x0002},
485e8c08826SMartin Kepplinger {0x203a, 0x0044},
486e8c08826SMartin Kepplinger {0x203c, 0x0016},
487e8c08826SMartin Kepplinger {0x203e, 0x1792},
488e8c08826SMartin Kepplinger {0x2040, 0x7002},
489e8c08826SMartin Kepplinger {0x2042, 0x154f},
490e8c08826SMartin Kepplinger {0x2044, 0x00d5},
491e8c08826SMartin Kepplinger {0x2046, 0x000b},
492e8c08826SMartin Kepplinger {0x2048, 0x0019},
493e8c08826SMartin Kepplinger {0x204a, 0x1698},
494e8c08826SMartin Kepplinger {0x204c, 0x000e},
495e8c08826SMartin Kepplinger {0x204e, 0x099a},
496e8c08826SMartin Kepplinger {0x2050, 0x0058},
497e8c08826SMartin Kepplinger {0x2052, 0x7000},
498e8c08826SMartin Kepplinger {0x2054, 0x1799},
499e8c08826SMartin Kepplinger {0x2056, 0x0310},
500e8c08826SMartin Kepplinger {0x2058, 0x03c3},
501e8c08826SMartin Kepplinger {0x205a, 0x004c},
502e8c08826SMartin Kepplinger {0x205c, 0x064a},
503e8c08826SMartin Kepplinger {0x205e, 0x0001},
504e8c08826SMartin Kepplinger {0x2060, 0x0007},
505e8c08826SMartin Kepplinger {0x2062, 0x0bc7},
506e8c08826SMartin Kepplinger {0x2064, 0x0055},
507e8c08826SMartin Kepplinger {0x2066, 0x7000},
508e8c08826SMartin Kepplinger {0x2068, 0x1550},
509e8c08826SMartin Kepplinger {0x206a, 0x158a},
510e8c08826SMartin Kepplinger {0x206c, 0x0004},
511e8c08826SMartin Kepplinger {0x206e, 0x1488},
512e8c08826SMartin Kepplinger {0x2070, 0x7010},
513e8c08826SMartin Kepplinger {0x2072, 0x1508},
514e8c08826SMartin Kepplinger {0x2074, 0x0004},
515e8c08826SMartin Kepplinger {0x2076, 0x0016},
516e8c08826SMartin Kepplinger {0x2078, 0x03d5},
517e8c08826SMartin Kepplinger {0x207a, 0x0055},
518e8c08826SMartin Kepplinger {0x207c, 0x08ca},
519e8c08826SMartin Kepplinger {0x207e, 0x2019},
520e8c08826SMartin Kepplinger {0x2080, 0x0007},
521e8c08826SMartin Kepplinger {0x2082, 0x7057},
522e8c08826SMartin Kepplinger {0x2084, 0x0fc7},
523e8c08826SMartin Kepplinger {0x2086, 0x5041},
524e8c08826SMartin Kepplinger {0x2088, 0x12c8},
525e8c08826SMartin Kepplinger {0x208a, 0x5060},
526e8c08826SMartin Kepplinger {0x208c, 0x5080},
527e8c08826SMartin Kepplinger {0x208e, 0x2084},
528e8c08826SMartin Kepplinger {0x2090, 0x12c8},
529e8c08826SMartin Kepplinger {0x2092, 0x7800},
530e8c08826SMartin Kepplinger {0x2094, 0x0802},
531e8c08826SMartin Kepplinger {0x2096, 0x040f},
532e8c08826SMartin Kepplinger {0x2098, 0x1007},
533e8c08826SMartin Kepplinger {0x209a, 0x0803},
534e8c08826SMartin Kepplinger {0x209c, 0x080b},
535e8c08826SMartin Kepplinger {0x209e, 0x3803},
536e8c08826SMartin Kepplinger {0x20a0, 0x0807},
537e8c08826SMartin Kepplinger {0x20a2, 0x0404},
538e8c08826SMartin Kepplinger {0x20a4, 0x0400},
539e8c08826SMartin Kepplinger {0x20a6, 0xffff},
540e8c08826SMartin Kepplinger {0x20a8, 0xf0b2},
541e8c08826SMartin Kepplinger {0x20aa, 0xffef},
542e8c08826SMartin Kepplinger {0x20ac, 0x0a84},
543e8c08826SMartin Kepplinger {0x20ae, 0x1292},
544e8c08826SMartin Kepplinger {0x20b0, 0xc02e},
545e8c08826SMartin Kepplinger {0x20b2, 0x4130},
546e8c08826SMartin Kepplinger {0x20b4, 0xf0b2},
547e8c08826SMartin Kepplinger {0x20b6, 0xffbf},
548e8c08826SMartin Kepplinger {0x20b8, 0x2004},
549e8c08826SMartin Kepplinger {0x20ba, 0x403f},
550e8c08826SMartin Kepplinger {0x20bc, 0x00c3},
551e8c08826SMartin Kepplinger {0x20be, 0x4fe2},
552e8c08826SMartin Kepplinger {0x20c0, 0x8318},
553e8c08826SMartin Kepplinger {0x20c2, 0x43cf},
554e8c08826SMartin Kepplinger {0x20c4, 0x0000},
555e8c08826SMartin Kepplinger {0x20c6, 0x9382},
556e8c08826SMartin Kepplinger {0x20c8, 0xc314},
557e8c08826SMartin Kepplinger {0x20ca, 0x2003},
558e8c08826SMartin Kepplinger {0x20cc, 0x12b0},
559e8c08826SMartin Kepplinger {0x20ce, 0xcab0},
560e8c08826SMartin Kepplinger {0x20d0, 0x4130},
561e8c08826SMartin Kepplinger {0x20d2, 0x12b0},
562e8c08826SMartin Kepplinger {0x20d4, 0xc90a},
563e8c08826SMartin Kepplinger {0x20d6, 0x4130},
564e8c08826SMartin Kepplinger {0x20d8, 0x42d2},
565e8c08826SMartin Kepplinger {0x20da, 0x8318},
566e8c08826SMartin Kepplinger {0x20dc, 0x00c3},
567e8c08826SMartin Kepplinger {0x20de, 0x9382},
568e8c08826SMartin Kepplinger {0x20e0, 0xc314},
569e8c08826SMartin Kepplinger {0x20e2, 0x2009},
570e8c08826SMartin Kepplinger {0x20e4, 0x120b},
571e8c08826SMartin Kepplinger {0x20e6, 0x120a},
572e8c08826SMartin Kepplinger {0x20e8, 0x1209},
573e8c08826SMartin Kepplinger {0x20ea, 0x1208},
574e8c08826SMartin Kepplinger {0x20ec, 0x1207},
575e8c08826SMartin Kepplinger {0x20ee, 0x1206},
576e8c08826SMartin Kepplinger {0x20f0, 0x4030},
577e8c08826SMartin Kepplinger {0x20f2, 0xc15e},
578e8c08826SMartin Kepplinger {0x20f4, 0x4130},
579e8c08826SMartin Kepplinger {0x20f6, 0x1292},
580e8c08826SMartin Kepplinger {0x20f8, 0xc008},
581e8c08826SMartin Kepplinger {0x20fa, 0x4130},
582e8c08826SMartin Kepplinger {0x20fc, 0x42d2},
583e8c08826SMartin Kepplinger {0x20fe, 0x82a1},
584e8c08826SMartin Kepplinger {0x2100, 0x00c2},
585e8c08826SMartin Kepplinger {0x2102, 0x1292},
586e8c08826SMartin Kepplinger {0x2104, 0xc040},
587e8c08826SMartin Kepplinger {0x2106, 0x4130},
588e8c08826SMartin Kepplinger {0x2108, 0x1292},
589e8c08826SMartin Kepplinger {0x210a, 0xc006},
590e8c08826SMartin Kepplinger {0x210c, 0x42a2},
591e8c08826SMartin Kepplinger {0x210e, 0x7324},
592e8c08826SMartin Kepplinger {0x2110, 0x9382},
593e8c08826SMartin Kepplinger {0x2112, 0xc314},
594e8c08826SMartin Kepplinger {0x2114, 0x2011},
595e8c08826SMartin Kepplinger {0x2116, 0x425f},
596e8c08826SMartin Kepplinger {0x2118, 0x82a1},
597e8c08826SMartin Kepplinger {0x211a, 0xf25f},
598e8c08826SMartin Kepplinger {0x211c, 0x00c1},
599e8c08826SMartin Kepplinger {0x211e, 0xf35f},
600e8c08826SMartin Kepplinger {0x2120, 0x2406},
601e8c08826SMartin Kepplinger {0x2122, 0x425f},
602e8c08826SMartin Kepplinger {0x2124, 0x00c0},
603e8c08826SMartin Kepplinger {0x2126, 0xf37f},
604e8c08826SMartin Kepplinger {0x2128, 0x522f},
605e8c08826SMartin Kepplinger {0x212a, 0x4f82},
606e8c08826SMartin Kepplinger {0x212c, 0x7324},
607e8c08826SMartin Kepplinger {0x212e, 0x425f},
608e8c08826SMartin Kepplinger {0x2130, 0x82d4},
609e8c08826SMartin Kepplinger {0x2132, 0xf35f},
610e8c08826SMartin Kepplinger {0x2134, 0x4fc2},
611e8c08826SMartin Kepplinger {0x2136, 0x01b3},
612e8c08826SMartin Kepplinger {0x2138, 0x93c2},
613e8c08826SMartin Kepplinger {0x213a, 0x829f},
614e8c08826SMartin Kepplinger {0x213c, 0x2421},
615e8c08826SMartin Kepplinger {0x213e, 0x403e},
616e8c08826SMartin Kepplinger {0x2140, 0xfffe},
617e8c08826SMartin Kepplinger {0x2142, 0x40b2},
618e8c08826SMartin Kepplinger {0x2144, 0xec78},
619e8c08826SMartin Kepplinger {0x2146, 0x831c},
620e8c08826SMartin Kepplinger {0x2148, 0x40b2},
621e8c08826SMartin Kepplinger {0x214a, 0xec78},
622e8c08826SMartin Kepplinger {0x214c, 0x831e},
623e8c08826SMartin Kepplinger {0x214e, 0x40b2},
624e8c08826SMartin Kepplinger {0x2150, 0xec78},
625e8c08826SMartin Kepplinger {0x2152, 0x8320},
626e8c08826SMartin Kepplinger {0x2154, 0xb3d2},
627e8c08826SMartin Kepplinger {0x2156, 0x008c},
628e8c08826SMartin Kepplinger {0x2158, 0x2405},
629e8c08826SMartin Kepplinger {0x215a, 0x4e0f},
630e8c08826SMartin Kepplinger {0x215c, 0x503f},
631e8c08826SMartin Kepplinger {0x215e, 0xffd8},
632e8c08826SMartin Kepplinger {0x2160, 0x4f82},
633e8c08826SMartin Kepplinger {0x2162, 0x831c},
634e8c08826SMartin Kepplinger {0x2164, 0x90f2},
635e8c08826SMartin Kepplinger {0x2166, 0x0003},
636e8c08826SMartin Kepplinger {0x2168, 0x008c},
637e8c08826SMartin Kepplinger {0x216a, 0x2401},
638e8c08826SMartin Kepplinger {0x216c, 0x4130},
639e8c08826SMartin Kepplinger {0x216e, 0x421f},
640e8c08826SMartin Kepplinger {0x2170, 0x831c},
641e8c08826SMartin Kepplinger {0x2172, 0x5e0f},
642e8c08826SMartin Kepplinger {0x2174, 0x4f82},
643e8c08826SMartin Kepplinger {0x2176, 0x831e},
644e8c08826SMartin Kepplinger {0x2178, 0x5e0f},
645e8c08826SMartin Kepplinger {0x217a, 0x4f82},
646e8c08826SMartin Kepplinger {0x217c, 0x8320},
647e8c08826SMartin Kepplinger {0x217e, 0x3ff6},
648e8c08826SMartin Kepplinger {0x2180, 0x432e},
649e8c08826SMartin Kepplinger {0x2182, 0x3fdf},
650e8c08826SMartin Kepplinger {0x2184, 0x421f},
651e8c08826SMartin Kepplinger {0x2186, 0x7100},
652e8c08826SMartin Kepplinger {0x2188, 0x4f0e},
653e8c08826SMartin Kepplinger {0x218a, 0x503e},
654e8c08826SMartin Kepplinger {0x218c, 0xffd8},
655e8c08826SMartin Kepplinger {0x218e, 0x4e82},
656e8c08826SMartin Kepplinger {0x2190, 0x7a04},
657e8c08826SMartin Kepplinger {0x2192, 0x421e},
658e8c08826SMartin Kepplinger {0x2194, 0x831c},
659e8c08826SMartin Kepplinger {0x2196, 0x5f0e},
660e8c08826SMartin Kepplinger {0x2198, 0x4e82},
661e8c08826SMartin Kepplinger {0x219a, 0x7a06},
662e8c08826SMartin Kepplinger {0x219c, 0x0b00},
663e8c08826SMartin Kepplinger {0x219e, 0x7304},
664e8c08826SMartin Kepplinger {0x21a0, 0x0050},
665e8c08826SMartin Kepplinger {0x21a2, 0x40b2},
666e8c08826SMartin Kepplinger {0x21a4, 0xd081},
667e8c08826SMartin Kepplinger {0x21a6, 0x0b88},
668e8c08826SMartin Kepplinger {0x21a8, 0x421e},
669e8c08826SMartin Kepplinger {0x21aa, 0x831e},
670e8c08826SMartin Kepplinger {0x21ac, 0x5f0e},
671e8c08826SMartin Kepplinger {0x21ae, 0x4e82},
672e8c08826SMartin Kepplinger {0x21b0, 0x7a0e},
673e8c08826SMartin Kepplinger {0x21b2, 0x521f},
674e8c08826SMartin Kepplinger {0x21b4, 0x8320},
675e8c08826SMartin Kepplinger {0x21b6, 0x4f82},
676e8c08826SMartin Kepplinger {0x21b8, 0x7a10},
677e8c08826SMartin Kepplinger {0x21ba, 0x0b00},
678e8c08826SMartin Kepplinger {0x21bc, 0x7304},
679e8c08826SMartin Kepplinger {0x21be, 0x007a},
680e8c08826SMartin Kepplinger {0x21c0, 0x40b2},
681e8c08826SMartin Kepplinger {0x21c2, 0x0081},
682e8c08826SMartin Kepplinger {0x21c4, 0x0b88},
683e8c08826SMartin Kepplinger {0x21c6, 0x4392},
684e8c08826SMartin Kepplinger {0x21c8, 0x7a0a},
685e8c08826SMartin Kepplinger {0x21ca, 0x0800},
686e8c08826SMartin Kepplinger {0x21cc, 0x7a0c},
687e8c08826SMartin Kepplinger {0x21ce, 0x0b00},
688e8c08826SMartin Kepplinger {0x21d0, 0x7304},
689e8c08826SMartin Kepplinger {0x21d2, 0x022b},
690e8c08826SMartin Kepplinger {0x21d4, 0x40b2},
691e8c08826SMartin Kepplinger {0x21d6, 0xd081},
692e8c08826SMartin Kepplinger {0x21d8, 0x0b88},
693e8c08826SMartin Kepplinger {0x21da, 0x0b00},
694e8c08826SMartin Kepplinger {0x21dc, 0x7304},
695e8c08826SMartin Kepplinger {0x21de, 0x0255},
696e8c08826SMartin Kepplinger {0x21e0, 0x40b2},
697e8c08826SMartin Kepplinger {0x21e2, 0x0081},
698e8c08826SMartin Kepplinger {0x21e4, 0x0b88},
699e8c08826SMartin Kepplinger {0x21e6, 0x4130},
700e8c08826SMartin Kepplinger {0x23fe, 0xc056},
701e8c08826SMartin Kepplinger {0x3232, 0xfc0c},
702e8c08826SMartin Kepplinger {0x3236, 0xfc22},
703e8c08826SMartin Kepplinger {0x3238, 0xfcfc},
704e8c08826SMartin Kepplinger {0x323a, 0xfd84},
705e8c08826SMartin Kepplinger {0x323c, 0xfd08},
706e8c08826SMartin Kepplinger {0x3246, 0xfcd8},
707e8c08826SMartin Kepplinger {0x3248, 0xfca8},
708e8c08826SMartin Kepplinger {0x324e, 0xfcb4},
709e8c08826SMartin Kepplinger {0x326a, 0x8302},
710e8c08826SMartin Kepplinger {0x326c, 0x830a},
711e8c08826SMartin Kepplinger {0x326e, 0x0000},
712e8c08826SMartin Kepplinger {0x32ca, 0xfc28},
713e8c08826SMartin Kepplinger {0x32cc, 0xc3bc},
714e8c08826SMartin Kepplinger {0x32ce, 0xc34c},
715e8c08826SMartin Kepplinger {0x32d0, 0xc35a},
716e8c08826SMartin Kepplinger {0x32d2, 0xc368},
717e8c08826SMartin Kepplinger {0x32d4, 0xc376},
718e8c08826SMartin Kepplinger {0x32d6, 0xc3c2},
719e8c08826SMartin Kepplinger {0x32d8, 0xc3e6},
720e8c08826SMartin Kepplinger {0x32da, 0x0003},
721e8c08826SMartin Kepplinger {0x32dc, 0x0003},
722e8c08826SMartin Kepplinger {0x32de, 0x00c7},
723e8c08826SMartin Kepplinger {0x32e0, 0x0031},
724e8c08826SMartin Kepplinger {0x32e2, 0x0031},
725e8c08826SMartin Kepplinger {0x32e4, 0x0031},
726e8c08826SMartin Kepplinger {0x32e6, 0xfc28},
727e8c08826SMartin Kepplinger {0x32e8, 0xc3bc},
728e8c08826SMartin Kepplinger {0x32ea, 0xc384},
729e8c08826SMartin Kepplinger {0x32ec, 0xc392},
730e8c08826SMartin Kepplinger {0x32ee, 0xc3a0},
731e8c08826SMartin Kepplinger {0x32f0, 0xc3ae},
732e8c08826SMartin Kepplinger {0x32f2, 0xc3c4},
733e8c08826SMartin Kepplinger {0x32f4, 0xc3e6},
734e8c08826SMartin Kepplinger {0x32f6, 0x0003},
735e8c08826SMartin Kepplinger {0x32f8, 0x0003},
736e8c08826SMartin Kepplinger {0x32fa, 0x00c7},
737e8c08826SMartin Kepplinger {0x32fc, 0x0031},
738e8c08826SMartin Kepplinger {0x32fe, 0x0031},
739e8c08826SMartin Kepplinger {0x3300, 0x0031},
740e8c08826SMartin Kepplinger {0x3302, 0x82ca},
741e8c08826SMartin Kepplinger {0x3304, 0xc164},
742e8c08826SMartin Kepplinger {0x3306, 0x82e6},
743e8c08826SMartin Kepplinger {0x3308, 0xc19c},
744e8c08826SMartin Kepplinger {0x330a, 0x001f},
745e8c08826SMartin Kepplinger {0x330c, 0x001a},
746e8c08826SMartin Kepplinger {0x330e, 0x0034},
747e8c08826SMartin Kepplinger {0x3310, 0x0000},
748e8c08826SMartin Kepplinger {0x3312, 0x0000},
749e8c08826SMartin Kepplinger {0x3314, 0xfc94},
750e8c08826SMartin Kepplinger {0x3316, 0xc3d8},
751e8c08826SMartin Kepplinger
752e8c08826SMartin Kepplinger {0x0a00, 0x0000},
753e8c08826SMartin Kepplinger {0x0e04, 0x0012},
754e8c08826SMartin Kepplinger {0x002e, 0x1111},
755e8c08826SMartin Kepplinger {0x0032, 0x1111},
756e8c08826SMartin Kepplinger {0x0022, 0x0008},
757e8c08826SMartin Kepplinger {0x0026, 0x0040},
758e8c08826SMartin Kepplinger {0x0028, 0x0017},
759e8c08826SMartin Kepplinger {0x002c, 0x09cf},
760e8c08826SMartin Kepplinger {0x005c, 0x2101},
761e8c08826SMartin Kepplinger {0x0006, 0x09de},
762e8c08826SMartin Kepplinger {0x0008, 0x0ed8},
763e8c08826SMartin Kepplinger {0x000e, 0x0100},
764e8c08826SMartin Kepplinger {0x000c, 0x0022},
765e8c08826SMartin Kepplinger {0x0a22, 0x0000},
766e8c08826SMartin Kepplinger {0x0a24, 0x0000},
767e8c08826SMartin Kepplinger {0x0804, 0x0000},
768e8c08826SMartin Kepplinger {0x0a12, 0x0cc0},
769e8c08826SMartin Kepplinger {0x0a14, 0x0990},
770e8c08826SMartin Kepplinger {0x0074, 0x09d8},
771e8c08826SMartin Kepplinger {0x0076, 0x0000},
772e8c08826SMartin Kepplinger {0x051e, 0x0000},
773e8c08826SMartin Kepplinger {0x0200, 0x0400},
774e8c08826SMartin Kepplinger {0x0a1a, 0x0c00},
775e8c08826SMartin Kepplinger {0x0a0c, 0x0010},
776e8c08826SMartin Kepplinger {0x0a1e, 0x0ccf},
777e8c08826SMartin Kepplinger {0x0402, 0x0110},
778e8c08826SMartin Kepplinger {0x0404, 0x00f4},
779e8c08826SMartin Kepplinger {0x0408, 0x0000},
780e8c08826SMartin Kepplinger {0x0410, 0x008d},
781e8c08826SMartin Kepplinger {0x0412, 0x011a},
782e8c08826SMartin Kepplinger {0x0414, 0x864c},
783e8c08826SMartin Kepplinger /* for OTP */
784e8c08826SMartin Kepplinger {0x021c, 0x0003},
785e8c08826SMartin Kepplinger {0x021e, 0x0235},
786e8c08826SMartin Kepplinger /* for OTP */
787e8c08826SMartin Kepplinger {0x0c00, 0x9950},
788e8c08826SMartin Kepplinger {0x0c06, 0x0021},
789e8c08826SMartin Kepplinger {0x0c10, 0x0040},
790e8c08826SMartin Kepplinger {0x0c12, 0x0040},
791e8c08826SMartin Kepplinger {0x0c14, 0x0040},
792e8c08826SMartin Kepplinger {0x0c16, 0x0040},
793e8c08826SMartin Kepplinger {0x0a02, 0x0100},
794e8c08826SMartin Kepplinger {0x0a04, 0x015a},
795e8c08826SMartin Kepplinger {0x0418, 0x0000},
796e8c08826SMartin Kepplinger {0x0128, 0x0028},
797e8c08826SMartin Kepplinger {0x012a, 0xffff},
798e8c08826SMartin Kepplinger {0x0120, 0x0046},
799e8c08826SMartin Kepplinger {0x0122, 0x0376},
800e8c08826SMartin Kepplinger {0x012c, 0x0020},
801e8c08826SMartin Kepplinger {0x012e, 0xffff},
802e8c08826SMartin Kepplinger {0x0124, 0x0040},
803e8c08826SMartin Kepplinger {0x0126, 0x0378},
804e8c08826SMartin Kepplinger {0x0746, 0x0050},
805e8c08826SMartin Kepplinger {0x0748, 0x01d5},
806e8c08826SMartin Kepplinger {0x074a, 0x022b},
807e8c08826SMartin Kepplinger {0x074c, 0x03b0},
808e8c08826SMartin Kepplinger {0x0756, 0x043f},
809e8c08826SMartin Kepplinger {0x0758, 0x3f1d},
810e8c08826SMartin Kepplinger {0x0b02, 0xe04d},
811e8c08826SMartin Kepplinger {0x0b10, 0x6821},
812e8c08826SMartin Kepplinger {0x0b12, 0x0120},
813e8c08826SMartin Kepplinger {0x0b14, 0x0001},
814e8c08826SMartin Kepplinger {0x2008, 0x38fd},
815e8c08826SMartin Kepplinger {0x326e, 0x0000},
816e8c08826SMartin Kepplinger {0x0900, 0x0300},
817e8c08826SMartin Kepplinger {0x0902, 0xc319},
818e8c08826SMartin Kepplinger {0x0914, 0xc109},
819e8c08826SMartin Kepplinger {0x0916, 0x061a},
820e8c08826SMartin Kepplinger {0x0918, 0x0407},
821e8c08826SMartin Kepplinger {0x091a, 0x0a0b},
822e8c08826SMartin Kepplinger {0x091c, 0x0e08},
823e8c08826SMartin Kepplinger {0x091e, 0x0a00},
824e8c08826SMartin Kepplinger {0x090c, 0x0427},
825e8c08826SMartin Kepplinger {0x090e, 0x0059},
826e8c08826SMartin Kepplinger {0x0954, 0x0089},
827e8c08826SMartin Kepplinger {0x0956, 0x0000},
828e8c08826SMartin Kepplinger {0x0958, 0xca80},
829e8c08826SMartin Kepplinger {0x095a, 0x9240},
830e8c08826SMartin Kepplinger {0x0f08, 0x2f04},
831e8c08826SMartin Kepplinger {0x0f30, 0x001f},
832e8c08826SMartin Kepplinger {0x0f36, 0x001f},
833e8c08826SMartin Kepplinger {0x0f04, 0x3a00},
834e8c08826SMartin Kepplinger {0x0f32, 0x025a},
835e8c08826SMartin Kepplinger {0x0f38, 0x025a},
836e8c08826SMartin Kepplinger {0x0f2a, 0x4124},
837e8c08826SMartin Kepplinger {0x006a, 0x0100},
838e8c08826SMartin Kepplinger {0x004c, 0x0100},
839e8c08826SMartin Kepplinger {0x0044, 0x0001},
840e8c08826SMartin Kepplinger };
841e8c08826SMartin Kepplinger
842e8c08826SMartin Kepplinger static const struct hi846_reg mode_640x480_config[] = {
843e8c08826SMartin Kepplinger {HI846_REG_MODE_SELECT, 0x0000},
844e8c08826SMartin Kepplinger {HI846_REG_Y_ODD_INC_FOBP, 0x7711},
845e8c08826SMartin Kepplinger {HI846_REG_Y_ODD_INC_VACT, 0x7711},
846e8c08826SMartin Kepplinger {HI846_REG_Y_ADDR_START_VACT_H, 0x0148},
847e8c08826SMartin Kepplinger {HI846_REG_Y_ADDR_END_VACT_H, 0x08c7},
848e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_005C, 0x4404},
849e8c08826SMartin Kepplinger {HI846_REG_FLL, 0x0277},
850e8c08826SMartin Kepplinger {HI846_REG_LLP, 0x0ed8},
851e8c08826SMartin Kepplinger {HI846_REG_BINNING_MODE, 0x0322},
852e8c08826SMartin Kepplinger {HI846_REG_HBIN_MODE, 0x0200},
853e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0A24, 0x0000},
854e8c08826SMartin Kepplinger {HI846_REG_X_START_H, 0x0058},
855e8c08826SMartin Kepplinger {HI846_REG_X_OUTPUT_SIZE_H, 0x0280},
856e8c08826SMartin Kepplinger {HI846_REG_Y_OUTPUT_SIZE_H, 0x01e0},
857e8c08826SMartin Kepplinger
858e8c08826SMartin Kepplinger /* For OTP */
859e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_021C, 0x0003},
860e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_021E, 0x0235},
861e8c08826SMartin Kepplinger
862e8c08826SMartin Kepplinger {HI846_REG_ISP_EN_H, 0x016a},
863e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0418, 0x0210},
864e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B02, 0xe04d},
865e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B10, 0x7021},
866e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B12, 0x0120},
867e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B14, 0x0001},
868e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_2008, 0x38fd},
869e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_326E, 0x0000},
870e8c08826SMartin Kepplinger };
871e8c08826SMartin Kepplinger
872e8c08826SMartin Kepplinger static const struct hi846_reg mode_640x480_mipi_2lane[] = {
873e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0900, 0x0300},
874e8c08826SMartin Kepplinger {HI846_REG_MIPI_TX_OP_MODE, 0x4319},
875e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0914, 0xc105},
876e8c08826SMartin Kepplinger {HI846_REG_TCLK_PREPARE, 0x030c},
877e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0918, 0x0304},
878e8c08826SMartin Kepplinger {HI846_REG_THS_ZERO, 0x0708},
879e8c08826SMartin Kepplinger {HI846_REG_TCLK_POST, 0x0b04},
880e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_091E, 0x0500},
881e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_090C, 0x0208},
882e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_090E, 0x009a},
883e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0954, 0x0089},
884e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0956, 0x0000},
885e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0958, 0xca80},
886e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_095A, 0x9240},
887e8c08826SMartin Kepplinger {HI846_REG_PLL_CFG_MIPI2_H, 0x4924},
888e8c08826SMartin Kepplinger {HI846_REG_TG_ENABLE, 0x0100},
889e8c08826SMartin Kepplinger };
890e8c08826SMartin Kepplinger
891e8c08826SMartin Kepplinger static const struct hi846_reg mode_1280x720_config[] = {
892e8c08826SMartin Kepplinger {HI846_REG_MODE_SELECT, 0x0000},
893e8c08826SMartin Kepplinger {HI846_REG_Y_ODD_INC_FOBP, 0x3311},
894e8c08826SMartin Kepplinger {HI846_REG_Y_ODD_INC_VACT, 0x3311},
895e8c08826SMartin Kepplinger {HI846_REG_Y_ADDR_START_VACT_H, 0x0238},
896e8c08826SMartin Kepplinger {HI846_REG_Y_ADDR_END_VACT_H, 0x07d7},
897e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_005C, 0x4202},
898e8c08826SMartin Kepplinger {HI846_REG_FLL, 0x034a},
899e8c08826SMartin Kepplinger {HI846_REG_LLP, 0x0ed8},
900e8c08826SMartin Kepplinger {HI846_REG_BINNING_MODE, 0x0122},
901e8c08826SMartin Kepplinger {HI846_REG_HBIN_MODE, 0x0100},
902e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0A24, 0x0000},
903e8c08826SMartin Kepplinger {HI846_REG_X_START_H, 0x00b0},
904e8c08826SMartin Kepplinger {HI846_REG_X_OUTPUT_SIZE_H, 0x0500},
905e8c08826SMartin Kepplinger {HI846_REG_Y_OUTPUT_SIZE_H, 0x02d0},
906e8c08826SMartin Kepplinger {HI846_REG_EXPOSURE, 0x0344},
907e8c08826SMartin Kepplinger
908e8c08826SMartin Kepplinger /* For OTP */
909e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_021C, 0x0003},
910e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_021E, 0x0235},
911e8c08826SMartin Kepplinger
912e8c08826SMartin Kepplinger {HI846_REG_ISP_EN_H, 0x016a},
913e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0418, 0x0410},
914e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B02, 0xe04d},
915e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B10, 0x6c21},
916e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B12, 0x0120},
917e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B14, 0x0005},
918e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_2008, 0x38fd},
919e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_326E, 0x0000},
920e8c08826SMartin Kepplinger };
921e8c08826SMartin Kepplinger
922e8c08826SMartin Kepplinger static const struct hi846_reg mode_1280x720_mipi_2lane[] = {
923e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0900, 0x0300},
924e8c08826SMartin Kepplinger {HI846_REG_MIPI_TX_OP_MODE, 0x4319},
925e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0914, 0xc109},
926e8c08826SMartin Kepplinger {HI846_REG_TCLK_PREPARE, 0x061a},
927e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0918, 0x0407},
928e8c08826SMartin Kepplinger {HI846_REG_THS_ZERO, 0x0a0b},
929e8c08826SMartin Kepplinger {HI846_REG_TCLK_POST, 0x0e08},
930e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_091E, 0x0a00},
931e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_090C, 0x0427},
932e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_090E, 0x0145},
933e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0954, 0x0089},
934e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0956, 0x0000},
935e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0958, 0xca80},
936e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_095A, 0x9240},
937e8c08826SMartin Kepplinger {HI846_REG_PLL_CFG_MIPI2_H, 0x4124},
938e8c08826SMartin Kepplinger {HI846_REG_TG_ENABLE, 0x0100},
939e8c08826SMartin Kepplinger };
940e8c08826SMartin Kepplinger
941e8c08826SMartin Kepplinger static const struct hi846_reg mode_1280x720_mipi_4lane[] = {
942e8c08826SMartin Kepplinger /* 360Mbps */
943e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0900, 0x0300},
944e8c08826SMartin Kepplinger {HI846_REG_MIPI_TX_OP_MODE, 0xc319},
945e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0914, 0xc105},
946e8c08826SMartin Kepplinger {HI846_REG_TCLK_PREPARE, 0x030c},
947e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0918, 0x0304},
948e8c08826SMartin Kepplinger {HI846_REG_THS_ZERO, 0x0708},
949e8c08826SMartin Kepplinger {HI846_REG_TCLK_POST, 0x0b04},
950e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_091E, 0x0500},
951e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_090C, 0x0208},
952e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_090E, 0x008a},
953e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0954, 0x0089},
954e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0956, 0x0000},
955e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0958, 0xca80},
956e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_095A, 0x9240},
957e8c08826SMartin Kepplinger {HI846_REG_PLL_CFG_MIPI2_H, 0x4924},
958e8c08826SMartin Kepplinger {HI846_REG_TG_ENABLE, 0x0100},
959e8c08826SMartin Kepplinger };
960e8c08826SMartin Kepplinger
961e8c08826SMartin Kepplinger static const struct hi846_reg mode_1632x1224_config[] = {
962e8c08826SMartin Kepplinger {HI846_REG_MODE_SELECT, 0x0000},
963e8c08826SMartin Kepplinger {HI846_REG_Y_ODD_INC_FOBP, 0x3311},
964e8c08826SMartin Kepplinger {HI846_REG_Y_ODD_INC_VACT, 0x3311},
965e8c08826SMartin Kepplinger {HI846_REG_Y_ADDR_START_VACT_H, 0x0040},
966e8c08826SMartin Kepplinger {HI846_REG_Y_ADDR_END_VACT_H, 0x09cf},
967e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_005C, 0x4202},
968e8c08826SMartin Kepplinger {HI846_REG_FLL, 0x09de},
969e8c08826SMartin Kepplinger {HI846_REG_LLP, 0x0ed8},
970e8c08826SMartin Kepplinger {HI846_REG_BINNING_MODE, 0x0122},
971e8c08826SMartin Kepplinger {HI846_REG_HBIN_MODE, 0x0100},
972e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0A24, 0x0000},
973e8c08826SMartin Kepplinger {HI846_REG_X_START_H, 0x0000},
974e8c08826SMartin Kepplinger {HI846_REG_X_OUTPUT_SIZE_H, 0x0660},
975e8c08826SMartin Kepplinger {HI846_REG_Y_OUTPUT_SIZE_H, 0x04c8},
976e8c08826SMartin Kepplinger {HI846_REG_EXPOSURE, 0x09d8},
977e8c08826SMartin Kepplinger
978e8c08826SMartin Kepplinger /* For OTP */
979e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_021C, 0x0003},
980e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_021E, 0x0235},
981e8c08826SMartin Kepplinger
982e8c08826SMartin Kepplinger {HI846_REG_ISP_EN_H, 0x016a},
983e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0418, 0x0000},
984e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B02, 0xe04d},
985e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B10, 0x6c21},
986e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B12, 0x0120},
987e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0B14, 0x0005},
988e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_2008, 0x38fd},
989e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_326E, 0x0000},
990e8c08826SMartin Kepplinger };
991e8c08826SMartin Kepplinger
992e8c08826SMartin Kepplinger static const struct hi846_reg mode_1632x1224_mipi_2lane[] = {
993e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0900, 0x0300},
994e8c08826SMartin Kepplinger {HI846_REG_MIPI_TX_OP_MODE, 0x4319},
995e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0914, 0xc109},
996e8c08826SMartin Kepplinger {HI846_REG_TCLK_PREPARE, 0x061a},
997e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0918, 0x0407},
998e8c08826SMartin Kepplinger {HI846_REG_THS_ZERO, 0x0a0b},
999e8c08826SMartin Kepplinger {HI846_REG_TCLK_POST, 0x0e08},
1000e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_091E, 0x0a00},
1001e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_090C, 0x0427},
1002e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_090E, 0x0069},
1003e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0954, 0x0089},
1004e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0956, 0x0000},
1005e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0958, 0xca80},
1006e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_095A, 0x9240},
1007e8c08826SMartin Kepplinger {HI846_REG_PLL_CFG_MIPI2_H, 0x4124},
1008e8c08826SMartin Kepplinger {HI846_REG_TG_ENABLE, 0x0100},
1009e8c08826SMartin Kepplinger };
1010e8c08826SMartin Kepplinger
1011e8c08826SMartin Kepplinger static const struct hi846_reg mode_1632x1224_mipi_4lane[] = {
1012e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0900, 0x0300},
1013e8c08826SMartin Kepplinger {HI846_REG_MIPI_TX_OP_MODE, 0xc319},
1014e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0914, 0xc105},
1015e8c08826SMartin Kepplinger {HI846_REG_TCLK_PREPARE, 0x030c},
1016e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0918, 0x0304},
1017e8c08826SMartin Kepplinger {HI846_REG_THS_ZERO, 0x0708},
1018e8c08826SMartin Kepplinger {HI846_REG_TCLK_POST, 0x0b04},
1019e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_091E, 0x0500},
1020e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_090C, 0x0208},
1021e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_090E, 0x001c},
1022e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0954, 0x0089},
1023e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0956, 0x0000},
1024e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_0958, 0xca80},
1025e8c08826SMartin Kepplinger {HI846_REG_UNKNOWN_095A, 0x9240},
1026e8c08826SMartin Kepplinger {HI846_REG_PLL_CFG_MIPI2_H, 0x4924},
1027e8c08826SMartin Kepplinger {HI846_REG_TG_ENABLE, 0x0100},
1028e8c08826SMartin Kepplinger };
1029e8c08826SMartin Kepplinger
1030e8c08826SMartin Kepplinger static const char * const hi846_test_pattern_menu[] = {
1031e8c08826SMartin Kepplinger "Disabled",
1032e8c08826SMartin Kepplinger "Solid Colour",
1033e8c08826SMartin Kepplinger "100% Colour Bars",
1034e8c08826SMartin Kepplinger "Fade To Grey Colour Bars",
1035e8c08826SMartin Kepplinger "PN9",
1036e8c08826SMartin Kepplinger "Gradient Horizontal",
1037e8c08826SMartin Kepplinger "Gradient Vertical",
1038e8c08826SMartin Kepplinger "Check Board",
1039e8c08826SMartin Kepplinger "Slant Pattern",
1040e8c08826SMartin Kepplinger "Resolution Pattern",
1041e8c08826SMartin Kepplinger };
1042e8c08826SMartin Kepplinger
1043e8c08826SMartin Kepplinger #define FREQ_INDEX_640 0
1044e8c08826SMartin Kepplinger #define FREQ_INDEX_1280 1
1045e8c08826SMartin Kepplinger static const s64 hi846_link_freqs[] = {
1046e8c08826SMartin Kepplinger [FREQ_INDEX_640] = 80000000,
1047e8c08826SMartin Kepplinger [FREQ_INDEX_1280] = 200000000,
1048e8c08826SMartin Kepplinger };
1049e8c08826SMartin Kepplinger
1050e8c08826SMartin Kepplinger static const struct hi846_reg_list hi846_init_regs_list_2lane = {
1051e8c08826SMartin Kepplinger .num_of_regs = ARRAY_SIZE(hi846_init_2lane),
1052e8c08826SMartin Kepplinger .regs = hi846_init_2lane,
1053e8c08826SMartin Kepplinger };
1054e8c08826SMartin Kepplinger
1055e8c08826SMartin Kepplinger static const struct hi846_reg_list hi846_init_regs_list_4lane = {
1056e8c08826SMartin Kepplinger .num_of_regs = ARRAY_SIZE(hi846_init_4lane),
1057e8c08826SMartin Kepplinger .regs = hi846_init_4lane,
1058e8c08826SMartin Kepplinger };
1059e8c08826SMartin Kepplinger
1060e8c08826SMartin Kepplinger static const struct hi846_mode supported_modes[] = {
1061e8c08826SMartin Kepplinger {
1062e8c08826SMartin Kepplinger .width = 640,
1063e8c08826SMartin Kepplinger .height = 480,
1064e8c08826SMartin Kepplinger .link_freq_index = FREQ_INDEX_640,
1065e8c08826SMartin Kepplinger .fps = 120,
1066e8c08826SMartin Kepplinger .frame_len = 631,
1067e8c08826SMartin Kepplinger .llp = HI846_LINE_LENGTH,
1068e8c08826SMartin Kepplinger .reg_list_config = {
1069e8c08826SMartin Kepplinger .num_of_regs = ARRAY_SIZE(mode_640x480_config),
1070e8c08826SMartin Kepplinger .regs = mode_640x480_config,
1071e8c08826SMartin Kepplinger },
1072e8c08826SMartin Kepplinger .reg_list_2lane = {
1073e8c08826SMartin Kepplinger .num_of_regs = ARRAY_SIZE(mode_640x480_mipi_2lane),
1074e8c08826SMartin Kepplinger .regs = mode_640x480_mipi_2lane,
1075e8c08826SMartin Kepplinger },
1076e8c08826SMartin Kepplinger .reg_list_4lane = {
1077e8c08826SMartin Kepplinger .num_of_regs = 0,
1078e8c08826SMartin Kepplinger },
1079e8c08826SMartin Kepplinger .crop = {
1080e8c08826SMartin Kepplinger .left = 0x58,
1081e8c08826SMartin Kepplinger .top = 0x148,
1082e8c08826SMartin Kepplinger .width = 640 * 4,
1083e8c08826SMartin Kepplinger .height = 480 * 4,
1084e8c08826SMartin Kepplinger },
1085e8c08826SMartin Kepplinger },
1086e8c08826SMartin Kepplinger {
1087e8c08826SMartin Kepplinger .width = 1280,
1088e8c08826SMartin Kepplinger .height = 720,
1089e8c08826SMartin Kepplinger .link_freq_index = FREQ_INDEX_1280,
1090e8c08826SMartin Kepplinger .fps = 90,
1091e8c08826SMartin Kepplinger .frame_len = 842,
1092e8c08826SMartin Kepplinger .llp = HI846_LINE_LENGTH,
1093e8c08826SMartin Kepplinger .reg_list_config = {
1094e8c08826SMartin Kepplinger .num_of_regs = ARRAY_SIZE(mode_1280x720_config),
1095e8c08826SMartin Kepplinger .regs = mode_1280x720_config,
1096e8c08826SMartin Kepplinger },
1097e8c08826SMartin Kepplinger .reg_list_2lane = {
1098e8c08826SMartin Kepplinger .num_of_regs = ARRAY_SIZE(mode_1280x720_mipi_2lane),
1099e8c08826SMartin Kepplinger .regs = mode_1280x720_mipi_2lane,
1100e8c08826SMartin Kepplinger },
1101e8c08826SMartin Kepplinger .reg_list_4lane = {
1102e8c08826SMartin Kepplinger .num_of_regs = ARRAY_SIZE(mode_1280x720_mipi_4lane),
1103e8c08826SMartin Kepplinger .regs = mode_1280x720_mipi_4lane,
1104e8c08826SMartin Kepplinger },
1105e8c08826SMartin Kepplinger .crop = {
1106e8c08826SMartin Kepplinger .left = 0xb0,
1107e8c08826SMartin Kepplinger .top = 0x238,
1108e8c08826SMartin Kepplinger .width = 1280 * 2,
1109e8c08826SMartin Kepplinger .height = 720 * 2,
1110e8c08826SMartin Kepplinger },
1111e8c08826SMartin Kepplinger },
1112e8c08826SMartin Kepplinger {
1113e8c08826SMartin Kepplinger .width = 1632,
1114e8c08826SMartin Kepplinger .height = 1224,
1115e8c08826SMartin Kepplinger .link_freq_index = FREQ_INDEX_1280,
1116e8c08826SMartin Kepplinger .fps = 30,
1117e8c08826SMartin Kepplinger .frame_len = 2526,
1118e8c08826SMartin Kepplinger .llp = HI846_LINE_LENGTH,
1119e8c08826SMartin Kepplinger .reg_list_config = {
1120e8c08826SMartin Kepplinger .num_of_regs = ARRAY_SIZE(mode_1632x1224_config),
1121e8c08826SMartin Kepplinger .regs = mode_1632x1224_config,
1122e8c08826SMartin Kepplinger },
1123e8c08826SMartin Kepplinger .reg_list_2lane = {
1124e8c08826SMartin Kepplinger .num_of_regs = ARRAY_SIZE(mode_1632x1224_mipi_2lane),
1125e8c08826SMartin Kepplinger .regs = mode_1632x1224_mipi_2lane,
1126e8c08826SMartin Kepplinger },
1127e8c08826SMartin Kepplinger .reg_list_4lane = {
1128e8c08826SMartin Kepplinger .num_of_regs = ARRAY_SIZE(mode_1632x1224_mipi_4lane),
1129e8c08826SMartin Kepplinger .regs = mode_1632x1224_mipi_4lane,
1130e8c08826SMartin Kepplinger },
1131e8c08826SMartin Kepplinger .crop = {
1132e8c08826SMartin Kepplinger .left = 0x0,
1133e8c08826SMartin Kepplinger .top = 0x0,
1134e8c08826SMartin Kepplinger .width = 1632 * 2,
1135e8c08826SMartin Kepplinger .height = 1224 * 2,
1136e8c08826SMartin Kepplinger },
1137e8c08826SMartin Kepplinger }
1138e8c08826SMartin Kepplinger };
1139e8c08826SMartin Kepplinger
1140e8c08826SMartin Kepplinger struct hi846_datafmt {
1141e8c08826SMartin Kepplinger u32 code;
1142e8c08826SMartin Kepplinger enum v4l2_colorspace colorspace;
1143e8c08826SMartin Kepplinger };
1144e8c08826SMartin Kepplinger
1145e8c08826SMartin Kepplinger static const char * const hi846_supply_names[] = {
1146e8c08826SMartin Kepplinger "vddio", /* Digital I/O (1.8V or 2.8V) */
1147e8c08826SMartin Kepplinger "vdda", /* Analog (2.8V) */
1148e8c08826SMartin Kepplinger "vddd", /* Digital Core (1.2V) */
1149e8c08826SMartin Kepplinger };
1150e8c08826SMartin Kepplinger
1151e8c08826SMartin Kepplinger #define HI846_NUM_SUPPLIES ARRAY_SIZE(hi846_supply_names)
1152e8c08826SMartin Kepplinger
1153e8c08826SMartin Kepplinger struct hi846 {
1154e8c08826SMartin Kepplinger struct gpio_desc *rst_gpio;
1155e8c08826SMartin Kepplinger struct gpio_desc *shutdown_gpio;
1156e8c08826SMartin Kepplinger struct regulator_bulk_data supplies[HI846_NUM_SUPPLIES];
1157e8c08826SMartin Kepplinger struct clk *clock;
1158e8c08826SMartin Kepplinger const struct hi846_datafmt *fmt;
1159e8c08826SMartin Kepplinger struct v4l2_subdev sd;
1160e8c08826SMartin Kepplinger struct media_pad pad;
1161e8c08826SMartin Kepplinger struct v4l2_ctrl_handler ctrl_handler;
1162e8c08826SMartin Kepplinger u8 nr_lanes;
1163e8c08826SMartin Kepplinger
1164e8c08826SMartin Kepplinger struct v4l2_ctrl *link_freq;
1165e8c08826SMartin Kepplinger struct v4l2_ctrl *pixel_rate;
1166e8c08826SMartin Kepplinger struct v4l2_ctrl *vblank;
1167e8c08826SMartin Kepplinger struct v4l2_ctrl *hblank;
1168e8c08826SMartin Kepplinger struct v4l2_ctrl *exposure;
1169e8c08826SMartin Kepplinger
1170e8c08826SMartin Kepplinger struct mutex mutex; /* protect cur_mode, streaming and chip access */
1171e8c08826SMartin Kepplinger const struct hi846_mode *cur_mode;
1172e8c08826SMartin Kepplinger bool streaming;
1173e8c08826SMartin Kepplinger };
1174e8c08826SMartin Kepplinger
to_hi846(struct v4l2_subdev * sd)1175e8c08826SMartin Kepplinger static inline struct hi846 *to_hi846(struct v4l2_subdev *sd)
1176e8c08826SMartin Kepplinger {
1177e8c08826SMartin Kepplinger return container_of(sd, struct hi846, sd);
1178e8c08826SMartin Kepplinger }
1179e8c08826SMartin Kepplinger
1180e8c08826SMartin Kepplinger static const struct hi846_datafmt hi846_colour_fmts[] = {
1181e8c08826SMartin Kepplinger { HI846_MEDIA_BUS_FORMAT, V4L2_COLORSPACE_RAW },
1182e8c08826SMartin Kepplinger };
1183e8c08826SMartin Kepplinger
hi846_find_datafmt(u32 code)1184e8c08826SMartin Kepplinger static const struct hi846_datafmt *hi846_find_datafmt(u32 code)
1185e8c08826SMartin Kepplinger {
1186e8c08826SMartin Kepplinger unsigned int i;
1187e8c08826SMartin Kepplinger
1188e8c08826SMartin Kepplinger for (i = 0; i < ARRAY_SIZE(hi846_colour_fmts); i++)
1189e8c08826SMartin Kepplinger if (hi846_colour_fmts[i].code == code)
1190e8c08826SMartin Kepplinger return &hi846_colour_fmts[i];
1191e8c08826SMartin Kepplinger
1192e8c08826SMartin Kepplinger return NULL;
1193e8c08826SMartin Kepplinger }
1194e8c08826SMartin Kepplinger
hi846_get_link_freq_index(struct hi846 * hi846)1195e8c08826SMartin Kepplinger static inline u8 hi846_get_link_freq_index(struct hi846 *hi846)
1196e8c08826SMartin Kepplinger {
1197e8c08826SMartin Kepplinger return hi846->cur_mode->link_freq_index;
1198e8c08826SMartin Kepplinger }
1199e8c08826SMartin Kepplinger
hi846_get_link_freq(struct hi846 * hi846)1200e8c08826SMartin Kepplinger static u64 hi846_get_link_freq(struct hi846 *hi846)
1201e8c08826SMartin Kepplinger {
1202e8c08826SMartin Kepplinger u8 index = hi846_get_link_freq_index(hi846);
1203e8c08826SMartin Kepplinger
1204e8c08826SMartin Kepplinger return hi846_link_freqs[index];
1205e8c08826SMartin Kepplinger }
1206e8c08826SMartin Kepplinger
hi846_calc_pixel_rate(struct hi846 * hi846)1207e8c08826SMartin Kepplinger static u64 hi846_calc_pixel_rate(struct hi846 *hi846)
1208e8c08826SMartin Kepplinger {
1209e8c08826SMartin Kepplinger u64 link_freq = hi846_get_link_freq(hi846);
1210e8c08826SMartin Kepplinger u64 pixel_rate = link_freq * 2 * hi846->nr_lanes;
1211e8c08826SMartin Kepplinger
1212e8c08826SMartin Kepplinger do_div(pixel_rate, HI846_RGB_DEPTH);
1213e8c08826SMartin Kepplinger
1214e8c08826SMartin Kepplinger return pixel_rate;
1215e8c08826SMartin Kepplinger }
1216e8c08826SMartin Kepplinger
hi846_read_reg(struct hi846 * hi846,u16 reg,u8 * val)1217e8c08826SMartin Kepplinger static int hi846_read_reg(struct hi846 *hi846, u16 reg, u8 *val)
1218e8c08826SMartin Kepplinger {
1219e8c08826SMartin Kepplinger struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd);
1220e8c08826SMartin Kepplinger struct i2c_msg msgs[2];
1221e8c08826SMartin Kepplinger u8 addr_buf[2];
1222e8c08826SMartin Kepplinger u8 data_buf[1] = {0};
1223e8c08826SMartin Kepplinger int ret;
1224e8c08826SMartin Kepplinger
1225e8c08826SMartin Kepplinger put_unaligned_be16(reg, addr_buf);
1226e8c08826SMartin Kepplinger msgs[0].addr = client->addr;
1227e8c08826SMartin Kepplinger msgs[0].flags = 0;
1228e8c08826SMartin Kepplinger msgs[0].len = sizeof(addr_buf);
1229e8c08826SMartin Kepplinger msgs[0].buf = addr_buf;
1230e8c08826SMartin Kepplinger msgs[1].addr = client->addr;
1231e8c08826SMartin Kepplinger msgs[1].flags = I2C_M_RD;
1232e8c08826SMartin Kepplinger msgs[1].len = 1;
1233e8c08826SMartin Kepplinger msgs[1].buf = data_buf;
1234e8c08826SMartin Kepplinger
1235e8c08826SMartin Kepplinger ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
1236e8c08826SMartin Kepplinger if (ret != ARRAY_SIZE(msgs)) {
1237e8c08826SMartin Kepplinger dev_err(&client->dev, "i2c read error: %d\n", ret);
1238e8c08826SMartin Kepplinger return -EIO;
1239e8c08826SMartin Kepplinger }
1240e8c08826SMartin Kepplinger
1241e8c08826SMartin Kepplinger *val = data_buf[0];
1242e8c08826SMartin Kepplinger
1243e8c08826SMartin Kepplinger return 0;
1244e8c08826SMartin Kepplinger }
1245e8c08826SMartin Kepplinger
hi846_write_reg(struct hi846 * hi846,u16 reg,u8 val)1246e8c08826SMartin Kepplinger static int hi846_write_reg(struct hi846 *hi846, u16 reg, u8 val)
1247e8c08826SMartin Kepplinger {
1248e8c08826SMartin Kepplinger struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd);
1249e8c08826SMartin Kepplinger u8 buf[3] = { reg >> 8, reg & 0xff, val };
1250e8c08826SMartin Kepplinger struct i2c_msg msg[] = {
1251e8c08826SMartin Kepplinger { .addr = client->addr, .flags = 0,
1252e8c08826SMartin Kepplinger .len = ARRAY_SIZE(buf), .buf = buf },
1253e8c08826SMartin Kepplinger };
1254e8c08826SMartin Kepplinger int ret;
1255e8c08826SMartin Kepplinger
1256e8c08826SMartin Kepplinger ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
1257e8c08826SMartin Kepplinger if (ret != ARRAY_SIZE(msg)) {
1258e8c08826SMartin Kepplinger dev_err(&client->dev, "i2c write error\n");
1259e8c08826SMartin Kepplinger return -EIO;
1260e8c08826SMartin Kepplinger }
1261e8c08826SMartin Kepplinger
1262e8c08826SMartin Kepplinger return 0;
1263e8c08826SMartin Kepplinger }
1264e8c08826SMartin Kepplinger
hi846_write_reg_16(struct hi846 * hi846,u16 reg,u16 val,int * err)1265e8c08826SMartin Kepplinger static void hi846_write_reg_16(struct hi846 *hi846, u16 reg, u16 val, int *err)
1266e8c08826SMartin Kepplinger {
1267e8c08826SMartin Kepplinger struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd);
1268e8c08826SMartin Kepplinger u8 buf[4];
1269e8c08826SMartin Kepplinger int ret;
1270e8c08826SMartin Kepplinger
1271e8c08826SMartin Kepplinger if (*err < 0)
1272e8c08826SMartin Kepplinger return;
1273e8c08826SMartin Kepplinger
1274e8c08826SMartin Kepplinger put_unaligned_be16(reg, buf);
1275e8c08826SMartin Kepplinger put_unaligned_be16(val, buf + 2);
1276e8c08826SMartin Kepplinger ret = i2c_master_send(client, buf, sizeof(buf));
1277e8c08826SMartin Kepplinger if (ret != sizeof(buf)) {
1278e8c08826SMartin Kepplinger dev_err(&client->dev, "i2c_master_send != %zu: %d\n",
1279e8c08826SMartin Kepplinger sizeof(buf), ret);
1280e8c08826SMartin Kepplinger *err = -EIO;
1281e8c08826SMartin Kepplinger }
1282e8c08826SMartin Kepplinger }
1283e8c08826SMartin Kepplinger
hi846_write_reg_list(struct hi846 * hi846,const struct hi846_reg_list * r_list)1284e8c08826SMartin Kepplinger static int hi846_write_reg_list(struct hi846 *hi846,
1285e8c08826SMartin Kepplinger const struct hi846_reg_list *r_list)
1286e8c08826SMartin Kepplinger {
1287e8c08826SMartin Kepplinger struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd);
1288e8c08826SMartin Kepplinger unsigned int i;
1289e8c08826SMartin Kepplinger int ret = 0;
1290e8c08826SMartin Kepplinger
1291e8c08826SMartin Kepplinger for (i = 0; i < r_list->num_of_regs; i++) {
1292e8c08826SMartin Kepplinger hi846_write_reg_16(hi846, r_list->regs[i].address,
1293e8c08826SMartin Kepplinger r_list->regs[i].val, &ret);
1294e8c08826SMartin Kepplinger if (ret) {
1295e8c08826SMartin Kepplinger dev_err_ratelimited(&client->dev,
1296e8c08826SMartin Kepplinger "failed to write reg 0x%4.4x: %d",
1297e8c08826SMartin Kepplinger r_list->regs[i].address, ret);
1298e8c08826SMartin Kepplinger return ret;
1299e8c08826SMartin Kepplinger }
1300e8c08826SMartin Kepplinger }
1301e8c08826SMartin Kepplinger
1302e8c08826SMartin Kepplinger return 0;
1303e8c08826SMartin Kepplinger }
1304e8c08826SMartin Kepplinger
hi846_update_digital_gain(struct hi846 * hi846,u16 d_gain)1305e8c08826SMartin Kepplinger static int hi846_update_digital_gain(struct hi846 *hi846, u16 d_gain)
1306e8c08826SMartin Kepplinger {
1307e8c08826SMartin Kepplinger int ret = 0;
1308e8c08826SMartin Kepplinger
1309e8c08826SMartin Kepplinger hi846_write_reg_16(hi846, HI846_REG_MWB_GR_GAIN_H, d_gain, &ret);
1310e8c08826SMartin Kepplinger hi846_write_reg_16(hi846, HI846_REG_MWB_GB_GAIN_H, d_gain, &ret);
1311e8c08826SMartin Kepplinger hi846_write_reg_16(hi846, HI846_REG_MWB_R_GAIN_H, d_gain, &ret);
1312e8c08826SMartin Kepplinger hi846_write_reg_16(hi846, HI846_REG_MWB_B_GAIN_H, d_gain, &ret);
1313e8c08826SMartin Kepplinger
1314e8c08826SMartin Kepplinger return ret;
1315e8c08826SMartin Kepplinger }
1316e8c08826SMartin Kepplinger
hi846_test_pattern(struct hi846 * hi846,u32 pattern)1317e8c08826SMartin Kepplinger static int hi846_test_pattern(struct hi846 *hi846, u32 pattern)
1318e8c08826SMartin Kepplinger {
1319e8c08826SMartin Kepplinger int ret;
1320e8c08826SMartin Kepplinger u8 val;
1321e8c08826SMartin Kepplinger
1322e8c08826SMartin Kepplinger if (pattern) {
1323e8c08826SMartin Kepplinger ret = hi846_read_reg(hi846, HI846_REG_ISP, &val);
1324e8c08826SMartin Kepplinger if (ret)
1325e8c08826SMartin Kepplinger return ret;
1326e8c08826SMartin Kepplinger
1327e8c08826SMartin Kepplinger ret = hi846_write_reg(hi846, HI846_REG_ISP,
1328e8c08826SMartin Kepplinger val | HI846_REG_ISP_TPG_EN);
1329e8c08826SMartin Kepplinger if (ret)
1330e8c08826SMartin Kepplinger return ret;
1331e8c08826SMartin Kepplinger }
1332e8c08826SMartin Kepplinger
1333e8c08826SMartin Kepplinger return hi846_write_reg(hi846, HI846_REG_TEST_PATTERN, pattern);
1334e8c08826SMartin Kepplinger }
1335e8c08826SMartin Kepplinger
hi846_set_ctrl(struct v4l2_ctrl * ctrl)1336e8c08826SMartin Kepplinger static int hi846_set_ctrl(struct v4l2_ctrl *ctrl)
1337e8c08826SMartin Kepplinger {
1338e8c08826SMartin Kepplinger struct hi846 *hi846 = container_of(ctrl->handler,
1339e8c08826SMartin Kepplinger struct hi846, ctrl_handler);
1340e8c08826SMartin Kepplinger struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd);
1341e8c08826SMartin Kepplinger s64 exposure_max;
1342e8c08826SMartin Kepplinger int ret = 0;
1343e8c08826SMartin Kepplinger u32 shutter, frame_len;
1344e8c08826SMartin Kepplinger
1345e8c08826SMartin Kepplinger /* Propagate change of current control to all related controls */
1346e8c08826SMartin Kepplinger if (ctrl->id == V4L2_CID_VBLANK) {
1347e8c08826SMartin Kepplinger /* Update max exposure while meeting expected vblanking */
1348e8c08826SMartin Kepplinger exposure_max = hi846->cur_mode->height + ctrl->val -
1349e8c08826SMartin Kepplinger HI846_EXPOSURE_MAX_MARGIN;
1350e8c08826SMartin Kepplinger __v4l2_ctrl_modify_range(hi846->exposure,
1351e8c08826SMartin Kepplinger hi846->exposure->minimum,
1352e8c08826SMartin Kepplinger exposure_max, hi846->exposure->step,
1353e8c08826SMartin Kepplinger exposure_max);
1354e8c08826SMartin Kepplinger }
1355e8c08826SMartin Kepplinger
1356e8c08826SMartin Kepplinger ret = pm_runtime_get_if_in_use(&client->dev);
1357e8c08826SMartin Kepplinger if (!ret || ret == -EAGAIN)
1358e8c08826SMartin Kepplinger return 0;
1359e8c08826SMartin Kepplinger
1360e8c08826SMartin Kepplinger switch (ctrl->id) {
1361e8c08826SMartin Kepplinger case V4L2_CID_ANALOGUE_GAIN:
1362e8c08826SMartin Kepplinger ret = hi846_write_reg(hi846, HI846_REG_ANALOG_GAIN, ctrl->val);
1363e8c08826SMartin Kepplinger break;
1364e8c08826SMartin Kepplinger
1365e8c08826SMartin Kepplinger case V4L2_CID_DIGITAL_GAIN:
1366e8c08826SMartin Kepplinger ret = hi846_update_digital_gain(hi846, ctrl->val);
1367e8c08826SMartin Kepplinger break;
1368e8c08826SMartin Kepplinger
1369e8c08826SMartin Kepplinger case V4L2_CID_EXPOSURE:
1370e8c08826SMartin Kepplinger shutter = ctrl->val;
1371e8c08826SMartin Kepplinger frame_len = hi846->cur_mode->frame_len;
1372e8c08826SMartin Kepplinger
1373e8c08826SMartin Kepplinger if (shutter > frame_len - 6) { /* margin */
1374e8c08826SMartin Kepplinger frame_len = shutter + 6;
1375e8c08826SMartin Kepplinger if (frame_len > 0xffff) { /* max frame len */
1376e8c08826SMartin Kepplinger frame_len = 0xffff;
1377e8c08826SMartin Kepplinger }
1378e8c08826SMartin Kepplinger }
1379e8c08826SMartin Kepplinger
1380e8c08826SMartin Kepplinger if (shutter < 6)
1381e8c08826SMartin Kepplinger shutter = 6;
1382e8c08826SMartin Kepplinger if (shutter > (0xffff - 6))
1383e8c08826SMartin Kepplinger shutter = 0xffff - 6;
1384e8c08826SMartin Kepplinger
1385e8c08826SMartin Kepplinger hi846_write_reg_16(hi846, HI846_REG_FLL, frame_len, &ret);
1386e8c08826SMartin Kepplinger hi846_write_reg_16(hi846, HI846_REG_EXPOSURE, shutter, &ret);
1387e8c08826SMartin Kepplinger break;
1388e8c08826SMartin Kepplinger
1389e8c08826SMartin Kepplinger case V4L2_CID_VBLANK:
1390e8c08826SMartin Kepplinger /* Update FLL that meets expected vertical blanking */
1391e8c08826SMartin Kepplinger hi846_write_reg_16(hi846, HI846_REG_FLL,
1392e8c08826SMartin Kepplinger hi846->cur_mode->height + ctrl->val, &ret);
1393e8c08826SMartin Kepplinger break;
1394e8c08826SMartin Kepplinger case V4L2_CID_TEST_PATTERN:
1395e8c08826SMartin Kepplinger ret = hi846_test_pattern(hi846, ctrl->val);
1396e8c08826SMartin Kepplinger break;
1397e8c08826SMartin Kepplinger
1398e8c08826SMartin Kepplinger default:
1399e8c08826SMartin Kepplinger ret = -EINVAL;
1400e8c08826SMartin Kepplinger break;
1401e8c08826SMartin Kepplinger }
1402e8c08826SMartin Kepplinger
1403e8c08826SMartin Kepplinger pm_runtime_put(&client->dev);
1404e8c08826SMartin Kepplinger
1405e8c08826SMartin Kepplinger return ret;
1406e8c08826SMartin Kepplinger }
1407e8c08826SMartin Kepplinger
1408e8c08826SMartin Kepplinger static const struct v4l2_ctrl_ops hi846_ctrl_ops = {
1409e8c08826SMartin Kepplinger .s_ctrl = hi846_set_ctrl,
1410e8c08826SMartin Kepplinger };
1411e8c08826SMartin Kepplinger
hi846_init_controls(struct hi846 * hi846)1412e8c08826SMartin Kepplinger static int hi846_init_controls(struct hi846 *hi846)
1413e8c08826SMartin Kepplinger {
1414e8c08826SMartin Kepplinger struct v4l2_ctrl_handler *ctrl_hdlr;
1415e8c08826SMartin Kepplinger s64 exposure_max, h_blank;
1416e8c08826SMartin Kepplinger int ret;
1417e8c08826SMartin Kepplinger struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd);
1418e8c08826SMartin Kepplinger struct v4l2_fwnode_device_properties props;
1419e8c08826SMartin Kepplinger
1420e8c08826SMartin Kepplinger ctrl_hdlr = &hi846->ctrl_handler;
1421e8c08826SMartin Kepplinger ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10);
1422e8c08826SMartin Kepplinger if (ret)
1423e8c08826SMartin Kepplinger return ret;
1424e8c08826SMartin Kepplinger
1425e8c08826SMartin Kepplinger ctrl_hdlr->lock = &hi846->mutex;
1426e8c08826SMartin Kepplinger
1427e8c08826SMartin Kepplinger hi846->link_freq =
1428e8c08826SMartin Kepplinger v4l2_ctrl_new_int_menu(ctrl_hdlr, &hi846_ctrl_ops,
1429e8c08826SMartin Kepplinger V4L2_CID_LINK_FREQ,
1430e8c08826SMartin Kepplinger ARRAY_SIZE(hi846_link_freqs) - 1,
1431e8c08826SMartin Kepplinger 0, hi846_link_freqs);
1432e8c08826SMartin Kepplinger if (hi846->link_freq)
1433e8c08826SMartin Kepplinger hi846->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
1434e8c08826SMartin Kepplinger
1435e8c08826SMartin Kepplinger hi846->pixel_rate =
1436e8c08826SMartin Kepplinger v4l2_ctrl_new_std(ctrl_hdlr, &hi846_ctrl_ops,
1437e8c08826SMartin Kepplinger V4L2_CID_PIXEL_RATE, 0,
1438e8c08826SMartin Kepplinger hi846_calc_pixel_rate(hi846), 1,
1439e8c08826SMartin Kepplinger hi846_calc_pixel_rate(hi846));
1440e8c08826SMartin Kepplinger hi846->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &hi846_ctrl_ops,
1441e8c08826SMartin Kepplinger V4L2_CID_VBLANK,
1442e8c08826SMartin Kepplinger hi846->cur_mode->frame_len -
1443e8c08826SMartin Kepplinger hi846->cur_mode->height,
1444e8c08826SMartin Kepplinger HI846_FLL_MAX -
1445e8c08826SMartin Kepplinger hi846->cur_mode->height, 1,
1446e8c08826SMartin Kepplinger hi846->cur_mode->frame_len -
1447e8c08826SMartin Kepplinger hi846->cur_mode->height);
1448e8c08826SMartin Kepplinger
1449e8c08826SMartin Kepplinger h_blank = hi846->cur_mode->llp - hi846->cur_mode->width;
1450e8c08826SMartin Kepplinger
1451e8c08826SMartin Kepplinger hi846->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &hi846_ctrl_ops,
1452e8c08826SMartin Kepplinger V4L2_CID_HBLANK, h_blank, h_blank, 1,
1453e8c08826SMartin Kepplinger h_blank);
1454e8c08826SMartin Kepplinger if (hi846->hblank)
1455e8c08826SMartin Kepplinger hi846->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
1456e8c08826SMartin Kepplinger
1457e8c08826SMartin Kepplinger v4l2_ctrl_new_std(ctrl_hdlr, &hi846_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
1458e8c08826SMartin Kepplinger HI846_ANAL_GAIN_MIN, HI846_ANAL_GAIN_MAX,
1459e8c08826SMartin Kepplinger HI846_ANAL_GAIN_STEP, HI846_ANAL_GAIN_MIN);
1460e8c08826SMartin Kepplinger v4l2_ctrl_new_std(ctrl_hdlr, &hi846_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
1461e8c08826SMartin Kepplinger HI846_DGTL_GAIN_MIN, HI846_DGTL_GAIN_MAX,
1462e8c08826SMartin Kepplinger HI846_DGTL_GAIN_STEP, HI846_DGTL_GAIN_DEFAULT);
1463e8c08826SMartin Kepplinger exposure_max = hi846->cur_mode->frame_len - HI846_EXPOSURE_MAX_MARGIN;
1464e8c08826SMartin Kepplinger hi846->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &hi846_ctrl_ops,
1465e8c08826SMartin Kepplinger V4L2_CID_EXPOSURE,
1466e8c08826SMartin Kepplinger HI846_EXPOSURE_MIN, exposure_max,
1467e8c08826SMartin Kepplinger HI846_EXPOSURE_STEP,
1468e8c08826SMartin Kepplinger exposure_max);
1469e8c08826SMartin Kepplinger v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &hi846_ctrl_ops,
1470e8c08826SMartin Kepplinger V4L2_CID_TEST_PATTERN,
1471e8c08826SMartin Kepplinger ARRAY_SIZE(hi846_test_pattern_menu) - 1,
1472e8c08826SMartin Kepplinger 0, 0, hi846_test_pattern_menu);
1473e8c08826SMartin Kepplinger if (ctrl_hdlr->error) {
1474e8c08826SMartin Kepplinger dev_err(&client->dev, "v4l ctrl handler error: %d\n",
1475*2649c1a2SWei Chen ctrl_hdlr->error);
1476*2649c1a2SWei Chen ret = ctrl_hdlr->error;
1477e8c08826SMartin Kepplinger goto error;
1478e8c08826SMartin Kepplinger }
1479e8c08826SMartin Kepplinger
1480e8c08826SMartin Kepplinger ret = v4l2_fwnode_device_parse(&client->dev, &props);
1481*2649c1a2SWei Chen if (ret)
1482e8c08826SMartin Kepplinger goto error;
1483e8c08826SMartin Kepplinger
1484e8c08826SMartin Kepplinger ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &hi846_ctrl_ops,
1485e8c08826SMartin Kepplinger &props);
1486*2649c1a2SWei Chen if (ret)
1487e8c08826SMartin Kepplinger goto error;
1488e8c08826SMartin Kepplinger
1489e8c08826SMartin Kepplinger hi846->sd.ctrl_handler = ctrl_hdlr;
1490e8c08826SMartin Kepplinger
1491*2649c1a2SWei Chen return 0;
1492*2649c1a2SWei Chen
1493*2649c1a2SWei Chen error:
1494*2649c1a2SWei Chen v4l2_ctrl_handler_free(ctrl_hdlr);
1495e8c08826SMartin Kepplinger return ret;
1496e8c08826SMartin Kepplinger }
1497e8c08826SMartin Kepplinger
hi846_set_video_mode(struct hi846 * hi846,int fps)1498e8c08826SMartin Kepplinger static int hi846_set_video_mode(struct hi846 *hi846, int fps)
1499e8c08826SMartin Kepplinger {
1500e8c08826SMartin Kepplinger struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd);
1501e8c08826SMartin Kepplinger u64 frame_length;
1502e8c08826SMartin Kepplinger int ret = 0;
1503e8c08826SMartin Kepplinger int dummy_lines;
1504e8c08826SMartin Kepplinger u64 link_freq = hi846_get_link_freq(hi846);
1505e8c08826SMartin Kepplinger
1506e8c08826SMartin Kepplinger dev_dbg(&client->dev, "%s: link freq: %llu\n", __func__,
1507e8c08826SMartin Kepplinger hi846_get_link_freq(hi846));
1508e8c08826SMartin Kepplinger
1509e8c08826SMartin Kepplinger do_div(link_freq, fps);
1510e8c08826SMartin Kepplinger frame_length = link_freq;
1511e8c08826SMartin Kepplinger do_div(frame_length, HI846_LINE_LENGTH);
1512e8c08826SMartin Kepplinger
1513e8c08826SMartin Kepplinger dummy_lines = (frame_length > hi846->cur_mode->frame_len) ?
1514e8c08826SMartin Kepplinger (frame_length - hi846->cur_mode->frame_len) : 0;
1515e8c08826SMartin Kepplinger
1516e8c08826SMartin Kepplinger frame_length = hi846->cur_mode->frame_len + dummy_lines;
1517e8c08826SMartin Kepplinger
1518e8c08826SMartin Kepplinger dev_dbg(&client->dev, "%s: frame length calculated: %llu\n", __func__,
1519e8c08826SMartin Kepplinger frame_length);
1520e8c08826SMartin Kepplinger
1521e8c08826SMartin Kepplinger hi846_write_reg_16(hi846, HI846_REG_FLL, frame_length & 0xFFFF, &ret);
1522e8c08826SMartin Kepplinger hi846_write_reg_16(hi846, HI846_REG_LLP,
1523e8c08826SMartin Kepplinger HI846_LINE_LENGTH & 0xFFFF, &ret);
1524e8c08826SMartin Kepplinger
1525e8c08826SMartin Kepplinger return ret;
1526e8c08826SMartin Kepplinger }
1527e8c08826SMartin Kepplinger
hi846_start_streaming(struct hi846 * hi846)1528e8c08826SMartin Kepplinger static int hi846_start_streaming(struct hi846 *hi846)
1529e8c08826SMartin Kepplinger {
1530e8c08826SMartin Kepplinger struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd);
1531e8c08826SMartin Kepplinger int ret = 0;
1532e8c08826SMartin Kepplinger u8 val;
1533e8c08826SMartin Kepplinger
1534e8c08826SMartin Kepplinger if (hi846->nr_lanes == 2)
1535e8c08826SMartin Kepplinger ret = hi846_write_reg_list(hi846, &hi846_init_regs_list_2lane);
1536e8c08826SMartin Kepplinger else
1537e8c08826SMartin Kepplinger ret = hi846_write_reg_list(hi846, &hi846_init_regs_list_4lane);
1538e8c08826SMartin Kepplinger if (ret) {
1539e8c08826SMartin Kepplinger dev_err(&client->dev, "failed to set plls: %d\n", ret);
1540e8c08826SMartin Kepplinger return ret;
1541e8c08826SMartin Kepplinger }
1542e8c08826SMartin Kepplinger
1543e8c08826SMartin Kepplinger ret = hi846_write_reg_list(hi846, &hi846->cur_mode->reg_list_config);
1544e8c08826SMartin Kepplinger if (ret) {
1545e8c08826SMartin Kepplinger dev_err(&client->dev, "failed to set mode: %d\n", ret);
1546e8c08826SMartin Kepplinger return ret;
1547e8c08826SMartin Kepplinger }
1548e8c08826SMartin Kepplinger
1549e8c08826SMartin Kepplinger if (hi846->nr_lanes == 2)
1550e8c08826SMartin Kepplinger ret = hi846_write_reg_list(hi846,
1551e8c08826SMartin Kepplinger &hi846->cur_mode->reg_list_2lane);
1552e8c08826SMartin Kepplinger else
1553e8c08826SMartin Kepplinger ret = hi846_write_reg_list(hi846,
1554e8c08826SMartin Kepplinger &hi846->cur_mode->reg_list_4lane);
1555e8c08826SMartin Kepplinger if (ret) {
1556e8c08826SMartin Kepplinger dev_err(&client->dev, "failed to set mipi mode: %d\n", ret);
1557e8c08826SMartin Kepplinger return ret;
1558e8c08826SMartin Kepplinger }
1559e8c08826SMartin Kepplinger
1560e8c08826SMartin Kepplinger hi846_set_video_mode(hi846, hi846->cur_mode->fps);
1561e8c08826SMartin Kepplinger
1562e8c08826SMartin Kepplinger ret = __v4l2_ctrl_handler_setup(hi846->sd.ctrl_handler);
1563e8c08826SMartin Kepplinger if (ret)
1564e8c08826SMartin Kepplinger return ret;
1565e8c08826SMartin Kepplinger
1566e8c08826SMartin Kepplinger /*
1567e8c08826SMartin Kepplinger * Reading 0x0034 is purely done for debugging reasons: It is not
1568e8c08826SMartin Kepplinger * documented in the DS but only mentioned once:
1569e8c08826SMartin Kepplinger * "If 0x0034[2] bit is disabled , Visible pixel width and height is 0."
1570e8c08826SMartin Kepplinger * So even though that sounds like we won't see anything, we don't
1571e8c08826SMartin Kepplinger * know more about this, so in that case only inform the user but do
1572e8c08826SMartin Kepplinger * nothing more.
1573e8c08826SMartin Kepplinger */
1574e8c08826SMartin Kepplinger ret = hi846_read_reg(hi846, 0x0034, &val);
1575e8c08826SMartin Kepplinger if (ret)
1576e8c08826SMartin Kepplinger return ret;
1577e8c08826SMartin Kepplinger if (!(val & BIT(2)))
1578e8c08826SMartin Kepplinger dev_info(&client->dev, "visible pixel width and height is 0\n");
1579e8c08826SMartin Kepplinger
1580e8c08826SMartin Kepplinger ret = hi846_write_reg(hi846, HI846_REG_MODE_SELECT,
1581e8c08826SMartin Kepplinger HI846_MODE_STREAMING);
1582e8c08826SMartin Kepplinger if (ret) {
1583e8c08826SMartin Kepplinger dev_err(&client->dev, "failed to start stream");
1584e8c08826SMartin Kepplinger return ret;
1585e8c08826SMartin Kepplinger }
1586e8c08826SMartin Kepplinger
1587e8c08826SMartin Kepplinger hi846->streaming = 1;
1588e8c08826SMartin Kepplinger
1589e8c08826SMartin Kepplinger dev_dbg(&client->dev, "%s: started streaming successfully\n", __func__);
1590e8c08826SMartin Kepplinger
1591e8c08826SMartin Kepplinger return ret;
1592e8c08826SMartin Kepplinger }
1593e8c08826SMartin Kepplinger
hi846_stop_streaming(struct hi846 * hi846)1594e8c08826SMartin Kepplinger static void hi846_stop_streaming(struct hi846 *hi846)
1595e8c08826SMartin Kepplinger {
1596e8c08826SMartin Kepplinger struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd);
1597e8c08826SMartin Kepplinger
1598e8c08826SMartin Kepplinger if (hi846_write_reg(hi846, HI846_REG_MODE_SELECT, HI846_MODE_STANDBY))
1599e8c08826SMartin Kepplinger dev_err(&client->dev, "failed to stop stream");
1600e8c08826SMartin Kepplinger
1601e8c08826SMartin Kepplinger hi846->streaming = 0;
1602e8c08826SMartin Kepplinger }
1603e8c08826SMartin Kepplinger
hi846_set_stream(struct v4l2_subdev * sd,int enable)1604e8c08826SMartin Kepplinger static int hi846_set_stream(struct v4l2_subdev *sd, int enable)
1605e8c08826SMartin Kepplinger {
1606e8c08826SMartin Kepplinger struct hi846 *hi846 = to_hi846(sd);
1607e8c08826SMartin Kepplinger struct i2c_client *client = v4l2_get_subdevdata(sd);
1608e8c08826SMartin Kepplinger int ret = 0;
1609e8c08826SMartin Kepplinger
1610e8c08826SMartin Kepplinger if (hi846->streaming == enable)
1611e8c08826SMartin Kepplinger return 0;
1612e8c08826SMartin Kepplinger
1613e8c08826SMartin Kepplinger mutex_lock(&hi846->mutex);
1614e8c08826SMartin Kepplinger
1615e8c08826SMartin Kepplinger if (enable) {
1616e8c08826SMartin Kepplinger ret = pm_runtime_get_sync(&client->dev);
1617e8c08826SMartin Kepplinger if (ret < 0) {
1618e8c08826SMartin Kepplinger pm_runtime_put_noidle(&client->dev);
1619e8c08826SMartin Kepplinger goto out;
1620e8c08826SMartin Kepplinger }
1621e8c08826SMartin Kepplinger
1622e8c08826SMartin Kepplinger ret = hi846_start_streaming(hi846);
1623e8c08826SMartin Kepplinger }
1624e8c08826SMartin Kepplinger
1625e8c08826SMartin Kepplinger if (!enable || ret) {
1626e8c08826SMartin Kepplinger hi846_stop_streaming(hi846);
1627e8c08826SMartin Kepplinger pm_runtime_put(&client->dev);
1628e8c08826SMartin Kepplinger }
1629e8c08826SMartin Kepplinger
1630e8c08826SMartin Kepplinger out:
1631e8c08826SMartin Kepplinger mutex_unlock(&hi846->mutex);
1632e8c08826SMartin Kepplinger
1633e8c08826SMartin Kepplinger return ret;
1634e8c08826SMartin Kepplinger }
1635e8c08826SMartin Kepplinger
hi846_power_on(struct hi846 * hi846)1636e8c08826SMartin Kepplinger static int hi846_power_on(struct hi846 *hi846)
1637e8c08826SMartin Kepplinger {
1638e8c08826SMartin Kepplinger int ret;
1639e8c08826SMartin Kepplinger
1640e8c08826SMartin Kepplinger ret = regulator_bulk_enable(HI846_NUM_SUPPLIES, hi846->supplies);
1641e8c08826SMartin Kepplinger if (ret < 0)
1642e8c08826SMartin Kepplinger return ret;
1643e8c08826SMartin Kepplinger
1644e8c08826SMartin Kepplinger ret = clk_prepare_enable(hi846->clock);
1645e8c08826SMartin Kepplinger if (ret < 0)
1646e8c08826SMartin Kepplinger goto err_reg;
1647e8c08826SMartin Kepplinger
1648e8c08826SMartin Kepplinger if (hi846->shutdown_gpio)
1649e8c08826SMartin Kepplinger gpiod_set_value_cansleep(hi846->shutdown_gpio, 0);
1650e8c08826SMartin Kepplinger
1651e8c08826SMartin Kepplinger /* 30us = 2400 cycles at 80Mhz */
1652e8c08826SMartin Kepplinger usleep_range(30, 60);
1653e8c08826SMartin Kepplinger if (hi846->rst_gpio)
1654e8c08826SMartin Kepplinger gpiod_set_value_cansleep(hi846->rst_gpio, 0);
1655e8c08826SMartin Kepplinger usleep_range(30, 60);
1656e8c08826SMartin Kepplinger
1657e8c08826SMartin Kepplinger return 0;
1658e8c08826SMartin Kepplinger
1659e8c08826SMartin Kepplinger err_reg:
1660e8c08826SMartin Kepplinger regulator_bulk_disable(HI846_NUM_SUPPLIES, hi846->supplies);
1661e8c08826SMartin Kepplinger
1662e8c08826SMartin Kepplinger return ret;
1663e8c08826SMartin Kepplinger }
1664e1cc0a05SMartin Kepplinger
hi846_power_off(struct hi846 * hi846)1665e8c08826SMartin Kepplinger static int hi846_power_off(struct hi846 *hi846)
1666e8c08826SMartin Kepplinger {
1667e8c08826SMartin Kepplinger if (hi846->rst_gpio)
1668e8c08826SMartin Kepplinger gpiod_set_value_cansleep(hi846->rst_gpio, 1);
1669e8c08826SMartin Kepplinger
1670e8c08826SMartin Kepplinger if (hi846->shutdown_gpio)
1671e8c08826SMartin Kepplinger gpiod_set_value_cansleep(hi846->shutdown_gpio, 1);
1672e8c08826SMartin Kepplinger
1673e1cc0a05SMartin Kepplinger clk_disable_unprepare(hi846->clock);
1674e8c08826SMartin Kepplinger return regulator_bulk_disable(HI846_NUM_SUPPLIES, hi846->supplies);
1675e8c08826SMartin Kepplinger }
1676e8c08826SMartin Kepplinger
hi846_suspend(struct device * dev)1677e8c08826SMartin Kepplinger static int __maybe_unused hi846_suspend(struct device *dev)
1678e8c08826SMartin Kepplinger {
1679e8c08826SMartin Kepplinger struct i2c_client *client = to_i2c_client(dev);
1680e8c08826SMartin Kepplinger struct v4l2_subdev *sd = i2c_get_clientdata(client);
1681e8c08826SMartin Kepplinger struct hi846 *hi846 = to_hi846(sd);
1682e8c08826SMartin Kepplinger
1683e8c08826SMartin Kepplinger if (hi846->streaming)
1684e8c08826SMartin Kepplinger hi846_stop_streaming(hi846);
1685e1cc0a05SMartin Kepplinger
1686e8c08826SMartin Kepplinger return hi846_power_off(hi846);
1687e8c08826SMartin Kepplinger }
1688e8c08826SMartin Kepplinger
hi846_resume(struct device * dev)1689e8c08826SMartin Kepplinger static int __maybe_unused hi846_resume(struct device *dev)
1690e8c08826SMartin Kepplinger {
1691e8c08826SMartin Kepplinger struct i2c_client *client = to_i2c_client(dev);
1692e8c08826SMartin Kepplinger struct v4l2_subdev *sd = i2c_get_clientdata(client);
1693e8c08826SMartin Kepplinger struct hi846 *hi846 = to_hi846(sd);
1694e8c08826SMartin Kepplinger int ret;
1695e8c08826SMartin Kepplinger
1696e8c08826SMartin Kepplinger ret = hi846_power_on(hi846);
1697e8c08826SMartin Kepplinger if (ret)
1698e8c08826SMartin Kepplinger return ret;
1699e8c08826SMartin Kepplinger
1700e8c08826SMartin Kepplinger if (hi846->streaming) {
1701e8c08826SMartin Kepplinger ret = hi846_start_streaming(hi846);
1702e8c08826SMartin Kepplinger if (ret) {
1703e8c08826SMartin Kepplinger dev_err(dev, "%s: start streaming failed: %d\n",
1704e8c08826SMartin Kepplinger __func__, ret);
1705e8c08826SMartin Kepplinger goto error;
1706e8c08826SMartin Kepplinger }
1707e8c08826SMartin Kepplinger }
1708e8c08826SMartin Kepplinger
1709e8c08826SMartin Kepplinger return 0;
1710e8c08826SMartin Kepplinger
1711e8c08826SMartin Kepplinger error:
1712e8c08826SMartin Kepplinger hi846_power_off(hi846);
1713e8c08826SMartin Kepplinger return ret;
1714e8c08826SMartin Kepplinger }
1715e8c08826SMartin Kepplinger
hi846_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)1716e8c08826SMartin Kepplinger static int hi846_set_format(struct v4l2_subdev *sd,
1717e8c08826SMartin Kepplinger struct v4l2_subdev_state *sd_state,
1718e8c08826SMartin Kepplinger struct v4l2_subdev_format *format)
1719e8c08826SMartin Kepplinger {
1720e8c08826SMartin Kepplinger struct hi846 *hi846 = to_hi846(sd);
1721e8c08826SMartin Kepplinger struct v4l2_mbus_framefmt *mf = &format->format;
1722e8c08826SMartin Kepplinger struct i2c_client *client = v4l2_get_subdevdata(sd);
1723e8c08826SMartin Kepplinger const struct hi846_datafmt *fmt = hi846_find_datafmt(mf->code);
1724e8c08826SMartin Kepplinger u32 tgt_fps;
1725e8c08826SMartin Kepplinger s32 vblank_def, h_blank;
1726e8c08826SMartin Kepplinger
1727e8c08826SMartin Kepplinger if (!fmt) {
1728e8c08826SMartin Kepplinger mf->code = hi846_colour_fmts[0].code;
1729e8c08826SMartin Kepplinger mf->colorspace = hi846_colour_fmts[0].colorspace;
1730e8c08826SMartin Kepplinger fmt = &hi846_colour_fmts[0];
1731e8c08826SMartin Kepplinger }
1732e8c08826SMartin Kepplinger
1733e8c08826SMartin Kepplinger if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
1734e8c08826SMartin Kepplinger *v4l2_subdev_get_try_format(sd, sd_state, format->pad) = *mf;
1735e8c08826SMartin Kepplinger return 0;
1736e8c08826SMartin Kepplinger }
1737e8c08826SMartin Kepplinger
1738e8c08826SMartin Kepplinger if (hi846->nr_lanes == 2) {
1739e8c08826SMartin Kepplinger if (!hi846->cur_mode->reg_list_2lane.num_of_regs) {
1740e8c08826SMartin Kepplinger dev_err(&client->dev,
1741e8c08826SMartin Kepplinger "this mode is not supported for 2 lanes\n");
1742e8c08826SMartin Kepplinger return -EINVAL;
1743e8c08826SMartin Kepplinger }
1744e8c08826SMartin Kepplinger } else {
1745e8c08826SMartin Kepplinger if (!hi846->cur_mode->reg_list_4lane.num_of_regs) {
1746e8c08826SMartin Kepplinger dev_err(&client->dev,
1747e8c08826SMartin Kepplinger "this mode is not supported for 4 lanes\n");
1748e8c08826SMartin Kepplinger return -EINVAL;
1749e8c08826SMartin Kepplinger }
1750e8c08826SMartin Kepplinger }
1751e8c08826SMartin Kepplinger
1752e8c08826SMartin Kepplinger mutex_lock(&hi846->mutex);
1753e8c08826SMartin Kepplinger
1754e8c08826SMartin Kepplinger if (hi846->streaming) {
1755e8c08826SMartin Kepplinger mutex_unlock(&hi846->mutex);
1756e8c08826SMartin Kepplinger return -EBUSY;
1757e8c08826SMartin Kepplinger }
1758e8c08826SMartin Kepplinger
1759e8c08826SMartin Kepplinger hi846->fmt = fmt;
1760e8c08826SMartin Kepplinger
1761e8c08826SMartin Kepplinger hi846->cur_mode =
1762e8c08826SMartin Kepplinger v4l2_find_nearest_size(supported_modes,
1763e8c08826SMartin Kepplinger ARRAY_SIZE(supported_modes),
1764e8c08826SMartin Kepplinger width, height, mf->width, mf->height);
1765e8c08826SMartin Kepplinger dev_dbg(&client->dev, "%s: found mode: %dx%d\n", __func__,
1766e8c08826SMartin Kepplinger hi846->cur_mode->width, hi846->cur_mode->height);
1767e8c08826SMartin Kepplinger
1768e8c08826SMartin Kepplinger tgt_fps = hi846->cur_mode->fps;
1769e8c08826SMartin Kepplinger dev_dbg(&client->dev, "%s: target fps: %d\n", __func__, tgt_fps);
1770e8c08826SMartin Kepplinger
1771e8c08826SMartin Kepplinger mf->width = hi846->cur_mode->width;
1772e8c08826SMartin Kepplinger mf->height = hi846->cur_mode->height;
1773e8c08826SMartin Kepplinger mf->code = HI846_MEDIA_BUS_FORMAT;
1774e8c08826SMartin Kepplinger mf->field = V4L2_FIELD_NONE;
1775e8c08826SMartin Kepplinger
1776e8c08826SMartin Kepplinger __v4l2_ctrl_s_ctrl(hi846->link_freq, hi846_get_link_freq_index(hi846));
1777e8c08826SMartin Kepplinger __v4l2_ctrl_s_ctrl_int64(hi846->pixel_rate,
1778e8c08826SMartin Kepplinger hi846_calc_pixel_rate(hi846));
1779e8c08826SMartin Kepplinger
1780e8c08826SMartin Kepplinger /* Update limits and set FPS to default */
1781e8c08826SMartin Kepplinger vblank_def = hi846->cur_mode->frame_len - hi846->cur_mode->height;
1782e8c08826SMartin Kepplinger __v4l2_ctrl_modify_range(hi846->vblank,
1783e8c08826SMartin Kepplinger hi846->cur_mode->frame_len -
1784e8c08826SMartin Kepplinger hi846->cur_mode->height,
1785e8c08826SMartin Kepplinger HI846_FLL_MAX - hi846->cur_mode->height, 1,
1786e8c08826SMartin Kepplinger vblank_def);
1787e8c08826SMartin Kepplinger __v4l2_ctrl_s_ctrl(hi846->vblank, vblank_def);
1788e8c08826SMartin Kepplinger
1789e8c08826SMartin Kepplinger h_blank = hi846->cur_mode->llp - hi846->cur_mode->width;
1790e8c08826SMartin Kepplinger
1791e8c08826SMartin Kepplinger __v4l2_ctrl_modify_range(hi846->hblank, h_blank, h_blank, 1,
1792e8c08826SMartin Kepplinger h_blank);
1793e8c08826SMartin Kepplinger
1794e8c08826SMartin Kepplinger dev_dbg(&client->dev, "Set fmt w=%d h=%d code=0x%x colorspace=0x%x\n",
1795e8c08826SMartin Kepplinger mf->width, mf->height,
1796e8c08826SMartin Kepplinger fmt->code, fmt->colorspace);
1797e8c08826SMartin Kepplinger
1798e8c08826SMartin Kepplinger mutex_unlock(&hi846->mutex);
1799e8c08826SMartin Kepplinger
1800e8c08826SMartin Kepplinger return 0;
1801e8c08826SMartin Kepplinger }
1802e8c08826SMartin Kepplinger
hi846_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)1803e8c08826SMartin Kepplinger static int hi846_get_format(struct v4l2_subdev *sd,
1804e8c08826SMartin Kepplinger struct v4l2_subdev_state *sd_state,
1805e8c08826SMartin Kepplinger struct v4l2_subdev_format *format)
1806e8c08826SMartin Kepplinger {
1807e8c08826SMartin Kepplinger struct hi846 *hi846 = to_hi846(sd);
1808e8c08826SMartin Kepplinger struct v4l2_mbus_framefmt *mf = &format->format;
1809e8c08826SMartin Kepplinger struct i2c_client *client = v4l2_get_subdevdata(sd);
1810e8c08826SMartin Kepplinger
1811e8c08826SMartin Kepplinger if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
1812e8c08826SMartin Kepplinger format->format = *v4l2_subdev_get_try_format(&hi846->sd,
1813e8c08826SMartin Kepplinger sd_state,
1814e8c08826SMartin Kepplinger format->pad);
1815e8c08826SMartin Kepplinger return 0;
1816e8c08826SMartin Kepplinger }
1817e8c08826SMartin Kepplinger
1818e8c08826SMartin Kepplinger mutex_lock(&hi846->mutex);
1819e8c08826SMartin Kepplinger mf->code = HI846_MEDIA_BUS_FORMAT;
1820e8c08826SMartin Kepplinger mf->colorspace = V4L2_COLORSPACE_RAW;
1821e8c08826SMartin Kepplinger mf->field = V4L2_FIELD_NONE;
1822e8c08826SMartin Kepplinger mf->width = hi846->cur_mode->width;
1823e8c08826SMartin Kepplinger mf->height = hi846->cur_mode->height;
1824e8c08826SMartin Kepplinger mutex_unlock(&hi846->mutex);
1825e8c08826SMartin Kepplinger dev_dbg(&client->dev,
1826e8c08826SMartin Kepplinger "Get format w=%d h=%d code=0x%x colorspace=0x%x\n",
1827e8c08826SMartin Kepplinger mf->width, mf->height, mf->code, mf->colorspace);
1828e8c08826SMartin Kepplinger
1829e8c08826SMartin Kepplinger return 0;
1830e8c08826SMartin Kepplinger }
1831e8c08826SMartin Kepplinger
hi846_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)1832e8c08826SMartin Kepplinger static int hi846_enum_mbus_code(struct v4l2_subdev *sd,
1833e8c08826SMartin Kepplinger struct v4l2_subdev_state *sd_state,
1834e8c08826SMartin Kepplinger struct v4l2_subdev_mbus_code_enum *code)
1835e8c08826SMartin Kepplinger {
1836e8c08826SMartin Kepplinger if (code->pad || code->index > 0)
1837e8c08826SMartin Kepplinger return -EINVAL;
1838e8c08826SMartin Kepplinger
1839e8c08826SMartin Kepplinger code->code = HI846_MEDIA_BUS_FORMAT;
1840e8c08826SMartin Kepplinger
1841e8c08826SMartin Kepplinger return 0;
1842e8c08826SMartin Kepplinger }
1843e8c08826SMartin Kepplinger
hi846_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)1844e8c08826SMartin Kepplinger static int hi846_enum_frame_size(struct v4l2_subdev *sd,
1845e8c08826SMartin Kepplinger struct v4l2_subdev_state *sd_state,
1846e8c08826SMartin Kepplinger struct v4l2_subdev_frame_size_enum *fse)
1847e8c08826SMartin Kepplinger {
1848e8c08826SMartin Kepplinger struct i2c_client *client = v4l2_get_subdevdata(sd);
1849e8c08826SMartin Kepplinger
1850e8c08826SMartin Kepplinger if (fse->pad || fse->index >= ARRAY_SIZE(supported_modes))
1851e8c08826SMartin Kepplinger return -EINVAL;
1852e8c08826SMartin Kepplinger
1853e8c08826SMartin Kepplinger if (fse->code != HI846_MEDIA_BUS_FORMAT) {
1854e8c08826SMartin Kepplinger dev_err(&client->dev, "frame size enum not matching\n");
1855e8c08826SMartin Kepplinger return -EINVAL;
1856e8c08826SMartin Kepplinger }
1857e8c08826SMartin Kepplinger
1858e8c08826SMartin Kepplinger fse->min_width = supported_modes[fse->index].width;
1859e8c08826SMartin Kepplinger fse->max_width = supported_modes[fse->index].width;
1860e8c08826SMartin Kepplinger fse->min_height = supported_modes[fse->index].height;
1861e8c08826SMartin Kepplinger fse->max_height = supported_modes[fse->index].height;
1862e8c08826SMartin Kepplinger
1863e8c08826SMartin Kepplinger dev_dbg(&client->dev, "%s: max width: %d max height: %d\n", __func__,
1864e8c08826SMartin Kepplinger fse->max_width, fse->max_height);
1865e8c08826SMartin Kepplinger
1866e8c08826SMartin Kepplinger return 0;
1867e8c08826SMartin Kepplinger }
1868e8c08826SMartin Kepplinger
hi846_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_selection * sel)1869e8c08826SMartin Kepplinger static int hi846_get_selection(struct v4l2_subdev *sd,
1870e8c08826SMartin Kepplinger struct v4l2_subdev_state *sd_state,
1871e8c08826SMartin Kepplinger struct v4l2_subdev_selection *sel)
1872e8c08826SMartin Kepplinger {
1873e8c08826SMartin Kepplinger struct hi846 *hi846 = to_hi846(sd);
1874e8c08826SMartin Kepplinger
1875e8c08826SMartin Kepplinger switch (sel->target) {
1876e8c08826SMartin Kepplinger case V4L2_SEL_TGT_CROP:
1877e8c08826SMartin Kepplinger case V4L2_SEL_TGT_CROP_DEFAULT:
1878e8c08826SMartin Kepplinger mutex_lock(&hi846->mutex);
1879e8c08826SMartin Kepplinger switch (sel->which) {
1880e8c08826SMartin Kepplinger case V4L2_SUBDEV_FORMAT_TRY:
1881e8c08826SMartin Kepplinger v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
1882e8c08826SMartin Kepplinger break;
1883e8c08826SMartin Kepplinger case V4L2_SUBDEV_FORMAT_ACTIVE:
1884e8c08826SMartin Kepplinger sel->r = hi846->cur_mode->crop;
1885e8c08826SMartin Kepplinger break;
1886e8c08826SMartin Kepplinger }
1887e8c08826SMartin Kepplinger mutex_unlock(&hi846->mutex);
1888e8c08826SMartin Kepplinger return 0;
1889e8c08826SMartin Kepplinger case V4L2_SEL_TGT_CROP_BOUNDS:
1890e8c08826SMartin Kepplinger case V4L2_SEL_TGT_NATIVE_SIZE:
1891e8c08826SMartin Kepplinger sel->r.top = 0;
1892e8c08826SMartin Kepplinger sel->r.left = 0;
1893e8c08826SMartin Kepplinger sel->r.width = 3264;
1894e8c08826SMartin Kepplinger sel->r.height = 2448;
1895e8c08826SMartin Kepplinger return 0;
1896e8c08826SMartin Kepplinger default:
1897e8c08826SMartin Kepplinger return -EINVAL;
1898e8c08826SMartin Kepplinger }
1899e8c08826SMartin Kepplinger }
1900e8c08826SMartin Kepplinger
hi846_init_cfg(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state)1901e8c08826SMartin Kepplinger static int hi846_init_cfg(struct v4l2_subdev *sd,
1902e8c08826SMartin Kepplinger struct v4l2_subdev_state *sd_state)
1903e8c08826SMartin Kepplinger {
1904e8c08826SMartin Kepplinger struct hi846 *hi846 = to_hi846(sd);
1905e8c08826SMartin Kepplinger struct v4l2_mbus_framefmt *mf;
1906e8c08826SMartin Kepplinger
1907e8c08826SMartin Kepplinger mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
1908e8c08826SMartin Kepplinger
1909e8c08826SMartin Kepplinger mutex_lock(&hi846->mutex);
1910e8c08826SMartin Kepplinger mf->code = HI846_MEDIA_BUS_FORMAT;
1911e8c08826SMartin Kepplinger mf->colorspace = V4L2_COLORSPACE_RAW;
1912e8c08826SMartin Kepplinger mf->field = V4L2_FIELD_NONE;
1913e8c08826SMartin Kepplinger mf->width = hi846->cur_mode->width;
1914e8c08826SMartin Kepplinger mf->height = hi846->cur_mode->height;
1915e8c08826SMartin Kepplinger mutex_unlock(&hi846->mutex);
1916e8c08826SMartin Kepplinger
1917e8c08826SMartin Kepplinger return 0;
1918e8c08826SMartin Kepplinger }
1919e8c08826SMartin Kepplinger
1920e8c08826SMartin Kepplinger static const struct v4l2_subdev_video_ops hi846_video_ops = {
1921e8c08826SMartin Kepplinger .s_stream = hi846_set_stream,
1922e8c08826SMartin Kepplinger };
1923e8c08826SMartin Kepplinger
1924e8c08826SMartin Kepplinger static const struct v4l2_subdev_pad_ops hi846_pad_ops = {
1925e8c08826SMartin Kepplinger .init_cfg = hi846_init_cfg,
1926e8c08826SMartin Kepplinger .enum_frame_size = hi846_enum_frame_size,
1927e8c08826SMartin Kepplinger .enum_mbus_code = hi846_enum_mbus_code,
1928e8c08826SMartin Kepplinger .set_fmt = hi846_set_format,
1929e8c08826SMartin Kepplinger .get_fmt = hi846_get_format,
1930e8c08826SMartin Kepplinger .get_selection = hi846_get_selection,
1931e8c08826SMartin Kepplinger };
1932e8c08826SMartin Kepplinger
1933e8c08826SMartin Kepplinger static const struct v4l2_subdev_ops hi846_subdev_ops = {
1934e8c08826SMartin Kepplinger .video = &hi846_video_ops,
1935e8c08826SMartin Kepplinger .pad = &hi846_pad_ops,
1936e8c08826SMartin Kepplinger };
1937e8c08826SMartin Kepplinger
1938e8c08826SMartin Kepplinger static const struct media_entity_operations hi846_subdev_entity_ops = {
1939e8c08826SMartin Kepplinger .link_validate = v4l2_subdev_link_validate,
1940e8c08826SMartin Kepplinger };
1941e8c08826SMartin Kepplinger
hi846_identify_module(struct hi846 * hi846)1942e8c08826SMartin Kepplinger static int hi846_identify_module(struct hi846 *hi846)
1943e8c08826SMartin Kepplinger {
1944e8c08826SMartin Kepplinger struct i2c_client *client = v4l2_get_subdevdata(&hi846->sd);
1945e8c08826SMartin Kepplinger int ret;
1946e8c08826SMartin Kepplinger u8 hi, lo;
1947e8c08826SMartin Kepplinger
1948e8c08826SMartin Kepplinger ret = hi846_read_reg(hi846, HI846_REG_CHIP_ID_L, &lo);
1949e8c08826SMartin Kepplinger if (ret)
1950e8c08826SMartin Kepplinger return ret;
1951e8c08826SMartin Kepplinger
1952e8c08826SMartin Kepplinger if (lo != HI846_CHIP_ID_L) {
1953e8c08826SMartin Kepplinger dev_err(&client->dev, "wrong chip id low byte: %x", lo);
1954e8c08826SMartin Kepplinger return -ENXIO;
1955e8c08826SMartin Kepplinger }
1956e8c08826SMartin Kepplinger
1957e8c08826SMartin Kepplinger ret = hi846_read_reg(hi846, HI846_REG_CHIP_ID_H, &hi);
1958e8c08826SMartin Kepplinger if (ret)
1959e8c08826SMartin Kepplinger return ret;
1960e8c08826SMartin Kepplinger
1961e8c08826SMartin Kepplinger if (hi != HI846_CHIP_ID_H) {
1962e8c08826SMartin Kepplinger dev_err(&client->dev, "wrong chip id high byte: %x", hi);
1963e8c08826SMartin Kepplinger return -ENXIO;
1964e8c08826SMartin Kepplinger }
1965e8c08826SMartin Kepplinger
1966e8c08826SMartin Kepplinger dev_info(&client->dev, "chip id %02X %02X using %d mipi lanes\n",
1967e8c08826SMartin Kepplinger hi, lo, hi846->nr_lanes);
1968e8c08826SMartin Kepplinger
1969e8c08826SMartin Kepplinger return 0;
1970e8c08826SMartin Kepplinger }
1971e8c08826SMartin Kepplinger
hi846_check_link_freqs(struct hi846 * hi846,struct v4l2_fwnode_endpoint * ep)1972e8c08826SMartin Kepplinger static s64 hi846_check_link_freqs(struct hi846 *hi846,
1973e8c08826SMartin Kepplinger struct v4l2_fwnode_endpoint *ep)
1974e8c08826SMartin Kepplinger {
1975e8c08826SMartin Kepplinger const s64 *freqs = hi846_link_freqs;
1976e8c08826SMartin Kepplinger int freqs_count = ARRAY_SIZE(hi846_link_freqs);
1977e8c08826SMartin Kepplinger int i, j;
1978e8c08826SMartin Kepplinger
1979e8c08826SMartin Kepplinger for (i = 0; i < freqs_count; i++) {
1980e8c08826SMartin Kepplinger for (j = 0; j < ep->nr_of_link_frequencies; j++)
1981e8c08826SMartin Kepplinger if (freqs[i] == ep->link_frequencies[j])
1982e8c08826SMartin Kepplinger break;
1983e8c08826SMartin Kepplinger if (j == ep->nr_of_link_frequencies)
1984e8c08826SMartin Kepplinger return freqs[i];
1985e8c08826SMartin Kepplinger }
1986e8c08826SMartin Kepplinger
1987e8c08826SMartin Kepplinger return 0;
1988e8c08826SMartin Kepplinger }
1989e8c08826SMartin Kepplinger
hi846_parse_dt(struct hi846 * hi846,struct device * dev)1990e8c08826SMartin Kepplinger static int hi846_parse_dt(struct hi846 *hi846, struct device *dev)
1991e8c08826SMartin Kepplinger {
1992e8c08826SMartin Kepplinger struct fwnode_handle *ep;
1993e8c08826SMartin Kepplinger struct fwnode_handle *fwnode = dev_fwnode(dev);
1994e8c08826SMartin Kepplinger struct v4l2_fwnode_endpoint bus_cfg = {
1995e8c08826SMartin Kepplinger .bus_type = V4L2_MBUS_CSI2_DPHY
1996e8c08826SMartin Kepplinger };
1997e8c08826SMartin Kepplinger int ret;
1998e8c08826SMartin Kepplinger s64 fq;
1999e8c08826SMartin Kepplinger
2000e8c08826SMartin Kepplinger ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
2001e8c08826SMartin Kepplinger if (!ep) {
2002e8c08826SMartin Kepplinger dev_err(dev, "unable to find endpoint node\n");
2003e8c08826SMartin Kepplinger return -ENXIO;
2004e8c08826SMartin Kepplinger }
2005e8c08826SMartin Kepplinger
2006e8c08826SMartin Kepplinger ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
2007e8c08826SMartin Kepplinger fwnode_handle_put(ep);
2008e8c08826SMartin Kepplinger if (ret) {
2009e8c08826SMartin Kepplinger dev_err(dev, "failed to parse endpoint node: %d\n", ret);
2010e8c08826SMartin Kepplinger return ret;
2011e8c08826SMartin Kepplinger }
2012e8c08826SMartin Kepplinger
2013e8c08826SMartin Kepplinger if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2 &&
2014e8c08826SMartin Kepplinger bus_cfg.bus.mipi_csi2.num_data_lanes != 4) {
2015e8c08826SMartin Kepplinger dev_err(dev, "number of CSI2 data lanes %d is not supported",
201680113026SRafael Mendonca bus_cfg.bus.mipi_csi2.num_data_lanes);
201780113026SRafael Mendonca ret = -EINVAL;
2018e8c08826SMartin Kepplinger goto check_hwcfg_error;
2019e8c08826SMartin Kepplinger }
2020e8c08826SMartin Kepplinger
2021e8c08826SMartin Kepplinger hi846->nr_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
2022e8c08826SMartin Kepplinger
2023e8c08826SMartin Kepplinger if (!bus_cfg.nr_of_link_frequencies) {
202480113026SRafael Mendonca dev_err(dev, "link-frequency property not found in DT\n");
202580113026SRafael Mendonca ret = -EINVAL;
2026e8c08826SMartin Kepplinger goto check_hwcfg_error;
2027e8c08826SMartin Kepplinger }
2028e8c08826SMartin Kepplinger
2029e8c08826SMartin Kepplinger /* Check that link frequences for all the modes are in device tree */
2030e8c08826SMartin Kepplinger fq = hi846_check_link_freqs(hi846, &bus_cfg);
2031e8c08826SMartin Kepplinger if (fq) {
203280113026SRafael Mendonca dev_err(dev, "Link frequency of %lld is not supported\n", fq);
203380113026SRafael Mendonca ret = -EINVAL;
2034e8c08826SMartin Kepplinger goto check_hwcfg_error;
2035e8c08826SMartin Kepplinger }
2036e8c08826SMartin Kepplinger
2037e8c08826SMartin Kepplinger v4l2_fwnode_endpoint_free(&bus_cfg);
2038e8c08826SMartin Kepplinger
2039e8c08826SMartin Kepplinger hi846->rst_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
2040e8c08826SMartin Kepplinger if (IS_ERR(hi846->rst_gpio)) {
2041e8c08826SMartin Kepplinger dev_err(dev, "failed to get reset gpio: %pe\n",
2042e8c08826SMartin Kepplinger hi846->rst_gpio);
2043e8c08826SMartin Kepplinger return PTR_ERR(hi846->rst_gpio);
2044e8c08826SMartin Kepplinger }
2045e8c08826SMartin Kepplinger
2046e8c08826SMartin Kepplinger hi846->shutdown_gpio = devm_gpiod_get_optional(dev, "shutdown",
2047e8c08826SMartin Kepplinger GPIOD_OUT_LOW);
2048e8c08826SMartin Kepplinger if (IS_ERR(hi846->shutdown_gpio)) {
2049e8c08826SMartin Kepplinger dev_err(dev, "failed to get shutdown gpio: %pe\n",
2050e8c08826SMartin Kepplinger hi846->shutdown_gpio);
2051e8c08826SMartin Kepplinger return PTR_ERR(hi846->shutdown_gpio);
2052e8c08826SMartin Kepplinger }
2053e8c08826SMartin Kepplinger
205480113026SRafael Mendonca return 0;
205580113026SRafael Mendonca
205680113026SRafael Mendonca check_hwcfg_error:
205780113026SRafael Mendonca v4l2_fwnode_endpoint_free(&bus_cfg);
2058e8c08826SMartin Kepplinger return ret;
2059e8c08826SMartin Kepplinger }
2060e8c08826SMartin Kepplinger
hi846_probe(struct i2c_client * client)2061e8c08826SMartin Kepplinger static int hi846_probe(struct i2c_client *client)
2062e8c08826SMartin Kepplinger {
2063e8c08826SMartin Kepplinger struct hi846 *hi846;
2064e8c08826SMartin Kepplinger int ret;
2065e8c08826SMartin Kepplinger int i;
2066e8c08826SMartin Kepplinger u32 mclk_freq;
2067e8c08826SMartin Kepplinger
2068e8c08826SMartin Kepplinger hi846 = devm_kzalloc(&client->dev, sizeof(*hi846), GFP_KERNEL);
2069e8c08826SMartin Kepplinger if (!hi846)
2070e8c08826SMartin Kepplinger return -ENOMEM;
2071e8c08826SMartin Kepplinger
2072e8c08826SMartin Kepplinger ret = hi846_parse_dt(hi846, &client->dev);
2073e8c08826SMartin Kepplinger if (ret) {
2074e8c08826SMartin Kepplinger dev_err(&client->dev, "failed to check HW configuration: %d",
2075e8c08826SMartin Kepplinger ret);
2076e8c08826SMartin Kepplinger return ret;
2077e8c08826SMartin Kepplinger }
2078e8c08826SMartin Kepplinger
2079e8c08826SMartin Kepplinger hi846->clock = devm_clk_get(&client->dev, NULL);
2080e8c08826SMartin Kepplinger if (IS_ERR(hi846->clock)) {
2081e8c08826SMartin Kepplinger dev_err(&client->dev, "failed to get clock: %pe\n",
2082e8c08826SMartin Kepplinger hi846->clock);
2083e8c08826SMartin Kepplinger return PTR_ERR(hi846->clock);
2084e8c08826SMartin Kepplinger }
2085e8c08826SMartin Kepplinger
2086e8c08826SMartin Kepplinger mclk_freq = clk_get_rate(hi846->clock);
2087e8c08826SMartin Kepplinger if (mclk_freq != 25000000)
2088e8c08826SMartin Kepplinger dev_warn(&client->dev,
2089e8c08826SMartin Kepplinger "External clock freq should be 25000000, not %u.\n",
2090e8c08826SMartin Kepplinger mclk_freq);
2091e8c08826SMartin Kepplinger
2092e8c08826SMartin Kepplinger for (i = 0; i < HI846_NUM_SUPPLIES; i++)
2093e8c08826SMartin Kepplinger hi846->supplies[i].supply = hi846_supply_names[i];
2094e8c08826SMartin Kepplinger
2095e8c08826SMartin Kepplinger ret = devm_regulator_bulk_get(&client->dev, HI846_NUM_SUPPLIES,
2096e8c08826SMartin Kepplinger hi846->supplies);
2097e8c08826SMartin Kepplinger if (ret < 0)
2098e8c08826SMartin Kepplinger return ret;
2099e8c08826SMartin Kepplinger
2100e8c08826SMartin Kepplinger v4l2_i2c_subdev_init(&hi846->sd, client, &hi846_subdev_ops);
2101e8c08826SMartin Kepplinger
2102e8c08826SMartin Kepplinger mutex_init(&hi846->mutex);
2103e8c08826SMartin Kepplinger
2104e8c08826SMartin Kepplinger ret = hi846_power_on(hi846);
2105e8c08826SMartin Kepplinger if (ret)
2106e8c08826SMartin Kepplinger goto err_mutex;
2107e8c08826SMartin Kepplinger
2108e8c08826SMartin Kepplinger ret = hi846_identify_module(hi846);
2109e8c08826SMartin Kepplinger if (ret)
2110e8c08826SMartin Kepplinger goto err_power_off;
2111e8c08826SMartin Kepplinger
2112e8c08826SMartin Kepplinger hi846->cur_mode = &supported_modes[0];
2113e8c08826SMartin Kepplinger
2114e8c08826SMartin Kepplinger ret = hi846_init_controls(hi846);
2115e8c08826SMartin Kepplinger if (ret) {
2116e8c08826SMartin Kepplinger dev_err(&client->dev, "failed to init controls: %d", ret);
2117e8c08826SMartin Kepplinger goto err_power_off;
2118e8c08826SMartin Kepplinger }
2119e8c08826SMartin Kepplinger
2120e8c08826SMartin Kepplinger hi846->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
2121e8c08826SMartin Kepplinger hi846->sd.entity.ops = &hi846_subdev_entity_ops;
2122e8c08826SMartin Kepplinger hi846->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
2123e8c08826SMartin Kepplinger hi846->pad.flags = MEDIA_PAD_FL_SOURCE;
2124e8c08826SMartin Kepplinger ret = media_entity_pads_init(&hi846->sd.entity, 1, &hi846->pad);
2125e8c08826SMartin Kepplinger if (ret) {
2126e8c08826SMartin Kepplinger dev_err(&client->dev, "failed to init entity pads: %d", ret);
2127e8c08826SMartin Kepplinger goto err_v4l2_ctrl_handler_free;
2128e8c08826SMartin Kepplinger }
2129e8c08826SMartin Kepplinger
2130e8c08826SMartin Kepplinger ret = v4l2_async_register_subdev_sensor(&hi846->sd);
2131e8c08826SMartin Kepplinger if (ret < 0) {
2132e8c08826SMartin Kepplinger dev_err(&client->dev, "failed to register V4L2 subdev: %d",
2133e8c08826SMartin Kepplinger ret);
2134e8c08826SMartin Kepplinger goto err_media_entity_cleanup;
2135e8c08826SMartin Kepplinger }
2136e8c08826SMartin Kepplinger
2137e8c08826SMartin Kepplinger pm_runtime_set_active(&client->dev);
2138e8c08826SMartin Kepplinger pm_runtime_enable(&client->dev);
2139e8c08826SMartin Kepplinger pm_runtime_idle(&client->dev);
2140e8c08826SMartin Kepplinger
2141e8c08826SMartin Kepplinger return 0;
2142e8c08826SMartin Kepplinger
2143e8c08826SMartin Kepplinger err_media_entity_cleanup:
2144e8c08826SMartin Kepplinger media_entity_cleanup(&hi846->sd.entity);
2145e8c08826SMartin Kepplinger
2146e8c08826SMartin Kepplinger err_v4l2_ctrl_handler_free:
2147e8c08826SMartin Kepplinger v4l2_ctrl_handler_free(hi846->sd.ctrl_handler);
2148e8c08826SMartin Kepplinger
2149e8c08826SMartin Kepplinger err_power_off:
2150e8c08826SMartin Kepplinger hi846_power_off(hi846);
2151e8c08826SMartin Kepplinger
2152e8c08826SMartin Kepplinger err_mutex:
2153e8c08826SMartin Kepplinger mutex_destroy(&hi846->mutex);
2154e8c08826SMartin Kepplinger
2155e8c08826SMartin Kepplinger return ret;
2156e8c08826SMartin Kepplinger }
2157ed5c2f5fSUwe Kleine-König
hi846_remove(struct i2c_client * client)2158e8c08826SMartin Kepplinger static void hi846_remove(struct i2c_client *client)
2159e8c08826SMartin Kepplinger {
2160e8c08826SMartin Kepplinger struct v4l2_subdev *sd = i2c_get_clientdata(client);
2161e8c08826SMartin Kepplinger struct hi846 *hi846 = to_hi846(sd);
2162e8c08826SMartin Kepplinger
2163e8c08826SMartin Kepplinger v4l2_async_unregister_subdev(sd);
2164e8c08826SMartin Kepplinger media_entity_cleanup(&sd->entity);
2165e8c08826SMartin Kepplinger v4l2_ctrl_handler_free(sd->ctrl_handler);
2166e8c08826SMartin Kepplinger
2167e8c08826SMartin Kepplinger pm_runtime_disable(&client->dev);
2168e8c08826SMartin Kepplinger if (!pm_runtime_status_suspended(&client->dev))
2169e8c08826SMartin Kepplinger hi846_suspend(&client->dev);
2170e8c08826SMartin Kepplinger pm_runtime_set_suspended(&client->dev);
2171e8c08826SMartin Kepplinger
2172e8c08826SMartin Kepplinger mutex_destroy(&hi846->mutex);
2173e8c08826SMartin Kepplinger }
217469a18745SMartin Kepplinger
217569a18745SMartin Kepplinger static const struct dev_pm_ops hi846_pm_ops = {
217669a18745SMartin Kepplinger SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
217769a18745SMartin Kepplinger pm_runtime_force_resume)
217869a18745SMartin Kepplinger SET_RUNTIME_PM_OPS(hi846_suspend, hi846_resume, NULL)
2179e8c08826SMartin Kepplinger };
2180e8c08826SMartin Kepplinger
2181e8c08826SMartin Kepplinger static const struct of_device_id hi846_of_match[] = {
2182e8c08826SMartin Kepplinger { .compatible = "hynix,hi846", },
2183e8c08826SMartin Kepplinger {},
2184e8c08826SMartin Kepplinger };
2185e8c08826SMartin Kepplinger MODULE_DEVICE_TABLE(of, hi846_of_match);
2186e8c08826SMartin Kepplinger
2187e8c08826SMartin Kepplinger static struct i2c_driver hi846_i2c_driver = {
2188e8c08826SMartin Kepplinger .driver = {
2189e8c08826SMartin Kepplinger .name = "hi846",
219062456590SMartin Kepplinger .pm = &hi846_pm_ops,
2191e8c08826SMartin Kepplinger .of_match_table = hi846_of_match,
2192e8c08826SMartin Kepplinger },
2193e8c08826SMartin Kepplinger .probe = hi846_probe,
2194e8c08826SMartin Kepplinger .remove = hi846_remove,
2195e8c08826SMartin Kepplinger };
2196e8c08826SMartin Kepplinger
2197e8c08826SMartin Kepplinger module_i2c_driver(hi846_i2c_driver);
2198e8c08826SMartin Kepplinger
2199e8c08826SMartin Kepplinger MODULE_AUTHOR("Angus Ainslie <angus@akkea.ca>");
2200e8c08826SMartin Kepplinger MODULE_AUTHOR("Martin Kepplinger <martin.kepplinger@puri.sm>");
2201e8c08826SMartin Kepplinger MODULE_DESCRIPTION("Hynix HI846 sensor driver");
2202 MODULE_LICENSE("GPL v2");
2203