3 * @author Brian Johnson
6 * @brief Common functions and data for the Omnivision OV965x sensor series.
8 * @note Copyright (C) Brian Johnson
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 * @brief Addresses and values for the initialization of ov965x sensors
36 static __u8 ov965x_init
[][2] = {
37 {OV965X_CTL_COM7
, OV965X_COM7_SCCB_RESET
},
38 {OV965X_CTL_GAIN
, 0x00},
39 {OV965X_CTL_BLUE
, 0x78},
40 {OV965X_CTL_RED
, 0x78},
41 {OV965X_CTL_VREF
, OV965X_VREF_VSTOP_LOW3(0x06) |
42 OV965X_VREF_VSTART_LOW3(0x06)},
43 {OV965X_CTL_COM1
, 0x03},
44 {OV965X_CTL_BAVE
, 0x00}, /* default */
45 {OV965X_CTL_GEAVE
, 0x00}, /* default */
46 {OV965X_CTL_RAVE
, 0x00}, /* default */
47 {OV965X_CTL_COM2
, OV965X_COM2_OUTPUT_DRIVE_CAP_2X
},
48 {OV965X_CTL_COM3
, 0x00},
49 {OV965X_CTL_COM4
, 0x00},
50 {OV965X_CTL_COM5
, OV965X_COM5_15FPS_48MHZ_RGB
| 0x20},
51 {OV965X_CTL_COM6
, OV965X_COM6_TIMING_RESET_ON_FMT_CHANGE
| 0x50},
52 {OV965X_CTL_AECH
, 0x7c},
53 {OV965X_CTL_CLKRC
, OV965X_CLKRC_DBL_CLK_ENABLE
},
54 {OV965X_CTL_COM7
, OV965X_COM7_OUTPUT_VGA
| OV965X_COM7_OUTPUT_RAW_RGB
},
55 {OV965X_CTL_COM8
, OV965X_COM8_FAST_AGC_AEC
|
56 OV965X_COM8_AEC_STEP_SIZE_NOLIMIT
|
57 OV965X_COM8_AGC_ENABLE
|
58 OV965X_COM8_AEC_ENABLE
|
59 OV965X_COM8_AWB_ENABLE
},
60 {OV965X_CTL_COM9
, OV965X_COM9_MAX_AGC_8X
|
61 OV965X_COM9_RELAX_EXPOSURE_TIMING
|
62 OV965X_COM9_DROP_VSYNC_ON_FRAME_DROP
|
63 OV965X_COM9_DROP_FRAME_ON_BIG_AEC
},
64 {OV965X_CTL_COM10
, 0x00},
65 {0x16, 0x07}, /* reserved */
66 {OV965X_CTL_HSTART
, 0x24},
67 {OV965X_CTL_HSTOP
, 0xc5},
68 {OV965X_CTL_VSTRT
, 0x00},
69 {OV965X_CTL_VSTOP
, 0x3c},
70 {OV965X_CTL_PSHIFT
, 0x00}, /* default */
71 {OV965X_CTL_MVFP
, 0x04},
72 {OV965X_CTL_LAEC
, 0x00}, /* reserved */
73 {OV965X_CTL_AEW
, 0x78}, /* default */
74 {OV965X_CTL_AEB
, 0x68}, /* default */
75 {OV965X_CTL_VPT
, 0xd4}, /* default */
76 {OV965X_CTL_BBIAS
, OV965X_BIAS_SUBTRACT
}, /* default */
77 {OV965X_CTL_GbBIAS
, OV965X_BIAS_SUBTRACT
}, /* default */
78 {OV965X_CTL_Gr_COM
, OV965X_Gr_COM_BYPASS_ANALOG_BLC
|
79 OV965X_Gr_COM_BYPASS_REGULATOR
},
80 {OV965X_CTL_EXHCH
, 0x00}, /* default */
81 {OV965X_CTL_EXHCL
, 0x00}, /* default */
82 {OV965X_CTL_RBIAS
, OV965X_BIAS_SUBTRACT
}, /* default */
83 {OV965X_CTL_ADVFL
, 0x00}, /* default */
84 {OV965X_CTL_ADVFH
, 0x00}, /* default */
85 {OV965X_CTL_YAVE
, 0x00}, /* default */
86 {OV965X_CTL_HSYST
, 0x08}, /* default */
87 {OV965X_CTL_HSYEN
, 0x30}, /* default */
88 {OV965X_CTL_HREF
, OV965X_HREF_EDGE_OFT_TO_DATA_OUT(2) |
89 OV965X_HREF_HSTOP_LOW3(0) |
90 OV965X_HREF_HSTART_LOW3(4)},
91 {OV965X_CTL_CHLF
, 0xe2}, /* reserved */
92 {OV965X_CTL_ARBLM
, 0xbf}, /* reserved */
93 {0x35, 0x81}, /* reserved */
94 {0x36, 0xf9}, /* reserved */
95 {OV965X_CTL_ADC
, 0x00}, /* reserved */
96 {OV965X_CTL_ACOM
, 0x93}, /* reserved */
97 {OV965X_CTL_OFON
, 0x50},
98 {OV965X_CTL_TSLB
, OV965X_TSLB_OUTPUT_SEQ_UYVY
|
99 OV965X_TSLB_DIGITAL_BLC_ENABLE
},
100 {OV965X_CTL_COM11
, OV965X_COM11_MANUAL_BANDING_FILTER
},
101 {OV965X_CTL_COM12
, 0x73},
102 {OV965X_CTL_COM13
, OV965X_COM13_ENABLE_COLOR_MATRIX
|
103 OV965X_COM13_DELAY_Y_CHANNEL
|
104 OV965X_COM13_OUTPUT_DELAY(1)},
105 {OV965X_CTL_COM14
, OV965X_COM14_YUV_EDGE_ENHANCE
|
106 OV965X_COM14_EDGE_ENHANCE_FACTOR_DBL
| 0x0b},
107 {OV965X_CTL_EDGE
, OV965X_EDGE_EDGE_ENHANCE_LOW4(8) |
108 OV965X_EDGE_EDGE_ENHANCE_FACTOR(8)},
109 {OV965X_CTL_COM15
, OV965X_COM15_OUTPUT_RANGE_O0_TO_FF
| 0x01},
110 {OV965X_CTL_COM16
, 0x00},
111 {OV965X_CTL_COM17
, 0x08},
112 {OV965X_CTL_MANU
, 0x80}, /* default */
113 {OV965X_CTL_MANV
, 0x80}, /* default */
114 {OV965X_CTL_HV
, 0x40},
115 {OV965X_CTL_MBD
, 0x00}, /* default */
116 {OV965X_CTL_DBLV
, 0x0a}, /* reserved */
117 {OV965X_CTL_COM21
, 0x06}, /* reserved */
118 {OV965X_CTL_COM22
, 0x20},
119 {OV965X_CTL_COM23
, 0x00}, /* default */
120 {OV965X_CTL_COM24
, 0x00}, /* reserved */
121 {OV965X_CTL_DBLC1
, 0xdf},
122 {OV965X_CTL_DM_LNL
, 0x00}, /* default */
123 {OV965X_CTL_DM_LNH
, 0x00}, /* default */
124 {0x94, 0x88}, /* reserved */
125 {0x95, 0x88}, /* reserved */
126 {0x96, 0x04}, /* reserved */
127 {OV965X_CTL_AECHM
, 0x00},
128 {OV965X_CTL_COM26
, 0x80}, /* reserved */
129 {0xa8, 0x80}, /* reserved */
130 {0xa9, 0xb8}, /* reserved */
131 {0xaa, 0x92}, /* reserved */
132 {0xab, 0x0a}, /* reserved */
136 * @brief Initialize ov965x sensors
138 * @param dev Pointer to device structure
140 * @return 0 or negative error code
142 * This function applies the default settings from #ov965x_init to
146 int ov965x_initialize(struct usb_microdia
*dev
)
151 for (i
= 0; i
< ARRAY_SIZE(ov965x_init
); i
++) {
152 reg
= ov965x_init
[i
][0];
153 value
= ov965x_init
[i
][1];
154 ret
= sn9c20x_write_i2c_data(dev
, dev
->sensor_slave_address
, 1,
155 reg
, dev
->sensor_flags
, &value
);
157 UDIA_INFO("Sensor Init Error (%d). line %d\n", ret
, i
);
168 * @brief Addresses and values for the initialization of SOI968 sensors
172 static __u8 soi968_init
[][2] = {
173 /* reset all registers */
178 /* snapshot mode: off */
181 /* enable offset adjustment,
183 * analogue2digital control black-level calibration
187 /* Clock: internal PLL on */
191 /* Analoge Black-level calibration off , no anaolgue gain */
197 /* special system settings (voltage, analogue2digital, ...) */
203 /* next 7 are unknown/reserved */
212 /* disable banding filter in dark environment,
213 * VSYNC is dropped when framerate is dropped,
214 * drop frmaes when exposure out of tolerance,
215 * unfreeze exposure and gain values
219 /* AEC, AGC, AWB disabled; fast AEC */
222 /* output: VGA, master mode */
225 /* set HSTART, HSTOP, VSTART and VSTOP */
230 {0x32, 0x24}, /* LSB for all four */
232 /* this register contains the product ID, it is read-only
235 /* AWB update threshold,
236 * blue and red gain LSB
240 /* CLock: internal PLL off */
243 /* Line interval adjustment */
253 /* blue and red gain - default*/
259 * @brief Initialize SOI968 sensors
261 * @param dev Pointer to device structure
263 * @return 0 or negative error code
267 * This function applies the default settings from #soi968_init to
271 int soi968_initialize(struct usb_microdia
*dev
)
276 for (i
= 0; i
< ARRAY_SIZE(soi968_init
); i
++) {
277 reg
= soi968_init
[i
][0];
278 value
= soi968_init
[i
][1];
279 ret
= sn9c20x_write_i2c_data(dev
, dev
->sensor_slave_address
, 1,
280 reg
, dev
->sensor_flags
, &value
);
282 UDIA_INFO("Sensor Init Error (%d). line %d\n", ret
, i
);
292 * @brief Set hflip and vflip in ov965x sensors
294 * @param dev Pointer to device structure
296 * @returns 0 or negative error code
299 int ov965x_set_hvflip(struct usb_microdia
*dev
)
304 * Changing hstop value seems to be necessary to keep correct
305 * colors during a vflip. The values don't seem to make much
306 * sense since to keep the correct color value i'm setting hstop
307 * to the same value as hstart is set for.
310 ret
= sn9c20x_read_i2c_data(dev
, dev
->sensor_slave_address
, 1,
311 OV965X_CTL_MVFP
, dev
->sensor_flags
, &value
);
315 if (dev
->vsettings
.hflip
)
316 value
|= OV965X_MVFP_MIRROR
;
318 value
&= ~OV965X_MVFP_MIRROR
;
320 if (dev
->vsettings
.vflip
) {
322 value
|= OV965X_MVFP_VFLIP
;
324 value
&= ~OV965X_MVFP_VFLIP
;
327 ret
= sn9c20x_write_i2c_data(dev
, dev
->sensor_slave_address
, 1,
328 OV965X_CTL_HSTOP
, dev
->sensor_flags
, &hstop
);
330 ret
= sn9c20x_write_i2c_data(dev
, dev
->sensor_slave_address
, 1,
331 OV965X_CTL_MVFP
, dev
->sensor_flags
, &value
);
337 * @brief Set exposure for ov965x sensors
341 * @returns 0 or negative error value
343 * The used registers do not show up the datasheets.
346 int ov965x_set_exposure(struct usb_microdia
*dev
)
349 __u8 v1
= (dev
->vsettings
.exposure
>> 4) & 0xff;
350 __u8 v2
= dev
->vsettings
.exposure
>> 12;
352 ret
|= sn9c20x_write_i2c_data(dev
, dev
->sensor_slave_address
, 1, 0x2d,
353 dev
->sensor_flags
, &v1
);
355 ret
|= sn9c20x_write_i2c_data(dev
, dev
->sensor_slave_address
, 1, 0x2e,
356 dev
->sensor_flags
, &v2
);
362 * @brief Set autoexposure for ov96xx sensors
366 * @returns 0 or negative error value
370 * For all OV965x and SOI968 sensors.
372 int ov965x_set_autoexposure(struct usb_microdia
*dev
)
377 /* Read current value of the I2C-register
378 * controlling AutoExposureControl:
380 ret
= sn9c20x_read_i2c_data(dev
, dev
->sensor_slave_address
,
381 1, 0x13, dev
->sensor_flags
, buf
);
383 UDIA_ERROR("Error: setting of auto exposure failed: "
384 "error while reading from I2C-register 0x13");
388 /* Determine new value for register 0x13: */
389 if (dev
->vsettings
.auto_exposure
== 1) {
390 /* Enable automatic exposure: */
392 } else if (dev
->vsettings
.auto_exposure
== 0) {
393 /* Disable automatic exposure: */
398 /* Write new value to I2C-register 0x13: */
399 ret
= sn9c20x_write_i2c_data(dev
, dev
->sensor_slave_address
,
400 1, 0x13, dev
->sensor_flags
, buf
);
402 UDIA_ERROR("Error: setting of auto exposure failed: "
403 "error while writing to I2C-register 0x13");
410 * @brief Set exposure for SOI968 sensors
414 * @returns 0 or negative error value
418 * For SOI968 sensors.
420 int soi968_set_exposure(struct usb_microdia
*dev
)
423 int exposure
= dev
->vsettings
.exposure
;
424 __u8 buf1
, buf2
, buf3
;
426 /* Read current value of the I2C-register
427 * containing exposure LSB:
429 ret
= sn9c20x_read_i2c_data(dev
, dev
->sensor_slave_address
,
430 1, 0x04, dev
->sensor_flags
, &buf1
);
432 UDIA_ERROR("Error: setting exposure failed: "
433 "error while reading from I2C-register 0x04");
437 value
= (exposure
* 0x07ff / 0xffff) & 0x07ff;
438 buf2
= ((__u8
) (value
& 0x07)) | (buf1
& ~0x07);
439 buf3
= (__u8
) (value
>> 3) & 0xff;
441 /* Write new value to I2C-register 0x04: */
442 ret
= sn9c20x_write_i2c_data(dev
, dev
->sensor_slave_address
,
443 1, 0x04, dev
->sensor_flags
, &buf2
);
445 UDIA_ERROR("Error: setting exposure failed: "
446 "error while writing to I2C-register 0x04");
450 /* Write new value to I2C-register 0x10: */
451 ret
= sn9c20x_write_i2c_data(dev
, dev
->sensor_slave_address
,
452 1, 0x10, dev
->sensor_flags
, &buf3
);
454 UDIA_ERROR("Error: setting exposure failed: "
455 "error while writing to I2C-register 0x10");