xref: /linux/drivers/media/i2c/s5kjn1.c (revision c17ee635fd3a482b2ad2bf5e269755c2eae5f25e)
1*e38fd093SVladimir Zapolskiy // SPDX-License-Identifier: GPL-2.0
2*e38fd093SVladimir Zapolskiy // Copyright (c) 2025 Linaro Ltd
3*e38fd093SVladimir Zapolskiy 
4*e38fd093SVladimir Zapolskiy #include <linux/clk.h>
5*e38fd093SVladimir Zapolskiy #include <linux/delay.h>
6*e38fd093SVladimir Zapolskiy #include <linux/gpio/consumer.h>
7*e38fd093SVladimir Zapolskiy #include <linux/i2c.h>
8*e38fd093SVladimir Zapolskiy #include <linux/module.h>
9*e38fd093SVladimir Zapolskiy #include <linux/pm_runtime.h>
10*e38fd093SVladimir Zapolskiy #include <linux/regulator/consumer.h>
11*e38fd093SVladimir Zapolskiy #include <linux/units.h>
12*e38fd093SVladimir Zapolskiy #include <media/v4l2-cci.h>
13*e38fd093SVladimir Zapolskiy #include <media/v4l2-ctrls.h>
14*e38fd093SVladimir Zapolskiy #include <media/v4l2-device.h>
15*e38fd093SVladimir Zapolskiy #include <media/v4l2-fwnode.h>
16*e38fd093SVladimir Zapolskiy 
17*e38fd093SVladimir Zapolskiy #define S5KJN1_LINK_FREQ_700MHZ		(700ULL * HZ_PER_MHZ)
18*e38fd093SVladimir Zapolskiy #define S5KJN1_MCLK_FREQ_24MHZ		(24 * HZ_PER_MHZ)
19*e38fd093SVladimir Zapolskiy #define S5KJN1_DATA_LANES		4
20*e38fd093SVladimir Zapolskiy 
21*e38fd093SVladimir Zapolskiy /* Register map is similar to MIPI CCS compliant camera sensors */
22*e38fd093SVladimir Zapolskiy #define S5KJN1_REG_CHIP_ID		CCI_REG16(0x0000)
23*e38fd093SVladimir Zapolskiy #define S5KJN1_CHIP_ID			0x38e1
24*e38fd093SVladimir Zapolskiy 
25*e38fd093SVladimir Zapolskiy #define S5KJN1_REG_CTRL_MODE		CCI_REG8(0x0100)
26*e38fd093SVladimir Zapolskiy #define S5KJN1_MODE_STREAMING		BIT(0)
27*e38fd093SVladimir Zapolskiy 
28*e38fd093SVladimir Zapolskiy #define S5KJN1_REG_ORIENTATION		CCI_REG8(0x0101)
29*e38fd093SVladimir Zapolskiy #define S5KJN1_VFLIP			BIT(1)
30*e38fd093SVladimir Zapolskiy #define S5KJN1_HFLIP			BIT(0)
31*e38fd093SVladimir Zapolskiy 
32*e38fd093SVladimir Zapolskiy #define S5KJN1_REG_EXPOSURE		CCI_REG16(0x0202)
33*e38fd093SVladimir Zapolskiy #define S5KJN1_EXPOSURE_MIN		8
34*e38fd093SVladimir Zapolskiy #define S5KJN1_EXPOSURE_STEP		1
35*e38fd093SVladimir Zapolskiy 
36*e38fd093SVladimir Zapolskiy #define S5KJN1_REG_AGAIN		CCI_REG16(0x0204)
37*e38fd093SVladimir Zapolskiy #define S5KJN1_AGAIN_MIN		1
38*e38fd093SVladimir Zapolskiy #define S5KJN1_AGAIN_MAX		64
39*e38fd093SVladimir Zapolskiy #define S5KJN1_AGAIN_STEP		1
40*e38fd093SVladimir Zapolskiy #define S5KJN1_AGAIN_DEFAULT		6
41*e38fd093SVladimir Zapolskiy #define S5KJN1_AGAIN_SHIFT		5
42*e38fd093SVladimir Zapolskiy 
43*e38fd093SVladimir Zapolskiy #define S5KJN1_REG_VTS			CCI_REG16(0x0340)
44*e38fd093SVladimir Zapolskiy #define S5KJN1_VTS_MAX			0xffff
45*e38fd093SVladimir Zapolskiy 
46*e38fd093SVladimir Zapolskiy #define S5KJN1_REG_HTS			CCI_REG16(0x0342)
47*e38fd093SVladimir Zapolskiy #define S5KJN1_REG_X_ADDR_START		CCI_REG16(0x0344)
48*e38fd093SVladimir Zapolskiy #define S5KJN1_REG_Y_ADDR_START		CCI_REG16(0x0346)
49*e38fd093SVladimir Zapolskiy #define S5KJN1_REG_X_ADDR_END		CCI_REG16(0x0348)
50*e38fd093SVladimir Zapolskiy #define S5KJN1_REG_Y_ADDR_END		CCI_REG16(0x034a)
51*e38fd093SVladimir Zapolskiy #define S5KJN1_REG_X_OUTPUT_SIZE	CCI_REG16(0x034c)
52*e38fd093SVladimir Zapolskiy #define S5KJN1_REG_Y_OUTPUT_SIZE	CCI_REG16(0x034e)
53*e38fd093SVladimir Zapolskiy 
54*e38fd093SVladimir Zapolskiy #define S5KJN1_REG_TEST_PATTERN		CCI_REG16(0x0600)
55*e38fd093SVladimir Zapolskiy 
56*e38fd093SVladimir Zapolskiy #define to_s5kjn1(_sd)			container_of(_sd, struct s5kjn1, sd)
57*e38fd093SVladimir Zapolskiy 
58*e38fd093SVladimir Zapolskiy static const s64 s5kjn1_link_freq_menu[] = {
59*e38fd093SVladimir Zapolskiy 	S5KJN1_LINK_FREQ_700MHZ,
60*e38fd093SVladimir Zapolskiy };
61*e38fd093SVladimir Zapolskiy 
62*e38fd093SVladimir Zapolskiy /* List of supported formats to cover horizontal and vertical flip controls */
63*e38fd093SVladimir Zapolskiy static const u32 s5kjn1_mbus_formats[] = {
64*e38fd093SVladimir Zapolskiy 	MEDIA_BUS_FMT_SGRBG10_1X10,	MEDIA_BUS_FMT_SRGGB10_1X10,
65*e38fd093SVladimir Zapolskiy 	MEDIA_BUS_FMT_SBGGR10_1X10,	MEDIA_BUS_FMT_SGBRG10_1X10,
66*e38fd093SVladimir Zapolskiy };
67*e38fd093SVladimir Zapolskiy 
68*e38fd093SVladimir Zapolskiy struct s5kjn1_reg_list {
69*e38fd093SVladimir Zapolskiy 	const struct cci_reg_sequence *regs;
70*e38fd093SVladimir Zapolskiy 	unsigned int num_regs;
71*e38fd093SVladimir Zapolskiy };
72*e38fd093SVladimir Zapolskiy 
73*e38fd093SVladimir Zapolskiy struct s5kjn1_mode {
74*e38fd093SVladimir Zapolskiy 	u32 width;			/* Frame width in pixels */
75*e38fd093SVladimir Zapolskiy 	u32 height;			/* Frame height in pixels */
76*e38fd093SVladimir Zapolskiy 	u32 hts;			/* Horizontal timing size */
77*e38fd093SVladimir Zapolskiy 	u32 vts;			/* Default vertical timing size */
78*e38fd093SVladimir Zapolskiy 	u32 exposure;			/* Default exposure value */
79*e38fd093SVladimir Zapolskiy 	u32 exposure_margin;		/* Exposure margin */
80*e38fd093SVladimir Zapolskiy 
81*e38fd093SVladimir Zapolskiy 	const struct s5kjn1_reg_list reg_list;	/* Sensor register setting */
82*e38fd093SVladimir Zapolskiy };
83*e38fd093SVladimir Zapolskiy 
84*e38fd093SVladimir Zapolskiy static const char * const s5kjn1_test_pattern_menu[] = {
85*e38fd093SVladimir Zapolskiy 	"Disabled",
86*e38fd093SVladimir Zapolskiy 	"Solid color",
87*e38fd093SVladimir Zapolskiy 	"Color bars",
88*e38fd093SVladimir Zapolskiy 	"Fade to grey color bars",
89*e38fd093SVladimir Zapolskiy 	"PN9",
90*e38fd093SVladimir Zapolskiy };
91*e38fd093SVladimir Zapolskiy 
92*e38fd093SVladimir Zapolskiy struct s5kjn1 {
93*e38fd093SVladimir Zapolskiy 	struct device *dev;
94*e38fd093SVladimir Zapolskiy 	struct regmap *regmap;
95*e38fd093SVladimir Zapolskiy 	struct clk *mclk;
96*e38fd093SVladimir Zapolskiy 	struct gpio_desc *reset_gpio;
97*e38fd093SVladimir Zapolskiy 	struct regulator *afvdd;	/* Autofocus actuator power */
98*e38fd093SVladimir Zapolskiy 	struct regulator *vdda;		/* Analog power */
99*e38fd093SVladimir Zapolskiy 	struct regulator *vddd;		/* Digital core power */
100*e38fd093SVladimir Zapolskiy 	struct regulator *vddio;	/* Digital I/O power */
101*e38fd093SVladimir Zapolskiy 
102*e38fd093SVladimir Zapolskiy 	struct v4l2_subdev sd;
103*e38fd093SVladimir Zapolskiy 	struct media_pad pad;
104*e38fd093SVladimir Zapolskiy 
105*e38fd093SVladimir Zapolskiy 	struct v4l2_ctrl_handler ctrl_handler;
106*e38fd093SVladimir Zapolskiy 	struct v4l2_ctrl *link_freq;
107*e38fd093SVladimir Zapolskiy 	struct v4l2_ctrl *pixel_rate;
108*e38fd093SVladimir Zapolskiy 	struct v4l2_ctrl *hblank;
109*e38fd093SVladimir Zapolskiy 	struct v4l2_ctrl *vblank;
110*e38fd093SVladimir Zapolskiy 	struct v4l2_ctrl *exposure;
111*e38fd093SVladimir Zapolskiy 	struct v4l2_ctrl *vflip;
112*e38fd093SVladimir Zapolskiy 	struct v4l2_ctrl *hflip;
113*e38fd093SVladimir Zapolskiy 
114*e38fd093SVladimir Zapolskiy 	const struct s5kjn1_mode *mode;
115*e38fd093SVladimir Zapolskiy };
116*e38fd093SVladimir Zapolskiy 
117*e38fd093SVladimir Zapolskiy static const struct cci_reg_sequence init_array_setting[] = {
118*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6028), 0x2400 },
119*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1354 },
120*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
121*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x7017 },
122*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x13b2 },
123*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
124*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1236 },
125*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
126*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a0a },
127*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x4c0a },
128*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x2210 },
129*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x3401 },
130*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x2176 },
131*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x6400 },
132*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x222e },
133*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0001 },
134*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x06b6 },
135*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0a00 },
136*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x06bc },
137*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1001 },
138*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x2140 },
139*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0101 },
140*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a0e },
141*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x9600 },
142*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6028), 0x4000 },
143*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0xf44e), 0x0011 },
144*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0xf44c), 0x0b0b },
145*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0xf44a), 0x0006 },
146*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0118), 0x0002 },
147*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x011a), 0x0001 },
148*e38fd093SVladimir Zapolskiy };
149*e38fd093SVladimir Zapolskiy 
150*e38fd093SVladimir Zapolskiy static const struct cci_reg_sequence s5kjn1_4080x3072_30fps_mode[] = {
151*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6028), 0x2400 },
152*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a28 },
153*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x4c00 },
154*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x065a },
155*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
156*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x139e },
157*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
158*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x139c },
159*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
160*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x13a0 },
161*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0a00 },
162*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0120 },
163*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x2072 },
164*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
165*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a64 },
166*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0301 },
167*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xff00 },
168*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x19e6 },
169*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0200 },
170*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a30 },
171*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x3401 },
172*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x19fc },
173*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0b00 },
174*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x19f4 },
175*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0606 },
176*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x19f8 },
177*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1010 },
178*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1b26 },
179*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x6f80 },
180*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xa060 },
181*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a3c },
182*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x6207 },
183*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a48 },
184*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x6207 },
185*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1444 },
186*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x2000 },
187*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x2000 },
188*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x144c },
189*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x3f00 },
190*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x3f00 },
191*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x7f6c },
192*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
193*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x2f00 },
194*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xfa00 },
195*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x2400 },
196*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xe500 },
197*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0650 },
198*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0600 },
199*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0654 },
200*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
201*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a46 },
202*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x8a00 },
203*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a52 },
204*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xbf00 },
205*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0674 },
206*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0500 },
207*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0500 },
208*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0500 },
209*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0500 },
210*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0668 },
211*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
212*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
213*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
214*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
215*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0684 },
216*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x4001 },
217*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0688 },
218*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x4001 },
219*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x147c },
220*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
221*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1480 },
222*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
223*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x19f6 },
224*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0904 },
225*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0812 },
226*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
227*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a02 },
228*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1800 },
229*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x2148 },
230*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
231*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x2042 },
232*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1a00 },
233*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0874 },
234*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
235*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x09c0 },
236*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x2008 },
237*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x09c4 },
238*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x2000 },
239*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x19fe },
240*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0e1c },
241*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x4d92 },
242*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
243*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x84c8 },
244*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
245*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x4d94 },
246*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0005 },
247*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x000a },
248*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0010 },
249*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0810 },
250*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x000a },
251*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0040 },
252*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0810 },
253*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0810 },
254*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x8002 },
255*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xfd03 },
256*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0010 },
257*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1510 },
258*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x3570 },
259*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
260*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x3574 },
261*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1201 },
262*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x21e4 },
263*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0400 },
264*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x21ec },
265*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1f04 },
266*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x2080 },
267*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0101 },
268*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xff00 },
269*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x7f01 },
270*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0001 },
271*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x8001 },
272*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xd244 },
273*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xd244 },
274*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x14f4 },
275*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
276*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
277*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
278*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x20ba },
279*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x141c },
280*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x111c },
281*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x54f4 },
282*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x120e },
283*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
284*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x212e },
285*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0200 },
286*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x13ae },
287*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0101 },
288*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0718 },
289*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0001 },
290*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0710 },
291*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0002 },
292*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0804 },
293*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
294*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1b5c },
295*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
296*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0786 },
297*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x7701 },
298*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x2022 },
299*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0500 },
300*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0500 },
301*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1360 },
302*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
303*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1376 },
304*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
305*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x6038 },
306*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x7038 },
307*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x8038 },
308*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1386 },
309*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0b00 },
310*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x06fa },
311*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
312*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x4a94 },
313*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0900 },
314*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
315*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0300 },
316*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
317*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
318*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
319*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
320*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
321*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0300 },
322*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
323*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0900 },
324*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
325*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
326*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
327*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
328*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
329*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0a76 },
330*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
331*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0aee },
332*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
333*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0b66 },
334*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
335*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0bde },
336*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
337*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0be8 },
338*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x3000 },
339*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x3000 },
340*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0c56 },
341*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
342*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0c60 },
343*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x3000 },
344*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x3000 },
345*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0cb6 },
346*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
347*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0cf2 },
348*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0001 },
349*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0cf0 },
350*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0101 },
351*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x11b8 },
352*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
353*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x11f6 },
354*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0020 },
355*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x4a74 },
356*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
357*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
358*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xd8ff },
359*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
360*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
361*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
362*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
363*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
364*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xd8ff },
365*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
366*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
367*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
368*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
369*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
370*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
371*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
372*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x218e },
373*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
374*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x2268 },
375*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xf279 },
376*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x5006 },
377*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
378*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x500e },
379*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
380*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x4e70 },
381*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x2062 },
382*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x5501 },
383*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x06dc },
384*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
385*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
386*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
387*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
388*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6028), 0x4000 },
389*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0xf46a), 0xae80 },
390*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_X_ADDR_START,  0x0000 },
391*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_Y_ADDR_START,  0x0000 },
392*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_X_ADDR_END,    0x1fff },
393*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_Y_ADDR_END,    0x181f },
394*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_X_OUTPUT_SIZE, 0x0ff0 },
395*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_Y_OUTPUT_SIZE, 0x0c00 },
396*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0350), 0x0008 },
397*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0352), 0x0008 },
398*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0900), 0x0122 },
399*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0380), 0x0002 },
400*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0382), 0x0002 },
401*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0384), 0x0002 },
402*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0386), 0x0002 },
403*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0110), 0x1002 },
404*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0114), 0x0301 },
405*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0116), 0x3000 },
406*e38fd093SVladimir Zapolskiy 
407*e38fd093SVladimir Zapolskiy 	/* Clock settings */
408*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0136), 0x1800 },
409*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x013e), 0x0000 },
410*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0300), 0x0006 },
411*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0302), 0x0001 },
412*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0304), 0x0004 },
413*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0306), 0x008c },
414*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0308), 0x0008 },
415*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x030a), 0x0001 },
416*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x030c), 0x0000 },
417*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x030e), 0x0004 },
418*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0310), 0x0092 },
419*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0312), 0x0000 },
420*e38fd093SVladimir Zapolskiy 
421*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x080e), 0x0000 },
422*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_VTS,    0x10c0 },
423*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_HTS,    0x1100 },
424*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0702), 0x0000 },
425*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_EXPOSURE, 0x0100 },
426*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0200), 0x0100 },
427*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0d00), 0x0101 },
428*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0d02), 0x0101 },
429*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0d04), 0x0102 },
430*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6226), 0x0000 },
431*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0816), 0x1c00 },
432*e38fd093SVladimir Zapolskiy };
433*e38fd093SVladimir Zapolskiy 
434*e38fd093SVladimir Zapolskiy static const struct cci_reg_sequence s5kjn1_8160x6144_10fps_mode[] = {
435*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6028), 0x2400 },
436*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a28 },
437*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x4c00 },
438*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x065a },
439*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
440*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x139e },
441*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0400 },
442*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x139c },
443*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
444*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x13a0 },
445*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0500 },
446*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0120 },
447*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x2072 },
448*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0101 },
449*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a64 },
450*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0001 },
451*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
452*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x19e6 },
453*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0200 },
454*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a30 },
455*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x3403 },
456*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x19fc },
457*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0700 },
458*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x19f4 },
459*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0707 },
460*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x19f8 },
461*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0b0b },
462*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1b26 },
463*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x6f80 },
464*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xa060 },
465*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a3c },
466*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x8207 },
467*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a48 },
468*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x8207 },
469*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1444 },
470*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x2000 },
471*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x2000 },
472*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x144c },
473*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x3f00 },
474*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x3f00 },
475*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x7f6c },
476*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
477*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x2f00 },
478*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xfa00 },
479*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x2400 },
480*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xe500 },
481*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0650 },
482*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0600 },
483*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0654 },
484*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
485*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a46 },
486*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x8500 },
487*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a52 },
488*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x9800 },
489*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0674 },
490*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0500 },
491*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0500 },
492*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0500 },
493*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0500 },
494*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0668 },
495*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
496*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
497*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
498*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
499*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0684 },
500*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x4001 },
501*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0688 },
502*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x4001 },
503*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x147c },
504*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0400 },
505*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1480 },
506*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0400 },
507*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x19f6 },
508*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0404 },
509*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0812 },
510*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
511*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1a02 },
512*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1800 },
513*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x2148 },
514*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
515*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x2042 },
516*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1a00 },
517*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0874 },
518*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0106 },
519*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x09c0 },
520*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x4000 },
521*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x09c4 },
522*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x4000 },
523*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x19fe },
524*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0c1c },
525*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x4d92 },
526*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
527*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x84c8 },
528*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
529*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x4d94 },
530*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
531*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
532*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
533*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
534*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
535*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
536*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
537*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
538*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
539*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
540*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
541*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
542*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x3570 },
543*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
544*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x3574 },
545*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x7306 },
546*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x21e4 },
547*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0400 },
548*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x21ec },
549*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x6902 },
550*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x2080 },
551*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
552*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xff00 },
553*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0002 },
554*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0001 },
555*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0002 },
556*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xd244 },
557*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xd244 },
558*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x14f4 },
559*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x101c },
560*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0d1c },
561*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x54f4 },
562*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x20ba },
563*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
564*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
565*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
566*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x120e },
567*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
568*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x212e },
569*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0200 },
570*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x13ae },
571*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
572*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0718 },
573*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
574*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0710 },
575*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0010 },
576*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0201 },
577*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
578*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1b5c },
579*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
580*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0786 },
581*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1401 },
582*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x2022 },
583*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0500 },
584*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0500 },
585*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1360 },
586*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
587*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1376 },
588*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
589*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x6038 },
590*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x7038 },
591*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x8038 },
592*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x1386 },
593*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0b00 },
594*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x06fa },
595*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
596*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x4a94 },
597*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0400 },
598*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0400 },
599*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0400 },
600*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0400 },
601*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
602*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
603*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
604*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
605*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0400 },
606*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0400 },
607*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0400 },
608*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0400 },
609*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
610*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
611*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
612*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0800 },
613*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0a76 },
614*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
615*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0aee },
616*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
617*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0b66 },
618*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
619*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0bde },
620*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
621*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0be8 },
622*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x5000 },
623*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x5000 },
624*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0c56 },
625*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x1000 },
626*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0c60 },
627*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x5000 },
628*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x5000 },
629*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0cb6 },
630*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
631*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0cf2 },
632*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0001 },
633*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x0cf0 },
634*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0101 },
635*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x11b8 },
636*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
637*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x11f6 },
638*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0010 },
639*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x4a74 },
640*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
641*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
642*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
643*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
644*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
645*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
646*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
647*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
648*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
649*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
650*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
651*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
652*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
653*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
654*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
655*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
656*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x218e },
657*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
658*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x2268 },
659*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0xf279 },
660*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x5006 },
661*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
662*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x500e },
663*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0100 },
664*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x4e70 },
665*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x2062 },
666*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x5501 },
667*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x602a), 0x06dc },
668*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
669*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
670*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
671*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6f12), 0x0000 },
672*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6028), 0x4000 },
673*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0xf46a), 0xae80 },
674*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_X_ADDR_START,  0x0000 },
675*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_Y_ADDR_START,  0x0000 },
676*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_X_ADDR_END,    0x1fff },
677*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_Y_ADDR_END,    0x181f },
678*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_X_OUTPUT_SIZE, 0x1fe0 },
679*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_Y_OUTPUT_SIZE, 0x1800 },
680*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0350), 0x0010 },
681*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0352), 0x0010 },
682*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0900), 0x0111 },
683*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0380), 0x0001 },
684*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0382), 0x0001 },
685*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0384), 0x0001 },
686*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0386), 0x0001 },
687*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0110), 0x1002 },
688*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0114), 0x0300 },
689*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0116), 0x3000 },
690*e38fd093SVladimir Zapolskiy 
691*e38fd093SVladimir Zapolskiy 	/* Clock settings */
692*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0136), 0x1800 },
693*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x013e), 0x0000 },
694*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0300), 0x0006 },
695*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0302), 0x0001 },
696*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0304), 0x0004 },
697*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0306), 0x008c },
698*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0308), 0x0008 },
699*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x030a), 0x0001 },
700*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x030c), 0x0000 },
701*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x030e), 0x0004 },
702*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0310), 0x0074 },
703*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0312), 0x0000 },
704*e38fd093SVladimir Zapolskiy 
705*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x080e), 0x0000 },
706*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_VTS,    0x1900 },
707*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_HTS,    0x21f0 },
708*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0702), 0x0000 },
709*e38fd093SVladimir Zapolskiy 	{ S5KJN1_REG_EXPOSURE, 0x0100 },
710*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0200), 0x0100 },
711*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0d00), 0x0100 },
712*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0d02), 0x0001 },
713*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x0d04), 0x0002 },
714*e38fd093SVladimir Zapolskiy 	{ CCI_REG16(0x6226), 0x0000 },
715*e38fd093SVladimir Zapolskiy };
716*e38fd093SVladimir Zapolskiy 
717*e38fd093SVladimir Zapolskiy static const struct s5kjn1_mode s5kjn1_supported_modes[] = {
718*e38fd093SVladimir Zapolskiy 	{
719*e38fd093SVladimir Zapolskiy 		.width = 4080,
720*e38fd093SVladimir Zapolskiy 		.height = 3072,
721*e38fd093SVladimir Zapolskiy 		.hts = 4352,
722*e38fd093SVladimir Zapolskiy 		.vts = 4288,
723*e38fd093SVladimir Zapolskiy 		.exposure = 3840,
724*e38fd093SVladimir Zapolskiy 		.exposure_margin = 22,
725*e38fd093SVladimir Zapolskiy 		.reg_list = {
726*e38fd093SVladimir Zapolskiy 			.regs = s5kjn1_4080x3072_30fps_mode,
727*e38fd093SVladimir Zapolskiy 			.num_regs = ARRAY_SIZE(s5kjn1_4080x3072_30fps_mode),
728*e38fd093SVladimir Zapolskiy 		},
729*e38fd093SVladimir Zapolskiy 	},
730*e38fd093SVladimir Zapolskiy 	{
731*e38fd093SVladimir Zapolskiy 		.width = 8160,
732*e38fd093SVladimir Zapolskiy 		.height = 6144,
733*e38fd093SVladimir Zapolskiy 		.hts = 8688,
734*e38fd093SVladimir Zapolskiy 		.vts = 6400,
735*e38fd093SVladimir Zapolskiy 		.exposure = 6144,
736*e38fd093SVladimir Zapolskiy 		.exposure_margin = 44,
737*e38fd093SVladimir Zapolskiy 		.reg_list = {
738*e38fd093SVladimir Zapolskiy 			.regs = s5kjn1_8160x6144_10fps_mode,
739*e38fd093SVladimir Zapolskiy 			.num_regs = ARRAY_SIZE(s5kjn1_8160x6144_10fps_mode),
740*e38fd093SVladimir Zapolskiy 		},
741*e38fd093SVladimir Zapolskiy 	},
742*e38fd093SVladimir Zapolskiy };
743*e38fd093SVladimir Zapolskiy 
744*e38fd093SVladimir Zapolskiy static int s5kjn1_set_ctrl(struct v4l2_ctrl *ctrl)
745*e38fd093SVladimir Zapolskiy {
746*e38fd093SVladimir Zapolskiy 	struct s5kjn1 *s5kjn1 = container_of(ctrl->handler, struct s5kjn1,
747*e38fd093SVladimir Zapolskiy 					     ctrl_handler);
748*e38fd093SVladimir Zapolskiy 	const struct s5kjn1_mode *mode = s5kjn1->mode;
749*e38fd093SVladimir Zapolskiy 	s64 exposure_max;
750*e38fd093SVladimir Zapolskiy 	int ret;
751*e38fd093SVladimir Zapolskiy 
752*e38fd093SVladimir Zapolskiy 	/* Propagate change of current control to all related controls */
753*e38fd093SVladimir Zapolskiy 	switch (ctrl->id) {
754*e38fd093SVladimir Zapolskiy 	case V4L2_CID_VBLANK:
755*e38fd093SVladimir Zapolskiy 		/* Update max exposure while meeting expected vblanking */
756*e38fd093SVladimir Zapolskiy 		exposure_max = mode->height + ctrl->val - mode->exposure_margin;
757*e38fd093SVladimir Zapolskiy 		__v4l2_ctrl_modify_range(s5kjn1->exposure,
758*e38fd093SVladimir Zapolskiy 					 s5kjn1->exposure->minimum,
759*e38fd093SVladimir Zapolskiy 					 exposure_max,
760*e38fd093SVladimir Zapolskiy 					 s5kjn1->exposure->step,
761*e38fd093SVladimir Zapolskiy 					 s5kjn1->exposure->default_value);
762*e38fd093SVladimir Zapolskiy 		break;
763*e38fd093SVladimir Zapolskiy 	}
764*e38fd093SVladimir Zapolskiy 
765*e38fd093SVladimir Zapolskiy 	/* V4L2 controls are applied, when sensor is powered up for streaming */
766*e38fd093SVladimir Zapolskiy 	if (!pm_runtime_get_if_active(s5kjn1->dev))
767*e38fd093SVladimir Zapolskiy 		return 0;
768*e38fd093SVladimir Zapolskiy 
769*e38fd093SVladimir Zapolskiy 	switch (ctrl->id) {
770*e38fd093SVladimir Zapolskiy 	case V4L2_CID_ANALOGUE_GAIN:
771*e38fd093SVladimir Zapolskiy 		ret = cci_write(s5kjn1->regmap, S5KJN1_REG_AGAIN,
772*e38fd093SVladimir Zapolskiy 				ctrl->val << S5KJN1_AGAIN_SHIFT, NULL);
773*e38fd093SVladimir Zapolskiy 		break;
774*e38fd093SVladimir Zapolskiy 	case V4L2_CID_EXPOSURE:
775*e38fd093SVladimir Zapolskiy 		ret = cci_write(s5kjn1->regmap, S5KJN1_REG_EXPOSURE,
776*e38fd093SVladimir Zapolskiy 				ctrl->val, NULL);
777*e38fd093SVladimir Zapolskiy 		break;
778*e38fd093SVladimir Zapolskiy 	case V4L2_CID_VBLANK:
779*e38fd093SVladimir Zapolskiy 		ret = cci_write(s5kjn1->regmap, S5KJN1_REG_VTS,
780*e38fd093SVladimir Zapolskiy 				ctrl->val + mode->height, NULL);
781*e38fd093SVladimir Zapolskiy 		break;
782*e38fd093SVladimir Zapolskiy 	case V4L2_CID_VFLIP:
783*e38fd093SVladimir Zapolskiy 	case V4L2_CID_HFLIP:
784*e38fd093SVladimir Zapolskiy 		ret = cci_write(s5kjn1->regmap, S5KJN1_REG_ORIENTATION,
785*e38fd093SVladimir Zapolskiy 				(s5kjn1->vflip->val ? S5KJN1_VFLIP : 0) |
786*e38fd093SVladimir Zapolskiy 				(s5kjn1->hflip->val ? S5KJN1_HFLIP : 0), NULL);
787*e38fd093SVladimir Zapolskiy 		break;
788*e38fd093SVladimir Zapolskiy 	case V4L2_CID_TEST_PATTERN:
789*e38fd093SVladimir Zapolskiy 		ret = cci_write(s5kjn1->regmap, S5KJN1_REG_TEST_PATTERN,
790*e38fd093SVladimir Zapolskiy 				ctrl->val, NULL);
791*e38fd093SVladimir Zapolskiy 		break;
792*e38fd093SVladimir Zapolskiy 	default:
793*e38fd093SVladimir Zapolskiy 		ret = -EINVAL;
794*e38fd093SVladimir Zapolskiy 		break;
795*e38fd093SVladimir Zapolskiy 	}
796*e38fd093SVladimir Zapolskiy 
797*e38fd093SVladimir Zapolskiy 	pm_runtime_put(s5kjn1->dev);
798*e38fd093SVladimir Zapolskiy 
799*e38fd093SVladimir Zapolskiy 	return ret;
800*e38fd093SVladimir Zapolskiy }
801*e38fd093SVladimir Zapolskiy 
802*e38fd093SVladimir Zapolskiy static const struct v4l2_ctrl_ops s5kjn1_ctrl_ops = {
803*e38fd093SVladimir Zapolskiy 	.s_ctrl = s5kjn1_set_ctrl,
804*e38fd093SVladimir Zapolskiy };
805*e38fd093SVladimir Zapolskiy 
806*e38fd093SVladimir Zapolskiy static inline u64 s5kjn1_freq_to_pixel_rate(const u64 freq)
807*e38fd093SVladimir Zapolskiy {
808*e38fd093SVladimir Zapolskiy 	return div_u64(freq * 2 * S5KJN1_DATA_LANES, 10);
809*e38fd093SVladimir Zapolskiy }
810*e38fd093SVladimir Zapolskiy 
811*e38fd093SVladimir Zapolskiy static int s5kjn1_init_controls(struct s5kjn1 *s5kjn1)
812*e38fd093SVladimir Zapolskiy {
813*e38fd093SVladimir Zapolskiy 	struct v4l2_ctrl_handler *ctrl_hdlr = &s5kjn1->ctrl_handler;
814*e38fd093SVladimir Zapolskiy 	const struct s5kjn1_mode *mode = s5kjn1->mode;
815*e38fd093SVladimir Zapolskiy 	s64 pixel_rate, hblank, vblank, exposure_max;
816*e38fd093SVladimir Zapolskiy 	struct v4l2_fwnode_device_properties props;
817*e38fd093SVladimir Zapolskiy 	int ret;
818*e38fd093SVladimir Zapolskiy 
819*e38fd093SVladimir Zapolskiy 	v4l2_ctrl_handler_init(ctrl_hdlr, 9);
820*e38fd093SVladimir Zapolskiy 
821*e38fd093SVladimir Zapolskiy 	s5kjn1->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &s5kjn1_ctrl_ops,
822*e38fd093SVladimir Zapolskiy 					V4L2_CID_LINK_FREQ,
823*e38fd093SVladimir Zapolskiy 					ARRAY_SIZE(s5kjn1_link_freq_menu) - 1,
824*e38fd093SVladimir Zapolskiy 					0, s5kjn1_link_freq_menu);
825*e38fd093SVladimir Zapolskiy 	if (s5kjn1->link_freq)
826*e38fd093SVladimir Zapolskiy 		s5kjn1->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
827*e38fd093SVladimir Zapolskiy 
828*e38fd093SVladimir Zapolskiy 	pixel_rate = s5kjn1_freq_to_pixel_rate(s5kjn1_link_freq_menu[0]);
829*e38fd093SVladimir Zapolskiy 	s5kjn1->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &s5kjn1_ctrl_ops,
830*e38fd093SVladimir Zapolskiy 					       V4L2_CID_PIXEL_RATE,
831*e38fd093SVladimir Zapolskiy 					       0, pixel_rate, 1, pixel_rate);
832*e38fd093SVladimir Zapolskiy 
833*e38fd093SVladimir Zapolskiy 	hblank = mode->hts - mode->width;
834*e38fd093SVladimir Zapolskiy 	s5kjn1->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &s5kjn1_ctrl_ops,
835*e38fd093SVladimir Zapolskiy 					   V4L2_CID_HBLANK, hblank,
836*e38fd093SVladimir Zapolskiy 					   hblank, 1, hblank);
837*e38fd093SVladimir Zapolskiy 	if (s5kjn1->hblank)
838*e38fd093SVladimir Zapolskiy 		s5kjn1->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
839*e38fd093SVladimir Zapolskiy 
840*e38fd093SVladimir Zapolskiy 	vblank = mode->vts - mode->height;
841*e38fd093SVladimir Zapolskiy 	s5kjn1->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &s5kjn1_ctrl_ops,
842*e38fd093SVladimir Zapolskiy 					   V4L2_CID_VBLANK, vblank,
843*e38fd093SVladimir Zapolskiy 					   S5KJN1_VTS_MAX - mode->height, 1,
844*e38fd093SVladimir Zapolskiy 					   vblank);
845*e38fd093SVladimir Zapolskiy 
846*e38fd093SVladimir Zapolskiy 	v4l2_ctrl_new_std(ctrl_hdlr, &s5kjn1_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
847*e38fd093SVladimir Zapolskiy 			  S5KJN1_AGAIN_MIN, S5KJN1_AGAIN_MAX,
848*e38fd093SVladimir Zapolskiy 			  S5KJN1_AGAIN_STEP, S5KJN1_AGAIN_DEFAULT);
849*e38fd093SVladimir Zapolskiy 
850*e38fd093SVladimir Zapolskiy 	exposure_max = mode->vts - mode->exposure_margin;
851*e38fd093SVladimir Zapolskiy 	s5kjn1->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &s5kjn1_ctrl_ops,
852*e38fd093SVladimir Zapolskiy 					     V4L2_CID_EXPOSURE,
853*e38fd093SVladimir Zapolskiy 					     S5KJN1_EXPOSURE_MIN,
854*e38fd093SVladimir Zapolskiy 					     exposure_max,
855*e38fd093SVladimir Zapolskiy 					     S5KJN1_EXPOSURE_STEP,
856*e38fd093SVladimir Zapolskiy 					     mode->exposure);
857*e38fd093SVladimir Zapolskiy 
858*e38fd093SVladimir Zapolskiy 	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &s5kjn1_ctrl_ops,
859*e38fd093SVladimir Zapolskiy 				     V4L2_CID_TEST_PATTERN,
860*e38fd093SVladimir Zapolskiy 				     ARRAY_SIZE(s5kjn1_test_pattern_menu) - 1,
861*e38fd093SVladimir Zapolskiy 				     0, 0, s5kjn1_test_pattern_menu);
862*e38fd093SVladimir Zapolskiy 
863*e38fd093SVladimir Zapolskiy 	s5kjn1->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &s5kjn1_ctrl_ops,
864*e38fd093SVladimir Zapolskiy 					  V4L2_CID_HFLIP, 0, 1, 1, 0);
865*e38fd093SVladimir Zapolskiy 	if (s5kjn1->hflip)
866*e38fd093SVladimir Zapolskiy 		s5kjn1->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
867*e38fd093SVladimir Zapolskiy 
868*e38fd093SVladimir Zapolskiy 	s5kjn1->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &s5kjn1_ctrl_ops,
869*e38fd093SVladimir Zapolskiy 					  V4L2_CID_VFLIP, 0, 1, 1, 0);
870*e38fd093SVladimir Zapolskiy 	if (s5kjn1->vflip)
871*e38fd093SVladimir Zapolskiy 		s5kjn1->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
872*e38fd093SVladimir Zapolskiy 
873*e38fd093SVladimir Zapolskiy 	ret = v4l2_fwnode_device_parse(s5kjn1->dev, &props);
874*e38fd093SVladimir Zapolskiy 	if (ret)
875*e38fd093SVladimir Zapolskiy 		goto error_free_hdlr;
876*e38fd093SVladimir Zapolskiy 
877*e38fd093SVladimir Zapolskiy 	ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &s5kjn1_ctrl_ops,
878*e38fd093SVladimir Zapolskiy 					      &props);
879*e38fd093SVladimir Zapolskiy 	if (ret)
880*e38fd093SVladimir Zapolskiy 		goto error_free_hdlr;
881*e38fd093SVladimir Zapolskiy 
882*e38fd093SVladimir Zapolskiy 	s5kjn1->sd.ctrl_handler = ctrl_hdlr;
883*e38fd093SVladimir Zapolskiy 
884*e38fd093SVladimir Zapolskiy 	return 0;
885*e38fd093SVladimir Zapolskiy 
886*e38fd093SVladimir Zapolskiy error_free_hdlr:
887*e38fd093SVladimir Zapolskiy 	v4l2_ctrl_handler_free(ctrl_hdlr);
888*e38fd093SVladimir Zapolskiy 
889*e38fd093SVladimir Zapolskiy 	return ret;
890*e38fd093SVladimir Zapolskiy }
891*e38fd093SVladimir Zapolskiy 
892*e38fd093SVladimir Zapolskiy static int s5kjn1_enable_streams(struct v4l2_subdev *sd,
893*e38fd093SVladimir Zapolskiy 				 struct v4l2_subdev_state *state, u32 pad,
894*e38fd093SVladimir Zapolskiy 				 u64 streams_mask)
895*e38fd093SVladimir Zapolskiy {
896*e38fd093SVladimir Zapolskiy 	struct s5kjn1 *s5kjn1 = to_s5kjn1(sd);
897*e38fd093SVladimir Zapolskiy 	const struct s5kjn1_reg_list *reg_list = &s5kjn1->mode->reg_list;
898*e38fd093SVladimir Zapolskiy 	int ret;
899*e38fd093SVladimir Zapolskiy 
900*e38fd093SVladimir Zapolskiy 	ret = pm_runtime_resume_and_get(s5kjn1->dev);
901*e38fd093SVladimir Zapolskiy 	if (ret)
902*e38fd093SVladimir Zapolskiy 		return ret;
903*e38fd093SVladimir Zapolskiy 
904*e38fd093SVladimir Zapolskiy 	/* Page pointer */
905*e38fd093SVladimir Zapolskiy 	cci_write(s5kjn1->regmap, CCI_REG16(0x6028), 0x4000, &ret);
906*e38fd093SVladimir Zapolskiy 
907*e38fd093SVladimir Zapolskiy 	/* Set version */
908*e38fd093SVladimir Zapolskiy 	cci_write(s5kjn1->regmap, CCI_REG16(0x0000), 0x0003, &ret);
909*e38fd093SVladimir Zapolskiy 	cci_write(s5kjn1->regmap, CCI_REG16(0x0000), S5KJN1_CHIP_ID, &ret);
910*e38fd093SVladimir Zapolskiy 	cci_write(s5kjn1->regmap, CCI_REG16(0x001e), 0x0007, &ret);
911*e38fd093SVladimir Zapolskiy 	cci_write(s5kjn1->regmap, CCI_REG16(0x6028), 0x4000, &ret);
912*e38fd093SVladimir Zapolskiy 	cci_write(s5kjn1->regmap, CCI_REG16(0x6010), 0x0001, &ret);
913*e38fd093SVladimir Zapolskiy 	if (ret)
914*e38fd093SVladimir Zapolskiy 		goto error;
915*e38fd093SVladimir Zapolskiy 
916*e38fd093SVladimir Zapolskiy 	usleep_range(5 * USEC_PER_MSEC, 6 * USEC_PER_MSEC);
917*e38fd093SVladimir Zapolskiy 
918*e38fd093SVladimir Zapolskiy 	cci_write(s5kjn1->regmap, CCI_REG16(0x6226), 0x0001, &ret);
919*e38fd093SVladimir Zapolskiy 	if (ret)
920*e38fd093SVladimir Zapolskiy 		goto error;
921*e38fd093SVladimir Zapolskiy 
922*e38fd093SVladimir Zapolskiy 	usleep_range(10 * USEC_PER_MSEC, 11 * USEC_PER_MSEC);
923*e38fd093SVladimir Zapolskiy 
924*e38fd093SVladimir Zapolskiy 	/* Sensor init settings */
925*e38fd093SVladimir Zapolskiy 	cci_multi_reg_write(s5kjn1->regmap, init_array_setting,
926*e38fd093SVladimir Zapolskiy 			    ARRAY_SIZE(init_array_setting), &ret);
927*e38fd093SVladimir Zapolskiy 	cci_multi_reg_write(s5kjn1->regmap, reg_list->regs,
928*e38fd093SVladimir Zapolskiy 			    reg_list->num_regs, &ret);
929*e38fd093SVladimir Zapolskiy 	if (ret)
930*e38fd093SVladimir Zapolskiy 		goto error;
931*e38fd093SVladimir Zapolskiy 
932*e38fd093SVladimir Zapolskiy 	ret = __v4l2_ctrl_handler_setup(s5kjn1->sd.ctrl_handler);
933*e38fd093SVladimir Zapolskiy 
934*e38fd093SVladimir Zapolskiy 	cci_write(s5kjn1->regmap, S5KJN1_REG_CTRL_MODE,
935*e38fd093SVladimir Zapolskiy 		  S5KJN1_MODE_STREAMING, &ret);
936*e38fd093SVladimir Zapolskiy 	if (ret)
937*e38fd093SVladimir Zapolskiy 		goto error;
938*e38fd093SVladimir Zapolskiy 
939*e38fd093SVladimir Zapolskiy 	return 0;
940*e38fd093SVladimir Zapolskiy 
941*e38fd093SVladimir Zapolskiy error:
942*e38fd093SVladimir Zapolskiy 	dev_err(s5kjn1->dev, "failed to start streaming: %d\n", ret);
943*e38fd093SVladimir Zapolskiy 	pm_runtime_put_autosuspend(s5kjn1->dev);
944*e38fd093SVladimir Zapolskiy 
945*e38fd093SVladimir Zapolskiy 	return ret;
946*e38fd093SVladimir Zapolskiy }
947*e38fd093SVladimir Zapolskiy 
948*e38fd093SVladimir Zapolskiy static int s5kjn1_disable_streams(struct v4l2_subdev *sd,
949*e38fd093SVladimir Zapolskiy 				  struct v4l2_subdev_state *state, u32 pad,
950*e38fd093SVladimir Zapolskiy 				  u64 streams_mask)
951*e38fd093SVladimir Zapolskiy {
952*e38fd093SVladimir Zapolskiy 	struct s5kjn1 *s5kjn1 = to_s5kjn1(sd);
953*e38fd093SVladimir Zapolskiy 	int ret;
954*e38fd093SVladimir Zapolskiy 
955*e38fd093SVladimir Zapolskiy 	ret = cci_write(s5kjn1->regmap, S5KJN1_REG_CTRL_MODE, 0x0, NULL);
956*e38fd093SVladimir Zapolskiy 	if (ret)
957*e38fd093SVladimir Zapolskiy 		dev_err(s5kjn1->dev, "failed to stop streaming: %d\n", ret);
958*e38fd093SVladimir Zapolskiy 
959*e38fd093SVladimir Zapolskiy 	pm_runtime_put_autosuspend(s5kjn1->dev);
960*e38fd093SVladimir Zapolskiy 
961*e38fd093SVladimir Zapolskiy 	return ret;
962*e38fd093SVladimir Zapolskiy }
963*e38fd093SVladimir Zapolskiy 
964*e38fd093SVladimir Zapolskiy static u32 s5kjn1_get_format_code(struct s5kjn1 *s5kjn1)
965*e38fd093SVladimir Zapolskiy {
966*e38fd093SVladimir Zapolskiy 	unsigned int i;
967*e38fd093SVladimir Zapolskiy 
968*e38fd093SVladimir Zapolskiy 	i = (s5kjn1->vflip->val ? 2 : 0) | (s5kjn1->hflip->val ? 1 : 0);
969*e38fd093SVladimir Zapolskiy 
970*e38fd093SVladimir Zapolskiy 	return s5kjn1_mbus_formats[i];
971*e38fd093SVladimir Zapolskiy }
972*e38fd093SVladimir Zapolskiy 
973*e38fd093SVladimir Zapolskiy static void s5kjn1_update_pad_format(struct s5kjn1 *s5kjn1,
974*e38fd093SVladimir Zapolskiy 				     const struct s5kjn1_mode *mode,
975*e38fd093SVladimir Zapolskiy 				     struct v4l2_mbus_framefmt *fmt)
976*e38fd093SVladimir Zapolskiy {
977*e38fd093SVladimir Zapolskiy 	fmt->code = s5kjn1_get_format_code(s5kjn1);
978*e38fd093SVladimir Zapolskiy 	fmt->width = mode->width;
979*e38fd093SVladimir Zapolskiy 	fmt->height = mode->height;
980*e38fd093SVladimir Zapolskiy 	fmt->field = V4L2_FIELD_NONE;
981*e38fd093SVladimir Zapolskiy 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
982*e38fd093SVladimir Zapolskiy 	fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
983*e38fd093SVladimir Zapolskiy 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
984*e38fd093SVladimir Zapolskiy 	fmt->xfer_func = V4L2_XFER_FUNC_NONE;
985*e38fd093SVladimir Zapolskiy }
986*e38fd093SVladimir Zapolskiy 
987*e38fd093SVladimir Zapolskiy static int s5kjn1_set_pad_format(struct v4l2_subdev *sd,
988*e38fd093SVladimir Zapolskiy 				 struct v4l2_subdev_state *state,
989*e38fd093SVladimir Zapolskiy 				 struct v4l2_subdev_format *fmt)
990*e38fd093SVladimir Zapolskiy {
991*e38fd093SVladimir Zapolskiy 	struct s5kjn1 *s5kjn1 = to_s5kjn1(sd);
992*e38fd093SVladimir Zapolskiy 	s64 hblank, vblank, exposure_max;
993*e38fd093SVladimir Zapolskiy 	const struct s5kjn1_mode *mode;
994*e38fd093SVladimir Zapolskiy 
995*e38fd093SVladimir Zapolskiy 	mode = v4l2_find_nearest_size(s5kjn1_supported_modes,
996*e38fd093SVladimir Zapolskiy 				      ARRAY_SIZE(s5kjn1_supported_modes),
997*e38fd093SVladimir Zapolskiy 				      width, height,
998*e38fd093SVladimir Zapolskiy 				      fmt->format.width, fmt->format.height);
999*e38fd093SVladimir Zapolskiy 
1000*e38fd093SVladimir Zapolskiy 	s5kjn1_update_pad_format(s5kjn1, mode, &fmt->format);
1001*e38fd093SVladimir Zapolskiy 
1002*e38fd093SVladimir Zapolskiy 	/* Format code could be updated with respect to flip controls */
1003*e38fd093SVladimir Zapolskiy 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY || s5kjn1->mode == mode)
1004*e38fd093SVladimir Zapolskiy 		goto set_format;
1005*e38fd093SVladimir Zapolskiy 
1006*e38fd093SVladimir Zapolskiy 	/* Update limits and set FPS and exposure to default values */
1007*e38fd093SVladimir Zapolskiy 	hblank = mode->hts - mode->width;
1008*e38fd093SVladimir Zapolskiy 	__v4l2_ctrl_modify_range(s5kjn1->hblank, hblank, hblank, 1, hblank);
1009*e38fd093SVladimir Zapolskiy 
1010*e38fd093SVladimir Zapolskiy 	vblank = mode->vts - mode->height;
1011*e38fd093SVladimir Zapolskiy 	__v4l2_ctrl_modify_range(s5kjn1->vblank, vblank,
1012*e38fd093SVladimir Zapolskiy 				 S5KJN1_VTS_MAX - mode->height, 1, vblank);
1013*e38fd093SVladimir Zapolskiy 	__v4l2_ctrl_s_ctrl(s5kjn1->vblank, vblank);
1014*e38fd093SVladimir Zapolskiy 
1015*e38fd093SVladimir Zapolskiy 	exposure_max = mode->vts - mode->exposure_margin;
1016*e38fd093SVladimir Zapolskiy 	__v4l2_ctrl_modify_range(s5kjn1->exposure, S5KJN1_EXPOSURE_MIN,
1017*e38fd093SVladimir Zapolskiy 				 exposure_max, S5KJN1_EXPOSURE_STEP,
1018*e38fd093SVladimir Zapolskiy 				 mode->exposure);
1019*e38fd093SVladimir Zapolskiy 	__v4l2_ctrl_s_ctrl(s5kjn1->exposure, mode->exposure);
1020*e38fd093SVladimir Zapolskiy 
1021*e38fd093SVladimir Zapolskiy 	if (s5kjn1->sd.ctrl_handler->error)
1022*e38fd093SVladimir Zapolskiy 		return s5kjn1->sd.ctrl_handler->error;
1023*e38fd093SVladimir Zapolskiy 
1024*e38fd093SVladimir Zapolskiy 	s5kjn1->mode = mode;
1025*e38fd093SVladimir Zapolskiy 
1026*e38fd093SVladimir Zapolskiy set_format:
1027*e38fd093SVladimir Zapolskiy 	*v4l2_subdev_state_get_format(state, 0) = fmt->format;
1028*e38fd093SVladimir Zapolskiy 
1029*e38fd093SVladimir Zapolskiy 	return 0;
1030*e38fd093SVladimir Zapolskiy }
1031*e38fd093SVladimir Zapolskiy 
1032*e38fd093SVladimir Zapolskiy static int s5kjn1_enum_mbus_code(struct v4l2_subdev *sd,
1033*e38fd093SVladimir Zapolskiy 				 struct v4l2_subdev_state *sd_state,
1034*e38fd093SVladimir Zapolskiy 				 struct v4l2_subdev_mbus_code_enum *code)
1035*e38fd093SVladimir Zapolskiy {
1036*e38fd093SVladimir Zapolskiy 	struct s5kjn1 *s5kjn1 = to_s5kjn1(sd);
1037*e38fd093SVladimir Zapolskiy 
1038*e38fd093SVladimir Zapolskiy 	/* Media bus code index is constant, but code formats are not */
1039*e38fd093SVladimir Zapolskiy 	if (code->index > 0)
1040*e38fd093SVladimir Zapolskiy 		return -EINVAL;
1041*e38fd093SVladimir Zapolskiy 
1042*e38fd093SVladimir Zapolskiy 	code->code = s5kjn1_get_format_code(s5kjn1);
1043*e38fd093SVladimir Zapolskiy 
1044*e38fd093SVladimir Zapolskiy 	return 0;
1045*e38fd093SVladimir Zapolskiy }
1046*e38fd093SVladimir Zapolskiy 
1047*e38fd093SVladimir Zapolskiy static int s5kjn1_enum_frame_size(struct v4l2_subdev *sd,
1048*e38fd093SVladimir Zapolskiy 				  struct v4l2_subdev_state *sd_state,
1049*e38fd093SVladimir Zapolskiy 				  struct v4l2_subdev_frame_size_enum *fse)
1050*e38fd093SVladimir Zapolskiy {
1051*e38fd093SVladimir Zapolskiy 	struct s5kjn1 *s5kjn1 = to_s5kjn1(sd);
1052*e38fd093SVladimir Zapolskiy 
1053*e38fd093SVladimir Zapolskiy 	if (fse->index >= ARRAY_SIZE(s5kjn1_supported_modes))
1054*e38fd093SVladimir Zapolskiy 		return -EINVAL;
1055*e38fd093SVladimir Zapolskiy 
1056*e38fd093SVladimir Zapolskiy 	if (fse->code != s5kjn1_get_format_code(s5kjn1))
1057*e38fd093SVladimir Zapolskiy 		return -EINVAL;
1058*e38fd093SVladimir Zapolskiy 
1059*e38fd093SVladimir Zapolskiy 	fse->min_width = s5kjn1_supported_modes[fse->index].width;
1060*e38fd093SVladimir Zapolskiy 	fse->max_width = fse->min_width;
1061*e38fd093SVladimir Zapolskiy 	fse->min_height = s5kjn1_supported_modes[fse->index].height;
1062*e38fd093SVladimir Zapolskiy 	fse->max_height = fse->min_height;
1063*e38fd093SVladimir Zapolskiy 
1064*e38fd093SVladimir Zapolskiy 	return 0;
1065*e38fd093SVladimir Zapolskiy }
1066*e38fd093SVladimir Zapolskiy 
1067*e38fd093SVladimir Zapolskiy static int s5kjn1_get_selection(struct v4l2_subdev *sd,
1068*e38fd093SVladimir Zapolskiy 				struct v4l2_subdev_state *sd_state,
1069*e38fd093SVladimir Zapolskiy 				struct v4l2_subdev_selection *sel)
1070*e38fd093SVladimir Zapolskiy {
1071*e38fd093SVladimir Zapolskiy 	struct s5kjn1 *s5kjn1 = to_s5kjn1(sd);
1072*e38fd093SVladimir Zapolskiy 
1073*e38fd093SVladimir Zapolskiy 	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
1074*e38fd093SVladimir Zapolskiy 		return -EINVAL;
1075*e38fd093SVladimir Zapolskiy 
1076*e38fd093SVladimir Zapolskiy 	switch (sel->target) {
1077*e38fd093SVladimir Zapolskiy 	case V4L2_SEL_TGT_CROP:
1078*e38fd093SVladimir Zapolskiy 	case V4L2_SEL_TGT_CROP_BOUNDS:
1079*e38fd093SVladimir Zapolskiy 		sel->r.left = 0;
1080*e38fd093SVladimir Zapolskiy 		sel->r.top = 0;
1081*e38fd093SVladimir Zapolskiy 		sel->r.width = s5kjn1->mode->width;
1082*e38fd093SVladimir Zapolskiy 		sel->r.height = s5kjn1->mode->width;
1083*e38fd093SVladimir Zapolskiy 		return 0;
1084*e38fd093SVladimir Zapolskiy 	default:
1085*e38fd093SVladimir Zapolskiy 		return -EINVAL;
1086*e38fd093SVladimir Zapolskiy 	}
1087*e38fd093SVladimir Zapolskiy 
1088*e38fd093SVladimir Zapolskiy 	return 0;
1089*e38fd093SVladimir Zapolskiy }
1090*e38fd093SVladimir Zapolskiy 
1091*e38fd093SVladimir Zapolskiy static int s5kjn1_init_state(struct v4l2_subdev *sd,
1092*e38fd093SVladimir Zapolskiy 			     struct v4l2_subdev_state *state)
1093*e38fd093SVladimir Zapolskiy {
1094*e38fd093SVladimir Zapolskiy 	struct s5kjn1 *s5kjn1 = to_s5kjn1(sd);
1095*e38fd093SVladimir Zapolskiy 	struct v4l2_subdev_format fmt = {
1096*e38fd093SVladimir Zapolskiy 		.which = V4L2_SUBDEV_FORMAT_TRY,
1097*e38fd093SVladimir Zapolskiy 		.pad = 0,
1098*e38fd093SVladimir Zapolskiy 		.format = {
1099*e38fd093SVladimir Zapolskiy 			/* Media bus code depends on current flip controls */
1100*e38fd093SVladimir Zapolskiy 			.width = s5kjn1->mode->width,
1101*e38fd093SVladimir Zapolskiy 			.height = s5kjn1->mode->height,
1102*e38fd093SVladimir Zapolskiy 		},
1103*e38fd093SVladimir Zapolskiy 	};
1104*e38fd093SVladimir Zapolskiy 
1105*e38fd093SVladimir Zapolskiy 	s5kjn1_set_pad_format(sd, state, &fmt);
1106*e38fd093SVladimir Zapolskiy 
1107*e38fd093SVladimir Zapolskiy 	return 0;
1108*e38fd093SVladimir Zapolskiy }
1109*e38fd093SVladimir Zapolskiy 
1110*e38fd093SVladimir Zapolskiy static const struct v4l2_subdev_video_ops s5kjn1_video_ops = {
1111*e38fd093SVladimir Zapolskiy 	.s_stream = v4l2_subdev_s_stream_helper,
1112*e38fd093SVladimir Zapolskiy };
1113*e38fd093SVladimir Zapolskiy 
1114*e38fd093SVladimir Zapolskiy static const struct v4l2_subdev_pad_ops s5kjn1_pad_ops = {
1115*e38fd093SVladimir Zapolskiy 	.set_fmt = s5kjn1_set_pad_format,
1116*e38fd093SVladimir Zapolskiy 	.get_fmt = v4l2_subdev_get_fmt,
1117*e38fd093SVladimir Zapolskiy 	.get_selection = s5kjn1_get_selection,
1118*e38fd093SVladimir Zapolskiy 	.enum_mbus_code = s5kjn1_enum_mbus_code,
1119*e38fd093SVladimir Zapolskiy 	.enum_frame_size = s5kjn1_enum_frame_size,
1120*e38fd093SVladimir Zapolskiy 	.enable_streams = s5kjn1_enable_streams,
1121*e38fd093SVladimir Zapolskiy 	.disable_streams = s5kjn1_disable_streams,
1122*e38fd093SVladimir Zapolskiy };
1123*e38fd093SVladimir Zapolskiy 
1124*e38fd093SVladimir Zapolskiy static const struct v4l2_subdev_ops s5kjn1_subdev_ops = {
1125*e38fd093SVladimir Zapolskiy 	.video = &s5kjn1_video_ops,
1126*e38fd093SVladimir Zapolskiy 	.pad = &s5kjn1_pad_ops,
1127*e38fd093SVladimir Zapolskiy };
1128*e38fd093SVladimir Zapolskiy 
1129*e38fd093SVladimir Zapolskiy static const struct v4l2_subdev_internal_ops s5kjn1_internal_ops = {
1130*e38fd093SVladimir Zapolskiy 	.init_state = s5kjn1_init_state,
1131*e38fd093SVladimir Zapolskiy };
1132*e38fd093SVladimir Zapolskiy 
1133*e38fd093SVladimir Zapolskiy static const struct media_entity_operations s5kjn1_subdev_entity_ops = {
1134*e38fd093SVladimir Zapolskiy 	.link_validate = v4l2_subdev_link_validate,
1135*e38fd093SVladimir Zapolskiy };
1136*e38fd093SVladimir Zapolskiy 
1137*e38fd093SVladimir Zapolskiy static int s5kjn1_identify_sensor(struct s5kjn1 *s5kjn1)
1138*e38fd093SVladimir Zapolskiy {
1139*e38fd093SVladimir Zapolskiy 	u64 val;
1140*e38fd093SVladimir Zapolskiy 	int ret;
1141*e38fd093SVladimir Zapolskiy 
1142*e38fd093SVladimir Zapolskiy 	ret = cci_read(s5kjn1->regmap, S5KJN1_REG_CHIP_ID, &val, NULL);
1143*e38fd093SVladimir Zapolskiy 	if (ret) {
1144*e38fd093SVladimir Zapolskiy 		dev_err(s5kjn1->dev, "failed to read chip id: %d\n", ret);
1145*e38fd093SVladimir Zapolskiy 		return ret;
1146*e38fd093SVladimir Zapolskiy 	}
1147*e38fd093SVladimir Zapolskiy 
1148*e38fd093SVladimir Zapolskiy 	if (val != S5KJN1_CHIP_ID) {
1149*e38fd093SVladimir Zapolskiy 		dev_err(s5kjn1->dev, "chip id mismatch: %x!=%llx\n",
1150*e38fd093SVladimir Zapolskiy 			S5KJN1_CHIP_ID, val);
1151*e38fd093SVladimir Zapolskiy 		return -ENODEV;
1152*e38fd093SVladimir Zapolskiy 	}
1153*e38fd093SVladimir Zapolskiy 
1154*e38fd093SVladimir Zapolskiy 	return 0;
1155*e38fd093SVladimir Zapolskiy }
1156*e38fd093SVladimir Zapolskiy 
1157*e38fd093SVladimir Zapolskiy static int s5kjn1_check_hwcfg(struct s5kjn1 *s5kjn1)
1158*e38fd093SVladimir Zapolskiy {
1159*e38fd093SVladimir Zapolskiy 	struct fwnode_handle *fwnode = dev_fwnode(s5kjn1->dev), *ep;
1160*e38fd093SVladimir Zapolskiy 	struct v4l2_fwnode_endpoint bus_cfg = {
1161*e38fd093SVladimir Zapolskiy 		.bus = {
1162*e38fd093SVladimir Zapolskiy 			.mipi_csi2 = {
1163*e38fd093SVladimir Zapolskiy 				.num_data_lanes = S5KJN1_DATA_LANES,
1164*e38fd093SVladimir Zapolskiy 			},
1165*e38fd093SVladimir Zapolskiy 		},
1166*e38fd093SVladimir Zapolskiy 		.bus_type = V4L2_MBUS_CSI2_DPHY,
1167*e38fd093SVladimir Zapolskiy 	};
1168*e38fd093SVladimir Zapolskiy 	unsigned long freq_bitmap;
1169*e38fd093SVladimir Zapolskiy 	int ret;
1170*e38fd093SVladimir Zapolskiy 
1171*e38fd093SVladimir Zapolskiy 	if (!fwnode)
1172*e38fd093SVladimir Zapolskiy 		return -ENODEV;
1173*e38fd093SVladimir Zapolskiy 
1174*e38fd093SVladimir Zapolskiy 	ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
1175*e38fd093SVladimir Zapolskiy 	if (!ep)
1176*e38fd093SVladimir Zapolskiy 		return -EINVAL;
1177*e38fd093SVladimir Zapolskiy 
1178*e38fd093SVladimir Zapolskiy 	ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
1179*e38fd093SVladimir Zapolskiy 	fwnode_handle_put(ep);
1180*e38fd093SVladimir Zapolskiy 	if (ret)
1181*e38fd093SVladimir Zapolskiy 		return ret;
1182*e38fd093SVladimir Zapolskiy 
1183*e38fd093SVladimir Zapolskiy 	if (bus_cfg.bus.mipi_csi2.num_data_lanes != S5KJN1_DATA_LANES) {
1184*e38fd093SVladimir Zapolskiy 		dev_err(s5kjn1->dev, "Invalid number of data lanes: %u\n",
1185*e38fd093SVladimir Zapolskiy 			bus_cfg.bus.mipi_csi2.num_data_lanes);
1186*e38fd093SVladimir Zapolskiy 		ret = -EINVAL;
1187*e38fd093SVladimir Zapolskiy 		goto endpoint_free;
1188*e38fd093SVladimir Zapolskiy 	}
1189*e38fd093SVladimir Zapolskiy 
1190*e38fd093SVladimir Zapolskiy 	ret = v4l2_link_freq_to_bitmap(s5kjn1->dev, bus_cfg.link_frequencies,
1191*e38fd093SVladimir Zapolskiy 				       bus_cfg.nr_of_link_frequencies,
1192*e38fd093SVladimir Zapolskiy 				       s5kjn1_link_freq_menu,
1193*e38fd093SVladimir Zapolskiy 				       ARRAY_SIZE(s5kjn1_link_freq_menu),
1194*e38fd093SVladimir Zapolskiy 				       &freq_bitmap);
1195*e38fd093SVladimir Zapolskiy 
1196*e38fd093SVladimir Zapolskiy endpoint_free:
1197*e38fd093SVladimir Zapolskiy 	v4l2_fwnode_endpoint_free(&bus_cfg);
1198*e38fd093SVladimir Zapolskiy 
1199*e38fd093SVladimir Zapolskiy 	return ret;
1200*e38fd093SVladimir Zapolskiy }
1201*e38fd093SVladimir Zapolskiy 
1202*e38fd093SVladimir Zapolskiy static int s5kjn1_power_on(struct device *dev)
1203*e38fd093SVladimir Zapolskiy {
1204*e38fd093SVladimir Zapolskiy 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
1205*e38fd093SVladimir Zapolskiy 	struct s5kjn1 *s5kjn1 = to_s5kjn1(sd);
1206*e38fd093SVladimir Zapolskiy 	int ret;
1207*e38fd093SVladimir Zapolskiy 
1208*e38fd093SVladimir Zapolskiy 	if (s5kjn1->vddd) {
1209*e38fd093SVladimir Zapolskiy 		ret = regulator_enable(s5kjn1->vddd);
1210*e38fd093SVladimir Zapolskiy 		if (ret)
1211*e38fd093SVladimir Zapolskiy 			return ret;
1212*e38fd093SVladimir Zapolskiy 
1213*e38fd093SVladimir Zapolskiy 		usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
1214*e38fd093SVladimir Zapolskiy 	}
1215*e38fd093SVladimir Zapolskiy 
1216*e38fd093SVladimir Zapolskiy 	if (s5kjn1->vdda) {
1217*e38fd093SVladimir Zapolskiy 		ret = regulator_enable(s5kjn1->vdda);
1218*e38fd093SVladimir Zapolskiy 		if (ret)
1219*e38fd093SVladimir Zapolskiy 			goto disable_vddd;
1220*e38fd093SVladimir Zapolskiy 	}
1221*e38fd093SVladimir Zapolskiy 
1222*e38fd093SVladimir Zapolskiy 	if (s5kjn1->vddio) {
1223*e38fd093SVladimir Zapolskiy 		ret = regulator_enable(s5kjn1->vddio);
1224*e38fd093SVladimir Zapolskiy 		if (ret)
1225*e38fd093SVladimir Zapolskiy 			goto disable_vdda;
1226*e38fd093SVladimir Zapolskiy 	}
1227*e38fd093SVladimir Zapolskiy 
1228*e38fd093SVladimir Zapolskiy 	if (s5kjn1->afvdd) {
1229*e38fd093SVladimir Zapolskiy 		ret = regulator_enable(s5kjn1->afvdd);
1230*e38fd093SVladimir Zapolskiy 		if (ret)
1231*e38fd093SVladimir Zapolskiy 			goto disable_vddio;
1232*e38fd093SVladimir Zapolskiy 	}
1233*e38fd093SVladimir Zapolskiy 
1234*e38fd093SVladimir Zapolskiy 	ret = clk_prepare_enable(s5kjn1->mclk);
1235*e38fd093SVladimir Zapolskiy 	if (ret)
1236*e38fd093SVladimir Zapolskiy 		goto disable_regulators;
1237*e38fd093SVladimir Zapolskiy 
1238*e38fd093SVladimir Zapolskiy 	gpiod_set_value_cansleep(s5kjn1->reset_gpio, 0);
1239*e38fd093SVladimir Zapolskiy 	usleep_range(10 * USEC_PER_MSEC, 15 * USEC_PER_MSEC);
1240*e38fd093SVladimir Zapolskiy 
1241*e38fd093SVladimir Zapolskiy 	return 0;
1242*e38fd093SVladimir Zapolskiy 
1243*e38fd093SVladimir Zapolskiy disable_regulators:
1244*e38fd093SVladimir Zapolskiy 	if (s5kjn1->afvdd)
1245*e38fd093SVladimir Zapolskiy 		regulator_disable(s5kjn1->afvdd);
1246*e38fd093SVladimir Zapolskiy 
1247*e38fd093SVladimir Zapolskiy disable_vddio:
1248*e38fd093SVladimir Zapolskiy 	if (s5kjn1->vddio)
1249*e38fd093SVladimir Zapolskiy 		regulator_disable(s5kjn1->vddio);
1250*e38fd093SVladimir Zapolskiy 
1251*e38fd093SVladimir Zapolskiy disable_vdda:
1252*e38fd093SVladimir Zapolskiy 	if (s5kjn1->vdda)
1253*e38fd093SVladimir Zapolskiy 		regulator_disable(s5kjn1->vdda);
1254*e38fd093SVladimir Zapolskiy 
1255*e38fd093SVladimir Zapolskiy disable_vddd:
1256*e38fd093SVladimir Zapolskiy 	if (s5kjn1->vddd) {
1257*e38fd093SVladimir Zapolskiy 		usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
1258*e38fd093SVladimir Zapolskiy 		regulator_disable(s5kjn1->vddd);
1259*e38fd093SVladimir Zapolskiy 	}
1260*e38fd093SVladimir Zapolskiy 
1261*e38fd093SVladimir Zapolskiy 	return ret;
1262*e38fd093SVladimir Zapolskiy }
1263*e38fd093SVladimir Zapolskiy 
1264*e38fd093SVladimir Zapolskiy static int s5kjn1_power_off(struct device *dev)
1265*e38fd093SVladimir Zapolskiy {
1266*e38fd093SVladimir Zapolskiy 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
1267*e38fd093SVladimir Zapolskiy 	struct s5kjn1 *s5kjn1 = to_s5kjn1(sd);
1268*e38fd093SVladimir Zapolskiy 
1269*e38fd093SVladimir Zapolskiy 	gpiod_set_value_cansleep(s5kjn1->reset_gpio, 1);
1270*e38fd093SVladimir Zapolskiy 
1271*e38fd093SVladimir Zapolskiy 	clk_disable_unprepare(s5kjn1->mclk);
1272*e38fd093SVladimir Zapolskiy 
1273*e38fd093SVladimir Zapolskiy 	if (s5kjn1->afvdd)
1274*e38fd093SVladimir Zapolskiy 		regulator_disable(s5kjn1->afvdd);
1275*e38fd093SVladimir Zapolskiy 
1276*e38fd093SVladimir Zapolskiy 	if (s5kjn1->vddio)
1277*e38fd093SVladimir Zapolskiy 		regulator_disable(s5kjn1->vddio);
1278*e38fd093SVladimir Zapolskiy 
1279*e38fd093SVladimir Zapolskiy 	if (s5kjn1->vdda)
1280*e38fd093SVladimir Zapolskiy 		regulator_disable(s5kjn1->vdda);
1281*e38fd093SVladimir Zapolskiy 
1282*e38fd093SVladimir Zapolskiy 	if (s5kjn1->vddd) {
1283*e38fd093SVladimir Zapolskiy 		usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
1284*e38fd093SVladimir Zapolskiy 		regulator_disable(s5kjn1->vddd);
1285*e38fd093SVladimir Zapolskiy 	}
1286*e38fd093SVladimir Zapolskiy 
1287*e38fd093SVladimir Zapolskiy 	return 0;
1288*e38fd093SVladimir Zapolskiy }
1289*e38fd093SVladimir Zapolskiy 
1290*e38fd093SVladimir Zapolskiy static int s5kjn1_probe(struct i2c_client *client)
1291*e38fd093SVladimir Zapolskiy {
1292*e38fd093SVladimir Zapolskiy 	struct s5kjn1 *s5kjn1;
1293*e38fd093SVladimir Zapolskiy 	unsigned long freq;
1294*e38fd093SVladimir Zapolskiy 	int ret;
1295*e38fd093SVladimir Zapolskiy 
1296*e38fd093SVladimir Zapolskiy 	s5kjn1 = devm_kzalloc(&client->dev, sizeof(*s5kjn1), GFP_KERNEL);
1297*e38fd093SVladimir Zapolskiy 	if (!s5kjn1)
1298*e38fd093SVladimir Zapolskiy 		return -ENOMEM;
1299*e38fd093SVladimir Zapolskiy 
1300*e38fd093SVladimir Zapolskiy 	s5kjn1->dev = &client->dev;
1301*e38fd093SVladimir Zapolskiy 	v4l2_i2c_subdev_init(&s5kjn1->sd, client, &s5kjn1_subdev_ops);
1302*e38fd093SVladimir Zapolskiy 
1303*e38fd093SVladimir Zapolskiy 	s5kjn1->regmap = devm_cci_regmap_init_i2c(client, 16);
1304*e38fd093SVladimir Zapolskiy 	if (IS_ERR(s5kjn1->regmap))
1305*e38fd093SVladimir Zapolskiy 		return dev_err_probe(s5kjn1->dev, PTR_ERR(s5kjn1->regmap),
1306*e38fd093SVladimir Zapolskiy 				     "failed to init CCI\n");
1307*e38fd093SVladimir Zapolskiy 
1308*e38fd093SVladimir Zapolskiy 	s5kjn1->mclk = devm_v4l2_sensor_clk_get(s5kjn1->dev, NULL);
1309*e38fd093SVladimir Zapolskiy 	if (IS_ERR(s5kjn1->mclk))
1310*e38fd093SVladimir Zapolskiy 		return dev_err_probe(s5kjn1->dev, PTR_ERR(s5kjn1->mclk),
1311*e38fd093SVladimir Zapolskiy 				     "failed to get MCLK clock\n");
1312*e38fd093SVladimir Zapolskiy 
1313*e38fd093SVladimir Zapolskiy 	freq = clk_get_rate(s5kjn1->mclk);
1314*e38fd093SVladimir Zapolskiy 	if (freq != S5KJN1_MCLK_FREQ_24MHZ)
1315*e38fd093SVladimir Zapolskiy 		return dev_err_probe(s5kjn1->dev, -EINVAL,
1316*e38fd093SVladimir Zapolskiy 				     "MCLK clock frequency %lu is not supported\n",
1317*e38fd093SVladimir Zapolskiy 				     freq);
1318*e38fd093SVladimir Zapolskiy 
1319*e38fd093SVladimir Zapolskiy 	ret = s5kjn1_check_hwcfg(s5kjn1);
1320*e38fd093SVladimir Zapolskiy 	if (ret)
1321*e38fd093SVladimir Zapolskiy 		return dev_err_probe(s5kjn1->dev, ret,
1322*e38fd093SVladimir Zapolskiy 				     "failed to check HW configuration\n");
1323*e38fd093SVladimir Zapolskiy 
1324*e38fd093SVladimir Zapolskiy 	s5kjn1->reset_gpio = devm_gpiod_get_optional(s5kjn1->dev, "reset",
1325*e38fd093SVladimir Zapolskiy 						     GPIOD_OUT_HIGH);
1326*e38fd093SVladimir Zapolskiy 	if (IS_ERR(s5kjn1->reset_gpio))
1327*e38fd093SVladimir Zapolskiy 		return dev_err_probe(s5kjn1->dev, PTR_ERR(s5kjn1->reset_gpio),
1328*e38fd093SVladimir Zapolskiy 				     "cannot get reset GPIO\n");
1329*e38fd093SVladimir Zapolskiy 
1330*e38fd093SVladimir Zapolskiy 	s5kjn1->afvdd = devm_regulator_get_optional(s5kjn1->dev, "afvdd");
1331*e38fd093SVladimir Zapolskiy 	if (IS_ERR(s5kjn1->afvdd)) {
1332*e38fd093SVladimir Zapolskiy 		ret = PTR_ERR(s5kjn1->afvdd);
1333*e38fd093SVladimir Zapolskiy 		if (ret != -ENODEV) {
1334*e38fd093SVladimir Zapolskiy 			return dev_err_probe(s5kjn1->dev, ret,
1335*e38fd093SVladimir Zapolskiy 					"Failed to get 'afvdd' regulator\n");
1336*e38fd093SVladimir Zapolskiy 		}
1337*e38fd093SVladimir Zapolskiy 
1338*e38fd093SVladimir Zapolskiy 		s5kjn1->afvdd = NULL;
1339*e38fd093SVladimir Zapolskiy 	}
1340*e38fd093SVladimir Zapolskiy 
1341*e38fd093SVladimir Zapolskiy 	s5kjn1->vdda = devm_regulator_get_optional(s5kjn1->dev, "vdda");
1342*e38fd093SVladimir Zapolskiy 	if (IS_ERR(s5kjn1->vdda)) {
1343*e38fd093SVladimir Zapolskiy 		ret = PTR_ERR(s5kjn1->vdda);
1344*e38fd093SVladimir Zapolskiy 		if (ret != -ENODEV) {
1345*e38fd093SVladimir Zapolskiy 			return dev_err_probe(s5kjn1->dev, ret,
1346*e38fd093SVladimir Zapolskiy 					"Failed to get 'vdda' regulator\n");
1347*e38fd093SVladimir Zapolskiy 		}
1348*e38fd093SVladimir Zapolskiy 
1349*e38fd093SVladimir Zapolskiy 		s5kjn1->vdda = NULL;
1350*e38fd093SVladimir Zapolskiy 	}
1351*e38fd093SVladimir Zapolskiy 
1352*e38fd093SVladimir Zapolskiy 	s5kjn1->vddd = devm_regulator_get_optional(s5kjn1->dev, "vddd");
1353*e38fd093SVladimir Zapolskiy 	if (IS_ERR(s5kjn1->vddd)) {
1354*e38fd093SVladimir Zapolskiy 		ret = PTR_ERR(s5kjn1->vddd);
1355*e38fd093SVladimir Zapolskiy 		if (ret != -ENODEV) {
1356*e38fd093SVladimir Zapolskiy 			return dev_err_probe(s5kjn1->dev, ret,
1357*e38fd093SVladimir Zapolskiy 					"Failed to get 'vddd' regulator\n");
1358*e38fd093SVladimir Zapolskiy 		}
1359*e38fd093SVladimir Zapolskiy 
1360*e38fd093SVladimir Zapolskiy 		s5kjn1->vddd = NULL;
1361*e38fd093SVladimir Zapolskiy 	}
1362*e38fd093SVladimir Zapolskiy 
1363*e38fd093SVladimir Zapolskiy 	s5kjn1->vddio = devm_regulator_get_optional(s5kjn1->dev, "vddio");
1364*e38fd093SVladimir Zapolskiy 	if (IS_ERR(s5kjn1->vddio)) {
1365*e38fd093SVladimir Zapolskiy 		ret = PTR_ERR(s5kjn1->vddio);
1366*e38fd093SVladimir Zapolskiy 		if (ret != -ENODEV) {
1367*e38fd093SVladimir Zapolskiy 			return dev_err_probe(s5kjn1->dev, ret,
1368*e38fd093SVladimir Zapolskiy 					"Failed to get 'vddio' regulator\n");
1369*e38fd093SVladimir Zapolskiy 		}
1370*e38fd093SVladimir Zapolskiy 
1371*e38fd093SVladimir Zapolskiy 		s5kjn1->vddio = NULL;
1372*e38fd093SVladimir Zapolskiy 	}
1373*e38fd093SVladimir Zapolskiy 
1374*e38fd093SVladimir Zapolskiy 	/* The sensor must be powered on to read the CHIP_ID register */
1375*e38fd093SVladimir Zapolskiy 	ret = s5kjn1_power_on(s5kjn1->dev);
1376*e38fd093SVladimir Zapolskiy 	if (ret)
1377*e38fd093SVladimir Zapolskiy 		return ret;
1378*e38fd093SVladimir Zapolskiy 
1379*e38fd093SVladimir Zapolskiy 	ret = s5kjn1_identify_sensor(s5kjn1);
1380*e38fd093SVladimir Zapolskiy 	if (ret) {
1381*e38fd093SVladimir Zapolskiy 		dev_err_probe(s5kjn1->dev, ret, "failed to find sensor\n");
1382*e38fd093SVladimir Zapolskiy 		goto power_off;
1383*e38fd093SVladimir Zapolskiy 	}
1384*e38fd093SVladimir Zapolskiy 
1385*e38fd093SVladimir Zapolskiy 	s5kjn1->mode = &s5kjn1_supported_modes[0];
1386*e38fd093SVladimir Zapolskiy 	ret = s5kjn1_init_controls(s5kjn1);
1387*e38fd093SVladimir Zapolskiy 	if (ret) {
1388*e38fd093SVladimir Zapolskiy 		dev_err_probe(s5kjn1->dev, ret, "failed to init controls\n");
1389*e38fd093SVladimir Zapolskiy 		goto power_off;
1390*e38fd093SVladimir Zapolskiy 	}
1391*e38fd093SVladimir Zapolskiy 
1392*e38fd093SVladimir Zapolskiy 	s5kjn1->sd.state_lock = s5kjn1->ctrl_handler.lock;
1393*e38fd093SVladimir Zapolskiy 	s5kjn1->sd.internal_ops = &s5kjn1_internal_ops;
1394*e38fd093SVladimir Zapolskiy 	s5kjn1->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1395*e38fd093SVladimir Zapolskiy 	s5kjn1->sd.entity.ops = &s5kjn1_subdev_entity_ops;
1396*e38fd093SVladimir Zapolskiy 	s5kjn1->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
1397*e38fd093SVladimir Zapolskiy 	s5kjn1->pad.flags = MEDIA_PAD_FL_SOURCE;
1398*e38fd093SVladimir Zapolskiy 
1399*e38fd093SVladimir Zapolskiy 	ret = media_entity_pads_init(&s5kjn1->sd.entity, 1, &s5kjn1->pad);
1400*e38fd093SVladimir Zapolskiy 	if (ret) {
1401*e38fd093SVladimir Zapolskiy 		dev_err_probe(s5kjn1->dev, ret,
1402*e38fd093SVladimir Zapolskiy 			      "failed to init media entity pads\n");
1403*e38fd093SVladimir Zapolskiy 		goto v4l2_ctrl_handler_free;
1404*e38fd093SVladimir Zapolskiy 	}
1405*e38fd093SVladimir Zapolskiy 
1406*e38fd093SVladimir Zapolskiy 	ret = v4l2_subdev_init_finalize(&s5kjn1->sd);
1407*e38fd093SVladimir Zapolskiy 	if (ret < 0) {
1408*e38fd093SVladimir Zapolskiy 		dev_err_probe(s5kjn1->dev, ret,
1409*e38fd093SVladimir Zapolskiy 			      "failed to init media entity pads\n");
1410*e38fd093SVladimir Zapolskiy 		goto media_entity_cleanup;
1411*e38fd093SVladimir Zapolskiy 	}
1412*e38fd093SVladimir Zapolskiy 
1413*e38fd093SVladimir Zapolskiy 	pm_runtime_set_active(s5kjn1->dev);
1414*e38fd093SVladimir Zapolskiy 	pm_runtime_enable(s5kjn1->dev);
1415*e38fd093SVladimir Zapolskiy 
1416*e38fd093SVladimir Zapolskiy 	ret = v4l2_async_register_subdev_sensor(&s5kjn1->sd);
1417*e38fd093SVladimir Zapolskiy 	if (ret < 0) {
1418*e38fd093SVladimir Zapolskiy 		dev_err_probe(s5kjn1->dev, ret,
1419*e38fd093SVladimir Zapolskiy 			      "failed to register V4L2 subdev\n");
1420*e38fd093SVladimir Zapolskiy 		goto subdev_cleanup;
1421*e38fd093SVladimir Zapolskiy 	}
1422*e38fd093SVladimir Zapolskiy 
1423*e38fd093SVladimir Zapolskiy 	pm_runtime_set_autosuspend_delay(s5kjn1->dev, 1000);
1424*e38fd093SVladimir Zapolskiy 	pm_runtime_use_autosuspend(s5kjn1->dev);
1425*e38fd093SVladimir Zapolskiy 	pm_runtime_idle(s5kjn1->dev);
1426*e38fd093SVladimir Zapolskiy 
1427*e38fd093SVladimir Zapolskiy 	return 0;
1428*e38fd093SVladimir Zapolskiy 
1429*e38fd093SVladimir Zapolskiy subdev_cleanup:
1430*e38fd093SVladimir Zapolskiy 	v4l2_subdev_cleanup(&s5kjn1->sd);
1431*e38fd093SVladimir Zapolskiy 	pm_runtime_disable(s5kjn1->dev);
1432*e38fd093SVladimir Zapolskiy 	pm_runtime_set_suspended(s5kjn1->dev);
1433*e38fd093SVladimir Zapolskiy 
1434*e38fd093SVladimir Zapolskiy media_entity_cleanup:
1435*e38fd093SVladimir Zapolskiy 	media_entity_cleanup(&s5kjn1->sd.entity);
1436*e38fd093SVladimir Zapolskiy 
1437*e38fd093SVladimir Zapolskiy v4l2_ctrl_handler_free:
1438*e38fd093SVladimir Zapolskiy 	v4l2_ctrl_handler_free(s5kjn1->sd.ctrl_handler);
1439*e38fd093SVladimir Zapolskiy 
1440*e38fd093SVladimir Zapolskiy power_off:
1441*e38fd093SVladimir Zapolskiy 	s5kjn1_power_off(s5kjn1->dev);
1442*e38fd093SVladimir Zapolskiy 
1443*e38fd093SVladimir Zapolskiy 	return ret;
1444*e38fd093SVladimir Zapolskiy }
1445*e38fd093SVladimir Zapolskiy 
1446*e38fd093SVladimir Zapolskiy static void s5kjn1_remove(struct i2c_client *client)
1447*e38fd093SVladimir Zapolskiy {
1448*e38fd093SVladimir Zapolskiy 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1449*e38fd093SVladimir Zapolskiy 	struct s5kjn1 *s5kjn1 = to_s5kjn1(sd);
1450*e38fd093SVladimir Zapolskiy 
1451*e38fd093SVladimir Zapolskiy 	v4l2_async_unregister_subdev(sd);
1452*e38fd093SVladimir Zapolskiy 	v4l2_subdev_cleanup(sd);
1453*e38fd093SVladimir Zapolskiy 	media_entity_cleanup(&sd->entity);
1454*e38fd093SVladimir Zapolskiy 	v4l2_ctrl_handler_free(sd->ctrl_handler);
1455*e38fd093SVladimir Zapolskiy 	pm_runtime_disable(s5kjn1->dev);
1456*e38fd093SVladimir Zapolskiy 
1457*e38fd093SVladimir Zapolskiy 	if (!pm_runtime_status_suspended(s5kjn1->dev)) {
1458*e38fd093SVladimir Zapolskiy 		s5kjn1_power_off(s5kjn1->dev);
1459*e38fd093SVladimir Zapolskiy 		pm_runtime_set_suspended(s5kjn1->dev);
1460*e38fd093SVladimir Zapolskiy 	}
1461*e38fd093SVladimir Zapolskiy }
1462*e38fd093SVladimir Zapolskiy 
1463*e38fd093SVladimir Zapolskiy static const struct dev_pm_ops s5kjn1_pm_ops = {
1464*e38fd093SVladimir Zapolskiy 	SET_RUNTIME_PM_OPS(s5kjn1_power_off, s5kjn1_power_on, NULL)
1465*e38fd093SVladimir Zapolskiy };
1466*e38fd093SVladimir Zapolskiy 
1467*e38fd093SVladimir Zapolskiy static const struct of_device_id s5kjn1_of_match[] = {
1468*e38fd093SVladimir Zapolskiy 	{ .compatible = "samsung,s5kjn1" },
1469*e38fd093SVladimir Zapolskiy 	{ /* sentinel */ }
1470*e38fd093SVladimir Zapolskiy };
1471*e38fd093SVladimir Zapolskiy MODULE_DEVICE_TABLE(of, s5kjn1_of_match);
1472*e38fd093SVladimir Zapolskiy 
1473*e38fd093SVladimir Zapolskiy static struct i2c_driver s5kjn1_i2c_driver = {
1474*e38fd093SVladimir Zapolskiy 	.driver = {
1475*e38fd093SVladimir Zapolskiy 		.name = "s5kjn1",
1476*e38fd093SVladimir Zapolskiy 		.pm = &s5kjn1_pm_ops,
1477*e38fd093SVladimir Zapolskiy 		.of_match_table = s5kjn1_of_match,
1478*e38fd093SVladimir Zapolskiy 	},
1479*e38fd093SVladimir Zapolskiy 	.probe = s5kjn1_probe,
1480*e38fd093SVladimir Zapolskiy 	.remove = s5kjn1_remove,
1481*e38fd093SVladimir Zapolskiy };
1482*e38fd093SVladimir Zapolskiy 
1483*e38fd093SVladimir Zapolskiy module_i2c_driver(s5kjn1_i2c_driver);
1484*e38fd093SVladimir Zapolskiy 
1485*e38fd093SVladimir Zapolskiy MODULE_AUTHOR("Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>");
1486*e38fd093SVladimir Zapolskiy MODULE_DESCRIPTION("Samsung S5KJN1 image sensor driver");
1487*e38fd093SVladimir Zapolskiy MODULE_LICENSE("GPL");
1488