Doxygen fixes and missing nextlines in UDIA
[microdia.git] / omnivision.c
blobdf1887112bc7c968c40c3221cadaef845346dd85
1 /**
2 * @file omnivision.c
3 * @date 2008-10-27
5 * @brief Common control functions for Omnivision Image Sensors.
7 * @par Licences
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "microdia.h"
25 #include "sn9c20x.h"
26 #include "ov7660.h"
27 #include "ov7670.h"
28 #include "ov965x.h"
30 static __u8 ov7660_init[][2] = {
31 /* System CLK selection, to get a higher Frame Rate */
32 {OV7660_CTL_COM5, 0x80},
33 /* OV7660 Wakeup */
34 /* COM4 is Reserved : using default value 0x40 OR windows driver value 0x08 */
35 {OV7660_CTL_COM4, 0x08},
36 /* Enable HREF at optical black, Use optical black line as BLC signal
37 Reset all timing when format changes, Enable ADBLC option */
38 {OV7660_CTL_COM6, 0xc3},
39 /* windows 0x00, default 0x00, trying 0x60 to enable CCIR656 format */
40 {OV7660_CTL_COM1, 0xc3},
41 /* default is 0x40, windows sets it to 0x00 */
42 {OV7660_CTL_AECH, 0x40},
43 /* default is 0x00, windows sets it to 0x40 */
44 {OV7660_CTL_CLKRC, 0x40},
45 /* Set O/P format - RGB Selection, Set O/P format Raw RGB */
46 {OV7660_CTL_COM7, 0x05},
47 /* default is 0x8f, windows used 0xf8 */
48 /* Enable fast AGC/AEC algorithm, AEC - Step size limit = 1/16 x AEC */
49 /* Banding & Reserved are disabled. AGC, AEC enabled, 0x85 */
50 {OV7660_CTL_COM8, 0xb8},
51 /* video appears jagged w/o these ADC writes */
52 {OV7660_CTL_ADC, 0x0f},
53 {OV7660_CTL_ACOM, 0x02},
54 {OV7660_CTL_OFON, 0x43},
55 /* video appears jagged w/o this write */
56 /* Default 0x0c sets format to uYvY, Windows driver 0x00 sets format to YuYv */
57 {OV7660_CTL_TSLB, 0x00},
58 /* Not doing this write makes the video look green */
59 /* Manual Banding Filter MSB , set B & R channel pre-gain */
60 {OV7660_CTL_HV, 0x90},
61 /* No video stream w/o these ADVFL/ADVFH write totally black */
62 {OV7660_CTL_ADVFL, 0xf6},
63 {OV7660_CTL_ADVFH, 0x0b},
64 /* Setting BLUE to 0x78; RED to 0x78 to get natural colors in artificial light */
65 {OV7660_CTL_BLUE, 0x78},
66 /* Setting RED to 0x50 to get natural colors in natural light */
67 {OV7660_CTL_RED, 0x50},
70 static __u8 ov7670_init[][2] = {
71 /* Phase 1 */
72 {OV7670_CTL_COM7, 0x80},
73 {OV7670_CTL_CLKRC, 0x80},
74 {OV7670_CTL_TSLB, 0x04},
75 {OV7670_CTL_COM7, 0x00},
76 {OV7670_CTL_HREF, 0xb6},
77 {OV7670_CTL_VREF, 0x0a},
78 {OV7670_CTL_COM3, 0x00},
79 {OV7670_CTL_COM14, 0x00},
80 {OV7670_CTL_SCALING_XSC, 0x3a},
81 {OV7670_CTL_SCALING_YSC, 0x35},
82 {OV7670_CTL_SCALING_DCWCTR, 0x11},
83 {OV7670_CTL_SCALING_PCLK_DIV, 0xf0},
84 {OV7670_CTL_SCALING_PCLK_DELAY, 0x02},
85 {OV7670_CTL_COM8, 0xe0},
86 {OV7670_CTL_GAIN, 0x00},
87 {OV7670_CTL_AECH, 0x00},
88 {OV7670_CTL_COM4, 0x40},
89 {OV7670_CTL_COM9, 0x08},
90 {OV7670_CTL_BD50MAX, 0x05},
91 {OV7670_CTL_BD60MAX, 0x07},
92 {OV7670_CTL_AEW, 0x95},
93 {OV7670_CTL_AEB, 0x33},
94 {OV7670_CTL_VPT, 0xe3},
95 {OV7670_CTL_HAECC1, 0x75},
96 {OV7670_CTL_HAECC2, 0x65},
97 {0xa1, 0x0b},
98 {OV7670_CTL_HAECC3, 0xd8},
99 {OV7670_CTL_HAECC4, 0xd8},
100 {OV7670_CTL_HAECC5, 0xf0},
101 {OV7670_CTL_HAECC6, 0x90},
102 {OV7670_CTL_HAECC7, 0x94},
103 {OV7670_CTL_COM8, 0xe5},
104 {OV7670_CTL_COM5, 0x61},
105 {OV7670_CTL_COM6, 0x4b},
106 {0x16, 0x02},
107 {OV7670_CTL_MVFP, 0x27},
108 {OV7670_CTL_ADCCTR1, 0x02},
109 {OV7670_CTL_ADCCTR2, 0x91},
110 {0x29, 0x07},
111 {OV7670_CTL_CHLF, 0x0b},
112 {0x35, 0x0b},
113 {OV7670_CTL_ADC, 0x1d},
114 {OV7670_CTL_ACOM, 0x71},
115 {OV7670_CTL_OFON, 0x2a},
116 {OV7670_CTL_COM12, 0x78},
117 {0x4d, 0x40},
118 {0x4e, 0x20},
119 {OV7670_CTL_GFIX, 0x00},
120 {OV7670_CTL_REG74, 0x19},
121 {0x8d, 0x4f},
122 {0x8e, 0x00},
123 {0x8f, 0x00},
124 {0x90, 0x00},
125 {0x91, 0x00},
126 {0x96, 0x00},
127 {0x9a, 0x80},
128 {0xb0, 0x84},
129 {OV7670_CTL_ABLC1, 0x0c},
130 {0xb2, 0x0e},
131 {OV7670_CTL_THL_ST, 0x82},
132 {0xb8, 0x0a},
133 {OV7670_CTL_AWBC1, 0x0a},
134 {OV7670_CTL_AWBC2, 0xf0},
135 {OV7670_CTL_AWBC3, 0x20},
136 {OV7670_CTL_AWBC4, 0x7d},
137 {OV7670_CTL_AWBC5, 0x29},
138 {OV7670_CTL_AWBC6, 0x4a},
139 {0x59, 0x8c},
140 {0x5a, 0xa5},
141 {0x5b, 0xde},
142 {0x5c, 0x96},
143 {0x5d, 0x66},
144 {0x5e, 0x10},
145 {OV7670_CTL_AWBCTR3, 0x0a},
146 {OV7670_CTL_AWBCTR2, 0x55},
147 {OV7670_CTL_AWBCTR1, 0x11},
148 {OV7670_CTL_AWBCTR0, 0x9e},
149 {OV7670_CTL_GGAIN, 0x40},
150 {OV7670_CTL_BLUE, 0x40},
151 {OV7670_CTL_RED, 0x40},
152 {OV7670_CTL_COM8, 0xe7},
153 {OV7670_CTL_MTX1, 0x6e},
154 {OV7670_CTL_MTX2, 0x70},
155 {OV7670_CTL_MTX3, 0x02},
156 {OV7670_CTL_MTX4, 0x1d},
157 {OV7670_CTL_MTX5, 0x56},
158 {OV7670_CTL_MTX6, 0x73},
159 {OV7670_CTL_BRIGHT, 0x0a},
160 {OV7670_CTL_CONTRAS, 0x55},
161 {OV7670_CTL_CONTRAS_CENTER, 0x80},
162 {OV7670_CTL_MTXS, 0x9e},
163 {OV7670_CTL_COM16, 0x08},
164 {OV7670_CTL_EDGE, 0x02},
165 {OV7670_CTL_REG75, 0x03},
166 {OV7670_CTL_REG76, 0x63},
167 {OV7670_CTL_DNSTH, 0x04},
168 {OV7670_CTL_REG77, 0x06},
169 {OV7670_CTL_COM13, 0xc2},
170 {OV7670_CTL_REG4B, 0x09},
171 {OV7670_CTL_SATCTR, 0x30},
172 {OV7670_CTL_COM16, 0x08},
173 {OV7670_CTL_CONTRAS, 0x48},
174 {OV7670_CTL_ARBLM, 0x11},
175 {OV7670_CTL_COM11, 0xc2},
176 {OV7670_CTL_NT_CTRL, 0x88},
177 {0x96, 0x00},
178 {0x97, 0x30},
179 {0x98, 0x20},
180 {0x99, 0x30},
181 {0x9a, 0x84},
182 {0x9b, 0x29},
183 {0x9c, 0x03},
184 {OV7670_CTL_BD50ST, 0x99},
185 {OV7670_CTL_BD60ST, 0x7f},
186 {0x78, 0x04},
187 {0x79, 0x01},
188 {0xc8, 0xf0},
189 {0x79, 0x0f},
190 {0xc8, 0x00},
191 {0x79, 0x10},
192 {0xc8, 0x7e},
193 {0x79, 0x0a},
194 {0xc8, 0x80},
195 {0x79, 0x0b},
196 {0xc8, 0x01},
197 {0x79, 0x0c},
198 {0xc8, 0x0f},
199 {0x79, 0x0d},
200 {0xc8, 0x20},
201 {0x79, 0x09},
202 {0xc8, 0x80},
203 {0x79, 0x02},
204 {0xc8, 0xc0},
205 {0x79, 0x03},
206 {0xc8, 0x40},
207 {0x79, 0x05},
208 {0xc8, 0x30},
209 {0x79, 0x26},
210 {OV7670_CTL_LCC1, 0x20},
211 {OV7670_CTL_LCC2, 0x00},
212 {OV7670_CTL_LCC3, 0x06},
213 {OV7670_CTL_LCC4, 0x00},
214 {OV7670_CTL_LCC5, 0x05},
215 {OV7670_CTL_LCC6, 0x05},
216 {OV7670_CTL_LCC7, 0x0a},
217 {OV7670_CTL_HSTART, 0x13},
218 {OV7670_CTL_HSTOP, 0x01},
219 {OV7670_CTL_VSTRT, 0x02},
220 {OV7670_CTL_VSTOP, 0x7a},
221 {OV7670_CTL_AWBC4, 0x59},
222 {OV7670_CTL_AWBC5, 0x30},
223 {OV7670_CTL_MTXS, 0x9a},
224 {0x59, 0x84},
225 {0x5a, 0x91},
226 {0x5b, 0x57},
227 {0x5c, 0x75},
228 {0x5d, 0x6d},
229 {0x5e, 0x13},
230 {OV7670_CTL_LCC3, 0x07},
231 {OV7670_CTL_LCC6, 0x07},
232 {OV7670_CTL_LCC7, 0x0d},
233 {OV7670_CTL_HAECC3, 0xdf},
234 {OV7670_CTL_HAECC4, 0xdf},
235 {OV7670_CTL_AWBC6, 0x4d},
236 {OV7670_CTL_MTX3, 0x00},
237 /* Phase 2 */
238 {OV7670_CTL_DBLV, 0x0a},
239 {OV7670_CTL_CLKRC, 0x80},
240 {OV7670_CTL_EXHCH, 0x00},
241 {OV7670_CTL_EXHCL, 0x00},
242 {OV7670_CTL_DM_LNL, 0x00},
243 {OV7670_CTL_DM_LNH,0x00},
244 {OV7670_CTL_COM11, 0xc2},
245 {OV7670_CTL_BRIGHT, 0x0a},
246 {OV7670_CTL_CONTRAS, 0x60},
247 {OV7670_CTL_MTX1, 0x6e},
248 {OV7670_CTL_MTX1 + 1, 0x70},
249 {OV7670_CTL_MTX1 + 2, 0x00},
250 {OV7670_CTL_MTX1 + 3, 0x1d},
251 {OV7670_CTL_MTX5, 0x56},
252 {OV7670_CTL_MTX5 + 1, 0x73},
253 {OV7670_CTL_MTXS, 0x9a},
254 {OV7670_CTL_MTX1, 0x6e},
255 {OV7670_CTL_MTX1 + 1, 0x70},
256 {OV7670_CTL_MTX1 + 2, 0x00},
257 {OV7670_CTL_MTX1 + 3, 0x1d},
258 {OV7670_CTL_MTX5, 0x56},
259 {OV7670_CTL_MTX5 + 1, 0x73},
260 {OV7670_CTL_MTXS, 0x9a},
261 {OV7670_CTL_EDGE, 0x01},
262 {OV7670_CTL_GAM1, 0x03},
263 {OV7670_CTL_GAM1 + 1, 0x09},
264 {OV7670_CTL_GAM1 + 2, 0x16},
265 {OV7670_CTL_GAM1 + 3, 0x38},
266 {OV7670_CTL_GAM5, 0x47},
267 {OV7670_CTL_GAM5 + 1, 0x53},
268 {OV7670_CTL_GAM5 + 2, 0x5e},
269 {OV7670_CTL_GAM5 + 3, 0x6a},
270 {OV7670_CTL_GAM9, 0x74},
271 {OV7670_CTL_GAM9 + 1, 0x80},
272 {OV7670_CTL_GAM9 + 2, 0x8c},
273 {OV7670_CTL_GAM9 + 3, 0x9b},
274 {OV7670_CTL_GAM13, 0xb2},
275 {OV7670_CTL_GAM13 + 1, 0xcc},
276 {OV7670_CTL_GAM13 + 2, 0xe5},
277 {OV7670_CTL_SLOP, 0x24},
278 {OV7670_CTL_COM11, 0xc0},
279 {OV7670_CTL_COM11, 0xc0},
280 {OV7670_CTL_HAECC1, 0x76},
281 {OV7670_CTL_HAECC1 + 1, 0x65},
282 {OV7670_CTL_COM8, 0xe7},
283 /* Phase 3 */
284 {OV7670_CTL_DBLV, 0x0a},
285 {OV7670_CTL_CLKRC, 0x80},
286 {OV7670_CTL_EXHCH, 0x00},
287 {OV7670_CTL_EXHCL, 0x00},
288 {OV7670_CTL_DM_LNL, 0x00},
289 {OV7670_CTL_DM_LNH, 0x00},
293 * @var ov9650_init
294 * @brief Addresses and values for the initialization of ov965x sensors
297 static __u8 ov9650_init[][2] = {
298 {OV965X_CTL_COM7, OV965X_COM7_SCCB_RESET},
299 {OV965X_CTL_GAIN, 0x00},
300 {OV965X_CTL_BLUE, 0x78},
301 {OV965X_CTL_RED, 0x78},
302 {OV965X_CTL_VREF, OV965X_VREF_VSTOP_LOW3(0x06) |
303 OV965X_VREF_VSTART_LOW3(0x06)},
304 {OV965X_CTL_COM1, 0x03},
305 {OV965X_CTL_BAVE, 0x00}, /* default */
306 {OV965X_CTL_GEAVE, 0x00}, /* default */
307 {OV965X_CTL_RAVE, 0x00}, /* default */
308 {OV965X_CTL_COM2, OV965X_COM2_OUTPUT_DRIVE_CAP_2X},
309 {OV965X_CTL_COM3, 0x00},
310 {OV965X_CTL_COM4, 0x00},
311 {OV965X_CTL_COM5, OV965X_COM5_15FPS_48MHZ_RGB | 0x20},
312 {OV965X_CTL_COM6, OV965X_COM6_TIMING_RESET_ON_FMT_CHANGE | 0x50},
313 {OV965X_CTL_AECH, 0x7c},
314 {OV965X_CTL_CLKRC, OV965X_CLKRC_DBL_CLK_ENABLE},
315 {OV965X_CTL_COM7, OV965X_COM7_OUTPUT_VGA | OV965X_COM7_OUTPUT_RAW_RGB},
316 {OV965X_CTL_COM8, OV965X_COM8_FAST_AGC_AEC |
317 OV965X_COM8_AEC_STEP_SIZE_NOLIMIT |
318 OV965X_COM8_AGC_ENABLE |
319 OV965X_COM8_AEC_ENABLE |
320 OV965X_COM8_AWB_ENABLE},
321 {OV965X_CTL_COM9, OV965X_COM9_MAX_AGC_8X |
322 OV965X_COM9_RELAX_EXPOSURE_TIMING |
323 OV965X_COM9_DROP_VSYNC_ON_FRAME_DROP |
324 OV965X_COM9_DROP_FRAME_ON_BIG_AEC},
325 {OV965X_CTL_COM10, 0x00},
326 {0x16, 0x07}, /* reserved */
327 {OV965X_CTL_HSTART, 0x24},
328 {OV965X_CTL_HSTOP, 0xc5},
329 {OV965X_CTL_VSTRT, 0x00},
330 {OV965X_CTL_VSTOP, 0x3c},
331 {OV965X_CTL_PSHIFT, 0x00}, /* default */
332 {OV965X_CTL_MVFP, 0x04},
333 {OV965X_CTL_LAEC, 0x00}, /* reserved */
334 {OV965X_CTL_AEW, 0x78}, /* default */
335 {OV965X_CTL_AEB, 0x68}, /* default */
336 {OV965X_CTL_VPT, 0xd4}, /* default */
337 {OV965X_CTL_BBIAS, OV965X_BIAS_SUBTRACT}, /* default */
338 {OV965X_CTL_GbBIAS, OV965X_BIAS_SUBTRACT}, /* default */
339 {OV965X_CTL_Gr_COM, OV965X_Gr_COM_BYPASS_ANALOG_BLC |
340 OV965X_Gr_COM_BYPASS_REGULATOR},
341 {OV965X_CTL_EXHCH, 0x00}, /* default */
342 {OV965X_CTL_EXHCL, 0x00}, /* default */
343 {OV965X_CTL_RBIAS, OV965X_BIAS_SUBTRACT}, /* default */
344 {OV965X_CTL_ADVFL, 0x00}, /* default */
345 {OV965X_CTL_ADVFH, 0x00}, /* default */
346 {OV965X_CTL_YAVE, 0x00}, /* default */
347 {OV965X_CTL_HSYST, 0x08}, /* default */
348 {OV965X_CTL_HSYEN, 0x30}, /* default */
349 {OV965X_CTL_HREF, OV965X_HREF_EDGE_OFT_TO_DATA_OUT(2) |
350 OV965X_HREF_HSTOP_LOW3(0) |
351 OV965X_HREF_HSTART_LOW3(4)},
352 {OV965X_CTL_CHLF, 0xe2}, /* reserved */
353 {OV965X_CTL_ARBLM, 0xbf}, /* reserved */
354 {0x35, 0x81}, /* reserved */
355 {0x36, 0xf9}, /* reserved */
356 {OV965X_CTL_ADC, 0x00}, /* reserved */
357 {OV965X_CTL_ACOM, 0x93}, /* reserved */
358 {OV965X_CTL_OFON, 0x50},
359 {OV965X_CTL_TSLB, OV965X_TSLB_OUTPUT_SEQ_UYVY |
360 OV965X_TSLB_DIGITAL_BLC_ENABLE},
361 {OV965X_CTL_COM11, OV965X_COM11_MANUAL_BANDING_FILTER},
362 {OV965X_CTL_COM12, 0x73},
363 {OV965X_CTL_COM13, OV965X_COM13_ENABLE_COLOR_MATRIX |
364 OV965X_COM13_DELAY_Y_CHANNEL |
365 OV965X_COM13_OUTPUT_DELAY(1)},
366 {OV965X_CTL_COM14, OV965X_COM14_YUV_EDGE_ENHANCE |
367 OV965X_COM14_EDGE_ENHANCE_FACTOR_DBL | 0x0b},
368 {OV965X_CTL_EDGE, OV965X_EDGE_EDGE_ENHANCE_LOW4(8) |
369 OV965X_EDGE_EDGE_ENHANCE_FACTOR(8)},
370 {OV965X_CTL_COM15, OV965X_COM15_OUTPUT_RANGE_O0_TO_FF | 0x01},
371 {OV965X_CTL_COM16, 0x00},
372 {OV965X_CTL_COM17, 0x08},
373 {OV965X_CTL_MANU, 0x80}, /* default */
374 {OV965X_CTL_MANV, 0x80}, /* default */
375 {OV965X_CTL_HV, 0x40},
376 {OV965X_CTL_MBD, 0x00}, /* default */
377 {OV965X_CTL_DBLV, 0x0a}, /* reserved */
378 {OV965X_CTL_COM21, 0x06}, /* reserved */
379 {OV965X_CTL_COM22, 0x20},
380 {OV965X_CTL_COM23, 0x00}, /* default */
381 {OV965X_CTL_COM24, 0x00}, /* reserved */
382 {OV965X_CTL_DBLC1, 0xdf},
383 {OV965X_CTL_DM_LNL, 0x00}, /* default */
384 {OV965X_CTL_DM_LNH, 0x00}, /* default */
385 {0x94, 0x88}, /* reserved */
386 {0x95, 0x88}, /* reserved */
387 {0x96, 0x04}, /* reserved */
388 {OV965X_CTL_AECHM, 0x00},
389 {OV965X_CTL_COM26, 0x80}, /* reserved */
390 {0xa8, 0x80}, /* reserved */
391 {0xa9, 0xb8}, /* reserved */
392 {0xaa, 0x92}, /* reserved */
393 {0xab, 0x0a}, /* reserved */
397 * @var soi968_init
398 * @brief Addresses and values for the initialization of SOI968 sensors
399 * @author GWater
402 static __u8 soi968_init[][2] = {
403 /* reset all registers */
404 {0x12, 0x80},
405 /* stop resetting */
406 {0x12, 0x00},
407 /* snapshot mode: off */
408 {0x0c, 0x00},
409 /* enable offset adjustment,
410 * full data range,
411 * analogue2digital control black-level calibration
413 {0x0f, 0x1f},
414 /* Clock: internal PLL on */
415 {0x11, 0x80},
416 /* Analoge Black-level calibration off , no anaolgue gain */
417 {0x38, 0x52},
418 /* reserved */
419 {0x1e, 0x00},
420 /* special system settings (voltage, analogue2digital, ...) */
421 {0x33, 0x08},
422 {0x35, 0x8c},
423 {0x36, 0x0c},
424 {0x37, 0x04},
425 /* next 7 are unknown/reserved */
426 {0x45, 0x04},
427 {0x47, 0xff},
428 {0x3e, 0x00},
429 {0x3f, 0x00},
430 {0x3b, 0x20},
431 {0x3a, 0x96},
432 {0x3d, 0x0a},
433 /* disable banding filter in dark environment,
434 * VSYNC is dropped when framerate is dropped,
435 * drop frmaes when exposure out of tolerance,
436 * unfreeze exposure and gain values
438 {0x14, 0x4e},
439 /* AEC, AGC, AWB disabled; fast AEC */
440 {0x13, 0x88},
441 /* output: VGA, master mode */
442 {0x12, 0x40},
443 /* set HSTART, HSTOP, VSTART and VSTOP */
444 {0x17, 0x13},
445 {0x18, 0x63},
446 {0x19, 0x01},
447 {0x1a, 0x79},
448 {0x32, 0x24}, /* LSB for all four */
449 /* AWB update threshold,
450 * blue and red gain LSB
452 {0x03, 0x00},
453 /* CLock: internal PLL off */
454 {0x11, 0x40},
455 /* Line interval adjustment */
456 {0x2a, 0x10},
457 {0x2b, 0xe0},
458 /* AEC MSB */
459 {0x10, 0x32},
460 /* gain - default*/
461 {0x00, 0x00},
462 /* blue and red gain - default*/
463 {0x01, 0x80},
464 {0x02, 0x80}
467 static __u8 ov9655_init[][2] = {
468 {0x12, 0x80},
469 {0x12, 0x01},
470 {0x0d, 0x00},
471 {0x0e, 0x61},
472 {0x11, 0x80},
473 {0x13, 0xb8},
474 {0x14, 0x3e},
475 {0x16, 0x24},
476 {0x1e, 0x04},
477 {0x1e, 0x04},
478 {0x1e, 0x04},
479 {0x27, 0x08},
480 {0x28, 0x08},
481 {0x29, 0x15},
482 {0x2c, 0x08},
483 {0x32, 0xbf},
484 {0x34, 0x3d},
485 {0x35, 0x00},
486 {0x36, 0xf8},
487 {0x38, 0x12},
488 {0x39, 0x57},
489 {0x3a, 0x00},
490 {0x3b, 0xcc},
491 {0x3c, 0x0c},
492 {0x3d, 0x19},
493 {0x3e, 0x0c},
494 {0x3f, 0x01},
495 {0x41, 0x40},
496 {0x42, 0x80},
497 {0x45, 0x46},
498 {0x46, 0x62},
499 {0x47, 0x2a},
500 {0x48, 0x3c},
501 {0x4a, 0xf0},
502 {0x4b, 0xdc},
503 {0x4c, 0xdc},
504 {0x4d, 0xdc},
505 {0x4e, 0xdc},
506 {0x69, 0x02},
507 {0x6c, 0x04},
508 {0x6f, 0x9e},
509 {0x70, 0x05},
510 {0x71, 0x78},
511 {0x77, 0x02},
512 {0x8a, 0x23},
513 {0x8c, 0x0d},
514 {0x90, 0x7e},
515 {0x91, 0x7c},
516 {0x9f, 0x6e},
517 {0xa0, 0x6e},
518 {0xa5, 0x68},
519 {0xa6, 0x60},
520 {0xa8, 0xc1},
521 {0xa9, 0xfa},
522 {0xaa, 0x92},
523 {0xab, 0x04},
524 {0xac, 0x80},
525 {0xad, 0x80},
526 {0xae, 0x80},
527 {0xaf, 0x80},
528 {0xb2, 0xf2},
529 {0xb3, 0x20},
530 {0xb5, 0x00},
531 {0xb6, 0xaf},
532 {0xbb, 0xae},
533 {0xbc, 0x44},
534 {0xbd, 0x44},
535 {0xbe, 0x3b},
536 {0xbf, 0x3a},
537 {0xc0, 0xe2},
538 {0xc1, 0xc8},
539 {0xc2, 0x01},
540 {0xc4, 0x00},
541 {0xc6, 0x85},
542 {0xc7, 0x81},
543 {0xc9, 0xe0},
544 {0xca, 0xe8},
545 {0xcc, 0xd8},
546 {0xcd, 0x93},
547 {0x12, 0x61},
548 {0x36, 0xfa},
549 {0x8c, 0x8d},
550 {0xc0, 0xaa},
551 {0x69, 0x0a},
552 {0x03, 0x12},
553 {0x17, 0x14},
554 {0x18, 0x00},
555 {0x19, 0x01},
556 {0x1a, 0x3d},
557 {0x32, 0xbf},
558 {0x11, 0x80},
559 {0x2a, 0x10},
560 {0x2b, 0x0a},
561 {0x92, 0x00},
562 {0x93, 0x00},
563 {0x1e, 0x04},
564 {0x1e, 0x04},
565 {0x10, 0x7c},
566 {0x04, 0x03},
567 {0xa1, 0x00},
568 {0x2d, 0x00},
569 {0x2e, 0x00},
570 {0x00, 0x00},
571 {0x01, 0x80},
572 {0x02, 0x80},
573 {0x12, 0x61},
574 {0x36, 0xfa},
575 {0x8c, 0x8d},
576 {0xc0, 0xaa},
577 {0x69, 0x0a},
578 {0x03, 0x12},
579 {0x17, 0x14},
580 {0x18, 0x00},
581 {0x19, 0x01},
582 {0x1a, 0x3d},
583 {0x32, 0xbf},
584 {0x11, 0x80},
585 {0x2a, 0x10},
586 {0x2b, 0x0a},
587 {0x92, 0x00},
588 {0x93, 0x00},
589 {0x04, 0x01},
590 {0x10, 0x1f},
591 {0xa1, 0x00},
592 {0x00, 0x0a},
593 {0xa1, 0x00},
594 {0x10, 0x5d},
595 {0x04, 0x03},
596 {0x00, 0x01},
597 {0xa1, 0x00},
598 {0x10, 0x7c},
599 {0x04, 0x03},
600 {0x00, 0x03},
601 {0x00, 0x0a},
602 {0x00, 0x10},
603 {0x00, 0x13},
606 struct microdia_video_format ov_fmts[] = {
608 .pix_fmt = V4L2_PIX_FMT_SBGGR8,
609 .desc = "Bayer 8bit (BGGR)",
610 .depth = 8,
611 .set_format = sn9c20x_set_raw
614 .pix_fmt = V4L2_PIX_FMT_JPEG,
615 .desc = "JPEG (YUV 4:2:2)",
616 .depth = 16,
617 .set_format = sn9c20x_set_jpeg
621 struct microdia_video_resolution ov965x_resolutions[] = {
623 .width = 160,
624 .height = 120,
625 .scale = SN9C20X_1_4_SCALE,
626 .window = {0, 17, 640, 480}
629 .width = 320,
630 .height = 240,
631 .scale = SN9C20X_1_2_SCALE,
632 .window = {0, 7, 640, 480}
635 .width = 640,
636 .height = 480,
637 .scale = SN9C20X_NO_SCALE,
638 .window = {0, 7, 640, 480}
642 struct microdia_video_resolution soi968_resolutions[] = {
644 .width = 160,
645 .height = 120,
646 .scale = SN9C20X_1_4_SCALE,
647 .window = {60, 17, 640, 480}
650 .width = 320,
651 .height = 240,
652 .scale = SN9C20X_1_2_SCALE,
653 .window = {60, 11, 640, 480}
656 .width = 640,
657 .height = 480,
658 .scale = SN9C20X_NO_SCALE,
659 .window = {60, 11, 640, 480}
663 struct microdia_video_resolution ov7670_resolutions[] = {
665 .width = 160,
666 .height = 120,
667 .scale = SN9C20X_1_4_SCALE,
668 .window = {0, 1, 640, 480}
671 .width = 320,
672 .height = 240,
673 .scale = SN9C20X_1_2_SCALE,
674 .window = {0, 1, 640, 480}
677 .width = 640,
678 .height = 480,
679 .scale = SN9C20X_NO_SCALE,
680 .window = {0, 1, 640, 480}
684 struct microdia_video_resolution ov7660_resolutions[] = {
686 .width = 160,
687 .height = 120,
688 .scale = SN9C20X_1_4_SCALE,
689 .window = {1, 1, 640, 480}
692 .width = 320,
693 .height = 240,
694 .scale = SN9C20X_1_2_SCALE,
695 .window = {1, 1, 640, 480}
698 .width = 640,
699 .height = 480,
700 .scale = SN9C20X_NO_SCALE,
701 .window = {1, 1, 640, 480}
705 int ov_probe(struct usb_microdia *dev)
707 int ret;
708 __u8 buf[2];
709 dev->camera.sensor_slave_address = 0x30;
710 ret = sn9c20x_read_i2c_data(dev, 2, 0x0a, buf);
711 if (ret == 0) {
712 if (buf[0] != 0x76 && buf[0] != 0x96)
713 return -EINVAL;
714 if (buf[1] == 0x60) {
715 ov_initialize(dev, ov7660_init, ARRAY_SIZE(ov7660_init));
716 dev->camera.set_exposure = ov7660_set_exposure;
717 dev->camera.set_auto_exposure = ov7660_set_autoexposure;
718 dev->camera.modes = ov7660_resolutions;
719 dev->camera.nmodes = ARRAY_SIZE(ov7660_resolutions);
720 dev->camera.fmts = ov_fmts;
721 dev->camera.nfmts = ARRAY_SIZE(ov_fmts);
722 return OV7660_SENSOR;
724 if (buf[1] == 0x70) {
725 ov_initialize(dev, ov7670_init, ARRAY_SIZE(ov7670_init));
726 dev->camera.flip_detect = ov7670_flip_detect;
727 dev->camera.modes = ov7670_resolutions;
728 dev->camera.nmodes = ARRAY_SIZE(ov7670_resolutions);
729 dev->camera.fmts = ov_fmts;
730 dev->camera.nfmts = ARRAY_SIZE(ov_fmts);
731 return OV7670_SENSOR;
733 if (buf[1] == 0x52) {
734 ov_initialize(dev, ov9650_init, ARRAY_SIZE(ov9650_init));
735 dev->camera.set_hvflip = ov965x_set_hvflip;
736 dev->camera.set_exposure = ov965x_set_exposure;
737 dev->camera.set_auto_exposure = ov965x_set_autoexposure;
738 dev->camera.flip_detect = ov965x_flip_detect;
739 dev->camera.modes = ov965x_resolutions;
740 dev->camera.nmodes = ARRAY_SIZE(ov965x_resolutions);
741 dev->camera.fmts = ov_fmts;
742 dev->camera.nfmts = ARRAY_SIZE(ov_fmts);
743 return OV9650_SENSOR;
745 if (buf[1] == 0x56 || buf[1] == 0x57) {
746 ov_initialize(dev, ov9655_init, ARRAY_SIZE(ov9655_init));
747 dev->camera.modes = ov7670_resolutions;
748 dev->camera.nmodes = ARRAY_SIZE(ov7670_resolutions);
749 dev->camera.fmts = ov_fmts;
750 dev->camera.nfmts = ARRAY_SIZE(ov_fmts);
751 return OV9655_SENSOR;
753 if (buf[1] == 0x28) {
754 ov_initialize(dev, soi968_init, ARRAY_SIZE(soi968_init));
755 dev->camera.set_exposure = soi968_set_exposure;
756 dev->camera.set_auto_exposure = ov965x_set_autoexposure;
757 dev->camera.modes = soi968_resolutions;
758 dev->camera.nmodes = ARRAY_SIZE(soi968_resolutions);
759 dev->camera.fmts = ov_fmts;
760 dev->camera.nfmts = ARRAY_SIZE(ov_fmts);
761 return SOI968_SENSOR;
763 } else {
764 UDIA_INFO("Failed on i2c read in ov_probe\n");
766 return -EINVAL;
770 * @brief Initialize ov sensors
772 * @param dev Pointer to device structure
773 * @param ov_init Data array for initialization
774 * @param array_size size of ov_init
776 * @return 0 or negative error code
779 int ov_initialize(struct usb_microdia *dev, __u8 ov_init[][2], int array_size)
781 int i;
782 int ret = 0;
783 __u8 value, reg;
785 for (i = 0; i < array_size; i++) {
786 reg = ov_init[i][0];
787 value = ov_init[i][1];
788 ret = sn9c20x_write_i2c_data(dev, 1, reg, &value);
789 if (ret < 0) {
790 UDIA_INFO("Sensor Init Error (%d). line %d\n", ret, i);
791 break;
795 return ret;
800 * @brief Set exposure for ov7660 sensors
802 * @param dev
804 * @return 0 or negative error value
806 * @author Neekhil
808 int ov7660_set_exposure(struct usb_microdia *dev)
810 int ret = 0;
811 __u8 v1 = (dev->vsettings.exposure >> 4) & 0xff;
812 __u8 v2 = dev->vsettings.exposure >> 12;
814 ret |= sn9c20x_write_i2c_data(dev, 1, OV7660_CTL_ADVFL, &v1);
816 ret |= sn9c20x_write_i2c_data(dev, 1, OV7660_CTL_ADVFH, &v2);
818 return ret;
822 * @brief Set autoexposure for ov7660 sensors
824 * @param dev
826 * @return 0 or negative error value
828 * @author Neekhil
830 int ov7660_set_autoexposure(struct usb_microdia *dev)
832 __u8 buf[1];
833 int ret = 0;
835 /* Read current value of the I2C-register
836 * controlling AutoExposureControl:
838 ret = sn9c20x_read_i2c_data(dev, 1, OV7660_CTL_COM8, buf);
839 if (ret < 0) {
840 UDIA_ERROR("Error: setting of auto exposure failed: "
841 "error while reading from I2C-register OV7660_CTL_COM8\n");
842 return ret;
845 /* Determine new value for OV7660_CTL_COM8 register */
846 if (dev->vsettings.auto_exposure == 1) {
847 /* Enable automatic exposure: */
848 buf[0] |= 0x01;
849 } else if (dev->vsettings.auto_exposure == 0) {
850 /* Disable automatic exposure: */
851 buf[0] &= ~0x01;
852 } else
853 return -EINVAL;
855 /* Write new value to I2C-register OV7660_CTL_COM8 */
856 ret = sn9c20x_write_i2c_data(dev, 1, OV7660_CTL_COM8, buf);
857 if (ret < 0) {
858 UDIA_ERROR("Error: setting of auto exposure failed: "
859 "error while writing to I2C-register OV7660_CTL_COM8\n");
860 return ret;
862 return 0;
866 * @brief Set ov7660 sensors to soft-sleep mode
867 * @param dev
868 * @return 0 or negative error value
869 * @author Neekhil
871 int ov7660_sleep(struct usb_microdia *dev)
873 __u8 buf[1];
874 int ret = 0;
876 /* Set the sensor to Soft Sleep mode, Set O/P drive capability to 4X*/
877 buf[0] = 0x13;
878 ret = sn9c20x_write_i2c_data(dev, 1, OV7660_CTL_COM2, buf);
879 if (ret < 0)
880 goto errI2C;
882 return 0;
884 errI2C:
885 UDIA_ERROR("Setting Image Sensor to soft sleep failed(%d)!\n", ret);
886 return ret;
890 * @brief Get ov7660 sensors to wake up from soft-sleep mode
891 * @param dev
892 * @return 0 or negative error value
893 * @author Neekhil
895 int ov7660_wakeup(struct usb_microdia *dev)
897 __u8 buf[1];
898 int ret = 0;
900 /* Wake the sensor from Soft Sleep mode, Set O/P drive capability to 4X */
901 buf[0] = 0x03;
902 ret = sn9c20x_write_i2c_data(dev, 1, OV7660_CTL_COM2, buf);
903 if (ret < 0)
904 goto errI2C;
906 return 0;
908 errI2C:
909 UDIA_ERROR("Image Sensor failed to wake-up from soft sleep (%d)!\n", ret);
910 return ret;
914 * @brief Resets all the registers on ov7660 sensor
915 * @param dev
916 * @return 0 or negative error value
917 * @author Neekhil
919 int ov7660_reset(struct usb_microdia *dev)
921 __u8 buf[1];
922 int ret = 0;
924 /* Reset all registers to default value */
925 /* Set O/P format - RGB Selection, Set O/P format Raw RGB */
926 buf[0] = 0x85;
927 ret = sn9c20x_write_i2c_data(dev, 1, OV7660_CTL_COM7, buf);
928 if (ret < 0)
929 goto errI2C;
931 return 0;
933 errI2C:
934 UDIA_ERROR("Failed to reset the Image Sensor (%d)!\n", ret);
935 return ret;
939 * @brief OV7670 Auto-Flip
941 * @param dev Pointer to the device
942 * @param vflip Flag to indicate whether or not Camera is currently flipped
944 * @return Zero (success) or negative (USB-error value)
947 int ov7670_auto_flip(struct usb_microdia *dev, __u8 vflip)
949 int ret;
950 __u8 buf[2];
952 ret = sn9c20x_read_i2c_data(dev, 1,
953 OV7670_CTL_MVFP, buf);
954 if (ret < 0)
955 return ret;
957 if (vflip == 0)
958 buf[0] = buf[0] & (0xff ^ OV7670_VFLIP_BIT);
959 else
960 buf[0] = buf[0] | OV7670_VFLIP_BIT;
961 ret = sn9c20x_write_i2c_data(dev, 1,
962 OV7670_CTL_MVFP, buf);
964 return ret;
968 * @brief Set hflip and vflip in ov965x sensors
970 * @param dev Pointer to device structure
972 * @returns 0 or negative error code
975 int ov965x_set_hvflip(struct usb_microdia *dev)
977 int ret;
978 __u8 value;
980 * Changing hstop value seems to be necessary to keep correct
981 * colors during a vflip. The values don't seem to make much
982 * sense since to keep the correct color value i'm setting hstop
983 * to the same value as hstart is set for.
985 __u8 hstop = 0xc5;
986 ret = sn9c20x_read_i2c_data(dev, 1, OV965X_CTL_MVFP, &value);
987 if (ret < 0)
988 return ret;
990 if (dev->vsettings.hflip)
991 value |= OV965X_MVFP_MIRROR;
992 else
993 value &= ~OV965X_MVFP_MIRROR;
995 if (dev->vsettings.vflip) {
996 hstop = 0x24;
997 value |= OV965X_MVFP_VFLIP;
998 } else {
999 value &= ~OV965X_MVFP_VFLIP;
1002 ret = sn9c20x_write_i2c_data(dev, 1, OV965X_CTL_HSTOP, &hstop);
1004 ret = sn9c20x_write_i2c_data(dev, 1, OV965X_CTL_MVFP, &value);
1006 return ret;
1010 * @brief Set exposure for ov965x sensors
1012 * @param dev
1014 * @returns 0 or negative error value
1016 * The used registers do not show up the datasheets.
1019 int ov965x_set_exposure(struct usb_microdia *dev)
1021 int ret = 0;
1022 __u8 v1 = (dev->vsettings.exposure >> 4) & 0xff;
1023 __u8 v2 = dev->vsettings.exposure >> 12;
1025 ret |= sn9c20x_write_i2c_data(dev, 1, 0x2d, &v1);
1027 ret |= sn9c20x_write_i2c_data(dev, 1, 0x2e, &v2);
1029 return ret;
1033 * @brief Set autoexposure for ov96xx sensors
1035 * @param dev
1037 * @returns 0 or negative error value
1039 * @author GWater
1041 * For all OV965x and SOI968 sensors.
1043 int ov965x_set_autoexposure(struct usb_microdia *dev)
1045 __u8 buf[1];
1046 int ret = 0;
1048 /* Read current value of the I2C-register
1049 * controlling AutoExposureControl:
1051 ret = sn9c20x_read_i2c_data(dev, 1, 0x13, buf);
1052 if (ret < 0) {
1053 UDIA_ERROR("Error: setting of auto exposure failed: "
1054 "error while reading from I2C-register 0x13\n");
1055 return ret;
1058 /* Determine new value for register 0x13: */
1059 if (dev->vsettings.auto_exposure == 1) {
1060 /* Enable automatic exposure: */
1061 buf[0] |= 0x01;
1062 } else if (dev->vsettings.auto_exposure == 0) {
1063 /* Disable automatic exposure: */
1064 buf[0] &= ~0x01;
1065 } else
1066 return -EINVAL;
1068 /* Write new value to I2C-register 0x13: */
1069 ret = sn9c20x_write_i2c_data(dev, 1, 0x13, buf);
1070 if (ret < 0) {
1071 UDIA_ERROR("Error: setting of auto exposure failed: "
1072 "error while writing to I2C-register 0x13\n");
1073 return ret;
1075 return 0;
1079 * @brief Set exposure for SOI968 sensors
1081 * @param dev
1083 * @returns 0 or negative error value
1085 * @author GWater
1087 * For SOI968 sensors.
1089 int soi968_set_exposure(struct usb_microdia *dev)
1091 int value, ret;
1092 int exposure = dev->vsettings.exposure;
1093 __u8 buf1, buf2, buf3;
1095 /* Read current value of the I2C-register
1096 * containing exposure LSB:
1098 ret = sn9c20x_read_i2c_data(dev, 1, 0x04, &buf1);
1099 if (ret < 0) {
1100 UDIA_ERROR("Error: setting exposure failed: "
1101 "error while reading from I2C-register 0x04\n");
1102 return ret;
1105 value = (exposure * 0x07ff / 0xffff) & 0x07ff;
1106 buf2 = ((__u8) (value & 0x07)) | (buf1 & ~0x07);
1107 buf3 = (__u8) (value >> 3) & 0xff;
1109 /* Write new value to I2C-register 0x04: */
1110 ret = sn9c20x_write_i2c_data(dev, 1, 0x04, &buf2);
1111 if (ret < 0) {
1112 UDIA_ERROR("Error: setting exposure failed: "
1113 "error while writing to I2C-register 0x04\n");
1114 return ret;
1117 /* Write new value to I2C-register 0x10: */
1118 ret = sn9c20x_write_i2c_data(dev, 1, 0x10, &buf3);
1119 if (ret < 0) {
1120 UDIA_ERROR("Error: setting exposure failed: "
1121 "error while writing to I2C-register 0x10\n");
1122 return ret;
1125 return 0;
1129 * @brief Detect whether the image for 6260 has to be flipped
1131 * @param dev Pointer to device structure
1133 * @returns 0 or negative error code
1136 int ov7670_flip_detect(struct usb_microdia *dev)
1138 const __u8 flip_bit = 0x01;
1139 int ret = 0;
1140 __u8 val;
1141 static __u8 flip_reg = flip_bit;
1142 __u8 vflip;
1144 ret = usb_microdia_control_read(dev, 0x1009, &val, 1);
1145 if (ret < 0)
1146 return -EAGAIN;
1147 if (flip_reg != (val & flip_bit)) {
1148 if (val & flip_bit)
1149 vflip = 0;
1150 else
1151 vflip = 1;
1152 ret = ov7670_auto_flip(dev, vflip);
1153 flip_reg = (val & flip_bit);
1156 return ret;
1160 * @brief Detect whether the image for 624f has to be flipped
1162 * @param dev Pointer to device structure
1164 * @returns 0 or negative error code
1167 int ov965x_flip_detect(struct usb_microdia *dev)
1169 int ret = 0;
1170 __u8 val;
1172 ret = usb_microdia_control_read(dev, 0x1009, &val, 1);
1173 if (ret < 0)
1174 return -EAGAIN;
1175 if (val & 0x01)
1176 dev->vsettings.vflip = 1;
1177 else
1178 dev->vsettings.vflip = 0;
1179 return ret;