blob: 479fdbb9e673aa997947b5a70c80093e8a0e3429 [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 */
58#define HAS_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 },
149 {}
150};
151
Marton Nemeth7e64dc42009-12-30 09:12:41 -0300152static const struct ctrl sd_ctrls[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300153 {
154#define BRIGHTNESS_IDX 0
155 {
156 .id = V4L2_CID_BRIGHTNESS,
157 .type = V4L2_CTRL_TYPE_INTEGER,
158 .name = "Brightness",
159 .minimum = 0,
160 .maximum = 0xff,
161 .step = 1,
162#define BRIGHTNESS_DEFAULT 0x7f
163 .default_value = BRIGHTNESS_DEFAULT,
164 },
165 .set = sd_setbrightness,
166 .get = sd_getbrightness,
167 },
168 {
169#define CONTRAST_IDX 1
170 {
171 .id = V4L2_CID_CONTRAST,
172 .type = V4L2_CTRL_TYPE_INTEGER,
173 .name = "Contrast",
174 .minimum = 0,
175 .maximum = 0xff,
176 .step = 1,
177#define CONTRAST_DEFAULT 0x7f
178 .default_value = CONTRAST_DEFAULT,
179 },
180 .set = sd_setcontrast,
181 .get = sd_getcontrast,
182 },
183 {
184#define SATURATION_IDX 2
185 {
186 .id = V4L2_CID_SATURATION,
187 .type = V4L2_CTRL_TYPE_INTEGER,
188 .name = "Saturation",
189 .minimum = 0,
190 .maximum = 0xff,
191 .step = 1,
192#define SATURATION_DEFAULT 0x7f
193 .default_value = SATURATION_DEFAULT,
194 },
195 .set = sd_setsaturation,
196 .get = sd_getsaturation,
197 },
198 {
199#define HUE_IDX 3
200 {
201 .id = V4L2_CID_HUE,
202 .type = V4L2_CTRL_TYPE_INTEGER,
203 .name = "Hue",
204 .minimum = -180,
205 .maximum = 180,
206 .step = 1,
207#define HUE_DEFAULT 0
208 .default_value = HUE_DEFAULT,
209 },
210 .set = sd_sethue,
211 .get = sd_gethue,
212 },
213 {
214#define GAMMA_IDX 4
215 {
216 .id = V4L2_CID_GAMMA,
217 .type = V4L2_CTRL_TYPE_INTEGER,
218 .name = "Gamma",
219 .minimum = 0,
220 .maximum = 0xff,
221 .step = 1,
222#define GAMMA_DEFAULT 0x10
223 .default_value = GAMMA_DEFAULT,
224 },
225 .set = sd_setgamma,
226 .get = sd_getgamma,
227 },
228 {
229#define BLUE_IDX 5
230 {
231 .id = V4L2_CID_BLUE_BALANCE,
232 .type = V4L2_CTRL_TYPE_INTEGER,
233 .name = "Blue Balance",
234 .minimum = 0,
235 .maximum = 0x7f,
236 .step = 1,
237#define BLUE_DEFAULT 0x28
238 .default_value = BLUE_DEFAULT,
239 },
240 .set = sd_setbluebalance,
241 .get = sd_getbluebalance,
242 },
243 {
244#define RED_IDX 6
245 {
246 .id = V4L2_CID_RED_BALANCE,
247 .type = V4L2_CTRL_TYPE_INTEGER,
248 .name = "Red Balance",
249 .minimum = 0,
250 .maximum = 0x7f,
251 .step = 1,
252#define RED_DEFAULT 0x28
253 .default_value = RED_DEFAULT,
254 },
255 .set = sd_setredbalance,
256 .get = sd_getredbalance,
257 },
258 {
259#define HFLIP_IDX 7
260 {
261 .id = V4L2_CID_HFLIP,
262 .type = V4L2_CTRL_TYPE_BOOLEAN,
263 .name = "Horizontal Flip",
264 .minimum = 0,
265 .maximum = 1,
266 .step = 1,
267#define HFLIP_DEFAULT 0
268 .default_value = HFLIP_DEFAULT,
269 },
270 .set = sd_sethflip,
271 .get = sd_gethflip,
272 },
273 {
274#define VFLIP_IDX 8
275 {
276 .id = V4L2_CID_VFLIP,
277 .type = V4L2_CTRL_TYPE_BOOLEAN,
278 .name = "Vertical Flip",
279 .minimum = 0,
280 .maximum = 1,
281 .step = 1,
282#define VFLIP_DEFAULT 0
283 .default_value = VFLIP_DEFAULT,
284 },
285 .set = sd_setvflip,
286 .get = sd_getvflip,
287 },
288 {
289#define EXPOSURE_IDX 9
290 {
291 .id = V4L2_CID_EXPOSURE,
292 .type = V4L2_CTRL_TYPE_INTEGER,
293 .name = "Exposure",
294 .minimum = 0,
295 .maximum = 0x1780,
296 .step = 1,
297#define EXPOSURE_DEFAULT 0x33
298 .default_value = EXPOSURE_DEFAULT,
299 },
300 .set = sd_setexposure,
301 .get = sd_getexposure,
302 },
303 {
304#define GAIN_IDX 10
305 {
306 .id = V4L2_CID_GAIN,
307 .type = V4L2_CTRL_TYPE_INTEGER,
308 .name = "Gain",
309 .minimum = 0,
310 .maximum = 28,
311 .step = 1,
312#define GAIN_DEFAULT 0x00
313 .default_value = GAIN_DEFAULT,
314 },
315 .set = sd_setgain,
316 .get = sd_getgain,
317 },
318 {
319#define AUTOGAIN_IDX 11
320 {
321 .id = V4L2_CID_AUTOGAIN,
322 .type = V4L2_CTRL_TYPE_BOOLEAN,
323 .name = "Auto Exposure",
324 .minimum = 0,
325 .maximum = 1,
326 .step = 1,
327#define AUTO_EXPOSURE_DEFAULT 1
328 .default_value = AUTO_EXPOSURE_DEFAULT,
329 },
330 .set = sd_setautoexposure,
331 .get = sd_getautoexposure,
332 },
333};
334
335static const struct v4l2_pix_format vga_mode[] = {
336 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
337 .bytesperline = 240,
338 .sizeimage = 240 * 120,
339 .colorspace = V4L2_COLORSPACE_JPEG,
340 .priv = 0 | MODE_JPEG},
341 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
342 .bytesperline = 160,
343 .sizeimage = 160 * 120,
344 .colorspace = V4L2_COLORSPACE_SRGB,
345 .priv = 0 | MODE_RAW},
346 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
347 .bytesperline = 240,
348 .sizeimage = 240 * 120,
349 .colorspace = V4L2_COLORSPACE_SRGB,
350 .priv = 0},
351 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
352 .bytesperline = 480,
353 .sizeimage = 480 * 240 ,
354 .colorspace = V4L2_COLORSPACE_JPEG,
355 .priv = 1 | MODE_JPEG},
356 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
357 .bytesperline = 320,
358 .sizeimage = 320 * 240 ,
359 .colorspace = V4L2_COLORSPACE_SRGB,
360 .priv = 1 | MODE_RAW},
361 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
362 .bytesperline = 480,
363 .sizeimage = 480 * 240 ,
364 .colorspace = V4L2_COLORSPACE_SRGB,
365 .priv = 1},
366 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
367 .bytesperline = 960,
368 .sizeimage = 960 * 480,
369 .colorspace = V4L2_COLORSPACE_JPEG,
370 .priv = 2 | MODE_JPEG},
371 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
372 .bytesperline = 640,
373 .sizeimage = 640 * 480,
374 .colorspace = V4L2_COLORSPACE_SRGB,
375 .priv = 2 | MODE_RAW},
376 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
377 .bytesperline = 960,
378 .sizeimage = 960 * 480,
379 .colorspace = V4L2_COLORSPACE_SRGB,
380 .priv = 2},
381};
382
383static const struct v4l2_pix_format sxga_mode[] = {
384 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
385 .bytesperline = 240,
386 .sizeimage = 240 * 120,
387 .colorspace = V4L2_COLORSPACE_JPEG,
388 .priv = 0 | MODE_JPEG},
389 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
390 .bytesperline = 160,
391 .sizeimage = 160 * 120,
392 .colorspace = V4L2_COLORSPACE_SRGB,
393 .priv = 0 | MODE_RAW},
394 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
395 .bytesperline = 240,
396 .sizeimage = 240 * 120,
397 .colorspace = V4L2_COLORSPACE_SRGB,
398 .priv = 0},
399 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
400 .bytesperline = 480,
401 .sizeimage = 480 * 240 ,
402 .colorspace = V4L2_COLORSPACE_JPEG,
403 .priv = 1 | MODE_JPEG},
404 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
405 .bytesperline = 320,
406 .sizeimage = 320 * 240 ,
407 .colorspace = V4L2_COLORSPACE_SRGB,
408 .priv = 1 | MODE_RAW},
409 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
410 .bytesperline = 480,
411 .sizeimage = 480 * 240 ,
412 .colorspace = V4L2_COLORSPACE_SRGB,
413 .priv = 1},
414 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
415 .bytesperline = 960,
416 .sizeimage = 960 * 480,
417 .colorspace = V4L2_COLORSPACE_JPEG,
418 .priv = 2 | MODE_JPEG},
419 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
420 .bytesperline = 640,
421 .sizeimage = 640 * 480,
422 .colorspace = V4L2_COLORSPACE_SRGB,
423 .priv = 2 | MODE_RAW},
424 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
425 .bytesperline = 960,
426 .sizeimage = 960 * 480,
427 .colorspace = V4L2_COLORSPACE_SRGB,
428 .priv = 2},
429 {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
430 .bytesperline = 1280,
431 .sizeimage = (1280 * 1024) + 64,
432 .colorspace = V4L2_COLORSPACE_SRGB,
433 .priv = 3 | MODE_RAW | MODE_SXGA},
434};
435
Joe Perches58aa68c2009-09-02 01:12:13 -0300436static const s16 hsv_red_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300437 41, 44, 46, 48, 50, 52, 54, 56,
438 58, 60, 62, 64, 66, 68, 70, 72,
439 74, 76, 78, 80, 81, 83, 85, 87,
440 88, 90, 92, 93, 95, 97, 98, 100,
441 101, 102, 104, 105, 107, 108, 109, 110,
442 112, 113, 114, 115, 116, 117, 118, 119,
443 120, 121, 122, 123, 123, 124, 125, 125,
444 126, 127, 127, 128, 128, 129, 129, 129,
445 130, 130, 130, 130, 131, 131, 131, 131,
446 131, 131, 131, 131, 130, 130, 130, 130,
447 129, 129, 129, 128, 128, 127, 127, 126,
448 125, 125, 124, 123, 122, 122, 121, 120,
449 119, 118, 117, 116, 115, 114, 112, 111,
450 110, 109, 107, 106, 105, 103, 102, 101,
451 99, 98, 96, 94, 93, 91, 90, 88,
452 86, 84, 83, 81, 79, 77, 75, 74,
453 72, 70, 68, 66, 64, 62, 60, 58,
454 56, 54, 52, 49, 47, 45, 43, 41,
455 39, 36, 34, 32, 30, 28, 25, 23,
456 21, 19, 16, 14, 12, 9, 7, 5,
457 3, 0, -1, -3, -6, -8, -10, -12,
458 -15, -17, -19, -22, -24, -26, -28, -30,
459 -33, -35, -37, -39, -41, -44, -46, -48,
460 -50, -52, -54, -56, -58, -60, -62, -64,
461 -66, -68, -70, -72, -74, -76, -78, -80,
462 -81, -83, -85, -87, -88, -90, -92, -93,
463 -95, -97, -98, -100, -101, -102, -104, -105,
464 -107, -108, -109, -110, -112, -113, -114, -115,
465 -116, -117, -118, -119, -120, -121, -122, -123,
466 -123, -124, -125, -125, -126, -127, -127, -128,
467 -128, -128, -128, -128, -128, -128, -128, -128,
468 -128, -128, -128, -128, -128, -128, -128, -128,
469 -128, -128, -128, -128, -128, -128, -128, -128,
470 -128, -127, -127, -126, -125, -125, -124, -123,
471 -122, -122, -121, -120, -119, -118, -117, -116,
472 -115, -114, -112, -111, -110, -109, -107, -106,
473 -105, -103, -102, -101, -99, -98, -96, -94,
474 -93, -91, -90, -88, -86, -84, -83, -81,
475 -79, -77, -75, -74, -72, -70, -68, -66,
476 -64, -62, -60, -58, -56, -54, -52, -49,
477 -47, -45, -43, -41, -39, -36, -34, -32,
478 -30, -28, -25, -23, -21, -19, -16, -14,
479 -12, -9, -7, -5, -3, 0, 1, 3,
480 6, 8, 10, 12, 15, 17, 19, 22,
481 24, 26, 28, 30, 33, 35, 37, 39, 41
482};
483
Joe Perches58aa68c2009-09-02 01:12:13 -0300484static const s16 hsv_red_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300485 82, 80, 78, 76, 74, 73, 71, 69,
486 67, 65, 63, 61, 58, 56, 54, 52,
487 50, 48, 46, 44, 41, 39, 37, 35,
488 32, 30, 28, 26, 23, 21, 19, 16,
489 14, 12, 10, 7, 5, 3, 0, -1,
490 -3, -6, -8, -10, -13, -15, -17, -19,
491 -22, -24, -26, -29, -31, -33, -35, -38,
492 -40, -42, -44, -46, -48, -51, -53, -55,
493 -57, -59, -61, -63, -65, -67, -69, -71,
494 -73, -75, -77, -79, -81, -82, -84, -86,
495 -88, -89, -91, -93, -94, -96, -98, -99,
496 -101, -102, -104, -105, -106, -108, -109, -110,
497 -112, -113, -114, -115, -116, -117, -119, -120,
498 -120, -121, -122, -123, -124, -125, -126, -126,
499 -127, -128, -128, -128, -128, -128, -128, -128,
500 -128, -128, -128, -128, -128, -128, -128, -128,
501 -128, -128, -128, -128, -128, -128, -128, -128,
502 -128, -128, -128, -128, -128, -128, -128, -128,
503 -127, -127, -126, -125, -125, -124, -123, -122,
504 -121, -120, -119, -118, -117, -116, -115, -114,
505 -113, -111, -110, -109, -107, -106, -105, -103,
506 -102, -100, -99, -97, -96, -94, -92, -91,
507 -89, -87, -85, -84, -82, -80, -78, -76,
508 -74, -73, -71, -69, -67, -65, -63, -61,
509 -58, -56, -54, -52, -50, -48, -46, -44,
510 -41, -39, -37, -35, -32, -30, -28, -26,
511 -23, -21, -19, -16, -14, -12, -10, -7,
512 -5, -3, 0, 1, 3, 6, 8, 10,
513 13, 15, 17, 19, 22, 24, 26, 29,
514 31, 33, 35, 38, 40, 42, 44, 46,
515 48, 51, 53, 55, 57, 59, 61, 63,
516 65, 67, 69, 71, 73, 75, 77, 79,
517 81, 82, 84, 86, 88, 89, 91, 93,
518 94, 96, 98, 99, 101, 102, 104, 105,
519 106, 108, 109, 110, 112, 113, 114, 115,
520 116, 117, 119, 120, 120, 121, 122, 123,
521 124, 125, 126, 126, 127, 128, 128, 129,
522 129, 130, 130, 131, 131, 131, 131, 132,
523 132, 132, 132, 132, 132, 132, 132, 132,
524 132, 132, 132, 131, 131, 131, 130, 130,
525 130, 129, 129, 128, 127, 127, 126, 125,
526 125, 124, 123, 122, 121, 120, 119, 118,
527 117, 116, 115, 114, 113, 111, 110, 109,
528 107, 106, 105, 103, 102, 100, 99, 97,
529 96, 94, 92, 91, 89, 87, 85, 84, 82
530};
531
Joe Perches58aa68c2009-09-02 01:12:13 -0300532static const s16 hsv_green_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300533 -124, -124, -125, -125, -125, -125, -125, -125,
534 -125, -126, -126, -125, -125, -125, -125, -125,
535 -125, -124, -124, -124, -123, -123, -122, -122,
536 -121, -121, -120, -120, -119, -118, -117, -117,
537 -116, -115, -114, -113, -112, -111, -110, -109,
538 -108, -107, -105, -104, -103, -102, -100, -99,
539 -98, -96, -95, -93, -92, -91, -89, -87,
540 -86, -84, -83, -81, -79, -77, -76, -74,
541 -72, -70, -69, -67, -65, -63, -61, -59,
542 -57, -55, -53, -51, -49, -47, -45, -43,
543 -41, -39, -37, -35, -33, -30, -28, -26,
544 -24, -22, -20, -18, -15, -13, -11, -9,
545 -7, -4, -2, 0, 1, 3, 6, 8,
546 10, 12, 14, 17, 19, 21, 23, 25,
547 27, 29, 32, 34, 36, 38, 40, 42,
548 44, 46, 48, 50, 52, 54, 56, 58,
549 60, 62, 64, 66, 68, 70, 71, 73,
550 75, 77, 78, 80, 82, 83, 85, 87,
551 88, 90, 91, 93, 94, 96, 97, 98,
552 100, 101, 102, 104, 105, 106, 107, 108,
553 109, 111, 112, 113, 113, 114, 115, 116,
554 117, 118, 118, 119, 120, 120, 121, 122,
555 122, 123, 123, 124, 124, 124, 125, 125,
556 125, 125, 125, 125, 125, 126, 126, 125,
557 125, 125, 125, 125, 125, 124, 124, 124,
558 123, 123, 122, 122, 121, 121, 120, 120,
559 119, 118, 117, 117, 116, 115, 114, 113,
560 112, 111, 110, 109, 108, 107, 105, 104,
561 103, 102, 100, 99, 98, 96, 95, 93,
562 92, 91, 89, 87, 86, 84, 83, 81,
563 79, 77, 76, 74, 72, 70, 69, 67,
564 65, 63, 61, 59, 57, 55, 53, 51,
565 49, 47, 45, 43, 41, 39, 37, 35,
566 33, 30, 28, 26, 24, 22, 20, 18,
567 15, 13, 11, 9, 7, 4, 2, 0,
568 -1, -3, -6, -8, -10, -12, -14, -17,
569 -19, -21, -23, -25, -27, -29, -32, -34,
570 -36, -38, -40, -42, -44, -46, -48, -50,
571 -52, -54, -56, -58, -60, -62, -64, -66,
572 -68, -70, -71, -73, -75, -77, -78, -80,
573 -82, -83, -85, -87, -88, -90, -91, -93,
574 -94, -96, -97, -98, -100, -101, -102, -104,
575 -105, -106, -107, -108, -109, -111, -112, -113,
576 -113, -114, -115, -116, -117, -118, -118, -119,
577 -120, -120, -121, -122, -122, -123, -123, -124, -124
578};
579
Joe Perches58aa68c2009-09-02 01:12:13 -0300580static const s16 hsv_green_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300581 -100, -99, -98, -97, -95, -94, -93, -91,
582 -90, -89, -87, -86, -84, -83, -81, -80,
583 -78, -76, -75, -73, -71, -70, -68, -66,
584 -64, -63, -61, -59, -57, -55, -53, -51,
585 -49, -48, -46, -44, -42, -40, -38, -36,
586 -34, -32, -30, -27, -25, -23, -21, -19,
587 -17, -15, -13, -11, -9, -7, -4, -2,
588 0, 1, 3, 5, 7, 9, 11, 14,
589 16, 18, 20, 22, 24, 26, 28, 30,
590 32, 34, 36, 38, 40, 42, 44, 46,
591 48, 50, 52, 54, 56, 58, 59, 61,
592 63, 65, 67, 68, 70, 72, 74, 75,
593 77, 78, 80, 82, 83, 85, 86, 88,
594 89, 90, 92, 93, 95, 96, 97, 98,
595 100, 101, 102, 103, 104, 105, 106, 107,
596 108, 109, 110, 111, 112, 112, 113, 114,
597 115, 115, 116, 116, 117, 117, 118, 118,
598 119, 119, 119, 120, 120, 120, 120, 120,
599 121, 121, 121, 121, 121, 121, 120, 120,
600 120, 120, 120, 119, 119, 119, 118, 118,
601 117, 117, 116, 116, 115, 114, 114, 113,
602 112, 111, 111, 110, 109, 108, 107, 106,
603 105, 104, 103, 102, 100, 99, 98, 97,
604 95, 94, 93, 91, 90, 89, 87, 86,
605 84, 83, 81, 80, 78, 76, 75, 73,
606 71, 70, 68, 66, 64, 63, 61, 59,
607 57, 55, 53, 51, 49, 48, 46, 44,
608 42, 40, 38, 36, 34, 32, 30, 27,
609 25, 23, 21, 19, 17, 15, 13, 11,
610 9, 7, 4, 2, 0, -1, -3, -5,
611 -7, -9, -11, -14, -16, -18, -20, -22,
612 -24, -26, -28, -30, -32, -34, -36, -38,
613 -40, -42, -44, -46, -48, -50, -52, -54,
614 -56, -58, -59, -61, -63, -65, -67, -68,
615 -70, -72, -74, -75, -77, -78, -80, -82,
616 -83, -85, -86, -88, -89, -90, -92, -93,
617 -95, -96, -97, -98, -100, -101, -102, -103,
618 -104, -105, -106, -107, -108, -109, -110, -111,
619 -112, -112, -113, -114, -115, -115, -116, -116,
620 -117, -117, -118, -118, -119, -119, -119, -120,
621 -120, -120, -120, -120, -121, -121, -121, -121,
622 -121, -121, -120, -120, -120, -120, -120, -119,
623 -119, -119, -118, -118, -117, -117, -116, -116,
624 -115, -114, -114, -113, -112, -111, -111, -110,
625 -109, -108, -107, -106, -105, -104, -103, -102, -100
626};
627
Joe Perches58aa68c2009-09-02 01:12:13 -0300628static const s16 hsv_blue_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300629 112, 113, 114, 114, 115, 116, 117, 117,
630 118, 118, 119, 119, 120, 120, 120, 121,
631 121, 121, 122, 122, 122, 122, 122, 122,
632 122, 122, 122, 122, 122, 122, 121, 121,
633 121, 120, 120, 120, 119, 119, 118, 118,
634 117, 116, 116, 115, 114, 113, 113, 112,
635 111, 110, 109, 108, 107, 106, 105, 104,
636 103, 102, 100, 99, 98, 97, 95, 94,
637 93, 91, 90, 88, 87, 85, 84, 82,
638 80, 79, 77, 76, 74, 72, 70, 69,
639 67, 65, 63, 61, 60, 58, 56, 54,
640 52, 50, 48, 46, 44, 42, 40, 38,
641 36, 34, 32, 30, 28, 26, 24, 22,
642 19, 17, 15, 13, 11, 9, 7, 5,
643 2, 0, -1, -3, -5, -7, -9, -12,
644 -14, -16, -18, -20, -22, -24, -26, -28,
645 -31, -33, -35, -37, -39, -41, -43, -45,
646 -47, -49, -51, -53, -54, -56, -58, -60,
647 -62, -64, -66, -67, -69, -71, -73, -74,
648 -76, -78, -79, -81, -83, -84, -86, -87,
649 -89, -90, -92, -93, -94, -96, -97, -98,
650 -99, -101, -102, -103, -104, -105, -106, -107,
651 -108, -109, -110, -111, -112, -113, -114, -114,
652 -115, -116, -117, -117, -118, -118, -119, -119,
653 -120, -120, -120, -121, -121, -121, -122, -122,
654 -122, -122, -122, -122, -122, -122, -122, -122,
655 -122, -122, -121, -121, -121, -120, -120, -120,
656 -119, -119, -118, -118, -117, -116, -116, -115,
657 -114, -113, -113, -112, -111, -110, -109, -108,
658 -107, -106, -105, -104, -103, -102, -100, -99,
659 -98, -97, -95, -94, -93, -91, -90, -88,
660 -87, -85, -84, -82, -80, -79, -77, -76,
661 -74, -72, -70, -69, -67, -65, -63, -61,
662 -60, -58, -56, -54, -52, -50, -48, -46,
663 -44, -42, -40, -38, -36, -34, -32, -30,
664 -28, -26, -24, -22, -19, -17, -15, -13,
665 -11, -9, -7, -5, -2, 0, 1, 3,
666 5, 7, 9, 12, 14, 16, 18, 20,
667 22, 24, 26, 28, 31, 33, 35, 37,
668 39, 41, 43, 45, 47, 49, 51, 53,
669 54, 56, 58, 60, 62, 64, 66, 67,
670 69, 71, 73, 74, 76, 78, 79, 81,
671 83, 84, 86, 87, 89, 90, 92, 93,
672 94, 96, 97, 98, 99, 101, 102, 103,
673 104, 105, 106, 107, 108, 109, 110, 111, 112
674};
675
Joe Perches58aa68c2009-09-02 01:12:13 -0300676static const s16 hsv_blue_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300677 -11, -13, -15, -17, -19, -21, -23, -25,
678 -27, -29, -31, -33, -35, -37, -39, -41,
679 -43, -45, -46, -48, -50, -52, -54, -55,
680 -57, -59, -61, -62, -64, -66, -67, -69,
681 -71, -72, -74, -75, -77, -78, -80, -81,
682 -83, -84, -86, -87, -88, -90, -91, -92,
683 -93, -95, -96, -97, -98, -99, -100, -101,
684 -102, -103, -104, -105, -106, -106, -107, -108,
685 -109, -109, -110, -111, -111, -112, -112, -113,
686 -113, -114, -114, -114, -115, -115, -115, -115,
687 -116, -116, -116, -116, -116, -116, -116, -116,
688 -116, -115, -115, -115, -115, -114, -114, -114,
689 -113, -113, -112, -112, -111, -111, -110, -110,
690 -109, -108, -108, -107, -106, -105, -104, -103,
691 -102, -101, -100, -99, -98, -97, -96, -95,
692 -94, -93, -91, -90, -89, -88, -86, -85,
693 -84, -82, -81, -79, -78, -76, -75, -73,
694 -71, -70, -68, -67, -65, -63, -62, -60,
695 -58, -56, -55, -53, -51, -49, -47, -45,
696 -44, -42, -40, -38, -36, -34, -32, -30,
697 -28, -26, -24, -22, -20, -18, -16, -14,
698 -12, -10, -8, -6, -4, -2, 0, 1,
699 3, 5, 7, 9, 11, 13, 15, 17,
700 19, 21, 23, 25, 27, 29, 31, 33,
701 35, 37, 39, 41, 43, 45, 46, 48,
702 50, 52, 54, 55, 57, 59, 61, 62,
703 64, 66, 67, 69, 71, 72, 74, 75,
704 77, 78, 80, 81, 83, 84, 86, 87,
705 88, 90, 91, 92, 93, 95, 96, 97,
706 98, 99, 100, 101, 102, 103, 104, 105,
707 106, 106, 107, 108, 109, 109, 110, 111,
708 111, 112, 112, 113, 113, 114, 114, 114,
709 115, 115, 115, 115, 116, 116, 116, 116,
710 116, 116, 116, 116, 116, 115, 115, 115,
711 115, 114, 114, 114, 113, 113, 112, 112,
712 111, 111, 110, 110, 109, 108, 108, 107,
713 106, 105, 104, 103, 102, 101, 100, 99,
714 98, 97, 96, 95, 94, 93, 91, 90,
715 89, 88, 86, 85, 84, 82, 81, 79,
716 78, 76, 75, 73, 71, 70, 68, 67,
717 65, 63, 62, 60, 58, 56, 55, 53,
718 51, 49, 47, 45, 44, 42, 40, 38,
719 36, 34, 32, 30, 28, 26, 24, 22,
720 20, 18, 16, 14, 12, 10, 8, 6,
721 4, 2, 0, -1, -3, -5, -7, -9, -11
722};
723
724static u16 i2c_ident[] = {
725 V4L2_IDENT_OV9650,
726 V4L2_IDENT_OV9655,
727 V4L2_IDENT_SOI968,
728 V4L2_IDENT_OV7660,
729 V4L2_IDENT_OV7670,
730 V4L2_IDENT_MT9V011,
731 V4L2_IDENT_MT9V111,
732 V4L2_IDENT_MT9V112,
733 V4L2_IDENT_MT9M001C12ST,
734 V4L2_IDENT_MT9M111,
Brian Johnsone99ac542010-03-16 13:58:28 -0300735 V4L2_IDENT_MT9M112,
Brian Johnson26e744b2009-07-19 05:52:58 -0300736 V4L2_IDENT_HV7131R,
737};
738
739static u16 bridge_init[][2] = {
740 {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c},
741 {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40},
742 {0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10},
743 {0x106b, 0x08}, {0x1188, 0x87}, {0x11a1, 0x00},
744 {0x11a2, 0x00}, {0x11a3, 0x6a}, {0x11a4, 0x50},
745 {0x11ab, 0x00}, {0x11ac, 0x00}, {0x11ad, 0x50},
746 {0x11ae, 0x3c}, {0x118a, 0x04}, {0x0395, 0x04},
747 {0x11b8, 0x3a}, {0x118b, 0x0e}, {0x10f7, 0x05},
748 {0x10f8, 0x14}, {0x10fa, 0xff}, {0x10f9, 0x00},
749 {0x11ba, 0x0a}, {0x11a5, 0x2d}, {0x11a6, 0x2d},
750 {0x11a7, 0x3a}, {0x11a8, 0x05}, {0x11a9, 0x04},
751 {0x11aa, 0x3f}, {0x11af, 0x28}, {0x11b0, 0xd8},
752 {0x11b1, 0x14}, {0x11b2, 0xec}, {0x11b3, 0x32},
753 {0x11b4, 0xdd}, {0x11b5, 0x32}, {0x11b6, 0xdd},
754 {0x10e0, 0x2c}, {0x11bc, 0x40}, {0x11bd, 0x01},
755 {0x11be, 0xf0}, {0x11bf, 0x00}, {0x118c, 0x1f},
756 {0x118d, 0x1f}, {0x118e, 0x1f}, {0x118f, 0x1f},
757 {0x1180, 0x01}, {0x1181, 0x00}, {0x1182, 0x01},
Brian Johnson0c045eb2010-03-16 13:58:27 -0300758 {0x1183, 0x00}, {0x1184, 0x50}, {0x1185, 0x80},
759 {0x1007, 0x00}
Brian Johnson26e744b2009-07-19 05:52:58 -0300760};
761
762/* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */
763static u8 ov_gain[] = {
764 0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */,
765 0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */,
766 0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */,
767 0x30 /* 4x */, 0x31 /* 4.25x */, 0x32 /* 4.5x */, 0x33 /* 4.75x */,
768 0x34 /* 5x */, 0x35 /* 5.25x */, 0x36 /* 5.5x */, 0x37 /* 5.75x */,
769 0x38 /* 6x */, 0x39 /* 6.25x */, 0x3a /* 6.5x */, 0x3b /* 6.75x */,
770 0x3c /* 7x */, 0x3d /* 7.25x */, 0x3e /* 7.5x */, 0x3f /* 7.75x */,
771 0x70 /* 8x */
772};
773
774/* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */
775static u16 micron1_gain[] = {
776 /* 1x 1.25x 1.5x 1.75x */
777 0x0020, 0x0028, 0x0030, 0x0038,
778 /* 2x 2.25x 2.5x 2.75x */
779 0x00a0, 0x00a4, 0x00a8, 0x00ac,
780 /* 3x 3.25x 3.5x 3.75x */
781 0x00b0, 0x00b4, 0x00b8, 0x00bc,
782 /* 4x 4.25x 4.5x 4.75x */
783 0x00c0, 0x00c4, 0x00c8, 0x00cc,
784 /* 5x 5.25x 5.5x 5.75x */
785 0x00d0, 0x00d4, 0x00d8, 0x00dc,
786 /* 6x 6.25x 6.5x 6.75x */
787 0x00e0, 0x00e4, 0x00e8, 0x00ec,
788 /* 7x 7.25x 7.5x 7.75x */
789 0x00f0, 0x00f4, 0x00f8, 0x00fc,
790 /* 8x */
791 0x01c0
792};
793
794/* mt9m001 sensor uses a different gain formula then other micron sensors */
795/* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */
796static u16 micron2_gain[] = {
797 /* 1x 1.25x 1.5x 1.75x */
798 0x0008, 0x000a, 0x000c, 0x000e,
799 /* 2x 2.25x 2.5x 2.75x */
800 0x0010, 0x0012, 0x0014, 0x0016,
801 /* 3x 3.25x 3.5x 3.75x */
802 0x0018, 0x001a, 0x001c, 0x001e,
803 /* 4x 4.25x 4.5x 4.75x */
804 0x0020, 0x0051, 0x0052, 0x0053,
805 /* 5x 5.25x 5.5x 5.75x */
806 0x0054, 0x0055, 0x0056, 0x0057,
807 /* 6x 6.25x 6.5x 6.75x */
808 0x0058, 0x0059, 0x005a, 0x005b,
809 /* 7x 7.25x 7.5x 7.75x */
810 0x005c, 0x005d, 0x005e, 0x005f,
811 /* 8x */
812 0x0060
813};
814
815/* Gain = .5 + bit[7:0] / 16 */
816static u8 hv7131r_gain[] = {
817 0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */,
818 0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */,
819 0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */,
820 0x38 /* 4x */, 0x3c /* 4.25x */, 0x40 /* 4.5x */, 0x44 /* 4.75x */,
821 0x48 /* 5x */, 0x4c /* 5.25x */, 0x50 /* 5.5x */, 0x54 /* 5.75x */,
822 0x58 /* 6x */, 0x5c /* 6.25x */, 0x60 /* 6.5x */, 0x64 /* 6.75x */,
823 0x68 /* 7x */, 0x6c /* 7.25x */, 0x70 /* 7.5x */, 0x74 /* 7.75x */,
824 0x78 /* 8x */
825};
826
Joe Perches58aa68c2009-09-02 01:12:13 -0300827static struct i2c_reg_u8 soi968_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300828 {0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f},
829 {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
830 {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
831 {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
832 {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20},
833 {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e},
Brian Johnsone1430472009-09-02 12:39:41 -0300834 {0x13, 0x8b}, {0x12, 0x40}, {0x17, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300835 {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79},
836 {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40},
837 {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32},
838 {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80},
839};
840
Joe Perches58aa68c2009-09-02 01:12:13 -0300841static struct i2c_reg_u8 ov7660_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300842 {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
843 {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
844 {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
845 {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43},
846 {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0xf6},
847 {0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50},
848};
849
Joe Perches58aa68c2009-09-02 01:12:13 -0300850static struct i2c_reg_u8 ov7670_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300851 {0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
852 {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
853 {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
854 {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
855 {0x0d, 0x40}, {0x14, 0x28}, {0xa5, 0x05}, {0xab, 0x07},
856 {0x24, 0x95}, {0x25, 0x33}, {0x26, 0xe3}, {0x9f, 0x75},
857 {0xa0, 0x65}, {0xa1, 0x0b}, {0xa6, 0xd8}, {0xa7, 0xd8},
858 {0xa8, 0xf0}, {0xa9, 0x90}, {0xaa, 0x94}, {0x13, 0xe5},
859 {0x0e, 0x61}, {0x0f, 0x4b}, {0x16, 0x02}, {0x1e, 0x27},
860 {0x21, 0x02}, {0x22, 0x91}, {0x29, 0x07}, {0x33, 0x0b},
861 {0x35, 0x0b}, {0x37, 0x1d}, {0x38, 0x71}, {0x39, 0x2a},
862 {0x3c, 0x78}, {0x4d, 0x40}, {0x4e, 0x20}, {0x69, 0x00},
863 {0x74, 0x19}, {0x8d, 0x4f}, {0x8e, 0x00}, {0x8f, 0x00},
864 {0x90, 0x00}, {0x91, 0x00}, {0x96, 0x00}, {0x9a, 0x80},
865 {0xb0, 0x84}, {0xb1, 0x0c}, {0xb2, 0x0e}, {0xb3, 0x82},
866 {0xb8, 0x0a}, {0x43, 0x0a}, {0x44, 0xf0}, {0x45, 0x20},
867 {0x46, 0x7d}, {0x47, 0x29}, {0x48, 0x4a}, {0x59, 0x8c},
868 {0x5a, 0xa5}, {0x5b, 0xde}, {0x5c, 0x96}, {0x5d, 0x66},
869 {0x5e, 0x10}, {0x6c, 0x0a}, {0x6d, 0x55}, {0x6e, 0x11},
870 {0x6f, 0x9e}, {0x6a, 0x40}, {0x01, 0x40}, {0x02, 0x40},
871 {0x13, 0xe7}, {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x02},
872 {0x52, 0x1d}, {0x53, 0x56}, {0x54, 0x73}, {0x55, 0x0a},
873 {0x56, 0x55}, {0x57, 0x80}, {0x58, 0x9e}, {0x41, 0x08},
874 {0x3f, 0x02}, {0x75, 0x03}, {0x76, 0x63}, {0x4c, 0x04},
875 {0x77, 0x06}, {0x3d, 0x02}, {0x4b, 0x09}, {0xc9, 0x30},
876 {0x41, 0x08}, {0x56, 0x48}, {0x34, 0x11}, {0xa4, 0x88},
877 {0x96, 0x00}, {0x97, 0x30}, {0x98, 0x20}, {0x99, 0x30},
878 {0x9a, 0x84}, {0x9b, 0x29}, {0x9c, 0x03}, {0x9d, 0x99},
879 {0x9e, 0x7f}, {0x78, 0x04}, {0x79, 0x01}, {0xc8, 0xf0},
880 {0x79, 0x0f}, {0xc8, 0x00}, {0x79, 0x10}, {0xc8, 0x7e},
881 {0x79, 0x0a}, {0xc8, 0x80}, {0x79, 0x0b}, {0xc8, 0x01},
882 {0x79, 0x0c}, {0xc8, 0x0f}, {0x79, 0x0d}, {0xc8, 0x20},
883 {0x79, 0x09}, {0xc8, 0x80}, {0x79, 0x02}, {0xc8, 0xc0},
884 {0x79, 0x03}, {0xc8, 0x40}, {0x79, 0x05}, {0xc8, 0x30},
885 {0x79, 0x26}, {0x62, 0x20}, {0x63, 0x00}, {0x64, 0x06},
886 {0x65, 0x00}, {0x66, 0x05}, {0x94, 0x05}, {0x95, 0x0a},
887 {0x17, 0x13}, {0x18, 0x01}, {0x19, 0x02}, {0x1a, 0x7a},
888 {0x46, 0x59}, {0x47, 0x30}, {0x58, 0x9a}, {0x59, 0x84},
889 {0x5a, 0x91}, {0x5b, 0x57}, {0x5c, 0x75}, {0x5d, 0x6d},
890 {0x5e, 0x13}, {0x64, 0x07}, {0x94, 0x07}, {0x95, 0x0d},
891 {0xa6, 0xdf}, {0xa7, 0xdf}, {0x48, 0x4d}, {0x51, 0x00},
892 {0x6b, 0x0a}, {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00},
893 {0x92, 0x00}, {0x93, 0x00}, {0x55, 0x0a}, {0x56, 0x60},
894 {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d},
895 {0x53, 0x56}, {0x54, 0x73}, {0x58, 0x9a}, {0x4f, 0x6e},
896 {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, {0x53, 0x56},
897 {0x54, 0x73}, {0x58, 0x9a}, {0x3f, 0x01}, {0x7b, 0x03},
898 {0x7c, 0x09}, {0x7d, 0x16}, {0x7e, 0x38}, {0x7f, 0x47},
899 {0x80, 0x53}, {0x81, 0x5e}, {0x82, 0x6a}, {0x83, 0x74},
900 {0x84, 0x80}, {0x85, 0x8c}, {0x86, 0x9b}, {0x87, 0xb2},
901 {0x88, 0xcc}, {0x89, 0xe5}, {0x7a, 0x24}, {0x3b, 0x00},
902 {0x9f, 0x76}, {0xa0, 0x65}, {0x13, 0xe2}, {0x6b, 0x0a},
903 {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, {0x92, 0x00},
904 {0x93, 0x00},
905};
906
Joe Perches58aa68c2009-09-02 01:12:13 -0300907static struct i2c_reg_u8 ov9650_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300908 {0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78},
909 {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
910 {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
911 {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
912 {0x0e, 0xa0}, {0x0f, 0x52}, {0x10, 0x7c},
913 {0x11, 0x80}, {0x12, 0x45}, {0x13, 0xc2},
914 {0x14, 0x2e}, {0x15, 0x00}, {0x16, 0x07},
915 {0x17, 0x24}, {0x18, 0xc5}, {0x19, 0x00},
916 {0x1a, 0x3c}, {0x1b, 0x00}, {0x1e, 0x04},
917 {0x1f, 0x00}, {0x24, 0x78}, {0x25, 0x68},
918 {0x26, 0xd4}, {0x27, 0x80}, {0x28, 0x80},
919 {0x29, 0x30}, {0x2a, 0x00}, {0x2b, 0x00},
920 {0x2c, 0x80}, {0x2d, 0x00}, {0x2e, 0x00},
921 {0x2f, 0x00}, {0x30, 0x08}, {0x31, 0x30},
922 {0x32, 0x84}, {0x33, 0xe2}, {0x34, 0xbf},
923 {0x35, 0x81}, {0x36, 0xf9}, {0x37, 0x00},
924 {0x38, 0x93}, {0x39, 0x50}, {0x3a, 0x01},
925 {0x3b, 0x01}, {0x3c, 0x73}, {0x3d, 0x19},
926 {0x3e, 0x0b}, {0x3f, 0x80}, {0x40, 0xc1},
927 {0x41, 0x00}, {0x42, 0x08}, {0x67, 0x80},
928 {0x68, 0x80}, {0x69, 0x40}, {0x6a, 0x00},
929 {0x6b, 0x0a}, {0x8b, 0x06}, {0x8c, 0x20},
930 {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0xdf},
931 {0x92, 0x00}, {0x93, 0x00}, {0x94, 0x88},
932 {0x95, 0x88}, {0x96, 0x04}, {0xa1, 0x00},
933 {0xa5, 0x80}, {0xa8, 0x80}, {0xa9, 0xb8},
934 {0xaa, 0x92}, {0xab, 0x0a},
935};
936
Joe Perches58aa68c2009-09-02 01:12:13 -0300937static struct i2c_reg_u8 ov9655_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300938 {0x12, 0x80}, {0x12, 0x01}, {0x0d, 0x00}, {0x0e, 0x61},
939 {0x11, 0x80}, {0x13, 0xba}, {0x14, 0x2e}, {0x16, 0x24},
940 {0x1e, 0x04}, {0x1e, 0x04}, {0x1e, 0x04}, {0x27, 0x08},
941 {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x32, 0xbf},
942 {0x34, 0x3d}, {0x35, 0x00}, {0x36, 0xf8}, {0x38, 0x12},
943 {0x39, 0x57}, {0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c},
944 {0x3d, 0x19}, {0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40},
945 {0x42, 0x80}, {0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a},
946 {0x48, 0x3c}, {0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc},
947 {0x4d, 0xdc}, {0x4e, 0xdc}, {0x69, 0x02}, {0x6c, 0x04},
948 {0x6f, 0x9e}, {0x70, 0x05}, {0x71, 0x78}, {0x77, 0x02},
949 {0x8a, 0x23}, {0x8c, 0x0d}, {0x90, 0x7e}, {0x91, 0x7c},
950 {0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68}, {0xa6, 0x60},
951 {0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92}, {0xab, 0x04},
952 {0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80}, {0xaf, 0x80},
953 {0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00}, {0xb6, 0xaf},
954 {0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44}, {0xbe, 0x3b},
955 {0xbf, 0x3a}, {0xc0, 0xe2}, {0xc1, 0xc8}, {0xc2, 0x01},
956 {0xc4, 0x00}, {0xc6, 0x85}, {0xc7, 0x81}, {0xc9, 0xe0},
957 {0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x12, 0x61},
958 {0x36, 0xfa}, {0x8c, 0x8d}, {0xc0, 0xaa}, {0x69, 0x0a},
959 {0x03, 0x12}, {0x17, 0x14}, {0x18, 0x00}, {0x19, 0x01},
960 {0x1a, 0x3d}, {0x32, 0xbf}, {0x11, 0x80}, {0x2a, 0x10},
961 {0x2b, 0x0a}, {0x92, 0x00}, {0x93, 0x00}, {0x1e, 0x04},
962 {0x1e, 0x04}, {0x10, 0x7c}, {0x04, 0x03}, {0xa1, 0x00},
963 {0x2d, 0x00}, {0x2e, 0x00}, {0x00, 0x00}, {0x01, 0x80},
964 {0x02, 0x80}, {0x12, 0x61}, {0x36, 0xfa}, {0x8c, 0x8d},
965 {0xc0, 0xaa}, {0x69, 0x0a}, {0x03, 0x12}, {0x17, 0x14},
966 {0x18, 0x00}, {0x19, 0x01}, {0x1a, 0x3d}, {0x32, 0xbf},
967 {0x11, 0x80}, {0x2a, 0x10}, {0x2b, 0x0a}, {0x92, 0x00},
968 {0x93, 0x00}, {0x04, 0x01}, {0x10, 0x1f}, {0xa1, 0x00},
969 {0x00, 0x0a}, {0xa1, 0x00}, {0x10, 0x5d}, {0x04, 0x03},
970 {0x00, 0x01}, {0xa1, 0x00}, {0x10, 0x7c}, {0x04, 0x03},
971 {0x00, 0x03}, {0x00, 0x0a}, {0x00, 0x10}, {0x00, 0x13},
972};
973
Joe Perches58aa68c2009-09-02 01:12:13 -0300974static struct i2c_reg_u16 mt9v112_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300975 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020},
976 {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
977 {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
978 {0x05, 0x0000}, {0x06, 0x340c}, {0x3b, 0x042a},
979 {0x3c, 0x0400}, {0xf0, 0x0002}, {0x2e, 0x0c58},
980 {0x5b, 0x0001}, {0xc8, 0x9f0b}, {0xf0, 0x0001},
981 {0x9b, 0x5300}, {0xf0, 0x0000}, {0x2b, 0x0020},
982 {0x2c, 0x002a}, {0x2d, 0x0032}, {0x2e, 0x0020},
983 {0x09, 0x01dc}, {0x01, 0x000c}, {0x02, 0x0020},
984 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
985 {0x05, 0x0098}, {0x20, 0x0703}, {0x09, 0x01f2},
986 {0x2b, 0x00a0}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
987 {0x2e, 0x00a0}, {0x01, 0x000c}, {0x02, 0x0020},
988 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
989 {0x05, 0x0098}, {0x09, 0x01c1}, {0x2b, 0x00ae},
990 {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
991};
992
Joe Perches58aa68c2009-09-02 01:12:13 -0300993static struct i2c_reg_u16 mt9v111_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300994 {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
995 {0x01, 0x0001}, {0x02, 0x0016}, {0x03, 0x01e1},
996 {0x04, 0x0281}, {0x05, 0x0004}, {0x07, 0x3002},
997 {0x21, 0x0000}, {0x25, 0x4024}, {0x26, 0xff03},
998 {0x27, 0xff10}, {0x2b, 0x7828}, {0x2c, 0xb43c},
999 {0x2d, 0xf0a0}, {0x2e, 0x0c64}, {0x2f, 0x0064},
1000 {0x67, 0x4010}, {0x06, 0x301e}, {0x08, 0x0480},
1001 {0x01, 0x0004}, {0x02, 0x0016}, {0x03, 0x01e6},
1002 {0x04, 0x0286}, {0x05, 0x0004}, {0x06, 0x0000},
1003 {0x07, 0x3002}, {0x08, 0x0008}, {0x0c, 0x0000},
1004 {0x0d, 0x0000}, {0x0e, 0x0000}, {0x0f, 0x0000},
1005 {0x10, 0x0000}, {0x11, 0x0000}, {0x12, 0x00b0},
1006 {0x13, 0x007c}, {0x14, 0x0000}, {0x15, 0x0000},
1007 {0x16, 0x0000}, {0x17, 0x0000}, {0x18, 0x0000},
1008 {0x19, 0x0000}, {0x1a, 0x0000}, {0x1b, 0x0000},
1009 {0x1c, 0x0000}, {0x1d, 0x0000}, {0x30, 0x0000},
1010 {0x30, 0x0005}, {0x31, 0x0000}, {0x02, 0x0016},
1011 {0x03, 0x01e1}, {0x04, 0x0281}, {0x05, 0x0004},
1012 {0x06, 0x0000}, {0x07, 0x3002}, {0x06, 0x002d},
1013 {0x05, 0x0004}, {0x09, 0x0064}, {0x2b, 0x00a0},
1014 {0x2c, 0x00a0}, {0x2d, 0x00a0}, {0x2e, 0x00a0},
1015 {0x02, 0x0016}, {0x03, 0x01e1}, {0x04, 0x0281},
1016 {0x05, 0x0004}, {0x06, 0x002d}, {0x07, 0x3002},
1017 {0x0e, 0x0008}, {0x06, 0x002d}, {0x05, 0x0004},
1018};
1019
Joe Perches58aa68c2009-09-02 01:12:13 -03001020static struct i2c_reg_u16 mt9v011_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001021 {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
1022 {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1},
1023 {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006},
1024 {0x0d, 0x0002}, {0x0a, 0x0000}, {0x0b, 0x0000},
1025 {0x0c, 0x0000}, {0x0d, 0x0000}, {0x0e, 0x0000},
1026 {0x0f, 0x0000}, {0x10, 0x0000}, {0x11, 0x0000},
1027 {0x12, 0x0000}, {0x13, 0x0000}, {0x14, 0x0000},
1028 {0x15, 0x0000}, {0x16, 0x0000}, {0x17, 0x0000},
1029 {0x18, 0x0000}, {0x19, 0x0000}, {0x1a, 0x0000},
1030 {0x1b, 0x0000}, {0x1c, 0x0000}, {0x1d, 0x0000},
1031 {0x32, 0x0000}, {0x20, 0x1101}, {0x21, 0x0000},
1032 {0x22, 0x0000}, {0x23, 0x0000}, {0x24, 0x0000},
1033 {0x25, 0x0000}, {0x26, 0x0000}, {0x27, 0x0024},
1034 {0x2f, 0xf7b0}, {0x30, 0x0005}, {0x31, 0x0000},
1035 {0x32, 0x0000}, {0x33, 0x0000}, {0x34, 0x0100},
1036 {0x3d, 0x068f}, {0x40, 0x01e0}, {0x41, 0x00d1},
1037 {0x44, 0x0082}, {0x5a, 0x0000}, {0x5b, 0x0000},
1038 {0x5c, 0x0000}, {0x5d, 0x0000}, {0x5e, 0x0000},
1039 {0x5f, 0xa31d}, {0x62, 0x0611}, {0x0a, 0x0000},
1040 {0x06, 0x0029}, {0x05, 0x0009}, {0x20, 0x1101},
1041 {0x20, 0x1101}, {0x09, 0x0064}, {0x07, 0x0003},
1042 {0x2b, 0x0033}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
1043 {0x2e, 0x0033}, {0x07, 0x0002}, {0x06, 0x0000},
1044 {0x06, 0x0029}, {0x05, 0x0009},
1045};
1046
Joe Perches58aa68c2009-09-02 01:12:13 -03001047static struct i2c_reg_u16 mt9m001_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001048 {0x0d, 0x0001}, {0x0d, 0x0000}, {0x01, 0x000e},
1049 {0x02, 0x0014}, {0x03, 0x03c1}, {0x04, 0x0501},
1050 {0x05, 0x0083}, {0x06, 0x0006}, {0x0d, 0x0002},
1051 {0x0a, 0x0000}, {0x0c, 0x0000}, {0x11, 0x0000},
1052 {0x1e, 0x8000}, {0x5f, 0x8904}, {0x60, 0x0000},
1053 {0x61, 0x0000}, {0x62, 0x0498}, {0x63, 0x0000},
1054 {0x64, 0x0000}, {0x20, 0x111d}, {0x06, 0x00f2},
1055 {0x05, 0x0013}, {0x09, 0x10f2}, {0x07, 0x0003},
1056 {0x2b, 0x002a}, {0x2d, 0x002a}, {0x2c, 0x002a},
1057 {0x2e, 0x0029}, {0x07, 0x0002},
1058};
1059
Joe Perches58aa68c2009-09-02 01:12:13 -03001060static struct i2c_reg_u16 mt9m111_init[] = {
Brian Johnson13a84fa2009-09-03 19:07:13 -03001061 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
1062 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
Brian Johnson4d708a52009-09-03 19:10:15 -03001063 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
1064 {0xf0, 0x0000},
Brian Johnson26e744b2009-07-19 05:52:58 -03001065};
1066
Brian Johnsone99ac542010-03-16 13:58:28 -03001067static struct i2c_reg_u16 mt9m112_init[] = {
1068 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
1069 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
1070 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
1071 {0xf0, 0x0000},
1072};
1073
Joe Perches58aa68c2009-09-02 01:12:13 -03001074static struct i2c_reg_u8 hv7131r_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001075 {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
1076 {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
1077 {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
1078 {0x01, 0x08}, {0x01, 0x08}, {0x25, 0x07},
1079 {0x26, 0xc3}, {0x27, 0x50}, {0x30, 0x62},
1080 {0x31, 0x10}, {0x32, 0x06}, {0x33, 0x10},
1081 {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00},
1082 {0x23, 0x09}, {0x01, 0x08},
1083};
1084
Joe Perches58aa68c2009-09-02 01:12:13 -03001085static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
Brian Johnson26e744b2009-07-19 05:52:58 -03001086{
1087 struct usb_device *dev = gspca_dev->dev;
1088 int result;
1089 result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
1090 0x00,
1091 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
1092 reg,
1093 0x00,
1094 gspca_dev->usb_buf,
1095 length,
1096 500);
1097 if (unlikely(result < 0 || result != length)) {
1098 err("Read register failed 0x%02X", reg);
1099 return -EIO;
1100 }
1101 return 0;
1102}
1103
Joe Perches58aa68c2009-09-02 01:12:13 -03001104static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
1105 const u8 *buffer, int length)
Brian Johnson26e744b2009-07-19 05:52:58 -03001106{
1107 struct usb_device *dev = gspca_dev->dev;
1108 int result;
1109 memcpy(gspca_dev->usb_buf, buffer, length);
1110 result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
1111 0x08,
1112 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
1113 reg,
1114 0x00,
1115 gspca_dev->usb_buf,
1116 length,
1117 500);
1118 if (unlikely(result < 0 || result != length)) {
1119 err("Write register failed index 0x%02X", reg);
1120 return -EIO;
1121 }
1122 return 0;
1123}
1124
Joe Perches58aa68c2009-09-02 01:12:13 -03001125static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
Brian Johnson26e744b2009-07-19 05:52:58 -03001126{
1127 u8 data[1] = {value};
1128 return reg_w(gspca_dev, reg, data, 1);
1129}
1130
Joe Perches58aa68c2009-09-02 01:12:13 -03001131static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
Brian Johnson26e744b2009-07-19 05:52:58 -03001132{
1133 int i;
1134 reg_w(gspca_dev, 0x10c0, buffer, 8);
1135 for (i = 0; i < 5; i++) {
1136 reg_r(gspca_dev, 0x10c0, 1);
1137 if (gspca_dev->usb_buf[0] & 0x04) {
1138 if (gspca_dev->usb_buf[0] & 0x08)
Brian Johnson00b581e2009-07-23 05:55:43 -03001139 return -EIO;
Brian Johnson26e744b2009-07-19 05:52:58 -03001140 return 0;
1141 }
1142 msleep(1);
1143 }
Brian Johnson00b581e2009-07-23 05:55:43 -03001144 return -EIO;
Brian Johnson26e744b2009-07-19 05:52:58 -03001145}
1146
Joe Perches58aa68c2009-09-02 01:12:13 -03001147static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001148{
1149 struct sd *sd = (struct sd *) gspca_dev;
1150
1151 u8 row[8];
1152
1153 /*
1154 * from the point of view of the bridge, the length
1155 * includes the address
1156 */
1157 row[0] = 0x81 | (2 << 4);
1158 row[1] = sd->i2c_addr;
1159 row[2] = reg;
1160 row[3] = val;
1161 row[4] = 0x00;
1162 row[5] = 0x00;
1163 row[6] = 0x00;
1164 row[7] = 0x10;
1165
1166 return i2c_w(gspca_dev, row);
1167}
1168
Joe Perches58aa68c2009-09-02 01:12:13 -03001169static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001170{
1171 struct sd *sd = (struct sd *) gspca_dev;
1172 u8 row[8];
1173
1174 /*
1175 * from the point of view of the bridge, the length
1176 * includes the address
1177 */
1178 row[0] = 0x81 | (3 << 4);
1179 row[1] = sd->i2c_addr;
1180 row[2] = reg;
1181 row[3] = (val >> 8) & 0xff;
1182 row[4] = val & 0xff;
1183 row[5] = 0x00;
1184 row[6] = 0x00;
1185 row[7] = 0x10;
1186
1187 return i2c_w(gspca_dev, row);
1188}
1189
Jean-Francois Moine83955552009-12-12 06:58:01 -03001190static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001191{
1192 struct sd *sd = (struct sd *) gspca_dev;
1193 u8 row[8];
1194
Brian Johnson00b581e2009-07-23 05:55:43 -03001195 row[0] = 0x81 | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001196 row[1] = sd->i2c_addr;
1197 row[2] = reg;
1198 row[3] = 0;
1199 row[4] = 0;
1200 row[5] = 0;
1201 row[6] = 0;
1202 row[7] = 0x10;
Brian Johnson00b581e2009-07-23 05:55:43 -03001203 if (i2c_w(gspca_dev, row) < 0)
1204 return -EIO;
1205 row[0] = 0x81 | (1 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001206 row[2] = 0;
Brian Johnson00b581e2009-07-23 05:55:43 -03001207 if (i2c_w(gspca_dev, row) < 0)
1208 return -EIO;
1209 if (reg_r(gspca_dev, 0x10c2, 5) < 0)
1210 return -EIO;
1211 *val = gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001212 return 0;
1213}
1214
Jean-Francois Moine83955552009-12-12 06:58:01 -03001215static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001216{
1217 struct sd *sd = (struct sd *) gspca_dev;
1218 u8 row[8];
1219
Brian Johnson00b581e2009-07-23 05:55:43 -03001220 row[0] = 0x81 | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001221 row[1] = sd->i2c_addr;
1222 row[2] = reg;
1223 row[3] = 0;
1224 row[4] = 0;
1225 row[5] = 0;
1226 row[6] = 0;
1227 row[7] = 0x10;
Brian Johnson00b581e2009-07-23 05:55:43 -03001228 if (i2c_w(gspca_dev, row) < 0)
1229 return -EIO;
1230 row[0] = 0x81 | (2 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001231 row[2] = 0;
Brian Johnson00b581e2009-07-23 05:55:43 -03001232 if (i2c_w(gspca_dev, row) < 0)
1233 return -EIO;
1234 if (reg_r(gspca_dev, 0x10c2, 5) < 0)
1235 return -EIO;
1236 *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001237 return 0;
1238}
1239
1240static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
1241{
1242 int i;
1243 struct sd *sd = (struct sd *) gspca_dev;
1244
1245 for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001246 if (i2c_w1(gspca_dev, ov9650_init[i].reg,
1247 ov9650_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001248 err("OV9650 sensor initialization failed");
1249 return -ENODEV;
1250 }
1251 }
1252 sd->hstart = 1;
1253 sd->vstart = 7;
1254 return 0;
1255}
1256
1257static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
1258{
1259 int i;
1260 struct sd *sd = (struct sd *) gspca_dev;
1261
1262 for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001263 if (i2c_w1(gspca_dev, ov9655_init[i].reg,
1264 ov9655_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001265 err("OV9655 sensor initialization failed");
1266 return -ENODEV;
1267 }
1268 }
1269 /* disable hflip and vflip */
1270 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1271 sd->hstart = 0;
1272 sd->vstart = 7;
1273 return 0;
1274}
1275
1276static int soi968_init_sensor(struct gspca_dev *gspca_dev)
1277{
1278 int i;
1279 struct sd *sd = (struct sd *) gspca_dev;
1280
1281 for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001282 if (i2c_w1(gspca_dev, soi968_init[i].reg,
1283 soi968_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001284 err("SOI968 sensor initialization failed");
1285 return -ENODEV;
1286 }
1287 }
1288 /* disable hflip and vflip */
Brian Johnsone1430472009-09-02 12:39:41 -03001289 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << EXPOSURE_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001290 sd->hstart = 60;
1291 sd->vstart = 11;
1292 return 0;
1293}
1294
1295static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
1296{
1297 int i;
1298 struct sd *sd = (struct sd *) gspca_dev;
1299
1300 for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001301 if (i2c_w1(gspca_dev, ov7660_init[i].reg,
1302 ov7660_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001303 err("OV7660 sensor initialization failed");
1304 return -ENODEV;
1305 }
1306 }
1307 /* disable hflip and vflip */
1308 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1309 sd->hstart = 1;
1310 sd->vstart = 1;
1311 return 0;
1312}
1313
1314static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
1315{
1316 int i;
1317 struct sd *sd = (struct sd *) gspca_dev;
1318
1319 for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001320 if (i2c_w1(gspca_dev, ov7670_init[i].reg,
1321 ov7670_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001322 err("OV7670 sensor initialization failed");
1323 return -ENODEV;
1324 }
1325 }
1326 /* disable hflip and vflip */
1327 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1328 sd->hstart = 0;
1329 sd->vstart = 1;
1330 return 0;
1331}
1332
1333static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
1334{
1335 struct sd *sd = (struct sd *) gspca_dev;
1336 int i;
1337 u16 value;
1338 int ret;
1339
1340 sd->i2c_addr = 0x5d;
1341 ret = i2c_r2(gspca_dev, 0xff, &value);
1342 if ((ret == 0) && (value == 0x8243)) {
1343 for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001344 if (i2c_w2(gspca_dev, mt9v011_init[i].reg,
1345 mt9v011_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001346 err("MT9V011 sensor initialization failed");
1347 return -ENODEV;
1348 }
1349 }
1350 sd->hstart = 2;
1351 sd->vstart = 2;
1352 sd->sensor = SENSOR_MT9V011;
1353 info("MT9V011 sensor detected");
1354 return 0;
1355 }
1356
1357 sd->i2c_addr = 0x5c;
1358 i2c_w2(gspca_dev, 0x01, 0x0004);
1359 ret = i2c_r2(gspca_dev, 0xff, &value);
1360 if ((ret == 0) && (value == 0x823a)) {
1361 for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001362 if (i2c_w2(gspca_dev, mt9v111_init[i].reg,
1363 mt9v111_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001364 err("MT9V111 sensor initialization failed");
1365 return -ENODEV;
1366 }
1367 }
1368 sd->hstart = 2;
1369 sd->vstart = 2;
1370 sd->sensor = SENSOR_MT9V111;
1371 info("MT9V111 sensor detected");
1372 return 0;
1373 }
1374
1375 sd->i2c_addr = 0x5d;
1376 ret = i2c_w2(gspca_dev, 0xf0, 0x0000);
1377 if (ret < 0) {
1378 sd->i2c_addr = 0x48;
1379 i2c_w2(gspca_dev, 0xf0, 0x0000);
1380 }
1381 ret = i2c_r2(gspca_dev, 0x00, &value);
1382 if ((ret == 0) && (value == 0x1229)) {
1383 for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001384 if (i2c_w2(gspca_dev, mt9v112_init[i].reg,
1385 mt9v112_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001386 err("MT9V112 sensor initialization failed");
1387 return -ENODEV;
1388 }
1389 }
1390 sd->hstart = 6;
1391 sd->vstart = 2;
1392 sd->sensor = SENSOR_MT9V112;
1393 info("MT9V112 sensor detected");
1394 return 0;
1395 }
1396
1397 return -ENODEV;
1398}
1399
Brian Johnsone99ac542010-03-16 13:58:28 -03001400static int mt9m112_init_sensor(struct gspca_dev *gspca_dev)
1401{
1402 struct sd *sd = (struct sd *) gspca_dev;
1403 int i;
1404 for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) {
1405 if (i2c_w2(gspca_dev, mt9m112_init[i].reg,
1406 mt9m112_init[i].val) < 0) {
1407 err("MT9M112 sensor initialization failed");
1408 return -ENODEV;
1409 }
1410 }
1411 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
1412 sd->hstart = 0;
1413 sd->vstart = 2;
1414 return 0;
1415}
1416
Brian Johnson26e744b2009-07-19 05:52:58 -03001417static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
1418{
1419 struct sd *sd = (struct sd *) gspca_dev;
1420 int i;
1421 for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001422 if (i2c_w2(gspca_dev, mt9m111_init[i].reg,
1423 mt9m111_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001424 err("MT9M111 sensor initialization failed");
1425 return -ENODEV;
1426 }
1427 }
Brian Johnson13a84fa2009-09-03 19:07:13 -03001428 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001429 sd->hstart = 0;
1430 sd->vstart = 2;
1431 return 0;
1432}
1433
1434static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
1435{
1436 struct sd *sd = (struct sd *) gspca_dev;
1437 int i;
1438 for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001439 if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
1440 mt9m001_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001441 err("MT9M001 sensor initialization failed");
1442 return -ENODEV;
1443 }
1444 }
1445 /* disable hflip and vflip */
1446 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1447 sd->hstart = 2;
1448 sd->vstart = 2;
1449 return 0;
1450}
1451
1452static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
1453{
1454 int i;
1455 struct sd *sd = (struct sd *) gspca_dev;
1456
1457 for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001458 if (i2c_w1(gspca_dev, hv7131r_init[i].reg,
1459 hv7131r_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001460 err("HV7131R Sensor initialization failed");
1461 return -ENODEV;
1462 }
1463 }
1464 sd->hstart = 0;
1465 sd->vstart = 1;
1466 return 0;
1467}
1468
Brian Johnson26e744b2009-07-19 05:52:58 -03001469static int set_cmatrix(struct gspca_dev *gspca_dev)
1470{
1471 struct sd *sd = (struct sd *) gspca_dev;
1472 s32 hue_coord, hue_index = 180 + sd->hue;
1473 u8 cmatrix[21];
Brian Johnson26e744b2009-07-19 05:52:58 -03001474
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001475 memset(cmatrix, 0, sizeof cmatrix);
Brian Johnson26e744b2009-07-19 05:52:58 -03001476 cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26;
1477 cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
1478 cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
1479 cmatrix[18] = sd->brightness - 0x80;
1480
1481 hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001482 cmatrix[6] = hue_coord;
1483 cmatrix[7] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001484
1485 hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001486 cmatrix[8] = hue_coord;
1487 cmatrix[9] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001488
1489 hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001490 cmatrix[10] = hue_coord;
1491 cmatrix[11] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001492
1493 hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001494 cmatrix[12] = hue_coord;
1495 cmatrix[13] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001496
1497 hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001498 cmatrix[14] = hue_coord;
1499 cmatrix[15] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001500
1501 hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001502 cmatrix[16] = hue_coord;
1503 cmatrix[17] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001504
1505 return reg_w(gspca_dev, 0x10e1, cmatrix, 21);
1506}
1507
1508static int set_gamma(struct gspca_dev *gspca_dev)
1509{
1510 struct sd *sd = (struct sd *) gspca_dev;
1511 u8 gamma[17];
1512 u8 gval = sd->gamma * 0xb8 / 0x100;
1513
1514
1515 gamma[0] = 0x0a;
1516 gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
1517 gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8);
1518 gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8);
1519 gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8);
1520 gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8);
1521 gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8);
1522 gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8);
1523 gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8);
1524 gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8);
1525 gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8);
1526 gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8);
1527 gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8);
1528 gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8);
1529 gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8);
1530 gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
1531 gamma[16] = 0xf5;
1532
1533 return reg_w(gspca_dev, 0x1190, gamma, 17);
1534}
1535
1536static int set_redblue(struct gspca_dev *gspca_dev)
1537{
1538 struct sd *sd = (struct sd *) gspca_dev;
1539 reg_w1(gspca_dev, 0x118c, sd->red);
1540 reg_w1(gspca_dev, 0x118f, sd->blue);
1541 return 0;
1542}
1543
1544static int set_hvflip(struct gspca_dev *gspca_dev)
1545{
Brian Johnson7ddaac72010-03-16 13:58:27 -03001546 u8 value, tslb, hflip, vflip;
Brian Johnson26e744b2009-07-19 05:52:58 -03001547 u16 value2;
1548 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001549
1550 if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
1551 hflip = !sd->hflip;
1552 vflip = !sd->vflip;
1553 } else {
1554 hflip = sd->hflip;
1555 vflip = sd->vflip;
1556 }
1557
Brian Johnson26e744b2009-07-19 05:52:58 -03001558 switch (sd->sensor) {
1559 case SENSOR_OV9650:
1560 i2c_r1(gspca_dev, 0x1e, &value);
1561 value &= ~0x30;
1562 tslb = 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001563 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001564 value |= 0x20;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001565 if (vflip) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001566 value |= 0x10;
1567 tslb = 0x49;
1568 }
1569 i2c_w1(gspca_dev, 0x1e, value);
1570 i2c_w1(gspca_dev, 0x3a, tslb);
1571 break;
1572 case SENSOR_MT9V111:
1573 case SENSOR_MT9V011:
1574 i2c_r2(gspca_dev, 0x20, &value2);
1575 value2 &= ~0xc0a0;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001576 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001577 value2 |= 0x8080;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001578 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001579 value2 |= 0x4020;
1580 i2c_w2(gspca_dev, 0x20, value2);
1581 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001582 case SENSOR_MT9M112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001583 case SENSOR_MT9M111:
1584 case SENSOR_MT9V112:
1585 i2c_r2(gspca_dev, 0x20, &value2);
1586 value2 &= ~0x0003;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001587 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001588 value2 |= 0x0002;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001589 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001590 value2 |= 0x0001;
1591 i2c_w2(gspca_dev, 0x20, value2);
1592 break;
1593 case SENSOR_HV7131R:
1594 i2c_r1(gspca_dev, 0x01, &value);
1595 value &= ~0x03;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001596 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001597 value |= 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001598 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001599 value |= 0x02;
1600 i2c_w1(gspca_dev, 0x01, value);
1601 break;
1602 }
1603 return 0;
1604}
1605
1606static int set_exposure(struct gspca_dev *gspca_dev)
1607{
1608 struct sd *sd = (struct sd *) gspca_dev;
1609 u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
1610 switch (sd->sensor) {
1611 case SENSOR_OV7660:
1612 case SENSOR_OV7670:
Brian Johnson26e744b2009-07-19 05:52:58 -03001613 case SENSOR_OV9655:
1614 case SENSOR_OV9650:
1615 exp[0] |= (3 << 4);
1616 exp[2] = 0x2d;
1617 exp[3] = sd->exposure & 0xff;
1618 exp[4] = sd->exposure >> 8;
1619 break;
1620 case SENSOR_MT9M001:
Brian Johnson26e744b2009-07-19 05:52:58 -03001621 case SENSOR_MT9V112:
1622 case SENSOR_MT9V111:
1623 case SENSOR_MT9V011:
1624 exp[0] |= (3 << 4);
1625 exp[2] = 0x09;
1626 exp[3] = sd->exposure >> 8;
1627 exp[4] = sd->exposure & 0xff;
1628 break;
1629 case SENSOR_HV7131R:
1630 exp[0] |= (4 << 4);
1631 exp[2] = 0x25;
German Galkine10f7312010-03-07 06:19:02 -03001632 exp[3] = (sd->exposure >> 5) & 0xff;
1633 exp[4] = (sd->exposure << 3) & 0xff;
1634 exp[5] = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001635 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001636 default:
1637 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001638 }
1639 i2c_w(gspca_dev, exp);
1640 return 0;
1641}
1642
1643static int set_gain(struct gspca_dev *gspca_dev)
1644{
1645 struct sd *sd = (struct sd *) gspca_dev;
1646 u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
1647 switch (sd->sensor) {
1648 case SENSOR_OV7660:
1649 case SENSOR_OV7670:
1650 case SENSOR_SOI968:
1651 case SENSOR_OV9655:
1652 case SENSOR_OV9650:
1653 gain[0] |= (2 << 4);
1654 gain[3] = ov_gain[sd->gain];
1655 break;
1656 case SENSOR_MT9V011:
1657 case SENSOR_MT9V111:
1658 gain[0] |= (3 << 4);
1659 gain[2] = 0x35;
1660 gain[3] = micron1_gain[sd->gain] >> 8;
1661 gain[4] = micron1_gain[sd->gain] & 0xff;
1662 break;
1663 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001664 gain[0] |= (3 << 4);
1665 gain[2] = 0x2f;
1666 gain[3] = micron1_gain[sd->gain] >> 8;
1667 gain[4] = micron1_gain[sd->gain] & 0xff;
1668 break;
1669 case SENSOR_MT9M001:
1670 gain[0] |= (3 << 4);
1671 gain[2] = 0x2f;
1672 gain[3] = micron2_gain[sd->gain] >> 8;
1673 gain[4] = micron2_gain[sd->gain] & 0xff;
1674 break;
1675 case SENSOR_HV7131R:
1676 gain[0] |= (2 << 4);
1677 gain[2] = 0x30;
1678 gain[3] = hv7131r_gain[sd->gain];
1679 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001680 default:
1681 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001682 }
1683 i2c_w(gspca_dev, gain);
1684 return 0;
1685}
1686
1687static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val)
1688{
1689 struct sd *sd = (struct sd *) gspca_dev;
1690
1691 sd->brightness = val;
1692 if (gspca_dev->streaming)
1693 return set_cmatrix(gspca_dev);
1694 return 0;
1695}
1696
1697static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val)
1698{
1699 struct sd *sd = (struct sd *) gspca_dev;
1700 *val = sd->brightness;
1701 return 0;
1702}
1703
1704
1705static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val)
1706{
1707 struct sd *sd = (struct sd *) gspca_dev;
1708
1709 sd->contrast = val;
1710 if (gspca_dev->streaming)
1711 return set_cmatrix(gspca_dev);
1712 return 0;
1713}
1714
1715static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val)
1716{
1717 struct sd *sd = (struct sd *) gspca_dev;
1718 *val = sd->contrast;
1719 return 0;
1720}
1721
1722static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val)
1723{
1724 struct sd *sd = (struct sd *) gspca_dev;
1725
1726 sd->saturation = val;
1727 if (gspca_dev->streaming)
1728 return set_cmatrix(gspca_dev);
1729 return 0;
1730}
1731
1732static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val)
1733{
1734 struct sd *sd = (struct sd *) gspca_dev;
1735 *val = sd->saturation;
1736 return 0;
1737}
1738
1739static int sd_sethue(struct gspca_dev *gspca_dev, s32 val)
1740{
1741 struct sd *sd = (struct sd *) gspca_dev;
1742
1743 sd->hue = val;
1744 if (gspca_dev->streaming)
1745 return set_cmatrix(gspca_dev);
1746 return 0;
1747}
1748
1749static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val)
1750{
1751 struct sd *sd = (struct sd *) gspca_dev;
1752 *val = sd->hue;
1753 return 0;
1754}
1755
1756static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val)
1757{
1758 struct sd *sd = (struct sd *) gspca_dev;
1759
1760 sd->gamma = val;
1761 if (gspca_dev->streaming)
1762 return set_gamma(gspca_dev);
1763 return 0;
1764}
1765
1766static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val)
1767{
1768 struct sd *sd = (struct sd *) gspca_dev;
1769 *val = sd->gamma;
1770 return 0;
1771}
1772
1773static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val)
1774{
1775 struct sd *sd = (struct sd *) gspca_dev;
1776
1777 sd->red = val;
1778 if (gspca_dev->streaming)
1779 return set_redblue(gspca_dev);
1780 return 0;
1781}
1782
1783static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val)
1784{
1785 struct sd *sd = (struct sd *) gspca_dev;
1786 *val = sd->red;
1787 return 0;
1788}
1789
1790static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val)
1791{
1792 struct sd *sd = (struct sd *) gspca_dev;
1793
1794 sd->blue = val;
1795 if (gspca_dev->streaming)
1796 return set_redblue(gspca_dev);
1797 return 0;
1798}
1799
1800static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val)
1801{
1802 struct sd *sd = (struct sd *) gspca_dev;
1803 *val = sd->blue;
1804 return 0;
1805}
1806
1807static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val)
1808{
1809 struct sd *sd = (struct sd *) gspca_dev;
1810
1811 sd->hflip = val;
1812 if (gspca_dev->streaming)
1813 return set_hvflip(gspca_dev);
1814 return 0;
1815}
1816
1817static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val)
1818{
1819 struct sd *sd = (struct sd *) gspca_dev;
1820 *val = sd->hflip;
1821 return 0;
1822}
1823
1824static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val)
1825{
1826 struct sd *sd = (struct sd *) gspca_dev;
1827
1828 sd->vflip = val;
1829 if (gspca_dev->streaming)
1830 return set_hvflip(gspca_dev);
1831 return 0;
1832}
1833
1834static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val)
1835{
1836 struct sd *sd = (struct sd *) gspca_dev;
1837 *val = sd->vflip;
1838 return 0;
1839}
1840
1841static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val)
1842{
1843 struct sd *sd = (struct sd *) gspca_dev;
1844
1845 sd->exposure = val;
1846 if (gspca_dev->streaming)
1847 return set_exposure(gspca_dev);
1848 return 0;
1849}
1850
1851static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val)
1852{
1853 struct sd *sd = (struct sd *) gspca_dev;
1854 *val = sd->exposure;
1855 return 0;
1856}
1857
1858static int sd_setgain(struct gspca_dev *gspca_dev, s32 val)
1859{
1860 struct sd *sd = (struct sd *) gspca_dev;
1861
1862 sd->gain = val;
1863 if (gspca_dev->streaming)
1864 return set_gain(gspca_dev);
1865 return 0;
1866}
1867
1868static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val)
1869{
1870 struct sd *sd = (struct sd *) gspca_dev;
1871 *val = sd->gain;
1872 return 0;
1873}
1874
1875static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val)
1876{
1877 struct sd *sd = (struct sd *) gspca_dev;
1878 sd->auto_exposure = val;
1879 return 0;
1880}
1881
1882static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val)
1883{
1884 struct sd *sd = (struct sd *) gspca_dev;
1885 *val = sd->auto_exposure;
1886 return 0;
1887}
1888
1889#ifdef CONFIG_VIDEO_ADV_DEBUG
1890static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
1891 struct v4l2_dbg_register *reg)
1892{
1893 struct sd *sd = (struct sd *) gspca_dev;
1894 switch (reg->match.type) {
1895 case V4L2_CHIP_MATCH_HOST:
1896 if (reg->match.addr != 0)
1897 return -EINVAL;
1898 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1899 return -EINVAL;
1900 if (reg_r(gspca_dev, reg->reg, 1) < 0)
1901 return -EINVAL;
1902 reg->val = gspca_dev->usb_buf[0];
1903 return 0;
1904 case V4L2_CHIP_MATCH_I2C_ADDR:
1905 if (reg->match.addr != sd->i2c_addr)
1906 return -EINVAL;
1907 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001908 sd->sensor <= SENSOR_MT9M112) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001909 if (i2c_r2(gspca_dev, reg->reg, (u16 *)&reg->val) < 0)
1910 return -EINVAL;
1911 } else {
1912 if (i2c_r1(gspca_dev, reg->reg, (u8 *)&reg->val) < 0)
1913 return -EINVAL;
1914 }
1915 return 0;
1916 }
1917 return -EINVAL;
1918}
1919
1920static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
1921 struct v4l2_dbg_register *reg)
1922{
1923 struct sd *sd = (struct sd *) gspca_dev;
1924 switch (reg->match.type) {
1925 case V4L2_CHIP_MATCH_HOST:
1926 if (reg->match.addr != 0)
1927 return -EINVAL;
1928 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1929 return -EINVAL;
1930 if (reg_w1(gspca_dev, reg->reg, reg->val) < 0)
1931 return -EINVAL;
1932 return 0;
1933 case V4L2_CHIP_MATCH_I2C_ADDR:
1934 if (reg->match.addr != sd->i2c_addr)
1935 return -EINVAL;
1936 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001937 sd->sensor <= SENSOR_MT9M112) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001938 if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0)
1939 return -EINVAL;
1940 } else {
1941 if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0)
1942 return -EINVAL;
1943 }
1944 return 0;
1945 }
1946 return -EINVAL;
1947}
1948#endif
1949
1950static int sd_chip_ident(struct gspca_dev *gspca_dev,
1951 struct v4l2_dbg_chip_ident *chip)
1952{
1953 struct sd *sd = (struct sd *) gspca_dev;
1954
1955 switch (chip->match.type) {
1956 case V4L2_CHIP_MATCH_HOST:
1957 if (chip->match.addr != 0)
1958 return -EINVAL;
1959 chip->revision = 0;
1960 chip->ident = V4L2_IDENT_SN9C20X;
1961 return 0;
1962 case V4L2_CHIP_MATCH_I2C_ADDR:
1963 if (chip->match.addr != sd->i2c_addr)
1964 return -EINVAL;
1965 chip->revision = 0;
1966 chip->ident = i2c_ident[sd->sensor];
1967 return 0;
1968 }
1969 return -EINVAL;
1970}
1971
1972static int sd_config(struct gspca_dev *gspca_dev,
1973 const struct usb_device_id *id)
1974{
1975 struct sd *sd = (struct sd *) gspca_dev;
1976 struct cam *cam;
1977
1978 cam = &gspca_dev->cam;
1979
1980 sd->sensor = (id->driver_info >> 8) & 0xff;
1981 sd->i2c_addr = id->driver_info & 0xff;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03001982 sd->flags = (id->driver_info >> 16) & 0xff;
Brian Johnson26e744b2009-07-19 05:52:58 -03001983
1984 switch (sd->sensor) {
Brian Johnsone99ac542010-03-16 13:58:28 -03001985 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03001986 case SENSOR_MT9M111:
Brian Johnson26e744b2009-07-19 05:52:58 -03001987 case SENSOR_OV9650:
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001988 case SENSOR_SOI968:
Brian Johnson26e744b2009-07-19 05:52:58 -03001989 cam->cam_mode = sxga_mode;
1990 cam->nmodes = ARRAY_SIZE(sxga_mode);
1991 break;
1992 default:
1993 cam->cam_mode = vga_mode;
1994 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001995 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001996 }
1997
1998 sd->old_step = 0;
1999 sd->older_step = 0;
2000 sd->exposure_step = 16;
2001
2002 sd->brightness = BRIGHTNESS_DEFAULT;
2003 sd->contrast = CONTRAST_DEFAULT;
2004 sd->saturation = SATURATION_DEFAULT;
2005 sd->hue = HUE_DEFAULT;
2006 sd->gamma = GAMMA_DEFAULT;
2007 sd->red = RED_DEFAULT;
2008 sd->blue = BLUE_DEFAULT;
2009
2010 sd->hflip = HFLIP_DEFAULT;
2011 sd->vflip = VFLIP_DEFAULT;
2012 sd->exposure = EXPOSURE_DEFAULT;
2013 sd->gain = GAIN_DEFAULT;
2014 sd->auto_exposure = AUTO_EXPOSURE_DEFAULT;
2015
2016 sd->quality = 95;
2017
Brian Johnson26e744b2009-07-19 05:52:58 -03002018 return 0;
2019}
2020
2021static int sd_init(struct gspca_dev *gspca_dev)
2022{
2023 struct sd *sd = (struct sd *) gspca_dev;
2024 int i;
2025 u8 value;
2026 u8 i2c_init[9] =
2027 {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03};
2028
2029 for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
2030 value = bridge_init[i][1];
2031 if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) {
2032 err("Device initialization failed");
2033 return -ENODEV;
2034 }
2035 }
2036
Brian Johnson0c045eb2010-03-16 13:58:27 -03002037 if (sd->flags & LED_REVERSE)
2038 reg_w1(gspca_dev, 0x1006, 0x00);
2039 else
2040 reg_w1(gspca_dev, 0x1006, 0x20);
2041
Brian Johnson26e744b2009-07-19 05:52:58 -03002042 if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
2043 err("Device initialization failed");
2044 return -ENODEV;
2045 }
2046
2047 switch (sd->sensor) {
2048 case SENSOR_OV9650:
2049 if (ov9650_init_sensor(gspca_dev) < 0)
2050 return -ENODEV;
2051 info("OV9650 sensor detected");
2052 break;
2053 case SENSOR_OV9655:
2054 if (ov9655_init_sensor(gspca_dev) < 0)
2055 return -ENODEV;
2056 info("OV9655 sensor detected");
2057 break;
2058 case SENSOR_SOI968:
2059 if (soi968_init_sensor(gspca_dev) < 0)
2060 return -ENODEV;
2061 info("SOI968 sensor detected");
2062 break;
2063 case SENSOR_OV7660:
2064 if (ov7660_init_sensor(gspca_dev) < 0)
2065 return -ENODEV;
2066 info("OV7660 sensor detected");
2067 break;
2068 case SENSOR_OV7670:
2069 if (ov7670_init_sensor(gspca_dev) < 0)
2070 return -ENODEV;
2071 info("OV7670 sensor detected");
2072 break;
2073 case SENSOR_MT9VPRB:
2074 if (mt9v_init_sensor(gspca_dev) < 0)
2075 return -ENODEV;
2076 break;
2077 case SENSOR_MT9M111:
2078 if (mt9m111_init_sensor(gspca_dev) < 0)
2079 return -ENODEV;
2080 info("MT9M111 sensor detected");
2081 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03002082 case SENSOR_MT9M112:
2083 if (mt9m112_init_sensor(gspca_dev) < 0)
2084 return -ENODEV;
2085 info("MT9M112 sensor detected");
2086 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002087 case SENSOR_MT9M001:
2088 if (mt9m001_init_sensor(gspca_dev) < 0)
2089 return -ENODEV;
2090 info("MT9M001 sensor detected");
2091 break;
2092 case SENSOR_HV7131R:
2093 if (hv7131r_init_sensor(gspca_dev) < 0)
2094 return -ENODEV;
2095 info("HV7131R sensor detected");
2096 break;
2097 default:
2098 info("Unsupported Sensor");
2099 return -ENODEV;
2100 }
2101
2102 return 0;
2103}
2104
2105static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
2106{
2107 struct sd *sd = (struct sd *) gspca_dev;
2108 u8 value;
2109 switch (sd->sensor) {
Brian Johnsone8b7acc2009-09-02 13:14:41 -03002110 case SENSOR_SOI968:
2111 if (mode & MODE_SXGA) {
2112 i2c_w1(gspca_dev, 0x17, 0x1d);
2113 i2c_w1(gspca_dev, 0x18, 0xbd);
2114 i2c_w1(gspca_dev, 0x19, 0x01);
2115 i2c_w1(gspca_dev, 0x1a, 0x81);
2116 i2c_w1(gspca_dev, 0x12, 0x00);
2117 sd->hstart = 140;
2118 sd->vstart = 19;
2119 } else {
2120 i2c_w1(gspca_dev, 0x17, 0x13);
2121 i2c_w1(gspca_dev, 0x18, 0x63);
2122 i2c_w1(gspca_dev, 0x19, 0x01);
2123 i2c_w1(gspca_dev, 0x1a, 0x79);
2124 i2c_w1(gspca_dev, 0x12, 0x40);
2125 sd->hstart = 60;
2126 sd->vstart = 11;
2127 }
2128 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002129 case SENSOR_OV9650:
2130 if (mode & MODE_SXGA) {
2131 i2c_w1(gspca_dev, 0x17, 0x1b);
2132 i2c_w1(gspca_dev, 0x18, 0xbc);
2133 i2c_w1(gspca_dev, 0x19, 0x01);
2134 i2c_w1(gspca_dev, 0x1a, 0x82);
2135 i2c_r1(gspca_dev, 0x12, &value);
2136 i2c_w1(gspca_dev, 0x12, value & 0x07);
2137 } else {
2138 i2c_w1(gspca_dev, 0x17, 0x24);
2139 i2c_w1(gspca_dev, 0x18, 0xc5);
2140 i2c_w1(gspca_dev, 0x19, 0x00);
2141 i2c_w1(gspca_dev, 0x1a, 0x3c);
2142 i2c_r1(gspca_dev, 0x12, &value);
2143 i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
2144 }
2145 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03002146 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03002147 case SENSOR_MT9M111:
2148 if (mode & MODE_SXGA) {
2149 i2c_w2(gspca_dev, 0xf0, 0x0002);
2150 i2c_w2(gspca_dev, 0xc8, 0x970b);
2151 i2c_w2(gspca_dev, 0xf0, 0x0000);
2152 } else {
2153 i2c_w2(gspca_dev, 0xf0, 0x0002);
2154 i2c_w2(gspca_dev, 0xc8, 0x8000);
2155 i2c_w2(gspca_dev, 0xf0, 0x0000);
2156 }
2157 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002158 }
2159}
2160
2161#define HW_WIN(mode, hstart, vstart) \
Jean-Francois Moine83955552009-12-12 06:58:01 -03002162((const u8 []){hstart, 0, vstart, 0, \
Brian Johnson26e744b2009-07-19 05:52:58 -03002163(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
2164(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)})
2165
2166#define CLR_WIN(width, height) \
2167((const u8 [])\
2168{0, width >> 2, 0, height >> 1,\
2169((width >> 10) & 0x01) | ((height >> 8) & 0x6)})
2170
2171static int sd_start(struct gspca_dev *gspca_dev)
2172{
2173 struct sd *sd = (struct sd *) gspca_dev;
2174 int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
2175 int width = gspca_dev->width;
2176 int height = gspca_dev->height;
2177 u8 fmt, scale = 0;
2178
2179 sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
2180 if (sd->jpeg_hdr == NULL)
2181 return -ENOMEM;
2182
2183 jpeg_define(sd->jpeg_hdr, height, width,
2184 0x21);
2185 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
2186
2187 if (mode & MODE_RAW)
2188 fmt = 0x2d;
2189 else if (mode & MODE_JPEG)
2190 fmt = 0x2c;
2191 else
2192 fmt = 0x2f;
2193
2194 switch (mode & 0x0f) {
2195 case 3:
2196 scale = 0xc0;
2197 info("Set 1280x1024");
2198 break;
2199 case 2:
2200 scale = 0x80;
2201 info("Set 640x480");
2202 break;
2203 case 1:
2204 scale = 0x90;
2205 info("Set 320x240");
2206 break;
2207 case 0:
2208 scale = 0xa0;
2209 info("Set 160x120");
2210 break;
2211 }
2212
2213 configure_sensor_output(gspca_dev, mode);
2214 reg_w(gspca_dev, 0x1100, sd->jpeg_hdr + JPEG_QT0_OFFSET, 64);
2215 reg_w(gspca_dev, 0x1140, sd->jpeg_hdr + JPEG_QT1_OFFSET, 64);
2216 reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
2217 reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
2218 reg_w1(gspca_dev, 0x1189, scale);
2219 reg_w1(gspca_dev, 0x10e0, fmt);
2220
2221 set_cmatrix(gspca_dev);
2222 set_gamma(gspca_dev);
2223 set_redblue(gspca_dev);
2224 set_gain(gspca_dev);
2225 set_exposure(gspca_dev);
2226 set_hvflip(gspca_dev);
2227
Brian Johnson0c045eb2010-03-16 13:58:27 -03002228 reg_w1(gspca_dev, 0x1007, 0x20);
2229
Brian Johnson26e744b2009-07-19 05:52:58 -03002230 reg_r(gspca_dev, 0x1061, 1);
2231 reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02);
2232 return 0;
2233}
2234
2235static void sd_stopN(struct gspca_dev *gspca_dev)
2236{
Brian Johnson0c045eb2010-03-16 13:58:27 -03002237 reg_w1(gspca_dev, 0x1007, 0x00);
2238
Brian Johnson26e744b2009-07-19 05:52:58 -03002239 reg_r(gspca_dev, 0x1061, 1);
2240 reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
2241}
2242
2243static void sd_stop0(struct gspca_dev *gspca_dev)
2244{
2245 struct sd *sd = (struct sd *) gspca_dev;
2246 kfree(sd->jpeg_hdr);
2247}
2248
Brian Johnsone1430472009-09-02 12:39:41 -03002249static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
Brian Johnson26e744b2009-07-19 05:52:58 -03002250{
2251 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnsone1430472009-09-02 12:39:41 -03002252 s16 new_exp;
Brian Johnson26e744b2009-07-19 05:52:58 -03002253
2254 /*
2255 * some hardcoded values are present
2256 * like those for maximal/minimal exposure
2257 * and exposure steps
2258 */
2259 if (avg_lum < MIN_AVG_LUM) {
2260 if (sd->exposure > 0x1770)
2261 return;
2262
2263 new_exp = sd->exposure + sd->exposure_step;
2264 if (new_exp > 0x1770)
2265 new_exp = 0x1770;
2266 if (new_exp < 0x10)
2267 new_exp = 0x10;
2268 sd->exposure = new_exp;
2269 set_exposure(gspca_dev);
2270
2271 sd->older_step = sd->old_step;
2272 sd->old_step = 1;
2273
2274 if (sd->old_step ^ sd->older_step)
2275 sd->exposure_step /= 2;
2276 else
2277 sd->exposure_step += 2;
2278 }
2279 if (avg_lum > MAX_AVG_LUM) {
2280 if (sd->exposure < 0x10)
2281 return;
2282 new_exp = sd->exposure - sd->exposure_step;
2283 if (new_exp > 0x1700)
2284 new_exp = 0x1770;
2285 if (new_exp < 0x10)
2286 new_exp = 0x10;
2287 sd->exposure = new_exp;
2288 set_exposure(gspca_dev);
2289 sd->older_step = sd->old_step;
2290 sd->old_step = 0;
2291
2292 if (sd->old_step ^ sd->older_step)
2293 sd->exposure_step /= 2;
2294 else
2295 sd->exposure_step += 2;
2296 }
2297}
2298
Brian Johnsone1430472009-09-02 12:39:41 -03002299static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
2300{
2301 struct sd *sd = (struct sd *) gspca_dev;
2302
2303 if (avg_lum < MIN_AVG_LUM) {
2304 if (sd->gain + 1 <= 28) {
2305 sd->gain++;
2306 set_gain(gspca_dev);
2307 }
2308 }
2309 if (avg_lum > MAX_AVG_LUM) {
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03002310 if (sd->gain > 0) {
Brian Johnsone1430472009-09-02 12:39:41 -03002311 sd->gain--;
2312 set_gain(gspca_dev);
2313 }
2314 }
2315}
2316
2317static void sd_dqcallback(struct gspca_dev *gspca_dev)
2318{
2319 struct sd *sd = (struct sd *) gspca_dev;
2320 int avg_lum;
2321
2322 if (!sd->auto_exposure)
2323 return;
2324
2325 avg_lum = atomic_read(&sd->avg_lum);
2326 if (sd->sensor == SENSOR_SOI968)
2327 do_autogain(gspca_dev, avg_lum);
2328 else
2329 do_autoexposure(gspca_dev, avg_lum);
2330}
2331
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002332#ifdef CONFIG_INPUT
2333static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
2334 u8 *data, /* interrupt packet */
2335 int len) /* interrupt packet length */
2336{
2337 struct sd *sd = (struct sd *) gspca_dev;
2338 int ret = -EINVAL;
2339 if (sd->flags & HAS_BUTTON && len == 1) {
2340 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
2341 input_sync(gspca_dev->input_dev);
2342 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
2343 input_sync(gspca_dev->input_dev);
2344 ret = 0;
2345 }
2346 return ret;
2347}
2348#endif
2349
Brian Johnson26e744b2009-07-19 05:52:58 -03002350static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Brian Johnson26e744b2009-07-19 05:52:58 -03002351 u8 *data, /* isoc packet */
2352 int len) /* iso packet length */
2353{
2354 struct sd *sd = (struct sd *) gspca_dev;
2355 int avg_lum;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03002356 static u8 frame_header[] =
Brian Johnson26e744b2009-07-19 05:52:58 -03002357 {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
2358 if (len == 64 && memcmp(data, frame_header, 6) == 0) {
2359 avg_lum = ((data[35] >> 2) & 3) |
2360 (data[20] << 2) |
2361 (data[19] << 10);
2362 avg_lum += ((data[35] >> 4) & 3) |
2363 (data[22] << 2) |
2364 (data[21] << 10);
2365 avg_lum += ((data[35] >> 6) & 3) |
2366 (data[24] << 2) |
2367 (data[23] << 10);
2368 avg_lum += (data[36] & 3) |
2369 (data[26] << 2) |
2370 (data[25] << 10);
2371 avg_lum += ((data[36] >> 2) & 3) |
2372 (data[28] << 2) |
2373 (data[27] << 10);
2374 avg_lum += ((data[36] >> 4) & 3) |
2375 (data[30] << 2) |
2376 (data[29] << 10);
2377 avg_lum += ((data[36] >> 6) & 3) |
2378 (data[32] << 2) |
2379 (data[31] << 10);
2380 avg_lum += ((data[44] >> 4) & 3) |
2381 (data[34] << 2) |
2382 (data[33] << 10);
2383 avg_lum >>= 9;
2384 atomic_set(&sd->avg_lum, avg_lum);
2385 gspca_frame_add(gspca_dev, LAST_PACKET,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002386 data, len);
Brian Johnson26e744b2009-07-19 05:52:58 -03002387 return;
2388 }
2389 if (gspca_dev->last_packet_type == LAST_PACKET) {
2390 if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv
2391 & MODE_JPEG) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002392 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002393 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002394 gspca_frame_add(gspca_dev, INTER_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002395 data, len);
2396 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002397 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002398 data, len);
2399 }
2400 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002401 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Brian Johnson26e744b2009-07-19 05:52:58 -03002402 }
2403}
2404
2405/* sub-driver description */
2406static const struct sd_desc sd_desc = {
2407 .name = MODULE_NAME,
2408 .ctrls = sd_ctrls,
2409 .nctrls = ARRAY_SIZE(sd_ctrls),
2410 .config = sd_config,
2411 .init = sd_init,
2412 .start = sd_start,
2413 .stopN = sd_stopN,
2414 .stop0 = sd_stop0,
2415 .pkt_scan = sd_pkt_scan,
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002416#ifdef CONFIG_INPUT
2417 .int_pkt_scan = sd_int_pkt_scan,
2418#endif
Brian Johnsone1430472009-09-02 12:39:41 -03002419 .dq_callback = sd_dqcallback,
Brian Johnson26e744b2009-07-19 05:52:58 -03002420#ifdef CONFIG_VIDEO_ADV_DEBUG
2421 .set_register = sd_dbg_s_register,
2422 .get_register = sd_dbg_g_register,
2423#endif
2424 .get_chip_ident = sd_chip_ident,
2425};
2426
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002427#define SN9C20X(sensor, i2c_addr, flags) \
Brian Johnson0c045eb2010-03-16 13:58:27 -03002428 .driver_info = ((flags & 0xff) << 16) \
Brian Johnson26e744b2009-07-19 05:52:58 -03002429 | (SENSOR_ ## sensor << 8) \
2430 | (i2c_addr)
2431
2432static const __devinitdata struct usb_device_id device_table[] = {
2433 {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
2434 {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
2435 {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002436 {USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson0c045eb2010-03-16 13:58:27 -03002437 {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30,
2438 (HAS_BUTTON | LED_REVERSE))},
Brian Johnson7ddaac72010-03-16 13:58:27 -03002439 {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30, FLIP_DETECT)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002440 {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
2441 {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
2442 {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
2443 {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)},
2444 {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, 0)},
2445 {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)},
2446 {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)},
2447 {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
2448 {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)},
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002449 {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, HAS_BUTTON)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002450 {USB_DEVICE(0x0c45, 0x628c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002451 {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)},
2452 {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
2453 {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
2454 {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
2455 {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)},
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002456 {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, HAS_BUTTON)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002457 {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
2458 {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
2459 {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
2460 {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002461 {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)},
2462 {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002463 {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
2464 {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)},
2465 {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)},
2466 {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)},
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002467 {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, HAS_BUTTON)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002468 {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)},
2469 {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)},
2470 {}
2471};
2472MODULE_DEVICE_TABLE(usb, device_table);
2473
2474/* -- device connect -- */
2475static int sd_probe(struct usb_interface *intf,
2476 const struct usb_device_id *id)
2477{
2478 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
2479 THIS_MODULE);
2480}
2481
Brian Johnson26e744b2009-07-19 05:52:58 -03002482static struct usb_driver sd_driver = {
2483 .name = MODULE_NAME,
2484 .id_table = device_table,
2485 .probe = sd_probe,
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002486 .disconnect = gspca_disconnect,
Brian Johnson26e744b2009-07-19 05:52:58 -03002487#ifdef CONFIG_PM
2488 .suspend = gspca_suspend,
2489 .resume = gspca_resume,
2490 .reset_resume = gspca_resume,
2491#endif
2492};
2493
2494/* -- module insert / remove -- */
2495static int __init sd_mod_init(void)
2496{
2497 int ret;
2498 ret = usb_register(&sd_driver);
2499 if (ret < 0)
2500 return ret;
2501 info("registered");
2502 return 0;
2503}
2504static void __exit sd_mod_exit(void)
2505{
2506 usb_deregister(&sd_driver);
2507 info("deregistered");
2508}
2509
2510module_init(sd_mod_init);
2511module_exit(sd_mod_exit);