xref: /openbmc/linux/drivers/media/i2c/imx355.c (revision 252ae106)
1df0b5c4aSBingbu Cao // SPDX-License-Identifier: GPL-2.0
2df0b5c4aSBingbu Cao // Copyright (C) 2018 Intel Corporation
3df0b5c4aSBingbu Cao 
4df0b5c4aSBingbu Cao #include <asm/unaligned.h>
5df0b5c4aSBingbu Cao #include <linux/acpi.h>
6df0b5c4aSBingbu Cao #include <linux/i2c.h>
7df0b5c4aSBingbu Cao #include <linux/module.h>
8df0b5c4aSBingbu Cao #include <linux/pm_runtime.h>
9df0b5c4aSBingbu Cao #include <media/v4l2-ctrls.h>
10df0b5c4aSBingbu Cao #include <media/v4l2-device.h>
11df0b5c4aSBingbu Cao #include <media/v4l2-event.h>
12df0b5c4aSBingbu Cao #include <media/v4l2-fwnode.h>
13df0b5c4aSBingbu Cao 
14df0b5c4aSBingbu Cao #define IMX355_REG_MODE_SELECT		0x0100
15df0b5c4aSBingbu Cao #define IMX355_MODE_STANDBY		0x00
16df0b5c4aSBingbu Cao #define IMX355_MODE_STREAMING		0x01
17df0b5c4aSBingbu Cao 
18df0b5c4aSBingbu Cao /* Chip ID */
19df0b5c4aSBingbu Cao #define IMX355_REG_CHIP_ID		0x0016
20df0b5c4aSBingbu Cao #define IMX355_CHIP_ID			0x0355
21df0b5c4aSBingbu Cao 
22df0b5c4aSBingbu Cao /* V_TIMING internal */
23df0b5c4aSBingbu Cao #define IMX355_REG_FLL			0x0340
24df0b5c4aSBingbu Cao #define IMX355_FLL_MAX			0xffff
25df0b5c4aSBingbu Cao 
26df0b5c4aSBingbu Cao /* Exposure control */
27df0b5c4aSBingbu Cao #define IMX355_REG_EXPOSURE		0x0202
28df0b5c4aSBingbu Cao #define IMX355_EXPOSURE_MIN		1
29df0b5c4aSBingbu Cao #define IMX355_EXPOSURE_STEP		1
30df0b5c4aSBingbu Cao #define IMX355_EXPOSURE_DEFAULT		0x0282
31df0b5c4aSBingbu Cao 
32df0b5c4aSBingbu Cao /* Analog gain control */
33df0b5c4aSBingbu Cao #define IMX355_REG_ANALOG_GAIN		0x0204
34df0b5c4aSBingbu Cao #define IMX355_ANA_GAIN_MIN		0
35df0b5c4aSBingbu Cao #define IMX355_ANA_GAIN_MAX		960
36df0b5c4aSBingbu Cao #define IMX355_ANA_GAIN_STEP		1
37df0b5c4aSBingbu Cao #define IMX355_ANA_GAIN_DEFAULT		0
38df0b5c4aSBingbu Cao 
39df0b5c4aSBingbu Cao /* Digital gain control */
40df0b5c4aSBingbu Cao #define IMX355_REG_DPGA_USE_GLOBAL_GAIN	0x3070
41df0b5c4aSBingbu Cao #define IMX355_REG_DIG_GAIN_GLOBAL	0x020e
42df0b5c4aSBingbu Cao #define IMX355_DGTL_GAIN_MIN		256
43df0b5c4aSBingbu Cao #define IMX355_DGTL_GAIN_MAX		4095
44df0b5c4aSBingbu Cao #define IMX355_DGTL_GAIN_STEP		1
45df0b5c4aSBingbu Cao #define IMX355_DGTL_GAIN_DEFAULT	256
46df0b5c4aSBingbu Cao 
47df0b5c4aSBingbu Cao /* Test Pattern Control */
48df0b5c4aSBingbu Cao #define IMX355_REG_TEST_PATTERN		0x0600
49df0b5c4aSBingbu Cao #define IMX355_TEST_PATTERN_DISABLED		0
50df0b5c4aSBingbu Cao #define IMX355_TEST_PATTERN_SOLID_COLOR		1
51df0b5c4aSBingbu Cao #define IMX355_TEST_PATTERN_COLOR_BARS		2
52df0b5c4aSBingbu Cao #define IMX355_TEST_PATTERN_GRAY_COLOR_BARS	3
53df0b5c4aSBingbu Cao #define IMX355_TEST_PATTERN_PN9			4
54df0b5c4aSBingbu Cao 
55df0b5c4aSBingbu Cao /* Flip Control */
56df0b5c4aSBingbu Cao #define IMX355_REG_ORIENTATION		0x0101
57df0b5c4aSBingbu Cao 
58df0b5c4aSBingbu Cao /* default link frequency and external clock */
59df0b5c4aSBingbu Cao #define IMX355_LINK_FREQ_DEFAULT	360000000
60df0b5c4aSBingbu Cao #define IMX355_EXT_CLK			19200000
61df0b5c4aSBingbu Cao #define IMX355_LINK_FREQ_INDEX		0
62df0b5c4aSBingbu Cao 
63df0b5c4aSBingbu Cao struct imx355_reg {
64df0b5c4aSBingbu Cao 	u16 address;
65df0b5c4aSBingbu Cao 	u8 val;
66df0b5c4aSBingbu Cao };
67df0b5c4aSBingbu Cao 
68df0b5c4aSBingbu Cao struct imx355_reg_list {
69df0b5c4aSBingbu Cao 	u32 num_of_regs;
70df0b5c4aSBingbu Cao 	const struct imx355_reg *regs;
71df0b5c4aSBingbu Cao };
72df0b5c4aSBingbu Cao 
73df0b5c4aSBingbu Cao /* Mode : resolution and related config&values */
74df0b5c4aSBingbu Cao struct imx355_mode {
75df0b5c4aSBingbu Cao 	/* Frame width */
76df0b5c4aSBingbu Cao 	u32 width;
77df0b5c4aSBingbu Cao 	/* Frame height */
78df0b5c4aSBingbu Cao 	u32 height;
79df0b5c4aSBingbu Cao 
80df0b5c4aSBingbu Cao 	/* V-timing */
81df0b5c4aSBingbu Cao 	u32 fll_def;
82df0b5c4aSBingbu Cao 	u32 fll_min;
83df0b5c4aSBingbu Cao 
84df0b5c4aSBingbu Cao 	/* H-timing */
85df0b5c4aSBingbu Cao 	u32 llp;
86df0b5c4aSBingbu Cao 
87df0b5c4aSBingbu Cao 	/* index of link frequency */
88df0b5c4aSBingbu Cao 	u32 link_freq_index;
89df0b5c4aSBingbu Cao 
90df0b5c4aSBingbu Cao 	/* Default register values */
91df0b5c4aSBingbu Cao 	struct imx355_reg_list reg_list;
92df0b5c4aSBingbu Cao };
93df0b5c4aSBingbu Cao 
94df0b5c4aSBingbu Cao struct imx355_hwcfg {
95df0b5c4aSBingbu Cao 	u32 ext_clk;			/* sensor external clk */
96df0b5c4aSBingbu Cao 	s64 *link_freqs;		/* CSI-2 link frequencies */
97df0b5c4aSBingbu Cao 	unsigned int nr_of_link_freqs;
98df0b5c4aSBingbu Cao };
99df0b5c4aSBingbu Cao 
100df0b5c4aSBingbu Cao struct imx355 {
101df0b5c4aSBingbu Cao 	struct v4l2_subdev sd;
102df0b5c4aSBingbu Cao 	struct media_pad pad;
103df0b5c4aSBingbu Cao 
104df0b5c4aSBingbu Cao 	struct v4l2_ctrl_handler ctrl_handler;
105df0b5c4aSBingbu Cao 	/* V4L2 Controls */
106df0b5c4aSBingbu Cao 	struct v4l2_ctrl *link_freq;
107df0b5c4aSBingbu Cao 	struct v4l2_ctrl *pixel_rate;
108df0b5c4aSBingbu Cao 	struct v4l2_ctrl *vblank;
109df0b5c4aSBingbu Cao 	struct v4l2_ctrl *hblank;
110df0b5c4aSBingbu Cao 	struct v4l2_ctrl *exposure;
111df0b5c4aSBingbu Cao 	struct v4l2_ctrl *vflip;
112df0b5c4aSBingbu Cao 	struct v4l2_ctrl *hflip;
113df0b5c4aSBingbu Cao 
114df0b5c4aSBingbu Cao 	/* Current mode */
115df0b5c4aSBingbu Cao 	const struct imx355_mode *cur_mode;
116df0b5c4aSBingbu Cao 
117df0b5c4aSBingbu Cao 	struct imx355_hwcfg *hwcfg;
118df0b5c4aSBingbu Cao 	s64 link_def_freq;	/* CSI-2 link default frequency */
119df0b5c4aSBingbu Cao 
120df0b5c4aSBingbu Cao 	/*
121df0b5c4aSBingbu Cao 	 * Mutex for serialized access:
122df0b5c4aSBingbu Cao 	 * Protect sensor set pad format and start/stop streaming safely.
123df0b5c4aSBingbu Cao 	 * Protect access to sensor v4l2 controls.
124df0b5c4aSBingbu Cao 	 */
125df0b5c4aSBingbu Cao 	struct mutex mutex;
126df0b5c4aSBingbu Cao 
127df0b5c4aSBingbu Cao 	/* Streaming on/off */
128df0b5c4aSBingbu Cao 	bool streaming;
129df0b5c4aSBingbu Cao };
130df0b5c4aSBingbu Cao 
131df0b5c4aSBingbu Cao static const struct imx355_reg imx355_global_regs[] = {
132df0b5c4aSBingbu Cao 	{ 0x0136, 0x13 },
133df0b5c4aSBingbu Cao 	{ 0x0137, 0x33 },
134df0b5c4aSBingbu Cao 	{ 0x304e, 0x03 },
135df0b5c4aSBingbu Cao 	{ 0x4348, 0x16 },
136df0b5c4aSBingbu Cao 	{ 0x4350, 0x19 },
137df0b5c4aSBingbu Cao 	{ 0x4408, 0x0a },
138df0b5c4aSBingbu Cao 	{ 0x440c, 0x0b },
139df0b5c4aSBingbu Cao 	{ 0x4411, 0x5f },
140df0b5c4aSBingbu Cao 	{ 0x4412, 0x2c },
141df0b5c4aSBingbu Cao 	{ 0x4623, 0x00 },
142df0b5c4aSBingbu Cao 	{ 0x462c, 0x0f },
143df0b5c4aSBingbu Cao 	{ 0x462d, 0x00 },
144df0b5c4aSBingbu Cao 	{ 0x462e, 0x00 },
145df0b5c4aSBingbu Cao 	{ 0x4684, 0x54 },
146df0b5c4aSBingbu Cao 	{ 0x480a, 0x07 },
147df0b5c4aSBingbu Cao 	{ 0x4908, 0x07 },
148df0b5c4aSBingbu Cao 	{ 0x4909, 0x07 },
149df0b5c4aSBingbu Cao 	{ 0x490d, 0x0a },
150df0b5c4aSBingbu Cao 	{ 0x491e, 0x0f },
151df0b5c4aSBingbu Cao 	{ 0x4921, 0x06 },
152df0b5c4aSBingbu Cao 	{ 0x4923, 0x28 },
153df0b5c4aSBingbu Cao 	{ 0x4924, 0x28 },
154df0b5c4aSBingbu Cao 	{ 0x4925, 0x29 },
155df0b5c4aSBingbu Cao 	{ 0x4926, 0x29 },
156df0b5c4aSBingbu Cao 	{ 0x4927, 0x1f },
157df0b5c4aSBingbu Cao 	{ 0x4928, 0x20 },
158df0b5c4aSBingbu Cao 	{ 0x4929, 0x20 },
159df0b5c4aSBingbu Cao 	{ 0x492a, 0x20 },
160df0b5c4aSBingbu Cao 	{ 0x492c, 0x05 },
161df0b5c4aSBingbu Cao 	{ 0x492d, 0x06 },
162df0b5c4aSBingbu Cao 	{ 0x492e, 0x06 },
163df0b5c4aSBingbu Cao 	{ 0x492f, 0x06 },
164df0b5c4aSBingbu Cao 	{ 0x4930, 0x03 },
165df0b5c4aSBingbu Cao 	{ 0x4931, 0x04 },
166df0b5c4aSBingbu Cao 	{ 0x4932, 0x04 },
167df0b5c4aSBingbu Cao 	{ 0x4933, 0x05 },
168df0b5c4aSBingbu Cao 	{ 0x595e, 0x01 },
169df0b5c4aSBingbu Cao 	{ 0x5963, 0x01 },
170df0b5c4aSBingbu Cao 	{ 0x3030, 0x01 },
171df0b5c4aSBingbu Cao 	{ 0x3031, 0x01 },
172df0b5c4aSBingbu Cao 	{ 0x3045, 0x01 },
173df0b5c4aSBingbu Cao 	{ 0x4010, 0x00 },
174df0b5c4aSBingbu Cao 	{ 0x4011, 0x00 },
175df0b5c4aSBingbu Cao 	{ 0x4012, 0x00 },
176df0b5c4aSBingbu Cao 	{ 0x4013, 0x01 },
177df0b5c4aSBingbu Cao 	{ 0x68a8, 0xfe },
178df0b5c4aSBingbu Cao 	{ 0x68a9, 0xff },
179df0b5c4aSBingbu Cao 	{ 0x6888, 0x00 },
180df0b5c4aSBingbu Cao 	{ 0x6889, 0x00 },
181df0b5c4aSBingbu Cao 	{ 0x68b0, 0x00 },
182df0b5c4aSBingbu Cao 	{ 0x3058, 0x00 },
183df0b5c4aSBingbu Cao 	{ 0x305a, 0x00 },
184df0b5c4aSBingbu Cao };
185df0b5c4aSBingbu Cao 
186df0b5c4aSBingbu Cao static const struct imx355_reg_list imx355_global_setting = {
187df0b5c4aSBingbu Cao 	.num_of_regs = ARRAY_SIZE(imx355_global_regs),
188df0b5c4aSBingbu Cao 	.regs = imx355_global_regs,
189df0b5c4aSBingbu Cao };
190df0b5c4aSBingbu Cao 
191df0b5c4aSBingbu Cao static const struct imx355_reg mode_3268x2448_regs[] = {
192df0b5c4aSBingbu Cao 	{ 0x0112, 0x0a },
193df0b5c4aSBingbu Cao 	{ 0x0113, 0x0a },
194df0b5c4aSBingbu Cao 	{ 0x0114, 0x03 },
195df0b5c4aSBingbu Cao 	{ 0x0342, 0x0e },
196df0b5c4aSBingbu Cao 	{ 0x0343, 0x58 },
197df0b5c4aSBingbu Cao 	{ 0x0340, 0x0a },
198df0b5c4aSBingbu Cao 	{ 0x0341, 0x37 },
199df0b5c4aSBingbu Cao 	{ 0x0344, 0x00 },
200df0b5c4aSBingbu Cao 	{ 0x0345, 0x08 },
201df0b5c4aSBingbu Cao 	{ 0x0346, 0x00 },
202df0b5c4aSBingbu Cao 	{ 0x0347, 0x08 },
203df0b5c4aSBingbu Cao 	{ 0x0348, 0x0c },
204df0b5c4aSBingbu Cao 	{ 0x0349, 0xcb },
205df0b5c4aSBingbu Cao 	{ 0x034a, 0x09 },
206df0b5c4aSBingbu Cao 	{ 0x034b, 0x97 },
207df0b5c4aSBingbu Cao 	{ 0x0220, 0x00 },
208df0b5c4aSBingbu Cao 	{ 0x0222, 0x01 },
209df0b5c4aSBingbu Cao 	{ 0x0900, 0x00 },
210df0b5c4aSBingbu Cao 	{ 0x0901, 0x11 },
211df0b5c4aSBingbu Cao 	{ 0x0902, 0x00 },
212df0b5c4aSBingbu Cao 	{ 0x034c, 0x0c },
213df0b5c4aSBingbu Cao 	{ 0x034d, 0xc4 },
214df0b5c4aSBingbu Cao 	{ 0x034e, 0x09 },
215df0b5c4aSBingbu Cao 	{ 0x034f, 0x90 },
216df0b5c4aSBingbu Cao 	{ 0x0301, 0x05 },
217df0b5c4aSBingbu Cao 	{ 0x0303, 0x01 },
218df0b5c4aSBingbu Cao 	{ 0x0305, 0x02 },
219df0b5c4aSBingbu Cao 	{ 0x0306, 0x00 },
220df0b5c4aSBingbu Cao 	{ 0x0307, 0x78 },
221df0b5c4aSBingbu Cao 	{ 0x030b, 0x01 },
222df0b5c4aSBingbu Cao 	{ 0x030d, 0x02 },
223df0b5c4aSBingbu Cao 	{ 0x030e, 0x00 },
224df0b5c4aSBingbu Cao 	{ 0x030f, 0x4b },
225df0b5c4aSBingbu Cao 	{ 0x0310, 0x00 },
226df0b5c4aSBingbu Cao 	{ 0x0700, 0x00 },
227df0b5c4aSBingbu Cao 	{ 0x0701, 0x10 },
228df0b5c4aSBingbu Cao 	{ 0x0820, 0x0b },
229df0b5c4aSBingbu Cao 	{ 0x0821, 0x40 },
230df0b5c4aSBingbu Cao 	{ 0x3088, 0x04 },
231df0b5c4aSBingbu Cao 	{ 0x6813, 0x02 },
232df0b5c4aSBingbu Cao 	{ 0x6835, 0x07 },
233df0b5c4aSBingbu Cao 	{ 0x6836, 0x01 },
234df0b5c4aSBingbu Cao 	{ 0x6837, 0x04 },
235df0b5c4aSBingbu Cao 	{ 0x684d, 0x07 },
236df0b5c4aSBingbu Cao 	{ 0x684e, 0x01 },
237df0b5c4aSBingbu Cao 	{ 0x684f, 0x04 },
238df0b5c4aSBingbu Cao };
239df0b5c4aSBingbu Cao 
240df0b5c4aSBingbu Cao static const struct imx355_reg mode_3264x2448_regs[] = {
241df0b5c4aSBingbu Cao 	{ 0x0112, 0x0a },
242df0b5c4aSBingbu Cao 	{ 0x0113, 0x0a },
243df0b5c4aSBingbu Cao 	{ 0x0114, 0x03 },
244df0b5c4aSBingbu Cao 	{ 0x0342, 0x0e },
245df0b5c4aSBingbu Cao 	{ 0x0343, 0x58 },
246df0b5c4aSBingbu Cao 	{ 0x0340, 0x0a },
247df0b5c4aSBingbu Cao 	{ 0x0341, 0x37 },
248df0b5c4aSBingbu Cao 	{ 0x0344, 0x00 },
249df0b5c4aSBingbu Cao 	{ 0x0345, 0x08 },
250df0b5c4aSBingbu Cao 	{ 0x0346, 0x00 },
251df0b5c4aSBingbu Cao 	{ 0x0347, 0x08 },
252df0b5c4aSBingbu Cao 	{ 0x0348, 0x0c },
253df0b5c4aSBingbu Cao 	{ 0x0349, 0xc7 },
254df0b5c4aSBingbu Cao 	{ 0x034a, 0x09 },
255df0b5c4aSBingbu Cao 	{ 0x034b, 0x97 },
256df0b5c4aSBingbu Cao 	{ 0x0220, 0x00 },
257df0b5c4aSBingbu Cao 	{ 0x0222, 0x01 },
258df0b5c4aSBingbu Cao 	{ 0x0900, 0x00 },
259df0b5c4aSBingbu Cao 	{ 0x0901, 0x11 },
260df0b5c4aSBingbu Cao 	{ 0x0902, 0x00 },
261df0b5c4aSBingbu Cao 	{ 0x034c, 0x0c },
262df0b5c4aSBingbu Cao 	{ 0x034d, 0xc0 },
263df0b5c4aSBingbu Cao 	{ 0x034e, 0x09 },
264df0b5c4aSBingbu Cao 	{ 0x034f, 0x90 },
265df0b5c4aSBingbu Cao 	{ 0x0301, 0x05 },
266df0b5c4aSBingbu Cao 	{ 0x0303, 0x01 },
267df0b5c4aSBingbu Cao 	{ 0x0305, 0x02 },
268df0b5c4aSBingbu Cao 	{ 0x0306, 0x00 },
269df0b5c4aSBingbu Cao 	{ 0x0307, 0x78 },
270df0b5c4aSBingbu Cao 	{ 0x030b, 0x01 },
271df0b5c4aSBingbu Cao 	{ 0x030d, 0x02 },
272df0b5c4aSBingbu Cao 	{ 0x030e, 0x00 },
273df0b5c4aSBingbu Cao 	{ 0x030f, 0x4b },
274df0b5c4aSBingbu Cao 	{ 0x0310, 0x00 },
275df0b5c4aSBingbu Cao 	{ 0x0700, 0x00 },
276df0b5c4aSBingbu Cao 	{ 0x0701, 0x10 },
277df0b5c4aSBingbu Cao 	{ 0x0820, 0x0b },
278df0b5c4aSBingbu Cao 	{ 0x0821, 0x40 },
279df0b5c4aSBingbu Cao 	{ 0x3088, 0x04 },
280df0b5c4aSBingbu Cao 	{ 0x6813, 0x02 },
281df0b5c4aSBingbu Cao 	{ 0x6835, 0x07 },
282df0b5c4aSBingbu Cao 	{ 0x6836, 0x01 },
283df0b5c4aSBingbu Cao 	{ 0x6837, 0x04 },
284df0b5c4aSBingbu Cao 	{ 0x684d, 0x07 },
285df0b5c4aSBingbu Cao 	{ 0x684e, 0x01 },
286df0b5c4aSBingbu Cao 	{ 0x684f, 0x04 },
287df0b5c4aSBingbu Cao };
288df0b5c4aSBingbu Cao 
289df0b5c4aSBingbu Cao static const struct imx355_reg mode_3280x2464_regs[] = {
290df0b5c4aSBingbu Cao 	{ 0x0112, 0x0a },
291df0b5c4aSBingbu Cao 	{ 0x0113, 0x0a },
292df0b5c4aSBingbu Cao 	{ 0x0114, 0x03 },
293df0b5c4aSBingbu Cao 	{ 0x0342, 0x0e },
294df0b5c4aSBingbu Cao 	{ 0x0343, 0x58 },
295df0b5c4aSBingbu Cao 	{ 0x0340, 0x0a },
296df0b5c4aSBingbu Cao 	{ 0x0341, 0x37 },
297df0b5c4aSBingbu Cao 	{ 0x0344, 0x00 },
298df0b5c4aSBingbu Cao 	{ 0x0345, 0x00 },
299df0b5c4aSBingbu Cao 	{ 0x0346, 0x00 },
300df0b5c4aSBingbu Cao 	{ 0x0347, 0x00 },
301df0b5c4aSBingbu Cao 	{ 0x0348, 0x0c },
302df0b5c4aSBingbu Cao 	{ 0x0349, 0xcf },
303df0b5c4aSBingbu Cao 	{ 0x034a, 0x09 },
304df0b5c4aSBingbu Cao 	{ 0x034b, 0x9f },
305df0b5c4aSBingbu Cao 	{ 0x0220, 0x00 },
306df0b5c4aSBingbu Cao 	{ 0x0222, 0x01 },
307df0b5c4aSBingbu Cao 	{ 0x0900, 0x00 },
308df0b5c4aSBingbu Cao 	{ 0x0901, 0x11 },
309df0b5c4aSBingbu Cao 	{ 0x0902, 0x00 },
310df0b5c4aSBingbu Cao 	{ 0x034c, 0x0c },
311df0b5c4aSBingbu Cao 	{ 0x034d, 0xd0 },
312df0b5c4aSBingbu Cao 	{ 0x034e, 0x09 },
313df0b5c4aSBingbu Cao 	{ 0x034f, 0xa0 },
314df0b5c4aSBingbu Cao 	{ 0x0301, 0x05 },
315df0b5c4aSBingbu Cao 	{ 0x0303, 0x01 },
316df0b5c4aSBingbu Cao 	{ 0x0305, 0x02 },
317df0b5c4aSBingbu Cao 	{ 0x0306, 0x00 },
318df0b5c4aSBingbu Cao 	{ 0x0307, 0x78 },
319df0b5c4aSBingbu Cao 	{ 0x030b, 0x01 },
320df0b5c4aSBingbu Cao 	{ 0x030d, 0x02 },
321df0b5c4aSBingbu Cao 	{ 0x030e, 0x00 },
322df0b5c4aSBingbu Cao 	{ 0x030f, 0x4b },
323df0b5c4aSBingbu Cao 	{ 0x0310, 0x00 },
324df0b5c4aSBingbu Cao 	{ 0x0700, 0x00 },
325df0b5c4aSBingbu Cao 	{ 0x0701, 0x10 },
326df0b5c4aSBingbu Cao 	{ 0x0820, 0x0b },
327df0b5c4aSBingbu Cao 	{ 0x0821, 0x40 },
328df0b5c4aSBingbu Cao 	{ 0x3088, 0x04 },
329df0b5c4aSBingbu Cao 	{ 0x6813, 0x02 },
330df0b5c4aSBingbu Cao 	{ 0x6835, 0x07 },
331df0b5c4aSBingbu Cao 	{ 0x6836, 0x01 },
332df0b5c4aSBingbu Cao 	{ 0x6837, 0x04 },
333df0b5c4aSBingbu Cao 	{ 0x684d, 0x07 },
334df0b5c4aSBingbu Cao 	{ 0x684e, 0x01 },
335df0b5c4aSBingbu Cao 	{ 0x684f, 0x04 },
336df0b5c4aSBingbu Cao };
337df0b5c4aSBingbu Cao 
338df0b5c4aSBingbu Cao static const struct imx355_reg mode_1940x1096_regs[] = {
339df0b5c4aSBingbu Cao 	{ 0x0112, 0x0a },
340df0b5c4aSBingbu Cao 	{ 0x0113, 0x0a },
341df0b5c4aSBingbu Cao 	{ 0x0114, 0x03 },
342df0b5c4aSBingbu Cao 	{ 0x0342, 0x0e },
343df0b5c4aSBingbu Cao 	{ 0x0343, 0x58 },
344df0b5c4aSBingbu Cao 	{ 0x0340, 0x05 },
345df0b5c4aSBingbu Cao 	{ 0x0341, 0x1a },
346df0b5c4aSBingbu Cao 	{ 0x0344, 0x02 },
347df0b5c4aSBingbu Cao 	{ 0x0345, 0xa0 },
348df0b5c4aSBingbu Cao 	{ 0x0346, 0x02 },
349df0b5c4aSBingbu Cao 	{ 0x0347, 0xac },
350df0b5c4aSBingbu Cao 	{ 0x0348, 0x0a },
351df0b5c4aSBingbu Cao 	{ 0x0349, 0x33 },
352df0b5c4aSBingbu Cao 	{ 0x034a, 0x06 },
353df0b5c4aSBingbu Cao 	{ 0x034b, 0xf3 },
354df0b5c4aSBingbu Cao 	{ 0x0220, 0x00 },
355df0b5c4aSBingbu Cao 	{ 0x0222, 0x01 },
356df0b5c4aSBingbu Cao 	{ 0x0900, 0x00 },
357df0b5c4aSBingbu Cao 	{ 0x0901, 0x11 },
358df0b5c4aSBingbu Cao 	{ 0x0902, 0x00 },
359df0b5c4aSBingbu Cao 	{ 0x034c, 0x07 },
360df0b5c4aSBingbu Cao 	{ 0x034d, 0x94 },
361df0b5c4aSBingbu Cao 	{ 0x034e, 0x04 },
362df0b5c4aSBingbu Cao 	{ 0x034f, 0x48 },
363df0b5c4aSBingbu Cao 	{ 0x0301, 0x05 },
364df0b5c4aSBingbu Cao 	{ 0x0303, 0x01 },
365df0b5c4aSBingbu Cao 	{ 0x0305, 0x02 },
366df0b5c4aSBingbu Cao 	{ 0x0306, 0x00 },
367df0b5c4aSBingbu Cao 	{ 0x0307, 0x78 },
368df0b5c4aSBingbu Cao 	{ 0x030b, 0x01 },
369df0b5c4aSBingbu Cao 	{ 0x030d, 0x02 },
370df0b5c4aSBingbu Cao 	{ 0x030e, 0x00 },
371df0b5c4aSBingbu Cao 	{ 0x030f, 0x4b },
372df0b5c4aSBingbu Cao 	{ 0x0310, 0x00 },
373df0b5c4aSBingbu Cao 	{ 0x0700, 0x00 },
374df0b5c4aSBingbu Cao 	{ 0x0701, 0x10 },
375df0b5c4aSBingbu Cao 	{ 0x0820, 0x0b },
376df0b5c4aSBingbu Cao 	{ 0x0821, 0x40 },
377df0b5c4aSBingbu Cao 	{ 0x3088, 0x04 },
378df0b5c4aSBingbu Cao 	{ 0x6813, 0x02 },
379df0b5c4aSBingbu Cao 	{ 0x6835, 0x07 },
380df0b5c4aSBingbu Cao 	{ 0x6836, 0x01 },
381df0b5c4aSBingbu Cao 	{ 0x6837, 0x04 },
382df0b5c4aSBingbu Cao 	{ 0x684d, 0x07 },
383df0b5c4aSBingbu Cao 	{ 0x684e, 0x01 },
384df0b5c4aSBingbu Cao 	{ 0x684f, 0x04 },
385df0b5c4aSBingbu Cao };
386df0b5c4aSBingbu Cao 
387df0b5c4aSBingbu Cao static const struct imx355_reg mode_1936x1096_regs[] = {
388df0b5c4aSBingbu Cao 	{ 0x0112, 0x0a },
389df0b5c4aSBingbu Cao 	{ 0x0113, 0x0a },
390df0b5c4aSBingbu Cao 	{ 0x0114, 0x03 },
391df0b5c4aSBingbu Cao 	{ 0x0342, 0x0e },
392df0b5c4aSBingbu Cao 	{ 0x0343, 0x58 },
393df0b5c4aSBingbu Cao 	{ 0x0340, 0x05 },
394df0b5c4aSBingbu Cao 	{ 0x0341, 0x1a },
395df0b5c4aSBingbu Cao 	{ 0x0344, 0x02 },
396df0b5c4aSBingbu Cao 	{ 0x0345, 0xa0 },
397df0b5c4aSBingbu Cao 	{ 0x0346, 0x02 },
398df0b5c4aSBingbu Cao 	{ 0x0347, 0xac },
399df0b5c4aSBingbu Cao 	{ 0x0348, 0x0a },
400df0b5c4aSBingbu Cao 	{ 0x0349, 0x2f },
401df0b5c4aSBingbu Cao 	{ 0x034a, 0x06 },
402df0b5c4aSBingbu Cao 	{ 0x034b, 0xf3 },
403df0b5c4aSBingbu Cao 	{ 0x0220, 0x00 },
404df0b5c4aSBingbu Cao 	{ 0x0222, 0x01 },
405df0b5c4aSBingbu Cao 	{ 0x0900, 0x00 },
406df0b5c4aSBingbu Cao 	{ 0x0901, 0x11 },
407df0b5c4aSBingbu Cao 	{ 0x0902, 0x00 },
408df0b5c4aSBingbu Cao 	{ 0x034c, 0x07 },
409df0b5c4aSBingbu Cao 	{ 0x034d, 0x90 },
410df0b5c4aSBingbu Cao 	{ 0x034e, 0x04 },
411df0b5c4aSBingbu Cao 	{ 0x034f, 0x48 },
412df0b5c4aSBingbu Cao 	{ 0x0301, 0x05 },
413df0b5c4aSBingbu Cao 	{ 0x0303, 0x01 },
414df0b5c4aSBingbu Cao 	{ 0x0305, 0x02 },
415df0b5c4aSBingbu Cao 	{ 0x0306, 0x00 },
416df0b5c4aSBingbu Cao 	{ 0x0307, 0x78 },
417df0b5c4aSBingbu Cao 	{ 0x030b, 0x01 },
418df0b5c4aSBingbu Cao 	{ 0x030d, 0x02 },
419df0b5c4aSBingbu Cao 	{ 0x030e, 0x00 },
420df0b5c4aSBingbu Cao 	{ 0x030f, 0x4b },
421df0b5c4aSBingbu Cao 	{ 0x0310, 0x00 },
422df0b5c4aSBingbu Cao 	{ 0x0700, 0x00 },
423df0b5c4aSBingbu Cao 	{ 0x0701, 0x10 },
424df0b5c4aSBingbu Cao 	{ 0x0820, 0x0b },
425df0b5c4aSBingbu Cao 	{ 0x0821, 0x40 },
426df0b5c4aSBingbu Cao 	{ 0x3088, 0x04 },
427df0b5c4aSBingbu Cao 	{ 0x6813, 0x02 },
428df0b5c4aSBingbu Cao 	{ 0x6835, 0x07 },
429df0b5c4aSBingbu Cao 	{ 0x6836, 0x01 },
430df0b5c4aSBingbu Cao 	{ 0x6837, 0x04 },
431df0b5c4aSBingbu Cao 	{ 0x684d, 0x07 },
432df0b5c4aSBingbu Cao 	{ 0x684e, 0x01 },
433df0b5c4aSBingbu Cao 	{ 0x684f, 0x04 },
434df0b5c4aSBingbu Cao };
435df0b5c4aSBingbu Cao 
436df0b5c4aSBingbu Cao static const struct imx355_reg mode_1924x1080_regs[] = {
437df0b5c4aSBingbu Cao 	{ 0x0112, 0x0a },
438df0b5c4aSBingbu Cao 	{ 0x0113, 0x0a },
439df0b5c4aSBingbu Cao 	{ 0x0114, 0x03 },
440df0b5c4aSBingbu Cao 	{ 0x0342, 0x0e },
441df0b5c4aSBingbu Cao 	{ 0x0343, 0x58 },
442df0b5c4aSBingbu Cao 	{ 0x0340, 0x05 },
443df0b5c4aSBingbu Cao 	{ 0x0341, 0x1a },
444df0b5c4aSBingbu Cao 	{ 0x0344, 0x02 },
445df0b5c4aSBingbu Cao 	{ 0x0345, 0xa8 },
446df0b5c4aSBingbu Cao 	{ 0x0346, 0x02 },
447df0b5c4aSBingbu Cao 	{ 0x0347, 0xb4 },
448df0b5c4aSBingbu Cao 	{ 0x0348, 0x0a },
449df0b5c4aSBingbu Cao 	{ 0x0349, 0x2b },
450df0b5c4aSBingbu Cao 	{ 0x034a, 0x06 },
451df0b5c4aSBingbu Cao 	{ 0x034b, 0xeb },
452df0b5c4aSBingbu Cao 	{ 0x0220, 0x00 },
453df0b5c4aSBingbu Cao 	{ 0x0222, 0x01 },
454df0b5c4aSBingbu Cao 	{ 0x0900, 0x00 },
455df0b5c4aSBingbu Cao 	{ 0x0901, 0x11 },
456df0b5c4aSBingbu Cao 	{ 0x0902, 0x00 },
457df0b5c4aSBingbu Cao 	{ 0x034c, 0x07 },
458df0b5c4aSBingbu Cao 	{ 0x034d, 0x84 },
459df0b5c4aSBingbu Cao 	{ 0x034e, 0x04 },
460df0b5c4aSBingbu Cao 	{ 0x034f, 0x38 },
461df0b5c4aSBingbu Cao 	{ 0x0301, 0x05 },
462df0b5c4aSBingbu Cao 	{ 0x0303, 0x01 },
463df0b5c4aSBingbu Cao 	{ 0x0305, 0x02 },
464df0b5c4aSBingbu Cao 	{ 0x0306, 0x00 },
465df0b5c4aSBingbu Cao 	{ 0x0307, 0x78 },
466df0b5c4aSBingbu Cao 	{ 0x030b, 0x01 },
467df0b5c4aSBingbu Cao 	{ 0x030d, 0x02 },
468df0b5c4aSBingbu Cao 	{ 0x030e, 0x00 },
469df0b5c4aSBingbu Cao 	{ 0x030f, 0x4b },
470df0b5c4aSBingbu Cao 	{ 0x0310, 0x00 },
471df0b5c4aSBingbu Cao 	{ 0x0700, 0x00 },
472df0b5c4aSBingbu Cao 	{ 0x0701, 0x10 },
473df0b5c4aSBingbu Cao 	{ 0x0820, 0x0b },
474df0b5c4aSBingbu Cao 	{ 0x0821, 0x40 },
475df0b5c4aSBingbu Cao 	{ 0x3088, 0x04 },
476df0b5c4aSBingbu Cao 	{ 0x6813, 0x02 },
477df0b5c4aSBingbu Cao 	{ 0x6835, 0x07 },
478df0b5c4aSBingbu Cao 	{ 0x6836, 0x01 },
479df0b5c4aSBingbu Cao 	{ 0x6837, 0x04 },
480df0b5c4aSBingbu Cao 	{ 0x684d, 0x07 },
481df0b5c4aSBingbu Cao 	{ 0x684e, 0x01 },
482df0b5c4aSBingbu Cao 	{ 0x684f, 0x04 },
483df0b5c4aSBingbu Cao };
484df0b5c4aSBingbu Cao 
485df0b5c4aSBingbu Cao static const struct imx355_reg mode_1920x1080_regs[] = {
486df0b5c4aSBingbu Cao 	{ 0x0112, 0x0a },
487df0b5c4aSBingbu Cao 	{ 0x0113, 0x0a },
488df0b5c4aSBingbu Cao 	{ 0x0114, 0x03 },
489df0b5c4aSBingbu Cao 	{ 0x0342, 0x0e },
490df0b5c4aSBingbu Cao 	{ 0x0343, 0x58 },
491df0b5c4aSBingbu Cao 	{ 0x0340, 0x05 },
492df0b5c4aSBingbu Cao 	{ 0x0341, 0x1a },
493df0b5c4aSBingbu Cao 	{ 0x0344, 0x02 },
494df0b5c4aSBingbu Cao 	{ 0x0345, 0xa8 },
495df0b5c4aSBingbu Cao 	{ 0x0346, 0x02 },
496df0b5c4aSBingbu Cao 	{ 0x0347, 0xb4 },
497df0b5c4aSBingbu Cao 	{ 0x0348, 0x0a },
498df0b5c4aSBingbu Cao 	{ 0x0349, 0x27 },
499df0b5c4aSBingbu Cao 	{ 0x034a, 0x06 },
500df0b5c4aSBingbu Cao 	{ 0x034b, 0xeb },
501df0b5c4aSBingbu Cao 	{ 0x0220, 0x00 },
502df0b5c4aSBingbu Cao 	{ 0x0222, 0x01 },
503df0b5c4aSBingbu Cao 	{ 0x0900, 0x00 },
504df0b5c4aSBingbu Cao 	{ 0x0901, 0x11 },
505df0b5c4aSBingbu Cao 	{ 0x0902, 0x00 },
506df0b5c4aSBingbu Cao 	{ 0x034c, 0x07 },
507df0b5c4aSBingbu Cao 	{ 0x034d, 0x80 },
508df0b5c4aSBingbu Cao 	{ 0x034e, 0x04 },
509df0b5c4aSBingbu Cao 	{ 0x034f, 0x38 },
510df0b5c4aSBingbu Cao 	{ 0x0301, 0x05 },
511df0b5c4aSBingbu Cao 	{ 0x0303, 0x01 },
512df0b5c4aSBingbu Cao 	{ 0x0305, 0x02 },
513df0b5c4aSBingbu Cao 	{ 0x0306, 0x00 },
514df0b5c4aSBingbu Cao 	{ 0x0307, 0x78 },
515df0b5c4aSBingbu Cao 	{ 0x030b, 0x01 },
516df0b5c4aSBingbu Cao 	{ 0x030d, 0x02 },
517df0b5c4aSBingbu Cao 	{ 0x030e, 0x00 },
518df0b5c4aSBingbu Cao 	{ 0x030f, 0x4b },
519df0b5c4aSBingbu Cao 	{ 0x0310, 0x00 },
520df0b5c4aSBingbu Cao 	{ 0x0700, 0x00 },
521df0b5c4aSBingbu Cao 	{ 0x0701, 0x10 },
522df0b5c4aSBingbu Cao 	{ 0x0820, 0x0b },
523df0b5c4aSBingbu Cao 	{ 0x0821, 0x40 },
524df0b5c4aSBingbu Cao 	{ 0x3088, 0x04 },
525df0b5c4aSBingbu Cao 	{ 0x6813, 0x02 },
526df0b5c4aSBingbu Cao 	{ 0x6835, 0x07 },
527df0b5c4aSBingbu Cao 	{ 0x6836, 0x01 },
528df0b5c4aSBingbu Cao 	{ 0x6837, 0x04 },
529df0b5c4aSBingbu Cao 	{ 0x684d, 0x07 },
530df0b5c4aSBingbu Cao 	{ 0x684e, 0x01 },
531df0b5c4aSBingbu Cao 	{ 0x684f, 0x04 },
532df0b5c4aSBingbu Cao };
533df0b5c4aSBingbu Cao 
534df0b5c4aSBingbu Cao static const struct imx355_reg mode_1640x1232_regs[] = {
535df0b5c4aSBingbu Cao 	{ 0x0112, 0x0a },
536df0b5c4aSBingbu Cao 	{ 0x0113, 0x0a },
537df0b5c4aSBingbu Cao 	{ 0x0114, 0x03 },
538df0b5c4aSBingbu Cao 	{ 0x0342, 0x07 },
539df0b5c4aSBingbu Cao 	{ 0x0343, 0x2c },
540df0b5c4aSBingbu Cao 	{ 0x0340, 0x05 },
541df0b5c4aSBingbu Cao 	{ 0x0341, 0x1a },
542df0b5c4aSBingbu Cao 	{ 0x0344, 0x00 },
543df0b5c4aSBingbu Cao 	{ 0x0345, 0x00 },
544df0b5c4aSBingbu Cao 	{ 0x0346, 0x00 },
545df0b5c4aSBingbu Cao 	{ 0x0347, 0x00 },
546df0b5c4aSBingbu Cao 	{ 0x0348, 0x0c },
547df0b5c4aSBingbu Cao 	{ 0x0349, 0xcf },
548df0b5c4aSBingbu Cao 	{ 0x034a, 0x09 },
549df0b5c4aSBingbu Cao 	{ 0x034b, 0x9f },
550df0b5c4aSBingbu Cao 	{ 0x0220, 0x00 },
551df0b5c4aSBingbu Cao 	{ 0x0222, 0x01 },
552df0b5c4aSBingbu Cao 	{ 0x0900, 0x01 },
553df0b5c4aSBingbu Cao 	{ 0x0901, 0x22 },
554df0b5c4aSBingbu Cao 	{ 0x0902, 0x00 },
555df0b5c4aSBingbu Cao 	{ 0x034c, 0x06 },
556df0b5c4aSBingbu Cao 	{ 0x034d, 0x68 },
557df0b5c4aSBingbu Cao 	{ 0x034e, 0x04 },
558df0b5c4aSBingbu Cao 	{ 0x034f, 0xd0 },
559df0b5c4aSBingbu Cao 	{ 0x0301, 0x05 },
560df0b5c4aSBingbu Cao 	{ 0x0303, 0x01 },
561df0b5c4aSBingbu Cao 	{ 0x0305, 0x02 },
562df0b5c4aSBingbu Cao 	{ 0x0306, 0x00 },
563df0b5c4aSBingbu Cao 	{ 0x0307, 0x78 },
564df0b5c4aSBingbu Cao 	{ 0x030b, 0x01 },
565df0b5c4aSBingbu Cao 	{ 0x030d, 0x02 },
566df0b5c4aSBingbu Cao 	{ 0x030e, 0x00 },
567df0b5c4aSBingbu Cao 	{ 0x030f, 0x4b },
568df0b5c4aSBingbu Cao 	{ 0x0310, 0x00 },
569df0b5c4aSBingbu Cao 	{ 0x0700, 0x00 },
570df0b5c4aSBingbu Cao 	{ 0x0701, 0x10 },
571df0b5c4aSBingbu Cao 	{ 0x0820, 0x0b },
572df0b5c4aSBingbu Cao 	{ 0x0821, 0x40 },
573df0b5c4aSBingbu Cao 	{ 0x3088, 0x04 },
574df0b5c4aSBingbu Cao 	{ 0x6813, 0x02 },
575df0b5c4aSBingbu Cao 	{ 0x6835, 0x07 },
576df0b5c4aSBingbu Cao 	{ 0x6836, 0x01 },
577df0b5c4aSBingbu Cao 	{ 0x6837, 0x04 },
578df0b5c4aSBingbu Cao 	{ 0x684d, 0x07 },
579df0b5c4aSBingbu Cao 	{ 0x684e, 0x01 },
580df0b5c4aSBingbu Cao 	{ 0x684f, 0x04 },
581df0b5c4aSBingbu Cao };
582df0b5c4aSBingbu Cao 
583df0b5c4aSBingbu Cao static const struct imx355_reg mode_1640x922_regs[] = {
584df0b5c4aSBingbu Cao 	{ 0x0112, 0x0a },
585df0b5c4aSBingbu Cao 	{ 0x0113, 0x0a },
586df0b5c4aSBingbu Cao 	{ 0x0114, 0x03 },
587df0b5c4aSBingbu Cao 	{ 0x0342, 0x07 },
588df0b5c4aSBingbu Cao 	{ 0x0343, 0x2c },
589df0b5c4aSBingbu Cao 	{ 0x0340, 0x05 },
590df0b5c4aSBingbu Cao 	{ 0x0341, 0x1a },
591df0b5c4aSBingbu Cao 	{ 0x0344, 0x00 },
592df0b5c4aSBingbu Cao 	{ 0x0345, 0x00 },
593df0b5c4aSBingbu Cao 	{ 0x0346, 0x01 },
594df0b5c4aSBingbu Cao 	{ 0x0347, 0x30 },
595df0b5c4aSBingbu Cao 	{ 0x0348, 0x0c },
596df0b5c4aSBingbu Cao 	{ 0x0349, 0xcf },
597df0b5c4aSBingbu Cao 	{ 0x034a, 0x08 },
598df0b5c4aSBingbu Cao 	{ 0x034b, 0x63 },
599df0b5c4aSBingbu Cao 	{ 0x0220, 0x00 },
600df0b5c4aSBingbu Cao 	{ 0x0222, 0x01 },
601df0b5c4aSBingbu Cao 	{ 0x0900, 0x01 },
602df0b5c4aSBingbu Cao 	{ 0x0901, 0x22 },
603df0b5c4aSBingbu Cao 	{ 0x0902, 0x00 },
604df0b5c4aSBingbu Cao 	{ 0x034c, 0x06 },
605df0b5c4aSBingbu Cao 	{ 0x034d, 0x68 },
606df0b5c4aSBingbu Cao 	{ 0x034e, 0x03 },
607df0b5c4aSBingbu Cao 	{ 0x034f, 0x9a },
608df0b5c4aSBingbu Cao 	{ 0x0301, 0x05 },
609df0b5c4aSBingbu Cao 	{ 0x0303, 0x01 },
610df0b5c4aSBingbu Cao 	{ 0x0305, 0x02 },
611df0b5c4aSBingbu Cao 	{ 0x0306, 0x00 },
612df0b5c4aSBingbu Cao 	{ 0x0307, 0x78 },
613df0b5c4aSBingbu Cao 	{ 0x030b, 0x01 },
614df0b5c4aSBingbu Cao 	{ 0x030d, 0x02 },
615df0b5c4aSBingbu Cao 	{ 0x030e, 0x00 },
616df0b5c4aSBingbu Cao 	{ 0x030f, 0x4b },
617df0b5c4aSBingbu Cao 	{ 0x0310, 0x00 },
618df0b5c4aSBingbu Cao 	{ 0x0700, 0x00 },
619df0b5c4aSBingbu Cao 	{ 0x0701, 0x10 },
620df0b5c4aSBingbu Cao 	{ 0x0820, 0x0b },
621df0b5c4aSBingbu Cao 	{ 0x0821, 0x40 },
622df0b5c4aSBingbu Cao 	{ 0x3088, 0x04 },
623df0b5c4aSBingbu Cao 	{ 0x6813, 0x02 },
624df0b5c4aSBingbu Cao 	{ 0x6835, 0x07 },
625df0b5c4aSBingbu Cao 	{ 0x6836, 0x01 },
626df0b5c4aSBingbu Cao 	{ 0x6837, 0x04 },
627df0b5c4aSBingbu Cao 	{ 0x684d, 0x07 },
628df0b5c4aSBingbu Cao 	{ 0x684e, 0x01 },
629df0b5c4aSBingbu Cao 	{ 0x684f, 0x04 },
630df0b5c4aSBingbu Cao };
631df0b5c4aSBingbu Cao 
632df0b5c4aSBingbu Cao static const struct imx355_reg mode_1300x736_regs[] = {
633df0b5c4aSBingbu Cao 	{ 0x0112, 0x0a },
634df0b5c4aSBingbu Cao 	{ 0x0113, 0x0a },
635df0b5c4aSBingbu Cao 	{ 0x0114, 0x03 },
636df0b5c4aSBingbu Cao 	{ 0x0342, 0x07 },
637df0b5c4aSBingbu Cao 	{ 0x0343, 0x2c },
638df0b5c4aSBingbu Cao 	{ 0x0340, 0x05 },
639df0b5c4aSBingbu Cao 	{ 0x0341, 0x1a },
640df0b5c4aSBingbu Cao 	{ 0x0344, 0x01 },
641df0b5c4aSBingbu Cao 	{ 0x0345, 0x58 },
642df0b5c4aSBingbu Cao 	{ 0x0346, 0x01 },
643df0b5c4aSBingbu Cao 	{ 0x0347, 0xf0 },
644df0b5c4aSBingbu Cao 	{ 0x0348, 0x0b },
645df0b5c4aSBingbu Cao 	{ 0x0349, 0x7f },
646df0b5c4aSBingbu Cao 	{ 0x034a, 0x07 },
647df0b5c4aSBingbu Cao 	{ 0x034b, 0xaf },
648df0b5c4aSBingbu Cao 	{ 0x0220, 0x00 },
649df0b5c4aSBingbu Cao 	{ 0x0222, 0x01 },
650df0b5c4aSBingbu Cao 	{ 0x0900, 0x01 },
651df0b5c4aSBingbu Cao 	{ 0x0901, 0x22 },
652df0b5c4aSBingbu Cao 	{ 0x0902, 0x00 },
653df0b5c4aSBingbu Cao 	{ 0x034c, 0x05 },
654df0b5c4aSBingbu Cao 	{ 0x034d, 0x14 },
655df0b5c4aSBingbu Cao 	{ 0x034e, 0x02 },
656df0b5c4aSBingbu Cao 	{ 0x034f, 0xe0 },
657df0b5c4aSBingbu Cao 	{ 0x0301, 0x05 },
658df0b5c4aSBingbu Cao 	{ 0x0303, 0x01 },
659df0b5c4aSBingbu Cao 	{ 0x0305, 0x02 },
660df0b5c4aSBingbu Cao 	{ 0x0306, 0x00 },
661df0b5c4aSBingbu Cao 	{ 0x0307, 0x78 },
662df0b5c4aSBingbu Cao 	{ 0x030b, 0x01 },
663df0b5c4aSBingbu Cao 	{ 0x030d, 0x02 },
664df0b5c4aSBingbu Cao 	{ 0x030e, 0x00 },
665df0b5c4aSBingbu Cao 	{ 0x030f, 0x4b },
666df0b5c4aSBingbu Cao 	{ 0x0310, 0x00 },
667df0b5c4aSBingbu Cao 	{ 0x0700, 0x00 },
668df0b5c4aSBingbu Cao 	{ 0x0701, 0x10 },
669df0b5c4aSBingbu Cao 	{ 0x0820, 0x0b },
670df0b5c4aSBingbu Cao 	{ 0x0821, 0x40 },
671df0b5c4aSBingbu Cao 	{ 0x3088, 0x04 },
672df0b5c4aSBingbu Cao 	{ 0x6813, 0x02 },
673df0b5c4aSBingbu Cao 	{ 0x6835, 0x07 },
674df0b5c4aSBingbu Cao 	{ 0x6836, 0x01 },
675df0b5c4aSBingbu Cao 	{ 0x6837, 0x04 },
676df0b5c4aSBingbu Cao 	{ 0x684d, 0x07 },
677df0b5c4aSBingbu Cao 	{ 0x684e, 0x01 },
678df0b5c4aSBingbu Cao 	{ 0x684f, 0x04 },
679df0b5c4aSBingbu Cao };
680df0b5c4aSBingbu Cao 
681df0b5c4aSBingbu Cao static const struct imx355_reg mode_1296x736_regs[] = {
682df0b5c4aSBingbu Cao 	{ 0x0112, 0x0a },
683df0b5c4aSBingbu Cao 	{ 0x0113, 0x0a },
684df0b5c4aSBingbu Cao 	{ 0x0114, 0x03 },
685df0b5c4aSBingbu Cao 	{ 0x0342, 0x07 },
686df0b5c4aSBingbu Cao 	{ 0x0343, 0x2c },
687df0b5c4aSBingbu Cao 	{ 0x0340, 0x05 },
688df0b5c4aSBingbu Cao 	{ 0x0341, 0x1a },
689df0b5c4aSBingbu Cao 	{ 0x0344, 0x01 },
690df0b5c4aSBingbu Cao 	{ 0x0345, 0x58 },
691df0b5c4aSBingbu Cao 	{ 0x0346, 0x01 },
692df0b5c4aSBingbu Cao 	{ 0x0347, 0xf0 },
693df0b5c4aSBingbu Cao 	{ 0x0348, 0x0b },
694df0b5c4aSBingbu Cao 	{ 0x0349, 0x77 },
695df0b5c4aSBingbu Cao 	{ 0x034a, 0x07 },
696df0b5c4aSBingbu Cao 	{ 0x034b, 0xaf },
697df0b5c4aSBingbu Cao 	{ 0x0220, 0x00 },
698df0b5c4aSBingbu Cao 	{ 0x0222, 0x01 },
699df0b5c4aSBingbu Cao 	{ 0x0900, 0x01 },
700df0b5c4aSBingbu Cao 	{ 0x0901, 0x22 },
701df0b5c4aSBingbu Cao 	{ 0x0902, 0x00 },
702df0b5c4aSBingbu Cao 	{ 0x034c, 0x05 },
703df0b5c4aSBingbu Cao 	{ 0x034d, 0x10 },
704df0b5c4aSBingbu Cao 	{ 0x034e, 0x02 },
705df0b5c4aSBingbu Cao 	{ 0x034f, 0xe0 },
706df0b5c4aSBingbu Cao 	{ 0x0301, 0x05 },
707df0b5c4aSBingbu Cao 	{ 0x0303, 0x01 },
708df0b5c4aSBingbu Cao 	{ 0x0305, 0x02 },
709df0b5c4aSBingbu Cao 	{ 0x0306, 0x00 },
710df0b5c4aSBingbu Cao 	{ 0x0307, 0x78 },
711df0b5c4aSBingbu Cao 	{ 0x030b, 0x01 },
712df0b5c4aSBingbu Cao 	{ 0x030d, 0x02 },
713df0b5c4aSBingbu Cao 	{ 0x030e, 0x00 },
714df0b5c4aSBingbu Cao 	{ 0x030f, 0x4b },
715df0b5c4aSBingbu Cao 	{ 0x0310, 0x00 },
716df0b5c4aSBingbu Cao 	{ 0x0700, 0x00 },
717df0b5c4aSBingbu Cao 	{ 0x0701, 0x10 },
718df0b5c4aSBingbu Cao 	{ 0x0820, 0x0b },
719df0b5c4aSBingbu Cao 	{ 0x0821, 0x40 },
720df0b5c4aSBingbu Cao 	{ 0x3088, 0x04 },
721df0b5c4aSBingbu Cao 	{ 0x6813, 0x02 },
722df0b5c4aSBingbu Cao 	{ 0x6835, 0x07 },
723df0b5c4aSBingbu Cao 	{ 0x6836, 0x01 },
724df0b5c4aSBingbu Cao 	{ 0x6837, 0x04 },
725df0b5c4aSBingbu Cao 	{ 0x684d, 0x07 },
726df0b5c4aSBingbu Cao 	{ 0x684e, 0x01 },
727df0b5c4aSBingbu Cao 	{ 0x684f, 0x04 },
728df0b5c4aSBingbu Cao };
729df0b5c4aSBingbu Cao 
730df0b5c4aSBingbu Cao static const struct imx355_reg mode_1284x720_regs[] = {
731df0b5c4aSBingbu Cao 	{ 0x0112, 0x0a },
732df0b5c4aSBingbu Cao 	{ 0x0113, 0x0a },
733df0b5c4aSBingbu Cao 	{ 0x0114, 0x03 },
734df0b5c4aSBingbu Cao 	{ 0x0342, 0x07 },
735df0b5c4aSBingbu Cao 	{ 0x0343, 0x2c },
736df0b5c4aSBingbu Cao 	{ 0x0340, 0x05 },
737df0b5c4aSBingbu Cao 	{ 0x0341, 0x1a },
738df0b5c4aSBingbu Cao 	{ 0x0344, 0x01 },
739df0b5c4aSBingbu Cao 	{ 0x0345, 0x68 },
740df0b5c4aSBingbu Cao 	{ 0x0346, 0x02 },
741df0b5c4aSBingbu Cao 	{ 0x0347, 0x00 },
742df0b5c4aSBingbu Cao 	{ 0x0348, 0x0b },
743df0b5c4aSBingbu Cao 	{ 0x0349, 0x6f },
744df0b5c4aSBingbu Cao 	{ 0x034a, 0x07 },
745df0b5c4aSBingbu Cao 	{ 0x034b, 0x9f },
746df0b5c4aSBingbu Cao 	{ 0x0220, 0x00 },
747df0b5c4aSBingbu Cao 	{ 0x0222, 0x01 },
748df0b5c4aSBingbu Cao 	{ 0x0900, 0x01 },
749df0b5c4aSBingbu Cao 	{ 0x0901, 0x22 },
750df0b5c4aSBingbu Cao 	{ 0x0902, 0x00 },
751df0b5c4aSBingbu Cao 	{ 0x034c, 0x05 },
752df0b5c4aSBingbu Cao 	{ 0x034d, 0x04 },
753df0b5c4aSBingbu Cao 	{ 0x034e, 0x02 },
754df0b5c4aSBingbu Cao 	{ 0x034f, 0xd0 },
755df0b5c4aSBingbu Cao 	{ 0x0301, 0x05 },
756df0b5c4aSBingbu Cao 	{ 0x0303, 0x01 },
757df0b5c4aSBingbu Cao 	{ 0x0305, 0x02 },
758df0b5c4aSBingbu Cao 	{ 0x0306, 0x00 },
759df0b5c4aSBingbu Cao 	{ 0x0307, 0x78 },
760df0b5c4aSBingbu Cao 	{ 0x030b, 0x01 },
761df0b5c4aSBingbu Cao 	{ 0x030d, 0x02 },
762df0b5c4aSBingbu Cao 	{ 0x030e, 0x00 },
763df0b5c4aSBingbu Cao 	{ 0x030f, 0x4b },
764df0b5c4aSBingbu Cao 	{ 0x0310, 0x00 },
765df0b5c4aSBingbu Cao 	{ 0x0700, 0x00 },
766df0b5c4aSBingbu Cao 	{ 0x0701, 0x10 },
767df0b5c4aSBingbu Cao 	{ 0x0820, 0x0b },
768df0b5c4aSBingbu Cao 	{ 0x0821, 0x40 },
769df0b5c4aSBingbu Cao 	{ 0x3088, 0x04 },
770df0b5c4aSBingbu Cao 	{ 0x6813, 0x02 },
771df0b5c4aSBingbu Cao 	{ 0x6835, 0x07 },
772df0b5c4aSBingbu Cao 	{ 0x6836, 0x01 },
773df0b5c4aSBingbu Cao 	{ 0x6837, 0x04 },
774df0b5c4aSBingbu Cao 	{ 0x684d, 0x07 },
775df0b5c4aSBingbu Cao 	{ 0x684e, 0x01 },
776df0b5c4aSBingbu Cao 	{ 0x684f, 0x04 },
777df0b5c4aSBingbu Cao };
778df0b5c4aSBingbu Cao 
779df0b5c4aSBingbu Cao static const struct imx355_reg mode_1280x720_regs[] = {
780df0b5c4aSBingbu Cao 	{ 0x0112, 0x0a },
781df0b5c4aSBingbu Cao 	{ 0x0113, 0x0a },
782df0b5c4aSBingbu Cao 	{ 0x0114, 0x03 },
783df0b5c4aSBingbu Cao 	{ 0x0342, 0x07 },
784df0b5c4aSBingbu Cao 	{ 0x0343, 0x2c },
785df0b5c4aSBingbu Cao 	{ 0x0340, 0x05 },
786df0b5c4aSBingbu Cao 	{ 0x0341, 0x1a },
787df0b5c4aSBingbu Cao 	{ 0x0344, 0x01 },
788df0b5c4aSBingbu Cao 	{ 0x0345, 0x68 },
789df0b5c4aSBingbu Cao 	{ 0x0346, 0x02 },
790df0b5c4aSBingbu Cao 	{ 0x0347, 0x00 },
791df0b5c4aSBingbu Cao 	{ 0x0348, 0x0b },
792df0b5c4aSBingbu Cao 	{ 0x0349, 0x67 },
793df0b5c4aSBingbu Cao 	{ 0x034a, 0x07 },
794df0b5c4aSBingbu Cao 	{ 0x034b, 0x9f },
795df0b5c4aSBingbu Cao 	{ 0x0220, 0x00 },
796df0b5c4aSBingbu Cao 	{ 0x0222, 0x01 },
797df0b5c4aSBingbu Cao 	{ 0x0900, 0x01 },
798df0b5c4aSBingbu Cao 	{ 0x0901, 0x22 },
799df0b5c4aSBingbu Cao 	{ 0x0902, 0x00 },
800df0b5c4aSBingbu Cao 	{ 0x034c, 0x05 },
801df0b5c4aSBingbu Cao 	{ 0x034d, 0x00 },
802df0b5c4aSBingbu Cao 	{ 0x034e, 0x02 },
803df0b5c4aSBingbu Cao 	{ 0x034f, 0xd0 },
804df0b5c4aSBingbu Cao 	{ 0x0301, 0x05 },
805df0b5c4aSBingbu Cao 	{ 0x0303, 0x01 },
806df0b5c4aSBingbu Cao 	{ 0x0305, 0x02 },
807df0b5c4aSBingbu Cao 	{ 0x0306, 0x00 },
808df0b5c4aSBingbu Cao 	{ 0x0307, 0x78 },
809df0b5c4aSBingbu Cao 	{ 0x030b, 0x01 },
810df0b5c4aSBingbu Cao 	{ 0x030d, 0x02 },
811df0b5c4aSBingbu Cao 	{ 0x030e, 0x00 },
812df0b5c4aSBingbu Cao 	{ 0x030f, 0x4b },
813df0b5c4aSBingbu Cao 	{ 0x0310, 0x00 },
814df0b5c4aSBingbu Cao 	{ 0x0700, 0x00 },
815df0b5c4aSBingbu Cao 	{ 0x0701, 0x10 },
816df0b5c4aSBingbu Cao 	{ 0x0820, 0x0b },
817df0b5c4aSBingbu Cao 	{ 0x0821, 0x40 },
818df0b5c4aSBingbu Cao 	{ 0x3088, 0x04 },
819df0b5c4aSBingbu Cao 	{ 0x6813, 0x02 },
820df0b5c4aSBingbu Cao 	{ 0x6835, 0x07 },
821df0b5c4aSBingbu Cao 	{ 0x6836, 0x01 },
822df0b5c4aSBingbu Cao 	{ 0x6837, 0x04 },
823df0b5c4aSBingbu Cao 	{ 0x684d, 0x07 },
824df0b5c4aSBingbu Cao 	{ 0x684e, 0x01 },
825df0b5c4aSBingbu Cao 	{ 0x684f, 0x04 },
826df0b5c4aSBingbu Cao };
827df0b5c4aSBingbu Cao 
828df0b5c4aSBingbu Cao static const struct imx355_reg mode_820x616_regs[] = {
829df0b5c4aSBingbu Cao 	{ 0x0112, 0x0a },
830df0b5c4aSBingbu Cao 	{ 0x0113, 0x0a },
831df0b5c4aSBingbu Cao 	{ 0x0114, 0x03 },
832df0b5c4aSBingbu Cao 	{ 0x0342, 0x0e },
833df0b5c4aSBingbu Cao 	{ 0x0343, 0x58 },
834df0b5c4aSBingbu Cao 	{ 0x0340, 0x02 },
835df0b5c4aSBingbu Cao 	{ 0x0341, 0x8c },
836df0b5c4aSBingbu Cao 	{ 0x0344, 0x00 },
837df0b5c4aSBingbu Cao 	{ 0x0345, 0x00 },
838df0b5c4aSBingbu Cao 	{ 0x0346, 0x00 },
839df0b5c4aSBingbu Cao 	{ 0x0347, 0x00 },
840df0b5c4aSBingbu Cao 	{ 0x0348, 0x0c },
841df0b5c4aSBingbu Cao 	{ 0x0349, 0xcf },
842df0b5c4aSBingbu Cao 	{ 0x034a, 0x09 },
843df0b5c4aSBingbu Cao 	{ 0x034b, 0x9f },
844df0b5c4aSBingbu Cao 	{ 0x0220, 0x00 },
845df0b5c4aSBingbu Cao 	{ 0x0222, 0x01 },
846df0b5c4aSBingbu Cao 	{ 0x0900, 0x01 },
847df0b5c4aSBingbu Cao 	{ 0x0901, 0x44 },
848df0b5c4aSBingbu Cao 	{ 0x0902, 0x00 },
849df0b5c4aSBingbu Cao 	{ 0x034c, 0x03 },
850df0b5c4aSBingbu Cao 	{ 0x034d, 0x34 },
851df0b5c4aSBingbu Cao 	{ 0x034e, 0x02 },
852df0b5c4aSBingbu Cao 	{ 0x034f, 0x68 },
853df0b5c4aSBingbu Cao 	{ 0x0301, 0x05 },
854df0b5c4aSBingbu Cao 	{ 0x0303, 0x01 },
855df0b5c4aSBingbu Cao 	{ 0x0305, 0x02 },
856df0b5c4aSBingbu Cao 	{ 0x0306, 0x00 },
857df0b5c4aSBingbu Cao 	{ 0x0307, 0x78 },
858df0b5c4aSBingbu Cao 	{ 0x030b, 0x01 },
859df0b5c4aSBingbu Cao 	{ 0x030d, 0x02 },
860df0b5c4aSBingbu Cao 	{ 0x030e, 0x00 },
861df0b5c4aSBingbu Cao 	{ 0x030f, 0x4b },
862df0b5c4aSBingbu Cao 	{ 0x0310, 0x00 },
863df0b5c4aSBingbu Cao 	{ 0x0700, 0x02 },
864df0b5c4aSBingbu Cao 	{ 0x0701, 0x78 },
865df0b5c4aSBingbu Cao 	{ 0x0820, 0x0b },
866df0b5c4aSBingbu Cao 	{ 0x0821, 0x40 },
867df0b5c4aSBingbu Cao 	{ 0x3088, 0x04 },
868df0b5c4aSBingbu Cao 	{ 0x6813, 0x02 },
869df0b5c4aSBingbu Cao 	{ 0x6835, 0x07 },
870df0b5c4aSBingbu Cao 	{ 0x6836, 0x01 },
871df0b5c4aSBingbu Cao 	{ 0x6837, 0x04 },
872df0b5c4aSBingbu Cao 	{ 0x684d, 0x07 },
873df0b5c4aSBingbu Cao 	{ 0x684e, 0x01 },
874df0b5c4aSBingbu Cao 	{ 0x684f, 0x04 },
875df0b5c4aSBingbu Cao };
876df0b5c4aSBingbu Cao 
877df0b5c4aSBingbu Cao static const char * const imx355_test_pattern_menu[] = {
878df0b5c4aSBingbu Cao 	"Disabled",
879ce6ebeacSBingbu Cao 	"Solid Colour",
880ce6ebeacSBingbu Cao 	"Eight Vertical Colour Bars",
881ce6ebeacSBingbu Cao 	"Colour Bars With Fade to Grey",
882ce6ebeacSBingbu Cao 	"Pseudorandom Sequence (PN9)",
883df0b5c4aSBingbu Cao };
884df0b5c4aSBingbu Cao 
885df0b5c4aSBingbu Cao /* supported link frequencies */
886df0b5c4aSBingbu Cao static const s64 link_freq_menu_items[] = {
887df0b5c4aSBingbu Cao 	IMX355_LINK_FREQ_DEFAULT,
888df0b5c4aSBingbu Cao };
889df0b5c4aSBingbu Cao 
890df0b5c4aSBingbu Cao /* Mode configs */
891df0b5c4aSBingbu Cao static const struct imx355_mode supported_modes[] = {
892df0b5c4aSBingbu Cao 	{
893df0b5c4aSBingbu Cao 		.width = 3280,
894df0b5c4aSBingbu Cao 		.height = 2464,
895df0b5c4aSBingbu Cao 		.fll_def = 2615,
896df0b5c4aSBingbu Cao 		.fll_min = 2615,
897df0b5c4aSBingbu Cao 		.llp = 3672,
898df0b5c4aSBingbu Cao 		.link_freq_index = IMX355_LINK_FREQ_INDEX,
899df0b5c4aSBingbu Cao 		.reg_list = {
900df0b5c4aSBingbu Cao 			.num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
901df0b5c4aSBingbu Cao 			.regs = mode_3280x2464_regs,
902df0b5c4aSBingbu Cao 		},
903df0b5c4aSBingbu Cao 	},
904df0b5c4aSBingbu Cao 	{
905df0b5c4aSBingbu Cao 		.width = 3268,
906df0b5c4aSBingbu Cao 		.height = 2448,
907df0b5c4aSBingbu Cao 		.fll_def = 2615,
908df0b5c4aSBingbu Cao 		.fll_min = 2615,
909df0b5c4aSBingbu Cao 		.llp = 3672,
910df0b5c4aSBingbu Cao 		.link_freq_index = IMX355_LINK_FREQ_INDEX,
911df0b5c4aSBingbu Cao 		.reg_list = {
912df0b5c4aSBingbu Cao 			.num_of_regs = ARRAY_SIZE(mode_3268x2448_regs),
913df0b5c4aSBingbu Cao 			.regs = mode_3268x2448_regs,
914df0b5c4aSBingbu Cao 		},
915df0b5c4aSBingbu Cao 	},
916df0b5c4aSBingbu Cao 	{
917df0b5c4aSBingbu Cao 		.width = 3264,
918df0b5c4aSBingbu Cao 		.height = 2448,
919df0b5c4aSBingbu Cao 		.fll_def = 2615,
920df0b5c4aSBingbu Cao 		.fll_min = 2615,
921df0b5c4aSBingbu Cao 		.llp = 3672,
922df0b5c4aSBingbu Cao 		.link_freq_index = IMX355_LINK_FREQ_INDEX,
923df0b5c4aSBingbu Cao 		.reg_list = {
924df0b5c4aSBingbu Cao 			.num_of_regs = ARRAY_SIZE(mode_3264x2448_regs),
925df0b5c4aSBingbu Cao 			.regs = mode_3264x2448_regs,
926df0b5c4aSBingbu Cao 		},
927df0b5c4aSBingbu Cao 	},
928df0b5c4aSBingbu Cao 	{
929df0b5c4aSBingbu Cao 		.width = 1940,
930df0b5c4aSBingbu Cao 		.height = 1096,
931df0b5c4aSBingbu Cao 		.fll_def = 1306,
932df0b5c4aSBingbu Cao 		.fll_min = 1306,
933df0b5c4aSBingbu Cao 		.llp = 3672,
934df0b5c4aSBingbu Cao 		.link_freq_index = IMX355_LINK_FREQ_INDEX,
935df0b5c4aSBingbu Cao 		.reg_list = {
936df0b5c4aSBingbu Cao 			.num_of_regs = ARRAY_SIZE(mode_1940x1096_regs),
937df0b5c4aSBingbu Cao 			.regs = mode_1940x1096_regs,
938df0b5c4aSBingbu Cao 		},
939df0b5c4aSBingbu Cao 	},
940df0b5c4aSBingbu Cao 	{
941df0b5c4aSBingbu Cao 		.width = 1936,
942df0b5c4aSBingbu Cao 		.height = 1096,
943df0b5c4aSBingbu Cao 		.fll_def = 1306,
944df0b5c4aSBingbu Cao 		.fll_min = 1306,
945df0b5c4aSBingbu Cao 		.llp = 3672,
946df0b5c4aSBingbu Cao 		.link_freq_index = IMX355_LINK_FREQ_INDEX,
947df0b5c4aSBingbu Cao 		.reg_list = {
948df0b5c4aSBingbu Cao 			.num_of_regs = ARRAY_SIZE(mode_1936x1096_regs),
949df0b5c4aSBingbu Cao 			.regs = mode_1936x1096_regs,
950df0b5c4aSBingbu Cao 		},
951df0b5c4aSBingbu Cao 	},
952df0b5c4aSBingbu Cao 	{
953df0b5c4aSBingbu Cao 		.width = 1924,
954df0b5c4aSBingbu Cao 		.height = 1080,
955df0b5c4aSBingbu Cao 		.fll_def = 1306,
956df0b5c4aSBingbu Cao 		.fll_min = 1306,
957df0b5c4aSBingbu Cao 		.llp = 3672,
958df0b5c4aSBingbu Cao 		.link_freq_index = IMX355_LINK_FREQ_INDEX,
959df0b5c4aSBingbu Cao 		.reg_list = {
960df0b5c4aSBingbu Cao 			.num_of_regs = ARRAY_SIZE(mode_1924x1080_regs),
961df0b5c4aSBingbu Cao 			.regs = mode_1924x1080_regs,
962df0b5c4aSBingbu Cao 		},
963df0b5c4aSBingbu Cao 	},
964df0b5c4aSBingbu Cao 	{
965df0b5c4aSBingbu Cao 		.width = 1920,
966df0b5c4aSBingbu Cao 		.height = 1080,
967df0b5c4aSBingbu Cao 		.fll_def = 1306,
968df0b5c4aSBingbu Cao 		.fll_min = 1306,
969df0b5c4aSBingbu Cao 		.llp = 3672,
970df0b5c4aSBingbu Cao 		.link_freq_index = IMX355_LINK_FREQ_INDEX,
971df0b5c4aSBingbu Cao 		.reg_list = {
972df0b5c4aSBingbu Cao 			.num_of_regs = ARRAY_SIZE(mode_1920x1080_regs),
973df0b5c4aSBingbu Cao 			.regs = mode_1920x1080_regs,
974df0b5c4aSBingbu Cao 		},
975df0b5c4aSBingbu Cao 	},
976df0b5c4aSBingbu Cao 	{
977df0b5c4aSBingbu Cao 		.width = 1640,
978df0b5c4aSBingbu Cao 		.height = 1232,
979df0b5c4aSBingbu Cao 		.fll_def = 1306,
980df0b5c4aSBingbu Cao 		.fll_min = 1306,
981df0b5c4aSBingbu Cao 		.llp = 1836,
982df0b5c4aSBingbu Cao 		.link_freq_index = IMX355_LINK_FREQ_INDEX,
983df0b5c4aSBingbu Cao 		.reg_list = {
984df0b5c4aSBingbu Cao 			.num_of_regs = ARRAY_SIZE(mode_1640x1232_regs),
985df0b5c4aSBingbu Cao 			.regs = mode_1640x1232_regs,
986df0b5c4aSBingbu Cao 		},
987df0b5c4aSBingbu Cao 	},
988df0b5c4aSBingbu Cao 	{
989df0b5c4aSBingbu Cao 		.width = 1640,
990df0b5c4aSBingbu Cao 		.height = 922,
991df0b5c4aSBingbu Cao 		.fll_def = 1306,
992df0b5c4aSBingbu Cao 		.fll_min = 1306,
993df0b5c4aSBingbu Cao 		.llp = 1836,
994df0b5c4aSBingbu Cao 		.link_freq_index = IMX355_LINK_FREQ_INDEX,
995df0b5c4aSBingbu Cao 		.reg_list = {
996df0b5c4aSBingbu Cao 			.num_of_regs = ARRAY_SIZE(mode_1640x922_regs),
997df0b5c4aSBingbu Cao 			.regs = mode_1640x922_regs,
998df0b5c4aSBingbu Cao 		},
999df0b5c4aSBingbu Cao 	},
1000df0b5c4aSBingbu Cao 	{
1001df0b5c4aSBingbu Cao 		.width = 1300,
1002df0b5c4aSBingbu Cao 		.height = 736,
1003df0b5c4aSBingbu Cao 		.fll_def = 1306,
1004df0b5c4aSBingbu Cao 		.fll_min = 1306,
1005df0b5c4aSBingbu Cao 		.llp = 1836,
1006df0b5c4aSBingbu Cao 		.link_freq_index = IMX355_LINK_FREQ_INDEX,
1007df0b5c4aSBingbu Cao 		.reg_list = {
1008df0b5c4aSBingbu Cao 			.num_of_regs = ARRAY_SIZE(mode_1300x736_regs),
1009df0b5c4aSBingbu Cao 			.regs = mode_1300x736_regs,
1010df0b5c4aSBingbu Cao 		},
1011df0b5c4aSBingbu Cao 	},
1012df0b5c4aSBingbu Cao 	{
1013df0b5c4aSBingbu Cao 		.width = 1296,
1014df0b5c4aSBingbu Cao 		.height = 736,
1015df0b5c4aSBingbu Cao 		.fll_def = 1306,
1016df0b5c4aSBingbu Cao 		.fll_min = 1306,
1017df0b5c4aSBingbu Cao 		.llp = 1836,
1018df0b5c4aSBingbu Cao 		.link_freq_index = IMX355_LINK_FREQ_INDEX,
1019df0b5c4aSBingbu Cao 		.reg_list = {
1020df0b5c4aSBingbu Cao 			.num_of_regs = ARRAY_SIZE(mode_1296x736_regs),
1021df0b5c4aSBingbu Cao 			.regs = mode_1296x736_regs,
1022df0b5c4aSBingbu Cao 		},
1023df0b5c4aSBingbu Cao 	},
1024df0b5c4aSBingbu Cao 	{
1025df0b5c4aSBingbu Cao 		.width = 1284,
1026df0b5c4aSBingbu Cao 		.height = 720,
1027df0b5c4aSBingbu Cao 		.fll_def = 1306,
1028df0b5c4aSBingbu Cao 		.fll_min = 1306,
1029df0b5c4aSBingbu Cao 		.llp = 1836,
1030df0b5c4aSBingbu Cao 		.link_freq_index = IMX355_LINK_FREQ_INDEX,
1031df0b5c4aSBingbu Cao 		.reg_list = {
1032df0b5c4aSBingbu Cao 			.num_of_regs = ARRAY_SIZE(mode_1284x720_regs),
1033df0b5c4aSBingbu Cao 			.regs = mode_1284x720_regs,
1034df0b5c4aSBingbu Cao 		},
1035df0b5c4aSBingbu Cao 	},
1036df0b5c4aSBingbu Cao 	{
1037df0b5c4aSBingbu Cao 		.width = 1280,
1038df0b5c4aSBingbu Cao 		.height = 720,
1039df0b5c4aSBingbu Cao 		.fll_def = 1306,
1040df0b5c4aSBingbu Cao 		.fll_min = 1306,
1041df0b5c4aSBingbu Cao 		.llp = 1836,
1042df0b5c4aSBingbu Cao 		.link_freq_index = IMX355_LINK_FREQ_INDEX,
1043df0b5c4aSBingbu Cao 		.reg_list = {
1044df0b5c4aSBingbu Cao 			.num_of_regs = ARRAY_SIZE(mode_1280x720_regs),
1045df0b5c4aSBingbu Cao 			.regs = mode_1280x720_regs,
1046df0b5c4aSBingbu Cao 		},
1047df0b5c4aSBingbu Cao 	},
1048df0b5c4aSBingbu Cao 	{
1049df0b5c4aSBingbu Cao 		.width = 820,
1050df0b5c4aSBingbu Cao 		.height = 616,
1051df0b5c4aSBingbu Cao 		.fll_def = 652,
1052df0b5c4aSBingbu Cao 		.fll_min = 652,
1053df0b5c4aSBingbu Cao 		.llp = 3672,
1054df0b5c4aSBingbu Cao 		.link_freq_index = IMX355_LINK_FREQ_INDEX,
1055df0b5c4aSBingbu Cao 		.reg_list = {
1056df0b5c4aSBingbu Cao 			.num_of_regs = ARRAY_SIZE(mode_820x616_regs),
1057df0b5c4aSBingbu Cao 			.regs = mode_820x616_regs,
1058df0b5c4aSBingbu Cao 		},
1059df0b5c4aSBingbu Cao 	},
1060df0b5c4aSBingbu Cao };
1061df0b5c4aSBingbu Cao 
to_imx355(struct v4l2_subdev * _sd)1062df0b5c4aSBingbu Cao static inline struct imx355 *to_imx355(struct v4l2_subdev *_sd)
1063df0b5c4aSBingbu Cao {
1064df0b5c4aSBingbu Cao 	return container_of(_sd, struct imx355, sd);
1065df0b5c4aSBingbu Cao }
1066df0b5c4aSBingbu Cao 
1067df0b5c4aSBingbu Cao /* Get bayer order based on flip setting. */
imx355_get_format_code(struct imx355 * imx355)1068df0b5c4aSBingbu Cao static u32 imx355_get_format_code(struct imx355 *imx355)
1069df0b5c4aSBingbu Cao {
1070df0b5c4aSBingbu Cao 	/*
1071df0b5c4aSBingbu Cao 	 * Only one bayer order is supported.
1072df0b5c4aSBingbu Cao 	 * It depends on the flip settings.
1073df0b5c4aSBingbu Cao 	 */
1074df0b5c4aSBingbu Cao 	u32 code;
1075df0b5c4aSBingbu Cao 	static const u32 codes[2][2] = {
1076df0b5c4aSBingbu Cao 		{ MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, },
1077df0b5c4aSBingbu Cao 		{ MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, },
1078df0b5c4aSBingbu Cao 	};
1079df0b5c4aSBingbu Cao 
1080df0b5c4aSBingbu Cao 	lockdep_assert_held(&imx355->mutex);
1081df0b5c4aSBingbu Cao 	code = codes[imx355->vflip->val][imx355->hflip->val];
1082df0b5c4aSBingbu Cao 
1083df0b5c4aSBingbu Cao 	return code;
1084df0b5c4aSBingbu Cao }
1085df0b5c4aSBingbu Cao 
1086df0b5c4aSBingbu Cao /* Read registers up to 4 at a time */
imx355_read_reg(struct imx355 * imx355,u16 reg,u32 len,u32 * val)1087df0b5c4aSBingbu Cao static int imx355_read_reg(struct imx355 *imx355, u16 reg, u32 len, u32 *val)
1088df0b5c4aSBingbu Cao {
1089df0b5c4aSBingbu Cao 	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
1090df0b5c4aSBingbu Cao 	struct i2c_msg msgs[2];
1091df0b5c4aSBingbu Cao 	u8 addr_buf[2];
1092df0b5c4aSBingbu Cao 	u8 data_buf[4] = { 0 };
1093df0b5c4aSBingbu Cao 	int ret;
1094df0b5c4aSBingbu Cao 
1095df0b5c4aSBingbu Cao 	if (len > 4)
1096df0b5c4aSBingbu Cao 		return -EINVAL;
1097df0b5c4aSBingbu Cao 
1098df0b5c4aSBingbu Cao 	put_unaligned_be16(reg, addr_buf);
1099df0b5c4aSBingbu Cao 	/* Write register address */
1100df0b5c4aSBingbu Cao 	msgs[0].addr = client->addr;
1101df0b5c4aSBingbu Cao 	msgs[0].flags = 0;
1102df0b5c4aSBingbu Cao 	msgs[0].len = ARRAY_SIZE(addr_buf);
1103df0b5c4aSBingbu Cao 	msgs[0].buf = addr_buf;
1104df0b5c4aSBingbu Cao 
1105df0b5c4aSBingbu Cao 	/* Read data from register */
1106df0b5c4aSBingbu Cao 	msgs[1].addr = client->addr;
1107df0b5c4aSBingbu Cao 	msgs[1].flags = I2C_M_RD;
1108df0b5c4aSBingbu Cao 	msgs[1].len = len;
1109df0b5c4aSBingbu Cao 	msgs[1].buf = &data_buf[4 - len];
1110df0b5c4aSBingbu Cao 
1111df0b5c4aSBingbu Cao 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
1112df0b5c4aSBingbu Cao 	if (ret != ARRAY_SIZE(msgs))
1113df0b5c4aSBingbu Cao 		return -EIO;
1114df0b5c4aSBingbu Cao 
1115df0b5c4aSBingbu Cao 	*val = get_unaligned_be32(data_buf);
1116df0b5c4aSBingbu Cao 
1117df0b5c4aSBingbu Cao 	return 0;
1118df0b5c4aSBingbu Cao }
1119df0b5c4aSBingbu Cao 
1120df0b5c4aSBingbu Cao /* Write registers up to 4 at a time */
imx355_write_reg(struct imx355 * imx355,u16 reg,u32 len,u32 val)1121df0b5c4aSBingbu Cao static int imx355_write_reg(struct imx355 *imx355, u16 reg, u32 len, u32 val)
1122df0b5c4aSBingbu Cao {
1123df0b5c4aSBingbu Cao 	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
1124df0b5c4aSBingbu Cao 	u8 buf[6];
1125df0b5c4aSBingbu Cao 
1126df0b5c4aSBingbu Cao 	if (len > 4)
1127df0b5c4aSBingbu Cao 		return -EINVAL;
1128df0b5c4aSBingbu Cao 
1129df0b5c4aSBingbu Cao 	put_unaligned_be16(reg, buf);
1130df0b5c4aSBingbu Cao 	put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
1131df0b5c4aSBingbu Cao 	if (i2c_master_send(client, buf, len + 2) != len + 2)
1132df0b5c4aSBingbu Cao 		return -EIO;
1133df0b5c4aSBingbu Cao 
1134df0b5c4aSBingbu Cao 	return 0;
1135df0b5c4aSBingbu Cao }
1136df0b5c4aSBingbu Cao 
1137df0b5c4aSBingbu Cao /* Write a list of registers */
imx355_write_regs(struct imx355 * imx355,const struct imx355_reg * regs,u32 len)1138df0b5c4aSBingbu Cao static int imx355_write_regs(struct imx355 *imx355,
1139df0b5c4aSBingbu Cao 			     const struct imx355_reg *regs, u32 len)
1140df0b5c4aSBingbu Cao {
1141df0b5c4aSBingbu Cao 	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
1142df0b5c4aSBingbu Cao 	int ret;
1143df0b5c4aSBingbu Cao 	u32 i;
1144df0b5c4aSBingbu Cao 
1145df0b5c4aSBingbu Cao 	for (i = 0; i < len; i++) {
1146df0b5c4aSBingbu Cao 		ret = imx355_write_reg(imx355, regs[i].address, 1, regs[i].val);
1147df0b5c4aSBingbu Cao 		if (ret) {
1148df0b5c4aSBingbu Cao 			dev_err_ratelimited(&client->dev,
1149df0b5c4aSBingbu Cao 					    "write reg 0x%4.4x return err %d",
1150df0b5c4aSBingbu Cao 					    regs[i].address, ret);
1151df0b5c4aSBingbu Cao 
1152df0b5c4aSBingbu Cao 			return ret;
1153df0b5c4aSBingbu Cao 		}
1154df0b5c4aSBingbu Cao 	}
1155df0b5c4aSBingbu Cao 
1156df0b5c4aSBingbu Cao 	return 0;
1157df0b5c4aSBingbu Cao }
1158df0b5c4aSBingbu Cao 
1159df0b5c4aSBingbu Cao /* Open sub-device */
imx355_open(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)1160df0b5c4aSBingbu Cao static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
1161df0b5c4aSBingbu Cao {
1162df0b5c4aSBingbu Cao 	struct imx355 *imx355 = to_imx355(sd);
1163df0b5c4aSBingbu Cao 	struct v4l2_mbus_framefmt *try_fmt =
11640d346d2aSTomi Valkeinen 		v4l2_subdev_get_try_format(sd, fh->state, 0);
1165df0b5c4aSBingbu Cao 
1166df0b5c4aSBingbu Cao 	mutex_lock(&imx355->mutex);
1167df0b5c4aSBingbu Cao 
1168df0b5c4aSBingbu Cao 	/* Initialize try_fmt */
1169df0b5c4aSBingbu Cao 	try_fmt->width = imx355->cur_mode->width;
1170df0b5c4aSBingbu Cao 	try_fmt->height = imx355->cur_mode->height;
1171df0b5c4aSBingbu Cao 	try_fmt->code = imx355_get_format_code(imx355);
1172df0b5c4aSBingbu Cao 	try_fmt->field = V4L2_FIELD_NONE;
1173df0b5c4aSBingbu Cao 
1174df0b5c4aSBingbu Cao 	mutex_unlock(&imx355->mutex);
1175df0b5c4aSBingbu Cao 
1176df0b5c4aSBingbu Cao 	return 0;
1177df0b5c4aSBingbu Cao }
1178df0b5c4aSBingbu Cao 
imx355_set_ctrl(struct v4l2_ctrl * ctrl)1179df0b5c4aSBingbu Cao static int imx355_set_ctrl(struct v4l2_ctrl *ctrl)
1180df0b5c4aSBingbu Cao {
1181df0b5c4aSBingbu Cao 	struct imx355 *imx355 = container_of(ctrl->handler,
1182df0b5c4aSBingbu Cao 					     struct imx355, ctrl_handler);
1183df0b5c4aSBingbu Cao 	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
1184df0b5c4aSBingbu Cao 	s64 max;
1185df0b5c4aSBingbu Cao 	int ret;
1186df0b5c4aSBingbu Cao 
1187df0b5c4aSBingbu Cao 	/* Propagate change of current control to all related controls */
1188df0b5c4aSBingbu Cao 	switch (ctrl->id) {
1189df0b5c4aSBingbu Cao 	case V4L2_CID_VBLANK:
1190df0b5c4aSBingbu Cao 		/* Update max exposure while meeting expected vblanking */
1191df0b5c4aSBingbu Cao 		max = imx355->cur_mode->height + ctrl->val - 10;
1192df0b5c4aSBingbu Cao 		__v4l2_ctrl_modify_range(imx355->exposure,
1193df0b5c4aSBingbu Cao 					 imx355->exposure->minimum,
1194df0b5c4aSBingbu Cao 					 max, imx355->exposure->step, max);
1195df0b5c4aSBingbu Cao 		break;
1196df0b5c4aSBingbu Cao 	}
1197df0b5c4aSBingbu Cao 
1198df0b5c4aSBingbu Cao 	/*
1199df0b5c4aSBingbu Cao 	 * Applying V4L2 control value only happens
1200df0b5c4aSBingbu Cao 	 * when power is up for streaming
1201df0b5c4aSBingbu Cao 	 */
1202df0b5c4aSBingbu Cao 	if (!pm_runtime_get_if_in_use(&client->dev))
1203df0b5c4aSBingbu Cao 		return 0;
1204df0b5c4aSBingbu Cao 
1205df0b5c4aSBingbu Cao 	switch (ctrl->id) {
1206df0b5c4aSBingbu Cao 	case V4L2_CID_ANALOGUE_GAIN:
1207df0b5c4aSBingbu Cao 		/* Analog gain = 1024/(1024 - ctrl->val) times */
1208df0b5c4aSBingbu Cao 		ret = imx355_write_reg(imx355, IMX355_REG_ANALOG_GAIN, 2,
1209df0b5c4aSBingbu Cao 				       ctrl->val);
1210df0b5c4aSBingbu Cao 		break;
1211df0b5c4aSBingbu Cao 	case V4L2_CID_DIGITAL_GAIN:
1212df0b5c4aSBingbu Cao 		ret = imx355_write_reg(imx355, IMX355_REG_DIG_GAIN_GLOBAL, 2,
1213df0b5c4aSBingbu Cao 				       ctrl->val);
1214df0b5c4aSBingbu Cao 		break;
1215df0b5c4aSBingbu Cao 	case V4L2_CID_EXPOSURE:
1216df0b5c4aSBingbu Cao 		ret = imx355_write_reg(imx355, IMX355_REG_EXPOSURE, 2,
1217df0b5c4aSBingbu Cao 				       ctrl->val);
1218df0b5c4aSBingbu Cao 		break;
1219df0b5c4aSBingbu Cao 	case V4L2_CID_VBLANK:
1220df0b5c4aSBingbu Cao 		/* Update FLL that meets expected vertical blanking */
1221df0b5c4aSBingbu Cao 		ret = imx355_write_reg(imx355, IMX355_REG_FLL, 2,
1222df0b5c4aSBingbu Cao 				       imx355->cur_mode->height + ctrl->val);
1223df0b5c4aSBingbu Cao 		break;
1224df0b5c4aSBingbu Cao 	case V4L2_CID_TEST_PATTERN:
1225df0b5c4aSBingbu Cao 		ret = imx355_write_reg(imx355, IMX355_REG_TEST_PATTERN,
1226df0b5c4aSBingbu Cao 				       2, ctrl->val);
1227df0b5c4aSBingbu Cao 		break;
1228df0b5c4aSBingbu Cao 	case V4L2_CID_HFLIP:
1229df0b5c4aSBingbu Cao 	case V4L2_CID_VFLIP:
1230df0b5c4aSBingbu Cao 		ret = imx355_write_reg(imx355, IMX355_REG_ORIENTATION, 1,
1231df0b5c4aSBingbu Cao 				       imx355->hflip->val |
1232df0b5c4aSBingbu Cao 				       imx355->vflip->val << 1);
1233df0b5c4aSBingbu Cao 		break;
1234df0b5c4aSBingbu Cao 	default:
1235df0b5c4aSBingbu Cao 		ret = -EINVAL;
1236df0b5c4aSBingbu Cao 		dev_info(&client->dev, "ctrl(id:0x%x,val:0x%x) is not handled",
1237df0b5c4aSBingbu Cao 			 ctrl->id, ctrl->val);
1238df0b5c4aSBingbu Cao 		break;
1239df0b5c4aSBingbu Cao 	}
1240df0b5c4aSBingbu Cao 
1241df0b5c4aSBingbu Cao 	pm_runtime_put(&client->dev);
1242df0b5c4aSBingbu Cao 
1243df0b5c4aSBingbu Cao 	return ret;
1244df0b5c4aSBingbu Cao }
1245df0b5c4aSBingbu Cao 
1246df0b5c4aSBingbu Cao static const struct v4l2_ctrl_ops imx355_ctrl_ops = {
1247df0b5c4aSBingbu Cao 	.s_ctrl = imx355_set_ctrl,
1248df0b5c4aSBingbu Cao };
1249df0b5c4aSBingbu Cao 
imx355_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)1250df0b5c4aSBingbu Cao static int imx355_enum_mbus_code(struct v4l2_subdev *sd,
12510d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
1252df0b5c4aSBingbu Cao 				 struct v4l2_subdev_mbus_code_enum *code)
1253df0b5c4aSBingbu Cao {
1254df0b5c4aSBingbu Cao 	struct imx355 *imx355 = to_imx355(sd);
1255df0b5c4aSBingbu Cao 
1256df0b5c4aSBingbu Cao 	if (code->index > 0)
1257df0b5c4aSBingbu Cao 		return -EINVAL;
1258df0b5c4aSBingbu Cao 
1259df0b5c4aSBingbu Cao 	mutex_lock(&imx355->mutex);
1260df0b5c4aSBingbu Cao 	code->code = imx355_get_format_code(imx355);
1261df0b5c4aSBingbu Cao 	mutex_unlock(&imx355->mutex);
1262df0b5c4aSBingbu Cao 
1263df0b5c4aSBingbu Cao 	return 0;
1264df0b5c4aSBingbu Cao }
1265df0b5c4aSBingbu Cao 
imx355_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)1266df0b5c4aSBingbu Cao static int imx355_enum_frame_size(struct v4l2_subdev *sd,
12670d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
1268df0b5c4aSBingbu Cao 				  struct v4l2_subdev_frame_size_enum *fse)
1269df0b5c4aSBingbu Cao {
1270df0b5c4aSBingbu Cao 	struct imx355 *imx355 = to_imx355(sd);
1271df0b5c4aSBingbu Cao 
1272df0b5c4aSBingbu Cao 	if (fse->index >= ARRAY_SIZE(supported_modes))
1273df0b5c4aSBingbu Cao 		return -EINVAL;
1274df0b5c4aSBingbu Cao 
1275df0b5c4aSBingbu Cao 	mutex_lock(&imx355->mutex);
1276df0b5c4aSBingbu Cao 	if (fse->code != imx355_get_format_code(imx355)) {
1277df0b5c4aSBingbu Cao 		mutex_unlock(&imx355->mutex);
1278df0b5c4aSBingbu Cao 		return -EINVAL;
1279df0b5c4aSBingbu Cao 	}
1280df0b5c4aSBingbu Cao 	mutex_unlock(&imx355->mutex);
1281df0b5c4aSBingbu Cao 
1282df0b5c4aSBingbu Cao 	fse->min_width = supported_modes[fse->index].width;
1283df0b5c4aSBingbu Cao 	fse->max_width = fse->min_width;
1284df0b5c4aSBingbu Cao 	fse->min_height = supported_modes[fse->index].height;
1285df0b5c4aSBingbu Cao 	fse->max_height = fse->min_height;
1286df0b5c4aSBingbu Cao 
1287df0b5c4aSBingbu Cao 	return 0;
1288df0b5c4aSBingbu Cao }
1289df0b5c4aSBingbu Cao 
imx355_update_pad_format(struct imx355 * imx355,const struct imx355_mode * mode,struct v4l2_subdev_format * fmt)1290df0b5c4aSBingbu Cao static void imx355_update_pad_format(struct imx355 *imx355,
1291df0b5c4aSBingbu Cao 				     const struct imx355_mode *mode,
1292df0b5c4aSBingbu Cao 				     struct v4l2_subdev_format *fmt)
1293df0b5c4aSBingbu Cao {
1294df0b5c4aSBingbu Cao 	fmt->format.width = mode->width;
1295df0b5c4aSBingbu Cao 	fmt->format.height = mode->height;
1296df0b5c4aSBingbu Cao 	fmt->format.code = imx355_get_format_code(imx355);
1297df0b5c4aSBingbu Cao 	fmt->format.field = V4L2_FIELD_NONE;
1298df0b5c4aSBingbu Cao }
1299df0b5c4aSBingbu Cao 
imx355_do_get_pad_format(struct imx355 * imx355,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)1300df0b5c4aSBingbu Cao static int imx355_do_get_pad_format(struct imx355 *imx355,
13010d346d2aSTomi Valkeinen 				    struct v4l2_subdev_state *sd_state,
1302df0b5c4aSBingbu Cao 				    struct v4l2_subdev_format *fmt)
1303df0b5c4aSBingbu Cao {
1304df0b5c4aSBingbu Cao 	struct v4l2_mbus_framefmt *framefmt;
1305df0b5c4aSBingbu Cao 	struct v4l2_subdev *sd = &imx355->sd;
1306df0b5c4aSBingbu Cao 
1307df0b5c4aSBingbu Cao 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
13080d346d2aSTomi Valkeinen 		framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
1309df0b5c4aSBingbu Cao 		fmt->format = *framefmt;
1310df0b5c4aSBingbu Cao 	} else {
1311df0b5c4aSBingbu Cao 		imx355_update_pad_format(imx355, imx355->cur_mode, fmt);
1312df0b5c4aSBingbu Cao 	}
1313df0b5c4aSBingbu Cao 
1314df0b5c4aSBingbu Cao 	return 0;
1315df0b5c4aSBingbu Cao }
1316df0b5c4aSBingbu Cao 
imx355_get_pad_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)1317df0b5c4aSBingbu Cao static int imx355_get_pad_format(struct v4l2_subdev *sd,
13180d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
1319df0b5c4aSBingbu Cao 				 struct v4l2_subdev_format *fmt)
1320df0b5c4aSBingbu Cao {
1321df0b5c4aSBingbu Cao 	struct imx355 *imx355 = to_imx355(sd);
1322df0b5c4aSBingbu Cao 	int ret;
1323df0b5c4aSBingbu Cao 
1324df0b5c4aSBingbu Cao 	mutex_lock(&imx355->mutex);
13250d346d2aSTomi Valkeinen 	ret = imx355_do_get_pad_format(imx355, sd_state, fmt);
1326df0b5c4aSBingbu Cao 	mutex_unlock(&imx355->mutex);
1327df0b5c4aSBingbu Cao 
1328df0b5c4aSBingbu Cao 	return ret;
1329df0b5c4aSBingbu Cao }
1330df0b5c4aSBingbu Cao 
1331df0b5c4aSBingbu Cao static int
imx355_set_pad_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)1332df0b5c4aSBingbu Cao imx355_set_pad_format(struct v4l2_subdev *sd,
13330d346d2aSTomi Valkeinen 		      struct v4l2_subdev_state *sd_state,
1334df0b5c4aSBingbu Cao 		      struct v4l2_subdev_format *fmt)
1335df0b5c4aSBingbu Cao {
1336df0b5c4aSBingbu Cao 	struct imx355 *imx355 = to_imx355(sd);
1337df0b5c4aSBingbu Cao 	const struct imx355_mode *mode;
1338df0b5c4aSBingbu Cao 	struct v4l2_mbus_framefmt *framefmt;
1339df0b5c4aSBingbu Cao 	s32 vblank_def;
1340df0b5c4aSBingbu Cao 	s32 vblank_min;
1341df0b5c4aSBingbu Cao 	s64 h_blank;
1342df0b5c4aSBingbu Cao 	u64 pixel_rate;
1343df0b5c4aSBingbu Cao 	u32 height;
1344df0b5c4aSBingbu Cao 
1345df0b5c4aSBingbu Cao 	mutex_lock(&imx355->mutex);
1346df0b5c4aSBingbu Cao 
1347df0b5c4aSBingbu Cao 	/*
1348df0b5c4aSBingbu Cao 	 * Only one bayer order is supported.
1349df0b5c4aSBingbu Cao 	 * It depends on the flip settings.
1350df0b5c4aSBingbu Cao 	 */
1351df0b5c4aSBingbu Cao 	fmt->format.code = imx355_get_format_code(imx355);
1352df0b5c4aSBingbu Cao 
1353df0b5c4aSBingbu Cao 	mode = v4l2_find_nearest_size(supported_modes,
1354df0b5c4aSBingbu Cao 				      ARRAY_SIZE(supported_modes),
1355df0b5c4aSBingbu Cao 				      width, height,
1356df0b5c4aSBingbu Cao 				      fmt->format.width, fmt->format.height);
1357df0b5c4aSBingbu Cao 	imx355_update_pad_format(imx355, mode, fmt);
1358df0b5c4aSBingbu Cao 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
13590d346d2aSTomi Valkeinen 		framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
1360df0b5c4aSBingbu Cao 		*framefmt = fmt->format;
1361df0b5c4aSBingbu Cao 	} else {
1362df0b5c4aSBingbu Cao 		imx355->cur_mode = mode;
1363df0b5c4aSBingbu Cao 		pixel_rate = imx355->link_def_freq * 2 * 4;
1364df0b5c4aSBingbu Cao 		do_div(pixel_rate, 10);
1365df0b5c4aSBingbu Cao 		__v4l2_ctrl_s_ctrl_int64(imx355->pixel_rate, pixel_rate);
1366df0b5c4aSBingbu Cao 		/* Update limits and set FPS to default */
1367df0b5c4aSBingbu Cao 		height = imx355->cur_mode->height;
1368df0b5c4aSBingbu Cao 		vblank_def = imx355->cur_mode->fll_def - height;
1369df0b5c4aSBingbu Cao 		vblank_min = imx355->cur_mode->fll_min - height;
1370df0b5c4aSBingbu Cao 		height = IMX355_FLL_MAX - height;
1371df0b5c4aSBingbu Cao 		__v4l2_ctrl_modify_range(imx355->vblank, vblank_min, height, 1,
1372df0b5c4aSBingbu Cao 					 vblank_def);
1373df0b5c4aSBingbu Cao 		__v4l2_ctrl_s_ctrl(imx355->vblank, vblank_def);
1374df0b5c4aSBingbu Cao 		h_blank = mode->llp - imx355->cur_mode->width;
1375df0b5c4aSBingbu Cao 		/*
1376df0b5c4aSBingbu Cao 		 * Currently hblank is not changeable.
1377df0b5c4aSBingbu Cao 		 * So FPS control is done only by vblank.
1378df0b5c4aSBingbu Cao 		 */
1379df0b5c4aSBingbu Cao 		__v4l2_ctrl_modify_range(imx355->hblank, h_blank,
1380df0b5c4aSBingbu Cao 					 h_blank, 1, h_blank);
1381df0b5c4aSBingbu Cao 	}
1382df0b5c4aSBingbu Cao 
1383df0b5c4aSBingbu Cao 	mutex_unlock(&imx355->mutex);
1384df0b5c4aSBingbu Cao 
1385df0b5c4aSBingbu Cao 	return 0;
1386df0b5c4aSBingbu Cao }
1387df0b5c4aSBingbu Cao 
1388df0b5c4aSBingbu Cao /* Start streaming */
imx355_start_streaming(struct imx355 * imx355)1389df0b5c4aSBingbu Cao static int imx355_start_streaming(struct imx355 *imx355)
1390df0b5c4aSBingbu Cao {
1391df0b5c4aSBingbu Cao 	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
1392df0b5c4aSBingbu Cao 	const struct imx355_reg_list *reg_list;
1393df0b5c4aSBingbu Cao 	int ret;
1394df0b5c4aSBingbu Cao 
1395df0b5c4aSBingbu Cao 	/* Global Setting */
1396df0b5c4aSBingbu Cao 	reg_list = &imx355_global_setting;
1397df0b5c4aSBingbu Cao 	ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs);
1398df0b5c4aSBingbu Cao 	if (ret) {
1399df0b5c4aSBingbu Cao 		dev_err(&client->dev, "failed to set global settings");
1400df0b5c4aSBingbu Cao 		return ret;
1401df0b5c4aSBingbu Cao 	}
1402df0b5c4aSBingbu Cao 
1403df0b5c4aSBingbu Cao 	/* Apply default values of current mode */
1404df0b5c4aSBingbu Cao 	reg_list = &imx355->cur_mode->reg_list;
1405df0b5c4aSBingbu Cao 	ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs);
1406df0b5c4aSBingbu Cao 	if (ret) {
1407df0b5c4aSBingbu Cao 		dev_err(&client->dev, "failed to set mode");
1408df0b5c4aSBingbu Cao 		return ret;
1409df0b5c4aSBingbu Cao 	}
1410df0b5c4aSBingbu Cao 
1411df0b5c4aSBingbu Cao 	/* set digital gain control to all color mode */
1412df0b5c4aSBingbu Cao 	ret = imx355_write_reg(imx355, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, 1);
1413df0b5c4aSBingbu Cao 	if (ret)
1414df0b5c4aSBingbu Cao 		return ret;
1415df0b5c4aSBingbu Cao 
1416df0b5c4aSBingbu Cao 	/* Apply customized values from user */
1417df0b5c4aSBingbu Cao 	ret =  __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler);
1418df0b5c4aSBingbu Cao 	if (ret)
1419df0b5c4aSBingbu Cao 		return ret;
1420df0b5c4aSBingbu Cao 
1421df0b5c4aSBingbu Cao 	return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT,
1422df0b5c4aSBingbu Cao 				1, IMX355_MODE_STREAMING);
1423df0b5c4aSBingbu Cao }
1424df0b5c4aSBingbu Cao 
1425df0b5c4aSBingbu Cao /* Stop streaming */
imx355_stop_streaming(struct imx355 * imx355)1426df0b5c4aSBingbu Cao static int imx355_stop_streaming(struct imx355 *imx355)
1427df0b5c4aSBingbu Cao {
1428df0b5c4aSBingbu Cao 	return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT,
1429df0b5c4aSBingbu Cao 				1, IMX355_MODE_STANDBY);
1430df0b5c4aSBingbu Cao }
1431df0b5c4aSBingbu Cao 
imx355_set_stream(struct v4l2_subdev * sd,int enable)1432df0b5c4aSBingbu Cao static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
1433df0b5c4aSBingbu Cao {
1434df0b5c4aSBingbu Cao 	struct imx355 *imx355 = to_imx355(sd);
1435df0b5c4aSBingbu Cao 	struct i2c_client *client = v4l2_get_subdevdata(sd);
1436df0b5c4aSBingbu Cao 	int ret = 0;
1437df0b5c4aSBingbu Cao 
1438df0b5c4aSBingbu Cao 	mutex_lock(&imx355->mutex);
1439df0b5c4aSBingbu Cao 	if (imx355->streaming == enable) {
1440df0b5c4aSBingbu Cao 		mutex_unlock(&imx355->mutex);
1441df0b5c4aSBingbu Cao 		return 0;
1442df0b5c4aSBingbu Cao 	}
1443df0b5c4aSBingbu Cao 
1444df0b5c4aSBingbu Cao 	if (enable) {
14455f070f4dSMauro Carvalho Chehab 		ret = pm_runtime_resume_and_get(&client->dev);
14465f070f4dSMauro Carvalho Chehab 		if (ret < 0)
1447df0b5c4aSBingbu Cao 			goto err_unlock;
1448df0b5c4aSBingbu Cao 
1449df0b5c4aSBingbu Cao 		/*
1450df0b5c4aSBingbu Cao 		 * Apply default & customized values
1451df0b5c4aSBingbu Cao 		 * and then start streaming.
1452df0b5c4aSBingbu Cao 		 */
1453df0b5c4aSBingbu Cao 		ret = imx355_start_streaming(imx355);
1454df0b5c4aSBingbu Cao 		if (ret)
1455df0b5c4aSBingbu Cao 			goto err_rpm_put;
1456df0b5c4aSBingbu Cao 	} else {
1457df0b5c4aSBingbu Cao 		imx355_stop_streaming(imx355);
1458df0b5c4aSBingbu Cao 		pm_runtime_put(&client->dev);
1459df0b5c4aSBingbu Cao 	}
1460df0b5c4aSBingbu Cao 
1461df0b5c4aSBingbu Cao 	imx355->streaming = enable;
1462df0b5c4aSBingbu Cao 
1463df0b5c4aSBingbu Cao 	/* vflip and hflip cannot change during streaming */
1464df0b5c4aSBingbu Cao 	__v4l2_ctrl_grab(imx355->vflip, enable);
1465df0b5c4aSBingbu Cao 	__v4l2_ctrl_grab(imx355->hflip, enable);
1466df0b5c4aSBingbu Cao 
1467df0b5c4aSBingbu Cao 	mutex_unlock(&imx355->mutex);
1468df0b5c4aSBingbu Cao 
1469df0b5c4aSBingbu Cao 	return ret;
1470df0b5c4aSBingbu Cao 
1471df0b5c4aSBingbu Cao err_rpm_put:
1472df0b5c4aSBingbu Cao 	pm_runtime_put(&client->dev);
1473df0b5c4aSBingbu Cao err_unlock:
1474df0b5c4aSBingbu Cao 	mutex_unlock(&imx355->mutex);
1475df0b5c4aSBingbu Cao 
1476df0b5c4aSBingbu Cao 	return ret;
1477df0b5c4aSBingbu Cao }
1478df0b5c4aSBingbu Cao 
imx355_suspend(struct device * dev)1479df0b5c4aSBingbu Cao static int __maybe_unused imx355_suspend(struct device *dev)
1480df0b5c4aSBingbu Cao {
1481be0b9b63SKrzysztof Kozlowski 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
1482df0b5c4aSBingbu Cao 	struct imx355 *imx355 = to_imx355(sd);
1483df0b5c4aSBingbu Cao 
1484df0b5c4aSBingbu Cao 	if (imx355->streaming)
1485df0b5c4aSBingbu Cao 		imx355_stop_streaming(imx355);
1486df0b5c4aSBingbu Cao 
1487df0b5c4aSBingbu Cao 	return 0;
1488df0b5c4aSBingbu Cao }
1489df0b5c4aSBingbu Cao 
imx355_resume(struct device * dev)1490df0b5c4aSBingbu Cao static int __maybe_unused imx355_resume(struct device *dev)
1491df0b5c4aSBingbu Cao {
1492be0b9b63SKrzysztof Kozlowski 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
1493df0b5c4aSBingbu Cao 	struct imx355 *imx355 = to_imx355(sd);
1494df0b5c4aSBingbu Cao 	int ret;
1495df0b5c4aSBingbu Cao 
1496df0b5c4aSBingbu Cao 	if (imx355->streaming) {
1497df0b5c4aSBingbu Cao 		ret = imx355_start_streaming(imx355);
1498df0b5c4aSBingbu Cao 		if (ret)
1499df0b5c4aSBingbu Cao 			goto error;
1500df0b5c4aSBingbu Cao 	}
1501df0b5c4aSBingbu Cao 
1502df0b5c4aSBingbu Cao 	return 0;
1503df0b5c4aSBingbu Cao 
1504df0b5c4aSBingbu Cao error:
1505df0b5c4aSBingbu Cao 	imx355_stop_streaming(imx355);
1506df0b5c4aSBingbu Cao 	imx355->streaming = 0;
1507df0b5c4aSBingbu Cao 	return ret;
1508df0b5c4aSBingbu Cao }
1509df0b5c4aSBingbu Cao 
1510df0b5c4aSBingbu Cao /* Verify chip ID */
imx355_identify_module(struct imx355 * imx355)1511df0b5c4aSBingbu Cao static int imx355_identify_module(struct imx355 *imx355)
1512df0b5c4aSBingbu Cao {
1513df0b5c4aSBingbu Cao 	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
1514df0b5c4aSBingbu Cao 	int ret;
1515df0b5c4aSBingbu Cao 	u32 val;
1516df0b5c4aSBingbu Cao 
1517df0b5c4aSBingbu Cao 	ret = imx355_read_reg(imx355, IMX355_REG_CHIP_ID, 2, &val);
1518df0b5c4aSBingbu Cao 	if (ret)
1519df0b5c4aSBingbu Cao 		return ret;
1520df0b5c4aSBingbu Cao 
1521df0b5c4aSBingbu Cao 	if (val != IMX355_CHIP_ID) {
1522df0b5c4aSBingbu Cao 		dev_err(&client->dev, "chip id mismatch: %x!=%x",
1523df0b5c4aSBingbu Cao 			IMX355_CHIP_ID, val);
1524df0b5c4aSBingbu Cao 		return -EIO;
1525df0b5c4aSBingbu Cao 	}
1526df0b5c4aSBingbu Cao 	return 0;
1527df0b5c4aSBingbu Cao }
1528df0b5c4aSBingbu Cao 
1529df0b5c4aSBingbu Cao static const struct v4l2_subdev_core_ops imx355_subdev_core_ops = {
1530df0b5c4aSBingbu Cao 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
1531df0b5c4aSBingbu Cao 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
1532df0b5c4aSBingbu Cao };
1533df0b5c4aSBingbu Cao 
1534df0b5c4aSBingbu Cao static const struct v4l2_subdev_video_ops imx355_video_ops = {
1535df0b5c4aSBingbu Cao 	.s_stream = imx355_set_stream,
1536df0b5c4aSBingbu Cao };
1537df0b5c4aSBingbu Cao 
1538df0b5c4aSBingbu Cao static const struct v4l2_subdev_pad_ops imx355_pad_ops = {
1539df0b5c4aSBingbu Cao 	.enum_mbus_code = imx355_enum_mbus_code,
1540df0b5c4aSBingbu Cao 	.get_fmt = imx355_get_pad_format,
1541df0b5c4aSBingbu Cao 	.set_fmt = imx355_set_pad_format,
1542df0b5c4aSBingbu Cao 	.enum_frame_size = imx355_enum_frame_size,
1543df0b5c4aSBingbu Cao };
1544df0b5c4aSBingbu Cao 
1545df0b5c4aSBingbu Cao static const struct v4l2_subdev_ops imx355_subdev_ops = {
1546df0b5c4aSBingbu Cao 	.core = &imx355_subdev_core_ops,
1547df0b5c4aSBingbu Cao 	.video = &imx355_video_ops,
1548df0b5c4aSBingbu Cao 	.pad = &imx355_pad_ops,
1549df0b5c4aSBingbu Cao };
1550df0b5c4aSBingbu Cao 
1551df0b5c4aSBingbu Cao static const struct media_entity_operations imx355_subdev_entity_ops = {
1552df0b5c4aSBingbu Cao 	.link_validate = v4l2_subdev_link_validate,
1553df0b5c4aSBingbu Cao };
1554df0b5c4aSBingbu Cao 
1555df0b5c4aSBingbu Cao static const struct v4l2_subdev_internal_ops imx355_internal_ops = {
1556df0b5c4aSBingbu Cao 	.open = imx355_open,
1557df0b5c4aSBingbu Cao };
1558df0b5c4aSBingbu Cao 
1559df0b5c4aSBingbu Cao /* Initialize control handlers */
imx355_init_controls(struct imx355 * imx355)1560df0b5c4aSBingbu Cao static int imx355_init_controls(struct imx355 *imx355)
1561df0b5c4aSBingbu Cao {
1562df0b5c4aSBingbu Cao 	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
1563df0b5c4aSBingbu Cao 	struct v4l2_ctrl_handler *ctrl_hdlr;
1564df0b5c4aSBingbu Cao 	s64 exposure_max;
1565df0b5c4aSBingbu Cao 	s64 vblank_def;
1566df0b5c4aSBingbu Cao 	s64 vblank_min;
1567df0b5c4aSBingbu Cao 	s64 hblank;
1568df0b5c4aSBingbu Cao 	u64 pixel_rate;
1569df0b5c4aSBingbu Cao 	const struct imx355_mode *mode;
1570df0b5c4aSBingbu Cao 	u32 max;
1571df0b5c4aSBingbu Cao 	int ret;
1572df0b5c4aSBingbu Cao 
1573df0b5c4aSBingbu Cao 	ctrl_hdlr = &imx355->ctrl_handler;
1574df0b5c4aSBingbu Cao 	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10);
1575df0b5c4aSBingbu Cao 	if (ret)
1576df0b5c4aSBingbu Cao 		return ret;
1577df0b5c4aSBingbu Cao 
1578df0b5c4aSBingbu Cao 	ctrl_hdlr->lock = &imx355->mutex;
1579df0b5c4aSBingbu Cao 	max = ARRAY_SIZE(link_freq_menu_items) - 1;
1580df0b5c4aSBingbu Cao 	imx355->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx355_ctrl_ops,
1581df0b5c4aSBingbu Cao 						   V4L2_CID_LINK_FREQ, max, 0,
1582df0b5c4aSBingbu Cao 						   link_freq_menu_items);
1583df0b5c4aSBingbu Cao 	if (imx355->link_freq)
1584df0b5c4aSBingbu Cao 		imx355->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
1585df0b5c4aSBingbu Cao 
1586df0b5c4aSBingbu Cao 	/* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
1587df0b5c4aSBingbu Cao 	pixel_rate = imx355->link_def_freq * 2 * 4;
1588df0b5c4aSBingbu Cao 	do_div(pixel_rate, 10);
1589df0b5c4aSBingbu Cao 	/* By default, PIXEL_RATE is read only */
1590df0b5c4aSBingbu Cao 	imx355->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
1591df0b5c4aSBingbu Cao 					       V4L2_CID_PIXEL_RATE, pixel_rate,
1592df0b5c4aSBingbu Cao 					       pixel_rate, 1, pixel_rate);
1593df0b5c4aSBingbu Cao 
1594df0b5c4aSBingbu Cao 	/* Initialize vblank/hblank/exposure parameters based on current mode */
1595df0b5c4aSBingbu Cao 	mode = imx355->cur_mode;
1596df0b5c4aSBingbu Cao 	vblank_def = mode->fll_def - mode->height;
1597df0b5c4aSBingbu Cao 	vblank_min = mode->fll_min - mode->height;
1598df0b5c4aSBingbu Cao 	imx355->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
1599df0b5c4aSBingbu Cao 					   V4L2_CID_VBLANK, vblank_min,
1600df0b5c4aSBingbu Cao 					   IMX355_FLL_MAX - mode->height,
1601df0b5c4aSBingbu Cao 					   1, vblank_def);
1602df0b5c4aSBingbu Cao 
1603df0b5c4aSBingbu Cao 	hblank = mode->llp - mode->width;
1604df0b5c4aSBingbu Cao 	imx355->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
1605df0b5c4aSBingbu Cao 					   V4L2_CID_HBLANK, hblank, hblank,
1606df0b5c4aSBingbu Cao 					   1, hblank);
1607df0b5c4aSBingbu Cao 	if (imx355->hblank)
1608df0b5c4aSBingbu Cao 		imx355->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
1609df0b5c4aSBingbu Cao 
1610df0b5c4aSBingbu Cao 	/* fll >= exposure time + adjust parameter (default value is 10) */
1611df0b5c4aSBingbu Cao 	exposure_max = mode->fll_def - 10;
1612df0b5c4aSBingbu Cao 	imx355->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
1613df0b5c4aSBingbu Cao 					     V4L2_CID_EXPOSURE,
1614df0b5c4aSBingbu Cao 					     IMX355_EXPOSURE_MIN, exposure_max,
1615df0b5c4aSBingbu Cao 					     IMX355_EXPOSURE_STEP,
1616df0b5c4aSBingbu Cao 					     IMX355_EXPOSURE_DEFAULT);
1617df0b5c4aSBingbu Cao 
1618df0b5c4aSBingbu Cao 	imx355->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
1619df0b5c4aSBingbu Cao 					  V4L2_CID_HFLIP, 0, 1, 1, 0);
16201dc33888SDave Stevenson 	if (imx355->hflip)
16211dc33888SDave Stevenson 		imx355->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
1622df0b5c4aSBingbu Cao 	imx355->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
1623df0b5c4aSBingbu Cao 					  V4L2_CID_VFLIP, 0, 1, 1, 0);
16241dc33888SDave Stevenson 	if (imx355->vflip)
16251dc33888SDave Stevenson 		imx355->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
1626df0b5c4aSBingbu Cao 
1627df0b5c4aSBingbu Cao 	v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
1628df0b5c4aSBingbu Cao 			  IMX355_ANA_GAIN_MIN, IMX355_ANA_GAIN_MAX,
1629df0b5c4aSBingbu Cao 			  IMX355_ANA_GAIN_STEP, IMX355_ANA_GAIN_DEFAULT);
1630df0b5c4aSBingbu Cao 
1631df0b5c4aSBingbu Cao 	/* Digital gain */
1632df0b5c4aSBingbu Cao 	v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
1633df0b5c4aSBingbu Cao 			  IMX355_DGTL_GAIN_MIN, IMX355_DGTL_GAIN_MAX,
1634df0b5c4aSBingbu Cao 			  IMX355_DGTL_GAIN_STEP, IMX355_DGTL_GAIN_DEFAULT);
1635df0b5c4aSBingbu Cao 
1636df0b5c4aSBingbu Cao 	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx355_ctrl_ops,
1637df0b5c4aSBingbu Cao 				     V4L2_CID_TEST_PATTERN,
1638df0b5c4aSBingbu Cao 				     ARRAY_SIZE(imx355_test_pattern_menu) - 1,
1639df0b5c4aSBingbu Cao 				     0, 0, imx355_test_pattern_menu);
1640df0b5c4aSBingbu Cao 	if (ctrl_hdlr->error) {
1641df0b5c4aSBingbu Cao 		ret = ctrl_hdlr->error;
1642df0b5c4aSBingbu Cao 		dev_err(&client->dev, "control init failed: %d", ret);
1643df0b5c4aSBingbu Cao 		goto error;
1644df0b5c4aSBingbu Cao 	}
1645df0b5c4aSBingbu Cao 
1646df0b5c4aSBingbu Cao 	imx355->sd.ctrl_handler = ctrl_hdlr;
1647df0b5c4aSBingbu Cao 
1648df0b5c4aSBingbu Cao 	return 0;
1649df0b5c4aSBingbu Cao 
1650df0b5c4aSBingbu Cao error:
1651df0b5c4aSBingbu Cao 	v4l2_ctrl_handler_free(ctrl_hdlr);
1652df0b5c4aSBingbu Cao 
1653df0b5c4aSBingbu Cao 	return ret;
1654df0b5c4aSBingbu Cao }
1655df0b5c4aSBingbu Cao 
imx355_get_hwcfg(struct device * dev)1656df0b5c4aSBingbu Cao static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev)
1657df0b5c4aSBingbu Cao {
1658df0b5c4aSBingbu Cao 	struct imx355_hwcfg *cfg;
1659df0b5c4aSBingbu Cao 	struct v4l2_fwnode_endpoint bus_cfg = {
1660df0b5c4aSBingbu Cao 		.bus_type = V4L2_MBUS_CSI2_DPHY
1661df0b5c4aSBingbu Cao 	};
1662df0b5c4aSBingbu Cao 	struct fwnode_handle *ep;
1663df0b5c4aSBingbu Cao 	struct fwnode_handle *fwnode = dev_fwnode(dev);
1664df0b5c4aSBingbu Cao 	unsigned int i;
1665df0b5c4aSBingbu Cao 	int ret;
1666df0b5c4aSBingbu Cao 
1667df0b5c4aSBingbu Cao 	if (!fwnode)
1668df0b5c4aSBingbu Cao 		return NULL;
1669df0b5c4aSBingbu Cao 
1670df0b5c4aSBingbu Cao 	ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
1671df0b5c4aSBingbu Cao 	if (!ep)
1672df0b5c4aSBingbu Cao 		return NULL;
1673df0b5c4aSBingbu Cao 
1674df0b5c4aSBingbu Cao 	ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
1675df0b5c4aSBingbu Cao 	if (ret)
1676df0b5c4aSBingbu Cao 		goto out_err;
1677df0b5c4aSBingbu Cao 
1678df0b5c4aSBingbu Cao 	cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
1679df0b5c4aSBingbu Cao 	if (!cfg)
1680df0b5c4aSBingbu Cao 		goto out_err;
1681df0b5c4aSBingbu Cao 
1682df0b5c4aSBingbu Cao 	ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
1683df0b5c4aSBingbu Cao 				       &cfg->ext_clk);
1684df0b5c4aSBingbu Cao 	if (ret) {
1685df0b5c4aSBingbu Cao 		dev_err(dev, "can't get clock frequency");
1686df0b5c4aSBingbu Cao 		goto out_err;
1687df0b5c4aSBingbu Cao 	}
1688df0b5c4aSBingbu Cao 
1689df0b5c4aSBingbu Cao 	dev_dbg(dev, "ext clk: %d", cfg->ext_clk);
1690df0b5c4aSBingbu Cao 	if (cfg->ext_clk != IMX355_EXT_CLK) {
1691df0b5c4aSBingbu Cao 		dev_err(dev, "external clock %d is not supported",
1692df0b5c4aSBingbu Cao 			cfg->ext_clk);
1693df0b5c4aSBingbu Cao 		goto out_err;
1694df0b5c4aSBingbu Cao 	}
1695df0b5c4aSBingbu Cao 
1696df0b5c4aSBingbu Cao 	dev_dbg(dev, "num of link freqs: %d", bus_cfg.nr_of_link_frequencies);
1697df0b5c4aSBingbu Cao 	if (!bus_cfg.nr_of_link_frequencies) {
1698df0b5c4aSBingbu Cao 		dev_warn(dev, "no link frequencies defined");
1699df0b5c4aSBingbu Cao 		goto out_err;
1700df0b5c4aSBingbu Cao 	}
1701df0b5c4aSBingbu Cao 
1702df0b5c4aSBingbu Cao 	cfg->nr_of_link_freqs = bus_cfg.nr_of_link_frequencies;
1703370d8e2aSMauro Carvalho Chehab 	cfg->link_freqs = devm_kcalloc(dev,
1704370d8e2aSMauro Carvalho Chehab 				       bus_cfg.nr_of_link_frequencies + 1,
1705df0b5c4aSBingbu Cao 				       sizeof(*cfg->link_freqs), GFP_KERNEL);
1706df0b5c4aSBingbu Cao 	if (!cfg->link_freqs)
1707df0b5c4aSBingbu Cao 		goto out_err;
1708df0b5c4aSBingbu Cao 
1709df0b5c4aSBingbu Cao 	for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) {
1710df0b5c4aSBingbu Cao 		cfg->link_freqs[i] = bus_cfg.link_frequencies[i];
1711df0b5c4aSBingbu Cao 		dev_dbg(dev, "link_freq[%d] = %lld", i, cfg->link_freqs[i]);
1712df0b5c4aSBingbu Cao 	}
1713df0b5c4aSBingbu Cao 
1714df0b5c4aSBingbu Cao 	v4l2_fwnode_endpoint_free(&bus_cfg);
1715df0b5c4aSBingbu Cao 	fwnode_handle_put(ep);
1716df0b5c4aSBingbu Cao 	return cfg;
1717df0b5c4aSBingbu Cao 
1718df0b5c4aSBingbu Cao out_err:
1719df0b5c4aSBingbu Cao 	v4l2_fwnode_endpoint_free(&bus_cfg);
1720df0b5c4aSBingbu Cao 	fwnode_handle_put(ep);
1721df0b5c4aSBingbu Cao 	return NULL;
1722df0b5c4aSBingbu Cao }
1723df0b5c4aSBingbu Cao 
imx355_probe(struct i2c_client * client)1724df0b5c4aSBingbu Cao static int imx355_probe(struct i2c_client *client)
1725df0b5c4aSBingbu Cao {
1726df0b5c4aSBingbu Cao 	struct imx355 *imx355;
1727df0b5c4aSBingbu Cao 	int ret;
1728df0b5c4aSBingbu Cao 	u32 i;
1729df0b5c4aSBingbu Cao 
1730df0b5c4aSBingbu Cao 	imx355 = devm_kzalloc(&client->dev, sizeof(*imx355), GFP_KERNEL);
1731df0b5c4aSBingbu Cao 	if (!imx355)
1732df0b5c4aSBingbu Cao 		return -ENOMEM;
1733df0b5c4aSBingbu Cao 
1734df0b5c4aSBingbu Cao 	mutex_init(&imx355->mutex);
1735df0b5c4aSBingbu Cao 
1736df0b5c4aSBingbu Cao 	/* Initialize subdev */
1737df0b5c4aSBingbu Cao 	v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops);
1738df0b5c4aSBingbu Cao 
1739df0b5c4aSBingbu Cao 	/* Check module identity */
1740df0b5c4aSBingbu Cao 	ret = imx355_identify_module(imx355);
1741df0b5c4aSBingbu Cao 	if (ret) {
1742df0b5c4aSBingbu Cao 		dev_err(&client->dev, "failed to find sensor: %d", ret);
1743df0b5c4aSBingbu Cao 		goto error_probe;
1744df0b5c4aSBingbu Cao 	}
1745df0b5c4aSBingbu Cao 
1746df0b5c4aSBingbu Cao 	imx355->hwcfg = imx355_get_hwcfg(&client->dev);
1747df0b5c4aSBingbu Cao 	if (!imx355->hwcfg) {
1748df0b5c4aSBingbu Cao 		dev_err(&client->dev, "failed to get hwcfg");
1749df0b5c4aSBingbu Cao 		ret = -ENODEV;
1750df0b5c4aSBingbu Cao 		goto error_probe;
1751df0b5c4aSBingbu Cao 	}
1752df0b5c4aSBingbu Cao 
1753df0b5c4aSBingbu Cao 	imx355->link_def_freq = link_freq_menu_items[IMX355_LINK_FREQ_INDEX];
1754df0b5c4aSBingbu Cao 	for (i = 0; i < imx355->hwcfg->nr_of_link_freqs; i++) {
1755df0b5c4aSBingbu Cao 		if (imx355->hwcfg->link_freqs[i] == imx355->link_def_freq) {
1756df0b5c4aSBingbu Cao 			dev_dbg(&client->dev, "link freq index %d matched", i);
1757df0b5c4aSBingbu Cao 			break;
1758df0b5c4aSBingbu Cao 		}
1759df0b5c4aSBingbu Cao 	}
1760df0b5c4aSBingbu Cao 
1761df0b5c4aSBingbu Cao 	if (i == imx355->hwcfg->nr_of_link_freqs) {
1762df0b5c4aSBingbu Cao 		dev_err(&client->dev, "no link frequency supported");
1763df0b5c4aSBingbu Cao 		ret = -EINVAL;
1764df0b5c4aSBingbu Cao 		goto error_probe;
1765df0b5c4aSBingbu Cao 	}
1766df0b5c4aSBingbu Cao 
1767df0b5c4aSBingbu Cao 	/* Set default mode to max resolution */
1768df0b5c4aSBingbu Cao 	imx355->cur_mode = &supported_modes[0];
1769df0b5c4aSBingbu Cao 
1770df0b5c4aSBingbu Cao 	ret = imx355_init_controls(imx355);
1771df0b5c4aSBingbu Cao 	if (ret) {
1772df0b5c4aSBingbu Cao 		dev_err(&client->dev, "failed to init controls: %d", ret);
1773df0b5c4aSBingbu Cao 		goto error_probe;
1774df0b5c4aSBingbu Cao 	}
1775df0b5c4aSBingbu Cao 
1776df0b5c4aSBingbu Cao 	/* Initialize subdev */
1777df0b5c4aSBingbu Cao 	imx355->sd.internal_ops = &imx355_internal_ops;
1778df0b5c4aSBingbu Cao 	imx355->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
1779df0b5c4aSBingbu Cao 		V4L2_SUBDEV_FL_HAS_EVENTS;
1780df0b5c4aSBingbu Cao 	imx355->sd.entity.ops = &imx355_subdev_entity_ops;
1781df0b5c4aSBingbu Cao 	imx355->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
1782df0b5c4aSBingbu Cao 
1783df0b5c4aSBingbu Cao 	/* Initialize source pad */
1784df0b5c4aSBingbu Cao 	imx355->pad.flags = MEDIA_PAD_FL_SOURCE;
1785df0b5c4aSBingbu Cao 	ret = media_entity_pads_init(&imx355->sd.entity, 1, &imx355->pad);
1786df0b5c4aSBingbu Cao 	if (ret) {
1787df0b5c4aSBingbu Cao 		dev_err(&client->dev, "failed to init entity pads: %d", ret);
1788df0b5c4aSBingbu Cao 		goto error_handler_free;
1789df0b5c4aSBingbu Cao 	}
1790df0b5c4aSBingbu Cao 
1791df0b5c4aSBingbu Cao 	/*
1792df0b5c4aSBingbu Cao 	 * Device is already turned on by i2c-core with ACPI domain PM.
1793df0b5c4aSBingbu Cao 	 * Enable runtime PM and turn off the device.
1794df0b5c4aSBingbu Cao 	 */
1795df0b5c4aSBingbu Cao 	pm_runtime_set_active(&client->dev);
1796df0b5c4aSBingbu Cao 	pm_runtime_enable(&client->dev);
1797df0b5c4aSBingbu Cao 	pm_runtime_idle(&client->dev);
1798df0b5c4aSBingbu Cao 
1799*252ae106SBingbu Cao 	ret = v4l2_async_register_subdev_sensor(&imx355->sd);
1800*252ae106SBingbu Cao 	if (ret < 0)
1801*252ae106SBingbu Cao 		goto error_media_entity_runtime_pm;
1802*252ae106SBingbu Cao 
1803df0b5c4aSBingbu Cao 	return 0;
1804df0b5c4aSBingbu Cao 
1805*252ae106SBingbu Cao error_media_entity_runtime_pm:
1806*252ae106SBingbu Cao 	pm_runtime_disable(&client->dev);
1807*252ae106SBingbu Cao 	pm_runtime_set_suspended(&client->dev);
1808df0b5c4aSBingbu Cao 	media_entity_cleanup(&imx355->sd.entity);
1809df0b5c4aSBingbu Cao 
1810df0b5c4aSBingbu Cao error_handler_free:
1811df0b5c4aSBingbu Cao 	v4l2_ctrl_handler_free(imx355->sd.ctrl_handler);
1812df0b5c4aSBingbu Cao 
1813df0b5c4aSBingbu Cao error_probe:
1814df0b5c4aSBingbu Cao 	mutex_destroy(&imx355->mutex);
1815df0b5c4aSBingbu Cao 
1816df0b5c4aSBingbu Cao 	return ret;
1817df0b5c4aSBingbu Cao }
1818df0b5c4aSBingbu Cao 
imx355_remove(struct i2c_client * client)1819ed5c2f5fSUwe Kleine-König static void imx355_remove(struct i2c_client *client)
1820df0b5c4aSBingbu Cao {
1821df0b5c4aSBingbu Cao 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1822df0b5c4aSBingbu Cao 	struct imx355 *imx355 = to_imx355(sd);
1823df0b5c4aSBingbu Cao 
1824df0b5c4aSBingbu Cao 	v4l2_async_unregister_subdev(sd);
1825df0b5c4aSBingbu Cao 	media_entity_cleanup(&sd->entity);
1826df0b5c4aSBingbu Cao 	v4l2_ctrl_handler_free(sd->ctrl_handler);
1827df0b5c4aSBingbu Cao 
1828df0b5c4aSBingbu Cao 	pm_runtime_disable(&client->dev);
1829df0b5c4aSBingbu Cao 	pm_runtime_set_suspended(&client->dev);
1830df0b5c4aSBingbu Cao 
1831df0b5c4aSBingbu Cao 	mutex_destroy(&imx355->mutex);
1832df0b5c4aSBingbu Cao }
1833df0b5c4aSBingbu Cao 
1834df0b5c4aSBingbu Cao static const struct dev_pm_ops imx355_pm_ops = {
1835df0b5c4aSBingbu Cao 	SET_SYSTEM_SLEEP_PM_OPS(imx355_suspend, imx355_resume)
1836df0b5c4aSBingbu Cao };
1837df0b5c4aSBingbu Cao 
1838bbaecc36SKrzysztof Kozlowski static const struct acpi_device_id imx355_acpi_ids[] __maybe_unused = {
1839df0b5c4aSBingbu Cao 	{ "SONY355A" },
1840df0b5c4aSBingbu Cao 	{ /* sentinel */ }
1841df0b5c4aSBingbu Cao };
1842df0b5c4aSBingbu Cao MODULE_DEVICE_TABLE(acpi, imx355_acpi_ids);
1843df0b5c4aSBingbu Cao 
1844df0b5c4aSBingbu Cao static struct i2c_driver imx355_i2c_driver = {
1845df0b5c4aSBingbu Cao 	.driver = {
1846df0b5c4aSBingbu Cao 		.name = "imx355",
1847df0b5c4aSBingbu Cao 		.pm = &imx355_pm_ops,
1848df0b5c4aSBingbu Cao 		.acpi_match_table = ACPI_PTR(imx355_acpi_ids),
1849df0b5c4aSBingbu Cao 	},
1850aaeb31c0SUwe Kleine-König 	.probe = imx355_probe,
1851df0b5c4aSBingbu Cao 	.remove = imx355_remove,
1852df0b5c4aSBingbu Cao };
1853df0b5c4aSBingbu Cao module_i2c_driver(imx355_i2c_driver);
1854df0b5c4aSBingbu Cao 
1855df0b5c4aSBingbu Cao MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>");
18564106cd72SSakari Ailus MODULE_AUTHOR("Rapolu, Chiranjeevi");
1857df0b5c4aSBingbu Cao MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
18585fcec420SSakari Ailus MODULE_AUTHOR("Yang, Hyungwoo");
1859df0b5c4aSBingbu Cao MODULE_DESCRIPTION("Sony imx355 sensor driver");
1860df0b5c4aSBingbu Cao MODULE_LICENSE("GPL v2");
1861