blob: b43f89fee6c1d3beba6f33c9ea4e8072e23b5b5a [file] [log] [blame]
Thomas Gleixnerfd9871f2019-05-19 15:51:54 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Brian Johnson26e744b2009-07-19 05:52:58 -03002/*
3 * Sonix sn9c201 sn9c202 library
Jean-François Moineff38d582012-03-19 04:55:16 -03004 *
5 * Copyright (C) 2012 Jean-Francois Moine <http://moinejf.free.fr>
Brian Johnson26e744b2009-07-19 05:52:58 -03006 * Copyright (C) 2008-2009 microdia project <microdia@googlegroups.com>
7 * Copyright (C) 2009 Brian Johnson <brijohn@gmail.com>
Brian Johnson26e744b2009-07-19 05:52:58 -03008 */
9
Joe Perches91f58422011-08-21 19:56:55 -030010#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
Brian Johnson26e744b2009-07-19 05:52:58 -030012#include <linux/input.h>
Brian Johnson26e744b2009-07-19 05:52:58 -030013
Mauro Carvalho Chehabc15b95e2009-07-19 18:03:23 -030014#include "gspca.h"
15#include "jpeg.h"
16
Brian Johnson7ddaac72010-03-16 13:58:27 -030017#include <linux/dmi.h>
Mauro Carvalho Chehabc15b95e2009-07-19 18:03:23 -030018
Mauro Carvalho Chehab1ddc9f72016-10-18 17:44:16 -020019MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, microdia project <microdia@googlegroups.com>");
Brian Johnson26e744b2009-07-19 05:52:58 -030020MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver");
21MODULE_LICENSE("GPL");
22
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -030023/*
24 * Pixel format private data
25 */
26#define SCALE_MASK 0x0f
27#define SCALE_160x120 0
28#define SCALE_320x240 1
29#define SCALE_640x480 2
30#define SCALE_1280x1024 3
Brian Johnson26e744b2009-07-19 05:52:58 -030031#define MODE_RAW 0x10
32#define MODE_JPEG 0x20
33#define MODE_SXGA 0x80
34
35#define SENSOR_OV9650 0
36#define SENSOR_OV9655 1
37#define SENSOR_SOI968 2
38#define SENSOR_OV7660 3
39#define SENSOR_OV7670 4
40#define SENSOR_MT9V011 5
41#define SENSOR_MT9V111 6
42#define SENSOR_MT9V112 7
43#define SENSOR_MT9M001 8
44#define SENSOR_MT9M111 9
Brian Johnsone99ac542010-03-16 13:58:28 -030045#define SENSOR_MT9M112 10
46#define SENSOR_HV7131R 11
Jean-François Moine9637c652012-03-24 09:16:14 -030047#define SENSOR_MT9VPRB 12
Brian Johnson26e744b2009-07-19 05:52:58 -030048
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030049/* camera flags */
Brian Johnson33ddc162010-04-18 21:42:40 -030050#define HAS_NO_BUTTON 0x1
Brian Johnson0c045eb2010-03-16 13:58:27 -030051#define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */
Brian Johnson7ddaac72010-03-16 13:58:27 -030052#define FLIP_DETECT 0x4
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030053
Brian Johnson26e744b2009-07-19 05:52:58 -030054/* specific webcam descriptor */
55struct sd {
56 struct gspca_dev gspca_dev;
57
Hans Verkuil63069da2012-05-06 09:28:29 -030058 struct { /* color control cluster */
59 struct v4l2_ctrl *brightness;
60 struct v4l2_ctrl *contrast;
61 struct v4l2_ctrl *saturation;
62 struct v4l2_ctrl *hue;
63 };
64 struct { /* blue/red balance control cluster */
65 struct v4l2_ctrl *blue;
66 struct v4l2_ctrl *red;
67 };
68 struct { /* h/vflip control cluster */
69 struct v4l2_ctrl *hflip;
70 struct v4l2_ctrl *vflip;
71 };
72 struct v4l2_ctrl *gamma;
73 struct { /* autogain and exposure or gain control cluster */
74 struct v4l2_ctrl *autogain;
75 struct v4l2_ctrl *exposure;
76 struct v4l2_ctrl *gain;
77 };
78 struct v4l2_ctrl *jpegqual;
Jean-François Moinec5224d82012-03-19 04:30:07 -030079
Jean-François Moine92dcffc2012-03-19 04:47:24 -030080 struct work_struct work;
Jean-François Moine92dcffc2012-03-19 04:47:24 -030081
82 u32 pktsz; /* (used by pkt_scan) */
83 u16 npkt;
84 s8 nchg;
Jean-François Moine4c632e42012-03-19 04:35:34 -030085 u8 fmt; /* (used for JPEG QTAB update */
86
Brian Johnson26e744b2009-07-19 05:52:58 -030087#define MIN_AVG_LUM 80
88#define MAX_AVG_LUM 130
89 atomic_t avg_lum;
90 u8 old_step;
91 u8 older_step;
92 u8 exposure_step;
93
Brian Johnson26e744b2009-07-19 05:52:58 -030094 u8 i2c_addr;
Jean-François Moinec4407fe2012-03-24 09:23:56 -030095 u8 i2c_intf;
Brian Johnson26e744b2009-07-19 05:52:58 -030096 u8 sensor;
97 u8 hstart;
98 u8 vstart;
99
Jean-François Moine9a731a32010-06-04 05:26:42 -0300100 u8 jpeg_hdr[JPEG_HDR_SZ];
Brian Johnson26e744b2009-07-19 05:52:58 -0300101
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -0300102 u8 flags;
Brian Johnson26e744b2009-07-19 05:52:58 -0300103};
104
Jean-François Moine92dcffc2012-03-19 04:47:24 -0300105static void qual_upd(struct work_struct *work);
106
Joe Perches58aa68c2009-09-02 01:12:13 -0300107struct i2c_reg_u8 {
108 u8 reg;
109 u8 val;
110};
111
112struct i2c_reg_u16 {
113 u8 reg;
114 u16 val;
115};
116
Brian Johnson7ddaac72010-03-16 13:58:27 -0300117static const struct dmi_system_id flip_dmi_table[] = {
118 {
119 .ident = "MSI MS-1034",
120 .matches = {
121 DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."),
122 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1034"),
123 DMI_MATCH(DMI_PRODUCT_VERSION, "0341")
124 }
125 },
126 {
127 .ident = "MSI MS-1632",
128 .matches = {
129 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
130 DMI_MATCH(DMI_BOARD_NAME, "MS-1632")
131 }
132 },
Brian Johnsone077f862010-04-05 20:52:52 -0300133 {
Hans de Goedebcc6f662011-02-17 06:27:57 -0300134 .ident = "MSI MS-1633X",
135 .matches = {
136 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
137 DMI_MATCH(DMI_BOARD_NAME, "MS-1633X")
138 }
139 },
140 {
Brian Johnson5d26ed92010-04-10 02:12:46 -0300141 .ident = "MSI MS-1635X",
142 .matches = {
143 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
144 DMI_MATCH(DMI_BOARD_NAME, "MS-1635X")
145 }
146 },
147 {
Brian Johnsone077f862010-04-05 20:52:52 -0300148 .ident = "ASUSTeK W7J",
149 .matches = {
150 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
151 DMI_MATCH(DMI_BOARD_NAME, "W7J ")
152 }
153 },
Brian Johnson7ddaac72010-03-16 13:58:27 -0300154 {}
155};
156
Brian Johnson26e744b2009-07-19 05:52:58 -0300157static const struct v4l2_pix_format vga_mode[] = {
158 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300159 .bytesperline = 160,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300160 .sizeimage = 160 * 120 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300161 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300162 .priv = SCALE_160x120 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300163 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
164 .bytesperline = 160,
165 .sizeimage = 160 * 120,
166 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300167 .priv = SCALE_160x120 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300168 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300169 .bytesperline = 160,
Brian Johnson26e744b2009-07-19 05:52:58 -0300170 .sizeimage = 240 * 120,
171 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300172 .priv = SCALE_160x120},
Brian Johnson26e744b2009-07-19 05:52:58 -0300173 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300174 .bytesperline = 320,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300175 .sizeimage = 320 * 240 * 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_320x240 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300178 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
179 .bytesperline = 320,
180 .sizeimage = 320 * 240 ,
181 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300182 .priv = SCALE_320x240 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300183 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300184 .bytesperline = 320,
Brian Johnson26e744b2009-07-19 05:52:58 -0300185 .sizeimage = 480 * 240 ,
186 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300187 .priv = SCALE_320x240},
Brian Johnson26e744b2009-07-19 05:52:58 -0300188 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300189 .bytesperline = 640,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300190 .sizeimage = 640 * 480 * 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_640x480 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300193 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
194 .bytesperline = 640,
195 .sizeimage = 640 * 480,
196 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300197 .priv = SCALE_640x480 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300198 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300199 .bytesperline = 640,
Brian Johnson26e744b2009-07-19 05:52:58 -0300200 .sizeimage = 960 * 480,
201 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300202 .priv = SCALE_640x480},
Brian Johnson26e744b2009-07-19 05:52:58 -0300203};
204
205static const struct v4l2_pix_format sxga_mode[] = {
206 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300207 .bytesperline = 160,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300208 .sizeimage = 160 * 120 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300209 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300210 .priv = SCALE_160x120 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300211 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
212 .bytesperline = 160,
213 .sizeimage = 160 * 120,
214 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300215 .priv = SCALE_160x120 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300216 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300217 .bytesperline = 160,
Brian Johnson26e744b2009-07-19 05:52:58 -0300218 .sizeimage = 240 * 120,
219 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300220 .priv = SCALE_160x120},
Brian Johnson26e744b2009-07-19 05:52:58 -0300221 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300222 .bytesperline = 320,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300223 .sizeimage = 320 * 240 * 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_320x240 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300226 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
227 .bytesperline = 320,
228 .sizeimage = 320 * 240 ,
229 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300230 .priv = SCALE_320x240 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300231 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300232 .bytesperline = 320,
Brian Johnson26e744b2009-07-19 05:52:58 -0300233 .sizeimage = 480 * 240 ,
234 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300235 .priv = SCALE_320x240},
Brian Johnson26e744b2009-07-19 05:52:58 -0300236 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300237 .bytesperline = 640,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300238 .sizeimage = 640 * 480 * 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_640x480 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300241 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
242 .bytesperline = 640,
243 .sizeimage = 640 * 480,
244 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300245 .priv = SCALE_640x480 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300246 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300247 .bytesperline = 640,
Brian Johnson26e744b2009-07-19 05:52:58 -0300248 .sizeimage = 960 * 480,
249 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300250 .priv = SCALE_640x480},
Brian Johnson26e744b2009-07-19 05:52:58 -0300251 {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
252 .bytesperline = 1280,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300253 .sizeimage = 1280 * 1024,
Brian Johnson26e744b2009-07-19 05:52:58 -0300254 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300255 .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
Brian Johnson26e744b2009-07-19 05:52:58 -0300256};
257
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -0300258static const struct v4l2_pix_format mono_mode[] = {
259 {160, 120, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
260 .bytesperline = 160,
261 .sizeimage = 160 * 120,
262 .colorspace = V4L2_COLORSPACE_SRGB,
263 .priv = SCALE_160x120 | MODE_RAW},
264 {320, 240, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
265 .bytesperline = 320,
266 .sizeimage = 320 * 240 ,
267 .colorspace = V4L2_COLORSPACE_SRGB,
268 .priv = SCALE_320x240 | MODE_RAW},
269 {640, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
270 .bytesperline = 640,
271 .sizeimage = 640 * 480,
272 .colorspace = V4L2_COLORSPACE_SRGB,
273 .priv = SCALE_640x480 | MODE_RAW},
274 {1280, 1024, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
275 .bytesperline = 1280,
276 .sizeimage = 1280 * 1024,
277 .colorspace = V4L2_COLORSPACE_SRGB,
278 .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
279};
280
Joe Perches58aa68c2009-09-02 01:12:13 -0300281static const s16 hsv_red_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300282 41, 44, 46, 48, 50, 52, 54, 56,
283 58, 60, 62, 64, 66, 68, 70, 72,
284 74, 76, 78, 80, 81, 83, 85, 87,
285 88, 90, 92, 93, 95, 97, 98, 100,
286 101, 102, 104, 105, 107, 108, 109, 110,
287 112, 113, 114, 115, 116, 117, 118, 119,
288 120, 121, 122, 123, 123, 124, 125, 125,
289 126, 127, 127, 128, 128, 129, 129, 129,
290 130, 130, 130, 130, 131, 131, 131, 131,
291 131, 131, 131, 131, 130, 130, 130, 130,
292 129, 129, 129, 128, 128, 127, 127, 126,
293 125, 125, 124, 123, 122, 122, 121, 120,
294 119, 118, 117, 116, 115, 114, 112, 111,
295 110, 109, 107, 106, 105, 103, 102, 101,
296 99, 98, 96, 94, 93, 91, 90, 88,
297 86, 84, 83, 81, 79, 77, 75, 74,
298 72, 70, 68, 66, 64, 62, 60, 58,
299 56, 54, 52, 49, 47, 45, 43, 41,
300 39, 36, 34, 32, 30, 28, 25, 23,
301 21, 19, 16, 14, 12, 9, 7, 5,
302 3, 0, -1, -3, -6, -8, -10, -12,
303 -15, -17, -19, -22, -24, -26, -28, -30,
304 -33, -35, -37, -39, -41, -44, -46, -48,
305 -50, -52, -54, -56, -58, -60, -62, -64,
306 -66, -68, -70, -72, -74, -76, -78, -80,
307 -81, -83, -85, -87, -88, -90, -92, -93,
308 -95, -97, -98, -100, -101, -102, -104, -105,
309 -107, -108, -109, -110, -112, -113, -114, -115,
310 -116, -117, -118, -119, -120, -121, -122, -123,
311 -123, -124, -125, -125, -126, -127, -127, -128,
312 -128, -128, -128, -128, -128, -128, -128, -128,
313 -128, -128, -128, -128, -128, -128, -128, -128,
314 -128, -128, -128, -128, -128, -128, -128, -128,
315 -128, -127, -127, -126, -125, -125, -124, -123,
316 -122, -122, -121, -120, -119, -118, -117, -116,
317 -115, -114, -112, -111, -110, -109, -107, -106,
318 -105, -103, -102, -101, -99, -98, -96, -94,
319 -93, -91, -90, -88, -86, -84, -83, -81,
320 -79, -77, -75, -74, -72, -70, -68, -66,
321 -64, -62, -60, -58, -56, -54, -52, -49,
322 -47, -45, -43, -41, -39, -36, -34, -32,
323 -30, -28, -25, -23, -21, -19, -16, -14,
324 -12, -9, -7, -5, -3, 0, 1, 3,
325 6, 8, 10, 12, 15, 17, 19, 22,
326 24, 26, 28, 30, 33, 35, 37, 39, 41
327};
328
Joe Perches58aa68c2009-09-02 01:12:13 -0300329static const s16 hsv_red_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300330 82, 80, 78, 76, 74, 73, 71, 69,
331 67, 65, 63, 61, 58, 56, 54, 52,
332 50, 48, 46, 44, 41, 39, 37, 35,
333 32, 30, 28, 26, 23, 21, 19, 16,
334 14, 12, 10, 7, 5, 3, 0, -1,
335 -3, -6, -8, -10, -13, -15, -17, -19,
336 -22, -24, -26, -29, -31, -33, -35, -38,
337 -40, -42, -44, -46, -48, -51, -53, -55,
338 -57, -59, -61, -63, -65, -67, -69, -71,
339 -73, -75, -77, -79, -81, -82, -84, -86,
340 -88, -89, -91, -93, -94, -96, -98, -99,
341 -101, -102, -104, -105, -106, -108, -109, -110,
342 -112, -113, -114, -115, -116, -117, -119, -120,
343 -120, -121, -122, -123, -124, -125, -126, -126,
344 -127, -128, -128, -128, -128, -128, -128, -128,
345 -128, -128, -128, -128, -128, -128, -128, -128,
346 -128, -128, -128, -128, -128, -128, -128, -128,
347 -128, -128, -128, -128, -128, -128, -128, -128,
348 -127, -127, -126, -125, -125, -124, -123, -122,
349 -121, -120, -119, -118, -117, -116, -115, -114,
350 -113, -111, -110, -109, -107, -106, -105, -103,
351 -102, -100, -99, -97, -96, -94, -92, -91,
352 -89, -87, -85, -84, -82, -80, -78, -76,
353 -74, -73, -71, -69, -67, -65, -63, -61,
354 -58, -56, -54, -52, -50, -48, -46, -44,
355 -41, -39, -37, -35, -32, -30, -28, -26,
356 -23, -21, -19, -16, -14, -12, -10, -7,
357 -5, -3, 0, 1, 3, 6, 8, 10,
358 13, 15, 17, 19, 22, 24, 26, 29,
359 31, 33, 35, 38, 40, 42, 44, 46,
360 48, 51, 53, 55, 57, 59, 61, 63,
361 65, 67, 69, 71, 73, 75, 77, 79,
362 81, 82, 84, 86, 88, 89, 91, 93,
363 94, 96, 98, 99, 101, 102, 104, 105,
364 106, 108, 109, 110, 112, 113, 114, 115,
365 116, 117, 119, 120, 120, 121, 122, 123,
366 124, 125, 126, 126, 127, 128, 128, 129,
367 129, 130, 130, 131, 131, 131, 131, 132,
368 132, 132, 132, 132, 132, 132, 132, 132,
369 132, 132, 132, 131, 131, 131, 130, 130,
370 130, 129, 129, 128, 127, 127, 126, 125,
371 125, 124, 123, 122, 121, 120, 119, 118,
372 117, 116, 115, 114, 113, 111, 110, 109,
373 107, 106, 105, 103, 102, 100, 99, 97,
374 96, 94, 92, 91, 89, 87, 85, 84, 82
375};
376
Joe Perches58aa68c2009-09-02 01:12:13 -0300377static const s16 hsv_green_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300378 -124, -124, -125, -125, -125, -125, -125, -125,
379 -125, -126, -126, -125, -125, -125, -125, -125,
380 -125, -124, -124, -124, -123, -123, -122, -122,
381 -121, -121, -120, -120, -119, -118, -117, -117,
382 -116, -115, -114, -113, -112, -111, -110, -109,
383 -108, -107, -105, -104, -103, -102, -100, -99,
384 -98, -96, -95, -93, -92, -91, -89, -87,
385 -86, -84, -83, -81, -79, -77, -76, -74,
386 -72, -70, -69, -67, -65, -63, -61, -59,
387 -57, -55, -53, -51, -49, -47, -45, -43,
388 -41, -39, -37, -35, -33, -30, -28, -26,
389 -24, -22, -20, -18, -15, -13, -11, -9,
390 -7, -4, -2, 0, 1, 3, 6, 8,
391 10, 12, 14, 17, 19, 21, 23, 25,
392 27, 29, 32, 34, 36, 38, 40, 42,
393 44, 46, 48, 50, 52, 54, 56, 58,
394 60, 62, 64, 66, 68, 70, 71, 73,
395 75, 77, 78, 80, 82, 83, 85, 87,
396 88, 90, 91, 93, 94, 96, 97, 98,
397 100, 101, 102, 104, 105, 106, 107, 108,
398 109, 111, 112, 113, 113, 114, 115, 116,
399 117, 118, 118, 119, 120, 120, 121, 122,
400 122, 123, 123, 124, 124, 124, 125, 125,
401 125, 125, 125, 125, 125, 126, 126, 125,
402 125, 125, 125, 125, 125, 124, 124, 124,
403 123, 123, 122, 122, 121, 121, 120, 120,
404 119, 118, 117, 117, 116, 115, 114, 113,
405 112, 111, 110, 109, 108, 107, 105, 104,
406 103, 102, 100, 99, 98, 96, 95, 93,
407 92, 91, 89, 87, 86, 84, 83, 81,
408 79, 77, 76, 74, 72, 70, 69, 67,
409 65, 63, 61, 59, 57, 55, 53, 51,
410 49, 47, 45, 43, 41, 39, 37, 35,
411 33, 30, 28, 26, 24, 22, 20, 18,
412 15, 13, 11, 9, 7, 4, 2, 0,
413 -1, -3, -6, -8, -10, -12, -14, -17,
414 -19, -21, -23, -25, -27, -29, -32, -34,
415 -36, -38, -40, -42, -44, -46, -48, -50,
416 -52, -54, -56, -58, -60, -62, -64, -66,
417 -68, -70, -71, -73, -75, -77, -78, -80,
418 -82, -83, -85, -87, -88, -90, -91, -93,
419 -94, -96, -97, -98, -100, -101, -102, -104,
420 -105, -106, -107, -108, -109, -111, -112, -113,
421 -113, -114, -115, -116, -117, -118, -118, -119,
422 -120, -120, -121, -122, -122, -123, -123, -124, -124
423};
424
Joe Perches58aa68c2009-09-02 01:12:13 -0300425static const s16 hsv_green_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300426 -100, -99, -98, -97, -95, -94, -93, -91,
427 -90, -89, -87, -86, -84, -83, -81, -80,
428 -78, -76, -75, -73, -71, -70, -68, -66,
429 -64, -63, -61, -59, -57, -55, -53, -51,
430 -49, -48, -46, -44, -42, -40, -38, -36,
431 -34, -32, -30, -27, -25, -23, -21, -19,
432 -17, -15, -13, -11, -9, -7, -4, -2,
433 0, 1, 3, 5, 7, 9, 11, 14,
434 16, 18, 20, 22, 24, 26, 28, 30,
435 32, 34, 36, 38, 40, 42, 44, 46,
436 48, 50, 52, 54, 56, 58, 59, 61,
437 63, 65, 67, 68, 70, 72, 74, 75,
438 77, 78, 80, 82, 83, 85, 86, 88,
439 89, 90, 92, 93, 95, 96, 97, 98,
440 100, 101, 102, 103, 104, 105, 106, 107,
441 108, 109, 110, 111, 112, 112, 113, 114,
442 115, 115, 116, 116, 117, 117, 118, 118,
443 119, 119, 119, 120, 120, 120, 120, 120,
444 121, 121, 121, 121, 121, 121, 120, 120,
445 120, 120, 120, 119, 119, 119, 118, 118,
446 117, 117, 116, 116, 115, 114, 114, 113,
447 112, 111, 111, 110, 109, 108, 107, 106,
448 105, 104, 103, 102, 100, 99, 98, 97,
449 95, 94, 93, 91, 90, 89, 87, 86,
450 84, 83, 81, 80, 78, 76, 75, 73,
451 71, 70, 68, 66, 64, 63, 61, 59,
452 57, 55, 53, 51, 49, 48, 46, 44,
453 42, 40, 38, 36, 34, 32, 30, 27,
454 25, 23, 21, 19, 17, 15, 13, 11,
455 9, 7, 4, 2, 0, -1, -3, -5,
456 -7, -9, -11, -14, -16, -18, -20, -22,
457 -24, -26, -28, -30, -32, -34, -36, -38,
458 -40, -42, -44, -46, -48, -50, -52, -54,
459 -56, -58, -59, -61, -63, -65, -67, -68,
460 -70, -72, -74, -75, -77, -78, -80, -82,
461 -83, -85, -86, -88, -89, -90, -92, -93,
462 -95, -96, -97, -98, -100, -101, -102, -103,
463 -104, -105, -106, -107, -108, -109, -110, -111,
464 -112, -112, -113, -114, -115, -115, -116, -116,
465 -117, -117, -118, -118, -119, -119, -119, -120,
466 -120, -120, -120, -120, -121, -121, -121, -121,
467 -121, -121, -120, -120, -120, -120, -120, -119,
468 -119, -119, -118, -118, -117, -117, -116, -116,
469 -115, -114, -114, -113, -112, -111, -111, -110,
470 -109, -108, -107, -106, -105, -104, -103, -102, -100
471};
472
Joe Perches58aa68c2009-09-02 01:12:13 -0300473static const s16 hsv_blue_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300474 112, 113, 114, 114, 115, 116, 117, 117,
475 118, 118, 119, 119, 120, 120, 120, 121,
476 121, 121, 122, 122, 122, 122, 122, 122,
477 122, 122, 122, 122, 122, 122, 121, 121,
478 121, 120, 120, 120, 119, 119, 118, 118,
479 117, 116, 116, 115, 114, 113, 113, 112,
480 111, 110, 109, 108, 107, 106, 105, 104,
481 103, 102, 100, 99, 98, 97, 95, 94,
482 93, 91, 90, 88, 87, 85, 84, 82,
483 80, 79, 77, 76, 74, 72, 70, 69,
484 67, 65, 63, 61, 60, 58, 56, 54,
485 52, 50, 48, 46, 44, 42, 40, 38,
486 36, 34, 32, 30, 28, 26, 24, 22,
487 19, 17, 15, 13, 11, 9, 7, 5,
488 2, 0, -1, -3, -5, -7, -9, -12,
489 -14, -16, -18, -20, -22, -24, -26, -28,
490 -31, -33, -35, -37, -39, -41, -43, -45,
491 -47, -49, -51, -53, -54, -56, -58, -60,
492 -62, -64, -66, -67, -69, -71, -73, -74,
493 -76, -78, -79, -81, -83, -84, -86, -87,
494 -89, -90, -92, -93, -94, -96, -97, -98,
495 -99, -101, -102, -103, -104, -105, -106, -107,
496 -108, -109, -110, -111, -112, -113, -114, -114,
497 -115, -116, -117, -117, -118, -118, -119, -119,
498 -120, -120, -120, -121, -121, -121, -122, -122,
499 -122, -122, -122, -122, -122, -122, -122, -122,
500 -122, -122, -121, -121, -121, -120, -120, -120,
501 -119, -119, -118, -118, -117, -116, -116, -115,
502 -114, -113, -113, -112, -111, -110, -109, -108,
503 -107, -106, -105, -104, -103, -102, -100, -99,
504 -98, -97, -95, -94, -93, -91, -90, -88,
505 -87, -85, -84, -82, -80, -79, -77, -76,
506 -74, -72, -70, -69, -67, -65, -63, -61,
507 -60, -58, -56, -54, -52, -50, -48, -46,
508 -44, -42, -40, -38, -36, -34, -32, -30,
509 -28, -26, -24, -22, -19, -17, -15, -13,
510 -11, -9, -7, -5, -2, 0, 1, 3,
511 5, 7, 9, 12, 14, 16, 18, 20,
512 22, 24, 26, 28, 31, 33, 35, 37,
513 39, 41, 43, 45, 47, 49, 51, 53,
514 54, 56, 58, 60, 62, 64, 66, 67,
515 69, 71, 73, 74, 76, 78, 79, 81,
516 83, 84, 86, 87, 89, 90, 92, 93,
517 94, 96, 97, 98, 99, 101, 102, 103,
518 104, 105, 106, 107, 108, 109, 110, 111, 112
519};
520
Joe Perches58aa68c2009-09-02 01:12:13 -0300521static const s16 hsv_blue_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300522 -11, -13, -15, -17, -19, -21, -23, -25,
523 -27, -29, -31, -33, -35, -37, -39, -41,
524 -43, -45, -46, -48, -50, -52, -54, -55,
525 -57, -59, -61, -62, -64, -66, -67, -69,
526 -71, -72, -74, -75, -77, -78, -80, -81,
527 -83, -84, -86, -87, -88, -90, -91, -92,
528 -93, -95, -96, -97, -98, -99, -100, -101,
529 -102, -103, -104, -105, -106, -106, -107, -108,
530 -109, -109, -110, -111, -111, -112, -112, -113,
531 -113, -114, -114, -114, -115, -115, -115, -115,
532 -116, -116, -116, -116, -116, -116, -116, -116,
533 -116, -115, -115, -115, -115, -114, -114, -114,
534 -113, -113, -112, -112, -111, -111, -110, -110,
535 -109, -108, -108, -107, -106, -105, -104, -103,
536 -102, -101, -100, -99, -98, -97, -96, -95,
537 -94, -93, -91, -90, -89, -88, -86, -85,
538 -84, -82, -81, -79, -78, -76, -75, -73,
539 -71, -70, -68, -67, -65, -63, -62, -60,
540 -58, -56, -55, -53, -51, -49, -47, -45,
541 -44, -42, -40, -38, -36, -34, -32, -30,
542 -28, -26, -24, -22, -20, -18, -16, -14,
543 -12, -10, -8, -6, -4, -2, 0, 1,
544 3, 5, 7, 9, 11, 13, 15, 17,
545 19, 21, 23, 25, 27, 29, 31, 33,
546 35, 37, 39, 41, 43, 45, 46, 48,
547 50, 52, 54, 55, 57, 59, 61, 62,
548 64, 66, 67, 69, 71, 72, 74, 75,
549 77, 78, 80, 81, 83, 84, 86, 87,
550 88, 90, 91, 92, 93, 95, 96, 97,
551 98, 99, 100, 101, 102, 103, 104, 105,
552 106, 106, 107, 108, 109, 109, 110, 111,
553 111, 112, 112, 113, 113, 114, 114, 114,
554 115, 115, 115, 115, 116, 116, 116, 116,
555 116, 116, 116, 116, 116, 115, 115, 115,
556 115, 114, 114, 114, 113, 113, 112, 112,
557 111, 111, 110, 110, 109, 108, 108, 107,
558 106, 105, 104, 103, 102, 101, 100, 99,
559 98, 97, 96, 95, 94, 93, 91, 90,
560 89, 88, 86, 85, 84, 82, 81, 79,
561 78, 76, 75, 73, 71, 70, 68, 67,
562 65, 63, 62, 60, 58, 56, 55, 53,
563 51, 49, 47, 45, 44, 42, 40, 38,
564 36, 34, 32, 30, 28, 26, 24, 22,
565 20, 18, 16, 14, 12, 10, 8, 6,
566 4, 2, 0, -1, -3, -5, -7, -9, -11
567};
568
Jean-François Moinedae1de62012-03-24 09:20:25 -0300569static const u16 bridge_init[][2] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300570 {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c},
571 {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40},
572 {0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10},
573 {0x106b, 0x08}, {0x1188, 0x87}, {0x11a1, 0x00},
574 {0x11a2, 0x00}, {0x11a3, 0x6a}, {0x11a4, 0x50},
575 {0x11ab, 0x00}, {0x11ac, 0x00}, {0x11ad, 0x50},
576 {0x11ae, 0x3c}, {0x118a, 0x04}, {0x0395, 0x04},
577 {0x11b8, 0x3a}, {0x118b, 0x0e}, {0x10f7, 0x05},
578 {0x10f8, 0x14}, {0x10fa, 0xff}, {0x10f9, 0x00},
579 {0x11ba, 0x0a}, {0x11a5, 0x2d}, {0x11a6, 0x2d},
580 {0x11a7, 0x3a}, {0x11a8, 0x05}, {0x11a9, 0x04},
581 {0x11aa, 0x3f}, {0x11af, 0x28}, {0x11b0, 0xd8},
582 {0x11b1, 0x14}, {0x11b2, 0xec}, {0x11b3, 0x32},
583 {0x11b4, 0xdd}, {0x11b5, 0x32}, {0x11b6, 0xdd},
584 {0x10e0, 0x2c}, {0x11bc, 0x40}, {0x11bd, 0x01},
585 {0x11be, 0xf0}, {0x11bf, 0x00}, {0x118c, 0x1f},
586 {0x118d, 0x1f}, {0x118e, 0x1f}, {0x118f, 0x1f},
587 {0x1180, 0x01}, {0x1181, 0x00}, {0x1182, 0x01},
Brian Johnson0c045eb2010-03-16 13:58:27 -0300588 {0x1183, 0x00}, {0x1184, 0x50}, {0x1185, 0x80},
589 {0x1007, 0x00}
Brian Johnson26e744b2009-07-19 05:52:58 -0300590};
591
592/* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300593static const u8 ov_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300594 0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */,
595 0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */,
596 0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */,
597 0x30 /* 4x */, 0x31 /* 4.25x */, 0x32 /* 4.5x */, 0x33 /* 4.75x */,
598 0x34 /* 5x */, 0x35 /* 5.25x */, 0x36 /* 5.5x */, 0x37 /* 5.75x */,
599 0x38 /* 6x */, 0x39 /* 6.25x */, 0x3a /* 6.5x */, 0x3b /* 6.75x */,
600 0x3c /* 7x */, 0x3d /* 7.25x */, 0x3e /* 7.5x */, 0x3f /* 7.75x */,
601 0x70 /* 8x */
602};
603
604/* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300605static const u16 micron1_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300606 /* 1x 1.25x 1.5x 1.75x */
607 0x0020, 0x0028, 0x0030, 0x0038,
608 /* 2x 2.25x 2.5x 2.75x */
609 0x00a0, 0x00a4, 0x00a8, 0x00ac,
610 /* 3x 3.25x 3.5x 3.75x */
611 0x00b0, 0x00b4, 0x00b8, 0x00bc,
612 /* 4x 4.25x 4.5x 4.75x */
613 0x00c0, 0x00c4, 0x00c8, 0x00cc,
614 /* 5x 5.25x 5.5x 5.75x */
615 0x00d0, 0x00d4, 0x00d8, 0x00dc,
616 /* 6x 6.25x 6.5x 6.75x */
617 0x00e0, 0x00e4, 0x00e8, 0x00ec,
618 /* 7x 7.25x 7.5x 7.75x */
619 0x00f0, 0x00f4, 0x00f8, 0x00fc,
620 /* 8x */
621 0x01c0
622};
623
624/* mt9m001 sensor uses a different gain formula then other micron sensors */
625/* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300626static const u16 micron2_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300627 /* 1x 1.25x 1.5x 1.75x */
628 0x0008, 0x000a, 0x000c, 0x000e,
629 /* 2x 2.25x 2.5x 2.75x */
630 0x0010, 0x0012, 0x0014, 0x0016,
631 /* 3x 3.25x 3.5x 3.75x */
632 0x0018, 0x001a, 0x001c, 0x001e,
633 /* 4x 4.25x 4.5x 4.75x */
634 0x0020, 0x0051, 0x0052, 0x0053,
635 /* 5x 5.25x 5.5x 5.75x */
636 0x0054, 0x0055, 0x0056, 0x0057,
637 /* 6x 6.25x 6.5x 6.75x */
638 0x0058, 0x0059, 0x005a, 0x005b,
639 /* 7x 7.25x 7.5x 7.75x */
640 0x005c, 0x005d, 0x005e, 0x005f,
641 /* 8x */
642 0x0060
643};
644
645/* Gain = .5 + bit[7:0] / 16 */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300646static const u8 hv7131r_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300647 0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */,
648 0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */,
649 0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */,
650 0x38 /* 4x */, 0x3c /* 4.25x */, 0x40 /* 4.5x */, 0x44 /* 4.75x */,
651 0x48 /* 5x */, 0x4c /* 5.25x */, 0x50 /* 5.5x */, 0x54 /* 5.75x */,
652 0x58 /* 6x */, 0x5c /* 6.25x */, 0x60 /* 6.5x */, 0x64 /* 6.75x */,
653 0x68 /* 7x */, 0x6c /* 7.25x */, 0x70 /* 7.5x */, 0x74 /* 7.75x */,
654 0x78 /* 8x */
655};
656
Jean-François Moinedae1de62012-03-24 09:20:25 -0300657static const struct i2c_reg_u8 soi968_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300658 {0x0c, 0x00}, {0x0f, 0x1f},
Brian Johnson26e744b2009-07-19 05:52:58 -0300659 {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
660 {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
661 {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
662 {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20},
663 {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e},
Brian Johnsone1430472009-09-02 12:39:41 -0300664 {0x13, 0x8b}, {0x12, 0x40}, {0x17, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300665 {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79},
666 {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40},
667 {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32},
668 {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80},
669};
670
Jean-François Moinedae1de62012-03-24 09:20:25 -0300671static const struct i2c_reg_u8 ov7660_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300672 {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
673 {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
674 {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
Hans de Goede8bc50f32011-02-16 07:11:14 -0300675 /* HDG Set hstart and hstop, datasheet default 0x11, 0x61, using
676 0x10, 0x61 and sd->hstart, vstart = 3, fixes ugly colored borders */
677 {0x17, 0x10}, {0x18, 0x61},
Brian Johnson26e744b2009-07-19 05:52:58 -0300678 {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43},
Jean-François Moinea1ac5dc2012-03-24 09:33:42 -0300679 {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0x00},
680 {0x2e, 0x00}, {0x01, 0x78}, {0x02, 0x50},
Brian Johnson26e744b2009-07-19 05:52:58 -0300681};
682
Jean-François Moinedae1de62012-03-24 09:20:25 -0300683static const struct i2c_reg_u8 ov7670_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300684 {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
Brian Johnson26e744b2009-07-19 05:52:58 -0300685 {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
686 {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
687 {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
688 {0x0d, 0x40}, {0x14, 0x28}, {0xa5, 0x05}, {0xab, 0x07},
689 {0x24, 0x95}, {0x25, 0x33}, {0x26, 0xe3}, {0x9f, 0x75},
690 {0xa0, 0x65}, {0xa1, 0x0b}, {0xa6, 0xd8}, {0xa7, 0xd8},
691 {0xa8, 0xf0}, {0xa9, 0x90}, {0xaa, 0x94}, {0x13, 0xe5},
692 {0x0e, 0x61}, {0x0f, 0x4b}, {0x16, 0x02}, {0x1e, 0x27},
693 {0x21, 0x02}, {0x22, 0x91}, {0x29, 0x07}, {0x33, 0x0b},
694 {0x35, 0x0b}, {0x37, 0x1d}, {0x38, 0x71}, {0x39, 0x2a},
695 {0x3c, 0x78}, {0x4d, 0x40}, {0x4e, 0x20}, {0x69, 0x00},
696 {0x74, 0x19}, {0x8d, 0x4f}, {0x8e, 0x00}, {0x8f, 0x00},
697 {0x90, 0x00}, {0x91, 0x00}, {0x96, 0x00}, {0x9a, 0x80},
698 {0xb0, 0x84}, {0xb1, 0x0c}, {0xb2, 0x0e}, {0xb3, 0x82},
699 {0xb8, 0x0a}, {0x43, 0x0a}, {0x44, 0xf0}, {0x45, 0x20},
700 {0x46, 0x7d}, {0x47, 0x29}, {0x48, 0x4a}, {0x59, 0x8c},
701 {0x5a, 0xa5}, {0x5b, 0xde}, {0x5c, 0x96}, {0x5d, 0x66},
702 {0x5e, 0x10}, {0x6c, 0x0a}, {0x6d, 0x55}, {0x6e, 0x11},
703 {0x6f, 0x9e}, {0x6a, 0x40}, {0x01, 0x40}, {0x02, 0x40},
704 {0x13, 0xe7}, {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x02},
705 {0x52, 0x1d}, {0x53, 0x56}, {0x54, 0x73}, {0x55, 0x0a},
706 {0x56, 0x55}, {0x57, 0x80}, {0x58, 0x9e}, {0x41, 0x08},
707 {0x3f, 0x02}, {0x75, 0x03}, {0x76, 0x63}, {0x4c, 0x04},
708 {0x77, 0x06}, {0x3d, 0x02}, {0x4b, 0x09}, {0xc9, 0x30},
709 {0x41, 0x08}, {0x56, 0x48}, {0x34, 0x11}, {0xa4, 0x88},
710 {0x96, 0x00}, {0x97, 0x30}, {0x98, 0x20}, {0x99, 0x30},
711 {0x9a, 0x84}, {0x9b, 0x29}, {0x9c, 0x03}, {0x9d, 0x99},
712 {0x9e, 0x7f}, {0x78, 0x04}, {0x79, 0x01}, {0xc8, 0xf0},
713 {0x79, 0x0f}, {0xc8, 0x00}, {0x79, 0x10}, {0xc8, 0x7e},
714 {0x79, 0x0a}, {0xc8, 0x80}, {0x79, 0x0b}, {0xc8, 0x01},
715 {0x79, 0x0c}, {0xc8, 0x0f}, {0x79, 0x0d}, {0xc8, 0x20},
716 {0x79, 0x09}, {0xc8, 0x80}, {0x79, 0x02}, {0xc8, 0xc0},
717 {0x79, 0x03}, {0xc8, 0x40}, {0x79, 0x05}, {0xc8, 0x30},
718 {0x79, 0x26}, {0x62, 0x20}, {0x63, 0x00}, {0x64, 0x06},
719 {0x65, 0x00}, {0x66, 0x05}, {0x94, 0x05}, {0x95, 0x0a},
720 {0x17, 0x13}, {0x18, 0x01}, {0x19, 0x02}, {0x1a, 0x7a},
721 {0x46, 0x59}, {0x47, 0x30}, {0x58, 0x9a}, {0x59, 0x84},
722 {0x5a, 0x91}, {0x5b, 0x57}, {0x5c, 0x75}, {0x5d, 0x6d},
723 {0x5e, 0x13}, {0x64, 0x07}, {0x94, 0x07}, {0x95, 0x0d},
724 {0xa6, 0xdf}, {0xa7, 0xdf}, {0x48, 0x4d}, {0x51, 0x00},
725 {0x6b, 0x0a}, {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00},
726 {0x92, 0x00}, {0x93, 0x00}, {0x55, 0x0a}, {0x56, 0x60},
727 {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d},
728 {0x53, 0x56}, {0x54, 0x73}, {0x58, 0x9a}, {0x4f, 0x6e},
729 {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, {0x53, 0x56},
730 {0x54, 0x73}, {0x58, 0x9a}, {0x3f, 0x01}, {0x7b, 0x03},
731 {0x7c, 0x09}, {0x7d, 0x16}, {0x7e, 0x38}, {0x7f, 0x47},
732 {0x80, 0x53}, {0x81, 0x5e}, {0x82, 0x6a}, {0x83, 0x74},
733 {0x84, 0x80}, {0x85, 0x8c}, {0x86, 0x9b}, {0x87, 0xb2},
734 {0x88, 0xcc}, {0x89, 0xe5}, {0x7a, 0x24}, {0x3b, 0x00},
735 {0x9f, 0x76}, {0xa0, 0x65}, {0x13, 0xe2}, {0x6b, 0x0a},
736 {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, {0x92, 0x00},
737 {0x93, 0x00},
738};
739
Jean-François Moinedae1de62012-03-24 09:20:25 -0300740static const struct i2c_reg_u8 ov9650_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300741 {0x00, 0x00}, {0x01, 0x78},
Brian Johnson26e744b2009-07-19 05:52:58 -0300742 {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
743 {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
744 {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
745 {0x0e, 0xa0}, {0x0f, 0x52}, {0x10, 0x7c},
746 {0x11, 0x80}, {0x12, 0x45}, {0x13, 0xc2},
747 {0x14, 0x2e}, {0x15, 0x00}, {0x16, 0x07},
748 {0x17, 0x24}, {0x18, 0xc5}, {0x19, 0x00},
749 {0x1a, 0x3c}, {0x1b, 0x00}, {0x1e, 0x04},
750 {0x1f, 0x00}, {0x24, 0x78}, {0x25, 0x68},
751 {0x26, 0xd4}, {0x27, 0x80}, {0x28, 0x80},
752 {0x29, 0x30}, {0x2a, 0x00}, {0x2b, 0x00},
753 {0x2c, 0x80}, {0x2d, 0x00}, {0x2e, 0x00},
754 {0x2f, 0x00}, {0x30, 0x08}, {0x31, 0x30},
755 {0x32, 0x84}, {0x33, 0xe2}, {0x34, 0xbf},
756 {0x35, 0x81}, {0x36, 0xf9}, {0x37, 0x00},
757 {0x38, 0x93}, {0x39, 0x50}, {0x3a, 0x01},
758 {0x3b, 0x01}, {0x3c, 0x73}, {0x3d, 0x19},
759 {0x3e, 0x0b}, {0x3f, 0x80}, {0x40, 0xc1},
760 {0x41, 0x00}, {0x42, 0x08}, {0x67, 0x80},
761 {0x68, 0x80}, {0x69, 0x40}, {0x6a, 0x00},
762 {0x6b, 0x0a}, {0x8b, 0x06}, {0x8c, 0x20},
763 {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0xdf},
764 {0x92, 0x00}, {0x93, 0x00}, {0x94, 0x88},
765 {0x95, 0x88}, {0x96, 0x04}, {0xa1, 0x00},
766 {0xa5, 0x80}, {0xa8, 0x80}, {0xa9, 0xb8},
767 {0xaa, 0x92}, {0xab, 0x0a},
768};
769
Jean-François Moinedae1de62012-03-24 09:20:25 -0300770static const struct i2c_reg_u8 ov9655_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300771 {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300772 {0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
773 {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
774 {0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57},
775 {0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c}, {0x3d, 0x19},
776 {0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40}, {0x42, 0x80},
777 {0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a}, {0x48, 0x3c},
778 {0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc}, {0x4d, 0xdc},
779 {0x4e, 0xdc}, {0x6c, 0x04}, {0x6f, 0x9e}, {0x70, 0x05},
780 {0x71, 0x78}, {0x77, 0x02}, {0x8a, 0x23}, {0x90, 0x7e},
781 {0x91, 0x7c}, {0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68},
782 {0xa6, 0x60}, {0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92},
783 {0xab, 0x04}, {0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80},
784 {0xaf, 0x80}, {0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00},
785 {0xb6, 0xaf}, {0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44},
786 {0xbe, 0x3b}, {0xbf, 0x3a}, {0xc1, 0xc8}, {0xc2, 0x01},
Brian Johnson26e744b2009-07-19 05:52:58 -0300787 {0xc4, 0x00}, {0xc6, 0x85}, {0xc7, 0x81}, {0xc9, 0xe0},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300788 {0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x2d, 0x00},
789 {0x2e, 0x00}, {0x01, 0x80}, {0x02, 0x80}, {0x12, 0x61},
Brian Johnson26e744b2009-07-19 05:52:58 -0300790 {0x36, 0xfa}, {0x8c, 0x8d}, {0xc0, 0xaa}, {0x69, 0x0a},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300791 {0x03, 0x09}, {0x17, 0x16}, {0x18, 0x6e}, {0x19, 0x01},
792 {0x1a, 0x3e}, {0x32, 0x09}, {0x2a, 0x10}, {0x2b, 0x0a},
793 {0x92, 0x00}, {0x93, 0x00}, {0xa1, 0x00}, {0x10, 0x7c},
794 {0x04, 0x03}, {0x00, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300795};
796
Jean-François Moinedae1de62012-03-24 09:20:25 -0300797static const struct i2c_reg_u16 mt9v112_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300798 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020},
799 {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
800 {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
801 {0x05, 0x0000}, {0x06, 0x340c}, {0x3b, 0x042a},
802 {0x3c, 0x0400}, {0xf0, 0x0002}, {0x2e, 0x0c58},
803 {0x5b, 0x0001}, {0xc8, 0x9f0b}, {0xf0, 0x0001},
804 {0x9b, 0x5300}, {0xf0, 0x0000}, {0x2b, 0x0020},
805 {0x2c, 0x002a}, {0x2d, 0x0032}, {0x2e, 0x0020},
806 {0x09, 0x01dc}, {0x01, 0x000c}, {0x02, 0x0020},
807 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
808 {0x05, 0x0098}, {0x20, 0x0703}, {0x09, 0x01f2},
809 {0x2b, 0x00a0}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
810 {0x2e, 0x00a0}, {0x01, 0x000c}, {0x02, 0x0020},
811 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
812 {0x05, 0x0098}, {0x09, 0x01c1}, {0x2b, 0x00ae},
813 {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
814};
815
Jean-François Moinedae1de62012-03-24 09:20:25 -0300816static const struct i2c_reg_u16 mt9v111_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300817 {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
Brian Johnson6ea23bd2010-05-05 13:22:45 -0300818 {0x01, 0x0001}, {0x05, 0x0004}, {0x2d, 0xe0a0},
819 {0x2e, 0x0c64}, {0x2f, 0x0064}, {0x06, 0x600e},
820 {0x08, 0x0480}, {0x01, 0x0004}, {0x02, 0x0016},
821 {0x03, 0x01e7}, {0x04, 0x0287}, {0x05, 0x0004},
822 {0x06, 0x002d}, {0x07, 0x3002}, {0x08, 0x0008},
823 {0x0e, 0x0008}, {0x20, 0x0000}
Brian Johnson26e744b2009-07-19 05:52:58 -0300824};
825
Jean-François Moinedae1de62012-03-24 09:20:25 -0300826static const struct i2c_reg_u16 mt9v011_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300827 {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
828 {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1},
829 {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006},
830 {0x0d, 0x0002}, {0x0a, 0x0000}, {0x0b, 0x0000},
831 {0x0c, 0x0000}, {0x0d, 0x0000}, {0x0e, 0x0000},
832 {0x0f, 0x0000}, {0x10, 0x0000}, {0x11, 0x0000},
833 {0x12, 0x0000}, {0x13, 0x0000}, {0x14, 0x0000},
834 {0x15, 0x0000}, {0x16, 0x0000}, {0x17, 0x0000},
835 {0x18, 0x0000}, {0x19, 0x0000}, {0x1a, 0x0000},
836 {0x1b, 0x0000}, {0x1c, 0x0000}, {0x1d, 0x0000},
837 {0x32, 0x0000}, {0x20, 0x1101}, {0x21, 0x0000},
838 {0x22, 0x0000}, {0x23, 0x0000}, {0x24, 0x0000},
839 {0x25, 0x0000}, {0x26, 0x0000}, {0x27, 0x0024},
840 {0x2f, 0xf7b0}, {0x30, 0x0005}, {0x31, 0x0000},
841 {0x32, 0x0000}, {0x33, 0x0000}, {0x34, 0x0100},
842 {0x3d, 0x068f}, {0x40, 0x01e0}, {0x41, 0x00d1},
843 {0x44, 0x0082}, {0x5a, 0x0000}, {0x5b, 0x0000},
844 {0x5c, 0x0000}, {0x5d, 0x0000}, {0x5e, 0x0000},
845 {0x5f, 0xa31d}, {0x62, 0x0611}, {0x0a, 0x0000},
846 {0x06, 0x0029}, {0x05, 0x0009}, {0x20, 0x1101},
847 {0x20, 0x1101}, {0x09, 0x0064}, {0x07, 0x0003},
848 {0x2b, 0x0033}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
849 {0x2e, 0x0033}, {0x07, 0x0002}, {0x06, 0x0000},
850 {0x06, 0x0029}, {0x05, 0x0009},
851};
852
Jean-François Moinedae1de62012-03-24 09:20:25 -0300853static const struct i2c_reg_u16 mt9m001_init[] = {
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -0300854 {0x0d, 0x0001},
855 {0x0d, 0x0000},
856 {0x04, 0x0500}, /* hres = 1280 */
857 {0x03, 0x0400}, /* vres = 1024 */
858 {0x20, 0x1100},
859 {0x06, 0x0010},
860 {0x2b, 0x0024},
861 {0x2e, 0x0024},
862 {0x35, 0x0024},
863 {0x2d, 0x0020},
864 {0x2c, 0x0020},
865 {0x09, 0x0ad4},
866 {0x35, 0x0057},
Brian Johnson26e744b2009-07-19 05:52:58 -0300867};
868
Jean-François Moinedae1de62012-03-24 09:20:25 -0300869static const struct i2c_reg_u16 mt9m111_init[] = {
Brian Johnson13a84fa2009-09-03 19:07:13 -0300870 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
871 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
Brian Johnson4d708a52009-09-03 19:10:15 -0300872 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
873 {0xf0, 0x0000},
Brian Johnson26e744b2009-07-19 05:52:58 -0300874};
875
Jean-François Moinedae1de62012-03-24 09:20:25 -0300876static const struct i2c_reg_u16 mt9m112_init[] = {
Brian Johnsone99ac542010-03-16 13:58:28 -0300877 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
878 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
879 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
880 {0xf0, 0x0000},
881};
882
Jean-François Moinedae1de62012-03-24 09:20:25 -0300883static const struct i2c_reg_u8 hv7131r_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300884 {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
885 {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
886 {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
887 {0x01, 0x08}, {0x01, 0x08}, {0x25, 0x07},
888 {0x26, 0xc3}, {0x27, 0x50}, {0x30, 0x62},
889 {0x31, 0x10}, {0x32, 0x06}, {0x33, 0x10},
890 {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00},
891 {0x23, 0x09}, {0x01, 0x08},
892};
893
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300894static void reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
Brian Johnson26e744b2009-07-19 05:52:58 -0300895{
896 struct usb_device *dev = gspca_dev->dev;
897 int result;
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300898
899 if (gspca_dev->usb_err < 0)
900 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300901 result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
902 0x00,
903 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
904 reg,
905 0x00,
906 gspca_dev->usb_buf,
907 length,
908 500);
909 if (unlikely(result < 0 || result != length)) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300910 pr_err("Read register %02x failed %d\n", reg, result);
911 gspca_dev->usb_err = result;
Brian Johnson26e744b2009-07-19 05:52:58 -0300912 }
Brian Johnson26e744b2009-07-19 05:52:58 -0300913}
914
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300915static void reg_w(struct gspca_dev *gspca_dev, u16 reg,
Joe Perches58aa68c2009-09-02 01:12:13 -0300916 const u8 *buffer, int length)
Brian Johnson26e744b2009-07-19 05:52:58 -0300917{
918 struct usb_device *dev = gspca_dev->dev;
919 int result;
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300920
921 if (gspca_dev->usb_err < 0)
922 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300923 memcpy(gspca_dev->usb_buf, buffer, length);
924 result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
925 0x08,
926 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
927 reg,
928 0x00,
929 gspca_dev->usb_buf,
930 length,
931 500);
932 if (unlikely(result < 0 || result != length)) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300933 pr_err("Write register %02x failed %d\n", reg, result);
934 gspca_dev->usb_err = result;
Brian Johnson26e744b2009-07-19 05:52:58 -0300935 }
Brian Johnson26e744b2009-07-19 05:52:58 -0300936}
937
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300938static void reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
Brian Johnson26e744b2009-07-19 05:52:58 -0300939{
Jean-François Moineff38d582012-03-19 04:55:16 -0300940 reg_w(gspca_dev, reg, &value, 1);
Brian Johnson26e744b2009-07-19 05:52:58 -0300941}
942
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300943static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
Brian Johnson26e744b2009-07-19 05:52:58 -0300944{
945 int i;
Jean-François Moineff38d582012-03-19 04:55:16 -0300946
Brian Johnson26e744b2009-07-19 05:52:58 -0300947 reg_w(gspca_dev, 0x10c0, buffer, 8);
948 for (i = 0; i < 5; i++) {
949 reg_r(gspca_dev, 0x10c0, 1);
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300950 if (gspca_dev->usb_err < 0)
951 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300952 if (gspca_dev->usb_buf[0] & 0x04) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300953 if (gspca_dev->usb_buf[0] & 0x08) {
954 pr_err("i2c_w error\n");
955 gspca_dev->usb_err = -EIO;
956 }
957 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300958 }
Jean-François Moinee71389b2012-03-19 04:45:20 -0300959 msleep(10);
Brian Johnson26e744b2009-07-19 05:52:58 -0300960 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300961 pr_err("i2c_w reg %02x no response\n", buffer[2]);
962/* gspca_dev->usb_err = -EIO; fixme: may occur */
Brian Johnson26e744b2009-07-19 05:52:58 -0300963}
964
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300965static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
Brian Johnson26e744b2009-07-19 05:52:58 -0300966{
967 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson26e744b2009-07-19 05:52:58 -0300968 u8 row[8];
969
970 /*
971 * from the point of view of the bridge, the length
972 * includes the address
973 */
Jean-François Moinec4407fe2012-03-24 09:23:56 -0300974 row[0] = sd->i2c_intf | (2 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -0300975 row[1] = sd->i2c_addr;
976 row[2] = reg;
977 row[3] = val;
978 row[4] = 0x00;
979 row[5] = 0x00;
980 row[6] = 0x00;
981 row[7] = 0x10;
982
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300983 i2c_w(gspca_dev, row);
Brian Johnson26e744b2009-07-19 05:52:58 -0300984}
985
Jean-François Moined4689b72012-03-19 04:42:45 -0300986static void i2c_w1_buf(struct gspca_dev *gspca_dev,
Jean-François Moinedae1de62012-03-24 09:20:25 -0300987 const struct i2c_reg_u8 *buf, int sz)
Jean-François Moined4689b72012-03-19 04:42:45 -0300988{
989 while (--sz >= 0) {
990 i2c_w1(gspca_dev, buf->reg, buf->val);
991 buf++;
992 }
993}
994
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300995static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
Brian Johnson26e744b2009-07-19 05:52:58 -0300996{
997 struct sd *sd = (struct sd *) gspca_dev;
998 u8 row[8];
999
1000 /*
1001 * from the point of view of the bridge, the length
1002 * includes the address
1003 */
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001004 row[0] = sd->i2c_intf | (3 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001005 row[1] = sd->i2c_addr;
1006 row[2] = reg;
Jean-François Moineff38d582012-03-19 04:55:16 -03001007 row[3] = val >> 8;
1008 row[4] = val;
Brian Johnson26e744b2009-07-19 05:52:58 -03001009 row[5] = 0x00;
1010 row[6] = 0x00;
1011 row[7] = 0x10;
1012
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001013 i2c_w(gspca_dev, row);
Brian Johnson26e744b2009-07-19 05:52:58 -03001014}
1015
Jean-François Moined4689b72012-03-19 04:42:45 -03001016static void i2c_w2_buf(struct gspca_dev *gspca_dev,
Jean-François Moinedae1de62012-03-24 09:20:25 -03001017 const struct i2c_reg_u16 *buf, int sz)
Jean-François Moined4689b72012-03-19 04:42:45 -03001018{
1019 while (--sz >= 0) {
1020 i2c_w2(gspca_dev, buf->reg, buf->val);
1021 buf++;
1022 }
1023}
1024
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001025static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001026{
1027 struct sd *sd = (struct sd *) gspca_dev;
1028 u8 row[8];
1029
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001030 row[0] = sd->i2c_intf | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001031 row[1] = sd->i2c_addr;
1032 row[2] = reg;
1033 row[3] = 0;
1034 row[4] = 0;
1035 row[5] = 0;
1036 row[6] = 0;
1037 row[7] = 0x10;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001038 i2c_w(gspca_dev, row);
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001039 row[0] = sd->i2c_intf | (1 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001040 row[2] = 0;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001041 i2c_w(gspca_dev, row);
1042 reg_r(gspca_dev, 0x10c2, 5);
Brian Johnson00b581e2009-07-23 05:55:43 -03001043 *val = gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001044}
1045
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001046static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001047{
1048 struct sd *sd = (struct sd *) gspca_dev;
1049 u8 row[8];
1050
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001051 row[0] = sd->i2c_intf | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001052 row[1] = sd->i2c_addr;
1053 row[2] = reg;
1054 row[3] = 0;
1055 row[4] = 0;
1056 row[5] = 0;
1057 row[6] = 0;
1058 row[7] = 0x10;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001059 i2c_w(gspca_dev, row);
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001060 row[0] = sd->i2c_intf | (2 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001061 row[2] = 0;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001062 i2c_w(gspca_dev, row);
1063 reg_r(gspca_dev, 0x10c2, 5);
Brian Johnson00b581e2009-07-23 05:55:43 -03001064 *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001065}
1066
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001067static void ov9650_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001068{
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001069 u16 id;
Brian Johnson26e744b2009-07-19 05:52:58 -03001070 struct sd *sd = (struct sd *) gspca_dev;
1071
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001072 i2c_r2(gspca_dev, 0x1c, &id);
1073 if (gspca_dev->usb_err < 0)
1074 return;
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001075
1076 if (id != 0x7fa2) {
Joe Perches91f58422011-08-21 19:56:55 -03001077 pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001078 gspca_dev->usb_err = -ENODEV;
1079 return;
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001080 }
1081
Jean-François Moine92884f82012-03-19 04:33:30 -03001082 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1083 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001084 i2c_w1_buf(gspca_dev, ov9650_init, ARRAY_SIZE(ov9650_init));
1085 if (gspca_dev->usb_err < 0)
1086 pr_err("OV9650 sensor initialization failed\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001087 sd->hstart = 1;
1088 sd->vstart = 7;
Brian Johnson26e744b2009-07-19 05:52:58 -03001089}
1090
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001091static void ov9655_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001092{
Brian Johnson26e744b2009-07-19 05:52:58 -03001093 struct sd *sd = (struct sd *) gspca_dev;
1094
Jean-François Moine92884f82012-03-19 04:33:30 -03001095 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1096 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001097 i2c_w1_buf(gspca_dev, ov9655_init, ARRAY_SIZE(ov9655_init));
1098 if (gspca_dev->usb_err < 0)
1099 pr_err("OV9655 sensor initialization failed\n");
1100
Brian Johnsoncc2a8332010-03-16 13:58:28 -03001101 sd->hstart = 1;
1102 sd->vstart = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001103}
1104
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001105static void soi968_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001106{
Brian Johnson26e744b2009-07-19 05:52:58 -03001107 struct sd *sd = (struct sd *) gspca_dev;
1108
Jean-François Moine92884f82012-03-19 04:33:30 -03001109 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1110 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001111 i2c_w1_buf(gspca_dev, soi968_init, ARRAY_SIZE(soi968_init));
1112 if (gspca_dev->usb_err < 0)
1113 pr_err("SOI968 sensor initialization failed\n");
1114
Brian Johnson26e744b2009-07-19 05:52:58 -03001115 sd->hstart = 60;
1116 sd->vstart = 11;
Brian Johnson26e744b2009-07-19 05:52:58 -03001117}
1118
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001119static void ov7660_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001120{
Brian Johnson26e744b2009-07-19 05:52:58 -03001121 struct sd *sd = (struct sd *) gspca_dev;
1122
Jean-François Moine92884f82012-03-19 04:33:30 -03001123 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1124 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001125 i2c_w1_buf(gspca_dev, ov7660_init, ARRAY_SIZE(ov7660_init));
1126 if (gspca_dev->usb_err < 0)
1127 pr_err("OV7660 sensor initialization failed\n");
Hans de Goede8bc50f32011-02-16 07:11:14 -03001128 sd->hstart = 3;
1129 sd->vstart = 3;
Brian Johnson26e744b2009-07-19 05:52:58 -03001130}
1131
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001132static void ov7670_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001133{
Brian Johnson26e744b2009-07-19 05:52:58 -03001134 struct sd *sd = (struct sd *) gspca_dev;
1135
Jean-François Moine92884f82012-03-19 04:33:30 -03001136 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1137 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001138 i2c_w1_buf(gspca_dev, ov7670_init, ARRAY_SIZE(ov7670_init));
1139 if (gspca_dev->usb_err < 0)
1140 pr_err("OV7670 sensor initialization failed\n");
1141
Brian Johnson26e744b2009-07-19 05:52:58 -03001142 sd->hstart = 0;
1143 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001144}
1145
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001146static void mt9v_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001147{
1148 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson26e744b2009-07-19 05:52:58 -03001149 u16 value;
Brian Johnson26e744b2009-07-19 05:52:58 -03001150
1151 sd->i2c_addr = 0x5d;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001152 i2c_r2(gspca_dev, 0xff, &value);
1153 if (gspca_dev->usb_err >= 0
1154 && value == 0x8243) {
Jean-François Moined4689b72012-03-19 04:42:45 -03001155 i2c_w2_buf(gspca_dev, mt9v011_init, ARRAY_SIZE(mt9v011_init));
1156 if (gspca_dev->usb_err < 0) {
1157 pr_err("MT9V011 sensor initialization failed\n");
1158 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001159 }
1160 sd->hstart = 2;
1161 sd->vstart = 2;
1162 sd->sensor = SENSOR_MT9V011;
Joe Perches91f58422011-08-21 19:56:55 -03001163 pr_info("MT9V011 sensor detected\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001164 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001165 }
1166
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001167 gspca_dev->usb_err = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001168 sd->i2c_addr = 0x5c;
1169 i2c_w2(gspca_dev, 0x01, 0x0004);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001170 i2c_r2(gspca_dev, 0xff, &value);
1171 if (gspca_dev->usb_err >= 0
1172 && value == 0x823a) {
Jean-François Moined4689b72012-03-19 04:42:45 -03001173 i2c_w2_buf(gspca_dev, mt9v111_init, ARRAY_SIZE(mt9v111_init));
1174 if (gspca_dev->usb_err < 0) {
1175 pr_err("MT9V111 sensor initialization failed\n");
1176 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001177 }
1178 sd->hstart = 2;
1179 sd->vstart = 2;
1180 sd->sensor = SENSOR_MT9V111;
Joe Perches91f58422011-08-21 19:56:55 -03001181 pr_info("MT9V111 sensor detected\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001182 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001183 }
1184
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001185 gspca_dev->usb_err = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001186 sd->i2c_addr = 0x5d;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001187 i2c_w2(gspca_dev, 0xf0, 0x0000);
1188 if (gspca_dev->usb_err < 0) {
1189 gspca_dev->usb_err = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001190 sd->i2c_addr = 0x48;
1191 i2c_w2(gspca_dev, 0xf0, 0x0000);
1192 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001193 i2c_r2(gspca_dev, 0x00, &value);
1194 if (gspca_dev->usb_err >= 0
1195 && value == 0x1229) {
Jean-François Moined4689b72012-03-19 04:42:45 -03001196 i2c_w2_buf(gspca_dev, mt9v112_init, ARRAY_SIZE(mt9v112_init));
1197 if (gspca_dev->usb_err < 0) {
1198 pr_err("MT9V112 sensor initialization failed\n");
1199 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001200 }
1201 sd->hstart = 6;
1202 sd->vstart = 2;
1203 sd->sensor = SENSOR_MT9V112;
Joe Perches91f58422011-08-21 19:56:55 -03001204 pr_info("MT9V112 sensor detected\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001205 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001206 }
1207
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001208 gspca_dev->usb_err = -ENODEV;
Brian Johnson26e744b2009-07-19 05:52:58 -03001209}
1210
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001211static void mt9m112_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnsone99ac542010-03-16 13:58:28 -03001212{
1213 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moined4689b72012-03-19 04:42:45 -03001214
1215 i2c_w2_buf(gspca_dev, mt9m112_init, ARRAY_SIZE(mt9m112_init));
1216 if (gspca_dev->usb_err < 0)
1217 pr_err("MT9M112 sensor initialization failed\n");
1218
Brian Johnsone99ac542010-03-16 13:58:28 -03001219 sd->hstart = 0;
1220 sd->vstart = 2;
Brian Johnsone99ac542010-03-16 13:58:28 -03001221}
1222
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001223static void mt9m111_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001224{
1225 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moined4689b72012-03-19 04:42:45 -03001226
1227 i2c_w2_buf(gspca_dev, mt9m111_init, ARRAY_SIZE(mt9m111_init));
1228 if (gspca_dev->usb_err < 0)
1229 pr_err("MT9M111 sensor initialization failed\n");
1230
Brian Johnson26e744b2009-07-19 05:52:58 -03001231 sd->hstart = 0;
1232 sd->vstart = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001233}
1234
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001235static void mt9m001_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001236{
1237 struct sd *sd = (struct sd *) gspca_dev;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001238 u16 id;
1239
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001240 i2c_r2(gspca_dev, 0x00, &id);
1241 if (gspca_dev->usb_err < 0)
1242 return;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001243
1244 /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
1245 switch (id) {
1246 case 0x8411:
1247 case 0x8421:
Joe Perches91f58422011-08-21 19:56:55 -03001248 pr_info("MT9M001 color sensor detected\n");
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001249 break;
1250 case 0x8431:
Joe Perches91f58422011-08-21 19:56:55 -03001251 pr_info("MT9M001 mono sensor detected\n");
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001252 break;
1253 default:
Joe Perches91f58422011-08-21 19:56:55 -03001254 pr_err("No MT9M001 chip detected, ID = %x\n\n", id);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001255 gspca_dev->usb_err = -ENODEV;
1256 return;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001257 }
1258
Jean-François Moined4689b72012-03-19 04:42:45 -03001259 i2c_w2_buf(gspca_dev, mt9m001_init, ARRAY_SIZE(mt9m001_init));
1260 if (gspca_dev->usb_err < 0)
1261 pr_err("MT9M001 sensor initialization failed\n");
1262
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001263 sd->hstart = 1;
1264 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001265}
1266
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001267static void hv7131r_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001268{
Brian Johnson26e744b2009-07-19 05:52:58 -03001269 struct sd *sd = (struct sd *) gspca_dev;
1270
Jean-François Moined4689b72012-03-19 04:42:45 -03001271 i2c_w1_buf(gspca_dev, hv7131r_init, ARRAY_SIZE(hv7131r_init));
1272 if (gspca_dev->usb_err < 0)
1273 pr_err("HV7131R Sensor initialization failed\n");
1274
Brian Johnson26e744b2009-07-19 05:52:58 -03001275 sd->hstart = 0;
1276 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001277}
1278
Hans Verkuil63069da2012-05-06 09:28:29 -03001279static void set_cmatrix(struct gspca_dev *gspca_dev,
1280 s32 brightness, s32 contrast, s32 satur, s32 hue)
Brian Johnson26e744b2009-07-19 05:52:58 -03001281{
Hans Verkuil63069da2012-05-06 09:28:29 -03001282 s32 hue_coord, hue_index = 180 + hue;
Brian Johnson26e744b2009-07-19 05:52:58 -03001283 u8 cmatrix[21];
Brian Johnson26e744b2009-07-19 05:52:58 -03001284
Morgan Phillipse0aa2b22014-09-08 09:49:47 -03001285 memset(cmatrix, 0, sizeof(cmatrix));
Hans Verkuil63069da2012-05-06 09:28:29 -03001286 cmatrix[2] = (contrast * 0x25 / 0x100) + 0x26;
Brian Johnson26e744b2009-07-19 05:52:58 -03001287 cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
1288 cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
Hans Verkuil63069da2012-05-06 09:28:29 -03001289 cmatrix[18] = brightness - 0x80;
Brian Johnson26e744b2009-07-19 05:52:58 -03001290
Jean-François Moinec5224d82012-03-19 04:30:07 -03001291 hue_coord = (hsv_red_x[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001292 cmatrix[6] = hue_coord;
1293 cmatrix[7] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001294
Jean-François Moinec5224d82012-03-19 04:30:07 -03001295 hue_coord = (hsv_red_y[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001296 cmatrix[8] = hue_coord;
1297 cmatrix[9] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001298
Jean-François Moinec5224d82012-03-19 04:30:07 -03001299 hue_coord = (hsv_green_x[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001300 cmatrix[10] = hue_coord;
1301 cmatrix[11] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001302
Jean-François Moinec5224d82012-03-19 04:30:07 -03001303 hue_coord = (hsv_green_y[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001304 cmatrix[12] = hue_coord;
1305 cmatrix[13] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001306
Jean-François Moinec5224d82012-03-19 04:30:07 -03001307 hue_coord = (hsv_blue_x[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001308 cmatrix[14] = hue_coord;
1309 cmatrix[15] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001310
Jean-François Moinec5224d82012-03-19 04:30:07 -03001311 hue_coord = (hsv_blue_y[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001312 cmatrix[16] = hue_coord;
1313 cmatrix[17] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001314
Jean-François Moinec5224d82012-03-19 04:30:07 -03001315 reg_w(gspca_dev, 0x10e1, cmatrix, 21);
Brian Johnson26e744b2009-07-19 05:52:58 -03001316}
1317
Hans Verkuil63069da2012-05-06 09:28:29 -03001318static void set_gamma(struct gspca_dev *gspca_dev, s32 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001319{
Brian Johnson26e744b2009-07-19 05:52:58 -03001320 u8 gamma[17];
Hans Verkuil63069da2012-05-06 09:28:29 -03001321 u8 gval = val * 0xb8 / 0x100;
Brian Johnson26e744b2009-07-19 05:52:58 -03001322
1323 gamma[0] = 0x0a;
1324 gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
1325 gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8);
1326 gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8);
1327 gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8);
1328 gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8);
1329 gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8);
1330 gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8);
1331 gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8);
1332 gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8);
1333 gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8);
1334 gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8);
1335 gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8);
1336 gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8);
1337 gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8);
1338 gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
1339 gamma[16] = 0xf5;
1340
Jean-François Moinec5224d82012-03-19 04:30:07 -03001341 reg_w(gspca_dev, 0x1190, gamma, 17);
Brian Johnson26e744b2009-07-19 05:52:58 -03001342}
1343
Hans Verkuil63069da2012-05-06 09:28:29 -03001344static void set_redblue(struct gspca_dev *gspca_dev, s32 blue, s32 red)
Brian Johnson26e744b2009-07-19 05:52:58 -03001345{
Hans Verkuil63069da2012-05-06 09:28:29 -03001346 reg_w1(gspca_dev, 0x118c, red);
1347 reg_w1(gspca_dev, 0x118f, blue);
Brian Johnson26e744b2009-07-19 05:52:58 -03001348}
1349
Hans Verkuil63069da2012-05-06 09:28:29 -03001350static void set_hvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001351{
Hans Verkuil63069da2012-05-06 09:28:29 -03001352 u8 value, tslb;
Brian Johnson26e744b2009-07-19 05:52:58 -03001353 u16 value2;
1354 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001355
1356 if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
Hans Verkuil63069da2012-05-06 09:28:29 -03001357 hflip = !hflip;
1358 vflip = !vflip;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001359 }
1360
Brian Johnson26e744b2009-07-19 05:52:58 -03001361 switch (sd->sensor) {
Hans de Goede779b51f2011-02-16 08:17:36 -03001362 case SENSOR_OV7660:
1363 value = 0x01;
1364 if (hflip)
1365 value |= 0x20;
1366 if (vflip) {
1367 value |= 0x10;
1368 sd->vstart = 2;
Jean-François Moineff38d582012-03-19 04:55:16 -03001369 } else {
Hans de Goede779b51f2011-02-16 08:17:36 -03001370 sd->vstart = 3;
Jean-François Moineff38d582012-03-19 04:55:16 -03001371 }
Hans de Goede779b51f2011-02-16 08:17:36 -03001372 reg_w1(gspca_dev, 0x1182, sd->vstart);
1373 i2c_w1(gspca_dev, 0x1e, value);
1374 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001375 case SENSOR_OV9650:
1376 i2c_r1(gspca_dev, 0x1e, &value);
1377 value &= ~0x30;
1378 tslb = 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001379 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001380 value |= 0x20;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001381 if (vflip) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001382 value |= 0x10;
1383 tslb = 0x49;
1384 }
1385 i2c_w1(gspca_dev, 0x1e, value);
1386 i2c_w1(gspca_dev, 0x3a, tslb);
1387 break;
1388 case SENSOR_MT9V111:
1389 case SENSOR_MT9V011:
1390 i2c_r2(gspca_dev, 0x20, &value2);
1391 value2 &= ~0xc0a0;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001392 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001393 value2 |= 0x8080;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001394 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001395 value2 |= 0x4020;
1396 i2c_w2(gspca_dev, 0x20, value2);
1397 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001398 case SENSOR_MT9M112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001399 case SENSOR_MT9M111:
1400 case SENSOR_MT9V112:
1401 i2c_r2(gspca_dev, 0x20, &value2);
1402 value2 &= ~0x0003;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001403 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001404 value2 |= 0x0002;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001405 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001406 value2 |= 0x0001;
1407 i2c_w2(gspca_dev, 0x20, value2);
1408 break;
1409 case SENSOR_HV7131R:
1410 i2c_r1(gspca_dev, 0x01, &value);
1411 value &= ~0x03;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001412 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001413 value |= 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001414 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001415 value |= 0x02;
1416 i2c_w1(gspca_dev, 0x01, value);
1417 break;
1418 }
Brian Johnson26e744b2009-07-19 05:52:58 -03001419}
1420
Hans Verkuil63069da2012-05-06 09:28:29 -03001421static void set_exposure(struct gspca_dev *gspca_dev, s32 expo)
Brian Johnson26e744b2009-07-19 05:52:58 -03001422{
1423 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001424 u8 exp[8] = {sd->i2c_intf, sd->i2c_addr,
Jean-François Moine4fb81372012-03-24 09:28:39 -03001425 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans Verkuil63069da2012-05-06 09:28:29 -03001426 int expo2;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001427
Jean-François Moine4fb81372012-03-24 09:28:39 -03001428 if (gspca_dev->streaming)
1429 exp[7] = 0x1e;
1430
Brian Johnson26e744b2009-07-19 05:52:58 -03001431 switch (sd->sensor) {
1432 case SENSOR_OV7660:
1433 case SENSOR_OV7670:
Brian Johnson26e744b2009-07-19 05:52:58 -03001434 case SENSOR_OV9655:
1435 case SENSOR_OV9650:
Jean-François Moinea1ac5dc2012-03-24 09:33:42 -03001436 if (expo > 547)
1437 expo2 = 547;
1438 else
1439 expo2 = expo;
1440 exp[0] |= (2 << 4);
1441 exp[2] = 0x10; /* AECH */
1442 exp[3] = expo2 >> 2;
1443 exp[7] = 0x10;
1444 i2c_w(gspca_dev, exp);
1445 exp[2] = 0x04; /* COM1 */
1446 exp[3] = expo2 & 0x0003;
1447 exp[7] = 0x10;
1448 i2c_w(gspca_dev, exp);
1449 expo -= expo2;
1450 exp[7] = 0x1e;
Brian Johnson26e744b2009-07-19 05:52:58 -03001451 exp[0] |= (3 << 4);
Jean-François Moinea1ac5dc2012-03-24 09:33:42 -03001452 exp[2] = 0x2d; /* ADVFL & ADVFH */
Jean-François Moinec5224d82012-03-19 04:30:07 -03001453 exp[3] = expo;
1454 exp[4] = expo >> 8;
Brian Johnson26e744b2009-07-19 05:52:58 -03001455 break;
1456 case SENSOR_MT9M001:
Brian Johnson26e744b2009-07-19 05:52:58 -03001457 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001458 case SENSOR_MT9V011:
1459 exp[0] |= (3 << 4);
1460 exp[2] = 0x09;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001461 exp[3] = expo >> 8;
1462 exp[4] = expo;
Brian Johnson26e744b2009-07-19 05:52:58 -03001463 break;
1464 case SENSOR_HV7131R:
1465 exp[0] |= (4 << 4);
1466 exp[2] = 0x25;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001467 exp[3] = expo >> 5;
1468 exp[4] = expo << 3;
German Galkine10f7312010-03-07 06:19:02 -03001469 exp[5] = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001470 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001471 default:
Jean-François Moinec5224d82012-03-19 04:30:07 -03001472 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001473 }
1474 i2c_w(gspca_dev, exp);
Brian Johnson26e744b2009-07-19 05:52:58 -03001475}
1476
Hans Verkuil63069da2012-05-06 09:28:29 -03001477static void set_gain(struct gspca_dev *gspca_dev, s32 g)
Brian Johnson26e744b2009-07-19 05:52:58 -03001478{
1479 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001480 u8 gain[8] = {sd->i2c_intf, sd->i2c_addr,
Jean-François Moine4fb81372012-03-24 09:28:39 -03001481 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Jean-François Moinec5224d82012-03-19 04:30:07 -03001482
Jean-François Moine4fb81372012-03-24 09:28:39 -03001483 if (gspca_dev->streaming)
1484 gain[7] = 0x15; /* or 1d ? */
1485
Brian Johnson26e744b2009-07-19 05:52:58 -03001486 switch (sd->sensor) {
1487 case SENSOR_OV7660:
1488 case SENSOR_OV7670:
1489 case SENSOR_SOI968:
1490 case SENSOR_OV9655:
1491 case SENSOR_OV9650:
1492 gain[0] |= (2 << 4);
Jean-François Moinec5224d82012-03-19 04:30:07 -03001493 gain[3] = ov_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001494 break;
1495 case SENSOR_MT9V011:
Brian Johnson26e744b2009-07-19 05:52:58 -03001496 gain[0] |= (3 << 4);
1497 gain[2] = 0x35;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001498 gain[3] = micron1_gain[g] >> 8;
1499 gain[4] = micron1_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001500 break;
1501 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001502 gain[0] |= (3 << 4);
1503 gain[2] = 0x2f;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001504 gain[3] = micron1_gain[g] >> 8;
1505 gain[4] = micron1_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001506 break;
1507 case SENSOR_MT9M001:
1508 gain[0] |= (3 << 4);
1509 gain[2] = 0x2f;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001510 gain[3] = micron2_gain[g] >> 8;
1511 gain[4] = micron2_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001512 break;
1513 case SENSOR_HV7131R:
1514 gain[0] |= (2 << 4);
1515 gain[2] = 0x30;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001516 gain[3] = hv7131r_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001517 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001518 default:
Jean-François Moinec5224d82012-03-19 04:30:07 -03001519 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001520 }
1521 i2c_w(gspca_dev, gain);
Brian Johnson26e744b2009-07-19 05:52:58 -03001522}
1523
Hans Verkuil63069da2012-05-06 09:28:29 -03001524static void set_quality(struct gspca_dev *gspca_dev, s32 val)
Jean-François Moine4c632e42012-03-19 04:35:34 -03001525{
1526 struct sd *sd = (struct sd *) gspca_dev;
1527
Hans Verkuil63069da2012-05-06 09:28:29 -03001528 jpeg_set_qual(sd->jpeg_hdr, val);
Jean-François Moine4c632e42012-03-19 04:35:34 -03001529 reg_w1(gspca_dev, 0x1061, 0x01); /* stop transfer */
1530 reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */
1531 reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
1532 reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
1533 reg_w1(gspca_dev, 0x1061, 0x03); /* restart transfer */
1534 reg_w1(gspca_dev, 0x10e0, sd->fmt);
1535 sd->fmt ^= 0x0c; /* invert QTAB use + write */
1536 reg_w1(gspca_dev, 0x10e0, sd->fmt);
1537}
1538
Brian Johnson26e744b2009-07-19 05:52:58 -03001539#ifdef CONFIG_VIDEO_ADV_DEBUG
1540static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
1541 struct v4l2_dbg_register *reg)
1542{
1543 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03001544
Hans Verkuilf82fadc2013-05-29 07:00:05 -03001545 reg->size = 1;
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03001546 switch (reg->match.addr) {
1547 case 0:
Brian Johnson26e744b2009-07-19 05:52:58 -03001548 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1549 return -EINVAL;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001550 reg_r(gspca_dev, reg->reg, 1);
Brian Johnson26e744b2009-07-19 05:52:58 -03001551 reg->val = gspca_dev->usb_buf[0];
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001552 return gspca_dev->usb_err;
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03001553 case 1:
Brian Johnson26e744b2009-07-19 05:52:58 -03001554 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001555 sd->sensor <= SENSOR_MT9M112) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001556 i2c_r2(gspca_dev, reg->reg, (u16 *) &reg->val);
Hans Verkuilf82fadc2013-05-29 07:00:05 -03001557 reg->size = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001558 } else {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001559 i2c_r1(gspca_dev, reg->reg, (u8 *) &reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001560 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001561 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001562 }
1563 return -EINVAL;
1564}
1565
1566static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
Hans Verkuil977ba3b12013-03-24 08:28:46 -03001567 const struct v4l2_dbg_register *reg)
Brian Johnson26e744b2009-07-19 05:52:58 -03001568{
1569 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03001570
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03001571 switch (reg->match.addr) {
1572 case 0:
Brian Johnson26e744b2009-07-19 05:52:58 -03001573 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1574 return -EINVAL;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001575 reg_w1(gspca_dev, reg->reg, reg->val);
1576 return gspca_dev->usb_err;
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03001577 case 1:
Brian Johnson26e744b2009-07-19 05:52:58 -03001578 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001579 sd->sensor <= SENSOR_MT9M112) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001580 i2c_w2(gspca_dev, reg->reg, reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001581 } else {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001582 i2c_w1(gspca_dev, reg->reg, reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001583 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001584 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001585 }
1586 return -EINVAL;
1587}
Brian Johnson26e744b2009-07-19 05:52:58 -03001588
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03001589static int sd_chip_info(struct gspca_dev *gspca_dev,
1590 struct v4l2_dbg_chip_info *chip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001591{
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03001592 if (chip->match.addr > 1)
1593 return -EINVAL;
1594 if (chip->match.addr == 1)
Mauro Carvalho Chehabc0decac2018-09-10 08:19:14 -04001595 strscpy(chip->name, "sensor", sizeof(chip->name));
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03001596 return 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001597}
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03001598#endif
Brian Johnson26e744b2009-07-19 05:52:58 -03001599
1600static int sd_config(struct gspca_dev *gspca_dev,
1601 const struct usb_device_id *id)
1602{
1603 struct sd *sd = (struct sd *) gspca_dev;
1604 struct cam *cam;
1605
1606 cam = &gspca_dev->cam;
Hans de Goedeeb3fb7c2012-01-01 16:35:01 -03001607 cam->needs_full_bandwidth = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001608
Jean-François Moineff38d582012-03-19 04:55:16 -03001609 sd->sensor = id->driver_info >> 8;
1610 sd->i2c_addr = id->driver_info;
1611 sd->flags = id->driver_info >> 16;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001612 sd->i2c_intf = 0x80; /* i2c 100 Kb/s */
Brian Johnson26e744b2009-07-19 05:52:58 -03001613
1614 switch (sd->sensor) {
Brian Johnsone99ac542010-03-16 13:58:28 -03001615 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03001616 case SENSOR_MT9M111:
Brian Johnson26e744b2009-07-19 05:52:58 -03001617 case SENSOR_OV9650:
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001618 case SENSOR_SOI968:
Brian Johnson26e744b2009-07-19 05:52:58 -03001619 cam->cam_mode = sxga_mode;
1620 cam->nmodes = ARRAY_SIZE(sxga_mode);
1621 break;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001622 case SENSOR_MT9M001:
1623 cam->cam_mode = mono_mode;
1624 cam->nmodes = ARRAY_SIZE(mono_mode);
1625 break;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001626 case SENSOR_HV7131R:
1627 sd->i2c_intf = 0x81; /* i2c 400 Kb/s */
Mauro Carvalho Chehab3e4d8f42019-02-18 14:29:03 -05001628 /* fall through */
Brian Johnson26e744b2009-07-19 05:52:58 -03001629 default:
1630 cam->cam_mode = vga_mode;
1631 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001632 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001633 }
1634
1635 sd->old_step = 0;
1636 sd->older_step = 0;
1637 sd->exposure_step = 16;
1638
Jean-François Moine92dcffc2012-03-19 04:47:24 -03001639 INIT_WORK(&sd->work, qual_upd);
Brian Johnson26e744b2009-07-19 05:52:58 -03001640
Brian Johnson26e744b2009-07-19 05:52:58 -03001641 return 0;
1642}
1643
Hans Verkuil63069da2012-05-06 09:28:29 -03001644static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
1645{
Hans de Goedea8a47862012-05-09 11:19:00 -03001646 struct gspca_dev *gspca_dev =
1647 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
1648 struct sd *sd = (struct sd *)gspca_dev;
Hans Verkuil63069da2012-05-06 09:28:29 -03001649
1650 gspca_dev->usb_err = 0;
1651
1652 if (!gspca_dev->streaming)
1653 return 0;
1654
1655 switch (ctrl->id) {
1656 /* color control cluster */
1657 case V4L2_CID_BRIGHTNESS:
Hans de Goedea8a47862012-05-09 11:19:00 -03001658 set_cmatrix(gspca_dev, sd->brightness->val,
Hans Verkuil63069da2012-05-06 09:28:29 -03001659 sd->contrast->val, sd->saturation->val, sd->hue->val);
1660 break;
1661 case V4L2_CID_GAMMA:
Hans de Goedea8a47862012-05-09 11:19:00 -03001662 set_gamma(gspca_dev, ctrl->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001663 break;
1664 /* blue/red balance cluster */
1665 case V4L2_CID_BLUE_BALANCE:
Hans de Goedea8a47862012-05-09 11:19:00 -03001666 set_redblue(gspca_dev, sd->blue->val, sd->red->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001667 break;
1668 /* h/vflip cluster */
1669 case V4L2_CID_HFLIP:
Hans de Goedea8a47862012-05-09 11:19:00 -03001670 set_hvflip(gspca_dev, sd->hflip->val, sd->vflip->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001671 break;
1672 /* standalone exposure control */
1673 case V4L2_CID_EXPOSURE:
Hans de Goedea8a47862012-05-09 11:19:00 -03001674 set_exposure(gspca_dev, ctrl->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001675 break;
1676 /* standalone gain control */
1677 case V4L2_CID_GAIN:
Hans de Goedea8a47862012-05-09 11:19:00 -03001678 set_gain(gspca_dev, ctrl->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001679 break;
1680 /* autogain + exposure or gain control cluster */
1681 case V4L2_CID_AUTOGAIN:
1682 if (sd->sensor == SENSOR_SOI968)
Hans de Goedea8a47862012-05-09 11:19:00 -03001683 set_gain(gspca_dev, sd->gain->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001684 else
Hans de Goedea8a47862012-05-09 11:19:00 -03001685 set_exposure(gspca_dev, sd->exposure->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001686 break;
1687 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Hans de Goedea8a47862012-05-09 11:19:00 -03001688 set_quality(gspca_dev, ctrl->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001689 break;
1690 }
1691 return gspca_dev->usb_err;
1692}
1693
1694static const struct v4l2_ctrl_ops sd_ctrl_ops = {
1695 .s_ctrl = sd_s_ctrl,
1696};
1697
1698static int sd_init_controls(struct gspca_dev *gspca_dev)
1699{
1700 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea8a47862012-05-09 11:19:00 -03001701 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
Hans Verkuil63069da2012-05-06 09:28:29 -03001702
1703 gspca_dev->vdev.ctrl_handler = hdl;
1704 v4l2_ctrl_handler_init(hdl, 13);
1705
1706 sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1707 V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
1708 sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1709 V4L2_CID_CONTRAST, 0, 255, 1, 127);
1710 sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1711 V4L2_CID_SATURATION, 0, 255, 1, 127);
1712 sd->hue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1713 V4L2_CID_HUE, -180, 180, 1, 0);
Hans Verkuil63069da2012-05-06 09:28:29 -03001714
1715 sd->gamma = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1716 V4L2_CID_GAMMA, 0, 255, 1, 0x10);
1717
1718 sd->blue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1719 V4L2_CID_BLUE_BALANCE, 0, 127, 1, 0x28);
1720 sd->red = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1721 V4L2_CID_RED_BALANCE, 0, 127, 1, 0x28);
Hans Verkuil63069da2012-05-06 09:28:29 -03001722
1723 if (sd->sensor != SENSOR_OV9655 && sd->sensor != SENSOR_SOI968 &&
1724 sd->sensor != SENSOR_OV7670 && sd->sensor != SENSOR_MT9M001 &&
1725 sd->sensor != SENSOR_MT9VPRB) {
1726 sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1727 V4L2_CID_HFLIP, 0, 1, 1, 0);
1728 sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1729 V4L2_CID_VFLIP, 0, 1, 1, 0);
Hans Verkuil63069da2012-05-06 09:28:29 -03001730 }
1731
1732 if (sd->sensor != SENSOR_SOI968 && sd->sensor != SENSOR_MT9VPRB &&
1733 sd->sensor != SENSOR_MT9M112 && sd->sensor != SENSOR_MT9M111 &&
1734 sd->sensor != SENSOR_MT9V111)
1735 sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1736 V4L2_CID_EXPOSURE, 0, 0x1780, 1, 0x33);
1737
1738 if (sd->sensor != SENSOR_MT9VPRB && sd->sensor != SENSOR_MT9M112 &&
1739 sd->sensor != SENSOR_MT9M111 && sd->sensor != SENSOR_MT9V111) {
1740 sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1741 V4L2_CID_GAIN, 0, 28, 1, 0);
1742 sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1743 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
Hans de Goedebc378fe2012-05-14 14:55:15 -03001744 }
1745
1746 sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1747 V4L2_CID_JPEG_COMPRESSION_QUALITY, 50, 90, 1, 80);
1748 if (hdl->error) {
1749 pr_err("Could not initialize controls\n");
1750 return hdl->error;
1751 }
1752
1753 v4l2_ctrl_cluster(4, &sd->brightness);
1754 v4l2_ctrl_cluster(2, &sd->blue);
1755 if (sd->hflip)
1756 v4l2_ctrl_cluster(2, &sd->hflip);
1757 if (sd->autogain) {
Hans Verkuil63069da2012-05-06 09:28:29 -03001758 if (sd->sensor == SENSOR_SOI968)
1759 /* this sensor doesn't have the exposure control and
1760 autogain is clustered with gain instead. This works
1761 because sd->exposure == NULL. */
1762 v4l2_ctrl_auto_cluster(3, &sd->autogain, 0, false);
1763 else
1764 /* Otherwise autogain is clustered with exposure. */
1765 v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
1766 }
Hans Verkuil63069da2012-05-06 09:28:29 -03001767 return 0;
1768}
1769
Brian Johnson26e744b2009-07-19 05:52:58 -03001770static int sd_init(struct gspca_dev *gspca_dev)
1771{
1772 struct sd *sd = (struct sd *) gspca_dev;
1773 int i;
1774 u8 value;
Morgan Phillips312487c2014-09-08 09:32:22 -03001775 u8 i2c_init[9] = {
1776 0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03
1777 };
Brian Johnson26e744b2009-07-19 05:52:58 -03001778
1779 for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
1780 value = bridge_init[i][1];
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001781 reg_w(gspca_dev, bridge_init[i][0], &value, 1);
1782 if (gspca_dev->usb_err < 0) {
Joe Perches91f58422011-08-21 19:56:55 -03001783 pr_err("Device initialization failed\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001784 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001785 }
1786 }
1787
Brian Johnson0c045eb2010-03-16 13:58:27 -03001788 if (sd->flags & LED_REVERSE)
1789 reg_w1(gspca_dev, 0x1006, 0x00);
1790 else
1791 reg_w1(gspca_dev, 0x1006, 0x20);
1792
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001793 reg_w(gspca_dev, 0x10c0, i2c_init, 9);
1794 if (gspca_dev->usb_err < 0) {
Joe Perches91f58422011-08-21 19:56:55 -03001795 pr_err("Device initialization failed\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001796 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001797 }
1798
1799 switch (sd->sensor) {
1800 case SENSOR_OV9650:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001801 ov9650_init_sensor(gspca_dev);
1802 if (gspca_dev->usb_err < 0)
1803 break;
Joe Perches91f58422011-08-21 19:56:55 -03001804 pr_info("OV9650 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001805 break;
1806 case SENSOR_OV9655:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001807 ov9655_init_sensor(gspca_dev);
1808 if (gspca_dev->usb_err < 0)
1809 break;
Joe Perches91f58422011-08-21 19:56:55 -03001810 pr_info("OV9655 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001811 break;
1812 case SENSOR_SOI968:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001813 soi968_init_sensor(gspca_dev);
1814 if (gspca_dev->usb_err < 0)
1815 break;
Joe Perches91f58422011-08-21 19:56:55 -03001816 pr_info("SOI968 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001817 break;
1818 case SENSOR_OV7660:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001819 ov7660_init_sensor(gspca_dev);
1820 if (gspca_dev->usb_err < 0)
1821 break;
Joe Perches91f58422011-08-21 19:56:55 -03001822 pr_info("OV7660 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001823 break;
1824 case SENSOR_OV7670:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001825 ov7670_init_sensor(gspca_dev);
1826 if (gspca_dev->usb_err < 0)
1827 break;
Joe Perches91f58422011-08-21 19:56:55 -03001828 pr_info("OV7670 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001829 break;
1830 case SENSOR_MT9VPRB:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001831 mt9v_init_sensor(gspca_dev);
1832 if (gspca_dev->usb_err < 0)
1833 break;
Jean-François Moineff38d582012-03-19 04:55:16 -03001834 pr_info("MT9VPRB sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001835 break;
1836 case SENSOR_MT9M111:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001837 mt9m111_init_sensor(gspca_dev);
1838 if (gspca_dev->usb_err < 0)
1839 break;
Joe Perches91f58422011-08-21 19:56:55 -03001840 pr_info("MT9M111 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001841 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001842 case SENSOR_MT9M112:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001843 mt9m112_init_sensor(gspca_dev);
1844 if (gspca_dev->usb_err < 0)
1845 break;
Joe Perches91f58422011-08-21 19:56:55 -03001846 pr_info("MT9M112 sensor detected\n");
Brian Johnsone99ac542010-03-16 13:58:28 -03001847 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001848 case SENSOR_MT9M001:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001849 mt9m001_init_sensor(gspca_dev);
1850 if (gspca_dev->usb_err < 0)
1851 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001852 break;
1853 case SENSOR_HV7131R:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001854 hv7131r_init_sensor(gspca_dev);
1855 if (gspca_dev->usb_err < 0)
1856 break;
Joe Perches91f58422011-08-21 19:56:55 -03001857 pr_info("HV7131R sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001858 break;
1859 default:
Jean-François Moineff38d582012-03-19 04:55:16 -03001860 pr_err("Unsupported sensor\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001861 gspca_dev->usb_err = -ENODEV;
Brian Johnson26e744b2009-07-19 05:52:58 -03001862 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001863 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001864}
1865
1866static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
1867{
1868 struct sd *sd = (struct sd *) gspca_dev;
1869 u8 value;
Jean-François Moineff38d582012-03-19 04:55:16 -03001870
Brian Johnson26e744b2009-07-19 05:52:58 -03001871 switch (sd->sensor) {
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001872 case SENSOR_SOI968:
1873 if (mode & MODE_SXGA) {
1874 i2c_w1(gspca_dev, 0x17, 0x1d);
1875 i2c_w1(gspca_dev, 0x18, 0xbd);
1876 i2c_w1(gspca_dev, 0x19, 0x01);
1877 i2c_w1(gspca_dev, 0x1a, 0x81);
1878 i2c_w1(gspca_dev, 0x12, 0x00);
1879 sd->hstart = 140;
1880 sd->vstart = 19;
1881 } else {
1882 i2c_w1(gspca_dev, 0x17, 0x13);
1883 i2c_w1(gspca_dev, 0x18, 0x63);
1884 i2c_w1(gspca_dev, 0x19, 0x01);
1885 i2c_w1(gspca_dev, 0x1a, 0x79);
1886 i2c_w1(gspca_dev, 0x12, 0x40);
1887 sd->hstart = 60;
1888 sd->vstart = 11;
1889 }
1890 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001891 case SENSOR_OV9650:
1892 if (mode & MODE_SXGA) {
1893 i2c_w1(gspca_dev, 0x17, 0x1b);
1894 i2c_w1(gspca_dev, 0x18, 0xbc);
1895 i2c_w1(gspca_dev, 0x19, 0x01);
1896 i2c_w1(gspca_dev, 0x1a, 0x82);
1897 i2c_r1(gspca_dev, 0x12, &value);
1898 i2c_w1(gspca_dev, 0x12, value & 0x07);
1899 } else {
1900 i2c_w1(gspca_dev, 0x17, 0x24);
1901 i2c_w1(gspca_dev, 0x18, 0xc5);
1902 i2c_w1(gspca_dev, 0x19, 0x00);
1903 i2c_w1(gspca_dev, 0x1a, 0x3c);
1904 i2c_r1(gspca_dev, 0x12, &value);
1905 i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
1906 }
1907 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001908 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03001909 case SENSOR_MT9M111:
1910 if (mode & MODE_SXGA) {
1911 i2c_w2(gspca_dev, 0xf0, 0x0002);
1912 i2c_w2(gspca_dev, 0xc8, 0x970b);
1913 i2c_w2(gspca_dev, 0xf0, 0x0000);
1914 } else {
1915 i2c_w2(gspca_dev, 0xf0, 0x0002);
1916 i2c_w2(gspca_dev, 0xc8, 0x8000);
1917 i2c_w2(gspca_dev, 0xf0, 0x0000);
1918 }
1919 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001920 }
1921}
1922
Hans de Goeded80dd5d2012-01-01 16:03:37 -03001923static int sd_isoc_init(struct gspca_dev *gspca_dev)
1924{
1925 struct usb_interface *intf;
1926 u32 flags = gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv;
1927
1928 /*
1929 * When using the SN9C20X_I420 fmt the sn9c20x needs more bandwidth
1930 * than our regular bandwidth calculations reserve, so we force the
1931 * use of a specific altsetting when using the SN9C20X_I420 fmt.
1932 */
1933 if (!(flags & (MODE_RAW | MODE_JPEG))) {
1934 intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
1935
1936 if (intf->num_altsetting != 9) {
Mauro Carvalho Chehab1ddc9f72016-10-18 17:44:16 -02001937 pr_warn("sn9c20x camera with unknown number of alt settings (%d), please report!\n",
Hans de Goede7135d882012-05-12 05:43:49 -03001938 intf->num_altsetting);
Hans de Goeded80dd5d2012-01-01 16:03:37 -03001939 gspca_dev->alt = intf->num_altsetting;
1940 return 0;
1941 }
1942
Ondrej Zary1966bc22013-08-30 17:54:23 -03001943 switch (gspca_dev->pixfmt.width) {
Hans de Goeded80dd5d2012-01-01 16:03:37 -03001944 case 160: /* 160x120 */
1945 gspca_dev->alt = 2;
1946 break;
1947 case 320: /* 320x240 */
1948 gspca_dev->alt = 6;
1949 break;
1950 default: /* >= 640x480 */
1951 gspca_dev->alt = 9;
Jean-François Moineff38d582012-03-19 04:55:16 -03001952 break;
Hans de Goeded80dd5d2012-01-01 16:03:37 -03001953 }
1954 }
1955
1956 return 0;
1957}
1958
Brian Johnson26e744b2009-07-19 05:52:58 -03001959#define HW_WIN(mode, hstart, vstart) \
Jean-Francois Moine83955552009-12-12 06:58:01 -03001960((const u8 []){hstart, 0, vstart, 0, \
Brian Johnson26e744b2009-07-19 05:52:58 -03001961(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
1962(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)})
1963
1964#define CLR_WIN(width, height) \
1965((const u8 [])\
1966{0, width >> 2, 0, height >> 1,\
1967((width >> 10) & 0x01) | ((height >> 8) & 0x6)})
1968
1969static int sd_start(struct gspca_dev *gspca_dev)
1970{
1971 struct sd *sd = (struct sd *) gspca_dev;
1972 int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Ondrej Zary1966bc22013-08-30 17:54:23 -03001973 int width = gspca_dev->pixfmt.width;
1974 int height = gspca_dev->pixfmt.height;
Brian Johnson26e744b2009-07-19 05:52:58 -03001975 u8 fmt, scale = 0;
1976
Brian Johnson26e744b2009-07-19 05:52:58 -03001977 jpeg_define(sd->jpeg_hdr, height, width,
1978 0x21);
Hans Verkuil63069da2012-05-06 09:28:29 -03001979 jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual));
Brian Johnson26e744b2009-07-19 05:52:58 -03001980
1981 if (mode & MODE_RAW)
1982 fmt = 0x2d;
1983 else if (mode & MODE_JPEG)
Jean-François Moine4c632e42012-03-19 04:35:34 -03001984 fmt = 0x24;
Brian Johnson26e744b2009-07-19 05:52:58 -03001985 else
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03001986 fmt = 0x2f; /* YUV 420 */
Jean-François Moine4c632e42012-03-19 04:35:34 -03001987 sd->fmt = fmt;
Brian Johnson26e744b2009-07-19 05:52:58 -03001988
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03001989 switch (mode & SCALE_MASK) {
1990 case SCALE_1280x1024:
Brian Johnson26e744b2009-07-19 05:52:58 -03001991 scale = 0xc0;
Joe Perches91f58422011-08-21 19:56:55 -03001992 pr_info("Set 1280x1024\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001993 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03001994 case SCALE_640x480:
Brian Johnson26e744b2009-07-19 05:52:58 -03001995 scale = 0x80;
Joe Perches91f58422011-08-21 19:56:55 -03001996 pr_info("Set 640x480\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001997 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03001998 case SCALE_320x240:
Brian Johnson26e744b2009-07-19 05:52:58 -03001999 scale = 0x90;
Joe Perches91f58422011-08-21 19:56:55 -03002000 pr_info("Set 320x240\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002001 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002002 case SCALE_160x120:
Brian Johnson26e744b2009-07-19 05:52:58 -03002003 scale = 0xa0;
Joe Perches91f58422011-08-21 19:56:55 -03002004 pr_info("Set 160x120\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002005 break;
2006 }
2007
2008 configure_sensor_output(gspca_dev, mode);
Jean-François Moine9a731a32010-06-04 05:26:42 -03002009 reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
2010 reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
Brian Johnson26e744b2009-07-19 05:52:58 -03002011 reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
2012 reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
2013 reg_w1(gspca_dev, 0x1189, scale);
2014 reg_w1(gspca_dev, 0x10e0, fmt);
2015
Hans Verkuil63069da2012-05-06 09:28:29 -03002016 set_cmatrix(gspca_dev, v4l2_ctrl_g_ctrl(sd->brightness),
2017 v4l2_ctrl_g_ctrl(sd->contrast),
2018 v4l2_ctrl_g_ctrl(sd->saturation),
2019 v4l2_ctrl_g_ctrl(sd->hue));
2020 set_gamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma));
2021 set_redblue(gspca_dev, v4l2_ctrl_g_ctrl(sd->blue),
2022 v4l2_ctrl_g_ctrl(sd->red));
Hans de Goede6c6ee532012-07-08 19:41:14 +02002023 if (sd->gain)
2024 set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
2025 if (sd->exposure)
2026 set_exposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure));
2027 if (sd->hflip)
2028 set_hvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip),
2029 v4l2_ctrl_g_ctrl(sd->vflip));
Brian Johnson26e744b2009-07-19 05:52:58 -03002030
Brian Johnson0c045eb2010-03-16 13:58:27 -03002031 reg_w1(gspca_dev, 0x1007, 0x20);
Jean-François Moineccbaba42012-03-19 04:51:30 -03002032 reg_w1(gspca_dev, 0x1061, 0x03);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002033
2034 /* if JPEG, prepare the compression quality update */
2035 if (mode & MODE_JPEG) {
2036 sd->pktsz = sd->npkt = 0;
2037 sd->nchg = 0;
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002038 }
2039
Jean-François Moinefe86ec72012-03-19 04:32:15 -03002040 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03002041}
2042
2043static void sd_stopN(struct gspca_dev *gspca_dev)
2044{
Brian Johnson0c045eb2010-03-16 13:58:27 -03002045 reg_w1(gspca_dev, 0x1007, 0x00);
Jean-François Moineccbaba42012-03-19 04:51:30 -03002046 reg_w1(gspca_dev, 0x1061, 0x01);
Brian Johnson26e744b2009-07-19 05:52:58 -03002047}
2048
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002049/* called on streamoff with alt==0 and on disconnect */
2050/* the usb_lock is held at entry - restore on exit */
2051static void sd_stop0(struct gspca_dev *gspca_dev)
2052{
2053 struct sd *sd = (struct sd *) gspca_dev;
2054
Bhaktipriya Shridharedf096b2016-07-02 07:51:22 -03002055 mutex_unlock(&gspca_dev->usb_lock);
2056 flush_work(&sd->work);
2057 mutex_lock(&gspca_dev->usb_lock);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002058}
2059
Brian Johnsone1430472009-09-02 12:39:41 -03002060static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
Brian Johnson26e744b2009-07-19 05:52:58 -03002061{
2062 struct sd *sd = (struct sd *) gspca_dev;
Hans Verkuil63069da2012-05-06 09:28:29 -03002063 s32 cur_exp = v4l2_ctrl_g_ctrl(sd->exposure);
2064 s32 max = sd->exposure->maximum - sd->exposure_step;
2065 s32 min = sd->exposure->minimum + sd->exposure_step;
Brian Johnsone1430472009-09-02 12:39:41 -03002066 s16 new_exp;
Brian Johnson26e744b2009-07-19 05:52:58 -03002067
2068 /*
2069 * some hardcoded values are present
2070 * like those for maximal/minimal exposure
2071 * and exposure steps
2072 */
2073 if (avg_lum < MIN_AVG_LUM) {
Hans Verkuil63069da2012-05-06 09:28:29 -03002074 if (cur_exp > max)
Brian Johnson26e744b2009-07-19 05:52:58 -03002075 return;
2076
Hans Verkuil63069da2012-05-06 09:28:29 -03002077 new_exp = cur_exp + sd->exposure_step;
2078 if (new_exp > max)
2079 new_exp = max;
2080 if (new_exp < min)
2081 new_exp = min;
2082 v4l2_ctrl_s_ctrl(sd->exposure, new_exp);
Brian Johnson26e744b2009-07-19 05:52:58 -03002083
2084 sd->older_step = sd->old_step;
2085 sd->old_step = 1;
2086
2087 if (sd->old_step ^ sd->older_step)
2088 sd->exposure_step /= 2;
2089 else
2090 sd->exposure_step += 2;
2091 }
2092 if (avg_lum > MAX_AVG_LUM) {
Hans Verkuil63069da2012-05-06 09:28:29 -03002093 if (cur_exp < min)
Brian Johnson26e744b2009-07-19 05:52:58 -03002094 return;
Hans Verkuil63069da2012-05-06 09:28:29 -03002095 new_exp = cur_exp - sd->exposure_step;
2096 if (new_exp > max)
2097 new_exp = max;
2098 if (new_exp < min)
2099 new_exp = min;
2100 v4l2_ctrl_s_ctrl(sd->exposure, new_exp);
Brian Johnson26e744b2009-07-19 05:52:58 -03002101 sd->older_step = sd->old_step;
2102 sd->old_step = 0;
2103
2104 if (sd->old_step ^ sd->older_step)
2105 sd->exposure_step /= 2;
2106 else
2107 sd->exposure_step += 2;
2108 }
2109}
2110
Brian Johnsone1430472009-09-02 12:39:41 -03002111static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
2112{
2113 struct sd *sd = (struct sd *) gspca_dev;
Hans Verkuil63069da2012-05-06 09:28:29 -03002114 s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain);
Brian Johnsone1430472009-09-02 12:39:41 -03002115
Hans Verkuil63069da2012-05-06 09:28:29 -03002116 if (avg_lum < MIN_AVG_LUM && cur_gain < sd->gain->maximum)
2117 v4l2_ctrl_s_ctrl(sd->gain, cur_gain + 1);
2118 if (avg_lum > MAX_AVG_LUM && cur_gain > sd->gain->minimum)
2119 v4l2_ctrl_s_ctrl(sd->gain, cur_gain - 1);
Brian Johnsone1430472009-09-02 12:39:41 -03002120}
2121
2122static void sd_dqcallback(struct gspca_dev *gspca_dev)
2123{
2124 struct sd *sd = (struct sd *) gspca_dev;
2125 int avg_lum;
2126
Hans de Goede6c6ee532012-07-08 19:41:14 +02002127 if (sd->autogain == NULL || !v4l2_ctrl_g_ctrl(sd->autogain))
Brian Johnsone1430472009-09-02 12:39:41 -03002128 return;
2129
2130 avg_lum = atomic_read(&sd->avg_lum);
2131 if (sd->sensor == SENSOR_SOI968)
2132 do_autogain(gspca_dev, avg_lum);
2133 else
2134 do_autoexposure(gspca_dev, avg_lum);
2135}
2136
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002137/* JPEG quality update */
2138/* This function is executed from a work queue. */
2139static void qual_upd(struct work_struct *work)
2140{
2141 struct sd *sd = container_of(work, struct sd, work);
2142 struct gspca_dev *gspca_dev = &sd->gspca_dev;
Hans Verkuil63069da2012-05-06 09:28:29 -03002143 s32 qual = v4l2_ctrl_g_ctrl(sd->jpegqual);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002144
Hans de Goede844db452012-09-09 07:30:02 -03002145 /* To protect gspca_dev->usb_buf and gspca_dev->usb_err */
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002146 mutex_lock(&gspca_dev->usb_lock);
Joe Perches37d5efb2017-09-22 15:20:33 -04002147 gspca_dbg(gspca_dev, D_STREAM, "qual_upd %d%%\n", qual);
Hans de Goede844db452012-09-09 07:30:02 -03002148 gspca_dev->usb_err = 0;
Hans Verkuil63069da2012-05-06 09:28:29 -03002149 set_quality(gspca_dev, qual);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002150 mutex_unlock(&gspca_dev->usb_lock);
2151}
2152
Peter Senna Tschudin8099aff2013-01-24 19:29:06 -03002153#if IS_ENABLED(CONFIG_INPUT)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002154static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
2155 u8 *data, /* interrupt packet */
2156 int len) /* interrupt packet length */
2157{
2158 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03002159
Brian Johnson33ddc162010-04-18 21:42:40 -03002160 if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
Jean-François Moineff38d582012-03-19 04:55:16 -03002161 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
2162 input_sync(gspca_dev->input_dev);
2163 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
2164 input_sync(gspca_dev->input_dev);
2165 return 0;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002166 }
Jean-François Moineff38d582012-03-19 04:55:16 -03002167 return -EINVAL;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002168}
2169#endif
2170
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002171/* check the JPEG compression */
2172static void transfer_check(struct gspca_dev *gspca_dev,
2173 u8 *data)
2174{
2175 struct sd *sd = (struct sd *) gspca_dev;
2176 int new_qual, r;
2177
2178 new_qual = 0;
2179
2180 /* if USB error, discard the frame and decrease the quality */
2181 if (data[6] & 0x08) { /* USB FIFO full */
2182 gspca_dev->last_packet_type = DISCARD_PACKET;
2183 new_qual = -5;
2184 } else {
2185
2186 /* else, compute the filling rate and a new JPEG quality */
2187 r = (sd->pktsz * 100) /
2188 (sd->npkt *
2189 gspca_dev->urb[0]->iso_frame_desc[0].length);
2190 if (r >= 85)
2191 new_qual = -3;
2192 else if (r < 75)
2193 new_qual = 2;
2194 }
2195 if (new_qual != 0) {
2196 sd->nchg += new_qual;
2197 if (sd->nchg < -6 || sd->nchg >= 12) {
Hans Verkuil63069da2012-05-06 09:28:29 -03002198 /* Note: we are in interrupt context, so we can't
2199 use v4l2_ctrl_g/s_ctrl here. Access the value
2200 directly instead. */
2201 s32 curqual = sd->jpegqual->cur.val;
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002202 sd->nchg = 0;
Hans Verkuil63069da2012-05-06 09:28:29 -03002203 new_qual += curqual;
2204 if (new_qual < sd->jpegqual->minimum)
2205 new_qual = sd->jpegqual->minimum;
2206 else if (new_qual > sd->jpegqual->maximum)
2207 new_qual = sd->jpegqual->maximum;
2208 if (new_qual != curqual) {
2209 sd->jpegqual->cur.val = new_qual;
Bhaktipriya Shridharedf096b2016-07-02 07:51:22 -03002210 schedule_work(&sd->work);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002211 }
2212 }
2213 } else {
2214 sd->nchg = 0;
2215 }
2216 sd->pktsz = sd->npkt = 0;
2217}
2218
Brian Johnson26e744b2009-07-19 05:52:58 -03002219static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Brian Johnson26e744b2009-07-19 05:52:58 -03002220 u8 *data, /* isoc packet */
2221 int len) /* iso packet length */
2222{
2223 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03002224 int avg_lum, is_jpeg;
Morgan Phillips312487c2014-09-08 09:32:22 -03002225 static const u8 frame_header[] = {
2226 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96
2227 };
Jean-François Moineff38d582012-03-19 04:55:16 -03002228
2229 is_jpeg = (sd->fmt & 0x03) == 0;
Jean-François Moine1f42df02012-03-19 04:22:44 -03002230 if (len >= 64 && memcmp(data, frame_header, 6) == 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03002231 avg_lum = ((data[35] >> 2) & 3) |
2232 (data[20] << 2) |
2233 (data[19] << 10);
2234 avg_lum += ((data[35] >> 4) & 3) |
2235 (data[22] << 2) |
2236 (data[21] << 10);
2237 avg_lum += ((data[35] >> 6) & 3) |
2238 (data[24] << 2) |
2239 (data[23] << 10);
2240 avg_lum += (data[36] & 3) |
2241 (data[26] << 2) |
2242 (data[25] << 10);
2243 avg_lum += ((data[36] >> 2) & 3) |
2244 (data[28] << 2) |
2245 (data[27] << 10);
2246 avg_lum += ((data[36] >> 4) & 3) |
2247 (data[30] << 2) |
2248 (data[29] << 10);
2249 avg_lum += ((data[36] >> 6) & 3) |
2250 (data[32] << 2) |
2251 (data[31] << 10);
2252 avg_lum += ((data[44] >> 4) & 3) |
2253 (data[34] << 2) |
2254 (data[33] << 10);
2255 avg_lum >>= 9;
2256 atomic_set(&sd->avg_lum, avg_lum);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002257
Jean-François Moineff38d582012-03-19 04:55:16 -03002258 if (is_jpeg)
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002259 transfer_check(gspca_dev, data);
2260
Jean-François Moine04d174e2010-09-13 05:22:37 -03002261 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Jean-François Moine1f42df02012-03-19 04:22:44 -03002262 len -= 64;
2263 if (len == 0)
2264 return;
2265 data += 64;
Brian Johnson26e744b2009-07-19 05:52:58 -03002266 }
2267 if (gspca_dev->last_packet_type == LAST_PACKET) {
Jean-François Moineff38d582012-03-19 04:55:16 -03002268 if (is_jpeg) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002269 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002270 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002271 gspca_frame_add(gspca_dev, INTER_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002272 data, len);
2273 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002274 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002275 data, len);
2276 }
2277 } else {
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002278 /* if JPEG, count the packets and their size */
Jean-François Moineff38d582012-03-19 04:55:16 -03002279 if (is_jpeg) {
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002280 sd->npkt++;
2281 sd->pktsz += len;
2282 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002283 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Brian Johnson26e744b2009-07-19 05:52:58 -03002284 }
2285}
2286
2287/* sub-driver description */
2288static const struct sd_desc sd_desc = {
Jean-François Moineff38d582012-03-19 04:55:16 -03002289 .name = KBUILD_MODNAME,
Brian Johnson26e744b2009-07-19 05:52:58 -03002290 .config = sd_config,
2291 .init = sd_init,
Hans Verkuil63069da2012-05-06 09:28:29 -03002292 .init_controls = sd_init_controls,
Hans de Goeded80dd5d2012-01-01 16:03:37 -03002293 .isoc_init = sd_isoc_init,
Brian Johnson26e744b2009-07-19 05:52:58 -03002294 .start = sd_start,
2295 .stopN = sd_stopN,
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002296 .stop0 = sd_stop0,
Brian Johnson26e744b2009-07-19 05:52:58 -03002297 .pkt_scan = sd_pkt_scan,
Peter Senna Tschudin8099aff2013-01-24 19:29:06 -03002298#if IS_ENABLED(CONFIG_INPUT)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002299 .int_pkt_scan = sd_int_pkt_scan,
2300#endif
Brian Johnsone1430472009-09-02 12:39:41 -03002301 .dq_callback = sd_dqcallback,
Brian Johnson26e744b2009-07-19 05:52:58 -03002302#ifdef CONFIG_VIDEO_ADV_DEBUG
2303 .set_register = sd_dbg_s_register,
2304 .get_register = sd_dbg_g_register,
Hans Verkuilb1c85cc2013-05-29 06:59:42 -03002305 .get_chip_info = sd_chip_info,
Brian Johnson26e744b2009-07-19 05:52:58 -03002306#endif
Brian Johnson26e744b2009-07-19 05:52:58 -03002307};
2308
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002309#define SN9C20X(sensor, i2c_addr, flags) \
Brian Johnson0c045eb2010-03-16 13:58:27 -03002310 .driver_info = ((flags & 0xff) << 16) \
Brian Johnson26e744b2009-07-19 05:52:58 -03002311 | (SENSOR_ ## sensor << 8) \
2312 | (i2c_addr)
2313
Jean-François Moine95c967c2011-01-13 05:20:29 -03002314static const struct usb_device_id device_table[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03002315 {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
2316 {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
2317 {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002318 {USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002319 {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, LED_REVERSE)},
2320 {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30,
2321 (FLIP_DETECT | HAS_NO_BUTTON))},
Brian Johnson26e744b2009-07-19 05:52:58 -03002322 {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
2323 {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
2324 {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
2325 {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)},
Hans de Goede779b51f2011-02-16 08:17:36 -03002326 {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, FLIP_DETECT)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002327 {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)},
2328 {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)},
2329 {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
2330 {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002331 {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002332 {USB_DEVICE(0x0c45, 0x628c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002333 {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)},
2334 {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
2335 {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
2336 {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
Frank Schaefer114cfbd2011-09-23 05:05:37 -03002337 {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, LED_REVERSE)},
Hans de Goedeb39e0cb2011-02-16 08:33:16 -03002338 {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, LED_REVERSE)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002339 {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
2340 {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
2341 {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
2342 {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
Wolfram Sang61f03192014-02-01 15:26:00 -03002343 {USB_DEVICE(0x0458, 0x7045), SN9C20X(MT9M112, 0x5d, LED_REVERSE)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002344 {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)},
2345 {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002346 {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
2347 {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)},
2348 {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)},
2349 {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002350 {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002351 {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)},
2352 {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)},
2353 {}
2354};
2355MODULE_DEVICE_TABLE(usb, device_table);
2356
2357/* -- device connect -- */
2358static int sd_probe(struct usb_interface *intf,
2359 const struct usb_device_id *id)
2360{
2361 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
2362 THIS_MODULE);
2363}
2364
Brian Johnson26e744b2009-07-19 05:52:58 -03002365static struct usb_driver sd_driver = {
Jean-François Moineff38d582012-03-19 04:55:16 -03002366 .name = KBUILD_MODNAME,
Brian Johnson26e744b2009-07-19 05:52:58 -03002367 .id_table = device_table,
2368 .probe = sd_probe,
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002369 .disconnect = gspca_disconnect,
Brian Johnson26e744b2009-07-19 05:52:58 -03002370#ifdef CONFIG_PM
2371 .suspend = gspca_suspend,
2372 .resume = gspca_resume,
2373 .reset_resume = gspca_resume,
2374#endif
2375};
2376
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -08002377module_usb_driver(sd_driver);