1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/init.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/i2c.h>
22#include <linux/slab.h>
23#include <linux/delay.h>
24#include <linux/v4l2-mediabus.h>
25#include <linux/videodev2.h>
26
27#include <media/ov772x.h>
28#include <media/soc_camera.h>
29#include <media/v4l2-ctrls.h>
30#include <media/v4l2-chip-ident.h>
31#include <media/v4l2-subdev.h>
32
33
34
35
36#define GAIN 0x00
37#define BLUE 0x01
38#define RED 0x02
39#define GREEN 0x03
40#define COM1 0x04
41#define BAVG 0x05
42#define GAVG 0x06
43#define RAVG 0x07
44#define AECH 0x08
45#define COM2 0x09
46#define PID 0x0A
47#define VER 0x0B
48#define COM3 0x0C
49#define COM4 0x0D
50#define COM5 0x0E
51#define COM6 0x0F
52#define AEC 0x10
53#define CLKRC 0x11
54#define COM7 0x12
55#define COM8 0x13
56#define COM9 0x14
57#define COM10 0x15
58#define REG16 0x16
59#define HSTART 0x17
60#define HSIZE 0x18
61#define VSTART 0x19
62#define VSIZE 0x1A
63#define PSHFT 0x1B
64#define MIDH 0x1C
65#define MIDL 0x1D
66#define LAEC 0x1F
67#define COM11 0x20
68#define BDBASE 0x22
69#define DBSTEP 0x23
70#define AEW 0x24
71#define AEB 0x25
72#define VPT 0x26
73#define REG28 0x28
74#define HOUTSIZE 0x29
75#define EXHCH 0x2A
76#define EXHCL 0x2B
77#define VOUTSIZE 0x2C
78#define ADVFL 0x2D
79#define ADVFH 0x2E
80#define YAVE 0x2F
81#define LUMHTH 0x30
82#define LUMLTH 0x31
83#define HREF 0x32
84#define DM_LNL 0x33
85#define DM_LNH 0x34
86#define ADOFF_B 0x35
87#define ADOFF_R 0x36
88#define ADOFF_GB 0x37
89#define ADOFF_GR 0x38
90#define OFF_B 0x39
91#define OFF_R 0x3A
92#define OFF_GB 0x3B
93#define OFF_GR 0x3C
94#define COM12 0x3D
95#define COM13 0x3E
96#define COM14 0x3F
97#define COM15 0x40
98#define COM16 0x41
99#define TGT_B 0x42
100#define TGT_R 0x43
101#define TGT_GB 0x44
102#define TGT_GR 0x45
103
104#define LCC0 0x46
105#define LCC1 0x47
106#define LCC2 0x48
107#define LCC3 0x49
108#define LCC4 0x4A
109#define LCC5 0x4B
110#define LCC6 0x4C
111
112#define LC_CTR 0x46
113#define LC_XC 0x47
114#define LC_YC 0x48
115#define LC_COEF 0x49
116#define LC_RADI 0x4A
117#define LC_COEFB 0x4B
118#define LC_COEFR 0x4C
119
120#define FIXGAIN 0x4D
121#define AREF0 0x4E
122#define AREF1 0x4F
123#define AREF2 0x50
124#define AREF3 0x51
125#define AREF4 0x52
126#define AREF5 0x53
127#define AREF6 0x54
128#define AREF7 0x55
129#define UFIX 0x60
130#define VFIX 0x61
131#define AWBB_BLK 0x62
132#define AWB_CTRL0 0x63
133#define DSP_CTRL1 0x64
134#define DSP_CTRL2 0x65
135#define DSP_CTRL3 0x66
136#define DSP_CTRL4 0x67
137#define AWB_BIAS 0x68
138#define AWB_CTRL1 0x69
139#define AWB_CTRL2 0x6A
140#define AWB_CTRL3 0x6B
141#define AWB_CTRL4 0x6C
142#define AWB_CTRL5 0x6D
143#define AWB_CTRL6 0x6E
144#define AWB_CTRL7 0x6F
145#define AWB_CTRL8 0x70
146#define AWB_CTRL9 0x71
147#define AWB_CTRL10 0x72
148#define AWB_CTRL11 0x73
149#define AWB_CTRL12 0x74
150#define AWB_CTRL13 0x75
151#define AWB_CTRL14 0x76
152#define AWB_CTRL15 0x77
153#define AWB_CTRL16 0x78
154#define AWB_CTRL17 0x79
155#define AWB_CTRL18 0x7A
156#define AWB_CTRL19 0x7B
157#define AWB_CTRL20 0x7C
158#define AWB_CTRL21 0x7D
159#define GAM1 0x7E
160#define GAM2 0x7F
161#define GAM3 0x80
162#define GAM4 0x81
163#define GAM5 0x82
164#define GAM6 0x83
165#define GAM7 0x84
166#define GAM8 0x85
167#define GAM9 0x86
168#define GAM10 0x87
169#define GAM11 0x88
170#define GAM12 0x89
171#define GAM13 0x8A
172#define GAM14 0x8B
173#define GAM15 0x8C
174#define SLOP 0x8D
175#define DNSTH 0x8E
176#define EDGE_STRNGT 0x8F
177#define EDGE_TRSHLD 0x90
178#define DNSOFF 0x91
179#define EDGE_UPPER 0x92
180#define EDGE_LOWER 0x93
181#define MTX1 0x94
182#define MTX2 0x95
183#define MTX3 0x96
184#define MTX4 0x97
185#define MTX5 0x98
186#define MTX6 0x99
187#define MTX_CTRL 0x9A
188#define BRIGHT 0x9B
189#define CNTRST 0x9C
190#define CNTRST_CTRL 0x9D
191#define UVAD_J0 0x9E
192#define UVAD_J1 0x9F
193#define SCAL0 0xA0
194#define SCAL1 0xA1
195#define SCAL2 0xA2
196#define FIFODLYM 0xA3
197#define FIFODLYA 0xA4
198#define SDE 0xA6
199#define USAT 0xA7
200#define VSAT 0xA8
201
202#define HUE0 0xA9
203#define HUE1 0xAA
204
205#define HUECOS 0xA9
206#define HUESIN 0xAA
207
208#define SIGN 0xAB
209#define DSPAUTO 0xAC
210
211
212
213
214
215
216#define SOFT_SLEEP_MODE 0x10
217
218#define OCAP_1x 0x00
219#define OCAP_2x 0x01
220#define OCAP_3x 0x02
221#define OCAP_4x 0x03
222
223
224#define SWAP_MASK (SWAP_RGB | SWAP_YUV | SWAP_ML)
225#define IMG_MASK (VFLIP_IMG | HFLIP_IMG)
226
227#define VFLIP_IMG 0x80
228#define HFLIP_IMG 0x40
229#define SWAP_RGB 0x20
230#define SWAP_YUV 0x10
231#define SWAP_ML 0x08
232
233#define NOTRI_CLOCK 0x04
234
235
236#define NOTRI_DATA 0x02
237
238#define SCOLOR_TEST 0x01
239
240
241
242#define PLL_BYPASS 0x00
243#define PLL_4x 0x40
244#define PLL_6x 0x80
245#define PLL_8x 0xc0
246
247#define AEC_FULL 0x00
248#define AEC_1p2 0x10
249#define AEC_1p4 0x20
250#define AEC_2p3 0x30
251
252
253#define AFR_ON_OFF 0x80
254#define AFR_SPPED 0x40
255
256#define AFR_NO_RATE 0x00
257#define AFR_1p2 0x10
258#define AFR_1p4 0x20
259#define AFR_1p8 0x30
260
261#define AF_2x 0x00
262#define AF_4x 0x04
263#define AF_8x 0x08
264#define AF_16x 0x0c
265
266#define AEC_NO_LIMIT 0x01
267
268
269
270
271#define SCCB_RESET 0x80
272
273
274#define SLCT_MASK 0x40
275#define SLCT_VGA 0x00
276#define SLCT_QVGA 0x40
277#define ITU656_ON_OFF 0x20
278#define SENSOR_RAW 0x10
279
280#define FMT_MASK 0x0c
281#define FMT_GBR422 0x00
282#define FMT_RGB565 0x04
283#define FMT_RGB555 0x08
284#define FMT_RGB444 0x0c
285
286#define OFMT_MASK 0x03
287#define OFMT_YUV 0x00
288#define OFMT_P_BRAW 0x01
289#define OFMT_RGB 0x02
290#define OFMT_BRAW 0x03
291
292
293#define FAST_ALGO 0x80
294
295#define UNLMT_STEP 0x40
296
297#define BNDF_ON_OFF 0x20
298#define AEC_BND 0x10
299#define AEC_ON_OFF 0x08
300#define AGC_ON 0x04
301#define AWB_ON 0x02
302#define AEC_ON 0x01
303
304
305#define BASE_AECAGC 0x80
306
307#define GAIN_2x 0x00
308#define GAIN_4x 0x10
309#define GAIN_8x 0x20
310#define GAIN_16x 0x30
311#define GAIN_32x 0x40
312#define GAIN_64x 0x50
313#define GAIN_128x 0x60
314#define DROP_VSYNC 0x04
315#define DROP_HREF 0x02
316
317
318#define SGLF_ON_OFF 0x02
319#define SGLF_TRIG 0x01
320
321
322#define HREF_VSTART_SHIFT 6
323#define HREF_HSTART_SHIFT 4
324#define HREF_VSIZE_SHIFT 2
325#define HREF_HSIZE_SHIFT 0
326
327
328#define EXHCH_VSIZE_SHIFT 2
329#define EXHCH_HSIZE_SHIFT 0
330
331
332#define FIFO_ON 0x80
333#define UV_ON_OFF 0x40
334#define YUV444_2_422 0x20
335#define CLR_MTRX_ON_OFF 0x10
336#define INTPLT_ON_OFF 0x08
337#define GMM_ON_OFF 0x04
338#define AUTO_BLK_ON_OFF 0x02
339#define AUTO_WHT_ON_OFF 0x01
340
341
342#define UV_MASK 0x80
343#define UV_ON 0x80
344#define UV_OFF 0x00
345#define CBAR_MASK 0x20
346#define CBAR_ON 0x20
347#define CBAR_OFF 0x00
348
349
350#define DSP_OFMT_YUV 0x00
351#define DSP_OFMT_RGB 0x00
352#define DSP_OFMT_RAW8 0x02
353#define DSP_OFMT_RAW10 0x03
354
355
356#define AWB_ACTRL 0x80
357#define DENOISE_ACTRL 0x40
358#define EDGE_ACTRL 0x20
359#define UV_ACTRL 0x10
360#define SCAL0_ACTRL 0x08
361#define SCAL1_2_ACTRL 0x04
362
363#define VGA_WIDTH 640
364#define VGA_HEIGHT 480
365#define QVGA_WIDTH 320
366#define QVGA_HEIGHT 240
367#define OV772X_MAX_WIDTH VGA_WIDTH
368#define OV772X_MAX_HEIGHT VGA_HEIGHT
369
370
371
372
373#define OV7720 0x7720
374#define OV7725 0x7721
375#define VERSION(pid, ver) ((pid<<8)|(ver&0xFF))
376
377
378
379
380
381struct ov772x_color_format {
382 enum v4l2_mbus_pixelcode code;
383 enum v4l2_colorspace colorspace;
384 u8 dsp3;
385 u8 dsp4;
386 u8 com3;
387 u8 com7;
388};
389
390struct ov772x_win_size {
391 char *name;
392 unsigned char com7_bit;
393 struct v4l2_rect rect;
394};
395
396struct ov772x_priv {
397 struct v4l2_subdev subdev;
398 struct v4l2_ctrl_handler hdl;
399 struct ov772x_camera_info *info;
400 const struct ov772x_color_format *cfmt;
401 const struct ov772x_win_size *win;
402 int model;
403 unsigned short flag_vflip:1;
404 unsigned short flag_hflip:1;
405
406 unsigned short band_filter;
407};
408
409
410
411
412static const struct ov772x_color_format ov772x_cfmts[] = {
413 {
414 .code = V4L2_MBUS_FMT_YUYV8_2X8,
415 .colorspace = V4L2_COLORSPACE_JPEG,
416 .dsp3 = 0x0,
417 .dsp4 = DSP_OFMT_YUV,
418 .com3 = SWAP_YUV,
419 .com7 = OFMT_YUV,
420 },
421 {
422 .code = V4L2_MBUS_FMT_YVYU8_2X8,
423 .colorspace = V4L2_COLORSPACE_JPEG,
424 .dsp3 = UV_ON,
425 .dsp4 = DSP_OFMT_YUV,
426 .com3 = SWAP_YUV,
427 .com7 = OFMT_YUV,
428 },
429 {
430 .code = V4L2_MBUS_FMT_UYVY8_2X8,
431 .colorspace = V4L2_COLORSPACE_JPEG,
432 .dsp3 = 0x0,
433 .dsp4 = DSP_OFMT_YUV,
434 .com3 = 0x0,
435 .com7 = OFMT_YUV,
436 },
437 {
438 .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
439 .colorspace = V4L2_COLORSPACE_SRGB,
440 .dsp3 = 0x0,
441 .dsp4 = DSP_OFMT_YUV,
442 .com3 = SWAP_RGB,
443 .com7 = FMT_RGB555 | OFMT_RGB,
444 },
445 {
446 .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
447 .colorspace = V4L2_COLORSPACE_SRGB,
448 .dsp3 = 0x0,
449 .dsp4 = DSP_OFMT_YUV,
450 .com3 = 0x0,
451 .com7 = FMT_RGB555 | OFMT_RGB,
452 },
453 {
454 .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
455 .colorspace = V4L2_COLORSPACE_SRGB,
456 .dsp3 = 0x0,
457 .dsp4 = DSP_OFMT_YUV,
458 .com3 = SWAP_RGB,
459 .com7 = FMT_RGB565 | OFMT_RGB,
460 },
461 {
462 .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
463 .colorspace = V4L2_COLORSPACE_SRGB,
464 .dsp3 = 0x0,
465 .dsp4 = DSP_OFMT_YUV,
466 .com3 = 0x0,
467 .com7 = FMT_RGB565 | OFMT_RGB,
468 },
469 {
470
471
472
473
474 .code = V4L2_MBUS_FMT_SBGGR10_1X10,
475 .colorspace = V4L2_COLORSPACE_SRGB,
476 .dsp3 = 0x0,
477 .dsp4 = DSP_OFMT_RAW10,
478 .com3 = 0x0,
479 .com7 = SENSOR_RAW | OFMT_BRAW,
480 },
481};
482
483
484
485
486
487
488static const struct ov772x_win_size ov772x_win_sizes[] = {
489 {
490 .name = "VGA",
491 .com7_bit = SLCT_VGA,
492 .rect = {
493 .left = 140,
494 .top = 14,
495 .width = VGA_WIDTH,
496 .height = VGA_HEIGHT,
497 },
498 }, {
499 .name = "QVGA",
500 .com7_bit = SLCT_QVGA,
501 .rect = {
502 .left = 252,
503 .top = 6,
504 .width = QVGA_WIDTH,
505 .height = QVGA_HEIGHT,
506 },
507 },
508};
509
510
511
512
513
514static struct ov772x_priv *to_ov772x(struct v4l2_subdev *sd)
515{
516 return container_of(sd, struct ov772x_priv, subdev);
517}
518
519static inline int ov772x_read(struct i2c_client *client, u8 addr)
520{
521 return i2c_smbus_read_byte_data(client, addr);
522}
523
524static inline int ov772x_write(struct i2c_client *client, u8 addr, u8 value)
525{
526 return i2c_smbus_write_byte_data(client, addr, value);
527}
528
529static int ov772x_mask_set(struct i2c_client *client, u8 command, u8 mask,
530 u8 set)
531{
532 s32 val = ov772x_read(client, command);
533 if (val < 0)
534 return val;
535
536 val &= ~mask;
537 val |= set & mask;
538
539 return ov772x_write(client, command, val);
540}
541
542static int ov772x_reset(struct i2c_client *client)
543{
544 int ret;
545
546 ret = ov772x_write(client, COM7, SCCB_RESET);
547 if (ret < 0)
548 return ret;
549
550 msleep(1);
551
552 return ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
553}
554
555
556
557
558
559static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
560{
561 struct i2c_client *client = v4l2_get_subdevdata(sd);
562 struct ov772x_priv *priv = to_ov772x(sd);
563
564 if (!enable) {
565 ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
566 return 0;
567 }
568
569 ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0);
570
571 dev_dbg(&client->dev, "format %d, win %s\n",
572 priv->cfmt->code, priv->win->name);
573
574 return 0;
575}
576
577static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
578{
579 struct ov772x_priv *priv = container_of(ctrl->handler,
580 struct ov772x_priv, hdl);
581 struct v4l2_subdev *sd = &priv->subdev;
582 struct i2c_client *client = v4l2_get_subdevdata(sd);
583 int ret = 0;
584 u8 val;
585
586 switch (ctrl->id) {
587 case V4L2_CID_VFLIP:
588 val = ctrl->val ? VFLIP_IMG : 0x00;
589 priv->flag_vflip = ctrl->val;
590 if (priv->info->flags & OV772X_FLAG_VFLIP)
591 val ^= VFLIP_IMG;
592 return ov772x_mask_set(client, COM3, VFLIP_IMG, val);
593 case V4L2_CID_HFLIP:
594 val = ctrl->val ? HFLIP_IMG : 0x00;
595 priv->flag_hflip = ctrl->val;
596 if (priv->info->flags & OV772X_FLAG_HFLIP)
597 val ^= HFLIP_IMG;
598 return ov772x_mask_set(client, COM3, HFLIP_IMG, val);
599 case V4L2_CID_BAND_STOP_FILTER:
600 if (!ctrl->val) {
601
602 ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff);
603 if (!ret)
604 ret = ov772x_mask_set(client, COM8,
605 BNDF_ON_OFF, 0);
606 } else {
607
608 val = 256 - ctrl->val;
609 ret = ov772x_mask_set(client, COM8,
610 BNDF_ON_OFF, BNDF_ON_OFF);
611 if (!ret)
612 ret = ov772x_mask_set(client, BDBASE,
613 0xff, val);
614 }
615 if (!ret)
616 priv->band_filter = ctrl->val;
617 return ret;
618 }
619
620 return -EINVAL;
621}
622
623static int ov772x_g_chip_ident(struct v4l2_subdev *sd,
624 struct v4l2_dbg_chip_ident *id)
625{
626 struct ov772x_priv *priv = to_ov772x(sd);
627
628 id->ident = priv->model;
629 id->revision = 0;
630
631 return 0;
632}
633
634#ifdef CONFIG_VIDEO_ADV_DEBUG
635static int ov772x_g_register(struct v4l2_subdev *sd,
636 struct v4l2_dbg_register *reg)
637{
638 struct i2c_client *client = v4l2_get_subdevdata(sd);
639 int ret;
640
641 reg->size = 1;
642 if (reg->reg > 0xff)
643 return -EINVAL;
644
645 ret = ov772x_read(client, reg->reg);
646 if (ret < 0)
647 return ret;
648
649 reg->val = (__u64)ret;
650
651 return 0;
652}
653
654static int ov772x_s_register(struct v4l2_subdev *sd,
655 const struct v4l2_dbg_register *reg)
656{
657 struct i2c_client *client = v4l2_get_subdevdata(sd);
658
659 if (reg->reg > 0xff ||
660 reg->val > 0xff)
661 return -EINVAL;
662
663 return ov772x_write(client, reg->reg, reg->val);
664}
665#endif
666
667static int ov772x_s_power(struct v4l2_subdev *sd, int on)
668{
669 struct i2c_client *client = v4l2_get_subdevdata(sd);
670 struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
671
672 return soc_camera_set_power(&client->dev, ssdd, on);
673}
674
675static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
676{
677 const struct ov772x_win_size *win = &ov772x_win_sizes[0];
678 u32 best_diff = UINT_MAX;
679 unsigned int i;
680
681 for (i = 0; i < ARRAY_SIZE(ov772x_win_sizes); ++i) {
682 u32 diff = abs(width - ov772x_win_sizes[i].rect.width)
683 + abs(height - ov772x_win_sizes[i].rect.height);
684 if (diff < best_diff) {
685 best_diff = diff;
686 win = &ov772x_win_sizes[i];
687 }
688 }
689
690 return win;
691}
692
693static void ov772x_select_params(const struct v4l2_mbus_framefmt *mf,
694 const struct ov772x_color_format **cfmt,
695 const struct ov772x_win_size **win)
696{
697 unsigned int i;
698
699
700 *cfmt = &ov772x_cfmts[0];
701
702 for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) {
703 if (mf->code == ov772x_cfmts[i].code) {
704 *cfmt = &ov772x_cfmts[i];
705 break;
706 }
707 }
708
709
710 *win = ov772x_select_win(mf->width, mf->height);
711}
712
713static int ov772x_set_params(struct ov772x_priv *priv,
714 const struct ov772x_color_format *cfmt,
715 const struct ov772x_win_size *win)
716{
717 struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
718 int ret;
719 u8 val;
720
721
722
723
724 ov772x_reset(client);
725
726
727
728
729 if (priv->info->edgectrl.strength & OV772X_MANUAL_EDGE_CTRL) {
730
731
732
733
734
735
736
737
738 ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00);
739 if (ret < 0)
740 goto ov772x_set_fmt_error;
741
742 ret = ov772x_mask_set(client,
743 EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK,
744 priv->info->edgectrl.threshold);
745 if (ret < 0)
746 goto ov772x_set_fmt_error;
747
748 ret = ov772x_mask_set(client,
749 EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK,
750 priv->info->edgectrl.strength);
751 if (ret < 0)
752 goto ov772x_set_fmt_error;
753
754 } else if (priv->info->edgectrl.upper > priv->info->edgectrl.lower) {
755
756
757
758
759
760 ret = ov772x_mask_set(client,
761 EDGE_UPPER, OV772X_EDGE_UPPER_MASK,
762 priv->info->edgectrl.upper);
763 if (ret < 0)
764 goto ov772x_set_fmt_error;
765
766 ret = ov772x_mask_set(client,
767 EDGE_LOWER, OV772X_EDGE_LOWER_MASK,
768 priv->info->edgectrl.lower);
769 if (ret < 0)
770 goto ov772x_set_fmt_error;
771 }
772
773
774 ret = ov772x_write(client, HSTART, win->rect.left >> 2);
775 if (ret < 0)
776 goto ov772x_set_fmt_error;
777 ret = ov772x_write(client, HSIZE, win->rect.width >> 2);
778 if (ret < 0)
779 goto ov772x_set_fmt_error;
780 ret = ov772x_write(client, VSTART, win->rect.top >> 1);
781 if (ret < 0)
782 goto ov772x_set_fmt_error;
783 ret = ov772x_write(client, VSIZE, win->rect.height >> 1);
784 if (ret < 0)
785 goto ov772x_set_fmt_error;
786 ret = ov772x_write(client, HOUTSIZE, win->rect.width >> 2);
787 if (ret < 0)
788 goto ov772x_set_fmt_error;
789 ret = ov772x_write(client, VOUTSIZE, win->rect.height >> 1);
790 if (ret < 0)
791 goto ov772x_set_fmt_error;
792 ret = ov772x_write(client, HREF,
793 ((win->rect.top & 1) << HREF_VSTART_SHIFT) |
794 ((win->rect.left & 3) << HREF_HSTART_SHIFT) |
795 ((win->rect.height & 1) << HREF_VSIZE_SHIFT) |
796 ((win->rect.width & 3) << HREF_HSIZE_SHIFT));
797 if (ret < 0)
798 goto ov772x_set_fmt_error;
799 ret = ov772x_write(client, EXHCH,
800 ((win->rect.height & 1) << EXHCH_VSIZE_SHIFT) |
801 ((win->rect.width & 3) << EXHCH_HSIZE_SHIFT));
802 if (ret < 0)
803 goto ov772x_set_fmt_error;
804
805
806
807
808 val = cfmt->dsp3;
809 if (val) {
810 ret = ov772x_mask_set(client,
811 DSP_CTRL3, UV_MASK, val);
812 if (ret < 0)
813 goto ov772x_set_fmt_error;
814 }
815
816
817 if (cfmt->dsp4) {
818 ret = ov772x_write(client, DSP_CTRL4, cfmt->dsp4);
819 if (ret < 0)
820 goto ov772x_set_fmt_error;
821 }
822
823
824
825
826 val = cfmt->com3;
827 if (priv->info->flags & OV772X_FLAG_VFLIP)
828 val |= VFLIP_IMG;
829 if (priv->info->flags & OV772X_FLAG_HFLIP)
830 val |= HFLIP_IMG;
831 if (priv->flag_vflip)
832 val ^= VFLIP_IMG;
833 if (priv->flag_hflip)
834 val ^= HFLIP_IMG;
835
836 ret = ov772x_mask_set(client,
837 COM3, SWAP_MASK | IMG_MASK, val);
838 if (ret < 0)
839 goto ov772x_set_fmt_error;
840
841
842 ret = ov772x_write(client, COM7, win->com7_bit | cfmt->com7);
843 if (ret < 0)
844 goto ov772x_set_fmt_error;
845
846
847
848
849 if (priv->band_filter) {
850 ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1);
851 if (!ret)
852 ret = ov772x_mask_set(client, BDBASE,
853 0xff, 256 - priv->band_filter);
854 if (ret < 0)
855 goto ov772x_set_fmt_error;
856 }
857
858 return ret;
859
860ov772x_set_fmt_error:
861
862 ov772x_reset(client);
863
864 return ret;
865}
866
867static int ov772x_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
868{
869 a->c.left = 0;
870 a->c.top = 0;
871 a->c.width = VGA_WIDTH;
872 a->c.height = VGA_HEIGHT;
873 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
874
875 return 0;
876}
877
878static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
879{
880 a->bounds.left = 0;
881 a->bounds.top = 0;
882 a->bounds.width = OV772X_MAX_WIDTH;
883 a->bounds.height = OV772X_MAX_HEIGHT;
884 a->defrect = a->bounds;
885 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
886 a->pixelaspect.numerator = 1;
887 a->pixelaspect.denominator = 1;
888
889 return 0;
890}
891
892static int ov772x_g_fmt(struct v4l2_subdev *sd,
893 struct v4l2_mbus_framefmt *mf)
894{
895 struct ov772x_priv *priv = to_ov772x(sd);
896
897 mf->width = priv->win->rect.width;
898 mf->height = priv->win->rect.height;
899 mf->code = priv->cfmt->code;
900 mf->colorspace = priv->cfmt->colorspace;
901 mf->field = V4L2_FIELD_NONE;
902
903 return 0;
904}
905
906static int ov772x_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
907{
908 struct ov772x_priv *priv = to_ov772x(sd);
909 const struct ov772x_color_format *cfmt;
910 const struct ov772x_win_size *win;
911 int ret;
912
913 ov772x_select_params(mf, &cfmt, &win);
914
915 ret = ov772x_set_params(priv, cfmt, win);
916 if (ret < 0)
917 return ret;
918
919 priv->win = win;
920 priv->cfmt = cfmt;
921
922 mf->code = cfmt->code;
923 mf->width = win->rect.width;
924 mf->height = win->rect.height;
925 mf->field = V4L2_FIELD_NONE;
926 mf->colorspace = cfmt->colorspace;
927
928 return 0;
929}
930
931static int ov772x_try_fmt(struct v4l2_subdev *sd,
932 struct v4l2_mbus_framefmt *mf)
933{
934 const struct ov772x_color_format *cfmt;
935 const struct ov772x_win_size *win;
936
937 ov772x_select_params(mf, &cfmt, &win);
938
939 mf->code = cfmt->code;
940 mf->width = win->rect.width;
941 mf->height = win->rect.height;
942 mf->field = V4L2_FIELD_NONE;
943 mf->colorspace = cfmt->colorspace;
944
945 return 0;
946}
947
948static int ov772x_video_probe(struct ov772x_priv *priv)
949{
950 struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
951 u8 pid, ver;
952 const char *devname;
953 int ret;
954
955 ret = ov772x_s_power(&priv->subdev, 1);
956 if (ret < 0)
957 return ret;
958
959
960
961
962 pid = ov772x_read(client, PID);
963 ver = ov772x_read(client, VER);
964
965 switch (VERSION(pid, ver)) {
966 case OV7720:
967 devname = "ov7720";
968 priv->model = V4L2_IDENT_OV7720;
969 break;
970 case OV7725:
971 devname = "ov7725";
972 priv->model = V4L2_IDENT_OV7725;
973 break;
974 default:
975 dev_err(&client->dev,
976 "Product ID error %x:%x\n", pid, ver);
977 ret = -ENODEV;
978 goto done;
979 }
980
981 dev_info(&client->dev,
982 "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
983 devname,
984 pid,
985 ver,
986 ov772x_read(client, MIDH),
987 ov772x_read(client, MIDL));
988 ret = v4l2_ctrl_handler_setup(&priv->hdl);
989
990done:
991 ov772x_s_power(&priv->subdev, 0);
992 return ret;
993}
994
995static const struct v4l2_ctrl_ops ov772x_ctrl_ops = {
996 .s_ctrl = ov772x_s_ctrl,
997};
998
999static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
1000 .g_chip_ident = ov772x_g_chip_ident,
1001#ifdef CONFIG_VIDEO_ADV_DEBUG
1002 .g_register = ov772x_g_register,
1003 .s_register = ov772x_s_register,
1004#endif
1005 .s_power = ov772x_s_power,
1006};
1007
1008static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
1009 enum v4l2_mbus_pixelcode *code)
1010{
1011 if (index >= ARRAY_SIZE(ov772x_cfmts))
1012 return -EINVAL;
1013
1014 *code = ov772x_cfmts[index].code;
1015 return 0;
1016}
1017
1018static int ov772x_g_mbus_config(struct v4l2_subdev *sd,
1019 struct v4l2_mbus_config *cfg)
1020{
1021 struct i2c_client *client = v4l2_get_subdevdata(sd);
1022 struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
1023
1024 cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
1025 V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
1026 V4L2_MBUS_DATA_ACTIVE_HIGH;
1027 cfg->type = V4L2_MBUS_PARALLEL;
1028 cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
1029
1030 return 0;
1031}
1032
1033static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
1034 .s_stream = ov772x_s_stream,
1035 .g_mbus_fmt = ov772x_g_fmt,
1036 .s_mbus_fmt = ov772x_s_fmt,
1037 .try_mbus_fmt = ov772x_try_fmt,
1038 .cropcap = ov772x_cropcap,
1039 .g_crop = ov772x_g_crop,
1040 .enum_mbus_fmt = ov772x_enum_fmt,
1041 .g_mbus_config = ov772x_g_mbus_config,
1042};
1043
1044static struct v4l2_subdev_ops ov772x_subdev_ops = {
1045 .core = &ov772x_subdev_core_ops,
1046 .video = &ov772x_subdev_video_ops,
1047};
1048
1049
1050
1051
1052
1053static int ov772x_probe(struct i2c_client *client,
1054 const struct i2c_device_id *did)
1055{
1056 struct ov772x_priv *priv;
1057 struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
1058 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
1059 int ret;
1060
1061 if (!ssdd || !ssdd->drv_priv) {
1062 dev_err(&client->dev, "OV772X: missing platform data!\n");
1063 return -EINVAL;
1064 }
1065
1066 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
1067 dev_err(&adapter->dev,
1068 "I2C-Adapter doesn't support "
1069 "I2C_FUNC_SMBUS_BYTE_DATA\n");
1070 return -EIO;
1071 }
1072
1073 priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
1074 if (!priv)
1075 return -ENOMEM;
1076
1077 priv->info = ssdd->drv_priv;
1078
1079 v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
1080 v4l2_ctrl_handler_init(&priv->hdl, 3);
1081 v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
1082 V4L2_CID_VFLIP, 0, 1, 1, 0);
1083 v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
1084 V4L2_CID_HFLIP, 0, 1, 1, 0);
1085 v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
1086 V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0);
1087 priv->subdev.ctrl_handler = &priv->hdl;
1088 if (priv->hdl.error)
1089 return priv->hdl.error;
1090
1091 ret = ov772x_video_probe(priv);
1092 if (ret < 0) {
1093 v4l2_ctrl_handler_free(&priv->hdl);
1094 } else {
1095 priv->cfmt = &ov772x_cfmts[0];
1096 priv->win = &ov772x_win_sizes[0];
1097 }
1098 return ret;
1099}
1100
1101static int ov772x_remove(struct i2c_client *client)
1102{
1103 struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client));
1104
1105 v4l2_device_unregister_subdev(&priv->subdev);
1106 v4l2_ctrl_handler_free(&priv->hdl);
1107 return 0;
1108}
1109
1110static const struct i2c_device_id ov772x_id[] = {
1111 { "ov772x", 0 },
1112 { }
1113};
1114MODULE_DEVICE_TABLE(i2c, ov772x_id);
1115
1116static struct i2c_driver ov772x_i2c_driver = {
1117 .driver = {
1118 .name = "ov772x",
1119 },
1120 .probe = ov772x_probe,
1121 .remove = ov772x_remove,
1122 .id_table = ov772x_id,
1123};
1124
1125module_i2c_driver(ov772x_i2c_driver);
1126
1127MODULE_DESCRIPTION("SoC Camera driver for ov772x");
1128MODULE_AUTHOR("Kuninori Morimoto");
1129MODULE_LICENSE("GPL v2");
1130