xref: /openbmc/linux/drivers/media/i2c/ov8858.c (revision c46f16f1)
1e14d3ac8SNicholas Roth // SPDX-License-Identifier: GPL-2.0
2e14d3ac8SNicholas Roth /*
3e14d3ac8SNicholas Roth  * Copyright (C) 2023 Jacopo Mondi <jacopo.mondi@ideasonboard.com>
4e14d3ac8SNicholas Roth  * Copyright (C) 2022 Nicholas Roth <nicholas@rothemail.net>
5e14d3ac8SNicholas Roth  * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
6e14d3ac8SNicholas Roth  */
7e14d3ac8SNicholas Roth 
8e14d3ac8SNicholas Roth #include <asm/unaligned.h>
9e14d3ac8SNicholas Roth 
10e14d3ac8SNicholas Roth #include <linux/clk.h>
11e14d3ac8SNicholas Roth #include <linux/delay.h>
12e14d3ac8SNicholas Roth #include <linux/device.h>
13e14d3ac8SNicholas Roth #include <linux/gpio/consumer.h>
14e14d3ac8SNicholas Roth #include <linux/i2c.h>
15e14d3ac8SNicholas Roth #include <linux/module.h>
16e14d3ac8SNicholas Roth #include <linux/of.h>
17e14d3ac8SNicholas Roth #include <linux/pm_runtime.h>
18e14d3ac8SNicholas Roth #include <linux/property.h>
19e14d3ac8SNicholas Roth #include <linux/regulator/consumer.h>
20e14d3ac8SNicholas Roth #include <linux/slab.h>
21e14d3ac8SNicholas Roth 
22e14d3ac8SNicholas Roth #include <media/media-entity.h>
23e14d3ac8SNicholas Roth #include <media/v4l2-async.h>
24e14d3ac8SNicholas Roth #include <media/v4l2-common.h>
25e14d3ac8SNicholas Roth #include <media/v4l2-ctrls.h>
26e14d3ac8SNicholas Roth #include <media/v4l2-device.h>
27e14d3ac8SNicholas Roth #include <media/v4l2-event.h>
28e14d3ac8SNicholas Roth #include <media/v4l2-fwnode.h>
29e14d3ac8SNicholas Roth #include <media/v4l2-mediabus.h>
30e14d3ac8SNicholas Roth #include <media/v4l2-subdev.h>
31e14d3ac8SNicholas Roth 
32e14d3ac8SNicholas Roth #define OV8858_LINK_FREQ		360000000U
33e14d3ac8SNicholas Roth #define OV8858_XVCLK_FREQ		24000000
34e14d3ac8SNicholas Roth 
35e14d3ac8SNicholas Roth #define OV8858_REG_SIZE_SHIFT		16
36e14d3ac8SNicholas Roth #define OV8858_REG_ADDR_MASK		0xffff
37e14d3ac8SNicholas Roth #define OV8858_REG_8BIT(n)		((1U << OV8858_REG_SIZE_SHIFT) | (n))
38e14d3ac8SNicholas Roth #define OV8858_REG_16BIT(n)		((2U << OV8858_REG_SIZE_SHIFT) | (n))
39e14d3ac8SNicholas Roth #define OV8858_REG_24BIT(n)		((3U << OV8858_REG_SIZE_SHIFT) | (n))
40e14d3ac8SNicholas Roth 
41e14d3ac8SNicholas Roth #define OV8858_REG_SC_CTRL0100		OV8858_REG_8BIT(0x0100)
42e14d3ac8SNicholas Roth #define OV8858_MODE_SW_STANDBY		0x0
43e14d3ac8SNicholas Roth #define OV8858_MODE_STREAMING		0x1
44e14d3ac8SNicholas Roth 
45e14d3ac8SNicholas Roth #define OV8858_REG_CHIP_ID		OV8858_REG_24BIT(0x300a)
46e14d3ac8SNicholas Roth #define OV8858_CHIP_ID			0x008858
47e14d3ac8SNicholas Roth 
48e14d3ac8SNicholas Roth #define OV8858_REG_SUB_ID		OV8858_REG_8BIT(0x302a)
49e14d3ac8SNicholas Roth #define OV8858_R1A			0xb0
50e14d3ac8SNicholas Roth #define OV8858_R2A			0xb2
51e14d3ac8SNicholas Roth 
52e14d3ac8SNicholas Roth #define OV8858_REG_LONG_EXPO		OV8858_REG_24BIT(0x3500)
53e14d3ac8SNicholas Roth #define OV8858_EXPOSURE_MIN		4
54e14d3ac8SNicholas Roth #define OV8858_EXPOSURE_STEP		1
55e14d3ac8SNicholas Roth #define OV8858_EXPOSURE_MARGIN		4
56e14d3ac8SNicholas Roth 
57e14d3ac8SNicholas Roth #define OV8858_REG_LONG_GAIN		OV8858_REG_16BIT(0x3508)
58e14d3ac8SNicholas Roth #define OV8858_LONG_GAIN_MIN		0x0
59e14d3ac8SNicholas Roth #define OV8858_LONG_GAIN_MAX		0x7ff
60e14d3ac8SNicholas Roth #define OV8858_LONG_GAIN_STEP		1
61e14d3ac8SNicholas Roth #define OV8858_LONG_GAIN_DEFAULT	0x80
62e14d3ac8SNicholas Roth 
63e14d3ac8SNicholas Roth #define OV8858_REG_LONG_DIGIGAIN	OV8858_REG_16BIT(0x350a)
64e14d3ac8SNicholas Roth #define OV8858_LONG_DIGIGAIN_H_MASK	0x3fc0
65e14d3ac8SNicholas Roth #define OV8858_LONG_DIGIGAIN_L_MASK	0x3f
66e14d3ac8SNicholas Roth #define OV8858_LONG_DIGIGAIN_H_SHIFT	2
67e14d3ac8SNicholas Roth #define OV8858_LONG_DIGIGAIN_MIN	0x0
68e14d3ac8SNicholas Roth #define OV8858_LONG_DIGIGAIN_MAX	0x3fff
69e14d3ac8SNicholas Roth #define OV8858_LONG_DIGIGAIN_STEP	1
70e14d3ac8SNicholas Roth #define OV8858_LONG_DIGIGAIN_DEFAULT	0x200
71e14d3ac8SNicholas Roth 
72e14d3ac8SNicholas Roth #define OV8858_REG_VTS			OV8858_REG_16BIT(0x380e)
73e14d3ac8SNicholas Roth #define OV8858_VTS_MAX			0x7fff
74e14d3ac8SNicholas Roth 
75e14d3ac8SNicholas Roth #define OV8858_REG_TEST_PATTERN		OV8858_REG_8BIT(0x5e00)
76e14d3ac8SNicholas Roth #define OV8858_TEST_PATTERN_ENABLE	0x80
77e14d3ac8SNicholas Roth #define OV8858_TEST_PATTERN_DISABLE	0x0
78e14d3ac8SNicholas Roth 
79e14d3ac8SNicholas Roth #define REG_NULL			0xffff
80e14d3ac8SNicholas Roth 
81e14d3ac8SNicholas Roth static const char * const ov8858_supply_names[] = {
82e14d3ac8SNicholas Roth 	"avdd",		/* Analog power */
83e14d3ac8SNicholas Roth 	"dovdd",	/* Digital I/O power */
84e14d3ac8SNicholas Roth 	"dvdd",		/* Digital core power */
85e14d3ac8SNicholas Roth };
86e14d3ac8SNicholas Roth 
87e14d3ac8SNicholas Roth struct regval {
88e14d3ac8SNicholas Roth 	u16 addr;
89e14d3ac8SNicholas Roth 	u8 val;
90e14d3ac8SNicholas Roth };
91e14d3ac8SNicholas Roth 
92e14d3ac8SNicholas Roth struct regval_modes {
93e14d3ac8SNicholas Roth 	const struct regval *mode_2lanes;
94e14d3ac8SNicholas Roth 	const struct regval *mode_4lanes;
95e14d3ac8SNicholas Roth };
96e14d3ac8SNicholas Roth 
97e14d3ac8SNicholas Roth struct ov8858_mode {
98e14d3ac8SNicholas Roth 	u32 width;
99e14d3ac8SNicholas Roth 	u32 height;
100e14d3ac8SNicholas Roth 	u32 hts_def;
101e14d3ac8SNicholas Roth 	u32 vts_def;
102e14d3ac8SNicholas Roth 	u32 exp_def;
103e14d3ac8SNicholas Roth 	const struct regval_modes reg_modes;
104e14d3ac8SNicholas Roth };
105e14d3ac8SNicholas Roth 
106e14d3ac8SNicholas Roth struct ov8858 {
107e14d3ac8SNicholas Roth 	struct clk		*xvclk;
108e14d3ac8SNicholas Roth 	struct gpio_desc	*reset_gpio;
109e14d3ac8SNicholas Roth 	struct gpio_desc	*pwdn_gpio;
110e14d3ac8SNicholas Roth 	struct regulator_bulk_data supplies[ARRAY_SIZE(ov8858_supply_names)];
111e14d3ac8SNicholas Roth 
112e14d3ac8SNicholas Roth 	struct v4l2_subdev	subdev;
113e14d3ac8SNicholas Roth 	struct media_pad	pad;
114e14d3ac8SNicholas Roth 
115e14d3ac8SNicholas Roth 	struct v4l2_ctrl_handler ctrl_handler;
116e14d3ac8SNicholas Roth 	struct v4l2_ctrl	*exposure;
117e14d3ac8SNicholas Roth 	struct v4l2_ctrl	*hblank;
118e14d3ac8SNicholas Roth 	struct v4l2_ctrl	*vblank;
119e14d3ac8SNicholas Roth 
120e14d3ac8SNicholas Roth 	const struct regval	*global_regs;
121e14d3ac8SNicholas Roth 
122e14d3ac8SNicholas Roth 	unsigned int		num_lanes;
123e14d3ac8SNicholas Roth };
124e14d3ac8SNicholas Roth 
sd_to_ov8858(struct v4l2_subdev * sd)125e14d3ac8SNicholas Roth static inline struct ov8858 *sd_to_ov8858(struct v4l2_subdev *sd)
126e14d3ac8SNicholas Roth {
127e14d3ac8SNicholas Roth 	return container_of(sd, struct ov8858, subdev);
128e14d3ac8SNicholas Roth }
129e14d3ac8SNicholas Roth 
130e14d3ac8SNicholas Roth static const struct regval ov8858_global_regs_r1a[] = {
131e14d3ac8SNicholas Roth 	{0x0100, 0x00},
132e14d3ac8SNicholas Roth 	{0x0100, 0x00},
133e14d3ac8SNicholas Roth 	{0x0100, 0x00},
134e14d3ac8SNicholas Roth 	{0x0100, 0x00},
135e14d3ac8SNicholas Roth 	{0x0302, 0x1e},
136e14d3ac8SNicholas Roth 	{0x0303, 0x00},
137e14d3ac8SNicholas Roth 	{0x0304, 0x03},
138e14d3ac8SNicholas Roth 	{0x030e, 0x00},
139e14d3ac8SNicholas Roth 	{0x030f, 0x09},
140e14d3ac8SNicholas Roth 	{0x0312, 0x01},
141e14d3ac8SNicholas Roth 	{0x031e, 0x0c},
142e14d3ac8SNicholas Roth 	{0x3600, 0x00},
143e14d3ac8SNicholas Roth 	{0x3601, 0x00},
144e14d3ac8SNicholas Roth 	{0x3602, 0x00},
145e14d3ac8SNicholas Roth 	{0x3603, 0x00},
146e14d3ac8SNicholas Roth 	{0x3604, 0x22},
147e14d3ac8SNicholas Roth 	{0x3605, 0x30},
148e14d3ac8SNicholas Roth 	{0x3606, 0x00},
149e14d3ac8SNicholas Roth 	{0x3607, 0x20},
150e14d3ac8SNicholas Roth 	{0x3608, 0x11},
151e14d3ac8SNicholas Roth 	{0x3609, 0x28},
152e14d3ac8SNicholas Roth 	{0x360a, 0x00},
153e14d3ac8SNicholas Roth 	{0x360b, 0x06},
154e14d3ac8SNicholas Roth 	{0x360c, 0xdc},
155e14d3ac8SNicholas Roth 	{0x360d, 0x40},
156e14d3ac8SNicholas Roth 	{0x360e, 0x0c},
157e14d3ac8SNicholas Roth 	{0x360f, 0x20},
158e14d3ac8SNicholas Roth 	{0x3610, 0x07},
159e14d3ac8SNicholas Roth 	{0x3611, 0x20},
160e14d3ac8SNicholas Roth 	{0x3612, 0x88},
161e14d3ac8SNicholas Roth 	{0x3613, 0x80},
162e14d3ac8SNicholas Roth 	{0x3614, 0x58},
163e14d3ac8SNicholas Roth 	{0x3615, 0x00},
164e14d3ac8SNicholas Roth 	{0x3616, 0x4a},
165e14d3ac8SNicholas Roth 	{0x3617, 0xb0},
166e14d3ac8SNicholas Roth 	{0x3618, 0x56},
167e14d3ac8SNicholas Roth 	{0x3619, 0x70},
168e14d3ac8SNicholas Roth 	{0x361a, 0x99},
169e14d3ac8SNicholas Roth 	{0x361b, 0x00},
170e14d3ac8SNicholas Roth 	{0x361c, 0x07},
171e14d3ac8SNicholas Roth 	{0x361d, 0x00},
172e14d3ac8SNicholas Roth 	{0x361e, 0x00},
173e14d3ac8SNicholas Roth 	{0x361f, 0x00},
174e14d3ac8SNicholas Roth 	{0x3638, 0xff},
175e14d3ac8SNicholas Roth 	{0x3633, 0x0c},
176e14d3ac8SNicholas Roth 	{0x3634, 0x0c},
177e14d3ac8SNicholas Roth 	{0x3635, 0x0c},
178e14d3ac8SNicholas Roth 	{0x3636, 0x0c},
179e14d3ac8SNicholas Roth 	{0x3645, 0x13},
180e14d3ac8SNicholas Roth 	{0x3646, 0x83},
181e14d3ac8SNicholas Roth 	{0x364a, 0x07},
182e14d3ac8SNicholas Roth 	{0x3015, 0x01},
183e14d3ac8SNicholas Roth 	{0x3018, 0x32},
184e14d3ac8SNicholas Roth 	{0x3020, 0x93},
185e14d3ac8SNicholas Roth 	{0x3022, 0x01},
186e14d3ac8SNicholas Roth 	{0x3031, 0x0a},
187e14d3ac8SNicholas Roth 	{0x3034, 0x00},
188e14d3ac8SNicholas Roth 	{0x3106, 0x01},
189e14d3ac8SNicholas Roth 	{0x3305, 0xf1},
190e14d3ac8SNicholas Roth 	{0x3308, 0x00},
191e14d3ac8SNicholas Roth 	{0x3309, 0x28},
192e14d3ac8SNicholas Roth 	{0x330a, 0x00},
193e14d3ac8SNicholas Roth 	{0x330b, 0x20},
194e14d3ac8SNicholas Roth 	{0x330c, 0x00},
195e14d3ac8SNicholas Roth 	{0x330d, 0x00},
196e14d3ac8SNicholas Roth 	{0x330e, 0x00},
197e14d3ac8SNicholas Roth 	{0x330f, 0x40},
198e14d3ac8SNicholas Roth 	{0x3307, 0x04},
199e14d3ac8SNicholas Roth 	{0x3500, 0x00},
200e14d3ac8SNicholas Roth 	{0x3501, 0x4d},
201e14d3ac8SNicholas Roth 	{0x3502, 0x40},
202e14d3ac8SNicholas Roth 	{0x3503, 0x00},
203e14d3ac8SNicholas Roth 	{0x3505, 0x80},
204e14d3ac8SNicholas Roth 	{0x3508, 0x04},
205e14d3ac8SNicholas Roth 	{0x3509, 0x00},
206e14d3ac8SNicholas Roth 	{0x350c, 0x00},
207e14d3ac8SNicholas Roth 	{0x350d, 0x80},
208e14d3ac8SNicholas Roth 	{0x3510, 0x00},
209e14d3ac8SNicholas Roth 	{0x3511, 0x02},
210e14d3ac8SNicholas Roth 	{0x3512, 0x00},
211e14d3ac8SNicholas Roth 	{0x3700, 0x18},
212e14d3ac8SNicholas Roth 	{0x3701, 0x0c},
213e14d3ac8SNicholas Roth 	{0x3702, 0x28},
214e14d3ac8SNicholas Roth 	{0x3703, 0x19},
215e14d3ac8SNicholas Roth 	{0x3704, 0x14},
216e14d3ac8SNicholas Roth 	{0x3705, 0x00},
217e14d3ac8SNicholas Roth 	{0x3706, 0x35},
218e14d3ac8SNicholas Roth 	{0x3707, 0x04},
219e14d3ac8SNicholas Roth 	{0x3708, 0x24},
220e14d3ac8SNicholas Roth 	{0x3709, 0x33},
221e14d3ac8SNicholas Roth 	{0x370a, 0x00},
222e14d3ac8SNicholas Roth 	{0x370b, 0xb5},
223e14d3ac8SNicholas Roth 	{0x370c, 0x04},
224e14d3ac8SNicholas Roth 	{0x3718, 0x12},
225e14d3ac8SNicholas Roth 	{0x3719, 0x31},
226e14d3ac8SNicholas Roth 	{0x3712, 0x42},
227e14d3ac8SNicholas Roth 	{0x3714, 0x24},
228e14d3ac8SNicholas Roth 	{0x371e, 0x19},
229e14d3ac8SNicholas Roth 	{0x371f, 0x40},
230e14d3ac8SNicholas Roth 	{0x3720, 0x05},
231e14d3ac8SNicholas Roth 	{0x3721, 0x05},
232e14d3ac8SNicholas Roth 	{0x3724, 0x06},
233e14d3ac8SNicholas Roth 	{0x3725, 0x01},
234e14d3ac8SNicholas Roth 	{0x3726, 0x06},
235e14d3ac8SNicholas Roth 	{0x3728, 0x05},
236e14d3ac8SNicholas Roth 	{0x3729, 0x02},
237e14d3ac8SNicholas Roth 	{0x372a, 0x03},
238e14d3ac8SNicholas Roth 	{0x372b, 0x53},
239e14d3ac8SNicholas Roth 	{0x372c, 0xa3},
240e14d3ac8SNicholas Roth 	{0x372d, 0x53},
241e14d3ac8SNicholas Roth 	{0x372e, 0x06},
242e14d3ac8SNicholas Roth 	{0x372f, 0x10},
243e14d3ac8SNicholas Roth 	{0x3730, 0x01},
244e14d3ac8SNicholas Roth 	{0x3731, 0x06},
245e14d3ac8SNicholas Roth 	{0x3732, 0x14},
246e14d3ac8SNicholas Roth 	{0x3733, 0x10},
247e14d3ac8SNicholas Roth 	{0x3734, 0x40},
248e14d3ac8SNicholas Roth 	{0x3736, 0x20},
249e14d3ac8SNicholas Roth 	{0x373a, 0x05},
250e14d3ac8SNicholas Roth 	{0x373b, 0x06},
251e14d3ac8SNicholas Roth 	{0x373c, 0x0a},
252e14d3ac8SNicholas Roth 	{0x373e, 0x03},
253e14d3ac8SNicholas Roth 	{0x3755, 0x10},
254e14d3ac8SNicholas Roth 	{0x3758, 0x00},
255e14d3ac8SNicholas Roth 	{0x3759, 0x4c},
256e14d3ac8SNicholas Roth 	{0x375a, 0x06},
257e14d3ac8SNicholas Roth 	{0x375b, 0x13},
258e14d3ac8SNicholas Roth 	{0x375c, 0x20},
259e14d3ac8SNicholas Roth 	{0x375d, 0x02},
260e14d3ac8SNicholas Roth 	{0x375e, 0x00},
261e14d3ac8SNicholas Roth 	{0x375f, 0x14},
262e14d3ac8SNicholas Roth 	{0x3768, 0x22},
263e14d3ac8SNicholas Roth 	{0x3769, 0x44},
264e14d3ac8SNicholas Roth 	{0x376a, 0x44},
265e14d3ac8SNicholas Roth 	{0x3761, 0x00},
266e14d3ac8SNicholas Roth 	{0x3762, 0x00},
267e14d3ac8SNicholas Roth 	{0x3763, 0x00},
268e14d3ac8SNicholas Roth 	{0x3766, 0xff},
269e14d3ac8SNicholas Roth 	{0x376b, 0x00},
270e14d3ac8SNicholas Roth 	{0x3772, 0x23},
271e14d3ac8SNicholas Roth 	{0x3773, 0x02},
272e14d3ac8SNicholas Roth 	{0x3774, 0x16},
273e14d3ac8SNicholas Roth 	{0x3775, 0x12},
274e14d3ac8SNicholas Roth 	{0x3776, 0x04},
275e14d3ac8SNicholas Roth 	{0x3777, 0x00},
276e14d3ac8SNicholas Roth 	{0x3778, 0x1b},
277e14d3ac8SNicholas Roth 	{0x37a0, 0x44},
278e14d3ac8SNicholas Roth 	{0x37a1, 0x3d},
279e14d3ac8SNicholas Roth 	{0x37a2, 0x3d},
280e14d3ac8SNicholas Roth 	{0x37a3, 0x00},
281e14d3ac8SNicholas Roth 	{0x37a4, 0x00},
282e14d3ac8SNicholas Roth 	{0x37a5, 0x00},
283e14d3ac8SNicholas Roth 	{0x37a6, 0x00},
284e14d3ac8SNicholas Roth 	{0x37a7, 0x44},
285e14d3ac8SNicholas Roth 	{0x37a8, 0x4c},
286e14d3ac8SNicholas Roth 	{0x37a9, 0x4c},
287e14d3ac8SNicholas Roth 	{0x3760, 0x00},
288e14d3ac8SNicholas Roth 	{0x376f, 0x01},
289e14d3ac8SNicholas Roth 	{0x37aa, 0x44},
290e14d3ac8SNicholas Roth 	{0x37ab, 0x2e},
291e14d3ac8SNicholas Roth 	{0x37ac, 0x2e},
292e14d3ac8SNicholas Roth 	{0x37ad, 0x33},
293e14d3ac8SNicholas Roth 	{0x37ae, 0x0d},
294e14d3ac8SNicholas Roth 	{0x37af, 0x0d},
295e14d3ac8SNicholas Roth 	{0x37b0, 0x00},
296e14d3ac8SNicholas Roth 	{0x37b1, 0x00},
297e14d3ac8SNicholas Roth 	{0x37b2, 0x00},
298e14d3ac8SNicholas Roth 	{0x37b3, 0x42},
299e14d3ac8SNicholas Roth 	{0x37b4, 0x42},
300e14d3ac8SNicholas Roth 	{0x37b5, 0x33},
301e14d3ac8SNicholas Roth 	{0x37b6, 0x00},
302e14d3ac8SNicholas Roth 	{0x37b7, 0x00},
303e14d3ac8SNicholas Roth 	{0x37b8, 0x00},
304e14d3ac8SNicholas Roth 	{0x37b9, 0xff},
305e14d3ac8SNicholas Roth 	{0x3800, 0x00},
306e14d3ac8SNicholas Roth 	{0x3801, 0x0c},
307e14d3ac8SNicholas Roth 	{0x3802, 0x00},
308e14d3ac8SNicholas Roth 	{0x3803, 0x0c},
309e14d3ac8SNicholas Roth 	{0x3804, 0x0c},
310e14d3ac8SNicholas Roth 	{0x3805, 0xd3},
311e14d3ac8SNicholas Roth 	{0x3806, 0x09},
312e14d3ac8SNicholas Roth 	{0x3807, 0xa3},
313e14d3ac8SNicholas Roth 	{0x3808, 0x06},
314e14d3ac8SNicholas Roth 	{0x3809, 0x60},
315e14d3ac8SNicholas Roth 	{0x380a, 0x04},
316e14d3ac8SNicholas Roth 	{0x380b, 0xc8},
317e14d3ac8SNicholas Roth 	{0x380c, 0x07},
318e14d3ac8SNicholas Roth 	{0x380d, 0x88},
319e14d3ac8SNicholas Roth 	{0x380e, 0x04},
320e14d3ac8SNicholas Roth 	{0x380f, 0xdc},
321e14d3ac8SNicholas Roth 	{0x3810, 0x00},
322e14d3ac8SNicholas Roth 	{0x3811, 0x04},
323e14d3ac8SNicholas Roth 	{0x3813, 0x02},
324e14d3ac8SNicholas Roth 	{0x3814, 0x03},
325e14d3ac8SNicholas Roth 	{0x3815, 0x01},
326e14d3ac8SNicholas Roth 	{0x3820, 0x00},
327e14d3ac8SNicholas Roth 	{0x3821, 0x67},
328e14d3ac8SNicholas Roth 	{0x382a, 0x03},
329e14d3ac8SNicholas Roth 	{0x382b, 0x01},
330e14d3ac8SNicholas Roth 	{0x3830, 0x08},
331e14d3ac8SNicholas Roth 	{0x3836, 0x02},
332e14d3ac8SNicholas Roth 	{0x3837, 0x18},
333e14d3ac8SNicholas Roth 	{0x3841, 0xff},
334e14d3ac8SNicholas Roth 	{0x3846, 0x48},
335e14d3ac8SNicholas Roth 	{0x3d85, 0x14},
336e14d3ac8SNicholas Roth 	{0x3f08, 0x08},
337e14d3ac8SNicholas Roth 	{0x3f0a, 0x80},
338e14d3ac8SNicholas Roth 	{0x4000, 0xf1},
339e14d3ac8SNicholas Roth 	{0x4001, 0x10},
340e14d3ac8SNicholas Roth 	{0x4005, 0x10},
341e14d3ac8SNicholas Roth 	{0x4002, 0x27},
342e14d3ac8SNicholas Roth 	{0x4009, 0x81},
343e14d3ac8SNicholas Roth 	{0x400b, 0x0c},
344e14d3ac8SNicholas Roth 	{0x401b, 0x00},
345e14d3ac8SNicholas Roth 	{0x401d, 0x00},
346e14d3ac8SNicholas Roth 	{0x4020, 0x00},
347e14d3ac8SNicholas Roth 	{0x4021, 0x04},
348e14d3ac8SNicholas Roth 	{0x4022, 0x04},
349e14d3ac8SNicholas Roth 	{0x4023, 0xb9},
350e14d3ac8SNicholas Roth 	{0x4024, 0x05},
351e14d3ac8SNicholas Roth 	{0x4025, 0x2a},
352e14d3ac8SNicholas Roth 	{0x4026, 0x05},
353e14d3ac8SNicholas Roth 	{0x4027, 0x2b},
354e14d3ac8SNicholas Roth 	{0x4028, 0x00},
355e14d3ac8SNicholas Roth 	{0x4029, 0x02},
356e14d3ac8SNicholas Roth 	{0x402a, 0x04},
357e14d3ac8SNicholas Roth 	{0x402b, 0x04},
358e14d3ac8SNicholas Roth 	{0x402c, 0x02},
359e14d3ac8SNicholas Roth 	{0x402d, 0x02},
360e14d3ac8SNicholas Roth 	{0x402e, 0x08},
361e14d3ac8SNicholas Roth 	{0x402f, 0x02},
362e14d3ac8SNicholas Roth 	{0x401f, 0x00},
363e14d3ac8SNicholas Roth 	{0x4034, 0x3f},
364e14d3ac8SNicholas Roth 	{0x403d, 0x04},
365e14d3ac8SNicholas Roth 	{0x4300, 0xff},
366e14d3ac8SNicholas Roth 	{0x4301, 0x00},
367e14d3ac8SNicholas Roth 	{0x4302, 0x0f},
368e14d3ac8SNicholas Roth 	{0x4316, 0x00},
369e14d3ac8SNicholas Roth 	{0x4500, 0x38},
370e14d3ac8SNicholas Roth 	{0x4503, 0x18},
371e14d3ac8SNicholas Roth 	{0x4600, 0x00},
372e14d3ac8SNicholas Roth 	{0x4601, 0xcb},
373e14d3ac8SNicholas Roth 	{0x481f, 0x32},
374e14d3ac8SNicholas Roth 	{0x4837, 0x16},
375e14d3ac8SNicholas Roth 	{0x4850, 0x10},
376e14d3ac8SNicholas Roth 	{0x4851, 0x32},
377e14d3ac8SNicholas Roth 	{0x4b00, 0x2a},
378e14d3ac8SNicholas Roth 	{0x4b0d, 0x00},
379e14d3ac8SNicholas Roth 	{0x4d00, 0x04},
380e14d3ac8SNicholas Roth 	{0x4d01, 0x18},
381e14d3ac8SNicholas Roth 	{0x4d02, 0xc3},
382e14d3ac8SNicholas Roth 	{0x4d03, 0xff},
383e14d3ac8SNicholas Roth 	{0x4d04, 0xff},
384e14d3ac8SNicholas Roth 	{0x4d05, 0xff},
385e14d3ac8SNicholas Roth 	{0x5000, 0x7e},
386e14d3ac8SNicholas Roth 	{0x5001, 0x01},
387e14d3ac8SNicholas Roth 	{0x5002, 0x08},
388e14d3ac8SNicholas Roth 	{0x5003, 0x20},
389e14d3ac8SNicholas Roth 	{0x5046, 0x12},
390e14d3ac8SNicholas Roth 	{0x5901, 0x00},
391e14d3ac8SNicholas Roth 	{0x5e00, 0x00},
392e14d3ac8SNicholas Roth 	{0x5e01, 0x41},
393e14d3ac8SNicholas Roth 	{0x382d, 0x7f},
394e14d3ac8SNicholas Roth 	{0x4825, 0x3a},
395e14d3ac8SNicholas Roth 	{0x4826, 0x40},
396e14d3ac8SNicholas Roth 	{0x4808, 0x25},
397e14d3ac8SNicholas Roth 	{REG_NULL, 0x00},
398e14d3ac8SNicholas Roth };
399e14d3ac8SNicholas Roth 
400e14d3ac8SNicholas Roth static const struct regval ov8858_global_regs_r2a_2lane[] = {
401e14d3ac8SNicholas Roth 	/*
402e14d3ac8SNicholas Roth 	 * MIPI=720Mbps, SysClk=144Mhz,Dac Clock=360Mhz.
403e14d3ac8SNicholas Roth 	 * v00_01_00 (05/29/2014) : initial setting
404e14d3ac8SNicholas Roth 	 * AM19 : 3617 <- 0xC0
405e14d3ac8SNicholas Roth 	 * AM20 : change FWC_6K_EN to be default 0x3618=0x5a
406e14d3ac8SNicholas Roth 	 */
407e14d3ac8SNicholas Roth 	{0x0103, 0x01}, /* software reset */
408e14d3ac8SNicholas Roth 	{0x0100, 0x00}, /* software standby */
409e14d3ac8SNicholas Roth 	{0x0302, 0x1e}, /* pll1_multi */
410e14d3ac8SNicholas Roth 	{0x0303, 0x00}, /* pll1_divm */
411e14d3ac8SNicholas Roth 	{0x0304, 0x03}, /* pll1_div_mipi */
412e14d3ac8SNicholas Roth 	{0x030e, 0x02}, /* pll2_rdiv */
413e14d3ac8SNicholas Roth 	{0x030f, 0x04}, /* pll2_divsp */
414e14d3ac8SNicholas Roth 	{0x0312, 0x03}, /* pll2_pre_div0, pll2_r_divdac */
415e14d3ac8SNicholas Roth 	{0x031e, 0x0c}, /* pll1_no_lat */
416e14d3ac8SNicholas Roth 	{0x3600, 0x00},
417e14d3ac8SNicholas Roth 	{0x3601, 0x00},
418e14d3ac8SNicholas Roth 	{0x3602, 0x00},
419e14d3ac8SNicholas Roth 	{0x3603, 0x00},
420e14d3ac8SNicholas Roth 	{0x3604, 0x22},
421e14d3ac8SNicholas Roth 	{0x3605, 0x20},
422e14d3ac8SNicholas Roth 	{0x3606, 0x00},
423e14d3ac8SNicholas Roth 	{0x3607, 0x20},
424e14d3ac8SNicholas Roth 	{0x3608, 0x11},
425e14d3ac8SNicholas Roth 	{0x3609, 0x28},
426e14d3ac8SNicholas Roth 	{0x360a, 0x00},
427e14d3ac8SNicholas Roth 	{0x360b, 0x05},
428e14d3ac8SNicholas Roth 	{0x360c, 0xd4},
429e14d3ac8SNicholas Roth 	{0x360d, 0x40},
430e14d3ac8SNicholas Roth 	{0x360e, 0x0c},
431e14d3ac8SNicholas Roth 	{0x360f, 0x20},
432e14d3ac8SNicholas Roth 	{0x3610, 0x07},
433e14d3ac8SNicholas Roth 	{0x3611, 0x20},
434e14d3ac8SNicholas Roth 	{0x3612, 0x88},
435e14d3ac8SNicholas Roth 	{0x3613, 0x80},
436e14d3ac8SNicholas Roth 	{0x3614, 0x58},
437e14d3ac8SNicholas Roth 	{0x3615, 0x00},
438e14d3ac8SNicholas Roth 	{0x3616, 0x4a},
439e14d3ac8SNicholas Roth 	{0x3617, 0x90},
440e14d3ac8SNicholas Roth 	{0x3618, 0x5a},
441e14d3ac8SNicholas Roth 	{0x3619, 0x70},
442e14d3ac8SNicholas Roth 	{0x361a, 0x99},
443e14d3ac8SNicholas Roth 	{0x361b, 0x0a},
444e14d3ac8SNicholas Roth 	{0x361c, 0x07},
445e14d3ac8SNicholas Roth 	{0x361d, 0x00},
446e14d3ac8SNicholas Roth 	{0x361e, 0x00},
447e14d3ac8SNicholas Roth 	{0x361f, 0x00},
448e14d3ac8SNicholas Roth 	{0x3638, 0xff},
449e14d3ac8SNicholas Roth 	{0x3633, 0x0f},
450e14d3ac8SNicholas Roth 	{0x3634, 0x0f},
451e14d3ac8SNicholas Roth 	{0x3635, 0x0f},
452e14d3ac8SNicholas Roth 	{0x3636, 0x12},
453e14d3ac8SNicholas Roth 	{0x3645, 0x13},
454e14d3ac8SNicholas Roth 	{0x3646, 0x83},
455e14d3ac8SNicholas Roth 	{0x364a, 0x07},
456e14d3ac8SNicholas Roth 	{0x3015, 0x00},
457e14d3ac8SNicholas Roth 	{0x3018, 0x32}, /* MIPI 2 lane */
458e14d3ac8SNicholas Roth 	{0x3020, 0x93}, /* Clock switch output normal, pclk_div =/1 */
459e14d3ac8SNicholas Roth 	{0x3022, 0x01}, /* pd_mipi enable when rst_sync */
460e14d3ac8SNicholas Roth 	{0x3031, 0x0a}, /* MIPI 10-bit mode */
461e14d3ac8SNicholas Roth 	{0x3034, 0x00},
462e14d3ac8SNicholas Roth 	{0x3106, 0x01}, /* sclk_div, sclk_pre_div */
463e14d3ac8SNicholas Roth 	{0x3305, 0xf1},
464e14d3ac8SNicholas Roth 	{0x3308, 0x00},
465e14d3ac8SNicholas Roth 	{0x3309, 0x28},
466e14d3ac8SNicholas Roth 	{0x330a, 0x00},
467e14d3ac8SNicholas Roth 	{0x330b, 0x20},
468e14d3ac8SNicholas Roth 	{0x330c, 0x00},
469e14d3ac8SNicholas Roth 	{0x330d, 0x00},
470e14d3ac8SNicholas Roth 	{0x330e, 0x00},
471e14d3ac8SNicholas Roth 	{0x330f, 0x40},
472e14d3ac8SNicholas Roth 	{0x3307, 0x04},
473e14d3ac8SNicholas Roth 	{0x3500, 0x00}, /* exposure H */
474e14d3ac8SNicholas Roth 	{0x3501, 0x4d}, /* exposure M */
475e14d3ac8SNicholas Roth 	{0x3502, 0x40}, /* exposure L */
476e14d3ac8SNicholas Roth 	{0x3503, 0x80}, /* gain delay ?, exposure delay 1 frame, real gain */
477e14d3ac8SNicholas Roth 	{0x3505, 0x80}, /* gain option */
478e14d3ac8SNicholas Roth 	{0x3508, 0x02}, /* gain H */
479e14d3ac8SNicholas Roth 	{0x3509, 0x00}, /* gain L */
480e14d3ac8SNicholas Roth 	{0x350c, 0x00}, /* short gain H */
481e14d3ac8SNicholas Roth 	{0x350d, 0x80}, /* short gain L */
482e14d3ac8SNicholas Roth 	{0x3510, 0x00}, /* short exposure H */
483e14d3ac8SNicholas Roth 	{0x3511, 0x02}, /* short exposure M */
484e14d3ac8SNicholas Roth 	{0x3512, 0x00}, /* short exposure L */
485e14d3ac8SNicholas Roth 	{0x3700, 0x18},
486e14d3ac8SNicholas Roth 	{0x3701, 0x0c},
487e14d3ac8SNicholas Roth 	{0x3702, 0x28},
488e14d3ac8SNicholas Roth 	{0x3703, 0x19},
489e14d3ac8SNicholas Roth 	{0x3704, 0x14},
490e14d3ac8SNicholas Roth 	{0x3705, 0x00},
491e14d3ac8SNicholas Roth 	{0x3706, 0x82},
492e14d3ac8SNicholas Roth 	{0x3707, 0x04},
493e14d3ac8SNicholas Roth 	{0x3708, 0x24},
494e14d3ac8SNicholas Roth 	{0x3709, 0x33},
495e14d3ac8SNicholas Roth 	{0x370a, 0x01},
496e14d3ac8SNicholas Roth 	{0x370b, 0x82},
497e14d3ac8SNicholas Roth 	{0x370c, 0x04},
498e14d3ac8SNicholas Roth 	{0x3718, 0x12},
499e14d3ac8SNicholas Roth 	{0x3719, 0x31},
500e14d3ac8SNicholas Roth 	{0x3712, 0x42},
501e14d3ac8SNicholas Roth 	{0x3714, 0x24},
502e14d3ac8SNicholas Roth 	{0x371e, 0x19},
503e14d3ac8SNicholas Roth 	{0x371f, 0x40},
504e14d3ac8SNicholas Roth 	{0x3720, 0x05},
505e14d3ac8SNicholas Roth 	{0x3721, 0x05},
506e14d3ac8SNicholas Roth 	{0x3724, 0x06},
507e14d3ac8SNicholas Roth 	{0x3725, 0x01},
508e14d3ac8SNicholas Roth 	{0x3726, 0x06},
509e14d3ac8SNicholas Roth 	{0x3728, 0x05},
510e14d3ac8SNicholas Roth 	{0x3729, 0x02},
511e14d3ac8SNicholas Roth 	{0x372a, 0x03},
512e14d3ac8SNicholas Roth 	{0x372b, 0x53},
513e14d3ac8SNicholas Roth 	{0x372c, 0xa3},
514e14d3ac8SNicholas Roth 	{0x372d, 0x53},
515e14d3ac8SNicholas Roth 	{0x372e, 0x06},
516e14d3ac8SNicholas Roth 	{0x372f, 0x10},
517e14d3ac8SNicholas Roth 	{0x3730, 0x01},
518e14d3ac8SNicholas Roth 	{0x3731, 0x06},
519e14d3ac8SNicholas Roth 	{0x3732, 0x14},
520e14d3ac8SNicholas Roth 	{0x3733, 0x10},
521e14d3ac8SNicholas Roth 	{0x3734, 0x40},
522e14d3ac8SNicholas Roth 	{0x3736, 0x20},
523e14d3ac8SNicholas Roth 	{0x373a, 0x05},
524e14d3ac8SNicholas Roth 	{0x373b, 0x06},
525e14d3ac8SNicholas Roth 	{0x373c, 0x0a},
526e14d3ac8SNicholas Roth 	{0x373e, 0x03},
527e14d3ac8SNicholas Roth 	{0x3750, 0x0a},
528e14d3ac8SNicholas Roth 	{0x3751, 0x0e},
529e14d3ac8SNicholas Roth 	{0x3755, 0x10},
530e14d3ac8SNicholas Roth 	{0x3758, 0x00},
531e14d3ac8SNicholas Roth 	{0x3759, 0x4c},
532e14d3ac8SNicholas Roth 	{0x375a, 0x06},
533e14d3ac8SNicholas Roth 	{0x375b, 0x13},
534e14d3ac8SNicholas Roth 	{0x375c, 0x20},
535e14d3ac8SNicholas Roth 	{0x375d, 0x02},
536e14d3ac8SNicholas Roth 	{0x375e, 0x00},
537e14d3ac8SNicholas Roth 	{0x375f, 0x14},
538e14d3ac8SNicholas Roth 	{0x3768, 0x22},
539e14d3ac8SNicholas Roth 	{0x3769, 0x44},
540e14d3ac8SNicholas Roth 	{0x376a, 0x44},
541e14d3ac8SNicholas Roth 	{0x3761, 0x00},
542e14d3ac8SNicholas Roth 	{0x3762, 0x00},
543e14d3ac8SNicholas Roth 	{0x3763, 0x00},
544e14d3ac8SNicholas Roth 	{0x3766, 0xff},
545e14d3ac8SNicholas Roth 	{0x376b, 0x00},
546e14d3ac8SNicholas Roth 	{0x3772, 0x23},
547e14d3ac8SNicholas Roth 	{0x3773, 0x02},
548e14d3ac8SNicholas Roth 	{0x3774, 0x16},
549e14d3ac8SNicholas Roth 	{0x3775, 0x12},
550e14d3ac8SNicholas Roth 	{0x3776, 0x04},
551e14d3ac8SNicholas Roth 	{0x3777, 0x00},
552e14d3ac8SNicholas Roth 	{0x3778, 0x17},
553e14d3ac8SNicholas Roth 	{0x37a0, 0x44},
554e14d3ac8SNicholas Roth 	{0x37a1, 0x3d},
555e14d3ac8SNicholas Roth 	{0x37a2, 0x3d},
556e14d3ac8SNicholas Roth 	{0x37a3, 0x00},
557e14d3ac8SNicholas Roth 	{0x37a4, 0x00},
558e14d3ac8SNicholas Roth 	{0x37a5, 0x00},
559e14d3ac8SNicholas Roth 	{0x37a6, 0x00},
560e14d3ac8SNicholas Roth 	{0x37a7, 0x44},
561e14d3ac8SNicholas Roth 	{0x37a8, 0x4c},
562e14d3ac8SNicholas Roth 	{0x37a9, 0x4c},
563e14d3ac8SNicholas Roth 	{0x3760, 0x00},
564e14d3ac8SNicholas Roth 	{0x376f, 0x01},
565e14d3ac8SNicholas Roth 	{0x37aa, 0x44},
566e14d3ac8SNicholas Roth 	{0x37ab, 0x2e},
567e14d3ac8SNicholas Roth 	{0x37ac, 0x2e},
568e14d3ac8SNicholas Roth 	{0x37ad, 0x33},
569e14d3ac8SNicholas Roth 	{0x37ae, 0x0d},
570e14d3ac8SNicholas Roth 	{0x37af, 0x0d},
571e14d3ac8SNicholas Roth 	{0x37b0, 0x00},
572e14d3ac8SNicholas Roth 	{0x37b1, 0x00},
573e14d3ac8SNicholas Roth 	{0x37b2, 0x00},
574e14d3ac8SNicholas Roth 	{0x37b3, 0x42},
575e14d3ac8SNicholas Roth 	{0x37b4, 0x42},
576e14d3ac8SNicholas Roth 	{0x37b5, 0x31},
577e14d3ac8SNicholas Roth 	{0x37b6, 0x00},
578e14d3ac8SNicholas Roth 	{0x37b7, 0x00},
579e14d3ac8SNicholas Roth 	{0x37b8, 0x00},
580e14d3ac8SNicholas Roth 	{0x37b9, 0xff},
581e14d3ac8SNicholas Roth 	{0x3800, 0x00}, /* x start H */
582e14d3ac8SNicholas Roth 	{0x3801, 0x0c}, /* x start L */
583e14d3ac8SNicholas Roth 	{0x3802, 0x00}, /* y start H */
584e14d3ac8SNicholas Roth 	{0x3803, 0x0c}, /* y start L */
585e14d3ac8SNicholas Roth 	{0x3804, 0x0c}, /* x end H */
586e14d3ac8SNicholas Roth 	{0x3805, 0xd3}, /* x end L */
587e14d3ac8SNicholas Roth 	{0x3806, 0x09}, /* y end H */
588e14d3ac8SNicholas Roth 	{0x3807, 0xa3}, /* y end L */
589e14d3ac8SNicholas Roth 	{0x3808, 0x06}, /* x output size H */
590e14d3ac8SNicholas Roth 	{0x3809, 0x60}, /* x output size L */
591e14d3ac8SNicholas Roth 	{0x380a, 0x04}, /* y output size H */
592e14d3ac8SNicholas Roth 	{0x380b, 0xc8}, /* y output size L */
593e14d3ac8SNicholas Roth 	{0x380c, 0x07}, /* HTS H */
594e14d3ac8SNicholas Roth 	{0x380d, 0x88}, /* HTS L */
595e14d3ac8SNicholas Roth 	{0x380e, 0x04}, /* VTS H */
596e14d3ac8SNicholas Roth 	{0x380f, 0xdc}, /* VTS L */
597e14d3ac8SNicholas Roth 	{0x3810, 0x00}, /* ISP x win H */
598e14d3ac8SNicholas Roth 	{0x3811, 0x04}, /* ISP x win L */
599e14d3ac8SNicholas Roth 	{0x3813, 0x02}, /* ISP y win L */
600e14d3ac8SNicholas Roth 	{0x3814, 0x03}, /* x odd inc */
601e14d3ac8SNicholas Roth 	{0x3815, 0x01}, /* x even inc */
602e14d3ac8SNicholas Roth 	{0x3820, 0x00}, /* vflip off */
603e14d3ac8SNicholas Roth 	{0x3821, 0x67}, /* mirror on, bin on */
604e14d3ac8SNicholas Roth 	{0x382a, 0x03}, /* y odd inc */
605e14d3ac8SNicholas Roth 	{0x382b, 0x01}, /* y even inc */
606e14d3ac8SNicholas Roth 	{0x3830, 0x08},
607e14d3ac8SNicholas Roth 	{0x3836, 0x02},
608e14d3ac8SNicholas Roth 	{0x3837, 0x18},
609e14d3ac8SNicholas Roth 	{0x3841, 0xff}, /* window auto size enable */
610e14d3ac8SNicholas Roth 	{0x3846, 0x48},
611e14d3ac8SNicholas Roth 	{0x3d85, 0x16}, /* OTP power up load data enable with BIST */
612e14d3ac8SNicholas Roth 	{0x3d8c, 0x73}, /* OTP setting start High */
613e14d3ac8SNicholas Roth 	{0x3d8d, 0xde}, /* OTP setting start Low */
614e14d3ac8SNicholas Roth 	{0x3f08, 0x08},
615e14d3ac8SNicholas Roth 	{0x3f0a, 0x00},
616e14d3ac8SNicholas Roth 	{0x4000, 0xf1}, /* out_range_trig, format_chg_trig */
617e14d3ac8SNicholas Roth 	{0x4001, 0x10}, /* total 128 black column */
618e14d3ac8SNicholas Roth 	{0x4005, 0x10}, /* BLC target L */
619e14d3ac8SNicholas Roth 	{0x4002, 0x27}, /* value used to limit BLC offset */
620e14d3ac8SNicholas Roth 	{0x4009, 0x81}, /* final BLC offset limitation enable */
621e14d3ac8SNicholas Roth 	{0x400b, 0x0c}, /* DCBLC on, DCBLC manual mode on */
622e14d3ac8SNicholas Roth 	{0x401b, 0x00}, /* zero line R coefficient */
623e14d3ac8SNicholas Roth 	{0x401d, 0x00}, /* zoro line T coefficient */
624e14d3ac8SNicholas Roth 	{0x4020, 0x00}, /* Anchor left start H */
625e14d3ac8SNicholas Roth 	{0x4021, 0x04}, /* Anchor left start L */
626e14d3ac8SNicholas Roth 	{0x4022, 0x06}, /* Anchor left end H */
627e14d3ac8SNicholas Roth 	{0x4023, 0x00}, /* Anchor left end L */
628e14d3ac8SNicholas Roth 	{0x4024, 0x0f}, /* Anchor right start H */
629e14d3ac8SNicholas Roth 	{0x4025, 0x2a}, /* Anchor right start L */
630e14d3ac8SNicholas Roth 	{0x4026, 0x0f}, /* Anchor right end H */
631e14d3ac8SNicholas Roth 	{0x4027, 0x2b}, /* Anchor right end L */
632e14d3ac8SNicholas Roth 	{0x4028, 0x00}, /* top zero line start */
633e14d3ac8SNicholas Roth 	{0x4029, 0x02}, /* top zero line number */
634e14d3ac8SNicholas Roth 	{0x402a, 0x04}, /* top black line start */
635e14d3ac8SNicholas Roth 	{0x402b, 0x04}, /* top black line number */
636e14d3ac8SNicholas Roth 	{0x402c, 0x00}, /* bottom zero line start */
637e14d3ac8SNicholas Roth 	{0x402d, 0x02}, /* bottom zoro line number */
638e14d3ac8SNicholas Roth 	{0x402e, 0x04}, /* bottom black line start */
639e14d3ac8SNicholas Roth 	{0x402f, 0x04}, /* bottom black line number */
640e14d3ac8SNicholas Roth 	{0x401f, 0x00}, /* interpolation x/y disable, Anchor one disable */
641e14d3ac8SNicholas Roth 	{0x4034, 0x3f},
642e14d3ac8SNicholas Roth 	{0x403d, 0x04}, /* md_precision_en */
643e14d3ac8SNicholas Roth 	{0x4300, 0xff}, /* clip max H */
644e14d3ac8SNicholas Roth 	{0x4301, 0x00}, /* clip min H */
645e14d3ac8SNicholas Roth 	{0x4302, 0x0f}, /* clip min L, clip max L */
646e14d3ac8SNicholas Roth 	{0x4316, 0x00},
647e14d3ac8SNicholas Roth 	{0x4500, 0x58},
648e14d3ac8SNicholas Roth 	{0x4503, 0x18},
649e14d3ac8SNicholas Roth 	{0x4600, 0x00},
650e14d3ac8SNicholas Roth 	{0x4601, 0xcb},
651e14d3ac8SNicholas Roth 	{0x481f, 0x32}, /* clk prepare min */
652e14d3ac8SNicholas Roth 	{0x4837, 0x16}, /* global timing */
653e14d3ac8SNicholas Roth 	{0x4850, 0x10}, /* lane 1 = 1, lane 0 = 0 */
654e14d3ac8SNicholas Roth 	{0x4851, 0x32}, /* lane 3 = 3, lane 2 = 2 */
655e14d3ac8SNicholas Roth 	{0x4b00, 0x2a},
656e14d3ac8SNicholas Roth 	{0x4b0d, 0x00},
657e14d3ac8SNicholas Roth 	{0x4d00, 0x04}, /* temperature sensor */
658e14d3ac8SNicholas Roth 	{0x4d01, 0x18},
659e14d3ac8SNicholas Roth 	{0x4d02, 0xc3},
660e14d3ac8SNicholas Roth 	{0x4d03, 0xff},
661e14d3ac8SNicholas Roth 	{0x4d04, 0xff},
662e14d3ac8SNicholas Roth 	{0x4d05, 0xff}, /* temperature sensor */
663e14d3ac8SNicholas Roth 	{0x5000, 0xfe}, /* lenc on, slave/master AWB gain/statistics enable */
664e14d3ac8SNicholas Roth 	{0x5001, 0x01}, /* BLC on */
665e14d3ac8SNicholas Roth 	{0x5002, 0x08}, /* H scale off, WBMATCH off, OTP_DPC */
666e14d3ac8SNicholas Roth 	{0x5003, 0x20}, /* DPC_DBC buffer control enable, WB */
667e14d3ac8SNicholas Roth 	{0x501e, 0x93}, /* enable digital gain */
668e14d3ac8SNicholas Roth 	{0x5046, 0x12},
669e14d3ac8SNicholas Roth 	{0x5780, 0x3e}, /* DPC */
670e14d3ac8SNicholas Roth 	{0x5781, 0x0f},
671e14d3ac8SNicholas Roth 	{0x5782, 0x44},
672e14d3ac8SNicholas Roth 	{0x5783, 0x02},
673e14d3ac8SNicholas Roth 	{0x5784, 0x01},
674e14d3ac8SNicholas Roth 	{0x5785, 0x00},
675e14d3ac8SNicholas Roth 	{0x5786, 0x00},
676e14d3ac8SNicholas Roth 	{0x5787, 0x04},
677e14d3ac8SNicholas Roth 	{0x5788, 0x02},
678e14d3ac8SNicholas Roth 	{0x5789, 0x0f},
679e14d3ac8SNicholas Roth 	{0x578a, 0xfd},
680e14d3ac8SNicholas Roth 	{0x578b, 0xf5},
681e14d3ac8SNicholas Roth 	{0x578c, 0xf5},
682e14d3ac8SNicholas Roth 	{0x578d, 0x03},
683e14d3ac8SNicholas Roth 	{0x578e, 0x08},
684e14d3ac8SNicholas Roth 	{0x578f, 0x0c},
685e14d3ac8SNicholas Roth 	{0x5790, 0x08},
686e14d3ac8SNicholas Roth 	{0x5791, 0x04},
687e14d3ac8SNicholas Roth 	{0x5792, 0x00},
688e14d3ac8SNicholas Roth 	{0x5793, 0x52},
689e14d3ac8SNicholas Roth 	{0x5794, 0xa3}, /* DPC */
690e14d3ac8SNicholas Roth 	{0x5871, 0x0d}, /* Lenc */
691e14d3ac8SNicholas Roth 	{0x5870, 0x18},
692e14d3ac8SNicholas Roth 	{0x586e, 0x10},
693e14d3ac8SNicholas Roth 	{0x586f, 0x08},
694e14d3ac8SNicholas Roth 	{0x58f7, 0x01},
695e14d3ac8SNicholas Roth 	{0x58f8, 0x3d}, /* Lenc */
696e14d3ac8SNicholas Roth 	{0x5901, 0x00}, /* H skip off, V skip off */
697e14d3ac8SNicholas Roth 	{0x5b00, 0x02}, /* OTP DPC start address */
698e14d3ac8SNicholas Roth 	{0x5b01, 0x10}, /* OTP DPC start address */
699e14d3ac8SNicholas Roth 	{0x5b02, 0x03}, /* OTP DPC end address */
700e14d3ac8SNicholas Roth 	{0x5b03, 0xcf}, /* OTP DPC end address */
701e14d3ac8SNicholas Roth 	{0x5b05, 0x6c}, /* recover method = 2b11, */
702e14d3ac8SNicholas Roth 	{0x5e00, 0x00}, /* use 0x3ff to test pattern off */
703e14d3ac8SNicholas Roth 	{0x5e01, 0x41}, /* window cut enable */
704e14d3ac8SNicholas Roth 	{0x382d, 0x7f},
705e14d3ac8SNicholas Roth 	{0x4825, 0x3a}, /* lpx_p_min */
706e14d3ac8SNicholas Roth 	{0x4826, 0x40}, /* hs_prepare_min */
707e14d3ac8SNicholas Roth 	{0x4808, 0x25}, /* wake up delay in 1/1024 s */
708e14d3ac8SNicholas Roth 	{0x3763, 0x18},
709e14d3ac8SNicholas Roth 	{0x3768, 0xcc},
710e14d3ac8SNicholas Roth 	{0x470b, 0x28},
711e14d3ac8SNicholas Roth 	{0x4202, 0x00},
712e14d3ac8SNicholas Roth 	{0x400d, 0x10}, /* BLC offset trigger L */
713e14d3ac8SNicholas Roth 	{0x4040, 0x04}, /* BLC gain th2 */
714e14d3ac8SNicholas Roth 	{0x403e, 0x04}, /* BLC gain th1 */
715e14d3ac8SNicholas Roth 	{0x4041, 0xc6}, /* BLC */
716e14d3ac8SNicholas Roth 	{0x3007, 0x80},
717e14d3ac8SNicholas Roth 	{0x400a, 0x01},
718e14d3ac8SNicholas Roth 	{REG_NULL, 0x00},
719e14d3ac8SNicholas Roth };
720e14d3ac8SNicholas Roth 
721e14d3ac8SNicholas Roth /*
722e14d3ac8SNicholas Roth  * Xclk 24Mhz
723e14d3ac8SNicholas Roth  * max_framerate 30fps
724e14d3ac8SNicholas Roth  * mipi_datarate per lane 720Mbps
725e14d3ac8SNicholas Roth  */
726e14d3ac8SNicholas Roth static const struct regval ov8858_1632x1224_regs_2lane[] = {
727e14d3ac8SNicholas Roth 	/*
728e14d3ac8SNicholas Roth 	 * MIPI=720Mbps, SysClk=144Mhz,Dac Clock=360Mhz.
729e14d3ac8SNicholas Roth 	 * v00_01_00 (05/29/2014) : initial setting
730e14d3ac8SNicholas Roth 	 * AM19 : 3617 <- 0xC0
731e14d3ac8SNicholas Roth 	 * AM20 : change FWC_6K_EN to be default 0x3618=0x5a
732e14d3ac8SNicholas Roth 	 */
733e14d3ac8SNicholas Roth 	{0x0100, 0x00},
734e14d3ac8SNicholas Roth 	{0x3501, 0x4d}, /* exposure M */
735e14d3ac8SNicholas Roth 	{0x3502, 0x40}, /* exposure L */
736e14d3ac8SNicholas Roth 	{0x3778, 0x17},
737e14d3ac8SNicholas Roth 	{0x3808, 0x06}, /* x output size H */
738e14d3ac8SNicholas Roth 	{0x3809, 0x60}, /* x output size L */
739e14d3ac8SNicholas Roth 	{0x380a, 0x04}, /* y output size H */
740e14d3ac8SNicholas Roth 	{0x380b, 0xc8}, /* y output size L */
741e14d3ac8SNicholas Roth 	{0x380c, 0x07}, /* HTS H */
742e14d3ac8SNicholas Roth 	{0x380d, 0x88}, /* HTS L */
743e14d3ac8SNicholas Roth 	{0x380e, 0x04}, /* VTS H */
744e14d3ac8SNicholas Roth 	{0x380f, 0xdc}, /* VTS L */
745e14d3ac8SNicholas Roth 	{0x3814, 0x03}, /* x odd inc */
746e14d3ac8SNicholas Roth 	{0x3821, 0x67}, /* mirror on, bin on */
747e14d3ac8SNicholas Roth 	{0x382a, 0x03}, /* y odd inc */
748e14d3ac8SNicholas Roth 	{0x3830, 0x08},
749e14d3ac8SNicholas Roth 	{0x3836, 0x02},
750e14d3ac8SNicholas Roth 	{0x3f0a, 0x00},
751e14d3ac8SNicholas Roth 	{0x4001, 0x10}, /* total 128 black column */
752e14d3ac8SNicholas Roth 	{0x4022, 0x06}, /* Anchor left end H */
753e14d3ac8SNicholas Roth 	{0x4023, 0x00}, /* Anchor left end L */
754e14d3ac8SNicholas Roth 	{0x4025, 0x2a}, /* Anchor right start L */
755e14d3ac8SNicholas Roth 	{0x4027, 0x2b}, /* Anchor right end L */
756e14d3ac8SNicholas Roth 	{0x402b, 0x04}, /* top black line number */
757e14d3ac8SNicholas Roth 	{0x402f, 0x04}, /* bottom black line number */
758e14d3ac8SNicholas Roth 	{0x4500, 0x58},
759e14d3ac8SNicholas Roth 	{0x4600, 0x00},
760e14d3ac8SNicholas Roth 	{0x4601, 0xcb},
761e14d3ac8SNicholas Roth 	{0x382d, 0x7f},
762e14d3ac8SNicholas Roth 	{0x0100, 0x01},
763e14d3ac8SNicholas Roth 	{REG_NULL, 0x00},
764e14d3ac8SNicholas Roth };
765e14d3ac8SNicholas Roth 
766e14d3ac8SNicholas Roth /*
767e14d3ac8SNicholas Roth  * Xclk 24Mhz
768e14d3ac8SNicholas Roth  * max_framerate 15fps
769e14d3ac8SNicholas Roth  * mipi_datarate per lane 720Mbps
770e14d3ac8SNicholas Roth  */
771e14d3ac8SNicholas Roth static const struct regval ov8858_3264x2448_regs_2lane[] = {
772e14d3ac8SNicholas Roth 	{0x0100, 0x00},
773e14d3ac8SNicholas Roth 	{0x3501, 0x9a}, /* exposure M */
774e14d3ac8SNicholas Roth 	{0x3502, 0x20}, /* exposure L */
775e14d3ac8SNicholas Roth 	{0x3778, 0x1a},
776e14d3ac8SNicholas Roth 	{0x3808, 0x0c}, /* x output size H */
777e14d3ac8SNicholas Roth 	{0x3809, 0xc0}, /* x output size L */
778e14d3ac8SNicholas Roth 	{0x380a, 0x09}, /* y output size H */
779e14d3ac8SNicholas Roth 	{0x380b, 0x90}, /* y output size L */
780e14d3ac8SNicholas Roth 	{0x380c, 0x07}, /* HTS H */
781e14d3ac8SNicholas Roth 	{0x380d, 0x94}, /* HTS L */
782e14d3ac8SNicholas Roth 	{0x380e, 0x09}, /* VTS H */
783e14d3ac8SNicholas Roth 	{0x380f, 0xaa}, /* VTS L */
784e14d3ac8SNicholas Roth 	{0x3814, 0x01}, /* x odd inc */
785e14d3ac8SNicholas Roth 	{0x3821, 0x46}, /* mirror on, bin off */
786e14d3ac8SNicholas Roth 	{0x382a, 0x01}, /* y odd inc */
787e14d3ac8SNicholas Roth 	{0x3830, 0x06},
788e14d3ac8SNicholas Roth 	{0x3836, 0x01},
789e14d3ac8SNicholas Roth 	{0x3f0a, 0x00},
790e14d3ac8SNicholas Roth 	{0x4001, 0x00}, /* total 256 black column */
791e14d3ac8SNicholas Roth 	{0x4022, 0x0c}, /* Anchor left end H */
792e14d3ac8SNicholas Roth 	{0x4023, 0x60}, /* Anchor left end L */
793e14d3ac8SNicholas Roth 	{0x4025, 0x36}, /* Anchor right start L */
794e14d3ac8SNicholas Roth 	{0x4027, 0x37}, /* Anchor right end L */
795e14d3ac8SNicholas Roth 	{0x402b, 0x08}, /* top black line number */
796e14d3ac8SNicholas Roth 	{0x402f, 0x08}, /* bottom black line number */
797e14d3ac8SNicholas Roth 	{0x4500, 0x58},
798e14d3ac8SNicholas Roth 	{0x4600, 0x01},
799e14d3ac8SNicholas Roth 	{0x4601, 0x97},
800e14d3ac8SNicholas Roth 	{0x382d, 0xff},
801e14d3ac8SNicholas Roth 	{REG_NULL, 0x00},
802e14d3ac8SNicholas Roth };
803e14d3ac8SNicholas Roth 
804e14d3ac8SNicholas Roth static const struct regval ov8858_global_regs_r2a_4lane[] = {
805e14d3ac8SNicholas Roth 	/*
806e14d3ac8SNicholas Roth 	 * MIPI=720Mbps, SysClk=144Mhz,Dac Clock=360Mhz.
807e14d3ac8SNicholas Roth 	 * v00_01_00 (05/29/2014) : initial setting
808e14d3ac8SNicholas Roth 	 * AM19 : 3617 <- 0xC0
809e14d3ac8SNicholas Roth 	 * AM20 : change FWC_6K_EN to be default 0x3618=0x5a
810e14d3ac8SNicholas Roth 	 */
811e14d3ac8SNicholas Roth 	{0x0103, 0x01}, /* software reset for OVTATool only */
812e14d3ac8SNicholas Roth 	{0x0103, 0x01}, /* software reset */
813e14d3ac8SNicholas Roth 	{0x0100, 0x00}, /* software standby */
814e14d3ac8SNicholas Roth 	{0x0302, 0x1e}, /* pll1_multi */
815e14d3ac8SNicholas Roth 	{0x0303, 0x00}, /* pll1_divm */
816e14d3ac8SNicholas Roth 	{0x0304, 0x03}, /* pll1_div_mipi */
817e14d3ac8SNicholas Roth 	{0x030e, 0x00}, /* pll2_rdiv */
818e14d3ac8SNicholas Roth 	{0x030f, 0x04}, /* pll2_divsp */
819e14d3ac8SNicholas Roth 	{0x0312, 0x01}, /* pll2_pre_div0, pll2_r_divdac */
820e14d3ac8SNicholas Roth 	{0x031e, 0x0c}, /* pll1_no_lat */
821e14d3ac8SNicholas Roth 	{0x3600, 0x00},
822e14d3ac8SNicholas Roth 	{0x3601, 0x00},
823e14d3ac8SNicholas Roth 	{0x3602, 0x00},
824e14d3ac8SNicholas Roth 	{0x3603, 0x00},
825e14d3ac8SNicholas Roth 	{0x3604, 0x22},
826e14d3ac8SNicholas Roth 	{0x3605, 0x20},
827e14d3ac8SNicholas Roth 	{0x3606, 0x00},
828e14d3ac8SNicholas Roth 	{0x3607, 0x20},
829e14d3ac8SNicholas Roth 	{0x3608, 0x11},
830e14d3ac8SNicholas Roth 	{0x3609, 0x28},
831e14d3ac8SNicholas Roth 	{0x360a, 0x00},
832e14d3ac8SNicholas Roth 	{0x360b, 0x05},
833e14d3ac8SNicholas Roth 	{0x360c, 0xd4},
834e14d3ac8SNicholas Roth 	{0x360d, 0x40},
835e14d3ac8SNicholas Roth 	{0x360e, 0x0c},
836e14d3ac8SNicholas Roth 	{0x360f, 0x20},
837e14d3ac8SNicholas Roth 	{0x3610, 0x07},
838e14d3ac8SNicholas Roth 	{0x3611, 0x20},
839e14d3ac8SNicholas Roth 	{0x3612, 0x88},
840e14d3ac8SNicholas Roth 	{0x3613, 0x80},
841e14d3ac8SNicholas Roth 	{0x3614, 0x58},
842e14d3ac8SNicholas Roth 	{0x3615, 0x00},
843e14d3ac8SNicholas Roth 	{0x3616, 0x4a},
844e14d3ac8SNicholas Roth 	{0x3617, 0x90},
845e14d3ac8SNicholas Roth 	{0x3618, 0x5a},
846e14d3ac8SNicholas Roth 	{0x3619, 0x70},
847e14d3ac8SNicholas Roth 	{0x361a, 0x99},
848e14d3ac8SNicholas Roth 	{0x361b, 0x0a},
849e14d3ac8SNicholas Roth 	{0x361c, 0x07},
850e14d3ac8SNicholas Roth 	{0x361d, 0x00},
851e14d3ac8SNicholas Roth 	{0x361e, 0x00},
852e14d3ac8SNicholas Roth 	{0x361f, 0x00},
853e14d3ac8SNicholas Roth 	{0x3638, 0xff},
854e14d3ac8SNicholas Roth 	{0x3633, 0x0f},
855e14d3ac8SNicholas Roth 	{0x3634, 0x0f},
856e14d3ac8SNicholas Roth 	{0x3635, 0x0f},
857e14d3ac8SNicholas Roth 	{0x3636, 0x12},
858e14d3ac8SNicholas Roth 	{0x3645, 0x13},
859e14d3ac8SNicholas Roth 	{0x3646, 0x83},
860e14d3ac8SNicholas Roth 	{0x364a, 0x07},
861e14d3ac8SNicholas Roth 	{0x3015, 0x01},
862e14d3ac8SNicholas Roth 	{0x3018, 0x72}, /* MIPI 4 lane */
863e14d3ac8SNicholas Roth 	{0x3020, 0x93}, /* Clock switch output normal, pclk_div =/1 */
864e14d3ac8SNicholas Roth 	{0x3022, 0x01}, /* pd_mipi enable when rst_sync */
865e14d3ac8SNicholas Roth 	{0x3031, 0x0a}, /* MIPI 10-bit mode */
866e14d3ac8SNicholas Roth 	{0x3034, 0x00},
867e14d3ac8SNicholas Roth 	{0x3106, 0x01}, /* sclk_div, sclk_pre_div */
868e14d3ac8SNicholas Roth 	{0x3305, 0xf1},
869e14d3ac8SNicholas Roth 	{0x3308, 0x00},
870e14d3ac8SNicholas Roth 	{0x3309, 0x28},
871e14d3ac8SNicholas Roth 	{0x330a, 0x00},
872e14d3ac8SNicholas Roth 	{0x330b, 0x20},
873e14d3ac8SNicholas Roth 	{0x330c, 0x00},
874e14d3ac8SNicholas Roth 	{0x330d, 0x00},
875e14d3ac8SNicholas Roth 	{0x330e, 0x00},
876e14d3ac8SNicholas Roth 	{0x330f, 0x40},
877e14d3ac8SNicholas Roth 	{0x3307, 0x04},
878e14d3ac8SNicholas Roth 	{0x3500, 0x00}, /* exposure H */
879e14d3ac8SNicholas Roth 	{0x3501, 0x4d}, /* exposure M */
880e14d3ac8SNicholas Roth 	{0x3502, 0x40}, /* exposure L */
881e14d3ac8SNicholas Roth 	{0x3503, 0x80}, /* gain delay ?, exposure delay 1 frame, real gain */
882e14d3ac8SNicholas Roth 	{0x3505, 0x80}, /* gain option */
883e14d3ac8SNicholas Roth 	{0x3508, 0x02}, /* gain H */
884e14d3ac8SNicholas Roth 	{0x3509, 0x00}, /* gain L */
885e14d3ac8SNicholas Roth 	{0x350c, 0x00}, /* short gain H */
886e14d3ac8SNicholas Roth 	{0x350d, 0x80}, /* short gain L */
887e14d3ac8SNicholas Roth 	{0x3510, 0x00}, /* short exposure H */
888e14d3ac8SNicholas Roth 	{0x3511, 0x02}, /* short exposure M */
889e14d3ac8SNicholas Roth 	{0x3512, 0x00}, /* short exposure L */
890e14d3ac8SNicholas Roth 	{0x3700, 0x30},
891e14d3ac8SNicholas Roth 	{0x3701, 0x18},
892e14d3ac8SNicholas Roth 	{0x3702, 0x50},
893e14d3ac8SNicholas Roth 	{0x3703, 0x32},
894e14d3ac8SNicholas Roth 	{0x3704, 0x28},
895e14d3ac8SNicholas Roth 	{0x3705, 0x00},
896e14d3ac8SNicholas Roth 	{0x3706, 0x82},
897e14d3ac8SNicholas Roth 	{0x3707, 0x08},
898e14d3ac8SNicholas Roth 	{0x3708, 0x48},
899e14d3ac8SNicholas Roth 	{0x3709, 0x66},
900e14d3ac8SNicholas Roth 	{0x370a, 0x01},
901e14d3ac8SNicholas Roth 	{0x370b, 0x82},
902e14d3ac8SNicholas Roth 	{0x370c, 0x07},
903e14d3ac8SNicholas Roth 	{0x3718, 0x14},
904e14d3ac8SNicholas Roth 	{0x3719, 0x31},
905e14d3ac8SNicholas Roth 	{0x3712, 0x44},
906e14d3ac8SNicholas Roth 	{0x3714, 0x24},
907e14d3ac8SNicholas Roth 	{0x371e, 0x31},
908e14d3ac8SNicholas Roth 	{0x371f, 0x7f},
909e14d3ac8SNicholas Roth 	{0x3720, 0x0a},
910e14d3ac8SNicholas Roth 	{0x3721, 0x0a},
911e14d3ac8SNicholas Roth 	{0x3724, 0x0c},
912e14d3ac8SNicholas Roth 	{0x3725, 0x02},
913e14d3ac8SNicholas Roth 	{0x3726, 0x0c},
914e14d3ac8SNicholas Roth 	{0x3728, 0x0a},
915e14d3ac8SNicholas Roth 	{0x3729, 0x03},
916e14d3ac8SNicholas Roth 	{0x372a, 0x06},
917e14d3ac8SNicholas Roth 	{0x372b, 0xa6},
918e14d3ac8SNicholas Roth 	{0x372c, 0xa6},
919e14d3ac8SNicholas Roth 	{0x372d, 0xa6},
920e14d3ac8SNicholas Roth 	{0x372e, 0x0c},
921e14d3ac8SNicholas Roth 	{0x372f, 0x20},
922e14d3ac8SNicholas Roth 	{0x3730, 0x02},
923e14d3ac8SNicholas Roth 	{0x3731, 0x0c},
924e14d3ac8SNicholas Roth 	{0x3732, 0x28},
925e14d3ac8SNicholas Roth 	{0x3733, 0x10},
926e14d3ac8SNicholas Roth 	{0x3734, 0x40},
927e14d3ac8SNicholas Roth 	{0x3736, 0x30},
928e14d3ac8SNicholas Roth 	{0x373a, 0x0a},
929e14d3ac8SNicholas Roth 	{0x373b, 0x0b},
930e14d3ac8SNicholas Roth 	{0x373c, 0x14},
931e14d3ac8SNicholas Roth 	{0x373e, 0x06},
932e14d3ac8SNicholas Roth 	{0x3750, 0x0a},
933e14d3ac8SNicholas Roth 	{0x3751, 0x0e},
934e14d3ac8SNicholas Roth 	{0x3755, 0x10},
935e14d3ac8SNicholas Roth 	{0x3758, 0x00},
936e14d3ac8SNicholas Roth 	{0x3759, 0x4c},
937e14d3ac8SNicholas Roth 	{0x375a, 0x0c},
938e14d3ac8SNicholas Roth 	{0x375b, 0x26},
939e14d3ac8SNicholas Roth 	{0x375c, 0x20},
940e14d3ac8SNicholas Roth 	{0x375d, 0x04},
941e14d3ac8SNicholas Roth 	{0x375e, 0x00},
942e14d3ac8SNicholas Roth 	{0x375f, 0x28},
943e14d3ac8SNicholas Roth 	{0x3768, 0x22},
944e14d3ac8SNicholas Roth 	{0x3769, 0x44},
945e14d3ac8SNicholas Roth 	{0x376a, 0x44},
946e14d3ac8SNicholas Roth 	{0x3761, 0x00},
947e14d3ac8SNicholas Roth 	{0x3762, 0x00},
948e14d3ac8SNicholas Roth 	{0x3763, 0x00},
949e14d3ac8SNicholas Roth 	{0x3766, 0xff},
950e14d3ac8SNicholas Roth 	{0x376b, 0x00},
951e14d3ac8SNicholas Roth 	{0x3772, 0x46},
952e14d3ac8SNicholas Roth 	{0x3773, 0x04},
953e14d3ac8SNicholas Roth 	{0x3774, 0x2c},
954e14d3ac8SNicholas Roth 	{0x3775, 0x13},
955e14d3ac8SNicholas Roth 	{0x3776, 0x08},
956e14d3ac8SNicholas Roth 	{0x3777, 0x00},
957e14d3ac8SNicholas Roth 	{0x3778, 0x17},
958e14d3ac8SNicholas Roth 	{0x37a0, 0x88},
959e14d3ac8SNicholas Roth 	{0x37a1, 0x7a},
960e14d3ac8SNicholas Roth 	{0x37a2, 0x7a},
961e14d3ac8SNicholas Roth 	{0x37a3, 0x00},
962e14d3ac8SNicholas Roth 	{0x37a4, 0x00},
963e14d3ac8SNicholas Roth 	{0x37a5, 0x00},
964e14d3ac8SNicholas Roth 	{0x37a6, 0x00},
965e14d3ac8SNicholas Roth 	{0x37a7, 0x88},
966e14d3ac8SNicholas Roth 	{0x37a8, 0x98},
967e14d3ac8SNicholas Roth 	{0x37a9, 0x98},
968e14d3ac8SNicholas Roth 	{0x3760, 0x00},
969e14d3ac8SNicholas Roth 	{0x376f, 0x01},
970e14d3ac8SNicholas Roth 	{0x37aa, 0x88},
971e14d3ac8SNicholas Roth 	{0x37ab, 0x5c},
972e14d3ac8SNicholas Roth 	{0x37ac, 0x5c},
973e14d3ac8SNicholas Roth 	{0x37ad, 0x55},
974e14d3ac8SNicholas Roth 	{0x37ae, 0x19},
975e14d3ac8SNicholas Roth 	{0x37af, 0x19},
976e14d3ac8SNicholas Roth 	{0x37b0, 0x00},
977e14d3ac8SNicholas Roth 	{0x37b1, 0x00},
978e14d3ac8SNicholas Roth 	{0x37b2, 0x00},
979e14d3ac8SNicholas Roth 	{0x37b3, 0x84},
980e14d3ac8SNicholas Roth 	{0x37b4, 0x84},
981e14d3ac8SNicholas Roth 	{0x37b5, 0x60},
982e14d3ac8SNicholas Roth 	{0x37b6, 0x00},
983e14d3ac8SNicholas Roth 	{0x37b7, 0x00},
984e14d3ac8SNicholas Roth 	{0x37b8, 0x00},
985e14d3ac8SNicholas Roth 	{0x37b9, 0xff},
986e14d3ac8SNicholas Roth 	{0x3800, 0x00}, /* x start H */
987e14d3ac8SNicholas Roth 	{0x3801, 0x0c}, /* x start L */
988e14d3ac8SNicholas Roth 	{0x3802, 0x00}, /* y start H */
989e14d3ac8SNicholas Roth 	{0x3803, 0x0c}, /* y start L */
990e14d3ac8SNicholas Roth 	{0x3804, 0x0c}, /* x end H */
991e14d3ac8SNicholas Roth 	{0x3805, 0xd3}, /* x end L */
992e14d3ac8SNicholas Roth 	{0x3806, 0x09}, /* y end H */
993e14d3ac8SNicholas Roth 	{0x3807, 0xa3}, /* y end L */
994e14d3ac8SNicholas Roth 	{0x3808, 0x06}, /* x output size H */
995e14d3ac8SNicholas Roth 	{0x3809, 0x60}, /* x output size L */
996e14d3ac8SNicholas Roth 	{0x380a, 0x04}, /* y output size H */
997e14d3ac8SNicholas Roth 	{0x380b, 0xc8}, /* y output size L */
998e14d3ac8SNicholas Roth 	{0x380c, 0x07}, /* HTS H */
999e14d3ac8SNicholas Roth 	{0x380d, 0x88}, /* HTS L */
1000e14d3ac8SNicholas Roth 	{0x380e, 0x04}, /* VTS H */
1001e14d3ac8SNicholas Roth 	{0x380f, 0xdc}, /* VTS L */
1002e14d3ac8SNicholas Roth 	{0x3810, 0x00}, /* ISP x win H */
1003e14d3ac8SNicholas Roth 	{0x3811, 0x04}, /* ISP x win L */
1004e14d3ac8SNicholas Roth 	{0x3813, 0x02}, /* ISP y win L */
1005e14d3ac8SNicholas Roth 	{0x3814, 0x03}, /* x odd inc */
1006e14d3ac8SNicholas Roth 	{0x3815, 0x01}, /* x even inc */
1007e14d3ac8SNicholas Roth 	{0x3820, 0x00}, /* vflip off */
1008e14d3ac8SNicholas Roth 	{0x3821, 0x67}, /* mirror on, bin o */
1009e14d3ac8SNicholas Roth 	{0x382a, 0x03}, /* y odd inc */
1010e14d3ac8SNicholas Roth 	{0x382b, 0x01}, /* y even inc */
1011e14d3ac8SNicholas Roth 	{0x3830, 0x08},
1012e14d3ac8SNicholas Roth 	{0x3836, 0x02},
1013e14d3ac8SNicholas Roth 	{0x3837, 0x18},
1014e14d3ac8SNicholas Roth 	{0x3841, 0xff}, /* window auto size enable */
1015e14d3ac8SNicholas Roth 	{0x3846, 0x48},
1016e14d3ac8SNicholas Roth 	{0x3d85, 0x16}, /* OTP power up load data/setting enable */
1017e14d3ac8SNicholas Roth 	{0x3d8c, 0x73}, /* OTP setting start High */
1018e14d3ac8SNicholas Roth 	{0x3d8d, 0xde}, /* OTP setting start Low */
1019e14d3ac8SNicholas Roth 	{0x3f08, 0x10},
1020e14d3ac8SNicholas Roth 	{0x3f0a, 0x00},
1021e14d3ac8SNicholas Roth 	{0x4000, 0xf1}, /* out_range/format_chg/gain/exp_chg trig enable */
1022e14d3ac8SNicholas Roth 	{0x4001, 0x10}, /* total 128 black column */
1023e14d3ac8SNicholas Roth 	{0x4005, 0x10}, /* BLC target L */
1024e14d3ac8SNicholas Roth 	{0x4002, 0x27}, /* value used to limit BLC offset */
1025e14d3ac8SNicholas Roth 	{0x4009, 0x81}, /* final BLC offset limitation enable */
1026e14d3ac8SNicholas Roth 	{0x400b, 0x0c}, /* DCBLC on, DCBLC manual mode on */
1027e14d3ac8SNicholas Roth 	{0x401b, 0x00}, /* zero line R coefficient */
1028e14d3ac8SNicholas Roth 	{0x401d, 0x00}, /* zoro line T coefficient */
1029e14d3ac8SNicholas Roth 	{0x4020, 0x00}, /* Anchor left start H */
1030e14d3ac8SNicholas Roth 	{0x4021, 0x04}, /* Anchor left start L */
1031e14d3ac8SNicholas Roth 	{0x4022, 0x06}, /* Anchor left end H */
1032e14d3ac8SNicholas Roth 	{0x4023, 0x00}, /* Anchor left end L */
1033e14d3ac8SNicholas Roth 	{0x4024, 0x0f}, /* Anchor right start H */
1034e14d3ac8SNicholas Roth 	{0x4025, 0x2a}, /* Anchor right start L */
1035e14d3ac8SNicholas Roth 	{0x4026, 0x0f}, /* Anchor right end H */
1036e14d3ac8SNicholas Roth 	{0x4027, 0x2b}, /* Anchor right end L */
1037e14d3ac8SNicholas Roth 	{0x4028, 0x00}, /* top zero line start */
1038e14d3ac8SNicholas Roth 	{0x4029, 0x02}, /* top zero line number */
1039e14d3ac8SNicholas Roth 	{0x402a, 0x04}, /* top black line start */
1040e14d3ac8SNicholas Roth 	{0x402b, 0x04}, /* top black line number */
1041e14d3ac8SNicholas Roth 	{0x402c, 0x00}, /* bottom zero line start */
1042e14d3ac8SNicholas Roth 	{0x402d, 0x02}, /* bottom zoro line number */
1043e14d3ac8SNicholas Roth 	{0x402e, 0x04}, /* bottom black line start */
1044e14d3ac8SNicholas Roth 	{0x402f, 0x04}, /* bottom black line number */
1045e14d3ac8SNicholas Roth 	{0x401f, 0x00}, /* interpolation x/y disable, Anchor one disable */
1046e14d3ac8SNicholas Roth 	{0x4034, 0x3f},
1047e14d3ac8SNicholas Roth 	{0x403d, 0x04}, /* md_precision_en */
1048e14d3ac8SNicholas Roth 	{0x4300, 0xff}, /* clip max H */
1049e14d3ac8SNicholas Roth 	{0x4301, 0x00}, /* clip min H */
1050e14d3ac8SNicholas Roth 	{0x4302, 0x0f}, /* clip min L, clip max L */
1051e14d3ac8SNicholas Roth 	{0x4316, 0x00},
1052e14d3ac8SNicholas Roth 	{0x4500, 0x58},
1053e14d3ac8SNicholas Roth 	{0x4503, 0x18},
1054e14d3ac8SNicholas Roth 	{0x4600, 0x00},
1055e14d3ac8SNicholas Roth 	{0x4601, 0xcb},
1056e14d3ac8SNicholas Roth 	{0x481f, 0x32}, /* clk prepare min */
1057e14d3ac8SNicholas Roth 	{0x4837, 0x16}, /* global timing */
1058e14d3ac8SNicholas Roth 	{0x4850, 0x10}, /* lane 1 = 1, lane 0 = 0 */
1059e14d3ac8SNicholas Roth 	{0x4851, 0x32}, /* lane 3 = 3, lane 2 = 2 */
1060e14d3ac8SNicholas Roth 	{0x4b00, 0x2a},
1061e14d3ac8SNicholas Roth 	{0x4b0d, 0x00},
1062e14d3ac8SNicholas Roth 	{0x4d00, 0x04}, /* temperature sensor */
1063e14d3ac8SNicholas Roth 	{0x4d01, 0x18},
1064e14d3ac8SNicholas Roth 	{0x4d02, 0xc3},
1065e14d3ac8SNicholas Roth 	{0x4d03, 0xff},
1066e14d3ac8SNicholas Roth 	{0x4d04, 0xff},
1067e14d3ac8SNicholas Roth 	{0x4d05, 0xff}, /* temperature sensor */
1068e14d3ac8SNicholas Roth 	{0x5000, 0xfe}, /* lenc on, slave/master AWB gain/statistics enable */
1069e14d3ac8SNicholas Roth 	{0x5001, 0x01}, /* BLC on */
1070e14d3ac8SNicholas Roth 	{0x5002, 0x08}, /* WBMATCH sensor's gain, H scale/WBMATCH/OTP_DPC off */
1071e14d3ac8SNicholas Roth 	{0x5003, 0x20}, /* DPC_DBC buffer control enable, WB */
1072e14d3ac8SNicholas Roth 	{0x501e, 0x93}, /* enable digital gain */
1073e14d3ac8SNicholas Roth 	{0x5046, 0x12},
1074e14d3ac8SNicholas Roth 	{0x5780, 0x3e}, /* DPC */
1075e14d3ac8SNicholas Roth 	{0x5781, 0x0f},
1076e14d3ac8SNicholas Roth 	{0x5782, 0x44},
1077e14d3ac8SNicholas Roth 	{0x5783, 0x02},
1078e14d3ac8SNicholas Roth 	{0x5784, 0x01},
1079e14d3ac8SNicholas Roth 	{0x5785, 0x00},
1080e14d3ac8SNicholas Roth 	{0x5786, 0x00},
1081e14d3ac8SNicholas Roth 	{0x5787, 0x04},
1082e14d3ac8SNicholas Roth 	{0x5788, 0x02},
1083e14d3ac8SNicholas Roth 	{0x5789, 0x0f},
1084e14d3ac8SNicholas Roth 	{0x578a, 0xfd},
1085e14d3ac8SNicholas Roth 	{0x578b, 0xf5},
1086e14d3ac8SNicholas Roth 	{0x578c, 0xf5},
1087e14d3ac8SNicholas Roth 	{0x578d, 0x03},
1088e14d3ac8SNicholas Roth 	{0x578e, 0x08},
1089e14d3ac8SNicholas Roth 	{0x578f, 0x0c},
1090e14d3ac8SNicholas Roth 	{0x5790, 0x08},
1091e14d3ac8SNicholas Roth 	{0x5791, 0x04},
1092e14d3ac8SNicholas Roth 	{0x5792, 0x00},
1093e14d3ac8SNicholas Roth 	{0x5793, 0x52},
1094e14d3ac8SNicholas Roth 	{0x5794, 0xa3}, /* DPC */
1095e14d3ac8SNicholas Roth 	{0x5871, 0x0d}, /* Lenc */
1096e14d3ac8SNicholas Roth 	{0x5870, 0x18},
1097e14d3ac8SNicholas Roth 	{0x586e, 0x10},
1098e14d3ac8SNicholas Roth 	{0x586f, 0x08},
1099e14d3ac8SNicholas Roth 	{0x58f7, 0x01},
1100e14d3ac8SNicholas Roth 	{0x58f8, 0x3d}, /* Lenc */
1101e14d3ac8SNicholas Roth 	{0x5901, 0x00}, /* H skip off, V skip off */
1102e14d3ac8SNicholas Roth 	{0x5b00, 0x02}, /* OTP DPC start address */
1103e14d3ac8SNicholas Roth 	{0x5b01, 0x10}, /* OTP DPC start address */
1104e14d3ac8SNicholas Roth 	{0x5b02, 0x03}, /* OTP DPC end address */
1105e14d3ac8SNicholas Roth 	{0x5b03, 0xcf}, /* OTP DPC end address */
1106e14d3ac8SNicholas Roth 	{0x5b05, 0x6c}, /* recover method = 2b11 */
1107e14d3ac8SNicholas Roth 	{0x5e00, 0x00}, /* use 0x3ff to test pattern off */
1108e14d3ac8SNicholas Roth 	{0x5e01, 0x41}, /* window cut enable */
1109e14d3ac8SNicholas Roth 	{0x382d, 0x7f},
1110e14d3ac8SNicholas Roth 	{0x4825, 0x3a}, /* lpx_p_min */
1111e14d3ac8SNicholas Roth 	{0x4826, 0x40}, /* hs_prepare_min */
1112e14d3ac8SNicholas Roth 	{0x4808, 0x25}, /* wake up delay in 1/1024 s */
1113e14d3ac8SNicholas Roth 	{0x3763, 0x18},
1114e14d3ac8SNicholas Roth 	{0x3768, 0xcc},
1115e14d3ac8SNicholas Roth 	{0x470b, 0x28},
1116e14d3ac8SNicholas Roth 	{0x4202, 0x00},
1117e14d3ac8SNicholas Roth 	{0x400d, 0x10}, /* BLC offset trigger L */
1118e14d3ac8SNicholas Roth 	{0x4040, 0x04}, /* BLC gain th2 */
1119e14d3ac8SNicholas Roth 	{0x403e, 0x04}, /* BLC gain th1 */
1120e14d3ac8SNicholas Roth 	{0x4041, 0xc6}, /* BLC */
1121e14d3ac8SNicholas Roth 	{0x3007, 0x80},
1122e14d3ac8SNicholas Roth 	{0x400a, 0x01},
1123e14d3ac8SNicholas Roth 	{REG_NULL, 0x00},
1124e14d3ac8SNicholas Roth };
1125e14d3ac8SNicholas Roth 
1126e14d3ac8SNicholas Roth /*
1127e14d3ac8SNicholas Roth  * Xclk 24Mhz
1128e14d3ac8SNicholas Roth  * max_framerate 60fps
1129e14d3ac8SNicholas Roth  * mipi_datarate per lane 720Mbps
1130e14d3ac8SNicholas Roth  */
1131e14d3ac8SNicholas Roth static const struct regval ov8858_1632x1224_regs_4lane[] = {
1132e14d3ac8SNicholas Roth 	{0x0100, 0x00},
1133e14d3ac8SNicholas Roth 	{0x3501, 0x4d}, /* exposure M */
1134e14d3ac8SNicholas Roth 	{0x3502, 0x40}, /* exposure L */
1135e14d3ac8SNicholas Roth 	{0x3808, 0x06}, /* x output size H */
1136e14d3ac8SNicholas Roth 	{0x3809, 0x60}, /* x output size L */
1137e14d3ac8SNicholas Roth 	{0x380a, 0x04}, /* y output size H */
1138e14d3ac8SNicholas Roth 	{0x380b, 0xc8}, /* y output size L */
1139e14d3ac8SNicholas Roth 	{0x380c, 0x07}, /* HTS H */
1140e14d3ac8SNicholas Roth 	{0x380d, 0x88}, /* HTS L */
1141e14d3ac8SNicholas Roth 	{0x380e, 0x04}, /* VTS H */
1142e14d3ac8SNicholas Roth 	{0x380f, 0xdc}, /* VTS L */
1143e14d3ac8SNicholas Roth 	{0x3814, 0x03}, /* x odd inc */
1144e14d3ac8SNicholas Roth 	{0x3821, 0x67}, /* mirror on, bin on */
1145e14d3ac8SNicholas Roth 	{0x382a, 0x03}, /* y odd inc */
1146e14d3ac8SNicholas Roth 	{0x3830, 0x08},
1147e14d3ac8SNicholas Roth 	{0x3836, 0x02},
1148e14d3ac8SNicholas Roth 	{0x3f0a, 0x00},
1149e14d3ac8SNicholas Roth 	{0x4001, 0x10}, /* total 128 black column */
1150e14d3ac8SNicholas Roth 	{0x4022, 0x06}, /* Anchor left end H */
1151e14d3ac8SNicholas Roth 	{0x4023, 0x00}, /* Anchor left end L */
1152e14d3ac8SNicholas Roth 	{0x4025, 0x2a}, /* Anchor right start L */
1153e14d3ac8SNicholas Roth 	{0x4027, 0x2b}, /* Anchor right end L */
1154e14d3ac8SNicholas Roth 	{0x402b, 0x04}, /* top black line number */
1155e14d3ac8SNicholas Roth 	{0x402f, 0x04}, /* bottom black line number */
1156e14d3ac8SNicholas Roth 	{0x4500, 0x58},
1157e14d3ac8SNicholas Roth 	{0x4600, 0x00},
1158e14d3ac8SNicholas Roth 	{0x4601, 0xcb},
1159e14d3ac8SNicholas Roth 	{0x382d, 0x7f},
1160e14d3ac8SNicholas Roth 	{0x0100, 0x01},
1161e14d3ac8SNicholas Roth 	{REG_NULL, 0x00},
1162e14d3ac8SNicholas Roth };
1163e14d3ac8SNicholas Roth 
1164e14d3ac8SNicholas Roth /*
1165e14d3ac8SNicholas Roth  * Xclk 24Mhz
1166e14d3ac8SNicholas Roth  * max_framerate 30fps
1167e14d3ac8SNicholas Roth  * mipi_datarate per lane 720Mbps
1168e14d3ac8SNicholas Roth  */
1169e14d3ac8SNicholas Roth static const struct regval ov8858_3264x2448_regs_4lane[] = {
1170e14d3ac8SNicholas Roth 	{0x0100, 0x00},
1171e14d3ac8SNicholas Roth 	{0x3501, 0x9a}, /* exposure M */
1172e14d3ac8SNicholas Roth 	{0x3502, 0x20}, /* exposure L */
1173e14d3ac8SNicholas Roth 	{0x3808, 0x0c}, /* x output size H */
1174e14d3ac8SNicholas Roth 	{0x3809, 0xc0}, /* x output size L */
1175e14d3ac8SNicholas Roth 	{0x380a, 0x09}, /* y output size H */
1176e14d3ac8SNicholas Roth 	{0x380b, 0x90}, /* y output size L */
1177e14d3ac8SNicholas Roth 	{0x380c, 0x07}, /* HTS H */
1178e14d3ac8SNicholas Roth 	{0x380d, 0x94}, /* HTS L */
1179e14d3ac8SNicholas Roth 	{0x380e, 0x09}, /* VTS H */
1180e14d3ac8SNicholas Roth 	{0x380f, 0xaa}, /* VTS L */
1181e14d3ac8SNicholas Roth 	{0x3814, 0x01}, /* x odd inc */
1182e14d3ac8SNicholas Roth 	{0x3821, 0x46}, /* mirror on, bin off */
1183e14d3ac8SNicholas Roth 	{0x382a, 0x01}, /* y odd inc */
1184e14d3ac8SNicholas Roth 	{0x3830, 0x06},
1185e14d3ac8SNicholas Roth 	{0x3836, 0x01},
1186e14d3ac8SNicholas Roth 	{0x3f0a, 0x00},
1187e14d3ac8SNicholas Roth 	{0x4001, 0x00}, /* total 256 black column */
1188e14d3ac8SNicholas Roth 	{0x4022, 0x0c}, /* Anchor left end H */
1189e14d3ac8SNicholas Roth 	{0x4023, 0x60}, /* Anchor left end L */
1190e14d3ac8SNicholas Roth 	{0x4025, 0x36}, /* Anchor right start L */
1191e14d3ac8SNicholas Roth 	{0x4027, 0x37}, /* Anchor right end L */
1192e14d3ac8SNicholas Roth 	{0x402b, 0x08}, /* top black line number */
1193e14d3ac8SNicholas Roth 	{0x402f, 0x08}, /* interpolation x/y disable, Anchor one disable */
1194e14d3ac8SNicholas Roth 	{0x4500, 0x58},
1195e14d3ac8SNicholas Roth 	{0x4600, 0x01},
1196e14d3ac8SNicholas Roth 	{0x4601, 0x97},
1197e14d3ac8SNicholas Roth 	{0x382d, 0xff},
1198e14d3ac8SNicholas Roth 	{REG_NULL, 0x00},
1199e14d3ac8SNicholas Roth };
1200e14d3ac8SNicholas Roth 
1201e14d3ac8SNicholas Roth static const struct ov8858_mode ov8858_modes[] = {
1202e14d3ac8SNicholas Roth 	{
1203e14d3ac8SNicholas Roth 		.width = 3264,
1204e14d3ac8SNicholas Roth 		.height = 2448,
1205e14d3ac8SNicholas Roth 		.exp_def = 2464,
1206e14d3ac8SNicholas Roth 		.hts_def = 1940 * 2,
1207e14d3ac8SNicholas Roth 		.vts_def = 2472,
1208e14d3ac8SNicholas Roth 		.reg_modes = {
1209e14d3ac8SNicholas Roth 			.mode_2lanes = ov8858_3264x2448_regs_2lane,
1210e14d3ac8SNicholas Roth 			.mode_4lanes = ov8858_3264x2448_regs_4lane,
1211e14d3ac8SNicholas Roth 		},
1212e14d3ac8SNicholas Roth 	},
1213e14d3ac8SNicholas Roth 	{
1214e14d3ac8SNicholas Roth 		.width = 1632,
1215e14d3ac8SNicholas Roth 		.height = 1224,
1216e14d3ac8SNicholas Roth 		.exp_def = 1232,
1217e14d3ac8SNicholas Roth 		.hts_def = 1928 * 2,
1218e14d3ac8SNicholas Roth 		.vts_def = 1244,
1219e14d3ac8SNicholas Roth 		.reg_modes = {
1220e14d3ac8SNicholas Roth 			.mode_2lanes = ov8858_1632x1224_regs_2lane,
1221e14d3ac8SNicholas Roth 			.mode_4lanes = ov8858_1632x1224_regs_4lane,
1222e14d3ac8SNicholas Roth 		},
1223e14d3ac8SNicholas Roth 	},
1224e14d3ac8SNicholas Roth };
1225e14d3ac8SNicholas Roth 
1226e14d3ac8SNicholas Roth static const s64 link_freq_menu_items[] = {
1227e14d3ac8SNicholas Roth 	OV8858_LINK_FREQ
1228e14d3ac8SNicholas Roth };
1229e14d3ac8SNicholas Roth 
1230e14d3ac8SNicholas Roth static const char * const ov8858_test_pattern_menu[] = {
1231e14d3ac8SNicholas Roth 	"Disabled",
1232e14d3ac8SNicholas Roth 	"Vertical Color Bar Type 1",
1233e14d3ac8SNicholas Roth 	"Vertical Color Bar Type 2",
1234e14d3ac8SNicholas Roth 	"Vertical Color Bar Type 3",
1235e14d3ac8SNicholas Roth 	"Vertical Color Bar Type 4"
1236e14d3ac8SNicholas Roth };
1237e14d3ac8SNicholas Roth 
1238e14d3ac8SNicholas Roth /* ----------------------------------------------------------------------------
1239e14d3ac8SNicholas Roth  * HW access
1240e14d3ac8SNicholas Roth  */
1241e14d3ac8SNicholas Roth 
ov8858_write(struct ov8858 * ov8858,u32 reg,u32 val,int * err)1242e14d3ac8SNicholas Roth static int ov8858_write(struct ov8858 *ov8858, u32 reg, u32 val, int *err)
1243e14d3ac8SNicholas Roth {
1244e14d3ac8SNicholas Roth 	struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
1245e14d3ac8SNicholas Roth 	unsigned int len = (reg >> OV8858_REG_SIZE_SHIFT) & 3;
1246e14d3ac8SNicholas Roth 	u16 addr = reg & OV8858_REG_ADDR_MASK;
1247e14d3ac8SNicholas Roth 	u8 buf[6];
1248e14d3ac8SNicholas Roth 	int ret;
1249e14d3ac8SNicholas Roth 
1250e14d3ac8SNicholas Roth 	if (err && *err)
1251e14d3ac8SNicholas Roth 		return *err;
1252e14d3ac8SNicholas Roth 
1253e14d3ac8SNicholas Roth 	put_unaligned_be16(addr, buf);
1254e14d3ac8SNicholas Roth 	put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
1255e14d3ac8SNicholas Roth 
1256e14d3ac8SNicholas Roth 	ret = i2c_master_send(client, buf, len + 2);
1257e14d3ac8SNicholas Roth 	if (ret != len + 2) {
1258e14d3ac8SNicholas Roth 		ret = ret < 0 ? ret : -EIO;
1259e14d3ac8SNicholas Roth 		if (err)
1260e14d3ac8SNicholas Roth 			*err = ret;
1261e14d3ac8SNicholas Roth 
1262e14d3ac8SNicholas Roth 		dev_err(&client->dev,
1263e14d3ac8SNicholas Roth 			"Failed to write reg %u: %d\n", addr, ret);
1264e14d3ac8SNicholas Roth 		return ret;
1265e14d3ac8SNicholas Roth 	}
1266e14d3ac8SNicholas Roth 
1267e14d3ac8SNicholas Roth 	return 0;
1268e14d3ac8SNicholas Roth }
1269e14d3ac8SNicholas Roth 
ov8858_write_array(struct ov8858 * ov8858,const struct regval * regs)1270e14d3ac8SNicholas Roth static int ov8858_write_array(struct ov8858 *ov8858, const struct regval *regs)
1271e14d3ac8SNicholas Roth {
1272e14d3ac8SNicholas Roth 	unsigned int i;
1273e14d3ac8SNicholas Roth 	int ret = 0;
1274e14d3ac8SNicholas Roth 
1275e14d3ac8SNicholas Roth 	for (i = 0; ret == 0 && regs[i].addr != REG_NULL; ++i) {
1276e14d3ac8SNicholas Roth 		ov8858_write(ov8858, OV8858_REG_8BIT(regs[i].addr),
1277e14d3ac8SNicholas Roth 			     regs[i].val, &ret);
1278e14d3ac8SNicholas Roth 	}
1279e14d3ac8SNicholas Roth 
1280e14d3ac8SNicholas Roth 	return ret;
1281e14d3ac8SNicholas Roth }
1282e14d3ac8SNicholas Roth 
ov8858_read(struct ov8858 * ov8858,u32 reg,u32 * val)1283e14d3ac8SNicholas Roth static int ov8858_read(struct ov8858 *ov8858, u32 reg, u32 *val)
1284e14d3ac8SNicholas Roth {
1285e14d3ac8SNicholas Roth 	struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
1286e14d3ac8SNicholas Roth 	__be16 reg_addr_be = cpu_to_be16(reg & OV8858_REG_ADDR_MASK);
1287e14d3ac8SNicholas Roth 	unsigned int len = (reg >> OV8858_REG_SIZE_SHIFT) & 3;
1288e14d3ac8SNicholas Roth 	struct i2c_msg msgs[2];
1289e14d3ac8SNicholas Roth 	__be32 data_be = 0;
1290e14d3ac8SNicholas Roth 	u8 *data_be_p;
1291e14d3ac8SNicholas Roth 	int ret;
1292e14d3ac8SNicholas Roth 
1293e14d3ac8SNicholas Roth 	data_be_p = (u8 *)&data_be;
1294e14d3ac8SNicholas Roth 
1295e14d3ac8SNicholas Roth 	/* Write register address */
1296e14d3ac8SNicholas Roth 	msgs[0].addr = client->addr;
1297e14d3ac8SNicholas Roth 	msgs[0].flags = 0;
1298e14d3ac8SNicholas Roth 	msgs[0].len = 2;
1299e14d3ac8SNicholas Roth 	msgs[0].buf = (u8 *)&reg_addr_be;
1300e14d3ac8SNicholas Roth 
1301e14d3ac8SNicholas Roth 	/* Read data from register */
1302e14d3ac8SNicholas Roth 	msgs[1].addr = client->addr;
1303e14d3ac8SNicholas Roth 	msgs[1].flags = I2C_M_RD;
1304e14d3ac8SNicholas Roth 	msgs[1].len = len;
1305e14d3ac8SNicholas Roth 	msgs[1].buf = &data_be_p[4 - len];
1306e14d3ac8SNicholas Roth 
1307e14d3ac8SNicholas Roth 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
1308e14d3ac8SNicholas Roth 	if (ret != ARRAY_SIZE(msgs)) {
1309e14d3ac8SNicholas Roth 		ret = ret < 0 ? ret : -EIO;
1310e14d3ac8SNicholas Roth 		dev_err(&client->dev,
1311e14d3ac8SNicholas Roth 			"Failed to read reg %u: %d\n", reg, ret);
1312e14d3ac8SNicholas Roth 		return ret;
1313e14d3ac8SNicholas Roth 	}
1314e14d3ac8SNicholas Roth 
1315e14d3ac8SNicholas Roth 	*val = be32_to_cpu(data_be);
1316e14d3ac8SNicholas Roth 
1317e14d3ac8SNicholas Roth 	return 0;
1318e14d3ac8SNicholas Roth }
1319e14d3ac8SNicholas Roth 
1320e14d3ac8SNicholas Roth /* ----------------------------------------------------------------------------
1321e14d3ac8SNicholas Roth  * Streaming
1322e14d3ac8SNicholas Roth  */
1323e14d3ac8SNicholas Roth 
ov8858_start_stream(struct ov8858 * ov8858,struct v4l2_subdev_state * state)1324e14d3ac8SNicholas Roth static int ov8858_start_stream(struct ov8858 *ov8858,
1325e14d3ac8SNicholas Roth 			       struct v4l2_subdev_state *state)
1326e14d3ac8SNicholas Roth {
1327e14d3ac8SNicholas Roth 	struct v4l2_mbus_framefmt *format;
1328e14d3ac8SNicholas Roth 	const struct ov8858_mode *mode;
1329e14d3ac8SNicholas Roth 	const struct regval *reg_list;
1330e14d3ac8SNicholas Roth 	int ret;
1331e14d3ac8SNicholas Roth 
1332e14d3ac8SNicholas Roth 	ret = ov8858_write_array(ov8858, ov8858->global_regs);
1333e14d3ac8SNicholas Roth 	if (ret)
1334e14d3ac8SNicholas Roth 		return ret;
1335e14d3ac8SNicholas Roth 
1336e14d3ac8SNicholas Roth 	format = v4l2_subdev_get_pad_format(&ov8858->subdev, state, 0);
1337e14d3ac8SNicholas Roth 	mode = v4l2_find_nearest_size(ov8858_modes, ARRAY_SIZE(ov8858_modes),
1338e14d3ac8SNicholas Roth 				      width, height, format->width,
1339e14d3ac8SNicholas Roth 				      format->height);
1340e14d3ac8SNicholas Roth 
1341e14d3ac8SNicholas Roth 	reg_list = ov8858->num_lanes == 4
1342e14d3ac8SNicholas Roth 		 ? mode->reg_modes.mode_4lanes
1343e14d3ac8SNicholas Roth 		 : mode->reg_modes.mode_2lanes;
1344e14d3ac8SNicholas Roth 
1345e14d3ac8SNicholas Roth 	ret = ov8858_write_array(ov8858, reg_list);
1346e14d3ac8SNicholas Roth 	if (ret)
1347e14d3ac8SNicholas Roth 		return ret;
1348e14d3ac8SNicholas Roth 
1349e14d3ac8SNicholas Roth 	/* 200 usec max to let PLL stabilize. */
1350e14d3ac8SNicholas Roth 	fsleep(200);
1351e14d3ac8SNicholas Roth 
1352e14d3ac8SNicholas Roth 	ret = __v4l2_ctrl_handler_setup(&ov8858->ctrl_handler);
1353e14d3ac8SNicholas Roth 	if (ret)
1354e14d3ac8SNicholas Roth 		return ret;
1355e14d3ac8SNicholas Roth 
1356e14d3ac8SNicholas Roth 	ret = ov8858_write(ov8858, OV8858_REG_SC_CTRL0100,
1357e14d3ac8SNicholas Roth 			   OV8858_MODE_STREAMING, NULL);
1358e14d3ac8SNicholas Roth 	if (ret)
1359e14d3ac8SNicholas Roth 		return ret;
1360e14d3ac8SNicholas Roth 
1361e14d3ac8SNicholas Roth 	/* t5 (fixed) = 10msec before entering streaming state */
1362e14d3ac8SNicholas Roth 	fsleep(10000);
1363e14d3ac8SNicholas Roth 
1364e14d3ac8SNicholas Roth 	return 0;
1365e14d3ac8SNicholas Roth }
1366e14d3ac8SNicholas Roth 
ov8858_stop_stream(struct ov8858 * ov8858)1367e14d3ac8SNicholas Roth static int ov8858_stop_stream(struct ov8858 *ov8858)
1368e14d3ac8SNicholas Roth {
1369e14d3ac8SNicholas Roth 	return ov8858_write(ov8858, OV8858_REG_SC_CTRL0100,
1370e14d3ac8SNicholas Roth 			    OV8858_MODE_SW_STANDBY, NULL);
1371e14d3ac8SNicholas Roth }
1372e14d3ac8SNicholas Roth 
ov8858_s_stream(struct v4l2_subdev * sd,int on)1373e14d3ac8SNicholas Roth static int ov8858_s_stream(struct v4l2_subdev *sd, int on)
1374e14d3ac8SNicholas Roth {
1375e14d3ac8SNicholas Roth 	struct i2c_client *client = v4l2_get_subdevdata(sd);
1376e14d3ac8SNicholas Roth 	struct ov8858 *ov8858 = sd_to_ov8858(sd);
1377e14d3ac8SNicholas Roth 	struct v4l2_subdev_state *state;
1378e14d3ac8SNicholas Roth 	int ret = 0;
1379e14d3ac8SNicholas Roth 
1380e14d3ac8SNicholas Roth 	state = v4l2_subdev_lock_and_get_active_state(sd);
1381e14d3ac8SNicholas Roth 
1382e14d3ac8SNicholas Roth 	if (on) {
1383e14d3ac8SNicholas Roth 		ret = pm_runtime_resume_and_get(&client->dev);
1384e14d3ac8SNicholas Roth 		if (ret < 0)
1385e14d3ac8SNicholas Roth 			goto unlock_and_return;
1386e14d3ac8SNicholas Roth 
1387e14d3ac8SNicholas Roth 		ret = ov8858_start_stream(ov8858, state);
1388e14d3ac8SNicholas Roth 		if (ret) {
1389e14d3ac8SNicholas Roth 			dev_err(&client->dev, "Failed to start streaming\n");
1390e14d3ac8SNicholas Roth 			pm_runtime_put_sync(&client->dev);
1391e14d3ac8SNicholas Roth 			goto unlock_and_return;
1392e14d3ac8SNicholas Roth 		}
1393e14d3ac8SNicholas Roth 	} else {
1394e14d3ac8SNicholas Roth 		ov8858_stop_stream(ov8858);
1395e14d3ac8SNicholas Roth 		pm_runtime_mark_last_busy(&client->dev);
1396e14d3ac8SNicholas Roth 		pm_runtime_put_autosuspend(&client->dev);
1397e14d3ac8SNicholas Roth 	}
1398e14d3ac8SNicholas Roth 
1399e14d3ac8SNicholas Roth unlock_and_return:
1400e14d3ac8SNicholas Roth 	v4l2_subdev_unlock_state(state);
1401e14d3ac8SNicholas Roth 
1402e14d3ac8SNicholas Roth 	return ret;
1403e14d3ac8SNicholas Roth }
1404e14d3ac8SNicholas Roth 
1405e14d3ac8SNicholas Roth static const struct v4l2_subdev_video_ops ov8858_video_ops = {
1406e14d3ac8SNicholas Roth 	.s_stream = ov8858_s_stream,
1407e14d3ac8SNicholas Roth };
1408e14d3ac8SNicholas Roth 
1409e14d3ac8SNicholas Roth /* ----------------------------------------------------------------------------
1410e14d3ac8SNicholas Roth  * Pad ops
1411e14d3ac8SNicholas Roth  */
1412e14d3ac8SNicholas Roth 
ov8858_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,struct v4l2_subdev_format * fmt)1413e14d3ac8SNicholas Roth static int ov8858_set_fmt(struct v4l2_subdev *sd,
1414e14d3ac8SNicholas Roth 			  struct v4l2_subdev_state *state,
1415e14d3ac8SNicholas Roth 			  struct v4l2_subdev_format *fmt)
1416e14d3ac8SNicholas Roth {
1417e14d3ac8SNicholas Roth 	struct ov8858 *ov8858 = sd_to_ov8858(sd);
1418e14d3ac8SNicholas Roth 	const struct ov8858_mode *mode;
1419e14d3ac8SNicholas Roth 	s64 h_blank, vblank_def;
1420e14d3ac8SNicholas Roth 
1421e14d3ac8SNicholas Roth 	mode = v4l2_find_nearest_size(ov8858_modes, ARRAY_SIZE(ov8858_modes),
1422e14d3ac8SNicholas Roth 				      width, height, fmt->format.width,
1423e14d3ac8SNicholas Roth 				      fmt->format.height);
1424e14d3ac8SNicholas Roth 
1425e14d3ac8SNicholas Roth 	fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
1426e14d3ac8SNicholas Roth 	fmt->format.width = mode->width;
1427e14d3ac8SNicholas Roth 	fmt->format.height = mode->height;
1428e14d3ac8SNicholas Roth 	fmt->format.field = V4L2_FIELD_NONE;
1429e14d3ac8SNicholas Roth 
1430e14d3ac8SNicholas Roth 	/* Store the format in the current subdev state. */
1431e14d3ac8SNicholas Roth 	*v4l2_subdev_get_pad_format(sd, state, 0) =  fmt->format;
1432e14d3ac8SNicholas Roth 
1433e14d3ac8SNicholas Roth 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
1434e14d3ac8SNicholas Roth 		return 0;
1435e14d3ac8SNicholas Roth 
1436e14d3ac8SNicholas Roth 	/* Adjust control limits when a new mode is applied. */
1437e14d3ac8SNicholas Roth 	h_blank = mode->hts_def - mode->width;
1438e14d3ac8SNicholas Roth 	__v4l2_ctrl_modify_range(ov8858->hblank, h_blank, h_blank, 1,
1439e14d3ac8SNicholas Roth 				 h_blank);
1440e14d3ac8SNicholas Roth 
1441e14d3ac8SNicholas Roth 	vblank_def = mode->vts_def - mode->height;
1442e14d3ac8SNicholas Roth 	__v4l2_ctrl_modify_range(ov8858->vblank, vblank_def,
1443e14d3ac8SNicholas Roth 				 OV8858_VTS_MAX - mode->height, 1,
1444e14d3ac8SNicholas Roth 				 vblank_def);
1445e14d3ac8SNicholas Roth 
1446e14d3ac8SNicholas Roth 	return 0;
1447e14d3ac8SNicholas Roth }
1448e14d3ac8SNicholas Roth 
ov8858_enum_frame_sizes(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,struct v4l2_subdev_frame_size_enum * fse)1449e14d3ac8SNicholas Roth static int ov8858_enum_frame_sizes(struct v4l2_subdev *sd,
1450e14d3ac8SNicholas Roth 				   struct v4l2_subdev_state *state,
1451e14d3ac8SNicholas Roth 				   struct v4l2_subdev_frame_size_enum *fse)
1452e14d3ac8SNicholas Roth {
1453e14d3ac8SNicholas Roth 	if (fse->index >= ARRAY_SIZE(ov8858_modes))
1454e14d3ac8SNicholas Roth 		return -EINVAL;
1455e14d3ac8SNicholas Roth 
1456e14d3ac8SNicholas Roth 	if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
1457e14d3ac8SNicholas Roth 		return -EINVAL;
1458e14d3ac8SNicholas Roth 
1459e14d3ac8SNicholas Roth 	fse->min_width  = ov8858_modes[fse->index].width;
1460e14d3ac8SNicholas Roth 	fse->max_width  = ov8858_modes[fse->index].width;
1461e14d3ac8SNicholas Roth 	fse->max_height = ov8858_modes[fse->index].height;
1462e14d3ac8SNicholas Roth 	fse->min_height = ov8858_modes[fse->index].height;
1463e14d3ac8SNicholas Roth 
1464e14d3ac8SNicholas Roth 	return 0;
1465e14d3ac8SNicholas Roth }
1466e14d3ac8SNicholas Roth 
ov8858_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,struct v4l2_subdev_mbus_code_enum * code)1467e14d3ac8SNicholas Roth static int ov8858_enum_mbus_code(struct v4l2_subdev *sd,
1468e14d3ac8SNicholas Roth 				 struct v4l2_subdev_state *state,
1469e14d3ac8SNicholas Roth 				 struct v4l2_subdev_mbus_code_enum *code)
1470e14d3ac8SNicholas Roth {
1471e14d3ac8SNicholas Roth 	if (code->index != 0)
1472e14d3ac8SNicholas Roth 		return -EINVAL;
1473e14d3ac8SNicholas Roth 
1474e14d3ac8SNicholas Roth 	code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
1475e14d3ac8SNicholas Roth 
1476e14d3ac8SNicholas Roth 	return 0;
1477e14d3ac8SNicholas Roth }
1478e14d3ac8SNicholas Roth 
ov8858_init_cfg(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state)1479e14d3ac8SNicholas Roth static int ov8858_init_cfg(struct v4l2_subdev *sd,
1480e14d3ac8SNicholas Roth 			   struct v4l2_subdev_state *sd_state)
1481e14d3ac8SNicholas Roth {
1482e14d3ac8SNicholas Roth 	const struct ov8858_mode *def_mode = &ov8858_modes[0];
1483e14d3ac8SNicholas Roth 	struct v4l2_subdev_format fmt = {
1484e14d3ac8SNicholas Roth 		.which = V4L2_SUBDEV_FORMAT_TRY,
1485e14d3ac8SNicholas Roth 		.format = {
1486e14d3ac8SNicholas Roth 			.width = def_mode->width,
1487e14d3ac8SNicholas Roth 			.height = def_mode->height,
1488e14d3ac8SNicholas Roth 		},
1489e14d3ac8SNicholas Roth 	};
1490e14d3ac8SNicholas Roth 
1491e14d3ac8SNicholas Roth 	ov8858_set_fmt(sd, sd_state, &fmt);
1492e14d3ac8SNicholas Roth 
1493e14d3ac8SNicholas Roth 	return 0;
1494e14d3ac8SNicholas Roth }
1495e14d3ac8SNicholas Roth 
1496e14d3ac8SNicholas Roth static const struct v4l2_subdev_pad_ops ov8858_pad_ops = {
1497e14d3ac8SNicholas Roth 	.init_cfg = ov8858_init_cfg,
1498e14d3ac8SNicholas Roth 	.enum_mbus_code = ov8858_enum_mbus_code,
1499e14d3ac8SNicholas Roth 	.enum_frame_size = ov8858_enum_frame_sizes,
1500e14d3ac8SNicholas Roth 	.get_fmt = v4l2_subdev_get_fmt,
1501e14d3ac8SNicholas Roth 	.set_fmt = ov8858_set_fmt,
1502e14d3ac8SNicholas Roth };
1503e14d3ac8SNicholas Roth 
1504e14d3ac8SNicholas Roth static const struct v4l2_subdev_core_ops ov8858_core_ops = {
1505e14d3ac8SNicholas Roth 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
1506e14d3ac8SNicholas Roth 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
1507e14d3ac8SNicholas Roth };
1508e14d3ac8SNicholas Roth 
1509e14d3ac8SNicholas Roth static const struct v4l2_subdev_ops ov8858_subdev_ops = {
1510e14d3ac8SNicholas Roth 	.core	= &ov8858_core_ops,
1511e14d3ac8SNicholas Roth 	.video	= &ov8858_video_ops,
1512e14d3ac8SNicholas Roth 	.pad	= &ov8858_pad_ops,
1513e14d3ac8SNicholas Roth };
1514e14d3ac8SNicholas Roth 
1515e14d3ac8SNicholas Roth /* ----------------------------------------------------------------------------
1516e14d3ac8SNicholas Roth  * Controls handling
1517e14d3ac8SNicholas Roth  */
1518e14d3ac8SNicholas Roth 
ov8858_enable_test_pattern(struct ov8858 * ov8858,u32 pattern)1519e14d3ac8SNicholas Roth static int ov8858_enable_test_pattern(struct ov8858 *ov8858, u32 pattern)
1520e14d3ac8SNicholas Roth {
1521e14d3ac8SNicholas Roth 	u32 val;
1522e14d3ac8SNicholas Roth 
1523e14d3ac8SNicholas Roth 	if (pattern)
1524e14d3ac8SNicholas Roth 		val = (pattern - 1) | OV8858_TEST_PATTERN_ENABLE;
1525e14d3ac8SNicholas Roth 	else
1526e14d3ac8SNicholas Roth 		val = OV8858_TEST_PATTERN_DISABLE;
1527e14d3ac8SNicholas Roth 
1528e14d3ac8SNicholas Roth 	return ov8858_write(ov8858, OV8858_REG_TEST_PATTERN, val, NULL);
1529e14d3ac8SNicholas Roth }
1530e14d3ac8SNicholas Roth 
ov8858_set_ctrl(struct v4l2_ctrl * ctrl)1531e14d3ac8SNicholas Roth static int ov8858_set_ctrl(struct v4l2_ctrl *ctrl)
1532e14d3ac8SNicholas Roth {
1533e14d3ac8SNicholas Roth 	struct ov8858 *ov8858 = container_of(ctrl->handler,
1534e14d3ac8SNicholas Roth 					     struct ov8858, ctrl_handler);
1535e14d3ac8SNicholas Roth 
1536e14d3ac8SNicholas Roth 	struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
1537e14d3ac8SNicholas Roth 	struct v4l2_mbus_framefmt *format;
1538e14d3ac8SNicholas Roth 	struct v4l2_subdev_state *state;
1539e14d3ac8SNicholas Roth 	u16 digi_gain;
1540e14d3ac8SNicholas Roth 	s64 max_exp;
1541e14d3ac8SNicholas Roth 	int ret;
1542e14d3ac8SNicholas Roth 
1543e14d3ac8SNicholas Roth 	/*
1544e14d3ac8SNicholas Roth 	 * The control handler and the subdev state use the same mutex and the
1545e14d3ac8SNicholas Roth 	 * mutex is guaranteed to be locked:
1546e14d3ac8SNicholas Roth 	 * - by the core when s_ctrl is called int the VIDIOC_S_CTRL call path
1547e14d3ac8SNicholas Roth 	 * - by the driver when s_ctrl is called in the s_stream(1) call path
1548e14d3ac8SNicholas Roth 	 */
1549e14d3ac8SNicholas Roth 	state = v4l2_subdev_get_locked_active_state(&ov8858->subdev);
1550e14d3ac8SNicholas Roth 	format = v4l2_subdev_get_pad_format(&ov8858->subdev, state, 0);
1551e14d3ac8SNicholas Roth 
1552e14d3ac8SNicholas Roth 	/* Propagate change of current control to all related controls */
1553e14d3ac8SNicholas Roth 	switch (ctrl->id) {
1554e14d3ac8SNicholas Roth 	case V4L2_CID_VBLANK:
1555e14d3ac8SNicholas Roth 		/* Update max exposure while meeting expected vblanking */
1556e14d3ac8SNicholas Roth 		max_exp = format->height + ctrl->val - OV8858_EXPOSURE_MARGIN;
1557e14d3ac8SNicholas Roth 		__v4l2_ctrl_modify_range(ov8858->exposure,
1558e14d3ac8SNicholas Roth 					 ov8858->exposure->minimum, max_exp,
1559e14d3ac8SNicholas Roth 					 ov8858->exposure->step,
1560e14d3ac8SNicholas Roth 					 ov8858->exposure->default_value);
1561e14d3ac8SNicholas Roth 		break;
1562e14d3ac8SNicholas Roth 	}
1563e14d3ac8SNicholas Roth 
1564e14d3ac8SNicholas Roth 	if (!pm_runtime_get_if_in_use(&client->dev))
1565e14d3ac8SNicholas Roth 		return 0;
1566e14d3ac8SNicholas Roth 
1567e14d3ac8SNicholas Roth 	switch (ctrl->id) {
1568e14d3ac8SNicholas Roth 	case V4L2_CID_EXPOSURE:
1569e14d3ac8SNicholas Roth 		/* 4 least significant bits of exposure are fractional part */
1570e14d3ac8SNicholas Roth 		ret = ov8858_write(ov8858, OV8858_REG_LONG_EXPO,
1571e14d3ac8SNicholas Roth 				   ctrl->val << 4, NULL);
1572e14d3ac8SNicholas Roth 		break;
1573e14d3ac8SNicholas Roth 	case V4L2_CID_ANALOGUE_GAIN:
1574e14d3ac8SNicholas Roth 		ret = ov8858_write(ov8858, OV8858_REG_LONG_GAIN,
1575e14d3ac8SNicholas Roth 				   ctrl->val, NULL);
1576e14d3ac8SNicholas Roth 		break;
1577e14d3ac8SNicholas Roth 	case V4L2_CID_DIGITAL_GAIN:
1578e14d3ac8SNicholas Roth 		/*
1579e14d3ac8SNicholas Roth 		 * Digital gain is assembled as:
1580e14d3ac8SNicholas Roth 		 * 0x350a[7:0] = dgain[13:6]
1581e14d3ac8SNicholas Roth 		 * 0x350b[5:0] = dgain[5:0]
1582e14d3ac8SNicholas Roth 		 * Reassemble the control value to write it in one go.
1583e14d3ac8SNicholas Roth 		 */
1584e14d3ac8SNicholas Roth 		digi_gain = (ctrl->val & OV8858_LONG_DIGIGAIN_L_MASK)
1585e14d3ac8SNicholas Roth 			  | ((ctrl->val & OV8858_LONG_DIGIGAIN_H_MASK) <<
1586e14d3ac8SNicholas Roth 			      OV8858_LONG_DIGIGAIN_H_SHIFT);
1587e14d3ac8SNicholas Roth 		ret = ov8858_write(ov8858, OV8858_REG_LONG_DIGIGAIN,
1588e14d3ac8SNicholas Roth 				   digi_gain, NULL);
1589e14d3ac8SNicholas Roth 		break;
1590e14d3ac8SNicholas Roth 	case V4L2_CID_VBLANK:
1591e14d3ac8SNicholas Roth 		ret = ov8858_write(ov8858, OV8858_REG_VTS,
1592e14d3ac8SNicholas Roth 				   ctrl->val + format->height, NULL);
1593e14d3ac8SNicholas Roth 		break;
1594e14d3ac8SNicholas Roth 	case V4L2_CID_TEST_PATTERN:
1595e14d3ac8SNicholas Roth 		ret = ov8858_enable_test_pattern(ov8858, ctrl->val);
1596e14d3ac8SNicholas Roth 		break;
1597e14d3ac8SNicholas Roth 	default:
1598e14d3ac8SNicholas Roth 		ret = -EINVAL;
1599e14d3ac8SNicholas Roth 		dev_warn(&client->dev, "%s Unhandled id: 0x%x\n",
1600e14d3ac8SNicholas Roth 			 __func__, ctrl->id);
1601e14d3ac8SNicholas Roth 		break;
1602e14d3ac8SNicholas Roth 	}
1603e14d3ac8SNicholas Roth 
1604e14d3ac8SNicholas Roth 	pm_runtime_put(&client->dev);
1605e14d3ac8SNicholas Roth 
1606e14d3ac8SNicholas Roth 	return ret;
1607e14d3ac8SNicholas Roth }
1608e14d3ac8SNicholas Roth 
1609e14d3ac8SNicholas Roth static const struct v4l2_ctrl_ops ov8858_ctrl_ops = {
1610e14d3ac8SNicholas Roth 	.s_ctrl = ov8858_set_ctrl,
1611e14d3ac8SNicholas Roth };
1612e14d3ac8SNicholas Roth 
1613e14d3ac8SNicholas Roth /* ----------------------------------------------------------------------------
1614e14d3ac8SNicholas Roth  * Power Management
1615e14d3ac8SNicholas Roth  */
1616e14d3ac8SNicholas Roth 
ov8858_power_on(struct ov8858 * ov8858)1617e14d3ac8SNicholas Roth static int ov8858_power_on(struct ov8858 *ov8858)
1618e14d3ac8SNicholas Roth {
1619e14d3ac8SNicholas Roth 	struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
1620e14d3ac8SNicholas Roth 	struct device *dev = &client->dev;
1621e14d3ac8SNicholas Roth 	unsigned long delay_us;
1622e14d3ac8SNicholas Roth 	int ret;
1623e14d3ac8SNicholas Roth 
1624e14d3ac8SNicholas Roth 	if (clk_get_rate(ov8858->xvclk) != OV8858_XVCLK_FREQ)
1625e14d3ac8SNicholas Roth 		dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
1626e14d3ac8SNicholas Roth 
1627e14d3ac8SNicholas Roth 	ret = clk_prepare_enable(ov8858->xvclk);
1628e14d3ac8SNicholas Roth 	if (ret < 0) {
1629e14d3ac8SNicholas Roth 		dev_err(dev, "Failed to enable xvclk\n");
1630e14d3ac8SNicholas Roth 		return ret;
1631e14d3ac8SNicholas Roth 	}
1632e14d3ac8SNicholas Roth 
1633e14d3ac8SNicholas Roth 	ret = regulator_bulk_enable(ARRAY_SIZE(ov8858_supply_names),
1634e14d3ac8SNicholas Roth 				    ov8858->supplies);
1635e14d3ac8SNicholas Roth 	if (ret < 0) {
1636e14d3ac8SNicholas Roth 		dev_err(dev, "Failed to enable regulators\n");
1637e14d3ac8SNicholas Roth 		goto disable_clk;
1638e14d3ac8SNicholas Roth 	}
1639e14d3ac8SNicholas Roth 
1640e14d3ac8SNicholas Roth 	/*
1641e14d3ac8SNicholas Roth 	 * The chip manual only suggests 8192 cycles prior to first SCCB
1642e14d3ac8SNicholas Roth 	 * transaction, but a double sleep between the release of gpios
1643e14d3ac8SNicholas Roth 	 * helps with sporadic failures observed at probe time.
1644e14d3ac8SNicholas Roth 	 */
1645e14d3ac8SNicholas Roth 	delay_us = DIV_ROUND_UP(8192, OV8858_XVCLK_FREQ / 1000 / 1000);
1646e14d3ac8SNicholas Roth 
1647e14d3ac8SNicholas Roth 	gpiod_set_value_cansleep(ov8858->reset_gpio, 0);
1648e14d3ac8SNicholas Roth 	fsleep(delay_us);
1649e14d3ac8SNicholas Roth 	gpiod_set_value_cansleep(ov8858->pwdn_gpio, 0);
1650e14d3ac8SNicholas Roth 	fsleep(delay_us);
1651e14d3ac8SNicholas Roth 
1652e14d3ac8SNicholas Roth 	return 0;
1653e14d3ac8SNicholas Roth 
1654e14d3ac8SNicholas Roth disable_clk:
1655e14d3ac8SNicholas Roth 	clk_disable_unprepare(ov8858->xvclk);
1656e14d3ac8SNicholas Roth 
1657e14d3ac8SNicholas Roth 	return ret;
1658e14d3ac8SNicholas Roth }
1659e14d3ac8SNicholas Roth 
ov8858_power_off(struct ov8858 * ov8858)1660e14d3ac8SNicholas Roth static void ov8858_power_off(struct ov8858 *ov8858)
1661e14d3ac8SNicholas Roth {
1662e14d3ac8SNicholas Roth 	gpiod_set_value_cansleep(ov8858->pwdn_gpio, 1);
1663e14d3ac8SNicholas Roth 	clk_disable_unprepare(ov8858->xvclk);
1664e14d3ac8SNicholas Roth 	gpiod_set_value_cansleep(ov8858->reset_gpio, 1);
1665e14d3ac8SNicholas Roth 
1666e14d3ac8SNicholas Roth 	regulator_bulk_disable(ARRAY_SIZE(ov8858_supply_names),
1667e14d3ac8SNicholas Roth 			       ov8858->supplies);
1668e14d3ac8SNicholas Roth }
1669e14d3ac8SNicholas Roth 
ov8858_runtime_resume(struct device * dev)1670e14d3ac8SNicholas Roth static int ov8858_runtime_resume(struct device *dev)
1671e14d3ac8SNicholas Roth {
1672e14d3ac8SNicholas Roth 	struct i2c_client *client = to_i2c_client(dev);
1673e14d3ac8SNicholas Roth 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1674e14d3ac8SNicholas Roth 	struct ov8858 *ov8858 = sd_to_ov8858(sd);
1675e14d3ac8SNicholas Roth 
1676e14d3ac8SNicholas Roth 	return ov8858_power_on(ov8858);
1677e14d3ac8SNicholas Roth }
1678e14d3ac8SNicholas Roth 
ov8858_runtime_suspend(struct device * dev)1679e14d3ac8SNicholas Roth static int ov8858_runtime_suspend(struct device *dev)
1680e14d3ac8SNicholas Roth {
1681e14d3ac8SNicholas Roth 	struct i2c_client *client = to_i2c_client(dev);
1682e14d3ac8SNicholas Roth 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1683e14d3ac8SNicholas Roth 	struct ov8858 *ov8858 = sd_to_ov8858(sd);
1684e14d3ac8SNicholas Roth 
1685e14d3ac8SNicholas Roth 	ov8858_power_off(ov8858);
1686e14d3ac8SNicholas Roth 
1687e14d3ac8SNicholas Roth 	return 0;
1688e14d3ac8SNicholas Roth }
1689e14d3ac8SNicholas Roth 
1690e14d3ac8SNicholas Roth static const struct dev_pm_ops ov8858_pm_ops = {
1691e14d3ac8SNicholas Roth 	SET_RUNTIME_PM_OPS(ov8858_runtime_suspend,
1692e14d3ac8SNicholas Roth 			   ov8858_runtime_resume, NULL)
1693e14d3ac8SNicholas Roth };
1694e14d3ac8SNicholas Roth 
1695e14d3ac8SNicholas Roth /* ----------------------------------------------------------------------------
1696e14d3ac8SNicholas Roth  * Probe and initialization
1697e14d3ac8SNicholas Roth  */
1698e14d3ac8SNicholas Roth 
ov8858_init_ctrls(struct ov8858 * ov8858)1699e14d3ac8SNicholas Roth static int ov8858_init_ctrls(struct ov8858 *ov8858)
1700e14d3ac8SNicholas Roth {
1701e14d3ac8SNicholas Roth 	struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
1702e14d3ac8SNicholas Roth 	struct v4l2_ctrl_handler *handler = &ov8858->ctrl_handler;
1703e14d3ac8SNicholas Roth 	const struct ov8858_mode *mode = &ov8858_modes[0];
1704e14d3ac8SNicholas Roth 	struct v4l2_fwnode_device_properties props;
1705e14d3ac8SNicholas Roth 	s64 exposure_max, vblank_def;
1706e14d3ac8SNicholas Roth 	unsigned int pixel_rate;
1707e14d3ac8SNicholas Roth 	struct v4l2_ctrl *ctrl;
1708e14d3ac8SNicholas Roth 	u32 h_blank;
1709e14d3ac8SNicholas Roth 	int ret;
1710e14d3ac8SNicholas Roth 
1711e14d3ac8SNicholas Roth 	ret = v4l2_ctrl_handler_init(handler, 10);
1712e14d3ac8SNicholas Roth 	if (ret)
1713e14d3ac8SNicholas Roth 		return ret;
1714e14d3ac8SNicholas Roth 
1715e14d3ac8SNicholas Roth 	ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ,
1716e14d3ac8SNicholas Roth 				      0, 0, link_freq_menu_items);
1717e14d3ac8SNicholas Roth 	if (ctrl)
1718e14d3ac8SNicholas Roth 		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
1719e14d3ac8SNicholas Roth 
1720e14d3ac8SNicholas Roth 	/* pixel rate = link frequency * 2 * lanes / bpp */
1721e14d3ac8SNicholas Roth 	pixel_rate = OV8858_LINK_FREQ * 2 * ov8858->num_lanes / 10;
1722e14d3ac8SNicholas Roth 	v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE,
1723e14d3ac8SNicholas Roth 			  0, pixel_rate, 1, pixel_rate);
1724e14d3ac8SNicholas Roth 
1725e14d3ac8SNicholas Roth 	h_blank = mode->hts_def - mode->width;
1726e14d3ac8SNicholas Roth 	ov8858->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
1727e14d3ac8SNicholas Roth 					   h_blank, h_blank, 1, h_blank);
1728e14d3ac8SNicholas Roth 	if (ov8858->hblank)
1729e14d3ac8SNicholas Roth 		ov8858->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
1730e14d3ac8SNicholas Roth 
1731e14d3ac8SNicholas Roth 	vblank_def = mode->vts_def - mode->height;
1732e14d3ac8SNicholas Roth 	ov8858->vblank = v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops,
1733e14d3ac8SNicholas Roth 					   V4L2_CID_VBLANK, vblank_def,
1734e14d3ac8SNicholas Roth 					   OV8858_VTS_MAX - mode->height,
1735e14d3ac8SNicholas Roth 					   1, vblank_def);
1736e14d3ac8SNicholas Roth 
1737e14d3ac8SNicholas Roth 	exposure_max = mode->vts_def - OV8858_EXPOSURE_MARGIN;
1738e14d3ac8SNicholas Roth 	ov8858->exposure = v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops,
1739e14d3ac8SNicholas Roth 					     V4L2_CID_EXPOSURE,
1740e14d3ac8SNicholas Roth 					     OV8858_EXPOSURE_MIN,
1741e14d3ac8SNicholas Roth 					     exposure_max, OV8858_EXPOSURE_STEP,
1742e14d3ac8SNicholas Roth 					     mode->exp_def);
1743e14d3ac8SNicholas Roth 
1744e14d3ac8SNicholas Roth 	v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
1745e14d3ac8SNicholas Roth 			  OV8858_LONG_GAIN_MIN, OV8858_LONG_GAIN_MAX,
1746e14d3ac8SNicholas Roth 			  OV8858_LONG_GAIN_STEP, OV8858_LONG_GAIN_DEFAULT);
1747e14d3ac8SNicholas Roth 
1748e14d3ac8SNicholas Roth 	v4l2_ctrl_new_std(handler, &ov8858_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
1749e14d3ac8SNicholas Roth 			  OV8858_LONG_DIGIGAIN_MIN, OV8858_LONG_DIGIGAIN_MAX,
1750e14d3ac8SNicholas Roth 			  OV8858_LONG_DIGIGAIN_STEP,
1751e14d3ac8SNicholas Roth 			  OV8858_LONG_DIGIGAIN_DEFAULT);
1752e14d3ac8SNicholas Roth 
1753e14d3ac8SNicholas Roth 	v4l2_ctrl_new_std_menu_items(handler, &ov8858_ctrl_ops,
1754e14d3ac8SNicholas Roth 				     V4L2_CID_TEST_PATTERN,
1755e14d3ac8SNicholas Roth 				     ARRAY_SIZE(ov8858_test_pattern_menu) - 1,
1756e14d3ac8SNicholas Roth 				     0, 0, ov8858_test_pattern_menu);
1757e14d3ac8SNicholas Roth 
1758e14d3ac8SNicholas Roth 	if (handler->error) {
1759e14d3ac8SNicholas Roth 		ret = handler->error;
1760e14d3ac8SNicholas Roth 		goto err_free_handler;
1761e14d3ac8SNicholas Roth 	}
1762e14d3ac8SNicholas Roth 
1763e14d3ac8SNicholas Roth 	ret = v4l2_fwnode_device_parse(&client->dev, &props);
1764e14d3ac8SNicholas Roth 	if (ret)
1765e14d3ac8SNicholas Roth 		goto err_free_handler;
1766e14d3ac8SNicholas Roth 
1767e14d3ac8SNicholas Roth 	ret = v4l2_ctrl_new_fwnode_properties(handler, &ov8858_ctrl_ops,
1768e14d3ac8SNicholas Roth 					      &props);
1769e14d3ac8SNicholas Roth 	if (ret)
1770e14d3ac8SNicholas Roth 		goto err_free_handler;
1771e14d3ac8SNicholas Roth 
1772e14d3ac8SNicholas Roth 	ov8858->subdev.ctrl_handler = handler;
1773e14d3ac8SNicholas Roth 
1774e14d3ac8SNicholas Roth 	return 0;
1775e14d3ac8SNicholas Roth 
1776e14d3ac8SNicholas Roth err_free_handler:
1777e14d3ac8SNicholas Roth 	dev_err(&client->dev, "Failed to init controls: %d\n", ret);
1778e14d3ac8SNicholas Roth 	v4l2_ctrl_handler_free(handler);
1779e14d3ac8SNicholas Roth 
1780e14d3ac8SNicholas Roth 	return ret;
1781e14d3ac8SNicholas Roth }
1782e14d3ac8SNicholas Roth 
ov8858_check_sensor_id(struct ov8858 * ov8858)1783e14d3ac8SNicholas Roth static int ov8858_check_sensor_id(struct ov8858 *ov8858)
1784e14d3ac8SNicholas Roth {
1785e14d3ac8SNicholas Roth 	struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
1786e14d3ac8SNicholas Roth 	u32 id = 0;
1787e14d3ac8SNicholas Roth 	int ret;
1788e14d3ac8SNicholas Roth 
1789e14d3ac8SNicholas Roth 	ret = ov8858_read(ov8858, OV8858_REG_CHIP_ID, &id);
1790e14d3ac8SNicholas Roth 	if (ret)
1791e14d3ac8SNicholas Roth 		return ret;
1792e14d3ac8SNicholas Roth 
1793e14d3ac8SNicholas Roth 	if (id != OV8858_CHIP_ID) {
1794e14d3ac8SNicholas Roth 		dev_err(&client->dev, "Unexpected sensor id 0x%x\n", id);
1795e14d3ac8SNicholas Roth 		return -ENODEV;
1796e14d3ac8SNicholas Roth 	}
1797e14d3ac8SNicholas Roth 
1798e14d3ac8SNicholas Roth 	ret = ov8858_read(ov8858, OV8858_REG_SUB_ID, &id);
1799e14d3ac8SNicholas Roth 	if (ret)
1800e14d3ac8SNicholas Roth 		return ret;
1801e14d3ac8SNicholas Roth 
1802e14d3ac8SNicholas Roth 	dev_info(&client->dev, "Detected OV8858 sensor, revision 0x%x\n", id);
1803e14d3ac8SNicholas Roth 
1804e14d3ac8SNicholas Roth 	if (id == OV8858_R2A) {
1805e14d3ac8SNicholas Roth 		/* R2A supports 2 and 4 lanes modes. */
1806e14d3ac8SNicholas Roth 		ov8858->global_regs = ov8858->num_lanes == 4
1807e14d3ac8SNicholas Roth 				    ? ov8858_global_regs_r2a_4lane
1808e14d3ac8SNicholas Roth 				    : ov8858_global_regs_r2a_2lane;
1809e14d3ac8SNicholas Roth 	} else if (ov8858->num_lanes == 2) {
1810e14d3ac8SNicholas Roth 		/*
1811e14d3ac8SNicholas Roth 		 * R1A only supports 2 lanes mode and it's only partially
1812e14d3ac8SNicholas Roth 		 * supported.
1813e14d3ac8SNicholas Roth 		 */
1814e14d3ac8SNicholas Roth 		ov8858->global_regs = ov8858_global_regs_r1a;
1815e14d3ac8SNicholas Roth 		dev_warn(&client->dev, "R1A may not work well!\n");
1816e14d3ac8SNicholas Roth 	} else {
1817e14d3ac8SNicholas Roth 		dev_err(&client->dev,
1818e14d3ac8SNicholas Roth 			"Unsupported number of data lanes for R1A revision.\n");
1819e14d3ac8SNicholas Roth 		return -EINVAL;
1820e14d3ac8SNicholas Roth 	}
1821e14d3ac8SNicholas Roth 
1822e14d3ac8SNicholas Roth 	return 0;
1823e14d3ac8SNicholas Roth }
1824e14d3ac8SNicholas Roth 
ov8858_configure_regulators(struct ov8858 * ov8858)1825e14d3ac8SNicholas Roth static int ov8858_configure_regulators(struct ov8858 *ov8858)
1826e14d3ac8SNicholas Roth {
1827e14d3ac8SNicholas Roth 	struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
1828e14d3ac8SNicholas Roth 	unsigned int i;
1829e14d3ac8SNicholas Roth 
1830e14d3ac8SNicholas Roth 	for (i = 0; i < ARRAY_SIZE(ov8858_supply_names); i++)
1831e14d3ac8SNicholas Roth 		ov8858->supplies[i].supply = ov8858_supply_names[i];
1832e14d3ac8SNicholas Roth 
1833e14d3ac8SNicholas Roth 	return devm_regulator_bulk_get(&client->dev,
1834e14d3ac8SNicholas Roth 				       ARRAY_SIZE(ov8858_supply_names),
1835e14d3ac8SNicholas Roth 				       ov8858->supplies);
1836e14d3ac8SNicholas Roth }
1837e14d3ac8SNicholas Roth 
ov8858_parse_of(struct ov8858 * ov8858)1838e14d3ac8SNicholas Roth static int ov8858_parse_of(struct ov8858 *ov8858)
1839e14d3ac8SNicholas Roth {
1840e14d3ac8SNicholas Roth 	struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_CSI2_DPHY };
1841e14d3ac8SNicholas Roth 	struct i2c_client *client = v4l2_get_subdevdata(&ov8858->subdev);
1842e14d3ac8SNicholas Roth 	struct device *dev = &client->dev;
1843e14d3ac8SNicholas Roth 	struct fwnode_handle *endpoint;
1844e14d3ac8SNicholas Roth 	int ret;
1845e14d3ac8SNicholas Roth 
1846e14d3ac8SNicholas Roth 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
1847e14d3ac8SNicholas Roth 	if (!endpoint) {
1848e14d3ac8SNicholas Roth 		dev_err(dev, "Failed to get endpoint\n");
1849e14d3ac8SNicholas Roth 		return -EINVAL;
1850e14d3ac8SNicholas Roth 	}
1851e14d3ac8SNicholas Roth 
1852e14d3ac8SNicholas Roth 	ret = v4l2_fwnode_endpoint_parse(endpoint, &vep);
1853*c46f16f1SOndrej Jirman 	fwnode_handle_put(endpoint);
1854e14d3ac8SNicholas Roth 	if (ret) {
1855e14d3ac8SNicholas Roth 		dev_err(dev, "Failed to parse endpoint: %d\n", ret);
1856e14d3ac8SNicholas Roth 		return ret;
1857e14d3ac8SNicholas Roth 	}
1858e14d3ac8SNicholas Roth 
1859e14d3ac8SNicholas Roth 	ov8858->num_lanes = vep.bus.mipi_csi2.num_data_lanes;
1860e14d3ac8SNicholas Roth 	switch (ov8858->num_lanes) {
1861e14d3ac8SNicholas Roth 	case 4:
1862e14d3ac8SNicholas Roth 	case 2:
1863e14d3ac8SNicholas Roth 		break;
1864e14d3ac8SNicholas Roth 	default:
1865e14d3ac8SNicholas Roth 		dev_err(dev, "Unsupported number of data lanes %u\n",
1866e14d3ac8SNicholas Roth 			ov8858->num_lanes);
1867e14d3ac8SNicholas Roth 		return -EINVAL;
1868e14d3ac8SNicholas Roth 	}
1869e14d3ac8SNicholas Roth 
1870e14d3ac8SNicholas Roth 	return 0;
1871e14d3ac8SNicholas Roth }
1872e14d3ac8SNicholas Roth 
ov8858_probe(struct i2c_client * client)1873e14d3ac8SNicholas Roth static int ov8858_probe(struct i2c_client *client)
1874e14d3ac8SNicholas Roth {
1875e14d3ac8SNicholas Roth 	struct device *dev = &client->dev;
1876e14d3ac8SNicholas Roth 	struct v4l2_subdev *sd;
1877e14d3ac8SNicholas Roth 	struct ov8858 *ov8858;
1878e14d3ac8SNicholas Roth 	int ret;
1879e14d3ac8SNicholas Roth 
1880e14d3ac8SNicholas Roth 	ov8858 = devm_kzalloc(dev, sizeof(*ov8858), GFP_KERNEL);
1881e14d3ac8SNicholas Roth 	if (!ov8858)
1882e14d3ac8SNicholas Roth 		return -ENOMEM;
1883e14d3ac8SNicholas Roth 
1884e14d3ac8SNicholas Roth 	ov8858->xvclk = devm_clk_get(dev, "xvclk");
1885e14d3ac8SNicholas Roth 	if (IS_ERR(ov8858->xvclk))
1886e14d3ac8SNicholas Roth 		return dev_err_probe(dev, PTR_ERR(ov8858->xvclk),
1887e14d3ac8SNicholas Roth 				     "Failed to get xvclk\n");
1888e14d3ac8SNicholas Roth 
1889e14d3ac8SNicholas Roth 	ov8858->reset_gpio = devm_gpiod_get_optional(dev, "reset",
1890e14d3ac8SNicholas Roth 						     GPIOD_OUT_HIGH);
1891e14d3ac8SNicholas Roth 	if (IS_ERR(ov8858->reset_gpio))
1892e14d3ac8SNicholas Roth 		return dev_err_probe(dev, PTR_ERR(ov8858->reset_gpio),
1893e14d3ac8SNicholas Roth 				     "Failed to get reset gpio\n");
1894e14d3ac8SNicholas Roth 
1895e14d3ac8SNicholas Roth 	ov8858->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
1896e14d3ac8SNicholas Roth 						    GPIOD_OUT_HIGH);
1897e14d3ac8SNicholas Roth 	if (IS_ERR(ov8858->pwdn_gpio))
1898e14d3ac8SNicholas Roth 		return dev_err_probe(dev, PTR_ERR(ov8858->pwdn_gpio),
1899e14d3ac8SNicholas Roth 				     "Failed to get powerdown gpio\n");
1900e14d3ac8SNicholas Roth 
1901e14d3ac8SNicholas Roth 	v4l2_i2c_subdev_init(&ov8858->subdev, client, &ov8858_subdev_ops);
1902e14d3ac8SNicholas Roth 
1903e14d3ac8SNicholas Roth 	ret = ov8858_configure_regulators(ov8858);
1904e14d3ac8SNicholas Roth 	if (ret)
1905e14d3ac8SNicholas Roth 		return dev_err_probe(dev, ret, "Failed to get regulators\n");
1906e14d3ac8SNicholas Roth 
1907e14d3ac8SNicholas Roth 	ret = ov8858_parse_of(ov8858);
1908e14d3ac8SNicholas Roth 	if (ret)
1909e14d3ac8SNicholas Roth 		return ret;
1910e14d3ac8SNicholas Roth 
1911e14d3ac8SNicholas Roth 	ret = ov8858_init_ctrls(ov8858);
1912e14d3ac8SNicholas Roth 	if (ret)
1913*c46f16f1SOndrej Jirman 		return ret;
1914e14d3ac8SNicholas Roth 
1915e14d3ac8SNicholas Roth 	sd = &ov8858->subdev;
1916e14d3ac8SNicholas Roth 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
1917e14d3ac8SNicholas Roth 	ov8858->pad.flags = MEDIA_PAD_FL_SOURCE;
1918e14d3ac8SNicholas Roth 	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
1919e14d3ac8SNicholas Roth 	ret = media_entity_pads_init(&sd->entity, 1, &ov8858->pad);
1920e14d3ac8SNicholas Roth 	if (ret < 0)
1921e14d3ac8SNicholas Roth 		goto err_free_handler;
1922e14d3ac8SNicholas Roth 
1923e14d3ac8SNicholas Roth 	sd->state_lock = ov8858->ctrl_handler.lock;
1924e14d3ac8SNicholas Roth 	ret = v4l2_subdev_init_finalize(sd);
1925e14d3ac8SNicholas Roth 	if (ret < 0) {
1926e14d3ac8SNicholas Roth 		dev_err(&client->dev, "Subdev initialization error %d\n", ret);
1927e14d3ac8SNicholas Roth 		goto err_clean_entity;
1928e14d3ac8SNicholas Roth 	}
1929e14d3ac8SNicholas Roth 
1930e14d3ac8SNicholas Roth 	ret = ov8858_power_on(ov8858);
1931e14d3ac8SNicholas Roth 	if (ret)
1932e14d3ac8SNicholas Roth 		goto err_clean_entity;
1933e14d3ac8SNicholas Roth 
1934e14d3ac8SNicholas Roth 	pm_runtime_set_active(dev);
1935e14d3ac8SNicholas Roth 	pm_runtime_get_noresume(dev);
1936e14d3ac8SNicholas Roth 	pm_runtime_enable(dev);
1937e14d3ac8SNicholas Roth 
1938e14d3ac8SNicholas Roth 	ret = ov8858_check_sensor_id(ov8858);
1939e14d3ac8SNicholas Roth 	if (ret)
1940e14d3ac8SNicholas Roth 		goto err_power_off;
1941e14d3ac8SNicholas Roth 
1942e14d3ac8SNicholas Roth 	pm_runtime_set_autosuspend_delay(dev, 1000);
1943e14d3ac8SNicholas Roth 	pm_runtime_use_autosuspend(dev);
1944e14d3ac8SNicholas Roth 
1945e14d3ac8SNicholas Roth 	ret = v4l2_async_register_subdev_sensor(sd);
1946e14d3ac8SNicholas Roth 	if (ret) {
1947e14d3ac8SNicholas Roth 		dev_err(dev, "v4l2 async register subdev failed\n");
1948e14d3ac8SNicholas Roth 		goto err_power_off;
1949e14d3ac8SNicholas Roth 	}
1950e14d3ac8SNicholas Roth 
1951e14d3ac8SNicholas Roth 	pm_runtime_mark_last_busy(dev);
1952e14d3ac8SNicholas Roth 	pm_runtime_put_autosuspend(dev);
1953e14d3ac8SNicholas Roth 
1954e14d3ac8SNicholas Roth 	return 0;
1955e14d3ac8SNicholas Roth 
1956e14d3ac8SNicholas Roth err_power_off:
1957e14d3ac8SNicholas Roth 	pm_runtime_disable(dev);
1958e14d3ac8SNicholas Roth 	pm_runtime_put_noidle(dev);
1959e14d3ac8SNicholas Roth 	ov8858_power_off(ov8858);
1960e14d3ac8SNicholas Roth err_clean_entity:
1961e14d3ac8SNicholas Roth 	media_entity_cleanup(&sd->entity);
1962e14d3ac8SNicholas Roth err_free_handler:
1963e14d3ac8SNicholas Roth 	v4l2_ctrl_handler_free(&ov8858->ctrl_handler);
1964e14d3ac8SNicholas Roth 
1965e14d3ac8SNicholas Roth 	return ret;
1966e14d3ac8SNicholas Roth }
1967e14d3ac8SNicholas Roth 
ov8858_remove(struct i2c_client * client)1968e14d3ac8SNicholas Roth static void ov8858_remove(struct i2c_client *client)
1969e14d3ac8SNicholas Roth {
1970e14d3ac8SNicholas Roth 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1971e14d3ac8SNicholas Roth 	struct ov8858 *ov8858 = sd_to_ov8858(sd);
1972e14d3ac8SNicholas Roth 
1973e14d3ac8SNicholas Roth 	v4l2_async_unregister_subdev(sd);
1974e14d3ac8SNicholas Roth 	media_entity_cleanup(&sd->entity);
1975e14d3ac8SNicholas Roth 	v4l2_ctrl_handler_free(&ov8858->ctrl_handler);
1976e14d3ac8SNicholas Roth 
1977e14d3ac8SNicholas Roth 	pm_runtime_disable(&client->dev);
1978e14d3ac8SNicholas Roth 	if (!pm_runtime_status_suspended(&client->dev))
1979e14d3ac8SNicholas Roth 		ov8858_power_off(ov8858);
1980e14d3ac8SNicholas Roth 	pm_runtime_set_suspended(&client->dev);
1981e14d3ac8SNicholas Roth }
1982e14d3ac8SNicholas Roth 
1983e14d3ac8SNicholas Roth static const struct of_device_id ov8858_of_match[] = {
1984e14d3ac8SNicholas Roth 	{ .compatible = "ovti,ov8858" },
1985e14d3ac8SNicholas Roth 	{ /* sentinel */ },
1986e14d3ac8SNicholas Roth };
1987e14d3ac8SNicholas Roth MODULE_DEVICE_TABLE(of, ov8858_of_match);
1988e14d3ac8SNicholas Roth 
1989e14d3ac8SNicholas Roth static struct i2c_driver ov8858_i2c_driver = {
1990e14d3ac8SNicholas Roth 	.driver = {
1991e14d3ac8SNicholas Roth 		.name = "ov8858",
1992e14d3ac8SNicholas Roth 		.pm = &ov8858_pm_ops,
1993e14d3ac8SNicholas Roth 		.of_match_table = ov8858_of_match,
1994e14d3ac8SNicholas Roth 	},
1995aaeb31c0SUwe Kleine-König 	.probe		= ov8858_probe,
1996aaeb31c0SUwe Kleine-König 	.remove		= ov8858_remove,
1997e14d3ac8SNicholas Roth };
1998e14d3ac8SNicholas Roth 
1999e14d3ac8SNicholas Roth module_i2c_driver(ov8858_i2c_driver);
2000e14d3ac8SNicholas Roth 
2001e14d3ac8SNicholas Roth MODULE_DESCRIPTION("OmniVision OV8858 sensor driver");
2002e14d3ac8SNicholas Roth MODULE_LICENSE("GPL");
2003