blob: 6b155ae3a746e18d32c704fd773750f82b220a4b [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 */
Jean-François Moine780e3122010-10-19 04:29:10 -03001273 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX)
1274 | (1 << EXPOSURE_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001275 sd->hstart = 60;
1276 sd->vstart = 11;
1277 return 0;
1278}
1279
1280static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
1281{
1282 int i;
1283 struct sd *sd = (struct sd *) gspca_dev;
1284
1285 for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001286 if (i2c_w1(gspca_dev, ov7660_init[i].reg,
1287 ov7660_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001288 err("OV7660 sensor initialization failed");
1289 return -ENODEV;
1290 }
1291 }
1292 /* disable hflip and vflip */
1293 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1294 sd->hstart = 1;
1295 sd->vstart = 1;
1296 return 0;
1297}
1298
1299static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
1300{
1301 int i;
1302 struct sd *sd = (struct sd *) gspca_dev;
1303
1304 for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001305 if (i2c_w1(gspca_dev, ov7670_init[i].reg,
1306 ov7670_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001307 err("OV7670 sensor initialization failed");
1308 return -ENODEV;
1309 }
1310 }
1311 /* disable hflip and vflip */
1312 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1313 sd->hstart = 0;
1314 sd->vstart = 1;
1315 return 0;
1316}
1317
1318static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
1319{
1320 struct sd *sd = (struct sd *) gspca_dev;
1321 int i;
1322 u16 value;
1323 int ret;
1324
1325 sd->i2c_addr = 0x5d;
1326 ret = i2c_r2(gspca_dev, 0xff, &value);
1327 if ((ret == 0) && (value == 0x8243)) {
1328 for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001329 if (i2c_w2(gspca_dev, mt9v011_init[i].reg,
1330 mt9v011_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001331 err("MT9V011 sensor initialization failed");
1332 return -ENODEV;
1333 }
1334 }
1335 sd->hstart = 2;
1336 sd->vstart = 2;
1337 sd->sensor = SENSOR_MT9V011;
1338 info("MT9V011 sensor detected");
1339 return 0;
1340 }
1341
1342 sd->i2c_addr = 0x5c;
1343 i2c_w2(gspca_dev, 0x01, 0x0004);
1344 ret = i2c_r2(gspca_dev, 0xff, &value);
1345 if ((ret == 0) && (value == 0x823a)) {
1346 for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001347 if (i2c_w2(gspca_dev, mt9v111_init[i].reg,
1348 mt9v111_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001349 err("MT9V111 sensor initialization failed");
1350 return -ENODEV;
1351 }
1352 }
Jean-François Moine780e3122010-10-19 04:29:10 -03001353 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX)
1354 | (1 << AUTOGAIN_IDX)
1355 | (1 << GAIN_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001356 sd->hstart = 2;
1357 sd->vstart = 2;
1358 sd->sensor = SENSOR_MT9V111;
1359 info("MT9V111 sensor detected");
1360 return 0;
1361 }
1362
1363 sd->i2c_addr = 0x5d;
1364 ret = i2c_w2(gspca_dev, 0xf0, 0x0000);
1365 if (ret < 0) {
1366 sd->i2c_addr = 0x48;
1367 i2c_w2(gspca_dev, 0xf0, 0x0000);
1368 }
1369 ret = i2c_r2(gspca_dev, 0x00, &value);
1370 if ((ret == 0) && (value == 0x1229)) {
1371 for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001372 if (i2c_w2(gspca_dev, mt9v112_init[i].reg,
1373 mt9v112_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001374 err("MT9V112 sensor initialization failed");
1375 return -ENODEV;
1376 }
1377 }
1378 sd->hstart = 6;
1379 sd->vstart = 2;
1380 sd->sensor = SENSOR_MT9V112;
1381 info("MT9V112 sensor detected");
1382 return 0;
1383 }
1384
1385 return -ENODEV;
1386}
1387
Brian Johnsone99ac542010-03-16 13:58:28 -03001388static int mt9m112_init_sensor(struct gspca_dev *gspca_dev)
1389{
1390 struct sd *sd = (struct sd *) gspca_dev;
1391 int i;
1392 for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) {
1393 if (i2c_w2(gspca_dev, mt9m112_init[i].reg,
1394 mt9m112_init[i].val) < 0) {
1395 err("MT9M112 sensor initialization failed");
1396 return -ENODEV;
1397 }
1398 }
Jean-François Moine780e3122010-10-19 04:29:10 -03001399 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
1400 | (1 << GAIN_IDX);
Brian Johnsone99ac542010-03-16 13:58:28 -03001401 sd->hstart = 0;
1402 sd->vstart = 2;
1403 return 0;
1404}
1405
Brian Johnson26e744b2009-07-19 05:52:58 -03001406static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
1407{
1408 struct sd *sd = (struct sd *) gspca_dev;
1409 int i;
1410 for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001411 if (i2c_w2(gspca_dev, mt9m111_init[i].reg,
1412 mt9m111_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001413 err("MT9M111 sensor initialization failed");
1414 return -ENODEV;
1415 }
1416 }
Jean-François Moine780e3122010-10-19 04:29:10 -03001417 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
1418 | (1 << GAIN_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001419 sd->hstart = 0;
1420 sd->vstart = 2;
1421 return 0;
1422}
1423
1424static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
1425{
1426 struct sd *sd = (struct sd *) gspca_dev;
1427 int i;
1428 for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001429 if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
1430 mt9m001_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001431 err("MT9M001 sensor initialization failed");
1432 return -ENODEV;
1433 }
1434 }
1435 /* disable hflip and vflip */
1436 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1437 sd->hstart = 2;
1438 sd->vstart = 2;
1439 return 0;
1440}
1441
1442static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
1443{
1444 int i;
1445 struct sd *sd = (struct sd *) gspca_dev;
1446
1447 for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001448 if (i2c_w1(gspca_dev, hv7131r_init[i].reg,
1449 hv7131r_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001450 err("HV7131R Sensor initialization failed");
1451 return -ENODEV;
1452 }
1453 }
1454 sd->hstart = 0;
1455 sd->vstart = 1;
1456 return 0;
1457}
1458
Brian Johnson26e744b2009-07-19 05:52:58 -03001459static int set_cmatrix(struct gspca_dev *gspca_dev)
1460{
1461 struct sd *sd = (struct sd *) gspca_dev;
1462 s32 hue_coord, hue_index = 180 + sd->hue;
1463 u8 cmatrix[21];
Brian Johnson26e744b2009-07-19 05:52:58 -03001464
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001465 memset(cmatrix, 0, sizeof cmatrix);
Brian Johnson26e744b2009-07-19 05:52:58 -03001466 cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26;
1467 cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
1468 cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
1469 cmatrix[18] = sd->brightness - 0x80;
1470
1471 hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001472 cmatrix[6] = hue_coord;
1473 cmatrix[7] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001474
1475 hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001476 cmatrix[8] = hue_coord;
1477 cmatrix[9] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001478
1479 hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001480 cmatrix[10] = hue_coord;
1481 cmatrix[11] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001482
1483 hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001484 cmatrix[12] = hue_coord;
1485 cmatrix[13] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001486
1487 hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001488 cmatrix[14] = hue_coord;
1489 cmatrix[15] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001490
1491 hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001492 cmatrix[16] = hue_coord;
1493 cmatrix[17] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001494
1495 return reg_w(gspca_dev, 0x10e1, cmatrix, 21);
1496}
1497
1498static int set_gamma(struct gspca_dev *gspca_dev)
1499{
1500 struct sd *sd = (struct sd *) gspca_dev;
1501 u8 gamma[17];
1502 u8 gval = sd->gamma * 0xb8 / 0x100;
1503
1504
1505 gamma[0] = 0x0a;
1506 gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
1507 gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8);
1508 gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8);
1509 gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8);
1510 gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8);
1511 gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8);
1512 gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8);
1513 gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8);
1514 gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8);
1515 gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8);
1516 gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8);
1517 gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8);
1518 gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8);
1519 gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8);
1520 gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
1521 gamma[16] = 0xf5;
1522
1523 return reg_w(gspca_dev, 0x1190, gamma, 17);
1524}
1525
1526static int set_redblue(struct gspca_dev *gspca_dev)
1527{
1528 struct sd *sd = (struct sd *) gspca_dev;
1529 reg_w1(gspca_dev, 0x118c, sd->red);
1530 reg_w1(gspca_dev, 0x118f, sd->blue);
1531 return 0;
1532}
1533
1534static int set_hvflip(struct gspca_dev *gspca_dev)
1535{
Brian Johnson7ddaac72010-03-16 13:58:27 -03001536 u8 value, tslb, hflip, vflip;
Brian Johnson26e744b2009-07-19 05:52:58 -03001537 u16 value2;
1538 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001539
1540 if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
1541 hflip = !sd->hflip;
1542 vflip = !sd->vflip;
1543 } else {
1544 hflip = sd->hflip;
1545 vflip = sd->vflip;
1546 }
1547
Brian Johnson26e744b2009-07-19 05:52:58 -03001548 switch (sd->sensor) {
1549 case SENSOR_OV9650:
1550 i2c_r1(gspca_dev, 0x1e, &value);
1551 value &= ~0x30;
1552 tslb = 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001553 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001554 value |= 0x20;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001555 if (vflip) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001556 value |= 0x10;
1557 tslb = 0x49;
1558 }
1559 i2c_w1(gspca_dev, 0x1e, value);
1560 i2c_w1(gspca_dev, 0x3a, tslb);
1561 break;
1562 case SENSOR_MT9V111:
1563 case SENSOR_MT9V011:
1564 i2c_r2(gspca_dev, 0x20, &value2);
1565 value2 &= ~0xc0a0;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001566 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001567 value2 |= 0x8080;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001568 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001569 value2 |= 0x4020;
1570 i2c_w2(gspca_dev, 0x20, value2);
1571 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001572 case SENSOR_MT9M112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001573 case SENSOR_MT9M111:
1574 case SENSOR_MT9V112:
1575 i2c_r2(gspca_dev, 0x20, &value2);
1576 value2 &= ~0x0003;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001577 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001578 value2 |= 0x0002;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001579 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001580 value2 |= 0x0001;
1581 i2c_w2(gspca_dev, 0x20, value2);
1582 break;
1583 case SENSOR_HV7131R:
1584 i2c_r1(gspca_dev, 0x01, &value);
1585 value &= ~0x03;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001586 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001587 value |= 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001588 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001589 value |= 0x02;
1590 i2c_w1(gspca_dev, 0x01, value);
1591 break;
1592 }
1593 return 0;
1594}
1595
1596static int set_exposure(struct gspca_dev *gspca_dev)
1597{
1598 struct sd *sd = (struct sd *) gspca_dev;
1599 u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
1600 switch (sd->sensor) {
1601 case SENSOR_OV7660:
1602 case SENSOR_OV7670:
Brian Johnson26e744b2009-07-19 05:52:58 -03001603 case SENSOR_OV9655:
1604 case SENSOR_OV9650:
1605 exp[0] |= (3 << 4);
1606 exp[2] = 0x2d;
1607 exp[3] = sd->exposure & 0xff;
1608 exp[4] = sd->exposure >> 8;
1609 break;
1610 case SENSOR_MT9M001:
Brian Johnson26e744b2009-07-19 05:52:58 -03001611 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001612 case SENSOR_MT9V011:
1613 exp[0] |= (3 << 4);
1614 exp[2] = 0x09;
1615 exp[3] = sd->exposure >> 8;
1616 exp[4] = sd->exposure & 0xff;
1617 break;
1618 case SENSOR_HV7131R:
1619 exp[0] |= (4 << 4);
1620 exp[2] = 0x25;
German Galkine10f7312010-03-07 06:19:02 -03001621 exp[3] = (sd->exposure >> 5) & 0xff;
1622 exp[4] = (sd->exposure << 3) & 0xff;
1623 exp[5] = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001624 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001625 default:
1626 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001627 }
1628 i2c_w(gspca_dev, exp);
1629 return 0;
1630}
1631
1632static int set_gain(struct gspca_dev *gspca_dev)
1633{
1634 struct sd *sd = (struct sd *) gspca_dev;
1635 u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
1636 switch (sd->sensor) {
1637 case SENSOR_OV7660:
1638 case SENSOR_OV7670:
1639 case SENSOR_SOI968:
1640 case SENSOR_OV9655:
1641 case SENSOR_OV9650:
1642 gain[0] |= (2 << 4);
1643 gain[3] = ov_gain[sd->gain];
1644 break;
1645 case SENSOR_MT9V011:
Brian Johnson26e744b2009-07-19 05:52:58 -03001646 gain[0] |= (3 << 4);
1647 gain[2] = 0x35;
1648 gain[3] = micron1_gain[sd->gain] >> 8;
1649 gain[4] = micron1_gain[sd->gain] & 0xff;
1650 break;
1651 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001652 gain[0] |= (3 << 4);
1653 gain[2] = 0x2f;
1654 gain[3] = micron1_gain[sd->gain] >> 8;
1655 gain[4] = micron1_gain[sd->gain] & 0xff;
1656 break;
1657 case SENSOR_MT9M001:
1658 gain[0] |= (3 << 4);
1659 gain[2] = 0x2f;
1660 gain[3] = micron2_gain[sd->gain] >> 8;
1661 gain[4] = micron2_gain[sd->gain] & 0xff;
1662 break;
1663 case SENSOR_HV7131R:
1664 gain[0] |= (2 << 4);
1665 gain[2] = 0x30;
1666 gain[3] = hv7131r_gain[sd->gain];
1667 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001668 default:
1669 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001670 }
1671 i2c_w(gspca_dev, gain);
1672 return 0;
1673}
1674
1675static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val)
1676{
1677 struct sd *sd = (struct sd *) gspca_dev;
1678
1679 sd->brightness = val;
1680 if (gspca_dev->streaming)
1681 return set_cmatrix(gspca_dev);
1682 return 0;
1683}
1684
1685static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val)
1686{
1687 struct sd *sd = (struct sd *) gspca_dev;
1688 *val = sd->brightness;
1689 return 0;
1690}
1691
1692
1693static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val)
1694{
1695 struct sd *sd = (struct sd *) gspca_dev;
1696
1697 sd->contrast = val;
1698 if (gspca_dev->streaming)
1699 return set_cmatrix(gspca_dev);
1700 return 0;
1701}
1702
1703static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val)
1704{
1705 struct sd *sd = (struct sd *) gspca_dev;
1706 *val = sd->contrast;
1707 return 0;
1708}
1709
1710static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val)
1711{
1712 struct sd *sd = (struct sd *) gspca_dev;
1713
1714 sd->saturation = val;
1715 if (gspca_dev->streaming)
1716 return set_cmatrix(gspca_dev);
1717 return 0;
1718}
1719
1720static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val)
1721{
1722 struct sd *sd = (struct sd *) gspca_dev;
1723 *val = sd->saturation;
1724 return 0;
1725}
1726
1727static int sd_sethue(struct gspca_dev *gspca_dev, s32 val)
1728{
1729 struct sd *sd = (struct sd *) gspca_dev;
1730
1731 sd->hue = val;
1732 if (gspca_dev->streaming)
1733 return set_cmatrix(gspca_dev);
1734 return 0;
1735}
1736
1737static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val)
1738{
1739 struct sd *sd = (struct sd *) gspca_dev;
1740 *val = sd->hue;
1741 return 0;
1742}
1743
1744static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val)
1745{
1746 struct sd *sd = (struct sd *) gspca_dev;
1747
1748 sd->gamma = val;
1749 if (gspca_dev->streaming)
1750 return set_gamma(gspca_dev);
1751 return 0;
1752}
1753
1754static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val)
1755{
1756 struct sd *sd = (struct sd *) gspca_dev;
1757 *val = sd->gamma;
1758 return 0;
1759}
1760
1761static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val)
1762{
1763 struct sd *sd = (struct sd *) gspca_dev;
1764
1765 sd->red = val;
1766 if (gspca_dev->streaming)
1767 return set_redblue(gspca_dev);
1768 return 0;
1769}
1770
1771static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val)
1772{
1773 struct sd *sd = (struct sd *) gspca_dev;
1774 *val = sd->red;
1775 return 0;
1776}
1777
1778static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val)
1779{
1780 struct sd *sd = (struct sd *) gspca_dev;
1781
1782 sd->blue = val;
1783 if (gspca_dev->streaming)
1784 return set_redblue(gspca_dev);
1785 return 0;
1786}
1787
1788static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val)
1789{
1790 struct sd *sd = (struct sd *) gspca_dev;
1791 *val = sd->blue;
1792 return 0;
1793}
1794
1795static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val)
1796{
1797 struct sd *sd = (struct sd *) gspca_dev;
1798
1799 sd->hflip = val;
1800 if (gspca_dev->streaming)
1801 return set_hvflip(gspca_dev);
1802 return 0;
1803}
1804
1805static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val)
1806{
1807 struct sd *sd = (struct sd *) gspca_dev;
1808 *val = sd->hflip;
1809 return 0;
1810}
1811
1812static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val)
1813{
1814 struct sd *sd = (struct sd *) gspca_dev;
1815
1816 sd->vflip = val;
1817 if (gspca_dev->streaming)
1818 return set_hvflip(gspca_dev);
1819 return 0;
1820}
1821
1822static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val)
1823{
1824 struct sd *sd = (struct sd *) gspca_dev;
1825 *val = sd->vflip;
1826 return 0;
1827}
1828
1829static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val)
1830{
1831 struct sd *sd = (struct sd *) gspca_dev;
1832
1833 sd->exposure = val;
1834 if (gspca_dev->streaming)
1835 return set_exposure(gspca_dev);
1836 return 0;
1837}
1838
1839static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val)
1840{
1841 struct sd *sd = (struct sd *) gspca_dev;
1842 *val = sd->exposure;
1843 return 0;
1844}
1845
1846static int sd_setgain(struct gspca_dev *gspca_dev, s32 val)
1847{
1848 struct sd *sd = (struct sd *) gspca_dev;
1849
1850 sd->gain = val;
1851 if (gspca_dev->streaming)
1852 return set_gain(gspca_dev);
1853 return 0;
1854}
1855
1856static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val)
1857{
1858 struct sd *sd = (struct sd *) gspca_dev;
1859 *val = sd->gain;
1860 return 0;
1861}
1862
1863static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val)
1864{
1865 struct sd *sd = (struct sd *) gspca_dev;
1866 sd->auto_exposure = val;
1867 return 0;
1868}
1869
1870static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val)
1871{
1872 struct sd *sd = (struct sd *) gspca_dev;
1873 *val = sd->auto_exposure;
1874 return 0;
1875}
1876
1877#ifdef CONFIG_VIDEO_ADV_DEBUG
1878static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
1879 struct v4l2_dbg_register *reg)
1880{
1881 struct sd *sd = (struct sd *) gspca_dev;
1882 switch (reg->match.type) {
1883 case V4L2_CHIP_MATCH_HOST:
1884 if (reg->match.addr != 0)
1885 return -EINVAL;
1886 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1887 return -EINVAL;
1888 if (reg_r(gspca_dev, reg->reg, 1) < 0)
1889 return -EINVAL;
1890 reg->val = gspca_dev->usb_buf[0];
1891 return 0;
1892 case V4L2_CHIP_MATCH_I2C_ADDR:
1893 if (reg->match.addr != sd->i2c_addr)
1894 return -EINVAL;
1895 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001896 sd->sensor <= SENSOR_MT9M112) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001897 if (i2c_r2(gspca_dev, reg->reg, (u16 *)&reg->val) < 0)
1898 return -EINVAL;
1899 } else {
1900 if (i2c_r1(gspca_dev, reg->reg, (u8 *)&reg->val) < 0)
1901 return -EINVAL;
1902 }
1903 return 0;
1904 }
1905 return -EINVAL;
1906}
1907
1908static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
1909 struct v4l2_dbg_register *reg)
1910{
1911 struct sd *sd = (struct sd *) gspca_dev;
1912 switch (reg->match.type) {
1913 case V4L2_CHIP_MATCH_HOST:
1914 if (reg->match.addr != 0)
1915 return -EINVAL;
1916 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1917 return -EINVAL;
1918 if (reg_w1(gspca_dev, reg->reg, reg->val) < 0)
1919 return -EINVAL;
1920 return 0;
1921 case V4L2_CHIP_MATCH_I2C_ADDR:
1922 if (reg->match.addr != sd->i2c_addr)
1923 return -EINVAL;
1924 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001925 sd->sensor <= SENSOR_MT9M112) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001926 if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0)
1927 return -EINVAL;
1928 } else {
1929 if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0)
1930 return -EINVAL;
1931 }
1932 return 0;
1933 }
1934 return -EINVAL;
1935}
1936#endif
1937
1938static int sd_chip_ident(struct gspca_dev *gspca_dev,
1939 struct v4l2_dbg_chip_ident *chip)
1940{
1941 struct sd *sd = (struct sd *) gspca_dev;
1942
1943 switch (chip->match.type) {
1944 case V4L2_CHIP_MATCH_HOST:
1945 if (chip->match.addr != 0)
1946 return -EINVAL;
1947 chip->revision = 0;
1948 chip->ident = V4L2_IDENT_SN9C20X;
1949 return 0;
1950 case V4L2_CHIP_MATCH_I2C_ADDR:
1951 if (chip->match.addr != sd->i2c_addr)
1952 return -EINVAL;
1953 chip->revision = 0;
1954 chip->ident = i2c_ident[sd->sensor];
1955 return 0;
1956 }
1957 return -EINVAL;
1958}
1959
1960static int sd_config(struct gspca_dev *gspca_dev,
1961 const struct usb_device_id *id)
1962{
1963 struct sd *sd = (struct sd *) gspca_dev;
1964 struct cam *cam;
1965
1966 cam = &gspca_dev->cam;
1967
1968 sd->sensor = (id->driver_info >> 8) & 0xff;
1969 sd->i2c_addr = id->driver_info & 0xff;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03001970 sd->flags = (id->driver_info >> 16) & 0xff;
Brian Johnson26e744b2009-07-19 05:52:58 -03001971
1972 switch (sd->sensor) {
Brian Johnsone99ac542010-03-16 13:58:28 -03001973 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03001974 case SENSOR_MT9M111:
Brian Johnson26e744b2009-07-19 05:52:58 -03001975 case SENSOR_OV9650:
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001976 case SENSOR_SOI968:
Brian Johnson26e744b2009-07-19 05:52:58 -03001977 cam->cam_mode = sxga_mode;
1978 cam->nmodes = ARRAY_SIZE(sxga_mode);
1979 break;
1980 default:
1981 cam->cam_mode = vga_mode;
1982 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001983 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001984 }
1985
1986 sd->old_step = 0;
1987 sd->older_step = 0;
1988 sd->exposure_step = 16;
1989
1990 sd->brightness = BRIGHTNESS_DEFAULT;
1991 sd->contrast = CONTRAST_DEFAULT;
1992 sd->saturation = SATURATION_DEFAULT;
1993 sd->hue = HUE_DEFAULT;
1994 sd->gamma = GAMMA_DEFAULT;
1995 sd->red = RED_DEFAULT;
1996 sd->blue = BLUE_DEFAULT;
1997
1998 sd->hflip = HFLIP_DEFAULT;
1999 sd->vflip = VFLIP_DEFAULT;
2000 sd->exposure = EXPOSURE_DEFAULT;
2001 sd->gain = GAIN_DEFAULT;
2002 sd->auto_exposure = AUTO_EXPOSURE_DEFAULT;
2003
2004 sd->quality = 95;
2005
Brian Johnson26e744b2009-07-19 05:52:58 -03002006 return 0;
2007}
2008
2009static int sd_init(struct gspca_dev *gspca_dev)
2010{
2011 struct sd *sd = (struct sd *) gspca_dev;
2012 int i;
2013 u8 value;
2014 u8 i2c_init[9] =
2015 {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03};
2016
2017 for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
2018 value = bridge_init[i][1];
2019 if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) {
2020 err("Device initialization failed");
2021 return -ENODEV;
2022 }
2023 }
2024
Brian Johnson0c045eb2010-03-16 13:58:27 -03002025 if (sd->flags & LED_REVERSE)
2026 reg_w1(gspca_dev, 0x1006, 0x00);
2027 else
2028 reg_w1(gspca_dev, 0x1006, 0x20);
2029
Brian Johnson26e744b2009-07-19 05:52:58 -03002030 if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
2031 err("Device initialization failed");
2032 return -ENODEV;
2033 }
2034
2035 switch (sd->sensor) {
2036 case SENSOR_OV9650:
2037 if (ov9650_init_sensor(gspca_dev) < 0)
2038 return -ENODEV;
2039 info("OV9650 sensor detected");
2040 break;
2041 case SENSOR_OV9655:
2042 if (ov9655_init_sensor(gspca_dev) < 0)
2043 return -ENODEV;
2044 info("OV9655 sensor detected");
2045 break;
2046 case SENSOR_SOI968:
2047 if (soi968_init_sensor(gspca_dev) < 0)
2048 return -ENODEV;
2049 info("SOI968 sensor detected");
2050 break;
2051 case SENSOR_OV7660:
2052 if (ov7660_init_sensor(gspca_dev) < 0)
2053 return -ENODEV;
2054 info("OV7660 sensor detected");
2055 break;
2056 case SENSOR_OV7670:
2057 if (ov7670_init_sensor(gspca_dev) < 0)
2058 return -ENODEV;
2059 info("OV7670 sensor detected");
2060 break;
2061 case SENSOR_MT9VPRB:
2062 if (mt9v_init_sensor(gspca_dev) < 0)
2063 return -ENODEV;
2064 break;
2065 case SENSOR_MT9M111:
2066 if (mt9m111_init_sensor(gspca_dev) < 0)
2067 return -ENODEV;
2068 info("MT9M111 sensor detected");
2069 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03002070 case SENSOR_MT9M112:
2071 if (mt9m112_init_sensor(gspca_dev) < 0)
2072 return -ENODEV;
2073 info("MT9M112 sensor detected");
2074 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002075 case SENSOR_MT9M001:
2076 if (mt9m001_init_sensor(gspca_dev) < 0)
2077 return -ENODEV;
2078 info("MT9M001 sensor detected");
2079 break;
2080 case SENSOR_HV7131R:
2081 if (hv7131r_init_sensor(gspca_dev) < 0)
2082 return -ENODEV;
2083 info("HV7131R sensor detected");
2084 break;
2085 default:
2086 info("Unsupported Sensor");
2087 return -ENODEV;
2088 }
2089
2090 return 0;
2091}
2092
2093static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
2094{
2095 struct sd *sd = (struct sd *) gspca_dev;
2096 u8 value;
2097 switch (sd->sensor) {
Brian Johnsone8b7acc2009-09-02 13:14:41 -03002098 case SENSOR_SOI968:
2099 if (mode & MODE_SXGA) {
2100 i2c_w1(gspca_dev, 0x17, 0x1d);
2101 i2c_w1(gspca_dev, 0x18, 0xbd);
2102 i2c_w1(gspca_dev, 0x19, 0x01);
2103 i2c_w1(gspca_dev, 0x1a, 0x81);
2104 i2c_w1(gspca_dev, 0x12, 0x00);
2105 sd->hstart = 140;
2106 sd->vstart = 19;
2107 } else {
2108 i2c_w1(gspca_dev, 0x17, 0x13);
2109 i2c_w1(gspca_dev, 0x18, 0x63);
2110 i2c_w1(gspca_dev, 0x19, 0x01);
2111 i2c_w1(gspca_dev, 0x1a, 0x79);
2112 i2c_w1(gspca_dev, 0x12, 0x40);
2113 sd->hstart = 60;
2114 sd->vstart = 11;
2115 }
2116 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002117 case SENSOR_OV9650:
2118 if (mode & MODE_SXGA) {
2119 i2c_w1(gspca_dev, 0x17, 0x1b);
2120 i2c_w1(gspca_dev, 0x18, 0xbc);
2121 i2c_w1(gspca_dev, 0x19, 0x01);
2122 i2c_w1(gspca_dev, 0x1a, 0x82);
2123 i2c_r1(gspca_dev, 0x12, &value);
2124 i2c_w1(gspca_dev, 0x12, value & 0x07);
2125 } else {
2126 i2c_w1(gspca_dev, 0x17, 0x24);
2127 i2c_w1(gspca_dev, 0x18, 0xc5);
2128 i2c_w1(gspca_dev, 0x19, 0x00);
2129 i2c_w1(gspca_dev, 0x1a, 0x3c);
2130 i2c_r1(gspca_dev, 0x12, &value);
2131 i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
2132 }
2133 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03002134 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03002135 case SENSOR_MT9M111:
2136 if (mode & MODE_SXGA) {
2137 i2c_w2(gspca_dev, 0xf0, 0x0002);
2138 i2c_w2(gspca_dev, 0xc8, 0x970b);
2139 i2c_w2(gspca_dev, 0xf0, 0x0000);
2140 } else {
2141 i2c_w2(gspca_dev, 0xf0, 0x0002);
2142 i2c_w2(gspca_dev, 0xc8, 0x8000);
2143 i2c_w2(gspca_dev, 0xf0, 0x0000);
2144 }
2145 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002146 }
2147}
2148
2149#define HW_WIN(mode, hstart, vstart) \
Jean-Francois Moine83955552009-12-12 06:58:01 -03002150((const u8 []){hstart, 0, vstart, 0, \
Brian Johnson26e744b2009-07-19 05:52:58 -03002151(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
2152(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)})
2153
2154#define CLR_WIN(width, height) \
2155((const u8 [])\
2156{0, width >> 2, 0, height >> 1,\
2157((width >> 10) & 0x01) | ((height >> 8) & 0x6)})
2158
2159static int sd_start(struct gspca_dev *gspca_dev)
2160{
2161 struct sd *sd = (struct sd *) gspca_dev;
2162 int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
2163 int width = gspca_dev->width;
2164 int height = gspca_dev->height;
2165 u8 fmt, scale = 0;
2166
Brian Johnson26e744b2009-07-19 05:52:58 -03002167 jpeg_define(sd->jpeg_hdr, height, width,
2168 0x21);
2169 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
2170
2171 if (mode & MODE_RAW)
2172 fmt = 0x2d;
2173 else if (mode & MODE_JPEG)
2174 fmt = 0x2c;
2175 else
2176 fmt = 0x2f;
2177
2178 switch (mode & 0x0f) {
2179 case 3:
2180 scale = 0xc0;
2181 info("Set 1280x1024");
2182 break;
2183 case 2:
2184 scale = 0x80;
2185 info("Set 640x480");
2186 break;
2187 case 1:
2188 scale = 0x90;
2189 info("Set 320x240");
2190 break;
2191 case 0:
2192 scale = 0xa0;
2193 info("Set 160x120");
2194 break;
2195 }
2196
2197 configure_sensor_output(gspca_dev, mode);
Jean-François Moine9a731a32010-06-04 05:26:42 -03002198 reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
2199 reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
Brian Johnson26e744b2009-07-19 05:52:58 -03002200 reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
2201 reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
2202 reg_w1(gspca_dev, 0x1189, scale);
2203 reg_w1(gspca_dev, 0x10e0, fmt);
2204
2205 set_cmatrix(gspca_dev);
2206 set_gamma(gspca_dev);
2207 set_redblue(gspca_dev);
2208 set_gain(gspca_dev);
2209 set_exposure(gspca_dev);
2210 set_hvflip(gspca_dev);
2211
Brian Johnson0c045eb2010-03-16 13:58:27 -03002212 reg_w1(gspca_dev, 0x1007, 0x20);
2213
Brian Johnson26e744b2009-07-19 05:52:58 -03002214 reg_r(gspca_dev, 0x1061, 1);
2215 reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02);
2216 return 0;
2217}
2218
2219static void sd_stopN(struct gspca_dev *gspca_dev)
2220{
Brian Johnson0c045eb2010-03-16 13:58:27 -03002221 reg_w1(gspca_dev, 0x1007, 0x00);
2222
Brian Johnson26e744b2009-07-19 05:52:58 -03002223 reg_r(gspca_dev, 0x1061, 1);
2224 reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
2225}
2226
Brian Johnsone1430472009-09-02 12:39:41 -03002227static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
Brian Johnson26e744b2009-07-19 05:52:58 -03002228{
2229 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnsone1430472009-09-02 12:39:41 -03002230 s16 new_exp;
Brian Johnson26e744b2009-07-19 05:52:58 -03002231
2232 /*
2233 * some hardcoded values are present
2234 * like those for maximal/minimal exposure
2235 * and exposure steps
2236 */
2237 if (avg_lum < MIN_AVG_LUM) {
2238 if (sd->exposure > 0x1770)
2239 return;
2240
2241 new_exp = sd->exposure + sd->exposure_step;
2242 if (new_exp > 0x1770)
2243 new_exp = 0x1770;
2244 if (new_exp < 0x10)
2245 new_exp = 0x10;
2246 sd->exposure = new_exp;
2247 set_exposure(gspca_dev);
2248
2249 sd->older_step = sd->old_step;
2250 sd->old_step = 1;
2251
2252 if (sd->old_step ^ sd->older_step)
2253 sd->exposure_step /= 2;
2254 else
2255 sd->exposure_step += 2;
2256 }
2257 if (avg_lum > MAX_AVG_LUM) {
2258 if (sd->exposure < 0x10)
2259 return;
2260 new_exp = sd->exposure - sd->exposure_step;
2261 if (new_exp > 0x1700)
2262 new_exp = 0x1770;
2263 if (new_exp < 0x10)
2264 new_exp = 0x10;
2265 sd->exposure = new_exp;
2266 set_exposure(gspca_dev);
2267 sd->older_step = sd->old_step;
2268 sd->old_step = 0;
2269
2270 if (sd->old_step ^ sd->older_step)
2271 sd->exposure_step /= 2;
2272 else
2273 sd->exposure_step += 2;
2274 }
2275}
2276
Brian Johnsone1430472009-09-02 12:39:41 -03002277static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
2278{
2279 struct sd *sd = (struct sd *) gspca_dev;
2280
2281 if (avg_lum < MIN_AVG_LUM) {
2282 if (sd->gain + 1 <= 28) {
2283 sd->gain++;
2284 set_gain(gspca_dev);
2285 }
2286 }
2287 if (avg_lum > MAX_AVG_LUM) {
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03002288 if (sd->gain > 0) {
Brian Johnsone1430472009-09-02 12:39:41 -03002289 sd->gain--;
2290 set_gain(gspca_dev);
2291 }
2292 }
2293}
2294
2295static void sd_dqcallback(struct gspca_dev *gspca_dev)
2296{
2297 struct sd *sd = (struct sd *) gspca_dev;
2298 int avg_lum;
2299
2300 if (!sd->auto_exposure)
2301 return;
2302
2303 avg_lum = atomic_read(&sd->avg_lum);
2304 if (sd->sensor == SENSOR_SOI968)
2305 do_autogain(gspca_dev, avg_lum);
2306 else
2307 do_autoexposure(gspca_dev, avg_lum);
2308}
2309
Jean-François Moine28566432010-10-01 07:33:26 -03002310#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002311static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
2312 u8 *data, /* interrupt packet */
2313 int len) /* interrupt packet length */
2314{
2315 struct sd *sd = (struct sd *) gspca_dev;
2316 int ret = -EINVAL;
Brian Johnson33ddc162010-04-18 21:42:40 -03002317 if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002318 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
2319 input_sync(gspca_dev->input_dev);
2320 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
2321 input_sync(gspca_dev->input_dev);
2322 ret = 0;
2323 }
2324 return ret;
2325}
2326#endif
2327
Brian Johnson26e744b2009-07-19 05:52:58 -03002328static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Brian Johnson26e744b2009-07-19 05:52:58 -03002329 u8 *data, /* isoc packet */
2330 int len) /* iso packet length */
2331{
2332 struct sd *sd = (struct sd *) gspca_dev;
2333 int avg_lum;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03002334 static u8 frame_header[] =
Brian Johnson26e744b2009-07-19 05:52:58 -03002335 {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
2336 if (len == 64 && memcmp(data, frame_header, 6) == 0) {
2337 avg_lum = ((data[35] >> 2) & 3) |
2338 (data[20] << 2) |
2339 (data[19] << 10);
2340 avg_lum += ((data[35] >> 4) & 3) |
2341 (data[22] << 2) |
2342 (data[21] << 10);
2343 avg_lum += ((data[35] >> 6) & 3) |
2344 (data[24] << 2) |
2345 (data[23] << 10);
2346 avg_lum += (data[36] & 3) |
2347 (data[26] << 2) |
2348 (data[25] << 10);
2349 avg_lum += ((data[36] >> 2) & 3) |
2350 (data[28] << 2) |
2351 (data[27] << 10);
2352 avg_lum += ((data[36] >> 4) & 3) |
2353 (data[30] << 2) |
2354 (data[29] << 10);
2355 avg_lum += ((data[36] >> 6) & 3) |
2356 (data[32] << 2) |
2357 (data[31] << 10);
2358 avg_lum += ((data[44] >> 4) & 3) |
2359 (data[34] << 2) |
2360 (data[33] << 10);
2361 avg_lum >>= 9;
2362 atomic_set(&sd->avg_lum, avg_lum);
Jean-François Moine04d174e2010-09-13 05:22:37 -03002363 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Brian Johnson26e744b2009-07-19 05:52:58 -03002364 return;
2365 }
2366 if (gspca_dev->last_packet_type == LAST_PACKET) {
2367 if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv
2368 & MODE_JPEG) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002369 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002370 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002371 gspca_frame_add(gspca_dev, INTER_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002372 data, len);
2373 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002374 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002375 data, len);
2376 }
2377 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002378 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Brian Johnson26e744b2009-07-19 05:52:58 -03002379 }
2380}
2381
2382/* sub-driver description */
2383static const struct sd_desc sd_desc = {
2384 .name = MODULE_NAME,
2385 .ctrls = sd_ctrls,
2386 .nctrls = ARRAY_SIZE(sd_ctrls),
2387 .config = sd_config,
2388 .init = sd_init,
2389 .start = sd_start,
2390 .stopN = sd_stopN,
Brian Johnson26e744b2009-07-19 05:52:58 -03002391 .pkt_scan = sd_pkt_scan,
Jean-François Moine28566432010-10-01 07:33:26 -03002392#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002393 .int_pkt_scan = sd_int_pkt_scan,
2394#endif
Brian Johnsone1430472009-09-02 12:39:41 -03002395 .dq_callback = sd_dqcallback,
Brian Johnson26e744b2009-07-19 05:52:58 -03002396#ifdef CONFIG_VIDEO_ADV_DEBUG
2397 .set_register = sd_dbg_s_register,
2398 .get_register = sd_dbg_g_register,
2399#endif
2400 .get_chip_ident = sd_chip_ident,
2401};
2402
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002403#define SN9C20X(sensor, i2c_addr, flags) \
Brian Johnson0c045eb2010-03-16 13:58:27 -03002404 .driver_info = ((flags & 0xff) << 16) \
Brian Johnson26e744b2009-07-19 05:52:58 -03002405 | (SENSOR_ ## sensor << 8) \
2406 | (i2c_addr)
2407
2408static const __devinitdata struct usb_device_id device_table[] = {
2409 {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
2410 {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
2411 {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002412 {USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002413 {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, LED_REVERSE)},
2414 {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30,
2415 (FLIP_DETECT | HAS_NO_BUTTON))},
Brian Johnson26e744b2009-07-19 05:52:58 -03002416 {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
2417 {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
2418 {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
2419 {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)},
2420 {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, 0)},
2421 {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)},
2422 {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)},
2423 {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
2424 {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002425 {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002426 {USB_DEVICE(0x0c45, 0x628c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002427 {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)},
2428 {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
2429 {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
2430 {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
2431 {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002432 {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002433 {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
2434 {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
2435 {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
2436 {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002437 {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)},
2438 {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002439 {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
2440 {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)},
2441 {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)},
2442 {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002443 {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002444 {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)},
2445 {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)},
2446 {}
2447};
2448MODULE_DEVICE_TABLE(usb, device_table);
2449
2450/* -- device connect -- */
2451static int sd_probe(struct usb_interface *intf,
2452 const struct usb_device_id *id)
2453{
2454 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
2455 THIS_MODULE);
2456}
2457
Brian Johnson26e744b2009-07-19 05:52:58 -03002458static struct usb_driver sd_driver = {
2459 .name = MODULE_NAME,
2460 .id_table = device_table,
2461 .probe = sd_probe,
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002462 .disconnect = gspca_disconnect,
Brian Johnson26e744b2009-07-19 05:52:58 -03002463#ifdef CONFIG_PM
2464 .suspend = gspca_suspend,
2465 .resume = gspca_resume,
2466 .reset_resume = gspca_resume,
2467#endif
2468};
2469
2470/* -- module insert / remove -- */
2471static int __init sd_mod_init(void)
2472{
Jean-François Moine54826432010-09-13 04:53:03 -03002473 return usb_register(&sd_driver);
Brian Johnson26e744b2009-07-19 05:52:58 -03002474}
2475static void __exit sd_mod_exit(void)
2476{
2477 usb_deregister(&sd_driver);
Brian Johnson26e744b2009-07-19 05:52:58 -03002478}
2479
2480module_init(sd_mod_init);
2481module_exit(sd_mod_exit);