Merge 5.0-rc6 into driver-core-next
[linux/fpc-iii.git] / drivers / media / i2c / vs6624.c
blobbc9825f4a73d6a4221d85faed392617afc607cb9
1 /*
2 * vs6624.c ST VS6624 CMOS image sensor driver
4 * Copyright (c) 2011 Analog Devices Inc.
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.
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.
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>
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>
31 #include "vs6624_regs.h"
33 #define MAX_FRAME_RATE 30
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;
43 static const struct vs6624_format {
44 u32 mbus_code;
45 enum v4l2_colorspace colorspace;
46 } vs6624_formats[] = {
48 .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
49 .colorspace = V4L2_COLORSPACE_JPEG,
52 .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
53 .colorspace = V4L2_COLORSPACE_JPEG,
56 .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
57 .colorspace = V4L2_COLORSPACE_SRGB,
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,
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,
395 static const u16 vs6624_p2[] = {
396 0x806f, 0x01,
397 0x058c, 0x01,
398 0x0000, 0x00,
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,
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,
481 static inline struct vs6624 *to_vs6624(struct v4l2_subdev *sd)
483 return container_of(sd, struct vs6624, sd);
485 static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
487 return &container_of(ctrl->handler, struct vs6624, hdl)->sd;
490 #ifdef CONFIG_VIDEO_ADV_DEBUG
491 static int vs6624_read(struct v4l2_subdev *sd, u16 index)
493 struct i2c_client *client = v4l2_get_subdevdata(sd);
494 u8 buf[2];
496 buf[0] = index >> 8;
497 buf[1] = index;
498 i2c_master_send(client, buf, 2);
499 i2c_master_recv(client, buf, 1);
501 return buf[0];
503 #endif
505 static int vs6624_write(struct v4l2_subdev *sd, u16 index,
506 u8 value)
508 struct i2c_client *client = v4l2_get_subdevdata(sd);
509 u8 buf[3];
511 buf[0] = index >> 8;
512 buf[1] = index;
513 buf[2] = value;
515 return i2c_master_send(client, buf, 3);
518 static int vs6624_writeregs(struct v4l2_subdev *sd, const u16 *regs)
520 u16 reg;
521 u8 data;
523 while (*regs != 0x00) {
524 reg = *regs++;
525 data = *regs++;
527 vs6624_write(sd, reg, data);
529 return 0;
532 static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl)
534 struct v4l2_subdev *sd = to_sd(ctrl);
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;
553 return 0;
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)
560 if (code->pad || code->index >= ARRAY_SIZE(vs6624_formats))
561 return -EINVAL;
563 code->code = vs6624_formats[code->index].mbus_code;
564 return 0;
567 static int vs6624_set_fmt(struct v4l2_subdev *sd,
568 struct v4l2_subdev_pad_config *cfg,
569 struct v4l2_subdev_format *format)
571 struct v4l2_mbus_framefmt *fmt = &format->format;
572 struct vs6624 *sensor = to_vs6624(sd);
573 int index;
575 if (format->pad)
576 return -EINVAL;
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;
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;
597 if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
598 cfg->try_fmt = *fmt;
599 return 0;
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;
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);
642 sensor->fmt = *fmt;
644 return 0;
647 static int vs6624_get_fmt(struct v4l2_subdev *sd,
648 struct v4l2_subdev_pad_config *cfg,
649 struct v4l2_subdev_format *format)
651 struct vs6624 *sensor = to_vs6624(sd);
653 if (format->pad)
654 return -EINVAL;
656 format->format = sensor->fmt;
657 return 0;
660 static int vs6624_g_frame_interval(struct v4l2_subdev *sd,
661 struct v4l2_subdev_frame_interval *ival)
663 struct vs6624 *sensor = to_vs6624(sd);
665 ival->interval.numerator = sensor->frame_rate.denominator;
666 ival->interval.denominator = sensor->frame_rate.numerator;
667 return 0;
670 static int vs6624_s_frame_interval(struct v4l2_subdev *sd,
671 struct v4l2_subdev_frame_interval *ival)
673 struct vs6624 *sensor = to_vs6624(sd);
674 struct v4l2_fract *tpf = &ival->interval;
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;
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;
695 static int vs6624_s_stream(struct v4l2_subdev *sd, int enable)
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;
705 #ifdef CONFIG_VIDEO_ADV_DEBUG
706 static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
708 reg->val = vs6624_read(sd, reg->reg & 0xffff);
709 reg->size = 1;
710 return 0;
713 static int vs6624_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
715 vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff);
716 return 0;
718 #endif
720 static const struct v4l2_ctrl_ops vs6624_ctrl_ops = {
721 .s_ctrl = vs6624_s_ctrl,
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
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,
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,
743 static const struct v4l2_subdev_ops vs6624_ops = {
744 .core = &vs6624_core_ops,
745 .video = &vs6624_video_ops,
746 .pad = &vs6624_pad_ops,
749 static int vs6624_probe(struct i2c_client *client,
750 const struct i2c_device_id *id)
752 struct vs6624 *sensor;
753 struct v4l2_subdev *sd;
754 struct v4l2_ctrl_handler *hdl;
755 const unsigned *ce;
756 int ret;
758 /* Check if the adapter supports the needed features */
759 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
760 return -EIO;
762 ce = client->dev.platform_data;
763 if (ce == NULL)
764 return -EINVAL;
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;
772 /* wait 100ms before any further i2c writes are performed */
773 msleep(100);
775 sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
776 if (sensor == NULL)
777 return -ENOMEM;
779 sd = &sensor->sd;
780 v4l2_i2c_subdev_init(sd, client, &vs6624_ops);
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);
788 vs6624_writeregs(sd, vs6624_default);
789 vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF);
790 vs6624_writeregs(sd, vs6624_run_setup);
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);
803 sensor->fmt = vs6624_default_fmt;
804 sensor->ce_pin = *ce;
806 v4l_info(client, "chip found @ 0x%02x (%s)\n",
807 client->addr << 1, client->adapter->name);
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;
824 v4l2_ctrl_handler_free(hdl);
825 return err;
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;
835 static int vs6624_remove(struct i2c_client *client)
837 struct v4l2_subdev *sd = i2c_get_clientdata(client);
839 v4l2_device_unregister_subdev(sd);
840 v4l2_ctrl_handler_free(sd->ctrl_handler);
841 return 0;
844 static const struct i2c_device_id vs6624_id[] = {
845 {"vs6624", 0},
849 MODULE_DEVICE_TABLE(i2c, vs6624_id);
851 static struct i2c_driver vs6624_driver = {
852 .driver = {
853 .name = "vs6624",
855 .probe = vs6624_probe,
856 .remove = vs6624_remove,
857 .id_table = vs6624_id,
860 module_i2c_driver(vs6624_driver);
862 MODULE_DESCRIPTION("VS6624 sensor driver");
863 MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
864 MODULE_LICENSE("GPL v2");