blob: 57673891c2c2ce27c9c907c59fd380603c3aaf57 [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
Brian Johnson26e744b2009-07-19 05:52:58 -030021#include <linux/input.h>
Brian Johnson26e744b2009-07-19 05:52:58 -030022
Mauro Carvalho Chehabc15b95e2009-07-19 18:03:23 -030023#include "gspca.h"
24#include "jpeg.h"
25
26#include <media/v4l2-chip-ident.h>
Brian Johnson7ddaac72010-03-16 13:58:27 -030027#include <linux/dmi.h>
Mauro Carvalho Chehabc15b95e2009-07-19 18:03:23 -030028
Brian Johnson26e744b2009-07-19 05:52:58 -030029MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, "
30 "microdia project <microdia@googlegroups.com>");
31MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver");
32MODULE_LICENSE("GPL");
33
34#define MODULE_NAME "sn9c20x"
35
36#define MODE_RAW 0x10
37#define MODE_JPEG 0x20
38#define MODE_SXGA 0x80
39
40#define SENSOR_OV9650 0
41#define SENSOR_OV9655 1
42#define SENSOR_SOI968 2
43#define SENSOR_OV7660 3
44#define SENSOR_OV7670 4
45#define SENSOR_MT9V011 5
46#define SENSOR_MT9V111 6
47#define SENSOR_MT9V112 7
48#define SENSOR_MT9M001 8
49#define SENSOR_MT9M111 9
Brian Johnsone99ac542010-03-16 13:58:28 -030050#define SENSOR_MT9M112 10
51#define SENSOR_HV7131R 11
Brian Johnson26e744b2009-07-19 05:52:58 -030052#define SENSOR_MT9VPRB 20
53
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030054/* camera flags */
Brian Johnson33ddc162010-04-18 21:42:40 -030055#define HAS_NO_BUTTON 0x1
Brian Johnson0c045eb2010-03-16 13:58:27 -030056#define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */
Brian Johnson7ddaac72010-03-16 13:58:27 -030057#define FLIP_DETECT 0x4
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030058
Brian Johnson26e744b2009-07-19 05:52:58 -030059/* specific webcam descriptor */
60struct sd {
61 struct gspca_dev gspca_dev;
62
63#define MIN_AVG_LUM 80
64#define MAX_AVG_LUM 130
65 atomic_t avg_lum;
66 u8 old_step;
67 u8 older_step;
68 u8 exposure_step;
69
70 u8 brightness;
71 u8 contrast;
72 u8 saturation;
73 s16 hue;
74 u8 gamma;
75 u8 red;
76 u8 blue;
77
78 u8 hflip;
79 u8 vflip;
80 u8 gain;
81 u16 exposure;
82 u8 auto_exposure;
83
84 u8 i2c_addr;
85 u8 sensor;
86 u8 hstart;
87 u8 vstart;
88
Jean-François Moine9a731a32010-06-04 05:26:42 -030089 u8 jpeg_hdr[JPEG_HDR_SZ];
Brian Johnson26e744b2009-07-19 05:52:58 -030090 u8 quality;
91
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030092 u8 flags;
Brian Johnson26e744b2009-07-19 05:52:58 -030093};
94
Joe Perches58aa68c2009-09-02 01:12:13 -030095struct i2c_reg_u8 {
96 u8 reg;
97 u8 val;
98};
99
100struct i2c_reg_u16 {
101 u8 reg;
102 u16 val;
103};
104
Brian Johnson26e744b2009-07-19 05:52:58 -0300105static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val);
106static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val);
107static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val);
108static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val);
109static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val);
110static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val);
111static int sd_sethue(struct gspca_dev *gspca_dev, s32 val);
112static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val);
113static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val);
114static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val);
115static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val);
116static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val);
117static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val);
118static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val);
119static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val);
120static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val);
121static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val);
122static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val);
123static int sd_setgain(struct gspca_dev *gspca_dev, s32 val);
124static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val);
125static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val);
126static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val);
127static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val);
128static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val);
129
Brian Johnson7ddaac72010-03-16 13:58:27 -0300130static const struct dmi_system_id flip_dmi_table[] = {
131 {
132 .ident = "MSI MS-1034",
133 .matches = {
134 DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."),
135 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1034"),
136 DMI_MATCH(DMI_PRODUCT_VERSION, "0341")
137 }
138 },
139 {
140 .ident = "MSI MS-1632",
141 .matches = {
142 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
143 DMI_MATCH(DMI_BOARD_NAME, "MS-1632")
144 }
145 },
Brian Johnsone077f862010-04-05 20:52:52 -0300146 {
Brian Johnson5d26ed92010-04-10 02:12:46 -0300147 .ident = "MSI MS-1635X",
148 .matches = {
149 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
150 DMI_MATCH(DMI_BOARD_NAME, "MS-1635X")
151 }
152 },
153 {
Brian Johnsone077f862010-04-05 20:52:52 -0300154 .ident = "ASUSTeK W7J",
155 .matches = {
156 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
157 DMI_MATCH(DMI_BOARD_NAME, "W7J ")
158 }
159 },
Brian Johnson7ddaac72010-03-16 13:58:27 -0300160 {}
161};
162
Marton Nemeth7e64dc42009-12-30 09:12:41 -0300163static const struct ctrl sd_ctrls[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300164 {
165#define BRIGHTNESS_IDX 0
166 {
167 .id = V4L2_CID_BRIGHTNESS,
168 .type = V4L2_CTRL_TYPE_INTEGER,
169 .name = "Brightness",
170 .minimum = 0,
171 .maximum = 0xff,
172 .step = 1,
173#define BRIGHTNESS_DEFAULT 0x7f
174 .default_value = BRIGHTNESS_DEFAULT,
175 },
176 .set = sd_setbrightness,
177 .get = sd_getbrightness,
178 },
179 {
180#define CONTRAST_IDX 1
181 {
182 .id = V4L2_CID_CONTRAST,
183 .type = V4L2_CTRL_TYPE_INTEGER,
184 .name = "Contrast",
185 .minimum = 0,
186 .maximum = 0xff,
187 .step = 1,
188#define CONTRAST_DEFAULT 0x7f
189 .default_value = CONTRAST_DEFAULT,
190 },
191 .set = sd_setcontrast,
192 .get = sd_getcontrast,
193 },
194 {
195#define SATURATION_IDX 2
196 {
197 .id = V4L2_CID_SATURATION,
198 .type = V4L2_CTRL_TYPE_INTEGER,
199 .name = "Saturation",
200 .minimum = 0,
201 .maximum = 0xff,
202 .step = 1,
203#define SATURATION_DEFAULT 0x7f
204 .default_value = SATURATION_DEFAULT,
205 },
206 .set = sd_setsaturation,
207 .get = sd_getsaturation,
208 },
209 {
210#define HUE_IDX 3
211 {
212 .id = V4L2_CID_HUE,
213 .type = V4L2_CTRL_TYPE_INTEGER,
214 .name = "Hue",
215 .minimum = -180,
216 .maximum = 180,
217 .step = 1,
218#define HUE_DEFAULT 0
219 .default_value = HUE_DEFAULT,
220 },
221 .set = sd_sethue,
222 .get = sd_gethue,
223 },
224 {
225#define GAMMA_IDX 4
226 {
227 .id = V4L2_CID_GAMMA,
228 .type = V4L2_CTRL_TYPE_INTEGER,
229 .name = "Gamma",
230 .minimum = 0,
231 .maximum = 0xff,
232 .step = 1,
233#define GAMMA_DEFAULT 0x10
234 .default_value = GAMMA_DEFAULT,
235 },
236 .set = sd_setgamma,
237 .get = sd_getgamma,
238 },
239 {
240#define BLUE_IDX 5
241 {
242 .id = V4L2_CID_BLUE_BALANCE,
243 .type = V4L2_CTRL_TYPE_INTEGER,
244 .name = "Blue Balance",
245 .minimum = 0,
246 .maximum = 0x7f,
247 .step = 1,
248#define BLUE_DEFAULT 0x28
249 .default_value = BLUE_DEFAULT,
250 },
251 .set = sd_setbluebalance,
252 .get = sd_getbluebalance,
253 },
254 {
255#define RED_IDX 6
256 {
257 .id = V4L2_CID_RED_BALANCE,
258 .type = V4L2_CTRL_TYPE_INTEGER,
259 .name = "Red Balance",
260 .minimum = 0,
261 .maximum = 0x7f,
262 .step = 1,
263#define RED_DEFAULT 0x28
264 .default_value = RED_DEFAULT,
265 },
266 .set = sd_setredbalance,
267 .get = sd_getredbalance,
268 },
269 {
270#define HFLIP_IDX 7
271 {
272 .id = V4L2_CID_HFLIP,
273 .type = V4L2_CTRL_TYPE_BOOLEAN,
274 .name = "Horizontal Flip",
275 .minimum = 0,
276 .maximum = 1,
277 .step = 1,
278#define HFLIP_DEFAULT 0
279 .default_value = HFLIP_DEFAULT,
280 },
281 .set = sd_sethflip,
282 .get = sd_gethflip,
283 },
284 {
285#define VFLIP_IDX 8
286 {
287 .id = V4L2_CID_VFLIP,
288 .type = V4L2_CTRL_TYPE_BOOLEAN,
289 .name = "Vertical Flip",
290 .minimum = 0,
291 .maximum = 1,
292 .step = 1,
293#define VFLIP_DEFAULT 0
294 .default_value = VFLIP_DEFAULT,
295 },
296 .set = sd_setvflip,
297 .get = sd_getvflip,
298 },
299 {
300#define EXPOSURE_IDX 9
301 {
302 .id = V4L2_CID_EXPOSURE,
303 .type = V4L2_CTRL_TYPE_INTEGER,
304 .name = "Exposure",
305 .minimum = 0,
306 .maximum = 0x1780,
307 .step = 1,
308#define EXPOSURE_DEFAULT 0x33
309 .default_value = EXPOSURE_DEFAULT,
310 },
311 .set = sd_setexposure,
312 .get = sd_getexposure,
313 },
314 {
315#define GAIN_IDX 10
316 {
317 .id = V4L2_CID_GAIN,
318 .type = V4L2_CTRL_TYPE_INTEGER,
319 .name = "Gain",
320 .minimum = 0,
321 .maximum = 28,
322 .step = 1,
323#define GAIN_DEFAULT 0x00
324 .default_value = GAIN_DEFAULT,
325 },
326 .set = sd_setgain,
327 .get = sd_getgain,
328 },
329 {
330#define AUTOGAIN_IDX 11
331 {
332 .id = V4L2_CID_AUTOGAIN,
333 .type = V4L2_CTRL_TYPE_BOOLEAN,
334 .name = "Auto Exposure",
335 .minimum = 0,
336 .maximum = 1,
337 .step = 1,
338#define AUTO_EXPOSURE_DEFAULT 1
339 .default_value = AUTO_EXPOSURE_DEFAULT,
340 },
341 .set = sd_setautoexposure,
342 .get = sd_getautoexposure,
343 },
344};
345
346static const struct v4l2_pix_format vga_mode[] = {
347 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300348 .bytesperline = 160,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300349 .sizeimage = 160 * 120 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300350 .colorspace = V4L2_COLORSPACE_JPEG,
351 .priv = 0 | MODE_JPEG},
352 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
353 .bytesperline = 160,
354 .sizeimage = 160 * 120,
355 .colorspace = V4L2_COLORSPACE_SRGB,
356 .priv = 0 | MODE_RAW},
357 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300358 .bytesperline = 160,
Brian Johnson26e744b2009-07-19 05:52:58 -0300359 .sizeimage = 240 * 120,
360 .colorspace = V4L2_COLORSPACE_SRGB,
361 .priv = 0},
362 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300363 .bytesperline = 320,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300364 .sizeimage = 320 * 240 * 3 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300365 .colorspace = V4L2_COLORSPACE_JPEG,
366 .priv = 1 | MODE_JPEG},
367 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
368 .bytesperline = 320,
369 .sizeimage = 320 * 240 ,
370 .colorspace = V4L2_COLORSPACE_SRGB,
371 .priv = 1 | MODE_RAW},
372 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300373 .bytesperline = 320,
Brian Johnson26e744b2009-07-19 05:52:58 -0300374 .sizeimage = 480 * 240 ,
375 .colorspace = V4L2_COLORSPACE_SRGB,
376 .priv = 1},
377 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300378 .bytesperline = 640,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300379 .sizeimage = 640 * 480 * 3 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300380 .colorspace = V4L2_COLORSPACE_JPEG,
381 .priv = 2 | MODE_JPEG},
382 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
383 .bytesperline = 640,
384 .sizeimage = 640 * 480,
385 .colorspace = V4L2_COLORSPACE_SRGB,
386 .priv = 2 | MODE_RAW},
387 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300388 .bytesperline = 640,
Brian Johnson26e744b2009-07-19 05:52:58 -0300389 .sizeimage = 960 * 480,
390 .colorspace = V4L2_COLORSPACE_SRGB,
391 .priv = 2},
392};
393
394static const struct v4l2_pix_format sxga_mode[] = {
395 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300396 .bytesperline = 160,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300397 .sizeimage = 160 * 120 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300398 .colorspace = V4L2_COLORSPACE_JPEG,
399 .priv = 0 | MODE_JPEG},
400 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
401 .bytesperline = 160,
402 .sizeimage = 160 * 120,
403 .colorspace = V4L2_COLORSPACE_SRGB,
404 .priv = 0 | MODE_RAW},
405 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300406 .bytesperline = 160,
Brian Johnson26e744b2009-07-19 05:52:58 -0300407 .sizeimage = 240 * 120,
408 .colorspace = V4L2_COLORSPACE_SRGB,
409 .priv = 0},
410 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300411 .bytesperline = 320,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300412 .sizeimage = 320 * 240 * 3 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300413 .colorspace = V4L2_COLORSPACE_JPEG,
414 .priv = 1 | MODE_JPEG},
415 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
416 .bytesperline = 320,
417 .sizeimage = 320 * 240 ,
418 .colorspace = V4L2_COLORSPACE_SRGB,
419 .priv = 1 | MODE_RAW},
420 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300421 .bytesperline = 320,
Brian Johnson26e744b2009-07-19 05:52:58 -0300422 .sizeimage = 480 * 240 ,
423 .colorspace = V4L2_COLORSPACE_SRGB,
424 .priv = 1},
425 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300426 .bytesperline = 640,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300427 .sizeimage = 640 * 480 * 3 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300428 .colorspace = V4L2_COLORSPACE_JPEG,
429 .priv = 2 | MODE_JPEG},
430 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
431 .bytesperline = 640,
432 .sizeimage = 640 * 480,
433 .colorspace = V4L2_COLORSPACE_SRGB,
434 .priv = 2 | MODE_RAW},
435 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300436 .bytesperline = 640,
Brian Johnson26e744b2009-07-19 05:52:58 -0300437 .sizeimage = 960 * 480,
438 .colorspace = V4L2_COLORSPACE_SRGB,
439 .priv = 2},
440 {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
441 .bytesperline = 1280,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300442 .sizeimage = 1280 * 1024,
Brian Johnson26e744b2009-07-19 05:52:58 -0300443 .colorspace = V4L2_COLORSPACE_SRGB,
444 .priv = 3 | MODE_RAW | MODE_SXGA},
445};
446
Joe Perches58aa68c2009-09-02 01:12:13 -0300447static const s16 hsv_red_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300448 41, 44, 46, 48, 50, 52, 54, 56,
449 58, 60, 62, 64, 66, 68, 70, 72,
450 74, 76, 78, 80, 81, 83, 85, 87,
451 88, 90, 92, 93, 95, 97, 98, 100,
452 101, 102, 104, 105, 107, 108, 109, 110,
453 112, 113, 114, 115, 116, 117, 118, 119,
454 120, 121, 122, 123, 123, 124, 125, 125,
455 126, 127, 127, 128, 128, 129, 129, 129,
456 130, 130, 130, 130, 131, 131, 131, 131,
457 131, 131, 131, 131, 130, 130, 130, 130,
458 129, 129, 129, 128, 128, 127, 127, 126,
459 125, 125, 124, 123, 122, 122, 121, 120,
460 119, 118, 117, 116, 115, 114, 112, 111,
461 110, 109, 107, 106, 105, 103, 102, 101,
462 99, 98, 96, 94, 93, 91, 90, 88,
463 86, 84, 83, 81, 79, 77, 75, 74,
464 72, 70, 68, 66, 64, 62, 60, 58,
465 56, 54, 52, 49, 47, 45, 43, 41,
466 39, 36, 34, 32, 30, 28, 25, 23,
467 21, 19, 16, 14, 12, 9, 7, 5,
468 3, 0, -1, -3, -6, -8, -10, -12,
469 -15, -17, -19, -22, -24, -26, -28, -30,
470 -33, -35, -37, -39, -41, -44, -46, -48,
471 -50, -52, -54, -56, -58, -60, -62, -64,
472 -66, -68, -70, -72, -74, -76, -78, -80,
473 -81, -83, -85, -87, -88, -90, -92, -93,
474 -95, -97, -98, -100, -101, -102, -104, -105,
475 -107, -108, -109, -110, -112, -113, -114, -115,
476 -116, -117, -118, -119, -120, -121, -122, -123,
477 -123, -124, -125, -125, -126, -127, -127, -128,
478 -128, -128, -128, -128, -128, -128, -128, -128,
479 -128, -128, -128, -128, -128, -128, -128, -128,
480 -128, -128, -128, -128, -128, -128, -128, -128,
481 -128, -127, -127, -126, -125, -125, -124, -123,
482 -122, -122, -121, -120, -119, -118, -117, -116,
483 -115, -114, -112, -111, -110, -109, -107, -106,
484 -105, -103, -102, -101, -99, -98, -96, -94,
485 -93, -91, -90, -88, -86, -84, -83, -81,
486 -79, -77, -75, -74, -72, -70, -68, -66,
487 -64, -62, -60, -58, -56, -54, -52, -49,
488 -47, -45, -43, -41, -39, -36, -34, -32,
489 -30, -28, -25, -23, -21, -19, -16, -14,
490 -12, -9, -7, -5, -3, 0, 1, 3,
491 6, 8, 10, 12, 15, 17, 19, 22,
492 24, 26, 28, 30, 33, 35, 37, 39, 41
493};
494
Joe Perches58aa68c2009-09-02 01:12:13 -0300495static const s16 hsv_red_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300496 82, 80, 78, 76, 74, 73, 71, 69,
497 67, 65, 63, 61, 58, 56, 54, 52,
498 50, 48, 46, 44, 41, 39, 37, 35,
499 32, 30, 28, 26, 23, 21, 19, 16,
500 14, 12, 10, 7, 5, 3, 0, -1,
501 -3, -6, -8, -10, -13, -15, -17, -19,
502 -22, -24, -26, -29, -31, -33, -35, -38,
503 -40, -42, -44, -46, -48, -51, -53, -55,
504 -57, -59, -61, -63, -65, -67, -69, -71,
505 -73, -75, -77, -79, -81, -82, -84, -86,
506 -88, -89, -91, -93, -94, -96, -98, -99,
507 -101, -102, -104, -105, -106, -108, -109, -110,
508 -112, -113, -114, -115, -116, -117, -119, -120,
509 -120, -121, -122, -123, -124, -125, -126, -126,
510 -127, -128, -128, -128, -128, -128, -128, -128,
511 -128, -128, -128, -128, -128, -128, -128, -128,
512 -128, -128, -128, -128, -128, -128, -128, -128,
513 -128, -128, -128, -128, -128, -128, -128, -128,
514 -127, -127, -126, -125, -125, -124, -123, -122,
515 -121, -120, -119, -118, -117, -116, -115, -114,
516 -113, -111, -110, -109, -107, -106, -105, -103,
517 -102, -100, -99, -97, -96, -94, -92, -91,
518 -89, -87, -85, -84, -82, -80, -78, -76,
519 -74, -73, -71, -69, -67, -65, -63, -61,
520 -58, -56, -54, -52, -50, -48, -46, -44,
521 -41, -39, -37, -35, -32, -30, -28, -26,
522 -23, -21, -19, -16, -14, -12, -10, -7,
523 -5, -3, 0, 1, 3, 6, 8, 10,
524 13, 15, 17, 19, 22, 24, 26, 29,
525 31, 33, 35, 38, 40, 42, 44, 46,
526 48, 51, 53, 55, 57, 59, 61, 63,
527 65, 67, 69, 71, 73, 75, 77, 79,
528 81, 82, 84, 86, 88, 89, 91, 93,
529 94, 96, 98, 99, 101, 102, 104, 105,
530 106, 108, 109, 110, 112, 113, 114, 115,
531 116, 117, 119, 120, 120, 121, 122, 123,
532 124, 125, 126, 126, 127, 128, 128, 129,
533 129, 130, 130, 131, 131, 131, 131, 132,
534 132, 132, 132, 132, 132, 132, 132, 132,
535 132, 132, 132, 131, 131, 131, 130, 130,
536 130, 129, 129, 128, 127, 127, 126, 125,
537 125, 124, 123, 122, 121, 120, 119, 118,
538 117, 116, 115, 114, 113, 111, 110, 109,
539 107, 106, 105, 103, 102, 100, 99, 97,
540 96, 94, 92, 91, 89, 87, 85, 84, 82
541};
542
Joe Perches58aa68c2009-09-02 01:12:13 -0300543static const s16 hsv_green_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300544 -124, -124, -125, -125, -125, -125, -125, -125,
545 -125, -126, -126, -125, -125, -125, -125, -125,
546 -125, -124, -124, -124, -123, -123, -122, -122,
547 -121, -121, -120, -120, -119, -118, -117, -117,
548 -116, -115, -114, -113, -112, -111, -110, -109,
549 -108, -107, -105, -104, -103, -102, -100, -99,
550 -98, -96, -95, -93, -92, -91, -89, -87,
551 -86, -84, -83, -81, -79, -77, -76, -74,
552 -72, -70, -69, -67, -65, -63, -61, -59,
553 -57, -55, -53, -51, -49, -47, -45, -43,
554 -41, -39, -37, -35, -33, -30, -28, -26,
555 -24, -22, -20, -18, -15, -13, -11, -9,
556 -7, -4, -2, 0, 1, 3, 6, 8,
557 10, 12, 14, 17, 19, 21, 23, 25,
558 27, 29, 32, 34, 36, 38, 40, 42,
559 44, 46, 48, 50, 52, 54, 56, 58,
560 60, 62, 64, 66, 68, 70, 71, 73,
561 75, 77, 78, 80, 82, 83, 85, 87,
562 88, 90, 91, 93, 94, 96, 97, 98,
563 100, 101, 102, 104, 105, 106, 107, 108,
564 109, 111, 112, 113, 113, 114, 115, 116,
565 117, 118, 118, 119, 120, 120, 121, 122,
566 122, 123, 123, 124, 124, 124, 125, 125,
567 125, 125, 125, 125, 125, 126, 126, 125,
568 125, 125, 125, 125, 125, 124, 124, 124,
569 123, 123, 122, 122, 121, 121, 120, 120,
570 119, 118, 117, 117, 116, 115, 114, 113,
571 112, 111, 110, 109, 108, 107, 105, 104,
572 103, 102, 100, 99, 98, 96, 95, 93,
573 92, 91, 89, 87, 86, 84, 83, 81,
574 79, 77, 76, 74, 72, 70, 69, 67,
575 65, 63, 61, 59, 57, 55, 53, 51,
576 49, 47, 45, 43, 41, 39, 37, 35,
577 33, 30, 28, 26, 24, 22, 20, 18,
578 15, 13, 11, 9, 7, 4, 2, 0,
579 -1, -3, -6, -8, -10, -12, -14, -17,
580 -19, -21, -23, -25, -27, -29, -32, -34,
581 -36, -38, -40, -42, -44, -46, -48, -50,
582 -52, -54, -56, -58, -60, -62, -64, -66,
583 -68, -70, -71, -73, -75, -77, -78, -80,
584 -82, -83, -85, -87, -88, -90, -91, -93,
585 -94, -96, -97, -98, -100, -101, -102, -104,
586 -105, -106, -107, -108, -109, -111, -112, -113,
587 -113, -114, -115, -116, -117, -118, -118, -119,
588 -120, -120, -121, -122, -122, -123, -123, -124, -124
589};
590
Joe Perches58aa68c2009-09-02 01:12:13 -0300591static const s16 hsv_green_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300592 -100, -99, -98, -97, -95, -94, -93, -91,
593 -90, -89, -87, -86, -84, -83, -81, -80,
594 -78, -76, -75, -73, -71, -70, -68, -66,
595 -64, -63, -61, -59, -57, -55, -53, -51,
596 -49, -48, -46, -44, -42, -40, -38, -36,
597 -34, -32, -30, -27, -25, -23, -21, -19,
598 -17, -15, -13, -11, -9, -7, -4, -2,
599 0, 1, 3, 5, 7, 9, 11, 14,
600 16, 18, 20, 22, 24, 26, 28, 30,
601 32, 34, 36, 38, 40, 42, 44, 46,
602 48, 50, 52, 54, 56, 58, 59, 61,
603 63, 65, 67, 68, 70, 72, 74, 75,
604 77, 78, 80, 82, 83, 85, 86, 88,
605 89, 90, 92, 93, 95, 96, 97, 98,
606 100, 101, 102, 103, 104, 105, 106, 107,
607 108, 109, 110, 111, 112, 112, 113, 114,
608 115, 115, 116, 116, 117, 117, 118, 118,
609 119, 119, 119, 120, 120, 120, 120, 120,
610 121, 121, 121, 121, 121, 121, 120, 120,
611 120, 120, 120, 119, 119, 119, 118, 118,
612 117, 117, 116, 116, 115, 114, 114, 113,
613 112, 111, 111, 110, 109, 108, 107, 106,
614 105, 104, 103, 102, 100, 99, 98, 97,
615 95, 94, 93, 91, 90, 89, 87, 86,
616 84, 83, 81, 80, 78, 76, 75, 73,
617 71, 70, 68, 66, 64, 63, 61, 59,
618 57, 55, 53, 51, 49, 48, 46, 44,
619 42, 40, 38, 36, 34, 32, 30, 27,
620 25, 23, 21, 19, 17, 15, 13, 11,
621 9, 7, 4, 2, 0, -1, -3, -5,
622 -7, -9, -11, -14, -16, -18, -20, -22,
623 -24, -26, -28, -30, -32, -34, -36, -38,
624 -40, -42, -44, -46, -48, -50, -52, -54,
625 -56, -58, -59, -61, -63, -65, -67, -68,
626 -70, -72, -74, -75, -77, -78, -80, -82,
627 -83, -85, -86, -88, -89, -90, -92, -93,
628 -95, -96, -97, -98, -100, -101, -102, -103,
629 -104, -105, -106, -107, -108, -109, -110, -111,
630 -112, -112, -113, -114, -115, -115, -116, -116,
631 -117, -117, -118, -118, -119, -119, -119, -120,
632 -120, -120, -120, -120, -121, -121, -121, -121,
633 -121, -121, -120, -120, -120, -120, -120, -119,
634 -119, -119, -118, -118, -117, -117, -116, -116,
635 -115, -114, -114, -113, -112, -111, -111, -110,
636 -109, -108, -107, -106, -105, -104, -103, -102, -100
637};
638
Joe Perches58aa68c2009-09-02 01:12:13 -0300639static const s16 hsv_blue_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300640 112, 113, 114, 114, 115, 116, 117, 117,
641 118, 118, 119, 119, 120, 120, 120, 121,
642 121, 121, 122, 122, 122, 122, 122, 122,
643 122, 122, 122, 122, 122, 122, 121, 121,
644 121, 120, 120, 120, 119, 119, 118, 118,
645 117, 116, 116, 115, 114, 113, 113, 112,
646 111, 110, 109, 108, 107, 106, 105, 104,
647 103, 102, 100, 99, 98, 97, 95, 94,
648 93, 91, 90, 88, 87, 85, 84, 82,
649 80, 79, 77, 76, 74, 72, 70, 69,
650 67, 65, 63, 61, 60, 58, 56, 54,
651 52, 50, 48, 46, 44, 42, 40, 38,
652 36, 34, 32, 30, 28, 26, 24, 22,
653 19, 17, 15, 13, 11, 9, 7, 5,
654 2, 0, -1, -3, -5, -7, -9, -12,
655 -14, -16, -18, -20, -22, -24, -26, -28,
656 -31, -33, -35, -37, -39, -41, -43, -45,
657 -47, -49, -51, -53, -54, -56, -58, -60,
658 -62, -64, -66, -67, -69, -71, -73, -74,
659 -76, -78, -79, -81, -83, -84, -86, -87,
660 -89, -90, -92, -93, -94, -96, -97, -98,
661 -99, -101, -102, -103, -104, -105, -106, -107,
662 -108, -109, -110, -111, -112, -113, -114, -114,
663 -115, -116, -117, -117, -118, -118, -119, -119,
664 -120, -120, -120, -121, -121, -121, -122, -122,
665 -122, -122, -122, -122, -122, -122, -122, -122,
666 -122, -122, -121, -121, -121, -120, -120, -120,
667 -119, -119, -118, -118, -117, -116, -116, -115,
668 -114, -113, -113, -112, -111, -110, -109, -108,
669 -107, -106, -105, -104, -103, -102, -100, -99,
670 -98, -97, -95, -94, -93, -91, -90, -88,
671 -87, -85, -84, -82, -80, -79, -77, -76,
672 -74, -72, -70, -69, -67, -65, -63, -61,
673 -60, -58, -56, -54, -52, -50, -48, -46,
674 -44, -42, -40, -38, -36, -34, -32, -30,
675 -28, -26, -24, -22, -19, -17, -15, -13,
676 -11, -9, -7, -5, -2, 0, 1, 3,
677 5, 7, 9, 12, 14, 16, 18, 20,
678 22, 24, 26, 28, 31, 33, 35, 37,
679 39, 41, 43, 45, 47, 49, 51, 53,
680 54, 56, 58, 60, 62, 64, 66, 67,
681 69, 71, 73, 74, 76, 78, 79, 81,
682 83, 84, 86, 87, 89, 90, 92, 93,
683 94, 96, 97, 98, 99, 101, 102, 103,
684 104, 105, 106, 107, 108, 109, 110, 111, 112
685};
686
Joe Perches58aa68c2009-09-02 01:12:13 -0300687static const s16 hsv_blue_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300688 -11, -13, -15, -17, -19, -21, -23, -25,
689 -27, -29, -31, -33, -35, -37, -39, -41,
690 -43, -45, -46, -48, -50, -52, -54, -55,
691 -57, -59, -61, -62, -64, -66, -67, -69,
692 -71, -72, -74, -75, -77, -78, -80, -81,
693 -83, -84, -86, -87, -88, -90, -91, -92,
694 -93, -95, -96, -97, -98, -99, -100, -101,
695 -102, -103, -104, -105, -106, -106, -107, -108,
696 -109, -109, -110, -111, -111, -112, -112, -113,
697 -113, -114, -114, -114, -115, -115, -115, -115,
698 -116, -116, -116, -116, -116, -116, -116, -116,
699 -116, -115, -115, -115, -115, -114, -114, -114,
700 -113, -113, -112, -112, -111, -111, -110, -110,
701 -109, -108, -108, -107, -106, -105, -104, -103,
702 -102, -101, -100, -99, -98, -97, -96, -95,
703 -94, -93, -91, -90, -89, -88, -86, -85,
704 -84, -82, -81, -79, -78, -76, -75, -73,
705 -71, -70, -68, -67, -65, -63, -62, -60,
706 -58, -56, -55, -53, -51, -49, -47, -45,
707 -44, -42, -40, -38, -36, -34, -32, -30,
708 -28, -26, -24, -22, -20, -18, -16, -14,
709 -12, -10, -8, -6, -4, -2, 0, 1,
710 3, 5, 7, 9, 11, 13, 15, 17,
711 19, 21, 23, 25, 27, 29, 31, 33,
712 35, 37, 39, 41, 43, 45, 46, 48,
713 50, 52, 54, 55, 57, 59, 61, 62,
714 64, 66, 67, 69, 71, 72, 74, 75,
715 77, 78, 80, 81, 83, 84, 86, 87,
716 88, 90, 91, 92, 93, 95, 96, 97,
717 98, 99, 100, 101, 102, 103, 104, 105,
718 106, 106, 107, 108, 109, 109, 110, 111,
719 111, 112, 112, 113, 113, 114, 114, 114,
720 115, 115, 115, 115, 116, 116, 116, 116,
721 116, 116, 116, 116, 116, 115, 115, 115,
722 115, 114, 114, 114, 113, 113, 112, 112,
723 111, 111, 110, 110, 109, 108, 108, 107,
724 106, 105, 104, 103, 102, 101, 100, 99,
725 98, 97, 96, 95, 94, 93, 91, 90,
726 89, 88, 86, 85, 84, 82, 81, 79,
727 78, 76, 75, 73, 71, 70, 68, 67,
728 65, 63, 62, 60, 58, 56, 55, 53,
729 51, 49, 47, 45, 44, 42, 40, 38,
730 36, 34, 32, 30, 28, 26, 24, 22,
731 20, 18, 16, 14, 12, 10, 8, 6,
732 4, 2, 0, -1, -3, -5, -7, -9, -11
733};
734
735static u16 i2c_ident[] = {
736 V4L2_IDENT_OV9650,
737 V4L2_IDENT_OV9655,
738 V4L2_IDENT_SOI968,
739 V4L2_IDENT_OV7660,
740 V4L2_IDENT_OV7670,
741 V4L2_IDENT_MT9V011,
742 V4L2_IDENT_MT9V111,
743 V4L2_IDENT_MT9V112,
744 V4L2_IDENT_MT9M001C12ST,
745 V4L2_IDENT_MT9M111,
Brian Johnsone99ac542010-03-16 13:58:28 -0300746 V4L2_IDENT_MT9M112,
Brian Johnson26e744b2009-07-19 05:52:58 -0300747 V4L2_IDENT_HV7131R,
748};
749
750static u16 bridge_init[][2] = {
751 {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c},
752 {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40},
753 {0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10},
754 {0x106b, 0x08}, {0x1188, 0x87}, {0x11a1, 0x00},
755 {0x11a2, 0x00}, {0x11a3, 0x6a}, {0x11a4, 0x50},
756 {0x11ab, 0x00}, {0x11ac, 0x00}, {0x11ad, 0x50},
757 {0x11ae, 0x3c}, {0x118a, 0x04}, {0x0395, 0x04},
758 {0x11b8, 0x3a}, {0x118b, 0x0e}, {0x10f7, 0x05},
759 {0x10f8, 0x14}, {0x10fa, 0xff}, {0x10f9, 0x00},
760 {0x11ba, 0x0a}, {0x11a5, 0x2d}, {0x11a6, 0x2d},
761 {0x11a7, 0x3a}, {0x11a8, 0x05}, {0x11a9, 0x04},
762 {0x11aa, 0x3f}, {0x11af, 0x28}, {0x11b0, 0xd8},
763 {0x11b1, 0x14}, {0x11b2, 0xec}, {0x11b3, 0x32},
764 {0x11b4, 0xdd}, {0x11b5, 0x32}, {0x11b6, 0xdd},
765 {0x10e0, 0x2c}, {0x11bc, 0x40}, {0x11bd, 0x01},
766 {0x11be, 0xf0}, {0x11bf, 0x00}, {0x118c, 0x1f},
767 {0x118d, 0x1f}, {0x118e, 0x1f}, {0x118f, 0x1f},
768 {0x1180, 0x01}, {0x1181, 0x00}, {0x1182, 0x01},
Brian Johnson0c045eb2010-03-16 13:58:27 -0300769 {0x1183, 0x00}, {0x1184, 0x50}, {0x1185, 0x80},
770 {0x1007, 0x00}
Brian Johnson26e744b2009-07-19 05:52:58 -0300771};
772
773/* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */
774static u8 ov_gain[] = {
775 0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */,
776 0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */,
777 0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */,
778 0x30 /* 4x */, 0x31 /* 4.25x */, 0x32 /* 4.5x */, 0x33 /* 4.75x */,
779 0x34 /* 5x */, 0x35 /* 5.25x */, 0x36 /* 5.5x */, 0x37 /* 5.75x */,
780 0x38 /* 6x */, 0x39 /* 6.25x */, 0x3a /* 6.5x */, 0x3b /* 6.75x */,
781 0x3c /* 7x */, 0x3d /* 7.25x */, 0x3e /* 7.5x */, 0x3f /* 7.75x */,
782 0x70 /* 8x */
783};
784
785/* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */
786static u16 micron1_gain[] = {
787 /* 1x 1.25x 1.5x 1.75x */
788 0x0020, 0x0028, 0x0030, 0x0038,
789 /* 2x 2.25x 2.5x 2.75x */
790 0x00a0, 0x00a4, 0x00a8, 0x00ac,
791 /* 3x 3.25x 3.5x 3.75x */
792 0x00b0, 0x00b4, 0x00b8, 0x00bc,
793 /* 4x 4.25x 4.5x 4.75x */
794 0x00c0, 0x00c4, 0x00c8, 0x00cc,
795 /* 5x 5.25x 5.5x 5.75x */
796 0x00d0, 0x00d4, 0x00d8, 0x00dc,
797 /* 6x 6.25x 6.5x 6.75x */
798 0x00e0, 0x00e4, 0x00e8, 0x00ec,
799 /* 7x 7.25x 7.5x 7.75x */
800 0x00f0, 0x00f4, 0x00f8, 0x00fc,
801 /* 8x */
802 0x01c0
803};
804
805/* mt9m001 sensor uses a different gain formula then other micron sensors */
806/* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */
807static u16 micron2_gain[] = {
808 /* 1x 1.25x 1.5x 1.75x */
809 0x0008, 0x000a, 0x000c, 0x000e,
810 /* 2x 2.25x 2.5x 2.75x */
811 0x0010, 0x0012, 0x0014, 0x0016,
812 /* 3x 3.25x 3.5x 3.75x */
813 0x0018, 0x001a, 0x001c, 0x001e,
814 /* 4x 4.25x 4.5x 4.75x */
815 0x0020, 0x0051, 0x0052, 0x0053,
816 /* 5x 5.25x 5.5x 5.75x */
817 0x0054, 0x0055, 0x0056, 0x0057,
818 /* 6x 6.25x 6.5x 6.75x */
819 0x0058, 0x0059, 0x005a, 0x005b,
820 /* 7x 7.25x 7.5x 7.75x */
821 0x005c, 0x005d, 0x005e, 0x005f,
822 /* 8x */
823 0x0060
824};
825
826/* Gain = .5 + bit[7:0] / 16 */
827static u8 hv7131r_gain[] = {
828 0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */,
829 0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */,
830 0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */,
831 0x38 /* 4x */, 0x3c /* 4.25x */, 0x40 /* 4.5x */, 0x44 /* 4.75x */,
832 0x48 /* 5x */, 0x4c /* 5.25x */, 0x50 /* 5.5x */, 0x54 /* 5.75x */,
833 0x58 /* 6x */, 0x5c /* 6.25x */, 0x60 /* 6.5x */, 0x64 /* 6.75x */,
834 0x68 /* 7x */, 0x6c /* 7.25x */, 0x70 /* 7.5x */, 0x74 /* 7.75x */,
835 0x78 /* 8x */
836};
837
Joe Perches58aa68c2009-09-02 01:12:13 -0300838static struct i2c_reg_u8 soi968_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300839 {0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f},
840 {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
841 {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
842 {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
843 {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20},
844 {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e},
Brian Johnsone1430472009-09-02 12:39:41 -0300845 {0x13, 0x8b}, {0x12, 0x40}, {0x17, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300846 {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79},
847 {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40},
848 {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32},
849 {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80},
850};
851
Joe Perches58aa68c2009-09-02 01:12:13 -0300852static struct i2c_reg_u8 ov7660_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300853 {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
854 {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
855 {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
856 {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43},
857 {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0xf6},
858 {0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50},
859};
860
Joe Perches58aa68c2009-09-02 01:12:13 -0300861static struct i2c_reg_u8 ov7670_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300862 {0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
863 {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
864 {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
865 {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
866 {0x0d, 0x40}, {0x14, 0x28}, {0xa5, 0x05}, {0xab, 0x07},
867 {0x24, 0x95}, {0x25, 0x33}, {0x26, 0xe3}, {0x9f, 0x75},
868 {0xa0, 0x65}, {0xa1, 0x0b}, {0xa6, 0xd8}, {0xa7, 0xd8},
869 {0xa8, 0xf0}, {0xa9, 0x90}, {0xaa, 0x94}, {0x13, 0xe5},
870 {0x0e, 0x61}, {0x0f, 0x4b}, {0x16, 0x02}, {0x1e, 0x27},
871 {0x21, 0x02}, {0x22, 0x91}, {0x29, 0x07}, {0x33, 0x0b},
872 {0x35, 0x0b}, {0x37, 0x1d}, {0x38, 0x71}, {0x39, 0x2a},
873 {0x3c, 0x78}, {0x4d, 0x40}, {0x4e, 0x20}, {0x69, 0x00},
874 {0x74, 0x19}, {0x8d, 0x4f}, {0x8e, 0x00}, {0x8f, 0x00},
875 {0x90, 0x00}, {0x91, 0x00}, {0x96, 0x00}, {0x9a, 0x80},
876 {0xb0, 0x84}, {0xb1, 0x0c}, {0xb2, 0x0e}, {0xb3, 0x82},
877 {0xb8, 0x0a}, {0x43, 0x0a}, {0x44, 0xf0}, {0x45, 0x20},
878 {0x46, 0x7d}, {0x47, 0x29}, {0x48, 0x4a}, {0x59, 0x8c},
879 {0x5a, 0xa5}, {0x5b, 0xde}, {0x5c, 0x96}, {0x5d, 0x66},
880 {0x5e, 0x10}, {0x6c, 0x0a}, {0x6d, 0x55}, {0x6e, 0x11},
881 {0x6f, 0x9e}, {0x6a, 0x40}, {0x01, 0x40}, {0x02, 0x40},
882 {0x13, 0xe7}, {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x02},
883 {0x52, 0x1d}, {0x53, 0x56}, {0x54, 0x73}, {0x55, 0x0a},
884 {0x56, 0x55}, {0x57, 0x80}, {0x58, 0x9e}, {0x41, 0x08},
885 {0x3f, 0x02}, {0x75, 0x03}, {0x76, 0x63}, {0x4c, 0x04},
886 {0x77, 0x06}, {0x3d, 0x02}, {0x4b, 0x09}, {0xc9, 0x30},
887 {0x41, 0x08}, {0x56, 0x48}, {0x34, 0x11}, {0xa4, 0x88},
888 {0x96, 0x00}, {0x97, 0x30}, {0x98, 0x20}, {0x99, 0x30},
889 {0x9a, 0x84}, {0x9b, 0x29}, {0x9c, 0x03}, {0x9d, 0x99},
890 {0x9e, 0x7f}, {0x78, 0x04}, {0x79, 0x01}, {0xc8, 0xf0},
891 {0x79, 0x0f}, {0xc8, 0x00}, {0x79, 0x10}, {0xc8, 0x7e},
892 {0x79, 0x0a}, {0xc8, 0x80}, {0x79, 0x0b}, {0xc8, 0x01},
893 {0x79, 0x0c}, {0xc8, 0x0f}, {0x79, 0x0d}, {0xc8, 0x20},
894 {0x79, 0x09}, {0xc8, 0x80}, {0x79, 0x02}, {0xc8, 0xc0},
895 {0x79, 0x03}, {0xc8, 0x40}, {0x79, 0x05}, {0xc8, 0x30},
896 {0x79, 0x26}, {0x62, 0x20}, {0x63, 0x00}, {0x64, 0x06},
897 {0x65, 0x00}, {0x66, 0x05}, {0x94, 0x05}, {0x95, 0x0a},
898 {0x17, 0x13}, {0x18, 0x01}, {0x19, 0x02}, {0x1a, 0x7a},
899 {0x46, 0x59}, {0x47, 0x30}, {0x58, 0x9a}, {0x59, 0x84},
900 {0x5a, 0x91}, {0x5b, 0x57}, {0x5c, 0x75}, {0x5d, 0x6d},
901 {0x5e, 0x13}, {0x64, 0x07}, {0x94, 0x07}, {0x95, 0x0d},
902 {0xa6, 0xdf}, {0xa7, 0xdf}, {0x48, 0x4d}, {0x51, 0x00},
903 {0x6b, 0x0a}, {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00},
904 {0x92, 0x00}, {0x93, 0x00}, {0x55, 0x0a}, {0x56, 0x60},
905 {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d},
906 {0x53, 0x56}, {0x54, 0x73}, {0x58, 0x9a}, {0x4f, 0x6e},
907 {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, {0x53, 0x56},
908 {0x54, 0x73}, {0x58, 0x9a}, {0x3f, 0x01}, {0x7b, 0x03},
909 {0x7c, 0x09}, {0x7d, 0x16}, {0x7e, 0x38}, {0x7f, 0x47},
910 {0x80, 0x53}, {0x81, 0x5e}, {0x82, 0x6a}, {0x83, 0x74},
911 {0x84, 0x80}, {0x85, 0x8c}, {0x86, 0x9b}, {0x87, 0xb2},
912 {0x88, 0xcc}, {0x89, 0xe5}, {0x7a, 0x24}, {0x3b, 0x00},
913 {0x9f, 0x76}, {0xa0, 0x65}, {0x13, 0xe2}, {0x6b, 0x0a},
914 {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, {0x92, 0x00},
915 {0x93, 0x00},
916};
917
Joe Perches58aa68c2009-09-02 01:12:13 -0300918static struct i2c_reg_u8 ov9650_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300919 {0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78},
920 {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
921 {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
922 {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
923 {0x0e, 0xa0}, {0x0f, 0x52}, {0x10, 0x7c},
924 {0x11, 0x80}, {0x12, 0x45}, {0x13, 0xc2},
925 {0x14, 0x2e}, {0x15, 0x00}, {0x16, 0x07},
926 {0x17, 0x24}, {0x18, 0xc5}, {0x19, 0x00},
927 {0x1a, 0x3c}, {0x1b, 0x00}, {0x1e, 0x04},
928 {0x1f, 0x00}, {0x24, 0x78}, {0x25, 0x68},
929 {0x26, 0xd4}, {0x27, 0x80}, {0x28, 0x80},
930 {0x29, 0x30}, {0x2a, 0x00}, {0x2b, 0x00},
931 {0x2c, 0x80}, {0x2d, 0x00}, {0x2e, 0x00},
932 {0x2f, 0x00}, {0x30, 0x08}, {0x31, 0x30},
933 {0x32, 0x84}, {0x33, 0xe2}, {0x34, 0xbf},
934 {0x35, 0x81}, {0x36, 0xf9}, {0x37, 0x00},
935 {0x38, 0x93}, {0x39, 0x50}, {0x3a, 0x01},
936 {0x3b, 0x01}, {0x3c, 0x73}, {0x3d, 0x19},
937 {0x3e, 0x0b}, {0x3f, 0x80}, {0x40, 0xc1},
938 {0x41, 0x00}, {0x42, 0x08}, {0x67, 0x80},
939 {0x68, 0x80}, {0x69, 0x40}, {0x6a, 0x00},
940 {0x6b, 0x0a}, {0x8b, 0x06}, {0x8c, 0x20},
941 {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0xdf},
942 {0x92, 0x00}, {0x93, 0x00}, {0x94, 0x88},
943 {0x95, 0x88}, {0x96, 0x04}, {0xa1, 0x00},
944 {0xa5, 0x80}, {0xa8, 0x80}, {0xa9, 0xb8},
945 {0xaa, 0x92}, {0xab, 0x0a},
946};
947
Joe Perches58aa68c2009-09-02 01:12:13 -0300948static struct i2c_reg_u8 ov9655_init[] = {
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300949 {0x12, 0x80}, {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
950 {0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
951 {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
952 {0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57},
953 {0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c}, {0x3d, 0x19},
954 {0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40}, {0x42, 0x80},
955 {0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a}, {0x48, 0x3c},
956 {0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc}, {0x4d, 0xdc},
957 {0x4e, 0xdc}, {0x6c, 0x04}, {0x6f, 0x9e}, {0x70, 0x05},
958 {0x71, 0x78}, {0x77, 0x02}, {0x8a, 0x23}, {0x90, 0x7e},
959 {0x91, 0x7c}, {0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68},
960 {0xa6, 0x60}, {0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92},
961 {0xab, 0x04}, {0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80},
962 {0xaf, 0x80}, {0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00},
963 {0xb6, 0xaf}, {0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44},
964 {0xbe, 0x3b}, {0xbf, 0x3a}, {0xc1, 0xc8}, {0xc2, 0x01},
Brian Johnson26e744b2009-07-19 05:52:58 -0300965 {0xc4, 0x00}, {0xc6, 0x85}, {0xc7, 0x81}, {0xc9, 0xe0},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300966 {0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x2d, 0x00},
967 {0x2e, 0x00}, {0x01, 0x80}, {0x02, 0x80}, {0x12, 0x61},
Brian Johnson26e744b2009-07-19 05:52:58 -0300968 {0x36, 0xfa}, {0x8c, 0x8d}, {0xc0, 0xaa}, {0x69, 0x0a},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300969 {0x03, 0x09}, {0x17, 0x16}, {0x18, 0x6e}, {0x19, 0x01},
970 {0x1a, 0x3e}, {0x32, 0x09}, {0x2a, 0x10}, {0x2b, 0x0a},
971 {0x92, 0x00}, {0x93, 0x00}, {0xa1, 0x00}, {0x10, 0x7c},
972 {0x04, 0x03}, {0x00, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300973};
974
Joe Perches58aa68c2009-09-02 01:12:13 -0300975static struct i2c_reg_u16 mt9v112_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300976 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020},
977 {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
978 {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
979 {0x05, 0x0000}, {0x06, 0x340c}, {0x3b, 0x042a},
980 {0x3c, 0x0400}, {0xf0, 0x0002}, {0x2e, 0x0c58},
981 {0x5b, 0x0001}, {0xc8, 0x9f0b}, {0xf0, 0x0001},
982 {0x9b, 0x5300}, {0xf0, 0x0000}, {0x2b, 0x0020},
983 {0x2c, 0x002a}, {0x2d, 0x0032}, {0x2e, 0x0020},
984 {0x09, 0x01dc}, {0x01, 0x000c}, {0x02, 0x0020},
985 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
986 {0x05, 0x0098}, {0x20, 0x0703}, {0x09, 0x01f2},
987 {0x2b, 0x00a0}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
988 {0x2e, 0x00a0}, {0x01, 0x000c}, {0x02, 0x0020},
989 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
990 {0x05, 0x0098}, {0x09, 0x01c1}, {0x2b, 0x00ae},
991 {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
992};
993
Joe Perches58aa68c2009-09-02 01:12:13 -0300994static struct i2c_reg_u16 mt9v111_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300995 {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
Brian Johnson6ea23bd2010-05-05 13:22:45 -0300996 {0x01, 0x0001}, {0x05, 0x0004}, {0x2d, 0xe0a0},
997 {0x2e, 0x0c64}, {0x2f, 0x0064}, {0x06, 0x600e},
998 {0x08, 0x0480}, {0x01, 0x0004}, {0x02, 0x0016},
999 {0x03, 0x01e7}, {0x04, 0x0287}, {0x05, 0x0004},
1000 {0x06, 0x002d}, {0x07, 0x3002}, {0x08, 0x0008},
1001 {0x0e, 0x0008}, {0x20, 0x0000}
Brian Johnson26e744b2009-07-19 05:52:58 -03001002};
1003
Joe Perches58aa68c2009-09-02 01:12:13 -03001004static struct i2c_reg_u16 mt9v011_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001005 {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
1006 {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1},
1007 {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006},
1008 {0x0d, 0x0002}, {0x0a, 0x0000}, {0x0b, 0x0000},
1009 {0x0c, 0x0000}, {0x0d, 0x0000}, {0x0e, 0x0000},
1010 {0x0f, 0x0000}, {0x10, 0x0000}, {0x11, 0x0000},
1011 {0x12, 0x0000}, {0x13, 0x0000}, {0x14, 0x0000},
1012 {0x15, 0x0000}, {0x16, 0x0000}, {0x17, 0x0000},
1013 {0x18, 0x0000}, {0x19, 0x0000}, {0x1a, 0x0000},
1014 {0x1b, 0x0000}, {0x1c, 0x0000}, {0x1d, 0x0000},
1015 {0x32, 0x0000}, {0x20, 0x1101}, {0x21, 0x0000},
1016 {0x22, 0x0000}, {0x23, 0x0000}, {0x24, 0x0000},
1017 {0x25, 0x0000}, {0x26, 0x0000}, {0x27, 0x0024},
1018 {0x2f, 0xf7b0}, {0x30, 0x0005}, {0x31, 0x0000},
1019 {0x32, 0x0000}, {0x33, 0x0000}, {0x34, 0x0100},
1020 {0x3d, 0x068f}, {0x40, 0x01e0}, {0x41, 0x00d1},
1021 {0x44, 0x0082}, {0x5a, 0x0000}, {0x5b, 0x0000},
1022 {0x5c, 0x0000}, {0x5d, 0x0000}, {0x5e, 0x0000},
1023 {0x5f, 0xa31d}, {0x62, 0x0611}, {0x0a, 0x0000},
1024 {0x06, 0x0029}, {0x05, 0x0009}, {0x20, 0x1101},
1025 {0x20, 0x1101}, {0x09, 0x0064}, {0x07, 0x0003},
1026 {0x2b, 0x0033}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
1027 {0x2e, 0x0033}, {0x07, 0x0002}, {0x06, 0x0000},
1028 {0x06, 0x0029}, {0x05, 0x0009},
1029};
1030
Joe Perches58aa68c2009-09-02 01:12:13 -03001031static struct i2c_reg_u16 mt9m001_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001032 {0x0d, 0x0001}, {0x0d, 0x0000}, {0x01, 0x000e},
1033 {0x02, 0x0014}, {0x03, 0x03c1}, {0x04, 0x0501},
1034 {0x05, 0x0083}, {0x06, 0x0006}, {0x0d, 0x0002},
1035 {0x0a, 0x0000}, {0x0c, 0x0000}, {0x11, 0x0000},
1036 {0x1e, 0x8000}, {0x5f, 0x8904}, {0x60, 0x0000},
1037 {0x61, 0x0000}, {0x62, 0x0498}, {0x63, 0x0000},
1038 {0x64, 0x0000}, {0x20, 0x111d}, {0x06, 0x00f2},
1039 {0x05, 0x0013}, {0x09, 0x10f2}, {0x07, 0x0003},
1040 {0x2b, 0x002a}, {0x2d, 0x002a}, {0x2c, 0x002a},
1041 {0x2e, 0x0029}, {0x07, 0x0002},
1042};
1043
Joe Perches58aa68c2009-09-02 01:12:13 -03001044static struct i2c_reg_u16 mt9m111_init[] = {
Brian Johnson13a84fa2009-09-03 19:07:13 -03001045 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
1046 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
Brian Johnson4d708a52009-09-03 19:10:15 -03001047 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
1048 {0xf0, 0x0000},
Brian Johnson26e744b2009-07-19 05:52:58 -03001049};
1050
Brian Johnsone99ac542010-03-16 13:58:28 -03001051static struct i2c_reg_u16 mt9m112_init[] = {
1052 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
1053 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
1054 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
1055 {0xf0, 0x0000},
1056};
1057
Joe Perches58aa68c2009-09-02 01:12:13 -03001058static struct i2c_reg_u8 hv7131r_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001059 {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
1060 {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
1061 {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
1062 {0x01, 0x08}, {0x01, 0x08}, {0x25, 0x07},
1063 {0x26, 0xc3}, {0x27, 0x50}, {0x30, 0x62},
1064 {0x31, 0x10}, {0x32, 0x06}, {0x33, 0x10},
1065 {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00},
1066 {0x23, 0x09}, {0x01, 0x08},
1067};
1068
Joe Perches58aa68c2009-09-02 01:12:13 -03001069static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
Brian Johnson26e744b2009-07-19 05:52:58 -03001070{
1071 struct usb_device *dev = gspca_dev->dev;
1072 int result;
1073 result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
1074 0x00,
1075 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
1076 reg,
1077 0x00,
1078 gspca_dev->usb_buf,
1079 length,
1080 500);
1081 if (unlikely(result < 0 || result != length)) {
1082 err("Read register failed 0x%02X", reg);
1083 return -EIO;
1084 }
1085 return 0;
1086}
1087
Joe Perches58aa68c2009-09-02 01:12:13 -03001088static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
1089 const u8 *buffer, int length)
Brian Johnson26e744b2009-07-19 05:52:58 -03001090{
1091 struct usb_device *dev = gspca_dev->dev;
1092 int result;
1093 memcpy(gspca_dev->usb_buf, buffer, length);
1094 result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
1095 0x08,
1096 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
1097 reg,
1098 0x00,
1099 gspca_dev->usb_buf,
1100 length,
1101 500);
1102 if (unlikely(result < 0 || result != length)) {
1103 err("Write register failed index 0x%02X", reg);
1104 return -EIO;
1105 }
1106 return 0;
1107}
1108
Joe Perches58aa68c2009-09-02 01:12:13 -03001109static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
Brian Johnson26e744b2009-07-19 05:52:58 -03001110{
1111 u8 data[1] = {value};
1112 return reg_w(gspca_dev, reg, data, 1);
1113}
1114
Joe Perches58aa68c2009-09-02 01:12:13 -03001115static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
Brian Johnson26e744b2009-07-19 05:52:58 -03001116{
1117 int i;
1118 reg_w(gspca_dev, 0x10c0, buffer, 8);
1119 for (i = 0; i < 5; i++) {
1120 reg_r(gspca_dev, 0x10c0, 1);
1121 if (gspca_dev->usb_buf[0] & 0x04) {
1122 if (gspca_dev->usb_buf[0] & 0x08)
Brian Johnson00b581e2009-07-23 05:55:43 -03001123 return -EIO;
Brian Johnson26e744b2009-07-19 05:52:58 -03001124 return 0;
1125 }
1126 msleep(1);
1127 }
Brian Johnson00b581e2009-07-23 05:55:43 -03001128 return -EIO;
Brian Johnson26e744b2009-07-19 05:52:58 -03001129}
1130
Joe Perches58aa68c2009-09-02 01:12:13 -03001131static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001132{
1133 struct sd *sd = (struct sd *) gspca_dev;
1134
1135 u8 row[8];
1136
1137 /*
1138 * from the point of view of the bridge, the length
1139 * includes the address
1140 */
1141 row[0] = 0x81 | (2 << 4);
1142 row[1] = sd->i2c_addr;
1143 row[2] = reg;
1144 row[3] = val;
1145 row[4] = 0x00;
1146 row[5] = 0x00;
1147 row[6] = 0x00;
1148 row[7] = 0x10;
1149
1150 return i2c_w(gspca_dev, row);
1151}
1152
Joe Perches58aa68c2009-09-02 01:12:13 -03001153static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001154{
1155 struct sd *sd = (struct sd *) gspca_dev;
1156 u8 row[8];
1157
1158 /*
1159 * from the point of view of the bridge, the length
1160 * includes the address
1161 */
1162 row[0] = 0x81 | (3 << 4);
1163 row[1] = sd->i2c_addr;
1164 row[2] = reg;
1165 row[3] = (val >> 8) & 0xff;
1166 row[4] = val & 0xff;
1167 row[5] = 0x00;
1168 row[6] = 0x00;
1169 row[7] = 0x10;
1170
1171 return i2c_w(gspca_dev, row);
1172}
1173
Jean-Francois Moine83955552009-12-12 06:58:01 -03001174static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001175{
1176 struct sd *sd = (struct sd *) gspca_dev;
1177 u8 row[8];
1178
Brian Johnson00b581e2009-07-23 05:55:43 -03001179 row[0] = 0x81 | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001180 row[1] = sd->i2c_addr;
1181 row[2] = reg;
1182 row[3] = 0;
1183 row[4] = 0;
1184 row[5] = 0;
1185 row[6] = 0;
1186 row[7] = 0x10;
Brian Johnson00b581e2009-07-23 05:55:43 -03001187 if (i2c_w(gspca_dev, row) < 0)
1188 return -EIO;
1189 row[0] = 0x81 | (1 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001190 row[2] = 0;
Brian Johnson00b581e2009-07-23 05:55:43 -03001191 if (i2c_w(gspca_dev, row) < 0)
1192 return -EIO;
1193 if (reg_r(gspca_dev, 0x10c2, 5) < 0)
1194 return -EIO;
1195 *val = gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001196 return 0;
1197}
1198
Jean-Francois Moine83955552009-12-12 06:58:01 -03001199static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001200{
1201 struct sd *sd = (struct sd *) gspca_dev;
1202 u8 row[8];
1203
Brian Johnson00b581e2009-07-23 05:55:43 -03001204 row[0] = 0x81 | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001205 row[1] = sd->i2c_addr;
1206 row[2] = reg;
1207 row[3] = 0;
1208 row[4] = 0;
1209 row[5] = 0;
1210 row[6] = 0;
1211 row[7] = 0x10;
Brian Johnson00b581e2009-07-23 05:55:43 -03001212 if (i2c_w(gspca_dev, row) < 0)
1213 return -EIO;
1214 row[0] = 0x81 | (2 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001215 row[2] = 0;
Brian Johnson00b581e2009-07-23 05:55:43 -03001216 if (i2c_w(gspca_dev, row) < 0)
1217 return -EIO;
1218 if (reg_r(gspca_dev, 0x10c2, 5) < 0)
1219 return -EIO;
1220 *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001221 return 0;
1222}
1223
1224static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
1225{
1226 int i;
1227 struct sd *sd = (struct sd *) gspca_dev;
1228
1229 for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001230 if (i2c_w1(gspca_dev, ov9650_init[i].reg,
1231 ov9650_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001232 err("OV9650 sensor initialization failed");
1233 return -ENODEV;
1234 }
1235 }
1236 sd->hstart = 1;
1237 sd->vstart = 7;
1238 return 0;
1239}
1240
1241static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
1242{
1243 int i;
1244 struct sd *sd = (struct sd *) gspca_dev;
1245
1246 for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001247 if (i2c_w1(gspca_dev, ov9655_init[i].reg,
1248 ov9655_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001249 err("OV9655 sensor initialization failed");
1250 return -ENODEV;
1251 }
1252 }
1253 /* disable hflip and vflip */
1254 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
Brian Johnsoncc2a8332010-03-16 13:58:28 -03001255 sd->hstart = 1;
1256 sd->vstart = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001257 return 0;
1258}
1259
1260static int soi968_init_sensor(struct gspca_dev *gspca_dev)
1261{
1262 int i;
1263 struct sd *sd = (struct sd *) gspca_dev;
1264
1265 for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001266 if (i2c_w1(gspca_dev, soi968_init[i].reg,
1267 soi968_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001268 err("SOI968 sensor initialization failed");
1269 return -ENODEV;
1270 }
1271 }
1272 /* disable hflip and vflip */
Brian Johnsone1430472009-09-02 12:39:41 -03001273 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << EXPOSURE_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001274 sd->hstart = 60;
1275 sd->vstart = 11;
1276 return 0;
1277}
1278
1279static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
1280{
1281 int i;
1282 struct sd *sd = (struct sd *) gspca_dev;
1283
1284 for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001285 if (i2c_w1(gspca_dev, ov7660_init[i].reg,
1286 ov7660_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001287 err("OV7660 sensor initialization failed");
1288 return -ENODEV;
1289 }
1290 }
1291 /* disable hflip and vflip */
1292 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1293 sd->hstart = 1;
1294 sd->vstart = 1;
1295 return 0;
1296}
1297
1298static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
1299{
1300 int i;
1301 struct sd *sd = (struct sd *) gspca_dev;
1302
1303 for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001304 if (i2c_w1(gspca_dev, ov7670_init[i].reg,
1305 ov7670_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001306 err("OV7670 sensor initialization failed");
1307 return -ENODEV;
1308 }
1309 }
1310 /* disable hflip and vflip */
1311 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1312 sd->hstart = 0;
1313 sd->vstart = 1;
1314 return 0;
1315}
1316
1317static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
1318{
1319 struct sd *sd = (struct sd *) gspca_dev;
1320 int i;
1321 u16 value;
1322 int ret;
1323
1324 sd->i2c_addr = 0x5d;
1325 ret = i2c_r2(gspca_dev, 0xff, &value);
1326 if ((ret == 0) && (value == 0x8243)) {
1327 for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001328 if (i2c_w2(gspca_dev, mt9v011_init[i].reg,
1329 mt9v011_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001330 err("MT9V011 sensor initialization failed");
1331 return -ENODEV;
1332 }
1333 }
1334 sd->hstart = 2;
1335 sd->vstart = 2;
1336 sd->sensor = SENSOR_MT9V011;
1337 info("MT9V011 sensor detected");
1338 return 0;
1339 }
1340
1341 sd->i2c_addr = 0x5c;
1342 i2c_w2(gspca_dev, 0x01, 0x0004);
1343 ret = i2c_r2(gspca_dev, 0xff, &value);
1344 if ((ret == 0) && (value == 0x823a)) {
1345 for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001346 if (i2c_w2(gspca_dev, mt9v111_init[i].reg,
1347 mt9v111_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001348 err("MT9V111 sensor initialization failed");
1349 return -ENODEV;
1350 }
1351 }
Brian Johnson6ea23bd2010-05-05 13:22:45 -03001352 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001353 sd->hstart = 2;
1354 sd->vstart = 2;
1355 sd->sensor = SENSOR_MT9V111;
1356 info("MT9V111 sensor detected");
1357 return 0;
1358 }
1359
1360 sd->i2c_addr = 0x5d;
1361 ret = i2c_w2(gspca_dev, 0xf0, 0x0000);
1362 if (ret < 0) {
1363 sd->i2c_addr = 0x48;
1364 i2c_w2(gspca_dev, 0xf0, 0x0000);
1365 }
1366 ret = i2c_r2(gspca_dev, 0x00, &value);
1367 if ((ret == 0) && (value == 0x1229)) {
1368 for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001369 if (i2c_w2(gspca_dev, mt9v112_init[i].reg,
1370 mt9v112_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001371 err("MT9V112 sensor initialization failed");
1372 return -ENODEV;
1373 }
1374 }
1375 sd->hstart = 6;
1376 sd->vstart = 2;
1377 sd->sensor = SENSOR_MT9V112;
1378 info("MT9V112 sensor detected");
1379 return 0;
1380 }
1381
1382 return -ENODEV;
1383}
1384
Brian Johnsone99ac542010-03-16 13:58:28 -03001385static int mt9m112_init_sensor(struct gspca_dev *gspca_dev)
1386{
1387 struct sd *sd = (struct sd *) gspca_dev;
1388 int i;
1389 for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) {
1390 if (i2c_w2(gspca_dev, mt9m112_init[i].reg,
1391 mt9m112_init[i].val) < 0) {
1392 err("MT9M112 sensor initialization failed");
1393 return -ENODEV;
1394 }
1395 }
1396 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
1397 sd->hstart = 0;
1398 sd->vstart = 2;
1399 return 0;
1400}
1401
Brian Johnson26e744b2009-07-19 05:52:58 -03001402static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
1403{
1404 struct sd *sd = (struct sd *) gspca_dev;
1405 int i;
1406 for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001407 if (i2c_w2(gspca_dev, mt9m111_init[i].reg,
1408 mt9m111_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001409 err("MT9M111 sensor initialization failed");
1410 return -ENODEV;
1411 }
1412 }
Brian Johnson13a84fa2009-09-03 19:07:13 -03001413 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001414 sd->hstart = 0;
1415 sd->vstart = 2;
1416 return 0;
1417}
1418
1419static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
1420{
1421 struct sd *sd = (struct sd *) gspca_dev;
1422 int i;
1423 for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001424 if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
1425 mt9m001_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001426 err("MT9M001 sensor initialization failed");
1427 return -ENODEV;
1428 }
1429 }
1430 /* disable hflip and vflip */
1431 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1432 sd->hstart = 2;
1433 sd->vstart = 2;
1434 return 0;
1435}
1436
1437static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
1438{
1439 int i;
1440 struct sd *sd = (struct sd *) gspca_dev;
1441
1442 for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001443 if (i2c_w1(gspca_dev, hv7131r_init[i].reg,
1444 hv7131r_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001445 err("HV7131R Sensor initialization failed");
1446 return -ENODEV;
1447 }
1448 }
1449 sd->hstart = 0;
1450 sd->vstart = 1;
1451 return 0;
1452}
1453
Brian Johnson26e744b2009-07-19 05:52:58 -03001454static int set_cmatrix(struct gspca_dev *gspca_dev)
1455{
1456 struct sd *sd = (struct sd *) gspca_dev;
1457 s32 hue_coord, hue_index = 180 + sd->hue;
1458 u8 cmatrix[21];
Brian Johnson26e744b2009-07-19 05:52:58 -03001459
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001460 memset(cmatrix, 0, sizeof cmatrix);
Brian Johnson26e744b2009-07-19 05:52:58 -03001461 cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26;
1462 cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
1463 cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
1464 cmatrix[18] = sd->brightness - 0x80;
1465
1466 hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001467 cmatrix[6] = hue_coord;
1468 cmatrix[7] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001469
1470 hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001471 cmatrix[8] = hue_coord;
1472 cmatrix[9] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001473
1474 hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001475 cmatrix[10] = hue_coord;
1476 cmatrix[11] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001477
1478 hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001479 cmatrix[12] = hue_coord;
1480 cmatrix[13] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001481
1482 hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001483 cmatrix[14] = hue_coord;
1484 cmatrix[15] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001485
1486 hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001487 cmatrix[16] = hue_coord;
1488 cmatrix[17] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001489
1490 return reg_w(gspca_dev, 0x10e1, cmatrix, 21);
1491}
1492
1493static int set_gamma(struct gspca_dev *gspca_dev)
1494{
1495 struct sd *sd = (struct sd *) gspca_dev;
1496 u8 gamma[17];
1497 u8 gval = sd->gamma * 0xb8 / 0x100;
1498
1499
1500 gamma[0] = 0x0a;
1501 gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
1502 gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8);
1503 gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8);
1504 gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8);
1505 gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8);
1506 gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8);
1507 gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8);
1508 gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8);
1509 gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8);
1510 gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8);
1511 gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8);
1512 gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8);
1513 gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8);
1514 gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8);
1515 gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
1516 gamma[16] = 0xf5;
1517
1518 return reg_w(gspca_dev, 0x1190, gamma, 17);
1519}
1520
1521static int set_redblue(struct gspca_dev *gspca_dev)
1522{
1523 struct sd *sd = (struct sd *) gspca_dev;
1524 reg_w1(gspca_dev, 0x118c, sd->red);
1525 reg_w1(gspca_dev, 0x118f, sd->blue);
1526 return 0;
1527}
1528
1529static int set_hvflip(struct gspca_dev *gspca_dev)
1530{
Brian Johnson7ddaac72010-03-16 13:58:27 -03001531 u8 value, tslb, hflip, vflip;
Brian Johnson26e744b2009-07-19 05:52:58 -03001532 u16 value2;
1533 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001534
1535 if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
1536 hflip = !sd->hflip;
1537 vflip = !sd->vflip;
1538 } else {
1539 hflip = sd->hflip;
1540 vflip = sd->vflip;
1541 }
1542
Brian Johnson26e744b2009-07-19 05:52:58 -03001543 switch (sd->sensor) {
1544 case SENSOR_OV9650:
1545 i2c_r1(gspca_dev, 0x1e, &value);
1546 value &= ~0x30;
1547 tslb = 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001548 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001549 value |= 0x20;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001550 if (vflip) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001551 value |= 0x10;
1552 tslb = 0x49;
1553 }
1554 i2c_w1(gspca_dev, 0x1e, value);
1555 i2c_w1(gspca_dev, 0x3a, tslb);
1556 break;
1557 case SENSOR_MT9V111:
1558 case SENSOR_MT9V011:
1559 i2c_r2(gspca_dev, 0x20, &value2);
1560 value2 &= ~0xc0a0;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001561 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001562 value2 |= 0x8080;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001563 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001564 value2 |= 0x4020;
1565 i2c_w2(gspca_dev, 0x20, value2);
1566 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001567 case SENSOR_MT9M112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001568 case SENSOR_MT9M111:
1569 case SENSOR_MT9V112:
1570 i2c_r2(gspca_dev, 0x20, &value2);
1571 value2 &= ~0x0003;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001572 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001573 value2 |= 0x0002;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001574 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001575 value2 |= 0x0001;
1576 i2c_w2(gspca_dev, 0x20, value2);
1577 break;
1578 case SENSOR_HV7131R:
1579 i2c_r1(gspca_dev, 0x01, &value);
1580 value &= ~0x03;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001581 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001582 value |= 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001583 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001584 value |= 0x02;
1585 i2c_w1(gspca_dev, 0x01, value);
1586 break;
1587 }
1588 return 0;
1589}
1590
1591static int set_exposure(struct gspca_dev *gspca_dev)
1592{
1593 struct sd *sd = (struct sd *) gspca_dev;
1594 u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
1595 switch (sd->sensor) {
1596 case SENSOR_OV7660:
1597 case SENSOR_OV7670:
Brian Johnson26e744b2009-07-19 05:52:58 -03001598 case SENSOR_OV9655:
1599 case SENSOR_OV9650:
1600 exp[0] |= (3 << 4);
1601 exp[2] = 0x2d;
1602 exp[3] = sd->exposure & 0xff;
1603 exp[4] = sd->exposure >> 8;
1604 break;
1605 case SENSOR_MT9M001:
Brian Johnson26e744b2009-07-19 05:52:58 -03001606 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001607 case SENSOR_MT9V011:
1608 exp[0] |= (3 << 4);
1609 exp[2] = 0x09;
1610 exp[3] = sd->exposure >> 8;
1611 exp[4] = sd->exposure & 0xff;
1612 break;
1613 case SENSOR_HV7131R:
1614 exp[0] |= (4 << 4);
1615 exp[2] = 0x25;
German Galkine10f7312010-03-07 06:19:02 -03001616 exp[3] = (sd->exposure >> 5) & 0xff;
1617 exp[4] = (sd->exposure << 3) & 0xff;
1618 exp[5] = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001619 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001620 default:
1621 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001622 }
1623 i2c_w(gspca_dev, exp);
1624 return 0;
1625}
1626
1627static int set_gain(struct gspca_dev *gspca_dev)
1628{
1629 struct sd *sd = (struct sd *) gspca_dev;
1630 u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
1631 switch (sd->sensor) {
1632 case SENSOR_OV7660:
1633 case SENSOR_OV7670:
1634 case SENSOR_SOI968:
1635 case SENSOR_OV9655:
1636 case SENSOR_OV9650:
1637 gain[0] |= (2 << 4);
1638 gain[3] = ov_gain[sd->gain];
1639 break;
1640 case SENSOR_MT9V011:
Brian Johnson26e744b2009-07-19 05:52:58 -03001641 gain[0] |= (3 << 4);
1642 gain[2] = 0x35;
1643 gain[3] = micron1_gain[sd->gain] >> 8;
1644 gain[4] = micron1_gain[sd->gain] & 0xff;
1645 break;
1646 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001647 gain[0] |= (3 << 4);
1648 gain[2] = 0x2f;
1649 gain[3] = micron1_gain[sd->gain] >> 8;
1650 gain[4] = micron1_gain[sd->gain] & 0xff;
1651 break;
1652 case SENSOR_MT9M001:
1653 gain[0] |= (3 << 4);
1654 gain[2] = 0x2f;
1655 gain[3] = micron2_gain[sd->gain] >> 8;
1656 gain[4] = micron2_gain[sd->gain] & 0xff;
1657 break;
1658 case SENSOR_HV7131R:
1659 gain[0] |= (2 << 4);
1660 gain[2] = 0x30;
1661 gain[3] = hv7131r_gain[sd->gain];
1662 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001663 default:
1664 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001665 }
1666 i2c_w(gspca_dev, gain);
1667 return 0;
1668}
1669
1670static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val)
1671{
1672 struct sd *sd = (struct sd *) gspca_dev;
1673
1674 sd->brightness = val;
1675 if (gspca_dev->streaming)
1676 return set_cmatrix(gspca_dev);
1677 return 0;
1678}
1679
1680static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val)
1681{
1682 struct sd *sd = (struct sd *) gspca_dev;
1683 *val = sd->brightness;
1684 return 0;
1685}
1686
1687
1688static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val)
1689{
1690 struct sd *sd = (struct sd *) gspca_dev;
1691
1692 sd->contrast = val;
1693 if (gspca_dev->streaming)
1694 return set_cmatrix(gspca_dev);
1695 return 0;
1696}
1697
1698static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val)
1699{
1700 struct sd *sd = (struct sd *) gspca_dev;
1701 *val = sd->contrast;
1702 return 0;
1703}
1704
1705static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val)
1706{
1707 struct sd *sd = (struct sd *) gspca_dev;
1708
1709 sd->saturation = val;
1710 if (gspca_dev->streaming)
1711 return set_cmatrix(gspca_dev);
1712 return 0;
1713}
1714
1715static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val)
1716{
1717 struct sd *sd = (struct sd *) gspca_dev;
1718 *val = sd->saturation;
1719 return 0;
1720}
1721
1722static int sd_sethue(struct gspca_dev *gspca_dev, s32 val)
1723{
1724 struct sd *sd = (struct sd *) gspca_dev;
1725
1726 sd->hue = val;
1727 if (gspca_dev->streaming)
1728 return set_cmatrix(gspca_dev);
1729 return 0;
1730}
1731
1732static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val)
1733{
1734 struct sd *sd = (struct sd *) gspca_dev;
1735 *val = sd->hue;
1736 return 0;
1737}
1738
1739static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val)
1740{
1741 struct sd *sd = (struct sd *) gspca_dev;
1742
1743 sd->gamma = val;
1744 if (gspca_dev->streaming)
1745 return set_gamma(gspca_dev);
1746 return 0;
1747}
1748
1749static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val)
1750{
1751 struct sd *sd = (struct sd *) gspca_dev;
1752 *val = sd->gamma;
1753 return 0;
1754}
1755
1756static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val)
1757{
1758 struct sd *sd = (struct sd *) gspca_dev;
1759
1760 sd->red = val;
1761 if (gspca_dev->streaming)
1762 return set_redblue(gspca_dev);
1763 return 0;
1764}
1765
1766static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val)
1767{
1768 struct sd *sd = (struct sd *) gspca_dev;
1769 *val = sd->red;
1770 return 0;
1771}
1772
1773static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val)
1774{
1775 struct sd *sd = (struct sd *) gspca_dev;
1776
1777 sd->blue = val;
1778 if (gspca_dev->streaming)
1779 return set_redblue(gspca_dev);
1780 return 0;
1781}
1782
1783static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val)
1784{
1785 struct sd *sd = (struct sd *) gspca_dev;
1786 *val = sd->blue;
1787 return 0;
1788}
1789
1790static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val)
1791{
1792 struct sd *sd = (struct sd *) gspca_dev;
1793
1794 sd->hflip = val;
1795 if (gspca_dev->streaming)
1796 return set_hvflip(gspca_dev);
1797 return 0;
1798}
1799
1800static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val)
1801{
1802 struct sd *sd = (struct sd *) gspca_dev;
1803 *val = sd->hflip;
1804 return 0;
1805}
1806
1807static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val)
1808{
1809 struct sd *sd = (struct sd *) gspca_dev;
1810
1811 sd->vflip = val;
1812 if (gspca_dev->streaming)
1813 return set_hvflip(gspca_dev);
1814 return 0;
1815}
1816
1817static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val)
1818{
1819 struct sd *sd = (struct sd *) gspca_dev;
1820 *val = sd->vflip;
1821 return 0;
1822}
1823
1824static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val)
1825{
1826 struct sd *sd = (struct sd *) gspca_dev;
1827
1828 sd->exposure = val;
1829 if (gspca_dev->streaming)
1830 return set_exposure(gspca_dev);
1831 return 0;
1832}
1833
1834static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val)
1835{
1836 struct sd *sd = (struct sd *) gspca_dev;
1837 *val = sd->exposure;
1838 return 0;
1839}
1840
1841static int sd_setgain(struct gspca_dev *gspca_dev, s32 val)
1842{
1843 struct sd *sd = (struct sd *) gspca_dev;
1844
1845 sd->gain = val;
1846 if (gspca_dev->streaming)
1847 return set_gain(gspca_dev);
1848 return 0;
1849}
1850
1851static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val)
1852{
1853 struct sd *sd = (struct sd *) gspca_dev;
1854 *val = sd->gain;
1855 return 0;
1856}
1857
1858static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val)
1859{
1860 struct sd *sd = (struct sd *) gspca_dev;
1861 sd->auto_exposure = val;
1862 return 0;
1863}
1864
1865static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val)
1866{
1867 struct sd *sd = (struct sd *) gspca_dev;
1868 *val = sd->auto_exposure;
1869 return 0;
1870}
1871
1872#ifdef CONFIG_VIDEO_ADV_DEBUG
1873static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
1874 struct v4l2_dbg_register *reg)
1875{
1876 struct sd *sd = (struct sd *) gspca_dev;
1877 switch (reg->match.type) {
1878 case V4L2_CHIP_MATCH_HOST:
1879 if (reg->match.addr != 0)
1880 return -EINVAL;
1881 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1882 return -EINVAL;
1883 if (reg_r(gspca_dev, reg->reg, 1) < 0)
1884 return -EINVAL;
1885 reg->val = gspca_dev->usb_buf[0];
1886 return 0;
1887 case V4L2_CHIP_MATCH_I2C_ADDR:
1888 if (reg->match.addr != sd->i2c_addr)
1889 return -EINVAL;
1890 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001891 sd->sensor <= SENSOR_MT9M112) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001892 if (i2c_r2(gspca_dev, reg->reg, (u16 *)&reg->val) < 0)
1893 return -EINVAL;
1894 } else {
1895 if (i2c_r1(gspca_dev, reg->reg, (u8 *)&reg->val) < 0)
1896 return -EINVAL;
1897 }
1898 return 0;
1899 }
1900 return -EINVAL;
1901}
1902
1903static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
1904 struct v4l2_dbg_register *reg)
1905{
1906 struct sd *sd = (struct sd *) gspca_dev;
1907 switch (reg->match.type) {
1908 case V4L2_CHIP_MATCH_HOST:
1909 if (reg->match.addr != 0)
1910 return -EINVAL;
1911 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1912 return -EINVAL;
1913 if (reg_w1(gspca_dev, reg->reg, reg->val) < 0)
1914 return -EINVAL;
1915 return 0;
1916 case V4L2_CHIP_MATCH_I2C_ADDR:
1917 if (reg->match.addr != sd->i2c_addr)
1918 return -EINVAL;
1919 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001920 sd->sensor <= SENSOR_MT9M112) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001921 if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0)
1922 return -EINVAL;
1923 } else {
1924 if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0)
1925 return -EINVAL;
1926 }
1927 return 0;
1928 }
1929 return -EINVAL;
1930}
1931#endif
1932
1933static int sd_chip_ident(struct gspca_dev *gspca_dev,
1934 struct v4l2_dbg_chip_ident *chip)
1935{
1936 struct sd *sd = (struct sd *) gspca_dev;
1937
1938 switch (chip->match.type) {
1939 case V4L2_CHIP_MATCH_HOST:
1940 if (chip->match.addr != 0)
1941 return -EINVAL;
1942 chip->revision = 0;
1943 chip->ident = V4L2_IDENT_SN9C20X;
1944 return 0;
1945 case V4L2_CHIP_MATCH_I2C_ADDR:
1946 if (chip->match.addr != sd->i2c_addr)
1947 return -EINVAL;
1948 chip->revision = 0;
1949 chip->ident = i2c_ident[sd->sensor];
1950 return 0;
1951 }
1952 return -EINVAL;
1953}
1954
1955static int sd_config(struct gspca_dev *gspca_dev,
1956 const struct usb_device_id *id)
1957{
1958 struct sd *sd = (struct sd *) gspca_dev;
1959 struct cam *cam;
1960
1961 cam = &gspca_dev->cam;
1962
1963 sd->sensor = (id->driver_info >> 8) & 0xff;
1964 sd->i2c_addr = id->driver_info & 0xff;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03001965 sd->flags = (id->driver_info >> 16) & 0xff;
Brian Johnson26e744b2009-07-19 05:52:58 -03001966
1967 switch (sd->sensor) {
Brian Johnsone99ac542010-03-16 13:58:28 -03001968 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03001969 case SENSOR_MT9M111:
Brian Johnson26e744b2009-07-19 05:52:58 -03001970 case SENSOR_OV9650:
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001971 case SENSOR_SOI968:
Brian Johnson26e744b2009-07-19 05:52:58 -03001972 cam->cam_mode = sxga_mode;
1973 cam->nmodes = ARRAY_SIZE(sxga_mode);
1974 break;
1975 default:
1976 cam->cam_mode = vga_mode;
1977 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001978 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001979 }
1980
1981 sd->old_step = 0;
1982 sd->older_step = 0;
1983 sd->exposure_step = 16;
1984
1985 sd->brightness = BRIGHTNESS_DEFAULT;
1986 sd->contrast = CONTRAST_DEFAULT;
1987 sd->saturation = SATURATION_DEFAULT;
1988 sd->hue = HUE_DEFAULT;
1989 sd->gamma = GAMMA_DEFAULT;
1990 sd->red = RED_DEFAULT;
1991 sd->blue = BLUE_DEFAULT;
1992
1993 sd->hflip = HFLIP_DEFAULT;
1994 sd->vflip = VFLIP_DEFAULT;
1995 sd->exposure = EXPOSURE_DEFAULT;
1996 sd->gain = GAIN_DEFAULT;
1997 sd->auto_exposure = AUTO_EXPOSURE_DEFAULT;
1998
1999 sd->quality = 95;
2000
Brian Johnson26e744b2009-07-19 05:52:58 -03002001 return 0;
2002}
2003
2004static int sd_init(struct gspca_dev *gspca_dev)
2005{
2006 struct sd *sd = (struct sd *) gspca_dev;
2007 int i;
2008 u8 value;
2009 u8 i2c_init[9] =
2010 {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03};
2011
2012 for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
2013 value = bridge_init[i][1];
2014 if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) {
2015 err("Device initialization failed");
2016 return -ENODEV;
2017 }
2018 }
2019
Brian Johnson0c045eb2010-03-16 13:58:27 -03002020 if (sd->flags & LED_REVERSE)
2021 reg_w1(gspca_dev, 0x1006, 0x00);
2022 else
2023 reg_w1(gspca_dev, 0x1006, 0x20);
2024
Brian Johnson26e744b2009-07-19 05:52:58 -03002025 if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
2026 err("Device initialization failed");
2027 return -ENODEV;
2028 }
2029
2030 switch (sd->sensor) {
2031 case SENSOR_OV9650:
2032 if (ov9650_init_sensor(gspca_dev) < 0)
2033 return -ENODEV;
2034 info("OV9650 sensor detected");
2035 break;
2036 case SENSOR_OV9655:
2037 if (ov9655_init_sensor(gspca_dev) < 0)
2038 return -ENODEV;
2039 info("OV9655 sensor detected");
2040 break;
2041 case SENSOR_SOI968:
2042 if (soi968_init_sensor(gspca_dev) < 0)
2043 return -ENODEV;
2044 info("SOI968 sensor detected");
2045 break;
2046 case SENSOR_OV7660:
2047 if (ov7660_init_sensor(gspca_dev) < 0)
2048 return -ENODEV;
2049 info("OV7660 sensor detected");
2050 break;
2051 case SENSOR_OV7670:
2052 if (ov7670_init_sensor(gspca_dev) < 0)
2053 return -ENODEV;
2054 info("OV7670 sensor detected");
2055 break;
2056 case SENSOR_MT9VPRB:
2057 if (mt9v_init_sensor(gspca_dev) < 0)
2058 return -ENODEV;
2059 break;
2060 case SENSOR_MT9M111:
2061 if (mt9m111_init_sensor(gspca_dev) < 0)
2062 return -ENODEV;
2063 info("MT9M111 sensor detected");
2064 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03002065 case SENSOR_MT9M112:
2066 if (mt9m112_init_sensor(gspca_dev) < 0)
2067 return -ENODEV;
2068 info("MT9M112 sensor detected");
2069 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002070 case SENSOR_MT9M001:
2071 if (mt9m001_init_sensor(gspca_dev) < 0)
2072 return -ENODEV;
2073 info("MT9M001 sensor detected");
2074 break;
2075 case SENSOR_HV7131R:
2076 if (hv7131r_init_sensor(gspca_dev) < 0)
2077 return -ENODEV;
2078 info("HV7131R sensor detected");
2079 break;
2080 default:
2081 info("Unsupported Sensor");
2082 return -ENODEV;
2083 }
2084
2085 return 0;
2086}
2087
2088static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
2089{
2090 struct sd *sd = (struct sd *) gspca_dev;
2091 u8 value;
2092 switch (sd->sensor) {
Brian Johnsone8b7acc2009-09-02 13:14:41 -03002093 case SENSOR_SOI968:
2094 if (mode & MODE_SXGA) {
2095 i2c_w1(gspca_dev, 0x17, 0x1d);
2096 i2c_w1(gspca_dev, 0x18, 0xbd);
2097 i2c_w1(gspca_dev, 0x19, 0x01);
2098 i2c_w1(gspca_dev, 0x1a, 0x81);
2099 i2c_w1(gspca_dev, 0x12, 0x00);
2100 sd->hstart = 140;
2101 sd->vstart = 19;
2102 } else {
2103 i2c_w1(gspca_dev, 0x17, 0x13);
2104 i2c_w1(gspca_dev, 0x18, 0x63);
2105 i2c_w1(gspca_dev, 0x19, 0x01);
2106 i2c_w1(gspca_dev, 0x1a, 0x79);
2107 i2c_w1(gspca_dev, 0x12, 0x40);
2108 sd->hstart = 60;
2109 sd->vstart = 11;
2110 }
2111 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002112 case SENSOR_OV9650:
2113 if (mode & MODE_SXGA) {
2114 i2c_w1(gspca_dev, 0x17, 0x1b);
2115 i2c_w1(gspca_dev, 0x18, 0xbc);
2116 i2c_w1(gspca_dev, 0x19, 0x01);
2117 i2c_w1(gspca_dev, 0x1a, 0x82);
2118 i2c_r1(gspca_dev, 0x12, &value);
2119 i2c_w1(gspca_dev, 0x12, value & 0x07);
2120 } else {
2121 i2c_w1(gspca_dev, 0x17, 0x24);
2122 i2c_w1(gspca_dev, 0x18, 0xc5);
2123 i2c_w1(gspca_dev, 0x19, 0x00);
2124 i2c_w1(gspca_dev, 0x1a, 0x3c);
2125 i2c_r1(gspca_dev, 0x12, &value);
2126 i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
2127 }
2128 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03002129 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03002130 case SENSOR_MT9M111:
2131 if (mode & MODE_SXGA) {
2132 i2c_w2(gspca_dev, 0xf0, 0x0002);
2133 i2c_w2(gspca_dev, 0xc8, 0x970b);
2134 i2c_w2(gspca_dev, 0xf0, 0x0000);
2135 } else {
2136 i2c_w2(gspca_dev, 0xf0, 0x0002);
2137 i2c_w2(gspca_dev, 0xc8, 0x8000);
2138 i2c_w2(gspca_dev, 0xf0, 0x0000);
2139 }
2140 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002141 }
2142}
2143
2144#define HW_WIN(mode, hstart, vstart) \
Jean-Francois Moine83955552009-12-12 06:58:01 -03002145((const u8 []){hstart, 0, vstart, 0, \
Brian Johnson26e744b2009-07-19 05:52:58 -03002146(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
2147(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)})
2148
2149#define CLR_WIN(width, height) \
2150((const u8 [])\
2151{0, width >> 2, 0, height >> 1,\
2152((width >> 10) & 0x01) | ((height >> 8) & 0x6)})
2153
2154static int sd_start(struct gspca_dev *gspca_dev)
2155{
2156 struct sd *sd = (struct sd *) gspca_dev;
2157 int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
2158 int width = gspca_dev->width;
2159 int height = gspca_dev->height;
2160 u8 fmt, scale = 0;
2161
Brian Johnson26e744b2009-07-19 05:52:58 -03002162 jpeg_define(sd->jpeg_hdr, height, width,
2163 0x21);
2164 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
2165
2166 if (mode & MODE_RAW)
2167 fmt = 0x2d;
2168 else if (mode & MODE_JPEG)
2169 fmt = 0x2c;
2170 else
2171 fmt = 0x2f;
2172
2173 switch (mode & 0x0f) {
2174 case 3:
2175 scale = 0xc0;
2176 info("Set 1280x1024");
2177 break;
2178 case 2:
2179 scale = 0x80;
2180 info("Set 640x480");
2181 break;
2182 case 1:
2183 scale = 0x90;
2184 info("Set 320x240");
2185 break;
2186 case 0:
2187 scale = 0xa0;
2188 info("Set 160x120");
2189 break;
2190 }
2191
2192 configure_sensor_output(gspca_dev, mode);
Jean-François Moine9a731a32010-06-04 05:26:42 -03002193 reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
2194 reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
Brian Johnson26e744b2009-07-19 05:52:58 -03002195 reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
2196 reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
2197 reg_w1(gspca_dev, 0x1189, scale);
2198 reg_w1(gspca_dev, 0x10e0, fmt);
2199
2200 set_cmatrix(gspca_dev);
2201 set_gamma(gspca_dev);
2202 set_redblue(gspca_dev);
2203 set_gain(gspca_dev);
2204 set_exposure(gspca_dev);
2205 set_hvflip(gspca_dev);
2206
Brian Johnson0c045eb2010-03-16 13:58:27 -03002207 reg_w1(gspca_dev, 0x1007, 0x20);
2208
Brian Johnson26e744b2009-07-19 05:52:58 -03002209 reg_r(gspca_dev, 0x1061, 1);
2210 reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02);
2211 return 0;
2212}
2213
2214static void sd_stopN(struct gspca_dev *gspca_dev)
2215{
Brian Johnson0c045eb2010-03-16 13:58:27 -03002216 reg_w1(gspca_dev, 0x1007, 0x00);
2217
Brian Johnson26e744b2009-07-19 05:52:58 -03002218 reg_r(gspca_dev, 0x1061, 1);
2219 reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
2220}
2221
Brian Johnsone1430472009-09-02 12:39:41 -03002222static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
Brian Johnson26e744b2009-07-19 05:52:58 -03002223{
2224 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnsone1430472009-09-02 12:39:41 -03002225 s16 new_exp;
Brian Johnson26e744b2009-07-19 05:52:58 -03002226
2227 /*
2228 * some hardcoded values are present
2229 * like those for maximal/minimal exposure
2230 * and exposure steps
2231 */
2232 if (avg_lum < MIN_AVG_LUM) {
2233 if (sd->exposure > 0x1770)
2234 return;
2235
2236 new_exp = sd->exposure + sd->exposure_step;
2237 if (new_exp > 0x1770)
2238 new_exp = 0x1770;
2239 if (new_exp < 0x10)
2240 new_exp = 0x10;
2241 sd->exposure = new_exp;
2242 set_exposure(gspca_dev);
2243
2244 sd->older_step = sd->old_step;
2245 sd->old_step = 1;
2246
2247 if (sd->old_step ^ sd->older_step)
2248 sd->exposure_step /= 2;
2249 else
2250 sd->exposure_step += 2;
2251 }
2252 if (avg_lum > MAX_AVG_LUM) {
2253 if (sd->exposure < 0x10)
2254 return;
2255 new_exp = sd->exposure - sd->exposure_step;
2256 if (new_exp > 0x1700)
2257 new_exp = 0x1770;
2258 if (new_exp < 0x10)
2259 new_exp = 0x10;
2260 sd->exposure = new_exp;
2261 set_exposure(gspca_dev);
2262 sd->older_step = sd->old_step;
2263 sd->old_step = 0;
2264
2265 if (sd->old_step ^ sd->older_step)
2266 sd->exposure_step /= 2;
2267 else
2268 sd->exposure_step += 2;
2269 }
2270}
2271
Brian Johnsone1430472009-09-02 12:39:41 -03002272static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
2273{
2274 struct sd *sd = (struct sd *) gspca_dev;
2275
2276 if (avg_lum < MIN_AVG_LUM) {
2277 if (sd->gain + 1 <= 28) {
2278 sd->gain++;
2279 set_gain(gspca_dev);
2280 }
2281 }
2282 if (avg_lum > MAX_AVG_LUM) {
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03002283 if (sd->gain > 0) {
Brian Johnsone1430472009-09-02 12:39:41 -03002284 sd->gain--;
2285 set_gain(gspca_dev);
2286 }
2287 }
2288}
2289
2290static void sd_dqcallback(struct gspca_dev *gspca_dev)
2291{
2292 struct sd *sd = (struct sd *) gspca_dev;
2293 int avg_lum;
2294
2295 if (!sd->auto_exposure)
2296 return;
2297
2298 avg_lum = atomic_read(&sd->avg_lum);
2299 if (sd->sensor == SENSOR_SOI968)
2300 do_autogain(gspca_dev, avg_lum);
2301 else
2302 do_autoexposure(gspca_dev, avg_lum);
2303}
2304
Jean-François Moine28566432010-10-01 07:33:26 -03002305#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002306static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
2307 u8 *data, /* interrupt packet */
2308 int len) /* interrupt packet length */
2309{
2310 struct sd *sd = (struct sd *) gspca_dev;
2311 int ret = -EINVAL;
Brian Johnson33ddc162010-04-18 21:42:40 -03002312 if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002313 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
2314 input_sync(gspca_dev->input_dev);
2315 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
2316 input_sync(gspca_dev->input_dev);
2317 ret = 0;
2318 }
2319 return ret;
2320}
2321#endif
2322
Brian Johnson26e744b2009-07-19 05:52:58 -03002323static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Brian Johnson26e744b2009-07-19 05:52:58 -03002324 u8 *data, /* isoc packet */
2325 int len) /* iso packet length */
2326{
2327 struct sd *sd = (struct sd *) gspca_dev;
2328 int avg_lum;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03002329 static u8 frame_header[] =
Brian Johnson26e744b2009-07-19 05:52:58 -03002330 {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
2331 if (len == 64 && memcmp(data, frame_header, 6) == 0) {
2332 avg_lum = ((data[35] >> 2) & 3) |
2333 (data[20] << 2) |
2334 (data[19] << 10);
2335 avg_lum += ((data[35] >> 4) & 3) |
2336 (data[22] << 2) |
2337 (data[21] << 10);
2338 avg_lum += ((data[35] >> 6) & 3) |
2339 (data[24] << 2) |
2340 (data[23] << 10);
2341 avg_lum += (data[36] & 3) |
2342 (data[26] << 2) |
2343 (data[25] << 10);
2344 avg_lum += ((data[36] >> 2) & 3) |
2345 (data[28] << 2) |
2346 (data[27] << 10);
2347 avg_lum += ((data[36] >> 4) & 3) |
2348 (data[30] << 2) |
2349 (data[29] << 10);
2350 avg_lum += ((data[36] >> 6) & 3) |
2351 (data[32] << 2) |
2352 (data[31] << 10);
2353 avg_lum += ((data[44] >> 4) & 3) |
2354 (data[34] << 2) |
2355 (data[33] << 10);
2356 avg_lum >>= 9;
2357 atomic_set(&sd->avg_lum, avg_lum);
Jean-François Moine04d174e2010-09-13 05:22:37 -03002358 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Brian Johnson26e744b2009-07-19 05:52:58 -03002359 return;
2360 }
2361 if (gspca_dev->last_packet_type == LAST_PACKET) {
2362 if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv
2363 & MODE_JPEG) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002364 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002365 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002366 gspca_frame_add(gspca_dev, INTER_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002367 data, len);
2368 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002369 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002370 data, len);
2371 }
2372 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002373 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Brian Johnson26e744b2009-07-19 05:52:58 -03002374 }
2375}
2376
2377/* sub-driver description */
2378static const struct sd_desc sd_desc = {
2379 .name = MODULE_NAME,
2380 .ctrls = sd_ctrls,
2381 .nctrls = ARRAY_SIZE(sd_ctrls),
2382 .config = sd_config,
2383 .init = sd_init,
2384 .start = sd_start,
2385 .stopN = sd_stopN,
Brian Johnson26e744b2009-07-19 05:52:58 -03002386 .pkt_scan = sd_pkt_scan,
Jean-François Moine28566432010-10-01 07:33:26 -03002387#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002388 .int_pkt_scan = sd_int_pkt_scan,
2389#endif
Brian Johnsone1430472009-09-02 12:39:41 -03002390 .dq_callback = sd_dqcallback,
Brian Johnson26e744b2009-07-19 05:52:58 -03002391#ifdef CONFIG_VIDEO_ADV_DEBUG
2392 .set_register = sd_dbg_s_register,
2393 .get_register = sd_dbg_g_register,
2394#endif
2395 .get_chip_ident = sd_chip_ident,
2396};
2397
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002398#define SN9C20X(sensor, i2c_addr, flags) \
Brian Johnson0c045eb2010-03-16 13:58:27 -03002399 .driver_info = ((flags & 0xff) << 16) \
Brian Johnson26e744b2009-07-19 05:52:58 -03002400 | (SENSOR_ ## sensor << 8) \
2401 | (i2c_addr)
2402
2403static const __devinitdata struct usb_device_id device_table[] = {
2404 {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
2405 {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
2406 {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002407 {USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002408 {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, LED_REVERSE)},
2409 {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30,
2410 (FLIP_DETECT | HAS_NO_BUTTON))},
Brian Johnson26e744b2009-07-19 05:52:58 -03002411 {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
2412 {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
2413 {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
2414 {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)},
2415 {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, 0)},
2416 {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)},
2417 {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)},
2418 {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
2419 {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002420 {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002421 {USB_DEVICE(0x0c45, 0x628c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002422 {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)},
2423 {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
2424 {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
2425 {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
2426 {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002427 {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002428 {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
2429 {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
2430 {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
2431 {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002432 {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)},
2433 {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002434 {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
2435 {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)},
2436 {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)},
2437 {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002438 {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002439 {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)},
2440 {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)},
2441 {}
2442};
2443MODULE_DEVICE_TABLE(usb, device_table);
2444
2445/* -- device connect -- */
2446static int sd_probe(struct usb_interface *intf,
2447 const struct usb_device_id *id)
2448{
2449 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
2450 THIS_MODULE);
2451}
2452
Brian Johnson26e744b2009-07-19 05:52:58 -03002453static struct usb_driver sd_driver = {
2454 .name = MODULE_NAME,
2455 .id_table = device_table,
2456 .probe = sd_probe,
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002457 .disconnect = gspca_disconnect,
Brian Johnson26e744b2009-07-19 05:52:58 -03002458#ifdef CONFIG_PM
2459 .suspend = gspca_suspend,
2460 .resume = gspca_resume,
2461 .reset_resume = gspca_resume,
2462#endif
2463};
2464
2465/* -- module insert / remove -- */
2466static int __init sd_mod_init(void)
2467{
Jean-François Moine54826432010-09-13 04:53:03 -03002468 return usb_register(&sd_driver);
Brian Johnson26e744b2009-07-19 05:52:58 -03002469}
2470static void __exit sd_mod_exit(void)
2471{
2472 usb_deregister(&sd_driver);
Brian Johnson26e744b2009-07-19 05:52:58 -03002473}
2474
2475module_init(sd_mod_init);
2476module_exit(sd_mod_exit);