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