xref: /OK3568_Linux_fs/kernel/drivers/media/i2c/vs6624.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * vs6624.c ST VS6624 CMOS image sensor driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2011 Analog Devices Inc.
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/delay.h>
9*4882a593Smuzhiyun #include <linux/errno.h>
10*4882a593Smuzhiyun #include <linux/gpio.h>
11*4882a593Smuzhiyun #include <linux/i2c.h>
12*4882a593Smuzhiyun #include <linux/init.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/slab.h>
15*4882a593Smuzhiyun #include <linux/types.h>
16*4882a593Smuzhiyun #include <linux/videodev2.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <media/v4l2-ctrls.h>
19*4882a593Smuzhiyun #include <media/v4l2-device.h>
20*4882a593Smuzhiyun #include <media/v4l2-mediabus.h>
21*4882a593Smuzhiyun #include <media/v4l2-image-sizes.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #include "vs6624_regs.h"
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #define MAX_FRAME_RATE  30
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun struct vs6624 {
28*4882a593Smuzhiyun 	struct v4l2_subdev sd;
29*4882a593Smuzhiyun 	struct v4l2_ctrl_handler hdl;
30*4882a593Smuzhiyun 	struct v4l2_fract frame_rate;
31*4882a593Smuzhiyun 	struct v4l2_mbus_framefmt fmt;
32*4882a593Smuzhiyun 	unsigned ce_pin;
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun static const struct vs6624_format {
36*4882a593Smuzhiyun 	u32 mbus_code;
37*4882a593Smuzhiyun 	enum v4l2_colorspace colorspace;
38*4882a593Smuzhiyun } vs6624_formats[] = {
39*4882a593Smuzhiyun 	{
40*4882a593Smuzhiyun 		.mbus_code      = MEDIA_BUS_FMT_UYVY8_2X8,
41*4882a593Smuzhiyun 		.colorspace     = V4L2_COLORSPACE_JPEG,
42*4882a593Smuzhiyun 	},
43*4882a593Smuzhiyun 	{
44*4882a593Smuzhiyun 		.mbus_code      = MEDIA_BUS_FMT_YUYV8_2X8,
45*4882a593Smuzhiyun 		.colorspace     = V4L2_COLORSPACE_JPEG,
46*4882a593Smuzhiyun 	},
47*4882a593Smuzhiyun 	{
48*4882a593Smuzhiyun 		.mbus_code      = MEDIA_BUS_FMT_RGB565_2X8_LE,
49*4882a593Smuzhiyun 		.colorspace     = V4L2_COLORSPACE_SRGB,
50*4882a593Smuzhiyun 	},
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun static const struct v4l2_mbus_framefmt vs6624_default_fmt = {
54*4882a593Smuzhiyun 	.width = VGA_WIDTH,
55*4882a593Smuzhiyun 	.height = VGA_HEIGHT,
56*4882a593Smuzhiyun 	.code = MEDIA_BUS_FMT_UYVY8_2X8,
57*4882a593Smuzhiyun 	.field = V4L2_FIELD_NONE,
58*4882a593Smuzhiyun 	.colorspace = V4L2_COLORSPACE_JPEG,
59*4882a593Smuzhiyun };
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun static const u16 vs6624_p1[] = {
62*4882a593Smuzhiyun 	0x8104, 0x03,
63*4882a593Smuzhiyun 	0x8105, 0x01,
64*4882a593Smuzhiyun 	0xc900, 0x03,
65*4882a593Smuzhiyun 	0xc904, 0x47,
66*4882a593Smuzhiyun 	0xc905, 0x10,
67*4882a593Smuzhiyun 	0xc906, 0x80,
68*4882a593Smuzhiyun 	0xc907, 0x3a,
69*4882a593Smuzhiyun 	0x903a, 0x02,
70*4882a593Smuzhiyun 	0x903b, 0x47,
71*4882a593Smuzhiyun 	0x903c, 0x15,
72*4882a593Smuzhiyun 	0xc908, 0x31,
73*4882a593Smuzhiyun 	0xc909, 0xdc,
74*4882a593Smuzhiyun 	0xc90a, 0x80,
75*4882a593Smuzhiyun 	0xc90b, 0x44,
76*4882a593Smuzhiyun 	0x9044, 0x02,
77*4882a593Smuzhiyun 	0x9045, 0x31,
78*4882a593Smuzhiyun 	0x9046, 0xe2,
79*4882a593Smuzhiyun 	0xc90c, 0x07,
80*4882a593Smuzhiyun 	0xc90d, 0xe0,
81*4882a593Smuzhiyun 	0xc90e, 0x80,
82*4882a593Smuzhiyun 	0xc90f, 0x47,
83*4882a593Smuzhiyun 	0x9047, 0x90,
84*4882a593Smuzhiyun 	0x9048, 0x83,
85*4882a593Smuzhiyun 	0x9049, 0x81,
86*4882a593Smuzhiyun 	0x904a, 0xe0,
87*4882a593Smuzhiyun 	0x904b, 0x60,
88*4882a593Smuzhiyun 	0x904c, 0x08,
89*4882a593Smuzhiyun 	0x904d, 0x90,
90*4882a593Smuzhiyun 	0x904e, 0xc0,
91*4882a593Smuzhiyun 	0x904f, 0x43,
92*4882a593Smuzhiyun 	0x9050, 0x74,
93*4882a593Smuzhiyun 	0x9051, 0x01,
94*4882a593Smuzhiyun 	0x9052, 0xf0,
95*4882a593Smuzhiyun 	0x9053, 0x80,
96*4882a593Smuzhiyun 	0x9054, 0x05,
97*4882a593Smuzhiyun 	0x9055, 0xE4,
98*4882a593Smuzhiyun 	0x9056, 0x90,
99*4882a593Smuzhiyun 	0x9057, 0xc0,
100*4882a593Smuzhiyun 	0x9058, 0x43,
101*4882a593Smuzhiyun 	0x9059, 0xf0,
102*4882a593Smuzhiyun 	0x905a, 0x02,
103*4882a593Smuzhiyun 	0x905b, 0x07,
104*4882a593Smuzhiyun 	0x905c, 0xec,
105*4882a593Smuzhiyun 	0xc910, 0x5d,
106*4882a593Smuzhiyun 	0xc911, 0xca,
107*4882a593Smuzhiyun 	0xc912, 0x80,
108*4882a593Smuzhiyun 	0xc913, 0x5d,
109*4882a593Smuzhiyun 	0x905d, 0xa3,
110*4882a593Smuzhiyun 	0x905e, 0x04,
111*4882a593Smuzhiyun 	0x905f, 0xf0,
112*4882a593Smuzhiyun 	0x9060, 0xa3,
113*4882a593Smuzhiyun 	0x9061, 0x04,
114*4882a593Smuzhiyun 	0x9062, 0xf0,
115*4882a593Smuzhiyun 	0x9063, 0x22,
116*4882a593Smuzhiyun 	0xc914, 0x72,
117*4882a593Smuzhiyun 	0xc915, 0x92,
118*4882a593Smuzhiyun 	0xc916, 0x80,
119*4882a593Smuzhiyun 	0xc917, 0x64,
120*4882a593Smuzhiyun 	0x9064, 0x74,
121*4882a593Smuzhiyun 	0x9065, 0x01,
122*4882a593Smuzhiyun 	0x9066, 0x02,
123*4882a593Smuzhiyun 	0x9067, 0x72,
124*4882a593Smuzhiyun 	0x9068, 0x95,
125*4882a593Smuzhiyun 	0xc918, 0x47,
126*4882a593Smuzhiyun 	0xc919, 0xf2,
127*4882a593Smuzhiyun 	0xc91a, 0x81,
128*4882a593Smuzhiyun 	0xc91b, 0x69,
129*4882a593Smuzhiyun 	0x9169, 0x74,
130*4882a593Smuzhiyun 	0x916a, 0x02,
131*4882a593Smuzhiyun 	0x916b, 0xf0,
132*4882a593Smuzhiyun 	0x916c, 0xec,
133*4882a593Smuzhiyun 	0x916d, 0xb4,
134*4882a593Smuzhiyun 	0x916e, 0x10,
135*4882a593Smuzhiyun 	0x916f, 0x0a,
136*4882a593Smuzhiyun 	0x9170, 0x90,
137*4882a593Smuzhiyun 	0x9171, 0x80,
138*4882a593Smuzhiyun 	0x9172, 0x16,
139*4882a593Smuzhiyun 	0x9173, 0xe0,
140*4882a593Smuzhiyun 	0x9174, 0x70,
141*4882a593Smuzhiyun 	0x9175, 0x04,
142*4882a593Smuzhiyun 	0x9176, 0x90,
143*4882a593Smuzhiyun 	0x9177, 0xd3,
144*4882a593Smuzhiyun 	0x9178, 0xc4,
145*4882a593Smuzhiyun 	0x9179, 0xf0,
146*4882a593Smuzhiyun 	0x917a, 0x22,
147*4882a593Smuzhiyun 	0xc91c, 0x0a,
148*4882a593Smuzhiyun 	0xc91d, 0xbe,
149*4882a593Smuzhiyun 	0xc91e, 0x80,
150*4882a593Smuzhiyun 	0xc91f, 0x73,
151*4882a593Smuzhiyun 	0x9073, 0xfc,
152*4882a593Smuzhiyun 	0x9074, 0xa3,
153*4882a593Smuzhiyun 	0x9075, 0xe0,
154*4882a593Smuzhiyun 	0x9076, 0xf5,
155*4882a593Smuzhiyun 	0x9077, 0x82,
156*4882a593Smuzhiyun 	0x9078, 0x8c,
157*4882a593Smuzhiyun 	0x9079, 0x83,
158*4882a593Smuzhiyun 	0x907a, 0xa3,
159*4882a593Smuzhiyun 	0x907b, 0xa3,
160*4882a593Smuzhiyun 	0x907c, 0xe0,
161*4882a593Smuzhiyun 	0x907d, 0xfc,
162*4882a593Smuzhiyun 	0x907e, 0xa3,
163*4882a593Smuzhiyun 	0x907f, 0xe0,
164*4882a593Smuzhiyun 	0x9080, 0xc3,
165*4882a593Smuzhiyun 	0x9081, 0x9f,
166*4882a593Smuzhiyun 	0x9082, 0xff,
167*4882a593Smuzhiyun 	0x9083, 0xec,
168*4882a593Smuzhiyun 	0x9084, 0x9e,
169*4882a593Smuzhiyun 	0x9085, 0xfe,
170*4882a593Smuzhiyun 	0x9086, 0x02,
171*4882a593Smuzhiyun 	0x9087, 0x0a,
172*4882a593Smuzhiyun 	0x9088, 0xea,
173*4882a593Smuzhiyun 	0xc920, 0x47,
174*4882a593Smuzhiyun 	0xc921, 0x38,
175*4882a593Smuzhiyun 	0xc922, 0x80,
176*4882a593Smuzhiyun 	0xc923, 0x89,
177*4882a593Smuzhiyun 	0x9089, 0xec,
178*4882a593Smuzhiyun 	0x908a, 0xd3,
179*4882a593Smuzhiyun 	0x908b, 0x94,
180*4882a593Smuzhiyun 	0x908c, 0x20,
181*4882a593Smuzhiyun 	0x908d, 0x40,
182*4882a593Smuzhiyun 	0x908e, 0x01,
183*4882a593Smuzhiyun 	0x908f, 0x1c,
184*4882a593Smuzhiyun 	0x9090, 0x90,
185*4882a593Smuzhiyun 	0x9091, 0xd3,
186*4882a593Smuzhiyun 	0x9092, 0xd4,
187*4882a593Smuzhiyun 	0x9093, 0xec,
188*4882a593Smuzhiyun 	0x9094, 0xf0,
189*4882a593Smuzhiyun 	0x9095, 0x02,
190*4882a593Smuzhiyun 	0x9096, 0x47,
191*4882a593Smuzhiyun 	0x9097, 0x3d,
192*4882a593Smuzhiyun 	0xc924, 0x45,
193*4882a593Smuzhiyun 	0xc925, 0xca,
194*4882a593Smuzhiyun 	0xc926, 0x80,
195*4882a593Smuzhiyun 	0xc927, 0x98,
196*4882a593Smuzhiyun 	0x9098, 0x12,
197*4882a593Smuzhiyun 	0x9099, 0x77,
198*4882a593Smuzhiyun 	0x909a, 0xd6,
199*4882a593Smuzhiyun 	0x909b, 0x02,
200*4882a593Smuzhiyun 	0x909c, 0x45,
201*4882a593Smuzhiyun 	0x909d, 0xcd,
202*4882a593Smuzhiyun 	0xc928, 0x20,
203*4882a593Smuzhiyun 	0xc929, 0xd5,
204*4882a593Smuzhiyun 	0xc92a, 0x80,
205*4882a593Smuzhiyun 	0xc92b, 0x9e,
206*4882a593Smuzhiyun 	0x909e, 0x90,
207*4882a593Smuzhiyun 	0x909f, 0x82,
208*4882a593Smuzhiyun 	0x90a0, 0x18,
209*4882a593Smuzhiyun 	0x90a1, 0xe0,
210*4882a593Smuzhiyun 	0x90a2, 0xb4,
211*4882a593Smuzhiyun 	0x90a3, 0x03,
212*4882a593Smuzhiyun 	0x90a4, 0x0e,
213*4882a593Smuzhiyun 	0x90a5, 0x90,
214*4882a593Smuzhiyun 	0x90a6, 0x83,
215*4882a593Smuzhiyun 	0x90a7, 0xbf,
216*4882a593Smuzhiyun 	0x90a8, 0xe0,
217*4882a593Smuzhiyun 	0x90a9, 0x60,
218*4882a593Smuzhiyun 	0x90aa, 0x08,
219*4882a593Smuzhiyun 	0x90ab, 0x90,
220*4882a593Smuzhiyun 	0x90ac, 0x81,
221*4882a593Smuzhiyun 	0x90ad, 0xfc,
222*4882a593Smuzhiyun 	0x90ae, 0xe0,
223*4882a593Smuzhiyun 	0x90af, 0xff,
224*4882a593Smuzhiyun 	0x90b0, 0xc3,
225*4882a593Smuzhiyun 	0x90b1, 0x13,
226*4882a593Smuzhiyun 	0x90b2, 0xf0,
227*4882a593Smuzhiyun 	0x90b3, 0x90,
228*4882a593Smuzhiyun 	0x90b4, 0x81,
229*4882a593Smuzhiyun 	0x90b5, 0xfc,
230*4882a593Smuzhiyun 	0x90b6, 0xe0,
231*4882a593Smuzhiyun 	0x90b7, 0xff,
232*4882a593Smuzhiyun 	0x90b8, 0x02,
233*4882a593Smuzhiyun 	0x90b9, 0x20,
234*4882a593Smuzhiyun 	0x90ba, 0xda,
235*4882a593Smuzhiyun 	0xc92c, 0x70,
236*4882a593Smuzhiyun 	0xc92d, 0xbc,
237*4882a593Smuzhiyun 	0xc92e, 0x80,
238*4882a593Smuzhiyun 	0xc92f, 0xbb,
239*4882a593Smuzhiyun 	0x90bb, 0x90,
240*4882a593Smuzhiyun 	0x90bc, 0x82,
241*4882a593Smuzhiyun 	0x90bd, 0x18,
242*4882a593Smuzhiyun 	0x90be, 0xe0,
243*4882a593Smuzhiyun 	0x90bf, 0xb4,
244*4882a593Smuzhiyun 	0x90c0, 0x03,
245*4882a593Smuzhiyun 	0x90c1, 0x06,
246*4882a593Smuzhiyun 	0x90c2, 0x90,
247*4882a593Smuzhiyun 	0x90c3, 0xc1,
248*4882a593Smuzhiyun 	0x90c4, 0x06,
249*4882a593Smuzhiyun 	0x90c5, 0x74,
250*4882a593Smuzhiyun 	0x90c6, 0x05,
251*4882a593Smuzhiyun 	0x90c7, 0xf0,
252*4882a593Smuzhiyun 	0x90c8, 0x90,
253*4882a593Smuzhiyun 	0x90c9, 0xd3,
254*4882a593Smuzhiyun 	0x90ca, 0xa0,
255*4882a593Smuzhiyun 	0x90cb, 0x02,
256*4882a593Smuzhiyun 	0x90cc, 0x70,
257*4882a593Smuzhiyun 	0x90cd, 0xbf,
258*4882a593Smuzhiyun 	0xc930, 0x72,
259*4882a593Smuzhiyun 	0xc931, 0x21,
260*4882a593Smuzhiyun 	0xc932, 0x81,
261*4882a593Smuzhiyun 	0xc933, 0x3b,
262*4882a593Smuzhiyun 	0x913b, 0x7d,
263*4882a593Smuzhiyun 	0x913c, 0x02,
264*4882a593Smuzhiyun 	0x913d, 0x7f,
265*4882a593Smuzhiyun 	0x913e, 0x7b,
266*4882a593Smuzhiyun 	0x913f, 0x02,
267*4882a593Smuzhiyun 	0x9140, 0x72,
268*4882a593Smuzhiyun 	0x9141, 0x25,
269*4882a593Smuzhiyun 	0xc934, 0x28,
270*4882a593Smuzhiyun 	0xc935, 0xae,
271*4882a593Smuzhiyun 	0xc936, 0x80,
272*4882a593Smuzhiyun 	0xc937, 0xd2,
273*4882a593Smuzhiyun 	0x90d2, 0xf0,
274*4882a593Smuzhiyun 	0x90d3, 0x90,
275*4882a593Smuzhiyun 	0x90d4, 0xd2,
276*4882a593Smuzhiyun 	0x90d5, 0x0a,
277*4882a593Smuzhiyun 	0x90d6, 0x02,
278*4882a593Smuzhiyun 	0x90d7, 0x28,
279*4882a593Smuzhiyun 	0x90d8, 0xb4,
280*4882a593Smuzhiyun 	0xc938, 0x28,
281*4882a593Smuzhiyun 	0xc939, 0xb1,
282*4882a593Smuzhiyun 	0xc93a, 0x80,
283*4882a593Smuzhiyun 	0xc93b, 0xd9,
284*4882a593Smuzhiyun 	0x90d9, 0x90,
285*4882a593Smuzhiyun 	0x90da, 0x83,
286*4882a593Smuzhiyun 	0x90db, 0xba,
287*4882a593Smuzhiyun 	0x90dc, 0xe0,
288*4882a593Smuzhiyun 	0x90dd, 0xff,
289*4882a593Smuzhiyun 	0x90de, 0x90,
290*4882a593Smuzhiyun 	0x90df, 0xd2,
291*4882a593Smuzhiyun 	0x90e0, 0x08,
292*4882a593Smuzhiyun 	0x90e1, 0xe0,
293*4882a593Smuzhiyun 	0x90e2, 0xe4,
294*4882a593Smuzhiyun 	0x90e3, 0xef,
295*4882a593Smuzhiyun 	0x90e4, 0xf0,
296*4882a593Smuzhiyun 	0x90e5, 0xa3,
297*4882a593Smuzhiyun 	0x90e6, 0xe0,
298*4882a593Smuzhiyun 	0x90e7, 0x74,
299*4882a593Smuzhiyun 	0x90e8, 0xff,
300*4882a593Smuzhiyun 	0x90e9, 0xf0,
301*4882a593Smuzhiyun 	0x90ea, 0x90,
302*4882a593Smuzhiyun 	0x90eb, 0xd2,
303*4882a593Smuzhiyun 	0x90ec, 0x0a,
304*4882a593Smuzhiyun 	0x90ed, 0x02,
305*4882a593Smuzhiyun 	0x90ee, 0x28,
306*4882a593Smuzhiyun 	0x90ef, 0xb4,
307*4882a593Smuzhiyun 	0xc93c, 0x29,
308*4882a593Smuzhiyun 	0xc93d, 0x79,
309*4882a593Smuzhiyun 	0xc93e, 0x80,
310*4882a593Smuzhiyun 	0xc93f, 0xf0,
311*4882a593Smuzhiyun 	0x90f0, 0xf0,
312*4882a593Smuzhiyun 	0x90f1, 0x90,
313*4882a593Smuzhiyun 	0x90f2, 0xd2,
314*4882a593Smuzhiyun 	0x90f3, 0x0e,
315*4882a593Smuzhiyun 	0x90f4, 0x02,
316*4882a593Smuzhiyun 	0x90f5, 0x29,
317*4882a593Smuzhiyun 	0x90f6, 0x7f,
318*4882a593Smuzhiyun 	0xc940, 0x29,
319*4882a593Smuzhiyun 	0xc941, 0x7c,
320*4882a593Smuzhiyun 	0xc942, 0x80,
321*4882a593Smuzhiyun 	0xc943, 0xf7,
322*4882a593Smuzhiyun 	0x90f7, 0x90,
323*4882a593Smuzhiyun 	0x90f8, 0x83,
324*4882a593Smuzhiyun 	0x90f9, 0xba,
325*4882a593Smuzhiyun 	0x90fa, 0xe0,
326*4882a593Smuzhiyun 	0x90fb, 0xff,
327*4882a593Smuzhiyun 	0x90fc, 0x90,
328*4882a593Smuzhiyun 	0x90fd, 0xd2,
329*4882a593Smuzhiyun 	0x90fe, 0x0c,
330*4882a593Smuzhiyun 	0x90ff, 0xe0,
331*4882a593Smuzhiyun 	0x9100, 0xe4,
332*4882a593Smuzhiyun 	0x9101, 0xef,
333*4882a593Smuzhiyun 	0x9102, 0xf0,
334*4882a593Smuzhiyun 	0x9103, 0xa3,
335*4882a593Smuzhiyun 	0x9104, 0xe0,
336*4882a593Smuzhiyun 	0x9105, 0x74,
337*4882a593Smuzhiyun 	0x9106, 0xff,
338*4882a593Smuzhiyun 	0x9107, 0xf0,
339*4882a593Smuzhiyun 	0x9108, 0x90,
340*4882a593Smuzhiyun 	0x9109, 0xd2,
341*4882a593Smuzhiyun 	0x910a, 0x0e,
342*4882a593Smuzhiyun 	0x910b, 0x02,
343*4882a593Smuzhiyun 	0x910c, 0x29,
344*4882a593Smuzhiyun 	0x910d, 0x7f,
345*4882a593Smuzhiyun 	0xc944, 0x2a,
346*4882a593Smuzhiyun 	0xc945, 0x42,
347*4882a593Smuzhiyun 	0xc946, 0x81,
348*4882a593Smuzhiyun 	0xc947, 0x0e,
349*4882a593Smuzhiyun 	0x910e, 0xf0,
350*4882a593Smuzhiyun 	0x910f, 0x90,
351*4882a593Smuzhiyun 	0x9110, 0xd2,
352*4882a593Smuzhiyun 	0x9111, 0x12,
353*4882a593Smuzhiyun 	0x9112, 0x02,
354*4882a593Smuzhiyun 	0x9113, 0x2a,
355*4882a593Smuzhiyun 	0x9114, 0x48,
356*4882a593Smuzhiyun 	0xc948, 0x2a,
357*4882a593Smuzhiyun 	0xc949, 0x45,
358*4882a593Smuzhiyun 	0xc94a, 0x81,
359*4882a593Smuzhiyun 	0xc94b, 0x15,
360*4882a593Smuzhiyun 	0x9115, 0x90,
361*4882a593Smuzhiyun 	0x9116, 0x83,
362*4882a593Smuzhiyun 	0x9117, 0xba,
363*4882a593Smuzhiyun 	0x9118, 0xe0,
364*4882a593Smuzhiyun 	0x9119, 0xff,
365*4882a593Smuzhiyun 	0x911a, 0x90,
366*4882a593Smuzhiyun 	0x911b, 0xd2,
367*4882a593Smuzhiyun 	0x911c, 0x10,
368*4882a593Smuzhiyun 	0x911d, 0xe0,
369*4882a593Smuzhiyun 	0x911e, 0xe4,
370*4882a593Smuzhiyun 	0x911f, 0xef,
371*4882a593Smuzhiyun 	0x9120, 0xf0,
372*4882a593Smuzhiyun 	0x9121, 0xa3,
373*4882a593Smuzhiyun 	0x9122, 0xe0,
374*4882a593Smuzhiyun 	0x9123, 0x74,
375*4882a593Smuzhiyun 	0x9124, 0xff,
376*4882a593Smuzhiyun 	0x9125, 0xf0,
377*4882a593Smuzhiyun 	0x9126, 0x90,
378*4882a593Smuzhiyun 	0x9127, 0xd2,
379*4882a593Smuzhiyun 	0x9128, 0x12,
380*4882a593Smuzhiyun 	0x9129, 0x02,
381*4882a593Smuzhiyun 	0x912a, 0x2a,
382*4882a593Smuzhiyun 	0x912b, 0x48,
383*4882a593Smuzhiyun 	0xc900, 0x01,
384*4882a593Smuzhiyun 	0x0000, 0x00,
385*4882a593Smuzhiyun };
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun static const u16 vs6624_p2[] = {
388*4882a593Smuzhiyun 	0x806f, 0x01,
389*4882a593Smuzhiyun 	0x058c, 0x01,
390*4882a593Smuzhiyun 	0x0000, 0x00,
391*4882a593Smuzhiyun };
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun static const u16 vs6624_run_setup[] = {
394*4882a593Smuzhiyun 	0x1d18, 0x00,				/* Enableconstrainedwhitebalance */
395*4882a593Smuzhiyun 	VS6624_PEAK_MIN_OUT_G_MSB, 0x3c,	/* Damper PeakGain Output MSB */
396*4882a593Smuzhiyun 	VS6624_PEAK_MIN_OUT_G_LSB, 0x66,	/* Damper PeakGain Output LSB */
397*4882a593Smuzhiyun 	VS6624_CM_LOW_THR_MSB, 0x65,		/* Damper Low MSB */
398*4882a593Smuzhiyun 	VS6624_CM_LOW_THR_LSB, 0xd1,		/* Damper Low LSB */
399*4882a593Smuzhiyun 	VS6624_CM_HIGH_THR_MSB, 0x66,		/* Damper High MSB */
400*4882a593Smuzhiyun 	VS6624_CM_HIGH_THR_LSB, 0x62,		/* Damper High LSB */
401*4882a593Smuzhiyun 	VS6624_CM_MIN_OUT_MSB, 0x00,		/* Damper Min output MSB */
402*4882a593Smuzhiyun 	VS6624_CM_MIN_OUT_LSB, 0x00,		/* Damper Min output LSB */
403*4882a593Smuzhiyun 	VS6624_NORA_DISABLE, 0x00,		/* Nora fDisable */
404*4882a593Smuzhiyun 	VS6624_NORA_USAGE, 0x04,		/* Nora usage */
405*4882a593Smuzhiyun 	VS6624_NORA_LOW_THR_MSB, 0x63,		/* Damper Low MSB Changed 0x63 to 0x65 */
406*4882a593Smuzhiyun 	VS6624_NORA_LOW_THR_LSB, 0xd1,		/* Damper Low LSB */
407*4882a593Smuzhiyun 	VS6624_NORA_HIGH_THR_MSB, 0x68,		/* Damper High MSB */
408*4882a593Smuzhiyun 	VS6624_NORA_HIGH_THR_LSB, 0xdd,		/* Damper High LSB */
409*4882a593Smuzhiyun 	VS6624_NORA_MIN_OUT_MSB, 0x3a,		/* Damper Min output MSB */
410*4882a593Smuzhiyun 	VS6624_NORA_MIN_OUT_LSB, 0x00,		/* Damper Min output LSB */
411*4882a593Smuzhiyun 	VS6624_F2B_DISABLE, 0x00,		/* Disable */
412*4882a593Smuzhiyun 	0x1d8a, 0x30,				/* MAXWeightHigh */
413*4882a593Smuzhiyun 	0x1d91, 0x62,				/* fpDamperLowThresholdHigh MSB */
414*4882a593Smuzhiyun 	0x1d92, 0x4a,				/* fpDamperLowThresholdHigh LSB */
415*4882a593Smuzhiyun 	0x1d95, 0x65,				/* fpDamperHighThresholdHigh MSB */
416*4882a593Smuzhiyun 	0x1d96, 0x0e,				/* fpDamperHighThresholdHigh LSB */
417*4882a593Smuzhiyun 	0x1da1, 0x3a,				/* fpMinimumDamperOutputLow MSB */
418*4882a593Smuzhiyun 	0x1da2, 0xb8,				/* fpMinimumDamperOutputLow LSB */
419*4882a593Smuzhiyun 	0x1e08, 0x06,				/* MAXWeightLow */
420*4882a593Smuzhiyun 	0x1e0a, 0x0a,				/* MAXWeightHigh */
421*4882a593Smuzhiyun 	0x1601, 0x3a,				/* Red A MSB */
422*4882a593Smuzhiyun 	0x1602, 0x14,				/* Red A LSB */
423*4882a593Smuzhiyun 	0x1605, 0x3b,				/* Blue A MSB */
424*4882a593Smuzhiyun 	0x1606, 0x85,				/* BLue A LSB */
425*4882a593Smuzhiyun 	0x1609, 0x3b,				/* RED B MSB */
426*4882a593Smuzhiyun 	0x160a, 0x85,				/* RED B LSB */
427*4882a593Smuzhiyun 	0x160d, 0x3a,				/* Blue B MSB */
428*4882a593Smuzhiyun 	0x160e, 0x14,				/* Blue B LSB */
429*4882a593Smuzhiyun 	0x1611, 0x30,				/* Max Distance from Locus MSB */
430*4882a593Smuzhiyun 	0x1612, 0x8f,				/* Max Distance from Locus MSB */
431*4882a593Smuzhiyun 	0x1614, 0x01,				/* Enable constrainer */
432*4882a593Smuzhiyun 	0x0000, 0x00,
433*4882a593Smuzhiyun };
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun static const u16 vs6624_default[] = {
436*4882a593Smuzhiyun 	VS6624_CONTRAST0, 0x84,
437*4882a593Smuzhiyun 	VS6624_SATURATION0, 0x75,
438*4882a593Smuzhiyun 	VS6624_GAMMA0, 0x11,
439*4882a593Smuzhiyun 	VS6624_CONTRAST1, 0x84,
440*4882a593Smuzhiyun 	VS6624_SATURATION1, 0x75,
441*4882a593Smuzhiyun 	VS6624_GAMMA1, 0x11,
442*4882a593Smuzhiyun 	VS6624_MAN_RG, 0x80,
443*4882a593Smuzhiyun 	VS6624_MAN_GG, 0x80,
444*4882a593Smuzhiyun 	VS6624_MAN_BG, 0x80,
445*4882a593Smuzhiyun 	VS6624_WB_MODE, 0x1,
446*4882a593Smuzhiyun 	VS6624_EXPO_COMPENSATION, 0xfe,
447*4882a593Smuzhiyun 	VS6624_EXPO_METER, 0x0,
448*4882a593Smuzhiyun 	VS6624_LIGHT_FREQ, 0x64,
449*4882a593Smuzhiyun 	VS6624_PEAK_GAIN, 0xe,
450*4882a593Smuzhiyun 	VS6624_PEAK_LOW_THR, 0x28,
451*4882a593Smuzhiyun 	VS6624_HMIRROR0, 0x0,
452*4882a593Smuzhiyun 	VS6624_VFLIP0, 0x0,
453*4882a593Smuzhiyun 	VS6624_ZOOM_HSTEP0_MSB, 0x0,
454*4882a593Smuzhiyun 	VS6624_ZOOM_HSTEP0_LSB, 0x1,
455*4882a593Smuzhiyun 	VS6624_ZOOM_VSTEP0_MSB, 0x0,
456*4882a593Smuzhiyun 	VS6624_ZOOM_VSTEP0_LSB, 0x1,
457*4882a593Smuzhiyun 	VS6624_PAN_HSTEP0_MSB, 0x0,
458*4882a593Smuzhiyun 	VS6624_PAN_HSTEP0_LSB, 0xf,
459*4882a593Smuzhiyun 	VS6624_PAN_VSTEP0_MSB, 0x0,
460*4882a593Smuzhiyun 	VS6624_PAN_VSTEP0_LSB, 0xf,
461*4882a593Smuzhiyun 	VS6624_SENSOR_MODE, 0x1,
462*4882a593Smuzhiyun 	VS6624_SYNC_CODE_SETUP, 0x21,
463*4882a593Smuzhiyun 	VS6624_DISABLE_FR_DAMPER, 0x0,
464*4882a593Smuzhiyun 	VS6624_FR_DEN, 0x1,
465*4882a593Smuzhiyun 	VS6624_FR_NUM_LSB, 0xf,
466*4882a593Smuzhiyun 	VS6624_INIT_PIPE_SETUP, 0x0,
467*4882a593Smuzhiyun 	VS6624_IMG_FMT0, 0x0,
468*4882a593Smuzhiyun 	VS6624_YUV_SETUP, 0x1,
469*4882a593Smuzhiyun 	VS6624_IMAGE_SIZE0, 0x2,
470*4882a593Smuzhiyun 	0x0000, 0x00,
471*4882a593Smuzhiyun };
472*4882a593Smuzhiyun 
to_vs6624(struct v4l2_subdev * sd)473*4882a593Smuzhiyun static inline struct vs6624 *to_vs6624(struct v4l2_subdev *sd)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun 	return container_of(sd, struct vs6624, sd);
476*4882a593Smuzhiyun }
to_sd(struct v4l2_ctrl * ctrl)477*4882a593Smuzhiyun static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun 	return &container_of(ctrl->handler, struct vs6624, hdl)->sd;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_ADV_DEBUG
vs6624_read(struct v4l2_subdev * sd,u16 index)483*4882a593Smuzhiyun static int vs6624_read(struct v4l2_subdev *sd, u16 index)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun 	struct i2c_client *client = v4l2_get_subdevdata(sd);
486*4882a593Smuzhiyun 	u8 buf[2];
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	buf[0] = index >> 8;
489*4882a593Smuzhiyun 	buf[1] = index;
490*4882a593Smuzhiyun 	i2c_master_send(client, buf, 2);
491*4882a593Smuzhiyun 	i2c_master_recv(client, buf, 1);
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	return buf[0];
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun #endif
496*4882a593Smuzhiyun 
vs6624_write(struct v4l2_subdev * sd,u16 index,u8 value)497*4882a593Smuzhiyun static int vs6624_write(struct v4l2_subdev *sd, u16 index,
498*4882a593Smuzhiyun 				u8 value)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun 	struct i2c_client *client = v4l2_get_subdevdata(sd);
501*4882a593Smuzhiyun 	u8 buf[3];
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	buf[0] = index >> 8;
504*4882a593Smuzhiyun 	buf[1] = index;
505*4882a593Smuzhiyun 	buf[2] = value;
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	return i2c_master_send(client, buf, 3);
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun 
vs6624_writeregs(struct v4l2_subdev * sd,const u16 * regs)510*4882a593Smuzhiyun static int vs6624_writeregs(struct v4l2_subdev *sd, const u16 *regs)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun 	u16 reg;
513*4882a593Smuzhiyun 	u8 data;
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	while (*regs != 0x00) {
516*4882a593Smuzhiyun 		reg = *regs++;
517*4882a593Smuzhiyun 		data = *regs++;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 		vs6624_write(sd, reg, data);
520*4882a593Smuzhiyun 	}
521*4882a593Smuzhiyun 	return 0;
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun 
vs6624_s_ctrl(struct v4l2_ctrl * ctrl)524*4882a593Smuzhiyun static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl)
525*4882a593Smuzhiyun {
526*4882a593Smuzhiyun 	struct v4l2_subdev *sd = to_sd(ctrl);
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	switch (ctrl->id) {
529*4882a593Smuzhiyun 	case V4L2_CID_CONTRAST:
530*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_CONTRAST0, ctrl->val);
531*4882a593Smuzhiyun 		break;
532*4882a593Smuzhiyun 	case V4L2_CID_SATURATION:
533*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_SATURATION0, ctrl->val);
534*4882a593Smuzhiyun 		break;
535*4882a593Smuzhiyun 	case V4L2_CID_HFLIP:
536*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_HMIRROR0, ctrl->val);
537*4882a593Smuzhiyun 		break;
538*4882a593Smuzhiyun 	case V4L2_CID_VFLIP:
539*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_VFLIP0, ctrl->val);
540*4882a593Smuzhiyun 		break;
541*4882a593Smuzhiyun 	default:
542*4882a593Smuzhiyun 		return -EINVAL;
543*4882a593Smuzhiyun 	}
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	return 0;
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun 
vs6624_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_mbus_code_enum * code)548*4882a593Smuzhiyun static int vs6624_enum_mbus_code(struct v4l2_subdev *sd,
549*4882a593Smuzhiyun 		struct v4l2_subdev_pad_config *cfg,
550*4882a593Smuzhiyun 		struct v4l2_subdev_mbus_code_enum *code)
551*4882a593Smuzhiyun {
552*4882a593Smuzhiyun 	if (code->pad || code->index >= ARRAY_SIZE(vs6624_formats))
553*4882a593Smuzhiyun 		return -EINVAL;
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	code->code = vs6624_formats[code->index].mbus_code;
556*4882a593Smuzhiyun 	return 0;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun 
vs6624_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * format)559*4882a593Smuzhiyun static int vs6624_set_fmt(struct v4l2_subdev *sd,
560*4882a593Smuzhiyun 		struct v4l2_subdev_pad_config *cfg,
561*4882a593Smuzhiyun 		struct v4l2_subdev_format *format)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun 	struct v4l2_mbus_framefmt *fmt = &format->format;
564*4882a593Smuzhiyun 	struct vs6624 *sensor = to_vs6624(sd);
565*4882a593Smuzhiyun 	int index;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	if (format->pad)
568*4882a593Smuzhiyun 		return -EINVAL;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++)
571*4882a593Smuzhiyun 		if (vs6624_formats[index].mbus_code == fmt->code)
572*4882a593Smuzhiyun 			break;
573*4882a593Smuzhiyun 	if (index >= ARRAY_SIZE(vs6624_formats)) {
574*4882a593Smuzhiyun 		/* default to first format */
575*4882a593Smuzhiyun 		index = 0;
576*4882a593Smuzhiyun 		fmt->code = vs6624_formats[0].mbus_code;
577*4882a593Smuzhiyun 	}
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	/* sensor mode is VGA */
580*4882a593Smuzhiyun 	if (fmt->width > VGA_WIDTH)
581*4882a593Smuzhiyun 		fmt->width = VGA_WIDTH;
582*4882a593Smuzhiyun 	if (fmt->height > VGA_HEIGHT)
583*4882a593Smuzhiyun 		fmt->height = VGA_HEIGHT;
584*4882a593Smuzhiyun 	fmt->width = fmt->width & (~3);
585*4882a593Smuzhiyun 	fmt->height = fmt->height & (~3);
586*4882a593Smuzhiyun 	fmt->field = V4L2_FIELD_NONE;
587*4882a593Smuzhiyun 	fmt->colorspace = vs6624_formats[index].colorspace;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
590*4882a593Smuzhiyun 		cfg->try_fmt = *fmt;
591*4882a593Smuzhiyun 		return 0;
592*4882a593Smuzhiyun 	}
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	/* set image format */
595*4882a593Smuzhiyun 	switch (fmt->code) {
596*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_UYVY8_2X8:
597*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
598*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_YUV_SETUP, 0x1);
599*4882a593Smuzhiyun 		break;
600*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_YUYV8_2X8:
601*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
602*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_YUV_SETUP, 0x3);
603*4882a593Smuzhiyun 		break;
604*4882a593Smuzhiyun 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
605*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_IMG_FMT0, 0x4);
606*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_RGB_SETUP, 0x0);
607*4882a593Smuzhiyun 		break;
608*4882a593Smuzhiyun 	default:
609*4882a593Smuzhiyun 		return -EINVAL;
610*4882a593Smuzhiyun 	}
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	/* set image size */
613*4882a593Smuzhiyun 	if ((fmt->width == VGA_WIDTH) && (fmt->height == VGA_HEIGHT))
614*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x2);
615*4882a593Smuzhiyun 	else if ((fmt->width == QVGA_WIDTH) && (fmt->height == QVGA_HEIGHT))
616*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x4);
617*4882a593Smuzhiyun 	else if ((fmt->width == QQVGA_WIDTH) && (fmt->height == QQVGA_HEIGHT))
618*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x6);
619*4882a593Smuzhiyun 	else if ((fmt->width == CIF_WIDTH) && (fmt->height == CIF_HEIGHT))
620*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x3);
621*4882a593Smuzhiyun 	else if ((fmt->width == QCIF_WIDTH) && (fmt->height == QCIF_HEIGHT))
622*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x5);
623*4882a593Smuzhiyun 	else if ((fmt->width == QQCIF_WIDTH) && (fmt->height == QQCIF_HEIGHT))
624*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x7);
625*4882a593Smuzhiyun 	else {
626*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x8);
627*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_MAN_HSIZE0_MSB, fmt->width >> 8);
628*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_MAN_HSIZE0_LSB, fmt->width & 0xFF);
629*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_MAN_VSIZE0_MSB, fmt->height >> 8);
630*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_MAN_VSIZE0_LSB, fmt->height & 0xFF);
631*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_CROP_CTRL0, 0x1);
632*4882a593Smuzhiyun 	}
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	sensor->fmt = *fmt;
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	return 0;
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun 
vs6624_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * format)639*4882a593Smuzhiyun static int vs6624_get_fmt(struct v4l2_subdev *sd,
640*4882a593Smuzhiyun 		struct v4l2_subdev_pad_config *cfg,
641*4882a593Smuzhiyun 		struct v4l2_subdev_format *format)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun 	struct vs6624 *sensor = to_vs6624(sd);
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	if (format->pad)
646*4882a593Smuzhiyun 		return -EINVAL;
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	format->format = sensor->fmt;
649*4882a593Smuzhiyun 	return 0;
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun 
vs6624_g_frame_interval(struct v4l2_subdev * sd,struct v4l2_subdev_frame_interval * ival)652*4882a593Smuzhiyun static int vs6624_g_frame_interval(struct v4l2_subdev *sd,
653*4882a593Smuzhiyun 				   struct v4l2_subdev_frame_interval *ival)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun 	struct vs6624 *sensor = to_vs6624(sd);
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	ival->interval.numerator = sensor->frame_rate.denominator;
658*4882a593Smuzhiyun 	ival->interval.denominator = sensor->frame_rate.numerator;
659*4882a593Smuzhiyun 	return 0;
660*4882a593Smuzhiyun }
661*4882a593Smuzhiyun 
vs6624_s_frame_interval(struct v4l2_subdev * sd,struct v4l2_subdev_frame_interval * ival)662*4882a593Smuzhiyun static int vs6624_s_frame_interval(struct v4l2_subdev *sd,
663*4882a593Smuzhiyun 				   struct v4l2_subdev_frame_interval *ival)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun 	struct vs6624 *sensor = to_vs6624(sd);
666*4882a593Smuzhiyun 	struct v4l2_fract *tpf = &ival->interval;
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	if (tpf->numerator == 0 || tpf->denominator == 0
670*4882a593Smuzhiyun 		|| (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) {
671*4882a593Smuzhiyun 		/* reset to max frame rate */
672*4882a593Smuzhiyun 		tpf->numerator = 1;
673*4882a593Smuzhiyun 		tpf->denominator = MAX_FRAME_RATE;
674*4882a593Smuzhiyun 	}
675*4882a593Smuzhiyun 	sensor->frame_rate.numerator = tpf->denominator;
676*4882a593Smuzhiyun 	sensor->frame_rate.denominator = tpf->numerator;
677*4882a593Smuzhiyun 	vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
678*4882a593Smuzhiyun 	vs6624_write(sd, VS6624_FR_NUM_MSB,
679*4882a593Smuzhiyun 			sensor->frame_rate.numerator >> 8);
680*4882a593Smuzhiyun 	vs6624_write(sd, VS6624_FR_NUM_LSB,
681*4882a593Smuzhiyun 			sensor->frame_rate.numerator & 0xFF);
682*4882a593Smuzhiyun 	vs6624_write(sd, VS6624_FR_DEN,
683*4882a593Smuzhiyun 			sensor->frame_rate.denominator & 0xFF);
684*4882a593Smuzhiyun 	return 0;
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun 
vs6624_s_stream(struct v4l2_subdev * sd,int enable)687*4882a593Smuzhiyun static int vs6624_s_stream(struct v4l2_subdev *sd, int enable)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun 	if (enable)
690*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_USER_CMD, 0x2);
691*4882a593Smuzhiyun 	else
692*4882a593Smuzhiyun 		vs6624_write(sd, VS6624_USER_CMD, 0x4);
693*4882a593Smuzhiyun 	udelay(100);
694*4882a593Smuzhiyun 	return 0;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_ADV_DEBUG
vs6624_g_register(struct v4l2_subdev * sd,struct v4l2_dbg_register * reg)698*4882a593Smuzhiyun static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
699*4882a593Smuzhiyun {
700*4882a593Smuzhiyun 	reg->val = vs6624_read(sd, reg->reg & 0xffff);
701*4882a593Smuzhiyun 	reg->size = 1;
702*4882a593Smuzhiyun 	return 0;
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun 
vs6624_s_register(struct v4l2_subdev * sd,const struct v4l2_dbg_register * reg)705*4882a593Smuzhiyun static int vs6624_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
706*4882a593Smuzhiyun {
707*4882a593Smuzhiyun 	vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff);
708*4882a593Smuzhiyun 	return 0;
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun #endif
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun static const struct v4l2_ctrl_ops vs6624_ctrl_ops = {
713*4882a593Smuzhiyun 	.s_ctrl = vs6624_s_ctrl,
714*4882a593Smuzhiyun };
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun static const struct v4l2_subdev_core_ops vs6624_core_ops = {
717*4882a593Smuzhiyun #ifdef CONFIG_VIDEO_ADV_DEBUG
718*4882a593Smuzhiyun 	.g_register = vs6624_g_register,
719*4882a593Smuzhiyun 	.s_register = vs6624_s_register,
720*4882a593Smuzhiyun #endif
721*4882a593Smuzhiyun };
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun static const struct v4l2_subdev_video_ops vs6624_video_ops = {
724*4882a593Smuzhiyun 	.s_frame_interval = vs6624_s_frame_interval,
725*4882a593Smuzhiyun 	.g_frame_interval = vs6624_g_frame_interval,
726*4882a593Smuzhiyun 	.s_stream = vs6624_s_stream,
727*4882a593Smuzhiyun };
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun static const struct v4l2_subdev_pad_ops vs6624_pad_ops = {
730*4882a593Smuzhiyun 	.enum_mbus_code = vs6624_enum_mbus_code,
731*4882a593Smuzhiyun 	.get_fmt = vs6624_get_fmt,
732*4882a593Smuzhiyun 	.set_fmt = vs6624_set_fmt,
733*4882a593Smuzhiyun };
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun static const struct v4l2_subdev_ops vs6624_ops = {
736*4882a593Smuzhiyun 	.core = &vs6624_core_ops,
737*4882a593Smuzhiyun 	.video = &vs6624_video_ops,
738*4882a593Smuzhiyun 	.pad = &vs6624_pad_ops,
739*4882a593Smuzhiyun };
740*4882a593Smuzhiyun 
vs6624_probe(struct i2c_client * client,const struct i2c_device_id * id)741*4882a593Smuzhiyun static int vs6624_probe(struct i2c_client *client,
742*4882a593Smuzhiyun 			const struct i2c_device_id *id)
743*4882a593Smuzhiyun {
744*4882a593Smuzhiyun 	struct vs6624 *sensor;
745*4882a593Smuzhiyun 	struct v4l2_subdev *sd;
746*4882a593Smuzhiyun 	struct v4l2_ctrl_handler *hdl;
747*4882a593Smuzhiyun 	const unsigned *ce;
748*4882a593Smuzhiyun 	int ret;
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 	/* Check if the adapter supports the needed features */
751*4882a593Smuzhiyun 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
752*4882a593Smuzhiyun 		return -EIO;
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	ce = client->dev.platform_data;
755*4882a593Smuzhiyun 	if (ce == NULL)
756*4882a593Smuzhiyun 		return -EINVAL;
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 	ret = devm_gpio_request_one(&client->dev, *ce, GPIOF_OUT_INIT_HIGH,
759*4882a593Smuzhiyun 				    "VS6624 Chip Enable");
760*4882a593Smuzhiyun 	if (ret) {
761*4882a593Smuzhiyun 		v4l_err(client, "failed to request GPIO %d\n", *ce);
762*4882a593Smuzhiyun 		return ret;
763*4882a593Smuzhiyun 	}
764*4882a593Smuzhiyun 	/* wait 100ms before any further i2c writes are performed */
765*4882a593Smuzhiyun 	msleep(100);
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 	sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
768*4882a593Smuzhiyun 	if (sensor == NULL)
769*4882a593Smuzhiyun 		return -ENOMEM;
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun 	sd = &sensor->sd;
772*4882a593Smuzhiyun 	v4l2_i2c_subdev_init(sd, client, &vs6624_ops);
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	vs6624_writeregs(sd, vs6624_p1);
775*4882a593Smuzhiyun 	vs6624_write(sd, VS6624_MICRO_EN, 0x2);
776*4882a593Smuzhiyun 	vs6624_write(sd, VS6624_DIO_EN, 0x1);
777*4882a593Smuzhiyun 	usleep_range(10000, 11000);
778*4882a593Smuzhiyun 	vs6624_writeregs(sd, vs6624_p2);
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	vs6624_writeregs(sd, vs6624_default);
781*4882a593Smuzhiyun 	vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF);
782*4882a593Smuzhiyun 	vs6624_writeregs(sd, vs6624_run_setup);
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	/* set frame rate */
785*4882a593Smuzhiyun 	sensor->frame_rate.numerator = MAX_FRAME_RATE;
786*4882a593Smuzhiyun 	sensor->frame_rate.denominator = 1;
787*4882a593Smuzhiyun 	vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
788*4882a593Smuzhiyun 	vs6624_write(sd, VS6624_FR_NUM_MSB,
789*4882a593Smuzhiyun 			sensor->frame_rate.numerator >> 8);
790*4882a593Smuzhiyun 	vs6624_write(sd, VS6624_FR_NUM_LSB,
791*4882a593Smuzhiyun 			sensor->frame_rate.numerator & 0xFF);
792*4882a593Smuzhiyun 	vs6624_write(sd, VS6624_FR_DEN,
793*4882a593Smuzhiyun 			sensor->frame_rate.denominator & 0xFF);
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	sensor->fmt = vs6624_default_fmt;
796*4882a593Smuzhiyun 	sensor->ce_pin = *ce;
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	v4l_info(client, "chip found @ 0x%02x (%s)\n",
799*4882a593Smuzhiyun 			client->addr << 1, client->adapter->name);
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	hdl = &sensor->hdl;
802*4882a593Smuzhiyun 	v4l2_ctrl_handler_init(hdl, 4);
803*4882a593Smuzhiyun 	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
804*4882a593Smuzhiyun 			V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x87);
805*4882a593Smuzhiyun 	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
806*4882a593Smuzhiyun 			V4L2_CID_SATURATION, 0, 0xFF, 1, 0x78);
807*4882a593Smuzhiyun 	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
808*4882a593Smuzhiyun 			V4L2_CID_HFLIP, 0, 1, 1, 0);
809*4882a593Smuzhiyun 	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
810*4882a593Smuzhiyun 			V4L2_CID_VFLIP, 0, 1, 1, 0);
811*4882a593Smuzhiyun 	/* hook the control handler into the driver */
812*4882a593Smuzhiyun 	sd->ctrl_handler = hdl;
813*4882a593Smuzhiyun 	if (hdl->error) {
814*4882a593Smuzhiyun 		int err = hdl->error;
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun 		v4l2_ctrl_handler_free(hdl);
817*4882a593Smuzhiyun 		return err;
818*4882a593Smuzhiyun 	}
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun 	/* initialize the hardware to the default control values */
821*4882a593Smuzhiyun 	ret = v4l2_ctrl_handler_setup(hdl);
822*4882a593Smuzhiyun 	if (ret)
823*4882a593Smuzhiyun 		v4l2_ctrl_handler_free(hdl);
824*4882a593Smuzhiyun 	return ret;
825*4882a593Smuzhiyun }
826*4882a593Smuzhiyun 
vs6624_remove(struct i2c_client * client)827*4882a593Smuzhiyun static int vs6624_remove(struct i2c_client *client)
828*4882a593Smuzhiyun {
829*4882a593Smuzhiyun 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	v4l2_device_unregister_subdev(sd);
832*4882a593Smuzhiyun 	v4l2_ctrl_handler_free(sd->ctrl_handler);
833*4882a593Smuzhiyun 	return 0;
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun static const struct i2c_device_id vs6624_id[] = {
837*4882a593Smuzhiyun 	{"vs6624", 0},
838*4882a593Smuzhiyun 	{},
839*4882a593Smuzhiyun };
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, vs6624_id);
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun static struct i2c_driver vs6624_driver = {
844*4882a593Smuzhiyun 	.driver = {
845*4882a593Smuzhiyun 		.name   = "vs6624",
846*4882a593Smuzhiyun 	},
847*4882a593Smuzhiyun 	.probe          = vs6624_probe,
848*4882a593Smuzhiyun 	.remove         = vs6624_remove,
849*4882a593Smuzhiyun 	.id_table       = vs6624_id,
850*4882a593Smuzhiyun };
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun module_i2c_driver(vs6624_driver);
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun MODULE_DESCRIPTION("VS6624 sensor driver");
855*4882a593Smuzhiyun MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
856*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
857