blob: 0958a93e0b82cbfd0aa6f5ab14d6c4eb0f4ca75c [file] [log] [blame]
Brian Johnson26e744b2009-07-19 05:52:58 -03001/*
2 * Sonix sn9c201 sn9c202 library
Jean-François Moineff38d582012-03-19 04:55:16 -03003 *
4 * Copyright (C) 2012 Jean-Francois Moine <http://moinejf.free.fr>
Brian Johnson26e744b2009-07-19 05:52:58 -03005 * Copyright (C) 2008-2009 microdia project <microdia@googlegroups.com>
6 * Copyright (C) 2009 Brian Johnson <brijohn@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
Joe Perches91f58422011-08-21 19:56:55 -030023#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24
Brian Johnson26e744b2009-07-19 05:52:58 -030025#include <linux/input.h>
Brian Johnson26e744b2009-07-19 05:52:58 -030026
Mauro Carvalho Chehabc15b95e2009-07-19 18:03:23 -030027#include "gspca.h"
28#include "jpeg.h"
29
30#include <media/v4l2-chip-ident.h>
Brian Johnson7ddaac72010-03-16 13:58:27 -030031#include <linux/dmi.h>
Mauro Carvalho Chehabc15b95e2009-07-19 18:03:23 -030032
Brian Johnson26e744b2009-07-19 05:52:58 -030033MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, "
34 "microdia project <microdia@googlegroups.com>");
35MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver");
36MODULE_LICENSE("GPL");
37
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -030038/*
39 * Pixel format private data
40 */
41#define SCALE_MASK 0x0f
42#define SCALE_160x120 0
43#define SCALE_320x240 1
44#define SCALE_640x480 2
45#define SCALE_1280x1024 3
Brian Johnson26e744b2009-07-19 05:52:58 -030046#define MODE_RAW 0x10
47#define MODE_JPEG 0x20
48#define MODE_SXGA 0x80
49
50#define SENSOR_OV9650 0
51#define SENSOR_OV9655 1
52#define SENSOR_SOI968 2
53#define SENSOR_OV7660 3
54#define SENSOR_OV7670 4
55#define SENSOR_MT9V011 5
56#define SENSOR_MT9V111 6
57#define SENSOR_MT9V112 7
58#define SENSOR_MT9M001 8
59#define SENSOR_MT9M111 9
Brian Johnsone99ac542010-03-16 13:58:28 -030060#define SENSOR_MT9M112 10
61#define SENSOR_HV7131R 11
Jean-François Moine9637c652012-03-24 09:16:14 -030062#define SENSOR_MT9VPRB 12
Brian Johnson26e744b2009-07-19 05:52:58 -030063
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030064/* camera flags */
Brian Johnson33ddc162010-04-18 21:42:40 -030065#define HAS_NO_BUTTON 0x1
Brian Johnson0c045eb2010-03-16 13:58:27 -030066#define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */
Brian Johnson7ddaac72010-03-16 13:58:27 -030067#define FLIP_DETECT 0x4
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030068
Jean-François Moinec5224d82012-03-19 04:30:07 -030069enum e_ctrl {
70 BRIGHTNESS,
71 CONTRAST,
72 SATURATION,
73 HUE,
74 GAMMA,
75 BLUE,
76 RED,
77 VFLIP,
78 HFLIP,
79 EXPOSURE,
80 GAIN,
81 AUTOGAIN,
Jean-François Moine4c632e42012-03-19 04:35:34 -030082 QUALITY,
Jean-François Moinec5224d82012-03-19 04:30:07 -030083 NCTRLS /* number of controls */
84};
85
Brian Johnson26e744b2009-07-19 05:52:58 -030086/* specific webcam descriptor */
87struct sd {
88 struct gspca_dev gspca_dev;
89
Jean-François Moinec5224d82012-03-19 04:30:07 -030090 struct gspca_ctrl ctrls[NCTRLS];
91
Jean-François Moine92dcffc2012-03-19 04:47:24 -030092 struct work_struct work;
93 struct workqueue_struct *work_thread;
94
95 u32 pktsz; /* (used by pkt_scan) */
96 u16 npkt;
97 s8 nchg;
Jean-François Moine4c632e42012-03-19 04:35:34 -030098 u8 fmt; /* (used for JPEG QTAB update */
99
Brian Johnson26e744b2009-07-19 05:52:58 -0300100#define MIN_AVG_LUM 80
101#define MAX_AVG_LUM 130
102 atomic_t avg_lum;
103 u8 old_step;
104 u8 older_step;
105 u8 exposure_step;
106
Brian Johnson26e744b2009-07-19 05:52:58 -0300107 u8 i2c_addr;
108 u8 sensor;
109 u8 hstart;
110 u8 vstart;
111
Jean-François Moine9a731a32010-06-04 05:26:42 -0300112 u8 jpeg_hdr[JPEG_HDR_SZ];
Brian Johnson26e744b2009-07-19 05:52:58 -0300113
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -0300114 u8 flags;
Brian Johnson26e744b2009-07-19 05:52:58 -0300115};
116
Jean-François Moine92dcffc2012-03-19 04:47:24 -0300117static void qual_upd(struct work_struct *work);
118
Joe Perches58aa68c2009-09-02 01:12:13 -0300119struct i2c_reg_u8 {
120 u8 reg;
121 u8 val;
122};
123
124struct i2c_reg_u16 {
125 u8 reg;
126 u16 val;
127};
128
Brian Johnson7ddaac72010-03-16 13:58:27 -0300129static const struct dmi_system_id flip_dmi_table[] = {
130 {
131 .ident = "MSI MS-1034",
132 .matches = {
133 DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."),
134 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1034"),
135 DMI_MATCH(DMI_PRODUCT_VERSION, "0341")
136 }
137 },
138 {
139 .ident = "MSI MS-1632",
140 .matches = {
141 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
142 DMI_MATCH(DMI_BOARD_NAME, "MS-1632")
143 }
144 },
Brian Johnsone077f862010-04-05 20:52:52 -0300145 {
Hans de Goedebcc6f662011-02-17 06:27:57 -0300146 .ident = "MSI MS-1633X",
147 .matches = {
148 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
149 DMI_MATCH(DMI_BOARD_NAME, "MS-1633X")
150 }
151 },
152 {
Brian Johnson5d26ed92010-04-10 02:12:46 -0300153 .ident = "MSI MS-1635X",
154 .matches = {
155 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
156 DMI_MATCH(DMI_BOARD_NAME, "MS-1635X")
157 }
158 },
159 {
Brian Johnsone077f862010-04-05 20:52:52 -0300160 .ident = "ASUSTeK W7J",
161 .matches = {
162 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
163 DMI_MATCH(DMI_BOARD_NAME, "W7J ")
164 }
165 },
Brian Johnson7ddaac72010-03-16 13:58:27 -0300166 {}
167};
168
Jean-François Moinec5224d82012-03-19 04:30:07 -0300169static void set_cmatrix(struct gspca_dev *gspca_dev);
170static void set_gamma(struct gspca_dev *gspca_dev);
171static void set_redblue(struct gspca_dev *gspca_dev);
172static void set_hvflip(struct gspca_dev *gspca_dev);
173static void set_exposure(struct gspca_dev *gspca_dev);
174static void set_gain(struct gspca_dev *gspca_dev);
Jean-François Moine4c632e42012-03-19 04:35:34 -0300175static void set_quality(struct gspca_dev *gspca_dev);
Jean-François Moinec5224d82012-03-19 04:30:07 -0300176
177static const struct ctrl sd_ctrls[NCTRLS] = {
178[BRIGHTNESS] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300179 {
180 .id = V4L2_CID_BRIGHTNESS,
181 .type = V4L2_CTRL_TYPE_INTEGER,
182 .name = "Brightness",
183 .minimum = 0,
184 .maximum = 0xff,
185 .step = 1,
Jean-François Moinec5224d82012-03-19 04:30:07 -0300186 .default_value = 0x7f
Brian Johnson26e744b2009-07-19 05:52:58 -0300187 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300188 .set_control = set_cmatrix
Brian Johnson26e744b2009-07-19 05:52:58 -0300189 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300190[CONTRAST] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300191 {
192 .id = V4L2_CID_CONTRAST,
193 .type = V4L2_CTRL_TYPE_INTEGER,
194 .name = "Contrast",
195 .minimum = 0,
196 .maximum = 0xff,
197 .step = 1,
Jean-François Moinec5224d82012-03-19 04:30:07 -0300198 .default_value = 0x7f
Brian Johnson26e744b2009-07-19 05:52:58 -0300199 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300200 .set_control = set_cmatrix
Brian Johnson26e744b2009-07-19 05:52:58 -0300201 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300202[SATURATION] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300203 {
204 .id = V4L2_CID_SATURATION,
205 .type = V4L2_CTRL_TYPE_INTEGER,
206 .name = "Saturation",
207 .minimum = 0,
208 .maximum = 0xff,
209 .step = 1,
Jean-François Moinec5224d82012-03-19 04:30:07 -0300210 .default_value = 0x7f
Brian Johnson26e744b2009-07-19 05:52:58 -0300211 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300212 .set_control = set_cmatrix
Brian Johnson26e744b2009-07-19 05:52:58 -0300213 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300214[HUE] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300215 {
216 .id = V4L2_CID_HUE,
217 .type = V4L2_CTRL_TYPE_INTEGER,
218 .name = "Hue",
219 .minimum = -180,
220 .maximum = 180,
221 .step = 1,
Jean-François Moinec5224d82012-03-19 04:30:07 -0300222 .default_value = 0
Brian Johnson26e744b2009-07-19 05:52:58 -0300223 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300224 .set_control = set_cmatrix
Brian Johnson26e744b2009-07-19 05:52:58 -0300225 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300226[GAMMA] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300227 {
228 .id = V4L2_CID_GAMMA,
229 .type = V4L2_CTRL_TYPE_INTEGER,
230 .name = "Gamma",
231 .minimum = 0,
232 .maximum = 0xff,
233 .step = 1,
Jean-François Moinec5224d82012-03-19 04:30:07 -0300234 .default_value = 0x10
Brian Johnson26e744b2009-07-19 05:52:58 -0300235 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300236 .set_control = set_gamma
Brian Johnson26e744b2009-07-19 05:52:58 -0300237 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300238[BLUE] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300239 {
240 .id = V4L2_CID_BLUE_BALANCE,
241 .type = V4L2_CTRL_TYPE_INTEGER,
242 .name = "Blue Balance",
243 .minimum = 0,
244 .maximum = 0x7f,
245 .step = 1,
Jean-François Moinec5224d82012-03-19 04:30:07 -0300246 .default_value = 0x28
Brian Johnson26e744b2009-07-19 05:52:58 -0300247 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300248 .set_control = set_redblue
Brian Johnson26e744b2009-07-19 05:52:58 -0300249 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300250[RED] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300251 {
252 .id = V4L2_CID_RED_BALANCE,
253 .type = V4L2_CTRL_TYPE_INTEGER,
254 .name = "Red Balance",
255 .minimum = 0,
256 .maximum = 0x7f,
257 .step = 1,
Jean-François Moinec5224d82012-03-19 04:30:07 -0300258 .default_value = 0x28
Brian Johnson26e744b2009-07-19 05:52:58 -0300259 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300260 .set_control = set_redblue
Brian Johnson26e744b2009-07-19 05:52:58 -0300261 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300262[HFLIP] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300263 {
264 .id = V4L2_CID_HFLIP,
265 .type = V4L2_CTRL_TYPE_BOOLEAN,
266 .name = "Horizontal Flip",
267 .minimum = 0,
268 .maximum = 1,
269 .step = 1,
Jean-François Moinec5224d82012-03-19 04:30:07 -0300270 .default_value = 0,
Brian Johnson26e744b2009-07-19 05:52:58 -0300271 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300272 .set_control = set_hvflip
Brian Johnson26e744b2009-07-19 05:52:58 -0300273 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300274[VFLIP] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300275 {
276 .id = V4L2_CID_VFLIP,
277 .type = V4L2_CTRL_TYPE_BOOLEAN,
278 .name = "Vertical Flip",
279 .minimum = 0,
280 .maximum = 1,
281 .step = 1,
Jean-François Moinec5224d82012-03-19 04:30:07 -0300282 .default_value = 0,
Brian Johnson26e744b2009-07-19 05:52:58 -0300283 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300284 .set_control = set_hvflip
Brian Johnson26e744b2009-07-19 05:52:58 -0300285 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300286[EXPOSURE] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300287 {
288 .id = V4L2_CID_EXPOSURE,
289 .type = V4L2_CTRL_TYPE_INTEGER,
290 .name = "Exposure",
291 .minimum = 0,
292 .maximum = 0x1780,
293 .step = 1,
Jean-François Moinec5224d82012-03-19 04:30:07 -0300294 .default_value = 0x33,
Brian Johnson26e744b2009-07-19 05:52:58 -0300295 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300296 .set_control = set_exposure
Brian Johnson26e744b2009-07-19 05:52:58 -0300297 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300298[GAIN] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300299 {
300 .id = V4L2_CID_GAIN,
301 .type = V4L2_CTRL_TYPE_INTEGER,
302 .name = "Gain",
303 .minimum = 0,
304 .maximum = 28,
305 .step = 1,
Jean-François Moinec5224d82012-03-19 04:30:07 -0300306 .default_value = 0,
Brian Johnson26e744b2009-07-19 05:52:58 -0300307 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300308 .set_control = set_gain
Brian Johnson26e744b2009-07-19 05:52:58 -0300309 },
Jean-François Moinec5224d82012-03-19 04:30:07 -0300310[AUTOGAIN] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300311 {
312 .id = V4L2_CID_AUTOGAIN,
313 .type = V4L2_CTRL_TYPE_BOOLEAN,
314 .name = "Auto Exposure",
315 .minimum = 0,
316 .maximum = 1,
317 .step = 1,
Jean-François Moinec5224d82012-03-19 04:30:07 -0300318 .default_value = 1,
Brian Johnson26e744b2009-07-19 05:52:58 -0300319 },
Brian Johnson26e744b2009-07-19 05:52:58 -0300320 },
Jean-François Moine4c632e42012-03-19 04:35:34 -0300321[QUALITY] = {
322 {
323 .id = V4L2_CID_JPEG_COMPRESSION_QUALITY,
324 .type = V4L2_CTRL_TYPE_INTEGER,
325 .name = "Compression Quality",
326#define QUALITY_MIN 50
327#define QUALITY_MAX 90
328#define QUALITY_DEF 80
329 .minimum = QUALITY_MIN,
330 .maximum = QUALITY_MAX,
331 .step = 1,
332 .default_value = QUALITY_DEF,
333 },
334 .set_control = set_quality
335 },
Brian Johnson26e744b2009-07-19 05:52:58 -0300336};
337
338static const struct v4l2_pix_format vga_mode[] = {
339 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300340 .bytesperline = 160,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300341 .sizeimage = 160 * 120 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300342 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300343 .priv = SCALE_160x120 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300344 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
345 .bytesperline = 160,
346 .sizeimage = 160 * 120,
347 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300348 .priv = SCALE_160x120 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300349 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300350 .bytesperline = 160,
Brian Johnson26e744b2009-07-19 05:52:58 -0300351 .sizeimage = 240 * 120,
352 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300353 .priv = SCALE_160x120},
Brian Johnson26e744b2009-07-19 05:52:58 -0300354 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300355 .bytesperline = 320,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300356 .sizeimage = 320 * 240 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300357 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300358 .priv = SCALE_320x240 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300359 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
360 .bytesperline = 320,
361 .sizeimage = 320 * 240 ,
362 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300363 .priv = SCALE_320x240 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300364 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300365 .bytesperline = 320,
Brian Johnson26e744b2009-07-19 05:52:58 -0300366 .sizeimage = 480 * 240 ,
367 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300368 .priv = SCALE_320x240},
Brian Johnson26e744b2009-07-19 05:52:58 -0300369 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300370 .bytesperline = 640,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300371 .sizeimage = 640 * 480 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300372 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300373 .priv = SCALE_640x480 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300374 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
375 .bytesperline = 640,
376 .sizeimage = 640 * 480,
377 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300378 .priv = SCALE_640x480 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300379 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300380 .bytesperline = 640,
Brian Johnson26e744b2009-07-19 05:52:58 -0300381 .sizeimage = 960 * 480,
382 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300383 .priv = SCALE_640x480},
Brian Johnson26e744b2009-07-19 05:52:58 -0300384};
385
386static const struct v4l2_pix_format sxga_mode[] = {
387 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300388 .bytesperline = 160,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300389 .sizeimage = 160 * 120 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300390 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300391 .priv = SCALE_160x120 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300392 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
393 .bytesperline = 160,
394 .sizeimage = 160 * 120,
395 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300396 .priv = SCALE_160x120 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300397 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300398 .bytesperline = 160,
Brian Johnson26e744b2009-07-19 05:52:58 -0300399 .sizeimage = 240 * 120,
400 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300401 .priv = SCALE_160x120},
Brian Johnson26e744b2009-07-19 05:52:58 -0300402 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300403 .bytesperline = 320,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300404 .sizeimage = 320 * 240 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300405 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300406 .priv = SCALE_320x240 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300407 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
408 .bytesperline = 320,
409 .sizeimage = 320 * 240 ,
410 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300411 .priv = SCALE_320x240 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300412 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300413 .bytesperline = 320,
Brian Johnson26e744b2009-07-19 05:52:58 -0300414 .sizeimage = 480 * 240 ,
415 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300416 .priv = SCALE_320x240},
Brian Johnson26e744b2009-07-19 05:52:58 -0300417 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300418 .bytesperline = 640,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300419 .sizeimage = 640 * 480 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300420 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300421 .priv = SCALE_640x480 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300422 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
423 .bytesperline = 640,
424 .sizeimage = 640 * 480,
425 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300426 .priv = SCALE_640x480 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300427 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300428 .bytesperline = 640,
Brian Johnson26e744b2009-07-19 05:52:58 -0300429 .sizeimage = 960 * 480,
430 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300431 .priv = SCALE_640x480},
Brian Johnson26e744b2009-07-19 05:52:58 -0300432 {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
433 .bytesperline = 1280,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300434 .sizeimage = 1280 * 1024,
Brian Johnson26e744b2009-07-19 05:52:58 -0300435 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300436 .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
Brian Johnson26e744b2009-07-19 05:52:58 -0300437};
438
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -0300439static const struct v4l2_pix_format mono_mode[] = {
440 {160, 120, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
441 .bytesperline = 160,
442 .sizeimage = 160 * 120,
443 .colorspace = V4L2_COLORSPACE_SRGB,
444 .priv = SCALE_160x120 | MODE_RAW},
445 {320, 240, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
446 .bytesperline = 320,
447 .sizeimage = 320 * 240 ,
448 .colorspace = V4L2_COLORSPACE_SRGB,
449 .priv = SCALE_320x240 | MODE_RAW},
450 {640, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
451 .bytesperline = 640,
452 .sizeimage = 640 * 480,
453 .colorspace = V4L2_COLORSPACE_SRGB,
454 .priv = SCALE_640x480 | MODE_RAW},
455 {1280, 1024, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
456 .bytesperline = 1280,
457 .sizeimage = 1280 * 1024,
458 .colorspace = V4L2_COLORSPACE_SRGB,
459 .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
460};
461
Joe Perches58aa68c2009-09-02 01:12:13 -0300462static const s16 hsv_red_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300463 41, 44, 46, 48, 50, 52, 54, 56,
464 58, 60, 62, 64, 66, 68, 70, 72,
465 74, 76, 78, 80, 81, 83, 85, 87,
466 88, 90, 92, 93, 95, 97, 98, 100,
467 101, 102, 104, 105, 107, 108, 109, 110,
468 112, 113, 114, 115, 116, 117, 118, 119,
469 120, 121, 122, 123, 123, 124, 125, 125,
470 126, 127, 127, 128, 128, 129, 129, 129,
471 130, 130, 130, 130, 131, 131, 131, 131,
472 131, 131, 131, 131, 130, 130, 130, 130,
473 129, 129, 129, 128, 128, 127, 127, 126,
474 125, 125, 124, 123, 122, 122, 121, 120,
475 119, 118, 117, 116, 115, 114, 112, 111,
476 110, 109, 107, 106, 105, 103, 102, 101,
477 99, 98, 96, 94, 93, 91, 90, 88,
478 86, 84, 83, 81, 79, 77, 75, 74,
479 72, 70, 68, 66, 64, 62, 60, 58,
480 56, 54, 52, 49, 47, 45, 43, 41,
481 39, 36, 34, 32, 30, 28, 25, 23,
482 21, 19, 16, 14, 12, 9, 7, 5,
483 3, 0, -1, -3, -6, -8, -10, -12,
484 -15, -17, -19, -22, -24, -26, -28, -30,
485 -33, -35, -37, -39, -41, -44, -46, -48,
486 -50, -52, -54, -56, -58, -60, -62, -64,
487 -66, -68, -70, -72, -74, -76, -78, -80,
488 -81, -83, -85, -87, -88, -90, -92, -93,
489 -95, -97, -98, -100, -101, -102, -104, -105,
490 -107, -108, -109, -110, -112, -113, -114, -115,
491 -116, -117, -118, -119, -120, -121, -122, -123,
492 -123, -124, -125, -125, -126, -127, -127, -128,
493 -128, -128, -128, -128, -128, -128, -128, -128,
494 -128, -128, -128, -128, -128, -128, -128, -128,
495 -128, -128, -128, -128, -128, -128, -128, -128,
496 -128, -127, -127, -126, -125, -125, -124, -123,
497 -122, -122, -121, -120, -119, -118, -117, -116,
498 -115, -114, -112, -111, -110, -109, -107, -106,
499 -105, -103, -102, -101, -99, -98, -96, -94,
500 -93, -91, -90, -88, -86, -84, -83, -81,
501 -79, -77, -75, -74, -72, -70, -68, -66,
502 -64, -62, -60, -58, -56, -54, -52, -49,
503 -47, -45, -43, -41, -39, -36, -34, -32,
504 -30, -28, -25, -23, -21, -19, -16, -14,
505 -12, -9, -7, -5, -3, 0, 1, 3,
506 6, 8, 10, 12, 15, 17, 19, 22,
507 24, 26, 28, 30, 33, 35, 37, 39, 41
508};
509
Joe Perches58aa68c2009-09-02 01:12:13 -0300510static const s16 hsv_red_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300511 82, 80, 78, 76, 74, 73, 71, 69,
512 67, 65, 63, 61, 58, 56, 54, 52,
513 50, 48, 46, 44, 41, 39, 37, 35,
514 32, 30, 28, 26, 23, 21, 19, 16,
515 14, 12, 10, 7, 5, 3, 0, -1,
516 -3, -6, -8, -10, -13, -15, -17, -19,
517 -22, -24, -26, -29, -31, -33, -35, -38,
518 -40, -42, -44, -46, -48, -51, -53, -55,
519 -57, -59, -61, -63, -65, -67, -69, -71,
520 -73, -75, -77, -79, -81, -82, -84, -86,
521 -88, -89, -91, -93, -94, -96, -98, -99,
522 -101, -102, -104, -105, -106, -108, -109, -110,
523 -112, -113, -114, -115, -116, -117, -119, -120,
524 -120, -121, -122, -123, -124, -125, -126, -126,
525 -127, -128, -128, -128, -128, -128, -128, -128,
526 -128, -128, -128, -128, -128, -128, -128, -128,
527 -128, -128, -128, -128, -128, -128, -128, -128,
528 -128, -128, -128, -128, -128, -128, -128, -128,
529 -127, -127, -126, -125, -125, -124, -123, -122,
530 -121, -120, -119, -118, -117, -116, -115, -114,
531 -113, -111, -110, -109, -107, -106, -105, -103,
532 -102, -100, -99, -97, -96, -94, -92, -91,
533 -89, -87, -85, -84, -82, -80, -78, -76,
534 -74, -73, -71, -69, -67, -65, -63, -61,
535 -58, -56, -54, -52, -50, -48, -46, -44,
536 -41, -39, -37, -35, -32, -30, -28, -26,
537 -23, -21, -19, -16, -14, -12, -10, -7,
538 -5, -3, 0, 1, 3, 6, 8, 10,
539 13, 15, 17, 19, 22, 24, 26, 29,
540 31, 33, 35, 38, 40, 42, 44, 46,
541 48, 51, 53, 55, 57, 59, 61, 63,
542 65, 67, 69, 71, 73, 75, 77, 79,
543 81, 82, 84, 86, 88, 89, 91, 93,
544 94, 96, 98, 99, 101, 102, 104, 105,
545 106, 108, 109, 110, 112, 113, 114, 115,
546 116, 117, 119, 120, 120, 121, 122, 123,
547 124, 125, 126, 126, 127, 128, 128, 129,
548 129, 130, 130, 131, 131, 131, 131, 132,
549 132, 132, 132, 132, 132, 132, 132, 132,
550 132, 132, 132, 131, 131, 131, 130, 130,
551 130, 129, 129, 128, 127, 127, 126, 125,
552 125, 124, 123, 122, 121, 120, 119, 118,
553 117, 116, 115, 114, 113, 111, 110, 109,
554 107, 106, 105, 103, 102, 100, 99, 97,
555 96, 94, 92, 91, 89, 87, 85, 84, 82
556};
557
Joe Perches58aa68c2009-09-02 01:12:13 -0300558static const s16 hsv_green_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300559 -124, -124, -125, -125, -125, -125, -125, -125,
560 -125, -126, -126, -125, -125, -125, -125, -125,
561 -125, -124, -124, -124, -123, -123, -122, -122,
562 -121, -121, -120, -120, -119, -118, -117, -117,
563 -116, -115, -114, -113, -112, -111, -110, -109,
564 -108, -107, -105, -104, -103, -102, -100, -99,
565 -98, -96, -95, -93, -92, -91, -89, -87,
566 -86, -84, -83, -81, -79, -77, -76, -74,
567 -72, -70, -69, -67, -65, -63, -61, -59,
568 -57, -55, -53, -51, -49, -47, -45, -43,
569 -41, -39, -37, -35, -33, -30, -28, -26,
570 -24, -22, -20, -18, -15, -13, -11, -9,
571 -7, -4, -2, 0, 1, 3, 6, 8,
572 10, 12, 14, 17, 19, 21, 23, 25,
573 27, 29, 32, 34, 36, 38, 40, 42,
574 44, 46, 48, 50, 52, 54, 56, 58,
575 60, 62, 64, 66, 68, 70, 71, 73,
576 75, 77, 78, 80, 82, 83, 85, 87,
577 88, 90, 91, 93, 94, 96, 97, 98,
578 100, 101, 102, 104, 105, 106, 107, 108,
579 109, 111, 112, 113, 113, 114, 115, 116,
580 117, 118, 118, 119, 120, 120, 121, 122,
581 122, 123, 123, 124, 124, 124, 125, 125,
582 125, 125, 125, 125, 125, 126, 126, 125,
583 125, 125, 125, 125, 125, 124, 124, 124,
584 123, 123, 122, 122, 121, 121, 120, 120,
585 119, 118, 117, 117, 116, 115, 114, 113,
586 112, 111, 110, 109, 108, 107, 105, 104,
587 103, 102, 100, 99, 98, 96, 95, 93,
588 92, 91, 89, 87, 86, 84, 83, 81,
589 79, 77, 76, 74, 72, 70, 69, 67,
590 65, 63, 61, 59, 57, 55, 53, 51,
591 49, 47, 45, 43, 41, 39, 37, 35,
592 33, 30, 28, 26, 24, 22, 20, 18,
593 15, 13, 11, 9, 7, 4, 2, 0,
594 -1, -3, -6, -8, -10, -12, -14, -17,
595 -19, -21, -23, -25, -27, -29, -32, -34,
596 -36, -38, -40, -42, -44, -46, -48, -50,
597 -52, -54, -56, -58, -60, -62, -64, -66,
598 -68, -70, -71, -73, -75, -77, -78, -80,
599 -82, -83, -85, -87, -88, -90, -91, -93,
600 -94, -96, -97, -98, -100, -101, -102, -104,
601 -105, -106, -107, -108, -109, -111, -112, -113,
602 -113, -114, -115, -116, -117, -118, -118, -119,
603 -120, -120, -121, -122, -122, -123, -123, -124, -124
604};
605
Joe Perches58aa68c2009-09-02 01:12:13 -0300606static const s16 hsv_green_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300607 -100, -99, -98, -97, -95, -94, -93, -91,
608 -90, -89, -87, -86, -84, -83, -81, -80,
609 -78, -76, -75, -73, -71, -70, -68, -66,
610 -64, -63, -61, -59, -57, -55, -53, -51,
611 -49, -48, -46, -44, -42, -40, -38, -36,
612 -34, -32, -30, -27, -25, -23, -21, -19,
613 -17, -15, -13, -11, -9, -7, -4, -2,
614 0, 1, 3, 5, 7, 9, 11, 14,
615 16, 18, 20, 22, 24, 26, 28, 30,
616 32, 34, 36, 38, 40, 42, 44, 46,
617 48, 50, 52, 54, 56, 58, 59, 61,
618 63, 65, 67, 68, 70, 72, 74, 75,
619 77, 78, 80, 82, 83, 85, 86, 88,
620 89, 90, 92, 93, 95, 96, 97, 98,
621 100, 101, 102, 103, 104, 105, 106, 107,
622 108, 109, 110, 111, 112, 112, 113, 114,
623 115, 115, 116, 116, 117, 117, 118, 118,
624 119, 119, 119, 120, 120, 120, 120, 120,
625 121, 121, 121, 121, 121, 121, 120, 120,
626 120, 120, 120, 119, 119, 119, 118, 118,
627 117, 117, 116, 116, 115, 114, 114, 113,
628 112, 111, 111, 110, 109, 108, 107, 106,
629 105, 104, 103, 102, 100, 99, 98, 97,
630 95, 94, 93, 91, 90, 89, 87, 86,
631 84, 83, 81, 80, 78, 76, 75, 73,
632 71, 70, 68, 66, 64, 63, 61, 59,
633 57, 55, 53, 51, 49, 48, 46, 44,
634 42, 40, 38, 36, 34, 32, 30, 27,
635 25, 23, 21, 19, 17, 15, 13, 11,
636 9, 7, 4, 2, 0, -1, -3, -5,
637 -7, -9, -11, -14, -16, -18, -20, -22,
638 -24, -26, -28, -30, -32, -34, -36, -38,
639 -40, -42, -44, -46, -48, -50, -52, -54,
640 -56, -58, -59, -61, -63, -65, -67, -68,
641 -70, -72, -74, -75, -77, -78, -80, -82,
642 -83, -85, -86, -88, -89, -90, -92, -93,
643 -95, -96, -97, -98, -100, -101, -102, -103,
644 -104, -105, -106, -107, -108, -109, -110, -111,
645 -112, -112, -113, -114, -115, -115, -116, -116,
646 -117, -117, -118, -118, -119, -119, -119, -120,
647 -120, -120, -120, -120, -121, -121, -121, -121,
648 -121, -121, -120, -120, -120, -120, -120, -119,
649 -119, -119, -118, -118, -117, -117, -116, -116,
650 -115, -114, -114, -113, -112, -111, -111, -110,
651 -109, -108, -107, -106, -105, -104, -103, -102, -100
652};
653
Joe Perches58aa68c2009-09-02 01:12:13 -0300654static const s16 hsv_blue_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300655 112, 113, 114, 114, 115, 116, 117, 117,
656 118, 118, 119, 119, 120, 120, 120, 121,
657 121, 121, 122, 122, 122, 122, 122, 122,
658 122, 122, 122, 122, 122, 122, 121, 121,
659 121, 120, 120, 120, 119, 119, 118, 118,
660 117, 116, 116, 115, 114, 113, 113, 112,
661 111, 110, 109, 108, 107, 106, 105, 104,
662 103, 102, 100, 99, 98, 97, 95, 94,
663 93, 91, 90, 88, 87, 85, 84, 82,
664 80, 79, 77, 76, 74, 72, 70, 69,
665 67, 65, 63, 61, 60, 58, 56, 54,
666 52, 50, 48, 46, 44, 42, 40, 38,
667 36, 34, 32, 30, 28, 26, 24, 22,
668 19, 17, 15, 13, 11, 9, 7, 5,
669 2, 0, -1, -3, -5, -7, -9, -12,
670 -14, -16, -18, -20, -22, -24, -26, -28,
671 -31, -33, -35, -37, -39, -41, -43, -45,
672 -47, -49, -51, -53, -54, -56, -58, -60,
673 -62, -64, -66, -67, -69, -71, -73, -74,
674 -76, -78, -79, -81, -83, -84, -86, -87,
675 -89, -90, -92, -93, -94, -96, -97, -98,
676 -99, -101, -102, -103, -104, -105, -106, -107,
677 -108, -109, -110, -111, -112, -113, -114, -114,
678 -115, -116, -117, -117, -118, -118, -119, -119,
679 -120, -120, -120, -121, -121, -121, -122, -122,
680 -122, -122, -122, -122, -122, -122, -122, -122,
681 -122, -122, -121, -121, -121, -120, -120, -120,
682 -119, -119, -118, -118, -117, -116, -116, -115,
683 -114, -113, -113, -112, -111, -110, -109, -108,
684 -107, -106, -105, -104, -103, -102, -100, -99,
685 -98, -97, -95, -94, -93, -91, -90, -88,
686 -87, -85, -84, -82, -80, -79, -77, -76,
687 -74, -72, -70, -69, -67, -65, -63, -61,
688 -60, -58, -56, -54, -52, -50, -48, -46,
689 -44, -42, -40, -38, -36, -34, -32, -30,
690 -28, -26, -24, -22, -19, -17, -15, -13,
691 -11, -9, -7, -5, -2, 0, 1, 3,
692 5, 7, 9, 12, 14, 16, 18, 20,
693 22, 24, 26, 28, 31, 33, 35, 37,
694 39, 41, 43, 45, 47, 49, 51, 53,
695 54, 56, 58, 60, 62, 64, 66, 67,
696 69, 71, 73, 74, 76, 78, 79, 81,
697 83, 84, 86, 87, 89, 90, 92, 93,
698 94, 96, 97, 98, 99, 101, 102, 103,
699 104, 105, 106, 107, 108, 109, 110, 111, 112
700};
701
Joe Perches58aa68c2009-09-02 01:12:13 -0300702static const s16 hsv_blue_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300703 -11, -13, -15, -17, -19, -21, -23, -25,
704 -27, -29, -31, -33, -35, -37, -39, -41,
705 -43, -45, -46, -48, -50, -52, -54, -55,
706 -57, -59, -61, -62, -64, -66, -67, -69,
707 -71, -72, -74, -75, -77, -78, -80, -81,
708 -83, -84, -86, -87, -88, -90, -91, -92,
709 -93, -95, -96, -97, -98, -99, -100, -101,
710 -102, -103, -104, -105, -106, -106, -107, -108,
711 -109, -109, -110, -111, -111, -112, -112, -113,
712 -113, -114, -114, -114, -115, -115, -115, -115,
713 -116, -116, -116, -116, -116, -116, -116, -116,
714 -116, -115, -115, -115, -115, -114, -114, -114,
715 -113, -113, -112, -112, -111, -111, -110, -110,
716 -109, -108, -108, -107, -106, -105, -104, -103,
717 -102, -101, -100, -99, -98, -97, -96, -95,
718 -94, -93, -91, -90, -89, -88, -86, -85,
719 -84, -82, -81, -79, -78, -76, -75, -73,
720 -71, -70, -68, -67, -65, -63, -62, -60,
721 -58, -56, -55, -53, -51, -49, -47, -45,
722 -44, -42, -40, -38, -36, -34, -32, -30,
723 -28, -26, -24, -22, -20, -18, -16, -14,
724 -12, -10, -8, -6, -4, -2, 0, 1,
725 3, 5, 7, 9, 11, 13, 15, 17,
726 19, 21, 23, 25, 27, 29, 31, 33,
727 35, 37, 39, 41, 43, 45, 46, 48,
728 50, 52, 54, 55, 57, 59, 61, 62,
729 64, 66, 67, 69, 71, 72, 74, 75,
730 77, 78, 80, 81, 83, 84, 86, 87,
731 88, 90, 91, 92, 93, 95, 96, 97,
732 98, 99, 100, 101, 102, 103, 104, 105,
733 106, 106, 107, 108, 109, 109, 110, 111,
734 111, 112, 112, 113, 113, 114, 114, 114,
735 115, 115, 115, 115, 116, 116, 116, 116,
736 116, 116, 116, 116, 116, 115, 115, 115,
737 115, 114, 114, 114, 113, 113, 112, 112,
738 111, 111, 110, 110, 109, 108, 108, 107,
739 106, 105, 104, 103, 102, 101, 100, 99,
740 98, 97, 96, 95, 94, 93, 91, 90,
741 89, 88, 86, 85, 84, 82, 81, 79,
742 78, 76, 75, 73, 71, 70, 68, 67,
743 65, 63, 62, 60, 58, 56, 55, 53,
744 51, 49, 47, 45, 44, 42, 40, 38,
745 36, 34, 32, 30, 28, 26, 24, 22,
746 20, 18, 16, 14, 12, 10, 8, 6,
747 4, 2, 0, -1, -3, -5, -7, -9, -11
748};
749
Jean-François Moinedae1de62012-03-24 09:20:25 -0300750static const u16 i2c_ident[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300751 V4L2_IDENT_OV9650,
752 V4L2_IDENT_OV9655,
753 V4L2_IDENT_SOI968,
754 V4L2_IDENT_OV7660,
755 V4L2_IDENT_OV7670,
756 V4L2_IDENT_MT9V011,
757 V4L2_IDENT_MT9V111,
758 V4L2_IDENT_MT9V112,
759 V4L2_IDENT_MT9M001C12ST,
760 V4L2_IDENT_MT9M111,
Brian Johnsone99ac542010-03-16 13:58:28 -0300761 V4L2_IDENT_MT9M112,
Brian Johnson26e744b2009-07-19 05:52:58 -0300762 V4L2_IDENT_HV7131R,
Jean-François Moinebed37382012-03-24 09:17:37 -0300763[SENSOR_MT9VPRB] = V4L2_IDENT_UNKNOWN,
Brian Johnson26e744b2009-07-19 05:52:58 -0300764};
765
Jean-François Moinedae1de62012-03-24 09:20:25 -0300766static const u16 bridge_init[][2] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300767 {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c},
768 {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40},
769 {0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10},
770 {0x106b, 0x08}, {0x1188, 0x87}, {0x11a1, 0x00},
771 {0x11a2, 0x00}, {0x11a3, 0x6a}, {0x11a4, 0x50},
772 {0x11ab, 0x00}, {0x11ac, 0x00}, {0x11ad, 0x50},
773 {0x11ae, 0x3c}, {0x118a, 0x04}, {0x0395, 0x04},
774 {0x11b8, 0x3a}, {0x118b, 0x0e}, {0x10f7, 0x05},
775 {0x10f8, 0x14}, {0x10fa, 0xff}, {0x10f9, 0x00},
776 {0x11ba, 0x0a}, {0x11a5, 0x2d}, {0x11a6, 0x2d},
777 {0x11a7, 0x3a}, {0x11a8, 0x05}, {0x11a9, 0x04},
778 {0x11aa, 0x3f}, {0x11af, 0x28}, {0x11b0, 0xd8},
779 {0x11b1, 0x14}, {0x11b2, 0xec}, {0x11b3, 0x32},
780 {0x11b4, 0xdd}, {0x11b5, 0x32}, {0x11b6, 0xdd},
781 {0x10e0, 0x2c}, {0x11bc, 0x40}, {0x11bd, 0x01},
782 {0x11be, 0xf0}, {0x11bf, 0x00}, {0x118c, 0x1f},
783 {0x118d, 0x1f}, {0x118e, 0x1f}, {0x118f, 0x1f},
784 {0x1180, 0x01}, {0x1181, 0x00}, {0x1182, 0x01},
Brian Johnson0c045eb2010-03-16 13:58:27 -0300785 {0x1183, 0x00}, {0x1184, 0x50}, {0x1185, 0x80},
786 {0x1007, 0x00}
Brian Johnson26e744b2009-07-19 05:52:58 -0300787};
788
789/* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300790static const u8 ov_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300791 0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */,
792 0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */,
793 0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */,
794 0x30 /* 4x */, 0x31 /* 4.25x */, 0x32 /* 4.5x */, 0x33 /* 4.75x */,
795 0x34 /* 5x */, 0x35 /* 5.25x */, 0x36 /* 5.5x */, 0x37 /* 5.75x */,
796 0x38 /* 6x */, 0x39 /* 6.25x */, 0x3a /* 6.5x */, 0x3b /* 6.75x */,
797 0x3c /* 7x */, 0x3d /* 7.25x */, 0x3e /* 7.5x */, 0x3f /* 7.75x */,
798 0x70 /* 8x */
799};
800
801/* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300802static const u16 micron1_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300803 /* 1x 1.25x 1.5x 1.75x */
804 0x0020, 0x0028, 0x0030, 0x0038,
805 /* 2x 2.25x 2.5x 2.75x */
806 0x00a0, 0x00a4, 0x00a8, 0x00ac,
807 /* 3x 3.25x 3.5x 3.75x */
808 0x00b0, 0x00b4, 0x00b8, 0x00bc,
809 /* 4x 4.25x 4.5x 4.75x */
810 0x00c0, 0x00c4, 0x00c8, 0x00cc,
811 /* 5x 5.25x 5.5x 5.75x */
812 0x00d0, 0x00d4, 0x00d8, 0x00dc,
813 /* 6x 6.25x 6.5x 6.75x */
814 0x00e0, 0x00e4, 0x00e8, 0x00ec,
815 /* 7x 7.25x 7.5x 7.75x */
816 0x00f0, 0x00f4, 0x00f8, 0x00fc,
817 /* 8x */
818 0x01c0
819};
820
821/* mt9m001 sensor uses a different gain formula then other micron sensors */
822/* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300823static const u16 micron2_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300824 /* 1x 1.25x 1.5x 1.75x */
825 0x0008, 0x000a, 0x000c, 0x000e,
826 /* 2x 2.25x 2.5x 2.75x */
827 0x0010, 0x0012, 0x0014, 0x0016,
828 /* 3x 3.25x 3.5x 3.75x */
829 0x0018, 0x001a, 0x001c, 0x001e,
830 /* 4x 4.25x 4.5x 4.75x */
831 0x0020, 0x0051, 0x0052, 0x0053,
832 /* 5x 5.25x 5.5x 5.75x */
833 0x0054, 0x0055, 0x0056, 0x0057,
834 /* 6x 6.25x 6.5x 6.75x */
835 0x0058, 0x0059, 0x005a, 0x005b,
836 /* 7x 7.25x 7.5x 7.75x */
837 0x005c, 0x005d, 0x005e, 0x005f,
838 /* 8x */
839 0x0060
840};
841
842/* Gain = .5 + bit[7:0] / 16 */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300843static const u8 hv7131r_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300844 0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */,
845 0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */,
846 0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */,
847 0x38 /* 4x */, 0x3c /* 4.25x */, 0x40 /* 4.5x */, 0x44 /* 4.75x */,
848 0x48 /* 5x */, 0x4c /* 5.25x */, 0x50 /* 5.5x */, 0x54 /* 5.75x */,
849 0x58 /* 6x */, 0x5c /* 6.25x */, 0x60 /* 6.5x */, 0x64 /* 6.75x */,
850 0x68 /* 7x */, 0x6c /* 7.25x */, 0x70 /* 7.5x */, 0x74 /* 7.75x */,
851 0x78 /* 8x */
852};
853
Jean-François Moinedae1de62012-03-24 09:20:25 -0300854static const struct i2c_reg_u8 soi968_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300855 {0x0c, 0x00}, {0x0f, 0x1f},
Brian Johnson26e744b2009-07-19 05:52:58 -0300856 {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
857 {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
858 {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
859 {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20},
860 {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e},
Brian Johnsone1430472009-09-02 12:39:41 -0300861 {0x13, 0x8b}, {0x12, 0x40}, {0x17, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300862 {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79},
863 {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40},
864 {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32},
865 {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80},
866};
867
Jean-François Moinedae1de62012-03-24 09:20:25 -0300868static const struct i2c_reg_u8 ov7660_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300869 {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
870 {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
871 {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
Hans de Goede8bc50f32011-02-16 07:11:14 -0300872 /* HDG Set hstart and hstop, datasheet default 0x11, 0x61, using
873 0x10, 0x61 and sd->hstart, vstart = 3, fixes ugly colored borders */
874 {0x17, 0x10}, {0x18, 0x61},
Brian Johnson26e744b2009-07-19 05:52:58 -0300875 {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43},
876 {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0xf6},
877 {0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50},
878};
879
Jean-François Moinedae1de62012-03-24 09:20:25 -0300880static const struct i2c_reg_u8 ov7670_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300881 {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
Brian Johnson26e744b2009-07-19 05:52:58 -0300882 {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
883 {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
884 {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
885 {0x0d, 0x40}, {0x14, 0x28}, {0xa5, 0x05}, {0xab, 0x07},
886 {0x24, 0x95}, {0x25, 0x33}, {0x26, 0xe3}, {0x9f, 0x75},
887 {0xa0, 0x65}, {0xa1, 0x0b}, {0xa6, 0xd8}, {0xa7, 0xd8},
888 {0xa8, 0xf0}, {0xa9, 0x90}, {0xaa, 0x94}, {0x13, 0xe5},
889 {0x0e, 0x61}, {0x0f, 0x4b}, {0x16, 0x02}, {0x1e, 0x27},
890 {0x21, 0x02}, {0x22, 0x91}, {0x29, 0x07}, {0x33, 0x0b},
891 {0x35, 0x0b}, {0x37, 0x1d}, {0x38, 0x71}, {0x39, 0x2a},
892 {0x3c, 0x78}, {0x4d, 0x40}, {0x4e, 0x20}, {0x69, 0x00},
893 {0x74, 0x19}, {0x8d, 0x4f}, {0x8e, 0x00}, {0x8f, 0x00},
894 {0x90, 0x00}, {0x91, 0x00}, {0x96, 0x00}, {0x9a, 0x80},
895 {0xb0, 0x84}, {0xb1, 0x0c}, {0xb2, 0x0e}, {0xb3, 0x82},
896 {0xb8, 0x0a}, {0x43, 0x0a}, {0x44, 0xf0}, {0x45, 0x20},
897 {0x46, 0x7d}, {0x47, 0x29}, {0x48, 0x4a}, {0x59, 0x8c},
898 {0x5a, 0xa5}, {0x5b, 0xde}, {0x5c, 0x96}, {0x5d, 0x66},
899 {0x5e, 0x10}, {0x6c, 0x0a}, {0x6d, 0x55}, {0x6e, 0x11},
900 {0x6f, 0x9e}, {0x6a, 0x40}, {0x01, 0x40}, {0x02, 0x40},
901 {0x13, 0xe7}, {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x02},
902 {0x52, 0x1d}, {0x53, 0x56}, {0x54, 0x73}, {0x55, 0x0a},
903 {0x56, 0x55}, {0x57, 0x80}, {0x58, 0x9e}, {0x41, 0x08},
904 {0x3f, 0x02}, {0x75, 0x03}, {0x76, 0x63}, {0x4c, 0x04},
905 {0x77, 0x06}, {0x3d, 0x02}, {0x4b, 0x09}, {0xc9, 0x30},
906 {0x41, 0x08}, {0x56, 0x48}, {0x34, 0x11}, {0xa4, 0x88},
907 {0x96, 0x00}, {0x97, 0x30}, {0x98, 0x20}, {0x99, 0x30},
908 {0x9a, 0x84}, {0x9b, 0x29}, {0x9c, 0x03}, {0x9d, 0x99},
909 {0x9e, 0x7f}, {0x78, 0x04}, {0x79, 0x01}, {0xc8, 0xf0},
910 {0x79, 0x0f}, {0xc8, 0x00}, {0x79, 0x10}, {0xc8, 0x7e},
911 {0x79, 0x0a}, {0xc8, 0x80}, {0x79, 0x0b}, {0xc8, 0x01},
912 {0x79, 0x0c}, {0xc8, 0x0f}, {0x79, 0x0d}, {0xc8, 0x20},
913 {0x79, 0x09}, {0xc8, 0x80}, {0x79, 0x02}, {0xc8, 0xc0},
914 {0x79, 0x03}, {0xc8, 0x40}, {0x79, 0x05}, {0xc8, 0x30},
915 {0x79, 0x26}, {0x62, 0x20}, {0x63, 0x00}, {0x64, 0x06},
916 {0x65, 0x00}, {0x66, 0x05}, {0x94, 0x05}, {0x95, 0x0a},
917 {0x17, 0x13}, {0x18, 0x01}, {0x19, 0x02}, {0x1a, 0x7a},
918 {0x46, 0x59}, {0x47, 0x30}, {0x58, 0x9a}, {0x59, 0x84},
919 {0x5a, 0x91}, {0x5b, 0x57}, {0x5c, 0x75}, {0x5d, 0x6d},
920 {0x5e, 0x13}, {0x64, 0x07}, {0x94, 0x07}, {0x95, 0x0d},
921 {0xa6, 0xdf}, {0xa7, 0xdf}, {0x48, 0x4d}, {0x51, 0x00},
922 {0x6b, 0x0a}, {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00},
923 {0x92, 0x00}, {0x93, 0x00}, {0x55, 0x0a}, {0x56, 0x60},
924 {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d},
925 {0x53, 0x56}, {0x54, 0x73}, {0x58, 0x9a}, {0x4f, 0x6e},
926 {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, {0x53, 0x56},
927 {0x54, 0x73}, {0x58, 0x9a}, {0x3f, 0x01}, {0x7b, 0x03},
928 {0x7c, 0x09}, {0x7d, 0x16}, {0x7e, 0x38}, {0x7f, 0x47},
929 {0x80, 0x53}, {0x81, 0x5e}, {0x82, 0x6a}, {0x83, 0x74},
930 {0x84, 0x80}, {0x85, 0x8c}, {0x86, 0x9b}, {0x87, 0xb2},
931 {0x88, 0xcc}, {0x89, 0xe5}, {0x7a, 0x24}, {0x3b, 0x00},
932 {0x9f, 0x76}, {0xa0, 0x65}, {0x13, 0xe2}, {0x6b, 0x0a},
933 {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, {0x92, 0x00},
934 {0x93, 0x00},
935};
936
Jean-François Moinedae1de62012-03-24 09:20:25 -0300937static const struct i2c_reg_u8 ov9650_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300938 {0x00, 0x00}, {0x01, 0x78},
Brian Johnson26e744b2009-07-19 05:52:58 -0300939 {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
940 {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
941 {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
942 {0x0e, 0xa0}, {0x0f, 0x52}, {0x10, 0x7c},
943 {0x11, 0x80}, {0x12, 0x45}, {0x13, 0xc2},
944 {0x14, 0x2e}, {0x15, 0x00}, {0x16, 0x07},
945 {0x17, 0x24}, {0x18, 0xc5}, {0x19, 0x00},
946 {0x1a, 0x3c}, {0x1b, 0x00}, {0x1e, 0x04},
947 {0x1f, 0x00}, {0x24, 0x78}, {0x25, 0x68},
948 {0x26, 0xd4}, {0x27, 0x80}, {0x28, 0x80},
949 {0x29, 0x30}, {0x2a, 0x00}, {0x2b, 0x00},
950 {0x2c, 0x80}, {0x2d, 0x00}, {0x2e, 0x00},
951 {0x2f, 0x00}, {0x30, 0x08}, {0x31, 0x30},
952 {0x32, 0x84}, {0x33, 0xe2}, {0x34, 0xbf},
953 {0x35, 0x81}, {0x36, 0xf9}, {0x37, 0x00},
954 {0x38, 0x93}, {0x39, 0x50}, {0x3a, 0x01},
955 {0x3b, 0x01}, {0x3c, 0x73}, {0x3d, 0x19},
956 {0x3e, 0x0b}, {0x3f, 0x80}, {0x40, 0xc1},
957 {0x41, 0x00}, {0x42, 0x08}, {0x67, 0x80},
958 {0x68, 0x80}, {0x69, 0x40}, {0x6a, 0x00},
959 {0x6b, 0x0a}, {0x8b, 0x06}, {0x8c, 0x20},
960 {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0xdf},
961 {0x92, 0x00}, {0x93, 0x00}, {0x94, 0x88},
962 {0x95, 0x88}, {0x96, 0x04}, {0xa1, 0x00},
963 {0xa5, 0x80}, {0xa8, 0x80}, {0xa9, 0xb8},
964 {0xaa, 0x92}, {0xab, 0x0a},
965};
966
Jean-François Moinedae1de62012-03-24 09:20:25 -0300967static const struct i2c_reg_u8 ov9655_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300968 {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300969 {0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
970 {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
971 {0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57},
972 {0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c}, {0x3d, 0x19},
973 {0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40}, {0x42, 0x80},
974 {0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a}, {0x48, 0x3c},
975 {0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc}, {0x4d, 0xdc},
976 {0x4e, 0xdc}, {0x6c, 0x04}, {0x6f, 0x9e}, {0x70, 0x05},
977 {0x71, 0x78}, {0x77, 0x02}, {0x8a, 0x23}, {0x90, 0x7e},
978 {0x91, 0x7c}, {0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68},
979 {0xa6, 0x60}, {0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92},
980 {0xab, 0x04}, {0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80},
981 {0xaf, 0x80}, {0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00},
982 {0xb6, 0xaf}, {0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44},
983 {0xbe, 0x3b}, {0xbf, 0x3a}, {0xc1, 0xc8}, {0xc2, 0x01},
Brian Johnson26e744b2009-07-19 05:52:58 -0300984 {0xc4, 0x00}, {0xc6, 0x85}, {0xc7, 0x81}, {0xc9, 0xe0},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300985 {0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x2d, 0x00},
986 {0x2e, 0x00}, {0x01, 0x80}, {0x02, 0x80}, {0x12, 0x61},
Brian Johnson26e744b2009-07-19 05:52:58 -0300987 {0x36, 0xfa}, {0x8c, 0x8d}, {0xc0, 0xaa}, {0x69, 0x0a},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300988 {0x03, 0x09}, {0x17, 0x16}, {0x18, 0x6e}, {0x19, 0x01},
989 {0x1a, 0x3e}, {0x32, 0x09}, {0x2a, 0x10}, {0x2b, 0x0a},
990 {0x92, 0x00}, {0x93, 0x00}, {0xa1, 0x00}, {0x10, 0x7c},
991 {0x04, 0x03}, {0x00, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300992};
993
Jean-François Moinedae1de62012-03-24 09:20:25 -0300994static const struct i2c_reg_u16 mt9v112_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300995 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020},
996 {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
997 {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
998 {0x05, 0x0000}, {0x06, 0x340c}, {0x3b, 0x042a},
999 {0x3c, 0x0400}, {0xf0, 0x0002}, {0x2e, 0x0c58},
1000 {0x5b, 0x0001}, {0xc8, 0x9f0b}, {0xf0, 0x0001},
1001 {0x9b, 0x5300}, {0xf0, 0x0000}, {0x2b, 0x0020},
1002 {0x2c, 0x002a}, {0x2d, 0x0032}, {0x2e, 0x0020},
1003 {0x09, 0x01dc}, {0x01, 0x000c}, {0x02, 0x0020},
1004 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
1005 {0x05, 0x0098}, {0x20, 0x0703}, {0x09, 0x01f2},
1006 {0x2b, 0x00a0}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
1007 {0x2e, 0x00a0}, {0x01, 0x000c}, {0x02, 0x0020},
1008 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
1009 {0x05, 0x0098}, {0x09, 0x01c1}, {0x2b, 0x00ae},
1010 {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
1011};
1012
Jean-François Moinedae1de62012-03-24 09:20:25 -03001013static const struct i2c_reg_u16 mt9v111_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001014 {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
Brian Johnson6ea23bd2010-05-05 13:22:45 -03001015 {0x01, 0x0001}, {0x05, 0x0004}, {0x2d, 0xe0a0},
1016 {0x2e, 0x0c64}, {0x2f, 0x0064}, {0x06, 0x600e},
1017 {0x08, 0x0480}, {0x01, 0x0004}, {0x02, 0x0016},
1018 {0x03, 0x01e7}, {0x04, 0x0287}, {0x05, 0x0004},
1019 {0x06, 0x002d}, {0x07, 0x3002}, {0x08, 0x0008},
1020 {0x0e, 0x0008}, {0x20, 0x0000}
Brian Johnson26e744b2009-07-19 05:52:58 -03001021};
1022
Jean-François Moinedae1de62012-03-24 09:20:25 -03001023static const struct i2c_reg_u16 mt9v011_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001024 {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
1025 {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1},
1026 {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006},
1027 {0x0d, 0x0002}, {0x0a, 0x0000}, {0x0b, 0x0000},
1028 {0x0c, 0x0000}, {0x0d, 0x0000}, {0x0e, 0x0000},
1029 {0x0f, 0x0000}, {0x10, 0x0000}, {0x11, 0x0000},
1030 {0x12, 0x0000}, {0x13, 0x0000}, {0x14, 0x0000},
1031 {0x15, 0x0000}, {0x16, 0x0000}, {0x17, 0x0000},
1032 {0x18, 0x0000}, {0x19, 0x0000}, {0x1a, 0x0000},
1033 {0x1b, 0x0000}, {0x1c, 0x0000}, {0x1d, 0x0000},
1034 {0x32, 0x0000}, {0x20, 0x1101}, {0x21, 0x0000},
1035 {0x22, 0x0000}, {0x23, 0x0000}, {0x24, 0x0000},
1036 {0x25, 0x0000}, {0x26, 0x0000}, {0x27, 0x0024},
1037 {0x2f, 0xf7b0}, {0x30, 0x0005}, {0x31, 0x0000},
1038 {0x32, 0x0000}, {0x33, 0x0000}, {0x34, 0x0100},
1039 {0x3d, 0x068f}, {0x40, 0x01e0}, {0x41, 0x00d1},
1040 {0x44, 0x0082}, {0x5a, 0x0000}, {0x5b, 0x0000},
1041 {0x5c, 0x0000}, {0x5d, 0x0000}, {0x5e, 0x0000},
1042 {0x5f, 0xa31d}, {0x62, 0x0611}, {0x0a, 0x0000},
1043 {0x06, 0x0029}, {0x05, 0x0009}, {0x20, 0x1101},
1044 {0x20, 0x1101}, {0x09, 0x0064}, {0x07, 0x0003},
1045 {0x2b, 0x0033}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
1046 {0x2e, 0x0033}, {0x07, 0x0002}, {0x06, 0x0000},
1047 {0x06, 0x0029}, {0x05, 0x0009},
1048};
1049
Jean-François Moinedae1de62012-03-24 09:20:25 -03001050static const struct i2c_reg_u16 mt9m001_init[] = {
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001051 {0x0d, 0x0001},
1052 {0x0d, 0x0000},
1053 {0x04, 0x0500}, /* hres = 1280 */
1054 {0x03, 0x0400}, /* vres = 1024 */
1055 {0x20, 0x1100},
1056 {0x06, 0x0010},
1057 {0x2b, 0x0024},
1058 {0x2e, 0x0024},
1059 {0x35, 0x0024},
1060 {0x2d, 0x0020},
1061 {0x2c, 0x0020},
1062 {0x09, 0x0ad4},
1063 {0x35, 0x0057},
Brian Johnson26e744b2009-07-19 05:52:58 -03001064};
1065
Jean-François Moinedae1de62012-03-24 09:20:25 -03001066static const struct i2c_reg_u16 mt9m111_init[] = {
Brian Johnson13a84fa2009-09-03 19:07:13 -03001067 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
1068 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
Brian Johnson4d708a52009-09-03 19:10:15 -03001069 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
1070 {0xf0, 0x0000},
Brian Johnson26e744b2009-07-19 05:52:58 -03001071};
1072
Jean-François Moinedae1de62012-03-24 09:20:25 -03001073static const struct i2c_reg_u16 mt9m112_init[] = {
Brian Johnsone99ac542010-03-16 13:58:28 -03001074 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
1075 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
1076 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
1077 {0xf0, 0x0000},
1078};
1079
Jean-François Moinedae1de62012-03-24 09:20:25 -03001080static const struct i2c_reg_u8 hv7131r_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03001081 {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
1082 {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
1083 {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
1084 {0x01, 0x08}, {0x01, 0x08}, {0x25, 0x07},
1085 {0x26, 0xc3}, {0x27, 0x50}, {0x30, 0x62},
1086 {0x31, 0x10}, {0x32, 0x06}, {0x33, 0x10},
1087 {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00},
1088 {0x23, 0x09}, {0x01, 0x08},
1089};
1090
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001091static void reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
Brian Johnson26e744b2009-07-19 05:52:58 -03001092{
1093 struct usb_device *dev = gspca_dev->dev;
1094 int result;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001095
1096 if (gspca_dev->usb_err < 0)
1097 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001098 result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
1099 0x00,
1100 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
1101 reg,
1102 0x00,
1103 gspca_dev->usb_buf,
1104 length,
1105 500);
1106 if (unlikely(result < 0 || result != length)) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001107 pr_err("Read register %02x failed %d\n", reg, result);
1108 gspca_dev->usb_err = result;
Brian Johnson26e744b2009-07-19 05:52:58 -03001109 }
Brian Johnson26e744b2009-07-19 05:52:58 -03001110}
1111
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001112static void reg_w(struct gspca_dev *gspca_dev, u16 reg,
Joe Perches58aa68c2009-09-02 01:12:13 -03001113 const u8 *buffer, int length)
Brian Johnson26e744b2009-07-19 05:52:58 -03001114{
1115 struct usb_device *dev = gspca_dev->dev;
1116 int result;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001117
1118 if (gspca_dev->usb_err < 0)
1119 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001120 memcpy(gspca_dev->usb_buf, buffer, length);
1121 result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
1122 0x08,
1123 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
1124 reg,
1125 0x00,
1126 gspca_dev->usb_buf,
1127 length,
1128 500);
1129 if (unlikely(result < 0 || result != length)) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001130 pr_err("Write register %02x failed %d\n", reg, result);
1131 gspca_dev->usb_err = result;
Brian Johnson26e744b2009-07-19 05:52:58 -03001132 }
Brian Johnson26e744b2009-07-19 05:52:58 -03001133}
1134
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001135static void reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
Brian Johnson26e744b2009-07-19 05:52:58 -03001136{
Jean-François Moineff38d582012-03-19 04:55:16 -03001137 reg_w(gspca_dev, reg, &value, 1);
Brian Johnson26e744b2009-07-19 05:52:58 -03001138}
1139
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001140static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
Brian Johnson26e744b2009-07-19 05:52:58 -03001141{
1142 int i;
Jean-François Moineff38d582012-03-19 04:55:16 -03001143
Brian Johnson26e744b2009-07-19 05:52:58 -03001144 reg_w(gspca_dev, 0x10c0, buffer, 8);
1145 for (i = 0; i < 5; i++) {
1146 reg_r(gspca_dev, 0x10c0, 1);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001147 if (gspca_dev->usb_err < 0)
1148 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001149 if (gspca_dev->usb_buf[0] & 0x04) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001150 if (gspca_dev->usb_buf[0] & 0x08) {
1151 pr_err("i2c_w error\n");
1152 gspca_dev->usb_err = -EIO;
1153 }
1154 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001155 }
Jean-François Moinee71389b2012-03-19 04:45:20 -03001156 msleep(10);
Brian Johnson26e744b2009-07-19 05:52:58 -03001157 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001158 pr_err("i2c_w reg %02x no response\n", buffer[2]);
1159/* gspca_dev->usb_err = -EIO; fixme: may occur */
Brian Johnson26e744b2009-07-19 05:52:58 -03001160}
1161
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001162static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001163{
1164 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson26e744b2009-07-19 05:52:58 -03001165 u8 row[8];
1166
1167 /*
1168 * from the point of view of the bridge, the length
1169 * includes the address
1170 */
1171 row[0] = 0x81 | (2 << 4);
1172 row[1] = sd->i2c_addr;
1173 row[2] = reg;
1174 row[3] = val;
1175 row[4] = 0x00;
1176 row[5] = 0x00;
1177 row[6] = 0x00;
1178 row[7] = 0x10;
1179
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001180 i2c_w(gspca_dev, row);
Brian Johnson26e744b2009-07-19 05:52:58 -03001181}
1182
Jean-François Moined4689b72012-03-19 04:42:45 -03001183static void i2c_w1_buf(struct gspca_dev *gspca_dev,
Jean-François Moinedae1de62012-03-24 09:20:25 -03001184 const struct i2c_reg_u8 *buf, int sz)
Jean-François Moined4689b72012-03-19 04:42:45 -03001185{
1186 while (--sz >= 0) {
1187 i2c_w1(gspca_dev, buf->reg, buf->val);
1188 buf++;
1189 }
1190}
1191
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001192static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001193{
1194 struct sd *sd = (struct sd *) gspca_dev;
1195 u8 row[8];
1196
1197 /*
1198 * from the point of view of the bridge, the length
1199 * includes the address
1200 */
1201 row[0] = 0x81 | (3 << 4);
1202 row[1] = sd->i2c_addr;
1203 row[2] = reg;
Jean-François Moineff38d582012-03-19 04:55:16 -03001204 row[3] = val >> 8;
1205 row[4] = val;
Brian Johnson26e744b2009-07-19 05:52:58 -03001206 row[5] = 0x00;
1207 row[6] = 0x00;
1208 row[7] = 0x10;
1209
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001210 i2c_w(gspca_dev, row);
Brian Johnson26e744b2009-07-19 05:52:58 -03001211}
1212
Jean-François Moined4689b72012-03-19 04:42:45 -03001213static void i2c_w2_buf(struct gspca_dev *gspca_dev,
Jean-François Moinedae1de62012-03-24 09:20:25 -03001214 const struct i2c_reg_u16 *buf, int sz)
Jean-François Moined4689b72012-03-19 04:42:45 -03001215{
1216 while (--sz >= 0) {
1217 i2c_w2(gspca_dev, buf->reg, buf->val);
1218 buf++;
1219 }
1220}
1221
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001222static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001223{
1224 struct sd *sd = (struct sd *) gspca_dev;
1225 u8 row[8];
1226
Brian Johnson00b581e2009-07-23 05:55:43 -03001227 row[0] = 0x81 | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001228 row[1] = sd->i2c_addr;
1229 row[2] = reg;
1230 row[3] = 0;
1231 row[4] = 0;
1232 row[5] = 0;
1233 row[6] = 0;
1234 row[7] = 0x10;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001235 i2c_w(gspca_dev, row);
Brian Johnson00b581e2009-07-23 05:55:43 -03001236 row[0] = 0x81 | (1 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001237 row[2] = 0;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001238 i2c_w(gspca_dev, row);
1239 reg_r(gspca_dev, 0x10c2, 5);
Brian Johnson00b581e2009-07-23 05:55:43 -03001240 *val = gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001241}
1242
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001243static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001244{
1245 struct sd *sd = (struct sd *) gspca_dev;
1246 u8 row[8];
1247
Brian Johnson00b581e2009-07-23 05:55:43 -03001248 row[0] = 0x81 | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001249 row[1] = sd->i2c_addr;
1250 row[2] = reg;
1251 row[3] = 0;
1252 row[4] = 0;
1253 row[5] = 0;
1254 row[6] = 0;
1255 row[7] = 0x10;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001256 i2c_w(gspca_dev, row);
Brian Johnson00b581e2009-07-23 05:55:43 -03001257 row[0] = 0x81 | (2 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001258 row[2] = 0;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001259 i2c_w(gspca_dev, row);
1260 reg_r(gspca_dev, 0x10c2, 5);
Brian Johnson00b581e2009-07-23 05:55:43 -03001261 *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001262}
1263
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001264static void ov9650_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001265{
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001266 u16 id;
Brian Johnson26e744b2009-07-19 05:52:58 -03001267 struct sd *sd = (struct sd *) gspca_dev;
1268
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001269 i2c_r2(gspca_dev, 0x1c, &id);
1270 if (gspca_dev->usb_err < 0)
1271 return;
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001272
1273 if (id != 0x7fa2) {
Joe Perches91f58422011-08-21 19:56:55 -03001274 pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001275 gspca_dev->usb_err = -ENODEV;
1276 return;
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001277 }
1278
Jean-François Moine92884f82012-03-19 04:33:30 -03001279 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1280 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001281 i2c_w1_buf(gspca_dev, ov9650_init, ARRAY_SIZE(ov9650_init));
1282 if (gspca_dev->usb_err < 0)
1283 pr_err("OV9650 sensor initialization failed\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001284 sd->hstart = 1;
1285 sd->vstart = 7;
Brian Johnson26e744b2009-07-19 05:52:58 -03001286}
1287
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001288static void ov9655_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001289{
Brian Johnson26e744b2009-07-19 05:52:58 -03001290 struct sd *sd = (struct sd *) gspca_dev;
1291
Jean-François Moine92884f82012-03-19 04:33:30 -03001292 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1293 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001294 i2c_w1_buf(gspca_dev, ov9655_init, ARRAY_SIZE(ov9655_init));
1295 if (gspca_dev->usb_err < 0)
1296 pr_err("OV9655 sensor initialization failed\n");
1297
Brian Johnson26e744b2009-07-19 05:52:58 -03001298 /* disable hflip and vflip */
Jean-François Moinec5224d82012-03-19 04:30:07 -03001299 gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
Brian Johnsoncc2a8332010-03-16 13:58:28 -03001300 sd->hstart = 1;
1301 sd->vstart = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001302}
1303
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001304static void soi968_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001305{
Brian Johnson26e744b2009-07-19 05:52:58 -03001306 struct sd *sd = (struct sd *) gspca_dev;
1307
Jean-François Moine92884f82012-03-19 04:33:30 -03001308 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1309 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001310 i2c_w1_buf(gspca_dev, soi968_init, ARRAY_SIZE(soi968_init));
1311 if (gspca_dev->usb_err < 0)
1312 pr_err("SOI968 sensor initialization failed\n");
1313
Brian Johnson26e744b2009-07-19 05:52:58 -03001314 /* disable hflip and vflip */
Jean-François Moinec5224d82012-03-19 04:30:07 -03001315 gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP)
1316 | (1 << EXPOSURE);
Brian Johnson26e744b2009-07-19 05:52:58 -03001317 sd->hstart = 60;
1318 sd->vstart = 11;
Brian Johnson26e744b2009-07-19 05:52:58 -03001319}
1320
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001321static void ov7660_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001322{
Brian Johnson26e744b2009-07-19 05:52:58 -03001323 struct sd *sd = (struct sd *) gspca_dev;
1324
Jean-François Moine92884f82012-03-19 04:33:30 -03001325 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1326 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001327 i2c_w1_buf(gspca_dev, ov7660_init, ARRAY_SIZE(ov7660_init));
1328 if (gspca_dev->usb_err < 0)
1329 pr_err("OV7660 sensor initialization failed\n");
Hans de Goede8bc50f32011-02-16 07:11:14 -03001330 sd->hstart = 3;
1331 sd->vstart = 3;
Brian Johnson26e744b2009-07-19 05:52:58 -03001332}
1333
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001334static void ov7670_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001335{
Brian Johnson26e744b2009-07-19 05:52:58 -03001336 struct sd *sd = (struct sd *) gspca_dev;
1337
Jean-François Moine92884f82012-03-19 04:33:30 -03001338 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1339 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001340 i2c_w1_buf(gspca_dev, ov7670_init, ARRAY_SIZE(ov7670_init));
1341 if (gspca_dev->usb_err < 0)
1342 pr_err("OV7670 sensor initialization failed\n");
1343
Brian Johnson26e744b2009-07-19 05:52:58 -03001344 /* disable hflip and vflip */
Jean-François Moinec5224d82012-03-19 04:30:07 -03001345 gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
Brian Johnson26e744b2009-07-19 05:52:58 -03001346 sd->hstart = 0;
1347 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001348}
1349
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001350static void mt9v_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001351{
1352 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson26e744b2009-07-19 05:52:58 -03001353 u16 value;
Brian Johnson26e744b2009-07-19 05:52:58 -03001354
1355 sd->i2c_addr = 0x5d;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001356 i2c_r2(gspca_dev, 0xff, &value);
1357 if (gspca_dev->usb_err >= 0
1358 && value == 0x8243) {
Jean-François Moined4689b72012-03-19 04:42:45 -03001359 i2c_w2_buf(gspca_dev, mt9v011_init, ARRAY_SIZE(mt9v011_init));
1360 if (gspca_dev->usb_err < 0) {
1361 pr_err("MT9V011 sensor initialization failed\n");
1362 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001363 }
1364 sd->hstart = 2;
1365 sd->vstart = 2;
1366 sd->sensor = SENSOR_MT9V011;
Joe Perches91f58422011-08-21 19:56:55 -03001367 pr_info("MT9V011 sensor detected\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001368 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001369 }
1370
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001371 gspca_dev->usb_err = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001372 sd->i2c_addr = 0x5c;
1373 i2c_w2(gspca_dev, 0x01, 0x0004);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001374 i2c_r2(gspca_dev, 0xff, &value);
1375 if (gspca_dev->usb_err >= 0
1376 && value == 0x823a) {
Jean-François Moined4689b72012-03-19 04:42:45 -03001377 i2c_w2_buf(gspca_dev, mt9v111_init, ARRAY_SIZE(mt9v111_init));
1378 if (gspca_dev->usb_err < 0) {
1379 pr_err("MT9V111 sensor initialization failed\n");
1380 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001381 }
Jean-François Moinec5224d82012-03-19 04:30:07 -03001382 gspca_dev->ctrl_dis = (1 << EXPOSURE)
1383 | (1 << AUTOGAIN)
1384 | (1 << GAIN);
Brian Johnson26e744b2009-07-19 05:52:58 -03001385 sd->hstart = 2;
1386 sd->vstart = 2;
1387 sd->sensor = SENSOR_MT9V111;
Joe Perches91f58422011-08-21 19:56:55 -03001388 pr_info("MT9V111 sensor detected\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001389 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001390 }
1391
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001392 gspca_dev->usb_err = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001393 sd->i2c_addr = 0x5d;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001394 i2c_w2(gspca_dev, 0xf0, 0x0000);
1395 if (gspca_dev->usb_err < 0) {
1396 gspca_dev->usb_err = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001397 sd->i2c_addr = 0x48;
1398 i2c_w2(gspca_dev, 0xf0, 0x0000);
1399 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001400 i2c_r2(gspca_dev, 0x00, &value);
1401 if (gspca_dev->usb_err >= 0
1402 && value == 0x1229) {
Jean-François Moined4689b72012-03-19 04:42:45 -03001403 i2c_w2_buf(gspca_dev, mt9v112_init, ARRAY_SIZE(mt9v112_init));
1404 if (gspca_dev->usb_err < 0) {
1405 pr_err("MT9V112 sensor initialization failed\n");
1406 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001407 }
1408 sd->hstart = 6;
1409 sd->vstart = 2;
1410 sd->sensor = SENSOR_MT9V112;
Joe Perches91f58422011-08-21 19:56:55 -03001411 pr_info("MT9V112 sensor detected\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001412 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001413 }
1414
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001415 gspca_dev->usb_err = -ENODEV;
Brian Johnson26e744b2009-07-19 05:52:58 -03001416}
1417
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001418static void mt9m112_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnsone99ac542010-03-16 13:58:28 -03001419{
1420 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moined4689b72012-03-19 04:42:45 -03001421
1422 i2c_w2_buf(gspca_dev, mt9m112_init, ARRAY_SIZE(mt9m112_init));
1423 if (gspca_dev->usb_err < 0)
1424 pr_err("MT9M112 sensor initialization failed\n");
1425
Jean-François Moinec5224d82012-03-19 04:30:07 -03001426 gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
1427 | (1 << GAIN);
Brian Johnsone99ac542010-03-16 13:58:28 -03001428 sd->hstart = 0;
1429 sd->vstart = 2;
Brian Johnsone99ac542010-03-16 13:58:28 -03001430}
1431
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001432static void mt9m111_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001433{
1434 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moined4689b72012-03-19 04:42:45 -03001435
1436 i2c_w2_buf(gspca_dev, mt9m111_init, ARRAY_SIZE(mt9m111_init));
1437 if (gspca_dev->usb_err < 0)
1438 pr_err("MT9M111 sensor initialization failed\n");
1439
Jean-François Moinec5224d82012-03-19 04:30:07 -03001440 gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
1441 | (1 << GAIN);
Brian Johnson26e744b2009-07-19 05:52:58 -03001442 sd->hstart = 0;
1443 sd->vstart = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001444}
1445
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001446static void mt9m001_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001447{
1448 struct sd *sd = (struct sd *) gspca_dev;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001449 u16 id;
1450
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001451 i2c_r2(gspca_dev, 0x00, &id);
1452 if (gspca_dev->usb_err < 0)
1453 return;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001454
1455 /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
1456 switch (id) {
1457 case 0x8411:
1458 case 0x8421:
Joe Perches91f58422011-08-21 19:56:55 -03001459 pr_info("MT9M001 color sensor detected\n");
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001460 break;
1461 case 0x8431:
Joe Perches91f58422011-08-21 19:56:55 -03001462 pr_info("MT9M001 mono sensor detected\n");
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001463 break;
1464 default:
Joe Perches91f58422011-08-21 19:56:55 -03001465 pr_err("No MT9M001 chip detected, ID = %x\n\n", id);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001466 gspca_dev->usb_err = -ENODEV;
1467 return;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001468 }
1469
Jean-François Moined4689b72012-03-19 04:42:45 -03001470 i2c_w2_buf(gspca_dev, mt9m001_init, ARRAY_SIZE(mt9m001_init));
1471 if (gspca_dev->usb_err < 0)
1472 pr_err("MT9M001 sensor initialization failed\n");
1473
Brian Johnson26e744b2009-07-19 05:52:58 -03001474 /* disable hflip and vflip */
Jean-François Moinec5224d82012-03-19 04:30:07 -03001475 gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001476 sd->hstart = 1;
1477 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001478}
1479
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001480static void hv7131r_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001481{
Brian Johnson26e744b2009-07-19 05:52:58 -03001482 struct sd *sd = (struct sd *) gspca_dev;
1483
Jean-François Moined4689b72012-03-19 04:42:45 -03001484 i2c_w1_buf(gspca_dev, hv7131r_init, ARRAY_SIZE(hv7131r_init));
1485 if (gspca_dev->usb_err < 0)
1486 pr_err("HV7131R Sensor initialization failed\n");
1487
Brian Johnson26e744b2009-07-19 05:52:58 -03001488 sd->hstart = 0;
1489 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001490}
1491
Jean-François Moinec5224d82012-03-19 04:30:07 -03001492static void set_cmatrix(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001493{
1494 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001495 int satur;
1496 s32 hue_coord, hue_index = 180 + sd->ctrls[HUE].val;
Brian Johnson26e744b2009-07-19 05:52:58 -03001497 u8 cmatrix[21];
Brian Johnson26e744b2009-07-19 05:52:58 -03001498
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001499 memset(cmatrix, 0, sizeof cmatrix);
Jean-François Moinec5224d82012-03-19 04:30:07 -03001500 cmatrix[2] = (sd->ctrls[CONTRAST].val * 0x25 / 0x100) + 0x26;
Brian Johnson26e744b2009-07-19 05:52:58 -03001501 cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
1502 cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001503 cmatrix[18] = sd->ctrls[BRIGHTNESS].val - 0x80;
Brian Johnson26e744b2009-07-19 05:52:58 -03001504
Jean-François Moinec5224d82012-03-19 04:30:07 -03001505 satur = sd->ctrls[SATURATION].val;
1506 hue_coord = (hsv_red_x[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001507 cmatrix[6] = hue_coord;
1508 cmatrix[7] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001509
Jean-François Moinec5224d82012-03-19 04:30:07 -03001510 hue_coord = (hsv_red_y[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001511 cmatrix[8] = hue_coord;
1512 cmatrix[9] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001513
Jean-François Moinec5224d82012-03-19 04:30:07 -03001514 hue_coord = (hsv_green_x[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001515 cmatrix[10] = hue_coord;
1516 cmatrix[11] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001517
Jean-François Moinec5224d82012-03-19 04:30:07 -03001518 hue_coord = (hsv_green_y[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001519 cmatrix[12] = hue_coord;
1520 cmatrix[13] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001521
Jean-François Moinec5224d82012-03-19 04:30:07 -03001522 hue_coord = (hsv_blue_x[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001523 cmatrix[14] = hue_coord;
1524 cmatrix[15] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001525
Jean-François Moinec5224d82012-03-19 04:30:07 -03001526 hue_coord = (hsv_blue_y[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001527 cmatrix[16] = hue_coord;
1528 cmatrix[17] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001529
Jean-François Moinec5224d82012-03-19 04:30:07 -03001530 reg_w(gspca_dev, 0x10e1, cmatrix, 21);
Brian Johnson26e744b2009-07-19 05:52:58 -03001531}
1532
Jean-François Moinec5224d82012-03-19 04:30:07 -03001533static void set_gamma(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001534{
1535 struct sd *sd = (struct sd *) gspca_dev;
1536 u8 gamma[17];
Jean-François Moinec5224d82012-03-19 04:30:07 -03001537 u8 gval = sd->ctrls[GAMMA].val * 0xb8 / 0x100;
Brian Johnson26e744b2009-07-19 05:52:58 -03001538
1539 gamma[0] = 0x0a;
1540 gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
1541 gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8);
1542 gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8);
1543 gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8);
1544 gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8);
1545 gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8);
1546 gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8);
1547 gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8);
1548 gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8);
1549 gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8);
1550 gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8);
1551 gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8);
1552 gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8);
1553 gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8);
1554 gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
1555 gamma[16] = 0xf5;
1556
Jean-François Moinec5224d82012-03-19 04:30:07 -03001557 reg_w(gspca_dev, 0x1190, gamma, 17);
Brian Johnson26e744b2009-07-19 05:52:58 -03001558}
1559
Jean-François Moinec5224d82012-03-19 04:30:07 -03001560static void set_redblue(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001561{
1562 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001563
1564 reg_w1(gspca_dev, 0x118c, sd->ctrls[RED].val);
1565 reg_w1(gspca_dev, 0x118f, sd->ctrls[BLUE].val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001566}
1567
Jean-François Moinec5224d82012-03-19 04:30:07 -03001568static void set_hvflip(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001569{
Brian Johnson7ddaac72010-03-16 13:58:27 -03001570 u8 value, tslb, hflip, vflip;
Brian Johnson26e744b2009-07-19 05:52:58 -03001571 u16 value2;
1572 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001573
1574 if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
Jean-François Moinec5224d82012-03-19 04:30:07 -03001575 hflip = !sd->ctrls[HFLIP].val;
1576 vflip = !sd->ctrls[VFLIP].val;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001577 } else {
Jean-François Moinec5224d82012-03-19 04:30:07 -03001578 hflip = sd->ctrls[HFLIP].val;
1579 vflip = sd->ctrls[VFLIP].val;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001580 }
1581
Brian Johnson26e744b2009-07-19 05:52:58 -03001582 switch (sd->sensor) {
Hans de Goede779b51f2011-02-16 08:17:36 -03001583 case SENSOR_OV7660:
1584 value = 0x01;
1585 if (hflip)
1586 value |= 0x20;
1587 if (vflip) {
1588 value |= 0x10;
1589 sd->vstart = 2;
Jean-François Moineff38d582012-03-19 04:55:16 -03001590 } else {
Hans de Goede779b51f2011-02-16 08:17:36 -03001591 sd->vstart = 3;
Jean-François Moineff38d582012-03-19 04:55:16 -03001592 }
Hans de Goede779b51f2011-02-16 08:17:36 -03001593 reg_w1(gspca_dev, 0x1182, sd->vstart);
1594 i2c_w1(gspca_dev, 0x1e, value);
1595 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001596 case SENSOR_OV9650:
1597 i2c_r1(gspca_dev, 0x1e, &value);
1598 value &= ~0x30;
1599 tslb = 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001600 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001601 value |= 0x20;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001602 if (vflip) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001603 value |= 0x10;
1604 tslb = 0x49;
1605 }
1606 i2c_w1(gspca_dev, 0x1e, value);
1607 i2c_w1(gspca_dev, 0x3a, tslb);
1608 break;
1609 case SENSOR_MT9V111:
1610 case SENSOR_MT9V011:
1611 i2c_r2(gspca_dev, 0x20, &value2);
1612 value2 &= ~0xc0a0;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001613 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001614 value2 |= 0x8080;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001615 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001616 value2 |= 0x4020;
1617 i2c_w2(gspca_dev, 0x20, value2);
1618 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001619 case SENSOR_MT9M112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001620 case SENSOR_MT9M111:
1621 case SENSOR_MT9V112:
1622 i2c_r2(gspca_dev, 0x20, &value2);
1623 value2 &= ~0x0003;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001624 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001625 value2 |= 0x0002;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001626 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001627 value2 |= 0x0001;
1628 i2c_w2(gspca_dev, 0x20, value2);
1629 break;
1630 case SENSOR_HV7131R:
1631 i2c_r1(gspca_dev, 0x01, &value);
1632 value &= ~0x03;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001633 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001634 value |= 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001635 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001636 value |= 0x02;
1637 i2c_w1(gspca_dev, 0x01, value);
1638 break;
1639 }
Brian Johnson26e744b2009-07-19 05:52:58 -03001640}
1641
Jean-François Moinec5224d82012-03-19 04:30:07 -03001642static void set_exposure(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001643{
1644 struct sd *sd = (struct sd *) gspca_dev;
1645 u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
Jean-François Moinec5224d82012-03-19 04:30:07 -03001646 int expo;
1647
1648 expo = sd->ctrls[EXPOSURE].val;
Brian Johnson26e744b2009-07-19 05:52:58 -03001649 switch (sd->sensor) {
1650 case SENSOR_OV7660:
1651 case SENSOR_OV7670:
Brian Johnson26e744b2009-07-19 05:52:58 -03001652 case SENSOR_OV9655:
1653 case SENSOR_OV9650:
1654 exp[0] |= (3 << 4);
1655 exp[2] = 0x2d;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001656 exp[3] = expo;
1657 exp[4] = expo >> 8;
Brian Johnson26e744b2009-07-19 05:52:58 -03001658 break;
1659 case SENSOR_MT9M001:
Brian Johnson26e744b2009-07-19 05:52:58 -03001660 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001661 case SENSOR_MT9V011:
1662 exp[0] |= (3 << 4);
1663 exp[2] = 0x09;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001664 exp[3] = expo >> 8;
1665 exp[4] = expo;
Brian Johnson26e744b2009-07-19 05:52:58 -03001666 break;
1667 case SENSOR_HV7131R:
1668 exp[0] |= (4 << 4);
1669 exp[2] = 0x25;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001670 exp[3] = expo >> 5;
1671 exp[4] = expo << 3;
German Galkine10f7312010-03-07 06:19:02 -03001672 exp[5] = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001673 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001674 default:
Jean-François Moinec5224d82012-03-19 04:30:07 -03001675 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001676 }
1677 i2c_w(gspca_dev, exp);
Brian Johnson26e744b2009-07-19 05:52:58 -03001678}
1679
Jean-François Moinec5224d82012-03-19 04:30:07 -03001680static void set_gain(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001681{
1682 struct sd *sd = (struct sd *) gspca_dev;
1683 u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
Jean-François Moinec5224d82012-03-19 04:30:07 -03001684 int g;
1685
1686 g = sd->ctrls[GAIN].val;
Brian Johnson26e744b2009-07-19 05:52:58 -03001687 switch (sd->sensor) {
1688 case SENSOR_OV7660:
1689 case SENSOR_OV7670:
1690 case SENSOR_SOI968:
1691 case SENSOR_OV9655:
1692 case SENSOR_OV9650:
1693 gain[0] |= (2 << 4);
Jean-François Moinec5224d82012-03-19 04:30:07 -03001694 gain[3] = ov_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001695 break;
1696 case SENSOR_MT9V011:
Brian Johnson26e744b2009-07-19 05:52:58 -03001697 gain[0] |= (3 << 4);
1698 gain[2] = 0x35;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001699 gain[3] = micron1_gain[g] >> 8;
1700 gain[4] = micron1_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001701 break;
1702 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001703 gain[0] |= (3 << 4);
1704 gain[2] = 0x2f;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001705 gain[3] = micron1_gain[g] >> 8;
1706 gain[4] = micron1_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001707 break;
1708 case SENSOR_MT9M001:
1709 gain[0] |= (3 << 4);
1710 gain[2] = 0x2f;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001711 gain[3] = micron2_gain[g] >> 8;
1712 gain[4] = micron2_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001713 break;
1714 case SENSOR_HV7131R:
1715 gain[0] |= (2 << 4);
1716 gain[2] = 0x30;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001717 gain[3] = hv7131r_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001718 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001719 default:
Jean-François Moinec5224d82012-03-19 04:30:07 -03001720 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001721 }
1722 i2c_w(gspca_dev, gain);
Brian Johnson26e744b2009-07-19 05:52:58 -03001723}
1724
Jean-François Moine4c632e42012-03-19 04:35:34 -03001725static void set_quality(struct gspca_dev *gspca_dev)
1726{
1727 struct sd *sd = (struct sd *) gspca_dev;
1728
1729 jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
1730 reg_w1(gspca_dev, 0x1061, 0x01); /* stop transfer */
1731 reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */
1732 reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
1733 reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
1734 reg_w1(gspca_dev, 0x1061, 0x03); /* restart transfer */
1735 reg_w1(gspca_dev, 0x10e0, sd->fmt);
1736 sd->fmt ^= 0x0c; /* invert QTAB use + write */
1737 reg_w1(gspca_dev, 0x10e0, sd->fmt);
1738}
1739
Brian Johnson26e744b2009-07-19 05:52:58 -03001740#ifdef CONFIG_VIDEO_ADV_DEBUG
1741static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
1742 struct v4l2_dbg_register *reg)
1743{
1744 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03001745
Brian Johnson26e744b2009-07-19 05:52:58 -03001746 switch (reg->match.type) {
1747 case V4L2_CHIP_MATCH_HOST:
1748 if (reg->match.addr != 0)
1749 return -EINVAL;
1750 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1751 return -EINVAL;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001752 reg_r(gspca_dev, reg->reg, 1);
Brian Johnson26e744b2009-07-19 05:52:58 -03001753 reg->val = gspca_dev->usb_buf[0];
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001754 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001755 case V4L2_CHIP_MATCH_I2C_ADDR:
1756 if (reg->match.addr != sd->i2c_addr)
1757 return -EINVAL;
1758 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001759 sd->sensor <= SENSOR_MT9M112) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001760 i2c_r2(gspca_dev, reg->reg, (u16 *) &reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001761 } else {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001762 i2c_r1(gspca_dev, reg->reg, (u8 *) &reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001763 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001764 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001765 }
1766 return -EINVAL;
1767}
1768
1769static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
1770 struct v4l2_dbg_register *reg)
1771{
1772 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03001773
Brian Johnson26e744b2009-07-19 05:52:58 -03001774 switch (reg->match.type) {
1775 case V4L2_CHIP_MATCH_HOST:
1776 if (reg->match.addr != 0)
1777 return -EINVAL;
1778 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1779 return -EINVAL;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001780 reg_w1(gspca_dev, reg->reg, reg->val);
1781 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001782 case V4L2_CHIP_MATCH_I2C_ADDR:
1783 if (reg->match.addr != sd->i2c_addr)
1784 return -EINVAL;
1785 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001786 sd->sensor <= SENSOR_MT9M112) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001787 i2c_w2(gspca_dev, reg->reg, reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001788 } else {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001789 i2c_w1(gspca_dev, reg->reg, reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001790 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001791 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001792 }
1793 return -EINVAL;
1794}
1795#endif
1796
1797static int sd_chip_ident(struct gspca_dev *gspca_dev,
1798 struct v4l2_dbg_chip_ident *chip)
1799{
1800 struct sd *sd = (struct sd *) gspca_dev;
1801
1802 switch (chip->match.type) {
1803 case V4L2_CHIP_MATCH_HOST:
1804 if (chip->match.addr != 0)
1805 return -EINVAL;
1806 chip->revision = 0;
1807 chip->ident = V4L2_IDENT_SN9C20X;
1808 return 0;
1809 case V4L2_CHIP_MATCH_I2C_ADDR:
1810 if (chip->match.addr != sd->i2c_addr)
1811 return -EINVAL;
1812 chip->revision = 0;
1813 chip->ident = i2c_ident[sd->sensor];
1814 return 0;
1815 }
1816 return -EINVAL;
1817}
1818
1819static int sd_config(struct gspca_dev *gspca_dev,
1820 const struct usb_device_id *id)
1821{
1822 struct sd *sd = (struct sd *) gspca_dev;
1823 struct cam *cam;
1824
1825 cam = &gspca_dev->cam;
Hans de Goedeeb3fb7c2012-01-01 16:35:01 -03001826 cam->needs_full_bandwidth = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001827
Jean-François Moineff38d582012-03-19 04:55:16 -03001828 sd->sensor = id->driver_info >> 8;
1829 sd->i2c_addr = id->driver_info;
1830 sd->flags = id->driver_info >> 16;
Brian Johnson26e744b2009-07-19 05:52:58 -03001831
1832 switch (sd->sensor) {
Brian Johnsone99ac542010-03-16 13:58:28 -03001833 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03001834 case SENSOR_MT9M111:
Brian Johnson26e744b2009-07-19 05:52:58 -03001835 case SENSOR_OV9650:
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001836 case SENSOR_SOI968:
Brian Johnson26e744b2009-07-19 05:52:58 -03001837 cam->cam_mode = sxga_mode;
1838 cam->nmodes = ARRAY_SIZE(sxga_mode);
1839 break;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001840 case SENSOR_MT9M001:
1841 cam->cam_mode = mono_mode;
1842 cam->nmodes = ARRAY_SIZE(mono_mode);
1843 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001844 default:
1845 cam->cam_mode = vga_mode;
1846 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001847 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001848 }
1849
1850 sd->old_step = 0;
1851 sd->older_step = 0;
1852 sd->exposure_step = 16;
1853
Jean-François Moinec5224d82012-03-19 04:30:07 -03001854 gspca_dev->cam.ctrls = sd->ctrls;
Brian Johnson26e744b2009-07-19 05:52:58 -03001855
Jean-François Moine92dcffc2012-03-19 04:47:24 -03001856 INIT_WORK(&sd->work, qual_upd);
Brian Johnson26e744b2009-07-19 05:52:58 -03001857
Brian Johnson26e744b2009-07-19 05:52:58 -03001858 return 0;
1859}
1860
1861static int sd_init(struct gspca_dev *gspca_dev)
1862{
1863 struct sd *sd = (struct sd *) gspca_dev;
1864 int i;
1865 u8 value;
1866 u8 i2c_init[9] =
1867 {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03};
1868
1869 for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
1870 value = bridge_init[i][1];
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001871 reg_w(gspca_dev, bridge_init[i][0], &value, 1);
1872 if (gspca_dev->usb_err < 0) {
Joe Perches91f58422011-08-21 19:56:55 -03001873 pr_err("Device initialization failed\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001874 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001875 }
1876 }
1877
Brian Johnson0c045eb2010-03-16 13:58:27 -03001878 if (sd->flags & LED_REVERSE)
1879 reg_w1(gspca_dev, 0x1006, 0x00);
1880 else
1881 reg_w1(gspca_dev, 0x1006, 0x20);
1882
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001883 reg_w(gspca_dev, 0x10c0, i2c_init, 9);
1884 if (gspca_dev->usb_err < 0) {
Joe Perches91f58422011-08-21 19:56:55 -03001885 pr_err("Device initialization failed\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001886 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001887 }
1888
1889 switch (sd->sensor) {
1890 case SENSOR_OV9650:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001891 ov9650_init_sensor(gspca_dev);
1892 if (gspca_dev->usb_err < 0)
1893 break;
Joe Perches91f58422011-08-21 19:56:55 -03001894 pr_info("OV9650 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001895 break;
1896 case SENSOR_OV9655:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001897 ov9655_init_sensor(gspca_dev);
1898 if (gspca_dev->usb_err < 0)
1899 break;
Joe Perches91f58422011-08-21 19:56:55 -03001900 pr_info("OV9655 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001901 break;
1902 case SENSOR_SOI968:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001903 soi968_init_sensor(gspca_dev);
1904 if (gspca_dev->usb_err < 0)
1905 break;
Joe Perches91f58422011-08-21 19:56:55 -03001906 pr_info("SOI968 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001907 break;
1908 case SENSOR_OV7660:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001909 ov7660_init_sensor(gspca_dev);
1910 if (gspca_dev->usb_err < 0)
1911 break;
Joe Perches91f58422011-08-21 19:56:55 -03001912 pr_info("OV7660 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001913 break;
1914 case SENSOR_OV7670:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001915 ov7670_init_sensor(gspca_dev);
1916 if (gspca_dev->usb_err < 0)
1917 break;
Joe Perches91f58422011-08-21 19:56:55 -03001918 pr_info("OV7670 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001919 break;
1920 case SENSOR_MT9VPRB:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001921 mt9v_init_sensor(gspca_dev);
1922 if (gspca_dev->usb_err < 0)
1923 break;
Jean-François Moineff38d582012-03-19 04:55:16 -03001924 pr_info("MT9VPRB sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001925 break;
1926 case SENSOR_MT9M111:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001927 mt9m111_init_sensor(gspca_dev);
1928 if (gspca_dev->usb_err < 0)
1929 break;
Joe Perches91f58422011-08-21 19:56:55 -03001930 pr_info("MT9M111 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001931 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001932 case SENSOR_MT9M112:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001933 mt9m112_init_sensor(gspca_dev);
1934 if (gspca_dev->usb_err < 0)
1935 break;
Joe Perches91f58422011-08-21 19:56:55 -03001936 pr_info("MT9M112 sensor detected\n");
Brian Johnsone99ac542010-03-16 13:58:28 -03001937 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001938 case SENSOR_MT9M001:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001939 mt9m001_init_sensor(gspca_dev);
1940 if (gspca_dev->usb_err < 0)
1941 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001942 break;
1943 case SENSOR_HV7131R:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001944 hv7131r_init_sensor(gspca_dev);
1945 if (gspca_dev->usb_err < 0)
1946 break;
Joe Perches91f58422011-08-21 19:56:55 -03001947 pr_info("HV7131R sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001948 break;
1949 default:
Jean-François Moineff38d582012-03-19 04:55:16 -03001950 pr_err("Unsupported sensor\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001951 gspca_dev->usb_err = -ENODEV;
Brian Johnson26e744b2009-07-19 05:52:58 -03001952 }
1953
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001954 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001955}
1956
1957static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
1958{
1959 struct sd *sd = (struct sd *) gspca_dev;
1960 u8 value;
Jean-François Moineff38d582012-03-19 04:55:16 -03001961
Brian Johnson26e744b2009-07-19 05:52:58 -03001962 switch (sd->sensor) {
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001963 case SENSOR_SOI968:
1964 if (mode & MODE_SXGA) {
1965 i2c_w1(gspca_dev, 0x17, 0x1d);
1966 i2c_w1(gspca_dev, 0x18, 0xbd);
1967 i2c_w1(gspca_dev, 0x19, 0x01);
1968 i2c_w1(gspca_dev, 0x1a, 0x81);
1969 i2c_w1(gspca_dev, 0x12, 0x00);
1970 sd->hstart = 140;
1971 sd->vstart = 19;
1972 } else {
1973 i2c_w1(gspca_dev, 0x17, 0x13);
1974 i2c_w1(gspca_dev, 0x18, 0x63);
1975 i2c_w1(gspca_dev, 0x19, 0x01);
1976 i2c_w1(gspca_dev, 0x1a, 0x79);
1977 i2c_w1(gspca_dev, 0x12, 0x40);
1978 sd->hstart = 60;
1979 sd->vstart = 11;
1980 }
1981 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001982 case SENSOR_OV9650:
1983 if (mode & MODE_SXGA) {
1984 i2c_w1(gspca_dev, 0x17, 0x1b);
1985 i2c_w1(gspca_dev, 0x18, 0xbc);
1986 i2c_w1(gspca_dev, 0x19, 0x01);
1987 i2c_w1(gspca_dev, 0x1a, 0x82);
1988 i2c_r1(gspca_dev, 0x12, &value);
1989 i2c_w1(gspca_dev, 0x12, value & 0x07);
1990 } else {
1991 i2c_w1(gspca_dev, 0x17, 0x24);
1992 i2c_w1(gspca_dev, 0x18, 0xc5);
1993 i2c_w1(gspca_dev, 0x19, 0x00);
1994 i2c_w1(gspca_dev, 0x1a, 0x3c);
1995 i2c_r1(gspca_dev, 0x12, &value);
1996 i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
1997 }
1998 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001999 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03002000 case SENSOR_MT9M111:
2001 if (mode & MODE_SXGA) {
2002 i2c_w2(gspca_dev, 0xf0, 0x0002);
2003 i2c_w2(gspca_dev, 0xc8, 0x970b);
2004 i2c_w2(gspca_dev, 0xf0, 0x0000);
2005 } else {
2006 i2c_w2(gspca_dev, 0xf0, 0x0002);
2007 i2c_w2(gspca_dev, 0xc8, 0x8000);
2008 i2c_w2(gspca_dev, 0xf0, 0x0000);
2009 }
2010 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03002011 }
2012}
2013
Hans de Goeded80dd5d2012-01-01 16:03:37 -03002014static int sd_isoc_init(struct gspca_dev *gspca_dev)
2015{
2016 struct usb_interface *intf;
2017 u32 flags = gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv;
2018
2019 /*
2020 * When using the SN9C20X_I420 fmt the sn9c20x needs more bandwidth
2021 * than our regular bandwidth calculations reserve, so we force the
2022 * use of a specific altsetting when using the SN9C20X_I420 fmt.
2023 */
2024 if (!(flags & (MODE_RAW | MODE_JPEG))) {
2025 intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
2026
2027 if (intf->num_altsetting != 9) {
2028 pr_warn("sn9c20x camera with unknown number of alt "
2029 "settings (%d), please report!\n",
2030 intf->num_altsetting);
2031 gspca_dev->alt = intf->num_altsetting;
2032 return 0;
2033 }
2034
2035 switch (gspca_dev->width) {
2036 case 160: /* 160x120 */
2037 gspca_dev->alt = 2;
2038 break;
2039 case 320: /* 320x240 */
2040 gspca_dev->alt = 6;
2041 break;
2042 default: /* >= 640x480 */
2043 gspca_dev->alt = 9;
Jean-François Moineff38d582012-03-19 04:55:16 -03002044 break;
Hans de Goeded80dd5d2012-01-01 16:03:37 -03002045 }
2046 }
2047
2048 return 0;
2049}
2050
Brian Johnson26e744b2009-07-19 05:52:58 -03002051#define HW_WIN(mode, hstart, vstart) \
Jean-Francois Moine83955552009-12-12 06:58:01 -03002052((const u8 []){hstart, 0, vstart, 0, \
Brian Johnson26e744b2009-07-19 05:52:58 -03002053(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
2054(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)})
2055
2056#define CLR_WIN(width, height) \
2057((const u8 [])\
2058{0, width >> 2, 0, height >> 1,\
2059((width >> 10) & 0x01) | ((height >> 8) & 0x6)})
2060
2061static int sd_start(struct gspca_dev *gspca_dev)
2062{
2063 struct sd *sd = (struct sd *) gspca_dev;
2064 int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
2065 int width = gspca_dev->width;
2066 int height = gspca_dev->height;
2067 u8 fmt, scale = 0;
2068
Brian Johnson26e744b2009-07-19 05:52:58 -03002069 jpeg_define(sd->jpeg_hdr, height, width,
2070 0x21);
Jean-François Moine4c632e42012-03-19 04:35:34 -03002071 jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
Brian Johnson26e744b2009-07-19 05:52:58 -03002072
2073 if (mode & MODE_RAW)
2074 fmt = 0x2d;
2075 else if (mode & MODE_JPEG)
Jean-François Moine4c632e42012-03-19 04:35:34 -03002076 fmt = 0x24;
Brian Johnson26e744b2009-07-19 05:52:58 -03002077 else
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002078 fmt = 0x2f; /* YUV 420 */
Jean-François Moine4c632e42012-03-19 04:35:34 -03002079 sd->fmt = fmt;
Brian Johnson26e744b2009-07-19 05:52:58 -03002080
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002081 switch (mode & SCALE_MASK) {
2082 case SCALE_1280x1024:
Brian Johnson26e744b2009-07-19 05:52:58 -03002083 scale = 0xc0;
Joe Perches91f58422011-08-21 19:56:55 -03002084 pr_info("Set 1280x1024\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002085 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002086 case SCALE_640x480:
Brian Johnson26e744b2009-07-19 05:52:58 -03002087 scale = 0x80;
Joe Perches91f58422011-08-21 19:56:55 -03002088 pr_info("Set 640x480\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002089 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002090 case SCALE_320x240:
Brian Johnson26e744b2009-07-19 05:52:58 -03002091 scale = 0x90;
Joe Perches91f58422011-08-21 19:56:55 -03002092 pr_info("Set 320x240\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002093 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002094 case SCALE_160x120:
Brian Johnson26e744b2009-07-19 05:52:58 -03002095 scale = 0xa0;
Joe Perches91f58422011-08-21 19:56:55 -03002096 pr_info("Set 160x120\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002097 break;
2098 }
2099
2100 configure_sensor_output(gspca_dev, mode);
Jean-François Moine9a731a32010-06-04 05:26:42 -03002101 reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
2102 reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
Brian Johnson26e744b2009-07-19 05:52:58 -03002103 reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
2104 reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
2105 reg_w1(gspca_dev, 0x1189, scale);
2106 reg_w1(gspca_dev, 0x10e0, fmt);
2107
2108 set_cmatrix(gspca_dev);
2109 set_gamma(gspca_dev);
2110 set_redblue(gspca_dev);
2111 set_gain(gspca_dev);
2112 set_exposure(gspca_dev);
2113 set_hvflip(gspca_dev);
2114
Brian Johnson0c045eb2010-03-16 13:58:27 -03002115 reg_w1(gspca_dev, 0x1007, 0x20);
Jean-François Moineccbaba42012-03-19 04:51:30 -03002116 reg_w1(gspca_dev, 0x1061, 0x03);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002117
2118 /* if JPEG, prepare the compression quality update */
2119 if (mode & MODE_JPEG) {
2120 sd->pktsz = sd->npkt = 0;
2121 sd->nchg = 0;
2122 sd->work_thread =
2123 create_singlethread_workqueue(KBUILD_MODNAME);
2124 }
2125
Jean-François Moinefe86ec72012-03-19 04:32:15 -03002126 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03002127}
2128
2129static void sd_stopN(struct gspca_dev *gspca_dev)
2130{
Brian Johnson0c045eb2010-03-16 13:58:27 -03002131 reg_w1(gspca_dev, 0x1007, 0x00);
Jean-François Moineccbaba42012-03-19 04:51:30 -03002132 reg_w1(gspca_dev, 0x1061, 0x01);
Brian Johnson26e744b2009-07-19 05:52:58 -03002133}
2134
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002135/* called on streamoff with alt==0 and on disconnect */
2136/* the usb_lock is held at entry - restore on exit */
2137static void sd_stop0(struct gspca_dev *gspca_dev)
2138{
2139 struct sd *sd = (struct sd *) gspca_dev;
2140
2141 if (sd->work_thread != NULL) {
2142 mutex_unlock(&gspca_dev->usb_lock);
2143 destroy_workqueue(sd->work_thread);
2144 mutex_lock(&gspca_dev->usb_lock);
2145 sd->work_thread = NULL;
2146 }
2147}
2148
Brian Johnsone1430472009-09-02 12:39:41 -03002149static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
Brian Johnson26e744b2009-07-19 05:52:58 -03002150{
2151 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnsone1430472009-09-02 12:39:41 -03002152 s16 new_exp;
Brian Johnson26e744b2009-07-19 05:52:58 -03002153
2154 /*
2155 * some hardcoded values are present
2156 * like those for maximal/minimal exposure
2157 * and exposure steps
2158 */
2159 if (avg_lum < MIN_AVG_LUM) {
Jean-François Moinec5224d82012-03-19 04:30:07 -03002160 if (sd->ctrls[EXPOSURE].val > 0x1770)
Brian Johnson26e744b2009-07-19 05:52:58 -03002161 return;
2162
Jean-François Moinec5224d82012-03-19 04:30:07 -03002163 new_exp = sd->ctrls[EXPOSURE].val + sd->exposure_step;
Brian Johnson26e744b2009-07-19 05:52:58 -03002164 if (new_exp > 0x1770)
2165 new_exp = 0x1770;
2166 if (new_exp < 0x10)
2167 new_exp = 0x10;
Jean-François Moinec5224d82012-03-19 04:30:07 -03002168 sd->ctrls[EXPOSURE].val = new_exp;
Brian Johnson26e744b2009-07-19 05:52:58 -03002169 set_exposure(gspca_dev);
2170
2171 sd->older_step = sd->old_step;
2172 sd->old_step = 1;
2173
2174 if (sd->old_step ^ sd->older_step)
2175 sd->exposure_step /= 2;
2176 else
2177 sd->exposure_step += 2;
2178 }
2179 if (avg_lum > MAX_AVG_LUM) {
Jean-François Moinec5224d82012-03-19 04:30:07 -03002180 if (sd->ctrls[EXPOSURE].val < 0x10)
Brian Johnson26e744b2009-07-19 05:52:58 -03002181 return;
Jean-François Moinec5224d82012-03-19 04:30:07 -03002182 new_exp = sd->ctrls[EXPOSURE].val - sd->exposure_step;
Brian Johnson26e744b2009-07-19 05:52:58 -03002183 if (new_exp > 0x1700)
2184 new_exp = 0x1770;
2185 if (new_exp < 0x10)
2186 new_exp = 0x10;
Jean-François Moinec5224d82012-03-19 04:30:07 -03002187 sd->ctrls[EXPOSURE].val = new_exp;
Brian Johnson26e744b2009-07-19 05:52:58 -03002188 set_exposure(gspca_dev);
2189 sd->older_step = sd->old_step;
2190 sd->old_step = 0;
2191
2192 if (sd->old_step ^ sd->older_step)
2193 sd->exposure_step /= 2;
2194 else
2195 sd->exposure_step += 2;
2196 }
2197}
2198
Brian Johnsone1430472009-09-02 12:39:41 -03002199static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
2200{
2201 struct sd *sd = (struct sd *) gspca_dev;
2202
2203 if (avg_lum < MIN_AVG_LUM) {
Jean-François Moinec5224d82012-03-19 04:30:07 -03002204 if (sd->ctrls[GAIN].val + 1 <= 28) {
2205 sd->ctrls[GAIN].val++;
Brian Johnsone1430472009-09-02 12:39:41 -03002206 set_gain(gspca_dev);
2207 }
2208 }
2209 if (avg_lum > MAX_AVG_LUM) {
Jean-François Moinec5224d82012-03-19 04:30:07 -03002210 if (sd->ctrls[GAIN].val > 0) {
2211 sd->ctrls[GAIN].val--;
Brian Johnsone1430472009-09-02 12:39:41 -03002212 set_gain(gspca_dev);
2213 }
2214 }
2215}
2216
2217static void sd_dqcallback(struct gspca_dev *gspca_dev)
2218{
2219 struct sd *sd = (struct sd *) gspca_dev;
2220 int avg_lum;
2221
Jean-François Moinec5224d82012-03-19 04:30:07 -03002222 if (!sd->ctrls[AUTOGAIN].val)
Brian Johnsone1430472009-09-02 12:39:41 -03002223 return;
2224
2225 avg_lum = atomic_read(&sd->avg_lum);
2226 if (sd->sensor == SENSOR_SOI968)
2227 do_autogain(gspca_dev, avg_lum);
2228 else
2229 do_autoexposure(gspca_dev, avg_lum);
2230}
2231
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002232/* JPEG quality update */
2233/* This function is executed from a work queue. */
2234static void qual_upd(struct work_struct *work)
2235{
2236 struct sd *sd = container_of(work, struct sd, work);
2237 struct gspca_dev *gspca_dev = &sd->gspca_dev;
2238
2239 mutex_lock(&gspca_dev->usb_lock);
2240 PDEBUG(D_STREAM, "qual_upd %d%%", sd->ctrls[QUALITY].val);
2241 set_quality(gspca_dev);
2242 mutex_unlock(&gspca_dev->usb_lock);
2243}
2244
Jean-François Moine28566432010-10-01 07:33:26 -03002245#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002246static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
2247 u8 *data, /* interrupt packet */
2248 int len) /* interrupt packet length */
2249{
2250 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03002251
Brian Johnson33ddc162010-04-18 21:42:40 -03002252 if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
Jean-François Moineff38d582012-03-19 04:55:16 -03002253 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
2254 input_sync(gspca_dev->input_dev);
2255 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
2256 input_sync(gspca_dev->input_dev);
2257 return 0;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002258 }
Jean-François Moineff38d582012-03-19 04:55:16 -03002259 return -EINVAL;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002260}
2261#endif
2262
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002263/* check the JPEG compression */
2264static void transfer_check(struct gspca_dev *gspca_dev,
2265 u8 *data)
2266{
2267 struct sd *sd = (struct sd *) gspca_dev;
2268 int new_qual, r;
2269
2270 new_qual = 0;
2271
2272 /* if USB error, discard the frame and decrease the quality */
2273 if (data[6] & 0x08) { /* USB FIFO full */
2274 gspca_dev->last_packet_type = DISCARD_PACKET;
2275 new_qual = -5;
2276 } else {
2277
2278 /* else, compute the filling rate and a new JPEG quality */
2279 r = (sd->pktsz * 100) /
2280 (sd->npkt *
2281 gspca_dev->urb[0]->iso_frame_desc[0].length);
2282 if (r >= 85)
2283 new_qual = -3;
2284 else if (r < 75)
2285 new_qual = 2;
2286 }
2287 if (new_qual != 0) {
2288 sd->nchg += new_qual;
2289 if (sd->nchg < -6 || sd->nchg >= 12) {
2290 sd->nchg = 0;
2291 new_qual += sd->ctrls[QUALITY].val;
2292 if (new_qual < QUALITY_MIN)
2293 new_qual = QUALITY_MIN;
2294 else if (new_qual > QUALITY_MAX)
2295 new_qual = QUALITY_MAX;
2296 if (new_qual != sd->ctrls[QUALITY].val) {
2297 sd->ctrls[QUALITY].val = new_qual;
2298 queue_work(sd->work_thread, &sd->work);
2299 }
2300 }
2301 } else {
2302 sd->nchg = 0;
2303 }
2304 sd->pktsz = sd->npkt = 0;
2305}
2306
Brian Johnson26e744b2009-07-19 05:52:58 -03002307static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Brian Johnson26e744b2009-07-19 05:52:58 -03002308 u8 *data, /* isoc packet */
2309 int len) /* iso packet length */
2310{
2311 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03002312 int avg_lum, is_jpeg;
Jean-François Moinedae1de62012-03-24 09:20:25 -03002313 static const u8 frame_header[] =
Brian Johnson26e744b2009-07-19 05:52:58 -03002314 {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
Jean-François Moineff38d582012-03-19 04:55:16 -03002315
2316 is_jpeg = (sd->fmt & 0x03) == 0;
Jean-François Moine1f42df02012-03-19 04:22:44 -03002317 if (len >= 64 && memcmp(data, frame_header, 6) == 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03002318 avg_lum = ((data[35] >> 2) & 3) |
2319 (data[20] << 2) |
2320 (data[19] << 10);
2321 avg_lum += ((data[35] >> 4) & 3) |
2322 (data[22] << 2) |
2323 (data[21] << 10);
2324 avg_lum += ((data[35] >> 6) & 3) |
2325 (data[24] << 2) |
2326 (data[23] << 10);
2327 avg_lum += (data[36] & 3) |
2328 (data[26] << 2) |
2329 (data[25] << 10);
2330 avg_lum += ((data[36] >> 2) & 3) |
2331 (data[28] << 2) |
2332 (data[27] << 10);
2333 avg_lum += ((data[36] >> 4) & 3) |
2334 (data[30] << 2) |
2335 (data[29] << 10);
2336 avg_lum += ((data[36] >> 6) & 3) |
2337 (data[32] << 2) |
2338 (data[31] << 10);
2339 avg_lum += ((data[44] >> 4) & 3) |
2340 (data[34] << 2) |
2341 (data[33] << 10);
2342 avg_lum >>= 9;
2343 atomic_set(&sd->avg_lum, avg_lum);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002344
Jean-François Moineff38d582012-03-19 04:55:16 -03002345 if (is_jpeg)
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002346 transfer_check(gspca_dev, data);
2347
Jean-François Moine04d174e2010-09-13 05:22:37 -03002348 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Jean-François Moine1f42df02012-03-19 04:22:44 -03002349 len -= 64;
2350 if (len == 0)
2351 return;
2352 data += 64;
Brian Johnson26e744b2009-07-19 05:52:58 -03002353 }
2354 if (gspca_dev->last_packet_type == LAST_PACKET) {
Jean-François Moineff38d582012-03-19 04:55:16 -03002355 if (is_jpeg) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002356 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002357 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002358 gspca_frame_add(gspca_dev, INTER_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002359 data, len);
2360 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002361 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002362 data, len);
2363 }
2364 } else {
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002365 /* if JPEG, count the packets and their size */
Jean-François Moineff38d582012-03-19 04:55:16 -03002366 if (is_jpeg) {
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002367 sd->npkt++;
2368 sd->pktsz += len;
2369 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002370 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Brian Johnson26e744b2009-07-19 05:52:58 -03002371 }
2372}
2373
2374/* sub-driver description */
2375static const struct sd_desc sd_desc = {
Jean-François Moineff38d582012-03-19 04:55:16 -03002376 .name = KBUILD_MODNAME,
Brian Johnson26e744b2009-07-19 05:52:58 -03002377 .ctrls = sd_ctrls,
2378 .nctrls = ARRAY_SIZE(sd_ctrls),
2379 .config = sd_config,
2380 .init = sd_init,
Hans de Goeded80dd5d2012-01-01 16:03:37 -03002381 .isoc_init = sd_isoc_init,
Brian Johnson26e744b2009-07-19 05:52:58 -03002382 .start = sd_start,
2383 .stopN = sd_stopN,
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002384 .stop0 = sd_stop0,
Brian Johnson26e744b2009-07-19 05:52:58 -03002385 .pkt_scan = sd_pkt_scan,
Jean-François Moine28566432010-10-01 07:33:26 -03002386#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002387 .int_pkt_scan = sd_int_pkt_scan,
2388#endif
Brian Johnsone1430472009-09-02 12:39:41 -03002389 .dq_callback = sd_dqcallback,
Brian Johnson26e744b2009-07-19 05:52:58 -03002390#ifdef CONFIG_VIDEO_ADV_DEBUG
2391 .set_register = sd_dbg_s_register,
2392 .get_register = sd_dbg_g_register,
2393#endif
2394 .get_chip_ident = sd_chip_ident,
2395};
2396
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002397#define SN9C20X(sensor, i2c_addr, flags) \
Brian Johnson0c045eb2010-03-16 13:58:27 -03002398 .driver_info = ((flags & 0xff) << 16) \
Brian Johnson26e744b2009-07-19 05:52:58 -03002399 | (SENSOR_ ## sensor << 8) \
2400 | (i2c_addr)
2401
Jean-François Moine95c967c2011-01-13 05:20:29 -03002402static const struct usb_device_id device_table[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03002403 {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
2404 {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
2405 {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002406 {USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002407 {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, LED_REVERSE)},
2408 {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30,
2409 (FLIP_DETECT | HAS_NO_BUTTON))},
Brian Johnson26e744b2009-07-19 05:52:58 -03002410 {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
2411 {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
2412 {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
2413 {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)},
Hans de Goede779b51f2011-02-16 08:17:36 -03002414 {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, FLIP_DETECT)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002415 {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)},
2416 {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)},
2417 {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
2418 {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002419 {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002420 {USB_DEVICE(0x0c45, 0x628c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002421 {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)},
2422 {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
2423 {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
2424 {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
Frank Schaefer114cfbd2011-09-23 05:05:37 -03002425 {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, LED_REVERSE)},
Hans de Goedeb39e0cb2011-02-16 08:33:16 -03002426 {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, LED_REVERSE)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002427 {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
2428 {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
2429 {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
2430 {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002431 {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)},
2432 {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002433 {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
2434 {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)},
2435 {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)},
2436 {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002437 {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002438 {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)},
2439 {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)},
2440 {}
2441};
2442MODULE_DEVICE_TABLE(usb, device_table);
2443
2444/* -- device connect -- */
2445static int sd_probe(struct usb_interface *intf,
2446 const struct usb_device_id *id)
2447{
2448 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
2449 THIS_MODULE);
2450}
2451
Brian Johnson26e744b2009-07-19 05:52:58 -03002452static struct usb_driver sd_driver = {
Jean-François Moineff38d582012-03-19 04:55:16 -03002453 .name = KBUILD_MODNAME,
Brian Johnson26e744b2009-07-19 05:52:58 -03002454 .id_table = device_table,
2455 .probe = sd_probe,
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002456 .disconnect = gspca_disconnect,
Brian Johnson26e744b2009-07-19 05:52:58 -03002457#ifdef CONFIG_PM
2458 .suspend = gspca_suspend,
2459 .resume = gspca_resume,
2460 .reset_resume = gspca_resume,
2461#endif
2462};
2463
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -08002464module_usb_driver(sd_driver);