blob: 1e0f219188acb7bdb86ad472d7448d61cd86b26a [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;
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001227 u16 id;
Brian Johnson26e744b2009-07-19 05:52:58 -03001228 struct sd *sd = (struct sd *) gspca_dev;
1229
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001230 if (i2c_r2(gspca_dev, 0x1c, &id) < 0)
1231 return -EINVAL;
1232
1233 if (id != 0x7fa2) {
1234 err("sensor id for ov9650 doesn't match (0x%04x)", id);
1235 return -ENODEV;
1236 }
1237
Brian Johnson26e744b2009-07-19 05:52:58 -03001238 for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001239 if (i2c_w1(gspca_dev, ov9650_init[i].reg,
1240 ov9650_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001241 err("OV9650 sensor initialization failed");
1242 return -ENODEV;
1243 }
1244 }
1245 sd->hstart = 1;
1246 sd->vstart = 7;
1247 return 0;
1248}
1249
1250static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
1251{
1252 int i;
1253 struct sd *sd = (struct sd *) gspca_dev;
1254
1255 for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001256 if (i2c_w1(gspca_dev, ov9655_init[i].reg,
1257 ov9655_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001258 err("OV9655 sensor initialization failed");
1259 return -ENODEV;
1260 }
1261 }
1262 /* disable hflip and vflip */
1263 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
Brian Johnsoncc2a8332010-03-16 13:58:28 -03001264 sd->hstart = 1;
1265 sd->vstart = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001266 return 0;
1267}
1268
1269static int soi968_init_sensor(struct gspca_dev *gspca_dev)
1270{
1271 int i;
1272 struct sd *sd = (struct sd *) gspca_dev;
1273
1274 for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001275 if (i2c_w1(gspca_dev, soi968_init[i].reg,
1276 soi968_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001277 err("SOI968 sensor initialization failed");
1278 return -ENODEV;
1279 }
1280 }
1281 /* disable hflip and vflip */
Jean-François Moine780e3122010-10-19 04:29:10 -03001282 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX)
1283 | (1 << EXPOSURE_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001284 sd->hstart = 60;
1285 sd->vstart = 11;
1286 return 0;
1287}
1288
1289static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
1290{
1291 int i;
1292 struct sd *sd = (struct sd *) gspca_dev;
1293
1294 for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001295 if (i2c_w1(gspca_dev, ov7660_init[i].reg,
1296 ov7660_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001297 err("OV7660 sensor initialization failed");
1298 return -ENODEV;
1299 }
1300 }
1301 /* disable hflip and vflip */
1302 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1303 sd->hstart = 1;
1304 sd->vstart = 1;
1305 return 0;
1306}
1307
1308static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
1309{
1310 int i;
1311 struct sd *sd = (struct sd *) gspca_dev;
1312
1313 for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001314 if (i2c_w1(gspca_dev, ov7670_init[i].reg,
1315 ov7670_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001316 err("OV7670 sensor initialization failed");
1317 return -ENODEV;
1318 }
1319 }
1320 /* disable hflip and vflip */
1321 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1322 sd->hstart = 0;
1323 sd->vstart = 1;
1324 return 0;
1325}
1326
1327static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
1328{
1329 struct sd *sd = (struct sd *) gspca_dev;
1330 int i;
1331 u16 value;
1332 int ret;
1333
1334 sd->i2c_addr = 0x5d;
1335 ret = i2c_r2(gspca_dev, 0xff, &value);
1336 if ((ret == 0) && (value == 0x8243)) {
1337 for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001338 if (i2c_w2(gspca_dev, mt9v011_init[i].reg,
1339 mt9v011_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001340 err("MT9V011 sensor initialization failed");
1341 return -ENODEV;
1342 }
1343 }
1344 sd->hstart = 2;
1345 sd->vstart = 2;
1346 sd->sensor = SENSOR_MT9V011;
1347 info("MT9V011 sensor detected");
1348 return 0;
1349 }
1350
1351 sd->i2c_addr = 0x5c;
1352 i2c_w2(gspca_dev, 0x01, 0x0004);
1353 ret = i2c_r2(gspca_dev, 0xff, &value);
1354 if ((ret == 0) && (value == 0x823a)) {
1355 for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001356 if (i2c_w2(gspca_dev, mt9v111_init[i].reg,
1357 mt9v111_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001358 err("MT9V111 sensor initialization failed");
1359 return -ENODEV;
1360 }
1361 }
Jean-François Moine780e3122010-10-19 04:29:10 -03001362 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX)
1363 | (1 << AUTOGAIN_IDX)
1364 | (1 << GAIN_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001365 sd->hstart = 2;
1366 sd->vstart = 2;
1367 sd->sensor = SENSOR_MT9V111;
1368 info("MT9V111 sensor detected");
1369 return 0;
1370 }
1371
1372 sd->i2c_addr = 0x5d;
1373 ret = i2c_w2(gspca_dev, 0xf0, 0x0000);
1374 if (ret < 0) {
1375 sd->i2c_addr = 0x48;
1376 i2c_w2(gspca_dev, 0xf0, 0x0000);
1377 }
1378 ret = i2c_r2(gspca_dev, 0x00, &value);
1379 if ((ret == 0) && (value == 0x1229)) {
1380 for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001381 if (i2c_w2(gspca_dev, mt9v112_init[i].reg,
1382 mt9v112_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001383 err("MT9V112 sensor initialization failed");
1384 return -ENODEV;
1385 }
1386 }
1387 sd->hstart = 6;
1388 sd->vstart = 2;
1389 sd->sensor = SENSOR_MT9V112;
1390 info("MT9V112 sensor detected");
1391 return 0;
1392 }
1393
1394 return -ENODEV;
1395}
1396
Brian Johnsone99ac542010-03-16 13:58:28 -03001397static int mt9m112_init_sensor(struct gspca_dev *gspca_dev)
1398{
1399 struct sd *sd = (struct sd *) gspca_dev;
1400 int i;
1401 for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) {
1402 if (i2c_w2(gspca_dev, mt9m112_init[i].reg,
1403 mt9m112_init[i].val) < 0) {
1404 err("MT9M112 sensor initialization failed");
1405 return -ENODEV;
1406 }
1407 }
Jean-François Moine780e3122010-10-19 04:29:10 -03001408 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
1409 | (1 << GAIN_IDX);
Brian Johnsone99ac542010-03-16 13:58:28 -03001410 sd->hstart = 0;
1411 sd->vstart = 2;
1412 return 0;
1413}
1414
Brian Johnson26e744b2009-07-19 05:52:58 -03001415static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
1416{
1417 struct sd *sd = (struct sd *) gspca_dev;
1418 int i;
1419 for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001420 if (i2c_w2(gspca_dev, mt9m111_init[i].reg,
1421 mt9m111_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001422 err("MT9M111 sensor initialization failed");
1423 return -ENODEV;
1424 }
1425 }
Jean-François Moine780e3122010-10-19 04:29:10 -03001426 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
1427 | (1 << GAIN_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001428 sd->hstart = 0;
1429 sd->vstart = 2;
1430 return 0;
1431}
1432
1433static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
1434{
1435 struct sd *sd = (struct sd *) gspca_dev;
1436 int i;
1437 for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001438 if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
1439 mt9m001_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001440 err("MT9M001 sensor initialization failed");
1441 return -ENODEV;
1442 }
1443 }
1444 /* disable hflip and vflip */
1445 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1446 sd->hstart = 2;
1447 sd->vstart = 2;
1448 return 0;
1449}
1450
1451static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
1452{
1453 int i;
1454 struct sd *sd = (struct sd *) gspca_dev;
1455
1456 for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001457 if (i2c_w1(gspca_dev, hv7131r_init[i].reg,
1458 hv7131r_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001459 err("HV7131R Sensor initialization failed");
1460 return -ENODEV;
1461 }
1462 }
1463 sd->hstart = 0;
1464 sd->vstart = 1;
1465 return 0;
1466}
1467
Brian Johnson26e744b2009-07-19 05:52:58 -03001468static int set_cmatrix(struct gspca_dev *gspca_dev)
1469{
1470 struct sd *sd = (struct sd *) gspca_dev;
1471 s32 hue_coord, hue_index = 180 + sd->hue;
1472 u8 cmatrix[21];
Brian Johnson26e744b2009-07-19 05:52:58 -03001473
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001474 memset(cmatrix, 0, sizeof cmatrix);
Brian Johnson26e744b2009-07-19 05:52:58 -03001475 cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26;
1476 cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
1477 cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
1478 cmatrix[18] = sd->brightness - 0x80;
1479
1480 hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001481 cmatrix[6] = hue_coord;
1482 cmatrix[7] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001483
1484 hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001485 cmatrix[8] = hue_coord;
1486 cmatrix[9] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001487
1488 hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001489 cmatrix[10] = hue_coord;
1490 cmatrix[11] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001491
1492 hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001493 cmatrix[12] = hue_coord;
1494 cmatrix[13] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001495
1496 hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001497 cmatrix[14] = hue_coord;
1498 cmatrix[15] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001499
1500 hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001501 cmatrix[16] = hue_coord;
1502 cmatrix[17] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001503
1504 return reg_w(gspca_dev, 0x10e1, cmatrix, 21);
1505}
1506
1507static int set_gamma(struct gspca_dev *gspca_dev)
1508{
1509 struct sd *sd = (struct sd *) gspca_dev;
1510 u8 gamma[17];
1511 u8 gval = sd->gamma * 0xb8 / 0x100;
1512
1513
1514 gamma[0] = 0x0a;
1515 gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
1516 gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8);
1517 gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8);
1518 gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8);
1519 gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8);
1520 gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8);
1521 gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8);
1522 gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8);
1523 gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8);
1524 gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8);
1525 gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8);
1526 gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8);
1527 gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8);
1528 gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8);
1529 gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
1530 gamma[16] = 0xf5;
1531
1532 return reg_w(gspca_dev, 0x1190, gamma, 17);
1533}
1534
1535static int set_redblue(struct gspca_dev *gspca_dev)
1536{
1537 struct sd *sd = (struct sd *) gspca_dev;
1538 reg_w1(gspca_dev, 0x118c, sd->red);
1539 reg_w1(gspca_dev, 0x118f, sd->blue);
1540 return 0;
1541}
1542
1543static int set_hvflip(struct gspca_dev *gspca_dev)
1544{
Brian Johnson7ddaac72010-03-16 13:58:27 -03001545 u8 value, tslb, hflip, vflip;
Brian Johnson26e744b2009-07-19 05:52:58 -03001546 u16 value2;
1547 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001548
1549 if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
1550 hflip = !sd->hflip;
1551 vflip = !sd->vflip;
1552 } else {
1553 hflip = sd->hflip;
1554 vflip = sd->vflip;
1555 }
1556
Brian Johnson26e744b2009-07-19 05:52:58 -03001557 switch (sd->sensor) {
1558 case SENSOR_OV9650:
1559 i2c_r1(gspca_dev, 0x1e, &value);
1560 value &= ~0x30;
1561 tslb = 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001562 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001563 value |= 0x20;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001564 if (vflip) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001565 value |= 0x10;
1566 tslb = 0x49;
1567 }
1568 i2c_w1(gspca_dev, 0x1e, value);
1569 i2c_w1(gspca_dev, 0x3a, tslb);
1570 break;
1571 case SENSOR_MT9V111:
1572 case SENSOR_MT9V011:
1573 i2c_r2(gspca_dev, 0x20, &value2);
1574 value2 &= ~0xc0a0;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001575 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001576 value2 |= 0x8080;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001577 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001578 value2 |= 0x4020;
1579 i2c_w2(gspca_dev, 0x20, value2);
1580 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001581 case SENSOR_MT9M112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001582 case SENSOR_MT9M111:
1583 case SENSOR_MT9V112:
1584 i2c_r2(gspca_dev, 0x20, &value2);
1585 value2 &= ~0x0003;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001586 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001587 value2 |= 0x0002;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001588 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001589 value2 |= 0x0001;
1590 i2c_w2(gspca_dev, 0x20, value2);
1591 break;
1592 case SENSOR_HV7131R:
1593 i2c_r1(gspca_dev, 0x01, &value);
1594 value &= ~0x03;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001595 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001596 value |= 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001597 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001598 value |= 0x02;
1599 i2c_w1(gspca_dev, 0x01, value);
1600 break;
1601 }
1602 return 0;
1603}
1604
1605static int set_exposure(struct gspca_dev *gspca_dev)
1606{
1607 struct sd *sd = (struct sd *) gspca_dev;
1608 u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
1609 switch (sd->sensor) {
1610 case SENSOR_OV7660:
1611 case SENSOR_OV7670:
Brian Johnson26e744b2009-07-19 05:52:58 -03001612 case SENSOR_OV9655:
1613 case SENSOR_OV9650:
1614 exp[0] |= (3 << 4);
1615 exp[2] = 0x2d;
1616 exp[3] = sd->exposure & 0xff;
1617 exp[4] = sd->exposure >> 8;
1618 break;
1619 case SENSOR_MT9M001:
Brian Johnson26e744b2009-07-19 05:52:58 -03001620 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001621 case SENSOR_MT9V011:
1622 exp[0] |= (3 << 4);
1623 exp[2] = 0x09;
1624 exp[3] = sd->exposure >> 8;
1625 exp[4] = sd->exposure & 0xff;
1626 break;
1627 case SENSOR_HV7131R:
1628 exp[0] |= (4 << 4);
1629 exp[2] = 0x25;
German Galkine10f7312010-03-07 06:19:02 -03001630 exp[3] = (sd->exposure >> 5) & 0xff;
1631 exp[4] = (sd->exposure << 3) & 0xff;
1632 exp[5] = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001633 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001634 default:
1635 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001636 }
1637 i2c_w(gspca_dev, exp);
1638 return 0;
1639}
1640
1641static int set_gain(struct gspca_dev *gspca_dev)
1642{
1643 struct sd *sd = (struct sd *) gspca_dev;
1644 u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
1645 switch (sd->sensor) {
1646 case SENSOR_OV7660:
1647 case SENSOR_OV7670:
1648 case SENSOR_SOI968:
1649 case SENSOR_OV9655:
1650 case SENSOR_OV9650:
1651 gain[0] |= (2 << 4);
1652 gain[3] = ov_gain[sd->gain];
1653 break;
1654 case SENSOR_MT9V011:
Brian Johnson26e744b2009-07-19 05:52:58 -03001655 gain[0] |= (3 << 4);
1656 gain[2] = 0x35;
1657 gain[3] = micron1_gain[sd->gain] >> 8;
1658 gain[4] = micron1_gain[sd->gain] & 0xff;
1659 break;
1660 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001661 gain[0] |= (3 << 4);
1662 gain[2] = 0x2f;
1663 gain[3] = micron1_gain[sd->gain] >> 8;
1664 gain[4] = micron1_gain[sd->gain] & 0xff;
1665 break;
1666 case SENSOR_MT9M001:
1667 gain[0] |= (3 << 4);
1668 gain[2] = 0x2f;
1669 gain[3] = micron2_gain[sd->gain] >> 8;
1670 gain[4] = micron2_gain[sd->gain] & 0xff;
1671 break;
1672 case SENSOR_HV7131R:
1673 gain[0] |= (2 << 4);
1674 gain[2] = 0x30;
1675 gain[3] = hv7131r_gain[sd->gain];
1676 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001677 default:
1678 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001679 }
1680 i2c_w(gspca_dev, gain);
1681 return 0;
1682}
1683
1684static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val)
1685{
1686 struct sd *sd = (struct sd *) gspca_dev;
1687
1688 sd->brightness = val;
1689 if (gspca_dev->streaming)
1690 return set_cmatrix(gspca_dev);
1691 return 0;
1692}
1693
1694static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val)
1695{
1696 struct sd *sd = (struct sd *) gspca_dev;
1697 *val = sd->brightness;
1698 return 0;
1699}
1700
1701
1702static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val)
1703{
1704 struct sd *sd = (struct sd *) gspca_dev;
1705
1706 sd->contrast = val;
1707 if (gspca_dev->streaming)
1708 return set_cmatrix(gspca_dev);
1709 return 0;
1710}
1711
1712static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val)
1713{
1714 struct sd *sd = (struct sd *) gspca_dev;
1715 *val = sd->contrast;
1716 return 0;
1717}
1718
1719static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val)
1720{
1721 struct sd *sd = (struct sd *) gspca_dev;
1722
1723 sd->saturation = val;
1724 if (gspca_dev->streaming)
1725 return set_cmatrix(gspca_dev);
1726 return 0;
1727}
1728
1729static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val)
1730{
1731 struct sd *sd = (struct sd *) gspca_dev;
1732 *val = sd->saturation;
1733 return 0;
1734}
1735
1736static int sd_sethue(struct gspca_dev *gspca_dev, s32 val)
1737{
1738 struct sd *sd = (struct sd *) gspca_dev;
1739
1740 sd->hue = val;
1741 if (gspca_dev->streaming)
1742 return set_cmatrix(gspca_dev);
1743 return 0;
1744}
1745
1746static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val)
1747{
1748 struct sd *sd = (struct sd *) gspca_dev;
1749 *val = sd->hue;
1750 return 0;
1751}
1752
1753static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val)
1754{
1755 struct sd *sd = (struct sd *) gspca_dev;
1756
1757 sd->gamma = val;
1758 if (gspca_dev->streaming)
1759 return set_gamma(gspca_dev);
1760 return 0;
1761}
1762
1763static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val)
1764{
1765 struct sd *sd = (struct sd *) gspca_dev;
1766 *val = sd->gamma;
1767 return 0;
1768}
1769
1770static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val)
1771{
1772 struct sd *sd = (struct sd *) gspca_dev;
1773
1774 sd->red = val;
1775 if (gspca_dev->streaming)
1776 return set_redblue(gspca_dev);
1777 return 0;
1778}
1779
1780static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val)
1781{
1782 struct sd *sd = (struct sd *) gspca_dev;
1783 *val = sd->red;
1784 return 0;
1785}
1786
1787static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val)
1788{
1789 struct sd *sd = (struct sd *) gspca_dev;
1790
1791 sd->blue = val;
1792 if (gspca_dev->streaming)
1793 return set_redblue(gspca_dev);
1794 return 0;
1795}
1796
1797static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val)
1798{
1799 struct sd *sd = (struct sd *) gspca_dev;
1800 *val = sd->blue;
1801 return 0;
1802}
1803
1804static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val)
1805{
1806 struct sd *sd = (struct sd *) gspca_dev;
1807
1808 sd->hflip = val;
1809 if (gspca_dev->streaming)
1810 return set_hvflip(gspca_dev);
1811 return 0;
1812}
1813
1814static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val)
1815{
1816 struct sd *sd = (struct sd *) gspca_dev;
1817 *val = sd->hflip;
1818 return 0;
1819}
1820
1821static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val)
1822{
1823 struct sd *sd = (struct sd *) gspca_dev;
1824
1825 sd->vflip = val;
1826 if (gspca_dev->streaming)
1827 return set_hvflip(gspca_dev);
1828 return 0;
1829}
1830
1831static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val)
1832{
1833 struct sd *sd = (struct sd *) gspca_dev;
1834 *val = sd->vflip;
1835 return 0;
1836}
1837
1838static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val)
1839{
1840 struct sd *sd = (struct sd *) gspca_dev;
1841
1842 sd->exposure = val;
1843 if (gspca_dev->streaming)
1844 return set_exposure(gspca_dev);
1845 return 0;
1846}
1847
1848static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val)
1849{
1850 struct sd *sd = (struct sd *) gspca_dev;
1851 *val = sd->exposure;
1852 return 0;
1853}
1854
1855static int sd_setgain(struct gspca_dev *gspca_dev, s32 val)
1856{
1857 struct sd *sd = (struct sd *) gspca_dev;
1858
1859 sd->gain = val;
1860 if (gspca_dev->streaming)
1861 return set_gain(gspca_dev);
1862 return 0;
1863}
1864
1865static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val)
1866{
1867 struct sd *sd = (struct sd *) gspca_dev;
1868 *val = sd->gain;
1869 return 0;
1870}
1871
1872static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val)
1873{
1874 struct sd *sd = (struct sd *) gspca_dev;
1875 sd->auto_exposure = val;
1876 return 0;
1877}
1878
1879static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val)
1880{
1881 struct sd *sd = (struct sd *) gspca_dev;
1882 *val = sd->auto_exposure;
1883 return 0;
1884}
1885
1886#ifdef CONFIG_VIDEO_ADV_DEBUG
1887static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
1888 struct v4l2_dbg_register *reg)
1889{
1890 struct sd *sd = (struct sd *) gspca_dev;
1891 switch (reg->match.type) {
1892 case V4L2_CHIP_MATCH_HOST:
1893 if (reg->match.addr != 0)
1894 return -EINVAL;
1895 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1896 return -EINVAL;
1897 if (reg_r(gspca_dev, reg->reg, 1) < 0)
1898 return -EINVAL;
1899 reg->val = gspca_dev->usb_buf[0];
1900 return 0;
1901 case V4L2_CHIP_MATCH_I2C_ADDR:
1902 if (reg->match.addr != sd->i2c_addr)
1903 return -EINVAL;
1904 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001905 sd->sensor <= SENSOR_MT9M112) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001906 if (i2c_r2(gspca_dev, reg->reg, (u16 *)&reg->val) < 0)
1907 return -EINVAL;
1908 } else {
1909 if (i2c_r1(gspca_dev, reg->reg, (u8 *)&reg->val) < 0)
1910 return -EINVAL;
1911 }
1912 return 0;
1913 }
1914 return -EINVAL;
1915}
1916
1917static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
1918 struct v4l2_dbg_register *reg)
1919{
1920 struct sd *sd = (struct sd *) gspca_dev;
1921 switch (reg->match.type) {
1922 case V4L2_CHIP_MATCH_HOST:
1923 if (reg->match.addr != 0)
1924 return -EINVAL;
1925 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1926 return -EINVAL;
1927 if (reg_w1(gspca_dev, reg->reg, reg->val) < 0)
1928 return -EINVAL;
1929 return 0;
1930 case V4L2_CHIP_MATCH_I2C_ADDR:
1931 if (reg->match.addr != sd->i2c_addr)
1932 return -EINVAL;
1933 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001934 sd->sensor <= SENSOR_MT9M112) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001935 if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0)
1936 return -EINVAL;
1937 } else {
1938 if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0)
1939 return -EINVAL;
1940 }
1941 return 0;
1942 }
1943 return -EINVAL;
1944}
1945#endif
1946
1947static int sd_chip_ident(struct gspca_dev *gspca_dev,
1948 struct v4l2_dbg_chip_ident *chip)
1949{
1950 struct sd *sd = (struct sd *) gspca_dev;
1951
1952 switch (chip->match.type) {
1953 case V4L2_CHIP_MATCH_HOST:
1954 if (chip->match.addr != 0)
1955 return -EINVAL;
1956 chip->revision = 0;
1957 chip->ident = V4L2_IDENT_SN9C20X;
1958 return 0;
1959 case V4L2_CHIP_MATCH_I2C_ADDR:
1960 if (chip->match.addr != sd->i2c_addr)
1961 return -EINVAL;
1962 chip->revision = 0;
1963 chip->ident = i2c_ident[sd->sensor];
1964 return 0;
1965 }
1966 return -EINVAL;
1967}
1968
1969static int sd_config(struct gspca_dev *gspca_dev,
1970 const struct usb_device_id *id)
1971{
1972 struct sd *sd = (struct sd *) gspca_dev;
1973 struct cam *cam;
1974
1975 cam = &gspca_dev->cam;
1976
1977 sd->sensor = (id->driver_info >> 8) & 0xff;
1978 sd->i2c_addr = id->driver_info & 0xff;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03001979 sd->flags = (id->driver_info >> 16) & 0xff;
Brian Johnson26e744b2009-07-19 05:52:58 -03001980
1981 switch (sd->sensor) {
Brian Johnsone99ac542010-03-16 13:58:28 -03001982 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03001983 case SENSOR_MT9M111:
Brian Johnson26e744b2009-07-19 05:52:58 -03001984 case SENSOR_OV9650:
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001985 case SENSOR_SOI968:
Brian Johnson26e744b2009-07-19 05:52:58 -03001986 cam->cam_mode = sxga_mode;
1987 cam->nmodes = ARRAY_SIZE(sxga_mode);
1988 break;
1989 default:
1990 cam->cam_mode = vga_mode;
1991 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001992 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001993 }
1994
1995 sd->old_step = 0;
1996 sd->older_step = 0;
1997 sd->exposure_step = 16;
1998
1999 sd->brightness = BRIGHTNESS_DEFAULT;
2000 sd->contrast = CONTRAST_DEFAULT;
2001 sd->saturation = SATURATION_DEFAULT;
2002 sd->hue = HUE_DEFAULT;
2003 sd->gamma = GAMMA_DEFAULT;
2004 sd->red = RED_DEFAULT;
2005 sd->blue = BLUE_DEFAULT;
2006
2007 sd->hflip = HFLIP_DEFAULT;
2008 sd->vflip = VFLIP_DEFAULT;
2009 sd->exposure = EXPOSURE_DEFAULT;
2010 sd->gain = GAIN_DEFAULT;
2011 sd->auto_exposure = AUTO_EXPOSURE_DEFAULT;
2012
2013 sd->quality = 95;
2014
Brian Johnson26e744b2009-07-19 05:52:58 -03002015 return 0;
2016}
2017
2018static int sd_init(struct gspca_dev *gspca_dev)
2019{
2020 struct sd *sd = (struct sd *) gspca_dev;
2021 int i;
2022 u8 value;
2023 u8 i2c_init[9] =
2024 {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03};
2025
2026 for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
2027 value = bridge_init[i][1];
2028 if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) {
2029 err("Device initialization failed");
2030 return -ENODEV;
2031 }
2032 }
2033
Brian Johnson0c045eb2010-03-16 13:58:27 -03002034 if (sd->flags & LED_REVERSE)
2035 reg_w1(gspca_dev, 0x1006, 0x00);
2036 else
2037 reg_w1(gspca_dev, 0x1006, 0x20);
2038
Brian Johnson26e744b2009-07-19 05:52:58 -03002039 if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
2040 err("Device initialization failed");
2041 return -ENODEV;
2042 }
2043
2044 switch (sd->sensor) {
2045 case SENSOR_OV9650:
2046 if (ov9650_init_sensor(gspca_dev) < 0)
2047 return -ENODEV;
2048 info("OV9650 sensor detected");
2049 break;
2050 case SENSOR_OV9655:
2051 if (ov9655_init_sensor(gspca_dev) < 0)
2052 return -ENODEV;
2053 info("OV9655 sensor detected");
2054 break;
2055 case SENSOR_SOI968:
2056 if (soi968_init_sensor(gspca_dev) < 0)
2057 return -ENODEV;
2058 info("SOI968 sensor detected");
2059 break;
2060 case SENSOR_OV7660:
2061 if (ov7660_init_sensor(gspca_dev) < 0)
2062 return -ENODEV;
2063 info("OV7660 sensor detected");
2064 break;
2065 case SENSOR_OV7670:
2066 if (ov7670_init_sensor(gspca_dev) < 0)
2067 return -ENODEV;
2068 info("OV7670 sensor detected");
2069 break;
2070 case SENSOR_MT9VPRB:
2071 if (mt9v_init_sensor(gspca_dev) < 0)
2072 return -ENODEV;
2073 break;
2074 case SENSOR_MT9M111:
2075 if (mt9m111_init_sensor(gspca_dev) < 0)
2076 return -ENODEV;
2077 info("MT9M111 sensor detected");
2078 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03002079 case SENSOR_MT9M112:
2080 if (mt9m112_init_sensor(gspca_dev) < 0)
2081 return -ENODEV;
2082 info("MT9M112 sensor detected");
2083 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002084 case SENSOR_MT9M001:
2085 if (mt9m001_init_sensor(gspca_dev) < 0)
2086 return -ENODEV;
2087 info("MT9M001 sensor detected");
2088 break;
2089 case SENSOR_HV7131R:
2090 if (hv7131r_init_sensor(gspca_dev) < 0)
2091 return -ENODEV;
2092 info("HV7131R sensor detected");
2093 break;
2094 default:
2095 info("Unsupported Sensor");
2096 return -ENODEV;
2097 }
2098
2099 return 0;
2100}
2101
2102static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
2103{
2104 struct sd *sd = (struct sd *) gspca_dev;
2105 u8 value;
2106 switch (sd->sensor) {
Brian Johnsone8b7acc2009-09-02 13:14:41 -03002107 case SENSOR_SOI968:
2108 if (mode & MODE_SXGA) {
2109 i2c_w1(gspca_dev, 0x17, 0x1d);
2110 i2c_w1(gspca_dev, 0x18, 0xbd);
2111 i2c_w1(gspca_dev, 0x19, 0x01);
2112 i2c_w1(gspca_dev, 0x1a, 0x81);
2113 i2c_w1(gspca_dev, 0x12, 0x00);
2114 sd->hstart = 140;
2115 sd->vstart = 19;
2116 } else {
2117 i2c_w1(gspca_dev, 0x17, 0x13);
2118 i2c_w1(gspca_dev, 0x18, 0x63);
2119 i2c_w1(gspca_dev, 0x19, 0x01);
2120 i2c_w1(gspca_dev, 0x1a, 0x79);
2121 i2c_w1(gspca_dev, 0x12, 0x40);
2122 sd->hstart = 60;
2123 sd->vstart = 11;
2124 }
2125 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002126 case SENSOR_OV9650:
2127 if (mode & MODE_SXGA) {
2128 i2c_w1(gspca_dev, 0x17, 0x1b);
2129 i2c_w1(gspca_dev, 0x18, 0xbc);
2130 i2c_w1(gspca_dev, 0x19, 0x01);
2131 i2c_w1(gspca_dev, 0x1a, 0x82);
2132 i2c_r1(gspca_dev, 0x12, &value);
2133 i2c_w1(gspca_dev, 0x12, value & 0x07);
2134 } else {
2135 i2c_w1(gspca_dev, 0x17, 0x24);
2136 i2c_w1(gspca_dev, 0x18, 0xc5);
2137 i2c_w1(gspca_dev, 0x19, 0x00);
2138 i2c_w1(gspca_dev, 0x1a, 0x3c);
2139 i2c_r1(gspca_dev, 0x12, &value);
2140 i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
2141 }
2142 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03002143 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03002144 case SENSOR_MT9M111:
2145 if (mode & MODE_SXGA) {
2146 i2c_w2(gspca_dev, 0xf0, 0x0002);
2147 i2c_w2(gspca_dev, 0xc8, 0x970b);
2148 i2c_w2(gspca_dev, 0xf0, 0x0000);
2149 } else {
2150 i2c_w2(gspca_dev, 0xf0, 0x0002);
2151 i2c_w2(gspca_dev, 0xc8, 0x8000);
2152 i2c_w2(gspca_dev, 0xf0, 0x0000);
2153 }
2154 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002155 }
2156}
2157
2158#define HW_WIN(mode, hstart, vstart) \
Jean-Francois Moine83955552009-12-12 06:58:01 -03002159((const u8 []){hstart, 0, vstart, 0, \
Brian Johnson26e744b2009-07-19 05:52:58 -03002160(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
2161(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)})
2162
2163#define CLR_WIN(width, height) \
2164((const u8 [])\
2165{0, width >> 2, 0, height >> 1,\
2166((width >> 10) & 0x01) | ((height >> 8) & 0x6)})
2167
2168static int sd_start(struct gspca_dev *gspca_dev)
2169{
2170 struct sd *sd = (struct sd *) gspca_dev;
2171 int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
2172 int width = gspca_dev->width;
2173 int height = gspca_dev->height;
2174 u8 fmt, scale = 0;
2175
Brian Johnson26e744b2009-07-19 05:52:58 -03002176 jpeg_define(sd->jpeg_hdr, height, width,
2177 0x21);
2178 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
2179
2180 if (mode & MODE_RAW)
2181 fmt = 0x2d;
2182 else if (mode & MODE_JPEG)
2183 fmt = 0x2c;
2184 else
2185 fmt = 0x2f;
2186
2187 switch (mode & 0x0f) {
2188 case 3:
2189 scale = 0xc0;
2190 info("Set 1280x1024");
2191 break;
2192 case 2:
2193 scale = 0x80;
2194 info("Set 640x480");
2195 break;
2196 case 1:
2197 scale = 0x90;
2198 info("Set 320x240");
2199 break;
2200 case 0:
2201 scale = 0xa0;
2202 info("Set 160x120");
2203 break;
2204 }
2205
2206 configure_sensor_output(gspca_dev, mode);
Jean-François Moine9a731a32010-06-04 05:26:42 -03002207 reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
2208 reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
Brian Johnson26e744b2009-07-19 05:52:58 -03002209 reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
2210 reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
2211 reg_w1(gspca_dev, 0x1189, scale);
2212 reg_w1(gspca_dev, 0x10e0, fmt);
2213
2214 set_cmatrix(gspca_dev);
2215 set_gamma(gspca_dev);
2216 set_redblue(gspca_dev);
2217 set_gain(gspca_dev);
2218 set_exposure(gspca_dev);
2219 set_hvflip(gspca_dev);
2220
Brian Johnson0c045eb2010-03-16 13:58:27 -03002221 reg_w1(gspca_dev, 0x1007, 0x20);
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 return 0;
2226}
2227
2228static void sd_stopN(struct gspca_dev *gspca_dev)
2229{
Brian Johnson0c045eb2010-03-16 13:58:27 -03002230 reg_w1(gspca_dev, 0x1007, 0x00);
2231
Brian Johnson26e744b2009-07-19 05:52:58 -03002232 reg_r(gspca_dev, 0x1061, 1);
2233 reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
2234}
2235
Brian Johnsone1430472009-09-02 12:39:41 -03002236static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
Brian Johnson26e744b2009-07-19 05:52:58 -03002237{
2238 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnsone1430472009-09-02 12:39:41 -03002239 s16 new_exp;
Brian Johnson26e744b2009-07-19 05:52:58 -03002240
2241 /*
2242 * some hardcoded values are present
2243 * like those for maximal/minimal exposure
2244 * and exposure steps
2245 */
2246 if (avg_lum < MIN_AVG_LUM) {
2247 if (sd->exposure > 0x1770)
2248 return;
2249
2250 new_exp = sd->exposure + sd->exposure_step;
2251 if (new_exp > 0x1770)
2252 new_exp = 0x1770;
2253 if (new_exp < 0x10)
2254 new_exp = 0x10;
2255 sd->exposure = new_exp;
2256 set_exposure(gspca_dev);
2257
2258 sd->older_step = sd->old_step;
2259 sd->old_step = 1;
2260
2261 if (sd->old_step ^ sd->older_step)
2262 sd->exposure_step /= 2;
2263 else
2264 sd->exposure_step += 2;
2265 }
2266 if (avg_lum > MAX_AVG_LUM) {
2267 if (sd->exposure < 0x10)
2268 return;
2269 new_exp = sd->exposure - sd->exposure_step;
2270 if (new_exp > 0x1700)
2271 new_exp = 0x1770;
2272 if (new_exp < 0x10)
2273 new_exp = 0x10;
2274 sd->exposure = new_exp;
2275 set_exposure(gspca_dev);
2276 sd->older_step = sd->old_step;
2277 sd->old_step = 0;
2278
2279 if (sd->old_step ^ sd->older_step)
2280 sd->exposure_step /= 2;
2281 else
2282 sd->exposure_step += 2;
2283 }
2284}
2285
Brian Johnsone1430472009-09-02 12:39:41 -03002286static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
2287{
2288 struct sd *sd = (struct sd *) gspca_dev;
2289
2290 if (avg_lum < MIN_AVG_LUM) {
2291 if (sd->gain + 1 <= 28) {
2292 sd->gain++;
2293 set_gain(gspca_dev);
2294 }
2295 }
2296 if (avg_lum > MAX_AVG_LUM) {
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03002297 if (sd->gain > 0) {
Brian Johnsone1430472009-09-02 12:39:41 -03002298 sd->gain--;
2299 set_gain(gspca_dev);
2300 }
2301 }
2302}
2303
2304static void sd_dqcallback(struct gspca_dev *gspca_dev)
2305{
2306 struct sd *sd = (struct sd *) gspca_dev;
2307 int avg_lum;
2308
2309 if (!sd->auto_exposure)
2310 return;
2311
2312 avg_lum = atomic_read(&sd->avg_lum);
2313 if (sd->sensor == SENSOR_SOI968)
2314 do_autogain(gspca_dev, avg_lum);
2315 else
2316 do_autoexposure(gspca_dev, avg_lum);
2317}
2318
Jean-François Moine28566432010-10-01 07:33:26 -03002319#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002320static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
2321 u8 *data, /* interrupt packet */
2322 int len) /* interrupt packet length */
2323{
2324 struct sd *sd = (struct sd *) gspca_dev;
2325 int ret = -EINVAL;
Brian Johnson33ddc162010-04-18 21:42:40 -03002326 if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002327 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
2328 input_sync(gspca_dev->input_dev);
2329 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
2330 input_sync(gspca_dev->input_dev);
2331 ret = 0;
2332 }
2333 return ret;
2334}
2335#endif
2336
Brian Johnson26e744b2009-07-19 05:52:58 -03002337static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Brian Johnson26e744b2009-07-19 05:52:58 -03002338 u8 *data, /* isoc packet */
2339 int len) /* iso packet length */
2340{
2341 struct sd *sd = (struct sd *) gspca_dev;
2342 int avg_lum;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03002343 static u8 frame_header[] =
Brian Johnson26e744b2009-07-19 05:52:58 -03002344 {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
2345 if (len == 64 && memcmp(data, frame_header, 6) == 0) {
2346 avg_lum = ((data[35] >> 2) & 3) |
2347 (data[20] << 2) |
2348 (data[19] << 10);
2349 avg_lum += ((data[35] >> 4) & 3) |
2350 (data[22] << 2) |
2351 (data[21] << 10);
2352 avg_lum += ((data[35] >> 6) & 3) |
2353 (data[24] << 2) |
2354 (data[23] << 10);
2355 avg_lum += (data[36] & 3) |
2356 (data[26] << 2) |
2357 (data[25] << 10);
2358 avg_lum += ((data[36] >> 2) & 3) |
2359 (data[28] << 2) |
2360 (data[27] << 10);
2361 avg_lum += ((data[36] >> 4) & 3) |
2362 (data[30] << 2) |
2363 (data[29] << 10);
2364 avg_lum += ((data[36] >> 6) & 3) |
2365 (data[32] << 2) |
2366 (data[31] << 10);
2367 avg_lum += ((data[44] >> 4) & 3) |
2368 (data[34] << 2) |
2369 (data[33] << 10);
2370 avg_lum >>= 9;
2371 atomic_set(&sd->avg_lum, avg_lum);
Jean-François Moine04d174e2010-09-13 05:22:37 -03002372 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Brian Johnson26e744b2009-07-19 05:52:58 -03002373 return;
2374 }
2375 if (gspca_dev->last_packet_type == LAST_PACKET) {
2376 if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv
2377 & MODE_JPEG) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002378 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002379 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002380 gspca_frame_add(gspca_dev, INTER_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002381 data, len);
2382 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002383 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002384 data, len);
2385 }
2386 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002387 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Brian Johnson26e744b2009-07-19 05:52:58 -03002388 }
2389}
2390
2391/* sub-driver description */
2392static const struct sd_desc sd_desc = {
2393 .name = MODULE_NAME,
2394 .ctrls = sd_ctrls,
2395 .nctrls = ARRAY_SIZE(sd_ctrls),
2396 .config = sd_config,
2397 .init = sd_init,
2398 .start = sd_start,
2399 .stopN = sd_stopN,
Brian Johnson26e744b2009-07-19 05:52:58 -03002400 .pkt_scan = sd_pkt_scan,
Jean-François Moine28566432010-10-01 07:33:26 -03002401#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002402 .int_pkt_scan = sd_int_pkt_scan,
2403#endif
Brian Johnsone1430472009-09-02 12:39:41 -03002404 .dq_callback = sd_dqcallback,
Brian Johnson26e744b2009-07-19 05:52:58 -03002405#ifdef CONFIG_VIDEO_ADV_DEBUG
2406 .set_register = sd_dbg_s_register,
2407 .get_register = sd_dbg_g_register,
2408#endif
2409 .get_chip_ident = sd_chip_ident,
2410};
2411
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002412#define SN9C20X(sensor, i2c_addr, flags) \
Brian Johnson0c045eb2010-03-16 13:58:27 -03002413 .driver_info = ((flags & 0xff) << 16) \
Brian Johnson26e744b2009-07-19 05:52:58 -03002414 | (SENSOR_ ## sensor << 8) \
2415 | (i2c_addr)
2416
2417static const __devinitdata struct usb_device_id device_table[] = {
2418 {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
2419 {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
2420 {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002421 {USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002422 {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, LED_REVERSE)},
2423 {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30,
2424 (FLIP_DETECT | HAS_NO_BUTTON))},
Brian Johnson26e744b2009-07-19 05:52:58 -03002425 {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
2426 {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
2427 {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
2428 {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)},
2429 {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, 0)},
2430 {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)},
2431 {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)},
2432 {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
2433 {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002434 {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002435 {USB_DEVICE(0x0c45, 0x628c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002436 {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)},
2437 {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
2438 {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
2439 {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
2440 {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002441 {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002442 {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
2443 {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
2444 {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
2445 {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002446 {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)},
2447 {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002448 {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
2449 {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)},
2450 {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)},
2451 {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002452 {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002453 {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)},
2454 {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)},
2455 {}
2456};
2457MODULE_DEVICE_TABLE(usb, device_table);
2458
2459/* -- device connect -- */
2460static int sd_probe(struct usb_interface *intf,
2461 const struct usb_device_id *id)
2462{
2463 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
2464 THIS_MODULE);
2465}
2466
Brian Johnson26e744b2009-07-19 05:52:58 -03002467static struct usb_driver sd_driver = {
2468 .name = MODULE_NAME,
2469 .id_table = device_table,
2470 .probe = sd_probe,
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002471 .disconnect = gspca_disconnect,
Brian Johnson26e744b2009-07-19 05:52:58 -03002472#ifdef CONFIG_PM
2473 .suspend = gspca_suspend,
2474 .resume = gspca_resume,
2475 .reset_resume = gspca_resume,
2476#endif
2477};
2478
2479/* -- module insert / remove -- */
2480static int __init sd_mod_init(void)
2481{
Jean-François Moine54826432010-09-13 04:53:03 -03002482 return usb_register(&sd_driver);
Brian Johnson26e744b2009-07-19 05:52:58 -03002483}
2484static void __exit sd_mod_exit(void)
2485{
2486 usb_deregister(&sd_driver);
Brian Johnson26e744b2009-07-19 05:52:58 -03002487}
2488
2489module_init(sd_mod_init);
2490module_exit(sd_mod_exit);