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_code(struct v4l2_subdev *sd,
561		struct v4l2_subdev_pad_config *cfg,
562		struct v4l2_subdev_mbus_code_enum *code)
563{
564	if (code->pad || code->index >= ARRAY_SIZE(vs6624_formats))
565		return -EINVAL;
566
567	code->code = vs6624_formats[code->index].mbus_code;
568	return 0;
569}
570
571static int vs6624_set_fmt(struct v4l2_subdev *sd,
572		struct v4l2_subdev_pad_config *cfg,
573		struct v4l2_subdev_format *format)
574{
575	struct v4l2_mbus_framefmt *fmt = &format->format;
576	struct vs6624 *sensor = to_vs6624(sd);
577	int index;
578
579	if (format->pad)
580		return -EINVAL;
581
582	for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++)
583		if (vs6624_formats[index].mbus_code == fmt->code)
584			break;
585	if (index >= ARRAY_SIZE(vs6624_formats)) {
586		/* default to first format */
587		index = 0;
588		fmt->code = vs6624_formats[0].mbus_code;
589	}
590
591	/* sensor mode is VGA */
592	if (fmt->width > VGA_WIDTH)
593		fmt->width = VGA_WIDTH;
594	if (fmt->height > VGA_HEIGHT)
595		fmt->height = VGA_HEIGHT;
596	fmt->width = fmt->width & (~3);
597	fmt->height = fmt->height & (~3);
598	fmt->field = V4L2_FIELD_NONE;
599	fmt->colorspace = vs6624_formats[index].colorspace;
600
601	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
602		cfg->try_fmt = *fmt;
603		return 0;
604	}
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_get_fmt(struct v4l2_subdev *sd,
652		struct v4l2_subdev_pad_config *cfg,
653		struct v4l2_subdev_format *format)
654{
655	struct vs6624 *sensor = to_vs6624(sd);
656
657	if (format->pad)
658		return -EINVAL;
659
660	format->format = sensor->fmt;
661	return 0;
662}
663
664static int vs6624_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
665{
666	struct vs6624 *sensor = to_vs6624(sd);
667	struct v4l2_captureparm *cp = &parms->parm.capture;
668
669	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
670		return -EINVAL;
671
672	memset(cp, 0, sizeof(*cp));
673	cp->capability = V4L2_CAP_TIMEPERFRAME;
674	cp->timeperframe.numerator = sensor->frame_rate.denominator;
675	cp->timeperframe.denominator = sensor->frame_rate.numerator;
676	return 0;
677}
678
679static int vs6624_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
680{
681	struct vs6624 *sensor = to_vs6624(sd);
682	struct v4l2_captureparm *cp = &parms->parm.capture;
683	struct v4l2_fract *tpf = &cp->timeperframe;
684
685	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
686		return -EINVAL;
687	if (cp->extendedmode != 0)
688		return -EINVAL;
689
690	if (tpf->numerator == 0 || tpf->denominator == 0
691		|| (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) {
692		/* reset to max frame rate */
693		tpf->numerator = 1;
694		tpf->denominator = MAX_FRAME_RATE;
695	}
696	sensor->frame_rate.numerator = tpf->denominator;
697	sensor->frame_rate.denominator = tpf->numerator;
698	vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
699	vs6624_write(sd, VS6624_FR_NUM_MSB,
700			sensor->frame_rate.numerator >> 8);
701	vs6624_write(sd, VS6624_FR_NUM_LSB,
702			sensor->frame_rate.numerator & 0xFF);
703	vs6624_write(sd, VS6624_FR_DEN,
704			sensor->frame_rate.denominator & 0xFF);
705	return 0;
706}
707
708static int vs6624_s_stream(struct v4l2_subdev *sd, int enable)
709{
710	if (enable)
711		vs6624_write(sd, VS6624_USER_CMD, 0x2);
712	else
713		vs6624_write(sd, VS6624_USER_CMD, 0x4);
714	udelay(100);
715	return 0;
716}
717
718#ifdef CONFIG_VIDEO_ADV_DEBUG
719static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
720{
721	reg->val = vs6624_read(sd, reg->reg & 0xffff);
722	reg->size = 1;
723	return 0;
724}
725
726static int vs6624_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
727{
728	vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff);
729	return 0;
730}
731#endif
732
733static const struct v4l2_ctrl_ops vs6624_ctrl_ops = {
734	.s_ctrl = vs6624_s_ctrl,
735};
736
737static const struct v4l2_subdev_core_ops vs6624_core_ops = {
738#ifdef CONFIG_VIDEO_ADV_DEBUG
739	.g_register = vs6624_g_register,
740	.s_register = vs6624_s_register,
741#endif
742};
743
744static const struct v4l2_subdev_video_ops vs6624_video_ops = {
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_pad_ops vs6624_pad_ops = {
751	.enum_mbus_code = vs6624_enum_mbus_code,
752	.get_fmt = vs6624_get_fmt,
753	.set_fmt = vs6624_set_fmt,
754};
755
756static const struct v4l2_subdev_ops vs6624_ops = {
757	.core = &vs6624_core_ops,
758	.video = &vs6624_video_ops,
759	.pad = &vs6624_pad_ops,
760};
761
762static int vs6624_probe(struct i2c_client *client,
763			const struct i2c_device_id *id)
764{
765	struct vs6624 *sensor;
766	struct v4l2_subdev *sd;
767	struct v4l2_ctrl_handler *hdl;
768	const unsigned *ce;
769	int ret;
770
771	/* Check if the adapter supports the needed features */
772	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
773		return -EIO;
774
775	ce = client->dev.platform_data;
776	if (ce == NULL)
777		return -EINVAL;
778
779	ret = devm_gpio_request_one(&client->dev, *ce, GPIOF_OUT_INIT_HIGH,
780				    "VS6624 Chip Enable");
781	if (ret) {
782		v4l_err(client, "failed to request GPIO %d\n", *ce);
783		return ret;
784	}
785	/* wait 100ms before any further i2c writes are performed */
786	mdelay(100);
787
788	sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
789	if (sensor == NULL)
790		return -ENOMEM;
791
792	sd = &sensor->sd;
793	v4l2_i2c_subdev_init(sd, client, &vs6624_ops);
794
795	vs6624_writeregs(sd, vs6624_p1);
796	vs6624_write(sd, VS6624_MICRO_EN, 0x2);
797	vs6624_write(sd, VS6624_DIO_EN, 0x1);
798	mdelay(10);
799	vs6624_writeregs(sd, vs6624_p2);
800
801	vs6624_writeregs(sd, vs6624_default);
802	vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF);
803	vs6624_writeregs(sd, vs6624_run_setup);
804
805	/* set frame rate */
806	sensor->frame_rate.numerator = MAX_FRAME_RATE;
807	sensor->frame_rate.denominator = 1;
808	vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
809	vs6624_write(sd, VS6624_FR_NUM_MSB,
810			sensor->frame_rate.numerator >> 8);
811	vs6624_write(sd, VS6624_FR_NUM_LSB,
812			sensor->frame_rate.numerator & 0xFF);
813	vs6624_write(sd, VS6624_FR_DEN,
814			sensor->frame_rate.denominator & 0xFF);
815
816	sensor->fmt = vs6624_default_fmt;
817	sensor->ce_pin = *ce;
818
819	v4l_info(client, "chip found @ 0x%02x (%s)\n",
820			client->addr << 1, client->adapter->name);
821
822	hdl = &sensor->hdl;
823	v4l2_ctrl_handler_init(hdl, 4);
824	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
825			V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x87);
826	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
827			V4L2_CID_SATURATION, 0, 0xFF, 1, 0x78);
828	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
829			V4L2_CID_HFLIP, 0, 1, 1, 0);
830	v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
831			V4L2_CID_VFLIP, 0, 1, 1, 0);
832	/* hook the control handler into the driver */
833	sd->ctrl_handler = hdl;
834	if (hdl->error) {
835		int err = hdl->error;
836
837		v4l2_ctrl_handler_free(hdl);
838		return err;
839	}
840
841	/* initialize the hardware to the default control values */
842	ret = v4l2_ctrl_handler_setup(hdl);
843	if (ret)
844		v4l2_ctrl_handler_free(hdl);
845	return ret;
846}
847
848static int vs6624_remove(struct i2c_client *client)
849{
850	struct v4l2_subdev *sd = i2c_get_clientdata(client);
851
852	v4l2_device_unregister_subdev(sd);
853	v4l2_ctrl_handler_free(sd->ctrl_handler);
854	return 0;
855}
856
857static const struct i2c_device_id vs6624_id[] = {
858	{"vs6624", 0},
859	{},
860};
861
862MODULE_DEVICE_TABLE(i2c, vs6624_id);
863
864static struct i2c_driver vs6624_driver = {
865	.driver = {
866		.owner  = THIS_MODULE,
867		.name   = "vs6624",
868	},
869	.probe          = vs6624_probe,
870	.remove         = vs6624_remove,
871	.id_table       = vs6624_id,
872};
873
874module_i2c_driver(vs6624_driver);
875
876MODULE_DESCRIPTION("VS6624 sensor driver");
877MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
878MODULE_LICENSE("GPL v2");
879