blob: 83a718f0f3f9841b8412c34967f41476040398e0 [file] [log] [blame]
Brian Johnson26e744b2009-07-19 05:52:58 -03001/*
2 * Sonix sn9c201 sn9c202 library
3 * Copyright (C) 2008-2009 microdia project <microdia@googlegroups.com>
4 * Copyright (C) 2009 Brian Johnson <brijohn@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030021#ifdef CONFIG_INPUT
Brian Johnson26e744b2009-07-19 05:52:58 -030022#include <linux/input.h>
23#endif
24
Mauro Carvalho Chehabc15b95e2009-07-19 18:03:23 -030025#include "gspca.h"
26#include "jpeg.h"
27
28#include <media/v4l2-chip-ident.h>
Brian Johnson7ddaac72010-03-16 13:58:27 -030029#include <linux/dmi.h>
Mauro Carvalho Chehabc15b95e2009-07-19 18:03:23 -030030
Brian Johnson26e744b2009-07-19 05:52:58 -030031MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, "
32 "microdia project <microdia@googlegroups.com>");
33MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver");
34MODULE_LICENSE("GPL");
35
36#define MODULE_NAME "sn9c20x"
37
38#define MODE_RAW 0x10
39#define MODE_JPEG 0x20
40#define MODE_SXGA 0x80
41
42#define SENSOR_OV9650 0
43#define SENSOR_OV9655 1
44#define SENSOR_SOI968 2
45#define SENSOR_OV7660 3
46#define SENSOR_OV7670 4
47#define SENSOR_MT9V011 5
48#define SENSOR_MT9V111 6
49#define SENSOR_MT9V112 7
50#define SENSOR_MT9M001 8
51#define SENSOR_MT9M111 9
Brian Johnsone99ac542010-03-16 13:58:28 -030052#define SENSOR_MT9M112 10
53#define SENSOR_HV7131R 11
Brian Johnson26e744b2009-07-19 05:52:58 -030054#define SENSOR_MT9VPRB 20
55
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030056/* camera flags */
Brian Johnson33ddc162010-04-18 21:42:40 -030057#define HAS_NO_BUTTON 0x1
Brian Johnson0c045eb2010-03-16 13:58:27 -030058#define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */
Brian Johnson7ddaac72010-03-16 13:58:27 -030059#define FLIP_DETECT 0x4
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030060
Brian Johnson26e744b2009-07-19 05:52:58 -030061/* specific webcam descriptor */
62struct sd {
63 struct gspca_dev gspca_dev;
64
65#define MIN_AVG_LUM 80
66#define MAX_AVG_LUM 130
67 atomic_t avg_lum;
68 u8 old_step;
69 u8 older_step;
70 u8 exposure_step;
71
72 u8 brightness;
73 u8 contrast;
74 u8 saturation;
75 s16 hue;
76 u8 gamma;
77 u8 red;
78 u8 blue;
79
80 u8 hflip;
81 u8 vflip;
82 u8 gain;
83 u16 exposure;
84 u8 auto_exposure;
85
86 u8 i2c_addr;
87 u8 sensor;
88 u8 hstart;
89 u8 vstart;
90
Jean-François Moine9a731a32010-06-04 05:26:42 -030091 u8 jpeg_hdr[JPEG_HDR_SZ];
Brian Johnson26e744b2009-07-19 05:52:58 -030092 u8 quality;
93
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030094 u8 flags;
Brian Johnson26e744b2009-07-19 05:52:58 -030095};
96
Joe Perches58aa68c2009-09-02 01:12:13 -030097struct i2c_reg_u8 {
98 u8 reg;
99 u8 val;
100};
101
102struct i2c_reg_u16 {
103 u8 reg;
104 u16 val;
105};
106
Brian Johnson26e744b2009-07-19 05:52:58 -0300107static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val);
108static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val);
109static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val);
110static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val);
111static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val);
112static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val);
113static int sd_sethue(struct gspca_dev *gspca_dev, s32 val);
114static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val);
115static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val);
116static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val);
117static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val);
118static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val);
119static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val);
120static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val);
121static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val);
122static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val);
123static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val);
124static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val);
125static int sd_setgain(struct gspca_dev *gspca_dev, s32 val);
126static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val);
127static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val);
128static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val);
129static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val);
130static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val);
131
Brian Johnson7ddaac72010-03-16 13:58:27 -0300132static const struct dmi_system_id flip_dmi_table[] = {
133 {
134 .ident = "MSI MS-1034",
135 .matches = {
136 DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."),
137 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1034"),
138 DMI_MATCH(DMI_PRODUCT_VERSION, "0341")
139 }
140 },
141 {
142 .ident = "MSI MS-1632",
143 .matches = {
144 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
145 DMI_MATCH(DMI_BOARD_NAME, "MS-1632")
146 }
147 },
Brian Johnsone077f862010-04-05 20:52:52 -0300148 {
Brian Johnson5d26ed92010-04-10 02:12:46 -0300149 .ident = "MSI MS-1635X",
150 .matches = {
151 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
152 DMI_MATCH(DMI_BOARD_NAME, "MS-1635X")
153 }
154 },
155 {
Brian Johnsone077f862010-04-05 20:52:52 -0300156 .ident = "ASUSTeK W7J",
157 .matches = {
158 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
159 DMI_MATCH(DMI_BOARD_NAME, "W7J ")
160 }
161 },
Brian Johnson7ddaac72010-03-16 13:58:27 -0300162 {}
163};
164
Marton Nemeth7e64dc42009-12-30 09:12:41 -0300165static const struct ctrl sd_ctrls[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300166 {
167#define BRIGHTNESS_IDX 0
168 {
169 .id = V4L2_CID_BRIGHTNESS,
170 .type = V4L2_CTRL_TYPE_INTEGER,
171 .name = "Brightness",
172 .minimum = 0,
173 .maximum = 0xff,
174 .step = 1,
175#define BRIGHTNESS_DEFAULT 0x7f
176 .default_value = BRIGHTNESS_DEFAULT,
177 },
178 .set = sd_setbrightness,
179 .get = sd_getbrightness,
180 },
181 {
182#define CONTRAST_IDX 1
183 {
184 .id = V4L2_CID_CONTRAST,
185 .type = V4L2_CTRL_TYPE_INTEGER,
186 .name = "Contrast",
187 .minimum = 0,
188 .maximum = 0xff,
189 .step = 1,
190#define CONTRAST_DEFAULT 0x7f
191 .default_value = CONTRAST_DEFAULT,
192 },
193 .set = sd_setcontrast,
194 .get = sd_getcontrast,
195 },
196 {
197#define SATURATION_IDX 2
198 {
199 .id = V4L2_CID_SATURATION,
200 .type = V4L2_CTRL_TYPE_INTEGER,
201 .name = "Saturation",
202 .minimum = 0,
203 .maximum = 0xff,
204 .step = 1,
205#define SATURATION_DEFAULT 0x7f
206 .default_value = SATURATION_DEFAULT,
207 },
208 .set = sd_setsaturation,
209 .get = sd_getsaturation,
210 },
211 {
212#define HUE_IDX 3
213 {
214 .id = V4L2_CID_HUE,
215 .type = V4L2_CTRL_TYPE_INTEGER,
216 .name = "Hue",
217 .minimum = -180,
218 .maximum = 180,
219 .step = 1,
220#define HUE_DEFAULT 0
221 .default_value = HUE_DEFAULT,
222 },
223 .set = sd_sethue,
224 .get = sd_gethue,
225 },
226 {
227#define GAMMA_IDX 4
228 {
229 .id = V4L2_CID_GAMMA,
230 .type = V4L2_CTRL_TYPE_INTEGER,
231 .name = "Gamma",
232 .minimum = 0,
233 .maximum = 0xff,
234 .step = 1,
235#define GAMMA_DEFAULT 0x10
236 .default_value = GAMMA_DEFAULT,
237 },
238 .set = sd_setgamma,
239 .get = sd_getgamma,
240 },
241 {
242#define BLUE_IDX 5
243 {
244 .id = V4L2_CID_BLUE_BALANCE,
245 .type = V4L2_CTRL_TYPE_INTEGER,
246 .name = "Blue Balance",
247 .minimum = 0,
248 .maximum = 0x7f,
249 .step = 1,
250#define BLUE_DEFAULT 0x28
251 .default_value = BLUE_DEFAULT,
252 },
253 .set = sd_setbluebalance,
254 .get = sd_getbluebalance,
255 },
256 {
257#define RED_IDX 6
258 {
259 .id = V4L2_CID_RED_BALANCE,
260 .type = V4L2_CTRL_TYPE_INTEGER,
261 .name = "Red Balance",
262 .minimum = 0,
263 .maximum = 0x7f,
264 .step = 1,
265#define RED_DEFAULT 0x28
266 .default_value = RED_DEFAULT,
267 },
268 .set = sd_setredbalance,
269 .get = sd_getredbalance,
270 },
271 {
272#define HFLIP_IDX 7
273 {
274 .id = V4L2_CID_HFLIP,
275 .type = V4L2_CTRL_TYPE_BOOLEAN,
276 .name = "Horizontal Flip",
277 .minimum = 0,
278 .maximum = 1,
279 .step = 1,
280#define HFLIP_DEFAULT 0
281 .default_value = HFLIP_DEFAULT,
282 },
283 .set = sd_sethflip,
284 .get = sd_gethflip,
285 },
286 {
287#define VFLIP_IDX 8
288 {
289 .id = V4L2_CID_VFLIP,
290 .type = V4L2_CTRL_TYPE_BOOLEAN,
291 .name = "Vertical Flip",
292 .minimum = 0,
293 .maximum = 1,
294 .step = 1,
295#define VFLIP_DEFAULT 0
296 .default_value = VFLIP_DEFAULT,
297 },
298 .set = sd_setvflip,
299 .get = sd_getvflip,
300 },
301 {
302#define EXPOSURE_IDX 9
303 {
304 .id = V4L2_CID_EXPOSURE,
305 .type = V4L2_CTRL_TYPE_INTEGER,
306 .name = "Exposure",
307 .minimum = 0,
308 .maximum = 0x1780,
309 .step = 1,
310#define EXPOSURE_DEFAULT 0x33
311 .default_value = EXPOSURE_DEFAULT,
312 },
313 .set = sd_setexposure,
314 .get = sd_getexposure,
315 },
316 {
317#define GAIN_IDX 10
318 {
319 .id = V4L2_CID_GAIN,
320 .type = V4L2_CTRL_TYPE_INTEGER,
321 .name = "Gain",
322 .minimum = 0,
323 .maximum = 28,
324 .step = 1,
325#define GAIN_DEFAULT 0x00
326 .default_value = GAIN_DEFAULT,
327 },
328 .set = sd_setgain,
329 .get = sd_getgain,
330 },
331 {
332#define AUTOGAIN_IDX 11
333 {
334 .id = V4L2_CID_AUTOGAIN,
335 .type = V4L2_CTRL_TYPE_BOOLEAN,
336 .name = "Auto Exposure",
337 .minimum = 0,
338 .maximum = 1,
339 .step = 1,
340#define AUTO_EXPOSURE_DEFAULT 1
341 .default_value = AUTO_EXPOSURE_DEFAULT,
342 },
343 .set = sd_setautoexposure,
344 .get = sd_getautoexposure,
345 },
346};
347
348static const struct v4l2_pix_format vga_mode[] = {
349 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
350 .bytesperline = 240,
351 .sizeimage = 240 * 120,
352 .colorspace = V4L2_COLORSPACE_JPEG,
353 .priv = 0 | MODE_JPEG},
354 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
355 .bytesperline = 160,
356 .sizeimage = 160 * 120,
357 .colorspace = V4L2_COLORSPACE_SRGB,
358 .priv = 0 | MODE_RAW},
359 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
360 .bytesperline = 240,
361 .sizeimage = 240 * 120,
362 .colorspace = V4L2_COLORSPACE_SRGB,
363 .priv = 0},
364 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
365 .bytesperline = 480,
366 .sizeimage = 480 * 240 ,
367 .colorspace = V4L2_COLORSPACE_JPEG,
368 .priv = 1 | MODE_JPEG},
369 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
370 .bytesperline = 320,
371 .sizeimage = 320 * 240 ,
372 .colorspace = V4L2_COLORSPACE_SRGB,
373 .priv = 1 | MODE_RAW},
374 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
375 .bytesperline = 480,
376 .sizeimage = 480 * 240 ,
377 .colorspace = V4L2_COLORSPACE_SRGB,
378 .priv = 1},
379 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
380 .bytesperline = 960,
381 .sizeimage = 960 * 480,
382 .colorspace = V4L2_COLORSPACE_JPEG,
383 .priv = 2 | MODE_JPEG},
384 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
385 .bytesperline = 640,
386 .sizeimage = 640 * 480,
387 .colorspace = V4L2_COLORSPACE_SRGB,
388 .priv = 2 | MODE_RAW},
389 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
390 .bytesperline = 960,
391 .sizeimage = 960 * 480,
392 .colorspace = V4L2_COLORSPACE_SRGB,
393 .priv = 2},
394};
395
396static const struct v4l2_pix_format sxga_mode[] = {
397 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
398 .bytesperline = 240,
399 .sizeimage = 240 * 120,
400 .colorspace = V4L2_COLORSPACE_JPEG,
401 .priv = 0 | MODE_JPEG},
402 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
403 .bytesperline = 160,
404 .sizeimage = 160 * 120,
405 .colorspace = V4L2_COLORSPACE_SRGB,
406 .priv = 0 | MODE_RAW},
407 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
408 .bytesperline = 240,
409 .sizeimage = 240 * 120,
410 .colorspace = V4L2_COLORSPACE_SRGB,
411 .priv = 0},
412 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
413 .bytesperline = 480,
414 .sizeimage = 480 * 240 ,
415 .colorspace = V4L2_COLORSPACE_JPEG,
416 .priv = 1 | MODE_JPEG},
417 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
418 .bytesperline = 320,
419 .sizeimage = 320 * 240 ,
420 .colorspace = V4L2_COLORSPACE_SRGB,
421 .priv = 1 | MODE_RAW},
422 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
423 .bytesperline = 480,
424 .sizeimage = 480 * 240 ,
425 .colorspace = V4L2_COLORSPACE_SRGB,
426 .priv = 1},
427 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
428 .bytesperline = 960,
429 .sizeimage = 960 * 480,
430 .colorspace = V4L2_COLORSPACE_JPEG,
431 .priv = 2 | MODE_JPEG},
432 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
433 .bytesperline = 640,
434 .sizeimage = 640 * 480,
435 .colorspace = V4L2_COLORSPACE_SRGB,
436 .priv = 2 | MODE_RAW},
437 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
438 .bytesperline = 960,
439 .sizeimage = 960 * 480,
440 .colorspace = V4L2_COLORSPACE_SRGB,
441 .priv = 2},
442 {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
443 .bytesperline = 1280,
444 .sizeimage = (1280 * 1024) + 64,
445 .colorspace = V4L2_COLORSPACE_SRGB,
446 .priv = 3 | MODE_RAW | MODE_SXGA},
447};
448
Joe Perches58aa68c2009-09-02 01:12:13 -0300449static const s16 hsv_red_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300450 41, 44, 46, 48, 50, 52, 54, 56,
451 58, 60, 62, 64, 66, 68, 70, 72,
452 74, 76, 78, 80, 81, 83, 85, 87,
453 88, 90, 92, 93, 95, 97, 98, 100,
454 101, 102, 104, 105, 107, 108, 109, 110,
455 112, 113, 114, 115, 116, 117, 118, 119,
456 120, 121, 122, 123, 123, 124, 125, 125,
457 126, 127, 127, 128, 128, 129, 129, 129,
458 130, 130, 130, 130, 131, 131, 131, 131,
459 131, 131, 131, 131, 130, 130, 130, 130,
460 129, 129, 129, 128, 128, 127, 127, 126,
461 125, 125, 124, 123, 122, 122, 121, 120,
462 119, 118, 117, 116, 115, 114, 112, 111,
463 110, 109, 107, 106, 105, 103, 102, 101,
464 99, 98, 96, 94, 93, 91, 90, 88,
465 86, 84, 83, 81, 79, 77, 75, 74,
466 72, 70, 68, 66, 64, 62, 60, 58,
467 56, 54, 52, 49, 47, 45, 43, 41,
468 39, 36, 34, 32, 30, 28, 25, 23,
469 21, 19, 16, 14, 12, 9, 7, 5,
470 3, 0, -1, -3, -6, -8, -10, -12,
471 -15, -17, -19, -22, -24, -26, -28, -30,
472 -33, -35, -37, -39, -41, -44, -46, -48,
473 -50, -52, -54, -56, -58, -60, -62, -64,
474 -66, -68, -70, -72, -74, -76, -78, -80,
475 -81, -83, -85, -87, -88, -90, -92, -93,
476 -95, -97, -98, -100, -101, -102, -104, -105,
477 -107, -108, -109, -110, -112, -113, -114, -115,
478 -116, -117, -118, -119, -120, -121, -122, -123,
479 -123, -124, -125, -125, -126, -127, -127, -128,
480 -128, -128, -128, -128, -128, -128, -128, -128,
481 -128, -128, -128, -128, -128, -128, -128, -128,
482 -128, -128, -128, -128, -128, -128, -128, -128,
483 -128, -127, -127, -126, -125, -125, -124, -123,
484 -122, -122, -121, -120, -119, -118, -117, -116,
485 -115, -114, -112, -111, -110, -109, -107, -106,
486 -105, -103, -102, -101, -99, -98, -96, -94,
487 -93, -91, -90, -88, -86, -84, -83, -81,
488 -79, -77, -75, -74, -72, -70, -68, -66,
489 -64, -62, -60, -58, -56, -54, -52, -49,
490 -47, -45, -43, -41, -39, -36, -34, -32,
491 -30, -28, -25, -23, -21, -19, -16, -14,
492 -12, -9, -7, -5, -3, 0, 1, 3,
493 6, 8, 10, 12, 15, 17, 19, 22,
494 24, 26, 28, 30, 33, 35, 37, 39, 41
495};
496
Joe Perches58aa68c2009-09-02 01:12:13 -0300497static const s16 hsv_red_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300498 82, 80, 78, 76, 74, 73, 71, 69,
499 67, 65, 63, 61, 58, 56, 54, 52,
500 50, 48, 46, 44, 41, 39, 37, 35,
501 32, 30, 28, 26, 23, 21, 19, 16,
502 14, 12, 10, 7, 5, 3, 0, -1,
503 -3, -6, -8, -10, -13, -15, -17, -19,
504 -22, -24, -26, -29, -31, -33, -35, -38,
505 -40, -42, -44, -46, -48, -51, -53, -55,
506 -57, -59, -61, -63, -65, -67, -69, -71,
507 -73, -75, -77, -79, -81, -82, -84, -86,
508 -88, -89, -91, -93, -94, -96, -98, -99,
509 -101, -102, -104, -105, -106, -108, -109, -110,
510 -112, -113, -114, -115, -116, -117, -119, -120,
511 -120, -121, -122, -123, -124, -125, -126, -126,
512 -127, -128, -128, -128, -128, -128, -128, -128,
513 -128, -128, -128, -128, -128, -128, -128, -128,
514 -128, -128, -128, -128, -128, -128, -128, -128,
515 -128, -128, -128, -128, -128, -128, -128, -128,
516 -127, -127, -126, -125, -125, -124, -123, -122,
517 -121, -120, -119, -118, -117, -116, -115, -114,
518 -113, -111, -110, -109, -107, -106, -105, -103,
519 -102, -100, -99, -97, -96, -94, -92, -91,
520 -89, -87, -85, -84, -82, -80, -78, -76,
521 -74, -73, -71, -69, -67, -65, -63, -61,
522 -58, -56, -54, -52, -50, -48, -46, -44,
523 -41, -39, -37, -35, -32, -30, -28, -26,
524 -23, -21, -19, -16, -14, -12, -10, -7,
525 -5, -3, 0, 1, 3, 6, 8, 10,
526 13, 15, 17, 19, 22, 24, 26, 29,
527 31, 33, 35, 38, 40, 42, 44, 46,
528 48, 51, 53, 55, 57, 59, 61, 63,
529 65, 67, 69, 71, 73, 75, 77, 79,
530 81, 82, 84, 86, 88, 89, 91, 93,
531 94, 96, 98, 99, 101, 102, 104, 105,
532 106, 108, 109, 110, 112, 113, 114, 115,
533 116, 117, 119, 120, 120, 121, 122, 123,
534 124, 125, 126, 126, 127, 128, 128, 129,
535 129, 130, 130, 131, 131, 131, 131, 132,
536 132, 132, 132, 132, 132, 132, 132, 132,
537 132, 132, 132, 131, 131, 131, 130, 130,
538 130, 129, 129, 128, 127, 127, 126, 125,
539 125, 124, 123, 122, 121, 120, 119, 118,
540 117, 116, 115, 114, 113, 111, 110, 109,
541 107, 106, 105, 103, 102, 100, 99, 97,
542 96, 94, 92, 91, 89, 87, 85, 84, 82
543};
544
Joe Perches58aa68c2009-09-02 01:12:13 -0300545static const s16 hsv_green_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300546 -124, -124, -125, -125, -125, -125, -125, -125,
547 -125, -126, -126, -125, -125, -125, -125, -125,
548 -125, -124, -124, -124, -123, -123, -122, -122,
549 -121, -121, -120, -120, -119, -118, -117, -117,
550 -116, -115, -114, -113, -112, -111, -110, -109,
551 -108, -107, -105, -104, -103, -102, -100, -99,
552 -98, -96, -95, -93, -92, -91, -89, -87,
553 -86, -84, -83, -81, -79, -77, -76, -74,
554 -72, -70, -69, -67, -65, -63, -61, -59,
555 -57, -55, -53, -51, -49, -47, -45, -43,
556 -41, -39, -37, -35, -33, -30, -28, -26,
557 -24, -22, -20, -18, -15, -13, -11, -9,
558 -7, -4, -2, 0, 1, 3, 6, 8,
559 10, 12, 14, 17, 19, 21, 23, 25,
560 27, 29, 32, 34, 36, 38, 40, 42,
561 44, 46, 48, 50, 52, 54, 56, 58,
562 60, 62, 64, 66, 68, 70, 71, 73,
563 75, 77, 78, 80, 82, 83, 85, 87,
564 88, 90, 91, 93, 94, 96, 97, 98,
565 100, 101, 102, 104, 105, 106, 107, 108,
566 109, 111, 112, 113, 113, 114, 115, 116,
567 117, 118, 118, 119, 120, 120, 121, 122,
568 122, 123, 123, 124, 124, 124, 125, 125,
569 125, 125, 125, 125, 125, 126, 126, 125,
570 125, 125, 125, 125, 125, 124, 124, 124,
571 123, 123, 122, 122, 121, 121, 120, 120,
572 119, 118, 117, 117, 116, 115, 114, 113,
573 112, 111, 110, 109, 108, 107, 105, 104,
574 103, 102, 100, 99, 98, 96, 95, 93,
575 92, 91, 89, 87, 86, 84, 83, 81,
576 79, 77, 76, 74, 72, 70, 69, 67,
577 65, 63, 61, 59, 57, 55, 53, 51,
578 49, 47, 45, 43, 41, 39, 37, 35,
579 33, 30, 28, 26, 24, 22, 20, 18,
580 15, 13, 11, 9, 7, 4, 2, 0,
581 -1, -3, -6, -8, -10, -12, -14, -17,
582 -19, -21, -23, -25, -27, -29, -32, -34,
583 -36, -38, -40, -42, -44, -46, -48, -50,
584 -52, -54, -56, -58, -60, -62, -64, -66,
585 -68, -70, -71, -73, -75, -77, -78, -80,
586 -82, -83, -85, -87, -88, -90, -91, -93,
587 -94, -96, -97, -98, -100, -101, -102, -104,
588 -105, -106, -107, -108, -109, -111, -112, -113,
589 -113, -114, -115, -116, -117, -118, -118, -119,
590 -120, -120, -121, -122, -122, -123, -123, -124, -124
591};
592
Joe Perches58aa68c2009-09-02 01:12:13 -0300593static const s16 hsv_green_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300594 -100, -99, -98, -97, -95, -94, -93, -91,
595 -90, -89, -87, -86, -84, -83, -81, -80,
596 -78, -76, -75, -73, -71, -70, -68, -66,
597 -64, -63, -61, -59, -57, -55, -53, -51,
598 -49, -48, -46, -44, -42, -40, -38, -36,
599 -34, -32, -30, -27, -25, -23, -21, -19,
600 -17, -15, -13, -11, -9, -7, -4, -2,
601 0, 1, 3, 5, 7, 9, 11, 14,
602 16, 18, 20, 22, 24, 26, 28, 30,
603 32, 34, 36, 38, 40, 42, 44, 46,
604 48, 50, 52, 54, 56, 58, 59, 61,
605 63, 65, 67, 68, 70, 72, 74, 75,
606 77, 78, 80, 82, 83, 85, 86, 88,
607 89, 90, 92, 93, 95, 96, 97, 98,
608 100, 101, 102, 103, 104, 105, 106, 107,
609 108, 109, 110, 111, 112, 112, 113, 114,
610 115, 115, 116, 116, 117, 117, 118, 118,
611 119, 119, 119, 120, 120, 120, 120, 120,
612 121, 121, 121, 121, 121, 121, 120, 120,
613 120, 120, 120, 119, 119, 119, 118, 118,
614 117, 117, 116, 116, 115, 114, 114, 113,
615 112, 111, 111, 110, 109, 108, 107, 106,
616 105, 104, 103, 102, 100, 99, 98, 97,
617 95, 94, 93, 91, 90, 89, 87, 86,
618 84, 83, 81, 80, 78, 76, 75, 73,
619 71, 70, 68, 66, 64, 63, 61, 59,
620 57, 55, 53, 51, 49, 48, 46, 44,
621 42, 40, 38, 36, 34, 32, 30, 27,
622 25, 23, 21, 19, 17, 15, 13, 11,
623 9, 7, 4, 2, 0, -1, -3, -5,
624 -7, -9, -11, -14, -16, -18, -20, -22,
625 -24, -26, -28, -30, -32, -34, -36, -38,
626 -40, -42, -44, -46, -48, -50, -52, -54,
627 -56, -58, -59, -61, -63, -65, -67, -68,
628 -70, -72, -74, -75, -77, -78, -80, -82,
629 -83, -85, -86, -88, -89, -90, -92, -93,
630 -95, -96, -97, -98, -100, -101, -102, -103,
631 -104, -105, -106, -107, -108, -109, -110, -111,
632 -112, -112, -113, -114, -115, -115, -116, -116,
633 -117, -117, -118, -118, -119, -119, -119, -120,
634 -120, -120, -120, -120, -121, -121, -121, -121,
635 -121, -121, -120, -120, -120, -120, -120, -119,
636 -119, -119, -118, -118, -117, -117, -116, -116,
637 -115, -114, -114, -113, -112, -111, -111, -110,
638 -109, -108, -107, -106, -105, -104, -103, -102, -100
639};
640
Joe Perches58aa68c2009-09-02 01:12:13 -0300641static const s16 hsv_blue_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300642 112, 113, 114, 114, 115, 116, 117, 117,
643 118, 118, 119, 119, 120, 120, 120, 121,
644 121, 121, 122, 122, 122, 122, 122, 122,
645 122, 122, 122, 122, 122, 122, 121, 121,
646 121, 120, 120, 120, 119, 119, 118, 118,
647 117, 116, 116, 115, 114, 113, 113, 112,
648 111, 110, 109, 108, 107, 106, 105, 104,
649 103, 102, 100, 99, 98, 97, 95, 94,
650 93, 91, 90, 88, 87, 85, 84, 82,
651 80, 79, 77, 76, 74, 72, 70, 69,
652 67, 65, 63, 61, 60, 58, 56, 54,
653 52, 50, 48, 46, 44, 42, 40, 38,
654 36, 34, 32, 30, 28, 26, 24, 22,
655 19, 17, 15, 13, 11, 9, 7, 5,
656 2, 0, -1, -3, -5, -7, -9, -12,
657 -14, -16, -18, -20, -22, -24, -26, -28,
658 -31, -33, -35, -37, -39, -41, -43, -45,
659 -47, -49, -51, -53, -54, -56, -58, -60,
660 -62, -64, -66, -67, -69, -71, -73, -74,
661 -76, -78, -79, -81, -83, -84, -86, -87,
662 -89, -90, -92, -93, -94, -96, -97, -98,
663 -99, -101, -102, -103, -104, -105, -106, -107,
664 -108, -109, -110, -111, -112, -113, -114, -114,
665 -115, -116, -117, -117, -118, -118, -119, -119,
666 -120, -120, -120, -121, -121, -121, -122, -122,
667 -122, -122, -122, -122, -122, -122, -122, -122,
668 -122, -122, -121, -121, -121, -120, -120, -120,
669 -119, -119, -118, -118, -117, -116, -116, -115,
670 -114, -113, -113, -112, -111, -110, -109, -108,
671 -107, -106, -105, -104, -103, -102, -100, -99,
672 -98, -97, -95, -94, -93, -91, -90, -88,
673 -87, -85, -84, -82, -80, -79, -77, -76,
674 -74, -72, -70, -69, -67, -65, -63, -61,
675 -60, -58, -56, -54, -52, -50, -48, -46,
676 -44, -42, -40, -38, -36, -34, -32, -30,
677 -28, -26, -24, -22, -19, -17, -15, -13,
678 -11, -9, -7, -5, -2, 0, 1, 3,
679 5, 7, 9, 12, 14, 16, 18, 20,
680 22, 24, 26, 28, 31, 33, 35, 37,
681 39, 41, 43, 45, 47, 49, 51, 53,
682 54, 56, 58, 60, 62, 64, 66, 67,
683 69, 71, 73, 74, 76, 78, 79, 81,
684 83, 84, 86, 87, 89, 90, 92, 93,
685 94, 96, 97, 98, 99, 101, 102, 103,
686 104, 105, 106, 107, 108, 109, 110, 111, 112
687};
688
Joe Perches58aa68c2009-09-02 01:12:13 -0300689static const s16 hsv_blue_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300690 -11, -13, -15, -17, -19, -21, -23, -25,
691 -27, -29, -31, -33, -35, -37, -39, -41,
692 -43, -45, -46, -48, -50, -52, -54, -55,
693 -57, -59, -61, -62, -64, -66, -67, -69,
694 -71, -72, -74, -75, -77, -78, -80, -81,
695 -83, -84, -86, -87, -88, -90, -91, -92,
696 -93, -95, -96, -97, -98, -99, -100, -101,
697 -102, -103, -104, -105, -106, -106, -107, -108,
698 -109, -109, -110, -111, -111, -112, -112, -113,
699 -113, -114, -114, -114, -115, -115, -115, -115,
700 -116, -116, -116, -116, -116, -116, -116, -116,
701 -116, -115, -115, -115, -115, -114, -114, -114,
702 -113, -113, -112, -112, -111, -111, -110, -110,
703 -109, -108, -108, -107, -106, -105, -104, -103,
704 -102, -101, -100, -99, -98, -97, -96, -95,
705 -94, -93, -91, -90, -89, -88, -86, -85,
706 -84, -82, -81, -79, -78, -76, -75, -73,
707 -71, -70, -68, -67, -65, -63, -62, -60,
708 -58, -56, -55, -53, -51, -49, -47, -45,
709 -44, -42, -40, -38, -36, -34, -32, -30,
710 -28, -26, -24, -22, -20, -18, -16, -14,
711 -12, -10, -8, -6, -4, -2, 0, 1,
712 3, 5, 7, 9, 11, 13, 15, 17,
713 19, 21, 23, 25, 27, 29, 31, 33,
714 35, 37, 39, 41, 43, 45, 46, 48,
715 50, 52, 54, 55, 57, 59, 61, 62,
716 64, 66, 67, 69, 71, 72, 74, 75,
717 77, 78, 80, 81, 83, 84, 86, 87,
718 88, 90, 91, 92, 93, 95, 96, 97,
719 98, 99, 100, 101, 102, 103, 104, 105,
720 106, 106, 107, 108, 109, 109, 110, 111,
721 111, 112, 112, 113, 113, 114, 114, 114,
722 115, 115, 115, 115, 116, 116, 116, 116,
723 116, 116, 116, 116, 116, 115, 115, 115,
724 115, 114, 114, 114, 113, 113, 112, 112,
725 111, 111, 110, 110, 109, 108, 108, 107,
726 106, 105, 104, 103, 102, 101, 100, 99,
727 98, 97, 96, 95, 94, 93, 91, 90,
728 89, 88, 86, 85, 84, 82, 81, 79,
729 78, 76, 75, 73, 71, 70, 68, 67,
730 65, 63, 62, 60, 58, 56, 55, 53,
731 51, 49, 47, 45, 44, 42, 40, 38,
732 36, 34, 32, 30, 28, 26, 24, 22,
733 20, 18, 16, 14, 12, 10, 8, 6,
734 4, 2, 0, -1, -3, -5, -7, -9, -11
735};
736
737static u16 i2c_ident[] = {
738 V4L2_IDENT_OV9650,
739 V4L2_IDENT_OV9655,
740 V4L2_IDENT_SOI968,
741 V4L2_IDENT_OV7660,
742 V4L2_IDENT_OV7670,
743 V4L2_IDENT_MT9V011,
744 V4L2_IDENT_MT9V111,
745 V4L2_IDENT_MT9V112,
746 V4L2_IDENT_MT9M001C12ST,
747 V4L2_IDENT_MT9M111,
Brian Johnsone99ac542010-03-16 13:58:28 -0300748 V4L2_IDENT_MT9M112,
Brian Johnson26e744b2009-07-19 05:52:58 -0300749 V4L2_IDENT_HV7131R,
750};
751
752static u16 bridge_init[][2] = {
753 {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c},
754 {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40},
755 {0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10},
756 {0x106b, 0x08}, {0x1188, 0x87}, {0x11a1, 0x00},
757 {0x11a2, 0x00}, {0x11a3, 0x6a}, {0x11a4, 0x50},
758 {0x11ab, 0x00}, {0x11ac, 0x00}, {0x11ad, 0x50},
759 {0x11ae, 0x3c}, {0x118a, 0x04}, {0x0395, 0x04},
760 {0x11b8, 0x3a}, {0x118b, 0x0e}, {0x10f7, 0x05},
761 {0x10f8, 0x14}, {0x10fa, 0xff}, {0x10f9, 0x00},
762 {0x11ba, 0x0a}, {0x11a5, 0x2d}, {0x11a6, 0x2d},
763 {0x11a7, 0x3a}, {0x11a8, 0x05}, {0x11a9, 0x04},
764 {0x11aa, 0x3f}, {0x11af, 0x28}, {0x11b0, 0xd8},
765 {0x11b1, 0x14}, {0x11b2, 0xec}, {0x11b3, 0x32},
766 {0x11b4, 0xdd}, {0x11b5, 0x32}, {0x11b6, 0xdd},
767 {0x10e0, 0x2c}, {0x11bc, 0x40}, {0x11bd, 0x01},
768 {0x11be, 0xf0}, {0x11bf, 0x00}, {0x118c, 0x1f},
769 {0x118d, 0x1f}, {0x118e, 0x1f}, {0x118f, 0x1f},
770 {0x1180, 0x01}, {0x1181, 0x00}, {0x1182, 0x01},
Brian Johnson0c045eb2010-03-16 13:58:27 -0300771 {0x1183, 0x00}, {0x1184, 0x50}, {0x1185, 0x80},
772 {0x1007, 0x00}
Brian Johnson26e744b2009-07-19 05:52:58 -0300773};
774
775/* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */
776static u8 ov_gain[] = {
777 0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */,
778 0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */,
779 0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */,
780 0x30 /* 4x */, 0x31 /* 4.25x */, 0x32 /* 4.5x */, 0x33 /* 4.75x */,
781 0x34 /* 5x */, 0x35 /* 5.25x */, 0x36 /* 5.5x */, 0x37 /* 5.75x */,
782 0x38 /* 6x */, 0x39 /* 6.25x */, 0x3a /* 6.5x */, 0x3b /* 6.75x */,
783 0x3c /* 7x */, 0x3d /* 7.25x */, 0x3e /* 7.5x */, 0x3f /* 7.75x */,
784 0x70 /* 8x */
785};
786
787/* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */
788static u16 micron1_gain[] = {
789 /* 1x 1.25x 1.5x 1.75x */
790 0x0020, 0x0028, 0x0030, 0x0038,
791 /* 2x 2.25x 2.5x 2.75x */
792 0x00a0, 0x00a4, 0x00a8, 0x00ac,
793 /* 3x 3.25x 3.5x 3.75x */
794 0x00b0, 0x00b4, 0x00b8, 0x00bc,
795 /* 4x 4.25x 4.5x 4.75x */
796 0x00c0, 0x00c4, 0x00c8, 0x00cc,
797 /* 5x 5.25x 5.5x 5.75x */
798 0x00d0, 0x00d4, 0x00d8, 0x00dc,
799 /* 6x 6.25x 6.5x 6.75x */
800 0x00e0, 0x00e4, 0x00e8, 0x00ec,
801 /* 7x 7.25x 7.5x 7.75x */
802 0x00f0, 0x00f4, 0x00f8, 0x00fc,
803 /* 8x */
804 0x01c0
805};
806
807/* mt9m001 sensor uses a different gain formula then other micron sensors */
808/* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */
809static u16 micron2_gain[] = {
810 /* 1x 1.25x 1.5x 1.75x */
811 0x0008, 0x000a, 0x000c, 0x000e,
812 /* 2x 2.25x 2.5x 2.75x */
813 0x0010, 0x0012, 0x0014, 0x0016,
814 /* 3x 3.25x 3.5x 3.75x */
815 0x0018, 0x001a, 0x001c, 0x001e,
816 /* 4x 4.25x 4.5x 4.75x */
817 0x0020, 0x0051, 0x0052, 0x0053,
818 /* 5x 5.25x 5.5x 5.75x */
819 0x0054, 0x0055, 0x0056, 0x0057,
820 /* 6x 6.25x 6.5x 6.75x */
821 0x0058, 0x0059, 0x005a, 0x005b,
822 /* 7x 7.25x 7.5x 7.75x */
823 0x005c, 0x005d, 0x005e, 0x005f,
824 /* 8x */
825 0x0060
826};
827
828/* Gain = .5 + bit[7:0] / 16 */
829static u8 hv7131r_gain[] = {
830 0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */,
831 0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */,
832 0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */,
833 0x38 /* 4x */, 0x3c /* 4.25x */, 0x40 /* 4.5x */, 0x44 /* 4.75x */,
834 0x48 /* 5x */, 0x4c /* 5.25x */, 0x50 /* 5.5x */, 0x54 /* 5.75x */,
835 0x58 /* 6x */, 0x5c /* 6.25x */, 0x60 /* 6.5x */, 0x64 /* 6.75x */,
836 0x68 /* 7x */, 0x6c /* 7.25x */, 0x70 /* 7.5x */, 0x74 /* 7.75x */,
837 0x78 /* 8x */
838};
839
Joe Perches58aa68c2009-09-02 01:12:13 -0300840static struct i2c_reg_u8 soi968_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300841 {0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f},
842 {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
843 {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
844 {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
845 {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20},
846 {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e},
Brian Johnsone1430472009-09-02 12:39:41 -0300847 {0x13, 0x8b}, {0x12, 0x40}, {0x17, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300848 {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79},
849 {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40},
850 {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32},
851 {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80},
852};
853
Joe Perches58aa68c2009-09-02 01:12:13 -0300854static struct i2c_reg_u8 ov7660_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300855 {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
856 {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
857 {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
858 {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43},
859 {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0xf6},
860 {0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50},
861};
862
Joe Perches58aa68c2009-09-02 01:12:13 -0300863static struct i2c_reg_u8 ov7670_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300864 {0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
865 {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
866 {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
867 {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
868 {0x0d, 0x40}, {0x14, 0x28}, {0xa5, 0x05}, {0xab, 0x07},
869 {0x24, 0x95}, {0x25, 0x33}, {0x26, 0xe3}, {0x9f, 0x75},
870 {0xa0, 0x65}, {0xa1, 0x0b}, {0xa6, 0xd8}, {0xa7, 0xd8},
871 {0xa8, 0xf0}, {0xa9, 0x90}, {0xaa, 0x94}, {0x13, 0xe5},
872 {0x0e, 0x61}, {0x0f, 0x4b}, {0x16, 0x02}, {0x1e, 0x27},
873 {0x21, 0x02}, {0x22, 0x91}, {0x29, 0x07}, {0x33, 0x0b},
874 {0x35, 0x0b}, {0x37, 0x1d}, {0x38, 0x71}, {0x39, 0x2a},
875 {0x3c, 0x78}, {0x4d, 0x40}, {0x4e, 0x20}, {0x69, 0x00},
876 {0x74, 0x19}, {0x8d, 0x4f}, {0x8e, 0x00}, {0x8f, 0x00},
877 {0x90, 0x00}, {0x91, 0x00}, {0x96, 0x00}, {0x9a, 0x80},
878 {0xb0, 0x84}, {0xb1, 0x0c}, {0xb2, 0x0e}, {0xb3, 0x82},
879 {0xb8, 0x0a}, {0x43, 0x0a}, {0x44, 0xf0}, {0x45, 0x20},
880 {0x46, 0x7d}, {0x47, 0x29}, {0x48, 0x4a}, {0x59, 0x8c},
881 {0x5a, 0xa5}, {0x5b, 0xde}, {0x5c, 0x96}, {0x5d, 0x66},
882 {0x5e, 0x10}, {0x6c, 0x0a}, {0x6d, 0x55}, {0x6e, 0x11},
883 {0x6f, 0x9e}, {0x6a, 0x40}, {0x01, 0x40}, {0x02, 0x40},
884 {0x13, 0xe7}, {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x02},
885 {0x52, 0x1d}, {0x53, 0x56}, {0x54, 0x73}, {0x55, 0x0a},
886 {0x56, 0x55}, {0x57, 0x80}, {0x58, 0x9e}, {0x41, 0x08},
887 {0x3f, 0x02}, {0x75, 0x03}, {0x76, 0x63}, {0x4c, 0x04},
888 {0x77, 0x06}, {0x3d, 0x02}, {0x4b, 0x09}, {0xc9, 0x30},
889 {0x41, 0x08}, {0x56, 0x48}, {0x34, 0x11}, {0xa4, 0x88},
890 {0x96, 0x00}, {0x97, 0x30}, {0x98, 0x20}, {0x99, 0x30},
891 {0x9a, 0x84}, {0x9b, 0x29}, {0x9c, 0x03}, {0x9d, 0x99},
892 {0x9e, 0x7f}, {0x78, 0x04}, {0x79, 0x01}, {0xc8, 0xf0},
893 {0x79, 0x0f}, {0xc8, 0x00}, {0x79, 0x10}, {0xc8, 0x7e},
894 {0x79, 0x0a}, {0xc8, 0x80}, {0x79, 0x0b}, {0xc8, 0x01},
895 {0x79, 0x0c}, {0xc8, 0x0f}, {0x79, 0x0d}, {0xc8, 0x20},
896 {0x79, 0x09}, {0xc8, 0x80}, {0x79, 0x02}, {0xc8, 0xc0},
897 {0x79, 0x03}, {0xc8, 0x40}, {0x79, 0x05}, {0xc8, 0x30},
898 {0x79, 0x26}, {0x62, 0x20}, {0x63, 0x00}, {0x64, 0x06},
899 {0x65, 0x00}, {0x66, 0x05}, {0x94, 0x05}, {0x95, 0x0a},
900 {0x17, 0x13}, {0x18, 0x01}, {0x19, 0x02}, {0x1a, 0x7a},
901 {0x46, 0x59}, {0x47, 0x30}, {0x58, 0x9a}, {0x59, 0x84},
902 {0x5a, 0x91}, {0x5b, 0x57}, {0x5c, 0x75}, {0x5d, 0x6d},
903 {0x5e, 0x13}, {0x64, 0x07}, {0x94, 0x07}, {0x95, 0x0d},
904 {0xa6, 0xdf}, {0xa7, 0xdf}, {0x48, 0x4d}, {0x51, 0x00},
905 {0x6b, 0x0a}, {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00},
906 {0x92, 0x00}, {0x93, 0x00}, {0x55, 0x0a}, {0x56, 0x60},
907 {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d},
908 {0x53, 0x56}, {0x54, 0x73}, {0x58, 0x9a}, {0x4f, 0x6e},
909 {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, {0x53, 0x56},
910 {0x54, 0x73}, {0x58, 0x9a}, {0x3f, 0x01}, {0x7b, 0x03},
911 {0x7c, 0x09}, {0x7d, 0x16}, {0x7e, 0x38}, {0x7f, 0x47},
912 {0x80, 0x53}, {0x81, 0x5e}, {0x82, 0x6a}, {0x83, 0x74},
913 {0x84, 0x80}, {0x85, 0x8c}, {0x86, 0x9b}, {0x87, 0xb2},
914 {0x88, 0xcc}, {0x89, 0xe5}, {0x7a, 0x24}, {0x3b, 0x00},
915 {0x9f, 0x76}, {0xa0, 0x65}, {0x13, 0xe2}, {0x6b, 0x0a},
916 {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, {0x92, 0x00},
917 {0x93, 0x00},
918};
919
Joe Perches58aa68c2009-09-02 01:12:13 -0300920static struct i2c_reg_u8 ov9650_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300921 {0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78},
922 {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
923 {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
924 {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
925 {0x0e, 0xa0}, {0x0f, 0x52}, {0x10, 0x7c},
926 {0x11, 0x80}, {0x12, 0x45}, {0x13, 0xc2},
927 {0x14, 0x2e}, {0x15, 0x00}, {0x16, 0x07},
928 {0x17, 0x24}, {0x18, 0xc5}, {0x19, 0x00},
929 {0x1a, 0x3c}, {0x1b, 0x00}, {0x1e, 0x04},
930 {0x1f, 0x00}, {0x24, 0x78}, {0x25, 0x68},
931 {0x26, 0xd4}, {0x27, 0x80}, {0x28, 0x80},
932 {0x29, 0x30}, {0x2a, 0x00}, {0x2b, 0x00},
933 {0x2c, 0x80}, {0x2d, 0x00}, {0x2e, 0x00},
934 {0x2f, 0x00}, {0x30, 0x08}, {0x31, 0x30},
935 {0x32, 0x84}, {0x33, 0xe2}, {0x34, 0xbf},
936 {0x35, 0x81}, {0x36, 0xf9}, {0x37, 0x00},
937 {0x38, 0x93}, {0x39, 0x50}, {0x3a, 0x01},
938 {0x3b, 0x01}, {0x3c, 0x73}, {0x3d, 0x19},
939 {0x3e, 0x0b}, {0x3f, 0x80}, {0x40, 0xc1},
940 {0x41, 0x00}, {0x42, 0x08}, {0x67, 0x80},
941 {0x68, 0x80}, {0x69, 0x40}, {0x6a, 0x00},
942 {0x6b, 0x0a}, {0x8b, 0x06}, {0x8c, 0x20},
943 {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0xdf},
944 {0x92, 0x00}, {0x93, 0x00}, {0x94, 0x88},
945 {0x95, 0x88}, {0x96, 0x04}, {0xa1, 0x00},
946 {0xa5, 0x80}, {0xa8, 0x80}, {0xa9, 0xb8},
947 {0xaa, 0x92}, {0xab, 0x0a},
948};
949
Joe Perches58aa68c2009-09-02 01:12:13 -0300950static struct i2c_reg_u8 ov9655_init[] = {
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300951 {0x12, 0x80}, {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
952 {0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
953 {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
954 {0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57},
955 {0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c}, {0x3d, 0x19},
956 {0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40}, {0x42, 0x80},
957 {0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a}, {0x48, 0x3c},
958 {0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc}, {0x4d, 0xdc},
959 {0x4e, 0xdc}, {0x6c, 0x04}, {0x6f, 0x9e}, {0x70, 0x05},
960 {0x71, 0x78}, {0x77, 0x02}, {0x8a, 0x23}, {0x90, 0x7e},
961 {0x91, 0x7c}, {0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68},
962 {0xa6, 0x60}, {0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92},
963 {0xab, 0x04}, {0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80},
964 {0xaf, 0x80}, {0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00},
965 {0xb6, 0xaf}, {0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44},
966 {0xbe, 0x3b}, {0xbf, 0x3a}, {0xc1, 0xc8}, {0xc2, 0x01},
Brian Johnson26e744b2009-07-19 05:52:58 -0300967 {0xc4, 0x00}, {0xc6, 0x85}, {0xc7, 0x81}, {0xc9, 0xe0},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300968 {0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x2d, 0x00},
969 {0x2e, 0x00}, {0x01, 0x80}, {0x02, 0x80}, {0x12, 0x61},
Brian Johnson26e744b2009-07-19 05:52:58 -0300970 {0x36, 0xfa}, {0x8c, 0x8d}, {0xc0, 0xaa}, {0x69, 0x0a},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300971 {0x03, 0x09}, {0x17, 0x16}, {0x18, 0x6e}, {0x19, 0x01},
972 {0x1a, 0x3e}, {0x32, 0x09}, {0x2a, 0x10}, {0x2b, 0x0a},
973 {0x92, 0x00}, {0x93, 0x00}, {0xa1, 0x00}, {0x10, 0x7c},
974 {0x04, 0x03}, {0x00, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300975};
976
Joe Perches58aa68c2009-09-02 01:12:13 -0300977static struct i2c_reg_u16 mt9v112_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300978 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020},
979 {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
980 {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
981 {0x05, 0x0000}, {0x06, 0x340c}, {0x3b, 0x042a},
982 {0x3c, 0x0400}, {0xf0, 0x0002}, {0x2e, 0x0c58},
983 {0x5b, 0x0001}, {0xc8, 0x9f0b}, {0xf0, 0x0001},
984 {0x9b, 0x5300}, {0xf0, 0x0000}, {0x2b, 0x0020},
985 {0x2c, 0x002a}, {0x2d, 0x0032}, {0x2e, 0x0020},
986 {0x09, 0x01dc}, {0x01, 0x000c}, {0x02, 0x0020},
987 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
988 {0x05, 0x0098}, {0x20, 0x0703}, {0x09, 0x01f2},
989 {0x2b, 0x00a0}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
990 {0x2e, 0x00a0}, {0x01, 0x000c}, {0x02, 0x0020},
991 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
992 {0x05, 0x0098}, {0x09, 0x01c1}, {0x2b, 0x00ae},
993 {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
994};
995
Joe Perches58aa68c2009-09-02 01:12:13 -0300996static struct i2c_reg_u16 mt9v111_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300997 {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
Brian Johnson6ea23bd2010-05-05 13:22:45 -0300998 {0x01, 0x0001}, {0x05, 0x0004}, {0x2d, 0xe0a0},
999 {0x2e, 0x0c64}, {0x2f, 0x0064}, {0x06, 0x600e},
1000 {0x08, 0x0480}, {0x01, 0x0004}, {0x02, 0x0016},
1001 {0x03, 0x01e7}, {0x04, 0x0287}, {0x05, 0x0004},
1002 {0x06, 0x002d}, {0x07, 0x3002}, {0x08, 0x0008},
1003 {0x0e, 0x0008}, {0x20, 0x0000}
Brian Johnson26e744b2009-07-19 05:52:58 -03001004};
1005
Joe Perches58aa68c2009-09-02 01:12:13 -03001006static struct i2c_reg_u16 mt9v011_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001007 {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
1008 {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1},
1009 {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006},
1010 {0x0d, 0x0002}, {0x0a, 0x0000}, {0x0b, 0x0000},
1011 {0x0c, 0x0000}, {0x0d, 0x0000}, {0x0e, 0x0000},
1012 {0x0f, 0x0000}, {0x10, 0x0000}, {0x11, 0x0000},
1013 {0x12, 0x0000}, {0x13, 0x0000}, {0x14, 0x0000},
1014 {0x15, 0x0000}, {0x16, 0x0000}, {0x17, 0x0000},
1015 {0x18, 0x0000}, {0x19, 0x0000}, {0x1a, 0x0000},
1016 {0x1b, 0x0000}, {0x1c, 0x0000}, {0x1d, 0x0000},
1017 {0x32, 0x0000}, {0x20, 0x1101}, {0x21, 0x0000},
1018 {0x22, 0x0000}, {0x23, 0x0000}, {0x24, 0x0000},
1019 {0x25, 0x0000}, {0x26, 0x0000}, {0x27, 0x0024},
1020 {0x2f, 0xf7b0}, {0x30, 0x0005}, {0x31, 0x0000},
1021 {0x32, 0x0000}, {0x33, 0x0000}, {0x34, 0x0100},
1022 {0x3d, 0x068f}, {0x40, 0x01e0}, {0x41, 0x00d1},
1023 {0x44, 0x0082}, {0x5a, 0x0000}, {0x5b, 0x0000},
1024 {0x5c, 0x0000}, {0x5d, 0x0000}, {0x5e, 0x0000},
1025 {0x5f, 0xa31d}, {0x62, 0x0611}, {0x0a, 0x0000},
1026 {0x06, 0x0029}, {0x05, 0x0009}, {0x20, 0x1101},
1027 {0x20, 0x1101}, {0x09, 0x0064}, {0x07, 0x0003},
1028 {0x2b, 0x0033}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
1029 {0x2e, 0x0033}, {0x07, 0x0002}, {0x06, 0x0000},
1030 {0x06, 0x0029}, {0x05, 0x0009},
1031};
1032
Joe Perches58aa68c2009-09-02 01:12:13 -03001033static struct i2c_reg_u16 mt9m001_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001034 {0x0d, 0x0001}, {0x0d, 0x0000}, {0x01, 0x000e},
1035 {0x02, 0x0014}, {0x03, 0x03c1}, {0x04, 0x0501},
1036 {0x05, 0x0083}, {0x06, 0x0006}, {0x0d, 0x0002},
1037 {0x0a, 0x0000}, {0x0c, 0x0000}, {0x11, 0x0000},
1038 {0x1e, 0x8000}, {0x5f, 0x8904}, {0x60, 0x0000},
1039 {0x61, 0x0000}, {0x62, 0x0498}, {0x63, 0x0000},
1040 {0x64, 0x0000}, {0x20, 0x111d}, {0x06, 0x00f2},
1041 {0x05, 0x0013}, {0x09, 0x10f2}, {0x07, 0x0003},
1042 {0x2b, 0x002a}, {0x2d, 0x002a}, {0x2c, 0x002a},
1043 {0x2e, 0x0029}, {0x07, 0x0002},
1044};
1045
Joe Perches58aa68c2009-09-02 01:12:13 -03001046static struct i2c_reg_u16 mt9m111_init[] = {
Brian Johnson13a84fa2009-09-03 19:07:13 -03001047 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
1048 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
Brian Johnson4d708a52009-09-03 19:10:15 -03001049 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
1050 {0xf0, 0x0000},
Brian Johnson26e744b2009-07-19 05:52:58 -03001051};
1052
Brian Johnsone99ac542010-03-16 13:58:28 -03001053static struct i2c_reg_u16 mt9m112_init[] = {
1054 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
1055 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
1056 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
1057 {0xf0, 0x0000},
1058};
1059
Joe Perches58aa68c2009-09-02 01:12:13 -03001060static struct i2c_reg_u8 hv7131r_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001061 {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
1062 {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
1063 {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
1064 {0x01, 0x08}, {0x01, 0x08}, {0x25, 0x07},
1065 {0x26, 0xc3}, {0x27, 0x50}, {0x30, 0x62},
1066 {0x31, 0x10}, {0x32, 0x06}, {0x33, 0x10},
1067 {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00},
1068 {0x23, 0x09}, {0x01, 0x08},
1069};
1070
Joe Perches58aa68c2009-09-02 01:12:13 -03001071static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
Brian Johnson26e744b2009-07-19 05:52:58 -03001072{
1073 struct usb_device *dev = gspca_dev->dev;
1074 int result;
1075 result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
1076 0x00,
1077 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
1078 reg,
1079 0x00,
1080 gspca_dev->usb_buf,
1081 length,
1082 500);
1083 if (unlikely(result < 0 || result != length)) {
1084 err("Read register failed 0x%02X", reg);
1085 return -EIO;
1086 }
1087 return 0;
1088}
1089
Joe Perches58aa68c2009-09-02 01:12:13 -03001090static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
1091 const u8 *buffer, int length)
Brian Johnson26e744b2009-07-19 05:52:58 -03001092{
1093 struct usb_device *dev = gspca_dev->dev;
1094 int result;
1095 memcpy(gspca_dev->usb_buf, buffer, length);
1096 result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
1097 0x08,
1098 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
1099 reg,
1100 0x00,
1101 gspca_dev->usb_buf,
1102 length,
1103 500);
1104 if (unlikely(result < 0 || result != length)) {
1105 err("Write register failed index 0x%02X", reg);
1106 return -EIO;
1107 }
1108 return 0;
1109}
1110
Joe Perches58aa68c2009-09-02 01:12:13 -03001111static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
Brian Johnson26e744b2009-07-19 05:52:58 -03001112{
1113 u8 data[1] = {value};
1114 return reg_w(gspca_dev, reg, data, 1);
1115}
1116
Joe Perches58aa68c2009-09-02 01:12:13 -03001117static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
Brian Johnson26e744b2009-07-19 05:52:58 -03001118{
1119 int i;
1120 reg_w(gspca_dev, 0x10c0, buffer, 8);
1121 for (i = 0; i < 5; i++) {
1122 reg_r(gspca_dev, 0x10c0, 1);
1123 if (gspca_dev->usb_buf[0] & 0x04) {
1124 if (gspca_dev->usb_buf[0] & 0x08)
Brian Johnson00b581e2009-07-23 05:55:43 -03001125 return -EIO;
Brian Johnson26e744b2009-07-19 05:52:58 -03001126 return 0;
1127 }
1128 msleep(1);
1129 }
Brian Johnson00b581e2009-07-23 05:55:43 -03001130 return -EIO;
Brian Johnson26e744b2009-07-19 05:52:58 -03001131}
1132
Joe Perches58aa68c2009-09-02 01:12:13 -03001133static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001134{
1135 struct sd *sd = (struct sd *) gspca_dev;
1136
1137 u8 row[8];
1138
1139 /*
1140 * from the point of view of the bridge, the length
1141 * includes the address
1142 */
1143 row[0] = 0x81 | (2 << 4);
1144 row[1] = sd->i2c_addr;
1145 row[2] = reg;
1146 row[3] = val;
1147 row[4] = 0x00;
1148 row[5] = 0x00;
1149 row[6] = 0x00;
1150 row[7] = 0x10;
1151
1152 return i2c_w(gspca_dev, row);
1153}
1154
Joe Perches58aa68c2009-09-02 01:12:13 -03001155static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001156{
1157 struct sd *sd = (struct sd *) gspca_dev;
1158 u8 row[8];
1159
1160 /*
1161 * from the point of view of the bridge, the length
1162 * includes the address
1163 */
1164 row[0] = 0x81 | (3 << 4);
1165 row[1] = sd->i2c_addr;
1166 row[2] = reg;
1167 row[3] = (val >> 8) & 0xff;
1168 row[4] = val & 0xff;
1169 row[5] = 0x00;
1170 row[6] = 0x00;
1171 row[7] = 0x10;
1172
1173 return i2c_w(gspca_dev, row);
1174}
1175
Jean-Francois Moine83955552009-12-12 06:58:01 -03001176static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001177{
1178 struct sd *sd = (struct sd *) gspca_dev;
1179 u8 row[8];
1180
Brian Johnson00b581e2009-07-23 05:55:43 -03001181 row[0] = 0x81 | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001182 row[1] = sd->i2c_addr;
1183 row[2] = reg;
1184 row[3] = 0;
1185 row[4] = 0;
1186 row[5] = 0;
1187 row[6] = 0;
1188 row[7] = 0x10;
Brian Johnson00b581e2009-07-23 05:55:43 -03001189 if (i2c_w(gspca_dev, row) < 0)
1190 return -EIO;
1191 row[0] = 0x81 | (1 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001192 row[2] = 0;
Brian Johnson00b581e2009-07-23 05:55:43 -03001193 if (i2c_w(gspca_dev, row) < 0)
1194 return -EIO;
1195 if (reg_r(gspca_dev, 0x10c2, 5) < 0)
1196 return -EIO;
1197 *val = gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001198 return 0;
1199}
1200
Jean-Francois Moine83955552009-12-12 06:58:01 -03001201static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001202{
1203 struct sd *sd = (struct sd *) gspca_dev;
1204 u8 row[8];
1205
Brian Johnson00b581e2009-07-23 05:55:43 -03001206 row[0] = 0x81 | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001207 row[1] = sd->i2c_addr;
1208 row[2] = reg;
1209 row[3] = 0;
1210 row[4] = 0;
1211 row[5] = 0;
1212 row[6] = 0;
1213 row[7] = 0x10;
Brian Johnson00b581e2009-07-23 05:55:43 -03001214 if (i2c_w(gspca_dev, row) < 0)
1215 return -EIO;
1216 row[0] = 0x81 | (2 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001217 row[2] = 0;
Brian Johnson00b581e2009-07-23 05:55:43 -03001218 if (i2c_w(gspca_dev, row) < 0)
1219 return -EIO;
1220 if (reg_r(gspca_dev, 0x10c2, 5) < 0)
1221 return -EIO;
1222 *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001223 return 0;
1224}
1225
1226static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
1227{
1228 int i;
1229 struct sd *sd = (struct sd *) gspca_dev;
1230
1231 for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001232 if (i2c_w1(gspca_dev, ov9650_init[i].reg,
1233 ov9650_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001234 err("OV9650 sensor initialization failed");
1235 return -ENODEV;
1236 }
1237 }
1238 sd->hstart = 1;
1239 sd->vstart = 7;
1240 return 0;
1241}
1242
1243static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
1244{
1245 int i;
1246 struct sd *sd = (struct sd *) gspca_dev;
1247
1248 for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001249 if (i2c_w1(gspca_dev, ov9655_init[i].reg,
1250 ov9655_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001251 err("OV9655 sensor initialization failed");
1252 return -ENODEV;
1253 }
1254 }
1255 /* disable hflip and vflip */
1256 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
Brian Johnsoncc2a8332010-03-16 13:58:28 -03001257 sd->hstart = 1;
1258 sd->vstart = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001259 return 0;
1260}
1261
1262static int soi968_init_sensor(struct gspca_dev *gspca_dev)
1263{
1264 int i;
1265 struct sd *sd = (struct sd *) gspca_dev;
1266
1267 for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001268 if (i2c_w1(gspca_dev, soi968_init[i].reg,
1269 soi968_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001270 err("SOI968 sensor initialization failed");
1271 return -ENODEV;
1272 }
1273 }
1274 /* disable hflip and vflip */
Brian Johnsone1430472009-09-02 12:39:41 -03001275 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << EXPOSURE_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001276 sd->hstart = 60;
1277 sd->vstart = 11;
1278 return 0;
1279}
1280
1281static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
1282{
1283 int i;
1284 struct sd *sd = (struct sd *) gspca_dev;
1285
1286 for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001287 if (i2c_w1(gspca_dev, ov7660_init[i].reg,
1288 ov7660_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001289 err("OV7660 sensor initialization failed");
1290 return -ENODEV;
1291 }
1292 }
1293 /* disable hflip and vflip */
1294 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1295 sd->hstart = 1;
1296 sd->vstart = 1;
1297 return 0;
1298}
1299
1300static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
1301{
1302 int i;
1303 struct sd *sd = (struct sd *) gspca_dev;
1304
1305 for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001306 if (i2c_w1(gspca_dev, ov7670_init[i].reg,
1307 ov7670_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001308 err("OV7670 sensor initialization failed");
1309 return -ENODEV;
1310 }
1311 }
1312 /* disable hflip and vflip */
1313 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1314 sd->hstart = 0;
1315 sd->vstart = 1;
1316 return 0;
1317}
1318
1319static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
1320{
1321 struct sd *sd = (struct sd *) gspca_dev;
1322 int i;
1323 u16 value;
1324 int ret;
1325
1326 sd->i2c_addr = 0x5d;
1327 ret = i2c_r2(gspca_dev, 0xff, &value);
1328 if ((ret == 0) && (value == 0x8243)) {
1329 for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001330 if (i2c_w2(gspca_dev, mt9v011_init[i].reg,
1331 mt9v011_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001332 err("MT9V011 sensor initialization failed");
1333 return -ENODEV;
1334 }
1335 }
1336 sd->hstart = 2;
1337 sd->vstart = 2;
1338 sd->sensor = SENSOR_MT9V011;
1339 info("MT9V011 sensor detected");
1340 return 0;
1341 }
1342
1343 sd->i2c_addr = 0x5c;
1344 i2c_w2(gspca_dev, 0x01, 0x0004);
1345 ret = i2c_r2(gspca_dev, 0xff, &value);
1346 if ((ret == 0) && (value == 0x823a)) {
1347 for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001348 if (i2c_w2(gspca_dev, mt9v111_init[i].reg,
1349 mt9v111_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001350 err("MT9V111 sensor initialization failed");
1351 return -ENODEV;
1352 }
1353 }
Brian Johnson6ea23bd2010-05-05 13:22:45 -03001354 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001355 sd->hstart = 2;
1356 sd->vstart = 2;
1357 sd->sensor = SENSOR_MT9V111;
1358 info("MT9V111 sensor detected");
1359 return 0;
1360 }
1361
1362 sd->i2c_addr = 0x5d;
1363 ret = i2c_w2(gspca_dev, 0xf0, 0x0000);
1364 if (ret < 0) {
1365 sd->i2c_addr = 0x48;
1366 i2c_w2(gspca_dev, 0xf0, 0x0000);
1367 }
1368 ret = i2c_r2(gspca_dev, 0x00, &value);
1369 if ((ret == 0) && (value == 0x1229)) {
1370 for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001371 if (i2c_w2(gspca_dev, mt9v112_init[i].reg,
1372 mt9v112_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001373 err("MT9V112 sensor initialization failed");
1374 return -ENODEV;
1375 }
1376 }
1377 sd->hstart = 6;
1378 sd->vstart = 2;
1379 sd->sensor = SENSOR_MT9V112;
1380 info("MT9V112 sensor detected");
1381 return 0;
1382 }
1383
1384 return -ENODEV;
1385}
1386
Brian Johnsone99ac542010-03-16 13:58:28 -03001387static int mt9m112_init_sensor(struct gspca_dev *gspca_dev)
1388{
1389 struct sd *sd = (struct sd *) gspca_dev;
1390 int i;
1391 for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) {
1392 if (i2c_w2(gspca_dev, mt9m112_init[i].reg,
1393 mt9m112_init[i].val) < 0) {
1394 err("MT9M112 sensor initialization failed");
1395 return -ENODEV;
1396 }
1397 }
1398 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
1399 sd->hstart = 0;
1400 sd->vstart = 2;
1401 return 0;
1402}
1403
Brian Johnson26e744b2009-07-19 05:52:58 -03001404static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
1405{
1406 struct sd *sd = (struct sd *) gspca_dev;
1407 int i;
1408 for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001409 if (i2c_w2(gspca_dev, mt9m111_init[i].reg,
1410 mt9m111_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001411 err("MT9M111 sensor initialization failed");
1412 return -ENODEV;
1413 }
1414 }
Brian Johnson13a84fa2009-09-03 19:07:13 -03001415 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001416 sd->hstart = 0;
1417 sd->vstart = 2;
1418 return 0;
1419}
1420
1421static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
1422{
1423 struct sd *sd = (struct sd *) gspca_dev;
1424 int i;
1425 for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001426 if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
1427 mt9m001_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001428 err("MT9M001 sensor initialization failed");
1429 return -ENODEV;
1430 }
1431 }
1432 /* disable hflip and vflip */
1433 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1434 sd->hstart = 2;
1435 sd->vstart = 2;
1436 return 0;
1437}
1438
1439static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
1440{
1441 int i;
1442 struct sd *sd = (struct sd *) gspca_dev;
1443
1444 for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001445 if (i2c_w1(gspca_dev, hv7131r_init[i].reg,
1446 hv7131r_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001447 err("HV7131R Sensor initialization failed");
1448 return -ENODEV;
1449 }
1450 }
1451 sd->hstart = 0;
1452 sd->vstart = 1;
1453 return 0;
1454}
1455
Brian Johnson26e744b2009-07-19 05:52:58 -03001456static int set_cmatrix(struct gspca_dev *gspca_dev)
1457{
1458 struct sd *sd = (struct sd *) gspca_dev;
1459 s32 hue_coord, hue_index = 180 + sd->hue;
1460 u8 cmatrix[21];
Brian Johnson26e744b2009-07-19 05:52:58 -03001461
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001462 memset(cmatrix, 0, sizeof cmatrix);
Brian Johnson26e744b2009-07-19 05:52:58 -03001463 cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26;
1464 cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
1465 cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
1466 cmatrix[18] = sd->brightness - 0x80;
1467
1468 hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001469 cmatrix[6] = hue_coord;
1470 cmatrix[7] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001471
1472 hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001473 cmatrix[8] = hue_coord;
1474 cmatrix[9] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001475
1476 hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001477 cmatrix[10] = hue_coord;
1478 cmatrix[11] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001479
1480 hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001481 cmatrix[12] = hue_coord;
1482 cmatrix[13] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001483
1484 hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001485 cmatrix[14] = hue_coord;
1486 cmatrix[15] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001487
1488 hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001489 cmatrix[16] = hue_coord;
1490 cmatrix[17] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001491
1492 return reg_w(gspca_dev, 0x10e1, cmatrix, 21);
1493}
1494
1495static int set_gamma(struct gspca_dev *gspca_dev)
1496{
1497 struct sd *sd = (struct sd *) gspca_dev;
1498 u8 gamma[17];
1499 u8 gval = sd->gamma * 0xb8 / 0x100;
1500
1501
1502 gamma[0] = 0x0a;
1503 gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
1504 gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8);
1505 gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8);
1506 gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8);
1507 gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8);
1508 gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8);
1509 gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8);
1510 gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8);
1511 gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8);
1512 gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8);
1513 gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8);
1514 gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8);
1515 gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8);
1516 gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8);
1517 gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
1518 gamma[16] = 0xf5;
1519
1520 return reg_w(gspca_dev, 0x1190, gamma, 17);
1521}
1522
1523static int set_redblue(struct gspca_dev *gspca_dev)
1524{
1525 struct sd *sd = (struct sd *) gspca_dev;
1526 reg_w1(gspca_dev, 0x118c, sd->red);
1527 reg_w1(gspca_dev, 0x118f, sd->blue);
1528 return 0;
1529}
1530
1531static int set_hvflip(struct gspca_dev *gspca_dev)
1532{
Brian Johnson7ddaac72010-03-16 13:58:27 -03001533 u8 value, tslb, hflip, vflip;
Brian Johnson26e744b2009-07-19 05:52:58 -03001534 u16 value2;
1535 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001536
1537 if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
1538 hflip = !sd->hflip;
1539 vflip = !sd->vflip;
1540 } else {
1541 hflip = sd->hflip;
1542 vflip = sd->vflip;
1543 }
1544
Brian Johnson26e744b2009-07-19 05:52:58 -03001545 switch (sd->sensor) {
1546 case SENSOR_OV9650:
1547 i2c_r1(gspca_dev, 0x1e, &value);
1548 value &= ~0x30;
1549 tslb = 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001550 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001551 value |= 0x20;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001552 if (vflip) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001553 value |= 0x10;
1554 tslb = 0x49;
1555 }
1556 i2c_w1(gspca_dev, 0x1e, value);
1557 i2c_w1(gspca_dev, 0x3a, tslb);
1558 break;
1559 case SENSOR_MT9V111:
1560 case SENSOR_MT9V011:
1561 i2c_r2(gspca_dev, 0x20, &value2);
1562 value2 &= ~0xc0a0;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001563 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001564 value2 |= 0x8080;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001565 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001566 value2 |= 0x4020;
1567 i2c_w2(gspca_dev, 0x20, value2);
1568 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001569 case SENSOR_MT9M112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001570 case SENSOR_MT9M111:
1571 case SENSOR_MT9V112:
1572 i2c_r2(gspca_dev, 0x20, &value2);
1573 value2 &= ~0x0003;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001574 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001575 value2 |= 0x0002;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001576 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001577 value2 |= 0x0001;
1578 i2c_w2(gspca_dev, 0x20, value2);
1579 break;
1580 case SENSOR_HV7131R:
1581 i2c_r1(gspca_dev, 0x01, &value);
1582 value &= ~0x03;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001583 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001584 value |= 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001585 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001586 value |= 0x02;
1587 i2c_w1(gspca_dev, 0x01, value);
1588 break;
1589 }
1590 return 0;
1591}
1592
1593static int set_exposure(struct gspca_dev *gspca_dev)
1594{
1595 struct sd *sd = (struct sd *) gspca_dev;
1596 u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
1597 switch (sd->sensor) {
1598 case SENSOR_OV7660:
1599 case SENSOR_OV7670:
Brian Johnson26e744b2009-07-19 05:52:58 -03001600 case SENSOR_OV9655:
1601 case SENSOR_OV9650:
1602 exp[0] |= (3 << 4);
1603 exp[2] = 0x2d;
1604 exp[3] = sd->exposure & 0xff;
1605 exp[4] = sd->exposure >> 8;
1606 break;
1607 case SENSOR_MT9M001:
Brian Johnson26e744b2009-07-19 05:52:58 -03001608 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001609 case SENSOR_MT9V011:
1610 exp[0] |= (3 << 4);
1611 exp[2] = 0x09;
1612 exp[3] = sd->exposure >> 8;
1613 exp[4] = sd->exposure & 0xff;
1614 break;
1615 case SENSOR_HV7131R:
1616 exp[0] |= (4 << 4);
1617 exp[2] = 0x25;
German Galkine10f7312010-03-07 06:19:02 -03001618 exp[3] = (sd->exposure >> 5) & 0xff;
1619 exp[4] = (sd->exposure << 3) & 0xff;
1620 exp[5] = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001621 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001622 default:
1623 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001624 }
1625 i2c_w(gspca_dev, exp);
1626 return 0;
1627}
1628
1629static int set_gain(struct gspca_dev *gspca_dev)
1630{
1631 struct sd *sd = (struct sd *) gspca_dev;
1632 u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
1633 switch (sd->sensor) {
1634 case SENSOR_OV7660:
1635 case SENSOR_OV7670:
1636 case SENSOR_SOI968:
1637 case SENSOR_OV9655:
1638 case SENSOR_OV9650:
1639 gain[0] |= (2 << 4);
1640 gain[3] = ov_gain[sd->gain];
1641 break;
1642 case SENSOR_MT9V011:
Brian Johnson26e744b2009-07-19 05:52:58 -03001643 gain[0] |= (3 << 4);
1644 gain[2] = 0x35;
1645 gain[3] = micron1_gain[sd->gain] >> 8;
1646 gain[4] = micron1_gain[sd->gain] & 0xff;
1647 break;
1648 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001649 gain[0] |= (3 << 4);
1650 gain[2] = 0x2f;
1651 gain[3] = micron1_gain[sd->gain] >> 8;
1652 gain[4] = micron1_gain[sd->gain] & 0xff;
1653 break;
1654 case SENSOR_MT9M001:
1655 gain[0] |= (3 << 4);
1656 gain[2] = 0x2f;
1657 gain[3] = micron2_gain[sd->gain] >> 8;
1658 gain[4] = micron2_gain[sd->gain] & 0xff;
1659 break;
1660 case SENSOR_HV7131R:
1661 gain[0] |= (2 << 4);
1662 gain[2] = 0x30;
1663 gain[3] = hv7131r_gain[sd->gain];
1664 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001665 default:
1666 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001667 }
1668 i2c_w(gspca_dev, gain);
1669 return 0;
1670}
1671
1672static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val)
1673{
1674 struct sd *sd = (struct sd *) gspca_dev;
1675
1676 sd->brightness = val;
1677 if (gspca_dev->streaming)
1678 return set_cmatrix(gspca_dev);
1679 return 0;
1680}
1681
1682static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val)
1683{
1684 struct sd *sd = (struct sd *) gspca_dev;
1685 *val = sd->brightness;
1686 return 0;
1687}
1688
1689
1690static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val)
1691{
1692 struct sd *sd = (struct sd *) gspca_dev;
1693
1694 sd->contrast = val;
1695 if (gspca_dev->streaming)
1696 return set_cmatrix(gspca_dev);
1697 return 0;
1698}
1699
1700static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val)
1701{
1702 struct sd *sd = (struct sd *) gspca_dev;
1703 *val = sd->contrast;
1704 return 0;
1705}
1706
1707static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val)
1708{
1709 struct sd *sd = (struct sd *) gspca_dev;
1710
1711 sd->saturation = val;
1712 if (gspca_dev->streaming)
1713 return set_cmatrix(gspca_dev);
1714 return 0;
1715}
1716
1717static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val)
1718{
1719 struct sd *sd = (struct sd *) gspca_dev;
1720 *val = sd->saturation;
1721 return 0;
1722}
1723
1724static int sd_sethue(struct gspca_dev *gspca_dev, s32 val)
1725{
1726 struct sd *sd = (struct sd *) gspca_dev;
1727
1728 sd->hue = val;
1729 if (gspca_dev->streaming)
1730 return set_cmatrix(gspca_dev);
1731 return 0;
1732}
1733
1734static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val)
1735{
1736 struct sd *sd = (struct sd *) gspca_dev;
1737 *val = sd->hue;
1738 return 0;
1739}
1740
1741static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val)
1742{
1743 struct sd *sd = (struct sd *) gspca_dev;
1744
1745 sd->gamma = val;
1746 if (gspca_dev->streaming)
1747 return set_gamma(gspca_dev);
1748 return 0;
1749}
1750
1751static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val)
1752{
1753 struct sd *sd = (struct sd *) gspca_dev;
1754 *val = sd->gamma;
1755 return 0;
1756}
1757
1758static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val)
1759{
1760 struct sd *sd = (struct sd *) gspca_dev;
1761
1762 sd->red = val;
1763 if (gspca_dev->streaming)
1764 return set_redblue(gspca_dev);
1765 return 0;
1766}
1767
1768static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val)
1769{
1770 struct sd *sd = (struct sd *) gspca_dev;
1771 *val = sd->red;
1772 return 0;
1773}
1774
1775static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val)
1776{
1777 struct sd *sd = (struct sd *) gspca_dev;
1778
1779 sd->blue = val;
1780 if (gspca_dev->streaming)
1781 return set_redblue(gspca_dev);
1782 return 0;
1783}
1784
1785static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val)
1786{
1787 struct sd *sd = (struct sd *) gspca_dev;
1788 *val = sd->blue;
1789 return 0;
1790}
1791
1792static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val)
1793{
1794 struct sd *sd = (struct sd *) gspca_dev;
1795
1796 sd->hflip = val;
1797 if (gspca_dev->streaming)
1798 return set_hvflip(gspca_dev);
1799 return 0;
1800}
1801
1802static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val)
1803{
1804 struct sd *sd = (struct sd *) gspca_dev;
1805 *val = sd->hflip;
1806 return 0;
1807}
1808
1809static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val)
1810{
1811 struct sd *sd = (struct sd *) gspca_dev;
1812
1813 sd->vflip = val;
1814 if (gspca_dev->streaming)
1815 return set_hvflip(gspca_dev);
1816 return 0;
1817}
1818
1819static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val)
1820{
1821 struct sd *sd = (struct sd *) gspca_dev;
1822 *val = sd->vflip;
1823 return 0;
1824}
1825
1826static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val)
1827{
1828 struct sd *sd = (struct sd *) gspca_dev;
1829
1830 sd->exposure = val;
1831 if (gspca_dev->streaming)
1832 return set_exposure(gspca_dev);
1833 return 0;
1834}
1835
1836static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val)
1837{
1838 struct sd *sd = (struct sd *) gspca_dev;
1839 *val = sd->exposure;
1840 return 0;
1841}
1842
1843static int sd_setgain(struct gspca_dev *gspca_dev, s32 val)
1844{
1845 struct sd *sd = (struct sd *) gspca_dev;
1846
1847 sd->gain = val;
1848 if (gspca_dev->streaming)
1849 return set_gain(gspca_dev);
1850 return 0;
1851}
1852
1853static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val)
1854{
1855 struct sd *sd = (struct sd *) gspca_dev;
1856 *val = sd->gain;
1857 return 0;
1858}
1859
1860static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val)
1861{
1862 struct sd *sd = (struct sd *) gspca_dev;
1863 sd->auto_exposure = val;
1864 return 0;
1865}
1866
1867static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val)
1868{
1869 struct sd *sd = (struct sd *) gspca_dev;
1870 *val = sd->auto_exposure;
1871 return 0;
1872}
1873
1874#ifdef CONFIG_VIDEO_ADV_DEBUG
1875static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
1876 struct v4l2_dbg_register *reg)
1877{
1878 struct sd *sd = (struct sd *) gspca_dev;
1879 switch (reg->match.type) {
1880 case V4L2_CHIP_MATCH_HOST:
1881 if (reg->match.addr != 0)
1882 return -EINVAL;
1883 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1884 return -EINVAL;
1885 if (reg_r(gspca_dev, reg->reg, 1) < 0)
1886 return -EINVAL;
1887 reg->val = gspca_dev->usb_buf[0];
1888 return 0;
1889 case V4L2_CHIP_MATCH_I2C_ADDR:
1890 if (reg->match.addr != sd->i2c_addr)
1891 return -EINVAL;
1892 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001893 sd->sensor <= SENSOR_MT9M112) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001894 if (i2c_r2(gspca_dev, reg->reg, (u16 *)&reg->val) < 0)
1895 return -EINVAL;
1896 } else {
1897 if (i2c_r1(gspca_dev, reg->reg, (u8 *)&reg->val) < 0)
1898 return -EINVAL;
1899 }
1900 return 0;
1901 }
1902 return -EINVAL;
1903}
1904
1905static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
1906 struct v4l2_dbg_register *reg)
1907{
1908 struct sd *sd = (struct sd *) gspca_dev;
1909 switch (reg->match.type) {
1910 case V4L2_CHIP_MATCH_HOST:
1911 if (reg->match.addr != 0)
1912 return -EINVAL;
1913 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1914 return -EINVAL;
1915 if (reg_w1(gspca_dev, reg->reg, reg->val) < 0)
1916 return -EINVAL;
1917 return 0;
1918 case V4L2_CHIP_MATCH_I2C_ADDR:
1919 if (reg->match.addr != sd->i2c_addr)
1920 return -EINVAL;
1921 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001922 sd->sensor <= SENSOR_MT9M112) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001923 if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0)
1924 return -EINVAL;
1925 } else {
1926 if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0)
1927 return -EINVAL;
1928 }
1929 return 0;
1930 }
1931 return -EINVAL;
1932}
1933#endif
1934
1935static int sd_chip_ident(struct gspca_dev *gspca_dev,
1936 struct v4l2_dbg_chip_ident *chip)
1937{
1938 struct sd *sd = (struct sd *) gspca_dev;
1939
1940 switch (chip->match.type) {
1941 case V4L2_CHIP_MATCH_HOST:
1942 if (chip->match.addr != 0)
1943 return -EINVAL;
1944 chip->revision = 0;
1945 chip->ident = V4L2_IDENT_SN9C20X;
1946 return 0;
1947 case V4L2_CHIP_MATCH_I2C_ADDR:
1948 if (chip->match.addr != sd->i2c_addr)
1949 return -EINVAL;
1950 chip->revision = 0;
1951 chip->ident = i2c_ident[sd->sensor];
1952 return 0;
1953 }
1954 return -EINVAL;
1955}
1956
1957static int sd_config(struct gspca_dev *gspca_dev,
1958 const struct usb_device_id *id)
1959{
1960 struct sd *sd = (struct sd *) gspca_dev;
1961 struct cam *cam;
1962
1963 cam = &gspca_dev->cam;
1964
1965 sd->sensor = (id->driver_info >> 8) & 0xff;
1966 sd->i2c_addr = id->driver_info & 0xff;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03001967 sd->flags = (id->driver_info >> 16) & 0xff;
Brian Johnson26e744b2009-07-19 05:52:58 -03001968
1969 switch (sd->sensor) {
Brian Johnsone99ac542010-03-16 13:58:28 -03001970 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03001971 case SENSOR_MT9M111:
Brian Johnson26e744b2009-07-19 05:52:58 -03001972 case SENSOR_OV9650:
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001973 case SENSOR_SOI968:
Brian Johnson26e744b2009-07-19 05:52:58 -03001974 cam->cam_mode = sxga_mode;
1975 cam->nmodes = ARRAY_SIZE(sxga_mode);
1976 break;
1977 default:
1978 cam->cam_mode = vga_mode;
1979 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001980 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001981 }
1982
1983 sd->old_step = 0;
1984 sd->older_step = 0;
1985 sd->exposure_step = 16;
1986
1987 sd->brightness = BRIGHTNESS_DEFAULT;
1988 sd->contrast = CONTRAST_DEFAULT;
1989 sd->saturation = SATURATION_DEFAULT;
1990 sd->hue = HUE_DEFAULT;
1991 sd->gamma = GAMMA_DEFAULT;
1992 sd->red = RED_DEFAULT;
1993 sd->blue = BLUE_DEFAULT;
1994
1995 sd->hflip = HFLIP_DEFAULT;
1996 sd->vflip = VFLIP_DEFAULT;
1997 sd->exposure = EXPOSURE_DEFAULT;
1998 sd->gain = GAIN_DEFAULT;
1999 sd->auto_exposure = AUTO_EXPOSURE_DEFAULT;
2000
2001 sd->quality = 95;
2002
Brian Johnson26e744b2009-07-19 05:52:58 -03002003 return 0;
2004}
2005
2006static int sd_init(struct gspca_dev *gspca_dev)
2007{
2008 struct sd *sd = (struct sd *) gspca_dev;
2009 int i;
2010 u8 value;
2011 u8 i2c_init[9] =
2012 {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03};
2013
2014 for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
2015 value = bridge_init[i][1];
2016 if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) {
2017 err("Device initialization failed");
2018 return -ENODEV;
2019 }
2020 }
2021
Brian Johnson0c045eb2010-03-16 13:58:27 -03002022 if (sd->flags & LED_REVERSE)
2023 reg_w1(gspca_dev, 0x1006, 0x00);
2024 else
2025 reg_w1(gspca_dev, 0x1006, 0x20);
2026
Brian Johnson26e744b2009-07-19 05:52:58 -03002027 if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
2028 err("Device initialization failed");
2029 return -ENODEV;
2030 }
2031
2032 switch (sd->sensor) {
2033 case SENSOR_OV9650:
2034 if (ov9650_init_sensor(gspca_dev) < 0)
2035 return -ENODEV;
2036 info("OV9650 sensor detected");
2037 break;
2038 case SENSOR_OV9655:
2039 if (ov9655_init_sensor(gspca_dev) < 0)
2040 return -ENODEV;
2041 info("OV9655 sensor detected");
2042 break;
2043 case SENSOR_SOI968:
2044 if (soi968_init_sensor(gspca_dev) < 0)
2045 return -ENODEV;
2046 info("SOI968 sensor detected");
2047 break;
2048 case SENSOR_OV7660:
2049 if (ov7660_init_sensor(gspca_dev) < 0)
2050 return -ENODEV;
2051 info("OV7660 sensor detected");
2052 break;
2053 case SENSOR_OV7670:
2054 if (ov7670_init_sensor(gspca_dev) < 0)
2055 return -ENODEV;
2056 info("OV7670 sensor detected");
2057 break;
2058 case SENSOR_MT9VPRB:
2059 if (mt9v_init_sensor(gspca_dev) < 0)
2060 return -ENODEV;
2061 break;
2062 case SENSOR_MT9M111:
2063 if (mt9m111_init_sensor(gspca_dev) < 0)
2064 return -ENODEV;
2065 info("MT9M111 sensor detected");
2066 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03002067 case SENSOR_MT9M112:
2068 if (mt9m112_init_sensor(gspca_dev) < 0)
2069 return -ENODEV;
2070 info("MT9M112 sensor detected");
2071 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002072 case SENSOR_MT9M001:
2073 if (mt9m001_init_sensor(gspca_dev) < 0)
2074 return -ENODEV;
2075 info("MT9M001 sensor detected");
2076 break;
2077 case SENSOR_HV7131R:
2078 if (hv7131r_init_sensor(gspca_dev) < 0)
2079 return -ENODEV;
2080 info("HV7131R sensor detected");
2081 break;
2082 default:
2083 info("Unsupported Sensor");
2084 return -ENODEV;
2085 }
2086
2087 return 0;
2088}
2089
2090static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
2091{
2092 struct sd *sd = (struct sd *) gspca_dev;
2093 u8 value;
2094 switch (sd->sensor) {
Brian Johnsone8b7acc2009-09-02 13:14:41 -03002095 case SENSOR_SOI968:
2096 if (mode & MODE_SXGA) {
2097 i2c_w1(gspca_dev, 0x17, 0x1d);
2098 i2c_w1(gspca_dev, 0x18, 0xbd);
2099 i2c_w1(gspca_dev, 0x19, 0x01);
2100 i2c_w1(gspca_dev, 0x1a, 0x81);
2101 i2c_w1(gspca_dev, 0x12, 0x00);
2102 sd->hstart = 140;
2103 sd->vstart = 19;
2104 } else {
2105 i2c_w1(gspca_dev, 0x17, 0x13);
2106 i2c_w1(gspca_dev, 0x18, 0x63);
2107 i2c_w1(gspca_dev, 0x19, 0x01);
2108 i2c_w1(gspca_dev, 0x1a, 0x79);
2109 i2c_w1(gspca_dev, 0x12, 0x40);
2110 sd->hstart = 60;
2111 sd->vstart = 11;
2112 }
2113 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002114 case SENSOR_OV9650:
2115 if (mode & MODE_SXGA) {
2116 i2c_w1(gspca_dev, 0x17, 0x1b);
2117 i2c_w1(gspca_dev, 0x18, 0xbc);
2118 i2c_w1(gspca_dev, 0x19, 0x01);
2119 i2c_w1(gspca_dev, 0x1a, 0x82);
2120 i2c_r1(gspca_dev, 0x12, &value);
2121 i2c_w1(gspca_dev, 0x12, value & 0x07);
2122 } else {
2123 i2c_w1(gspca_dev, 0x17, 0x24);
2124 i2c_w1(gspca_dev, 0x18, 0xc5);
2125 i2c_w1(gspca_dev, 0x19, 0x00);
2126 i2c_w1(gspca_dev, 0x1a, 0x3c);
2127 i2c_r1(gspca_dev, 0x12, &value);
2128 i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
2129 }
2130 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03002131 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03002132 case SENSOR_MT9M111:
2133 if (mode & MODE_SXGA) {
2134 i2c_w2(gspca_dev, 0xf0, 0x0002);
2135 i2c_w2(gspca_dev, 0xc8, 0x970b);
2136 i2c_w2(gspca_dev, 0xf0, 0x0000);
2137 } else {
2138 i2c_w2(gspca_dev, 0xf0, 0x0002);
2139 i2c_w2(gspca_dev, 0xc8, 0x8000);
2140 i2c_w2(gspca_dev, 0xf0, 0x0000);
2141 }
2142 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002143 }
2144}
2145
2146#define HW_WIN(mode, hstart, vstart) \
Jean-Francois Moine83955552009-12-12 06:58:01 -03002147((const u8 []){hstart, 0, vstart, 0, \
Brian Johnson26e744b2009-07-19 05:52:58 -03002148(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
2149(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)})
2150
2151#define CLR_WIN(width, height) \
2152((const u8 [])\
2153{0, width >> 2, 0, height >> 1,\
2154((width >> 10) & 0x01) | ((height >> 8) & 0x6)})
2155
2156static int sd_start(struct gspca_dev *gspca_dev)
2157{
2158 struct sd *sd = (struct sd *) gspca_dev;
2159 int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
2160 int width = gspca_dev->width;
2161 int height = gspca_dev->height;
2162 u8 fmt, scale = 0;
2163
Brian Johnson26e744b2009-07-19 05:52:58 -03002164 jpeg_define(sd->jpeg_hdr, height, width,
2165 0x21);
2166 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
2167
2168 if (mode & MODE_RAW)
2169 fmt = 0x2d;
2170 else if (mode & MODE_JPEG)
2171 fmt = 0x2c;
2172 else
2173 fmt = 0x2f;
2174
2175 switch (mode & 0x0f) {
2176 case 3:
2177 scale = 0xc0;
2178 info("Set 1280x1024");
2179 break;
2180 case 2:
2181 scale = 0x80;
2182 info("Set 640x480");
2183 break;
2184 case 1:
2185 scale = 0x90;
2186 info("Set 320x240");
2187 break;
2188 case 0:
2189 scale = 0xa0;
2190 info("Set 160x120");
2191 break;
2192 }
2193
2194 configure_sensor_output(gspca_dev, mode);
Jean-François Moine9a731a32010-06-04 05:26:42 -03002195 reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
2196 reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
Brian Johnson26e744b2009-07-19 05:52:58 -03002197 reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
2198 reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
2199 reg_w1(gspca_dev, 0x1189, scale);
2200 reg_w1(gspca_dev, 0x10e0, fmt);
2201
2202 set_cmatrix(gspca_dev);
2203 set_gamma(gspca_dev);
2204 set_redblue(gspca_dev);
2205 set_gain(gspca_dev);
2206 set_exposure(gspca_dev);
2207 set_hvflip(gspca_dev);
2208
Brian Johnson0c045eb2010-03-16 13:58:27 -03002209 reg_w1(gspca_dev, 0x1007, 0x20);
2210
Brian Johnson26e744b2009-07-19 05:52:58 -03002211 reg_r(gspca_dev, 0x1061, 1);
2212 reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02);
2213 return 0;
2214}
2215
2216static void sd_stopN(struct gspca_dev *gspca_dev)
2217{
Brian Johnson0c045eb2010-03-16 13:58:27 -03002218 reg_w1(gspca_dev, 0x1007, 0x00);
2219
Brian Johnson26e744b2009-07-19 05:52:58 -03002220 reg_r(gspca_dev, 0x1061, 1);
2221 reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
2222}
2223
Brian Johnsone1430472009-09-02 12:39:41 -03002224static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
Brian Johnson26e744b2009-07-19 05:52:58 -03002225{
2226 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnsone1430472009-09-02 12:39:41 -03002227 s16 new_exp;
Brian Johnson26e744b2009-07-19 05:52:58 -03002228
2229 /*
2230 * some hardcoded values are present
2231 * like those for maximal/minimal exposure
2232 * and exposure steps
2233 */
2234 if (avg_lum < MIN_AVG_LUM) {
2235 if (sd->exposure > 0x1770)
2236 return;
2237
2238 new_exp = sd->exposure + sd->exposure_step;
2239 if (new_exp > 0x1770)
2240 new_exp = 0x1770;
2241 if (new_exp < 0x10)
2242 new_exp = 0x10;
2243 sd->exposure = new_exp;
2244 set_exposure(gspca_dev);
2245
2246 sd->older_step = sd->old_step;
2247 sd->old_step = 1;
2248
2249 if (sd->old_step ^ sd->older_step)
2250 sd->exposure_step /= 2;
2251 else
2252 sd->exposure_step += 2;
2253 }
2254 if (avg_lum > MAX_AVG_LUM) {
2255 if (sd->exposure < 0x10)
2256 return;
2257 new_exp = sd->exposure - sd->exposure_step;
2258 if (new_exp > 0x1700)
2259 new_exp = 0x1770;
2260 if (new_exp < 0x10)
2261 new_exp = 0x10;
2262 sd->exposure = new_exp;
2263 set_exposure(gspca_dev);
2264 sd->older_step = sd->old_step;
2265 sd->old_step = 0;
2266
2267 if (sd->old_step ^ sd->older_step)
2268 sd->exposure_step /= 2;
2269 else
2270 sd->exposure_step += 2;
2271 }
2272}
2273
Brian Johnsone1430472009-09-02 12:39:41 -03002274static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
2275{
2276 struct sd *sd = (struct sd *) gspca_dev;
2277
2278 if (avg_lum < MIN_AVG_LUM) {
2279 if (sd->gain + 1 <= 28) {
2280 sd->gain++;
2281 set_gain(gspca_dev);
2282 }
2283 }
2284 if (avg_lum > MAX_AVG_LUM) {
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03002285 if (sd->gain > 0) {
Brian Johnsone1430472009-09-02 12:39:41 -03002286 sd->gain--;
2287 set_gain(gspca_dev);
2288 }
2289 }
2290}
2291
2292static void sd_dqcallback(struct gspca_dev *gspca_dev)
2293{
2294 struct sd *sd = (struct sd *) gspca_dev;
2295 int avg_lum;
2296
2297 if (!sd->auto_exposure)
2298 return;
2299
2300 avg_lum = atomic_read(&sd->avg_lum);
2301 if (sd->sensor == SENSOR_SOI968)
2302 do_autogain(gspca_dev, avg_lum);
2303 else
2304 do_autoexposure(gspca_dev, avg_lum);
2305}
2306
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002307#ifdef CONFIG_INPUT
2308static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
2309 u8 *data, /* interrupt packet */
2310 int len) /* interrupt packet length */
2311{
2312 struct sd *sd = (struct sd *) gspca_dev;
2313 int ret = -EINVAL;
Brian Johnson33ddc162010-04-18 21:42:40 -03002314 if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002315 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
2316 input_sync(gspca_dev->input_dev);
2317 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
2318 input_sync(gspca_dev->input_dev);
2319 ret = 0;
2320 }
2321 return ret;
2322}
2323#endif
2324
Brian Johnson26e744b2009-07-19 05:52:58 -03002325static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Brian Johnson26e744b2009-07-19 05:52:58 -03002326 u8 *data, /* isoc packet */
2327 int len) /* iso packet length */
2328{
2329 struct sd *sd = (struct sd *) gspca_dev;
2330 int avg_lum;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03002331 static u8 frame_header[] =
Brian Johnson26e744b2009-07-19 05:52:58 -03002332 {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
2333 if (len == 64 && memcmp(data, frame_header, 6) == 0) {
2334 avg_lum = ((data[35] >> 2) & 3) |
2335 (data[20] << 2) |
2336 (data[19] << 10);
2337 avg_lum += ((data[35] >> 4) & 3) |
2338 (data[22] << 2) |
2339 (data[21] << 10);
2340 avg_lum += ((data[35] >> 6) & 3) |
2341 (data[24] << 2) |
2342 (data[23] << 10);
2343 avg_lum += (data[36] & 3) |
2344 (data[26] << 2) |
2345 (data[25] << 10);
2346 avg_lum += ((data[36] >> 2) & 3) |
2347 (data[28] << 2) |
2348 (data[27] << 10);
2349 avg_lum += ((data[36] >> 4) & 3) |
2350 (data[30] << 2) |
2351 (data[29] << 10);
2352 avg_lum += ((data[36] >> 6) & 3) |
2353 (data[32] << 2) |
2354 (data[31] << 10);
2355 avg_lum += ((data[44] >> 4) & 3) |
2356 (data[34] << 2) |
2357 (data[33] << 10);
2358 avg_lum >>= 9;
2359 atomic_set(&sd->avg_lum, avg_lum);
2360 gspca_frame_add(gspca_dev, LAST_PACKET,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002361 data, len);
Brian Johnson26e744b2009-07-19 05:52:58 -03002362 return;
2363 }
2364 if (gspca_dev->last_packet_type == LAST_PACKET) {
2365 if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv
2366 & MODE_JPEG) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002367 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002368 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002369 gspca_frame_add(gspca_dev, INTER_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002370 data, len);
2371 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002372 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002373 data, len);
2374 }
2375 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002376 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Brian Johnson26e744b2009-07-19 05:52:58 -03002377 }
2378}
2379
2380/* sub-driver description */
2381static const struct sd_desc sd_desc = {
2382 .name = MODULE_NAME,
2383 .ctrls = sd_ctrls,
2384 .nctrls = ARRAY_SIZE(sd_ctrls),
2385 .config = sd_config,
2386 .init = sd_init,
2387 .start = sd_start,
2388 .stopN = sd_stopN,
Brian Johnson26e744b2009-07-19 05:52:58 -03002389 .pkt_scan = sd_pkt_scan,
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002390#ifdef CONFIG_INPUT
2391 .int_pkt_scan = sd_int_pkt_scan,
2392#endif
Brian Johnsone1430472009-09-02 12:39:41 -03002393 .dq_callback = sd_dqcallback,
Brian Johnson26e744b2009-07-19 05:52:58 -03002394#ifdef CONFIG_VIDEO_ADV_DEBUG
2395 .set_register = sd_dbg_s_register,
2396 .get_register = sd_dbg_g_register,
2397#endif
2398 .get_chip_ident = sd_chip_ident,
2399};
2400
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002401#define SN9C20X(sensor, i2c_addr, flags) \
Brian Johnson0c045eb2010-03-16 13:58:27 -03002402 .driver_info = ((flags & 0xff) << 16) \
Brian Johnson26e744b2009-07-19 05:52:58 -03002403 | (SENSOR_ ## sensor << 8) \
2404 | (i2c_addr)
2405
2406static const __devinitdata struct usb_device_id device_table[] = {
2407 {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
2408 {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
2409 {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002410 {USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002411 {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, LED_REVERSE)},
2412 {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30,
2413 (FLIP_DETECT | HAS_NO_BUTTON))},
Brian Johnson26e744b2009-07-19 05:52:58 -03002414 {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
2415 {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
2416 {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
2417 {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)},
2418 {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, 0)},
2419 {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)},
2420 {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)},
2421 {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
2422 {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002423 {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002424 {USB_DEVICE(0x0c45, 0x628c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002425 {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)},
2426 {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
2427 {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
2428 {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
2429 {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002430 {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002431 {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
2432 {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
2433 {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
2434 {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002435 {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)},
2436 {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002437 {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
2438 {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)},
2439 {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)},
2440 {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002441 {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002442 {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)},
2443 {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)},
2444 {}
2445};
2446MODULE_DEVICE_TABLE(usb, device_table);
2447
2448/* -- device connect -- */
2449static int sd_probe(struct usb_interface *intf,
2450 const struct usb_device_id *id)
2451{
2452 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
2453 THIS_MODULE);
2454}
2455
Brian Johnson26e744b2009-07-19 05:52:58 -03002456static struct usb_driver sd_driver = {
2457 .name = MODULE_NAME,
2458 .id_table = device_table,
2459 .probe = sd_probe,
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002460 .disconnect = gspca_disconnect,
Brian Johnson26e744b2009-07-19 05:52:58 -03002461#ifdef CONFIG_PM
2462 .suspend = gspca_suspend,
2463 .resume = gspca_resume,
2464 .reset_resume = gspca_resume,
2465#endif
2466};
2467
2468/* -- module insert / remove -- */
2469static int __init sd_mod_init(void)
2470{
2471 int ret;
2472 ret = usb_register(&sd_driver);
2473 if (ret < 0)
2474 return ret;
2475 info("registered");
2476 return 0;
2477}
2478static void __exit sd_mod_exit(void)
2479{
2480 usb_deregister(&sd_driver);
2481 info("deregistered");
2482}
2483
2484module_init(sd_mod_init);
2485module_exit(sd_mod_exit);