blob: 40e316ac3951101f986b236ace3a236fcb5f668f [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
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -030036/*
37 * Pixel format private data
38 */
39#define SCALE_MASK 0x0f
40#define SCALE_160x120 0
41#define SCALE_320x240 1
42#define SCALE_640x480 2
43#define SCALE_1280x1024 3
Brian Johnson26e744b2009-07-19 05:52:58 -030044#define MODE_RAW 0x10
45#define MODE_JPEG 0x20
46#define MODE_SXGA 0x80
47
48#define SENSOR_OV9650 0
49#define SENSOR_OV9655 1
50#define SENSOR_SOI968 2
51#define SENSOR_OV7660 3
52#define SENSOR_OV7670 4
53#define SENSOR_MT9V011 5
54#define SENSOR_MT9V111 6
55#define SENSOR_MT9V112 7
56#define SENSOR_MT9M001 8
57#define SENSOR_MT9M111 9
Brian Johnsone99ac542010-03-16 13:58:28 -030058#define SENSOR_MT9M112 10
59#define SENSOR_HV7131R 11
Brian Johnson26e744b2009-07-19 05:52:58 -030060#define SENSOR_MT9VPRB 20
61
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030062/* camera flags */
Brian Johnson33ddc162010-04-18 21:42:40 -030063#define HAS_NO_BUTTON 0x1
Brian Johnson0c045eb2010-03-16 13:58:27 -030064#define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */
Brian Johnson7ddaac72010-03-16 13:58:27 -030065#define FLIP_DETECT 0x4
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030066
Brian Johnson26e744b2009-07-19 05:52:58 -030067/* specific webcam descriptor */
68struct sd {
69 struct gspca_dev gspca_dev;
70
71#define MIN_AVG_LUM 80
72#define MAX_AVG_LUM 130
73 atomic_t avg_lum;
74 u8 old_step;
75 u8 older_step;
76 u8 exposure_step;
77
78 u8 brightness;
79 u8 contrast;
80 u8 saturation;
81 s16 hue;
82 u8 gamma;
83 u8 red;
84 u8 blue;
85
86 u8 hflip;
87 u8 vflip;
88 u8 gain;
89 u16 exposure;
90 u8 auto_exposure;
91
92 u8 i2c_addr;
93 u8 sensor;
94 u8 hstart;
95 u8 vstart;
96
Jean-François Moine9a731a32010-06-04 05:26:42 -030097 u8 jpeg_hdr[JPEG_HDR_SZ];
Brian Johnson26e744b2009-07-19 05:52:58 -030098 u8 quality;
99
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -0300100 u8 flags;
Brian Johnson26e744b2009-07-19 05:52:58 -0300101};
102
Joe Perches58aa68c2009-09-02 01:12:13 -0300103struct i2c_reg_u8 {
104 u8 reg;
105 u8 val;
106};
107
108struct i2c_reg_u16 {
109 u8 reg;
110 u16 val;
111};
112
Brian Johnson26e744b2009-07-19 05:52:58 -0300113static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val);
114static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val);
115static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val);
116static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val);
117static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val);
118static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val);
119static int sd_sethue(struct gspca_dev *gspca_dev, s32 val);
120static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val);
121static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val);
122static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val);
123static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val);
124static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val);
125static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val);
126static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val);
127static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val);
128static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val);
129static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val);
130static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val);
131static int sd_setgain(struct gspca_dev *gspca_dev, s32 val);
132static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val);
133static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val);
134static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val);
135static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val);
136static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val);
137
Brian Johnson7ddaac72010-03-16 13:58:27 -0300138static const struct dmi_system_id flip_dmi_table[] = {
139 {
140 .ident = "MSI MS-1034",
141 .matches = {
142 DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."),
143 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1034"),
144 DMI_MATCH(DMI_PRODUCT_VERSION, "0341")
145 }
146 },
147 {
148 .ident = "MSI MS-1632",
149 .matches = {
150 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
151 DMI_MATCH(DMI_BOARD_NAME, "MS-1632")
152 }
153 },
Brian Johnsone077f862010-04-05 20:52:52 -0300154 {
Brian Johnson5d26ed92010-04-10 02:12:46 -0300155 .ident = "MSI MS-1635X",
156 .matches = {
157 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
158 DMI_MATCH(DMI_BOARD_NAME, "MS-1635X")
159 }
160 },
161 {
Brian Johnsone077f862010-04-05 20:52:52 -0300162 .ident = "ASUSTeK W7J",
163 .matches = {
164 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
165 DMI_MATCH(DMI_BOARD_NAME, "W7J ")
166 }
167 },
Brian Johnson7ddaac72010-03-16 13:58:27 -0300168 {}
169};
170
Marton Nemeth7e64dc42009-12-30 09:12:41 -0300171static const struct ctrl sd_ctrls[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300172 {
173#define BRIGHTNESS_IDX 0
174 {
175 .id = V4L2_CID_BRIGHTNESS,
176 .type = V4L2_CTRL_TYPE_INTEGER,
177 .name = "Brightness",
178 .minimum = 0,
179 .maximum = 0xff,
180 .step = 1,
181#define BRIGHTNESS_DEFAULT 0x7f
182 .default_value = BRIGHTNESS_DEFAULT,
183 },
184 .set = sd_setbrightness,
185 .get = sd_getbrightness,
186 },
187 {
188#define CONTRAST_IDX 1
189 {
190 .id = V4L2_CID_CONTRAST,
191 .type = V4L2_CTRL_TYPE_INTEGER,
192 .name = "Contrast",
193 .minimum = 0,
194 .maximum = 0xff,
195 .step = 1,
196#define CONTRAST_DEFAULT 0x7f
197 .default_value = CONTRAST_DEFAULT,
198 },
199 .set = sd_setcontrast,
200 .get = sd_getcontrast,
201 },
202 {
203#define SATURATION_IDX 2
204 {
205 .id = V4L2_CID_SATURATION,
206 .type = V4L2_CTRL_TYPE_INTEGER,
207 .name = "Saturation",
208 .minimum = 0,
209 .maximum = 0xff,
210 .step = 1,
211#define SATURATION_DEFAULT 0x7f
212 .default_value = SATURATION_DEFAULT,
213 },
214 .set = sd_setsaturation,
215 .get = sd_getsaturation,
216 },
217 {
218#define HUE_IDX 3
219 {
220 .id = V4L2_CID_HUE,
221 .type = V4L2_CTRL_TYPE_INTEGER,
222 .name = "Hue",
223 .minimum = -180,
224 .maximum = 180,
225 .step = 1,
226#define HUE_DEFAULT 0
227 .default_value = HUE_DEFAULT,
228 },
229 .set = sd_sethue,
230 .get = sd_gethue,
231 },
232 {
233#define GAMMA_IDX 4
234 {
235 .id = V4L2_CID_GAMMA,
236 .type = V4L2_CTRL_TYPE_INTEGER,
237 .name = "Gamma",
238 .minimum = 0,
239 .maximum = 0xff,
240 .step = 1,
241#define GAMMA_DEFAULT 0x10
242 .default_value = GAMMA_DEFAULT,
243 },
244 .set = sd_setgamma,
245 .get = sd_getgamma,
246 },
247 {
248#define BLUE_IDX 5
249 {
250 .id = V4L2_CID_BLUE_BALANCE,
251 .type = V4L2_CTRL_TYPE_INTEGER,
252 .name = "Blue Balance",
253 .minimum = 0,
254 .maximum = 0x7f,
255 .step = 1,
256#define BLUE_DEFAULT 0x28
257 .default_value = BLUE_DEFAULT,
258 },
259 .set = sd_setbluebalance,
260 .get = sd_getbluebalance,
261 },
262 {
263#define RED_IDX 6
264 {
265 .id = V4L2_CID_RED_BALANCE,
266 .type = V4L2_CTRL_TYPE_INTEGER,
267 .name = "Red Balance",
268 .minimum = 0,
269 .maximum = 0x7f,
270 .step = 1,
271#define RED_DEFAULT 0x28
272 .default_value = RED_DEFAULT,
273 },
274 .set = sd_setredbalance,
275 .get = sd_getredbalance,
276 },
277 {
278#define HFLIP_IDX 7
279 {
280 .id = V4L2_CID_HFLIP,
281 .type = V4L2_CTRL_TYPE_BOOLEAN,
282 .name = "Horizontal Flip",
283 .minimum = 0,
284 .maximum = 1,
285 .step = 1,
286#define HFLIP_DEFAULT 0
287 .default_value = HFLIP_DEFAULT,
288 },
289 .set = sd_sethflip,
290 .get = sd_gethflip,
291 },
292 {
293#define VFLIP_IDX 8
294 {
295 .id = V4L2_CID_VFLIP,
296 .type = V4L2_CTRL_TYPE_BOOLEAN,
297 .name = "Vertical Flip",
298 .minimum = 0,
299 .maximum = 1,
300 .step = 1,
301#define VFLIP_DEFAULT 0
302 .default_value = VFLIP_DEFAULT,
303 },
304 .set = sd_setvflip,
305 .get = sd_getvflip,
306 },
307 {
308#define EXPOSURE_IDX 9
309 {
310 .id = V4L2_CID_EXPOSURE,
311 .type = V4L2_CTRL_TYPE_INTEGER,
312 .name = "Exposure",
313 .minimum = 0,
314 .maximum = 0x1780,
315 .step = 1,
316#define EXPOSURE_DEFAULT 0x33
317 .default_value = EXPOSURE_DEFAULT,
318 },
319 .set = sd_setexposure,
320 .get = sd_getexposure,
321 },
322 {
323#define GAIN_IDX 10
324 {
325 .id = V4L2_CID_GAIN,
326 .type = V4L2_CTRL_TYPE_INTEGER,
327 .name = "Gain",
328 .minimum = 0,
329 .maximum = 28,
330 .step = 1,
331#define GAIN_DEFAULT 0x00
332 .default_value = GAIN_DEFAULT,
333 },
334 .set = sd_setgain,
335 .get = sd_getgain,
336 },
337 {
338#define AUTOGAIN_IDX 11
339 {
340 .id = V4L2_CID_AUTOGAIN,
341 .type = V4L2_CTRL_TYPE_BOOLEAN,
342 .name = "Auto Exposure",
343 .minimum = 0,
344 .maximum = 1,
345 .step = 1,
346#define AUTO_EXPOSURE_DEFAULT 1
347 .default_value = AUTO_EXPOSURE_DEFAULT,
348 },
349 .set = sd_setautoexposure,
350 .get = sd_getautoexposure,
351 },
352};
353
354static const struct v4l2_pix_format vga_mode[] = {
355 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300356 .bytesperline = 160,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300357 .sizeimage = 160 * 120 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300358 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300359 .priv = SCALE_160x120 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300360 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
361 .bytesperline = 160,
362 .sizeimage = 160 * 120,
363 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300364 .priv = SCALE_160x120 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300365 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300366 .bytesperline = 160,
Brian Johnson26e744b2009-07-19 05:52:58 -0300367 .sizeimage = 240 * 120,
368 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300369 .priv = SCALE_160x120},
Brian Johnson26e744b2009-07-19 05:52:58 -0300370 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300371 .bytesperline = 320,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300372 .sizeimage = 320 * 240 * 3 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300373 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300374 .priv = SCALE_320x240 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300375 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
376 .bytesperline = 320,
377 .sizeimage = 320 * 240 ,
378 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300379 .priv = SCALE_320x240 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300380 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300381 .bytesperline = 320,
Brian Johnson26e744b2009-07-19 05:52:58 -0300382 .sizeimage = 480 * 240 ,
383 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300384 .priv = SCALE_320x240},
Brian Johnson26e744b2009-07-19 05:52:58 -0300385 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300386 .bytesperline = 640,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300387 .sizeimage = 640 * 480 * 3 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300388 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300389 .priv = SCALE_640x480 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300390 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
391 .bytesperline = 640,
392 .sizeimage = 640 * 480,
393 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300394 .priv = SCALE_640x480 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300395 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300396 .bytesperline = 640,
Brian Johnson26e744b2009-07-19 05:52:58 -0300397 .sizeimage = 960 * 480,
398 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300399 .priv = SCALE_640x480},
Brian Johnson26e744b2009-07-19 05:52:58 -0300400};
401
402static const struct v4l2_pix_format sxga_mode[] = {
403 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300404 .bytesperline = 160,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300405 .sizeimage = 160 * 120 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300406 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300407 .priv = SCALE_160x120 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300408 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
409 .bytesperline = 160,
410 .sizeimage = 160 * 120,
411 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300412 .priv = SCALE_160x120 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300413 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300414 .bytesperline = 160,
Brian Johnson26e744b2009-07-19 05:52:58 -0300415 .sizeimage = 240 * 120,
416 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300417 .priv = SCALE_160x120},
Brian Johnson26e744b2009-07-19 05:52:58 -0300418 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300419 .bytesperline = 320,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300420 .sizeimage = 320 * 240 * 3 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300421 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300422 .priv = SCALE_320x240 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300423 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
424 .bytesperline = 320,
425 .sizeimage = 320 * 240 ,
426 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300427 .priv = SCALE_320x240 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300428 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300429 .bytesperline = 320,
Brian Johnson26e744b2009-07-19 05:52:58 -0300430 .sizeimage = 480 * 240 ,
431 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300432 .priv = SCALE_320x240},
Brian Johnson26e744b2009-07-19 05:52:58 -0300433 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300434 .bytesperline = 640,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300435 .sizeimage = 640 * 480 * 3 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300436 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300437 .priv = SCALE_640x480 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300438 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
439 .bytesperline = 640,
440 .sizeimage = 640 * 480,
441 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300442 .priv = SCALE_640x480 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300443 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300444 .bytesperline = 640,
Brian Johnson26e744b2009-07-19 05:52:58 -0300445 .sizeimage = 960 * 480,
446 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300447 .priv = SCALE_640x480},
Brian Johnson26e744b2009-07-19 05:52:58 -0300448 {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
449 .bytesperline = 1280,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300450 .sizeimage = 1280 * 1024,
Brian Johnson26e744b2009-07-19 05:52:58 -0300451 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300452 .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
Brian Johnson26e744b2009-07-19 05:52:58 -0300453};
454
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -0300455static const struct v4l2_pix_format mono_mode[] = {
456 {160, 120, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
457 .bytesperline = 160,
458 .sizeimage = 160 * 120,
459 .colorspace = V4L2_COLORSPACE_SRGB,
460 .priv = SCALE_160x120 | MODE_RAW},
461 {320, 240, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
462 .bytesperline = 320,
463 .sizeimage = 320 * 240 ,
464 .colorspace = V4L2_COLORSPACE_SRGB,
465 .priv = SCALE_320x240 | MODE_RAW},
466 {640, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
467 .bytesperline = 640,
468 .sizeimage = 640 * 480,
469 .colorspace = V4L2_COLORSPACE_SRGB,
470 .priv = SCALE_640x480 | MODE_RAW},
471 {1280, 1024, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
472 .bytesperline = 1280,
473 .sizeimage = 1280 * 1024,
474 .colorspace = V4L2_COLORSPACE_SRGB,
475 .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
476};
477
Joe Perches58aa68c2009-09-02 01:12:13 -0300478static const s16 hsv_red_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300479 41, 44, 46, 48, 50, 52, 54, 56,
480 58, 60, 62, 64, 66, 68, 70, 72,
481 74, 76, 78, 80, 81, 83, 85, 87,
482 88, 90, 92, 93, 95, 97, 98, 100,
483 101, 102, 104, 105, 107, 108, 109, 110,
484 112, 113, 114, 115, 116, 117, 118, 119,
485 120, 121, 122, 123, 123, 124, 125, 125,
486 126, 127, 127, 128, 128, 129, 129, 129,
487 130, 130, 130, 130, 131, 131, 131, 131,
488 131, 131, 131, 131, 130, 130, 130, 130,
489 129, 129, 129, 128, 128, 127, 127, 126,
490 125, 125, 124, 123, 122, 122, 121, 120,
491 119, 118, 117, 116, 115, 114, 112, 111,
492 110, 109, 107, 106, 105, 103, 102, 101,
493 99, 98, 96, 94, 93, 91, 90, 88,
494 86, 84, 83, 81, 79, 77, 75, 74,
495 72, 70, 68, 66, 64, 62, 60, 58,
496 56, 54, 52, 49, 47, 45, 43, 41,
497 39, 36, 34, 32, 30, 28, 25, 23,
498 21, 19, 16, 14, 12, 9, 7, 5,
499 3, 0, -1, -3, -6, -8, -10, -12,
500 -15, -17, -19, -22, -24, -26, -28, -30,
501 -33, -35, -37, -39, -41, -44, -46, -48,
502 -50, -52, -54, -56, -58, -60, -62, -64,
503 -66, -68, -70, -72, -74, -76, -78, -80,
504 -81, -83, -85, -87, -88, -90, -92, -93,
505 -95, -97, -98, -100, -101, -102, -104, -105,
506 -107, -108, -109, -110, -112, -113, -114, -115,
507 -116, -117, -118, -119, -120, -121, -122, -123,
508 -123, -124, -125, -125, -126, -127, -127, -128,
509 -128, -128, -128, -128, -128, -128, -128, -128,
510 -128, -128, -128, -128, -128, -128, -128, -128,
511 -128, -128, -128, -128, -128, -128, -128, -128,
512 -128, -127, -127, -126, -125, -125, -124, -123,
513 -122, -122, -121, -120, -119, -118, -117, -116,
514 -115, -114, -112, -111, -110, -109, -107, -106,
515 -105, -103, -102, -101, -99, -98, -96, -94,
516 -93, -91, -90, -88, -86, -84, -83, -81,
517 -79, -77, -75, -74, -72, -70, -68, -66,
518 -64, -62, -60, -58, -56, -54, -52, -49,
519 -47, -45, -43, -41, -39, -36, -34, -32,
520 -30, -28, -25, -23, -21, -19, -16, -14,
521 -12, -9, -7, -5, -3, 0, 1, 3,
522 6, 8, 10, 12, 15, 17, 19, 22,
523 24, 26, 28, 30, 33, 35, 37, 39, 41
524};
525
Joe Perches58aa68c2009-09-02 01:12:13 -0300526static const s16 hsv_red_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300527 82, 80, 78, 76, 74, 73, 71, 69,
528 67, 65, 63, 61, 58, 56, 54, 52,
529 50, 48, 46, 44, 41, 39, 37, 35,
530 32, 30, 28, 26, 23, 21, 19, 16,
531 14, 12, 10, 7, 5, 3, 0, -1,
532 -3, -6, -8, -10, -13, -15, -17, -19,
533 -22, -24, -26, -29, -31, -33, -35, -38,
534 -40, -42, -44, -46, -48, -51, -53, -55,
535 -57, -59, -61, -63, -65, -67, -69, -71,
536 -73, -75, -77, -79, -81, -82, -84, -86,
537 -88, -89, -91, -93, -94, -96, -98, -99,
538 -101, -102, -104, -105, -106, -108, -109, -110,
539 -112, -113, -114, -115, -116, -117, -119, -120,
540 -120, -121, -122, -123, -124, -125, -126, -126,
541 -127, -128, -128, -128, -128, -128, -128, -128,
542 -128, -128, -128, -128, -128, -128, -128, -128,
543 -128, -128, -128, -128, -128, -128, -128, -128,
544 -128, -128, -128, -128, -128, -128, -128, -128,
545 -127, -127, -126, -125, -125, -124, -123, -122,
546 -121, -120, -119, -118, -117, -116, -115, -114,
547 -113, -111, -110, -109, -107, -106, -105, -103,
548 -102, -100, -99, -97, -96, -94, -92, -91,
549 -89, -87, -85, -84, -82, -80, -78, -76,
550 -74, -73, -71, -69, -67, -65, -63, -61,
551 -58, -56, -54, -52, -50, -48, -46, -44,
552 -41, -39, -37, -35, -32, -30, -28, -26,
553 -23, -21, -19, -16, -14, -12, -10, -7,
554 -5, -3, 0, 1, 3, 6, 8, 10,
555 13, 15, 17, 19, 22, 24, 26, 29,
556 31, 33, 35, 38, 40, 42, 44, 46,
557 48, 51, 53, 55, 57, 59, 61, 63,
558 65, 67, 69, 71, 73, 75, 77, 79,
559 81, 82, 84, 86, 88, 89, 91, 93,
560 94, 96, 98, 99, 101, 102, 104, 105,
561 106, 108, 109, 110, 112, 113, 114, 115,
562 116, 117, 119, 120, 120, 121, 122, 123,
563 124, 125, 126, 126, 127, 128, 128, 129,
564 129, 130, 130, 131, 131, 131, 131, 132,
565 132, 132, 132, 132, 132, 132, 132, 132,
566 132, 132, 132, 131, 131, 131, 130, 130,
567 130, 129, 129, 128, 127, 127, 126, 125,
568 125, 124, 123, 122, 121, 120, 119, 118,
569 117, 116, 115, 114, 113, 111, 110, 109,
570 107, 106, 105, 103, 102, 100, 99, 97,
571 96, 94, 92, 91, 89, 87, 85, 84, 82
572};
573
Joe Perches58aa68c2009-09-02 01:12:13 -0300574static const s16 hsv_green_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300575 -124, -124, -125, -125, -125, -125, -125, -125,
576 -125, -126, -126, -125, -125, -125, -125, -125,
577 -125, -124, -124, -124, -123, -123, -122, -122,
578 -121, -121, -120, -120, -119, -118, -117, -117,
579 -116, -115, -114, -113, -112, -111, -110, -109,
580 -108, -107, -105, -104, -103, -102, -100, -99,
581 -98, -96, -95, -93, -92, -91, -89, -87,
582 -86, -84, -83, -81, -79, -77, -76, -74,
583 -72, -70, -69, -67, -65, -63, -61, -59,
584 -57, -55, -53, -51, -49, -47, -45, -43,
585 -41, -39, -37, -35, -33, -30, -28, -26,
586 -24, -22, -20, -18, -15, -13, -11, -9,
587 -7, -4, -2, 0, 1, 3, 6, 8,
588 10, 12, 14, 17, 19, 21, 23, 25,
589 27, 29, 32, 34, 36, 38, 40, 42,
590 44, 46, 48, 50, 52, 54, 56, 58,
591 60, 62, 64, 66, 68, 70, 71, 73,
592 75, 77, 78, 80, 82, 83, 85, 87,
593 88, 90, 91, 93, 94, 96, 97, 98,
594 100, 101, 102, 104, 105, 106, 107, 108,
595 109, 111, 112, 113, 113, 114, 115, 116,
596 117, 118, 118, 119, 120, 120, 121, 122,
597 122, 123, 123, 124, 124, 124, 125, 125,
598 125, 125, 125, 125, 125, 126, 126, 125,
599 125, 125, 125, 125, 125, 124, 124, 124,
600 123, 123, 122, 122, 121, 121, 120, 120,
601 119, 118, 117, 117, 116, 115, 114, 113,
602 112, 111, 110, 109, 108, 107, 105, 104,
603 103, 102, 100, 99, 98, 96, 95, 93,
604 92, 91, 89, 87, 86, 84, 83, 81,
605 79, 77, 76, 74, 72, 70, 69, 67,
606 65, 63, 61, 59, 57, 55, 53, 51,
607 49, 47, 45, 43, 41, 39, 37, 35,
608 33, 30, 28, 26, 24, 22, 20, 18,
609 15, 13, 11, 9, 7, 4, 2, 0,
610 -1, -3, -6, -8, -10, -12, -14, -17,
611 -19, -21, -23, -25, -27, -29, -32, -34,
612 -36, -38, -40, -42, -44, -46, -48, -50,
613 -52, -54, -56, -58, -60, -62, -64, -66,
614 -68, -70, -71, -73, -75, -77, -78, -80,
615 -82, -83, -85, -87, -88, -90, -91, -93,
616 -94, -96, -97, -98, -100, -101, -102, -104,
617 -105, -106, -107, -108, -109, -111, -112, -113,
618 -113, -114, -115, -116, -117, -118, -118, -119,
619 -120, -120, -121, -122, -122, -123, -123, -124, -124
620};
621
Joe Perches58aa68c2009-09-02 01:12:13 -0300622static const s16 hsv_green_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300623 -100, -99, -98, -97, -95, -94, -93, -91,
624 -90, -89, -87, -86, -84, -83, -81, -80,
625 -78, -76, -75, -73, -71, -70, -68, -66,
626 -64, -63, -61, -59, -57, -55, -53, -51,
627 -49, -48, -46, -44, -42, -40, -38, -36,
628 -34, -32, -30, -27, -25, -23, -21, -19,
629 -17, -15, -13, -11, -9, -7, -4, -2,
630 0, 1, 3, 5, 7, 9, 11, 14,
631 16, 18, 20, 22, 24, 26, 28, 30,
632 32, 34, 36, 38, 40, 42, 44, 46,
633 48, 50, 52, 54, 56, 58, 59, 61,
634 63, 65, 67, 68, 70, 72, 74, 75,
635 77, 78, 80, 82, 83, 85, 86, 88,
636 89, 90, 92, 93, 95, 96, 97, 98,
637 100, 101, 102, 103, 104, 105, 106, 107,
638 108, 109, 110, 111, 112, 112, 113, 114,
639 115, 115, 116, 116, 117, 117, 118, 118,
640 119, 119, 119, 120, 120, 120, 120, 120,
641 121, 121, 121, 121, 121, 121, 120, 120,
642 120, 120, 120, 119, 119, 119, 118, 118,
643 117, 117, 116, 116, 115, 114, 114, 113,
644 112, 111, 111, 110, 109, 108, 107, 106,
645 105, 104, 103, 102, 100, 99, 98, 97,
646 95, 94, 93, 91, 90, 89, 87, 86,
647 84, 83, 81, 80, 78, 76, 75, 73,
648 71, 70, 68, 66, 64, 63, 61, 59,
649 57, 55, 53, 51, 49, 48, 46, 44,
650 42, 40, 38, 36, 34, 32, 30, 27,
651 25, 23, 21, 19, 17, 15, 13, 11,
652 9, 7, 4, 2, 0, -1, -3, -5,
653 -7, -9, -11, -14, -16, -18, -20, -22,
654 -24, -26, -28, -30, -32, -34, -36, -38,
655 -40, -42, -44, -46, -48, -50, -52, -54,
656 -56, -58, -59, -61, -63, -65, -67, -68,
657 -70, -72, -74, -75, -77, -78, -80, -82,
658 -83, -85, -86, -88, -89, -90, -92, -93,
659 -95, -96, -97, -98, -100, -101, -102, -103,
660 -104, -105, -106, -107, -108, -109, -110, -111,
661 -112, -112, -113, -114, -115, -115, -116, -116,
662 -117, -117, -118, -118, -119, -119, -119, -120,
663 -120, -120, -120, -120, -121, -121, -121, -121,
664 -121, -121, -120, -120, -120, -120, -120, -119,
665 -119, -119, -118, -118, -117, -117, -116, -116,
666 -115, -114, -114, -113, -112, -111, -111, -110,
667 -109, -108, -107, -106, -105, -104, -103, -102, -100
668};
669
Joe Perches58aa68c2009-09-02 01:12:13 -0300670static const s16 hsv_blue_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300671 112, 113, 114, 114, 115, 116, 117, 117,
672 118, 118, 119, 119, 120, 120, 120, 121,
673 121, 121, 122, 122, 122, 122, 122, 122,
674 122, 122, 122, 122, 122, 122, 121, 121,
675 121, 120, 120, 120, 119, 119, 118, 118,
676 117, 116, 116, 115, 114, 113, 113, 112,
677 111, 110, 109, 108, 107, 106, 105, 104,
678 103, 102, 100, 99, 98, 97, 95, 94,
679 93, 91, 90, 88, 87, 85, 84, 82,
680 80, 79, 77, 76, 74, 72, 70, 69,
681 67, 65, 63, 61, 60, 58, 56, 54,
682 52, 50, 48, 46, 44, 42, 40, 38,
683 36, 34, 32, 30, 28, 26, 24, 22,
684 19, 17, 15, 13, 11, 9, 7, 5,
685 2, 0, -1, -3, -5, -7, -9, -12,
686 -14, -16, -18, -20, -22, -24, -26, -28,
687 -31, -33, -35, -37, -39, -41, -43, -45,
688 -47, -49, -51, -53, -54, -56, -58, -60,
689 -62, -64, -66, -67, -69, -71, -73, -74,
690 -76, -78, -79, -81, -83, -84, -86, -87,
691 -89, -90, -92, -93, -94, -96, -97, -98,
692 -99, -101, -102, -103, -104, -105, -106, -107,
693 -108, -109, -110, -111, -112, -113, -114, -114,
694 -115, -116, -117, -117, -118, -118, -119, -119,
695 -120, -120, -120, -121, -121, -121, -122, -122,
696 -122, -122, -122, -122, -122, -122, -122, -122,
697 -122, -122, -121, -121, -121, -120, -120, -120,
698 -119, -119, -118, -118, -117, -116, -116, -115,
699 -114, -113, -113, -112, -111, -110, -109, -108,
700 -107, -106, -105, -104, -103, -102, -100, -99,
701 -98, -97, -95, -94, -93, -91, -90, -88,
702 -87, -85, -84, -82, -80, -79, -77, -76,
703 -74, -72, -70, -69, -67, -65, -63, -61,
704 -60, -58, -56, -54, -52, -50, -48, -46,
705 -44, -42, -40, -38, -36, -34, -32, -30,
706 -28, -26, -24, -22, -19, -17, -15, -13,
707 -11, -9, -7, -5, -2, 0, 1, 3,
708 5, 7, 9, 12, 14, 16, 18, 20,
709 22, 24, 26, 28, 31, 33, 35, 37,
710 39, 41, 43, 45, 47, 49, 51, 53,
711 54, 56, 58, 60, 62, 64, 66, 67,
712 69, 71, 73, 74, 76, 78, 79, 81,
713 83, 84, 86, 87, 89, 90, 92, 93,
714 94, 96, 97, 98, 99, 101, 102, 103,
715 104, 105, 106, 107, 108, 109, 110, 111, 112
716};
717
Joe Perches58aa68c2009-09-02 01:12:13 -0300718static const s16 hsv_blue_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300719 -11, -13, -15, -17, -19, -21, -23, -25,
720 -27, -29, -31, -33, -35, -37, -39, -41,
721 -43, -45, -46, -48, -50, -52, -54, -55,
722 -57, -59, -61, -62, -64, -66, -67, -69,
723 -71, -72, -74, -75, -77, -78, -80, -81,
724 -83, -84, -86, -87, -88, -90, -91, -92,
725 -93, -95, -96, -97, -98, -99, -100, -101,
726 -102, -103, -104, -105, -106, -106, -107, -108,
727 -109, -109, -110, -111, -111, -112, -112, -113,
728 -113, -114, -114, -114, -115, -115, -115, -115,
729 -116, -116, -116, -116, -116, -116, -116, -116,
730 -116, -115, -115, -115, -115, -114, -114, -114,
731 -113, -113, -112, -112, -111, -111, -110, -110,
732 -109, -108, -108, -107, -106, -105, -104, -103,
733 -102, -101, -100, -99, -98, -97, -96, -95,
734 -94, -93, -91, -90, -89, -88, -86, -85,
735 -84, -82, -81, -79, -78, -76, -75, -73,
736 -71, -70, -68, -67, -65, -63, -62, -60,
737 -58, -56, -55, -53, -51, -49, -47, -45,
738 -44, -42, -40, -38, -36, -34, -32, -30,
739 -28, -26, -24, -22, -20, -18, -16, -14,
740 -12, -10, -8, -6, -4, -2, 0, 1,
741 3, 5, 7, 9, 11, 13, 15, 17,
742 19, 21, 23, 25, 27, 29, 31, 33,
743 35, 37, 39, 41, 43, 45, 46, 48,
744 50, 52, 54, 55, 57, 59, 61, 62,
745 64, 66, 67, 69, 71, 72, 74, 75,
746 77, 78, 80, 81, 83, 84, 86, 87,
747 88, 90, 91, 92, 93, 95, 96, 97,
748 98, 99, 100, 101, 102, 103, 104, 105,
749 106, 106, 107, 108, 109, 109, 110, 111,
750 111, 112, 112, 113, 113, 114, 114, 114,
751 115, 115, 115, 115, 116, 116, 116, 116,
752 116, 116, 116, 116, 116, 115, 115, 115,
753 115, 114, 114, 114, 113, 113, 112, 112,
754 111, 111, 110, 110, 109, 108, 108, 107,
755 106, 105, 104, 103, 102, 101, 100, 99,
756 98, 97, 96, 95, 94, 93, 91, 90,
757 89, 88, 86, 85, 84, 82, 81, 79,
758 78, 76, 75, 73, 71, 70, 68, 67,
759 65, 63, 62, 60, 58, 56, 55, 53,
760 51, 49, 47, 45, 44, 42, 40, 38,
761 36, 34, 32, 30, 28, 26, 24, 22,
762 20, 18, 16, 14, 12, 10, 8, 6,
763 4, 2, 0, -1, -3, -5, -7, -9, -11
764};
765
766static u16 i2c_ident[] = {
767 V4L2_IDENT_OV9650,
768 V4L2_IDENT_OV9655,
769 V4L2_IDENT_SOI968,
770 V4L2_IDENT_OV7660,
771 V4L2_IDENT_OV7670,
772 V4L2_IDENT_MT9V011,
773 V4L2_IDENT_MT9V111,
774 V4L2_IDENT_MT9V112,
775 V4L2_IDENT_MT9M001C12ST,
776 V4L2_IDENT_MT9M111,
Brian Johnsone99ac542010-03-16 13:58:28 -0300777 V4L2_IDENT_MT9M112,
Brian Johnson26e744b2009-07-19 05:52:58 -0300778 V4L2_IDENT_HV7131R,
779};
780
781static u16 bridge_init[][2] = {
782 {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c},
783 {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40},
784 {0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10},
785 {0x106b, 0x08}, {0x1188, 0x87}, {0x11a1, 0x00},
786 {0x11a2, 0x00}, {0x11a3, 0x6a}, {0x11a4, 0x50},
787 {0x11ab, 0x00}, {0x11ac, 0x00}, {0x11ad, 0x50},
788 {0x11ae, 0x3c}, {0x118a, 0x04}, {0x0395, 0x04},
789 {0x11b8, 0x3a}, {0x118b, 0x0e}, {0x10f7, 0x05},
790 {0x10f8, 0x14}, {0x10fa, 0xff}, {0x10f9, 0x00},
791 {0x11ba, 0x0a}, {0x11a5, 0x2d}, {0x11a6, 0x2d},
792 {0x11a7, 0x3a}, {0x11a8, 0x05}, {0x11a9, 0x04},
793 {0x11aa, 0x3f}, {0x11af, 0x28}, {0x11b0, 0xd8},
794 {0x11b1, 0x14}, {0x11b2, 0xec}, {0x11b3, 0x32},
795 {0x11b4, 0xdd}, {0x11b5, 0x32}, {0x11b6, 0xdd},
796 {0x10e0, 0x2c}, {0x11bc, 0x40}, {0x11bd, 0x01},
797 {0x11be, 0xf0}, {0x11bf, 0x00}, {0x118c, 0x1f},
798 {0x118d, 0x1f}, {0x118e, 0x1f}, {0x118f, 0x1f},
799 {0x1180, 0x01}, {0x1181, 0x00}, {0x1182, 0x01},
Brian Johnson0c045eb2010-03-16 13:58:27 -0300800 {0x1183, 0x00}, {0x1184, 0x50}, {0x1185, 0x80},
801 {0x1007, 0x00}
Brian Johnson26e744b2009-07-19 05:52:58 -0300802};
803
804/* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */
805static u8 ov_gain[] = {
806 0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */,
807 0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */,
808 0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */,
809 0x30 /* 4x */, 0x31 /* 4.25x */, 0x32 /* 4.5x */, 0x33 /* 4.75x */,
810 0x34 /* 5x */, 0x35 /* 5.25x */, 0x36 /* 5.5x */, 0x37 /* 5.75x */,
811 0x38 /* 6x */, 0x39 /* 6.25x */, 0x3a /* 6.5x */, 0x3b /* 6.75x */,
812 0x3c /* 7x */, 0x3d /* 7.25x */, 0x3e /* 7.5x */, 0x3f /* 7.75x */,
813 0x70 /* 8x */
814};
815
816/* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */
817static u16 micron1_gain[] = {
818 /* 1x 1.25x 1.5x 1.75x */
819 0x0020, 0x0028, 0x0030, 0x0038,
820 /* 2x 2.25x 2.5x 2.75x */
821 0x00a0, 0x00a4, 0x00a8, 0x00ac,
822 /* 3x 3.25x 3.5x 3.75x */
823 0x00b0, 0x00b4, 0x00b8, 0x00bc,
824 /* 4x 4.25x 4.5x 4.75x */
825 0x00c0, 0x00c4, 0x00c8, 0x00cc,
826 /* 5x 5.25x 5.5x 5.75x */
827 0x00d0, 0x00d4, 0x00d8, 0x00dc,
828 /* 6x 6.25x 6.5x 6.75x */
829 0x00e0, 0x00e4, 0x00e8, 0x00ec,
830 /* 7x 7.25x 7.5x 7.75x */
831 0x00f0, 0x00f4, 0x00f8, 0x00fc,
832 /* 8x */
833 0x01c0
834};
835
836/* mt9m001 sensor uses a different gain formula then other micron sensors */
837/* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */
838static u16 micron2_gain[] = {
839 /* 1x 1.25x 1.5x 1.75x */
840 0x0008, 0x000a, 0x000c, 0x000e,
841 /* 2x 2.25x 2.5x 2.75x */
842 0x0010, 0x0012, 0x0014, 0x0016,
843 /* 3x 3.25x 3.5x 3.75x */
844 0x0018, 0x001a, 0x001c, 0x001e,
845 /* 4x 4.25x 4.5x 4.75x */
846 0x0020, 0x0051, 0x0052, 0x0053,
847 /* 5x 5.25x 5.5x 5.75x */
848 0x0054, 0x0055, 0x0056, 0x0057,
849 /* 6x 6.25x 6.5x 6.75x */
850 0x0058, 0x0059, 0x005a, 0x005b,
851 /* 7x 7.25x 7.5x 7.75x */
852 0x005c, 0x005d, 0x005e, 0x005f,
853 /* 8x */
854 0x0060
855};
856
857/* Gain = .5 + bit[7:0] / 16 */
858static u8 hv7131r_gain[] = {
859 0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */,
860 0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */,
861 0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */,
862 0x38 /* 4x */, 0x3c /* 4.25x */, 0x40 /* 4.5x */, 0x44 /* 4.75x */,
863 0x48 /* 5x */, 0x4c /* 5.25x */, 0x50 /* 5.5x */, 0x54 /* 5.75x */,
864 0x58 /* 6x */, 0x5c /* 6.25x */, 0x60 /* 6.5x */, 0x64 /* 6.75x */,
865 0x68 /* 7x */, 0x6c /* 7.25x */, 0x70 /* 7.5x */, 0x74 /* 7.75x */,
866 0x78 /* 8x */
867};
868
Joe Perches58aa68c2009-09-02 01:12:13 -0300869static struct i2c_reg_u8 soi968_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300870 {0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f},
871 {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
872 {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
873 {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
874 {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20},
875 {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e},
Brian Johnsone1430472009-09-02 12:39:41 -0300876 {0x13, 0x8b}, {0x12, 0x40}, {0x17, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300877 {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79},
878 {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40},
879 {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32},
880 {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80},
881};
882
Joe Perches58aa68c2009-09-02 01:12:13 -0300883static struct i2c_reg_u8 ov7660_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300884 {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
885 {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
886 {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
Hans de Goede8bc50f32011-02-16 07:11:14 -0300887 /* HDG Set hstart and hstop, datasheet default 0x11, 0x61, using
888 0x10, 0x61 and sd->hstart, vstart = 3, fixes ugly colored borders */
889 {0x17, 0x10}, {0x18, 0x61},
Brian Johnson26e744b2009-07-19 05:52:58 -0300890 {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43},
891 {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0xf6},
892 {0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50},
893};
894
Joe Perches58aa68c2009-09-02 01:12:13 -0300895static struct i2c_reg_u8 ov7670_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300896 {0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
897 {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
898 {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
899 {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
900 {0x0d, 0x40}, {0x14, 0x28}, {0xa5, 0x05}, {0xab, 0x07},
901 {0x24, 0x95}, {0x25, 0x33}, {0x26, 0xe3}, {0x9f, 0x75},
902 {0xa0, 0x65}, {0xa1, 0x0b}, {0xa6, 0xd8}, {0xa7, 0xd8},
903 {0xa8, 0xf0}, {0xa9, 0x90}, {0xaa, 0x94}, {0x13, 0xe5},
904 {0x0e, 0x61}, {0x0f, 0x4b}, {0x16, 0x02}, {0x1e, 0x27},
905 {0x21, 0x02}, {0x22, 0x91}, {0x29, 0x07}, {0x33, 0x0b},
906 {0x35, 0x0b}, {0x37, 0x1d}, {0x38, 0x71}, {0x39, 0x2a},
907 {0x3c, 0x78}, {0x4d, 0x40}, {0x4e, 0x20}, {0x69, 0x00},
908 {0x74, 0x19}, {0x8d, 0x4f}, {0x8e, 0x00}, {0x8f, 0x00},
909 {0x90, 0x00}, {0x91, 0x00}, {0x96, 0x00}, {0x9a, 0x80},
910 {0xb0, 0x84}, {0xb1, 0x0c}, {0xb2, 0x0e}, {0xb3, 0x82},
911 {0xb8, 0x0a}, {0x43, 0x0a}, {0x44, 0xf0}, {0x45, 0x20},
912 {0x46, 0x7d}, {0x47, 0x29}, {0x48, 0x4a}, {0x59, 0x8c},
913 {0x5a, 0xa5}, {0x5b, 0xde}, {0x5c, 0x96}, {0x5d, 0x66},
914 {0x5e, 0x10}, {0x6c, 0x0a}, {0x6d, 0x55}, {0x6e, 0x11},
915 {0x6f, 0x9e}, {0x6a, 0x40}, {0x01, 0x40}, {0x02, 0x40},
916 {0x13, 0xe7}, {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x02},
917 {0x52, 0x1d}, {0x53, 0x56}, {0x54, 0x73}, {0x55, 0x0a},
918 {0x56, 0x55}, {0x57, 0x80}, {0x58, 0x9e}, {0x41, 0x08},
919 {0x3f, 0x02}, {0x75, 0x03}, {0x76, 0x63}, {0x4c, 0x04},
920 {0x77, 0x06}, {0x3d, 0x02}, {0x4b, 0x09}, {0xc9, 0x30},
921 {0x41, 0x08}, {0x56, 0x48}, {0x34, 0x11}, {0xa4, 0x88},
922 {0x96, 0x00}, {0x97, 0x30}, {0x98, 0x20}, {0x99, 0x30},
923 {0x9a, 0x84}, {0x9b, 0x29}, {0x9c, 0x03}, {0x9d, 0x99},
924 {0x9e, 0x7f}, {0x78, 0x04}, {0x79, 0x01}, {0xc8, 0xf0},
925 {0x79, 0x0f}, {0xc8, 0x00}, {0x79, 0x10}, {0xc8, 0x7e},
926 {0x79, 0x0a}, {0xc8, 0x80}, {0x79, 0x0b}, {0xc8, 0x01},
927 {0x79, 0x0c}, {0xc8, 0x0f}, {0x79, 0x0d}, {0xc8, 0x20},
928 {0x79, 0x09}, {0xc8, 0x80}, {0x79, 0x02}, {0xc8, 0xc0},
929 {0x79, 0x03}, {0xc8, 0x40}, {0x79, 0x05}, {0xc8, 0x30},
930 {0x79, 0x26}, {0x62, 0x20}, {0x63, 0x00}, {0x64, 0x06},
931 {0x65, 0x00}, {0x66, 0x05}, {0x94, 0x05}, {0x95, 0x0a},
932 {0x17, 0x13}, {0x18, 0x01}, {0x19, 0x02}, {0x1a, 0x7a},
933 {0x46, 0x59}, {0x47, 0x30}, {0x58, 0x9a}, {0x59, 0x84},
934 {0x5a, 0x91}, {0x5b, 0x57}, {0x5c, 0x75}, {0x5d, 0x6d},
935 {0x5e, 0x13}, {0x64, 0x07}, {0x94, 0x07}, {0x95, 0x0d},
936 {0xa6, 0xdf}, {0xa7, 0xdf}, {0x48, 0x4d}, {0x51, 0x00},
937 {0x6b, 0x0a}, {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00},
938 {0x92, 0x00}, {0x93, 0x00}, {0x55, 0x0a}, {0x56, 0x60},
939 {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d},
940 {0x53, 0x56}, {0x54, 0x73}, {0x58, 0x9a}, {0x4f, 0x6e},
941 {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, {0x53, 0x56},
942 {0x54, 0x73}, {0x58, 0x9a}, {0x3f, 0x01}, {0x7b, 0x03},
943 {0x7c, 0x09}, {0x7d, 0x16}, {0x7e, 0x38}, {0x7f, 0x47},
944 {0x80, 0x53}, {0x81, 0x5e}, {0x82, 0x6a}, {0x83, 0x74},
945 {0x84, 0x80}, {0x85, 0x8c}, {0x86, 0x9b}, {0x87, 0xb2},
946 {0x88, 0xcc}, {0x89, 0xe5}, {0x7a, 0x24}, {0x3b, 0x00},
947 {0x9f, 0x76}, {0xa0, 0x65}, {0x13, 0xe2}, {0x6b, 0x0a},
948 {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, {0x92, 0x00},
949 {0x93, 0x00},
950};
951
Joe Perches58aa68c2009-09-02 01:12:13 -0300952static struct i2c_reg_u8 ov9650_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300953 {0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78},
954 {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
955 {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
956 {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
957 {0x0e, 0xa0}, {0x0f, 0x52}, {0x10, 0x7c},
958 {0x11, 0x80}, {0x12, 0x45}, {0x13, 0xc2},
959 {0x14, 0x2e}, {0x15, 0x00}, {0x16, 0x07},
960 {0x17, 0x24}, {0x18, 0xc5}, {0x19, 0x00},
961 {0x1a, 0x3c}, {0x1b, 0x00}, {0x1e, 0x04},
962 {0x1f, 0x00}, {0x24, 0x78}, {0x25, 0x68},
963 {0x26, 0xd4}, {0x27, 0x80}, {0x28, 0x80},
964 {0x29, 0x30}, {0x2a, 0x00}, {0x2b, 0x00},
965 {0x2c, 0x80}, {0x2d, 0x00}, {0x2e, 0x00},
966 {0x2f, 0x00}, {0x30, 0x08}, {0x31, 0x30},
967 {0x32, 0x84}, {0x33, 0xe2}, {0x34, 0xbf},
968 {0x35, 0x81}, {0x36, 0xf9}, {0x37, 0x00},
969 {0x38, 0x93}, {0x39, 0x50}, {0x3a, 0x01},
970 {0x3b, 0x01}, {0x3c, 0x73}, {0x3d, 0x19},
971 {0x3e, 0x0b}, {0x3f, 0x80}, {0x40, 0xc1},
972 {0x41, 0x00}, {0x42, 0x08}, {0x67, 0x80},
973 {0x68, 0x80}, {0x69, 0x40}, {0x6a, 0x00},
974 {0x6b, 0x0a}, {0x8b, 0x06}, {0x8c, 0x20},
975 {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0xdf},
976 {0x92, 0x00}, {0x93, 0x00}, {0x94, 0x88},
977 {0x95, 0x88}, {0x96, 0x04}, {0xa1, 0x00},
978 {0xa5, 0x80}, {0xa8, 0x80}, {0xa9, 0xb8},
979 {0xaa, 0x92}, {0xab, 0x0a},
980};
981
Joe Perches58aa68c2009-09-02 01:12:13 -0300982static struct i2c_reg_u8 ov9655_init[] = {
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300983 {0x12, 0x80}, {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
984 {0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
985 {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
986 {0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57},
987 {0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c}, {0x3d, 0x19},
988 {0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40}, {0x42, 0x80},
989 {0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a}, {0x48, 0x3c},
990 {0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc}, {0x4d, 0xdc},
991 {0x4e, 0xdc}, {0x6c, 0x04}, {0x6f, 0x9e}, {0x70, 0x05},
992 {0x71, 0x78}, {0x77, 0x02}, {0x8a, 0x23}, {0x90, 0x7e},
993 {0x91, 0x7c}, {0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68},
994 {0xa6, 0x60}, {0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92},
995 {0xab, 0x04}, {0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80},
996 {0xaf, 0x80}, {0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00},
997 {0xb6, 0xaf}, {0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44},
998 {0xbe, 0x3b}, {0xbf, 0x3a}, {0xc1, 0xc8}, {0xc2, 0x01},
Brian Johnson26e744b2009-07-19 05:52:58 -0300999 {0xc4, 0x00}, {0xc6, 0x85}, {0xc7, 0x81}, {0xc9, 0xe0},
Brian Johnsoncc2a8332010-03-16 13:58:28 -03001000 {0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x2d, 0x00},
1001 {0x2e, 0x00}, {0x01, 0x80}, {0x02, 0x80}, {0x12, 0x61},
Brian Johnson26e744b2009-07-19 05:52:58 -03001002 {0x36, 0xfa}, {0x8c, 0x8d}, {0xc0, 0xaa}, {0x69, 0x0a},
Brian Johnsoncc2a8332010-03-16 13:58:28 -03001003 {0x03, 0x09}, {0x17, 0x16}, {0x18, 0x6e}, {0x19, 0x01},
1004 {0x1a, 0x3e}, {0x32, 0x09}, {0x2a, 0x10}, {0x2b, 0x0a},
1005 {0x92, 0x00}, {0x93, 0x00}, {0xa1, 0x00}, {0x10, 0x7c},
1006 {0x04, 0x03}, {0x00, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -03001007};
1008
Joe Perches58aa68c2009-09-02 01:12:13 -03001009static struct i2c_reg_u16 mt9v112_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001010 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020},
1011 {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
1012 {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
1013 {0x05, 0x0000}, {0x06, 0x340c}, {0x3b, 0x042a},
1014 {0x3c, 0x0400}, {0xf0, 0x0002}, {0x2e, 0x0c58},
1015 {0x5b, 0x0001}, {0xc8, 0x9f0b}, {0xf0, 0x0001},
1016 {0x9b, 0x5300}, {0xf0, 0x0000}, {0x2b, 0x0020},
1017 {0x2c, 0x002a}, {0x2d, 0x0032}, {0x2e, 0x0020},
1018 {0x09, 0x01dc}, {0x01, 0x000c}, {0x02, 0x0020},
1019 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
1020 {0x05, 0x0098}, {0x20, 0x0703}, {0x09, 0x01f2},
1021 {0x2b, 0x00a0}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
1022 {0x2e, 0x00a0}, {0x01, 0x000c}, {0x02, 0x0020},
1023 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
1024 {0x05, 0x0098}, {0x09, 0x01c1}, {0x2b, 0x00ae},
1025 {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
1026};
1027
Joe Perches58aa68c2009-09-02 01:12:13 -03001028static struct i2c_reg_u16 mt9v111_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001029 {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
Brian Johnson6ea23bd2010-05-05 13:22:45 -03001030 {0x01, 0x0001}, {0x05, 0x0004}, {0x2d, 0xe0a0},
1031 {0x2e, 0x0c64}, {0x2f, 0x0064}, {0x06, 0x600e},
1032 {0x08, 0x0480}, {0x01, 0x0004}, {0x02, 0x0016},
1033 {0x03, 0x01e7}, {0x04, 0x0287}, {0x05, 0x0004},
1034 {0x06, 0x002d}, {0x07, 0x3002}, {0x08, 0x0008},
1035 {0x0e, 0x0008}, {0x20, 0x0000}
Brian Johnson26e744b2009-07-19 05:52:58 -03001036};
1037
Joe Perches58aa68c2009-09-02 01:12:13 -03001038static struct i2c_reg_u16 mt9v011_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001039 {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
1040 {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1},
1041 {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006},
1042 {0x0d, 0x0002}, {0x0a, 0x0000}, {0x0b, 0x0000},
1043 {0x0c, 0x0000}, {0x0d, 0x0000}, {0x0e, 0x0000},
1044 {0x0f, 0x0000}, {0x10, 0x0000}, {0x11, 0x0000},
1045 {0x12, 0x0000}, {0x13, 0x0000}, {0x14, 0x0000},
1046 {0x15, 0x0000}, {0x16, 0x0000}, {0x17, 0x0000},
1047 {0x18, 0x0000}, {0x19, 0x0000}, {0x1a, 0x0000},
1048 {0x1b, 0x0000}, {0x1c, 0x0000}, {0x1d, 0x0000},
1049 {0x32, 0x0000}, {0x20, 0x1101}, {0x21, 0x0000},
1050 {0x22, 0x0000}, {0x23, 0x0000}, {0x24, 0x0000},
1051 {0x25, 0x0000}, {0x26, 0x0000}, {0x27, 0x0024},
1052 {0x2f, 0xf7b0}, {0x30, 0x0005}, {0x31, 0x0000},
1053 {0x32, 0x0000}, {0x33, 0x0000}, {0x34, 0x0100},
1054 {0x3d, 0x068f}, {0x40, 0x01e0}, {0x41, 0x00d1},
1055 {0x44, 0x0082}, {0x5a, 0x0000}, {0x5b, 0x0000},
1056 {0x5c, 0x0000}, {0x5d, 0x0000}, {0x5e, 0x0000},
1057 {0x5f, 0xa31d}, {0x62, 0x0611}, {0x0a, 0x0000},
1058 {0x06, 0x0029}, {0x05, 0x0009}, {0x20, 0x1101},
1059 {0x20, 0x1101}, {0x09, 0x0064}, {0x07, 0x0003},
1060 {0x2b, 0x0033}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
1061 {0x2e, 0x0033}, {0x07, 0x0002}, {0x06, 0x0000},
1062 {0x06, 0x0029}, {0x05, 0x0009},
1063};
1064
Joe Perches58aa68c2009-09-02 01:12:13 -03001065static struct i2c_reg_u16 mt9m001_init[] = {
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001066 {0x0d, 0x0001},
1067 {0x0d, 0x0000},
1068 {0x04, 0x0500}, /* hres = 1280 */
1069 {0x03, 0x0400}, /* vres = 1024 */
1070 {0x20, 0x1100},
1071 {0x06, 0x0010},
1072 {0x2b, 0x0024},
1073 {0x2e, 0x0024},
1074 {0x35, 0x0024},
1075 {0x2d, 0x0020},
1076 {0x2c, 0x0020},
1077 {0x09, 0x0ad4},
1078 {0x35, 0x0057},
Brian Johnson26e744b2009-07-19 05:52:58 -03001079};
1080
Joe Perches58aa68c2009-09-02 01:12:13 -03001081static struct i2c_reg_u16 mt9m111_init[] = {
Brian Johnson13a84fa2009-09-03 19:07:13 -03001082 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
1083 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
Brian Johnson4d708a52009-09-03 19:10:15 -03001084 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
1085 {0xf0, 0x0000},
Brian Johnson26e744b2009-07-19 05:52:58 -03001086};
1087
Brian Johnsone99ac542010-03-16 13:58:28 -03001088static struct i2c_reg_u16 mt9m112_init[] = {
1089 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
1090 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
1091 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
1092 {0xf0, 0x0000},
1093};
1094
Joe Perches58aa68c2009-09-02 01:12:13 -03001095static struct i2c_reg_u8 hv7131r_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001096 {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
1097 {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
1098 {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
1099 {0x01, 0x08}, {0x01, 0x08}, {0x25, 0x07},
1100 {0x26, 0xc3}, {0x27, 0x50}, {0x30, 0x62},
1101 {0x31, 0x10}, {0x32, 0x06}, {0x33, 0x10},
1102 {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00},
1103 {0x23, 0x09}, {0x01, 0x08},
1104};
1105
Joe Perches58aa68c2009-09-02 01:12:13 -03001106static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
Brian Johnson26e744b2009-07-19 05:52:58 -03001107{
1108 struct usb_device *dev = gspca_dev->dev;
1109 int result;
1110 result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
1111 0x00,
1112 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
1113 reg,
1114 0x00,
1115 gspca_dev->usb_buf,
1116 length,
1117 500);
1118 if (unlikely(result < 0 || result != length)) {
1119 err("Read register failed 0x%02X", reg);
1120 return -EIO;
1121 }
1122 return 0;
1123}
1124
Joe Perches58aa68c2009-09-02 01:12:13 -03001125static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
1126 const u8 *buffer, int length)
Brian Johnson26e744b2009-07-19 05:52:58 -03001127{
1128 struct usb_device *dev = gspca_dev->dev;
1129 int result;
1130 memcpy(gspca_dev->usb_buf, buffer, length);
1131 result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
1132 0x08,
1133 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
1134 reg,
1135 0x00,
1136 gspca_dev->usb_buf,
1137 length,
1138 500);
1139 if (unlikely(result < 0 || result != length)) {
1140 err("Write register failed index 0x%02X", reg);
1141 return -EIO;
1142 }
1143 return 0;
1144}
1145
Joe Perches58aa68c2009-09-02 01:12:13 -03001146static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
Brian Johnson26e744b2009-07-19 05:52:58 -03001147{
1148 u8 data[1] = {value};
1149 return reg_w(gspca_dev, reg, data, 1);
1150}
1151
Joe Perches58aa68c2009-09-02 01:12:13 -03001152static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
Brian Johnson26e744b2009-07-19 05:52:58 -03001153{
1154 int i;
1155 reg_w(gspca_dev, 0x10c0, buffer, 8);
1156 for (i = 0; i < 5; i++) {
1157 reg_r(gspca_dev, 0x10c0, 1);
1158 if (gspca_dev->usb_buf[0] & 0x04) {
1159 if (gspca_dev->usb_buf[0] & 0x08)
Brian Johnson00b581e2009-07-23 05:55:43 -03001160 return -EIO;
Brian Johnson26e744b2009-07-19 05:52:58 -03001161 return 0;
1162 }
1163 msleep(1);
1164 }
Brian Johnson00b581e2009-07-23 05:55:43 -03001165 return -EIO;
Brian Johnson26e744b2009-07-19 05:52:58 -03001166}
1167
Joe Perches58aa68c2009-09-02 01:12:13 -03001168static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001169{
1170 struct sd *sd = (struct sd *) gspca_dev;
1171
1172 u8 row[8];
1173
1174 /*
1175 * from the point of view of the bridge, the length
1176 * includes the address
1177 */
1178 row[0] = 0x81 | (2 << 4);
1179 row[1] = sd->i2c_addr;
1180 row[2] = reg;
1181 row[3] = val;
1182 row[4] = 0x00;
1183 row[5] = 0x00;
1184 row[6] = 0x00;
1185 row[7] = 0x10;
1186
1187 return i2c_w(gspca_dev, row);
1188}
1189
Joe Perches58aa68c2009-09-02 01:12:13 -03001190static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001191{
1192 struct sd *sd = (struct sd *) gspca_dev;
1193 u8 row[8];
1194
1195 /*
1196 * from the point of view of the bridge, the length
1197 * includes the address
1198 */
1199 row[0] = 0x81 | (3 << 4);
1200 row[1] = sd->i2c_addr;
1201 row[2] = reg;
1202 row[3] = (val >> 8) & 0xff;
1203 row[4] = val & 0xff;
1204 row[5] = 0x00;
1205 row[6] = 0x00;
1206 row[7] = 0x10;
1207
1208 return i2c_w(gspca_dev, row);
1209}
1210
Jean-Francois Moine83955552009-12-12 06:58:01 -03001211static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001212{
1213 struct sd *sd = (struct sd *) gspca_dev;
1214 u8 row[8];
1215
Brian Johnson00b581e2009-07-23 05:55:43 -03001216 row[0] = 0x81 | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001217 row[1] = sd->i2c_addr;
1218 row[2] = reg;
1219 row[3] = 0;
1220 row[4] = 0;
1221 row[5] = 0;
1222 row[6] = 0;
1223 row[7] = 0x10;
Brian Johnson00b581e2009-07-23 05:55:43 -03001224 if (i2c_w(gspca_dev, row) < 0)
1225 return -EIO;
1226 row[0] = 0x81 | (1 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001227 row[2] = 0;
Brian Johnson00b581e2009-07-23 05:55:43 -03001228 if (i2c_w(gspca_dev, row) < 0)
1229 return -EIO;
1230 if (reg_r(gspca_dev, 0x10c2, 5) < 0)
1231 return -EIO;
1232 *val = gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001233 return 0;
1234}
1235
Jean-Francois Moine83955552009-12-12 06:58:01 -03001236static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001237{
1238 struct sd *sd = (struct sd *) gspca_dev;
1239 u8 row[8];
1240
Brian Johnson00b581e2009-07-23 05:55:43 -03001241 row[0] = 0x81 | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001242 row[1] = sd->i2c_addr;
1243 row[2] = reg;
1244 row[3] = 0;
1245 row[4] = 0;
1246 row[5] = 0;
1247 row[6] = 0;
1248 row[7] = 0x10;
Brian Johnson00b581e2009-07-23 05:55:43 -03001249 if (i2c_w(gspca_dev, row) < 0)
1250 return -EIO;
1251 row[0] = 0x81 | (2 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001252 row[2] = 0;
Brian Johnson00b581e2009-07-23 05:55:43 -03001253 if (i2c_w(gspca_dev, row) < 0)
1254 return -EIO;
1255 if (reg_r(gspca_dev, 0x10c2, 5) < 0)
1256 return -EIO;
1257 *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001258 return 0;
1259}
1260
1261static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
1262{
1263 int i;
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001264 u16 id;
Brian Johnson26e744b2009-07-19 05:52:58 -03001265 struct sd *sd = (struct sd *) gspca_dev;
1266
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001267 if (i2c_r2(gspca_dev, 0x1c, &id) < 0)
1268 return -EINVAL;
1269
1270 if (id != 0x7fa2) {
1271 err("sensor id for ov9650 doesn't match (0x%04x)", id);
1272 return -ENODEV;
1273 }
1274
Brian Johnson26e744b2009-07-19 05:52:58 -03001275 for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001276 if (i2c_w1(gspca_dev, ov9650_init[i].reg,
1277 ov9650_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001278 err("OV9650 sensor initialization failed");
1279 return -ENODEV;
1280 }
1281 }
1282 sd->hstart = 1;
1283 sd->vstart = 7;
1284 return 0;
1285}
1286
1287static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
1288{
1289 int i;
1290 struct sd *sd = (struct sd *) gspca_dev;
1291
1292 for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001293 if (i2c_w1(gspca_dev, ov9655_init[i].reg,
1294 ov9655_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001295 err("OV9655 sensor initialization failed");
1296 return -ENODEV;
1297 }
1298 }
1299 /* disable hflip and vflip */
1300 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
Brian Johnsoncc2a8332010-03-16 13:58:28 -03001301 sd->hstart = 1;
1302 sd->vstart = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001303 return 0;
1304}
1305
1306static int soi968_init_sensor(struct gspca_dev *gspca_dev)
1307{
1308 int i;
1309 struct sd *sd = (struct sd *) gspca_dev;
1310
1311 for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001312 if (i2c_w1(gspca_dev, soi968_init[i].reg,
1313 soi968_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001314 err("SOI968 sensor initialization failed");
1315 return -ENODEV;
1316 }
1317 }
1318 /* disable hflip and vflip */
Jean-François Moine780e3122010-10-19 04:29:10 -03001319 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX)
1320 | (1 << EXPOSURE_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001321 sd->hstart = 60;
1322 sd->vstart = 11;
1323 return 0;
1324}
1325
1326static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
1327{
1328 int i;
1329 struct sd *sd = (struct sd *) gspca_dev;
1330
1331 for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001332 if (i2c_w1(gspca_dev, ov7660_init[i].reg,
1333 ov7660_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001334 err("OV7660 sensor initialization failed");
1335 return -ENODEV;
1336 }
1337 }
1338 /* disable hflip and vflip */
1339 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
Hans de Goede8bc50f32011-02-16 07:11:14 -03001340 sd->hstart = 3;
1341 sd->vstart = 3;
Brian Johnson26e744b2009-07-19 05:52:58 -03001342 return 0;
1343}
1344
1345static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
1346{
1347 int i;
1348 struct sd *sd = (struct sd *) gspca_dev;
1349
1350 for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001351 if (i2c_w1(gspca_dev, ov7670_init[i].reg,
1352 ov7670_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001353 err("OV7670 sensor initialization failed");
1354 return -ENODEV;
1355 }
1356 }
1357 /* disable hflip and vflip */
1358 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
1359 sd->hstart = 0;
1360 sd->vstart = 1;
1361 return 0;
1362}
1363
1364static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
1365{
1366 struct sd *sd = (struct sd *) gspca_dev;
1367 int i;
1368 u16 value;
1369 int ret;
1370
1371 sd->i2c_addr = 0x5d;
1372 ret = i2c_r2(gspca_dev, 0xff, &value);
1373 if ((ret == 0) && (value == 0x8243)) {
1374 for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001375 if (i2c_w2(gspca_dev, mt9v011_init[i].reg,
1376 mt9v011_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001377 err("MT9V011 sensor initialization failed");
1378 return -ENODEV;
1379 }
1380 }
1381 sd->hstart = 2;
1382 sd->vstart = 2;
1383 sd->sensor = SENSOR_MT9V011;
1384 info("MT9V011 sensor detected");
1385 return 0;
1386 }
1387
1388 sd->i2c_addr = 0x5c;
1389 i2c_w2(gspca_dev, 0x01, 0x0004);
1390 ret = i2c_r2(gspca_dev, 0xff, &value);
1391 if ((ret == 0) && (value == 0x823a)) {
1392 for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001393 if (i2c_w2(gspca_dev, mt9v111_init[i].reg,
1394 mt9v111_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001395 err("MT9V111 sensor initialization failed");
1396 return -ENODEV;
1397 }
1398 }
Jean-François Moine780e3122010-10-19 04:29:10 -03001399 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX)
1400 | (1 << AUTOGAIN_IDX)
1401 | (1 << GAIN_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001402 sd->hstart = 2;
1403 sd->vstart = 2;
1404 sd->sensor = SENSOR_MT9V111;
1405 info("MT9V111 sensor detected");
1406 return 0;
1407 }
1408
1409 sd->i2c_addr = 0x5d;
1410 ret = i2c_w2(gspca_dev, 0xf0, 0x0000);
1411 if (ret < 0) {
1412 sd->i2c_addr = 0x48;
1413 i2c_w2(gspca_dev, 0xf0, 0x0000);
1414 }
1415 ret = i2c_r2(gspca_dev, 0x00, &value);
1416 if ((ret == 0) && (value == 0x1229)) {
1417 for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001418 if (i2c_w2(gspca_dev, mt9v112_init[i].reg,
1419 mt9v112_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001420 err("MT9V112 sensor initialization failed");
1421 return -ENODEV;
1422 }
1423 }
1424 sd->hstart = 6;
1425 sd->vstart = 2;
1426 sd->sensor = SENSOR_MT9V112;
1427 info("MT9V112 sensor detected");
1428 return 0;
1429 }
1430
1431 return -ENODEV;
1432}
1433
Brian Johnsone99ac542010-03-16 13:58:28 -03001434static int mt9m112_init_sensor(struct gspca_dev *gspca_dev)
1435{
1436 struct sd *sd = (struct sd *) gspca_dev;
1437 int i;
1438 for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) {
1439 if (i2c_w2(gspca_dev, mt9m112_init[i].reg,
1440 mt9m112_init[i].val) < 0) {
1441 err("MT9M112 sensor initialization failed");
1442 return -ENODEV;
1443 }
1444 }
Jean-François Moine780e3122010-10-19 04:29:10 -03001445 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
1446 | (1 << GAIN_IDX);
Brian Johnsone99ac542010-03-16 13:58:28 -03001447 sd->hstart = 0;
1448 sd->vstart = 2;
1449 return 0;
1450}
1451
Brian Johnson26e744b2009-07-19 05:52:58 -03001452static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
1453{
1454 struct sd *sd = (struct sd *) gspca_dev;
1455 int i;
1456 for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001457 if (i2c_w2(gspca_dev, mt9m111_init[i].reg,
1458 mt9m111_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001459 err("MT9M111 sensor initialization failed");
1460 return -ENODEV;
1461 }
1462 }
Jean-François Moine780e3122010-10-19 04:29:10 -03001463 gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
1464 | (1 << GAIN_IDX);
Brian Johnson26e744b2009-07-19 05:52:58 -03001465 sd->hstart = 0;
1466 sd->vstart = 2;
1467 return 0;
1468}
1469
1470static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
1471{
1472 struct sd *sd = (struct sd *) gspca_dev;
1473 int i;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001474 u16 id;
1475
1476 if (i2c_r2(gspca_dev, 0x00, &id) < 0)
1477 return -EINVAL;
1478
1479 /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
1480 switch (id) {
1481 case 0x8411:
1482 case 0x8421:
1483 info("MT9M001 color sensor detected");
1484 break;
1485 case 0x8431:
1486 info("MT9M001 mono sensor detected");
1487 break;
1488 default:
1489 err("No MT9M001 chip detected, ID = %x\n", id);
1490 return -ENODEV;
1491 }
1492
Brian Johnson26e744b2009-07-19 05:52:58 -03001493 for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001494 if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
1495 mt9m001_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001496 err("MT9M001 sensor initialization failed");
1497 return -ENODEV;
1498 }
1499 }
1500 /* disable hflip and vflip */
1501 gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001502 sd->hstart = 1;
1503 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001504 return 0;
1505}
1506
1507static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
1508{
1509 int i;
1510 struct sd *sd = (struct sd *) gspca_dev;
1511
1512 for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
Joe Perches58aa68c2009-09-02 01:12:13 -03001513 if (i2c_w1(gspca_dev, hv7131r_init[i].reg,
1514 hv7131r_init[i].val) < 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001515 err("HV7131R Sensor initialization failed");
1516 return -ENODEV;
1517 }
1518 }
1519 sd->hstart = 0;
1520 sd->vstart = 1;
1521 return 0;
1522}
1523
Brian Johnson26e744b2009-07-19 05:52:58 -03001524static int set_cmatrix(struct gspca_dev *gspca_dev)
1525{
1526 struct sd *sd = (struct sd *) gspca_dev;
1527 s32 hue_coord, hue_index = 180 + sd->hue;
1528 u8 cmatrix[21];
Brian Johnson26e744b2009-07-19 05:52:58 -03001529
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001530 memset(cmatrix, 0, sizeof cmatrix);
Brian Johnson26e744b2009-07-19 05:52:58 -03001531 cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26;
1532 cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
1533 cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
1534 cmatrix[18] = sd->brightness - 0x80;
1535
1536 hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001537 cmatrix[6] = hue_coord;
1538 cmatrix[7] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001539
1540 hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001541 cmatrix[8] = hue_coord;
1542 cmatrix[9] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001543
1544 hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001545 cmatrix[10] = hue_coord;
1546 cmatrix[11] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001547
1548 hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001549 cmatrix[12] = hue_coord;
1550 cmatrix[13] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001551
1552 hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001553 cmatrix[14] = hue_coord;
1554 cmatrix[15] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001555
1556 hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001557 cmatrix[16] = hue_coord;
1558 cmatrix[17] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001559
1560 return reg_w(gspca_dev, 0x10e1, cmatrix, 21);
1561}
1562
1563static int set_gamma(struct gspca_dev *gspca_dev)
1564{
1565 struct sd *sd = (struct sd *) gspca_dev;
1566 u8 gamma[17];
1567 u8 gval = sd->gamma * 0xb8 / 0x100;
1568
1569
1570 gamma[0] = 0x0a;
1571 gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
1572 gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8);
1573 gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8);
1574 gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8);
1575 gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8);
1576 gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8);
1577 gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8);
1578 gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8);
1579 gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8);
1580 gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8);
1581 gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8);
1582 gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8);
1583 gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8);
1584 gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8);
1585 gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
1586 gamma[16] = 0xf5;
1587
1588 return reg_w(gspca_dev, 0x1190, gamma, 17);
1589}
1590
1591static int set_redblue(struct gspca_dev *gspca_dev)
1592{
1593 struct sd *sd = (struct sd *) gspca_dev;
1594 reg_w1(gspca_dev, 0x118c, sd->red);
1595 reg_w1(gspca_dev, 0x118f, sd->blue);
1596 return 0;
1597}
1598
1599static int set_hvflip(struct gspca_dev *gspca_dev)
1600{
Brian Johnson7ddaac72010-03-16 13:58:27 -03001601 u8 value, tslb, hflip, vflip;
Brian Johnson26e744b2009-07-19 05:52:58 -03001602 u16 value2;
1603 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001604
1605 if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
1606 hflip = !sd->hflip;
1607 vflip = !sd->vflip;
1608 } else {
1609 hflip = sd->hflip;
1610 vflip = sd->vflip;
1611 }
1612
Brian Johnson26e744b2009-07-19 05:52:58 -03001613 switch (sd->sensor) {
1614 case SENSOR_OV9650:
1615 i2c_r1(gspca_dev, 0x1e, &value);
1616 value &= ~0x30;
1617 tslb = 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001618 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001619 value |= 0x20;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001620 if (vflip) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001621 value |= 0x10;
1622 tslb = 0x49;
1623 }
1624 i2c_w1(gspca_dev, 0x1e, value);
1625 i2c_w1(gspca_dev, 0x3a, tslb);
1626 break;
1627 case SENSOR_MT9V111:
1628 case SENSOR_MT9V011:
1629 i2c_r2(gspca_dev, 0x20, &value2);
1630 value2 &= ~0xc0a0;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001631 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001632 value2 |= 0x8080;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001633 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001634 value2 |= 0x4020;
1635 i2c_w2(gspca_dev, 0x20, value2);
1636 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001637 case SENSOR_MT9M112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001638 case SENSOR_MT9M111:
1639 case SENSOR_MT9V112:
1640 i2c_r2(gspca_dev, 0x20, &value2);
1641 value2 &= ~0x0003;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001642 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001643 value2 |= 0x0002;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001644 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001645 value2 |= 0x0001;
1646 i2c_w2(gspca_dev, 0x20, value2);
1647 break;
1648 case SENSOR_HV7131R:
1649 i2c_r1(gspca_dev, 0x01, &value);
1650 value &= ~0x03;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001651 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001652 value |= 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001653 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001654 value |= 0x02;
1655 i2c_w1(gspca_dev, 0x01, value);
1656 break;
1657 }
1658 return 0;
1659}
1660
1661static int set_exposure(struct gspca_dev *gspca_dev)
1662{
1663 struct sd *sd = (struct sd *) gspca_dev;
1664 u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
1665 switch (sd->sensor) {
1666 case SENSOR_OV7660:
1667 case SENSOR_OV7670:
Brian Johnson26e744b2009-07-19 05:52:58 -03001668 case SENSOR_OV9655:
1669 case SENSOR_OV9650:
1670 exp[0] |= (3 << 4);
1671 exp[2] = 0x2d;
1672 exp[3] = sd->exposure & 0xff;
1673 exp[4] = sd->exposure >> 8;
1674 break;
1675 case SENSOR_MT9M001:
Brian Johnson26e744b2009-07-19 05:52:58 -03001676 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001677 case SENSOR_MT9V011:
1678 exp[0] |= (3 << 4);
1679 exp[2] = 0x09;
1680 exp[3] = sd->exposure >> 8;
1681 exp[4] = sd->exposure & 0xff;
1682 break;
1683 case SENSOR_HV7131R:
1684 exp[0] |= (4 << 4);
1685 exp[2] = 0x25;
German Galkine10f7312010-03-07 06:19:02 -03001686 exp[3] = (sd->exposure >> 5) & 0xff;
1687 exp[4] = (sd->exposure << 3) & 0xff;
1688 exp[5] = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001689 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001690 default:
1691 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001692 }
1693 i2c_w(gspca_dev, exp);
1694 return 0;
1695}
1696
1697static int set_gain(struct gspca_dev *gspca_dev)
1698{
1699 struct sd *sd = (struct sd *) gspca_dev;
1700 u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
1701 switch (sd->sensor) {
1702 case SENSOR_OV7660:
1703 case SENSOR_OV7670:
1704 case SENSOR_SOI968:
1705 case SENSOR_OV9655:
1706 case SENSOR_OV9650:
1707 gain[0] |= (2 << 4);
1708 gain[3] = ov_gain[sd->gain];
1709 break;
1710 case SENSOR_MT9V011:
Brian Johnson26e744b2009-07-19 05:52:58 -03001711 gain[0] |= (3 << 4);
1712 gain[2] = 0x35;
1713 gain[3] = micron1_gain[sd->gain] >> 8;
1714 gain[4] = micron1_gain[sd->gain] & 0xff;
1715 break;
1716 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001717 gain[0] |= (3 << 4);
1718 gain[2] = 0x2f;
1719 gain[3] = micron1_gain[sd->gain] >> 8;
1720 gain[4] = micron1_gain[sd->gain] & 0xff;
1721 break;
1722 case SENSOR_MT9M001:
1723 gain[0] |= (3 << 4);
1724 gain[2] = 0x2f;
1725 gain[3] = micron2_gain[sd->gain] >> 8;
1726 gain[4] = micron2_gain[sd->gain] & 0xff;
1727 break;
1728 case SENSOR_HV7131R:
1729 gain[0] |= (2 << 4);
1730 gain[2] = 0x30;
1731 gain[3] = hv7131r_gain[sd->gain];
1732 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001733 default:
1734 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001735 }
1736 i2c_w(gspca_dev, gain);
1737 return 0;
1738}
1739
1740static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val)
1741{
1742 struct sd *sd = (struct sd *) gspca_dev;
1743
1744 sd->brightness = val;
1745 if (gspca_dev->streaming)
1746 return set_cmatrix(gspca_dev);
1747 return 0;
1748}
1749
1750static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val)
1751{
1752 struct sd *sd = (struct sd *) gspca_dev;
1753 *val = sd->brightness;
1754 return 0;
1755}
1756
1757
1758static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val)
1759{
1760 struct sd *sd = (struct sd *) gspca_dev;
1761
1762 sd->contrast = val;
1763 if (gspca_dev->streaming)
1764 return set_cmatrix(gspca_dev);
1765 return 0;
1766}
1767
1768static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val)
1769{
1770 struct sd *sd = (struct sd *) gspca_dev;
1771 *val = sd->contrast;
1772 return 0;
1773}
1774
1775static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val)
1776{
1777 struct sd *sd = (struct sd *) gspca_dev;
1778
1779 sd->saturation = val;
1780 if (gspca_dev->streaming)
1781 return set_cmatrix(gspca_dev);
1782 return 0;
1783}
1784
1785static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val)
1786{
1787 struct sd *sd = (struct sd *) gspca_dev;
1788 *val = sd->saturation;
1789 return 0;
1790}
1791
1792static int sd_sethue(struct gspca_dev *gspca_dev, s32 val)
1793{
1794 struct sd *sd = (struct sd *) gspca_dev;
1795
1796 sd->hue = val;
1797 if (gspca_dev->streaming)
1798 return set_cmatrix(gspca_dev);
1799 return 0;
1800}
1801
1802static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val)
1803{
1804 struct sd *sd = (struct sd *) gspca_dev;
1805 *val = sd->hue;
1806 return 0;
1807}
1808
1809static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val)
1810{
1811 struct sd *sd = (struct sd *) gspca_dev;
1812
1813 sd->gamma = val;
1814 if (gspca_dev->streaming)
1815 return set_gamma(gspca_dev);
1816 return 0;
1817}
1818
1819static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val)
1820{
1821 struct sd *sd = (struct sd *) gspca_dev;
1822 *val = sd->gamma;
1823 return 0;
1824}
1825
1826static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val)
1827{
1828 struct sd *sd = (struct sd *) gspca_dev;
1829
1830 sd->red = val;
1831 if (gspca_dev->streaming)
1832 return set_redblue(gspca_dev);
1833 return 0;
1834}
1835
1836static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val)
1837{
1838 struct sd *sd = (struct sd *) gspca_dev;
1839 *val = sd->red;
1840 return 0;
1841}
1842
1843static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val)
1844{
1845 struct sd *sd = (struct sd *) gspca_dev;
1846
1847 sd->blue = val;
1848 if (gspca_dev->streaming)
1849 return set_redblue(gspca_dev);
1850 return 0;
1851}
1852
1853static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val)
1854{
1855 struct sd *sd = (struct sd *) gspca_dev;
1856 *val = sd->blue;
1857 return 0;
1858}
1859
1860static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val)
1861{
1862 struct sd *sd = (struct sd *) gspca_dev;
1863
1864 sd->hflip = val;
1865 if (gspca_dev->streaming)
1866 return set_hvflip(gspca_dev);
1867 return 0;
1868}
1869
1870static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val)
1871{
1872 struct sd *sd = (struct sd *) gspca_dev;
1873 *val = sd->hflip;
1874 return 0;
1875}
1876
1877static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val)
1878{
1879 struct sd *sd = (struct sd *) gspca_dev;
1880
1881 sd->vflip = val;
1882 if (gspca_dev->streaming)
1883 return set_hvflip(gspca_dev);
1884 return 0;
1885}
1886
1887static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val)
1888{
1889 struct sd *sd = (struct sd *) gspca_dev;
1890 *val = sd->vflip;
1891 return 0;
1892}
1893
1894static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val)
1895{
1896 struct sd *sd = (struct sd *) gspca_dev;
1897
1898 sd->exposure = val;
1899 if (gspca_dev->streaming)
1900 return set_exposure(gspca_dev);
1901 return 0;
1902}
1903
1904static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val)
1905{
1906 struct sd *sd = (struct sd *) gspca_dev;
1907 *val = sd->exposure;
1908 return 0;
1909}
1910
1911static int sd_setgain(struct gspca_dev *gspca_dev, s32 val)
1912{
1913 struct sd *sd = (struct sd *) gspca_dev;
1914
1915 sd->gain = val;
1916 if (gspca_dev->streaming)
1917 return set_gain(gspca_dev);
1918 return 0;
1919}
1920
1921static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val)
1922{
1923 struct sd *sd = (struct sd *) gspca_dev;
1924 *val = sd->gain;
1925 return 0;
1926}
1927
1928static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val)
1929{
1930 struct sd *sd = (struct sd *) gspca_dev;
1931 sd->auto_exposure = val;
1932 return 0;
1933}
1934
1935static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val)
1936{
1937 struct sd *sd = (struct sd *) gspca_dev;
1938 *val = sd->auto_exposure;
1939 return 0;
1940}
1941
1942#ifdef CONFIG_VIDEO_ADV_DEBUG
1943static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
1944 struct v4l2_dbg_register *reg)
1945{
1946 struct sd *sd = (struct sd *) gspca_dev;
1947 switch (reg->match.type) {
1948 case V4L2_CHIP_MATCH_HOST:
1949 if (reg->match.addr != 0)
1950 return -EINVAL;
1951 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1952 return -EINVAL;
1953 if (reg_r(gspca_dev, reg->reg, 1) < 0)
1954 return -EINVAL;
1955 reg->val = gspca_dev->usb_buf[0];
1956 return 0;
1957 case V4L2_CHIP_MATCH_I2C_ADDR:
1958 if (reg->match.addr != sd->i2c_addr)
1959 return -EINVAL;
1960 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001961 sd->sensor <= SENSOR_MT9M112) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001962 if (i2c_r2(gspca_dev, reg->reg, (u16 *)&reg->val) < 0)
1963 return -EINVAL;
1964 } else {
1965 if (i2c_r1(gspca_dev, reg->reg, (u8 *)&reg->val) < 0)
1966 return -EINVAL;
1967 }
1968 return 0;
1969 }
1970 return -EINVAL;
1971}
1972
1973static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
1974 struct v4l2_dbg_register *reg)
1975{
1976 struct sd *sd = (struct sd *) gspca_dev;
1977 switch (reg->match.type) {
1978 case V4L2_CHIP_MATCH_HOST:
1979 if (reg->match.addr != 0)
1980 return -EINVAL;
1981 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1982 return -EINVAL;
1983 if (reg_w1(gspca_dev, reg->reg, reg->val) < 0)
1984 return -EINVAL;
1985 return 0;
1986 case V4L2_CHIP_MATCH_I2C_ADDR:
1987 if (reg->match.addr != sd->i2c_addr)
1988 return -EINVAL;
1989 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001990 sd->sensor <= SENSOR_MT9M112) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001991 if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0)
1992 return -EINVAL;
1993 } else {
1994 if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0)
1995 return -EINVAL;
1996 }
1997 return 0;
1998 }
1999 return -EINVAL;
2000}
2001#endif
2002
2003static int sd_chip_ident(struct gspca_dev *gspca_dev,
2004 struct v4l2_dbg_chip_ident *chip)
2005{
2006 struct sd *sd = (struct sd *) gspca_dev;
2007
2008 switch (chip->match.type) {
2009 case V4L2_CHIP_MATCH_HOST:
2010 if (chip->match.addr != 0)
2011 return -EINVAL;
2012 chip->revision = 0;
2013 chip->ident = V4L2_IDENT_SN9C20X;
2014 return 0;
2015 case V4L2_CHIP_MATCH_I2C_ADDR:
2016 if (chip->match.addr != sd->i2c_addr)
2017 return -EINVAL;
2018 chip->revision = 0;
2019 chip->ident = i2c_ident[sd->sensor];
2020 return 0;
2021 }
2022 return -EINVAL;
2023}
2024
2025static int sd_config(struct gspca_dev *gspca_dev,
2026 const struct usb_device_id *id)
2027{
2028 struct sd *sd = (struct sd *) gspca_dev;
2029 struct cam *cam;
2030
2031 cam = &gspca_dev->cam;
2032
2033 sd->sensor = (id->driver_info >> 8) & 0xff;
2034 sd->i2c_addr = id->driver_info & 0xff;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002035 sd->flags = (id->driver_info >> 16) & 0xff;
Brian Johnson26e744b2009-07-19 05:52:58 -03002036
2037 switch (sd->sensor) {
Brian Johnsone99ac542010-03-16 13:58:28 -03002038 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03002039 case SENSOR_MT9M111:
Brian Johnson26e744b2009-07-19 05:52:58 -03002040 case SENSOR_OV9650:
Brian Johnsone8b7acc2009-09-02 13:14:41 -03002041 case SENSOR_SOI968:
Brian Johnson26e744b2009-07-19 05:52:58 -03002042 cam->cam_mode = sxga_mode;
2043 cam->nmodes = ARRAY_SIZE(sxga_mode);
2044 break;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03002045 case SENSOR_MT9M001:
2046 cam->cam_mode = mono_mode;
2047 cam->nmodes = ARRAY_SIZE(mono_mode);
2048 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002049 default:
2050 cam->cam_mode = vga_mode;
2051 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03002052 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002053 }
2054
2055 sd->old_step = 0;
2056 sd->older_step = 0;
2057 sd->exposure_step = 16;
2058
2059 sd->brightness = BRIGHTNESS_DEFAULT;
2060 sd->contrast = CONTRAST_DEFAULT;
2061 sd->saturation = SATURATION_DEFAULT;
2062 sd->hue = HUE_DEFAULT;
2063 sd->gamma = GAMMA_DEFAULT;
2064 sd->red = RED_DEFAULT;
2065 sd->blue = BLUE_DEFAULT;
2066
2067 sd->hflip = HFLIP_DEFAULT;
2068 sd->vflip = VFLIP_DEFAULT;
2069 sd->exposure = EXPOSURE_DEFAULT;
2070 sd->gain = GAIN_DEFAULT;
2071 sd->auto_exposure = AUTO_EXPOSURE_DEFAULT;
2072
2073 sd->quality = 95;
2074
Brian Johnson26e744b2009-07-19 05:52:58 -03002075 return 0;
2076}
2077
2078static int sd_init(struct gspca_dev *gspca_dev)
2079{
2080 struct sd *sd = (struct sd *) gspca_dev;
2081 int i;
2082 u8 value;
2083 u8 i2c_init[9] =
2084 {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03};
2085
2086 for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
2087 value = bridge_init[i][1];
2088 if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) {
2089 err("Device initialization failed");
2090 return -ENODEV;
2091 }
2092 }
2093
Brian Johnson0c045eb2010-03-16 13:58:27 -03002094 if (sd->flags & LED_REVERSE)
2095 reg_w1(gspca_dev, 0x1006, 0x00);
2096 else
2097 reg_w1(gspca_dev, 0x1006, 0x20);
2098
Brian Johnson26e744b2009-07-19 05:52:58 -03002099 if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
2100 err("Device initialization failed");
2101 return -ENODEV;
2102 }
2103
2104 switch (sd->sensor) {
2105 case SENSOR_OV9650:
2106 if (ov9650_init_sensor(gspca_dev) < 0)
2107 return -ENODEV;
2108 info("OV9650 sensor detected");
2109 break;
2110 case SENSOR_OV9655:
2111 if (ov9655_init_sensor(gspca_dev) < 0)
2112 return -ENODEV;
2113 info("OV9655 sensor detected");
2114 break;
2115 case SENSOR_SOI968:
2116 if (soi968_init_sensor(gspca_dev) < 0)
2117 return -ENODEV;
2118 info("SOI968 sensor detected");
2119 break;
2120 case SENSOR_OV7660:
2121 if (ov7660_init_sensor(gspca_dev) < 0)
2122 return -ENODEV;
2123 info("OV7660 sensor detected");
2124 break;
2125 case SENSOR_OV7670:
2126 if (ov7670_init_sensor(gspca_dev) < 0)
2127 return -ENODEV;
2128 info("OV7670 sensor detected");
2129 break;
2130 case SENSOR_MT9VPRB:
2131 if (mt9v_init_sensor(gspca_dev) < 0)
2132 return -ENODEV;
2133 break;
2134 case SENSOR_MT9M111:
2135 if (mt9m111_init_sensor(gspca_dev) < 0)
2136 return -ENODEV;
2137 info("MT9M111 sensor detected");
2138 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03002139 case SENSOR_MT9M112:
2140 if (mt9m112_init_sensor(gspca_dev) < 0)
2141 return -ENODEV;
2142 info("MT9M112 sensor detected");
2143 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002144 case SENSOR_MT9M001:
2145 if (mt9m001_init_sensor(gspca_dev) < 0)
2146 return -ENODEV;
Brian Johnson26e744b2009-07-19 05:52:58 -03002147 break;
2148 case SENSOR_HV7131R:
2149 if (hv7131r_init_sensor(gspca_dev) < 0)
2150 return -ENODEV;
2151 info("HV7131R sensor detected");
2152 break;
2153 default:
2154 info("Unsupported Sensor");
2155 return -ENODEV;
2156 }
2157
2158 return 0;
2159}
2160
2161static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
2162{
2163 struct sd *sd = (struct sd *) gspca_dev;
2164 u8 value;
2165 switch (sd->sensor) {
Brian Johnsone8b7acc2009-09-02 13:14:41 -03002166 case SENSOR_SOI968:
2167 if (mode & MODE_SXGA) {
2168 i2c_w1(gspca_dev, 0x17, 0x1d);
2169 i2c_w1(gspca_dev, 0x18, 0xbd);
2170 i2c_w1(gspca_dev, 0x19, 0x01);
2171 i2c_w1(gspca_dev, 0x1a, 0x81);
2172 i2c_w1(gspca_dev, 0x12, 0x00);
2173 sd->hstart = 140;
2174 sd->vstart = 19;
2175 } else {
2176 i2c_w1(gspca_dev, 0x17, 0x13);
2177 i2c_w1(gspca_dev, 0x18, 0x63);
2178 i2c_w1(gspca_dev, 0x19, 0x01);
2179 i2c_w1(gspca_dev, 0x1a, 0x79);
2180 i2c_w1(gspca_dev, 0x12, 0x40);
2181 sd->hstart = 60;
2182 sd->vstart = 11;
2183 }
2184 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002185 case SENSOR_OV9650:
2186 if (mode & MODE_SXGA) {
2187 i2c_w1(gspca_dev, 0x17, 0x1b);
2188 i2c_w1(gspca_dev, 0x18, 0xbc);
2189 i2c_w1(gspca_dev, 0x19, 0x01);
2190 i2c_w1(gspca_dev, 0x1a, 0x82);
2191 i2c_r1(gspca_dev, 0x12, &value);
2192 i2c_w1(gspca_dev, 0x12, value & 0x07);
2193 } else {
2194 i2c_w1(gspca_dev, 0x17, 0x24);
2195 i2c_w1(gspca_dev, 0x18, 0xc5);
2196 i2c_w1(gspca_dev, 0x19, 0x00);
2197 i2c_w1(gspca_dev, 0x1a, 0x3c);
2198 i2c_r1(gspca_dev, 0x12, &value);
2199 i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
2200 }
2201 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03002202 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03002203 case SENSOR_MT9M111:
2204 if (mode & MODE_SXGA) {
2205 i2c_w2(gspca_dev, 0xf0, 0x0002);
2206 i2c_w2(gspca_dev, 0xc8, 0x970b);
2207 i2c_w2(gspca_dev, 0xf0, 0x0000);
2208 } else {
2209 i2c_w2(gspca_dev, 0xf0, 0x0002);
2210 i2c_w2(gspca_dev, 0xc8, 0x8000);
2211 i2c_w2(gspca_dev, 0xf0, 0x0000);
2212 }
2213 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002214 }
2215}
2216
2217#define HW_WIN(mode, hstart, vstart) \
Jean-Francois Moine83955552009-12-12 06:58:01 -03002218((const u8 []){hstart, 0, vstart, 0, \
Brian Johnson26e744b2009-07-19 05:52:58 -03002219(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
2220(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)})
2221
2222#define CLR_WIN(width, height) \
2223((const u8 [])\
2224{0, width >> 2, 0, height >> 1,\
2225((width >> 10) & 0x01) | ((height >> 8) & 0x6)})
2226
2227static int sd_start(struct gspca_dev *gspca_dev)
2228{
2229 struct sd *sd = (struct sd *) gspca_dev;
2230 int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
2231 int width = gspca_dev->width;
2232 int height = gspca_dev->height;
2233 u8 fmt, scale = 0;
2234
Brian Johnson26e744b2009-07-19 05:52:58 -03002235 jpeg_define(sd->jpeg_hdr, height, width,
2236 0x21);
2237 jpeg_set_qual(sd->jpeg_hdr, sd->quality);
2238
2239 if (mode & MODE_RAW)
2240 fmt = 0x2d;
2241 else if (mode & MODE_JPEG)
2242 fmt = 0x2c;
2243 else
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002244 fmt = 0x2f; /* YUV 420 */
Brian Johnson26e744b2009-07-19 05:52:58 -03002245
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002246 switch (mode & SCALE_MASK) {
2247 case SCALE_1280x1024:
Brian Johnson26e744b2009-07-19 05:52:58 -03002248 scale = 0xc0;
2249 info("Set 1280x1024");
2250 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002251 case SCALE_640x480:
Brian Johnson26e744b2009-07-19 05:52:58 -03002252 scale = 0x80;
2253 info("Set 640x480");
2254 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002255 case SCALE_320x240:
Brian Johnson26e744b2009-07-19 05:52:58 -03002256 scale = 0x90;
2257 info("Set 320x240");
2258 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002259 case SCALE_160x120:
Brian Johnson26e744b2009-07-19 05:52:58 -03002260 scale = 0xa0;
2261 info("Set 160x120");
2262 break;
2263 }
2264
2265 configure_sensor_output(gspca_dev, mode);
Jean-François Moine9a731a32010-06-04 05:26:42 -03002266 reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
2267 reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
Brian Johnson26e744b2009-07-19 05:52:58 -03002268 reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
2269 reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
2270 reg_w1(gspca_dev, 0x1189, scale);
2271 reg_w1(gspca_dev, 0x10e0, fmt);
2272
2273 set_cmatrix(gspca_dev);
2274 set_gamma(gspca_dev);
2275 set_redblue(gspca_dev);
2276 set_gain(gspca_dev);
2277 set_exposure(gspca_dev);
2278 set_hvflip(gspca_dev);
2279
Brian Johnson0c045eb2010-03-16 13:58:27 -03002280 reg_w1(gspca_dev, 0x1007, 0x20);
2281
Brian Johnson26e744b2009-07-19 05:52:58 -03002282 reg_r(gspca_dev, 0x1061, 1);
2283 reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02);
2284 return 0;
2285}
2286
2287static void sd_stopN(struct gspca_dev *gspca_dev)
2288{
Brian Johnson0c045eb2010-03-16 13:58:27 -03002289 reg_w1(gspca_dev, 0x1007, 0x00);
2290
Brian Johnson26e744b2009-07-19 05:52:58 -03002291 reg_r(gspca_dev, 0x1061, 1);
2292 reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
2293}
2294
Brian Johnsone1430472009-09-02 12:39:41 -03002295static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
Brian Johnson26e744b2009-07-19 05:52:58 -03002296{
2297 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnsone1430472009-09-02 12:39:41 -03002298 s16 new_exp;
Brian Johnson26e744b2009-07-19 05:52:58 -03002299
2300 /*
2301 * some hardcoded values are present
2302 * like those for maximal/minimal exposure
2303 * and exposure steps
2304 */
2305 if (avg_lum < MIN_AVG_LUM) {
2306 if (sd->exposure > 0x1770)
2307 return;
2308
2309 new_exp = sd->exposure + sd->exposure_step;
2310 if (new_exp > 0x1770)
2311 new_exp = 0x1770;
2312 if (new_exp < 0x10)
2313 new_exp = 0x10;
2314 sd->exposure = new_exp;
2315 set_exposure(gspca_dev);
2316
2317 sd->older_step = sd->old_step;
2318 sd->old_step = 1;
2319
2320 if (sd->old_step ^ sd->older_step)
2321 sd->exposure_step /= 2;
2322 else
2323 sd->exposure_step += 2;
2324 }
2325 if (avg_lum > MAX_AVG_LUM) {
2326 if (sd->exposure < 0x10)
2327 return;
2328 new_exp = sd->exposure - sd->exposure_step;
2329 if (new_exp > 0x1700)
2330 new_exp = 0x1770;
2331 if (new_exp < 0x10)
2332 new_exp = 0x10;
2333 sd->exposure = new_exp;
2334 set_exposure(gspca_dev);
2335 sd->older_step = sd->old_step;
2336 sd->old_step = 0;
2337
2338 if (sd->old_step ^ sd->older_step)
2339 sd->exposure_step /= 2;
2340 else
2341 sd->exposure_step += 2;
2342 }
2343}
2344
Brian Johnsone1430472009-09-02 12:39:41 -03002345static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
2346{
2347 struct sd *sd = (struct sd *) gspca_dev;
2348
2349 if (avg_lum < MIN_AVG_LUM) {
2350 if (sd->gain + 1 <= 28) {
2351 sd->gain++;
2352 set_gain(gspca_dev);
2353 }
2354 }
2355 if (avg_lum > MAX_AVG_LUM) {
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03002356 if (sd->gain > 0) {
Brian Johnsone1430472009-09-02 12:39:41 -03002357 sd->gain--;
2358 set_gain(gspca_dev);
2359 }
2360 }
2361}
2362
2363static void sd_dqcallback(struct gspca_dev *gspca_dev)
2364{
2365 struct sd *sd = (struct sd *) gspca_dev;
2366 int avg_lum;
2367
2368 if (!sd->auto_exposure)
2369 return;
2370
2371 avg_lum = atomic_read(&sd->avg_lum);
2372 if (sd->sensor == SENSOR_SOI968)
2373 do_autogain(gspca_dev, avg_lum);
2374 else
2375 do_autoexposure(gspca_dev, avg_lum);
2376}
2377
Jean-François Moine28566432010-10-01 07:33:26 -03002378#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002379static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
2380 u8 *data, /* interrupt packet */
2381 int len) /* interrupt packet length */
2382{
2383 struct sd *sd = (struct sd *) gspca_dev;
2384 int ret = -EINVAL;
Brian Johnson33ddc162010-04-18 21:42:40 -03002385 if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002386 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
2387 input_sync(gspca_dev->input_dev);
2388 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
2389 input_sync(gspca_dev->input_dev);
2390 ret = 0;
2391 }
2392 return ret;
2393}
2394#endif
2395
Brian Johnson26e744b2009-07-19 05:52:58 -03002396static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Brian Johnson26e744b2009-07-19 05:52:58 -03002397 u8 *data, /* isoc packet */
2398 int len) /* iso packet length */
2399{
2400 struct sd *sd = (struct sd *) gspca_dev;
2401 int avg_lum;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03002402 static u8 frame_header[] =
Brian Johnson26e744b2009-07-19 05:52:58 -03002403 {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
2404 if (len == 64 && memcmp(data, frame_header, 6) == 0) {
2405 avg_lum = ((data[35] >> 2) & 3) |
2406 (data[20] << 2) |
2407 (data[19] << 10);
2408 avg_lum += ((data[35] >> 4) & 3) |
2409 (data[22] << 2) |
2410 (data[21] << 10);
2411 avg_lum += ((data[35] >> 6) & 3) |
2412 (data[24] << 2) |
2413 (data[23] << 10);
2414 avg_lum += (data[36] & 3) |
2415 (data[26] << 2) |
2416 (data[25] << 10);
2417 avg_lum += ((data[36] >> 2) & 3) |
2418 (data[28] << 2) |
2419 (data[27] << 10);
2420 avg_lum += ((data[36] >> 4) & 3) |
2421 (data[30] << 2) |
2422 (data[29] << 10);
2423 avg_lum += ((data[36] >> 6) & 3) |
2424 (data[32] << 2) |
2425 (data[31] << 10);
2426 avg_lum += ((data[44] >> 4) & 3) |
2427 (data[34] << 2) |
2428 (data[33] << 10);
2429 avg_lum >>= 9;
2430 atomic_set(&sd->avg_lum, avg_lum);
Jean-François Moine04d174e2010-09-13 05:22:37 -03002431 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Brian Johnson26e744b2009-07-19 05:52:58 -03002432 return;
2433 }
2434 if (gspca_dev->last_packet_type == LAST_PACKET) {
2435 if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv
2436 & MODE_JPEG) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002437 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002438 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002439 gspca_frame_add(gspca_dev, INTER_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002440 data, len);
2441 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002442 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002443 data, len);
2444 }
2445 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002446 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Brian Johnson26e744b2009-07-19 05:52:58 -03002447 }
2448}
2449
2450/* sub-driver description */
2451static const struct sd_desc sd_desc = {
2452 .name = MODULE_NAME,
2453 .ctrls = sd_ctrls,
2454 .nctrls = ARRAY_SIZE(sd_ctrls),
2455 .config = sd_config,
2456 .init = sd_init,
2457 .start = sd_start,
2458 .stopN = sd_stopN,
Brian Johnson26e744b2009-07-19 05:52:58 -03002459 .pkt_scan = sd_pkt_scan,
Jean-François Moine28566432010-10-01 07:33:26 -03002460#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002461 .int_pkt_scan = sd_int_pkt_scan,
2462#endif
Brian Johnsone1430472009-09-02 12:39:41 -03002463 .dq_callback = sd_dqcallback,
Brian Johnson26e744b2009-07-19 05:52:58 -03002464#ifdef CONFIG_VIDEO_ADV_DEBUG
2465 .set_register = sd_dbg_s_register,
2466 .get_register = sd_dbg_g_register,
2467#endif
2468 .get_chip_ident = sd_chip_ident,
2469};
2470
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002471#define SN9C20X(sensor, i2c_addr, flags) \
Brian Johnson0c045eb2010-03-16 13:58:27 -03002472 .driver_info = ((flags & 0xff) << 16) \
Brian Johnson26e744b2009-07-19 05:52:58 -03002473 | (SENSOR_ ## sensor << 8) \
2474 | (i2c_addr)
2475
Jean-François Moine95c967c2011-01-13 05:20:29 -03002476static const struct usb_device_id device_table[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03002477 {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
2478 {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
2479 {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002480 {USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002481 {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, LED_REVERSE)},
2482 {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30,
2483 (FLIP_DETECT | HAS_NO_BUTTON))},
Brian Johnson26e744b2009-07-19 05:52:58 -03002484 {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
2485 {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
2486 {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
2487 {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)},
2488 {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, 0)},
2489 {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)},
2490 {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)},
2491 {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
2492 {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002493 {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002494 {USB_DEVICE(0x0c45, 0x628c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002495 {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)},
2496 {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
2497 {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
2498 {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
2499 {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002500 {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002501 {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
2502 {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
2503 {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
2504 {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002505 {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)},
2506 {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002507 {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
2508 {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)},
2509 {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)},
2510 {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002511 {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002512 {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)},
2513 {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)},
2514 {}
2515};
2516MODULE_DEVICE_TABLE(usb, device_table);
2517
2518/* -- device connect -- */
2519static int sd_probe(struct usb_interface *intf,
2520 const struct usb_device_id *id)
2521{
2522 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
2523 THIS_MODULE);
2524}
2525
Brian Johnson26e744b2009-07-19 05:52:58 -03002526static struct usb_driver sd_driver = {
2527 .name = MODULE_NAME,
2528 .id_table = device_table,
2529 .probe = sd_probe,
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002530 .disconnect = gspca_disconnect,
Brian Johnson26e744b2009-07-19 05:52:58 -03002531#ifdef CONFIG_PM
2532 .suspend = gspca_suspend,
2533 .resume = gspca_resume,
2534 .reset_resume = gspca_resume,
2535#endif
2536};
2537
2538/* -- module insert / remove -- */
2539static int __init sd_mod_init(void)
2540{
Jean-François Moine54826432010-09-13 04:53:03 -03002541 return usb_register(&sd_driver);
Brian Johnson26e744b2009-07-19 05:52:58 -03002542}
2543static void __exit sd_mod_exit(void)
2544{
2545 usb_deregister(&sd_driver);
Brian Johnson26e744b2009-07-19 05:52:58 -03002546}
2547
2548module_init(sd_mod_init);
2549module_exit(sd_mod_exit);