blob: b1d0a1b28ca86ddbc56e3a2a644c7ca104925ba4 [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>
Axel Lin37096b42014-08-09 02:59:44 -030033#include <media/v4l2-image-sizes.h>
Scott Jiangf877ed92012-03-08 17:44:16 -030034
35#include "vs6624_regs.h"
36
Scott Jiangf877ed92012-03-08 17:44:16 -030037#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 {
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -030048 u32 mbus_code;
Scott Jiangf877ed92012-03-08 17:44:16 -030049 enum v4l2_colorspace colorspace;
50} vs6624_formats[] = {
51 {
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -030052 .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
Scott Jiangf877ed92012-03-08 17:44:16 -030053 .colorspace = V4L2_COLORSPACE_JPEG,
54 },
55 {
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -030056 .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
Scott Jiangf877ed92012-03-08 17:44:16 -030057 .colorspace = V4L2_COLORSPACE_JPEG,
58 },
59 {
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -030060 .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
Scott Jiangf877ed92012-03-08 17:44:16 -030061 .colorspace = V4L2_COLORSPACE_SRGB,
62 },
63};
64
65static struct v4l2_mbus_framefmt vs6624_default_fmt = {
66 .width = VGA_WIDTH,
67 .height = VGA_HEIGHT,
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -030068 .code = MEDIA_BUS_FMT_UYVY8_2X8,
Scott Jiangf877ed92012-03-08 17:44:16 -030069 .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
Laurent Pinchart7b2f25c2013-11-29 20:01:34 -0300494#ifdef CONFIG_VIDEO_ADV_DEBUG
Scott Jiangf877ed92012-03-08 17:44:16 -0300495static 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}
Laurent Pinchart7b2f25c2013-11-29 20:01:34 -0300507#endif
Scott Jiangf877ed92012-03-08 17:44:16 -0300508
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
Hans Verkuilebcff5f2015-04-09 04:01:33 -0300560static int vs6624_enum_mbus_code(struct v4l2_subdev *sd,
561 struct v4l2_subdev_pad_config *cfg,
562 struct v4l2_subdev_mbus_code_enum *code)
Scott Jiangf877ed92012-03-08 17:44:16 -0300563{
Hans Verkuilebcff5f2015-04-09 04:01:33 -0300564 if (code->pad || code->index >= ARRAY_SIZE(vs6624_formats))
Scott Jiangf877ed92012-03-08 17:44:16 -0300565 return -EINVAL;
566
Hans Verkuilebcff5f2015-04-09 04:01:33 -0300567 code->code = vs6624_formats[code->index].mbus_code;
Scott Jiangf877ed92012-03-08 17:44:16 -0300568 return 0;
569}
570
571static int vs6624_try_mbus_fmt(struct v4l2_subdev *sd,
572 struct v4l2_mbus_framefmt *fmt)
573{
574 int index;
575
576 for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++)
577 if (vs6624_formats[index].mbus_code == fmt->code)
578 break;
579 if (index >= ARRAY_SIZE(vs6624_formats)) {
580 /* default to first format */
581 index = 0;
582 fmt->code = vs6624_formats[0].mbus_code;
583 }
584
585 /* sensor mode is VGA */
586 if (fmt->width > VGA_WIDTH)
587 fmt->width = VGA_WIDTH;
588 if (fmt->height > VGA_HEIGHT)
589 fmt->height = VGA_HEIGHT;
590 fmt->width = fmt->width & (~3);
591 fmt->height = fmt->height & (~3);
592 fmt->field = V4L2_FIELD_NONE;
593 fmt->colorspace = vs6624_formats[index].colorspace;
594 return 0;
595}
596
597static int vs6624_s_mbus_fmt(struct v4l2_subdev *sd,
598 struct v4l2_mbus_framefmt *fmt)
599{
600 struct vs6624 *sensor = to_vs6624(sd);
601 int ret;
602
603 ret = vs6624_try_mbus_fmt(sd, fmt);
604 if (ret)
605 return ret;
606
607 /* set image format */
608 switch (fmt->code) {
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300609 case MEDIA_BUS_FMT_UYVY8_2X8:
Scott Jiangf877ed92012-03-08 17:44:16 -0300610 vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
611 vs6624_write(sd, VS6624_YUV_SETUP, 0x1);
612 break;
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300613 case MEDIA_BUS_FMT_YUYV8_2X8:
Scott Jiangf877ed92012-03-08 17:44:16 -0300614 vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
615 vs6624_write(sd, VS6624_YUV_SETUP, 0x3);
616 break;
Boris BREZILLONf5fe58f2014-11-10 14:28:29 -0300617 case MEDIA_BUS_FMT_RGB565_2X8_LE:
Scott Jiangf877ed92012-03-08 17:44:16 -0300618 vs6624_write(sd, VS6624_IMG_FMT0, 0x4);
619 vs6624_write(sd, VS6624_RGB_SETUP, 0x0);
620 break;
621 default:
622 return -EINVAL;
623 }
624
625 /* set image size */
626 if ((fmt->width == VGA_WIDTH) && (fmt->height == VGA_HEIGHT))
627 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x2);
628 else if ((fmt->width == QVGA_WIDTH) && (fmt->height == QVGA_HEIGHT))
629 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x4);
630 else if ((fmt->width == QQVGA_WIDTH) && (fmt->height == QQVGA_HEIGHT))
631 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x6);
632 else if ((fmt->width == CIF_WIDTH) && (fmt->height == CIF_HEIGHT))
633 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x3);
634 else if ((fmt->width == QCIF_WIDTH) && (fmt->height == QCIF_HEIGHT))
635 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x5);
636 else if ((fmt->width == QQCIF_WIDTH) && (fmt->height == QQCIF_HEIGHT))
637 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x7);
638 else {
639 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x8);
640 vs6624_write(sd, VS6624_MAN_HSIZE0_MSB, fmt->width >> 8);
641 vs6624_write(sd, VS6624_MAN_HSIZE0_LSB, fmt->width & 0xFF);
642 vs6624_write(sd, VS6624_MAN_VSIZE0_MSB, fmt->height >> 8);
643 vs6624_write(sd, VS6624_MAN_VSIZE0_LSB, fmt->height & 0xFF);
644 vs6624_write(sd, VS6624_CROP_CTRL0, 0x1);
645 }
646
647 sensor->fmt = *fmt;
648
649 return 0;
650}
651
652static int vs6624_g_mbus_fmt(struct v4l2_subdev *sd,
653 struct v4l2_mbus_framefmt *fmt)
654{
655 struct vs6624 *sensor = to_vs6624(sd);
656
657 *fmt = sensor->fmt;
658 return 0;
659}
660
661static int vs6624_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
662{
663 struct vs6624 *sensor = to_vs6624(sd);
664 struct v4l2_captureparm *cp = &parms->parm.capture;
665
666 if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
667 return -EINVAL;
668
669 memset(cp, 0, sizeof(*cp));
670 cp->capability = V4L2_CAP_TIMEPERFRAME;
671 cp->timeperframe.numerator = sensor->frame_rate.denominator;
672 cp->timeperframe.denominator = sensor->frame_rate.numerator;
673 return 0;
674}
675
676static int vs6624_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
677{
678 struct vs6624 *sensor = to_vs6624(sd);
679 struct v4l2_captureparm *cp = &parms->parm.capture;
680 struct v4l2_fract *tpf = &cp->timeperframe;
681
682 if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
683 return -EINVAL;
684 if (cp->extendedmode != 0)
685 return -EINVAL;
686
687 if (tpf->numerator == 0 || tpf->denominator == 0
688 || (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) {
689 /* reset to max frame rate */
690 tpf->numerator = 1;
691 tpf->denominator = MAX_FRAME_RATE;
692 }
693 sensor->frame_rate.numerator = tpf->denominator;
694 sensor->frame_rate.denominator = tpf->numerator;
695 vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
696 vs6624_write(sd, VS6624_FR_NUM_MSB,
697 sensor->frame_rate.numerator >> 8);
698 vs6624_write(sd, VS6624_FR_NUM_LSB,
699 sensor->frame_rate.numerator & 0xFF);
700 vs6624_write(sd, VS6624_FR_DEN,
701 sensor->frame_rate.denominator & 0xFF);
702 return 0;
703}
704
705static int vs6624_s_stream(struct v4l2_subdev *sd, int enable)
706{
707 if (enable)
708 vs6624_write(sd, VS6624_USER_CMD, 0x2);
709 else
710 vs6624_write(sd, VS6624_USER_CMD, 0x4);
711 udelay(100);
712 return 0;
713}
714
Scott Jiangf877ed92012-03-08 17:44:16 -0300715#ifdef CONFIG_VIDEO_ADV_DEBUG
716static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
717{
Scott Jiangf877ed92012-03-08 17:44:16 -0300718 reg->val = vs6624_read(sd, reg->reg & 0xffff);
719 reg->size = 1;
720 return 0;
721}
722
Hans Verkuil977ba3b2013-03-24 08:28:46 -0300723static int vs6624_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
Scott Jiangf877ed92012-03-08 17:44:16 -0300724{
Scott Jiangf877ed92012-03-08 17:44:16 -0300725 vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff);
726 return 0;
727}
728#endif
729
730static const struct v4l2_ctrl_ops vs6624_ctrl_ops = {
731 .s_ctrl = vs6624_s_ctrl,
732};
733
734static const struct v4l2_subdev_core_ops vs6624_core_ops = {
Scott Jiangf877ed92012-03-08 17:44:16 -0300735#ifdef CONFIG_VIDEO_ADV_DEBUG
736 .g_register = vs6624_g_register,
737 .s_register = vs6624_s_register,
738#endif
739};
740
741static const struct v4l2_subdev_video_ops vs6624_video_ops = {
Scott Jiangf877ed92012-03-08 17:44:16 -0300742 .try_mbus_fmt = vs6624_try_mbus_fmt,
743 .s_mbus_fmt = vs6624_s_mbus_fmt,
744 .g_mbus_fmt = vs6624_g_mbus_fmt,
745 .s_parm = vs6624_s_parm,
746 .g_parm = vs6624_g_parm,
747 .s_stream = vs6624_s_stream,
748};
749
Hans Verkuilebcff5f2015-04-09 04:01:33 -0300750static const struct v4l2_subdev_pad_ops vs6624_pad_ops = {
751 .enum_mbus_code = vs6624_enum_mbus_code,
752};
753
Scott Jiangf877ed92012-03-08 17:44:16 -0300754static const struct v4l2_subdev_ops vs6624_ops = {
755 .core = &vs6624_core_ops,
756 .video = &vs6624_video_ops,
Hans Verkuilebcff5f2015-04-09 04:01:33 -0300757 .pad = &vs6624_pad_ops,
Scott Jiangf877ed92012-03-08 17:44:16 -0300758};
759
Greg Kroah-Hartman4c62e972012-12-21 13:17:53 -0800760static int vs6624_probe(struct i2c_client *client,
Scott Jiangf877ed92012-03-08 17:44:16 -0300761 const struct i2c_device_id *id)
762{
763 struct vs6624 *sensor;
764 struct v4l2_subdev *sd;
765 struct v4l2_ctrl_handler *hdl;
766 const unsigned *ce;
767 int ret;
768
769 /* Check if the adapter supports the needed features */
770 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
771 return -EIO;
772
773 ce = client->dev.platform_data;
774 if (ce == NULL)
775 return -EINVAL;
776
Laurent Pinchartb015ba22013-05-02 08:29:43 -0300777 ret = devm_gpio_request_one(&client->dev, *ce, GPIOF_OUT_INIT_HIGH,
778 "VS6624 Chip Enable");
Scott Jiangf877ed92012-03-08 17:44:16 -0300779 if (ret) {
780 v4l_err(client, "failed to request GPIO %d\n", *ce);
781 return ret;
782 }
Scott Jiangf877ed92012-03-08 17:44:16 -0300783 /* wait 100ms before any further i2c writes are performed */
784 mdelay(100);
785
Laurent Pinchartc02b2112013-05-02 08:29:43 -0300786 sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
787 if (sensor == NULL)
Scott Jiangf877ed92012-03-08 17:44:16 -0300788 return -ENOMEM;
Scott Jiangf877ed92012-03-08 17:44:16 -0300789
790 sd = &sensor->sd;
791 v4l2_i2c_subdev_init(sd, client, &vs6624_ops);
792
793 vs6624_writeregs(sd, vs6624_p1);
794 vs6624_write(sd, VS6624_MICRO_EN, 0x2);
795 vs6624_write(sd, VS6624_DIO_EN, 0x1);
796 mdelay(10);
797 vs6624_writeregs(sd, vs6624_p2);
798
799 vs6624_writeregs(sd, vs6624_default);
800 vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF);
801 vs6624_writeregs(sd, vs6624_run_setup);
802
803 /* set frame rate */
804 sensor->frame_rate.numerator = MAX_FRAME_RATE;
805 sensor->frame_rate.denominator = 1;
806 vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
807 vs6624_write(sd, VS6624_FR_NUM_MSB,
808 sensor->frame_rate.numerator >> 8);
809 vs6624_write(sd, VS6624_FR_NUM_LSB,
810 sensor->frame_rate.numerator & 0xFF);
811 vs6624_write(sd, VS6624_FR_DEN,
812 sensor->frame_rate.denominator & 0xFF);
813
814 sensor->fmt = vs6624_default_fmt;
815 sensor->ce_pin = *ce;
816
817 v4l_info(client, "chip found @ 0x%02x (%s)\n",
818 client->addr << 1, client->adapter->name);
819
820 hdl = &sensor->hdl;
821 v4l2_ctrl_handler_init(hdl, 4);
822 v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
823 V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x87);
824 v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
825 V4L2_CID_SATURATION, 0, 0xFF, 1, 0x78);
826 v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
827 V4L2_CID_HFLIP, 0, 1, 1, 0);
828 v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
829 V4L2_CID_VFLIP, 0, 1, 1, 0);
830 /* hook the control handler into the driver */
831 sd->ctrl_handler = hdl;
832 if (hdl->error) {
833 int err = hdl->error;
834
835 v4l2_ctrl_handler_free(hdl);
Scott Jiangf877ed92012-03-08 17:44:16 -0300836 return err;
837 }
838
839 /* initialize the hardware to the default control values */
840 ret = v4l2_ctrl_handler_setup(hdl);
Laurent Pinchartb015ba22013-05-02 08:29:43 -0300841 if (ret)
Scott Jiangf877ed92012-03-08 17:44:16 -0300842 v4l2_ctrl_handler_free(hdl);
Scott Jiangf877ed92012-03-08 17:44:16 -0300843 return ret;
844}
845
Greg Kroah-Hartman4c62e972012-12-21 13:17:53 -0800846static int vs6624_remove(struct i2c_client *client)
Scott Jiangf877ed92012-03-08 17:44:16 -0300847{
848 struct v4l2_subdev *sd = i2c_get_clientdata(client);
Scott Jiangf877ed92012-03-08 17:44:16 -0300849
850 v4l2_device_unregister_subdev(sd);
851 v4l2_ctrl_handler_free(sd->ctrl_handler);
Scott Jiangf877ed92012-03-08 17:44:16 -0300852 return 0;
853}
854
855static const struct i2c_device_id vs6624_id[] = {
856 {"vs6624", 0},
857 {},
858};
859
860MODULE_DEVICE_TABLE(i2c, vs6624_id);
861
862static struct i2c_driver vs6624_driver = {
863 .driver = {
864 .owner = THIS_MODULE,
865 .name = "vs6624",
866 },
867 .probe = vs6624_probe,
Greg Kroah-Hartman4c62e972012-12-21 13:17:53 -0800868 .remove = vs6624_remove,
Scott Jiangf877ed92012-03-08 17:44:16 -0300869 .id_table = vs6624_id,
870};
871
Wei Yongjun9ac15102012-10-08 10:13:09 -0300872module_i2c_driver(vs6624_driver);
Scott Jiangf877ed92012-03-08 17:44:16 -0300873
874MODULE_DESCRIPTION("VS6624 sensor driver");
875MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
876MODULE_LICENSE("GPL v2");