blob: ead9a1f5851318d31abf985dfc5bb653e6b28ce4 [file] [log] [blame]
Brian Johnson26e744b2009-07-19 05:52:58 -03001/*
2 * Sonix sn9c201 sn9c202 library
Jean-François Moineff38d582012-03-19 04:55:16 -03003 *
4 * Copyright (C) 2012 Jean-Francois Moine <http://moinejf.free.fr>
Brian Johnson26e744b2009-07-19 05:52:58 -03005 * Copyright (C) 2008-2009 microdia project <microdia@googlegroups.com>
6 * Copyright (C) 2009 Brian Johnson <brijohn@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
Joe Perches91f58422011-08-21 19:56:55 -030023#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24
Brian Johnson26e744b2009-07-19 05:52:58 -030025#include <linux/input.h>
Brian Johnson26e744b2009-07-19 05:52:58 -030026
Mauro Carvalho Chehabc15b95e2009-07-19 18:03:23 -030027#include "gspca.h"
28#include "jpeg.h"
29
30#include <media/v4l2-chip-ident.h>
Brian Johnson7ddaac72010-03-16 13:58:27 -030031#include <linux/dmi.h>
Mauro Carvalho Chehabc15b95e2009-07-19 18:03:23 -030032
Brian Johnson26e744b2009-07-19 05:52:58 -030033MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, "
34 "microdia project <microdia@googlegroups.com>");
35MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver");
36MODULE_LICENSE("GPL");
37
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -030038/*
39 * Pixel format private data
40 */
41#define SCALE_MASK 0x0f
42#define SCALE_160x120 0
43#define SCALE_320x240 1
44#define SCALE_640x480 2
45#define SCALE_1280x1024 3
Brian Johnson26e744b2009-07-19 05:52:58 -030046#define MODE_RAW 0x10
47#define MODE_JPEG 0x20
48#define MODE_SXGA 0x80
49
50#define SENSOR_OV9650 0
51#define SENSOR_OV9655 1
52#define SENSOR_SOI968 2
53#define SENSOR_OV7660 3
54#define SENSOR_OV7670 4
55#define SENSOR_MT9V011 5
56#define SENSOR_MT9V111 6
57#define SENSOR_MT9V112 7
58#define SENSOR_MT9M001 8
59#define SENSOR_MT9M111 9
Brian Johnsone99ac542010-03-16 13:58:28 -030060#define SENSOR_MT9M112 10
61#define SENSOR_HV7131R 11
Jean-François Moine9637c652012-03-24 09:16:14 -030062#define SENSOR_MT9VPRB 12
Brian Johnson26e744b2009-07-19 05:52:58 -030063
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030064/* camera flags */
Brian Johnson33ddc162010-04-18 21:42:40 -030065#define HAS_NO_BUTTON 0x1
Brian Johnson0c045eb2010-03-16 13:58:27 -030066#define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */
Brian Johnson7ddaac72010-03-16 13:58:27 -030067#define FLIP_DETECT 0x4
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -030068
Brian Johnson26e744b2009-07-19 05:52:58 -030069/* specific webcam descriptor */
70struct sd {
71 struct gspca_dev gspca_dev;
72
Hans Verkuil63069da2012-05-06 09:28:29 -030073 struct { /* color control cluster */
74 struct v4l2_ctrl *brightness;
75 struct v4l2_ctrl *contrast;
76 struct v4l2_ctrl *saturation;
77 struct v4l2_ctrl *hue;
78 };
79 struct { /* blue/red balance control cluster */
80 struct v4l2_ctrl *blue;
81 struct v4l2_ctrl *red;
82 };
83 struct { /* h/vflip control cluster */
84 struct v4l2_ctrl *hflip;
85 struct v4l2_ctrl *vflip;
86 };
87 struct v4l2_ctrl *gamma;
88 struct { /* autogain and exposure or gain control cluster */
89 struct v4l2_ctrl *autogain;
90 struct v4l2_ctrl *exposure;
91 struct v4l2_ctrl *gain;
92 };
93 struct v4l2_ctrl *jpegqual;
Jean-François Moinec5224d82012-03-19 04:30:07 -030094
Jean-François Moine92dcffc2012-03-19 04:47:24 -030095 struct work_struct work;
96 struct workqueue_struct *work_thread;
97
98 u32 pktsz; /* (used by pkt_scan) */
99 u16 npkt;
100 s8 nchg;
Jean-François Moine4c632e42012-03-19 04:35:34 -0300101 u8 fmt; /* (used for JPEG QTAB update */
102
Brian Johnson26e744b2009-07-19 05:52:58 -0300103#define MIN_AVG_LUM 80
104#define MAX_AVG_LUM 130
105 atomic_t avg_lum;
106 u8 old_step;
107 u8 older_step;
108 u8 exposure_step;
109
Brian Johnson26e744b2009-07-19 05:52:58 -0300110 u8 i2c_addr;
Jean-François Moinec4407fe2012-03-24 09:23:56 -0300111 u8 i2c_intf;
Brian Johnson26e744b2009-07-19 05:52:58 -0300112 u8 sensor;
113 u8 hstart;
114 u8 vstart;
115
Jean-François Moine9a731a32010-06-04 05:26:42 -0300116 u8 jpeg_hdr[JPEG_HDR_SZ];
Brian Johnson26e744b2009-07-19 05:52:58 -0300117
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -0300118 u8 flags;
Brian Johnson26e744b2009-07-19 05:52:58 -0300119};
120
Jean-François Moine92dcffc2012-03-19 04:47:24 -0300121static void qual_upd(struct work_struct *work);
122
Joe Perches58aa68c2009-09-02 01:12:13 -0300123struct i2c_reg_u8 {
124 u8 reg;
125 u8 val;
126};
127
128struct i2c_reg_u16 {
129 u8 reg;
130 u16 val;
131};
132
Brian Johnson7ddaac72010-03-16 13:58:27 -0300133static const struct dmi_system_id flip_dmi_table[] = {
134 {
135 .ident = "MSI MS-1034",
136 .matches = {
137 DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."),
138 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1034"),
139 DMI_MATCH(DMI_PRODUCT_VERSION, "0341")
140 }
141 },
142 {
143 .ident = "MSI MS-1632",
144 .matches = {
145 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
146 DMI_MATCH(DMI_BOARD_NAME, "MS-1632")
147 }
148 },
Brian Johnsone077f862010-04-05 20:52:52 -0300149 {
Hans de Goedebcc6f662011-02-17 06:27:57 -0300150 .ident = "MSI MS-1633X",
151 .matches = {
152 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
153 DMI_MATCH(DMI_BOARD_NAME, "MS-1633X")
154 }
155 },
156 {
Brian Johnson5d26ed92010-04-10 02:12:46 -0300157 .ident = "MSI MS-1635X",
158 .matches = {
159 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
160 DMI_MATCH(DMI_BOARD_NAME, "MS-1635X")
161 }
162 },
163 {
Brian Johnsone077f862010-04-05 20:52:52 -0300164 .ident = "ASUSTeK W7J",
165 .matches = {
166 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
167 DMI_MATCH(DMI_BOARD_NAME, "W7J ")
168 }
169 },
Brian Johnson7ddaac72010-03-16 13:58:27 -0300170 {}
171};
172
Brian Johnson26e744b2009-07-19 05:52:58 -0300173static const struct v4l2_pix_format vga_mode[] = {
174 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300175 .bytesperline = 160,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300176 .sizeimage = 160 * 120 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300177 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300178 .priv = SCALE_160x120 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300179 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
180 .bytesperline = 160,
181 .sizeimage = 160 * 120,
182 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300183 .priv = SCALE_160x120 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300184 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300185 .bytesperline = 160,
Brian Johnson26e744b2009-07-19 05:52:58 -0300186 .sizeimage = 240 * 120,
187 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300188 .priv = SCALE_160x120},
Brian Johnson26e744b2009-07-19 05:52:58 -0300189 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300190 .bytesperline = 320,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300191 .sizeimage = 320 * 240 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300192 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300193 .priv = SCALE_320x240 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300194 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
195 .bytesperline = 320,
196 .sizeimage = 320 * 240 ,
197 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300198 .priv = SCALE_320x240 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300199 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300200 .bytesperline = 320,
Brian Johnson26e744b2009-07-19 05:52:58 -0300201 .sizeimage = 480 * 240 ,
202 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300203 .priv = SCALE_320x240},
Brian Johnson26e744b2009-07-19 05:52:58 -0300204 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300205 .bytesperline = 640,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300206 .sizeimage = 640 * 480 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300207 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300208 .priv = SCALE_640x480 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300209 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
210 .bytesperline = 640,
211 .sizeimage = 640 * 480,
212 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300213 .priv = SCALE_640x480 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300214 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300215 .bytesperline = 640,
Brian Johnson26e744b2009-07-19 05:52:58 -0300216 .sizeimage = 960 * 480,
217 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300218 .priv = SCALE_640x480},
Brian Johnson26e744b2009-07-19 05:52:58 -0300219};
220
221static const struct v4l2_pix_format sxga_mode[] = {
222 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300223 .bytesperline = 160,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300224 .sizeimage = 160 * 120 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300225 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300226 .priv = SCALE_160x120 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300227 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
228 .bytesperline = 160,
229 .sizeimage = 160 * 120,
230 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300231 .priv = SCALE_160x120 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300232 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300233 .bytesperline = 160,
Brian Johnson26e744b2009-07-19 05:52:58 -0300234 .sizeimage = 240 * 120,
235 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300236 .priv = SCALE_160x120},
Brian Johnson26e744b2009-07-19 05:52:58 -0300237 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300238 .bytesperline = 320,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300239 .sizeimage = 320 * 240 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300240 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300241 .priv = SCALE_320x240 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300242 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
243 .bytesperline = 320,
244 .sizeimage = 320 * 240 ,
245 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300246 .priv = SCALE_320x240 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300247 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300248 .bytesperline = 320,
Brian Johnson26e744b2009-07-19 05:52:58 -0300249 .sizeimage = 480 * 240 ,
250 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300251 .priv = SCALE_320x240},
Brian Johnson26e744b2009-07-19 05:52:58 -0300252 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300253 .bytesperline = 640,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300254 .sizeimage = 640 * 480 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300255 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300256 .priv = SCALE_640x480 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300257 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
258 .bytesperline = 640,
259 .sizeimage = 640 * 480,
260 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300261 .priv = SCALE_640x480 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300262 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300263 .bytesperline = 640,
Brian Johnson26e744b2009-07-19 05:52:58 -0300264 .sizeimage = 960 * 480,
265 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300266 .priv = SCALE_640x480},
Brian Johnson26e744b2009-07-19 05:52:58 -0300267 {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
268 .bytesperline = 1280,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300269 .sizeimage = 1280 * 1024,
Brian Johnson26e744b2009-07-19 05:52:58 -0300270 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300271 .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
Brian Johnson26e744b2009-07-19 05:52:58 -0300272};
273
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -0300274static const struct v4l2_pix_format mono_mode[] = {
275 {160, 120, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
276 .bytesperline = 160,
277 .sizeimage = 160 * 120,
278 .colorspace = V4L2_COLORSPACE_SRGB,
279 .priv = SCALE_160x120 | MODE_RAW},
280 {320, 240, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
281 .bytesperline = 320,
282 .sizeimage = 320 * 240 ,
283 .colorspace = V4L2_COLORSPACE_SRGB,
284 .priv = SCALE_320x240 | MODE_RAW},
285 {640, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
286 .bytesperline = 640,
287 .sizeimage = 640 * 480,
288 .colorspace = V4L2_COLORSPACE_SRGB,
289 .priv = SCALE_640x480 | MODE_RAW},
290 {1280, 1024, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
291 .bytesperline = 1280,
292 .sizeimage = 1280 * 1024,
293 .colorspace = V4L2_COLORSPACE_SRGB,
294 .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
295};
296
Joe Perches58aa68c2009-09-02 01:12:13 -0300297static const s16 hsv_red_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300298 41, 44, 46, 48, 50, 52, 54, 56,
299 58, 60, 62, 64, 66, 68, 70, 72,
300 74, 76, 78, 80, 81, 83, 85, 87,
301 88, 90, 92, 93, 95, 97, 98, 100,
302 101, 102, 104, 105, 107, 108, 109, 110,
303 112, 113, 114, 115, 116, 117, 118, 119,
304 120, 121, 122, 123, 123, 124, 125, 125,
305 126, 127, 127, 128, 128, 129, 129, 129,
306 130, 130, 130, 130, 131, 131, 131, 131,
307 131, 131, 131, 131, 130, 130, 130, 130,
308 129, 129, 129, 128, 128, 127, 127, 126,
309 125, 125, 124, 123, 122, 122, 121, 120,
310 119, 118, 117, 116, 115, 114, 112, 111,
311 110, 109, 107, 106, 105, 103, 102, 101,
312 99, 98, 96, 94, 93, 91, 90, 88,
313 86, 84, 83, 81, 79, 77, 75, 74,
314 72, 70, 68, 66, 64, 62, 60, 58,
315 56, 54, 52, 49, 47, 45, 43, 41,
316 39, 36, 34, 32, 30, 28, 25, 23,
317 21, 19, 16, 14, 12, 9, 7, 5,
318 3, 0, -1, -3, -6, -8, -10, -12,
319 -15, -17, -19, -22, -24, -26, -28, -30,
320 -33, -35, -37, -39, -41, -44, -46, -48,
321 -50, -52, -54, -56, -58, -60, -62, -64,
322 -66, -68, -70, -72, -74, -76, -78, -80,
323 -81, -83, -85, -87, -88, -90, -92, -93,
324 -95, -97, -98, -100, -101, -102, -104, -105,
325 -107, -108, -109, -110, -112, -113, -114, -115,
326 -116, -117, -118, -119, -120, -121, -122, -123,
327 -123, -124, -125, -125, -126, -127, -127, -128,
328 -128, -128, -128, -128, -128, -128, -128, -128,
329 -128, -128, -128, -128, -128, -128, -128, -128,
330 -128, -128, -128, -128, -128, -128, -128, -128,
331 -128, -127, -127, -126, -125, -125, -124, -123,
332 -122, -122, -121, -120, -119, -118, -117, -116,
333 -115, -114, -112, -111, -110, -109, -107, -106,
334 -105, -103, -102, -101, -99, -98, -96, -94,
335 -93, -91, -90, -88, -86, -84, -83, -81,
336 -79, -77, -75, -74, -72, -70, -68, -66,
337 -64, -62, -60, -58, -56, -54, -52, -49,
338 -47, -45, -43, -41, -39, -36, -34, -32,
339 -30, -28, -25, -23, -21, -19, -16, -14,
340 -12, -9, -7, -5, -3, 0, 1, 3,
341 6, 8, 10, 12, 15, 17, 19, 22,
342 24, 26, 28, 30, 33, 35, 37, 39, 41
343};
344
Joe Perches58aa68c2009-09-02 01:12:13 -0300345static const s16 hsv_red_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300346 82, 80, 78, 76, 74, 73, 71, 69,
347 67, 65, 63, 61, 58, 56, 54, 52,
348 50, 48, 46, 44, 41, 39, 37, 35,
349 32, 30, 28, 26, 23, 21, 19, 16,
350 14, 12, 10, 7, 5, 3, 0, -1,
351 -3, -6, -8, -10, -13, -15, -17, -19,
352 -22, -24, -26, -29, -31, -33, -35, -38,
353 -40, -42, -44, -46, -48, -51, -53, -55,
354 -57, -59, -61, -63, -65, -67, -69, -71,
355 -73, -75, -77, -79, -81, -82, -84, -86,
356 -88, -89, -91, -93, -94, -96, -98, -99,
357 -101, -102, -104, -105, -106, -108, -109, -110,
358 -112, -113, -114, -115, -116, -117, -119, -120,
359 -120, -121, -122, -123, -124, -125, -126, -126,
360 -127, -128, -128, -128, -128, -128, -128, -128,
361 -128, -128, -128, -128, -128, -128, -128, -128,
362 -128, -128, -128, -128, -128, -128, -128, -128,
363 -128, -128, -128, -128, -128, -128, -128, -128,
364 -127, -127, -126, -125, -125, -124, -123, -122,
365 -121, -120, -119, -118, -117, -116, -115, -114,
366 -113, -111, -110, -109, -107, -106, -105, -103,
367 -102, -100, -99, -97, -96, -94, -92, -91,
368 -89, -87, -85, -84, -82, -80, -78, -76,
369 -74, -73, -71, -69, -67, -65, -63, -61,
370 -58, -56, -54, -52, -50, -48, -46, -44,
371 -41, -39, -37, -35, -32, -30, -28, -26,
372 -23, -21, -19, -16, -14, -12, -10, -7,
373 -5, -3, 0, 1, 3, 6, 8, 10,
374 13, 15, 17, 19, 22, 24, 26, 29,
375 31, 33, 35, 38, 40, 42, 44, 46,
376 48, 51, 53, 55, 57, 59, 61, 63,
377 65, 67, 69, 71, 73, 75, 77, 79,
378 81, 82, 84, 86, 88, 89, 91, 93,
379 94, 96, 98, 99, 101, 102, 104, 105,
380 106, 108, 109, 110, 112, 113, 114, 115,
381 116, 117, 119, 120, 120, 121, 122, 123,
382 124, 125, 126, 126, 127, 128, 128, 129,
383 129, 130, 130, 131, 131, 131, 131, 132,
384 132, 132, 132, 132, 132, 132, 132, 132,
385 132, 132, 132, 131, 131, 131, 130, 130,
386 130, 129, 129, 128, 127, 127, 126, 125,
387 125, 124, 123, 122, 121, 120, 119, 118,
388 117, 116, 115, 114, 113, 111, 110, 109,
389 107, 106, 105, 103, 102, 100, 99, 97,
390 96, 94, 92, 91, 89, 87, 85, 84, 82
391};
392
Joe Perches58aa68c2009-09-02 01:12:13 -0300393static const s16 hsv_green_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300394 -124, -124, -125, -125, -125, -125, -125, -125,
395 -125, -126, -126, -125, -125, -125, -125, -125,
396 -125, -124, -124, -124, -123, -123, -122, -122,
397 -121, -121, -120, -120, -119, -118, -117, -117,
398 -116, -115, -114, -113, -112, -111, -110, -109,
399 -108, -107, -105, -104, -103, -102, -100, -99,
400 -98, -96, -95, -93, -92, -91, -89, -87,
401 -86, -84, -83, -81, -79, -77, -76, -74,
402 -72, -70, -69, -67, -65, -63, -61, -59,
403 -57, -55, -53, -51, -49, -47, -45, -43,
404 -41, -39, -37, -35, -33, -30, -28, -26,
405 -24, -22, -20, -18, -15, -13, -11, -9,
406 -7, -4, -2, 0, 1, 3, 6, 8,
407 10, 12, 14, 17, 19, 21, 23, 25,
408 27, 29, 32, 34, 36, 38, 40, 42,
409 44, 46, 48, 50, 52, 54, 56, 58,
410 60, 62, 64, 66, 68, 70, 71, 73,
411 75, 77, 78, 80, 82, 83, 85, 87,
412 88, 90, 91, 93, 94, 96, 97, 98,
413 100, 101, 102, 104, 105, 106, 107, 108,
414 109, 111, 112, 113, 113, 114, 115, 116,
415 117, 118, 118, 119, 120, 120, 121, 122,
416 122, 123, 123, 124, 124, 124, 125, 125,
417 125, 125, 125, 125, 125, 126, 126, 125,
418 125, 125, 125, 125, 125, 124, 124, 124,
419 123, 123, 122, 122, 121, 121, 120, 120,
420 119, 118, 117, 117, 116, 115, 114, 113,
421 112, 111, 110, 109, 108, 107, 105, 104,
422 103, 102, 100, 99, 98, 96, 95, 93,
423 92, 91, 89, 87, 86, 84, 83, 81,
424 79, 77, 76, 74, 72, 70, 69, 67,
425 65, 63, 61, 59, 57, 55, 53, 51,
426 49, 47, 45, 43, 41, 39, 37, 35,
427 33, 30, 28, 26, 24, 22, 20, 18,
428 15, 13, 11, 9, 7, 4, 2, 0,
429 -1, -3, -6, -8, -10, -12, -14, -17,
430 -19, -21, -23, -25, -27, -29, -32, -34,
431 -36, -38, -40, -42, -44, -46, -48, -50,
432 -52, -54, -56, -58, -60, -62, -64, -66,
433 -68, -70, -71, -73, -75, -77, -78, -80,
434 -82, -83, -85, -87, -88, -90, -91, -93,
435 -94, -96, -97, -98, -100, -101, -102, -104,
436 -105, -106, -107, -108, -109, -111, -112, -113,
437 -113, -114, -115, -116, -117, -118, -118, -119,
438 -120, -120, -121, -122, -122, -123, -123, -124, -124
439};
440
Joe Perches58aa68c2009-09-02 01:12:13 -0300441static const s16 hsv_green_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300442 -100, -99, -98, -97, -95, -94, -93, -91,
443 -90, -89, -87, -86, -84, -83, -81, -80,
444 -78, -76, -75, -73, -71, -70, -68, -66,
445 -64, -63, -61, -59, -57, -55, -53, -51,
446 -49, -48, -46, -44, -42, -40, -38, -36,
447 -34, -32, -30, -27, -25, -23, -21, -19,
448 -17, -15, -13, -11, -9, -7, -4, -2,
449 0, 1, 3, 5, 7, 9, 11, 14,
450 16, 18, 20, 22, 24, 26, 28, 30,
451 32, 34, 36, 38, 40, 42, 44, 46,
452 48, 50, 52, 54, 56, 58, 59, 61,
453 63, 65, 67, 68, 70, 72, 74, 75,
454 77, 78, 80, 82, 83, 85, 86, 88,
455 89, 90, 92, 93, 95, 96, 97, 98,
456 100, 101, 102, 103, 104, 105, 106, 107,
457 108, 109, 110, 111, 112, 112, 113, 114,
458 115, 115, 116, 116, 117, 117, 118, 118,
459 119, 119, 119, 120, 120, 120, 120, 120,
460 121, 121, 121, 121, 121, 121, 120, 120,
461 120, 120, 120, 119, 119, 119, 118, 118,
462 117, 117, 116, 116, 115, 114, 114, 113,
463 112, 111, 111, 110, 109, 108, 107, 106,
464 105, 104, 103, 102, 100, 99, 98, 97,
465 95, 94, 93, 91, 90, 89, 87, 86,
466 84, 83, 81, 80, 78, 76, 75, 73,
467 71, 70, 68, 66, 64, 63, 61, 59,
468 57, 55, 53, 51, 49, 48, 46, 44,
469 42, 40, 38, 36, 34, 32, 30, 27,
470 25, 23, 21, 19, 17, 15, 13, 11,
471 9, 7, 4, 2, 0, -1, -3, -5,
472 -7, -9, -11, -14, -16, -18, -20, -22,
473 -24, -26, -28, -30, -32, -34, -36, -38,
474 -40, -42, -44, -46, -48, -50, -52, -54,
475 -56, -58, -59, -61, -63, -65, -67, -68,
476 -70, -72, -74, -75, -77, -78, -80, -82,
477 -83, -85, -86, -88, -89, -90, -92, -93,
478 -95, -96, -97, -98, -100, -101, -102, -103,
479 -104, -105, -106, -107, -108, -109, -110, -111,
480 -112, -112, -113, -114, -115, -115, -116, -116,
481 -117, -117, -118, -118, -119, -119, -119, -120,
482 -120, -120, -120, -120, -121, -121, -121, -121,
483 -121, -121, -120, -120, -120, -120, -120, -119,
484 -119, -119, -118, -118, -117, -117, -116, -116,
485 -115, -114, -114, -113, -112, -111, -111, -110,
486 -109, -108, -107, -106, -105, -104, -103, -102, -100
487};
488
Joe Perches58aa68c2009-09-02 01:12:13 -0300489static const s16 hsv_blue_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300490 112, 113, 114, 114, 115, 116, 117, 117,
491 118, 118, 119, 119, 120, 120, 120, 121,
492 121, 121, 122, 122, 122, 122, 122, 122,
493 122, 122, 122, 122, 122, 122, 121, 121,
494 121, 120, 120, 120, 119, 119, 118, 118,
495 117, 116, 116, 115, 114, 113, 113, 112,
496 111, 110, 109, 108, 107, 106, 105, 104,
497 103, 102, 100, 99, 98, 97, 95, 94,
498 93, 91, 90, 88, 87, 85, 84, 82,
499 80, 79, 77, 76, 74, 72, 70, 69,
500 67, 65, 63, 61, 60, 58, 56, 54,
501 52, 50, 48, 46, 44, 42, 40, 38,
502 36, 34, 32, 30, 28, 26, 24, 22,
503 19, 17, 15, 13, 11, 9, 7, 5,
504 2, 0, -1, -3, -5, -7, -9, -12,
505 -14, -16, -18, -20, -22, -24, -26, -28,
506 -31, -33, -35, -37, -39, -41, -43, -45,
507 -47, -49, -51, -53, -54, -56, -58, -60,
508 -62, -64, -66, -67, -69, -71, -73, -74,
509 -76, -78, -79, -81, -83, -84, -86, -87,
510 -89, -90, -92, -93, -94, -96, -97, -98,
511 -99, -101, -102, -103, -104, -105, -106, -107,
512 -108, -109, -110, -111, -112, -113, -114, -114,
513 -115, -116, -117, -117, -118, -118, -119, -119,
514 -120, -120, -120, -121, -121, -121, -122, -122,
515 -122, -122, -122, -122, -122, -122, -122, -122,
516 -122, -122, -121, -121, -121, -120, -120, -120,
517 -119, -119, -118, -118, -117, -116, -116, -115,
518 -114, -113, -113, -112, -111, -110, -109, -108,
519 -107, -106, -105, -104, -103, -102, -100, -99,
520 -98, -97, -95, -94, -93, -91, -90, -88,
521 -87, -85, -84, -82, -80, -79, -77, -76,
522 -74, -72, -70, -69, -67, -65, -63, -61,
523 -60, -58, -56, -54, -52, -50, -48, -46,
524 -44, -42, -40, -38, -36, -34, -32, -30,
525 -28, -26, -24, -22, -19, -17, -15, -13,
526 -11, -9, -7, -5, -2, 0, 1, 3,
527 5, 7, 9, 12, 14, 16, 18, 20,
528 22, 24, 26, 28, 31, 33, 35, 37,
529 39, 41, 43, 45, 47, 49, 51, 53,
530 54, 56, 58, 60, 62, 64, 66, 67,
531 69, 71, 73, 74, 76, 78, 79, 81,
532 83, 84, 86, 87, 89, 90, 92, 93,
533 94, 96, 97, 98, 99, 101, 102, 103,
534 104, 105, 106, 107, 108, 109, 110, 111, 112
535};
536
Joe Perches58aa68c2009-09-02 01:12:13 -0300537static const s16 hsv_blue_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300538 -11, -13, -15, -17, -19, -21, -23, -25,
539 -27, -29, -31, -33, -35, -37, -39, -41,
540 -43, -45, -46, -48, -50, -52, -54, -55,
541 -57, -59, -61, -62, -64, -66, -67, -69,
542 -71, -72, -74, -75, -77, -78, -80, -81,
543 -83, -84, -86, -87, -88, -90, -91, -92,
544 -93, -95, -96, -97, -98, -99, -100, -101,
545 -102, -103, -104, -105, -106, -106, -107, -108,
546 -109, -109, -110, -111, -111, -112, -112, -113,
547 -113, -114, -114, -114, -115, -115, -115, -115,
548 -116, -116, -116, -116, -116, -116, -116, -116,
549 -116, -115, -115, -115, -115, -114, -114, -114,
550 -113, -113, -112, -112, -111, -111, -110, -110,
551 -109, -108, -108, -107, -106, -105, -104, -103,
552 -102, -101, -100, -99, -98, -97, -96, -95,
553 -94, -93, -91, -90, -89, -88, -86, -85,
554 -84, -82, -81, -79, -78, -76, -75, -73,
555 -71, -70, -68, -67, -65, -63, -62, -60,
556 -58, -56, -55, -53, -51, -49, -47, -45,
557 -44, -42, -40, -38, -36, -34, -32, -30,
558 -28, -26, -24, -22, -20, -18, -16, -14,
559 -12, -10, -8, -6, -4, -2, 0, 1,
560 3, 5, 7, 9, 11, 13, 15, 17,
561 19, 21, 23, 25, 27, 29, 31, 33,
562 35, 37, 39, 41, 43, 45, 46, 48,
563 50, 52, 54, 55, 57, 59, 61, 62,
564 64, 66, 67, 69, 71, 72, 74, 75,
565 77, 78, 80, 81, 83, 84, 86, 87,
566 88, 90, 91, 92, 93, 95, 96, 97,
567 98, 99, 100, 101, 102, 103, 104, 105,
568 106, 106, 107, 108, 109, 109, 110, 111,
569 111, 112, 112, 113, 113, 114, 114, 114,
570 115, 115, 115, 115, 116, 116, 116, 116,
571 116, 116, 116, 116, 116, 115, 115, 115,
572 115, 114, 114, 114, 113, 113, 112, 112,
573 111, 111, 110, 110, 109, 108, 108, 107,
574 106, 105, 104, 103, 102, 101, 100, 99,
575 98, 97, 96, 95, 94, 93, 91, 90,
576 89, 88, 86, 85, 84, 82, 81, 79,
577 78, 76, 75, 73, 71, 70, 68, 67,
578 65, 63, 62, 60, 58, 56, 55, 53,
579 51, 49, 47, 45, 44, 42, 40, 38,
580 36, 34, 32, 30, 28, 26, 24, 22,
581 20, 18, 16, 14, 12, 10, 8, 6,
582 4, 2, 0, -1, -3, -5, -7, -9, -11
583};
584
Jean-François Moinedae1de62012-03-24 09:20:25 -0300585static const u16 i2c_ident[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300586 V4L2_IDENT_OV9650,
587 V4L2_IDENT_OV9655,
588 V4L2_IDENT_SOI968,
589 V4L2_IDENT_OV7660,
590 V4L2_IDENT_OV7670,
591 V4L2_IDENT_MT9V011,
592 V4L2_IDENT_MT9V111,
593 V4L2_IDENT_MT9V112,
594 V4L2_IDENT_MT9M001C12ST,
595 V4L2_IDENT_MT9M111,
Brian Johnsone99ac542010-03-16 13:58:28 -0300596 V4L2_IDENT_MT9M112,
Brian Johnson26e744b2009-07-19 05:52:58 -0300597 V4L2_IDENT_HV7131R,
Jean-François Moinebed37382012-03-24 09:17:37 -0300598[SENSOR_MT9VPRB] = V4L2_IDENT_UNKNOWN,
Brian Johnson26e744b2009-07-19 05:52:58 -0300599};
600
Jean-François Moinedae1de62012-03-24 09:20:25 -0300601static const u16 bridge_init[][2] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300602 {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c},
603 {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40},
604 {0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10},
605 {0x106b, 0x08}, {0x1188, 0x87}, {0x11a1, 0x00},
606 {0x11a2, 0x00}, {0x11a3, 0x6a}, {0x11a4, 0x50},
607 {0x11ab, 0x00}, {0x11ac, 0x00}, {0x11ad, 0x50},
608 {0x11ae, 0x3c}, {0x118a, 0x04}, {0x0395, 0x04},
609 {0x11b8, 0x3a}, {0x118b, 0x0e}, {0x10f7, 0x05},
610 {0x10f8, 0x14}, {0x10fa, 0xff}, {0x10f9, 0x00},
611 {0x11ba, 0x0a}, {0x11a5, 0x2d}, {0x11a6, 0x2d},
612 {0x11a7, 0x3a}, {0x11a8, 0x05}, {0x11a9, 0x04},
613 {0x11aa, 0x3f}, {0x11af, 0x28}, {0x11b0, 0xd8},
614 {0x11b1, 0x14}, {0x11b2, 0xec}, {0x11b3, 0x32},
615 {0x11b4, 0xdd}, {0x11b5, 0x32}, {0x11b6, 0xdd},
616 {0x10e0, 0x2c}, {0x11bc, 0x40}, {0x11bd, 0x01},
617 {0x11be, 0xf0}, {0x11bf, 0x00}, {0x118c, 0x1f},
618 {0x118d, 0x1f}, {0x118e, 0x1f}, {0x118f, 0x1f},
619 {0x1180, 0x01}, {0x1181, 0x00}, {0x1182, 0x01},
Brian Johnson0c045eb2010-03-16 13:58:27 -0300620 {0x1183, 0x00}, {0x1184, 0x50}, {0x1185, 0x80},
621 {0x1007, 0x00}
Brian Johnson26e744b2009-07-19 05:52:58 -0300622};
623
624/* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300625static const u8 ov_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300626 0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */,
627 0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */,
628 0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */,
629 0x30 /* 4x */, 0x31 /* 4.25x */, 0x32 /* 4.5x */, 0x33 /* 4.75x */,
630 0x34 /* 5x */, 0x35 /* 5.25x */, 0x36 /* 5.5x */, 0x37 /* 5.75x */,
631 0x38 /* 6x */, 0x39 /* 6.25x */, 0x3a /* 6.5x */, 0x3b /* 6.75x */,
632 0x3c /* 7x */, 0x3d /* 7.25x */, 0x3e /* 7.5x */, 0x3f /* 7.75x */,
633 0x70 /* 8x */
634};
635
636/* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300637static const u16 micron1_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300638 /* 1x 1.25x 1.5x 1.75x */
639 0x0020, 0x0028, 0x0030, 0x0038,
640 /* 2x 2.25x 2.5x 2.75x */
641 0x00a0, 0x00a4, 0x00a8, 0x00ac,
642 /* 3x 3.25x 3.5x 3.75x */
643 0x00b0, 0x00b4, 0x00b8, 0x00bc,
644 /* 4x 4.25x 4.5x 4.75x */
645 0x00c0, 0x00c4, 0x00c8, 0x00cc,
646 /* 5x 5.25x 5.5x 5.75x */
647 0x00d0, 0x00d4, 0x00d8, 0x00dc,
648 /* 6x 6.25x 6.5x 6.75x */
649 0x00e0, 0x00e4, 0x00e8, 0x00ec,
650 /* 7x 7.25x 7.5x 7.75x */
651 0x00f0, 0x00f4, 0x00f8, 0x00fc,
652 /* 8x */
653 0x01c0
654};
655
656/* mt9m001 sensor uses a different gain formula then other micron sensors */
657/* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300658static const u16 micron2_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300659 /* 1x 1.25x 1.5x 1.75x */
660 0x0008, 0x000a, 0x000c, 0x000e,
661 /* 2x 2.25x 2.5x 2.75x */
662 0x0010, 0x0012, 0x0014, 0x0016,
663 /* 3x 3.25x 3.5x 3.75x */
664 0x0018, 0x001a, 0x001c, 0x001e,
665 /* 4x 4.25x 4.5x 4.75x */
666 0x0020, 0x0051, 0x0052, 0x0053,
667 /* 5x 5.25x 5.5x 5.75x */
668 0x0054, 0x0055, 0x0056, 0x0057,
669 /* 6x 6.25x 6.5x 6.75x */
670 0x0058, 0x0059, 0x005a, 0x005b,
671 /* 7x 7.25x 7.5x 7.75x */
672 0x005c, 0x005d, 0x005e, 0x005f,
673 /* 8x */
674 0x0060
675};
676
677/* Gain = .5 + bit[7:0] / 16 */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300678static const u8 hv7131r_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300679 0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */,
680 0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */,
681 0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */,
682 0x38 /* 4x */, 0x3c /* 4.25x */, 0x40 /* 4.5x */, 0x44 /* 4.75x */,
683 0x48 /* 5x */, 0x4c /* 5.25x */, 0x50 /* 5.5x */, 0x54 /* 5.75x */,
684 0x58 /* 6x */, 0x5c /* 6.25x */, 0x60 /* 6.5x */, 0x64 /* 6.75x */,
685 0x68 /* 7x */, 0x6c /* 7.25x */, 0x70 /* 7.5x */, 0x74 /* 7.75x */,
686 0x78 /* 8x */
687};
688
Jean-François Moinedae1de62012-03-24 09:20:25 -0300689static const struct i2c_reg_u8 soi968_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300690 {0x0c, 0x00}, {0x0f, 0x1f},
Brian Johnson26e744b2009-07-19 05:52:58 -0300691 {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
692 {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
693 {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
694 {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20},
695 {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e},
Brian Johnsone1430472009-09-02 12:39:41 -0300696 {0x13, 0x8b}, {0x12, 0x40}, {0x17, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300697 {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79},
698 {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40},
699 {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32},
700 {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80},
701};
702
Jean-François Moinedae1de62012-03-24 09:20:25 -0300703static const struct i2c_reg_u8 ov7660_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300704 {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
705 {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
706 {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
Hans de Goede8bc50f32011-02-16 07:11:14 -0300707 /* HDG Set hstart and hstop, datasheet default 0x11, 0x61, using
708 0x10, 0x61 and sd->hstart, vstart = 3, fixes ugly colored borders */
709 {0x17, 0x10}, {0x18, 0x61},
Brian Johnson26e744b2009-07-19 05:52:58 -0300710 {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43},
Jean-François Moinea1ac5dc2012-03-24 09:33:42 -0300711 {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0x00},
712 {0x2e, 0x00}, {0x01, 0x78}, {0x02, 0x50},
Brian Johnson26e744b2009-07-19 05:52:58 -0300713};
714
Jean-François Moinedae1de62012-03-24 09:20:25 -0300715static const struct i2c_reg_u8 ov7670_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300716 {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
Brian Johnson26e744b2009-07-19 05:52:58 -0300717 {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
718 {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
719 {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
720 {0x0d, 0x40}, {0x14, 0x28}, {0xa5, 0x05}, {0xab, 0x07},
721 {0x24, 0x95}, {0x25, 0x33}, {0x26, 0xe3}, {0x9f, 0x75},
722 {0xa0, 0x65}, {0xa1, 0x0b}, {0xa6, 0xd8}, {0xa7, 0xd8},
723 {0xa8, 0xf0}, {0xa9, 0x90}, {0xaa, 0x94}, {0x13, 0xe5},
724 {0x0e, 0x61}, {0x0f, 0x4b}, {0x16, 0x02}, {0x1e, 0x27},
725 {0x21, 0x02}, {0x22, 0x91}, {0x29, 0x07}, {0x33, 0x0b},
726 {0x35, 0x0b}, {0x37, 0x1d}, {0x38, 0x71}, {0x39, 0x2a},
727 {0x3c, 0x78}, {0x4d, 0x40}, {0x4e, 0x20}, {0x69, 0x00},
728 {0x74, 0x19}, {0x8d, 0x4f}, {0x8e, 0x00}, {0x8f, 0x00},
729 {0x90, 0x00}, {0x91, 0x00}, {0x96, 0x00}, {0x9a, 0x80},
730 {0xb0, 0x84}, {0xb1, 0x0c}, {0xb2, 0x0e}, {0xb3, 0x82},
731 {0xb8, 0x0a}, {0x43, 0x0a}, {0x44, 0xf0}, {0x45, 0x20},
732 {0x46, 0x7d}, {0x47, 0x29}, {0x48, 0x4a}, {0x59, 0x8c},
733 {0x5a, 0xa5}, {0x5b, 0xde}, {0x5c, 0x96}, {0x5d, 0x66},
734 {0x5e, 0x10}, {0x6c, 0x0a}, {0x6d, 0x55}, {0x6e, 0x11},
735 {0x6f, 0x9e}, {0x6a, 0x40}, {0x01, 0x40}, {0x02, 0x40},
736 {0x13, 0xe7}, {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x02},
737 {0x52, 0x1d}, {0x53, 0x56}, {0x54, 0x73}, {0x55, 0x0a},
738 {0x56, 0x55}, {0x57, 0x80}, {0x58, 0x9e}, {0x41, 0x08},
739 {0x3f, 0x02}, {0x75, 0x03}, {0x76, 0x63}, {0x4c, 0x04},
740 {0x77, 0x06}, {0x3d, 0x02}, {0x4b, 0x09}, {0xc9, 0x30},
741 {0x41, 0x08}, {0x56, 0x48}, {0x34, 0x11}, {0xa4, 0x88},
742 {0x96, 0x00}, {0x97, 0x30}, {0x98, 0x20}, {0x99, 0x30},
743 {0x9a, 0x84}, {0x9b, 0x29}, {0x9c, 0x03}, {0x9d, 0x99},
744 {0x9e, 0x7f}, {0x78, 0x04}, {0x79, 0x01}, {0xc8, 0xf0},
745 {0x79, 0x0f}, {0xc8, 0x00}, {0x79, 0x10}, {0xc8, 0x7e},
746 {0x79, 0x0a}, {0xc8, 0x80}, {0x79, 0x0b}, {0xc8, 0x01},
747 {0x79, 0x0c}, {0xc8, 0x0f}, {0x79, 0x0d}, {0xc8, 0x20},
748 {0x79, 0x09}, {0xc8, 0x80}, {0x79, 0x02}, {0xc8, 0xc0},
749 {0x79, 0x03}, {0xc8, 0x40}, {0x79, 0x05}, {0xc8, 0x30},
750 {0x79, 0x26}, {0x62, 0x20}, {0x63, 0x00}, {0x64, 0x06},
751 {0x65, 0x00}, {0x66, 0x05}, {0x94, 0x05}, {0x95, 0x0a},
752 {0x17, 0x13}, {0x18, 0x01}, {0x19, 0x02}, {0x1a, 0x7a},
753 {0x46, 0x59}, {0x47, 0x30}, {0x58, 0x9a}, {0x59, 0x84},
754 {0x5a, 0x91}, {0x5b, 0x57}, {0x5c, 0x75}, {0x5d, 0x6d},
755 {0x5e, 0x13}, {0x64, 0x07}, {0x94, 0x07}, {0x95, 0x0d},
756 {0xa6, 0xdf}, {0xa7, 0xdf}, {0x48, 0x4d}, {0x51, 0x00},
757 {0x6b, 0x0a}, {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00},
758 {0x92, 0x00}, {0x93, 0x00}, {0x55, 0x0a}, {0x56, 0x60},
759 {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d},
760 {0x53, 0x56}, {0x54, 0x73}, {0x58, 0x9a}, {0x4f, 0x6e},
761 {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, {0x53, 0x56},
762 {0x54, 0x73}, {0x58, 0x9a}, {0x3f, 0x01}, {0x7b, 0x03},
763 {0x7c, 0x09}, {0x7d, 0x16}, {0x7e, 0x38}, {0x7f, 0x47},
764 {0x80, 0x53}, {0x81, 0x5e}, {0x82, 0x6a}, {0x83, 0x74},
765 {0x84, 0x80}, {0x85, 0x8c}, {0x86, 0x9b}, {0x87, 0xb2},
766 {0x88, 0xcc}, {0x89, 0xe5}, {0x7a, 0x24}, {0x3b, 0x00},
767 {0x9f, 0x76}, {0xa0, 0x65}, {0x13, 0xe2}, {0x6b, 0x0a},
768 {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, {0x92, 0x00},
769 {0x93, 0x00},
770};
771
Jean-François Moinedae1de62012-03-24 09:20:25 -0300772static const struct i2c_reg_u8 ov9650_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300773 {0x00, 0x00}, {0x01, 0x78},
Brian Johnson26e744b2009-07-19 05:52:58 -0300774 {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
775 {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
776 {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
777 {0x0e, 0xa0}, {0x0f, 0x52}, {0x10, 0x7c},
778 {0x11, 0x80}, {0x12, 0x45}, {0x13, 0xc2},
779 {0x14, 0x2e}, {0x15, 0x00}, {0x16, 0x07},
780 {0x17, 0x24}, {0x18, 0xc5}, {0x19, 0x00},
781 {0x1a, 0x3c}, {0x1b, 0x00}, {0x1e, 0x04},
782 {0x1f, 0x00}, {0x24, 0x78}, {0x25, 0x68},
783 {0x26, 0xd4}, {0x27, 0x80}, {0x28, 0x80},
784 {0x29, 0x30}, {0x2a, 0x00}, {0x2b, 0x00},
785 {0x2c, 0x80}, {0x2d, 0x00}, {0x2e, 0x00},
786 {0x2f, 0x00}, {0x30, 0x08}, {0x31, 0x30},
787 {0x32, 0x84}, {0x33, 0xe2}, {0x34, 0xbf},
788 {0x35, 0x81}, {0x36, 0xf9}, {0x37, 0x00},
789 {0x38, 0x93}, {0x39, 0x50}, {0x3a, 0x01},
790 {0x3b, 0x01}, {0x3c, 0x73}, {0x3d, 0x19},
791 {0x3e, 0x0b}, {0x3f, 0x80}, {0x40, 0xc1},
792 {0x41, 0x00}, {0x42, 0x08}, {0x67, 0x80},
793 {0x68, 0x80}, {0x69, 0x40}, {0x6a, 0x00},
794 {0x6b, 0x0a}, {0x8b, 0x06}, {0x8c, 0x20},
795 {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0xdf},
796 {0x92, 0x00}, {0x93, 0x00}, {0x94, 0x88},
797 {0x95, 0x88}, {0x96, 0x04}, {0xa1, 0x00},
798 {0xa5, 0x80}, {0xa8, 0x80}, {0xa9, 0xb8},
799 {0xaa, 0x92}, {0xab, 0x0a},
800};
801
Jean-François Moinedae1de62012-03-24 09:20:25 -0300802static const struct i2c_reg_u8 ov9655_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300803 {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300804 {0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
805 {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
806 {0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57},
807 {0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c}, {0x3d, 0x19},
808 {0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40}, {0x42, 0x80},
809 {0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a}, {0x48, 0x3c},
810 {0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc}, {0x4d, 0xdc},
811 {0x4e, 0xdc}, {0x6c, 0x04}, {0x6f, 0x9e}, {0x70, 0x05},
812 {0x71, 0x78}, {0x77, 0x02}, {0x8a, 0x23}, {0x90, 0x7e},
813 {0x91, 0x7c}, {0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68},
814 {0xa6, 0x60}, {0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92},
815 {0xab, 0x04}, {0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80},
816 {0xaf, 0x80}, {0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00},
817 {0xb6, 0xaf}, {0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44},
818 {0xbe, 0x3b}, {0xbf, 0x3a}, {0xc1, 0xc8}, {0xc2, 0x01},
Brian Johnson26e744b2009-07-19 05:52:58 -0300819 {0xc4, 0x00}, {0xc6, 0x85}, {0xc7, 0x81}, {0xc9, 0xe0},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300820 {0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x2d, 0x00},
821 {0x2e, 0x00}, {0x01, 0x80}, {0x02, 0x80}, {0x12, 0x61},
Brian Johnson26e744b2009-07-19 05:52:58 -0300822 {0x36, 0xfa}, {0x8c, 0x8d}, {0xc0, 0xaa}, {0x69, 0x0a},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300823 {0x03, 0x09}, {0x17, 0x16}, {0x18, 0x6e}, {0x19, 0x01},
824 {0x1a, 0x3e}, {0x32, 0x09}, {0x2a, 0x10}, {0x2b, 0x0a},
825 {0x92, 0x00}, {0x93, 0x00}, {0xa1, 0x00}, {0x10, 0x7c},
826 {0x04, 0x03}, {0x00, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300827};
828
Jean-François Moinedae1de62012-03-24 09:20:25 -0300829static const struct i2c_reg_u16 mt9v112_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300830 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020},
831 {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
832 {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
833 {0x05, 0x0000}, {0x06, 0x340c}, {0x3b, 0x042a},
834 {0x3c, 0x0400}, {0xf0, 0x0002}, {0x2e, 0x0c58},
835 {0x5b, 0x0001}, {0xc8, 0x9f0b}, {0xf0, 0x0001},
836 {0x9b, 0x5300}, {0xf0, 0x0000}, {0x2b, 0x0020},
837 {0x2c, 0x002a}, {0x2d, 0x0032}, {0x2e, 0x0020},
838 {0x09, 0x01dc}, {0x01, 0x000c}, {0x02, 0x0020},
839 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
840 {0x05, 0x0098}, {0x20, 0x0703}, {0x09, 0x01f2},
841 {0x2b, 0x00a0}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
842 {0x2e, 0x00a0}, {0x01, 0x000c}, {0x02, 0x0020},
843 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
844 {0x05, 0x0098}, {0x09, 0x01c1}, {0x2b, 0x00ae},
845 {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
846};
847
Jean-François Moinedae1de62012-03-24 09:20:25 -0300848static const struct i2c_reg_u16 mt9v111_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300849 {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
Brian Johnson6ea23bd2010-05-05 13:22:45 -0300850 {0x01, 0x0001}, {0x05, 0x0004}, {0x2d, 0xe0a0},
851 {0x2e, 0x0c64}, {0x2f, 0x0064}, {0x06, 0x600e},
852 {0x08, 0x0480}, {0x01, 0x0004}, {0x02, 0x0016},
853 {0x03, 0x01e7}, {0x04, 0x0287}, {0x05, 0x0004},
854 {0x06, 0x002d}, {0x07, 0x3002}, {0x08, 0x0008},
855 {0x0e, 0x0008}, {0x20, 0x0000}
Brian Johnson26e744b2009-07-19 05:52:58 -0300856};
857
Jean-François Moinedae1de62012-03-24 09:20:25 -0300858static const struct i2c_reg_u16 mt9v011_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300859 {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
860 {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1},
861 {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006},
862 {0x0d, 0x0002}, {0x0a, 0x0000}, {0x0b, 0x0000},
863 {0x0c, 0x0000}, {0x0d, 0x0000}, {0x0e, 0x0000},
864 {0x0f, 0x0000}, {0x10, 0x0000}, {0x11, 0x0000},
865 {0x12, 0x0000}, {0x13, 0x0000}, {0x14, 0x0000},
866 {0x15, 0x0000}, {0x16, 0x0000}, {0x17, 0x0000},
867 {0x18, 0x0000}, {0x19, 0x0000}, {0x1a, 0x0000},
868 {0x1b, 0x0000}, {0x1c, 0x0000}, {0x1d, 0x0000},
869 {0x32, 0x0000}, {0x20, 0x1101}, {0x21, 0x0000},
870 {0x22, 0x0000}, {0x23, 0x0000}, {0x24, 0x0000},
871 {0x25, 0x0000}, {0x26, 0x0000}, {0x27, 0x0024},
872 {0x2f, 0xf7b0}, {0x30, 0x0005}, {0x31, 0x0000},
873 {0x32, 0x0000}, {0x33, 0x0000}, {0x34, 0x0100},
874 {0x3d, 0x068f}, {0x40, 0x01e0}, {0x41, 0x00d1},
875 {0x44, 0x0082}, {0x5a, 0x0000}, {0x5b, 0x0000},
876 {0x5c, 0x0000}, {0x5d, 0x0000}, {0x5e, 0x0000},
877 {0x5f, 0xa31d}, {0x62, 0x0611}, {0x0a, 0x0000},
878 {0x06, 0x0029}, {0x05, 0x0009}, {0x20, 0x1101},
879 {0x20, 0x1101}, {0x09, 0x0064}, {0x07, 0x0003},
880 {0x2b, 0x0033}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
881 {0x2e, 0x0033}, {0x07, 0x0002}, {0x06, 0x0000},
882 {0x06, 0x0029}, {0x05, 0x0009},
883};
884
Jean-François Moinedae1de62012-03-24 09:20:25 -0300885static const struct i2c_reg_u16 mt9m001_init[] = {
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -0300886 {0x0d, 0x0001},
887 {0x0d, 0x0000},
888 {0x04, 0x0500}, /* hres = 1280 */
889 {0x03, 0x0400}, /* vres = 1024 */
890 {0x20, 0x1100},
891 {0x06, 0x0010},
892 {0x2b, 0x0024},
893 {0x2e, 0x0024},
894 {0x35, 0x0024},
895 {0x2d, 0x0020},
896 {0x2c, 0x0020},
897 {0x09, 0x0ad4},
898 {0x35, 0x0057},
Brian Johnson26e744b2009-07-19 05:52:58 -0300899};
900
Jean-François Moinedae1de62012-03-24 09:20:25 -0300901static const struct i2c_reg_u16 mt9m111_init[] = {
Brian Johnson13a84fa2009-09-03 19:07:13 -0300902 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
903 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
Brian Johnson4d708a52009-09-03 19:10:15 -0300904 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
905 {0xf0, 0x0000},
Brian Johnson26e744b2009-07-19 05:52:58 -0300906};
907
Jean-François Moinedae1de62012-03-24 09:20:25 -0300908static const struct i2c_reg_u16 mt9m112_init[] = {
Brian Johnsone99ac542010-03-16 13:58:28 -0300909 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
910 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
911 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
912 {0xf0, 0x0000},
913};
914
Jean-François Moinedae1de62012-03-24 09:20:25 -0300915static const struct i2c_reg_u8 hv7131r_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300916 {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
917 {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
918 {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
919 {0x01, 0x08}, {0x01, 0x08}, {0x25, 0x07},
920 {0x26, 0xc3}, {0x27, 0x50}, {0x30, 0x62},
921 {0x31, 0x10}, {0x32, 0x06}, {0x33, 0x10},
922 {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00},
923 {0x23, 0x09}, {0x01, 0x08},
924};
925
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300926static void reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
Brian Johnson26e744b2009-07-19 05:52:58 -0300927{
928 struct usb_device *dev = gspca_dev->dev;
929 int result;
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300930
931 if (gspca_dev->usb_err < 0)
932 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300933 result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
934 0x00,
935 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
936 reg,
937 0x00,
938 gspca_dev->usb_buf,
939 length,
940 500);
941 if (unlikely(result < 0 || result != length)) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300942 pr_err("Read register %02x failed %d\n", reg, result);
943 gspca_dev->usb_err = result;
Brian Johnson26e744b2009-07-19 05:52:58 -0300944 }
Brian Johnson26e744b2009-07-19 05:52:58 -0300945}
946
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300947static void reg_w(struct gspca_dev *gspca_dev, u16 reg,
Joe Perches58aa68c2009-09-02 01:12:13 -0300948 const u8 *buffer, int length)
Brian Johnson26e744b2009-07-19 05:52:58 -0300949{
950 struct usb_device *dev = gspca_dev->dev;
951 int result;
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300952
953 if (gspca_dev->usb_err < 0)
954 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300955 memcpy(gspca_dev->usb_buf, buffer, length);
956 result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
957 0x08,
958 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
959 reg,
960 0x00,
961 gspca_dev->usb_buf,
962 length,
963 500);
964 if (unlikely(result < 0 || result != length)) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300965 pr_err("Write register %02x failed %d\n", reg, result);
966 gspca_dev->usb_err = result;
Brian Johnson26e744b2009-07-19 05:52:58 -0300967 }
Brian Johnson26e744b2009-07-19 05:52:58 -0300968}
969
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300970static void reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
Brian Johnson26e744b2009-07-19 05:52:58 -0300971{
Jean-François Moineff38d582012-03-19 04:55:16 -0300972 reg_w(gspca_dev, reg, &value, 1);
Brian Johnson26e744b2009-07-19 05:52:58 -0300973}
974
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300975static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
Brian Johnson26e744b2009-07-19 05:52:58 -0300976{
977 int i;
Jean-François Moineff38d582012-03-19 04:55:16 -0300978
Brian Johnson26e744b2009-07-19 05:52:58 -0300979 reg_w(gspca_dev, 0x10c0, buffer, 8);
980 for (i = 0; i < 5; i++) {
981 reg_r(gspca_dev, 0x10c0, 1);
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300982 if (gspca_dev->usb_err < 0)
983 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300984 if (gspca_dev->usb_buf[0] & 0x04) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300985 if (gspca_dev->usb_buf[0] & 0x08) {
986 pr_err("i2c_w error\n");
987 gspca_dev->usb_err = -EIO;
988 }
989 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300990 }
Jean-François Moinee71389b2012-03-19 04:45:20 -0300991 msleep(10);
Brian Johnson26e744b2009-07-19 05:52:58 -0300992 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300993 pr_err("i2c_w reg %02x no response\n", buffer[2]);
994/* gspca_dev->usb_err = -EIO; fixme: may occur */
Brian Johnson26e744b2009-07-19 05:52:58 -0300995}
996
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300997static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
Brian Johnson26e744b2009-07-19 05:52:58 -0300998{
999 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson26e744b2009-07-19 05:52:58 -03001000 u8 row[8];
1001
1002 /*
1003 * from the point of view of the bridge, the length
1004 * includes the address
1005 */
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001006 row[0] = sd->i2c_intf | (2 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001007 row[1] = sd->i2c_addr;
1008 row[2] = reg;
1009 row[3] = val;
1010 row[4] = 0x00;
1011 row[5] = 0x00;
1012 row[6] = 0x00;
1013 row[7] = 0x10;
1014
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001015 i2c_w(gspca_dev, row);
Brian Johnson26e744b2009-07-19 05:52:58 -03001016}
1017
Jean-François Moined4689b72012-03-19 04:42:45 -03001018static void i2c_w1_buf(struct gspca_dev *gspca_dev,
Jean-François Moinedae1de62012-03-24 09:20:25 -03001019 const struct i2c_reg_u8 *buf, int sz)
Jean-François Moined4689b72012-03-19 04:42:45 -03001020{
1021 while (--sz >= 0) {
1022 i2c_w1(gspca_dev, buf->reg, buf->val);
1023 buf++;
1024 }
1025}
1026
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001027static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001028{
1029 struct sd *sd = (struct sd *) gspca_dev;
1030 u8 row[8];
1031
1032 /*
1033 * from the point of view of the bridge, the length
1034 * includes the address
1035 */
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001036 row[0] = sd->i2c_intf | (3 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001037 row[1] = sd->i2c_addr;
1038 row[2] = reg;
Jean-François Moineff38d582012-03-19 04:55:16 -03001039 row[3] = val >> 8;
1040 row[4] = val;
Brian Johnson26e744b2009-07-19 05:52:58 -03001041 row[5] = 0x00;
1042 row[6] = 0x00;
1043 row[7] = 0x10;
1044
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001045 i2c_w(gspca_dev, row);
Brian Johnson26e744b2009-07-19 05:52:58 -03001046}
1047
Jean-François Moined4689b72012-03-19 04:42:45 -03001048static void i2c_w2_buf(struct gspca_dev *gspca_dev,
Jean-François Moinedae1de62012-03-24 09:20:25 -03001049 const struct i2c_reg_u16 *buf, int sz)
Jean-François Moined4689b72012-03-19 04:42:45 -03001050{
1051 while (--sz >= 0) {
1052 i2c_w2(gspca_dev, buf->reg, buf->val);
1053 buf++;
1054 }
1055}
1056
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001057static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001058{
1059 struct sd *sd = (struct sd *) gspca_dev;
1060 u8 row[8];
1061
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001062 row[0] = sd->i2c_intf | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001063 row[1] = sd->i2c_addr;
1064 row[2] = reg;
1065 row[3] = 0;
1066 row[4] = 0;
1067 row[5] = 0;
1068 row[6] = 0;
1069 row[7] = 0x10;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001070 i2c_w(gspca_dev, row);
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001071 row[0] = sd->i2c_intf | (1 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001072 row[2] = 0;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001073 i2c_w(gspca_dev, row);
1074 reg_r(gspca_dev, 0x10c2, 5);
Brian Johnson00b581e2009-07-23 05:55:43 -03001075 *val = gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001076}
1077
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001078static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001079{
1080 struct sd *sd = (struct sd *) gspca_dev;
1081 u8 row[8];
1082
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001083 row[0] = sd->i2c_intf | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001084 row[1] = sd->i2c_addr;
1085 row[2] = reg;
1086 row[3] = 0;
1087 row[4] = 0;
1088 row[5] = 0;
1089 row[6] = 0;
1090 row[7] = 0x10;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001091 i2c_w(gspca_dev, row);
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001092 row[0] = sd->i2c_intf | (2 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001093 row[2] = 0;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001094 i2c_w(gspca_dev, row);
1095 reg_r(gspca_dev, 0x10c2, 5);
Brian Johnson00b581e2009-07-23 05:55:43 -03001096 *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001097}
1098
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001099static void ov9650_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001100{
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001101 u16 id;
Brian Johnson26e744b2009-07-19 05:52:58 -03001102 struct sd *sd = (struct sd *) gspca_dev;
1103
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001104 i2c_r2(gspca_dev, 0x1c, &id);
1105 if (gspca_dev->usb_err < 0)
1106 return;
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001107
1108 if (id != 0x7fa2) {
Joe Perches91f58422011-08-21 19:56:55 -03001109 pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001110 gspca_dev->usb_err = -ENODEV;
1111 return;
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001112 }
1113
Jean-François Moine92884f82012-03-19 04:33:30 -03001114 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1115 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001116 i2c_w1_buf(gspca_dev, ov9650_init, ARRAY_SIZE(ov9650_init));
1117 if (gspca_dev->usb_err < 0)
1118 pr_err("OV9650 sensor initialization failed\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001119 sd->hstart = 1;
1120 sd->vstart = 7;
Brian Johnson26e744b2009-07-19 05:52:58 -03001121}
1122
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001123static void ov9655_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001124{
Brian Johnson26e744b2009-07-19 05:52:58 -03001125 struct sd *sd = (struct sd *) gspca_dev;
1126
Jean-François Moine92884f82012-03-19 04:33:30 -03001127 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1128 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001129 i2c_w1_buf(gspca_dev, ov9655_init, ARRAY_SIZE(ov9655_init));
1130 if (gspca_dev->usb_err < 0)
1131 pr_err("OV9655 sensor initialization failed\n");
1132
Brian Johnsoncc2a8332010-03-16 13:58:28 -03001133 sd->hstart = 1;
1134 sd->vstart = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001135}
1136
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001137static void soi968_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001138{
Brian Johnson26e744b2009-07-19 05:52:58 -03001139 struct sd *sd = (struct sd *) gspca_dev;
1140
Jean-François Moine92884f82012-03-19 04:33:30 -03001141 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1142 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001143 i2c_w1_buf(gspca_dev, soi968_init, ARRAY_SIZE(soi968_init));
1144 if (gspca_dev->usb_err < 0)
1145 pr_err("SOI968 sensor initialization failed\n");
1146
Brian Johnson26e744b2009-07-19 05:52:58 -03001147 sd->hstart = 60;
1148 sd->vstart = 11;
Brian Johnson26e744b2009-07-19 05:52:58 -03001149}
1150
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001151static void ov7660_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001152{
Brian Johnson26e744b2009-07-19 05:52:58 -03001153 struct sd *sd = (struct sd *) gspca_dev;
1154
Jean-François Moine92884f82012-03-19 04:33:30 -03001155 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1156 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001157 i2c_w1_buf(gspca_dev, ov7660_init, ARRAY_SIZE(ov7660_init));
1158 if (gspca_dev->usb_err < 0)
1159 pr_err("OV7660 sensor initialization failed\n");
Hans de Goede8bc50f32011-02-16 07:11:14 -03001160 sd->hstart = 3;
1161 sd->vstart = 3;
Brian Johnson26e744b2009-07-19 05:52:58 -03001162}
1163
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001164static void ov7670_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001165{
Brian Johnson26e744b2009-07-19 05:52:58 -03001166 struct sd *sd = (struct sd *) gspca_dev;
1167
Jean-François Moine92884f82012-03-19 04:33:30 -03001168 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1169 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001170 i2c_w1_buf(gspca_dev, ov7670_init, ARRAY_SIZE(ov7670_init));
1171 if (gspca_dev->usb_err < 0)
1172 pr_err("OV7670 sensor initialization failed\n");
1173
Brian Johnson26e744b2009-07-19 05:52:58 -03001174 sd->hstart = 0;
1175 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001176}
1177
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001178static void mt9v_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001179{
1180 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson26e744b2009-07-19 05:52:58 -03001181 u16 value;
Brian Johnson26e744b2009-07-19 05:52:58 -03001182
1183 sd->i2c_addr = 0x5d;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001184 i2c_r2(gspca_dev, 0xff, &value);
1185 if (gspca_dev->usb_err >= 0
1186 && value == 0x8243) {
Jean-François Moined4689b72012-03-19 04:42:45 -03001187 i2c_w2_buf(gspca_dev, mt9v011_init, ARRAY_SIZE(mt9v011_init));
1188 if (gspca_dev->usb_err < 0) {
1189 pr_err("MT9V011 sensor initialization failed\n");
1190 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001191 }
1192 sd->hstart = 2;
1193 sd->vstart = 2;
1194 sd->sensor = SENSOR_MT9V011;
Joe Perches91f58422011-08-21 19:56:55 -03001195 pr_info("MT9V011 sensor detected\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001196 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001197 }
1198
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001199 gspca_dev->usb_err = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001200 sd->i2c_addr = 0x5c;
1201 i2c_w2(gspca_dev, 0x01, 0x0004);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001202 i2c_r2(gspca_dev, 0xff, &value);
1203 if (gspca_dev->usb_err >= 0
1204 && value == 0x823a) {
Jean-François Moined4689b72012-03-19 04:42:45 -03001205 i2c_w2_buf(gspca_dev, mt9v111_init, ARRAY_SIZE(mt9v111_init));
1206 if (gspca_dev->usb_err < 0) {
1207 pr_err("MT9V111 sensor initialization failed\n");
1208 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001209 }
1210 sd->hstart = 2;
1211 sd->vstart = 2;
1212 sd->sensor = SENSOR_MT9V111;
Joe Perches91f58422011-08-21 19:56:55 -03001213 pr_info("MT9V111 sensor detected\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001214 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001215 }
1216
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001217 gspca_dev->usb_err = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001218 sd->i2c_addr = 0x5d;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001219 i2c_w2(gspca_dev, 0xf0, 0x0000);
1220 if (gspca_dev->usb_err < 0) {
1221 gspca_dev->usb_err = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001222 sd->i2c_addr = 0x48;
1223 i2c_w2(gspca_dev, 0xf0, 0x0000);
1224 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001225 i2c_r2(gspca_dev, 0x00, &value);
1226 if (gspca_dev->usb_err >= 0
1227 && value == 0x1229) {
Jean-François Moined4689b72012-03-19 04:42:45 -03001228 i2c_w2_buf(gspca_dev, mt9v112_init, ARRAY_SIZE(mt9v112_init));
1229 if (gspca_dev->usb_err < 0) {
1230 pr_err("MT9V112 sensor initialization failed\n");
1231 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001232 }
1233 sd->hstart = 6;
1234 sd->vstart = 2;
1235 sd->sensor = SENSOR_MT9V112;
Joe Perches91f58422011-08-21 19:56:55 -03001236 pr_info("MT9V112 sensor detected\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001237 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001238 }
1239
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001240 gspca_dev->usb_err = -ENODEV;
Brian Johnson26e744b2009-07-19 05:52:58 -03001241}
1242
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001243static void mt9m112_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnsone99ac542010-03-16 13:58:28 -03001244{
1245 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moined4689b72012-03-19 04:42:45 -03001246
1247 i2c_w2_buf(gspca_dev, mt9m112_init, ARRAY_SIZE(mt9m112_init));
1248 if (gspca_dev->usb_err < 0)
1249 pr_err("MT9M112 sensor initialization failed\n");
1250
Brian Johnsone99ac542010-03-16 13:58:28 -03001251 sd->hstart = 0;
1252 sd->vstart = 2;
Brian Johnsone99ac542010-03-16 13:58:28 -03001253}
1254
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001255static void mt9m111_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001256{
1257 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moined4689b72012-03-19 04:42:45 -03001258
1259 i2c_w2_buf(gspca_dev, mt9m111_init, ARRAY_SIZE(mt9m111_init));
1260 if (gspca_dev->usb_err < 0)
1261 pr_err("MT9M111 sensor initialization failed\n");
1262
Brian Johnson26e744b2009-07-19 05:52:58 -03001263 sd->hstart = 0;
1264 sd->vstart = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001265}
1266
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001267static void mt9m001_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001268{
1269 struct sd *sd = (struct sd *) gspca_dev;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001270 u16 id;
1271
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001272 i2c_r2(gspca_dev, 0x00, &id);
1273 if (gspca_dev->usb_err < 0)
1274 return;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001275
1276 /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
1277 switch (id) {
1278 case 0x8411:
1279 case 0x8421:
Joe Perches91f58422011-08-21 19:56:55 -03001280 pr_info("MT9M001 color sensor detected\n");
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001281 break;
1282 case 0x8431:
Joe Perches91f58422011-08-21 19:56:55 -03001283 pr_info("MT9M001 mono sensor detected\n");
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001284 break;
1285 default:
Joe Perches91f58422011-08-21 19:56:55 -03001286 pr_err("No MT9M001 chip detected, ID = %x\n\n", id);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001287 gspca_dev->usb_err = -ENODEV;
1288 return;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001289 }
1290
Jean-François Moined4689b72012-03-19 04:42:45 -03001291 i2c_w2_buf(gspca_dev, mt9m001_init, ARRAY_SIZE(mt9m001_init));
1292 if (gspca_dev->usb_err < 0)
1293 pr_err("MT9M001 sensor initialization failed\n");
1294
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001295 sd->hstart = 1;
1296 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001297}
1298
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001299static void hv7131r_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001300{
Brian Johnson26e744b2009-07-19 05:52:58 -03001301 struct sd *sd = (struct sd *) gspca_dev;
1302
Jean-François Moined4689b72012-03-19 04:42:45 -03001303 i2c_w1_buf(gspca_dev, hv7131r_init, ARRAY_SIZE(hv7131r_init));
1304 if (gspca_dev->usb_err < 0)
1305 pr_err("HV7131R Sensor initialization failed\n");
1306
Brian Johnson26e744b2009-07-19 05:52:58 -03001307 sd->hstart = 0;
1308 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001309}
1310
Hans Verkuil63069da2012-05-06 09:28:29 -03001311static void set_cmatrix(struct gspca_dev *gspca_dev,
1312 s32 brightness, s32 contrast, s32 satur, s32 hue)
Brian Johnson26e744b2009-07-19 05:52:58 -03001313{
Hans Verkuil63069da2012-05-06 09:28:29 -03001314 s32 hue_coord, hue_index = 180 + hue;
Brian Johnson26e744b2009-07-19 05:52:58 -03001315 u8 cmatrix[21];
Brian Johnson26e744b2009-07-19 05:52:58 -03001316
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001317 memset(cmatrix, 0, sizeof cmatrix);
Hans Verkuil63069da2012-05-06 09:28:29 -03001318 cmatrix[2] = (contrast * 0x25 / 0x100) + 0x26;
Brian Johnson26e744b2009-07-19 05:52:58 -03001319 cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
1320 cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
Hans Verkuil63069da2012-05-06 09:28:29 -03001321 cmatrix[18] = brightness - 0x80;
Brian Johnson26e744b2009-07-19 05:52:58 -03001322
Jean-François Moinec5224d82012-03-19 04:30:07 -03001323 hue_coord = (hsv_red_x[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001324 cmatrix[6] = hue_coord;
1325 cmatrix[7] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001326
Jean-François Moinec5224d82012-03-19 04:30:07 -03001327 hue_coord = (hsv_red_y[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001328 cmatrix[8] = hue_coord;
1329 cmatrix[9] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001330
Jean-François Moinec5224d82012-03-19 04:30:07 -03001331 hue_coord = (hsv_green_x[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001332 cmatrix[10] = hue_coord;
1333 cmatrix[11] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001334
Jean-François Moinec5224d82012-03-19 04:30:07 -03001335 hue_coord = (hsv_green_y[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001336 cmatrix[12] = hue_coord;
1337 cmatrix[13] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001338
Jean-François Moinec5224d82012-03-19 04:30:07 -03001339 hue_coord = (hsv_blue_x[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001340 cmatrix[14] = hue_coord;
1341 cmatrix[15] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001342
Jean-François Moinec5224d82012-03-19 04:30:07 -03001343 hue_coord = (hsv_blue_y[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001344 cmatrix[16] = hue_coord;
1345 cmatrix[17] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001346
Jean-François Moinec5224d82012-03-19 04:30:07 -03001347 reg_w(gspca_dev, 0x10e1, cmatrix, 21);
Brian Johnson26e744b2009-07-19 05:52:58 -03001348}
1349
Hans Verkuil63069da2012-05-06 09:28:29 -03001350static void set_gamma(struct gspca_dev *gspca_dev, s32 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001351{
Brian Johnson26e744b2009-07-19 05:52:58 -03001352 u8 gamma[17];
Hans Verkuil63069da2012-05-06 09:28:29 -03001353 u8 gval = val * 0xb8 / 0x100;
Brian Johnson26e744b2009-07-19 05:52:58 -03001354
1355 gamma[0] = 0x0a;
1356 gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
1357 gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8);
1358 gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8);
1359 gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8);
1360 gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8);
1361 gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8);
1362 gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8);
1363 gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8);
1364 gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8);
1365 gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8);
1366 gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8);
1367 gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8);
1368 gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8);
1369 gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8);
1370 gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
1371 gamma[16] = 0xf5;
1372
Jean-François Moinec5224d82012-03-19 04:30:07 -03001373 reg_w(gspca_dev, 0x1190, gamma, 17);
Brian Johnson26e744b2009-07-19 05:52:58 -03001374}
1375
Hans Verkuil63069da2012-05-06 09:28:29 -03001376static void set_redblue(struct gspca_dev *gspca_dev, s32 blue, s32 red)
Brian Johnson26e744b2009-07-19 05:52:58 -03001377{
Hans Verkuil63069da2012-05-06 09:28:29 -03001378 reg_w1(gspca_dev, 0x118c, red);
1379 reg_w1(gspca_dev, 0x118f, blue);
Brian Johnson26e744b2009-07-19 05:52:58 -03001380}
1381
Hans Verkuil63069da2012-05-06 09:28:29 -03001382static void set_hvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001383{
Hans Verkuil63069da2012-05-06 09:28:29 -03001384 u8 value, tslb;
Brian Johnson26e744b2009-07-19 05:52:58 -03001385 u16 value2;
1386 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001387
1388 if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
Hans Verkuil63069da2012-05-06 09:28:29 -03001389 hflip = !hflip;
1390 vflip = !vflip;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001391 }
1392
Brian Johnson26e744b2009-07-19 05:52:58 -03001393 switch (sd->sensor) {
Hans de Goede779b51f2011-02-16 08:17:36 -03001394 case SENSOR_OV7660:
1395 value = 0x01;
1396 if (hflip)
1397 value |= 0x20;
1398 if (vflip) {
1399 value |= 0x10;
1400 sd->vstart = 2;
Jean-François Moineff38d582012-03-19 04:55:16 -03001401 } else {
Hans de Goede779b51f2011-02-16 08:17:36 -03001402 sd->vstart = 3;
Jean-François Moineff38d582012-03-19 04:55:16 -03001403 }
Hans de Goede779b51f2011-02-16 08:17:36 -03001404 reg_w1(gspca_dev, 0x1182, sd->vstart);
1405 i2c_w1(gspca_dev, 0x1e, value);
1406 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001407 case SENSOR_OV9650:
1408 i2c_r1(gspca_dev, 0x1e, &value);
1409 value &= ~0x30;
1410 tslb = 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001411 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001412 value |= 0x20;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001413 if (vflip) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001414 value |= 0x10;
1415 tslb = 0x49;
1416 }
1417 i2c_w1(gspca_dev, 0x1e, value);
1418 i2c_w1(gspca_dev, 0x3a, tslb);
1419 break;
1420 case SENSOR_MT9V111:
1421 case SENSOR_MT9V011:
1422 i2c_r2(gspca_dev, 0x20, &value2);
1423 value2 &= ~0xc0a0;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001424 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001425 value2 |= 0x8080;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001426 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001427 value2 |= 0x4020;
1428 i2c_w2(gspca_dev, 0x20, value2);
1429 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001430 case SENSOR_MT9M112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001431 case SENSOR_MT9M111:
1432 case SENSOR_MT9V112:
1433 i2c_r2(gspca_dev, 0x20, &value2);
1434 value2 &= ~0x0003;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001435 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001436 value2 |= 0x0002;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001437 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001438 value2 |= 0x0001;
1439 i2c_w2(gspca_dev, 0x20, value2);
1440 break;
1441 case SENSOR_HV7131R:
1442 i2c_r1(gspca_dev, 0x01, &value);
1443 value &= ~0x03;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001444 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001445 value |= 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001446 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001447 value |= 0x02;
1448 i2c_w1(gspca_dev, 0x01, value);
1449 break;
1450 }
Brian Johnson26e744b2009-07-19 05:52:58 -03001451}
1452
Hans Verkuil63069da2012-05-06 09:28:29 -03001453static void set_exposure(struct gspca_dev *gspca_dev, s32 expo)
Brian Johnson26e744b2009-07-19 05:52:58 -03001454{
1455 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001456 u8 exp[8] = {sd->i2c_intf, sd->i2c_addr,
Jean-François Moine4fb81372012-03-24 09:28:39 -03001457 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans Verkuil63069da2012-05-06 09:28:29 -03001458 int expo2;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001459
Jean-François Moine4fb81372012-03-24 09:28:39 -03001460 if (gspca_dev->streaming)
1461 exp[7] = 0x1e;
1462
Brian Johnson26e744b2009-07-19 05:52:58 -03001463 switch (sd->sensor) {
1464 case SENSOR_OV7660:
1465 case SENSOR_OV7670:
Brian Johnson26e744b2009-07-19 05:52:58 -03001466 case SENSOR_OV9655:
1467 case SENSOR_OV9650:
Jean-François Moinea1ac5dc2012-03-24 09:33:42 -03001468 if (expo > 547)
1469 expo2 = 547;
1470 else
1471 expo2 = expo;
1472 exp[0] |= (2 << 4);
1473 exp[2] = 0x10; /* AECH */
1474 exp[3] = expo2 >> 2;
1475 exp[7] = 0x10;
1476 i2c_w(gspca_dev, exp);
1477 exp[2] = 0x04; /* COM1 */
1478 exp[3] = expo2 & 0x0003;
1479 exp[7] = 0x10;
1480 i2c_w(gspca_dev, exp);
1481 expo -= expo2;
1482 exp[7] = 0x1e;
Brian Johnson26e744b2009-07-19 05:52:58 -03001483 exp[0] |= (3 << 4);
Jean-François Moinea1ac5dc2012-03-24 09:33:42 -03001484 exp[2] = 0x2d; /* ADVFL & ADVFH */
Jean-François Moinec5224d82012-03-19 04:30:07 -03001485 exp[3] = expo;
1486 exp[4] = expo >> 8;
Brian Johnson26e744b2009-07-19 05:52:58 -03001487 break;
1488 case SENSOR_MT9M001:
Brian Johnson26e744b2009-07-19 05:52:58 -03001489 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001490 case SENSOR_MT9V011:
1491 exp[0] |= (3 << 4);
1492 exp[2] = 0x09;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001493 exp[3] = expo >> 8;
1494 exp[4] = expo;
Brian Johnson26e744b2009-07-19 05:52:58 -03001495 break;
1496 case SENSOR_HV7131R:
1497 exp[0] |= (4 << 4);
1498 exp[2] = 0x25;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001499 exp[3] = expo >> 5;
1500 exp[4] = expo << 3;
German Galkine10f7312010-03-07 06:19:02 -03001501 exp[5] = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001502 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001503 default:
Jean-François Moinec5224d82012-03-19 04:30:07 -03001504 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001505 }
1506 i2c_w(gspca_dev, exp);
Brian Johnson26e744b2009-07-19 05:52:58 -03001507}
1508
Hans Verkuil63069da2012-05-06 09:28:29 -03001509static void set_gain(struct gspca_dev *gspca_dev, s32 g)
Brian Johnson26e744b2009-07-19 05:52:58 -03001510{
1511 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001512 u8 gain[8] = {sd->i2c_intf, sd->i2c_addr,
Jean-François Moine4fb81372012-03-24 09:28:39 -03001513 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Jean-François Moinec5224d82012-03-19 04:30:07 -03001514
Jean-François Moine4fb81372012-03-24 09:28:39 -03001515 if (gspca_dev->streaming)
1516 gain[7] = 0x15; /* or 1d ? */
1517
Brian Johnson26e744b2009-07-19 05:52:58 -03001518 switch (sd->sensor) {
1519 case SENSOR_OV7660:
1520 case SENSOR_OV7670:
1521 case SENSOR_SOI968:
1522 case SENSOR_OV9655:
1523 case SENSOR_OV9650:
1524 gain[0] |= (2 << 4);
Jean-François Moinec5224d82012-03-19 04:30:07 -03001525 gain[3] = ov_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001526 break;
1527 case SENSOR_MT9V011:
Brian Johnson26e744b2009-07-19 05:52:58 -03001528 gain[0] |= (3 << 4);
1529 gain[2] = 0x35;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001530 gain[3] = micron1_gain[g] >> 8;
1531 gain[4] = micron1_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001532 break;
1533 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001534 gain[0] |= (3 << 4);
1535 gain[2] = 0x2f;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001536 gain[3] = micron1_gain[g] >> 8;
1537 gain[4] = micron1_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001538 break;
1539 case SENSOR_MT9M001:
1540 gain[0] |= (3 << 4);
1541 gain[2] = 0x2f;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001542 gain[3] = micron2_gain[g] >> 8;
1543 gain[4] = micron2_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001544 break;
1545 case SENSOR_HV7131R:
1546 gain[0] |= (2 << 4);
1547 gain[2] = 0x30;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001548 gain[3] = hv7131r_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001549 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001550 default:
Jean-François Moinec5224d82012-03-19 04:30:07 -03001551 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001552 }
1553 i2c_w(gspca_dev, gain);
Brian Johnson26e744b2009-07-19 05:52:58 -03001554}
1555
Hans Verkuil63069da2012-05-06 09:28:29 -03001556static void set_quality(struct gspca_dev *gspca_dev, s32 val)
Jean-François Moine4c632e42012-03-19 04:35:34 -03001557{
1558 struct sd *sd = (struct sd *) gspca_dev;
1559
Hans Verkuil63069da2012-05-06 09:28:29 -03001560 jpeg_set_qual(sd->jpeg_hdr, val);
Jean-François Moine4c632e42012-03-19 04:35:34 -03001561 reg_w1(gspca_dev, 0x1061, 0x01); /* stop transfer */
1562 reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */
1563 reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
1564 reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
1565 reg_w1(gspca_dev, 0x1061, 0x03); /* restart transfer */
1566 reg_w1(gspca_dev, 0x10e0, sd->fmt);
1567 sd->fmt ^= 0x0c; /* invert QTAB use + write */
1568 reg_w1(gspca_dev, 0x10e0, sd->fmt);
1569}
1570
Brian Johnson26e744b2009-07-19 05:52:58 -03001571#ifdef CONFIG_VIDEO_ADV_DEBUG
1572static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
1573 struct v4l2_dbg_register *reg)
1574{
1575 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03001576
Brian Johnson26e744b2009-07-19 05:52:58 -03001577 switch (reg->match.type) {
1578 case V4L2_CHIP_MATCH_HOST:
1579 if (reg->match.addr != 0)
1580 return -EINVAL;
1581 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1582 return -EINVAL;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001583 reg_r(gspca_dev, reg->reg, 1);
Brian Johnson26e744b2009-07-19 05:52:58 -03001584 reg->val = gspca_dev->usb_buf[0];
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001585 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001586 case V4L2_CHIP_MATCH_I2C_ADDR:
1587 if (reg->match.addr != sd->i2c_addr)
1588 return -EINVAL;
1589 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001590 sd->sensor <= SENSOR_MT9M112) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001591 i2c_r2(gspca_dev, reg->reg, (u16 *) &reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001592 } else {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001593 i2c_r1(gspca_dev, reg->reg, (u8 *) &reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001594 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001595 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001596 }
1597 return -EINVAL;
1598}
1599
1600static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
Hans Verkuil977ba3b2013-03-24 08:28:46 -03001601 const struct v4l2_dbg_register *reg)
Brian Johnson26e744b2009-07-19 05:52:58 -03001602{
1603 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03001604
Brian Johnson26e744b2009-07-19 05:52:58 -03001605 switch (reg->match.type) {
1606 case V4L2_CHIP_MATCH_HOST:
1607 if (reg->match.addr != 0)
1608 return -EINVAL;
1609 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1610 return -EINVAL;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001611 reg_w1(gspca_dev, reg->reg, reg->val);
1612 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001613 case V4L2_CHIP_MATCH_I2C_ADDR:
1614 if (reg->match.addr != sd->i2c_addr)
1615 return -EINVAL;
1616 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001617 sd->sensor <= SENSOR_MT9M112) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001618 i2c_w2(gspca_dev, reg->reg, reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001619 } else {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001620 i2c_w1(gspca_dev, reg->reg, reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001621 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001622 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001623 }
1624 return -EINVAL;
1625}
1626#endif
1627
1628static int sd_chip_ident(struct gspca_dev *gspca_dev,
1629 struct v4l2_dbg_chip_ident *chip)
1630{
1631 struct sd *sd = (struct sd *) gspca_dev;
1632
1633 switch (chip->match.type) {
1634 case V4L2_CHIP_MATCH_HOST:
1635 if (chip->match.addr != 0)
1636 return -EINVAL;
1637 chip->revision = 0;
1638 chip->ident = V4L2_IDENT_SN9C20X;
1639 return 0;
1640 case V4L2_CHIP_MATCH_I2C_ADDR:
1641 if (chip->match.addr != sd->i2c_addr)
1642 return -EINVAL;
1643 chip->revision = 0;
1644 chip->ident = i2c_ident[sd->sensor];
1645 return 0;
1646 }
1647 return -EINVAL;
1648}
1649
1650static int sd_config(struct gspca_dev *gspca_dev,
1651 const struct usb_device_id *id)
1652{
1653 struct sd *sd = (struct sd *) gspca_dev;
1654 struct cam *cam;
1655
1656 cam = &gspca_dev->cam;
Hans de Goedeeb3fb7c2012-01-01 16:35:01 -03001657 cam->needs_full_bandwidth = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001658
Jean-François Moineff38d582012-03-19 04:55:16 -03001659 sd->sensor = id->driver_info >> 8;
1660 sd->i2c_addr = id->driver_info;
1661 sd->flags = id->driver_info >> 16;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001662 sd->i2c_intf = 0x80; /* i2c 100 Kb/s */
Brian Johnson26e744b2009-07-19 05:52:58 -03001663
1664 switch (sd->sensor) {
Brian Johnsone99ac542010-03-16 13:58:28 -03001665 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03001666 case SENSOR_MT9M111:
Brian Johnson26e744b2009-07-19 05:52:58 -03001667 case SENSOR_OV9650:
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001668 case SENSOR_SOI968:
Brian Johnson26e744b2009-07-19 05:52:58 -03001669 cam->cam_mode = sxga_mode;
1670 cam->nmodes = ARRAY_SIZE(sxga_mode);
1671 break;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001672 case SENSOR_MT9M001:
1673 cam->cam_mode = mono_mode;
1674 cam->nmodes = ARRAY_SIZE(mono_mode);
1675 break;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001676 case SENSOR_HV7131R:
1677 sd->i2c_intf = 0x81; /* i2c 400 Kb/s */
1678 /* fall thru */
Brian Johnson26e744b2009-07-19 05:52:58 -03001679 default:
1680 cam->cam_mode = vga_mode;
1681 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001682 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001683 }
1684
1685 sd->old_step = 0;
1686 sd->older_step = 0;
1687 sd->exposure_step = 16;
1688
Jean-François Moine92dcffc2012-03-19 04:47:24 -03001689 INIT_WORK(&sd->work, qual_upd);
Brian Johnson26e744b2009-07-19 05:52:58 -03001690
Brian Johnson26e744b2009-07-19 05:52:58 -03001691 return 0;
1692}
1693
Hans Verkuil63069da2012-05-06 09:28:29 -03001694static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
1695{
Hans de Goedea8a47862012-05-09 11:19:00 -03001696 struct gspca_dev *gspca_dev =
1697 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
1698 struct sd *sd = (struct sd *)gspca_dev;
Hans Verkuil63069da2012-05-06 09:28:29 -03001699
1700 gspca_dev->usb_err = 0;
1701
1702 if (!gspca_dev->streaming)
1703 return 0;
1704
1705 switch (ctrl->id) {
1706 /* color control cluster */
1707 case V4L2_CID_BRIGHTNESS:
Hans de Goedea8a47862012-05-09 11:19:00 -03001708 set_cmatrix(gspca_dev, sd->brightness->val,
Hans Verkuil63069da2012-05-06 09:28:29 -03001709 sd->contrast->val, sd->saturation->val, sd->hue->val);
1710 break;
1711 case V4L2_CID_GAMMA:
Hans de Goedea8a47862012-05-09 11:19:00 -03001712 set_gamma(gspca_dev, ctrl->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001713 break;
1714 /* blue/red balance cluster */
1715 case V4L2_CID_BLUE_BALANCE:
Hans de Goedea8a47862012-05-09 11:19:00 -03001716 set_redblue(gspca_dev, sd->blue->val, sd->red->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001717 break;
1718 /* h/vflip cluster */
1719 case V4L2_CID_HFLIP:
Hans de Goedea8a47862012-05-09 11:19:00 -03001720 set_hvflip(gspca_dev, sd->hflip->val, sd->vflip->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001721 break;
1722 /* standalone exposure control */
1723 case V4L2_CID_EXPOSURE:
Hans de Goedea8a47862012-05-09 11:19:00 -03001724 set_exposure(gspca_dev, ctrl->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001725 break;
1726 /* standalone gain control */
1727 case V4L2_CID_GAIN:
Hans de Goedea8a47862012-05-09 11:19:00 -03001728 set_gain(gspca_dev, ctrl->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001729 break;
1730 /* autogain + exposure or gain control cluster */
1731 case V4L2_CID_AUTOGAIN:
1732 if (sd->sensor == SENSOR_SOI968)
Hans de Goedea8a47862012-05-09 11:19:00 -03001733 set_gain(gspca_dev, sd->gain->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001734 else
Hans de Goedea8a47862012-05-09 11:19:00 -03001735 set_exposure(gspca_dev, sd->exposure->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001736 break;
1737 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
Hans de Goedea8a47862012-05-09 11:19:00 -03001738 set_quality(gspca_dev, ctrl->val);
Hans Verkuil63069da2012-05-06 09:28:29 -03001739 break;
1740 }
1741 return gspca_dev->usb_err;
1742}
1743
1744static const struct v4l2_ctrl_ops sd_ctrl_ops = {
1745 .s_ctrl = sd_s_ctrl,
1746};
1747
1748static int sd_init_controls(struct gspca_dev *gspca_dev)
1749{
1750 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea8a47862012-05-09 11:19:00 -03001751 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
Hans Verkuil63069da2012-05-06 09:28:29 -03001752
1753 gspca_dev->vdev.ctrl_handler = hdl;
1754 v4l2_ctrl_handler_init(hdl, 13);
1755
1756 sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1757 V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
1758 sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1759 V4L2_CID_CONTRAST, 0, 255, 1, 127);
1760 sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1761 V4L2_CID_SATURATION, 0, 255, 1, 127);
1762 sd->hue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1763 V4L2_CID_HUE, -180, 180, 1, 0);
Hans Verkuil63069da2012-05-06 09:28:29 -03001764
1765 sd->gamma = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1766 V4L2_CID_GAMMA, 0, 255, 1, 0x10);
1767
1768 sd->blue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1769 V4L2_CID_BLUE_BALANCE, 0, 127, 1, 0x28);
1770 sd->red = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1771 V4L2_CID_RED_BALANCE, 0, 127, 1, 0x28);
Hans Verkuil63069da2012-05-06 09:28:29 -03001772
1773 if (sd->sensor != SENSOR_OV9655 && sd->sensor != SENSOR_SOI968 &&
1774 sd->sensor != SENSOR_OV7670 && sd->sensor != SENSOR_MT9M001 &&
1775 sd->sensor != SENSOR_MT9VPRB) {
1776 sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1777 V4L2_CID_HFLIP, 0, 1, 1, 0);
1778 sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1779 V4L2_CID_VFLIP, 0, 1, 1, 0);
Hans Verkuil63069da2012-05-06 09:28:29 -03001780 }
1781
1782 if (sd->sensor != SENSOR_SOI968 && sd->sensor != SENSOR_MT9VPRB &&
1783 sd->sensor != SENSOR_MT9M112 && sd->sensor != SENSOR_MT9M111 &&
1784 sd->sensor != SENSOR_MT9V111)
1785 sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1786 V4L2_CID_EXPOSURE, 0, 0x1780, 1, 0x33);
1787
1788 if (sd->sensor != SENSOR_MT9VPRB && sd->sensor != SENSOR_MT9M112 &&
1789 sd->sensor != SENSOR_MT9M111 && sd->sensor != SENSOR_MT9V111) {
1790 sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1791 V4L2_CID_GAIN, 0, 28, 1, 0);
1792 sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1793 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
Hans de Goedebc378fe2012-05-14 14:55:15 -03001794 }
1795
1796 sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1797 V4L2_CID_JPEG_COMPRESSION_QUALITY, 50, 90, 1, 80);
1798 if (hdl->error) {
1799 pr_err("Could not initialize controls\n");
1800 return hdl->error;
1801 }
1802
1803 v4l2_ctrl_cluster(4, &sd->brightness);
1804 v4l2_ctrl_cluster(2, &sd->blue);
1805 if (sd->hflip)
1806 v4l2_ctrl_cluster(2, &sd->hflip);
1807 if (sd->autogain) {
Hans Verkuil63069da2012-05-06 09:28:29 -03001808 if (sd->sensor == SENSOR_SOI968)
1809 /* this sensor doesn't have the exposure control and
1810 autogain is clustered with gain instead. This works
1811 because sd->exposure == NULL. */
1812 v4l2_ctrl_auto_cluster(3, &sd->autogain, 0, false);
1813 else
1814 /* Otherwise autogain is clustered with exposure. */
1815 v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
1816 }
Hans Verkuil63069da2012-05-06 09:28:29 -03001817 return 0;
1818}
1819
Brian Johnson26e744b2009-07-19 05:52:58 -03001820static int sd_init(struct gspca_dev *gspca_dev)
1821{
1822 struct sd *sd = (struct sd *) gspca_dev;
1823 int i;
1824 u8 value;
1825 u8 i2c_init[9] =
1826 {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03};
1827
1828 for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
1829 value = bridge_init[i][1];
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001830 reg_w(gspca_dev, bridge_init[i][0], &value, 1);
1831 if (gspca_dev->usb_err < 0) {
Joe Perches91f58422011-08-21 19:56:55 -03001832 pr_err("Device initialization failed\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001833 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001834 }
1835 }
1836
Brian Johnson0c045eb2010-03-16 13:58:27 -03001837 if (sd->flags & LED_REVERSE)
1838 reg_w1(gspca_dev, 0x1006, 0x00);
1839 else
1840 reg_w1(gspca_dev, 0x1006, 0x20);
1841
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001842 reg_w(gspca_dev, 0x10c0, i2c_init, 9);
1843 if (gspca_dev->usb_err < 0) {
Joe Perches91f58422011-08-21 19:56:55 -03001844 pr_err("Device initialization failed\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001845 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001846 }
1847
1848 switch (sd->sensor) {
1849 case SENSOR_OV9650:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001850 ov9650_init_sensor(gspca_dev);
1851 if (gspca_dev->usb_err < 0)
1852 break;
Joe Perches91f58422011-08-21 19:56:55 -03001853 pr_info("OV9650 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001854 break;
1855 case SENSOR_OV9655:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001856 ov9655_init_sensor(gspca_dev);
1857 if (gspca_dev->usb_err < 0)
1858 break;
Joe Perches91f58422011-08-21 19:56:55 -03001859 pr_info("OV9655 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001860 break;
1861 case SENSOR_SOI968:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001862 soi968_init_sensor(gspca_dev);
1863 if (gspca_dev->usb_err < 0)
1864 break;
Joe Perches91f58422011-08-21 19:56:55 -03001865 pr_info("SOI968 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001866 break;
1867 case SENSOR_OV7660:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001868 ov7660_init_sensor(gspca_dev);
1869 if (gspca_dev->usb_err < 0)
1870 break;
Joe Perches91f58422011-08-21 19:56:55 -03001871 pr_info("OV7660 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001872 break;
1873 case SENSOR_OV7670:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001874 ov7670_init_sensor(gspca_dev);
1875 if (gspca_dev->usb_err < 0)
1876 break;
Joe Perches91f58422011-08-21 19:56:55 -03001877 pr_info("OV7670 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001878 break;
1879 case SENSOR_MT9VPRB:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001880 mt9v_init_sensor(gspca_dev);
1881 if (gspca_dev->usb_err < 0)
1882 break;
Jean-François Moineff38d582012-03-19 04:55:16 -03001883 pr_info("MT9VPRB sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001884 break;
1885 case SENSOR_MT9M111:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001886 mt9m111_init_sensor(gspca_dev);
1887 if (gspca_dev->usb_err < 0)
1888 break;
Joe Perches91f58422011-08-21 19:56:55 -03001889 pr_info("MT9M111 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001890 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001891 case SENSOR_MT9M112:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001892 mt9m112_init_sensor(gspca_dev);
1893 if (gspca_dev->usb_err < 0)
1894 break;
Joe Perches91f58422011-08-21 19:56:55 -03001895 pr_info("MT9M112 sensor detected\n");
Brian Johnsone99ac542010-03-16 13:58:28 -03001896 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001897 case SENSOR_MT9M001:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001898 mt9m001_init_sensor(gspca_dev);
1899 if (gspca_dev->usb_err < 0)
1900 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001901 break;
1902 case SENSOR_HV7131R:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001903 hv7131r_init_sensor(gspca_dev);
1904 if (gspca_dev->usb_err < 0)
1905 break;
Joe Perches91f58422011-08-21 19:56:55 -03001906 pr_info("HV7131R sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001907 break;
1908 default:
Jean-François Moineff38d582012-03-19 04:55:16 -03001909 pr_err("Unsupported sensor\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001910 gspca_dev->usb_err = -ENODEV;
Brian Johnson26e744b2009-07-19 05:52:58 -03001911 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001912 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001913}
1914
1915static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
1916{
1917 struct sd *sd = (struct sd *) gspca_dev;
1918 u8 value;
Jean-François Moineff38d582012-03-19 04:55:16 -03001919
Brian Johnson26e744b2009-07-19 05:52:58 -03001920 switch (sd->sensor) {
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001921 case SENSOR_SOI968:
1922 if (mode & MODE_SXGA) {
1923 i2c_w1(gspca_dev, 0x17, 0x1d);
1924 i2c_w1(gspca_dev, 0x18, 0xbd);
1925 i2c_w1(gspca_dev, 0x19, 0x01);
1926 i2c_w1(gspca_dev, 0x1a, 0x81);
1927 i2c_w1(gspca_dev, 0x12, 0x00);
1928 sd->hstart = 140;
1929 sd->vstart = 19;
1930 } else {
1931 i2c_w1(gspca_dev, 0x17, 0x13);
1932 i2c_w1(gspca_dev, 0x18, 0x63);
1933 i2c_w1(gspca_dev, 0x19, 0x01);
1934 i2c_w1(gspca_dev, 0x1a, 0x79);
1935 i2c_w1(gspca_dev, 0x12, 0x40);
1936 sd->hstart = 60;
1937 sd->vstart = 11;
1938 }
1939 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001940 case SENSOR_OV9650:
1941 if (mode & MODE_SXGA) {
1942 i2c_w1(gspca_dev, 0x17, 0x1b);
1943 i2c_w1(gspca_dev, 0x18, 0xbc);
1944 i2c_w1(gspca_dev, 0x19, 0x01);
1945 i2c_w1(gspca_dev, 0x1a, 0x82);
1946 i2c_r1(gspca_dev, 0x12, &value);
1947 i2c_w1(gspca_dev, 0x12, value & 0x07);
1948 } else {
1949 i2c_w1(gspca_dev, 0x17, 0x24);
1950 i2c_w1(gspca_dev, 0x18, 0xc5);
1951 i2c_w1(gspca_dev, 0x19, 0x00);
1952 i2c_w1(gspca_dev, 0x1a, 0x3c);
1953 i2c_r1(gspca_dev, 0x12, &value);
1954 i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
1955 }
1956 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001957 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03001958 case SENSOR_MT9M111:
1959 if (mode & MODE_SXGA) {
1960 i2c_w2(gspca_dev, 0xf0, 0x0002);
1961 i2c_w2(gspca_dev, 0xc8, 0x970b);
1962 i2c_w2(gspca_dev, 0xf0, 0x0000);
1963 } else {
1964 i2c_w2(gspca_dev, 0xf0, 0x0002);
1965 i2c_w2(gspca_dev, 0xc8, 0x8000);
1966 i2c_w2(gspca_dev, 0xf0, 0x0000);
1967 }
1968 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001969 }
1970}
1971
Hans de Goeded80dd5d2012-01-01 16:03:37 -03001972static int sd_isoc_init(struct gspca_dev *gspca_dev)
1973{
1974 struct usb_interface *intf;
1975 u32 flags = gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv;
1976
1977 /*
1978 * When using the SN9C20X_I420 fmt the sn9c20x needs more bandwidth
1979 * than our regular bandwidth calculations reserve, so we force the
1980 * use of a specific altsetting when using the SN9C20X_I420 fmt.
1981 */
1982 if (!(flags & (MODE_RAW | MODE_JPEG))) {
1983 intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
1984
1985 if (intf->num_altsetting != 9) {
1986 pr_warn("sn9c20x camera with unknown number of alt "
Hans de Goede7135d882012-05-12 05:43:49 -03001987 "settings (%d), please report!\n",
1988 intf->num_altsetting);
Hans de Goeded80dd5d2012-01-01 16:03:37 -03001989 gspca_dev->alt = intf->num_altsetting;
1990 return 0;
1991 }
1992
1993 switch (gspca_dev->width) {
1994 case 160: /* 160x120 */
1995 gspca_dev->alt = 2;
1996 break;
1997 case 320: /* 320x240 */
1998 gspca_dev->alt = 6;
1999 break;
2000 default: /* >= 640x480 */
2001 gspca_dev->alt = 9;
Jean-François Moineff38d582012-03-19 04:55:16 -03002002 break;
Hans de Goeded80dd5d2012-01-01 16:03:37 -03002003 }
2004 }
2005
2006 return 0;
2007}
2008
Brian Johnson26e744b2009-07-19 05:52:58 -03002009#define HW_WIN(mode, hstart, vstart) \
Jean-Francois Moine83955552009-12-12 06:58:01 -03002010((const u8 []){hstart, 0, vstart, 0, \
Brian Johnson26e744b2009-07-19 05:52:58 -03002011(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
2012(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)})
2013
2014#define CLR_WIN(width, height) \
2015((const u8 [])\
2016{0, width >> 2, 0, height >> 1,\
2017((width >> 10) & 0x01) | ((height >> 8) & 0x6)})
2018
2019static int sd_start(struct gspca_dev *gspca_dev)
2020{
2021 struct sd *sd = (struct sd *) gspca_dev;
2022 int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
2023 int width = gspca_dev->width;
2024 int height = gspca_dev->height;
2025 u8 fmt, scale = 0;
2026
Brian Johnson26e744b2009-07-19 05:52:58 -03002027 jpeg_define(sd->jpeg_hdr, height, width,
2028 0x21);
Hans Verkuil63069da2012-05-06 09:28:29 -03002029 jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual));
Brian Johnson26e744b2009-07-19 05:52:58 -03002030
2031 if (mode & MODE_RAW)
2032 fmt = 0x2d;
2033 else if (mode & MODE_JPEG)
Jean-François Moine4c632e42012-03-19 04:35:34 -03002034 fmt = 0x24;
Brian Johnson26e744b2009-07-19 05:52:58 -03002035 else
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002036 fmt = 0x2f; /* YUV 420 */
Jean-François Moine4c632e42012-03-19 04:35:34 -03002037 sd->fmt = fmt;
Brian Johnson26e744b2009-07-19 05:52:58 -03002038
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002039 switch (mode & SCALE_MASK) {
2040 case SCALE_1280x1024:
Brian Johnson26e744b2009-07-19 05:52:58 -03002041 scale = 0xc0;
Joe Perches91f58422011-08-21 19:56:55 -03002042 pr_info("Set 1280x1024\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002043 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002044 case SCALE_640x480:
Brian Johnson26e744b2009-07-19 05:52:58 -03002045 scale = 0x80;
Joe Perches91f58422011-08-21 19:56:55 -03002046 pr_info("Set 640x480\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002047 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002048 case SCALE_320x240:
Brian Johnson26e744b2009-07-19 05:52:58 -03002049 scale = 0x90;
Joe Perches91f58422011-08-21 19:56:55 -03002050 pr_info("Set 320x240\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002051 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002052 case SCALE_160x120:
Brian Johnson26e744b2009-07-19 05:52:58 -03002053 scale = 0xa0;
Joe Perches91f58422011-08-21 19:56:55 -03002054 pr_info("Set 160x120\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002055 break;
2056 }
2057
2058 configure_sensor_output(gspca_dev, mode);
Jean-François Moine9a731a32010-06-04 05:26:42 -03002059 reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
2060 reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
Brian Johnson26e744b2009-07-19 05:52:58 -03002061 reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
2062 reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
2063 reg_w1(gspca_dev, 0x1189, scale);
2064 reg_w1(gspca_dev, 0x10e0, fmt);
2065
Hans Verkuil63069da2012-05-06 09:28:29 -03002066 set_cmatrix(gspca_dev, v4l2_ctrl_g_ctrl(sd->brightness),
2067 v4l2_ctrl_g_ctrl(sd->contrast),
2068 v4l2_ctrl_g_ctrl(sd->saturation),
2069 v4l2_ctrl_g_ctrl(sd->hue));
2070 set_gamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma));
2071 set_redblue(gspca_dev, v4l2_ctrl_g_ctrl(sd->blue),
2072 v4l2_ctrl_g_ctrl(sd->red));
Hans de Goede6c6ee532012-07-08 19:41:14 +02002073 if (sd->gain)
2074 set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
2075 if (sd->exposure)
2076 set_exposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure));
2077 if (sd->hflip)
2078 set_hvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip),
2079 v4l2_ctrl_g_ctrl(sd->vflip));
Brian Johnson26e744b2009-07-19 05:52:58 -03002080
Brian Johnson0c045eb2010-03-16 13:58:27 -03002081 reg_w1(gspca_dev, 0x1007, 0x20);
Jean-François Moineccbaba42012-03-19 04:51:30 -03002082 reg_w1(gspca_dev, 0x1061, 0x03);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002083
2084 /* if JPEG, prepare the compression quality update */
2085 if (mode & MODE_JPEG) {
2086 sd->pktsz = sd->npkt = 0;
2087 sd->nchg = 0;
2088 sd->work_thread =
2089 create_singlethread_workqueue(KBUILD_MODNAME);
2090 }
2091
Jean-François Moinefe86ec72012-03-19 04:32:15 -03002092 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03002093}
2094
2095static void sd_stopN(struct gspca_dev *gspca_dev)
2096{
Brian Johnson0c045eb2010-03-16 13:58:27 -03002097 reg_w1(gspca_dev, 0x1007, 0x00);
Jean-François Moineccbaba42012-03-19 04:51:30 -03002098 reg_w1(gspca_dev, 0x1061, 0x01);
Brian Johnson26e744b2009-07-19 05:52:58 -03002099}
2100
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002101/* called on streamoff with alt==0 and on disconnect */
2102/* the usb_lock is held at entry - restore on exit */
2103static void sd_stop0(struct gspca_dev *gspca_dev)
2104{
2105 struct sd *sd = (struct sd *) gspca_dev;
2106
2107 if (sd->work_thread != NULL) {
2108 mutex_unlock(&gspca_dev->usb_lock);
2109 destroy_workqueue(sd->work_thread);
2110 mutex_lock(&gspca_dev->usb_lock);
2111 sd->work_thread = NULL;
2112 }
2113}
2114
Brian Johnsone1430472009-09-02 12:39:41 -03002115static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
Brian Johnson26e744b2009-07-19 05:52:58 -03002116{
2117 struct sd *sd = (struct sd *) gspca_dev;
Hans Verkuil63069da2012-05-06 09:28:29 -03002118 s32 cur_exp = v4l2_ctrl_g_ctrl(sd->exposure);
2119 s32 max = sd->exposure->maximum - sd->exposure_step;
2120 s32 min = sd->exposure->minimum + sd->exposure_step;
Brian Johnsone1430472009-09-02 12:39:41 -03002121 s16 new_exp;
Brian Johnson26e744b2009-07-19 05:52:58 -03002122
2123 /*
2124 * some hardcoded values are present
2125 * like those for maximal/minimal exposure
2126 * and exposure steps
2127 */
2128 if (avg_lum < MIN_AVG_LUM) {
Hans Verkuil63069da2012-05-06 09:28:29 -03002129 if (cur_exp > max)
Brian Johnson26e744b2009-07-19 05:52:58 -03002130 return;
2131
Hans Verkuil63069da2012-05-06 09:28:29 -03002132 new_exp = cur_exp + sd->exposure_step;
2133 if (new_exp > max)
2134 new_exp = max;
2135 if (new_exp < min)
2136 new_exp = min;
2137 v4l2_ctrl_s_ctrl(sd->exposure, new_exp);
Brian Johnson26e744b2009-07-19 05:52:58 -03002138
2139 sd->older_step = sd->old_step;
2140 sd->old_step = 1;
2141
2142 if (sd->old_step ^ sd->older_step)
2143 sd->exposure_step /= 2;
2144 else
2145 sd->exposure_step += 2;
2146 }
2147 if (avg_lum > MAX_AVG_LUM) {
Hans Verkuil63069da2012-05-06 09:28:29 -03002148 if (cur_exp < min)
Brian Johnson26e744b2009-07-19 05:52:58 -03002149 return;
Hans Verkuil63069da2012-05-06 09:28:29 -03002150 new_exp = cur_exp - sd->exposure_step;
2151 if (new_exp > max)
2152 new_exp = max;
2153 if (new_exp < min)
2154 new_exp = min;
2155 v4l2_ctrl_s_ctrl(sd->exposure, new_exp);
Brian Johnson26e744b2009-07-19 05:52:58 -03002156 sd->older_step = sd->old_step;
2157 sd->old_step = 0;
2158
2159 if (sd->old_step ^ sd->older_step)
2160 sd->exposure_step /= 2;
2161 else
2162 sd->exposure_step += 2;
2163 }
2164}
2165
Brian Johnsone1430472009-09-02 12:39:41 -03002166static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
2167{
2168 struct sd *sd = (struct sd *) gspca_dev;
Hans Verkuil63069da2012-05-06 09:28:29 -03002169 s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain);
Brian Johnsone1430472009-09-02 12:39:41 -03002170
Hans Verkuil63069da2012-05-06 09:28:29 -03002171 if (avg_lum < MIN_AVG_LUM && cur_gain < sd->gain->maximum)
2172 v4l2_ctrl_s_ctrl(sd->gain, cur_gain + 1);
2173 if (avg_lum > MAX_AVG_LUM && cur_gain > sd->gain->minimum)
2174 v4l2_ctrl_s_ctrl(sd->gain, cur_gain - 1);
Brian Johnsone1430472009-09-02 12:39:41 -03002175}
2176
2177static void sd_dqcallback(struct gspca_dev *gspca_dev)
2178{
2179 struct sd *sd = (struct sd *) gspca_dev;
2180 int avg_lum;
2181
Hans de Goede6c6ee532012-07-08 19:41:14 +02002182 if (sd->autogain == NULL || !v4l2_ctrl_g_ctrl(sd->autogain))
Brian Johnsone1430472009-09-02 12:39:41 -03002183 return;
2184
2185 avg_lum = atomic_read(&sd->avg_lum);
2186 if (sd->sensor == SENSOR_SOI968)
2187 do_autogain(gspca_dev, avg_lum);
2188 else
2189 do_autoexposure(gspca_dev, avg_lum);
2190}
2191
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002192/* JPEG quality update */
2193/* This function is executed from a work queue. */
2194static void qual_upd(struct work_struct *work)
2195{
2196 struct sd *sd = container_of(work, struct sd, work);
2197 struct gspca_dev *gspca_dev = &sd->gspca_dev;
Hans Verkuil63069da2012-05-06 09:28:29 -03002198 s32 qual = v4l2_ctrl_g_ctrl(sd->jpegqual);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002199
Hans de Goede844db452012-09-09 07:30:02 -03002200 /* To protect gspca_dev->usb_buf and gspca_dev->usb_err */
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002201 mutex_lock(&gspca_dev->usb_lock);
Hans Verkuil63069da2012-05-06 09:28:29 -03002202 PDEBUG(D_STREAM, "qual_upd %d%%", qual);
Hans de Goede844db452012-09-09 07:30:02 -03002203 gspca_dev->usb_err = 0;
Hans Verkuil63069da2012-05-06 09:28:29 -03002204 set_quality(gspca_dev, qual);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002205 mutex_unlock(&gspca_dev->usb_lock);
2206}
2207
Peter Senna Tschudin8099aff2013-01-24 19:29:06 -03002208#if IS_ENABLED(CONFIG_INPUT)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002209static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
2210 u8 *data, /* interrupt packet */
2211 int len) /* interrupt packet length */
2212{
2213 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03002214
Brian Johnson33ddc162010-04-18 21:42:40 -03002215 if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
Jean-François Moineff38d582012-03-19 04:55:16 -03002216 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
2217 input_sync(gspca_dev->input_dev);
2218 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
2219 input_sync(gspca_dev->input_dev);
2220 return 0;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002221 }
Jean-François Moineff38d582012-03-19 04:55:16 -03002222 return -EINVAL;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002223}
2224#endif
2225
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002226/* check the JPEG compression */
2227static void transfer_check(struct gspca_dev *gspca_dev,
2228 u8 *data)
2229{
2230 struct sd *sd = (struct sd *) gspca_dev;
2231 int new_qual, r;
2232
2233 new_qual = 0;
2234
2235 /* if USB error, discard the frame and decrease the quality */
2236 if (data[6] & 0x08) { /* USB FIFO full */
2237 gspca_dev->last_packet_type = DISCARD_PACKET;
2238 new_qual = -5;
2239 } else {
2240
2241 /* else, compute the filling rate and a new JPEG quality */
2242 r = (sd->pktsz * 100) /
2243 (sd->npkt *
2244 gspca_dev->urb[0]->iso_frame_desc[0].length);
2245 if (r >= 85)
2246 new_qual = -3;
2247 else if (r < 75)
2248 new_qual = 2;
2249 }
2250 if (new_qual != 0) {
2251 sd->nchg += new_qual;
2252 if (sd->nchg < -6 || sd->nchg >= 12) {
Hans Verkuil63069da2012-05-06 09:28:29 -03002253 /* Note: we are in interrupt context, so we can't
2254 use v4l2_ctrl_g/s_ctrl here. Access the value
2255 directly instead. */
2256 s32 curqual = sd->jpegqual->cur.val;
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002257 sd->nchg = 0;
Hans Verkuil63069da2012-05-06 09:28:29 -03002258 new_qual += curqual;
2259 if (new_qual < sd->jpegqual->minimum)
2260 new_qual = sd->jpegqual->minimum;
2261 else if (new_qual > sd->jpegqual->maximum)
2262 new_qual = sd->jpegqual->maximum;
2263 if (new_qual != curqual) {
2264 sd->jpegqual->cur.val = new_qual;
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002265 queue_work(sd->work_thread, &sd->work);
2266 }
2267 }
2268 } else {
2269 sd->nchg = 0;
2270 }
2271 sd->pktsz = sd->npkt = 0;
2272}
2273
Brian Johnson26e744b2009-07-19 05:52:58 -03002274static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Brian Johnson26e744b2009-07-19 05:52:58 -03002275 u8 *data, /* isoc packet */
2276 int len) /* iso packet length */
2277{
2278 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03002279 int avg_lum, is_jpeg;
Jean-François Moinedae1de62012-03-24 09:20:25 -03002280 static const u8 frame_header[] =
Brian Johnson26e744b2009-07-19 05:52:58 -03002281 {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
Jean-François Moineff38d582012-03-19 04:55:16 -03002282
2283 is_jpeg = (sd->fmt & 0x03) == 0;
Jean-François Moine1f42df02012-03-19 04:22:44 -03002284 if (len >= 64 && memcmp(data, frame_header, 6) == 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03002285 avg_lum = ((data[35] >> 2) & 3) |
2286 (data[20] << 2) |
2287 (data[19] << 10);
2288 avg_lum += ((data[35] >> 4) & 3) |
2289 (data[22] << 2) |
2290 (data[21] << 10);
2291 avg_lum += ((data[35] >> 6) & 3) |
2292 (data[24] << 2) |
2293 (data[23] << 10);
2294 avg_lum += (data[36] & 3) |
2295 (data[26] << 2) |
2296 (data[25] << 10);
2297 avg_lum += ((data[36] >> 2) & 3) |
2298 (data[28] << 2) |
2299 (data[27] << 10);
2300 avg_lum += ((data[36] >> 4) & 3) |
2301 (data[30] << 2) |
2302 (data[29] << 10);
2303 avg_lum += ((data[36] >> 6) & 3) |
2304 (data[32] << 2) |
2305 (data[31] << 10);
2306 avg_lum += ((data[44] >> 4) & 3) |
2307 (data[34] << 2) |
2308 (data[33] << 10);
2309 avg_lum >>= 9;
2310 atomic_set(&sd->avg_lum, avg_lum);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002311
Jean-François Moineff38d582012-03-19 04:55:16 -03002312 if (is_jpeg)
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002313 transfer_check(gspca_dev, data);
2314
Jean-François Moine04d174e2010-09-13 05:22:37 -03002315 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Jean-François Moine1f42df02012-03-19 04:22:44 -03002316 len -= 64;
2317 if (len == 0)
2318 return;
2319 data += 64;
Brian Johnson26e744b2009-07-19 05:52:58 -03002320 }
2321 if (gspca_dev->last_packet_type == LAST_PACKET) {
Jean-François Moineff38d582012-03-19 04:55:16 -03002322 if (is_jpeg) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002323 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002324 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002325 gspca_frame_add(gspca_dev, INTER_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002326 data, len);
2327 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002328 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002329 data, len);
2330 }
2331 } else {
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002332 /* if JPEG, count the packets and their size */
Jean-François Moineff38d582012-03-19 04:55:16 -03002333 if (is_jpeg) {
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002334 sd->npkt++;
2335 sd->pktsz += len;
2336 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002337 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Brian Johnson26e744b2009-07-19 05:52:58 -03002338 }
2339}
2340
2341/* sub-driver description */
2342static const struct sd_desc sd_desc = {
Jean-François Moineff38d582012-03-19 04:55:16 -03002343 .name = KBUILD_MODNAME,
Brian Johnson26e744b2009-07-19 05:52:58 -03002344 .config = sd_config,
2345 .init = sd_init,
Hans Verkuil63069da2012-05-06 09:28:29 -03002346 .init_controls = sd_init_controls,
Hans de Goeded80dd5d2012-01-01 16:03:37 -03002347 .isoc_init = sd_isoc_init,
Brian Johnson26e744b2009-07-19 05:52:58 -03002348 .start = sd_start,
2349 .stopN = sd_stopN,
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002350 .stop0 = sd_stop0,
Brian Johnson26e744b2009-07-19 05:52:58 -03002351 .pkt_scan = sd_pkt_scan,
Peter Senna Tschudin8099aff2013-01-24 19:29:06 -03002352#if IS_ENABLED(CONFIG_INPUT)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002353 .int_pkt_scan = sd_int_pkt_scan,
2354#endif
Brian Johnsone1430472009-09-02 12:39:41 -03002355 .dq_callback = sd_dqcallback,
Brian Johnson26e744b2009-07-19 05:52:58 -03002356#ifdef CONFIG_VIDEO_ADV_DEBUG
2357 .set_register = sd_dbg_s_register,
2358 .get_register = sd_dbg_g_register,
2359#endif
2360 .get_chip_ident = sd_chip_ident,
2361};
2362
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002363#define SN9C20X(sensor, i2c_addr, flags) \
Brian Johnson0c045eb2010-03-16 13:58:27 -03002364 .driver_info = ((flags & 0xff) << 16) \
Brian Johnson26e744b2009-07-19 05:52:58 -03002365 | (SENSOR_ ## sensor << 8) \
2366 | (i2c_addr)
2367
Jean-François Moine95c967c2011-01-13 05:20:29 -03002368static const struct usb_device_id device_table[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03002369 {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
2370 {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
2371 {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002372 {USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002373 {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, LED_REVERSE)},
2374 {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30,
2375 (FLIP_DETECT | HAS_NO_BUTTON))},
Brian Johnson26e744b2009-07-19 05:52:58 -03002376 {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
2377 {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
2378 {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
2379 {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)},
Hans de Goede779b51f2011-02-16 08:17:36 -03002380 {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, FLIP_DETECT)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002381 {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)},
2382 {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)},
2383 {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
2384 {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002385 {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002386 {USB_DEVICE(0x0c45, 0x628c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002387 {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)},
2388 {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
2389 {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
2390 {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
Frank Schaefer114cfbd2011-09-23 05:05:37 -03002391 {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, LED_REVERSE)},
Hans de Goedeb39e0cb2011-02-16 08:33:16 -03002392 {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, LED_REVERSE)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002393 {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
2394 {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
2395 {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
2396 {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002397 {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)},
2398 {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002399 {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
2400 {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)},
2401 {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)},
2402 {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002403 {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002404 {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)},
2405 {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)},
2406 {}
2407};
2408MODULE_DEVICE_TABLE(usb, device_table);
2409
2410/* -- device connect -- */
2411static int sd_probe(struct usb_interface *intf,
2412 const struct usb_device_id *id)
2413{
2414 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
2415 THIS_MODULE);
2416}
2417
Brian Johnson26e744b2009-07-19 05:52:58 -03002418static struct usb_driver sd_driver = {
Jean-François Moineff38d582012-03-19 04:55:16 -03002419 .name = KBUILD_MODNAME,
Brian Johnson26e744b2009-07-19 05:52:58 -03002420 .id_table = device_table,
2421 .probe = sd_probe,
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002422 .disconnect = gspca_disconnect,
Brian Johnson26e744b2009-07-19 05:52:58 -03002423#ifdef CONFIG_PM
2424 .suspend = gspca_suspend,
2425 .resume = gspca_resume,
2426 .reset_resume = gspca_resume,
2427#endif
2428};
2429
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -08002430module_usb_driver(sd_driver);