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