blob: dad5ddeb7ff38938bab0ca99c1d70c1bec69c216 [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},
999 {0x01, 0x0001}, {0x02, 0x0016}, {0x03, 0x01e1},
1000 {0x04, 0x0281}, {0x05, 0x0004}, {0x07, 0x3002},
1001 {0x21, 0x0000}, {0x25, 0x4024}, {0x26, 0xff03},
1002 {0x27, 0xff10}, {0x2b, 0x7828}, {0x2c, 0xb43c},
1003 {0x2d, 0xf0a0}, {0x2e, 0x0c64}, {0x2f, 0x0064},
1004 {0x67, 0x4010}, {0x06, 0x301e}, {0x08, 0x0480},
1005 {0x01, 0x0004}, {0x02, 0x0016}, {0x03, 0x01e6},
1006 {0x04, 0x0286}, {0x05, 0x0004}, {0x06, 0x0000},
1007 {0x07, 0x3002}, {0x08, 0x0008}, {0x0c, 0x0000},
1008 {0x0d, 0x0000}, {0x0e, 0x0000}, {0x0f, 0x0000},
1009 {0x10, 0x0000}, {0x11, 0x0000}, {0x12, 0x00b0},
1010 {0x13, 0x007c}, {0x14, 0x0000}, {0x15, 0x0000},
1011 {0x16, 0x0000}, {0x17, 0x0000}, {0x18, 0x0000},
1012 {0x19, 0x0000}, {0x1a, 0x0000}, {0x1b, 0x0000},
1013 {0x1c, 0x0000}, {0x1d, 0x0000}, {0x30, 0x0000},
1014 {0x30, 0x0005}, {0x31, 0x0000}, {0x02, 0x0016},
1015 {0x03, 0x01e1}, {0x04, 0x0281}, {0x05, 0x0004},
1016 {0x06, 0x0000}, {0x07, 0x3002}, {0x06, 0x002d},
1017 {0x05, 0x0004}, {0x09, 0x0064}, {0x2b, 0x00a0},
1018 {0x2c, 0x00a0}, {0x2d, 0x00a0}, {0x2e, 0x00a0},
1019 {0x02, 0x0016}, {0x03, 0x01e1}, {0x04, 0x0281},
1020 {0x05, 0x0004}, {0x06, 0x002d}, {0x07, 0x3002},
1021 {0x0e, 0x0008}, {0x06, 0x002d}, {0x05, 0x0004},
1022};
1023
Joe Perches58aa68c2009-09-02 01:12:13 -03001024static struct i2c_reg_u16 mt9v011_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001025 {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
1026 {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1},
1027 {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006},
1028 {0x0d, 0x0002}, {0x0a, 0x0000}, {0x0b, 0x0000},
1029 {0x0c, 0x0000}, {0x0d, 0x0000}, {0x0e, 0x0000},
1030 {0x0f, 0x0000}, {0x10, 0x0000}, {0x11, 0x0000},
1031 {0x12, 0x0000}, {0x13, 0x0000}, {0x14, 0x0000},
1032 {0x15, 0x0000}, {0x16, 0x0000}, {0x17, 0x0000},
1033 {0x18, 0x0000}, {0x19, 0x0000}, {0x1a, 0x0000},
1034 {0x1b, 0x0000}, {0x1c, 0x0000}, {0x1d, 0x0000},
1035 {0x32, 0x0000}, {0x20, 0x1101}, {0x21, 0x0000},
1036 {0x22, 0x0000}, {0x23, 0x0000}, {0x24, 0x0000},
1037 {0x25, 0x0000}, {0x26, 0x0000}, {0x27, 0x0024},
1038 {0x2f, 0xf7b0}, {0x30, 0x0005}, {0x31, 0x0000},
1039 {0x32, 0x0000}, {0x33, 0x0000}, {0x34, 0x0100},
1040 {0x3d, 0x068f}, {0x40, 0x01e0}, {0x41, 0x00d1},
1041 {0x44, 0x0082}, {0x5a, 0x0000}, {0x5b, 0x0000},
1042 {0x5c, 0x0000}, {0x5d, 0x0000}, {0x5e, 0x0000},
1043 {0x5f, 0xa31d}, {0x62, 0x0611}, {0x0a, 0x0000},
1044 {0x06, 0x0029}, {0x05, 0x0009}, {0x20, 0x1101},
1045 {0x20, 0x1101}, {0x09, 0x0064}, {0x07, 0x0003},
1046 {0x2b, 0x0033}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
1047 {0x2e, 0x0033}, {0x07, 0x0002}, {0x06, 0x0000},
1048 {0x06, 0x0029}, {0x05, 0x0009},
1049};
1050
Joe Perches58aa68c2009-09-02 01:12:13 -03001051static struct i2c_reg_u16 mt9m001_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001052 {0x0d, 0x0001}, {0x0d, 0x0000}, {0x01, 0x000e},
1053 {0x02, 0x0014}, {0x03, 0x03c1}, {0x04, 0x0501},
1054 {0x05, 0x0083}, {0x06, 0x0006}, {0x0d, 0x0002},
1055 {0x0a, 0x0000}, {0x0c, 0x0000}, {0x11, 0x0000},
1056 {0x1e, 0x8000}, {0x5f, 0x8904}, {0x60, 0x0000},
1057 {0x61, 0x0000}, {0x62, 0x0498}, {0x63, 0x0000},
1058 {0x64, 0x0000}, {0x20, 0x111d}, {0x06, 0x00f2},
1059 {0x05, 0x0013}, {0x09, 0x10f2}, {0x07, 0x0003},
1060 {0x2b, 0x002a}, {0x2d, 0x002a}, {0x2c, 0x002a},
1061 {0x2e, 0x0029}, {0x07, 0x0002},
1062};
1063
Joe Perches58aa68c2009-09-02 01:12:13 -03001064static struct i2c_reg_u16 mt9m111_init[] = {
Brian Johnson13a84fa2009-09-03 19:07:13 -03001065 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
1066 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
Brian Johnson4d708a52009-09-03 19:10:15 -03001067 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
1068 {0xf0, 0x0000},
Brian Johnson26e744b2009-07-19 05:52:58 -03001069};
1070
Brian Johnsone99ac542010-03-16 13:58:28 -03001071static struct i2c_reg_u16 mt9m112_init[] = {
1072 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
1073 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
1074 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
1075 {0xf0, 0x0000},
1076};
1077
Joe Perches58aa68c2009-09-02 01:12:13 -03001078static struct i2c_reg_u8 hv7131r_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001079 {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
1080 {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
1081 {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
1082 {0x01, 0x08}, {0x01, 0x08}, {0x25, 0x07},
1083 {0x26, 0xc3}, {0x27, 0x50}, {0x30, 0x62},
1084 {0x31, 0x10}, {0x32, 0x06}, {0x33, 0x10},
1085 {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00},
1086 {0x23, 0x09}, {0x01, 0x08},
1087};
1088
Joe Perches58aa68c2009-09-02 01:12:13 -03001089static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
Brian Johnson26e744b2009-07-19 05:52:58 -03001090{
1091 struct usb_device *dev = gspca_dev->dev;
1092 int result;
1093 result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
1094 0x00,
1095 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
1096 reg,
1097 0x00,
1098 gspca_dev->usb_buf,
1099 length,
1100 500);
1101 if (unlikely(result < 0 || result != length)) {
1102 err("Read register failed 0x%02X", reg);
1103 return -EIO;
1104 }
1105 return 0;
1106}
1107
Joe Perches58aa68c2009-09-02 01:12:13 -03001108static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
1109 const u8 *buffer, int length)
Brian Johnson26e744b2009-07-19 05:52:58 -03001110{
1111 struct usb_device *dev = gspca_dev->dev;
1112 int result;
1113 memcpy(gspca_dev->usb_buf, buffer, length);
1114 result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
1115 0x08,
1116 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
1117 reg,
1118 0x00,
1119 gspca_dev->usb_buf,
1120 length,
1121 500);
1122 if (unlikely(result < 0 || result != length)) {
1123 err("Write register failed index 0x%02X", reg);
1124 return -EIO;
1125 }
1126 return 0;
1127}
1128
Joe Perches58aa68c2009-09-02 01:12:13 -03001129static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
Brian Johnson26e744b2009-07-19 05:52:58 -03001130{
1131 u8 data[1] = {value};
1132 return reg_w(gspca_dev, reg, data, 1);
1133}
1134
Joe Perches58aa68c2009-09-02 01:12:13 -03001135static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
Brian Johnson26e744b2009-07-19 05:52:58 -03001136{
1137 int i;
1138 reg_w(gspca_dev, 0x10c0, buffer, 8);
1139 for (i = 0; i < 5; i++) {
1140 reg_r(gspca_dev, 0x10c0, 1);
1141 if (gspca_dev->usb_buf[0] & 0x04) {
1142 if (gspca_dev->usb_buf[0] & 0x08)
Brian Johnson00b581e2009-07-23 05:55:43 -03001143 return -EIO;
Brian Johnson26e744b2009-07-19 05:52:58 -03001144 return 0;
1145 }
1146 msleep(1);
1147 }
Brian Johnson00b581e2009-07-23 05:55:43 -03001148 return -EIO;
Brian Johnson26e744b2009-07-19 05:52:58 -03001149}
1150
Joe Perches58aa68c2009-09-02 01:12:13 -03001151static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001152{
1153 struct sd *sd = (struct sd *) gspca_dev;
1154
1155 u8 row[8];
1156
1157 /*
1158 * from the point of view of the bridge, the length
1159 * includes the address
1160 */
1161 row[0] = 0x81 | (2 << 4);
1162 row[1] = sd->i2c_addr;
1163 row[2] = reg;
1164 row[3] = val;
1165 row[4] = 0x00;
1166 row[5] = 0x00;
1167 row[6] = 0x00;
1168 row[7] = 0x10;
1169
1170 return i2c_w(gspca_dev, row);
1171}
1172
Joe Perches58aa68c2009-09-02 01:12:13 -03001173static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001174{
1175 struct sd *sd = (struct sd *) gspca_dev;
1176 u8 row[8];
1177
1178 /*
1179 * from the point of view of the bridge, the length
1180 * includes the address
1181 */
1182 row[0] = 0x81 | (3 << 4);
1183 row[1] = sd->i2c_addr;
1184 row[2] = reg;
1185 row[3] = (val >> 8) & 0xff;
1186 row[4] = val & 0xff;
1187 row[5] = 0x00;
1188 row[6] = 0x00;
1189 row[7] = 0x10;
1190
1191 return i2c_w(gspca_dev, row);
1192}
1193
Jean-Francois Moine83955552009-12-12 06:58:01 -03001194static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001195{
1196 struct sd *sd = (struct sd *) gspca_dev;
1197 u8 row[8];
1198
Brian Johnson00b581e2009-07-23 05:55:43 -03001199 row[0] = 0x81 | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001200 row[1] = sd->i2c_addr;
1201 row[2] = reg;
1202 row[3] = 0;
1203 row[4] = 0;
1204 row[5] = 0;
1205 row[6] = 0;
1206 row[7] = 0x10;
Brian Johnson00b581e2009-07-23 05:55:43 -03001207 if (i2c_w(gspca_dev, row) < 0)
1208 return -EIO;
1209 row[0] = 0x81 | (1 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001210 row[2] = 0;
Brian Johnson00b581e2009-07-23 05:55:43 -03001211 if (i2c_w(gspca_dev, row) < 0)
1212 return -EIO;
1213 if (reg_r(gspca_dev, 0x10c2, 5) < 0)
1214 return -EIO;
1215 *val = gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001216 return 0;
1217}
1218
Jean-Francois Moine83955552009-12-12 06:58:01 -03001219static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001220{
1221 struct sd *sd = (struct sd *) gspca_dev;
1222 u8 row[8];
1223
Brian Johnson00b581e2009-07-23 05:55:43 -03001224 row[0] = 0x81 | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001225 row[1] = sd->i2c_addr;
1226 row[2] = reg;
1227 row[3] = 0;
1228 row[4] = 0;
1229 row[5] = 0;
1230 row[6] = 0;
1231 row[7] = 0x10;
Brian Johnson00b581e2009-07-23 05:55:43 -03001232 if (i2c_w(gspca_dev, row) < 0)
1233 return -EIO;
1234 row[0] = 0x81 | (2 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001235 row[2] = 0;
Brian Johnson00b581e2009-07-23 05:55:43 -03001236 if (i2c_w(gspca_dev, row) < 0)
1237 return -EIO;
1238 if (reg_r(gspca_dev, 0x10c2, 5) < 0)
1239 return -EIO;
1240 *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001241 return 0;
1242}
1243
1244static int ov9650_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(ov9650_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001250 if (i2c_w1(gspca_dev, ov9650_init[i].reg,
1251 ov9650_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001252 err("OV9650 sensor initialization failed");
1253 return -ENODEV;
1254 }
1255 }
1256 sd->hstart = 1;
1257 sd->vstart = 7;
1258 return 0;
1259}
1260
1261static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
1262{
1263 int i;
1264 struct sd *sd = (struct sd *) gspca_dev;
1265
1266 for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001267 if (i2c_w1(gspca_dev, ov9655_init[i].reg,
1268 ov9655_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001269 err("OV9655 sensor initialization failed");
1270 return -ENODEV;
1271 }
1272 }
1273 /* disable hflip and vflip */
1274 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
Brian Johnsoncc2a8332010-03-16 13:58:28 -03001275 sd->hstart = 1;
1276 sd->vstart = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001277 return 0;
1278}
1279
1280static int soi968_init_sensor(struct gspca_dev *gspca_dev)
1281{
1282 int i;
1283 struct sd *sd = (struct sd *) gspca_dev;
1284
1285 for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001286 if (i2c_w1(gspca_dev, soi968_init[i].reg,
1287 soi968_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001288 err("SOI968 sensor initialization failed");
1289 return -ENODEV;
1290 }
1291 }
1292 /* disable hflip and vflip */
Brian Johnsone1430472009-09-02 12:39:41 -03001293 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << EXPOSURE_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001294 sd->hstart = 60;
1295 sd->vstart = 11;
1296 return 0;
1297}
1298
1299static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
1300{
1301 int i;
1302 struct sd *sd = (struct sd *) gspca_dev;
1303
1304 for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001305 if (i2c_w1(gspca_dev, ov7660_init[i].reg,
1306 ov7660_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001307 err("OV7660 sensor initialization failed");
1308 return -ENODEV;
1309 }
1310 }
1311 /* disable hflip and vflip */
1312 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1313 sd->hstart = 1;
1314 sd->vstart = 1;
1315 return 0;
1316}
1317
1318static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
1319{
1320 int i;
1321 struct sd *sd = (struct sd *) gspca_dev;
1322
1323 for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001324 if (i2c_w1(gspca_dev, ov7670_init[i].reg,
1325 ov7670_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001326 err("OV7670 sensor initialization failed");
1327 return -ENODEV;
1328 }
1329 }
1330 /* disable hflip and vflip */
1331 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1332 sd->hstart = 0;
1333 sd->vstart = 1;
1334 return 0;
1335}
1336
1337static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
1338{
1339 struct sd *sd = (struct sd *) gspca_dev;
1340 int i;
1341 u16 value;
1342 int ret;
1343
1344 sd->i2c_addr = 0x5d;
1345 ret = i2c_r2(gspca_dev, 0xff, &value);
1346 if ((ret == 0) && (value == 0x8243)) {
1347 for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001348 if (i2c_w2(gspca_dev, mt9v011_init[i].reg,
1349 mt9v011_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001350 err("MT9V011 sensor initialization failed");
1351 return -ENODEV;
1352 }
1353 }
1354 sd->hstart = 2;
1355 sd->vstart = 2;
1356 sd->sensor = SENSOR_MT9V011;
1357 info("MT9V011 sensor detected");
1358 return 0;
1359 }
1360
1361 sd->i2c_addr = 0x5c;
1362 i2c_w2(gspca_dev, 0x01, 0x0004);
1363 ret = i2c_r2(gspca_dev, 0xff, &value);
1364 if ((ret == 0) && (value == 0x823a)) {
1365 for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001366 if (i2c_w2(gspca_dev, mt9v111_init[i].reg,
1367 mt9v111_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001368 err("MT9V111 sensor initialization failed");
1369 return -ENODEV;
1370 }
1371 }
1372 sd->hstart = 2;
1373 sd->vstart = 2;
1374 sd->sensor = SENSOR_MT9V111;
1375 info("MT9V111 sensor detected");
1376 return 0;
1377 }
1378
1379 sd->i2c_addr = 0x5d;
1380 ret = i2c_w2(gspca_dev, 0xf0, 0x0000);
1381 if (ret < 0) {
1382 sd->i2c_addr = 0x48;
1383 i2c_w2(gspca_dev, 0xf0, 0x0000);
1384 }
1385 ret = i2c_r2(gspca_dev, 0x00, &value);
1386 if ((ret == 0) && (value == 0x1229)) {
1387 for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001388 if (i2c_w2(gspca_dev, mt9v112_init[i].reg,
1389 mt9v112_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001390 err("MT9V112 sensor initialization failed");
1391 return -ENODEV;
1392 }
1393 }
1394 sd->hstart = 6;
1395 sd->vstart = 2;
1396 sd->sensor = SENSOR_MT9V112;
1397 info("MT9V112 sensor detected");
1398 return 0;
1399 }
1400
1401 return -ENODEV;
1402}
1403
Brian Johnsone99ac542010-03-16 13:58:28 -03001404static int mt9m112_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(mt9m112_init); i++) {
1409 if (i2c_w2(gspca_dev, mt9m112_init[i].reg,
1410 mt9m112_init[i].val) < 0) {
1411 err("MT9M112 sensor initialization failed");
1412 return -ENODEV;
1413 }
1414 }
1415 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
1416 sd->hstart = 0;
1417 sd->vstart = 2;
1418 return 0;
1419}
1420
Brian Johnson26e744b2009-07-19 05:52:58 -03001421static int mt9m111_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(mt9m111_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001426 if (i2c_w2(gspca_dev, mt9m111_init[i].reg,
1427 mt9m111_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001428 err("MT9M111 sensor initialization failed");
1429 return -ENODEV;
1430 }
1431 }
Brian Johnson13a84fa2009-09-03 19:07:13 -03001432 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001433 sd->hstart = 0;
1434 sd->vstart = 2;
1435 return 0;
1436}
1437
1438static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
1439{
1440 struct sd *sd = (struct sd *) gspca_dev;
1441 int i;
1442 for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001443 if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
1444 mt9m001_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001445 err("MT9M001 sensor initialization failed");
1446 return -ENODEV;
1447 }
1448 }
1449 /* disable hflip and vflip */
1450 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1451 sd->hstart = 2;
1452 sd->vstart = 2;
1453 return 0;
1454}
1455
1456static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
1457{
1458 int i;
1459 struct sd *sd = (struct sd *) gspca_dev;
1460
1461 for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001462 if (i2c_w1(gspca_dev, hv7131r_init[i].reg,
1463 hv7131r_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001464 err("HV7131R Sensor initialization failed");
1465 return -ENODEV;
1466 }
1467 }
1468 sd->hstart = 0;
1469 sd->vstart = 1;
1470 return 0;
1471}
1472
Brian Johnson26e744b2009-07-19 05:52:58 -03001473static int set_cmatrix(struct gspca_dev *gspca_dev)
1474{
1475 struct sd *sd = (struct sd *) gspca_dev;
1476 s32 hue_coord, hue_index = 180 + sd->hue;
1477 u8 cmatrix[21];
Brian Johnson26e744b2009-07-19 05:52:58 -03001478
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001479 memset(cmatrix, 0, sizeof cmatrix);
Brian Johnson26e744b2009-07-19 05:52:58 -03001480 cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26;
1481 cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
1482 cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
1483 cmatrix[18] = sd->brightness - 0x80;
1484
1485 hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001486 cmatrix[6] = hue_coord;
1487 cmatrix[7] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001488
1489 hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001490 cmatrix[8] = hue_coord;
1491 cmatrix[9] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001492
1493 hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001494 cmatrix[10] = hue_coord;
1495 cmatrix[11] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001496
1497 hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001498 cmatrix[12] = hue_coord;
1499 cmatrix[13] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001500
1501 hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001502 cmatrix[14] = hue_coord;
1503 cmatrix[15] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001504
1505 hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001506 cmatrix[16] = hue_coord;
1507 cmatrix[17] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001508
1509 return reg_w(gspca_dev, 0x10e1, cmatrix, 21);
1510}
1511
1512static int set_gamma(struct gspca_dev *gspca_dev)
1513{
1514 struct sd *sd = (struct sd *) gspca_dev;
1515 u8 gamma[17];
1516 u8 gval = sd->gamma * 0xb8 / 0x100;
1517
1518
1519 gamma[0] = 0x0a;
1520 gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
1521 gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8);
1522 gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8);
1523 gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8);
1524 gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8);
1525 gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8);
1526 gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8);
1527 gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8);
1528 gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8);
1529 gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8);
1530 gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8);
1531 gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8);
1532 gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8);
1533 gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8);
1534 gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
1535 gamma[16] = 0xf5;
1536
1537 return reg_w(gspca_dev, 0x1190, gamma, 17);
1538}
1539
1540static int set_redblue(struct gspca_dev *gspca_dev)
1541{
1542 struct sd *sd = (struct sd *) gspca_dev;
1543 reg_w1(gspca_dev, 0x118c, sd->red);
1544 reg_w1(gspca_dev, 0x118f, sd->blue);
1545 return 0;
1546}
1547
1548static int set_hvflip(struct gspca_dev *gspca_dev)
1549{
Brian Johnson7ddaac72010-03-16 13:58:27 -03001550 u8 value, tslb, hflip, vflip;
Brian Johnson26e744b2009-07-19 05:52:58 -03001551 u16 value2;
1552 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001553
1554 if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
1555 hflip = !sd->hflip;
1556 vflip = !sd->vflip;
1557 } else {
1558 hflip = sd->hflip;
1559 vflip = sd->vflip;
1560 }
1561
Brian Johnson26e744b2009-07-19 05:52:58 -03001562 switch (sd->sensor) {
1563 case SENSOR_OV9650:
1564 i2c_r1(gspca_dev, 0x1e, &value);
1565 value &= ~0x30;
1566 tslb = 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001567 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001568 value |= 0x20;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001569 if (vflip) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001570 value |= 0x10;
1571 tslb = 0x49;
1572 }
1573 i2c_w1(gspca_dev, 0x1e, value);
1574 i2c_w1(gspca_dev, 0x3a, tslb);
1575 break;
1576 case SENSOR_MT9V111:
1577 case SENSOR_MT9V011:
1578 i2c_r2(gspca_dev, 0x20, &value2);
1579 value2 &= ~0xc0a0;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001580 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001581 value2 |= 0x8080;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001582 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001583 value2 |= 0x4020;
1584 i2c_w2(gspca_dev, 0x20, value2);
1585 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001586 case SENSOR_MT9M112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001587 case SENSOR_MT9M111:
1588 case SENSOR_MT9V112:
1589 i2c_r2(gspca_dev, 0x20, &value2);
1590 value2 &= ~0x0003;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001591 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001592 value2 |= 0x0002;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001593 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001594 value2 |= 0x0001;
1595 i2c_w2(gspca_dev, 0x20, value2);
1596 break;
1597 case SENSOR_HV7131R:
1598 i2c_r1(gspca_dev, 0x01, &value);
1599 value &= ~0x03;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001600 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001601 value |= 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001602 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001603 value |= 0x02;
1604 i2c_w1(gspca_dev, 0x01, value);
1605 break;
1606 }
1607 return 0;
1608}
1609
1610static int set_exposure(struct gspca_dev *gspca_dev)
1611{
1612 struct sd *sd = (struct sd *) gspca_dev;
1613 u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
1614 switch (sd->sensor) {
1615 case SENSOR_OV7660:
1616 case SENSOR_OV7670:
Brian Johnson26e744b2009-07-19 05:52:58 -03001617 case SENSOR_OV9655:
1618 case SENSOR_OV9650:
1619 exp[0] |= (3 << 4);
1620 exp[2] = 0x2d;
1621 exp[3] = sd->exposure & 0xff;
1622 exp[4] = sd->exposure >> 8;
1623 break;
1624 case SENSOR_MT9M001:
Brian Johnson26e744b2009-07-19 05:52:58 -03001625 case SENSOR_MT9V112:
1626 case SENSOR_MT9V111:
1627 case SENSOR_MT9V011:
1628 exp[0] |= (3 << 4);
1629 exp[2] = 0x09;
1630 exp[3] = sd->exposure >> 8;
1631 exp[4] = sd->exposure & 0xff;
1632 break;
1633 case SENSOR_HV7131R:
1634 exp[0] |= (4 << 4);
1635 exp[2] = 0x25;
German Galkine10f7312010-03-07 06:19:02 -03001636 exp[3] = (sd->exposure >> 5) & 0xff;
1637 exp[4] = (sd->exposure << 3) & 0xff;
1638 exp[5] = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001639 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001640 default:
1641 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001642 }
1643 i2c_w(gspca_dev, exp);
1644 return 0;
1645}
1646
1647static int set_gain(struct gspca_dev *gspca_dev)
1648{
1649 struct sd *sd = (struct sd *) gspca_dev;
1650 u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
1651 switch (sd->sensor) {
1652 case SENSOR_OV7660:
1653 case SENSOR_OV7670:
1654 case SENSOR_SOI968:
1655 case SENSOR_OV9655:
1656 case SENSOR_OV9650:
1657 gain[0] |= (2 << 4);
1658 gain[3] = ov_gain[sd->gain];
1659 break;
1660 case SENSOR_MT9V011:
1661 case SENSOR_MT9V111:
1662 gain[0] |= (3 << 4);
1663 gain[2] = 0x35;
1664 gain[3] = micron1_gain[sd->gain] >> 8;
1665 gain[4] = micron1_gain[sd->gain] & 0xff;
1666 break;
1667 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001668 gain[0] |= (3 << 4);
1669 gain[2] = 0x2f;
1670 gain[3] = micron1_gain[sd->gain] >> 8;
1671 gain[4] = micron1_gain[sd->gain] & 0xff;
1672 break;
1673 case SENSOR_MT9M001:
1674 gain[0] |= (3 << 4);
1675 gain[2] = 0x2f;
1676 gain[3] = micron2_gain[sd->gain] >> 8;
1677 gain[4] = micron2_gain[sd->gain] & 0xff;
1678 break;
1679 case SENSOR_HV7131R:
1680 gain[0] |= (2 << 4);
1681 gain[2] = 0x30;
1682 gain[3] = hv7131r_gain[sd->gain];
1683 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001684 default:
1685 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001686 }
1687 i2c_w(gspca_dev, gain);
1688 return 0;
1689}
1690
1691static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val)
1692{
1693 struct sd *sd = (struct sd *) gspca_dev;
1694
1695 sd->brightness = val;
1696 if (gspca_dev->streaming)
1697 return set_cmatrix(gspca_dev);
1698 return 0;
1699}
1700
1701static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val)
1702{
1703 struct sd *sd = (struct sd *) gspca_dev;
1704 *val = sd->brightness;
1705 return 0;
1706}
1707
1708
1709static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val)
1710{
1711 struct sd *sd = (struct sd *) gspca_dev;
1712
1713 sd->contrast = val;
1714 if (gspca_dev->streaming)
1715 return set_cmatrix(gspca_dev);
1716 return 0;
1717}
1718
1719static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val)
1720{
1721 struct sd *sd = (struct sd *) gspca_dev;
1722 *val = sd->contrast;
1723 return 0;
1724}
1725
1726static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val)
1727{
1728 struct sd *sd = (struct sd *) gspca_dev;
1729
1730 sd->saturation = val;
1731 if (gspca_dev->streaming)
1732 return set_cmatrix(gspca_dev);
1733 return 0;
1734}
1735
1736static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val)
1737{
1738 struct sd *sd = (struct sd *) gspca_dev;
1739 *val = sd->saturation;
1740 return 0;
1741}
1742
1743static int sd_sethue(struct gspca_dev *gspca_dev, s32 val)
1744{
1745 struct sd *sd = (struct sd *) gspca_dev;
1746
1747 sd->hue = val;
1748 if (gspca_dev->streaming)
1749 return set_cmatrix(gspca_dev);
1750 return 0;
1751}
1752
1753static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val)
1754{
1755 struct sd *sd = (struct sd *) gspca_dev;
1756 *val = sd->hue;
1757 return 0;
1758}
1759
1760static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val)
1761{
1762 struct sd *sd = (struct sd *) gspca_dev;
1763
1764 sd->gamma = val;
1765 if (gspca_dev->streaming)
1766 return set_gamma(gspca_dev);
1767 return 0;
1768}
1769
1770static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val)
1771{
1772 struct sd *sd = (struct sd *) gspca_dev;
1773 *val = sd->gamma;
1774 return 0;
1775}
1776
1777static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val)
1778{
1779 struct sd *sd = (struct sd *) gspca_dev;
1780
1781 sd->red = val;
1782 if (gspca_dev->streaming)
1783 return set_redblue(gspca_dev);
1784 return 0;
1785}
1786
1787static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val)
1788{
1789 struct sd *sd = (struct sd *) gspca_dev;
1790 *val = sd->red;
1791 return 0;
1792}
1793
1794static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val)
1795{
1796 struct sd *sd = (struct sd *) gspca_dev;
1797
1798 sd->blue = val;
1799 if (gspca_dev->streaming)
1800 return set_redblue(gspca_dev);
1801 return 0;
1802}
1803
1804static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val)
1805{
1806 struct sd *sd = (struct sd *) gspca_dev;
1807 *val = sd->blue;
1808 return 0;
1809}
1810
1811static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val)
1812{
1813 struct sd *sd = (struct sd *) gspca_dev;
1814
1815 sd->hflip = val;
1816 if (gspca_dev->streaming)
1817 return set_hvflip(gspca_dev);
1818 return 0;
1819}
1820
1821static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val)
1822{
1823 struct sd *sd = (struct sd *) gspca_dev;
1824 *val = sd->hflip;
1825 return 0;
1826}
1827
1828static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val)
1829{
1830 struct sd *sd = (struct sd *) gspca_dev;
1831
1832 sd->vflip = val;
1833 if (gspca_dev->streaming)
1834 return set_hvflip(gspca_dev);
1835 return 0;
1836}
1837
1838static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val)
1839{
1840 struct sd *sd = (struct sd *) gspca_dev;
1841 *val = sd->vflip;
1842 return 0;
1843}
1844
1845static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val)
1846{
1847 struct sd *sd = (struct sd *) gspca_dev;
1848
1849 sd->exposure = val;
1850 if (gspca_dev->streaming)
1851 return set_exposure(gspca_dev);
1852 return 0;
1853}
1854
1855static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val)
1856{
1857 struct sd *sd = (struct sd *) gspca_dev;
1858 *val = sd->exposure;
1859 return 0;
1860}
1861
1862static int sd_setgain(struct gspca_dev *gspca_dev, s32 val)
1863{
1864 struct sd *sd = (struct sd *) gspca_dev;
1865
1866 sd->gain = val;
1867 if (gspca_dev->streaming)
1868 return set_gain(gspca_dev);
1869 return 0;
1870}
1871
1872static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val)
1873{
1874 struct sd *sd = (struct sd *) gspca_dev;
1875 *val = sd->gain;
1876 return 0;
1877}
1878
1879static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val)
1880{
1881 struct sd *sd = (struct sd *) gspca_dev;
1882 sd->auto_exposure = val;
1883 return 0;
1884}
1885
1886static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val)
1887{
1888 struct sd *sd = (struct sd *) gspca_dev;
1889 *val = sd->auto_exposure;
1890 return 0;
1891}
1892
1893#ifdef CONFIG_VIDEO_ADV_DEBUG
1894static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
1895 struct v4l2_dbg_register *reg)
1896{
1897 struct sd *sd = (struct sd *) gspca_dev;
1898 switch (reg->match.type) {
1899 case V4L2_CHIP_MATCH_HOST:
1900 if (reg->match.addr != 0)
1901 return -EINVAL;
1902 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1903 return -EINVAL;
1904 if (reg_r(gspca_dev, reg->reg, 1) < 0)
1905 return -EINVAL;
1906 reg->val = gspca_dev->usb_buf[0];
1907 return 0;
1908 case V4L2_CHIP_MATCH_I2C_ADDR:
1909 if (reg->match.addr != sd->i2c_addr)
1910 return -EINVAL;
1911 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001912 sd->sensor <= SENSOR_MT9M112) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001913 if (i2c_r2(gspca_dev, reg->reg, (u16 *)&reg->val) < 0)
1914 return -EINVAL;
1915 } else {
1916 if (i2c_r1(gspca_dev, reg->reg, (u8 *)&reg->val) < 0)
1917 return -EINVAL;
1918 }
1919 return 0;
1920 }
1921 return -EINVAL;
1922}
1923
1924static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
1925 struct v4l2_dbg_register *reg)
1926{
1927 struct sd *sd = (struct sd *) gspca_dev;
1928 switch (reg->match.type) {
1929 case V4L2_CHIP_MATCH_HOST:
1930 if (reg->match.addr != 0)
1931 return -EINVAL;
1932 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1933 return -EINVAL;
1934 if (reg_w1(gspca_dev, reg->reg, reg->val) < 0)
1935 return -EINVAL;
1936 return 0;
1937 case V4L2_CHIP_MATCH_I2C_ADDR:
1938 if (reg->match.addr != sd->i2c_addr)
1939 return -EINVAL;
1940 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001941 sd->sensor <= SENSOR_MT9M112) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001942 if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0)
1943 return -EINVAL;
1944 } else {
1945 if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0)
1946 return -EINVAL;
1947 }
1948 return 0;
1949 }
1950 return -EINVAL;
1951}
1952#endif
1953
1954static int sd_chip_ident(struct gspca_dev *gspca_dev,
1955 struct v4l2_dbg_chip_ident *chip)
1956{
1957 struct sd *sd = (struct sd *) gspca_dev;
1958
1959 switch (chip->match.type) {
1960 case V4L2_CHIP_MATCH_HOST:
1961 if (chip->match.addr != 0)
1962 return -EINVAL;
1963 chip->revision = 0;
1964 chip->ident = V4L2_IDENT_SN9C20X;
1965 return 0;
1966 case V4L2_CHIP_MATCH_I2C_ADDR:
1967 if (chip->match.addr != sd->i2c_addr)
1968 return -EINVAL;
1969 chip->revision = 0;
1970 chip->ident = i2c_ident[sd->sensor];
1971 return 0;
1972 }
1973 return -EINVAL;
1974}
1975
1976static int sd_config(struct gspca_dev *gspca_dev,
1977 const struct usb_device_id *id)
1978{
1979 struct sd *sd = (struct sd *) gspca_dev;
1980 struct cam *cam;
1981
1982 cam = &gspca_dev->cam;
1983
1984 sd->sensor = (id->driver_info >> 8) & 0xff;
1985 sd->i2c_addr = id->driver_info & 0xff;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03001986 sd->flags = (id->driver_info >> 16) & 0xff;
Brian Johnson26e744b2009-07-19 05:52:58 -03001987
1988 switch (sd->sensor) {
Brian Johnsone99ac542010-03-16 13:58:28 -03001989 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03001990 case SENSOR_MT9M111:
Brian Johnson26e744b2009-07-19 05:52:58 -03001991 case SENSOR_OV9650:
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001992 case SENSOR_SOI968:
Brian Johnson26e744b2009-07-19 05:52:58 -03001993 cam->cam_mode = sxga_mode;
1994 cam->nmodes = ARRAY_SIZE(sxga_mode);
1995 break;
1996 default:
1997 cam->cam_mode = vga_mode;
1998 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001999 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002000 }
2001
2002 sd->old_step = 0;
2003 sd->older_step = 0;
2004 sd->exposure_step = 16;
2005
2006 sd->brightness = BRIGHTNESS_DEFAULT;
2007 sd->contrast = CONTRAST_DEFAULT;
2008 sd->saturation = SATURATION_DEFAULT;
2009 sd->hue = HUE_DEFAULT;
2010 sd->gamma = GAMMA_DEFAULT;
2011 sd->red = RED_DEFAULT;
2012 sd->blue = BLUE_DEFAULT;
2013
2014 sd->hflip = HFLIP_DEFAULT;
2015 sd->vflip = VFLIP_DEFAULT;
2016 sd->exposure = EXPOSURE_DEFAULT;
2017 sd->gain = GAIN_DEFAULT;
2018 sd->auto_exposure = AUTO_EXPOSURE_DEFAULT;
2019
2020 sd->quality = 95;
2021
Brian Johnson26e744b2009-07-19 05:52:58 -03002022 return 0;
2023}
2024
2025static int sd_init(struct gspca_dev *gspca_dev)
2026{
2027 struct sd *sd = (struct sd *) gspca_dev;
2028 int i;
2029 u8 value;
2030 u8 i2c_init[9] =
2031 {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03};
2032
2033 for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
2034 value = bridge_init[i][1];
2035 if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) {
2036 err("Device initialization failed");
2037 return -ENODEV;
2038 }
2039 }
2040
Brian Johnson0c045eb2010-03-16 13:58:27 -03002041 if (sd->flags & LED_REVERSE)
2042 reg_w1(gspca_dev, 0x1006, 0x00);
2043 else
2044 reg_w1(gspca_dev, 0x1006, 0x20);
2045
Brian Johnson26e744b2009-07-19 05:52:58 -03002046 if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
2047 err("Device initialization failed");
2048 return -ENODEV;
2049 }
2050
2051 switch (sd->sensor) {
2052 case SENSOR_OV9650:
2053 if (ov9650_init_sensor(gspca_dev) < 0)
2054 return -ENODEV;
2055 info("OV9650 sensor detected");
2056 break;
2057 case SENSOR_OV9655:
2058 if (ov9655_init_sensor(gspca_dev) < 0)
2059 return -ENODEV;
2060 info("OV9655 sensor detected");
2061 break;
2062 case SENSOR_SOI968:
2063 if (soi968_init_sensor(gspca_dev) < 0)
2064 return -ENODEV;
2065 info("SOI968 sensor detected");
2066 break;
2067 case SENSOR_OV7660:
2068 if (ov7660_init_sensor(gspca_dev) < 0)
2069 return -ENODEV;
2070 info("OV7660 sensor detected");
2071 break;
2072 case SENSOR_OV7670:
2073 if (ov7670_init_sensor(gspca_dev) < 0)
2074 return -ENODEV;
2075 info("OV7670 sensor detected");
2076 break;
2077 case SENSOR_MT9VPRB:
2078 if (mt9v_init_sensor(gspca_dev) < 0)
2079 return -ENODEV;
2080 break;
2081 case SENSOR_MT9M111:
2082 if (mt9m111_init_sensor(gspca_dev) < 0)
2083 return -ENODEV;
2084 info("MT9M111 sensor detected");
2085 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03002086 case SENSOR_MT9M112:
2087 if (mt9m112_init_sensor(gspca_dev) < 0)
2088 return -ENODEV;
2089 info("MT9M112 sensor detected");
2090 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002091 case SENSOR_MT9M001:
2092 if (mt9m001_init_sensor(gspca_dev) < 0)
2093 return -ENODEV;
2094 info("MT9M001 sensor detected");
2095 break;
2096 case SENSOR_HV7131R:
2097 if (hv7131r_init_sensor(gspca_dev) < 0)
2098 return -ENODEV;
2099 info("HV7131R sensor detected");
2100 break;
2101 default:
2102 info("Unsupported Sensor");
2103 return -ENODEV;
2104 }
2105
2106 return 0;
2107}
2108
2109static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
2110{
2111 struct sd *sd = (struct sd *) gspca_dev;
2112 u8 value;
2113 switch (sd->sensor) {
Brian Johnsone8b7acc2009-09-02 13:14:41 -03002114 case SENSOR_SOI968:
2115 if (mode & MODE_SXGA) {
2116 i2c_w1(gspca_dev, 0x17, 0x1d);
2117 i2c_w1(gspca_dev, 0x18, 0xbd);
2118 i2c_w1(gspca_dev, 0x19, 0x01);
2119 i2c_w1(gspca_dev, 0x1a, 0x81);
2120 i2c_w1(gspca_dev, 0x12, 0x00);
2121 sd->hstart = 140;
2122 sd->vstart = 19;
2123 } else {
2124 i2c_w1(gspca_dev, 0x17, 0x13);
2125 i2c_w1(gspca_dev, 0x18, 0x63);
2126 i2c_w1(gspca_dev, 0x19, 0x01);
2127 i2c_w1(gspca_dev, 0x1a, 0x79);
2128 i2c_w1(gspca_dev, 0x12, 0x40);
2129 sd->hstart = 60;
2130 sd->vstart = 11;
2131 }
2132 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002133 case SENSOR_OV9650:
2134 if (mode & MODE_SXGA) {
2135 i2c_w1(gspca_dev, 0x17, 0x1b);
2136 i2c_w1(gspca_dev, 0x18, 0xbc);
2137 i2c_w1(gspca_dev, 0x19, 0x01);
2138 i2c_w1(gspca_dev, 0x1a, 0x82);
2139 i2c_r1(gspca_dev, 0x12, &value);
2140 i2c_w1(gspca_dev, 0x12, value & 0x07);
2141 } else {
2142 i2c_w1(gspca_dev, 0x17, 0x24);
2143 i2c_w1(gspca_dev, 0x18, 0xc5);
2144 i2c_w1(gspca_dev, 0x19, 0x00);
2145 i2c_w1(gspca_dev, 0x1a, 0x3c);
2146 i2c_r1(gspca_dev, 0x12, &value);
2147 i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
2148 }
2149 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03002150 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03002151 case SENSOR_MT9M111:
2152 if (mode & MODE_SXGA) {
2153 i2c_w2(gspca_dev, 0xf0, 0x0002);
2154 i2c_w2(gspca_dev, 0xc8, 0x970b);
2155 i2c_w2(gspca_dev, 0xf0, 0x0000);
2156 } else {
2157 i2c_w2(gspca_dev, 0xf0, 0x0002);
2158 i2c_w2(gspca_dev, 0xc8, 0x8000);
2159 i2c_w2(gspca_dev, 0xf0, 0x0000);
2160 }
2161 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002162 }
2163}
2164
2165#define HW_WIN(mode, hstart, vstart) \
Jean-Francois Moine83955552009-12-12 06:58:01 -03002166((const u8 []){hstart, 0, vstart, 0, \
Brian Johnson26e744b2009-07-19 05:52:58 -03002167(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
2168(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)})
2169
2170#define CLR_WIN(width, height) \
2171((const u8 [])\
2172{0, width >> 2, 0, height >> 1,\
2173((width >> 10) & 0x01) | ((height >> 8) & 0x6)})
2174
2175static int sd_start(struct gspca_dev *gspca_dev)
2176{
2177 struct sd *sd = (struct sd *) gspca_dev;
2178 int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
2179 int width = gspca_dev->width;
2180 int height = gspca_dev->height;
2181 u8 fmt, scale = 0;
2182
2183 sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
2184 if (sd->jpeg_hdr == NULL)
2185 return -ENOMEM;
2186
2187 jpeg_define(sd->jpeg_hdr, height, width,
2188 0x21);
2189 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
2190
2191 if (mode & MODE_RAW)
2192 fmt = 0x2d;
2193 else if (mode & MODE_JPEG)
2194 fmt = 0x2c;
2195 else
2196 fmt = 0x2f;
2197
2198 switch (mode & 0x0f) {
2199 case 3:
2200 scale = 0xc0;
2201 info("Set 1280x1024");
2202 break;
2203 case 2:
2204 scale = 0x80;
2205 info("Set 640x480");
2206 break;
2207 case 1:
2208 scale = 0x90;
2209 info("Set 320x240");
2210 break;
2211 case 0:
2212 scale = 0xa0;
2213 info("Set 160x120");
2214 break;
2215 }
2216
2217 configure_sensor_output(gspca_dev, mode);
2218 reg_w(gspca_dev, 0x1100, sd->jpeg_hdr + JPEG_QT0_OFFSET, 64);
2219 reg_w(gspca_dev, 0x1140, sd->jpeg_hdr + JPEG_QT1_OFFSET, 64);
2220 reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
2221 reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
2222 reg_w1(gspca_dev, 0x1189, scale);
2223 reg_w1(gspca_dev, 0x10e0, fmt);
2224
2225 set_cmatrix(gspca_dev);
2226 set_gamma(gspca_dev);
2227 set_redblue(gspca_dev);
2228 set_gain(gspca_dev);
2229 set_exposure(gspca_dev);
2230 set_hvflip(gspca_dev);
2231
Brian Johnson0c045eb2010-03-16 13:58:27 -03002232 reg_w1(gspca_dev, 0x1007, 0x20);
2233
Brian Johnson26e744b2009-07-19 05:52:58 -03002234 reg_r(gspca_dev, 0x1061, 1);
2235 reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02);
2236 return 0;
2237}
2238
2239static void sd_stopN(struct gspca_dev *gspca_dev)
2240{
Brian Johnson0c045eb2010-03-16 13:58:27 -03002241 reg_w1(gspca_dev, 0x1007, 0x00);
2242
Brian Johnson26e744b2009-07-19 05:52:58 -03002243 reg_r(gspca_dev, 0x1061, 1);
2244 reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
2245}
2246
2247static void sd_stop0(struct gspca_dev *gspca_dev)
2248{
2249 struct sd *sd = (struct sd *) gspca_dev;
2250 kfree(sd->jpeg_hdr);
2251}
2252
Brian Johnsone1430472009-09-02 12:39:41 -03002253static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
Brian Johnson26e744b2009-07-19 05:52:58 -03002254{
2255 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnsone1430472009-09-02 12:39:41 -03002256 s16 new_exp;
Brian Johnson26e744b2009-07-19 05:52:58 -03002257
2258 /*
2259 * some hardcoded values are present
2260 * like those for maximal/minimal exposure
2261 * and exposure steps
2262 */
2263 if (avg_lum < MIN_AVG_LUM) {
2264 if (sd->exposure > 0x1770)
2265 return;
2266
2267 new_exp = sd->exposure + sd->exposure_step;
2268 if (new_exp > 0x1770)
2269 new_exp = 0x1770;
2270 if (new_exp < 0x10)
2271 new_exp = 0x10;
2272 sd->exposure = new_exp;
2273 set_exposure(gspca_dev);
2274
2275 sd->older_step = sd->old_step;
2276 sd->old_step = 1;
2277
2278 if (sd->old_step ^ sd->older_step)
2279 sd->exposure_step /= 2;
2280 else
2281 sd->exposure_step += 2;
2282 }
2283 if (avg_lum > MAX_AVG_LUM) {
2284 if (sd->exposure < 0x10)
2285 return;
2286 new_exp = sd->exposure - sd->exposure_step;
2287 if (new_exp > 0x1700)
2288 new_exp = 0x1770;
2289 if (new_exp < 0x10)
2290 new_exp = 0x10;
2291 sd->exposure = new_exp;
2292 set_exposure(gspca_dev);
2293 sd->older_step = sd->old_step;
2294 sd->old_step = 0;
2295
2296 if (sd->old_step ^ sd->older_step)
2297 sd->exposure_step /= 2;
2298 else
2299 sd->exposure_step += 2;
2300 }
2301}
2302
Brian Johnsone1430472009-09-02 12:39:41 -03002303static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
2304{
2305 struct sd *sd = (struct sd *) gspca_dev;
2306
2307 if (avg_lum < MIN_AVG_LUM) {
2308 if (sd->gain + 1 <= 28) {
2309 sd->gain++;
2310 set_gain(gspca_dev);
2311 }
2312 }
2313 if (avg_lum > MAX_AVG_LUM) {
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03002314 if (sd->gain > 0) {
Brian Johnsone1430472009-09-02 12:39:41 -03002315 sd->gain--;
2316 set_gain(gspca_dev);
2317 }
2318 }
2319}
2320
2321static void sd_dqcallback(struct gspca_dev *gspca_dev)
2322{
2323 struct sd *sd = (struct sd *) gspca_dev;
2324 int avg_lum;
2325
2326 if (!sd->auto_exposure)
2327 return;
2328
2329 avg_lum = atomic_read(&sd->avg_lum);
2330 if (sd->sensor == SENSOR_SOI968)
2331 do_autogain(gspca_dev, avg_lum);
2332 else
2333 do_autoexposure(gspca_dev, avg_lum);
2334}
2335
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002336#ifdef CONFIG_INPUT
2337static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
2338 u8 *data, /* interrupt packet */
2339 int len) /* interrupt packet length */
2340{
2341 struct sd *sd = (struct sd *) gspca_dev;
2342 int ret = -EINVAL;
Brian Johnson33ddc162010-04-18 21:42:40 -03002343 if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002344 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
2345 input_sync(gspca_dev->input_dev);
2346 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
2347 input_sync(gspca_dev->input_dev);
2348 ret = 0;
2349 }
2350 return ret;
2351}
2352#endif
2353
Brian Johnson26e744b2009-07-19 05:52:58 -03002354static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Brian Johnson26e744b2009-07-19 05:52:58 -03002355 u8 *data, /* isoc packet */
2356 int len) /* iso packet length */
2357{
2358 struct sd *sd = (struct sd *) gspca_dev;
2359 int avg_lum;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03002360 static u8 frame_header[] =
Brian Johnson26e744b2009-07-19 05:52:58 -03002361 {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
2362 if (len == 64 && memcmp(data, frame_header, 6) == 0) {
2363 avg_lum = ((data[35] >> 2) & 3) |
2364 (data[20] << 2) |
2365 (data[19] << 10);
2366 avg_lum += ((data[35] >> 4) & 3) |
2367 (data[22] << 2) |
2368 (data[21] << 10);
2369 avg_lum += ((data[35] >> 6) & 3) |
2370 (data[24] << 2) |
2371 (data[23] << 10);
2372 avg_lum += (data[36] & 3) |
2373 (data[26] << 2) |
2374 (data[25] << 10);
2375 avg_lum += ((data[36] >> 2) & 3) |
2376 (data[28] << 2) |
2377 (data[27] << 10);
2378 avg_lum += ((data[36] >> 4) & 3) |
2379 (data[30] << 2) |
2380 (data[29] << 10);
2381 avg_lum += ((data[36] >> 6) & 3) |
2382 (data[32] << 2) |
2383 (data[31] << 10);
2384 avg_lum += ((data[44] >> 4) & 3) |
2385 (data[34] << 2) |
2386 (data[33] << 10);
2387 avg_lum >>= 9;
2388 atomic_set(&sd->avg_lum, avg_lum);
2389 gspca_frame_add(gspca_dev, LAST_PACKET,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002390 data, len);
Brian Johnson26e744b2009-07-19 05:52:58 -03002391 return;
2392 }
2393 if (gspca_dev->last_packet_type == LAST_PACKET) {
2394 if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv
2395 & MODE_JPEG) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002396 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002397 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002398 gspca_frame_add(gspca_dev, INTER_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002399 data, len);
2400 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002401 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002402 data, len);
2403 }
2404 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002405 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Brian Johnson26e744b2009-07-19 05:52:58 -03002406 }
2407}
2408
2409/* sub-driver description */
2410static const struct sd_desc sd_desc = {
2411 .name = MODULE_NAME,
2412 .ctrls = sd_ctrls,
2413 .nctrls = ARRAY_SIZE(sd_ctrls),
2414 .config = sd_config,
2415 .init = sd_init,
2416 .start = sd_start,
2417 .stopN = sd_stopN,
2418 .stop0 = sd_stop0,
2419 .pkt_scan = sd_pkt_scan,
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002420#ifdef CONFIG_INPUT
2421 .int_pkt_scan = sd_int_pkt_scan,
2422#endif
Brian Johnsone1430472009-09-02 12:39:41 -03002423 .dq_callback = sd_dqcallback,
Brian Johnson26e744b2009-07-19 05:52:58 -03002424#ifdef CONFIG_VIDEO_ADV_DEBUG
2425 .set_register = sd_dbg_s_register,
2426 .get_register = sd_dbg_g_register,
2427#endif
2428 .get_chip_ident = sd_chip_ident,
2429};
2430
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002431#define SN9C20X(sensor, i2c_addr, flags) \
Brian Johnson0c045eb2010-03-16 13:58:27 -03002432 .driver_info = ((flags & 0xff) << 16) \
Brian Johnson26e744b2009-07-19 05:52:58 -03002433 | (SENSOR_ ## sensor << 8) \
2434 | (i2c_addr)
2435
2436static const __devinitdata struct usb_device_id device_table[] = {
2437 {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
2438 {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
2439 {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002440 {USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002441 {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, LED_REVERSE)},
2442 {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30,
2443 (FLIP_DETECT | HAS_NO_BUTTON))},
Brian Johnson26e744b2009-07-19 05:52:58 -03002444 {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
2445 {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
2446 {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
2447 {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)},
2448 {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, 0)},
2449 {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)},
2450 {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)},
2451 {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
2452 {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002453 {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002454 {USB_DEVICE(0x0c45, 0x628c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002455 {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)},
2456 {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
2457 {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
2458 {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
2459 {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002460 {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002461 {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
2462 {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
2463 {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
2464 {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002465 {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)},
2466 {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002467 {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
2468 {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)},
2469 {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)},
2470 {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002471 {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002472 {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)},
2473 {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)},
2474 {}
2475};
2476MODULE_DEVICE_TABLE(usb, device_table);
2477
2478/* -- device connect -- */
2479static int sd_probe(struct usb_interface *intf,
2480 const struct usb_device_id *id)
2481{
2482 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
2483 THIS_MODULE);
2484}
2485
Brian Johnson26e744b2009-07-19 05:52:58 -03002486static struct usb_driver sd_driver = {
2487 .name = MODULE_NAME,
2488 .id_table = device_table,
2489 .probe = sd_probe,
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002490 .disconnect = gspca_disconnect,
Brian Johnson26e744b2009-07-19 05:52:58 -03002491#ifdef CONFIG_PM
2492 .suspend = gspca_suspend,
2493 .resume = gspca_resume,
2494 .reset_resume = gspca_resume,
2495#endif
2496};
2497
2498/* -- module insert / remove -- */
2499static int __init sd_mod_init(void)
2500{
2501 int ret;
2502 ret = usb_register(&sd_driver);
2503 if (ret < 0)
2504 return ret;
2505 info("registered");
2506 return 0;
2507}
2508static void __exit sd_mod_exit(void)
2509{
2510 usb_deregister(&sd_driver);
2511 info("deregistered");
2512}
2513
2514module_init(sd_mod_init);
2515module_exit(sd_mod_exit);