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