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