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