xref: /openbmc/linux/drivers/media/i2c/hi556.c (revision 4106cd72)
1e6213840SShawn Tu // SPDX-License-Identifier: GPL-2.0
2e6213840SShawn Tu // Copyright (c) 2019 Intel Corporation.
3e6213840SShawn Tu 
4e6213840SShawn Tu #include <asm/unaligned.h>
5e6213840SShawn Tu #include <linux/acpi.h>
6e6213840SShawn Tu #include <linux/delay.h>
7e6213840SShawn Tu #include <linux/i2c.h>
8e6213840SShawn Tu #include <linux/module.h>
9e6213840SShawn Tu #include <linux/pm_runtime.h>
10e6213840SShawn Tu #include <media/v4l2-ctrls.h>
11e6213840SShawn Tu #include <media/v4l2-device.h>
12e6213840SShawn Tu #include <media/v4l2-fwnode.h>
13e6213840SShawn Tu 
14e6213840SShawn Tu #define HI556_REG_VALUE_08BIT		1
15e6213840SShawn Tu #define HI556_REG_VALUE_16BIT		2
16e6213840SShawn Tu #define HI556_REG_VALUE_24BIT		3
17e6213840SShawn Tu 
18e6213840SShawn Tu #define HI556_LINK_FREQ_437MHZ		437000000ULL
19e6213840SShawn Tu #define HI556_MCLK			19200000
20e6213840SShawn Tu #define HI556_DATA_LANES		2
21e6213840SShawn Tu #define HI556_RGB_DEPTH			10
22e6213840SShawn Tu 
23e6213840SShawn Tu #define HI556_REG_CHIP_ID		0x0f16
24e6213840SShawn Tu #define HI556_CHIP_ID			0x0556
25e6213840SShawn Tu 
26e6213840SShawn Tu #define HI556_REG_MODE_SELECT		0x0a00
27e6213840SShawn Tu #define HI556_MODE_STANDBY		0x0000
28e6213840SShawn Tu #define HI556_MODE_STREAMING		0x0100
29e6213840SShawn Tu 
30e6213840SShawn Tu /* vertical-timings from sensor */
31e6213840SShawn Tu #define HI556_REG_FLL			0x0006
32e6213840SShawn Tu #define HI556_FLL_30FPS			0x0814
33e6213840SShawn Tu #define HI556_FLL_30FPS_MIN		0x0814
34e6213840SShawn Tu #define HI556_FLL_MAX			0x7fff
35e6213840SShawn Tu 
36e6213840SShawn Tu /* horizontal-timings from sensor */
37e6213840SShawn Tu #define HI556_REG_LLP			0x0008
38e6213840SShawn Tu 
39e6213840SShawn Tu /* Exposure controls from sensor */
40e6213840SShawn Tu #define HI556_REG_EXPOSURE		0x0074
41e6213840SShawn Tu #define HI556_EXPOSURE_MIN		6
42e6213840SShawn Tu #define HI556_EXPOSURE_MAX_MARGIN	2
43e6213840SShawn Tu #define HI556_EXPOSURE_STEP		1
44e6213840SShawn Tu 
45e6213840SShawn Tu /* Analog gain controls from sensor */
46e6213840SShawn Tu #define HI556_REG_ANALOG_GAIN		0x0077
47e6213840SShawn Tu #define HI556_ANAL_GAIN_MIN		0
48e6213840SShawn Tu #define HI556_ANAL_GAIN_MAX		240
49e6213840SShawn Tu #define HI556_ANAL_GAIN_STEP		1
50e6213840SShawn Tu 
51e6213840SShawn Tu /* Digital gain controls from sensor */
52e6213840SShawn Tu #define HI556_REG_MWB_GR_GAIN		0x0078
53e6213840SShawn Tu #define HI556_REG_MWB_GB_GAIN		0x007a
54e6213840SShawn Tu #define HI556_REG_MWB_R_GAIN		0x007c
55e6213840SShawn Tu #define HI556_REG_MWB_B_GAIN		0x007e
56e6213840SShawn Tu #define HI556_DGTL_GAIN_MIN		0
57e6213840SShawn Tu #define HI556_DGTL_GAIN_MAX		2048
58e6213840SShawn Tu #define HI556_DGTL_GAIN_STEP		1
59e6213840SShawn Tu #define HI556_DGTL_GAIN_DEFAULT		256
60e6213840SShawn Tu 
61e6213840SShawn Tu /* Test Pattern Control */
62e6213840SShawn Tu #define HI556_REG_ISP			0X0a05
63e6213840SShawn Tu #define HI556_REG_ISP_TPG_EN		0x01
64e6213840SShawn Tu #define HI556_REG_TEST_PATTERN		0x0201
65e6213840SShawn Tu 
66c0bc1ca0SJim Lai /* HI556 native and active pixel array size. */
67c0bc1ca0SJim Lai #define HI556_NATIVE_WIDTH		2592U
68c0bc1ca0SJim Lai #define HI556_NATIVE_HEIGHT		1944U
69c0bc1ca0SJim Lai #define HI556_PIXEL_ARRAY_LEFT		0U
70c0bc1ca0SJim Lai #define HI556_PIXEL_ARRAY_TOP		0U
71c0bc1ca0SJim Lai #define HI556_PIXEL_ARRAY_WIDTH	2592U
72c0bc1ca0SJim Lai #define HI556_PIXEL_ARRAY_HEIGHT	1944U
73c0bc1ca0SJim Lai 
74e6213840SShawn Tu enum {
75e6213840SShawn Tu 	HI556_LINK_FREQ_437MHZ_INDEX,
76e6213840SShawn Tu };
77e6213840SShawn Tu 
78e6213840SShawn Tu struct hi556_reg {
79e6213840SShawn Tu 	u16 address;
80e6213840SShawn Tu 	u16 val;
81e6213840SShawn Tu };
82e6213840SShawn Tu 
83e6213840SShawn Tu struct hi556_reg_list {
84e6213840SShawn Tu 	u32 num_of_regs;
85e6213840SShawn Tu 	const struct hi556_reg *regs;
86e6213840SShawn Tu };
87e6213840SShawn Tu 
88e6213840SShawn Tu struct hi556_link_freq_config {
89e6213840SShawn Tu 	const struct hi556_reg_list reg_list;
90e6213840SShawn Tu };
91e6213840SShawn Tu 
92e6213840SShawn Tu struct hi556_mode {
93e6213840SShawn Tu 	/* Frame width in pixels */
94e6213840SShawn Tu 	u32 width;
95e6213840SShawn Tu 
96e6213840SShawn Tu 	/* Frame height in pixels */
97e6213840SShawn Tu 	u32 height;
98e6213840SShawn Tu 
99c0bc1ca0SJim Lai 	/* Analog crop rectangle. */
100c0bc1ca0SJim Lai 	struct v4l2_rect crop;
101c0bc1ca0SJim Lai 
102e6213840SShawn Tu 	/* Horizontal timining size */
103e6213840SShawn Tu 	u32 llp;
104e6213840SShawn Tu 
105e6213840SShawn Tu 	/* Default vertical timining size */
106e6213840SShawn Tu 	u32 fll_def;
107e6213840SShawn Tu 
108e6213840SShawn Tu 	/* Min vertical timining size */
109e6213840SShawn Tu 	u32 fll_min;
110e6213840SShawn Tu 
111e6213840SShawn Tu 	/* Link frequency needed for this resolution */
112e6213840SShawn Tu 	u32 link_freq_index;
113e6213840SShawn Tu 
114e6213840SShawn Tu 	/* Sensor register settings for this resolution */
115e6213840SShawn Tu 	const struct hi556_reg_list reg_list;
116e6213840SShawn Tu };
117e6213840SShawn Tu 
118e6213840SShawn Tu #define to_hi556(_sd) container_of(_sd, struct hi556, sd)
119e6213840SShawn Tu 
120e6213840SShawn Tu //SENSOR_INITIALIZATION
121e6213840SShawn Tu static const struct hi556_reg mipi_data_rate_874mbps[] = {
122e6213840SShawn Tu 	{0x0e00, 0x0102},
123e6213840SShawn Tu 	{0x0e02, 0x0102},
124e6213840SShawn Tu 	{0x0e0c, 0x0100},
125e6213840SShawn Tu 	{0x2000, 0x7400},
126e6213840SShawn Tu 	{0x2002, 0x001c},
127e6213840SShawn Tu 	{0x2004, 0x0242},
128e6213840SShawn Tu 	{0x2006, 0x0942},
129e6213840SShawn Tu 	{0x2008, 0x7007},
130e6213840SShawn Tu 	{0x200a, 0x0fd9},
131e6213840SShawn Tu 	{0x200c, 0x0259},
132e6213840SShawn Tu 	{0x200e, 0x7008},
133e6213840SShawn Tu 	{0x2010, 0x160e},
134e6213840SShawn Tu 	{0x2012, 0x0047},
135e6213840SShawn Tu 	{0x2014, 0x2118},
136e6213840SShawn Tu 	{0x2016, 0x0041},
137e6213840SShawn Tu 	{0x2018, 0x00d8},
138e6213840SShawn Tu 	{0x201a, 0x0145},
139e6213840SShawn Tu 	{0x201c, 0x0006},
140e6213840SShawn Tu 	{0x201e, 0x0181},
141e6213840SShawn Tu 	{0x2020, 0x13cc},
142e6213840SShawn Tu 	{0x2022, 0x2057},
143e6213840SShawn Tu 	{0x2024, 0x7001},
144e6213840SShawn Tu 	{0x2026, 0x0fca},
145e6213840SShawn Tu 	{0x2028, 0x00cb},
146e6213840SShawn Tu 	{0x202a, 0x009f},
147e6213840SShawn Tu 	{0x202c, 0x7002},
148e6213840SShawn Tu 	{0x202e, 0x13cc},
149e6213840SShawn Tu 	{0x2030, 0x019b},
150e6213840SShawn Tu 	{0x2032, 0x014d},
151e6213840SShawn Tu 	{0x2034, 0x2987},
152e6213840SShawn Tu 	{0x2036, 0x2766},
153e6213840SShawn Tu 	{0x2038, 0x0020},
154e6213840SShawn Tu 	{0x203a, 0x2060},
155e6213840SShawn Tu 	{0x203c, 0x0e5d},
156e6213840SShawn Tu 	{0x203e, 0x181d},
157e6213840SShawn Tu 	{0x2040, 0x2066},
158e6213840SShawn Tu 	{0x2042, 0x20c4},
159e6213840SShawn Tu 	{0x2044, 0x5000},
160e6213840SShawn Tu 	{0x2046, 0x0005},
161e6213840SShawn Tu 	{0x2048, 0x0000},
162e6213840SShawn Tu 	{0x204a, 0x01db},
163e6213840SShawn Tu 	{0x204c, 0x025a},
164e6213840SShawn Tu 	{0x204e, 0x00c0},
165e6213840SShawn Tu 	{0x2050, 0x0005},
166e6213840SShawn Tu 	{0x2052, 0x0006},
167e6213840SShawn Tu 	{0x2054, 0x0ad9},
168e6213840SShawn Tu 	{0x2056, 0x0259},
169e6213840SShawn Tu 	{0x2058, 0x0618},
170e6213840SShawn Tu 	{0x205a, 0x0258},
171e6213840SShawn Tu 	{0x205c, 0x2266},
172e6213840SShawn Tu 	{0x205e, 0x20c8},
173e6213840SShawn Tu 	{0x2060, 0x2060},
174e6213840SShawn Tu 	{0x2062, 0x707b},
175e6213840SShawn Tu 	{0x2064, 0x0fdd},
176e6213840SShawn Tu 	{0x2066, 0x81b8},
177e6213840SShawn Tu 	{0x2068, 0x5040},
178e6213840SShawn Tu 	{0x206a, 0x0020},
179e6213840SShawn Tu 	{0x206c, 0x5060},
180e6213840SShawn Tu 	{0x206e, 0x3143},
181e6213840SShawn Tu 	{0x2070, 0x5081},
182e6213840SShawn Tu 	{0x2072, 0x025c},
183e6213840SShawn Tu 	{0x2074, 0x7800},
184e6213840SShawn Tu 	{0x2076, 0x7400},
185e6213840SShawn Tu 	{0x2078, 0x001c},
186e6213840SShawn Tu 	{0x207a, 0x0242},
187e6213840SShawn Tu 	{0x207c, 0x0942},
188e6213840SShawn Tu 	{0x207e, 0x0bd9},
189e6213840SShawn Tu 	{0x2080, 0x0259},
190e6213840SShawn Tu 	{0x2082, 0x7008},
191e6213840SShawn Tu 	{0x2084, 0x160e},
192e6213840SShawn Tu 	{0x2086, 0x0047},
193e6213840SShawn Tu 	{0x2088, 0x2118},
194e6213840SShawn Tu 	{0x208a, 0x0041},
195e6213840SShawn Tu 	{0x208c, 0x00d8},
196e6213840SShawn Tu 	{0x208e, 0x0145},
197e6213840SShawn Tu 	{0x2090, 0x0006},
198e6213840SShawn Tu 	{0x2092, 0x0181},
199e6213840SShawn Tu 	{0x2094, 0x13cc},
200e6213840SShawn Tu 	{0x2096, 0x2057},
201e6213840SShawn Tu 	{0x2098, 0x7001},
202e6213840SShawn Tu 	{0x209a, 0x0fca},
203e6213840SShawn Tu 	{0x209c, 0x00cb},
204e6213840SShawn Tu 	{0x209e, 0x009f},
205e6213840SShawn Tu 	{0x20a0, 0x7002},
206e6213840SShawn Tu 	{0x20a2, 0x13cc},
207e6213840SShawn Tu 	{0x20a4, 0x019b},
208e6213840SShawn Tu 	{0x20a6, 0x014d},
209e6213840SShawn Tu 	{0x20a8, 0x2987},
210e6213840SShawn Tu 	{0x20aa, 0x2766},
211e6213840SShawn Tu 	{0x20ac, 0x0020},
212e6213840SShawn Tu 	{0x20ae, 0x2060},
213e6213840SShawn Tu 	{0x20b0, 0x0e5d},
214e6213840SShawn Tu 	{0x20b2, 0x181d},
215e6213840SShawn Tu 	{0x20b4, 0x2066},
216e6213840SShawn Tu 	{0x20b6, 0x20c4},
217e6213840SShawn Tu 	{0x20b8, 0x50a0},
218e6213840SShawn Tu 	{0x20ba, 0x0005},
219e6213840SShawn Tu 	{0x20bc, 0x0000},
220e6213840SShawn Tu 	{0x20be, 0x01db},
221e6213840SShawn Tu 	{0x20c0, 0x025a},
222e6213840SShawn Tu 	{0x20c2, 0x00c0},
223e6213840SShawn Tu 	{0x20c4, 0x0005},
224e6213840SShawn Tu 	{0x20c6, 0x0006},
225e6213840SShawn Tu 	{0x20c8, 0x0ad9},
226e6213840SShawn Tu 	{0x20ca, 0x0259},
227e6213840SShawn Tu 	{0x20cc, 0x0618},
228e6213840SShawn Tu 	{0x20ce, 0x0258},
229e6213840SShawn Tu 	{0x20d0, 0x2266},
230e6213840SShawn Tu 	{0x20d2, 0x20c8},
231e6213840SShawn Tu 	{0x20d4, 0x2060},
232e6213840SShawn Tu 	{0x20d6, 0x707b},
233e6213840SShawn Tu 	{0x20d8, 0x0fdd},
234e6213840SShawn Tu 	{0x20da, 0x86b8},
235e6213840SShawn Tu 	{0x20dc, 0x50e0},
236e6213840SShawn Tu 	{0x20de, 0x0020},
237e6213840SShawn Tu 	{0x20e0, 0x5100},
238e6213840SShawn Tu 	{0x20e2, 0x3143},
239e6213840SShawn Tu 	{0x20e4, 0x5121},
240e6213840SShawn Tu 	{0x20e6, 0x7800},
241e6213840SShawn Tu 	{0x20e8, 0x3140},
242e6213840SShawn Tu 	{0x20ea, 0x01c4},
243e6213840SShawn Tu 	{0x20ec, 0x01c1},
244e6213840SShawn Tu 	{0x20ee, 0x01c0},
245e6213840SShawn Tu 	{0x20f0, 0x01c4},
246e6213840SShawn Tu 	{0x20f2, 0x2700},
247e6213840SShawn Tu 	{0x20f4, 0x3d40},
248e6213840SShawn Tu 	{0x20f6, 0x7800},
249e6213840SShawn Tu 	{0x20f8, 0xffff},
250e6213840SShawn Tu 	{0x27fe, 0xe000},
251e6213840SShawn Tu 	{0x3000, 0x60f8},
252e6213840SShawn Tu 	{0x3002, 0x187f},
253e6213840SShawn Tu 	{0x3004, 0x7060},
254e6213840SShawn Tu 	{0x3006, 0x0114},
255e6213840SShawn Tu 	{0x3008, 0x60b0},
256e6213840SShawn Tu 	{0x300a, 0x1473},
257e6213840SShawn Tu 	{0x300c, 0x0013},
258e6213840SShawn Tu 	{0x300e, 0x140f},
259e6213840SShawn Tu 	{0x3010, 0x0040},
260e6213840SShawn Tu 	{0x3012, 0x100f},
261e6213840SShawn Tu 	{0x3014, 0x60f8},
262e6213840SShawn Tu 	{0x3016, 0x187f},
263e6213840SShawn Tu 	{0x3018, 0x7060},
264e6213840SShawn Tu 	{0x301a, 0x0114},
265e6213840SShawn Tu 	{0x301c, 0x60b0},
266e6213840SShawn Tu 	{0x301e, 0x1473},
267e6213840SShawn Tu 	{0x3020, 0x0013},
268e6213840SShawn Tu 	{0x3022, 0x140f},
269e6213840SShawn Tu 	{0x3024, 0x0040},
270e6213840SShawn Tu 	{0x3026, 0x000f},
271e6213840SShawn Tu 
272e6213840SShawn Tu 	{0x0b00, 0x0000},
273e6213840SShawn Tu 	{0x0b02, 0x0045},
274e6213840SShawn Tu 	{0x0b04, 0xb405},
275e6213840SShawn Tu 	{0x0b06, 0xc403},
276e6213840SShawn Tu 	{0x0b08, 0x0081},
277e6213840SShawn Tu 	{0x0b0a, 0x8252},
278e6213840SShawn Tu 	{0x0b0c, 0xf814},
279e6213840SShawn Tu 	{0x0b0e, 0xc618},
280e6213840SShawn Tu 	{0x0b10, 0xa828},
281e6213840SShawn Tu 	{0x0b12, 0x004c},
282e6213840SShawn Tu 	{0x0b14, 0x4068},
283e6213840SShawn Tu 	{0x0b16, 0x0000},
284e6213840SShawn Tu 	{0x0f30, 0x5b15},
285e6213840SShawn Tu 	{0x0f32, 0x7067},
286e6213840SShawn Tu 	{0x0954, 0x0009},
287e6213840SShawn Tu 	{0x0956, 0x0000},
288e6213840SShawn Tu 	{0x0958, 0xbb80},
289e6213840SShawn Tu 	{0x095a, 0x5140},
290e6213840SShawn Tu 	{0x0c00, 0x1110},
291e6213840SShawn Tu 	{0x0c02, 0x0011},
292e6213840SShawn Tu 	{0x0c04, 0x0000},
293e6213840SShawn Tu 	{0x0c06, 0x0200},
294e6213840SShawn Tu 	{0x0c10, 0x0040},
295e6213840SShawn Tu 	{0x0c12, 0x0040},
296e6213840SShawn Tu 	{0x0c14, 0x0040},
297e6213840SShawn Tu 	{0x0c16, 0x0040},
298e6213840SShawn Tu 	{0x0a10, 0x4000},
299e6213840SShawn Tu 	{0x3068, 0xf800},
300e6213840SShawn Tu 	{0x306a, 0xf876},
301e6213840SShawn Tu 	{0x006c, 0x0000},
302e6213840SShawn Tu 	{0x005e, 0x0200},
303e6213840SShawn Tu 	{0x000e, 0x0100},
304e6213840SShawn Tu 	{0x0e0a, 0x0001},
305e6213840SShawn Tu 	{0x004a, 0x0100},
306e6213840SShawn Tu 	{0x004c, 0x0000},
307e6213840SShawn Tu 	{0x004e, 0x0100},
308e6213840SShawn Tu 	{0x000c, 0x0022},
309e6213840SShawn Tu 	{0x0008, 0x0b00},
310e6213840SShawn Tu 	{0x005a, 0x0202},
311e6213840SShawn Tu 	{0x0012, 0x000e},
312e6213840SShawn Tu 	{0x0018, 0x0a33},
313e6213840SShawn Tu 	{0x0022, 0x0008},
314e6213840SShawn Tu 	{0x0028, 0x0017},
315e6213840SShawn Tu 	{0x0024, 0x0028},
316e6213840SShawn Tu 	{0x002a, 0x002d},
317e6213840SShawn Tu 	{0x0026, 0x0030},
318e6213840SShawn Tu 	{0x002c, 0x07c9},
319e6213840SShawn Tu 	{0x002e, 0x1111},
320e6213840SShawn Tu 	{0x0030, 0x1111},
321e6213840SShawn Tu 	{0x0032, 0x1111},
322e6213840SShawn Tu 	{0x0006, 0x07bc},
323e6213840SShawn Tu 	{0x0a22, 0x0000},
324e6213840SShawn Tu 	{0x0a12, 0x0a20},
325e6213840SShawn Tu 	{0x0a14, 0x0798},
326e6213840SShawn Tu 	{0x003e, 0x0000},
327e6213840SShawn Tu 	{0x0074, 0x080e},
328e6213840SShawn Tu 	{0x0070, 0x0407},
329e6213840SShawn Tu 	{0x0002, 0x0000},
330e6213840SShawn Tu 	{0x0a02, 0x0100},
331e6213840SShawn Tu 	{0x0a24, 0x0100},
332e6213840SShawn Tu 	{0x0046, 0x0000},
333e6213840SShawn Tu 	{0x0076, 0x0000},
334e6213840SShawn Tu 	{0x0060, 0x0000},
335e6213840SShawn Tu 	{0x0062, 0x0530},
336e6213840SShawn Tu 	{0x0064, 0x0500},
337e6213840SShawn Tu 	{0x0066, 0x0530},
338e6213840SShawn Tu 	{0x0068, 0x0500},
339e6213840SShawn Tu 	{0x0122, 0x0300},
340e6213840SShawn Tu 	{0x015a, 0xff08},
341e6213840SShawn Tu 	{0x0804, 0x0300},
342e6213840SShawn Tu 	{0x0806, 0x0100},
343e6213840SShawn Tu 	{0x005c, 0x0102},
344e6213840SShawn Tu 	{0x0a1a, 0x0800},
345e6213840SShawn Tu };
346e6213840SShawn Tu 
347e6213840SShawn Tu static const struct hi556_reg mode_2592x1944_regs[] = {
348e6213840SShawn Tu 	{0x0a00, 0x0000},
349e6213840SShawn Tu 	{0x0b0a, 0x8252},
350e6213840SShawn Tu 	{0x0f30, 0x5b15},
351e6213840SShawn Tu 	{0x0f32, 0x7067},
352e6213840SShawn Tu 	{0x004a, 0x0100},
353e6213840SShawn Tu 	{0x004c, 0x0000},
354e6213840SShawn Tu 	{0x004e, 0x0100},
355e6213840SShawn Tu 	{0x000c, 0x0022},
356e6213840SShawn Tu 	{0x0008, 0x0b00},
357e6213840SShawn Tu 	{0x005a, 0x0202},
358e6213840SShawn Tu 	{0x0012, 0x000e},
359e6213840SShawn Tu 	{0x0018, 0x0a33},
360e6213840SShawn Tu 	{0x0022, 0x0008},
361e6213840SShawn Tu 	{0x0028, 0x0017},
362e6213840SShawn Tu 	{0x0024, 0x0028},
363e6213840SShawn Tu 	{0x002a, 0x002d},
364e6213840SShawn Tu 	{0x0026, 0x0030},
365e6213840SShawn Tu 	{0x002c, 0x07c9},
366e6213840SShawn Tu 	{0x002e, 0x1111},
367e6213840SShawn Tu 	{0x0030, 0x1111},
368e6213840SShawn Tu 	{0x0032, 0x1111},
369e6213840SShawn Tu 	{0x0006, 0x0814},
370e6213840SShawn Tu 	{0x0a22, 0x0000},
371e6213840SShawn Tu 	{0x0a12, 0x0a20},
372e6213840SShawn Tu 	{0x0a14, 0x0798},
373e6213840SShawn Tu 	{0x003e, 0x0000},
374e6213840SShawn Tu 	{0x0074, 0x0812},
375e6213840SShawn Tu 	{0x0070, 0x0409},
376e6213840SShawn Tu 	{0x0804, 0x0300},
377e6213840SShawn Tu 	{0x0806, 0x0100},
378e6213840SShawn Tu 	{0x0a04, 0x014a},
379e6213840SShawn Tu 	{0x090c, 0x0fdc},
380e6213840SShawn Tu 	{0x090e, 0x002d},
381e6213840SShawn Tu 
382e6213840SShawn Tu 	{0x0902, 0x4319},
383e6213840SShawn Tu 	{0x0914, 0xc10a},
384e6213840SShawn Tu 	{0x0916, 0x071f},
385e6213840SShawn Tu 	{0x0918, 0x0408},
386e6213840SShawn Tu 	{0x091a, 0x0c0d},
387e6213840SShawn Tu 	{0x091c, 0x0f09},
388e6213840SShawn Tu 	{0x091e, 0x0a00},
389e6213840SShawn Tu 	{0x0958, 0xbb80},
390e6213840SShawn Tu };
391e6213840SShawn Tu 
392c0bc1ca0SJim Lai static const struct hi556_reg mode_2592x1444_regs[] = {
393c0bc1ca0SJim Lai 	{0x0a00, 0x0000},
394c0bc1ca0SJim Lai 	{0x0b0a, 0x8252},
395c0bc1ca0SJim Lai 	{0x0f30, 0xe545},
396c0bc1ca0SJim Lai 	{0x0f32, 0x7067},
397c0bc1ca0SJim Lai 	{0x004a, 0x0100},
398c0bc1ca0SJim Lai 	{0x004c, 0x0000},
399c0bc1ca0SJim Lai 	{0x000c, 0x0022},
400c0bc1ca0SJim Lai 	{0x0008, 0x0b00},
401c0bc1ca0SJim Lai 	{0x005a, 0x0202},
402c0bc1ca0SJim Lai 	{0x0012, 0x000e},
403c0bc1ca0SJim Lai 	{0x0018, 0x0a33},
404c0bc1ca0SJim Lai 	{0x0022, 0x0008},
405c0bc1ca0SJim Lai 	{0x0028, 0x0017},
406c0bc1ca0SJim Lai 	{0x0024, 0x0122},
407c0bc1ca0SJim Lai 	{0x002a, 0x0127},
408c0bc1ca0SJim Lai 	{0x0026, 0x012a},
409c0bc1ca0SJim Lai 	{0x002c, 0x06cf},
410c0bc1ca0SJim Lai 	{0x002e, 0x1111},
411c0bc1ca0SJim Lai 	{0x0030, 0x1111},
412c0bc1ca0SJim Lai 	{0x0032, 0x1111},
413c0bc1ca0SJim Lai 	{0x0006, 0x0821},
414c0bc1ca0SJim Lai 	{0x0a22, 0x0000},
415c0bc1ca0SJim Lai 	{0x0a12, 0x0a20},
416c0bc1ca0SJim Lai 	{0x0a14, 0x05a4},
417c0bc1ca0SJim Lai 	{0x003e, 0x0000},
418c0bc1ca0SJim Lai 	{0x0074, 0x081f},
419c0bc1ca0SJim Lai 	{0x0070, 0x040f},
420c0bc1ca0SJim Lai 	{0x0804, 0x0300},
421c0bc1ca0SJim Lai 	{0x0806, 0x0100},
422c0bc1ca0SJim Lai 	{0x0a04, 0x014a},
423c0bc1ca0SJim Lai 	{0x090c, 0x0fdc},
424c0bc1ca0SJim Lai 	{0x090e, 0x002d},
425c0bc1ca0SJim Lai 	{0x0902, 0x4319},
426c0bc1ca0SJim Lai 	{0x0914, 0xc10a},
427c0bc1ca0SJim Lai 	{0x0916, 0x071f},
428c0bc1ca0SJim Lai 	{0x0918, 0x0408},
429c0bc1ca0SJim Lai 	{0x091a, 0x0c0d},
430c0bc1ca0SJim Lai 	{0x091c, 0x0f09},
431c0bc1ca0SJim Lai 	{0x091e, 0x0a00},
432c0bc1ca0SJim Lai 	{0x0958, 0xbb80},
433c0bc1ca0SJim Lai };
434c0bc1ca0SJim Lai 
435e6213840SShawn Tu static const struct hi556_reg mode_1296x972_regs[] = {
436e6213840SShawn Tu 	{0x0a00, 0x0000},
437e6213840SShawn Tu 	{0x0b0a, 0x8259},
438e6213840SShawn Tu 	{0x0f30, 0x5b15},
439e6213840SShawn Tu 	{0x0f32, 0x7167},
440e6213840SShawn Tu 	{0x004a, 0x0100},
441e6213840SShawn Tu 	{0x004c, 0x0000},
442e6213840SShawn Tu 	{0x004e, 0x0100},
443e6213840SShawn Tu 	{0x000c, 0x0122},
444e6213840SShawn Tu 	{0x0008, 0x0b00},
445e6213840SShawn Tu 	{0x005a, 0x0404},
446e6213840SShawn Tu 	{0x0012, 0x000c},
447e6213840SShawn Tu 	{0x0018, 0x0a33},
448e6213840SShawn Tu 	{0x0022, 0x0008},
449e6213840SShawn Tu 	{0x0028, 0x0017},
450e6213840SShawn Tu 	{0x0024, 0x0022},
451e6213840SShawn Tu 	{0x002a, 0x002b},
452e6213840SShawn Tu 	{0x0026, 0x0030},
453e6213840SShawn Tu 	{0x002c, 0x07c9},
454e6213840SShawn Tu 	{0x002e, 0x3311},
455e6213840SShawn Tu 	{0x0030, 0x3311},
456e6213840SShawn Tu 	{0x0032, 0x3311},
457e6213840SShawn Tu 	{0x0006, 0x0814},
458e6213840SShawn Tu 	{0x0a22, 0x0000},
459e6213840SShawn Tu 	{0x0a12, 0x0510},
460e6213840SShawn Tu 	{0x0a14, 0x03cc},
461e6213840SShawn Tu 	{0x003e, 0x0000},
462e6213840SShawn Tu 	{0x0074, 0x0812},
463e6213840SShawn Tu 	{0x0070, 0x0409},
464e6213840SShawn Tu 	{0x0804, 0x0308},
465e6213840SShawn Tu 	{0x0806, 0x0100},
466e6213840SShawn Tu 	{0x0a04, 0x016a},
467e6213840SShawn Tu 	{0x090e, 0x0010},
468e6213840SShawn Tu 	{0x090c, 0x09c0},
469e6213840SShawn Tu 
470e6213840SShawn Tu 	{0x0902, 0x4319},
471e6213840SShawn Tu 	{0x0914, 0xc106},
472e6213840SShawn Tu 	{0x0916, 0x040e},
473e6213840SShawn Tu 	{0x0918, 0x0304},
474e6213840SShawn Tu 	{0x091a, 0x0708},
475e6213840SShawn Tu 	{0x091c, 0x0e06},
476e6213840SShawn Tu 	{0x091e, 0x0300},
477e6213840SShawn Tu 	{0x0958, 0xbb80},
478e6213840SShawn Tu };
479e6213840SShawn Tu 
480e6213840SShawn Tu static const char * const hi556_test_pattern_menu[] = {
481e6213840SShawn Tu 	"Disabled",
482e6213840SShawn Tu 	"Solid Colour",
483e6213840SShawn Tu 	"100% Colour Bars",
484e6213840SShawn Tu 	"Fade To Grey Colour Bars",
485e6213840SShawn Tu 	"PN9",
486e6213840SShawn Tu 	"Gradient Horizontal",
487e6213840SShawn Tu 	"Gradient Vertical",
488e6213840SShawn Tu 	"Check Board",
489e6213840SShawn Tu 	"Slant Pattern",
490e6213840SShawn Tu };
491e6213840SShawn Tu 
492e6213840SShawn Tu static const s64 link_freq_menu_items[] = {
493e6213840SShawn Tu 	HI556_LINK_FREQ_437MHZ,
494e6213840SShawn Tu };
495e6213840SShawn Tu 
496e6213840SShawn Tu static const struct hi556_link_freq_config link_freq_configs[] = {
497e6213840SShawn Tu 	[HI556_LINK_FREQ_437MHZ_INDEX] = {
498e6213840SShawn Tu 		.reg_list = {
499e6213840SShawn Tu 			.num_of_regs = ARRAY_SIZE(mipi_data_rate_874mbps),
500e6213840SShawn Tu 			.regs = mipi_data_rate_874mbps,
501e6213840SShawn Tu 		}
502e6213840SShawn Tu 	}
503e6213840SShawn Tu };
504e6213840SShawn Tu 
505e6213840SShawn Tu static const struct hi556_mode supported_modes[] = {
506e6213840SShawn Tu 	{
507c0bc1ca0SJim Lai 		.width = HI556_PIXEL_ARRAY_WIDTH,
508c0bc1ca0SJim Lai 		.height = HI556_PIXEL_ARRAY_HEIGHT,
509c0bc1ca0SJim Lai 		.crop = {
510c0bc1ca0SJim Lai 			.left = HI556_PIXEL_ARRAY_LEFT,
511c0bc1ca0SJim Lai 			.top = HI556_PIXEL_ARRAY_TOP,
512c0bc1ca0SJim Lai 			.width = HI556_PIXEL_ARRAY_WIDTH,
513c0bc1ca0SJim Lai 			.height = HI556_PIXEL_ARRAY_HEIGHT
514c0bc1ca0SJim Lai 		},
515e6213840SShawn Tu 		.fll_def = HI556_FLL_30FPS,
516e6213840SShawn Tu 		.fll_min = HI556_FLL_30FPS_MIN,
517e6213840SShawn Tu 		.llp = 0x0b00,
518e6213840SShawn Tu 		.reg_list = {
519e6213840SShawn Tu 			.num_of_regs = ARRAY_SIZE(mode_2592x1944_regs),
520e6213840SShawn Tu 			.regs = mode_2592x1944_regs,
521e6213840SShawn Tu 		},
522e6213840SShawn Tu 		.link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX,
523e6213840SShawn Tu 	},
524e6213840SShawn Tu 	{
525c0bc1ca0SJim Lai 		.width = HI556_PIXEL_ARRAY_WIDTH,
526c0bc1ca0SJim Lai 		.height = 1444,
527c0bc1ca0SJim Lai 		.crop = {
528c0bc1ca0SJim Lai 			.left = HI556_PIXEL_ARRAY_LEFT,
529c0bc1ca0SJim Lai 			.top = 250,
530c0bc1ca0SJim Lai 			.width = HI556_PIXEL_ARRAY_WIDTH,
531c0bc1ca0SJim Lai 			.height = 1444
532c0bc1ca0SJim Lai 		},
533c0bc1ca0SJim Lai 		.fll_def = 0x821,
534c0bc1ca0SJim Lai 		.fll_min = 0x821,
535c0bc1ca0SJim Lai 		.llp = 0x0b00,
536c0bc1ca0SJim Lai 		.reg_list = {
537c0bc1ca0SJim Lai 			.num_of_regs = ARRAY_SIZE(mode_2592x1444_regs),
538c0bc1ca0SJim Lai 			.regs = mode_2592x1444_regs,
539c0bc1ca0SJim Lai 		},
540c0bc1ca0SJim Lai 		.link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX,
541c0bc1ca0SJim Lai 	},
542c0bc1ca0SJim Lai 	{
543e6213840SShawn Tu 		.width = 1296,
544e6213840SShawn Tu 		.height = 972,
545c0bc1ca0SJim Lai 		.crop = {
546c0bc1ca0SJim Lai 			.left = HI556_PIXEL_ARRAY_LEFT,
547c0bc1ca0SJim Lai 			.top = HI556_PIXEL_ARRAY_TOP,
548c0bc1ca0SJim Lai 			.width = HI556_PIXEL_ARRAY_WIDTH,
549c0bc1ca0SJim Lai 			.height = HI556_PIXEL_ARRAY_HEIGHT
550c0bc1ca0SJim Lai 		},
551e6213840SShawn Tu 		.fll_def = HI556_FLL_30FPS,
552e6213840SShawn Tu 		.fll_min = HI556_FLL_30FPS_MIN,
553e6213840SShawn Tu 		.llp = 0x0b00,
554e6213840SShawn Tu 		.reg_list = {
555e6213840SShawn Tu 			.num_of_regs = ARRAY_SIZE(mode_1296x972_regs),
556e6213840SShawn Tu 			.regs = mode_1296x972_regs,
557e6213840SShawn Tu 		},
558e6213840SShawn Tu 		.link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX,
559e6213840SShawn Tu 	}
560e6213840SShawn Tu };
561e6213840SShawn Tu 
562e6213840SShawn Tu struct hi556 {
563e6213840SShawn Tu 	struct v4l2_subdev sd;
564e6213840SShawn Tu 	struct media_pad pad;
565e6213840SShawn Tu 	struct v4l2_ctrl_handler ctrl_handler;
566e6213840SShawn Tu 
567e6213840SShawn Tu 	/* V4L2 Controls */
568e6213840SShawn Tu 	struct v4l2_ctrl *link_freq;
569e6213840SShawn Tu 	struct v4l2_ctrl *pixel_rate;
570e6213840SShawn Tu 	struct v4l2_ctrl *vblank;
571e6213840SShawn Tu 	struct v4l2_ctrl *hblank;
572e6213840SShawn Tu 	struct v4l2_ctrl *exposure;
573e6213840SShawn Tu 
574e6213840SShawn Tu 	/* Current mode */
575e6213840SShawn Tu 	const struct hi556_mode *cur_mode;
576e6213840SShawn Tu 
577e6213840SShawn Tu 	/* To serialize asynchronus callbacks */
578e6213840SShawn Tu 	struct mutex mutex;
579e6213840SShawn Tu 
580e6213840SShawn Tu 	/* Streaming on/off */
581e6213840SShawn Tu 	bool streaming;
582d1d2ed59SBingbu Cao 
583d1d2ed59SBingbu Cao 	/* True if the device has been identified */
584d1d2ed59SBingbu Cao 	bool identified;
585e6213840SShawn Tu };
586e6213840SShawn Tu 
to_pixel_rate(u32 f_index)587e6213840SShawn Tu static u64 to_pixel_rate(u32 f_index)
588e6213840SShawn Tu {
589e6213840SShawn Tu 	u64 pixel_rate = link_freq_menu_items[f_index] * 2 * HI556_DATA_LANES;
590e6213840SShawn Tu 
591e6213840SShawn Tu 	do_div(pixel_rate, HI556_RGB_DEPTH);
592e6213840SShawn Tu 
593e6213840SShawn Tu 	return pixel_rate;
594e6213840SShawn Tu }
595e6213840SShawn Tu 
hi556_read_reg(struct hi556 * hi556,u16 reg,u16 len,u32 * val)596e6213840SShawn Tu static int hi556_read_reg(struct hi556 *hi556, u16 reg, u16 len, u32 *val)
597e6213840SShawn Tu {
598e6213840SShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd);
599e6213840SShawn Tu 	struct i2c_msg msgs[2];
600e6213840SShawn Tu 	u8 addr_buf[2];
601e6213840SShawn Tu 	u8 data_buf[4] = {0};
602e6213840SShawn Tu 	int ret;
603e6213840SShawn Tu 
604e6213840SShawn Tu 	if (len > 4)
605e6213840SShawn Tu 		return -EINVAL;
606e6213840SShawn Tu 
607e6213840SShawn Tu 	put_unaligned_be16(reg, addr_buf);
608e6213840SShawn Tu 	msgs[0].addr = client->addr;
609e6213840SShawn Tu 	msgs[0].flags = 0;
610e6213840SShawn Tu 	msgs[0].len = sizeof(addr_buf);
611e6213840SShawn Tu 	msgs[0].buf = addr_buf;
612e6213840SShawn Tu 	msgs[1].addr = client->addr;
613e6213840SShawn Tu 	msgs[1].flags = I2C_M_RD;
614e6213840SShawn Tu 	msgs[1].len = len;
615e6213840SShawn Tu 	msgs[1].buf = &data_buf[4 - len];
616e6213840SShawn Tu 
617e6213840SShawn Tu 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
618e6213840SShawn Tu 	if (ret != ARRAY_SIZE(msgs))
619e6213840SShawn Tu 		return -EIO;
620e6213840SShawn Tu 
621e6213840SShawn Tu 	*val = get_unaligned_be32(data_buf);
622e6213840SShawn Tu 
623e6213840SShawn Tu 	return 0;
624e6213840SShawn Tu }
625e6213840SShawn Tu 
hi556_write_reg(struct hi556 * hi556,u16 reg,u16 len,u32 val)626e6213840SShawn Tu static int hi556_write_reg(struct hi556 *hi556, u16 reg, u16 len, u32 val)
627e6213840SShawn Tu {
628e6213840SShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd);
629e6213840SShawn Tu 	u8 buf[6];
630e6213840SShawn Tu 
631e6213840SShawn Tu 	if (len > 4)
632e6213840SShawn Tu 		return -EINVAL;
633e6213840SShawn Tu 
634e6213840SShawn Tu 	put_unaligned_be16(reg, buf);
635e6213840SShawn Tu 	put_unaligned_be32(val << 8 * (4 - len), buf + 2);
636e6213840SShawn Tu 	if (i2c_master_send(client, buf, len + 2) != len + 2)
637e6213840SShawn Tu 		return -EIO;
638e6213840SShawn Tu 
639e6213840SShawn Tu 	return 0;
640e6213840SShawn Tu }
641e6213840SShawn Tu 
hi556_write_reg_list(struct hi556 * hi556,const struct hi556_reg_list * r_list)642e6213840SShawn Tu static int hi556_write_reg_list(struct hi556 *hi556,
643e6213840SShawn Tu 				const struct hi556_reg_list *r_list)
644e6213840SShawn Tu {
645e6213840SShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd);
646e6213840SShawn Tu 	unsigned int i;
647e6213840SShawn Tu 	int ret;
648e6213840SShawn Tu 
649e6213840SShawn Tu 	for (i = 0; i < r_list->num_of_regs; i++) {
650e6213840SShawn Tu 		ret = hi556_write_reg(hi556, r_list->regs[i].address,
651e6213840SShawn Tu 				      HI556_REG_VALUE_16BIT,
652e6213840SShawn Tu 				      r_list->regs[i].val);
653e6213840SShawn Tu 		if (ret) {
654e6213840SShawn Tu 			dev_err_ratelimited(&client->dev,
655e6213840SShawn Tu 					    "failed to write reg 0x%4.4x. error = %d",
656e6213840SShawn Tu 					    r_list->regs[i].address, ret);
657e6213840SShawn Tu 			return ret;
658e6213840SShawn Tu 		}
659e6213840SShawn Tu 	}
660e6213840SShawn Tu 
661e6213840SShawn Tu 	return 0;
662e6213840SShawn Tu }
663e6213840SShawn Tu 
hi556_update_digital_gain(struct hi556 * hi556,u32 d_gain)664e6213840SShawn Tu static int hi556_update_digital_gain(struct hi556 *hi556, u32 d_gain)
665e6213840SShawn Tu {
666e6213840SShawn Tu 	int ret;
667e6213840SShawn Tu 
668e6213840SShawn Tu 	ret = hi556_write_reg(hi556, HI556_REG_MWB_GR_GAIN,
669e6213840SShawn Tu 			      HI556_REG_VALUE_16BIT, d_gain);
670e6213840SShawn Tu 	if (ret)
671e6213840SShawn Tu 		return ret;
672e6213840SShawn Tu 
673e6213840SShawn Tu 	ret = hi556_write_reg(hi556, HI556_REG_MWB_GB_GAIN,
674e6213840SShawn Tu 			      HI556_REG_VALUE_16BIT, d_gain);
675e6213840SShawn Tu 	if (ret)
676e6213840SShawn Tu 		return ret;
677e6213840SShawn Tu 
678e6213840SShawn Tu 	ret = hi556_write_reg(hi556, HI556_REG_MWB_R_GAIN,
679e6213840SShawn Tu 			      HI556_REG_VALUE_16BIT, d_gain);
680e6213840SShawn Tu 	if (ret)
681e6213840SShawn Tu 		return ret;
682e6213840SShawn Tu 
683e6213840SShawn Tu 	return hi556_write_reg(hi556, HI556_REG_MWB_B_GAIN,
684e6213840SShawn Tu 			       HI556_REG_VALUE_16BIT, d_gain);
685e6213840SShawn Tu }
686e6213840SShawn Tu 
hi556_test_pattern(struct hi556 * hi556,u32 pattern)687e6213840SShawn Tu static int hi556_test_pattern(struct hi556 *hi556, u32 pattern)
688e6213840SShawn Tu {
689e6213840SShawn Tu 	int ret;
690e6213840SShawn Tu 	u32 val;
691e6213840SShawn Tu 
692e6213840SShawn Tu 	if (pattern) {
693e6213840SShawn Tu 		ret = hi556_read_reg(hi556, HI556_REG_ISP,
694e6213840SShawn Tu 				     HI556_REG_VALUE_08BIT, &val);
695e6213840SShawn Tu 		if (ret)
696e6213840SShawn Tu 			return ret;
697e6213840SShawn Tu 
698e6213840SShawn Tu 		ret = hi556_write_reg(hi556, HI556_REG_ISP,
699e6213840SShawn Tu 				      HI556_REG_VALUE_08BIT,
700e6213840SShawn Tu 				      val | HI556_REG_ISP_TPG_EN);
701e6213840SShawn Tu 		if (ret)
702e6213840SShawn Tu 			return ret;
703e6213840SShawn Tu 	}
704e6213840SShawn Tu 
705e6213840SShawn Tu 	return hi556_write_reg(hi556, HI556_REG_TEST_PATTERN,
706e6213840SShawn Tu 			       HI556_REG_VALUE_08BIT, pattern);
707e6213840SShawn Tu }
708e6213840SShawn Tu 
hi556_set_ctrl(struct v4l2_ctrl * ctrl)709e6213840SShawn Tu static int hi556_set_ctrl(struct v4l2_ctrl *ctrl)
710e6213840SShawn Tu {
711e6213840SShawn Tu 	struct hi556 *hi556 = container_of(ctrl->handler,
712e6213840SShawn Tu 					     struct hi556, ctrl_handler);
713e6213840SShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd);
714e6213840SShawn Tu 	s64 exposure_max;
715e6213840SShawn Tu 	int ret = 0;
716e6213840SShawn Tu 
717e6213840SShawn Tu 	/* Propagate change of current control to all related controls */
718e6213840SShawn Tu 	if (ctrl->id == V4L2_CID_VBLANK) {
719e6213840SShawn Tu 		/* Update max exposure while meeting expected vblanking */
720e6213840SShawn Tu 		exposure_max = hi556->cur_mode->height + ctrl->val -
721e6213840SShawn Tu 			       HI556_EXPOSURE_MAX_MARGIN;
722e6213840SShawn Tu 		__v4l2_ctrl_modify_range(hi556->exposure,
723e6213840SShawn Tu 					 hi556->exposure->minimum,
724e6213840SShawn Tu 					 exposure_max, hi556->exposure->step,
725e6213840SShawn Tu 					 exposure_max);
726e6213840SShawn Tu 	}
727e6213840SShawn Tu 
728e6213840SShawn Tu 	/* V4L2 controls values will be applied only when power is already up */
729e6213840SShawn Tu 	if (!pm_runtime_get_if_in_use(&client->dev))
730e6213840SShawn Tu 		return 0;
731e6213840SShawn Tu 
732e6213840SShawn Tu 	switch (ctrl->id) {
733e6213840SShawn Tu 	case V4L2_CID_ANALOGUE_GAIN:
734e6213840SShawn Tu 		ret = hi556_write_reg(hi556, HI556_REG_ANALOG_GAIN,
735e6213840SShawn Tu 				      HI556_REG_VALUE_16BIT, ctrl->val);
736e6213840SShawn Tu 		break;
737e6213840SShawn Tu 
738e6213840SShawn Tu 	case V4L2_CID_DIGITAL_GAIN:
739e6213840SShawn Tu 		ret = hi556_update_digital_gain(hi556, ctrl->val);
740e6213840SShawn Tu 		break;
741e6213840SShawn Tu 
742e6213840SShawn Tu 	case V4L2_CID_EXPOSURE:
743e6213840SShawn Tu 		ret = hi556_write_reg(hi556, HI556_REG_EXPOSURE,
744e6213840SShawn Tu 				      HI556_REG_VALUE_16BIT, ctrl->val);
745e6213840SShawn Tu 		break;
746e6213840SShawn Tu 
747e6213840SShawn Tu 	case V4L2_CID_VBLANK:
748e6213840SShawn Tu 		/* Update FLL that meets expected vertical blanking */
749e6213840SShawn Tu 		ret = hi556_write_reg(hi556, HI556_REG_FLL,
750e6213840SShawn Tu 				      HI556_REG_VALUE_16BIT,
751e6213840SShawn Tu 				      hi556->cur_mode->height + ctrl->val);
752e6213840SShawn Tu 		break;
753e6213840SShawn Tu 
754e6213840SShawn Tu 	case V4L2_CID_TEST_PATTERN:
755e6213840SShawn Tu 		ret = hi556_test_pattern(hi556, ctrl->val);
756e6213840SShawn Tu 		break;
757e6213840SShawn Tu 
758e6213840SShawn Tu 	default:
759e6213840SShawn Tu 		ret = -EINVAL;
760e6213840SShawn Tu 		break;
761e6213840SShawn Tu 	}
762e6213840SShawn Tu 
763e6213840SShawn Tu 	pm_runtime_put(&client->dev);
764e6213840SShawn Tu 
765e6213840SShawn Tu 	return ret;
766e6213840SShawn Tu }
767e6213840SShawn Tu 
768e6213840SShawn Tu static const struct v4l2_ctrl_ops hi556_ctrl_ops = {
769e6213840SShawn Tu 	.s_ctrl = hi556_set_ctrl,
770e6213840SShawn Tu };
771e6213840SShawn Tu 
hi556_init_controls(struct hi556 * hi556)772e6213840SShawn Tu static int hi556_init_controls(struct hi556 *hi556)
773e6213840SShawn Tu {
774e6213840SShawn Tu 	struct v4l2_ctrl_handler *ctrl_hdlr;
775e6213840SShawn Tu 	s64 exposure_max, h_blank;
776e6213840SShawn Tu 	int ret;
777e6213840SShawn Tu 
778e6213840SShawn Tu 	ctrl_hdlr = &hi556->ctrl_handler;
779e6213840SShawn Tu 	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
780e6213840SShawn Tu 	if (ret)
781e6213840SShawn Tu 		return ret;
782e6213840SShawn Tu 
783e6213840SShawn Tu 	ctrl_hdlr->lock = &hi556->mutex;
784e6213840SShawn Tu 	hi556->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &hi556_ctrl_ops,
785e6213840SShawn Tu 						  V4L2_CID_LINK_FREQ,
786e6213840SShawn Tu 					ARRAY_SIZE(link_freq_menu_items) - 1,
787e6213840SShawn Tu 					0, link_freq_menu_items);
788e6213840SShawn Tu 	if (hi556->link_freq)
789e6213840SShawn Tu 		hi556->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
790e6213840SShawn Tu 
791e6213840SShawn Tu 	hi556->pixel_rate = v4l2_ctrl_new_std
792e6213840SShawn Tu 			    (ctrl_hdlr, &hi556_ctrl_ops,
793e6213840SShawn Tu 			     V4L2_CID_PIXEL_RATE, 0,
794e6213840SShawn Tu 			     to_pixel_rate(HI556_LINK_FREQ_437MHZ_INDEX),
795e6213840SShawn Tu 			     1,
796e6213840SShawn Tu 			     to_pixel_rate(HI556_LINK_FREQ_437MHZ_INDEX));
797e6213840SShawn Tu 	hi556->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &hi556_ctrl_ops,
798e6213840SShawn Tu 					  V4L2_CID_VBLANK,
799e6213840SShawn Tu 					  hi556->cur_mode->fll_min -
800e6213840SShawn Tu 					  hi556->cur_mode->height,
801e6213840SShawn Tu 					  HI556_FLL_MAX -
802e6213840SShawn Tu 					  hi556->cur_mode->height, 1,
803e6213840SShawn Tu 					  hi556->cur_mode->fll_def -
804e6213840SShawn Tu 					  hi556->cur_mode->height);
805e6213840SShawn Tu 
806e6213840SShawn Tu 	h_blank = hi556->cur_mode->llp - hi556->cur_mode->width;
807e6213840SShawn Tu 
808e6213840SShawn Tu 	hi556->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &hi556_ctrl_ops,
809e6213840SShawn Tu 					  V4L2_CID_HBLANK, h_blank, h_blank, 1,
810e6213840SShawn Tu 					  h_blank);
811e6213840SShawn Tu 	if (hi556->hblank)
812e6213840SShawn Tu 		hi556->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
813e6213840SShawn Tu 
814e6213840SShawn Tu 	v4l2_ctrl_new_std(ctrl_hdlr, &hi556_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
815e6213840SShawn Tu 			  HI556_ANAL_GAIN_MIN, HI556_ANAL_GAIN_MAX,
816e6213840SShawn Tu 			  HI556_ANAL_GAIN_STEP, HI556_ANAL_GAIN_MIN);
817e6213840SShawn Tu 	v4l2_ctrl_new_std(ctrl_hdlr, &hi556_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
818e6213840SShawn Tu 			  HI556_DGTL_GAIN_MIN, HI556_DGTL_GAIN_MAX,
819e6213840SShawn Tu 			  HI556_DGTL_GAIN_STEP, HI556_DGTL_GAIN_DEFAULT);
820e6213840SShawn Tu 	exposure_max = hi556->cur_mode->fll_def - HI556_EXPOSURE_MAX_MARGIN;
821e6213840SShawn Tu 	hi556->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &hi556_ctrl_ops,
822e6213840SShawn Tu 					    V4L2_CID_EXPOSURE,
823e6213840SShawn Tu 					    HI556_EXPOSURE_MIN, exposure_max,
824e6213840SShawn Tu 					    HI556_EXPOSURE_STEP,
825e6213840SShawn Tu 					    exposure_max);
826e6213840SShawn Tu 	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &hi556_ctrl_ops,
827e6213840SShawn Tu 				     V4L2_CID_TEST_PATTERN,
828e6213840SShawn Tu 				     ARRAY_SIZE(hi556_test_pattern_menu) - 1,
829e6213840SShawn Tu 				     0, 0, hi556_test_pattern_menu);
830e6213840SShawn Tu 	if (ctrl_hdlr->error)
831e6213840SShawn Tu 		return ctrl_hdlr->error;
832e6213840SShawn Tu 
833e6213840SShawn Tu 	hi556->sd.ctrl_handler = ctrl_hdlr;
834e6213840SShawn Tu 
835e6213840SShawn Tu 	return 0;
836e6213840SShawn Tu }
837e6213840SShawn Tu 
hi556_assign_pad_format(const struct hi556_mode * mode,struct v4l2_mbus_framefmt * fmt)838e6213840SShawn Tu static void hi556_assign_pad_format(const struct hi556_mode *mode,
839e6213840SShawn Tu 				    struct v4l2_mbus_framefmt *fmt)
840e6213840SShawn Tu {
841e6213840SShawn Tu 	fmt->width = mode->width;
842e6213840SShawn Tu 	fmt->height = mode->height;
843e6213840SShawn Tu 	fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
844e6213840SShawn Tu 	fmt->field = V4L2_FIELD_NONE;
845e6213840SShawn Tu }
846e6213840SShawn Tu 
hi556_identify_module(struct hi556 * hi556)847d1d2ed59SBingbu Cao static int hi556_identify_module(struct hi556 *hi556)
848d1d2ed59SBingbu Cao {
849d1d2ed59SBingbu Cao 	struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd);
850d1d2ed59SBingbu Cao 	int ret;
851d1d2ed59SBingbu Cao 	u32 val;
852d1d2ed59SBingbu Cao 
853d1d2ed59SBingbu Cao 	if (hi556->identified)
854d1d2ed59SBingbu Cao 		return 0;
855d1d2ed59SBingbu Cao 
856d1d2ed59SBingbu Cao 	ret = hi556_read_reg(hi556, HI556_REG_CHIP_ID,
857d1d2ed59SBingbu Cao 			     HI556_REG_VALUE_16BIT, &val);
858d1d2ed59SBingbu Cao 	if (ret)
859d1d2ed59SBingbu Cao 		return ret;
860d1d2ed59SBingbu Cao 
861d1d2ed59SBingbu Cao 	if (val != HI556_CHIP_ID) {
862d1d2ed59SBingbu Cao 		dev_err(&client->dev, "chip id mismatch: %x!=%x",
863d1d2ed59SBingbu Cao 			HI556_CHIP_ID, val);
864d1d2ed59SBingbu Cao 		return -ENXIO;
865d1d2ed59SBingbu Cao 	}
866d1d2ed59SBingbu Cao 
867d1d2ed59SBingbu Cao 	hi556->identified = true;
868d1d2ed59SBingbu Cao 
869d1d2ed59SBingbu Cao 	return 0;
870d1d2ed59SBingbu Cao }
871d1d2ed59SBingbu Cao 
872c0bc1ca0SJim Lai static const struct v4l2_rect *
__hi556_get_pad_crop(struct hi556 * hi556,struct v4l2_subdev_state * sd_state,unsigned int pad,enum v4l2_subdev_format_whence which)873c0bc1ca0SJim Lai __hi556_get_pad_crop(struct hi556 *hi556,
874c0bc1ca0SJim Lai 		     struct v4l2_subdev_state *sd_state,
875c0bc1ca0SJim Lai 		     unsigned int pad, enum v4l2_subdev_format_whence which)
876c0bc1ca0SJim Lai {
877c0bc1ca0SJim Lai 	switch (which) {
878c0bc1ca0SJim Lai 	case V4L2_SUBDEV_FORMAT_TRY:
879c0bc1ca0SJim Lai 		return v4l2_subdev_get_try_crop(&hi556->sd, sd_state, pad);
880c0bc1ca0SJim Lai 	case V4L2_SUBDEV_FORMAT_ACTIVE:
881c0bc1ca0SJim Lai 		return &hi556->cur_mode->crop;
882c0bc1ca0SJim Lai 	}
883c0bc1ca0SJim Lai 
884c0bc1ca0SJim Lai 	return NULL;
885c0bc1ca0SJim Lai }
886c0bc1ca0SJim Lai 
hi556_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_selection * sel)887c0bc1ca0SJim Lai static int hi556_get_selection(struct v4l2_subdev *sd,
888c0bc1ca0SJim Lai 			       struct v4l2_subdev_state *sd_state,
889c0bc1ca0SJim Lai 			       struct v4l2_subdev_selection *sel)
890c0bc1ca0SJim Lai {
891c0bc1ca0SJim Lai 	switch (sel->target) {
892c0bc1ca0SJim Lai 	case V4L2_SEL_TGT_CROP: {
893c0bc1ca0SJim Lai 		struct hi556 *hi556 = to_hi556(sd);
894c0bc1ca0SJim Lai 
895c0bc1ca0SJim Lai 		mutex_lock(&hi556->mutex);
896c0bc1ca0SJim Lai 		sel->r = *__hi556_get_pad_crop(hi556, sd_state, sel->pad,
897c0bc1ca0SJim Lai 						sel->which);
898c0bc1ca0SJim Lai 		mutex_unlock(&hi556->mutex);
899c0bc1ca0SJim Lai 
900c0bc1ca0SJim Lai 		return 0;
901c0bc1ca0SJim Lai 	}
902c0bc1ca0SJim Lai 
903c0bc1ca0SJim Lai 	case V4L2_SEL_TGT_NATIVE_SIZE:
904c0bc1ca0SJim Lai 		sel->r.top = 0;
905c0bc1ca0SJim Lai 		sel->r.left = 0;
906c0bc1ca0SJim Lai 		sel->r.width = HI556_NATIVE_WIDTH;
907c0bc1ca0SJim Lai 		sel->r.height = HI556_NATIVE_HEIGHT;
908c0bc1ca0SJim Lai 
909c0bc1ca0SJim Lai 		return 0;
910c0bc1ca0SJim Lai 
911c0bc1ca0SJim Lai 	case V4L2_SEL_TGT_CROP_DEFAULT:
912c0bc1ca0SJim Lai 	case V4L2_SEL_TGT_CROP_BOUNDS:
913c0bc1ca0SJim Lai 		sel->r.top = HI556_PIXEL_ARRAY_TOP;
914c0bc1ca0SJim Lai 		sel->r.left = HI556_PIXEL_ARRAY_LEFT;
915c0bc1ca0SJim Lai 		sel->r.width = HI556_PIXEL_ARRAY_WIDTH;
916c0bc1ca0SJim Lai 		sel->r.height = HI556_PIXEL_ARRAY_HEIGHT;
917c0bc1ca0SJim Lai 
918c0bc1ca0SJim Lai 		return 0;
919c0bc1ca0SJim Lai 	}
920c0bc1ca0SJim Lai 
921c0bc1ca0SJim Lai 	return -EINVAL;
922c0bc1ca0SJim Lai }
923c0bc1ca0SJim Lai 
hi556_start_streaming(struct hi556 * hi556)924e6213840SShawn Tu static int hi556_start_streaming(struct hi556 *hi556)
925e6213840SShawn Tu {
926e6213840SShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd);
927e6213840SShawn Tu 	const struct hi556_reg_list *reg_list;
928e6213840SShawn Tu 	int link_freq_index, ret;
929e6213840SShawn Tu 
930d1d2ed59SBingbu Cao 	ret = hi556_identify_module(hi556);
931d1d2ed59SBingbu Cao 	if (ret)
932d1d2ed59SBingbu Cao 		return ret;
933d1d2ed59SBingbu Cao 
934e6213840SShawn Tu 	link_freq_index = hi556->cur_mode->link_freq_index;
935e6213840SShawn Tu 	reg_list = &link_freq_configs[link_freq_index].reg_list;
936e6213840SShawn Tu 	ret = hi556_write_reg_list(hi556, reg_list);
937e6213840SShawn Tu 	if (ret) {
938e6213840SShawn Tu 		dev_err(&client->dev, "failed to set plls");
939e6213840SShawn Tu 		return ret;
940e6213840SShawn Tu 	}
941e6213840SShawn Tu 
942e6213840SShawn Tu 	reg_list = &hi556->cur_mode->reg_list;
943e6213840SShawn Tu 	ret = hi556_write_reg_list(hi556, reg_list);
944e6213840SShawn Tu 	if (ret) {
945e6213840SShawn Tu 		dev_err(&client->dev, "failed to set mode");
946e6213840SShawn Tu 		return ret;
947e6213840SShawn Tu 	}
948e6213840SShawn Tu 
949e6213840SShawn Tu 	ret = __v4l2_ctrl_handler_setup(hi556->sd.ctrl_handler);
950e6213840SShawn Tu 	if (ret)
951e6213840SShawn Tu 		return ret;
952e6213840SShawn Tu 
953e6213840SShawn Tu 	ret = hi556_write_reg(hi556, HI556_REG_MODE_SELECT,
954e6213840SShawn Tu 			      HI556_REG_VALUE_16BIT, HI556_MODE_STREAMING);
955e6213840SShawn Tu 
956e6213840SShawn Tu 	if (ret) {
957e6213840SShawn Tu 		dev_err(&client->dev, "failed to set stream");
958e6213840SShawn Tu 		return ret;
959e6213840SShawn Tu 	}
960e6213840SShawn Tu 
961e6213840SShawn Tu 	return 0;
962e6213840SShawn Tu }
963e6213840SShawn Tu 
hi556_stop_streaming(struct hi556 * hi556)964e6213840SShawn Tu static void hi556_stop_streaming(struct hi556 *hi556)
965e6213840SShawn Tu {
966e6213840SShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd);
967e6213840SShawn Tu 
968e6213840SShawn Tu 	if (hi556_write_reg(hi556, HI556_REG_MODE_SELECT,
969e6213840SShawn Tu 			    HI556_REG_VALUE_16BIT, HI556_MODE_STANDBY))
970e6213840SShawn Tu 		dev_err(&client->dev, "failed to set stream");
971e6213840SShawn Tu }
972e6213840SShawn Tu 
hi556_set_stream(struct v4l2_subdev * sd,int enable)973e6213840SShawn Tu static int hi556_set_stream(struct v4l2_subdev *sd, int enable)
974e6213840SShawn Tu {
975e6213840SShawn Tu 	struct hi556 *hi556 = to_hi556(sd);
976e6213840SShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(sd);
977e6213840SShawn Tu 	int ret = 0;
978e6213840SShawn Tu 
979e6213840SShawn Tu 	if (hi556->streaming == enable)
980e6213840SShawn Tu 		return 0;
981e6213840SShawn Tu 
982e6213840SShawn Tu 	mutex_lock(&hi556->mutex);
983e6213840SShawn Tu 	if (enable) {
984c36c7d56SMauro Carvalho Chehab 		ret = pm_runtime_resume_and_get(&client->dev);
985e6213840SShawn Tu 		if (ret < 0) {
986e6213840SShawn Tu 			mutex_unlock(&hi556->mutex);
987e6213840SShawn Tu 			return ret;
988e6213840SShawn Tu 		}
989e6213840SShawn Tu 
990e6213840SShawn Tu 		ret = hi556_start_streaming(hi556);
991e6213840SShawn Tu 		if (ret) {
992e6213840SShawn Tu 			enable = 0;
993e6213840SShawn Tu 			hi556_stop_streaming(hi556);
994e6213840SShawn Tu 			pm_runtime_put(&client->dev);
995e6213840SShawn Tu 		}
996e6213840SShawn Tu 	} else {
997e6213840SShawn Tu 		hi556_stop_streaming(hi556);
998e6213840SShawn Tu 		pm_runtime_put(&client->dev);
999e6213840SShawn Tu 	}
1000e6213840SShawn Tu 
1001e6213840SShawn Tu 	hi556->streaming = enable;
1002e6213840SShawn Tu 	mutex_unlock(&hi556->mutex);
1003e6213840SShawn Tu 
1004e6213840SShawn Tu 	return ret;
1005e6213840SShawn Tu }
1006e6213840SShawn Tu 
hi556_suspend(struct device * dev)1007e6213840SShawn Tu static int __maybe_unused hi556_suspend(struct device *dev)
1008e6213840SShawn Tu {
100934b3c34dSKrzysztof Kozlowski 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
1010e6213840SShawn Tu 	struct hi556 *hi556 = to_hi556(sd);
1011e6213840SShawn Tu 
1012e6213840SShawn Tu 	mutex_lock(&hi556->mutex);
1013e6213840SShawn Tu 	if (hi556->streaming)
1014e6213840SShawn Tu 		hi556_stop_streaming(hi556);
1015e6213840SShawn Tu 
1016e6213840SShawn Tu 	mutex_unlock(&hi556->mutex);
1017e6213840SShawn Tu 
1018e6213840SShawn Tu 	return 0;
1019e6213840SShawn Tu }
1020e6213840SShawn Tu 
hi556_resume(struct device * dev)1021e6213840SShawn Tu static int __maybe_unused hi556_resume(struct device *dev)
1022e6213840SShawn Tu {
102334b3c34dSKrzysztof Kozlowski 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
1024e6213840SShawn Tu 	struct hi556 *hi556 = to_hi556(sd);
1025e6213840SShawn Tu 	int ret;
1026e6213840SShawn Tu 
1027e6213840SShawn Tu 	mutex_lock(&hi556->mutex);
1028e6213840SShawn Tu 	if (hi556->streaming) {
1029e6213840SShawn Tu 		ret = hi556_start_streaming(hi556);
1030e6213840SShawn Tu 		if (ret)
1031e6213840SShawn Tu 			goto error;
1032e6213840SShawn Tu 	}
1033e6213840SShawn Tu 
1034e6213840SShawn Tu 	mutex_unlock(&hi556->mutex);
1035e6213840SShawn Tu 
1036e6213840SShawn Tu 	return 0;
1037e6213840SShawn Tu 
1038e6213840SShawn Tu error:
1039e6213840SShawn Tu 	hi556_stop_streaming(hi556);
1040e6213840SShawn Tu 	hi556->streaming = 0;
1041e6213840SShawn Tu 	mutex_unlock(&hi556->mutex);
1042e6213840SShawn Tu 	return ret;
1043e6213840SShawn Tu }
1044e6213840SShawn Tu 
hi556_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)1045e6213840SShawn Tu static int hi556_set_format(struct v4l2_subdev *sd,
10460d346d2aSTomi Valkeinen 			    struct v4l2_subdev_state *sd_state,
1047e6213840SShawn Tu 			    struct v4l2_subdev_format *fmt)
1048e6213840SShawn Tu {
1049e6213840SShawn Tu 	struct hi556 *hi556 = to_hi556(sd);
1050e6213840SShawn Tu 	const struct hi556_mode *mode;
1051e6213840SShawn Tu 	s32 vblank_def, h_blank;
1052e6213840SShawn Tu 
1053e6213840SShawn Tu 	mode = v4l2_find_nearest_size(supported_modes,
1054e6213840SShawn Tu 				      ARRAY_SIZE(supported_modes), width,
1055e6213840SShawn Tu 				      height, fmt->format.width,
1056e6213840SShawn Tu 				      fmt->format.height);
1057e6213840SShawn Tu 
1058e6213840SShawn Tu 	mutex_lock(&hi556->mutex);
1059e6213840SShawn Tu 	hi556_assign_pad_format(mode, &fmt->format);
1060e6213840SShawn Tu 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
10610d346d2aSTomi Valkeinen 		*v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
1062e6213840SShawn Tu 	} else {
1063e6213840SShawn Tu 		hi556->cur_mode = mode;
1064e6213840SShawn Tu 		__v4l2_ctrl_s_ctrl(hi556->link_freq, mode->link_freq_index);
1065e6213840SShawn Tu 		__v4l2_ctrl_s_ctrl_int64(hi556->pixel_rate,
1066e6213840SShawn Tu 					 to_pixel_rate(mode->link_freq_index));
1067e6213840SShawn Tu 
1068e6213840SShawn Tu 		/* Update limits and set FPS to default */
1069e6213840SShawn Tu 		vblank_def = mode->fll_def - mode->height;
1070e6213840SShawn Tu 		__v4l2_ctrl_modify_range(hi556->vblank,
1071e6213840SShawn Tu 					 mode->fll_min - mode->height,
1072e6213840SShawn Tu 					 HI556_FLL_MAX - mode->height, 1,
1073e6213840SShawn Tu 					 vblank_def);
1074e6213840SShawn Tu 		__v4l2_ctrl_s_ctrl(hi556->vblank, vblank_def);
1075e6213840SShawn Tu 
1076e6213840SShawn Tu 		h_blank = hi556->cur_mode->llp - hi556->cur_mode->width;
1077e6213840SShawn Tu 
1078e6213840SShawn Tu 		__v4l2_ctrl_modify_range(hi556->hblank, h_blank, h_blank, 1,
1079e6213840SShawn Tu 					 h_blank);
1080e6213840SShawn Tu 	}
1081e6213840SShawn Tu 
1082e6213840SShawn Tu 	mutex_unlock(&hi556->mutex);
1083e6213840SShawn Tu 
1084e6213840SShawn Tu 	return 0;
1085e6213840SShawn Tu }
1086e6213840SShawn Tu 
hi556_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)1087e6213840SShawn Tu static int hi556_get_format(struct v4l2_subdev *sd,
10880d346d2aSTomi Valkeinen 			    struct v4l2_subdev_state *sd_state,
1089e6213840SShawn Tu 			    struct v4l2_subdev_format *fmt)
1090e6213840SShawn Tu {
1091e6213840SShawn Tu 	struct hi556 *hi556 = to_hi556(sd);
1092e6213840SShawn Tu 
1093e6213840SShawn Tu 	mutex_lock(&hi556->mutex);
1094e6213840SShawn Tu 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
10950d346d2aSTomi Valkeinen 		fmt->format = *v4l2_subdev_get_try_format(&hi556->sd,
10960d346d2aSTomi Valkeinen 							  sd_state,
1097e6213840SShawn Tu 							  fmt->pad);
1098e6213840SShawn Tu 	else
1099e6213840SShawn Tu 		hi556_assign_pad_format(hi556->cur_mode, &fmt->format);
1100e6213840SShawn Tu 
1101e6213840SShawn Tu 	mutex_unlock(&hi556->mutex);
1102e6213840SShawn Tu 
1103e6213840SShawn Tu 	return 0;
1104e6213840SShawn Tu }
1105e6213840SShawn Tu 
hi556_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)1106e6213840SShawn Tu static int hi556_enum_mbus_code(struct v4l2_subdev *sd,
11070d346d2aSTomi Valkeinen 				struct v4l2_subdev_state *sd_state,
1108e6213840SShawn Tu 				struct v4l2_subdev_mbus_code_enum *code)
1109e6213840SShawn Tu {
1110e6213840SShawn Tu 	if (code->index > 0)
1111e6213840SShawn Tu 		return -EINVAL;
1112e6213840SShawn Tu 
1113e6213840SShawn Tu 	code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
1114e6213840SShawn Tu 
1115e6213840SShawn Tu 	return 0;
1116e6213840SShawn Tu }
1117e6213840SShawn Tu 
hi556_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)1118e6213840SShawn Tu static int hi556_enum_frame_size(struct v4l2_subdev *sd,
11190d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
1120e6213840SShawn Tu 				 struct v4l2_subdev_frame_size_enum *fse)
1121e6213840SShawn Tu {
1122e6213840SShawn Tu 	if (fse->index >= ARRAY_SIZE(supported_modes))
1123e6213840SShawn Tu 		return -EINVAL;
1124e6213840SShawn Tu 
1125e6213840SShawn Tu 	if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
1126e6213840SShawn Tu 		return -EINVAL;
1127e6213840SShawn Tu 
1128e6213840SShawn Tu 	fse->min_width = supported_modes[fse->index].width;
1129e6213840SShawn Tu 	fse->max_width = fse->min_width;
1130e6213840SShawn Tu 	fse->min_height = supported_modes[fse->index].height;
1131e6213840SShawn Tu 	fse->max_height = fse->min_height;
1132e6213840SShawn Tu 
1133e6213840SShawn Tu 	return 0;
1134e6213840SShawn Tu }
1135e6213840SShawn Tu 
hi556_open(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)1136e6213840SShawn Tu static int hi556_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
1137e6213840SShawn Tu {
1138e6213840SShawn Tu 	struct hi556 *hi556 = to_hi556(sd);
1139c0bc1ca0SJim Lai 	struct v4l2_rect *try_crop;
1140e6213840SShawn Tu 
1141e6213840SShawn Tu 	mutex_lock(&hi556->mutex);
1142e6213840SShawn Tu 	hi556_assign_pad_format(&supported_modes[0],
11430d346d2aSTomi Valkeinen 				v4l2_subdev_get_try_format(sd, fh->state, 0));
1144c0bc1ca0SJim Lai 
1145c0bc1ca0SJim Lai 	/* Initialize try_crop rectangle. */
1146c0bc1ca0SJim Lai 	try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
1147c0bc1ca0SJim Lai 	try_crop->top = HI556_PIXEL_ARRAY_TOP;
1148c0bc1ca0SJim Lai 	try_crop->left = HI556_PIXEL_ARRAY_LEFT;
1149c0bc1ca0SJim Lai 	try_crop->width = HI556_PIXEL_ARRAY_WIDTH;
1150c0bc1ca0SJim Lai 	try_crop->height = HI556_PIXEL_ARRAY_HEIGHT;
1151c0bc1ca0SJim Lai 
1152e6213840SShawn Tu 	mutex_unlock(&hi556->mutex);
1153e6213840SShawn Tu 
1154e6213840SShawn Tu 	return 0;
1155e6213840SShawn Tu }
1156e6213840SShawn Tu 
1157e6213840SShawn Tu static const struct v4l2_subdev_video_ops hi556_video_ops = {
1158e6213840SShawn Tu 	.s_stream = hi556_set_stream,
1159e6213840SShawn Tu };
1160e6213840SShawn Tu 
1161e6213840SShawn Tu static const struct v4l2_subdev_pad_ops hi556_pad_ops = {
1162e6213840SShawn Tu 	.set_fmt = hi556_set_format,
1163e6213840SShawn Tu 	.get_fmt = hi556_get_format,
1164c0bc1ca0SJim Lai 	.get_selection = hi556_get_selection,
1165e6213840SShawn Tu 	.enum_mbus_code = hi556_enum_mbus_code,
1166e6213840SShawn Tu 	.enum_frame_size = hi556_enum_frame_size,
1167e6213840SShawn Tu };
1168e6213840SShawn Tu 
1169e6213840SShawn Tu static const struct v4l2_subdev_ops hi556_subdev_ops = {
1170e6213840SShawn Tu 	.video = &hi556_video_ops,
1171e6213840SShawn Tu 	.pad = &hi556_pad_ops,
1172e6213840SShawn Tu };
1173e6213840SShawn Tu 
1174e6213840SShawn Tu static const struct media_entity_operations hi556_subdev_entity_ops = {
1175e6213840SShawn Tu 	.link_validate = v4l2_subdev_link_validate,
1176e6213840SShawn Tu };
1177e6213840SShawn Tu 
1178e6213840SShawn Tu static const struct v4l2_subdev_internal_ops hi556_internal_ops = {
1179e6213840SShawn Tu 	.open = hi556_open,
1180e6213840SShawn Tu };
1181e6213840SShawn Tu 
hi556_check_hwcfg(struct device * dev)1182e6213840SShawn Tu static int hi556_check_hwcfg(struct device *dev)
1183e6213840SShawn Tu {
1184e6213840SShawn Tu 	struct fwnode_handle *ep;
1185e6213840SShawn Tu 	struct fwnode_handle *fwnode = dev_fwnode(dev);
1186e6213840SShawn Tu 	struct v4l2_fwnode_endpoint bus_cfg = {
1187e6213840SShawn Tu 		.bus_type = V4L2_MBUS_CSI2_DPHY
1188e6213840SShawn Tu 	};
1189e6213840SShawn Tu 	u32 mclk;
1190e6213840SShawn Tu 	int ret = 0;
1191e6213840SShawn Tu 	unsigned int i, j;
1192e6213840SShawn Tu 
1193e6213840SShawn Tu 	if (!fwnode)
1194e6213840SShawn Tu 		return -ENXIO;
1195e6213840SShawn Tu 
1196e6213840SShawn Tu 	ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk);
1197e6213840SShawn Tu 	if (ret) {
1198e6213840SShawn Tu 		dev_err(dev, "can't get clock frequency");
1199e6213840SShawn Tu 		return ret;
1200e6213840SShawn Tu 	}
1201e6213840SShawn Tu 
1202e6213840SShawn Tu 	if (mclk != HI556_MCLK) {
1203e6213840SShawn Tu 		dev_err(dev, "external clock %d is not supported", mclk);
1204e6213840SShawn Tu 		return -EINVAL;
1205e6213840SShawn Tu 	}
1206e6213840SShawn Tu 
1207e6213840SShawn Tu 	ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
1208e6213840SShawn Tu 	if (!ep)
1209e6213840SShawn Tu 		return -ENXIO;
1210e6213840SShawn Tu 
1211e6213840SShawn Tu 	ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
1212e6213840SShawn Tu 	fwnode_handle_put(ep);
1213e6213840SShawn Tu 	if (ret)
1214e6213840SShawn Tu 		return ret;
1215e6213840SShawn Tu 
1216e6213840SShawn Tu 	if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2) {
1217e6213840SShawn Tu 		dev_err(dev, "number of CSI2 data lanes %d is not supported",
1218e6213840SShawn Tu 			bus_cfg.bus.mipi_csi2.num_data_lanes);
1219e6213840SShawn Tu 		ret = -EINVAL;
1220e6213840SShawn Tu 		goto check_hwcfg_error;
1221e6213840SShawn Tu 	}
1222e6213840SShawn Tu 
1223e6213840SShawn Tu 	if (!bus_cfg.nr_of_link_frequencies) {
1224e6213840SShawn Tu 		dev_err(dev, "no link frequencies defined");
1225e6213840SShawn Tu 		ret = -EINVAL;
1226e6213840SShawn Tu 		goto check_hwcfg_error;
1227e6213840SShawn Tu 	}
1228e6213840SShawn Tu 
1229e6213840SShawn Tu 	for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) {
1230e6213840SShawn Tu 		for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) {
1231e6213840SShawn Tu 			if (link_freq_menu_items[i] ==
1232e6213840SShawn Tu 				bus_cfg.link_frequencies[j])
1233e6213840SShawn Tu 				break;
1234e6213840SShawn Tu 		}
1235e6213840SShawn Tu 
1236e6213840SShawn Tu 		if (j == bus_cfg.nr_of_link_frequencies) {
1237e6213840SShawn Tu 			dev_err(dev, "no link frequency %lld supported",
1238e6213840SShawn Tu 				link_freq_menu_items[i]);
1239e6213840SShawn Tu 			ret = -EINVAL;
1240e6213840SShawn Tu 			goto check_hwcfg_error;
1241e6213840SShawn Tu 		}
1242e6213840SShawn Tu 	}
1243e6213840SShawn Tu 
1244e6213840SShawn Tu check_hwcfg_error:
1245e6213840SShawn Tu 	v4l2_fwnode_endpoint_free(&bus_cfg);
1246e6213840SShawn Tu 
1247e6213840SShawn Tu 	return ret;
1248e6213840SShawn Tu }
1249e6213840SShawn Tu 
hi556_remove(struct i2c_client * client)1250ed5c2f5fSUwe Kleine-König static void hi556_remove(struct i2c_client *client)
1251e6213840SShawn Tu {
1252e6213840SShawn Tu 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1253e6213840SShawn Tu 	struct hi556 *hi556 = to_hi556(sd);
1254e6213840SShawn Tu 
1255e6213840SShawn Tu 	v4l2_async_unregister_subdev(sd);
1256e6213840SShawn Tu 	media_entity_cleanup(&sd->entity);
1257e6213840SShawn Tu 	v4l2_ctrl_handler_free(sd->ctrl_handler);
1258e6213840SShawn Tu 	pm_runtime_disable(&client->dev);
1259e6213840SShawn Tu 	mutex_destroy(&hi556->mutex);
1260e6213840SShawn Tu }
1261e6213840SShawn Tu 
hi556_probe(struct i2c_client * client)1262e6213840SShawn Tu static int hi556_probe(struct i2c_client *client)
1263e6213840SShawn Tu {
1264e6213840SShawn Tu 	struct hi556 *hi556;
1265d1d2ed59SBingbu Cao 	bool full_power;
1266e6213840SShawn Tu 	int ret;
1267e6213840SShawn Tu 
1268e6213840SShawn Tu 	ret = hi556_check_hwcfg(&client->dev);
1269e6213840SShawn Tu 	if (ret) {
1270e6213840SShawn Tu 		dev_err(&client->dev, "failed to check HW configuration: %d",
1271e6213840SShawn Tu 			ret);
1272e6213840SShawn Tu 		return ret;
1273e6213840SShawn Tu 	}
1274e6213840SShawn Tu 
1275e6213840SShawn Tu 	hi556 = devm_kzalloc(&client->dev, sizeof(*hi556), GFP_KERNEL);
1276e6213840SShawn Tu 	if (!hi556)
1277e6213840SShawn Tu 		return -ENOMEM;
1278e6213840SShawn Tu 
1279e6213840SShawn Tu 	v4l2_i2c_subdev_init(&hi556->sd, client, &hi556_subdev_ops);
1280d1d2ed59SBingbu Cao 
1281d1d2ed59SBingbu Cao 	full_power = acpi_dev_state_d0(&client->dev);
1282d1d2ed59SBingbu Cao 	if (full_power) {
1283e6213840SShawn Tu 		ret = hi556_identify_module(hi556);
1284e6213840SShawn Tu 		if (ret) {
1285e6213840SShawn Tu 			dev_err(&client->dev, "failed to find sensor: %d", ret);
1286e6213840SShawn Tu 			return ret;
1287e6213840SShawn Tu 		}
1288d1d2ed59SBingbu Cao 	}
1289e6213840SShawn Tu 
1290e6213840SShawn Tu 	mutex_init(&hi556->mutex);
1291e6213840SShawn Tu 	hi556->cur_mode = &supported_modes[0];
1292e6213840SShawn Tu 	ret = hi556_init_controls(hi556);
1293e6213840SShawn Tu 	if (ret) {
1294e6213840SShawn Tu 		dev_err(&client->dev, "failed to init controls: %d", ret);
1295e6213840SShawn Tu 		goto probe_error_v4l2_ctrl_handler_free;
1296e6213840SShawn Tu 	}
1297e6213840SShawn Tu 
1298e6213840SShawn Tu 	hi556->sd.internal_ops = &hi556_internal_ops;
1299e6213840SShawn Tu 	hi556->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1300e6213840SShawn Tu 	hi556->sd.entity.ops = &hi556_subdev_entity_ops;
1301e6213840SShawn Tu 	hi556->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
1302e6213840SShawn Tu 	hi556->pad.flags = MEDIA_PAD_FL_SOURCE;
1303e6213840SShawn Tu 	ret = media_entity_pads_init(&hi556->sd.entity, 1, &hi556->pad);
1304e6213840SShawn Tu 	if (ret) {
1305e6213840SShawn Tu 		dev_err(&client->dev, "failed to init entity pads: %d", ret);
1306e6213840SShawn Tu 		goto probe_error_v4l2_ctrl_handler_free;
1307e6213840SShawn Tu 	}
1308e6213840SShawn Tu 
130915786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&hi556->sd);
1310e6213840SShawn Tu 	if (ret < 0) {
1311e6213840SShawn Tu 		dev_err(&client->dev, "failed to register V4L2 subdev: %d",
1312e6213840SShawn Tu 			ret);
1313e6213840SShawn Tu 		goto probe_error_media_entity_cleanup;
1314e6213840SShawn Tu 	}
1315e6213840SShawn Tu 
1316d1d2ed59SBingbu Cao 	/* Set the device's state to active if it's in D0 state. */
1317d1d2ed59SBingbu Cao 	if (full_power)
1318e6213840SShawn Tu 		pm_runtime_set_active(&client->dev);
1319e6213840SShawn Tu 	pm_runtime_enable(&client->dev);
1320e6213840SShawn Tu 	pm_runtime_idle(&client->dev);
1321e6213840SShawn Tu 
1322e6213840SShawn Tu 	return 0;
1323e6213840SShawn Tu 
1324e6213840SShawn Tu probe_error_media_entity_cleanup:
1325e6213840SShawn Tu 	media_entity_cleanup(&hi556->sd.entity);
1326e6213840SShawn Tu 
1327e6213840SShawn Tu probe_error_v4l2_ctrl_handler_free:
1328e6213840SShawn Tu 	v4l2_ctrl_handler_free(hi556->sd.ctrl_handler);
1329e6213840SShawn Tu 	mutex_destroy(&hi556->mutex);
1330e6213840SShawn Tu 
1331e6213840SShawn Tu 	return ret;
1332e6213840SShawn Tu }
1333e6213840SShawn Tu 
1334e6213840SShawn Tu static const struct dev_pm_ops hi556_pm_ops = {
1335e6213840SShawn Tu 	SET_SYSTEM_SLEEP_PM_OPS(hi556_suspend, hi556_resume)
1336e6213840SShawn Tu };
1337e6213840SShawn Tu 
1338e6213840SShawn Tu #ifdef CONFIG_ACPI
1339e6213840SShawn Tu static const struct acpi_device_id hi556_acpi_ids[] = {
1340e6213840SShawn Tu 	{"INT3537"},
1341e6213840SShawn Tu 	{}
1342e6213840SShawn Tu };
1343e6213840SShawn Tu 
1344e6213840SShawn Tu MODULE_DEVICE_TABLE(acpi, hi556_acpi_ids);
1345e6213840SShawn Tu #endif
1346e6213840SShawn Tu 
1347e6213840SShawn Tu static struct i2c_driver hi556_i2c_driver = {
1348e6213840SShawn Tu 	.driver = {
1349e6213840SShawn Tu 		.name = "hi556",
1350e6213840SShawn Tu 		.pm = &hi556_pm_ops,
1351e6213840SShawn Tu 		.acpi_match_table = ACPI_PTR(hi556_acpi_ids),
1352e6213840SShawn Tu 	},
1353aaeb31c0SUwe Kleine-König 	.probe = hi556_probe,
1354e6213840SShawn Tu 	.remove = hi556_remove,
1355d1d2ed59SBingbu Cao 	.flags = I2C_DRV_ACPI_WAIVE_D0_PROBE,
1356e6213840SShawn Tu };
1357e6213840SShawn Tu 
1358e6213840SShawn Tu module_i2c_driver(hi556_i2c_driver);
1359e6213840SShawn Tu 
1360*4106cd72SSakari Ailus MODULE_AUTHOR("Shawn Tu");
1361e6213840SShawn Tu MODULE_DESCRIPTION("Hynix HI556 sensor driver");
1362e6213840SShawn Tu MODULE_LICENSE("GPL v2");
1363