blob: d0ee899584a9f1188d44613ec6f21228a0e94e7a [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
Brian Johnson7ddaac72010-03-16 13:58:27 -030030#include <linux/dmi.h>
Mauro Carvalho Chehabc15b95e2009-07-19 18:03:23 -030031
Brian Johnson26e744b2009-07-19 05:52:58 -030032MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, "
33 "microdia project <microdia@googlegroups.com>");
34MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver");
35MODULE_LICENSE("GPL");
36
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -030037/*
38 * Pixel format private data
39 */
40#define SCALE_MASK 0x0f
41#define SCALE_160x120 0
42#define SCALE_320x240 1
43#define SCALE_640x480 2
44#define SCALE_1280x1024 3
Brian Johnson26e744b2009-07-19 05:52:58 -030045#define MODE_RAW 0x10
46#define MODE_JPEG 0x20
47#define MODE_SXGA 0x80
48
49#define SENSOR_OV9650 0
50#define SENSOR_OV9655 1
51#define SENSOR_SOI968 2
52#define SENSOR_OV7660 3
53#define SENSOR_OV7670 4
54#define SENSOR_MT9V011 5
55#define SENSOR_MT9V111 6
56#define SENSOR_MT9V112 7
57#define SENSOR_MT9M001 8
58#define SENSOR_MT9M111 9
Brian Johnsone99ac542010-03-16 13:58:28 -030059#define SENSOR_MT9M112 10
60#define SENSOR_HV7131R 11
Jean-François Moine9637c652012-03-24 09:16:14 -030061#define SENSOR_MT9VPRB 12
Brian Johnson26e744b2009-07-19 05:52:58 -030062
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030063/* camera flags */
Brian Johnson33ddc162010-04-18 21:42:40 -030064#define HAS_NO_BUTTON 0x1
Brian Johnson0c045eb2010-03-16 13:58:27 -030065#define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */
Brian Johnson7ddaac72010-03-16 13:58:27 -030066#define FLIP_DETECT 0x4
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030067
Brian Johnson26e744b2009-07-19 05:52:58 -030068/* specific webcam descriptor */
69struct sd {
70 struct gspca_dev gspca_dev;
71
Hans Verkuil63069da2012-05-06 09:28:29 -030072 struct { /* color control cluster */
73 struct v4l2_ctrl *brightness;
74 struct v4l2_ctrl *contrast;
75 struct v4l2_ctrl *saturation;
76 struct v4l2_ctrl *hue;
77 };
78 struct { /* blue/red balance control cluster */
79 struct v4l2_ctrl *blue;
80 struct v4l2_ctrl *red;
81 };
82 struct { /* h/vflip control cluster */
83 struct v4l2_ctrl *hflip;
84 struct v4l2_ctrl *vflip;
85 };
86 struct v4l2_ctrl *gamma;
87 struct { /* autogain and exposure or gain control cluster */
88 struct v4l2_ctrl *autogain;
89 struct v4l2_ctrl *exposure;
90 struct v4l2_ctrl *gain;
91 };
92 struct v4l2_ctrl *jpegqual;
Jean-François Moinec5224d82012-03-19 04:30:07 -030093
Jean-François Moine92dcffc2012-03-19 04:47:24 -030094 struct work_struct work;
95 struct workqueue_struct *work_thread;
96
97 u32 pktsz; /* (used by pkt_scan) */
98 u16 npkt;
99 s8 nchg;
Jean-François Moine4c632e42012-03-19 04:35:34 -0300100 u8 fmt; /* (used for JPEG QTAB update */
101
Brian Johnson26e744b2009-07-19 05:52:58 -0300102#define MIN_AVG_LUM 80
103#define MAX_AVG_LUM 130
104 atomic_t avg_lum;
105 u8 old_step;
106 u8 older_step;
107 u8 exposure_step;
108
Brian Johnson26e744b2009-07-19 05:52:58 -0300109 u8 i2c_addr;
Jean-François Moinec4407fe2012-03-24 09:23:56 -0300110 u8 i2c_intf;
Brian Johnson26e744b2009-07-19 05:52:58 -0300111 u8 sensor;
112 u8 hstart;
113 u8 vstart;
114
Jean-François Moine9a731a32010-06-04 05:26:42 -0300115 u8 jpeg_hdr[JPEG_HDR_SZ];
Brian Johnson26e744b2009-07-19 05:52:58 -0300116
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -0300117 u8 flags;
Brian Johnson26e744b2009-07-19 05:52:58 -0300118};
119
Jean-François Moine92dcffc2012-03-19 04:47:24 -0300120static void qual_upd(struct work_struct *work);
121
Joe Perches58aa68c2009-09-02 01:12:13 -0300122struct i2c_reg_u8 {
123 u8 reg;
124 u8 val;
125};
126
127struct i2c_reg_u16 {
128 u8 reg;
129 u16 val;
130};
131
Brian Johnson7ddaac72010-03-16 13:58:27 -0300132static const struct dmi_system_id flip_dmi_table[] = {
133 {
134 .ident = "MSI MS-1034",
135 .matches = {
136 DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."),
137 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1034"),
138 DMI_MATCH(DMI_PRODUCT_VERSION, "0341")
139 }
140 },
141 {
142 .ident = "MSI MS-1632",
143 .matches = {
144 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
145 DMI_MATCH(DMI_BOARD_NAME, "MS-1632")
146 }
147 },
Brian Johnsone077f862010-04-05 20:52:52 -0300148 {
Hans de Goedebcc6f662011-02-17 06:27:57 -0300149 .ident = "MSI MS-1633X",
150 .matches = {
151 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
152 DMI_MATCH(DMI_BOARD_NAME, "MS-1633X")
153 }
154 },
155 {
Brian Johnson5d26ed92010-04-10 02:12:46 -0300156 .ident = "MSI MS-1635X",
157 .matches = {
158 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
159 DMI_MATCH(DMI_BOARD_NAME, "MS-1635X")
160 }
161 },
162 {
Brian Johnsone077f862010-04-05 20:52:52 -0300163 .ident = "ASUSTeK W7J",
164 .matches = {
165 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
166 DMI_MATCH(DMI_BOARD_NAME, "W7J ")
167 }
168 },
Brian Johnson7ddaac72010-03-16 13:58:27 -0300169 {}
170};
171
Brian Johnson26e744b2009-07-19 05:52:58 -0300172static const struct v4l2_pix_format vga_mode[] = {
173 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300174 .bytesperline = 160,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300175 .sizeimage = 160 * 120 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300176 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300177 .priv = SCALE_160x120 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300178 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
179 .bytesperline = 160,
180 .sizeimage = 160 * 120,
181 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300182 .priv = SCALE_160x120 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300183 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300184 .bytesperline = 160,
Brian Johnson26e744b2009-07-19 05:52:58 -0300185 .sizeimage = 240 * 120,
186 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300187 .priv = SCALE_160x120},
Brian Johnson26e744b2009-07-19 05:52:58 -0300188 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300189 .bytesperline = 320,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300190 .sizeimage = 320 * 240 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300191 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300192 .priv = SCALE_320x240 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300193 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
194 .bytesperline = 320,
195 .sizeimage = 320 * 240 ,
196 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300197 .priv = SCALE_320x240 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300198 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300199 .bytesperline = 320,
Brian Johnson26e744b2009-07-19 05:52:58 -0300200 .sizeimage = 480 * 240 ,
201 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300202 .priv = SCALE_320x240},
Brian Johnson26e744b2009-07-19 05:52:58 -0300203 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300204 .bytesperline = 640,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300205 .sizeimage = 640 * 480 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300206 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300207 .priv = SCALE_640x480 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300208 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
209 .bytesperline = 640,
210 .sizeimage = 640 * 480,
211 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300212 .priv = SCALE_640x480 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300213 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300214 .bytesperline = 640,
Brian Johnson26e744b2009-07-19 05:52:58 -0300215 .sizeimage = 960 * 480,
216 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300217 .priv = SCALE_640x480},
Brian Johnson26e744b2009-07-19 05:52:58 -0300218};
219
220static const struct v4l2_pix_format sxga_mode[] = {
221 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300222 .bytesperline = 160,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300223 .sizeimage = 160 * 120 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300224 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300225 .priv = SCALE_160x120 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300226 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
227 .bytesperline = 160,
228 .sizeimage = 160 * 120,
229 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300230 .priv = SCALE_160x120 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300231 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300232 .bytesperline = 160,
Brian Johnson26e744b2009-07-19 05:52:58 -0300233 .sizeimage = 240 * 120,
234 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300235 .priv = SCALE_160x120},
Brian Johnson26e744b2009-07-19 05:52:58 -0300236 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300237 .bytesperline = 320,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300238 .sizeimage = 320 * 240 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300239 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300240 .priv = SCALE_320x240 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300241 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
242 .bytesperline = 320,
243 .sizeimage = 320 * 240 ,
244 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300245 .priv = SCALE_320x240 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300246 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300247 .bytesperline = 320,
Brian Johnson26e744b2009-07-19 05:52:58 -0300248 .sizeimage = 480 * 240 ,
249 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300250 .priv = SCALE_320x240},
Brian Johnson26e744b2009-07-19 05:52:58 -0300251 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300252 .bytesperline = 640,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300253 .sizeimage = 640 * 480 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300254 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300255 .priv = SCALE_640x480 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300256 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
257 .bytesperline = 640,
258 .sizeimage = 640 * 480,
259 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300260 .priv = SCALE_640x480 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300261 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300262 .bytesperline = 640,
Brian Johnson26e744b2009-07-19 05:52:58 -0300263 .sizeimage = 960 * 480,
264 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300265 .priv = SCALE_640x480},
Brian Johnson26e744b2009-07-19 05:52:58 -0300266 {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
267 .bytesperline = 1280,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300268 .sizeimage = 1280 * 1024,
Brian Johnson26e744b2009-07-19 05:52:58 -0300269 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300270 .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
Brian Johnson26e744b2009-07-19 05:52:58 -0300271};
272
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -0300273static const struct v4l2_pix_format mono_mode[] = {
274 {160, 120, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
275 .bytesperline = 160,
276 .sizeimage = 160 * 120,
277 .colorspace = V4L2_COLORSPACE_SRGB,
278 .priv = SCALE_160x120 | MODE_RAW},
279 {320, 240, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
280 .bytesperline = 320,
281 .sizeimage = 320 * 240 ,
282 .colorspace = V4L2_COLORSPACE_SRGB,
283 .priv = SCALE_320x240 | MODE_RAW},
284 {640, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
285 .bytesperline = 640,
286 .sizeimage = 640 * 480,
287 .colorspace = V4L2_COLORSPACE_SRGB,
288 .priv = SCALE_640x480 | MODE_RAW},
289 {1280, 1024, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
290 .bytesperline = 1280,
291 .sizeimage = 1280 * 1024,
292 .colorspace = V4L2_COLORSPACE_SRGB,
293 .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
294};
295
Joe Perches58aa68c2009-09-02 01:12:13 -0300296static const s16 hsv_red_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300297 41, 44, 46, 48, 50, 52, 54, 56,
298 58, 60, 62, 64, 66, 68, 70, 72,
299 74, 76, 78, 80, 81, 83, 85, 87,
300 88, 90, 92, 93, 95, 97, 98, 100,
301 101, 102, 104, 105, 107, 108, 109, 110,
302 112, 113, 114, 115, 116, 117, 118, 119,
303 120, 121, 122, 123, 123, 124, 125, 125,
304 126, 127, 127, 128, 128, 129, 129, 129,
305 130, 130, 130, 130, 131, 131, 131, 131,
306 131, 131, 131, 131, 130, 130, 130, 130,
307 129, 129, 129, 128, 128, 127, 127, 126,
308 125, 125, 124, 123, 122, 122, 121, 120,
309 119, 118, 117, 116, 115, 114, 112, 111,
310 110, 109, 107, 106, 105, 103, 102, 101,
311 99, 98, 96, 94, 93, 91, 90, 88,
312 86, 84, 83, 81, 79, 77, 75, 74,
313 72, 70, 68, 66, 64, 62, 60, 58,
314 56, 54, 52, 49, 47, 45, 43, 41,
315 39, 36, 34, 32, 30, 28, 25, 23,
316 21, 19, 16, 14, 12, 9, 7, 5,
317 3, 0, -1, -3, -6, -8, -10, -12,
318 -15, -17, -19, -22, -24, -26, -28, -30,
319 -33, -35, -37, -39, -41, -44, -46, -48,
320 -50, -52, -54, -56, -58, -60, -62, -64,
321 -66, -68, -70, -72, -74, -76, -78, -80,
322 -81, -83, -85, -87, -88, -90, -92, -93,
323 -95, -97, -98, -100, -101, -102, -104, -105,
324 -107, -108, -109, -110, -112, -113, -114, -115,
325 -116, -117, -118, -119, -120, -121, -122, -123,
326 -123, -124, -125, -125, -126, -127, -127, -128,
327 -128, -128, -128, -128, -128, -128, -128, -128,
328 -128, -128, -128, -128, -128, -128, -128, -128,
329 -128, -128, -128, -128, -128, -128, -128, -128,
330 -128, -127, -127, -126, -125, -125, -124, -123,
331 -122, -122, -121, -120, -119, -118, -117, -116,
332 -115, -114, -112, -111, -110, -109, -107, -106,
333 -105, -103, -102, -101, -99, -98, -96, -94,
334 -93, -91, -90, -88, -86, -84, -83, -81,
335 -79, -77, -75, -74, -72, -70, -68, -66,
336 -64, -62, -60, -58, -56, -54, -52, -49,
337 -47, -45, -43, -41, -39, -36, -34, -32,
338 -30, -28, -25, -23, -21, -19, -16, -14,
339 -12, -9, -7, -5, -3, 0, 1, 3,
340 6, 8, 10, 12, 15, 17, 19, 22,
341 24, 26, 28, 30, 33, 35, 37, 39, 41
342};
343
Joe Perches58aa68c2009-09-02 01:12:13 -0300344static const s16 hsv_red_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300345 82, 80, 78, 76, 74, 73, 71, 69,
346 67, 65, 63, 61, 58, 56, 54, 52,
347 50, 48, 46, 44, 41, 39, 37, 35,
348 32, 30, 28, 26, 23, 21, 19, 16,
349 14, 12, 10, 7, 5, 3, 0, -1,
350 -3, -6, -8, -10, -13, -15, -17, -19,
351 -22, -24, -26, -29, -31, -33, -35, -38,
352 -40, -42, -44, -46, -48, -51, -53, -55,
353 -57, -59, -61, -63, -65, -67, -69, -71,
354 -73, -75, -77, -79, -81, -82, -84, -86,
355 -88, -89, -91, -93, -94, -96, -98, -99,
356 -101, -102, -104, -105, -106, -108, -109, -110,
357 -112, -113, -114, -115, -116, -117, -119, -120,
358 -120, -121, -122, -123, -124, -125, -126, -126,
359 -127, -128, -128, -128, -128, -128, -128, -128,
360 -128, -128, -128, -128, -128, -128, -128, -128,
361 -128, -128, -128, -128, -128, -128, -128, -128,
362 -128, -128, -128, -128, -128, -128, -128, -128,
363 -127, -127, -126, -125, -125, -124, -123, -122,
364 -121, -120, -119, -118, -117, -116, -115, -114,
365 -113, -111, -110, -109, -107, -106, -105, -103,
366 -102, -100, -99, -97, -96, -94, -92, -91,
367 -89, -87, -85, -84, -82, -80, -78, -76,
368 -74, -73, -71, -69, -67, -65, -63, -61,
369 -58, -56, -54, -52, -50, -48, -46, -44,
370 -41, -39, -37, -35, -32, -30, -28, -26,
371 -23, -21, -19, -16, -14, -12, -10, -7,
372 -5, -3, 0, 1, 3, 6, 8, 10,
373 13, 15, 17, 19, 22, 24, 26, 29,
374 31, 33, 35, 38, 40, 42, 44, 46,
375 48, 51, 53, 55, 57, 59, 61, 63,
376 65, 67, 69, 71, 73, 75, 77, 79,
377 81, 82, 84, 86, 88, 89, 91, 93,
378 94, 96, 98, 99, 101, 102, 104, 105,
379 106, 108, 109, 110, 112, 113, 114, 115,
380 116, 117, 119, 120, 120, 121, 122, 123,
381 124, 125, 126, 126, 127, 128, 128, 129,
382 129, 130, 130, 131, 131, 131, 131, 132,
383 132, 132, 132, 132, 132, 132, 132, 132,
384 132, 132, 132, 131, 131, 131, 130, 130,
385 130, 129, 129, 128, 127, 127, 126, 125,
386 125, 124, 123, 122, 121, 120, 119, 118,
387 117, 116, 115, 114, 113, 111, 110, 109,
388 107, 106, 105, 103, 102, 100, 99, 97,
389 96, 94, 92, 91, 89, 87, 85, 84, 82
390};
391
Joe Perches58aa68c2009-09-02 01:12:13 -0300392static const s16 hsv_green_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300393 -124, -124, -125, -125, -125, -125, -125, -125,
394 -125, -126, -126, -125, -125, -125, -125, -125,
395 -125, -124, -124, -124, -123, -123, -122, -122,
396 -121, -121, -120, -120, -119, -118, -117, -117,
397 -116, -115, -114, -113, -112, -111, -110, -109,
398 -108, -107, -105, -104, -103, -102, -100, -99,
399 -98, -96, -95, -93, -92, -91, -89, -87,
400 -86, -84, -83, -81, -79, -77, -76, -74,
401 -72, -70, -69, -67, -65, -63, -61, -59,
402 -57, -55, -53, -51, -49, -47, -45, -43,
403 -41, -39, -37, -35, -33, -30, -28, -26,
404 -24, -22, -20, -18, -15, -13, -11, -9,
405 -7, -4, -2, 0, 1, 3, 6, 8,
406 10, 12, 14, 17, 19, 21, 23, 25,
407 27, 29, 32, 34, 36, 38, 40, 42,
408 44, 46, 48, 50, 52, 54, 56, 58,
409 60, 62, 64, 66, 68, 70, 71, 73,
410 75, 77, 78, 80, 82, 83, 85, 87,
411 88, 90, 91, 93, 94, 96, 97, 98,
412 100, 101, 102, 104, 105, 106, 107, 108,
413 109, 111, 112, 113, 113, 114, 115, 116,
414 117, 118, 118, 119, 120, 120, 121, 122,
415 122, 123, 123, 124, 124, 124, 125, 125,
416 125, 125, 125, 125, 125, 126, 126, 125,
417 125, 125, 125, 125, 125, 124, 124, 124,
418 123, 123, 122, 122, 121, 121, 120, 120,
419 119, 118, 117, 117, 116, 115, 114, 113,
420 112, 111, 110, 109, 108, 107, 105, 104,
421 103, 102, 100, 99, 98, 96, 95, 93,
422 92, 91, 89, 87, 86, 84, 83, 81,
423 79, 77, 76, 74, 72, 70, 69, 67,
424 65, 63, 61, 59, 57, 55, 53, 51,
425 49, 47, 45, 43, 41, 39, 37, 35,
426 33, 30, 28, 26, 24, 22, 20, 18,
427 15, 13, 11, 9, 7, 4, 2, 0,
428 -1, -3, -6, -8, -10, -12, -14, -17,
429 -19, -21, -23, -25, -27, -29, -32, -34,
430 -36, -38, -40, -42, -44, -46, -48, -50,
431 -52, -54, -56, -58, -60, -62, -64, -66,
432 -68, -70, -71, -73, -75, -77, -78, -80,
433 -82, -83, -85, -87, -88, -90, -91, -93,
434 -94, -96, -97, -98, -100, -101, -102, -104,
435 -105, -106, -107, -108, -109, -111, -112, -113,
436 -113, -114, -115, -116, -117, -118, -118, -119,
437 -120, -120, -121, -122, -122, -123, -123, -124, -124
438};
439
Joe Perches58aa68c2009-09-02 01:12:13 -0300440static const s16 hsv_green_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300441 -100, -99, -98, -97, -95, -94, -93, -91,
442 -90, -89, -87, -86, -84, -83, -81, -80,
443 -78, -76, -75, -73, -71, -70, -68, -66,
444 -64, -63, -61, -59, -57, -55, -53, -51,
445 -49, -48, -46, -44, -42, -40, -38, -36,
446 -34, -32, -30, -27, -25, -23, -21, -19,
447 -17, -15, -13, -11, -9, -7, -4, -2,
448 0, 1, 3, 5, 7, 9, 11, 14,
449 16, 18, 20, 22, 24, 26, 28, 30,
450 32, 34, 36, 38, 40, 42, 44, 46,
451 48, 50, 52, 54, 56, 58, 59, 61,
452 63, 65, 67, 68, 70, 72, 74, 75,
453 77, 78, 80, 82, 83, 85, 86, 88,
454 89, 90, 92, 93, 95, 96, 97, 98,
455 100, 101, 102, 103, 104, 105, 106, 107,
456 108, 109, 110, 111, 112, 112, 113, 114,
457 115, 115, 116, 116, 117, 117, 118, 118,
458 119, 119, 119, 120, 120, 120, 120, 120,
459 121, 121, 121, 121, 121, 121, 120, 120,
460 120, 120, 120, 119, 119, 119, 118, 118,
461 117, 117, 116, 116, 115, 114, 114, 113,
462 112, 111, 111, 110, 109, 108, 107, 106,
463 105, 104, 103, 102, 100, 99, 98, 97,
464 95, 94, 93, 91, 90, 89, 87, 86,
465 84, 83, 81, 80, 78, 76, 75, 73,
466 71, 70, 68, 66, 64, 63, 61, 59,
467 57, 55, 53, 51, 49, 48, 46, 44,
468 42, 40, 38, 36, 34, 32, 30, 27,
469 25, 23, 21, 19, 17, 15, 13, 11,
470 9, 7, 4, 2, 0, -1, -3, -5,
471 -7, -9, -11, -14, -16, -18, -20, -22,
472 -24, -26, -28, -30, -32, -34, -36, -38,
473 -40, -42, -44, -46, -48, -50, -52, -54,
474 -56, -58, -59, -61, -63, -65, -67, -68,
475 -70, -72, -74, -75, -77, -78, -80, -82,
476 -83, -85, -86, -88, -89, -90, -92, -93,
477 -95, -96, -97, -98, -100, -101, -102, -103,
478 -104, -105, -106, -107, -108, -109, -110, -111,
479 -112, -112, -113, -114, -115, -115, -116, -116,
480 -117, -117, -118, -118, -119, -119, -119, -120,
481 -120, -120, -120, -120, -121, -121, -121, -121,
482 -121, -121, -120, -120, -120, -120, -120, -119,
483 -119, -119, -118, -118, -117, -117, -116, -116,
484 -115, -114, -114, -113, -112, -111, -111, -110,
485 -109, -108, -107, -106, -105, -104, -103, -102, -100
486};
487
Joe Perches58aa68c2009-09-02 01:12:13 -0300488static const s16 hsv_blue_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300489 112, 113, 114, 114, 115, 116, 117, 117,
490 118, 118, 119, 119, 120, 120, 120, 121,
491 121, 121, 122, 122, 122, 122, 122, 122,
492 122, 122, 122, 122, 122, 122, 121, 121,
493 121, 120, 120, 120, 119, 119, 118, 118,
494 117, 116, 116, 115, 114, 113, 113, 112,
495 111, 110, 109, 108, 107, 106, 105, 104,
496 103, 102, 100, 99, 98, 97, 95, 94,
497 93, 91, 90, 88, 87, 85, 84, 82,
498 80, 79, 77, 76, 74, 72, 70, 69,
499 67, 65, 63, 61, 60, 58, 56, 54,
500 52, 50, 48, 46, 44, 42, 40, 38,
501 36, 34, 32, 30, 28, 26, 24, 22,
502 19, 17, 15, 13, 11, 9, 7, 5,
503 2, 0, -1, -3, -5, -7, -9, -12,
504 -14, -16, -18, -20, -22, -24, -26, -28,
505 -31, -33, -35, -37, -39, -41, -43, -45,
506 -47, -49, -51, -53, -54, -56, -58, -60,
507 -62, -64, -66, -67, -69, -71, -73, -74,
508 -76, -78, -79, -81, -83, -84, -86, -87,
509 -89, -90, -92, -93, -94, -96, -97, -98,
510 -99, -101, -102, -103, -104, -105, -106, -107,
511 -108, -109, -110, -111, -112, -113, -114, -114,
512 -115, -116, -117, -117, -118, -118, -119, -119,
513 -120, -120, -120, -121, -121, -121, -122, -122,
514 -122, -122, -122, -122, -122, -122, -122, -122,
515 -122, -122, -121, -121, -121, -120, -120, -120,
516 -119, -119, -118, -118, -117, -116, -116, -115,
517 -114, -113, -113, -112, -111, -110, -109, -108,
518 -107, -106, -105, -104, -103, -102, -100, -99,
519 -98, -97, -95, -94, -93, -91, -90, -88,
520 -87, -85, -84, -82, -80, -79, -77, -76,
521 -74, -72, -70, -69, -67, -65, -63, -61,
522 -60, -58, -56, -54, -52, -50, -48, -46,
523 -44, -42, -40, -38, -36, -34, -32, -30,
524 -28, -26, -24, -22, -19, -17, -15, -13,
525 -11, -9, -7, -5, -2, 0, 1, 3,
526 5, 7, 9, 12, 14, 16, 18, 20,
527 22, 24, 26, 28, 31, 33, 35, 37,
528 39, 41, 43, 45, 47, 49, 51, 53,
529 54, 56, 58, 60, 62, 64, 66, 67,
530 69, 71, 73, 74, 76, 78, 79, 81,
531 83, 84, 86, 87, 89, 90, 92, 93,
532 94, 96, 97, 98, 99, 101, 102, 103,
533 104, 105, 106, 107, 108, 109, 110, 111, 112
534};
535
Joe Perches58aa68c2009-09-02 01:12:13 -0300536static const s16 hsv_blue_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300537 -11, -13, -15, -17, -19, -21, -23, -25,
538 -27, -29, -31, -33, -35, -37, -39, -41,
539 -43, -45, -46, -48, -50, -52, -54, -55,
540 -57, -59, -61, -62, -64, -66, -67, -69,
541 -71, -72, -74, -75, -77, -78, -80, -81,
542 -83, -84, -86, -87, -88, -90, -91, -92,
543 -93, -95, -96, -97, -98, -99, -100, -101,
544 -102, -103, -104, -105, -106, -106, -107, -108,
545 -109, -109, -110, -111, -111, -112, -112, -113,
546 -113, -114, -114, -114, -115, -115, -115, -115,
547 -116, -116, -116, -116, -116, -116, -116, -116,
548 -116, -115, -115, -115, -115, -114, -114, -114,
549 -113, -113, -112, -112, -111, -111, -110, -110,
550 -109, -108, -108, -107, -106, -105, -104, -103,
551 -102, -101, -100, -99, -98, -97, -96, -95,
552 -94, -93, -91, -90, -89, -88, -86, -85,
553 -84, -82, -81, -79, -78, -76, -75, -73,
554 -71, -70, -68, -67, -65, -63, -62, -60,
555 -58, -56, -55, -53, -51, -49, -47, -45,
556 -44, -42, -40, -38, -36, -34, -32, -30,
557 -28, -26, -24, -22, -20, -18, -16, -14,
558 -12, -10, -8, -6, -4, -2, 0, 1,
559 3, 5, 7, 9, 11, 13, 15, 17,
560 19, 21, 23, 25, 27, 29, 31, 33,
561 35, 37, 39, 41, 43, 45, 46, 48,
562 50, 52, 54, 55, 57, 59, 61, 62,
563 64, 66, 67, 69, 71, 72, 74, 75,
564 77, 78, 80, 81, 83, 84, 86, 87,
565 88, 90, 91, 92, 93, 95, 96, 97,
566 98, 99, 100, 101, 102, 103, 104, 105,
567 106, 106, 107, 108, 109, 109, 110, 111,
568 111, 112, 112, 113, 113, 114, 114, 114,
569 115, 115, 115, 115, 116, 116, 116, 116,
570 116, 116, 116, 116, 116, 115, 115, 115,
571 115, 114, 114, 114, 113, 113, 112, 112,
572 111, 111, 110, 110, 109, 108, 108, 107,
573 106, 105, 104, 103, 102, 101, 100, 99,
574 98, 97, 96, 95, 94, 93, 91, 90,
575 89, 88, 86, 85, 84, 82, 81, 79,
576 78, 76, 75, 73, 71, 70, 68, 67,
577 65, 63, 62, 60, 58, 56, 55, 53,
578 51, 49, 47, 45, 44, 42, 40, 38,
579 36, 34, 32, 30, 28, 26, 24, 22,
580 20, 18, 16, 14, 12, 10, 8, 6,
581 4, 2, 0, -1, -3, -5, -7, -9, -11
582};
583
Jean-François Moinedae1de62012-03-24 09:20:25 -0300584static const u16 bridge_init[][2] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300585 {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c},
586 {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40},
587 {0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10},
588 {0x106b, 0x08}, {0x1188, 0x87}, {0x11a1, 0x00},
589 {0x11a2, 0x00}, {0x11a3, 0x6a}, {0x11a4, 0x50},
590 {0x11ab, 0x00}, {0x11ac, 0x00}, {0x11ad, 0x50},
591 {0x11ae, 0x3c}, {0x118a, 0x04}, {0x0395, 0x04},
592 {0x11b8, 0x3a}, {0x118b, 0x0e}, {0x10f7, 0x05},
593 {0x10f8, 0x14}, {0x10fa, 0xff}, {0x10f9, 0x00},
594 {0x11ba, 0x0a}, {0x11a5, 0x2d}, {0x11a6, 0x2d},
595 {0x11a7, 0x3a}, {0x11a8, 0x05}, {0x11a9, 0x04},
596 {0x11aa, 0x3f}, {0x11af, 0x28}, {0x11b0, 0xd8},
597 {0x11b1, 0x14}, {0x11b2, 0xec}, {0x11b3, 0x32},
598 {0x11b4, 0xdd}, {0x11b5, 0x32}, {0x11b6, 0xdd},
599 {0x10e0, 0x2c}, {0x11bc, 0x40}, {0x11bd, 0x01},
600 {0x11be, 0xf0}, {0x11bf, 0x00}, {0x118c, 0x1f},
601 {0x118d, 0x1f}, {0x118e, 0x1f}, {0x118f, 0x1f},
602 {0x1180, 0x01}, {0x1181, 0x00}, {0x1182, 0x01},
Brian Johnson0c045eb2010-03-16 13:58:27 -0300603 {0x1183, 0x00}, {0x1184, 0x50}, {0x1185, 0x80},
604 {0x1007, 0x00}
Brian Johnson26e744b2009-07-19 05:52:58 -0300605};
606
607/* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300608static const u8 ov_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300609 0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */,
610 0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */,
611 0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */,
612 0x30 /* 4x */, 0x31 /* 4.25x */, 0x32 /* 4.5x */, 0x33 /* 4.75x */,
613 0x34 /* 5x */, 0x35 /* 5.25x */, 0x36 /* 5.5x */, 0x37 /* 5.75x */,
614 0x38 /* 6x */, 0x39 /* 6.25x */, 0x3a /* 6.5x */, 0x3b /* 6.75x */,
615 0x3c /* 7x */, 0x3d /* 7.25x */, 0x3e /* 7.5x */, 0x3f /* 7.75x */,
616 0x70 /* 8x */
617};
618
619/* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300620static const u16 micron1_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300621 /* 1x 1.25x 1.5x 1.75x */
622 0x0020, 0x0028, 0x0030, 0x0038,
623 /* 2x 2.25x 2.5x 2.75x */
624 0x00a0, 0x00a4, 0x00a8, 0x00ac,
625 /* 3x 3.25x 3.5x 3.75x */
626 0x00b0, 0x00b4, 0x00b8, 0x00bc,
627 /* 4x 4.25x 4.5x 4.75x */
628 0x00c0, 0x00c4, 0x00c8, 0x00cc,
629 /* 5x 5.25x 5.5x 5.75x */
630 0x00d0, 0x00d4, 0x00d8, 0x00dc,
631 /* 6x 6.25x 6.5x 6.75x */
632 0x00e0, 0x00e4, 0x00e8, 0x00ec,
633 /* 7x 7.25x 7.5x 7.75x */
634 0x00f0, 0x00f4, 0x00f8, 0x00fc,
635 /* 8x */
636 0x01c0
637};
638
639/* mt9m001 sensor uses a different gain formula then other micron sensors */
640/* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300641static const u16 micron2_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300642 /* 1x 1.25x 1.5x 1.75x */
643 0x0008, 0x000a, 0x000c, 0x000e,
644 /* 2x 2.25x 2.5x 2.75x */
645 0x0010, 0x0012, 0x0014, 0x0016,
646 /* 3x 3.25x 3.5x 3.75x */
647 0x0018, 0x001a, 0x001c, 0x001e,
648 /* 4x 4.25x 4.5x 4.75x */
649 0x0020, 0x0051, 0x0052, 0x0053,
650 /* 5x 5.25x 5.5x 5.75x */
651 0x0054, 0x0055, 0x0056, 0x0057,
652 /* 6x 6.25x 6.5x 6.75x */
653 0x0058, 0x0059, 0x005a, 0x005b,
654 /* 7x 7.25x 7.5x 7.75x */
655 0x005c, 0x005d, 0x005e, 0x005f,
656 /* 8x */
657 0x0060
658};
659
660/* Gain = .5 + bit[7:0] / 16 */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300661static const u8 hv7131r_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300662 0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */,
663 0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */,
664 0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */,
665 0x38 /* 4x */, 0x3c /* 4.25x */, 0x40 /* 4.5x */, 0x44 /* 4.75x */,
666 0x48 /* 5x */, 0x4c /* 5.25x */, 0x50 /* 5.5x */, 0x54 /* 5.75x */,
667 0x58 /* 6x */, 0x5c /* 6.25x */, 0x60 /* 6.5x */, 0x64 /* 6.75x */,
668 0x68 /* 7x */, 0x6c /* 7.25x */, 0x70 /* 7.5x */, 0x74 /* 7.75x */,
669 0x78 /* 8x */
670};
671
Jean-François Moinedae1de62012-03-24 09:20:25 -0300672static const struct i2c_reg_u8 soi968_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300673 {0x0c, 0x00}, {0x0f, 0x1f},
Brian Johnson26e744b2009-07-19 05:52:58 -0300674 {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
675 {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
676 {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
677 {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20},
678 {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e},
Brian Johnsone1430472009-09-02 12:39:41 -0300679 {0x13, 0x8b}, {0x12, 0x40}, {0x17, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300680 {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79},
681 {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40},
682 {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32},
683 {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80},
684};
685
Jean-François Moinedae1de62012-03-24 09:20:25 -0300686static const struct i2c_reg_u8 ov7660_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300687 {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
688 {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
689 {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
Hans de Goede8bc50f32011-02-16 07:11:14 -0300690 /* HDG Set hstart and hstop, datasheet default 0x11, 0x61, using
691 0x10, 0x61 and sd->hstart, vstart = 3, fixes ugly colored borders */
692 {0x17, 0x10}, {0x18, 0x61},
Brian Johnson26e744b2009-07-19 05:52:58 -0300693 {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43},
Jean-François Moinea1ac5dc2012-03-24 09:33:42 -0300694 {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0x00},
695 {0x2e, 0x00}, {0x01, 0x78}, {0x02, 0x50},
Brian Johnson26e744b2009-07-19 05:52:58 -0300696};
697
Jean-François Moinedae1de62012-03-24 09:20:25 -0300698static const struct i2c_reg_u8 ov7670_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300699 {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
Brian Johnson26e744b2009-07-19 05:52:58 -0300700 {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
701 {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
702 {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
703 {0x0d, 0x40}, {0x14, 0x28}, {0xa5, 0x05}, {0xab, 0x07},
704 {0x24, 0x95}, {0x25, 0x33}, {0x26, 0xe3}, {0x9f, 0x75},
705 {0xa0, 0x65}, {0xa1, 0x0b}, {0xa6, 0xd8}, {0xa7, 0xd8},
706 {0xa8, 0xf0}, {0xa9, 0x90}, {0xaa, 0x94}, {0x13, 0xe5},
707 {0x0e, 0x61}, {0x0f, 0x4b}, {0x16, 0x02}, {0x1e, 0x27},
708 {0x21, 0x02}, {0x22, 0x91}, {0x29, 0x07}, {0x33, 0x0b},
709 {0x35, 0x0b}, {0x37, 0x1d}, {0x38, 0x71}, {0x39, 0x2a},
710 {0x3c, 0x78}, {0x4d, 0x40}, {0x4e, 0x20}, {0x69, 0x00},
711 {0x74, 0x19}, {0x8d, 0x4f}, {0x8e, 0x00}, {0x8f, 0x00},
712 {0x90, 0x00}, {0x91, 0x00}, {0x96, 0x00}, {0x9a, 0x80},
713 {0xb0, 0x84}, {0xb1, 0x0c}, {0xb2, 0x0e}, {0xb3, 0x82},
714 {0xb8, 0x0a}, {0x43, 0x0a}, {0x44, 0xf0}, {0x45, 0x20},
715 {0x46, 0x7d}, {0x47, 0x29}, {0x48, 0x4a}, {0x59, 0x8c},
716 {0x5a, 0xa5}, {0x5b, 0xde}, {0x5c, 0x96}, {0x5d, 0x66},
717 {0x5e, 0x10}, {0x6c, 0x0a}, {0x6d, 0x55}, {0x6e, 0x11},
718 {0x6f, 0x9e}, {0x6a, 0x40}, {0x01, 0x40}, {0x02, 0x40},
719 {0x13, 0xe7}, {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x02},
720 {0x52, 0x1d}, {0x53, 0x56}, {0x54, 0x73}, {0x55, 0x0a},
721 {0x56, 0x55}, {0x57, 0x80}, {0x58, 0x9e}, {0x41, 0x08},
722 {0x3f, 0x02}, {0x75, 0x03}, {0x76, 0x63}, {0x4c, 0x04},
723 {0x77, 0x06}, {0x3d, 0x02}, {0x4b, 0x09}, {0xc9, 0x30},
724 {0x41, 0x08}, {0x56, 0x48}, {0x34, 0x11}, {0xa4, 0x88},
725 {0x96, 0x00}, {0x97, 0x30}, {0x98, 0x20}, {0x99, 0x30},
726 {0x9a, 0x84}, {0x9b, 0x29}, {0x9c, 0x03}, {0x9d, 0x99},
727 {0x9e, 0x7f}, {0x78, 0x04}, {0x79, 0x01}, {0xc8, 0xf0},
728 {0x79, 0x0f}, {0xc8, 0x00}, {0x79, 0x10}, {0xc8, 0x7e},
729 {0x79, 0x0a}, {0xc8, 0x80}, {0x79, 0x0b}, {0xc8, 0x01},
730 {0x79, 0x0c}, {0xc8, 0x0f}, {0x79, 0x0d}, {0xc8, 0x20},
731 {0x79, 0x09}, {0xc8, 0x80}, {0x79, 0x02}, {0xc8, 0xc0},
732 {0x79, 0x03}, {0xc8, 0x40}, {0x79, 0x05}, {0xc8, 0x30},
733 {0x79, 0x26}, {0x62, 0x20}, {0x63, 0x00}, {0x64, 0x06},
734 {0x65, 0x00}, {0x66, 0x05}, {0x94, 0x05}, {0x95, 0x0a},
735 {0x17, 0x13}, {0x18, 0x01}, {0x19, 0x02}, {0x1a, 0x7a},
736 {0x46, 0x59}, {0x47, 0x30}, {0x58, 0x9a}, {0x59, 0x84},
737 {0x5a, 0x91}, {0x5b, 0x57}, {0x5c, 0x75}, {0x5d, 0x6d},
738 {0x5e, 0x13}, {0x64, 0x07}, {0x94, 0x07}, {0x95, 0x0d},
739 {0xa6, 0xdf}, {0xa7, 0xdf}, {0x48, 0x4d}, {0x51, 0x00},
740 {0x6b, 0x0a}, {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00},
741 {0x92, 0x00}, {0x93, 0x00}, {0x55, 0x0a}, {0x56, 0x60},
742 {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d},
743 {0x53, 0x56}, {0x54, 0x73}, {0x58, 0x9a}, {0x4f, 0x6e},
744 {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, {0x53, 0x56},
745 {0x54, 0x73}, {0x58, 0x9a}, {0x3f, 0x01}, {0x7b, 0x03},
746 {0x7c, 0x09}, {0x7d, 0x16}, {0x7e, 0x38}, {0x7f, 0x47},
747 {0x80, 0x53}, {0x81, 0x5e}, {0x82, 0x6a}, {0x83, 0x74},
748 {0x84, 0x80}, {0x85, 0x8c}, {0x86, 0x9b}, {0x87, 0xb2},
749 {0x88, 0xcc}, {0x89, 0xe5}, {0x7a, 0x24}, {0x3b, 0x00},
750 {0x9f, 0x76}, {0xa0, 0x65}, {0x13, 0xe2}, {0x6b, 0x0a},
751 {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, {0x92, 0x00},
752 {0x93, 0x00},
753};
754
Jean-François Moinedae1de62012-03-24 09:20:25 -0300755static const struct i2c_reg_u8 ov9650_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300756 {0x00, 0x00}, {0x01, 0x78},
Brian Johnson26e744b2009-07-19 05:52:58 -0300757 {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
758 {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
759 {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
760 {0x0e, 0xa0}, {0x0f, 0x52}, {0x10, 0x7c},
761 {0x11, 0x80}, {0x12, 0x45}, {0x13, 0xc2},
762 {0x14, 0x2e}, {0x15, 0x00}, {0x16, 0x07},
763 {0x17, 0x24}, {0x18, 0xc5}, {0x19, 0x00},
764 {0x1a, 0x3c}, {0x1b, 0x00}, {0x1e, 0x04},
765 {0x1f, 0x00}, {0x24, 0x78}, {0x25, 0x68},
766 {0x26, 0xd4}, {0x27, 0x80}, {0x28, 0x80},
767 {0x29, 0x30}, {0x2a, 0x00}, {0x2b, 0x00},
768 {0x2c, 0x80}, {0x2d, 0x00}, {0x2e, 0x00},
769 {0x2f, 0x00}, {0x30, 0x08}, {0x31, 0x30},
770 {0x32, 0x84}, {0x33, 0xe2}, {0x34, 0xbf},
771 {0x35, 0x81}, {0x36, 0xf9}, {0x37, 0x00},
772 {0x38, 0x93}, {0x39, 0x50}, {0x3a, 0x01},
773 {0x3b, 0x01}, {0x3c, 0x73}, {0x3d, 0x19},
774 {0x3e, 0x0b}, {0x3f, 0x80}, {0x40, 0xc1},
775 {0x41, 0x00}, {0x42, 0x08}, {0x67, 0x80},
776 {0x68, 0x80}, {0x69, 0x40}, {0x6a, 0x00},
777 {0x6b, 0x0a}, {0x8b, 0x06}, {0x8c, 0x20},
778 {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0xdf},
779 {0x92, 0x00}, {0x93, 0x00}, {0x94, 0x88},
780 {0x95, 0x88}, {0x96, 0x04}, {0xa1, 0x00},
781 {0xa5, 0x80}, {0xa8, 0x80}, {0xa9, 0xb8},
782 {0xaa, 0x92}, {0xab, 0x0a},
783};
784
Jean-François Moinedae1de62012-03-24 09:20:25 -0300785static const struct i2c_reg_u8 ov9655_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300786 {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300787 {0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
788 {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
789 {0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57},
790 {0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c}, {0x3d, 0x19},
791 {0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40}, {0x42, 0x80},
792 {0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a}, {0x48, 0x3c},
793 {0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc}, {0x4d, 0xdc},
794 {0x4e, 0xdc}, {0x6c, 0x04}, {0x6f, 0x9e}, {0x70, 0x05},
795 {0x71, 0x78}, {0x77, 0x02}, {0x8a, 0x23}, {0x90, 0x7e},
796 {0x91, 0x7c}, {0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68},
797 {0xa6, 0x60}, {0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92},
798 {0xab, 0x04}, {0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80},
799 {0xaf, 0x80}, {0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00},
800 {0xb6, 0xaf}, {0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44},
801 {0xbe, 0x3b}, {0xbf, 0x3a}, {0xc1, 0xc8}, {0xc2, 0x01},
Brian Johnson26e744b2009-07-19 05:52:58 -0300802 {0xc4, 0x00}, {0xc6, 0x85}, {0xc7, 0x81}, {0xc9, 0xe0},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300803 {0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x2d, 0x00},
804 {0x2e, 0x00}, {0x01, 0x80}, {0x02, 0x80}, {0x12, 0x61},
Brian Johnson26e744b2009-07-19 05:52:58 -0300805 {0x36, 0xfa}, {0x8c, 0x8d}, {0xc0, 0xaa}, {0x69, 0x0a},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300806 {0x03, 0x09}, {0x17, 0x16}, {0x18, 0x6e}, {0x19, 0x01},
807 {0x1a, 0x3e}, {0x32, 0x09}, {0x2a, 0x10}, {0x2b, 0x0a},
808 {0x92, 0x00}, {0x93, 0x00}, {0xa1, 0x00}, {0x10, 0x7c},
809 {0x04, 0x03}, {0x00, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300810};
811
Jean-François Moinedae1de62012-03-24 09:20:25 -0300812static const struct i2c_reg_u16 mt9v112_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300813 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020},
814 {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
815 {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
816 {0x05, 0x0000}, {0x06, 0x340c}, {0x3b, 0x042a},
817 {0x3c, 0x0400}, {0xf0, 0x0002}, {0x2e, 0x0c58},
818 {0x5b, 0x0001}, {0xc8, 0x9f0b}, {0xf0, 0x0001},
819 {0x9b, 0x5300}, {0xf0, 0x0000}, {0x2b, 0x0020},
820 {0x2c, 0x002a}, {0x2d, 0x0032}, {0x2e, 0x0020},
821 {0x09, 0x01dc}, {0x01, 0x000c}, {0x02, 0x0020},
822 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
823 {0x05, 0x0098}, {0x20, 0x0703}, {0x09, 0x01f2},
824 {0x2b, 0x00a0}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
825 {0x2e, 0x00a0}, {0x01, 0x000c}, {0x02, 0x0020},
826 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
827 {0x05, 0x0098}, {0x09, 0x01c1}, {0x2b, 0x00ae},
828 {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
829};
830
Jean-François Moinedae1de62012-03-24 09:20:25 -0300831static const struct i2c_reg_u16 mt9v111_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300832 {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
Brian Johnson6ea23bd2010-05-05 13:22:45 -0300833 {0x01, 0x0001}, {0x05, 0x0004}, {0x2d, 0xe0a0},
834 {0x2e, 0x0c64}, {0x2f, 0x0064}, {0x06, 0x600e},
835 {0x08, 0x0480}, {0x01, 0x0004}, {0x02, 0x0016},
836 {0x03, 0x01e7}, {0x04, 0x0287}, {0x05, 0x0004},
837 {0x06, 0x002d}, {0x07, 0x3002}, {0x08, 0x0008},
838 {0x0e, 0x0008}, {0x20, 0x0000}
Brian Johnson26e744b2009-07-19 05:52:58 -0300839};
840
Jean-François Moinedae1de62012-03-24 09:20:25 -0300841static const struct i2c_reg_u16 mt9v011_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300842 {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
843 {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1},
844 {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006},
845 {0x0d, 0x0002}, {0x0a, 0x0000}, {0x0b, 0x0000},
846 {0x0c, 0x0000}, {0x0d, 0x0000}, {0x0e, 0x0000},
847 {0x0f, 0x0000}, {0x10, 0x0000}, {0x11, 0x0000},
848 {0x12, 0x0000}, {0x13, 0x0000}, {0x14, 0x0000},
849 {0x15, 0x0000}, {0x16, 0x0000}, {0x17, 0x0000},
850 {0x18, 0x0000}, {0x19, 0x0000}, {0x1a, 0x0000},
851 {0x1b, 0x0000}, {0x1c, 0x0000}, {0x1d, 0x0000},
852 {0x32, 0x0000}, {0x20, 0x1101}, {0x21, 0x0000},
853 {0x22, 0x0000}, {0x23, 0x0000}, {0x24, 0x0000},
854 {0x25, 0x0000}, {0x26, 0x0000}, {0x27, 0x0024},
855 {0x2f, 0xf7b0}, {0x30, 0x0005}, {0x31, 0x0000},
856 {0x32, 0x0000}, {0x33, 0x0000}, {0x34, 0x0100},
857 {0x3d, 0x068f}, {0x40, 0x01e0}, {0x41, 0x00d1},
858 {0x44, 0x0082}, {0x5a, 0x0000}, {0x5b, 0x0000},
859 {0x5c, 0x0000}, {0x5d, 0x0000}, {0x5e, 0x0000},
860 {0x5f, 0xa31d}, {0x62, 0x0611}, {0x0a, 0x0000},
861 {0x06, 0x0029}, {0x05, 0x0009}, {0x20, 0x1101},
862 {0x20, 0x1101}, {0x09, 0x0064}, {0x07, 0x0003},
863 {0x2b, 0x0033}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
864 {0x2e, 0x0033}, {0x07, 0x0002}, {0x06, 0x0000},
865 {0x06, 0x0029}, {0x05, 0x0009},
866};
867
Jean-François Moinedae1de62012-03-24 09:20:25 -0300868static const struct i2c_reg_u16 mt9m001_init[] = {
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -0300869 {0x0d, 0x0001},
870 {0x0d, 0x0000},
871 {0x04, 0x0500}, /* hres = 1280 */
872 {0x03, 0x0400}, /* vres = 1024 */
873 {0x20, 0x1100},
874 {0x06, 0x0010},
875 {0x2b, 0x0024},
876 {0x2e, 0x0024},
877 {0x35, 0x0024},
878 {0x2d, 0x0020},
879 {0x2c, 0x0020},
880 {0x09, 0x0ad4},
881 {0x35, 0x0057},
Brian Johnson26e744b2009-07-19 05:52:58 -0300882};
883
Jean-François Moinedae1de62012-03-24 09:20:25 -0300884static const struct i2c_reg_u16 mt9m111_init[] = {
Brian Johnson13a84fa2009-09-03 19:07:13 -0300885 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
886 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
Brian Johnson4d708a52009-09-03 19:10:15 -0300887 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
888 {0xf0, 0x0000},
Brian Johnson26e744b2009-07-19 05:52:58 -0300889};
890
Jean-François Moinedae1de62012-03-24 09:20:25 -0300891static const struct i2c_reg_u16 mt9m112_init[] = {
Brian Johnsone99ac542010-03-16 13:58:28 -0300892 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
893 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
894 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
895 {0xf0, 0x0000},
896};
897
Jean-François Moinedae1de62012-03-24 09:20:25 -0300898static const struct i2c_reg_u8 hv7131r_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300899 {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
900 {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
901 {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
902 {0x01, 0x08}, {0x01, 0x08}, {0x25, 0x07},
903 {0x26, 0xc3}, {0x27, 0x50}, {0x30, 0x62},
904 {0x31, 0x10}, {0x32, 0x06}, {0x33, 0x10},
905 {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00},
906 {0x23, 0x09}, {0x01, 0x08},
907};
908
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300909static void reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
Brian Johnson26e744b2009-07-19 05:52:58 -0300910{
911 struct usb_device *dev = gspca_dev->dev;
912 int result;
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300913
914 if (gspca_dev->usb_err < 0)
915 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300916 result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
917 0x00,
918 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
919 reg,
920 0x00,
921 gspca_dev->usb_buf,
922 length,
923 500);
924 if (unlikely(result < 0 || result != length)) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300925 pr_err("Read register %02x failed %d\n", reg, result);
926 gspca_dev->usb_err = result;
Brian Johnson26e744b2009-07-19 05:52:58 -0300927 }
Brian Johnson26e744b2009-07-19 05:52:58 -0300928}
929
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300930static void reg_w(struct gspca_dev *gspca_dev, u16 reg,
Joe Perches58aa68c2009-09-02 01:12:13 -0300931 const u8 *buffer, int length)
Brian Johnson26e744b2009-07-19 05:52:58 -0300932{
933 struct usb_device *dev = gspca_dev->dev;
934 int result;
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300935
936 if (gspca_dev->usb_err < 0)
937 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300938 memcpy(gspca_dev->usb_buf, buffer, length);
939 result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
940 0x08,
941 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
942 reg,
943 0x00,
944 gspca_dev->usb_buf,
945 length,
946 500);
947 if (unlikely(result < 0 || result != length)) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300948 pr_err("Write register %02x failed %d\n", reg, result);
949 gspca_dev->usb_err = result;
Brian Johnson26e744b2009-07-19 05:52:58 -0300950 }
Brian Johnson26e744b2009-07-19 05:52:58 -0300951}
952
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300953static void reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
Brian Johnson26e744b2009-07-19 05:52:58 -0300954{
Jean-François Moineff38d582012-03-19 04:55:16 -0300955 reg_w(gspca_dev, reg, &value, 1);
Brian Johnson26e744b2009-07-19 05:52:58 -0300956}
957
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300958static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
Brian Johnson26e744b2009-07-19 05:52:58 -0300959{
960 int i;
Jean-François Moineff38d582012-03-19 04:55:16 -0300961
Brian Johnson26e744b2009-07-19 05:52:58 -0300962 reg_w(gspca_dev, 0x10c0, buffer, 8);
963 for (i = 0; i < 5; i++) {
964 reg_r(gspca_dev, 0x10c0, 1);
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300965 if (gspca_dev->usb_err < 0)
966 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300967 if (gspca_dev->usb_buf[0] & 0x04) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300968 if (gspca_dev->usb_buf[0] & 0x08) {
969 pr_err("i2c_w error\n");
970 gspca_dev->usb_err = -EIO;
971 }
972 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300973 }
Jean-François Moinee71389b2012-03-19 04:45:20 -0300974 msleep(10);
Brian Johnson26e744b2009-07-19 05:52:58 -0300975 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300976 pr_err("i2c_w reg %02x no response\n", buffer[2]);
977/* gspca_dev->usb_err = -EIO; fixme: may occur */
Brian Johnson26e744b2009-07-19 05:52:58 -0300978}
979
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300980static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
Brian Johnson26e744b2009-07-19 05:52:58 -0300981{
982 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson26e744b2009-07-19 05:52:58 -0300983 u8 row[8];
984
985 /*
986 * from the point of view of the bridge, the length
987 * includes the address
988 */
Jean-François Moinec4407fe2012-03-24 09:23:56 -0300989 row[0] = sd->i2c_intf | (2 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -0300990 row[1] = sd->i2c_addr;
991 row[2] = reg;
992 row[3] = val;
993 row[4] = 0x00;
994 row[5] = 0x00;
995 row[6] = 0x00;
996 row[7] = 0x10;
997
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300998 i2c_w(gspca_dev, row);
Brian Johnson26e744b2009-07-19 05:52:58 -0300999}
1000
Jean-François Moined4689b72012-03-19 04:42:45 -03001001static void i2c_w1_buf(struct gspca_dev *gspca_dev,
Jean-François Moinedae1de62012-03-24 09:20:25 -03001002 const struct i2c_reg_u8 *buf, int sz)
Jean-François Moined4689b72012-03-19 04:42:45 -03001003{
1004 while (--sz >= 0) {
1005 i2c_w1(gspca_dev, buf->reg, buf->val);
1006 buf++;
1007 }
1008}
1009
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001010static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001011{
1012 struct sd *sd = (struct sd *) gspca_dev;
1013 u8 row[8];
1014
1015 /*
1016 * from the point of view of the bridge, the length
1017 * includes the address
1018 */
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001019 row[0] = sd->i2c_intf | (3 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001020 row[1] = sd->i2c_addr;
1021 row[2] = reg;
Jean-François Moineff38d582012-03-19 04:55:16 -03001022 row[3] = val >> 8;
1023 row[4] = val;
Brian Johnson26e744b2009-07-19 05:52:58 -03001024 row[5] = 0x00;
1025 row[6] = 0x00;
1026 row[7] = 0x10;
1027
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001028 i2c_w(gspca_dev, row);
Brian Johnson26e744b2009-07-19 05:52:58 -03001029}
1030
Jean-François Moined4689b72012-03-19 04:42:45 -03001031static void i2c_w2_buf(struct gspca_dev *gspca_dev,
Jean-François Moinedae1de62012-03-24 09:20:25 -03001032 const struct i2c_reg_u16 *buf, int sz)
Jean-François Moined4689b72012-03-19 04:42:45 -03001033{
1034 while (--sz >= 0) {
1035 i2c_w2(gspca_dev, buf->reg, buf->val);
1036 buf++;
1037 }
1038}
1039
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001040static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001041{
1042 struct sd *sd = (struct sd *) gspca_dev;
1043 u8 row[8];
1044
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001045 row[0] = sd->i2c_intf | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001046 row[1] = sd->i2c_addr;
1047 row[2] = reg;
1048 row[3] = 0;
1049 row[4] = 0;
1050 row[5] = 0;
1051 row[6] = 0;
1052 row[7] = 0x10;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001053 i2c_w(gspca_dev, row);
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001054 row[0] = sd->i2c_intf | (1 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001055 row[2] = 0;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001056 i2c_w(gspca_dev, row);
1057 reg_r(gspca_dev, 0x10c2, 5);
Brian Johnson00b581e2009-07-23 05:55:43 -03001058 *val = gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001059}
1060
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001061static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001062{
1063 struct sd *sd = (struct sd *) gspca_dev;
1064 u8 row[8];
1065
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001066 row[0] = sd->i2c_intf | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001067 row[1] = sd->i2c_addr;
1068 row[2] = reg;
1069 row[3] = 0;
1070 row[4] = 0;
1071 row[5] = 0;
1072 row[6] = 0;
1073 row[7] = 0x10;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001074 i2c_w(gspca_dev, row);
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001075 row[0] = sd->i2c_intf | (2 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001076 row[2] = 0;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001077 i2c_w(gspca_dev, row);
1078 reg_r(gspca_dev, 0x10c2, 5);
Brian Johnson00b581e2009-07-23 05:55:43 -03001079 *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001080}
1081
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001082static void ov9650_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001083{
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001084 u16 id;
Brian Johnson26e744b2009-07-19 05:52:58 -03001085 struct sd *sd = (struct sd *) gspca_dev;
1086
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001087 i2c_r2(gspca_dev, 0x1c, &id);
1088 if (gspca_dev->usb_err < 0)
1089 return;
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001090
1091 if (id != 0x7fa2) {
Joe Perches91f58422011-08-21 19:56:55 -03001092 pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001093 gspca_dev->usb_err = -ENODEV;
1094 return;
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001095 }
1096
Jean-François Moine92884f82012-03-19 04:33:30 -03001097 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1098 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001099 i2c_w1_buf(gspca_dev, ov9650_init, ARRAY_SIZE(ov9650_init));
1100 if (gspca_dev->usb_err < 0)
1101 pr_err("OV9650 sensor initialization failed\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001102 sd->hstart = 1;
1103 sd->vstart = 7;
Brian Johnson26e744b2009-07-19 05:52:58 -03001104}
1105
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001106static void ov9655_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001107{
Brian Johnson26e744b2009-07-19 05:52:58 -03001108 struct sd *sd = (struct sd *) gspca_dev;
1109
Jean-François Moine92884f82012-03-19 04:33:30 -03001110 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1111 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001112 i2c_w1_buf(gspca_dev, ov9655_init, ARRAY_SIZE(ov9655_init));
1113 if (gspca_dev->usb_err < 0)
1114 pr_err("OV9655 sensor initialization failed\n");
1115
Brian Johnsoncc2a8332010-03-16 13:58:28 -03001116 sd->hstart = 1;
1117 sd->vstart = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001118}
1119
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001120static void soi968_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001121{
Brian Johnson26e744b2009-07-19 05:52:58 -03001122 struct sd *sd = (struct sd *) gspca_dev;
1123
Jean-François Moine92884f82012-03-19 04:33:30 -03001124 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1125 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001126 i2c_w1_buf(gspca_dev, soi968_init, ARRAY_SIZE(soi968_init));
1127 if (gspca_dev->usb_err < 0)
1128 pr_err("SOI968 sensor initialization failed\n");
1129
Brian Johnson26e744b2009-07-19 05:52:58 -03001130 sd->hstart = 60;
1131 sd->vstart = 11;
Brian Johnson26e744b2009-07-19 05:52:58 -03001132}
1133
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001134static void ov7660_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001135{
Brian Johnson26e744b2009-07-19 05:52:58 -03001136 struct sd *sd = (struct sd *) gspca_dev;
1137
Jean-François Moine92884f82012-03-19 04:33:30 -03001138 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1139 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001140 i2c_w1_buf(gspca_dev, ov7660_init, ARRAY_SIZE(ov7660_init));
1141 if (gspca_dev->usb_err < 0)
1142 pr_err("OV7660 sensor initialization failed\n");
Hans de Goede8bc50f32011-02-16 07:11:14 -03001143 sd->hstart = 3;
1144 sd->vstart = 3;
Brian Johnson26e744b2009-07-19 05:52:58 -03001145}
1146
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001147static void ov7670_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001148{
Brian Johnson26e744b2009-07-19 05:52:58 -03001149 struct sd *sd = (struct sd *) gspca_dev;
1150
Jean-François Moine92884f82012-03-19 04:33:30 -03001151 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1152 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001153 i2c_w1_buf(gspca_dev, ov7670_init, ARRAY_SIZE(ov7670_init));
1154 if (gspca_dev->usb_err < 0)
1155 pr_err("OV7670 sensor initialization failed\n");
1156
Brian Johnson26e744b2009-07-19 05:52:58 -03001157 sd->hstart = 0;
1158 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001159}
1160
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001161static void mt9v_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001162{
1163 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson26e744b2009-07-19 05:52:58 -03001164 u16 value;
Brian Johnson26e744b2009-07-19 05:52:58 -03001165
1166 sd->i2c_addr = 0x5d;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001167 i2c_r2(gspca_dev, 0xff, &value);
1168 if (gspca_dev->usb_err >= 0
1169 && value == 0x8243) {
Jean-François Moined4689b72012-03-19 04:42:45 -03001170 i2c_w2_buf(gspca_dev, mt9v011_init, ARRAY_SIZE(mt9v011_init));
1171 if (gspca_dev->usb_err < 0) {
1172 pr_err("MT9V011 sensor initialization failed\n");
1173 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001174 }
1175 sd->hstart = 2;
1176 sd->vstart = 2;
1177 sd->sensor = SENSOR_MT9V011;
Joe Perches91f58422011-08-21 19:56:55 -03001178 pr_info("MT9V011 sensor detected\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001179 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001180 }
1181
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001182 gspca_dev->usb_err = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001183 sd->i2c_addr = 0x5c;
1184 i2c_w2(gspca_dev, 0x01, 0x0004);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001185 i2c_r2(gspca_dev, 0xff, &value);
1186 if (gspca_dev->usb_err >= 0
1187 && value == 0x823a) {
Jean-François Moined4689b72012-03-19 04:42:45 -03001188 i2c_w2_buf(gspca_dev, mt9v111_init, ARRAY_SIZE(mt9v111_init));
1189 if (gspca_dev->usb_err < 0) {
1190 pr_err("MT9V111 sensor initialization failed\n");
1191 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001192 }
1193 sd->hstart = 2;
1194 sd->vstart = 2;
1195 sd->sensor = SENSOR_MT9V111;
Joe Perches91f58422011-08-21 19:56:55 -03001196 pr_info("MT9V111 sensor detected\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001197 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001198 }
1199
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001200 gspca_dev->usb_err = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001201 sd->i2c_addr = 0x5d;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001202 i2c_w2(gspca_dev, 0xf0, 0x0000);
1203 if (gspca_dev->usb_err < 0) {
1204 gspca_dev->usb_err = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001205 sd->i2c_addr = 0x48;
1206 i2c_w2(gspca_dev, 0xf0, 0x0000);
1207 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001208 i2c_r2(gspca_dev, 0x00, &value);
1209 if (gspca_dev->usb_err >= 0
1210 && value == 0x1229) {
Jean-François Moined4689b72012-03-19 04:42:45 -03001211 i2c_w2_buf(gspca_dev, mt9v112_init, ARRAY_SIZE(mt9v112_init));
1212 if (gspca_dev->usb_err < 0) {
1213 pr_err("MT9V112 sensor initialization failed\n");
1214 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001215 }
1216 sd->hstart = 6;
1217 sd->vstart = 2;
1218 sd->sensor = SENSOR_MT9V112;
Joe Perches91f58422011-08-21 19:56:55 -03001219 pr_info("MT9V112 sensor detected\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001220 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001221 }
1222
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001223 gspca_dev->usb_err = -ENODEV;
Brian Johnson26e744b2009-07-19 05:52:58 -03001224}
1225
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001226static void mt9m112_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnsone99ac542010-03-16 13:58:28 -03001227{
1228 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moined4689b72012-03-19 04:42:45 -03001229
1230 i2c_w2_buf(gspca_dev, mt9m112_init, ARRAY_SIZE(mt9m112_init));
1231 if (gspca_dev->usb_err < 0)
1232 pr_err("MT9M112 sensor initialization failed\n");
1233
Brian Johnsone99ac542010-03-16 13:58:28 -03001234 sd->hstart = 0;
1235 sd->vstart = 2;
Brian Johnsone99ac542010-03-16 13:58:28 -03001236}
1237
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001238static void mt9m111_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001239{
1240 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moined4689b72012-03-19 04:42:45 -03001241
1242 i2c_w2_buf(gspca_dev, mt9m111_init, ARRAY_SIZE(mt9m111_init));
1243 if (gspca_dev->usb_err < 0)
1244 pr_err("MT9M111 sensor initialization failed\n");
1245
Brian Johnson26e744b2009-07-19 05:52:58 -03001246 sd->hstart = 0;
1247 sd->vstart = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001248}
1249
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001250static void mt9m001_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001251{
1252 struct sd *sd = (struct sd *) gspca_dev;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001253 u16 id;
1254
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001255 i2c_r2(gspca_dev, 0x00, &id);
1256 if (gspca_dev->usb_err < 0)
1257 return;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001258
1259 /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
1260 switch (id) {
1261 case 0x8411:
1262 case 0x8421:
Joe Perches91f58422011-08-21 19:56:55 -03001263 pr_info("MT9M001 color sensor detected\n");
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001264 break;
1265 case 0x8431:
Joe Perches91f58422011-08-21 19:56:55 -03001266 pr_info("MT9M001 mono sensor detected\n");
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001267 break;
1268 default:
Joe Perches91f58422011-08-21 19:56:55 -03001269 pr_err("No MT9M001 chip detected, ID = %x\n\n", id);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001270 gspca_dev->usb_err = -ENODEV;
1271 return;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001272 }
1273
Jean-François Moined4689b72012-03-19 04:42:45 -03001274 i2c_w2_buf(gspca_dev, mt9m001_init, ARRAY_SIZE(mt9m001_init));
1275 if (gspca_dev->usb_err < 0)
1276 pr_err("MT9M001 sensor initialization failed\n");
1277
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001278 sd->hstart = 1;
1279 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001280}
1281
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001282static void hv7131r_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001283{
Brian Johnson26e744b2009-07-19 05:52:58 -03001284 struct sd *sd = (struct sd *) gspca_dev;
1285
Jean-François Moined4689b72012-03-19 04:42:45 -03001286 i2c_w1_buf(gspca_dev, hv7131r_init, ARRAY_SIZE(hv7131r_init));
1287 if (gspca_dev->usb_err < 0)
1288 pr_err("HV7131R Sensor initialization failed\n");
1289
Brian Johnson26e744b2009-07-19 05:52:58 -03001290 sd->hstart = 0;
1291 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001292}
1293
Hans Verkuil63069da2012-05-06 09:28:29 -03001294static void set_cmatrix(struct gspca_dev *gspca_dev,
1295 s32 brightness, s32 contrast, s32 satur, s32 hue)
Brian Johnson26e744b2009-07-19 05:52:58 -03001296{
Hans Verkuil63069da2012-05-06 09:28:29 -03001297 s32 hue_coord, hue_index = 180 + hue;
Brian Johnson26e744b2009-07-19 05:52:58 -03001298 u8 cmatrix[21];
Brian Johnson26e744b2009-07-19 05:52:58 -03001299
Morgan Phillipse0aa2b22014-09-08 09:49:47 -03001300 memset(cmatrix, 0, sizeof(cmatrix));
Hans Verkuil63069da2012-05-06 09:28:29 -03001301 cmatrix[2] = (contrast * 0x25 / 0x100) + 0x26;
Brian Johnson26e744b2009-07-19 05:52:58 -03001302 cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
1303 cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
Hans Verkuil63069da2012-05-06 09:28:29 -03001304 cmatrix[18] = brightness - 0x80;
Brian Johnson26e744b2009-07-19 05:52:58 -03001305
Jean-François Moinec5224d82012-03-19 04:30:07 -03001306 hue_coord = (hsv_red_x[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001307 cmatrix[6] = hue_coord;
1308 cmatrix[7] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001309
Jean-François Moinec5224d82012-03-19 04:30:07 -03001310 hue_coord = (hsv_red_y[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001311 cmatrix[8] = hue_coord;
1312 cmatrix[9] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001313
Jean-François Moinec5224d82012-03-19 04:30:07 -03001314 hue_coord = (hsv_green_x[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001315 cmatrix[10] = hue_coord;
1316 cmatrix[11] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001317
Jean-François Moinec5224d82012-03-19 04:30:07 -03001318 hue_coord = (hsv_green_y[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001319 cmatrix[12] = hue_coord;
1320 cmatrix[13] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001321
Jean-François Moinec5224d82012-03-19 04:30:07 -03001322 hue_coord = (hsv_blue_x[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001323 cmatrix[14] = hue_coord;
1324 cmatrix[15] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001325
Jean-François Moinec5224d82012-03-19 04:30:07 -03001326 hue_coord = (hsv_blue_y[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001327 cmatrix[16] = hue_coord;
1328 cmatrix[17] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001329
Jean-François Moinec5224d82012-03-19 04:30:07 -03001330 reg_w(gspca_dev, 0x10e1, cmatrix, 21);
Brian Johnson26e744b2009-07-19 05:52:58 -03001331}
1332
Hans Verkuil63069da2012-05-06 09:28:29 -03001333static void set_gamma(struct gspca_dev *gspca_dev, s32 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001334{
Brian Johnson26e744b2009-07-19 05:52:58 -03001335 u8 gamma[17];
Hans Verkuil63069da2012-05-06 09:28:29 -03001336 u8 gval = val * 0xb8 / 0x100;
Brian Johnson26e744b2009-07-19 05:52:58 -03001337
1338 gamma[0] = 0x0a;
1339 gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
1340 gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8);
1341 gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8);
1342 gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8);
1343 gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8);
1344 gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8);
1345 gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8);
1346 gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8);
1347 gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8);
1348 gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8);
1349 gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8);
1350 gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8);
1351 gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8);
1352 gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8);
1353 gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
1354 gamma[16] = 0xf5;
1355
Jean-François Moinec5224d82012-03-19 04:30:07 -03001356 reg_w(gspca_dev, 0x1190, gamma, 17);
Brian Johnson26e744b2009-07-19 05:52:58 -03001357}
1358
Hans Verkuil63069da2012-05-06 09:28:29 -03001359static void set_redblue(struct gspca_dev *gspca_dev, s32 blue, s32 red)
Brian Johnson26e744b2009-07-19 05:52:58 -03001360{
Hans Verkuil63069da2012-05-06 09:28:29 -03001361 reg_w1(gspca_dev, 0x118c, red);
1362 reg_w1(gspca_dev, 0x118f, blue);
Brian Johnson26e744b2009-07-19 05:52:58 -03001363}
1364
Hans Verkuil63069da2012-05-06 09:28:29 -03001365static void set_hvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001366{
Hans Verkuil63069da2012-05-06 09:28:29 -03001367 u8 value, tslb;
Brian Johnson26e744b2009-07-19 05:52:58 -03001368 u16 value2;
1369 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001370
1371 if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
Hans Verkuil63069da2012-05-06 09:28:29 -03001372 hflip = !hflip;
1373 vflip = !vflip;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001374 }
1375
Brian Johnson26e744b2009-07-19 05:52:58 -03001376 switch (sd->sensor) {
Hans de Goede779b51f2011-02-16 08:17:36 -03001377 case SENSOR_OV7660:
1378 value = 0x01;
1379 if (hflip)
1380 value |= 0x20;
1381 if (vflip) {
1382 value |= 0x10;
1383 sd->vstart = 2;
Jean-François Moineff38d582012-03-19 04:55:16 -03001384 } else {
Hans de Goede779b51f2011-02-16 08:17:36 -03001385 sd->vstart = 3;
Jean-François Moineff38d582012-03-19 04:55:16 -03001386 }
Hans de Goede779b51f2011-02-16 08:17:36 -03001387 reg_w1(gspca_dev, 0x1182, sd->vstart);
1388 i2c_w1(gspca_dev, 0x1e, value);
1389 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001390 case SENSOR_OV9650:
1391 i2c_r1(gspca_dev, 0x1e, &value);
1392 value &= ~0x30;
1393 tslb = 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001394 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001395 value |= 0x20;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001396 if (vflip) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001397 value |= 0x10;
1398 tslb = 0x49;
1399 }
1400 i2c_w1(gspca_dev, 0x1e, value);
1401 i2c_w1(gspca_dev, 0x3a, tslb);
1402 break;
1403 case SENSOR_MT9V111:
1404 case SENSOR_MT9V011:
1405 i2c_r2(gspca_dev, 0x20, &value2);
1406 value2 &= ~0xc0a0;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001407 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001408 value2 |= 0x8080;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001409 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001410 value2 |= 0x4020;
1411 i2c_w2(gspca_dev, 0x20, value2);
1412 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001413 case SENSOR_MT9M112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001414 case SENSOR_MT9M111:
1415 case SENSOR_MT9V112:
1416 i2c_r2(gspca_dev, 0x20, &value2);
1417 value2 &= ~0x0003;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001418 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001419 value2 |= 0x0002;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001420 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001421 value2 |= 0x0001;
1422 i2c_w2(gspca_dev, 0x20, value2);
1423 break;
1424 case SENSOR_HV7131R:
1425 i2c_r1(gspca_dev, 0x01, &value);
1426 value &= ~0x03;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001427 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001428 value |= 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001429 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001430 value |= 0x02;
1431 i2c_w1(gspca_dev, 0x01, value);
1432 break;
1433 }
Brian Johnson26e744b2009-07-19 05:52:58 -03001434}
1435
Hans Verkuil63069da2012-05-06 09:28:29 -03001436static void set_exposure(struct gspca_dev *gspca_dev, s32 expo)
Brian Johnson26e744b2009-07-19 05:52:58 -03001437{
1438 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001439 u8 exp[8] = {sd->i2c_intf, sd->i2c_addr,
Jean-François Moine4fb81372012-03-24 09:28:39 -03001440 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans Verkuil63069da2012-05-06 09:28:29 -03001441 int expo2;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001442
Jean-François Moine4fb81372012-03-24 09:28:39 -03001443 if (gspca_dev->streaming)
1444 exp[7] = 0x1e;
1445
Brian Johnson26e744b2009-07-19 05:52:58 -03001446 switch (sd->sensor) {
1447 case SENSOR_OV7660:
1448 case SENSOR_OV7670:
Brian Johnson26e744b2009-07-19 05:52:58 -03001449 case SENSOR_OV9655:
1450 case SENSOR_OV9650:
Jean-François Moinea1ac5dc2012-03-24 09:33:42 -03001451 if (expo > 547)
1452 expo2 = 547;
1453 else
1454 expo2 = expo;
1455 exp[0] |= (2 << 4);
1456 exp[2] = 0x10; /* AECH */
1457 exp[3] = expo2 >> 2;
1458 exp[7] = 0x10;
1459 i2c_w(gspca_dev, exp);
1460 exp[2] = 0x04; /* COM1 */
1461 exp[3] = expo2 & 0x0003;
1462 exp[7] = 0x10;
1463 i2c_w(gspca_dev, exp);
1464 expo -= expo2;
1465 exp[7] = 0x1e;
Brian Johnson26e744b2009-07-19 05:52:58 -03001466 exp[0] |= (3 << 4);
Jean-François Moinea1ac5dc2012-03-24 09:33:42 -03001467 exp[2] = 0x2d; /* ADVFL & ADVFH */
Jean-François Moinec5224d82012-03-19 04:30:07 -03001468 exp[3] = expo;
1469 exp[4] = expo >> 8;
Brian Johnson26e744b2009-07-19 05:52:58 -03001470 break;
1471 case SENSOR_MT9M001:
Brian Johnson26e744b2009-07-19 05:52:58 -03001472 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001473 case SENSOR_MT9V011:
1474 exp[0] |= (3 << 4);
1475 exp[2] = 0x09;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001476 exp[3] = expo >> 8;
1477 exp[4] = expo;
Brian Johnson26e744b2009-07-19 05:52:58 -03001478 break;
1479 case SENSOR_HV7131R:
1480 exp[0] |= (4 << 4);
1481 exp[2] = 0x25;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001482 exp[3] = expo >> 5;
1483 exp[4] = expo << 3;
German Galkine10f7312010-03-07 06:19:02 -03001484 exp[5] = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001485 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001486 default:
Jean-François Moinec5224d82012-03-19 04:30:07 -03001487 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001488 }
1489 i2c_w(gspca_dev, exp);
Brian Johnson26e744b2009-07-19 05:52:58 -03001490}
1491
Hans Verkuil63069da2012-05-06 09:28:29 -03001492static void set_gain(struct gspca_dev *gspca_dev, s32 g)
Brian Johnson26e744b2009-07-19 05:52:58 -03001493{
1494 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001495 u8 gain[8] = {sd->i2c_intf, sd->i2c_addr,
Jean-François Moine4fb81372012-03-24 09:28:39 -03001496 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Jean-François Moinec5224d82012-03-19 04:30:07 -03001497
Jean-François Moine4fb81372012-03-24 09:28:39 -03001498 if (gspca_dev->streaming)
1499 gain[7] = 0x15; /* or 1d ? */
1500
Brian Johnson26e744b2009-07-19 05:52:58 -03001501 switch (sd->sensor) {
1502 case SENSOR_OV7660:
1503 case SENSOR_OV7670:
1504 case SENSOR_SOI968:
1505 case SENSOR_OV9655:
1506 case SENSOR_OV9650:
1507 gain[0] |= (2 << 4);
Jean-François Moinec5224d82012-03-19 04:30:07 -03001508 gain[3] = ov_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001509 break;
1510 case SENSOR_MT9V011:
Brian Johnson26e744b2009-07-19 05:52:58 -03001511 gain[0] |= (3 << 4);
1512 gain[2] = 0x35;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001513 gain[3] = micron1_gain[g] >> 8;
1514 gain[4] = micron1_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001515 break;
1516 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001517 gain[0] |= (3 << 4);
1518 gain[2] = 0x2f;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001519 gain[3] = micron1_gain[g] >> 8;
1520 gain[4] = micron1_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001521 break;
1522 case SENSOR_MT9M001:
1523 gain[0] |= (3 << 4);
1524 gain[2] = 0x2f;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001525 gain[3] = micron2_gain[g] >> 8;
1526 gain[4] = micron2_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001527 break;
1528 case SENSOR_HV7131R:
1529 gain[0] |= (2 << 4);
1530 gain[2] = 0x30;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001531 gain[3] = hv7131r_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001532 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001533 default:
Jean-François Moinec5224d82012-03-19 04:30:07 -03001534 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001535 }
1536 i2c_w(gspca_dev, gain);
Brian Johnson26e744b2009-07-19 05:52:58 -03001537}
1538
Hans Verkuil63069da2012-05-06 09:28:29 -03001539static void set_quality(struct gspca_dev *gspca_dev, s32 val)
Jean-François Moine4c632e42012-03-19 04:35:34 -03001540{
1541 struct sd *sd = (struct sd *) gspca_dev;
1542
Hans Verkuil63069da2012-05-06 09:28:29 -03001543 jpeg_set_qual(sd->jpeg_hdr, val);
Jean-François Moine4c632e42012-03-19 04:35:34 -03001544 reg_w1(gspca_dev, 0x1061, 0x01); /* stop transfer */
1545 reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */
1546 reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
1547 reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
1548 reg_w1(gspca_dev, 0x1061, 0x03); /* restart transfer */
1549 reg_w1(gspca_dev, 0x10e0, sd->fmt);
1550 sd->fmt ^= 0x0c; /* invert QTAB use + write */
1551 reg_w1(gspca_dev, 0x10e0, sd->fmt);
1552}
1553
Brian Johnson26e744b2009-07-19 05:52:58 -03001554#ifdef CONFIG_VIDEO_ADV_DEBUG
1555static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
1556 struct v4l2_dbg_register *reg)
1557{
1558 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03001559
Hans Verkuilf82fadc2013-05-29 07:00:05 -03001560 reg->size = 1;
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03001561 switch (reg->match.addr) {
1562 case 0:
Brian Johnson26e744b2009-07-19 05:52:58 -03001563 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1564 return -EINVAL;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001565 reg_r(gspca_dev, reg->reg, 1);
Brian Johnson26e744b2009-07-19 05:52:58 -03001566 reg->val = gspca_dev->usb_buf[0];
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001567 return gspca_dev->usb_err;
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03001568 case 1:
Brian Johnson26e744b2009-07-19 05:52:58 -03001569 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001570 sd->sensor <= SENSOR_MT9M112) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001571 i2c_r2(gspca_dev, reg->reg, (u16 *) &reg->val);
Hans Verkuilf82fadc2013-05-29 07:00:05 -03001572 reg->size = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001573 } else {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001574 i2c_r1(gspca_dev, reg->reg, (u8 *) &reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001575 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001576 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001577 }
1578 return -EINVAL;
1579}
1580
1581static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
Hans Verkuil977ba3b12013-03-24 08:28:46 -03001582 const struct v4l2_dbg_register *reg)
Brian Johnson26e744b2009-07-19 05:52:58 -03001583{
1584 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03001585
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03001586 switch (reg->match.addr) {
1587 case 0:
Brian Johnson26e744b2009-07-19 05:52:58 -03001588 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1589 return -EINVAL;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001590 reg_w1(gspca_dev, reg->reg, reg->val);
1591 return gspca_dev->usb_err;
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03001592 case 1:
Brian Johnson26e744b2009-07-19 05:52:58 -03001593 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001594 sd->sensor <= SENSOR_MT9M112) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001595 i2c_w2(gspca_dev, reg->reg, reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001596 } else {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001597 i2c_w1(gspca_dev, reg->reg, reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001598 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001599 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001600 }
1601 return -EINVAL;
1602}
Brian Johnson26e744b2009-07-19 05:52:58 -03001603
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03001604static int sd_chip_info(struct gspca_dev *gspca_dev,
1605 struct v4l2_dbg_chip_info *chip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001606{
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03001607 if (chip->match.addr > 1)
1608 return -EINVAL;
1609 if (chip->match.addr == 1)
1610 strlcpy(chip->name, "sensor", sizeof(chip->name));
1611 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001612}
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03001613#endif
Brian Johnson26e744b2009-07-19 05:52:58 -03001614
1615static int sd_config(struct gspca_dev *gspca_dev,
1616 const struct usb_device_id *id)
1617{
1618 struct sd *sd = (struct sd *) gspca_dev;
1619 struct cam *cam;
1620
1621 cam = &gspca_dev->cam;
Hans de Goedeeb3fb7c2012-01-01 16:35:01 -03001622 cam->needs_full_bandwidth = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001623
Jean-François Moineff38d582012-03-19 04:55:16 -03001624 sd->sensor = id->driver_info >> 8;
1625 sd->i2c_addr = id->driver_info;
1626 sd->flags = id->driver_info >> 16;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001627 sd->i2c_intf = 0x80; /* i2c 100 Kb/s */
Brian Johnson26e744b2009-07-19 05:52:58 -03001628
1629 switch (sd->sensor) {
Brian Johnsone99ac542010-03-16 13:58:28 -03001630 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03001631 case SENSOR_MT9M111:
Brian Johnson26e744b2009-07-19 05:52:58 -03001632 case SENSOR_OV9650:
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001633 case SENSOR_SOI968:
Brian Johnson26e744b2009-07-19 05:52:58 -03001634 cam->cam_mode = sxga_mode;
1635 cam->nmodes = ARRAY_SIZE(sxga_mode);
1636 break;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001637 case SENSOR_MT9M001:
1638 cam->cam_mode = mono_mode;
1639 cam->nmodes = ARRAY_SIZE(mono_mode);
1640 break;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001641 case SENSOR_HV7131R:
1642 sd->i2c_intf = 0x81; /* i2c 400 Kb/s */
1643 /* fall thru */
Brian Johnson26e744b2009-07-19 05:52:58 -03001644 default:
1645 cam->cam_mode = vga_mode;
1646 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001647 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001648 }
1649
1650 sd->old_step = 0;
1651 sd->older_step = 0;
1652 sd->exposure_step = 16;
1653
Jean-François Moine92dcffc2012-03-19 04:47:24 -03001654 INIT_WORK(&sd->work, qual_upd);
Brian Johnson26e744b2009-07-19 05:52:58 -03001655
Brian Johnson26e744b2009-07-19 05:52:58 -03001656 return 0;
1657}
1658
Hans Verkuil63069da2012-05-06 09:28:29 -03001659static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
1660{
Hans de Goedea8a47862012-05-09 11:19:00 -03001661 struct gspca_dev *gspca_dev =
1662 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
1663 struct sd *sd = (struct sd *)gspca_dev;
Hans Verkuil63069da2012-05-06 09:28:29 -03001664
1665 gspca_dev->usb_err = 0;
1666
1667 if (!gspca_dev->streaming)
1668 return 0;
1669
1670 switch (ctrl->id) {
1671 /* color control cluster */
1672 case V4L2_CID_BRIGHTNESS:
Hans de Goedea8a47862012-05-09 11:19:00 -03001673 set_cmatrix(gspca_dev, sd->brightness->val,
Hans Verkuil63069da2012-05-06 09:28:29 -03001674 sd->contrast->val, sd->saturation->val, sd->hue->val);
1675 break;
1676 case V4L2_CID_GAMMA:
Hans de Goedea8a47862012-05-09 11:19:00 -03001677 set_gamma(gspca_dev, ctrl->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001678 break;
1679 /* blue/red balance cluster */
1680 case V4L2_CID_BLUE_BALANCE:
Hans de Goedea8a47862012-05-09 11:19:00 -03001681 set_redblue(gspca_dev, sd->blue->val, sd->red->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001682 break;
1683 /* h/vflip cluster */
1684 case V4L2_CID_HFLIP:
Hans de Goedea8a47862012-05-09 11:19:00 -03001685 set_hvflip(gspca_dev, sd->hflip->val, sd->vflip->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001686 break;
1687 /* standalone exposure control */
1688 case V4L2_CID_EXPOSURE:
Hans de Goedea8a47862012-05-09 11:19:00 -03001689 set_exposure(gspca_dev, ctrl->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001690 break;
1691 /* standalone gain control */
1692 case V4L2_CID_GAIN:
Hans de Goedea8a47862012-05-09 11:19:00 -03001693 set_gain(gspca_dev, ctrl->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001694 break;
1695 /* autogain + exposure or gain control cluster */
1696 case V4L2_CID_AUTOGAIN:
1697 if (sd->sensor == SENSOR_SOI968)
Hans de Goedea8a47862012-05-09 11:19:00 -03001698 set_gain(gspca_dev, sd->gain->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001699 else
Hans de Goedea8a47862012-05-09 11:19:00 -03001700 set_exposure(gspca_dev, sd->exposure->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001701 break;
1702 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Hans de Goedea8a47862012-05-09 11:19:00 -03001703 set_quality(gspca_dev, ctrl->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001704 break;
1705 }
1706 return gspca_dev->usb_err;
1707}
1708
1709static const struct v4l2_ctrl_ops sd_ctrl_ops = {
1710 .s_ctrl = sd_s_ctrl,
1711};
1712
1713static int sd_init_controls(struct gspca_dev *gspca_dev)
1714{
1715 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea8a47862012-05-09 11:19:00 -03001716 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
Hans Verkuil63069da2012-05-06 09:28:29 -03001717
1718 gspca_dev->vdev.ctrl_handler = hdl;
1719 v4l2_ctrl_handler_init(hdl, 13);
1720
1721 sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1722 V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
1723 sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1724 V4L2_CID_CONTRAST, 0, 255, 1, 127);
1725 sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1726 V4L2_CID_SATURATION, 0, 255, 1, 127);
1727 sd->hue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1728 V4L2_CID_HUE, -180, 180, 1, 0);
Hans Verkuil63069da2012-05-06 09:28:29 -03001729
1730 sd->gamma = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1731 V4L2_CID_GAMMA, 0, 255, 1, 0x10);
1732
1733 sd->blue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1734 V4L2_CID_BLUE_BALANCE, 0, 127, 1, 0x28);
1735 sd->red = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1736 V4L2_CID_RED_BALANCE, 0, 127, 1, 0x28);
Hans Verkuil63069da2012-05-06 09:28:29 -03001737
1738 if (sd->sensor != SENSOR_OV9655 && sd->sensor != SENSOR_SOI968 &&
1739 sd->sensor != SENSOR_OV7670 && sd->sensor != SENSOR_MT9M001 &&
1740 sd->sensor != SENSOR_MT9VPRB) {
1741 sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1742 V4L2_CID_HFLIP, 0, 1, 1, 0);
1743 sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1744 V4L2_CID_VFLIP, 0, 1, 1, 0);
Hans Verkuil63069da2012-05-06 09:28:29 -03001745 }
1746
1747 if (sd->sensor != SENSOR_SOI968 && sd->sensor != SENSOR_MT9VPRB &&
1748 sd->sensor != SENSOR_MT9M112 && sd->sensor != SENSOR_MT9M111 &&
1749 sd->sensor != SENSOR_MT9V111)
1750 sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1751 V4L2_CID_EXPOSURE, 0, 0x1780, 1, 0x33);
1752
1753 if (sd->sensor != SENSOR_MT9VPRB && sd->sensor != SENSOR_MT9M112 &&
1754 sd->sensor != SENSOR_MT9M111 && sd->sensor != SENSOR_MT9V111) {
1755 sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1756 V4L2_CID_GAIN, 0, 28, 1, 0);
1757 sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1758 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
Hans de Goedebc378fe2012-05-14 14:55:15 -03001759 }
1760
1761 sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1762 V4L2_CID_JPEG_COMPRESSION_QUALITY, 50, 90, 1, 80);
1763 if (hdl->error) {
1764 pr_err("Could not initialize controls\n");
1765 return hdl->error;
1766 }
1767
1768 v4l2_ctrl_cluster(4, &sd->brightness);
1769 v4l2_ctrl_cluster(2, &sd->blue);
1770 if (sd->hflip)
1771 v4l2_ctrl_cluster(2, &sd->hflip);
1772 if (sd->autogain) {
Hans Verkuil63069da2012-05-06 09:28:29 -03001773 if (sd->sensor == SENSOR_SOI968)
1774 /* this sensor doesn't have the exposure control and
1775 autogain is clustered with gain instead. This works
1776 because sd->exposure == NULL. */
1777 v4l2_ctrl_auto_cluster(3, &sd->autogain, 0, false);
1778 else
1779 /* Otherwise autogain is clustered with exposure. */
1780 v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
1781 }
Hans Verkuil63069da2012-05-06 09:28:29 -03001782 return 0;
1783}
1784
Brian Johnson26e744b2009-07-19 05:52:58 -03001785static int sd_init(struct gspca_dev *gspca_dev)
1786{
1787 struct sd *sd = (struct sd *) gspca_dev;
1788 int i;
1789 u8 value;
Morgan Phillips312487cc2014-09-08 09:32:22 -03001790 u8 i2c_init[9] = {
1791 0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03
1792 };
Brian Johnson26e744b2009-07-19 05:52:58 -03001793
1794 for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
1795 value = bridge_init[i][1];
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001796 reg_w(gspca_dev, bridge_init[i][0], &value, 1);
1797 if (gspca_dev->usb_err < 0) {
Joe Perches91f58422011-08-21 19:56:55 -03001798 pr_err("Device initialization failed\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001799 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001800 }
1801 }
1802
Brian Johnson0c045eb2010-03-16 13:58:27 -03001803 if (sd->flags & LED_REVERSE)
1804 reg_w1(gspca_dev, 0x1006, 0x00);
1805 else
1806 reg_w1(gspca_dev, 0x1006, 0x20);
1807
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001808 reg_w(gspca_dev, 0x10c0, i2c_init, 9);
1809 if (gspca_dev->usb_err < 0) {
Joe Perches91f58422011-08-21 19:56:55 -03001810 pr_err("Device initialization failed\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001811 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001812 }
1813
1814 switch (sd->sensor) {
1815 case SENSOR_OV9650:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001816 ov9650_init_sensor(gspca_dev);
1817 if (gspca_dev->usb_err < 0)
1818 break;
Joe Perches91f58422011-08-21 19:56:55 -03001819 pr_info("OV9650 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001820 break;
1821 case SENSOR_OV9655:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001822 ov9655_init_sensor(gspca_dev);
1823 if (gspca_dev->usb_err < 0)
1824 break;
Joe Perches91f58422011-08-21 19:56:55 -03001825 pr_info("OV9655 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001826 break;
1827 case SENSOR_SOI968:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001828 soi968_init_sensor(gspca_dev);
1829 if (gspca_dev->usb_err < 0)
1830 break;
Joe Perches91f58422011-08-21 19:56:55 -03001831 pr_info("SOI968 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001832 break;
1833 case SENSOR_OV7660:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001834 ov7660_init_sensor(gspca_dev);
1835 if (gspca_dev->usb_err < 0)
1836 break;
Joe Perches91f58422011-08-21 19:56:55 -03001837 pr_info("OV7660 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001838 break;
1839 case SENSOR_OV7670:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001840 ov7670_init_sensor(gspca_dev);
1841 if (gspca_dev->usb_err < 0)
1842 break;
Joe Perches91f58422011-08-21 19:56:55 -03001843 pr_info("OV7670 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001844 break;
1845 case SENSOR_MT9VPRB:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001846 mt9v_init_sensor(gspca_dev);
1847 if (gspca_dev->usb_err < 0)
1848 break;
Jean-François Moineff38d582012-03-19 04:55:16 -03001849 pr_info("MT9VPRB sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001850 break;
1851 case SENSOR_MT9M111:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001852 mt9m111_init_sensor(gspca_dev);
1853 if (gspca_dev->usb_err < 0)
1854 break;
Joe Perches91f58422011-08-21 19:56:55 -03001855 pr_info("MT9M111 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001856 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001857 case SENSOR_MT9M112:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001858 mt9m112_init_sensor(gspca_dev);
1859 if (gspca_dev->usb_err < 0)
1860 break;
Joe Perches91f58422011-08-21 19:56:55 -03001861 pr_info("MT9M112 sensor detected\n");
Brian Johnsone99ac542010-03-16 13:58:28 -03001862 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001863 case SENSOR_MT9M001:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001864 mt9m001_init_sensor(gspca_dev);
1865 if (gspca_dev->usb_err < 0)
1866 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001867 break;
1868 case SENSOR_HV7131R:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001869 hv7131r_init_sensor(gspca_dev);
1870 if (gspca_dev->usb_err < 0)
1871 break;
Joe Perches91f58422011-08-21 19:56:55 -03001872 pr_info("HV7131R sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001873 break;
1874 default:
Jean-François Moineff38d582012-03-19 04:55:16 -03001875 pr_err("Unsupported sensor\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001876 gspca_dev->usb_err = -ENODEV;
Brian Johnson26e744b2009-07-19 05:52:58 -03001877 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001878 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001879}
1880
1881static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
1882{
1883 struct sd *sd = (struct sd *) gspca_dev;
1884 u8 value;
Jean-François Moineff38d582012-03-19 04:55:16 -03001885
Brian Johnson26e744b2009-07-19 05:52:58 -03001886 switch (sd->sensor) {
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001887 case SENSOR_SOI968:
1888 if (mode & MODE_SXGA) {
1889 i2c_w1(gspca_dev, 0x17, 0x1d);
1890 i2c_w1(gspca_dev, 0x18, 0xbd);
1891 i2c_w1(gspca_dev, 0x19, 0x01);
1892 i2c_w1(gspca_dev, 0x1a, 0x81);
1893 i2c_w1(gspca_dev, 0x12, 0x00);
1894 sd->hstart = 140;
1895 sd->vstart = 19;
1896 } else {
1897 i2c_w1(gspca_dev, 0x17, 0x13);
1898 i2c_w1(gspca_dev, 0x18, 0x63);
1899 i2c_w1(gspca_dev, 0x19, 0x01);
1900 i2c_w1(gspca_dev, 0x1a, 0x79);
1901 i2c_w1(gspca_dev, 0x12, 0x40);
1902 sd->hstart = 60;
1903 sd->vstart = 11;
1904 }
1905 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001906 case SENSOR_OV9650:
1907 if (mode & MODE_SXGA) {
1908 i2c_w1(gspca_dev, 0x17, 0x1b);
1909 i2c_w1(gspca_dev, 0x18, 0xbc);
1910 i2c_w1(gspca_dev, 0x19, 0x01);
1911 i2c_w1(gspca_dev, 0x1a, 0x82);
1912 i2c_r1(gspca_dev, 0x12, &value);
1913 i2c_w1(gspca_dev, 0x12, value & 0x07);
1914 } else {
1915 i2c_w1(gspca_dev, 0x17, 0x24);
1916 i2c_w1(gspca_dev, 0x18, 0xc5);
1917 i2c_w1(gspca_dev, 0x19, 0x00);
1918 i2c_w1(gspca_dev, 0x1a, 0x3c);
1919 i2c_r1(gspca_dev, 0x12, &value);
1920 i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
1921 }
1922 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001923 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03001924 case SENSOR_MT9M111:
1925 if (mode & MODE_SXGA) {
1926 i2c_w2(gspca_dev, 0xf0, 0x0002);
1927 i2c_w2(gspca_dev, 0xc8, 0x970b);
1928 i2c_w2(gspca_dev, 0xf0, 0x0000);
1929 } else {
1930 i2c_w2(gspca_dev, 0xf0, 0x0002);
1931 i2c_w2(gspca_dev, 0xc8, 0x8000);
1932 i2c_w2(gspca_dev, 0xf0, 0x0000);
1933 }
1934 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001935 }
1936}
1937
Hans de Goeded80dd5d2012-01-01 16:03:37 -03001938static int sd_isoc_init(struct gspca_dev *gspca_dev)
1939{
1940 struct usb_interface *intf;
1941 u32 flags = gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv;
1942
1943 /*
1944 * When using the SN9C20X_I420 fmt the sn9c20x needs more bandwidth
1945 * than our regular bandwidth calculations reserve, so we force the
1946 * use of a specific altsetting when using the SN9C20X_I420 fmt.
1947 */
1948 if (!(flags & (MODE_RAW | MODE_JPEG))) {
1949 intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
1950
1951 if (intf->num_altsetting != 9) {
1952 pr_warn("sn9c20x camera with unknown number of alt "
Hans de Goede7135d882012-05-12 05:43:49 -03001953 "settings (%d), please report!\n",
1954 intf->num_altsetting);
Hans de Goeded80dd5d2012-01-01 16:03:37 -03001955 gspca_dev->alt = intf->num_altsetting;
1956 return 0;
1957 }
1958
Ondrej Zary1966bc22013-08-30 17:54:23 -03001959 switch (gspca_dev->pixfmt.width) {
Hans de Goeded80dd5d2012-01-01 16:03:37 -03001960 case 160: /* 160x120 */
1961 gspca_dev->alt = 2;
1962 break;
1963 case 320: /* 320x240 */
1964 gspca_dev->alt = 6;
1965 break;
1966 default: /* >= 640x480 */
1967 gspca_dev->alt = 9;
Jean-François Moineff38d582012-03-19 04:55:16 -03001968 break;
Hans de Goeded80dd5d2012-01-01 16:03:37 -03001969 }
1970 }
1971
1972 return 0;
1973}
1974
Brian Johnson26e744b2009-07-19 05:52:58 -03001975#define HW_WIN(mode, hstart, vstart) \
Jean-Francois Moine83955552009-12-12 06:58:01 -03001976((const u8 []){hstart, 0, vstart, 0, \
Brian Johnson26e744b2009-07-19 05:52:58 -03001977(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
1978(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)})
1979
1980#define CLR_WIN(width, height) \
1981((const u8 [])\
1982{0, width >> 2, 0, height >> 1,\
1983((width >> 10) & 0x01) | ((height >> 8) & 0x6)})
1984
1985static int sd_start(struct gspca_dev *gspca_dev)
1986{
1987 struct sd *sd = (struct sd *) gspca_dev;
1988 int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Ondrej Zary1966bc22013-08-30 17:54:23 -03001989 int width = gspca_dev->pixfmt.width;
1990 int height = gspca_dev->pixfmt.height;
Brian Johnson26e744b2009-07-19 05:52:58 -03001991 u8 fmt, scale = 0;
1992
Brian Johnson26e744b2009-07-19 05:52:58 -03001993 jpeg_define(sd->jpeg_hdr, height, width,
1994 0x21);
Hans Verkuil63069da2012-05-06 09:28:29 -03001995 jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual));
Brian Johnson26e744b2009-07-19 05:52:58 -03001996
1997 if (mode & MODE_RAW)
1998 fmt = 0x2d;
1999 else if (mode & MODE_JPEG)
Jean-François Moine4c632e42012-03-19 04:35:34 -03002000 fmt = 0x24;
Brian Johnson26e744b2009-07-19 05:52:58 -03002001 else
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002002 fmt = 0x2f; /* YUV 420 */
Jean-François Moine4c632e42012-03-19 04:35:34 -03002003 sd->fmt = fmt;
Brian Johnson26e744b2009-07-19 05:52:58 -03002004
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002005 switch (mode & SCALE_MASK) {
2006 case SCALE_1280x1024:
Brian Johnson26e744b2009-07-19 05:52:58 -03002007 scale = 0xc0;
Joe Perches91f58422011-08-21 19:56:55 -03002008 pr_info("Set 1280x1024\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002009 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002010 case SCALE_640x480:
Brian Johnson26e744b2009-07-19 05:52:58 -03002011 scale = 0x80;
Joe Perches91f58422011-08-21 19:56:55 -03002012 pr_info("Set 640x480\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002013 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002014 case SCALE_320x240:
Brian Johnson26e744b2009-07-19 05:52:58 -03002015 scale = 0x90;
Joe Perches91f58422011-08-21 19:56:55 -03002016 pr_info("Set 320x240\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002017 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002018 case SCALE_160x120:
Brian Johnson26e744b2009-07-19 05:52:58 -03002019 scale = 0xa0;
Joe Perches91f58422011-08-21 19:56:55 -03002020 pr_info("Set 160x120\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002021 break;
2022 }
2023
2024 configure_sensor_output(gspca_dev, mode);
Jean-François Moine9a731a32010-06-04 05:26:42 -03002025 reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
2026 reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
Brian Johnson26e744b2009-07-19 05:52:58 -03002027 reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
2028 reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
2029 reg_w1(gspca_dev, 0x1189, scale);
2030 reg_w1(gspca_dev, 0x10e0, fmt);
2031
Hans Verkuil63069da2012-05-06 09:28:29 -03002032 set_cmatrix(gspca_dev, v4l2_ctrl_g_ctrl(sd->brightness),
2033 v4l2_ctrl_g_ctrl(sd->contrast),
2034 v4l2_ctrl_g_ctrl(sd->saturation),
2035 v4l2_ctrl_g_ctrl(sd->hue));
2036 set_gamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma));
2037 set_redblue(gspca_dev, v4l2_ctrl_g_ctrl(sd->blue),
2038 v4l2_ctrl_g_ctrl(sd->red));
Hans de Goede6c6ee532012-07-08 19:41:14 +02002039 if (sd->gain)
2040 set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
2041 if (sd->exposure)
2042 set_exposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure));
2043 if (sd->hflip)
2044 set_hvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip),
2045 v4l2_ctrl_g_ctrl(sd->vflip));
Brian Johnson26e744b2009-07-19 05:52:58 -03002046
Brian Johnson0c045eb2010-03-16 13:58:27 -03002047 reg_w1(gspca_dev, 0x1007, 0x20);
Jean-François Moineccbaba42012-03-19 04:51:30 -03002048 reg_w1(gspca_dev, 0x1061, 0x03);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002049
2050 /* if JPEG, prepare the compression quality update */
2051 if (mode & MODE_JPEG) {
2052 sd->pktsz = sd->npkt = 0;
2053 sd->nchg = 0;
2054 sd->work_thread =
2055 create_singlethread_workqueue(KBUILD_MODNAME);
2056 }
2057
Jean-François Moinefe86ec72012-03-19 04:32:15 -03002058 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03002059}
2060
2061static void sd_stopN(struct gspca_dev *gspca_dev)
2062{
Brian Johnson0c045eb2010-03-16 13:58:27 -03002063 reg_w1(gspca_dev, 0x1007, 0x00);
Jean-François Moineccbaba42012-03-19 04:51:30 -03002064 reg_w1(gspca_dev, 0x1061, 0x01);
Brian Johnson26e744b2009-07-19 05:52:58 -03002065}
2066
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002067/* called on streamoff with alt==0 and on disconnect */
2068/* the usb_lock is held at entry - restore on exit */
2069static void sd_stop0(struct gspca_dev *gspca_dev)
2070{
2071 struct sd *sd = (struct sd *) gspca_dev;
2072
2073 if (sd->work_thread != NULL) {
2074 mutex_unlock(&gspca_dev->usb_lock);
2075 destroy_workqueue(sd->work_thread);
2076 mutex_lock(&gspca_dev->usb_lock);
2077 sd->work_thread = NULL;
2078 }
2079}
2080
Brian Johnsone1430472009-09-02 12:39:41 -03002081static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
Brian Johnson26e744b2009-07-19 05:52:58 -03002082{
2083 struct sd *sd = (struct sd *) gspca_dev;
Hans Verkuil63069da2012-05-06 09:28:29 -03002084 s32 cur_exp = v4l2_ctrl_g_ctrl(sd->exposure);
2085 s32 max = sd->exposure->maximum - sd->exposure_step;
2086 s32 min = sd->exposure->minimum + sd->exposure_step;
Brian Johnsone1430472009-09-02 12:39:41 -03002087 s16 new_exp;
Brian Johnson26e744b2009-07-19 05:52:58 -03002088
2089 /*
2090 * some hardcoded values are present
2091 * like those for maximal/minimal exposure
2092 * and exposure steps
2093 */
2094 if (avg_lum < MIN_AVG_LUM) {
Hans Verkuil63069da2012-05-06 09:28:29 -03002095 if (cur_exp > max)
Brian Johnson26e744b2009-07-19 05:52:58 -03002096 return;
2097
Hans Verkuil63069da2012-05-06 09:28:29 -03002098 new_exp = cur_exp + sd->exposure_step;
2099 if (new_exp > max)
2100 new_exp = max;
2101 if (new_exp < min)
2102 new_exp = min;
2103 v4l2_ctrl_s_ctrl(sd->exposure, new_exp);
Brian Johnson26e744b2009-07-19 05:52:58 -03002104
2105 sd->older_step = sd->old_step;
2106 sd->old_step = 1;
2107
2108 if (sd->old_step ^ sd->older_step)
2109 sd->exposure_step /= 2;
2110 else
2111 sd->exposure_step += 2;
2112 }
2113 if (avg_lum > MAX_AVG_LUM) {
Hans Verkuil63069da2012-05-06 09:28:29 -03002114 if (cur_exp < min)
Brian Johnson26e744b2009-07-19 05:52:58 -03002115 return;
Hans Verkuil63069da2012-05-06 09:28:29 -03002116 new_exp = cur_exp - sd->exposure_step;
2117 if (new_exp > max)
2118 new_exp = max;
2119 if (new_exp < min)
2120 new_exp = min;
2121 v4l2_ctrl_s_ctrl(sd->exposure, new_exp);
Brian Johnson26e744b2009-07-19 05:52:58 -03002122 sd->older_step = sd->old_step;
2123 sd->old_step = 0;
2124
2125 if (sd->old_step ^ sd->older_step)
2126 sd->exposure_step /= 2;
2127 else
2128 sd->exposure_step += 2;
2129 }
2130}
2131
Brian Johnsone1430472009-09-02 12:39:41 -03002132static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
2133{
2134 struct sd *sd = (struct sd *) gspca_dev;
Hans Verkuil63069da2012-05-06 09:28:29 -03002135 s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain);
Brian Johnsone1430472009-09-02 12:39:41 -03002136
Hans Verkuil63069da2012-05-06 09:28:29 -03002137 if (avg_lum < MIN_AVG_LUM && cur_gain < sd->gain->maximum)
2138 v4l2_ctrl_s_ctrl(sd->gain, cur_gain + 1);
2139 if (avg_lum > MAX_AVG_LUM && cur_gain > sd->gain->minimum)
2140 v4l2_ctrl_s_ctrl(sd->gain, cur_gain - 1);
Brian Johnsone1430472009-09-02 12:39:41 -03002141}
2142
2143static void sd_dqcallback(struct gspca_dev *gspca_dev)
2144{
2145 struct sd *sd = (struct sd *) gspca_dev;
2146 int avg_lum;
2147
Hans de Goede6c6ee532012-07-08 19:41:14 +02002148 if (sd->autogain == NULL || !v4l2_ctrl_g_ctrl(sd->autogain))
Brian Johnsone1430472009-09-02 12:39:41 -03002149 return;
2150
2151 avg_lum = atomic_read(&sd->avg_lum);
2152 if (sd->sensor == SENSOR_SOI968)
2153 do_autogain(gspca_dev, avg_lum);
2154 else
2155 do_autoexposure(gspca_dev, avg_lum);
2156}
2157
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002158/* JPEG quality update */
2159/* This function is executed from a work queue. */
2160static void qual_upd(struct work_struct *work)
2161{
2162 struct sd *sd = container_of(work, struct sd, work);
2163 struct gspca_dev *gspca_dev = &sd->gspca_dev;
Hans Verkuil63069da2012-05-06 09:28:29 -03002164 s32 qual = v4l2_ctrl_g_ctrl(sd->jpegqual);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002165
Hans de Goede844db452012-09-09 07:30:02 -03002166 /* To protect gspca_dev->usb_buf and gspca_dev->usb_err */
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002167 mutex_lock(&gspca_dev->usb_lock);
Hans Verkuil63069da2012-05-06 09:28:29 -03002168 PDEBUG(D_STREAM, "qual_upd %d%%", qual);
Hans de Goede844db452012-09-09 07:30:02 -03002169 gspca_dev->usb_err = 0;
Hans Verkuil63069da2012-05-06 09:28:29 -03002170 set_quality(gspca_dev, qual);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002171 mutex_unlock(&gspca_dev->usb_lock);
2172}
2173
Peter Senna Tschudin8099aff2013-01-24 19:29:06 -03002174#if IS_ENABLED(CONFIG_INPUT)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002175static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
2176 u8 *data, /* interrupt packet */
2177 int len) /* interrupt packet length */
2178{
2179 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03002180
Brian Johnson33ddc162010-04-18 21:42:40 -03002181 if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
Jean-François Moineff38d582012-03-19 04:55:16 -03002182 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
2183 input_sync(gspca_dev->input_dev);
2184 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
2185 input_sync(gspca_dev->input_dev);
2186 return 0;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002187 }
Jean-François Moineff38d582012-03-19 04:55:16 -03002188 return -EINVAL;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002189}
2190#endif
2191
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002192/* check the JPEG compression */
2193static void transfer_check(struct gspca_dev *gspca_dev,
2194 u8 *data)
2195{
2196 struct sd *sd = (struct sd *) gspca_dev;
2197 int new_qual, r;
2198
2199 new_qual = 0;
2200
2201 /* if USB error, discard the frame and decrease the quality */
2202 if (data[6] & 0x08) { /* USB FIFO full */
2203 gspca_dev->last_packet_type = DISCARD_PACKET;
2204 new_qual = -5;
2205 } else {
2206
2207 /* else, compute the filling rate and a new JPEG quality */
2208 r = (sd->pktsz * 100) /
2209 (sd->npkt *
2210 gspca_dev->urb[0]->iso_frame_desc[0].length);
2211 if (r >= 85)
2212 new_qual = -3;
2213 else if (r < 75)
2214 new_qual = 2;
2215 }
2216 if (new_qual != 0) {
2217 sd->nchg += new_qual;
2218 if (sd->nchg < -6 || sd->nchg >= 12) {
Hans Verkuil63069da2012-05-06 09:28:29 -03002219 /* Note: we are in interrupt context, so we can't
2220 use v4l2_ctrl_g/s_ctrl here. Access the value
2221 directly instead. */
2222 s32 curqual = sd->jpegqual->cur.val;
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002223 sd->nchg = 0;
Hans Verkuil63069da2012-05-06 09:28:29 -03002224 new_qual += curqual;
2225 if (new_qual < sd->jpegqual->minimum)
2226 new_qual = sd->jpegqual->minimum;
2227 else if (new_qual > sd->jpegqual->maximum)
2228 new_qual = sd->jpegqual->maximum;
2229 if (new_qual != curqual) {
2230 sd->jpegqual->cur.val = new_qual;
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002231 queue_work(sd->work_thread, &sd->work);
2232 }
2233 }
2234 } else {
2235 sd->nchg = 0;
2236 }
2237 sd->pktsz = sd->npkt = 0;
2238}
2239
Brian Johnson26e744b2009-07-19 05:52:58 -03002240static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Brian Johnson26e744b2009-07-19 05:52:58 -03002241 u8 *data, /* isoc packet */
2242 int len) /* iso packet length */
2243{
2244 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03002245 int avg_lum, is_jpeg;
Morgan Phillips312487cc2014-09-08 09:32:22 -03002246 static const u8 frame_header[] = {
2247 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96
2248 };
Jean-François Moineff38d582012-03-19 04:55:16 -03002249
2250 is_jpeg = (sd->fmt & 0x03) == 0;
Jean-François Moine1f42df02012-03-19 04:22:44 -03002251 if (len >= 64 && memcmp(data, frame_header, 6) == 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03002252 avg_lum = ((data[35] >> 2) & 3) |
2253 (data[20] << 2) |
2254 (data[19] << 10);
2255 avg_lum += ((data[35] >> 4) & 3) |
2256 (data[22] << 2) |
2257 (data[21] << 10);
2258 avg_lum += ((data[35] >> 6) & 3) |
2259 (data[24] << 2) |
2260 (data[23] << 10);
2261 avg_lum += (data[36] & 3) |
2262 (data[26] << 2) |
2263 (data[25] << 10);
2264 avg_lum += ((data[36] >> 2) & 3) |
2265 (data[28] << 2) |
2266 (data[27] << 10);
2267 avg_lum += ((data[36] >> 4) & 3) |
2268 (data[30] << 2) |
2269 (data[29] << 10);
2270 avg_lum += ((data[36] >> 6) & 3) |
2271 (data[32] << 2) |
2272 (data[31] << 10);
2273 avg_lum += ((data[44] >> 4) & 3) |
2274 (data[34] << 2) |
2275 (data[33] << 10);
2276 avg_lum >>= 9;
2277 atomic_set(&sd->avg_lum, avg_lum);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002278
Jean-François Moineff38d582012-03-19 04:55:16 -03002279 if (is_jpeg)
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002280 transfer_check(gspca_dev, data);
2281
Jean-François Moine04d174e2010-09-13 05:22:37 -03002282 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Jean-François Moine1f42df02012-03-19 04:22:44 -03002283 len -= 64;
2284 if (len == 0)
2285 return;
2286 data += 64;
Brian Johnson26e744b2009-07-19 05:52:58 -03002287 }
2288 if (gspca_dev->last_packet_type == LAST_PACKET) {
Jean-François Moineff38d582012-03-19 04:55:16 -03002289 if (is_jpeg) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002290 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002291 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002292 gspca_frame_add(gspca_dev, INTER_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002293 data, len);
2294 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002295 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002296 data, len);
2297 }
2298 } else {
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002299 /* if JPEG, count the packets and their size */
Jean-François Moineff38d582012-03-19 04:55:16 -03002300 if (is_jpeg) {
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002301 sd->npkt++;
2302 sd->pktsz += len;
2303 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002304 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Brian Johnson26e744b2009-07-19 05:52:58 -03002305 }
2306}
2307
2308/* sub-driver description */
2309static const struct sd_desc sd_desc = {
Jean-François Moineff38d582012-03-19 04:55:16 -03002310 .name = KBUILD_MODNAME,
Brian Johnson26e744b2009-07-19 05:52:58 -03002311 .config = sd_config,
2312 .init = sd_init,
Hans Verkuil63069da2012-05-06 09:28:29 -03002313 .init_controls = sd_init_controls,
Hans de Goeded80dd5d2012-01-01 16:03:37 -03002314 .isoc_init = sd_isoc_init,
Brian Johnson26e744b2009-07-19 05:52:58 -03002315 .start = sd_start,
2316 .stopN = sd_stopN,
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002317 .stop0 = sd_stop0,
Brian Johnson26e744b2009-07-19 05:52:58 -03002318 .pkt_scan = sd_pkt_scan,
Peter Senna Tschudin8099aff2013-01-24 19:29:06 -03002319#if IS_ENABLED(CONFIG_INPUT)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002320 .int_pkt_scan = sd_int_pkt_scan,
2321#endif
Brian Johnsone1430472009-09-02 12:39:41 -03002322 .dq_callback = sd_dqcallback,
Brian Johnson26e744b2009-07-19 05:52:58 -03002323#ifdef CONFIG_VIDEO_ADV_DEBUG
2324 .set_register = sd_dbg_s_register,
2325 .get_register = sd_dbg_g_register,
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03002326 .get_chip_info = sd_chip_info,
Brian Johnson26e744b2009-07-19 05:52:58 -03002327#endif
Brian Johnson26e744b2009-07-19 05:52:58 -03002328};
2329
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002330#define SN9C20X(sensor, i2c_addr, flags) \
Brian Johnson0c045eb2010-03-16 13:58:27 -03002331 .driver_info = ((flags & 0xff) << 16) \
Brian Johnson26e744b2009-07-19 05:52:58 -03002332 | (SENSOR_ ## sensor << 8) \
2333 | (i2c_addr)
2334
Jean-François Moine95c967c2011-01-13 05:20:29 -03002335static const struct usb_device_id device_table[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03002336 {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
2337 {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
2338 {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002339 {USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002340 {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, LED_REVERSE)},
2341 {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30,
2342 (FLIP_DETECT | HAS_NO_BUTTON))},
Brian Johnson26e744b2009-07-19 05:52:58 -03002343 {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
2344 {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
2345 {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
2346 {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)},
Hans de Goede779b51f2011-02-16 08:17:36 -03002347 {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, FLIP_DETECT)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002348 {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)},
2349 {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)},
2350 {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
2351 {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002352 {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002353 {USB_DEVICE(0x0c45, 0x628c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002354 {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)},
2355 {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
2356 {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
2357 {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
Frank Schaefer114cfbd2011-09-23 05:05:37 -03002358 {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, LED_REVERSE)},
Hans de Goedeb39e0cb2011-02-16 08:33:16 -03002359 {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, LED_REVERSE)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002360 {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
2361 {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
2362 {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
2363 {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
Wolfram Sang61f03192014-02-01 15:26:00 -03002364 {USB_DEVICE(0x0458, 0x7045), SN9C20X(MT9M112, 0x5d, LED_REVERSE)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002365 {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)},
2366 {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002367 {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
2368 {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)},
2369 {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)},
2370 {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002371 {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002372 {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)},
2373 {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)},
2374 {}
2375};
2376MODULE_DEVICE_TABLE(usb, device_table);
2377
2378/* -- device connect -- */
2379static int sd_probe(struct usb_interface *intf,
2380 const struct usb_device_id *id)
2381{
2382 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
2383 THIS_MODULE);
2384}
2385
Brian Johnson26e744b2009-07-19 05:52:58 -03002386static struct usb_driver sd_driver = {
Jean-François Moineff38d582012-03-19 04:55:16 -03002387 .name = KBUILD_MODNAME,
Brian Johnson26e744b2009-07-19 05:52:58 -03002388 .id_table = device_table,
2389 .probe = sd_probe,
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002390 .disconnect = gspca_disconnect,
Brian Johnson26e744b2009-07-19 05:52:58 -03002391#ifdef CONFIG_PM
2392 .suspend = gspca_suspend,
2393 .resume = gspca_resume,
2394 .reset_resume = gspca_resume,
2395#endif
2396};
2397
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -08002398module_usb_driver(sd_driver);