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