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