2 * Driver for the ov7660 sensor
4 * Copyright (C) 2009 Erik Andrén
5 * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
6 * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
8 * Portions of code to USB interface and ALi driver software,
9 * Copyright (c) 2006 Willem Duinker
10 * v4l2 interface modeled after the V4L2 driver
11 * for SN9C10x PC Camera Controllers
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation, version 2.
19 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
21 #include "m5602_ov7660.h"
23 static int ov7660_s_ctrl(struct v4l2_ctrl
*ctrl
);
24 static void ov7660_dump_registers(struct sd
*sd
);
26 static const unsigned char preinit_ov7660
[][4] = {
27 {BRIDGE
, M5602_XB_MCU_CLK_DIV
, 0x02},
28 {BRIDGE
, M5602_XB_MCU_CLK_CTRL
, 0xb0},
29 {BRIDGE
, M5602_XB_SEN_CLK_DIV
, 0x00},
30 {BRIDGE
, M5602_XB_SEN_CLK_CTRL
, 0xb0},
31 {BRIDGE
, M5602_XB_ADC_CTRL
, 0xc0},
32 {BRIDGE
, M5602_XB_SENSOR_TYPE
, 0x0d},
33 {BRIDGE
, M5602_XB_SENSOR_CTRL
, 0x00},
34 {BRIDGE
, M5602_XB_GPIO_DIR
, 0x03},
35 {BRIDGE
, M5602_XB_GPIO_DIR
, 0x03},
36 {BRIDGE
, M5602_XB_ADC_CTRL
, 0xc0},
37 {BRIDGE
, M5602_XB_SENSOR_TYPE
, 0x0c},
39 {SENSOR
, OV7660_OFON
, 0x0c},
40 {SENSOR
, OV7660_COM2
, 0x11},
41 {SENSOR
, OV7660_COM7
, 0x05},
43 {BRIDGE
, M5602_XB_GPIO_DIR
, 0x01},
44 {BRIDGE
, M5602_XB_GPIO_DAT
, 0x04},
45 {BRIDGE
, M5602_XB_GPIO_EN_H
, 0x06},
46 {BRIDGE
, M5602_XB_GPIO_DIR_H
, 0x06},
47 {BRIDGE
, M5602_XB_GPIO_DAT_H
, 0x00},
48 {BRIDGE
, M5602_XB_SEN_CLK_DIV
, 0x08},
49 {BRIDGE
, M5602_XB_SEN_CLK_CTRL
, 0xb0},
50 {BRIDGE
, M5602_XB_SEN_CLK_DIV
, 0x00},
51 {BRIDGE
, M5602_XB_SEN_CLK_CTRL
, 0xb0},
52 {BRIDGE
, M5602_XB_ADC_CTRL
, 0xc0},
53 {BRIDGE
, M5602_XB_SENSOR_TYPE
, 0x0c},
54 {BRIDGE
, M5602_XB_GPIO_DIR
, 0x05},
55 {BRIDGE
, M5602_XB_GPIO_DAT
, 0x00},
56 {BRIDGE
, M5602_XB_GPIO_EN_H
, 0x06},
57 {BRIDGE
, M5602_XB_GPIO_EN_L
, 0x00}
60 static const unsigned char init_ov7660
[][4] = {
61 {BRIDGE
, M5602_XB_MCU_CLK_DIV
, 0x02},
62 {BRIDGE
, M5602_XB_MCU_CLK_CTRL
, 0xb0},
63 {BRIDGE
, M5602_XB_SEN_CLK_DIV
, 0x00},
64 {BRIDGE
, M5602_XB_SEN_CLK_CTRL
, 0xb0},
65 {BRIDGE
, M5602_XB_ADC_CTRL
, 0xc0},
66 {BRIDGE
, M5602_XB_SENSOR_TYPE
, 0x0d},
67 {BRIDGE
, M5602_XB_SENSOR_CTRL
, 0x00},
68 {BRIDGE
, M5602_XB_GPIO_DIR
, 0x01},
69 {BRIDGE
, M5602_XB_GPIO_DIR
, 0x01},
70 {BRIDGE
, M5602_XB_SEN_CLK_DIV
, 0x00},
71 {BRIDGE
, M5602_XB_SEN_CLK_CTRL
, 0xb0},
72 {BRIDGE
, M5602_XB_ADC_CTRL
, 0xc0},
73 {BRIDGE
, M5602_XB_SENSOR_TYPE
, 0x0c},
74 {BRIDGE
, M5602_XB_GPIO_DIR
, 0x05},
75 {BRIDGE
, M5602_XB_GPIO_DAT
, 0x00},
76 {BRIDGE
, M5602_XB_GPIO_EN_H
, 0x06},
77 {BRIDGE
, M5602_XB_GPIO_EN_L
, 0x00},
78 {SENSOR
, OV7660_COM7
, 0x80},
79 {SENSOR
, OV7660_CLKRC
, 0x80},
80 {SENSOR
, OV7660_COM9
, 0x4c},
81 {SENSOR
, OV7660_OFON
, 0x43},
82 {SENSOR
, OV7660_COM12
, 0x28},
83 {SENSOR
, OV7660_COM8
, 0x00},
84 {SENSOR
, OV7660_COM10
, 0x40},
85 {SENSOR
, OV7660_HSTART
, 0x0c},
86 {SENSOR
, OV7660_HSTOP
, 0x61},
87 {SENSOR
, OV7660_HREF
, 0xa4},
88 {SENSOR
, OV7660_PSHFT
, 0x0b},
89 {SENSOR
, OV7660_VSTART
, 0x01},
90 {SENSOR
, OV7660_VSTOP
, 0x7a},
91 {SENSOR
, OV7660_VSTOP
, 0x00},
92 {SENSOR
, OV7660_COM7
, 0x05},
93 {SENSOR
, OV7660_COM6
, 0x42},
94 {SENSOR
, OV7660_BBIAS
, 0x94},
95 {SENSOR
, OV7660_GbBIAS
, 0x94},
96 {SENSOR
, OV7660_RSVD29
, 0x94},
97 {SENSOR
, OV7660_RBIAS
, 0x94},
98 {SENSOR
, OV7660_COM1
, 0x00},
99 {SENSOR
, OV7660_AECH
, 0x00},
100 {SENSOR
, OV7660_AECHH
, 0x00},
101 {SENSOR
, OV7660_ADC
, 0x05},
102 {SENSOR
, OV7660_COM13
, 0x00},
103 {SENSOR
, OV7660_RSVDA1
, 0x23},
104 {SENSOR
, OV7660_TSLB
, 0x0d},
105 {SENSOR
, OV7660_HV
, 0x80},
106 {SENSOR
, OV7660_LCC1
, 0x00},
107 {SENSOR
, OV7660_LCC2
, 0x00},
108 {SENSOR
, OV7660_LCC3
, 0x10},
109 {SENSOR
, OV7660_LCC4
, 0x40},
110 {SENSOR
, OV7660_LCC5
, 0x01},
112 {SENSOR
, OV7660_AECH
, 0x20},
113 {SENSOR
, OV7660_COM1
, 0x00},
114 {SENSOR
, OV7660_OFON
, 0x0c},
115 {SENSOR
, OV7660_COM2
, 0x11},
116 {SENSOR
, OV7660_COM7
, 0x05},
117 {BRIDGE
, M5602_XB_GPIO_DIR
, 0x01},
118 {BRIDGE
, M5602_XB_GPIO_DAT
, 0x04},
119 {BRIDGE
, M5602_XB_GPIO_EN_H
, 0x06},
120 {BRIDGE
, M5602_XB_GPIO_DIR_H
, 0x06},
121 {BRIDGE
, M5602_XB_GPIO_DAT_H
, 0x00},
122 {BRIDGE
, M5602_XB_SEN_CLK_DIV
, 0x08},
123 {BRIDGE
, M5602_XB_SEN_CLK_CTRL
, 0xb0},
124 {BRIDGE
, M5602_XB_SEN_CLK_DIV
, 0x00},
125 {BRIDGE
, M5602_XB_SEN_CLK_CTRL
, 0xb0},
126 {BRIDGE
, M5602_XB_ADC_CTRL
, 0xc0},
127 {BRIDGE
, M5602_XB_SENSOR_TYPE
, 0x0c},
128 {BRIDGE
, M5602_XB_GPIO_DIR
, 0x05},
129 {BRIDGE
, M5602_XB_GPIO_DAT
, 0x00},
130 {BRIDGE
, M5602_XB_GPIO_EN_H
, 0x06},
131 {BRIDGE
, M5602_XB_GPIO_EN_L
, 0x00},
132 {SENSOR
, OV7660_AECH
, 0x5f},
133 {SENSOR
, OV7660_COM1
, 0x03},
134 {SENSOR
, OV7660_OFON
, 0x0c},
135 {SENSOR
, OV7660_COM2
, 0x11},
136 {SENSOR
, OV7660_COM7
, 0x05},
137 {BRIDGE
, M5602_XB_GPIO_DIR
, 0x01},
138 {BRIDGE
, M5602_XB_GPIO_DAT
, 0x04},
139 {BRIDGE
, M5602_XB_GPIO_EN_H
, 0x06},
140 {BRIDGE
, M5602_XB_GPIO_DIR_H
, 0x06},
141 {BRIDGE
, M5602_XB_GPIO_DAT_H
, 0x00},
142 {BRIDGE
, M5602_XB_SEN_CLK_DIV
, 0x08},
143 {BRIDGE
, M5602_XB_SEN_CLK_CTRL
, 0xb0},
144 {BRIDGE
, M5602_XB_SEN_CLK_DIV
, 0x00},
145 {BRIDGE
, M5602_XB_SEN_CLK_CTRL
, 0xb0},
146 {BRIDGE
, M5602_XB_ADC_CTRL
, 0xc0},
147 {BRIDGE
, M5602_XB_SENSOR_TYPE
, 0x0c},
148 {BRIDGE
, M5602_XB_GPIO_DIR
, 0x05},
149 {BRIDGE
, M5602_XB_GPIO_DAT
, 0x00},
150 {BRIDGE
, M5602_XB_GPIO_EN_H
, 0x06},
151 {BRIDGE
, M5602_XB_GPIO_EN_L
, 0x00},
153 {BRIDGE
, M5602_XB_SEN_CLK_DIV
, 0x06},
154 {BRIDGE
, M5602_XB_SEN_CLK_CTRL
, 0xb0},
155 {BRIDGE
, M5602_XB_ADC_CTRL
, 0xc0},
156 {BRIDGE
, M5602_XB_SENSOR_TYPE
, 0x0c},
157 {BRIDGE
, M5602_XB_LINE_OF_FRAME_H
, 0x81},
158 {BRIDGE
, M5602_XB_PIX_OF_LINE_H
, 0x82},
159 {BRIDGE
, M5602_XB_SIG_INI
, 0x01},
160 {BRIDGE
, M5602_XB_VSYNC_PARA
, 0x00},
161 {BRIDGE
, M5602_XB_VSYNC_PARA
, 0x08},
162 {BRIDGE
, M5602_XB_VSYNC_PARA
, 0x00},
163 {BRIDGE
, M5602_XB_VSYNC_PARA
, 0x00},
164 {BRIDGE
, M5602_XB_VSYNC_PARA
, 0x01},
165 {BRIDGE
, M5602_XB_VSYNC_PARA
, 0xec},
166 {BRIDGE
, M5602_XB_VSYNC_PARA
, 0x00},
167 {BRIDGE
, M5602_XB_VSYNC_PARA
, 0x00},
168 {BRIDGE
, M5602_XB_SIG_INI
, 0x00},
169 {BRIDGE
, M5602_XB_SIG_INI
, 0x02},
170 {BRIDGE
, M5602_XB_HSYNC_PARA
, 0x00},
171 {BRIDGE
, M5602_XB_HSYNC_PARA
, 0x27},
172 {BRIDGE
, M5602_XB_HSYNC_PARA
, 0x02},
173 {BRIDGE
, M5602_XB_HSYNC_PARA
, 0xa7},
174 {BRIDGE
, M5602_XB_SIG_INI
, 0x00},
175 {BRIDGE
, M5602_XB_SEN_CLK_DIV
, 0x00},
176 {BRIDGE
, M5602_XB_SEN_CLK_CTRL
, 0xb0},
179 static struct v4l2_pix_format ov7660_modes
[] = {
188 .colorspace
= V4L2_COLORSPACE_SRGB
,
193 static const struct v4l2_ctrl_ops ov7660_ctrl_ops
= {
194 .s_ctrl
= ov7660_s_ctrl
,
197 int ov7660_probe(struct sd
*sd
)
200 u8 prod_id
= 0, ver_id
= 0;
203 if (force_sensor
== OV7660_SENSOR
) {
204 pr_info("Forcing an %s sensor\n", ov7660
.name
);
207 /* If we want to force another sensor,
208 don't try to probe this one */
213 for (i
= 0; i
< ARRAY_SIZE(preinit_ov7660
) && !err
; i
++) {
216 if (preinit_ov7660
[i
][0] == BRIDGE
) {
217 err
= m5602_write_bridge(sd
,
218 preinit_ov7660
[i
][1],
219 preinit_ov7660
[i
][2]);
221 data
[0] = preinit_ov7660
[i
][2];
222 err
= m5602_write_sensor(sd
,
223 preinit_ov7660
[i
][1], data
, 1);
229 if (m5602_read_sensor(sd
, OV7660_PID
, &prod_id
, 1))
232 if (m5602_read_sensor(sd
, OV7660_VER
, &ver_id
, 1))
235 pr_info("Sensor reported 0x%x%x\n", prod_id
, ver_id
);
237 if ((prod_id
== 0x76) && (ver_id
== 0x60)) {
238 pr_info("Detected a ov7660 sensor\n");
244 sd
->gspca_dev
.cam
.cam_mode
= ov7660_modes
;
245 sd
->gspca_dev
.cam
.nmodes
= ARRAY_SIZE(ov7660_modes
);
250 int ov7660_init(struct sd
*sd
)
254 /* Init the sensor */
255 for (i
= 0; i
< ARRAY_SIZE(init_ov7660
); i
++) {
258 if (init_ov7660
[i
][0] == BRIDGE
) {
259 err
= m5602_write_bridge(sd
,
263 data
[0] = init_ov7660
[i
][2];
264 err
= m5602_write_sensor(sd
,
265 init_ov7660
[i
][1], data
, 1);
272 ov7660_dump_registers(sd
);
277 int ov7660_init_controls(struct sd
*sd
)
279 struct v4l2_ctrl_handler
*hdl
= &sd
->gspca_dev
.ctrl_handler
;
281 sd
->gspca_dev
.vdev
.ctrl_handler
= hdl
;
282 v4l2_ctrl_handler_init(hdl
, 6);
284 v4l2_ctrl_new_std(hdl
, &ov7660_ctrl_ops
, V4L2_CID_AUTO_WHITE_BALANCE
,
286 v4l2_ctrl_new_std_menu(hdl
, &ov7660_ctrl_ops
,
287 V4L2_CID_EXPOSURE_AUTO
, 1, 0, V4L2_EXPOSURE_AUTO
);
289 sd
->autogain
= v4l2_ctrl_new_std(hdl
, &ov7660_ctrl_ops
,
290 V4L2_CID_AUTOGAIN
, 0, 1, 1, 1);
291 sd
->gain
= v4l2_ctrl_new_std(hdl
, &ov7660_ctrl_ops
, V4L2_CID_GAIN
, 0,
292 255, 1, OV7660_DEFAULT_GAIN
);
294 sd
->hflip
= v4l2_ctrl_new_std(hdl
, &ov7660_ctrl_ops
, V4L2_CID_HFLIP
,
296 sd
->vflip
= v4l2_ctrl_new_std(hdl
, &ov7660_ctrl_ops
, V4L2_CID_VFLIP
,
300 pr_err("Could not initialize controls\n");
304 v4l2_ctrl_auto_cluster(2, &sd
->autogain
, 0, false);
305 v4l2_ctrl_cluster(2, &sd
->hflip
);
310 int ov7660_start(struct sd
*sd
)
315 int ov7660_stop(struct sd
*sd
)
320 void ov7660_disconnect(struct sd
*sd
)
327 static int ov7660_set_gain(struct gspca_dev
*gspca_dev
, __s32 val
)
331 struct sd
*sd
= (struct sd
*) gspca_dev
;
333 gspca_dbg(gspca_dev
, D_CONF
, "Setting gain to %d\n", val
);
335 err
= m5602_write_sensor(sd
, OV7660_GAIN
, &i2c_data
, 1);
339 static int ov7660_set_auto_white_balance(struct gspca_dev
*gspca_dev
,
344 struct sd
*sd
= (struct sd
*) gspca_dev
;
346 gspca_dbg(gspca_dev
, D_CONF
, "Set auto white balance to %d\n", val
);
348 err
= m5602_read_sensor(sd
, OV7660_COM8
, &i2c_data
, 1);
352 i2c_data
= ((i2c_data
& 0xfd) | ((val
& 0x01) << 1));
353 err
= m5602_write_sensor(sd
, OV7660_COM8
, &i2c_data
, 1);
358 static int ov7660_set_auto_gain(struct gspca_dev
*gspca_dev
, __s32 val
)
362 struct sd
*sd
= (struct sd
*) gspca_dev
;
364 gspca_dbg(gspca_dev
, D_CONF
, "Set auto gain control to %d\n", val
);
366 err
= m5602_read_sensor(sd
, OV7660_COM8
, &i2c_data
, 1);
370 i2c_data
= ((i2c_data
& 0xfb) | ((val
& 0x01) << 2));
372 return m5602_write_sensor(sd
, OV7660_COM8
, &i2c_data
, 1);
375 static int ov7660_set_auto_exposure(struct gspca_dev
*gspca_dev
,
380 struct sd
*sd
= (struct sd
*) gspca_dev
;
382 gspca_dbg(gspca_dev
, D_CONF
, "Set auto exposure control to %d\n", val
);
384 err
= m5602_read_sensor(sd
, OV7660_COM8
, &i2c_data
, 1);
388 val
= (val
== V4L2_EXPOSURE_AUTO
);
389 i2c_data
= ((i2c_data
& 0xfe) | ((val
& 0x01) << 0));
391 return m5602_write_sensor(sd
, OV7660_COM8
, &i2c_data
, 1);
394 static int ov7660_set_hvflip(struct gspca_dev
*gspca_dev
)
398 struct sd
*sd
= (struct sd
*) gspca_dev
;
400 gspca_dbg(gspca_dev
, D_CONF
, "Set hvflip to %d, %d\n",
401 sd
->hflip
->val
, sd
->vflip
->val
);
403 i2c_data
= (sd
->hflip
->val
<< 5) | (sd
->vflip
->val
<< 4);
405 err
= m5602_write_sensor(sd
, OV7660_MVFP
, &i2c_data
, 1);
410 static int ov7660_s_ctrl(struct v4l2_ctrl
*ctrl
)
412 struct gspca_dev
*gspca_dev
=
413 container_of(ctrl
->handler
, struct gspca_dev
, ctrl_handler
);
414 struct sd
*sd
= (struct sd
*) gspca_dev
;
417 if (!gspca_dev
->streaming
)
421 case V4L2_CID_AUTO_WHITE_BALANCE
:
422 err
= ov7660_set_auto_white_balance(gspca_dev
, ctrl
->val
);
424 case V4L2_CID_EXPOSURE_AUTO
:
425 err
= ov7660_set_auto_exposure(gspca_dev
, ctrl
->val
);
427 case V4L2_CID_AUTOGAIN
:
428 err
= ov7660_set_auto_gain(gspca_dev
, ctrl
->val
);
429 if (err
|| ctrl
->val
)
431 err
= ov7660_set_gain(gspca_dev
, sd
->gain
->val
);
434 err
= ov7660_set_hvflip(gspca_dev
);
443 static void ov7660_dump_registers(struct sd
*sd
)
446 pr_info("Dumping the ov7660 register state\n");
447 for (address
= 0; address
< 0xa9; address
++) {
449 m5602_read_sensor(sd
, address
, &value
, 1);
450 pr_info("register 0x%x contains 0x%x\n", address
, value
);
453 pr_info("ov7660 register state dump complete\n");
455 pr_info("Probing for which registers that are read/write\n");
456 for (address
= 0; address
< 0xff; address
++) {
457 u8 old_value
, ctrl_value
;
458 u8 test_value
[2] = {0xff, 0xff};
460 m5602_read_sensor(sd
, address
, &old_value
, 1);
461 m5602_write_sensor(sd
, address
, test_value
, 1);
462 m5602_read_sensor(sd
, address
, &ctrl_value
, 1);
464 if (ctrl_value
== test_value
[0])
465 pr_info("register 0x%x is writeable\n", address
);
467 pr_info("register 0x%x is read only\n", address
);
469 /* Restore original value */
470 m5602_write_sensor(sd
, address
, &old_value
, 1);