blob: f35f1a0d1caf3df01fe7baa58a65fdf225128833 [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 v4l2_ctrl_handler ctrl_handler;
74 struct { /* color control cluster */
75 struct v4l2_ctrl *brightness;
76 struct v4l2_ctrl *contrast;
77 struct v4l2_ctrl *saturation;
78 struct v4l2_ctrl *hue;
79 };
80 struct { /* blue/red balance control cluster */
81 struct v4l2_ctrl *blue;
82 struct v4l2_ctrl *red;
83 };
84 struct { /* h/vflip control cluster */
85 struct v4l2_ctrl *hflip;
86 struct v4l2_ctrl *vflip;
87 };
88 struct v4l2_ctrl *gamma;
89 struct { /* autogain and exposure or gain control cluster */
90 struct v4l2_ctrl *autogain;
91 struct v4l2_ctrl *exposure;
92 struct v4l2_ctrl *gain;
93 };
94 struct v4l2_ctrl *jpegqual;
Jean-François Moinec5224d82012-03-19 04:30:07 -030095
Jean-François Moine92dcffc2012-03-19 04:47:24 -030096 struct work_struct work;
97 struct workqueue_struct *work_thread;
98
99 u32 pktsz; /* (used by pkt_scan) */
100 u16 npkt;
101 s8 nchg;
Jean-François Moine4c632e42012-03-19 04:35:34 -0300102 u8 fmt; /* (used for JPEG QTAB update */
103
Brian Johnson26e744b2009-07-19 05:52:58 -0300104#define MIN_AVG_LUM 80
105#define MAX_AVG_LUM 130
106 atomic_t avg_lum;
107 u8 old_step;
108 u8 older_step;
109 u8 exposure_step;
110
Brian Johnson26e744b2009-07-19 05:52:58 -0300111 u8 i2c_addr;
Jean-François Moinec4407fe2012-03-24 09:23:56 -0300112 u8 i2c_intf;
Brian Johnson26e744b2009-07-19 05:52:58 -0300113 u8 sensor;
114 u8 hstart;
115 u8 vstart;
116
Jean-François Moine9a731a32010-06-04 05:26:42 -0300117 u8 jpeg_hdr[JPEG_HDR_SZ];
Brian Johnson26e744b2009-07-19 05:52:58 -0300118
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -0300119 u8 flags;
Brian Johnson26e744b2009-07-19 05:52:58 -0300120};
121
Jean-François Moine92dcffc2012-03-19 04:47:24 -0300122static void qual_upd(struct work_struct *work);
123
Joe Perches58aa68c2009-09-02 01:12:13 -0300124struct i2c_reg_u8 {
125 u8 reg;
126 u8 val;
127};
128
129struct i2c_reg_u16 {
130 u8 reg;
131 u16 val;
132};
133
Brian Johnson7ddaac72010-03-16 13:58:27 -0300134static const struct dmi_system_id flip_dmi_table[] = {
135 {
136 .ident = "MSI MS-1034",
137 .matches = {
138 DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."),
139 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1034"),
140 DMI_MATCH(DMI_PRODUCT_VERSION, "0341")
141 }
142 },
143 {
144 .ident = "MSI MS-1632",
145 .matches = {
146 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
147 DMI_MATCH(DMI_BOARD_NAME, "MS-1632")
148 }
149 },
Brian Johnsone077f862010-04-05 20:52:52 -0300150 {
Hans de Goedebcc6f662011-02-17 06:27:57 -0300151 .ident = "MSI MS-1633X",
152 .matches = {
153 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
154 DMI_MATCH(DMI_BOARD_NAME, "MS-1633X")
155 }
156 },
157 {
Brian Johnson5d26ed92010-04-10 02:12:46 -0300158 .ident = "MSI MS-1635X",
159 .matches = {
160 DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
161 DMI_MATCH(DMI_BOARD_NAME, "MS-1635X")
162 }
163 },
164 {
Brian Johnsone077f862010-04-05 20:52:52 -0300165 .ident = "ASUSTeK W7J",
166 .matches = {
167 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
168 DMI_MATCH(DMI_BOARD_NAME, "W7J ")
169 }
170 },
Brian Johnson7ddaac72010-03-16 13:58:27 -0300171 {}
172};
173
Brian Johnson26e744b2009-07-19 05:52:58 -0300174static const struct v4l2_pix_format vga_mode[] = {
175 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300176 .bytesperline = 160,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300177 .sizeimage = 160 * 120 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300178 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300179 .priv = SCALE_160x120 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300180 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
181 .bytesperline = 160,
182 .sizeimage = 160 * 120,
183 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300184 .priv = SCALE_160x120 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300185 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300186 .bytesperline = 160,
Brian Johnson26e744b2009-07-19 05:52:58 -0300187 .sizeimage = 240 * 120,
188 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300189 .priv = SCALE_160x120},
Brian Johnson26e744b2009-07-19 05:52:58 -0300190 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300191 .bytesperline = 320,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300192 .sizeimage = 320 * 240 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300193 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300194 .priv = SCALE_320x240 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300195 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
196 .bytesperline = 320,
197 .sizeimage = 320 * 240 ,
198 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300199 .priv = SCALE_320x240 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300200 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300201 .bytesperline = 320,
Brian Johnson26e744b2009-07-19 05:52:58 -0300202 .sizeimage = 480 * 240 ,
203 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300204 .priv = SCALE_320x240},
Brian Johnson26e744b2009-07-19 05:52:58 -0300205 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300206 .bytesperline = 640,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300207 .sizeimage = 640 * 480 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300208 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300209 .priv = SCALE_640x480 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300210 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
211 .bytesperline = 640,
212 .sizeimage = 640 * 480,
213 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300214 .priv = SCALE_640x480 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300215 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300216 .bytesperline = 640,
Brian Johnson26e744b2009-07-19 05:52:58 -0300217 .sizeimage = 960 * 480,
218 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300219 .priv = SCALE_640x480},
Brian Johnson26e744b2009-07-19 05:52:58 -0300220};
221
222static const struct v4l2_pix_format sxga_mode[] = {
223 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300224 .bytesperline = 160,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300225 .sizeimage = 160 * 120 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300226 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300227 .priv = SCALE_160x120 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300228 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
229 .bytesperline = 160,
230 .sizeimage = 160 * 120,
231 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300232 .priv = SCALE_160x120 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300233 {160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300234 .bytesperline = 160,
Brian Johnson26e744b2009-07-19 05:52:58 -0300235 .sizeimage = 240 * 120,
236 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300237 .priv = SCALE_160x120},
Brian Johnson26e744b2009-07-19 05:52:58 -0300238 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300239 .bytesperline = 320,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300240 .sizeimage = 320 * 240 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300241 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300242 .priv = SCALE_320x240 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300243 {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
244 .bytesperline = 320,
245 .sizeimage = 320 * 240 ,
246 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300247 .priv = SCALE_320x240 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300248 {320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300249 .bytesperline = 320,
Brian Johnson26e744b2009-07-19 05:52:58 -0300250 .sizeimage = 480 * 240 ,
251 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300252 .priv = SCALE_320x240},
Brian Johnson26e744b2009-07-19 05:52:58 -0300253 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300254 .bytesperline = 640,
Hans de Goede6899a9c2011-02-16 08:37:54 -0300255 .sizeimage = 640 * 480 * 4 / 8 + 590,
Brian Johnson26e744b2009-07-19 05:52:58 -0300256 .colorspace = V4L2_COLORSPACE_JPEG,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300257 .priv = SCALE_640x480 | MODE_JPEG},
Brian Johnson26e744b2009-07-19 05:52:58 -0300258 {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
259 .bytesperline = 640,
260 .sizeimage = 640 * 480,
261 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300262 .priv = SCALE_640x480 | MODE_RAW},
Brian Johnson26e744b2009-07-19 05:52:58 -0300263 {640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
Jean-François Moineb1e46652010-09-13 05:25:41 -0300264 .bytesperline = 640,
Brian Johnson26e744b2009-07-19 05:52:58 -0300265 .sizeimage = 960 * 480,
266 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300267 .priv = SCALE_640x480},
Brian Johnson26e744b2009-07-19 05:52:58 -0300268 {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
269 .bytesperline = 1280,
Jean-François Moine9b1d3ca2010-09-13 05:26:35 -0300270 .sizeimage = 1280 * 1024,
Brian Johnson26e744b2009-07-19 05:52:58 -0300271 .colorspace = V4L2_COLORSPACE_SRGB,
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -0300272 .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
Brian Johnson26e744b2009-07-19 05:52:58 -0300273};
274
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -0300275static const struct v4l2_pix_format mono_mode[] = {
276 {160, 120, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
277 .bytesperline = 160,
278 .sizeimage = 160 * 120,
279 .colorspace = V4L2_COLORSPACE_SRGB,
280 .priv = SCALE_160x120 | MODE_RAW},
281 {320, 240, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
282 .bytesperline = 320,
283 .sizeimage = 320 * 240 ,
284 .colorspace = V4L2_COLORSPACE_SRGB,
285 .priv = SCALE_320x240 | MODE_RAW},
286 {640, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
287 .bytesperline = 640,
288 .sizeimage = 640 * 480,
289 .colorspace = V4L2_COLORSPACE_SRGB,
290 .priv = SCALE_640x480 | MODE_RAW},
291 {1280, 1024, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
292 .bytesperline = 1280,
293 .sizeimage = 1280 * 1024,
294 .colorspace = V4L2_COLORSPACE_SRGB,
295 .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
296};
297
Joe Perches58aa68c2009-09-02 01:12:13 -0300298static const s16 hsv_red_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300299 41, 44, 46, 48, 50, 52, 54, 56,
300 58, 60, 62, 64, 66, 68, 70, 72,
301 74, 76, 78, 80, 81, 83, 85, 87,
302 88, 90, 92, 93, 95, 97, 98, 100,
303 101, 102, 104, 105, 107, 108, 109, 110,
304 112, 113, 114, 115, 116, 117, 118, 119,
305 120, 121, 122, 123, 123, 124, 125, 125,
306 126, 127, 127, 128, 128, 129, 129, 129,
307 130, 130, 130, 130, 131, 131, 131, 131,
308 131, 131, 131, 131, 130, 130, 130, 130,
309 129, 129, 129, 128, 128, 127, 127, 126,
310 125, 125, 124, 123, 122, 122, 121, 120,
311 119, 118, 117, 116, 115, 114, 112, 111,
312 110, 109, 107, 106, 105, 103, 102, 101,
313 99, 98, 96, 94, 93, 91, 90, 88,
314 86, 84, 83, 81, 79, 77, 75, 74,
315 72, 70, 68, 66, 64, 62, 60, 58,
316 56, 54, 52, 49, 47, 45, 43, 41,
317 39, 36, 34, 32, 30, 28, 25, 23,
318 21, 19, 16, 14, 12, 9, 7, 5,
319 3, 0, -1, -3, -6, -8, -10, -12,
320 -15, -17, -19, -22, -24, -26, -28, -30,
321 -33, -35, -37, -39, -41, -44, -46, -48,
322 -50, -52, -54, -56, -58, -60, -62, -64,
323 -66, -68, -70, -72, -74, -76, -78, -80,
324 -81, -83, -85, -87, -88, -90, -92, -93,
325 -95, -97, -98, -100, -101, -102, -104, -105,
326 -107, -108, -109, -110, -112, -113, -114, -115,
327 -116, -117, -118, -119, -120, -121, -122, -123,
328 -123, -124, -125, -125, -126, -127, -127, -128,
329 -128, -128, -128, -128, -128, -128, -128, -128,
330 -128, -128, -128, -128, -128, -128, -128, -128,
331 -128, -128, -128, -128, -128, -128, -128, -128,
332 -128, -127, -127, -126, -125, -125, -124, -123,
333 -122, -122, -121, -120, -119, -118, -117, -116,
334 -115, -114, -112, -111, -110, -109, -107, -106,
335 -105, -103, -102, -101, -99, -98, -96, -94,
336 -93, -91, -90, -88, -86, -84, -83, -81,
337 -79, -77, -75, -74, -72, -70, -68, -66,
338 -64, -62, -60, -58, -56, -54, -52, -49,
339 -47, -45, -43, -41, -39, -36, -34, -32,
340 -30, -28, -25, -23, -21, -19, -16, -14,
341 -12, -9, -7, -5, -3, 0, 1, 3,
342 6, 8, 10, 12, 15, 17, 19, 22,
343 24, 26, 28, 30, 33, 35, 37, 39, 41
344};
345
Joe Perches58aa68c2009-09-02 01:12:13 -0300346static const s16 hsv_red_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300347 82, 80, 78, 76, 74, 73, 71, 69,
348 67, 65, 63, 61, 58, 56, 54, 52,
349 50, 48, 46, 44, 41, 39, 37, 35,
350 32, 30, 28, 26, 23, 21, 19, 16,
351 14, 12, 10, 7, 5, 3, 0, -1,
352 -3, -6, -8, -10, -13, -15, -17, -19,
353 -22, -24, -26, -29, -31, -33, -35, -38,
354 -40, -42, -44, -46, -48, -51, -53, -55,
355 -57, -59, -61, -63, -65, -67, -69, -71,
356 -73, -75, -77, -79, -81, -82, -84, -86,
357 -88, -89, -91, -93, -94, -96, -98, -99,
358 -101, -102, -104, -105, -106, -108, -109, -110,
359 -112, -113, -114, -115, -116, -117, -119, -120,
360 -120, -121, -122, -123, -124, -125, -126, -126,
361 -127, -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 -128, -128, -128, -128, -128, -128, -128, -128,
365 -127, -127, -126, -125, -125, -124, -123, -122,
366 -121, -120, -119, -118, -117, -116, -115, -114,
367 -113, -111, -110, -109, -107, -106, -105, -103,
368 -102, -100, -99, -97, -96, -94, -92, -91,
369 -89, -87, -85, -84, -82, -80, -78, -76,
370 -74, -73, -71, -69, -67, -65, -63, -61,
371 -58, -56, -54, -52, -50, -48, -46, -44,
372 -41, -39, -37, -35, -32, -30, -28, -26,
373 -23, -21, -19, -16, -14, -12, -10, -7,
374 -5, -3, 0, 1, 3, 6, 8, 10,
375 13, 15, 17, 19, 22, 24, 26, 29,
376 31, 33, 35, 38, 40, 42, 44, 46,
377 48, 51, 53, 55, 57, 59, 61, 63,
378 65, 67, 69, 71, 73, 75, 77, 79,
379 81, 82, 84, 86, 88, 89, 91, 93,
380 94, 96, 98, 99, 101, 102, 104, 105,
381 106, 108, 109, 110, 112, 113, 114, 115,
382 116, 117, 119, 120, 120, 121, 122, 123,
383 124, 125, 126, 126, 127, 128, 128, 129,
384 129, 130, 130, 131, 131, 131, 131, 132,
385 132, 132, 132, 132, 132, 132, 132, 132,
386 132, 132, 132, 131, 131, 131, 130, 130,
387 130, 129, 129, 128, 127, 127, 126, 125,
388 125, 124, 123, 122, 121, 120, 119, 118,
389 117, 116, 115, 114, 113, 111, 110, 109,
390 107, 106, 105, 103, 102, 100, 99, 97,
391 96, 94, 92, 91, 89, 87, 85, 84, 82
392};
393
Joe Perches58aa68c2009-09-02 01:12:13 -0300394static const s16 hsv_green_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300395 -124, -124, -125, -125, -125, -125, -125, -125,
396 -125, -126, -126, -125, -125, -125, -125, -125,
397 -125, -124, -124, -124, -123, -123, -122, -122,
398 -121, -121, -120, -120, -119, -118, -117, -117,
399 -116, -115, -114, -113, -112, -111, -110, -109,
400 -108, -107, -105, -104, -103, -102, -100, -99,
401 -98, -96, -95, -93, -92, -91, -89, -87,
402 -86, -84, -83, -81, -79, -77, -76, -74,
403 -72, -70, -69, -67, -65, -63, -61, -59,
404 -57, -55, -53, -51, -49, -47, -45, -43,
405 -41, -39, -37, -35, -33, -30, -28, -26,
406 -24, -22, -20, -18, -15, -13, -11, -9,
407 -7, -4, -2, 0, 1, 3, 6, 8,
408 10, 12, 14, 17, 19, 21, 23, 25,
409 27, 29, 32, 34, 36, 38, 40, 42,
410 44, 46, 48, 50, 52, 54, 56, 58,
411 60, 62, 64, 66, 68, 70, 71, 73,
412 75, 77, 78, 80, 82, 83, 85, 87,
413 88, 90, 91, 93, 94, 96, 97, 98,
414 100, 101, 102, 104, 105, 106, 107, 108,
415 109, 111, 112, 113, 113, 114, 115, 116,
416 117, 118, 118, 119, 120, 120, 121, 122,
417 122, 123, 123, 124, 124, 124, 125, 125,
418 125, 125, 125, 125, 125, 126, 126, 125,
419 125, 125, 125, 125, 125, 124, 124, 124,
420 123, 123, 122, 122, 121, 121, 120, 120,
421 119, 118, 117, 117, 116, 115, 114, 113,
422 112, 111, 110, 109, 108, 107, 105, 104,
423 103, 102, 100, 99, 98, 96, 95, 93,
424 92, 91, 89, 87, 86, 84, 83, 81,
425 79, 77, 76, 74, 72, 70, 69, 67,
426 65, 63, 61, 59, 57, 55, 53, 51,
427 49, 47, 45, 43, 41, 39, 37, 35,
428 33, 30, 28, 26, 24, 22, 20, 18,
429 15, 13, 11, 9, 7, 4, 2, 0,
430 -1, -3, -6, -8, -10, -12, -14, -17,
431 -19, -21, -23, -25, -27, -29, -32, -34,
432 -36, -38, -40, -42, -44, -46, -48, -50,
433 -52, -54, -56, -58, -60, -62, -64, -66,
434 -68, -70, -71, -73, -75, -77, -78, -80,
435 -82, -83, -85, -87, -88, -90, -91, -93,
436 -94, -96, -97, -98, -100, -101, -102, -104,
437 -105, -106, -107, -108, -109, -111, -112, -113,
438 -113, -114, -115, -116, -117, -118, -118, -119,
439 -120, -120, -121, -122, -122, -123, -123, -124, -124
440};
441
Joe Perches58aa68c2009-09-02 01:12:13 -0300442static const s16 hsv_green_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300443 -100, -99, -98, -97, -95, -94, -93, -91,
444 -90, -89, -87, -86, -84, -83, -81, -80,
445 -78, -76, -75, -73, -71, -70, -68, -66,
446 -64, -63, -61, -59, -57, -55, -53, -51,
447 -49, -48, -46, -44, -42, -40, -38, -36,
448 -34, -32, -30, -27, -25, -23, -21, -19,
449 -17, -15, -13, -11, -9, -7, -4, -2,
450 0, 1, 3, 5, 7, 9, 11, 14,
451 16, 18, 20, 22, 24, 26, 28, 30,
452 32, 34, 36, 38, 40, 42, 44, 46,
453 48, 50, 52, 54, 56, 58, 59, 61,
454 63, 65, 67, 68, 70, 72, 74, 75,
455 77, 78, 80, 82, 83, 85, 86, 88,
456 89, 90, 92, 93, 95, 96, 97, 98,
457 100, 101, 102, 103, 104, 105, 106, 107,
458 108, 109, 110, 111, 112, 112, 113, 114,
459 115, 115, 116, 116, 117, 117, 118, 118,
460 119, 119, 119, 120, 120, 120, 120, 120,
461 121, 121, 121, 121, 121, 121, 120, 120,
462 120, 120, 120, 119, 119, 119, 118, 118,
463 117, 117, 116, 116, 115, 114, 114, 113,
464 112, 111, 111, 110, 109, 108, 107, 106,
465 105, 104, 103, 102, 100, 99, 98, 97,
466 95, 94, 93, 91, 90, 89, 87, 86,
467 84, 83, 81, 80, 78, 76, 75, 73,
468 71, 70, 68, 66, 64, 63, 61, 59,
469 57, 55, 53, 51, 49, 48, 46, 44,
470 42, 40, 38, 36, 34, 32, 30, 27,
471 25, 23, 21, 19, 17, 15, 13, 11,
472 9, 7, 4, 2, 0, -1, -3, -5,
473 -7, -9, -11, -14, -16, -18, -20, -22,
474 -24, -26, -28, -30, -32, -34, -36, -38,
475 -40, -42, -44, -46, -48, -50, -52, -54,
476 -56, -58, -59, -61, -63, -65, -67, -68,
477 -70, -72, -74, -75, -77, -78, -80, -82,
478 -83, -85, -86, -88, -89, -90, -92, -93,
479 -95, -96, -97, -98, -100, -101, -102, -103,
480 -104, -105, -106, -107, -108, -109, -110, -111,
481 -112, -112, -113, -114, -115, -115, -116, -116,
482 -117, -117, -118, -118, -119, -119, -119, -120,
483 -120, -120, -120, -120, -121, -121, -121, -121,
484 -121, -121, -120, -120, -120, -120, -120, -119,
485 -119, -119, -118, -118, -117, -117, -116, -116,
486 -115, -114, -114, -113, -112, -111, -111, -110,
487 -109, -108, -107, -106, -105, -104, -103, -102, -100
488};
489
Joe Perches58aa68c2009-09-02 01:12:13 -0300490static const s16 hsv_blue_x[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300491 112, 113, 114, 114, 115, 116, 117, 117,
492 118, 118, 119, 119, 120, 120, 120, 121,
493 121, 121, 122, 122, 122, 122, 122, 122,
494 122, 122, 122, 122, 122, 122, 121, 121,
495 121, 120, 120, 120, 119, 119, 118, 118,
496 117, 116, 116, 115, 114, 113, 113, 112,
497 111, 110, 109, 108, 107, 106, 105, 104,
498 103, 102, 100, 99, 98, 97, 95, 94,
499 93, 91, 90, 88, 87, 85, 84, 82,
500 80, 79, 77, 76, 74, 72, 70, 69,
501 67, 65, 63, 61, 60, 58, 56, 54,
502 52, 50, 48, 46, 44, 42, 40, 38,
503 36, 34, 32, 30, 28, 26, 24, 22,
504 19, 17, 15, 13, 11, 9, 7, 5,
505 2, 0, -1, -3, -5, -7, -9, -12,
506 -14, -16, -18, -20, -22, -24, -26, -28,
507 -31, -33, -35, -37, -39, -41, -43, -45,
508 -47, -49, -51, -53, -54, -56, -58, -60,
509 -62, -64, -66, -67, -69, -71, -73, -74,
510 -76, -78, -79, -81, -83, -84, -86, -87,
511 -89, -90, -92, -93, -94, -96, -97, -98,
512 -99, -101, -102, -103, -104, -105, -106, -107,
513 -108, -109, -110, -111, -112, -113, -114, -114,
514 -115, -116, -117, -117, -118, -118, -119, -119,
515 -120, -120, -120, -121, -121, -121, -122, -122,
516 -122, -122, -122, -122, -122, -122, -122, -122,
517 -122, -122, -121, -121, -121, -120, -120, -120,
518 -119, -119, -118, -118, -117, -116, -116, -115,
519 -114, -113, -113, -112, -111, -110, -109, -108,
520 -107, -106, -105, -104, -103, -102, -100, -99,
521 -98, -97, -95, -94, -93, -91, -90, -88,
522 -87, -85, -84, -82, -80, -79, -77, -76,
523 -74, -72, -70, -69, -67, -65, -63, -61,
524 -60, -58, -56, -54, -52, -50, -48, -46,
525 -44, -42, -40, -38, -36, -34, -32, -30,
526 -28, -26, -24, -22, -19, -17, -15, -13,
527 -11, -9, -7, -5, -2, 0, 1, 3,
528 5, 7, 9, 12, 14, 16, 18, 20,
529 22, 24, 26, 28, 31, 33, 35, 37,
530 39, 41, 43, 45, 47, 49, 51, 53,
531 54, 56, 58, 60, 62, 64, 66, 67,
532 69, 71, 73, 74, 76, 78, 79, 81,
533 83, 84, 86, 87, 89, 90, 92, 93,
534 94, 96, 97, 98, 99, 101, 102, 103,
535 104, 105, 106, 107, 108, 109, 110, 111, 112
536};
537
Joe Perches58aa68c2009-09-02 01:12:13 -0300538static const s16 hsv_blue_y[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300539 -11, -13, -15, -17, -19, -21, -23, -25,
540 -27, -29, -31, -33, -35, -37, -39, -41,
541 -43, -45, -46, -48, -50, -52, -54, -55,
542 -57, -59, -61, -62, -64, -66, -67, -69,
543 -71, -72, -74, -75, -77, -78, -80, -81,
544 -83, -84, -86, -87, -88, -90, -91, -92,
545 -93, -95, -96, -97, -98, -99, -100, -101,
546 -102, -103, -104, -105, -106, -106, -107, -108,
547 -109, -109, -110, -111, -111, -112, -112, -113,
548 -113, -114, -114, -114, -115, -115, -115, -115,
549 -116, -116, -116, -116, -116, -116, -116, -116,
550 -116, -115, -115, -115, -115, -114, -114, -114,
551 -113, -113, -112, -112, -111, -111, -110, -110,
552 -109, -108, -108, -107, -106, -105, -104, -103,
553 -102, -101, -100, -99, -98, -97, -96, -95,
554 -94, -93, -91, -90, -89, -88, -86, -85,
555 -84, -82, -81, -79, -78, -76, -75, -73,
556 -71, -70, -68, -67, -65, -63, -62, -60,
557 -58, -56, -55, -53, -51, -49, -47, -45,
558 -44, -42, -40, -38, -36, -34, -32, -30,
559 -28, -26, -24, -22, -20, -18, -16, -14,
560 -12, -10, -8, -6, -4, -2, 0, 1,
561 3, 5, 7, 9, 11, 13, 15, 17,
562 19, 21, 23, 25, 27, 29, 31, 33,
563 35, 37, 39, 41, 43, 45, 46, 48,
564 50, 52, 54, 55, 57, 59, 61, 62,
565 64, 66, 67, 69, 71, 72, 74, 75,
566 77, 78, 80, 81, 83, 84, 86, 87,
567 88, 90, 91, 92, 93, 95, 96, 97,
568 98, 99, 100, 101, 102, 103, 104, 105,
569 106, 106, 107, 108, 109, 109, 110, 111,
570 111, 112, 112, 113, 113, 114, 114, 114,
571 115, 115, 115, 115, 116, 116, 116, 116,
572 116, 116, 116, 116, 116, 115, 115, 115,
573 115, 114, 114, 114, 113, 113, 112, 112,
574 111, 111, 110, 110, 109, 108, 108, 107,
575 106, 105, 104, 103, 102, 101, 100, 99,
576 98, 97, 96, 95, 94, 93, 91, 90,
577 89, 88, 86, 85, 84, 82, 81, 79,
578 78, 76, 75, 73, 71, 70, 68, 67,
579 65, 63, 62, 60, 58, 56, 55, 53,
580 51, 49, 47, 45, 44, 42, 40, 38,
581 36, 34, 32, 30, 28, 26, 24, 22,
582 20, 18, 16, 14, 12, 10, 8, 6,
583 4, 2, 0, -1, -3, -5, -7, -9, -11
584};
585
Jean-François Moinedae1de62012-03-24 09:20:25 -0300586static const u16 i2c_ident[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300587 V4L2_IDENT_OV9650,
588 V4L2_IDENT_OV9655,
589 V4L2_IDENT_SOI968,
590 V4L2_IDENT_OV7660,
591 V4L2_IDENT_OV7670,
592 V4L2_IDENT_MT9V011,
593 V4L2_IDENT_MT9V111,
594 V4L2_IDENT_MT9V112,
595 V4L2_IDENT_MT9M001C12ST,
596 V4L2_IDENT_MT9M111,
Brian Johnsone99ac542010-03-16 13:58:28 -0300597 V4L2_IDENT_MT9M112,
Brian Johnson26e744b2009-07-19 05:52:58 -0300598 V4L2_IDENT_HV7131R,
Jean-François Moinebed37382012-03-24 09:17:37 -0300599[SENSOR_MT9VPRB] = V4L2_IDENT_UNKNOWN,
Brian Johnson26e744b2009-07-19 05:52:58 -0300600};
601
Jean-François Moinedae1de62012-03-24 09:20:25 -0300602static const u16 bridge_init[][2] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300603 {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c},
604 {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40},
605 {0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10},
606 {0x106b, 0x08}, {0x1188, 0x87}, {0x11a1, 0x00},
607 {0x11a2, 0x00}, {0x11a3, 0x6a}, {0x11a4, 0x50},
608 {0x11ab, 0x00}, {0x11ac, 0x00}, {0x11ad, 0x50},
609 {0x11ae, 0x3c}, {0x118a, 0x04}, {0x0395, 0x04},
610 {0x11b8, 0x3a}, {0x118b, 0x0e}, {0x10f7, 0x05},
611 {0x10f8, 0x14}, {0x10fa, 0xff}, {0x10f9, 0x00},
612 {0x11ba, 0x0a}, {0x11a5, 0x2d}, {0x11a6, 0x2d},
613 {0x11a7, 0x3a}, {0x11a8, 0x05}, {0x11a9, 0x04},
614 {0x11aa, 0x3f}, {0x11af, 0x28}, {0x11b0, 0xd8},
615 {0x11b1, 0x14}, {0x11b2, 0xec}, {0x11b3, 0x32},
616 {0x11b4, 0xdd}, {0x11b5, 0x32}, {0x11b6, 0xdd},
617 {0x10e0, 0x2c}, {0x11bc, 0x40}, {0x11bd, 0x01},
618 {0x11be, 0xf0}, {0x11bf, 0x00}, {0x118c, 0x1f},
619 {0x118d, 0x1f}, {0x118e, 0x1f}, {0x118f, 0x1f},
620 {0x1180, 0x01}, {0x1181, 0x00}, {0x1182, 0x01},
Brian Johnson0c045eb2010-03-16 13:58:27 -0300621 {0x1183, 0x00}, {0x1184, 0x50}, {0x1185, 0x80},
622 {0x1007, 0x00}
Brian Johnson26e744b2009-07-19 05:52:58 -0300623};
624
625/* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300626static const u8 ov_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300627 0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */,
628 0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */,
629 0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */,
630 0x30 /* 4x */, 0x31 /* 4.25x */, 0x32 /* 4.5x */, 0x33 /* 4.75x */,
631 0x34 /* 5x */, 0x35 /* 5.25x */, 0x36 /* 5.5x */, 0x37 /* 5.75x */,
632 0x38 /* 6x */, 0x39 /* 6.25x */, 0x3a /* 6.5x */, 0x3b /* 6.75x */,
633 0x3c /* 7x */, 0x3d /* 7.25x */, 0x3e /* 7.5x */, 0x3f /* 7.75x */,
634 0x70 /* 8x */
635};
636
637/* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300638static const u16 micron1_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300639 /* 1x 1.25x 1.5x 1.75x */
640 0x0020, 0x0028, 0x0030, 0x0038,
641 /* 2x 2.25x 2.5x 2.75x */
642 0x00a0, 0x00a4, 0x00a8, 0x00ac,
643 /* 3x 3.25x 3.5x 3.75x */
644 0x00b0, 0x00b4, 0x00b8, 0x00bc,
645 /* 4x 4.25x 4.5x 4.75x */
646 0x00c0, 0x00c4, 0x00c8, 0x00cc,
647 /* 5x 5.25x 5.5x 5.75x */
648 0x00d0, 0x00d4, 0x00d8, 0x00dc,
649 /* 6x 6.25x 6.5x 6.75x */
650 0x00e0, 0x00e4, 0x00e8, 0x00ec,
651 /* 7x 7.25x 7.5x 7.75x */
652 0x00f0, 0x00f4, 0x00f8, 0x00fc,
653 /* 8x */
654 0x01c0
655};
656
657/* mt9m001 sensor uses a different gain formula then other micron sensors */
658/* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300659static const u16 micron2_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300660 /* 1x 1.25x 1.5x 1.75x */
661 0x0008, 0x000a, 0x000c, 0x000e,
662 /* 2x 2.25x 2.5x 2.75x */
663 0x0010, 0x0012, 0x0014, 0x0016,
664 /* 3x 3.25x 3.5x 3.75x */
665 0x0018, 0x001a, 0x001c, 0x001e,
666 /* 4x 4.25x 4.5x 4.75x */
667 0x0020, 0x0051, 0x0052, 0x0053,
668 /* 5x 5.25x 5.5x 5.75x */
669 0x0054, 0x0055, 0x0056, 0x0057,
670 /* 6x 6.25x 6.5x 6.75x */
671 0x0058, 0x0059, 0x005a, 0x005b,
672 /* 7x 7.25x 7.5x 7.75x */
673 0x005c, 0x005d, 0x005e, 0x005f,
674 /* 8x */
675 0x0060
676};
677
678/* Gain = .5 + bit[7:0] / 16 */
Jean-François Moinedae1de62012-03-24 09:20:25 -0300679static const u8 hv7131r_gain[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300680 0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */,
681 0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */,
682 0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */,
683 0x38 /* 4x */, 0x3c /* 4.25x */, 0x40 /* 4.5x */, 0x44 /* 4.75x */,
684 0x48 /* 5x */, 0x4c /* 5.25x */, 0x50 /* 5.5x */, 0x54 /* 5.75x */,
685 0x58 /* 6x */, 0x5c /* 6.25x */, 0x60 /* 6.5x */, 0x64 /* 6.75x */,
686 0x68 /* 7x */, 0x6c /* 7.25x */, 0x70 /* 7.5x */, 0x74 /* 7.75x */,
687 0x78 /* 8x */
688};
689
Jean-François Moinedae1de62012-03-24 09:20:25 -0300690static const struct i2c_reg_u8 soi968_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300691 {0x0c, 0x00}, {0x0f, 0x1f},
Brian Johnson26e744b2009-07-19 05:52:58 -0300692 {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
693 {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
694 {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
695 {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20},
696 {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e},
Brian Johnsone1430472009-09-02 12:39:41 -0300697 {0x13, 0x8b}, {0x12, 0x40}, {0x17, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300698 {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79},
699 {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40},
700 {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32},
701 {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80},
702};
703
Jean-François Moinedae1de62012-03-24 09:20:25 -0300704static const struct i2c_reg_u8 ov7660_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300705 {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
706 {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
707 {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
Hans de Goede8bc50f32011-02-16 07:11:14 -0300708 /* HDG Set hstart and hstop, datasheet default 0x11, 0x61, using
709 0x10, 0x61 and sd->hstart, vstart = 3, fixes ugly colored borders */
710 {0x17, 0x10}, {0x18, 0x61},
Brian Johnson26e744b2009-07-19 05:52:58 -0300711 {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43},
Jean-François Moinea1ac5dc2012-03-24 09:33:42 -0300712 {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0x00},
713 {0x2e, 0x00}, {0x01, 0x78}, {0x02, 0x50},
Brian Johnson26e744b2009-07-19 05:52:58 -0300714};
715
Jean-François Moinedae1de62012-03-24 09:20:25 -0300716static const struct i2c_reg_u8 ov7670_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300717 {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
Brian Johnson26e744b2009-07-19 05:52:58 -0300718 {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
719 {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
720 {0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
721 {0x0d, 0x40}, {0x14, 0x28}, {0xa5, 0x05}, {0xab, 0x07},
722 {0x24, 0x95}, {0x25, 0x33}, {0x26, 0xe3}, {0x9f, 0x75},
723 {0xa0, 0x65}, {0xa1, 0x0b}, {0xa6, 0xd8}, {0xa7, 0xd8},
724 {0xa8, 0xf0}, {0xa9, 0x90}, {0xaa, 0x94}, {0x13, 0xe5},
725 {0x0e, 0x61}, {0x0f, 0x4b}, {0x16, 0x02}, {0x1e, 0x27},
726 {0x21, 0x02}, {0x22, 0x91}, {0x29, 0x07}, {0x33, 0x0b},
727 {0x35, 0x0b}, {0x37, 0x1d}, {0x38, 0x71}, {0x39, 0x2a},
728 {0x3c, 0x78}, {0x4d, 0x40}, {0x4e, 0x20}, {0x69, 0x00},
729 {0x74, 0x19}, {0x8d, 0x4f}, {0x8e, 0x00}, {0x8f, 0x00},
730 {0x90, 0x00}, {0x91, 0x00}, {0x96, 0x00}, {0x9a, 0x80},
731 {0xb0, 0x84}, {0xb1, 0x0c}, {0xb2, 0x0e}, {0xb3, 0x82},
732 {0xb8, 0x0a}, {0x43, 0x0a}, {0x44, 0xf0}, {0x45, 0x20},
733 {0x46, 0x7d}, {0x47, 0x29}, {0x48, 0x4a}, {0x59, 0x8c},
734 {0x5a, 0xa5}, {0x5b, 0xde}, {0x5c, 0x96}, {0x5d, 0x66},
735 {0x5e, 0x10}, {0x6c, 0x0a}, {0x6d, 0x55}, {0x6e, 0x11},
736 {0x6f, 0x9e}, {0x6a, 0x40}, {0x01, 0x40}, {0x02, 0x40},
737 {0x13, 0xe7}, {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x02},
738 {0x52, 0x1d}, {0x53, 0x56}, {0x54, 0x73}, {0x55, 0x0a},
739 {0x56, 0x55}, {0x57, 0x80}, {0x58, 0x9e}, {0x41, 0x08},
740 {0x3f, 0x02}, {0x75, 0x03}, {0x76, 0x63}, {0x4c, 0x04},
741 {0x77, 0x06}, {0x3d, 0x02}, {0x4b, 0x09}, {0xc9, 0x30},
742 {0x41, 0x08}, {0x56, 0x48}, {0x34, 0x11}, {0xa4, 0x88},
743 {0x96, 0x00}, {0x97, 0x30}, {0x98, 0x20}, {0x99, 0x30},
744 {0x9a, 0x84}, {0x9b, 0x29}, {0x9c, 0x03}, {0x9d, 0x99},
745 {0x9e, 0x7f}, {0x78, 0x04}, {0x79, 0x01}, {0xc8, 0xf0},
746 {0x79, 0x0f}, {0xc8, 0x00}, {0x79, 0x10}, {0xc8, 0x7e},
747 {0x79, 0x0a}, {0xc8, 0x80}, {0x79, 0x0b}, {0xc8, 0x01},
748 {0x79, 0x0c}, {0xc8, 0x0f}, {0x79, 0x0d}, {0xc8, 0x20},
749 {0x79, 0x09}, {0xc8, 0x80}, {0x79, 0x02}, {0xc8, 0xc0},
750 {0x79, 0x03}, {0xc8, 0x40}, {0x79, 0x05}, {0xc8, 0x30},
751 {0x79, 0x26}, {0x62, 0x20}, {0x63, 0x00}, {0x64, 0x06},
752 {0x65, 0x00}, {0x66, 0x05}, {0x94, 0x05}, {0x95, 0x0a},
753 {0x17, 0x13}, {0x18, 0x01}, {0x19, 0x02}, {0x1a, 0x7a},
754 {0x46, 0x59}, {0x47, 0x30}, {0x58, 0x9a}, {0x59, 0x84},
755 {0x5a, 0x91}, {0x5b, 0x57}, {0x5c, 0x75}, {0x5d, 0x6d},
756 {0x5e, 0x13}, {0x64, 0x07}, {0x94, 0x07}, {0x95, 0x0d},
757 {0xa6, 0xdf}, {0xa7, 0xdf}, {0x48, 0x4d}, {0x51, 0x00},
758 {0x6b, 0x0a}, {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00},
759 {0x92, 0x00}, {0x93, 0x00}, {0x55, 0x0a}, {0x56, 0x60},
760 {0x4f, 0x6e}, {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d},
761 {0x53, 0x56}, {0x54, 0x73}, {0x58, 0x9a}, {0x4f, 0x6e},
762 {0x50, 0x70}, {0x51, 0x00}, {0x52, 0x1d}, {0x53, 0x56},
763 {0x54, 0x73}, {0x58, 0x9a}, {0x3f, 0x01}, {0x7b, 0x03},
764 {0x7c, 0x09}, {0x7d, 0x16}, {0x7e, 0x38}, {0x7f, 0x47},
765 {0x80, 0x53}, {0x81, 0x5e}, {0x82, 0x6a}, {0x83, 0x74},
766 {0x84, 0x80}, {0x85, 0x8c}, {0x86, 0x9b}, {0x87, 0xb2},
767 {0x88, 0xcc}, {0x89, 0xe5}, {0x7a, 0x24}, {0x3b, 0x00},
768 {0x9f, 0x76}, {0xa0, 0x65}, {0x13, 0xe2}, {0x6b, 0x0a},
769 {0x11, 0x80}, {0x2a, 0x00}, {0x2b, 0x00}, {0x92, 0x00},
770 {0x93, 0x00},
771};
772
Jean-François Moinedae1de62012-03-24 09:20:25 -0300773static const struct i2c_reg_u8 ov9650_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300774 {0x00, 0x00}, {0x01, 0x78},
Brian Johnson26e744b2009-07-19 05:52:58 -0300775 {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
776 {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
777 {0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
778 {0x0e, 0xa0}, {0x0f, 0x52}, {0x10, 0x7c},
779 {0x11, 0x80}, {0x12, 0x45}, {0x13, 0xc2},
780 {0x14, 0x2e}, {0x15, 0x00}, {0x16, 0x07},
781 {0x17, 0x24}, {0x18, 0xc5}, {0x19, 0x00},
782 {0x1a, 0x3c}, {0x1b, 0x00}, {0x1e, 0x04},
783 {0x1f, 0x00}, {0x24, 0x78}, {0x25, 0x68},
784 {0x26, 0xd4}, {0x27, 0x80}, {0x28, 0x80},
785 {0x29, 0x30}, {0x2a, 0x00}, {0x2b, 0x00},
786 {0x2c, 0x80}, {0x2d, 0x00}, {0x2e, 0x00},
787 {0x2f, 0x00}, {0x30, 0x08}, {0x31, 0x30},
788 {0x32, 0x84}, {0x33, 0xe2}, {0x34, 0xbf},
789 {0x35, 0x81}, {0x36, 0xf9}, {0x37, 0x00},
790 {0x38, 0x93}, {0x39, 0x50}, {0x3a, 0x01},
791 {0x3b, 0x01}, {0x3c, 0x73}, {0x3d, 0x19},
792 {0x3e, 0x0b}, {0x3f, 0x80}, {0x40, 0xc1},
793 {0x41, 0x00}, {0x42, 0x08}, {0x67, 0x80},
794 {0x68, 0x80}, {0x69, 0x40}, {0x6a, 0x00},
795 {0x6b, 0x0a}, {0x8b, 0x06}, {0x8c, 0x20},
796 {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0xdf},
797 {0x92, 0x00}, {0x93, 0x00}, {0x94, 0x88},
798 {0x95, 0x88}, {0x96, 0x04}, {0xa1, 0x00},
799 {0xa5, 0x80}, {0xa8, 0x80}, {0xa9, 0xb8},
800 {0xaa, 0x92}, {0xab, 0x0a},
801};
802
Jean-François Moinedae1de62012-03-24 09:20:25 -0300803static const struct i2c_reg_u8 ov9655_init[] = {
Jean-François Moine92884f82012-03-19 04:33:30 -0300804 {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300805 {0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
806 {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
807 {0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57},
808 {0x3a, 0x00}, {0x3b, 0xcc}, {0x3c, 0x0c}, {0x3d, 0x19},
809 {0x3e, 0x0c}, {0x3f, 0x01}, {0x41, 0x40}, {0x42, 0x80},
810 {0x45, 0x46}, {0x46, 0x62}, {0x47, 0x2a}, {0x48, 0x3c},
811 {0x4a, 0xf0}, {0x4b, 0xdc}, {0x4c, 0xdc}, {0x4d, 0xdc},
812 {0x4e, 0xdc}, {0x6c, 0x04}, {0x6f, 0x9e}, {0x70, 0x05},
813 {0x71, 0x78}, {0x77, 0x02}, {0x8a, 0x23}, {0x90, 0x7e},
814 {0x91, 0x7c}, {0x9f, 0x6e}, {0xa0, 0x6e}, {0xa5, 0x68},
815 {0xa6, 0x60}, {0xa8, 0xc1}, {0xa9, 0xfa}, {0xaa, 0x92},
816 {0xab, 0x04}, {0xac, 0x80}, {0xad, 0x80}, {0xae, 0x80},
817 {0xaf, 0x80}, {0xb2, 0xf2}, {0xb3, 0x20}, {0xb5, 0x00},
818 {0xb6, 0xaf}, {0xbb, 0xae}, {0xbc, 0x44}, {0xbd, 0x44},
819 {0xbe, 0x3b}, {0xbf, 0x3a}, {0xc1, 0xc8}, {0xc2, 0x01},
Brian Johnson26e744b2009-07-19 05:52:58 -0300820 {0xc4, 0x00}, {0xc6, 0x85}, {0xc7, 0x81}, {0xc9, 0xe0},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300821 {0xca, 0xe8}, {0xcc, 0xd8}, {0xcd, 0x93}, {0x2d, 0x00},
822 {0x2e, 0x00}, {0x01, 0x80}, {0x02, 0x80}, {0x12, 0x61},
Brian Johnson26e744b2009-07-19 05:52:58 -0300823 {0x36, 0xfa}, {0x8c, 0x8d}, {0xc0, 0xaa}, {0x69, 0x0a},
Brian Johnsoncc2a8332010-03-16 13:58:28 -0300824 {0x03, 0x09}, {0x17, 0x16}, {0x18, 0x6e}, {0x19, 0x01},
825 {0x1a, 0x3e}, {0x32, 0x09}, {0x2a, 0x10}, {0x2b, 0x0a},
826 {0x92, 0x00}, {0x93, 0x00}, {0xa1, 0x00}, {0x10, 0x7c},
827 {0x04, 0x03}, {0x00, 0x13},
Brian Johnson26e744b2009-07-19 05:52:58 -0300828};
829
Jean-François Moinedae1de62012-03-24 09:20:25 -0300830static const struct i2c_reg_u16 mt9v112_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300831 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020},
832 {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
833 {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
834 {0x05, 0x0000}, {0x06, 0x340c}, {0x3b, 0x042a},
835 {0x3c, 0x0400}, {0xf0, 0x0002}, {0x2e, 0x0c58},
836 {0x5b, 0x0001}, {0xc8, 0x9f0b}, {0xf0, 0x0001},
837 {0x9b, 0x5300}, {0xf0, 0x0000}, {0x2b, 0x0020},
838 {0x2c, 0x002a}, {0x2d, 0x0032}, {0x2e, 0x0020},
839 {0x09, 0x01dc}, {0x01, 0x000c}, {0x02, 0x0020},
840 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
841 {0x05, 0x0098}, {0x20, 0x0703}, {0x09, 0x01f2},
842 {0x2b, 0x00a0}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
843 {0x2e, 0x00a0}, {0x01, 0x000c}, {0x02, 0x0020},
844 {0x03, 0x01e0}, {0x04, 0x0280}, {0x06, 0x000c},
845 {0x05, 0x0098}, {0x09, 0x01c1}, {0x2b, 0x00ae},
846 {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
847};
848
Jean-François Moinedae1de62012-03-24 09:20:25 -0300849static const struct i2c_reg_u16 mt9v111_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300850 {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
Brian Johnson6ea23bd2010-05-05 13:22:45 -0300851 {0x01, 0x0001}, {0x05, 0x0004}, {0x2d, 0xe0a0},
852 {0x2e, 0x0c64}, {0x2f, 0x0064}, {0x06, 0x600e},
853 {0x08, 0x0480}, {0x01, 0x0004}, {0x02, 0x0016},
854 {0x03, 0x01e7}, {0x04, 0x0287}, {0x05, 0x0004},
855 {0x06, 0x002d}, {0x07, 0x3002}, {0x08, 0x0008},
856 {0x0e, 0x0008}, {0x20, 0x0000}
Brian Johnson26e744b2009-07-19 05:52:58 -0300857};
858
Jean-François Moinedae1de62012-03-24 09:20:25 -0300859static const struct i2c_reg_u16 mt9v011_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300860 {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
861 {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1},
862 {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006},
863 {0x0d, 0x0002}, {0x0a, 0x0000}, {0x0b, 0x0000},
864 {0x0c, 0x0000}, {0x0d, 0x0000}, {0x0e, 0x0000},
865 {0x0f, 0x0000}, {0x10, 0x0000}, {0x11, 0x0000},
866 {0x12, 0x0000}, {0x13, 0x0000}, {0x14, 0x0000},
867 {0x15, 0x0000}, {0x16, 0x0000}, {0x17, 0x0000},
868 {0x18, 0x0000}, {0x19, 0x0000}, {0x1a, 0x0000},
869 {0x1b, 0x0000}, {0x1c, 0x0000}, {0x1d, 0x0000},
870 {0x32, 0x0000}, {0x20, 0x1101}, {0x21, 0x0000},
871 {0x22, 0x0000}, {0x23, 0x0000}, {0x24, 0x0000},
872 {0x25, 0x0000}, {0x26, 0x0000}, {0x27, 0x0024},
873 {0x2f, 0xf7b0}, {0x30, 0x0005}, {0x31, 0x0000},
874 {0x32, 0x0000}, {0x33, 0x0000}, {0x34, 0x0100},
875 {0x3d, 0x068f}, {0x40, 0x01e0}, {0x41, 0x00d1},
876 {0x44, 0x0082}, {0x5a, 0x0000}, {0x5b, 0x0000},
877 {0x5c, 0x0000}, {0x5d, 0x0000}, {0x5e, 0x0000},
878 {0x5f, 0xa31d}, {0x62, 0x0611}, {0x0a, 0x0000},
879 {0x06, 0x0029}, {0x05, 0x0009}, {0x20, 0x1101},
880 {0x20, 0x1101}, {0x09, 0x0064}, {0x07, 0x0003},
881 {0x2b, 0x0033}, {0x2c, 0x00a0}, {0x2d, 0x00a0},
882 {0x2e, 0x0033}, {0x07, 0x0002}, {0x06, 0x0000},
883 {0x06, 0x0029}, {0x05, 0x0009},
884};
885
Jean-François Moinedae1de62012-03-24 09:20:25 -0300886static const struct i2c_reg_u16 mt9m001_init[] = {
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -0300887 {0x0d, 0x0001},
888 {0x0d, 0x0000},
889 {0x04, 0x0500}, /* hres = 1280 */
890 {0x03, 0x0400}, /* vres = 1024 */
891 {0x20, 0x1100},
892 {0x06, 0x0010},
893 {0x2b, 0x0024},
894 {0x2e, 0x0024},
895 {0x35, 0x0024},
896 {0x2d, 0x0020},
897 {0x2c, 0x0020},
898 {0x09, 0x0ad4},
899 {0x35, 0x0057},
Brian Johnson26e744b2009-07-19 05:52:58 -0300900};
901
Jean-François Moinedae1de62012-03-24 09:20:25 -0300902static const struct i2c_reg_u16 mt9m111_init[] = {
Brian Johnson13a84fa2009-09-03 19:07:13 -0300903 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
904 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
Brian Johnson4d708a52009-09-03 19:10:15 -0300905 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
906 {0xf0, 0x0000},
Brian Johnson26e744b2009-07-19 05:52:58 -0300907};
908
Jean-François Moinedae1de62012-03-24 09:20:25 -0300909static const struct i2c_reg_u16 mt9m112_init[] = {
Brian Johnsone99ac542010-03-16 13:58:28 -0300910 {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
911 {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
912 {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
913 {0xf0, 0x0000},
914};
915
Jean-François Moinedae1de62012-03-24 09:20:25 -0300916static const struct i2c_reg_u8 hv7131r_init[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -0300917 {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
918 {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
919 {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
920 {0x01, 0x08}, {0x01, 0x08}, {0x25, 0x07},
921 {0x26, 0xc3}, {0x27, 0x50}, {0x30, 0x62},
922 {0x31, 0x10}, {0x32, 0x06}, {0x33, 0x10},
923 {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00},
924 {0x23, 0x09}, {0x01, 0x08},
925};
926
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300927static void reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
Brian Johnson26e744b2009-07-19 05:52:58 -0300928{
929 struct usb_device *dev = gspca_dev->dev;
930 int result;
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300931
932 if (gspca_dev->usb_err < 0)
933 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300934 result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
935 0x00,
936 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
937 reg,
938 0x00,
939 gspca_dev->usb_buf,
940 length,
941 500);
942 if (unlikely(result < 0 || result != length)) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300943 pr_err("Read register %02x failed %d\n", reg, result);
944 gspca_dev->usb_err = result;
Brian Johnson26e744b2009-07-19 05:52:58 -0300945 }
Brian Johnson26e744b2009-07-19 05:52:58 -0300946}
947
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300948static void reg_w(struct gspca_dev *gspca_dev, u16 reg,
Joe Perches58aa68c2009-09-02 01:12:13 -0300949 const u8 *buffer, int length)
Brian Johnson26e744b2009-07-19 05:52:58 -0300950{
951 struct usb_device *dev = gspca_dev->dev;
952 int result;
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300953
954 if (gspca_dev->usb_err < 0)
955 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300956 memcpy(gspca_dev->usb_buf, buffer, length);
957 result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
958 0x08,
959 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
960 reg,
961 0x00,
962 gspca_dev->usb_buf,
963 length,
964 500);
965 if (unlikely(result < 0 || result != length)) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300966 pr_err("Write register %02x failed %d\n", reg, result);
967 gspca_dev->usb_err = result;
Brian Johnson26e744b2009-07-19 05:52:58 -0300968 }
Brian Johnson26e744b2009-07-19 05:52:58 -0300969}
970
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300971static void reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
Brian Johnson26e744b2009-07-19 05:52:58 -0300972{
Jean-François Moineff38d582012-03-19 04:55:16 -0300973 reg_w(gspca_dev, reg, &value, 1);
Brian Johnson26e744b2009-07-19 05:52:58 -0300974}
975
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300976static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
Brian Johnson26e744b2009-07-19 05:52:58 -0300977{
978 int i;
Jean-François Moineff38d582012-03-19 04:55:16 -0300979
Brian Johnson26e744b2009-07-19 05:52:58 -0300980 reg_w(gspca_dev, 0x10c0, buffer, 8);
981 for (i = 0; i < 5; i++) {
982 reg_r(gspca_dev, 0x10c0, 1);
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300983 if (gspca_dev->usb_err < 0)
984 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300985 if (gspca_dev->usb_buf[0] & 0x04) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300986 if (gspca_dev->usb_buf[0] & 0x08) {
987 pr_err("i2c_w error\n");
988 gspca_dev->usb_err = -EIO;
989 }
990 return;
Brian Johnson26e744b2009-07-19 05:52:58 -0300991 }
Jean-François Moinee71389b2012-03-19 04:45:20 -0300992 msleep(10);
Brian Johnson26e744b2009-07-19 05:52:58 -0300993 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300994 pr_err("i2c_w reg %02x no response\n", buffer[2]);
995/* gspca_dev->usb_err = -EIO; fixme: may occur */
Brian Johnson26e744b2009-07-19 05:52:58 -0300996}
997
Jean-François Moinefe86ec72012-03-19 04:32:15 -0300998static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
Brian Johnson26e744b2009-07-19 05:52:58 -0300999{
1000 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson26e744b2009-07-19 05:52:58 -03001001 u8 row[8];
1002
1003 /*
1004 * from the point of view of the bridge, the length
1005 * includes the address
1006 */
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001007 row[0] = sd->i2c_intf | (2 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001008 row[1] = sd->i2c_addr;
1009 row[2] = reg;
1010 row[3] = val;
1011 row[4] = 0x00;
1012 row[5] = 0x00;
1013 row[6] = 0x00;
1014 row[7] = 0x10;
1015
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001016 i2c_w(gspca_dev, row);
Brian Johnson26e744b2009-07-19 05:52:58 -03001017}
1018
Jean-François Moined4689b72012-03-19 04:42:45 -03001019static void i2c_w1_buf(struct gspca_dev *gspca_dev,
Jean-François Moinedae1de62012-03-24 09:20:25 -03001020 const struct i2c_reg_u8 *buf, int sz)
Jean-François Moined4689b72012-03-19 04:42:45 -03001021{
1022 while (--sz >= 0) {
1023 i2c_w1(gspca_dev, buf->reg, buf->val);
1024 buf++;
1025 }
1026}
1027
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001028static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001029{
1030 struct sd *sd = (struct sd *) gspca_dev;
1031 u8 row[8];
1032
1033 /*
1034 * from the point of view of the bridge, the length
1035 * includes the address
1036 */
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001037 row[0] = sd->i2c_intf | (3 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001038 row[1] = sd->i2c_addr;
1039 row[2] = reg;
Jean-François Moineff38d582012-03-19 04:55:16 -03001040 row[3] = val >> 8;
1041 row[4] = val;
Brian Johnson26e744b2009-07-19 05:52:58 -03001042 row[5] = 0x00;
1043 row[6] = 0x00;
1044 row[7] = 0x10;
1045
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001046 i2c_w(gspca_dev, row);
Brian Johnson26e744b2009-07-19 05:52:58 -03001047}
1048
Jean-François Moined4689b72012-03-19 04:42:45 -03001049static void i2c_w2_buf(struct gspca_dev *gspca_dev,
Jean-François Moinedae1de62012-03-24 09:20:25 -03001050 const struct i2c_reg_u16 *buf, int sz)
Jean-François Moined4689b72012-03-19 04:42:45 -03001051{
1052 while (--sz >= 0) {
1053 i2c_w2(gspca_dev, buf->reg, buf->val);
1054 buf++;
1055 }
1056}
1057
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001058static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001059{
1060 struct sd *sd = (struct sd *) gspca_dev;
1061 u8 row[8];
1062
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001063 row[0] = sd->i2c_intf | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001064 row[1] = sd->i2c_addr;
1065 row[2] = reg;
1066 row[3] = 0;
1067 row[4] = 0;
1068 row[5] = 0;
1069 row[6] = 0;
1070 row[7] = 0x10;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001071 i2c_w(gspca_dev, row);
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001072 row[0] = sd->i2c_intf | (1 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001073 row[2] = 0;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001074 i2c_w(gspca_dev, row);
1075 reg_r(gspca_dev, 0x10c2, 5);
Brian Johnson00b581e2009-07-23 05:55:43 -03001076 *val = gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001077}
1078
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001079static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001080{
1081 struct sd *sd = (struct sd *) gspca_dev;
1082 u8 row[8];
1083
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001084 row[0] = sd->i2c_intf | (1 << 4);
Brian Johnson26e744b2009-07-19 05:52:58 -03001085 row[1] = sd->i2c_addr;
1086 row[2] = reg;
1087 row[3] = 0;
1088 row[4] = 0;
1089 row[5] = 0;
1090 row[6] = 0;
1091 row[7] = 0x10;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001092 i2c_w(gspca_dev, row);
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001093 row[0] = sd->i2c_intf | (2 << 4) | 0x02;
Brian Johnson26e744b2009-07-19 05:52:58 -03001094 row[2] = 0;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001095 i2c_w(gspca_dev, row);
1096 reg_r(gspca_dev, 0x10c2, 5);
Brian Johnson00b581e2009-07-23 05:55:43 -03001097 *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
Brian Johnson26e744b2009-07-19 05:52:58 -03001098}
1099
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001100static void ov9650_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001101{
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001102 u16 id;
Brian Johnson26e744b2009-07-19 05:52:58 -03001103 struct sd *sd = (struct sd *) gspca_dev;
1104
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001105 i2c_r2(gspca_dev, 0x1c, &id);
1106 if (gspca_dev->usb_err < 0)
1107 return;
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001108
1109 if (id != 0x7fa2) {
Joe Perches91f58422011-08-21 19:56:55 -03001110 pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001111 gspca_dev->usb_err = -ENODEV;
1112 return;
Mauro Carvalho Chehabe78567d2010-12-06 06:53:05 -03001113 }
1114
Jean-François Moine92884f82012-03-19 04:33:30 -03001115 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1116 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001117 i2c_w1_buf(gspca_dev, ov9650_init, ARRAY_SIZE(ov9650_init));
1118 if (gspca_dev->usb_err < 0)
1119 pr_err("OV9650 sensor initialization failed\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001120 sd->hstart = 1;
1121 sd->vstart = 7;
Brian Johnson26e744b2009-07-19 05:52:58 -03001122}
1123
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001124static void ov9655_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001125{
Brian Johnson26e744b2009-07-19 05:52:58 -03001126 struct sd *sd = (struct sd *) gspca_dev;
1127
Jean-François Moine92884f82012-03-19 04:33:30 -03001128 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1129 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001130 i2c_w1_buf(gspca_dev, ov9655_init, ARRAY_SIZE(ov9655_init));
1131 if (gspca_dev->usb_err < 0)
1132 pr_err("OV9655 sensor initialization failed\n");
1133
Brian Johnsoncc2a8332010-03-16 13:58:28 -03001134 sd->hstart = 1;
1135 sd->vstart = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001136}
1137
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001138static void soi968_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001139{
Brian Johnson26e744b2009-07-19 05:52:58 -03001140 struct sd *sd = (struct sd *) gspca_dev;
1141
Jean-François Moine92884f82012-03-19 04:33:30 -03001142 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1143 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001144 i2c_w1_buf(gspca_dev, soi968_init, ARRAY_SIZE(soi968_init));
1145 if (gspca_dev->usb_err < 0)
1146 pr_err("SOI968 sensor initialization failed\n");
1147
Brian Johnson26e744b2009-07-19 05:52:58 -03001148 sd->hstart = 60;
1149 sd->vstart = 11;
Brian Johnson26e744b2009-07-19 05:52:58 -03001150}
1151
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001152static void ov7660_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001153{
Brian Johnson26e744b2009-07-19 05:52:58 -03001154 struct sd *sd = (struct sd *) gspca_dev;
1155
Jean-François Moine92884f82012-03-19 04:33:30 -03001156 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1157 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001158 i2c_w1_buf(gspca_dev, ov7660_init, ARRAY_SIZE(ov7660_init));
1159 if (gspca_dev->usb_err < 0)
1160 pr_err("OV7660 sensor initialization failed\n");
Hans de Goede8bc50f32011-02-16 07:11:14 -03001161 sd->hstart = 3;
1162 sd->vstart = 3;
Brian Johnson26e744b2009-07-19 05:52:58 -03001163}
1164
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001165static void ov7670_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001166{
Brian Johnson26e744b2009-07-19 05:52:58 -03001167 struct sd *sd = (struct sd *) gspca_dev;
1168
Jean-François Moine92884f82012-03-19 04:33:30 -03001169 i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
1170 msleep(200);
Jean-François Moined4689b72012-03-19 04:42:45 -03001171 i2c_w1_buf(gspca_dev, ov7670_init, ARRAY_SIZE(ov7670_init));
1172 if (gspca_dev->usb_err < 0)
1173 pr_err("OV7670 sensor initialization failed\n");
1174
Brian Johnson26e744b2009-07-19 05:52:58 -03001175 sd->hstart = 0;
1176 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001177}
1178
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001179static void mt9v_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001180{
1181 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson26e744b2009-07-19 05:52:58 -03001182 u16 value;
Brian Johnson26e744b2009-07-19 05:52:58 -03001183
1184 sd->i2c_addr = 0x5d;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001185 i2c_r2(gspca_dev, 0xff, &value);
1186 if (gspca_dev->usb_err >= 0
1187 && value == 0x8243) {
Jean-François Moined4689b72012-03-19 04:42:45 -03001188 i2c_w2_buf(gspca_dev, mt9v011_init, ARRAY_SIZE(mt9v011_init));
1189 if (gspca_dev->usb_err < 0) {
1190 pr_err("MT9V011 sensor initialization failed\n");
1191 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001192 }
1193 sd->hstart = 2;
1194 sd->vstart = 2;
1195 sd->sensor = SENSOR_MT9V011;
Joe Perches91f58422011-08-21 19:56:55 -03001196 pr_info("MT9V011 sensor detected\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001197 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001198 }
1199
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001200 gspca_dev->usb_err = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001201 sd->i2c_addr = 0x5c;
1202 i2c_w2(gspca_dev, 0x01, 0x0004);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001203 i2c_r2(gspca_dev, 0xff, &value);
1204 if (gspca_dev->usb_err >= 0
1205 && value == 0x823a) {
Jean-François Moined4689b72012-03-19 04:42:45 -03001206 i2c_w2_buf(gspca_dev, mt9v111_init, ARRAY_SIZE(mt9v111_init));
1207 if (gspca_dev->usb_err < 0) {
1208 pr_err("MT9V111 sensor initialization failed\n");
1209 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001210 }
1211 sd->hstart = 2;
1212 sd->vstart = 2;
1213 sd->sensor = SENSOR_MT9V111;
Joe Perches91f58422011-08-21 19:56:55 -03001214 pr_info("MT9V111 sensor detected\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001215 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001216 }
1217
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001218 gspca_dev->usb_err = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001219 sd->i2c_addr = 0x5d;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001220 i2c_w2(gspca_dev, 0xf0, 0x0000);
1221 if (gspca_dev->usb_err < 0) {
1222 gspca_dev->usb_err = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001223 sd->i2c_addr = 0x48;
1224 i2c_w2(gspca_dev, 0xf0, 0x0000);
1225 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001226 i2c_r2(gspca_dev, 0x00, &value);
1227 if (gspca_dev->usb_err >= 0
1228 && value == 0x1229) {
Jean-François Moined4689b72012-03-19 04:42:45 -03001229 i2c_w2_buf(gspca_dev, mt9v112_init, ARRAY_SIZE(mt9v112_init));
1230 if (gspca_dev->usb_err < 0) {
1231 pr_err("MT9V112 sensor initialization failed\n");
1232 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001233 }
1234 sd->hstart = 6;
1235 sd->vstart = 2;
1236 sd->sensor = SENSOR_MT9V112;
Joe Perches91f58422011-08-21 19:56:55 -03001237 pr_info("MT9V112 sensor detected\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001238 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001239 }
1240
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001241 gspca_dev->usb_err = -ENODEV;
Brian Johnson26e744b2009-07-19 05:52:58 -03001242}
1243
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001244static void mt9m112_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnsone99ac542010-03-16 13:58:28 -03001245{
1246 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moined4689b72012-03-19 04:42:45 -03001247
1248 i2c_w2_buf(gspca_dev, mt9m112_init, ARRAY_SIZE(mt9m112_init));
1249 if (gspca_dev->usb_err < 0)
1250 pr_err("MT9M112 sensor initialization failed\n");
1251
Brian Johnsone99ac542010-03-16 13:58:28 -03001252 sd->hstart = 0;
1253 sd->vstart = 2;
Brian Johnsone99ac542010-03-16 13:58:28 -03001254}
1255
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001256static void mt9m111_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001257{
1258 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moined4689b72012-03-19 04:42:45 -03001259
1260 i2c_w2_buf(gspca_dev, mt9m111_init, ARRAY_SIZE(mt9m111_init));
1261 if (gspca_dev->usb_err < 0)
1262 pr_err("MT9M111 sensor initialization failed\n");
1263
Brian Johnson26e744b2009-07-19 05:52:58 -03001264 sd->hstart = 0;
1265 sd->vstart = 2;
Brian Johnson26e744b2009-07-19 05:52:58 -03001266}
1267
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001268static void mt9m001_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001269{
1270 struct sd *sd = (struct sd *) gspca_dev;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001271 u16 id;
1272
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001273 i2c_r2(gspca_dev, 0x00, &id);
1274 if (gspca_dev->usb_err < 0)
1275 return;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001276
1277 /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
1278 switch (id) {
1279 case 0x8411:
1280 case 0x8421:
Joe Perches91f58422011-08-21 19:56:55 -03001281 pr_info("MT9M001 color sensor detected\n");
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001282 break;
1283 case 0x8431:
Joe Perches91f58422011-08-21 19:56:55 -03001284 pr_info("MT9M001 mono sensor detected\n");
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001285 break;
1286 default:
Joe Perches91f58422011-08-21 19:56:55 -03001287 pr_err("No MT9M001 chip detected, ID = %x\n\n", id);
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001288 gspca_dev->usb_err = -ENODEV;
1289 return;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001290 }
1291
Jean-François Moined4689b72012-03-19 04:42:45 -03001292 i2c_w2_buf(gspca_dev, mt9m001_init, ARRAY_SIZE(mt9m001_init));
1293 if (gspca_dev->usb_err < 0)
1294 pr_err("MT9M001 sensor initialization failed\n");
1295
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001296 sd->hstart = 1;
1297 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001298}
1299
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001300static void hv7131r_init_sensor(struct gspca_dev *gspca_dev)
Brian Johnson26e744b2009-07-19 05:52:58 -03001301{
Brian Johnson26e744b2009-07-19 05:52:58 -03001302 struct sd *sd = (struct sd *) gspca_dev;
1303
Jean-François Moined4689b72012-03-19 04:42:45 -03001304 i2c_w1_buf(gspca_dev, hv7131r_init, ARRAY_SIZE(hv7131r_init));
1305 if (gspca_dev->usb_err < 0)
1306 pr_err("HV7131R Sensor initialization failed\n");
1307
Brian Johnson26e744b2009-07-19 05:52:58 -03001308 sd->hstart = 0;
1309 sd->vstart = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001310}
1311
Hans Verkuil63069da2012-05-06 09:28:29 -03001312static void set_cmatrix(struct gspca_dev *gspca_dev,
1313 s32 brightness, s32 contrast, s32 satur, s32 hue)
Brian Johnson26e744b2009-07-19 05:52:58 -03001314{
Hans Verkuil63069da2012-05-06 09:28:29 -03001315 s32 hue_coord, hue_index = 180 + hue;
Brian Johnson26e744b2009-07-19 05:52:58 -03001316 u8 cmatrix[21];
Brian Johnson26e744b2009-07-19 05:52:58 -03001317
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001318 memset(cmatrix, 0, sizeof cmatrix);
Hans Verkuil63069da2012-05-06 09:28:29 -03001319 cmatrix[2] = (contrast * 0x25 / 0x100) + 0x26;
Brian Johnson26e744b2009-07-19 05:52:58 -03001320 cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
1321 cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
Hans Verkuil63069da2012-05-06 09:28:29 -03001322 cmatrix[18] = brightness - 0x80;
Brian Johnson26e744b2009-07-19 05:52:58 -03001323
Jean-François Moinec5224d82012-03-19 04:30:07 -03001324 hue_coord = (hsv_red_x[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001325 cmatrix[6] = hue_coord;
1326 cmatrix[7] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001327
Jean-François Moinec5224d82012-03-19 04:30:07 -03001328 hue_coord = (hsv_red_y[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001329 cmatrix[8] = hue_coord;
1330 cmatrix[9] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001331
Jean-François Moinec5224d82012-03-19 04:30:07 -03001332 hue_coord = (hsv_green_x[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001333 cmatrix[10] = hue_coord;
1334 cmatrix[11] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001335
Jean-François Moinec5224d82012-03-19 04:30:07 -03001336 hue_coord = (hsv_green_y[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001337 cmatrix[12] = hue_coord;
1338 cmatrix[13] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001339
Jean-François Moinec5224d82012-03-19 04:30:07 -03001340 hue_coord = (hsv_blue_x[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001341 cmatrix[14] = hue_coord;
1342 cmatrix[15] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001343
Jean-François Moinec5224d82012-03-19 04:30:07 -03001344 hue_coord = (hsv_blue_y[hue_index] * satur) >> 8;
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001345 cmatrix[16] = hue_coord;
1346 cmatrix[17] = (hue_coord >> 8) & 0x0f;
Brian Johnson26e744b2009-07-19 05:52:58 -03001347
Jean-François Moinec5224d82012-03-19 04:30:07 -03001348 reg_w(gspca_dev, 0x10e1, cmatrix, 21);
Brian Johnson26e744b2009-07-19 05:52:58 -03001349}
1350
Hans Verkuil63069da2012-05-06 09:28:29 -03001351static void set_gamma(struct gspca_dev *gspca_dev, s32 val)
Brian Johnson26e744b2009-07-19 05:52:58 -03001352{
Brian Johnson26e744b2009-07-19 05:52:58 -03001353 u8 gamma[17];
Hans Verkuil63069da2012-05-06 09:28:29 -03001354 u8 gval = val * 0xb8 / 0x100;
Brian Johnson26e744b2009-07-19 05:52:58 -03001355
1356 gamma[0] = 0x0a;
1357 gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
1358 gamma[2] = 0x25 + (gval * (0xee - 0x25) / 0xb8);
1359 gamma[3] = 0x37 + (gval * (0xfa - 0x37) / 0xb8);
1360 gamma[4] = 0x45 + (gval * (0xfc - 0x45) / 0xb8);
1361 gamma[5] = 0x55 + (gval * (0xfb - 0x55) / 0xb8);
1362 gamma[6] = 0x65 + (gval * (0xfc - 0x65) / 0xb8);
1363 gamma[7] = 0x74 + (gval * (0xfd - 0x74) / 0xb8);
1364 gamma[8] = 0x83 + (gval * (0xfe - 0x83) / 0xb8);
1365 gamma[9] = 0x92 + (gval * (0xfc - 0x92) / 0xb8);
1366 gamma[10] = 0xa1 + (gval * (0xfc - 0xa1) / 0xb8);
1367 gamma[11] = 0xb0 + (gval * (0xfc - 0xb0) / 0xb8);
1368 gamma[12] = 0xbf + (gval * (0xfb - 0xbf) / 0xb8);
1369 gamma[13] = 0xce + (gval * (0xfb - 0xce) / 0xb8);
1370 gamma[14] = 0xdf + (gval * (0xfd - 0xdf) / 0xb8);
1371 gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
1372 gamma[16] = 0xf5;
1373
Jean-François Moinec5224d82012-03-19 04:30:07 -03001374 reg_w(gspca_dev, 0x1190, gamma, 17);
Brian Johnson26e744b2009-07-19 05:52:58 -03001375}
1376
Hans Verkuil63069da2012-05-06 09:28:29 -03001377static void set_redblue(struct gspca_dev *gspca_dev, s32 blue, s32 red)
Brian Johnson26e744b2009-07-19 05:52:58 -03001378{
Hans Verkuil63069da2012-05-06 09:28:29 -03001379 reg_w1(gspca_dev, 0x118c, red);
1380 reg_w1(gspca_dev, 0x118f, blue);
Brian Johnson26e744b2009-07-19 05:52:58 -03001381}
1382
Hans Verkuil63069da2012-05-06 09:28:29 -03001383static void set_hvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001384{
Hans Verkuil63069da2012-05-06 09:28:29 -03001385 u8 value, tslb;
Brian Johnson26e744b2009-07-19 05:52:58 -03001386 u16 value2;
1387 struct sd *sd = (struct sd *) gspca_dev;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001388
1389 if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
Hans Verkuil63069da2012-05-06 09:28:29 -03001390 hflip = !hflip;
1391 vflip = !vflip;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001392 }
1393
Brian Johnson26e744b2009-07-19 05:52:58 -03001394 switch (sd->sensor) {
Hans de Goede779b51f2011-02-16 08:17:36 -03001395 case SENSOR_OV7660:
1396 value = 0x01;
1397 if (hflip)
1398 value |= 0x20;
1399 if (vflip) {
1400 value |= 0x10;
1401 sd->vstart = 2;
Jean-François Moineff38d582012-03-19 04:55:16 -03001402 } else {
Hans de Goede779b51f2011-02-16 08:17:36 -03001403 sd->vstart = 3;
Jean-François Moineff38d582012-03-19 04:55:16 -03001404 }
Hans de Goede779b51f2011-02-16 08:17:36 -03001405 reg_w1(gspca_dev, 0x1182, sd->vstart);
1406 i2c_w1(gspca_dev, 0x1e, value);
1407 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001408 case SENSOR_OV9650:
1409 i2c_r1(gspca_dev, 0x1e, &value);
1410 value &= ~0x30;
1411 tslb = 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001412 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001413 value |= 0x20;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001414 if (vflip) {
Brian Johnson26e744b2009-07-19 05:52:58 -03001415 value |= 0x10;
1416 tslb = 0x49;
1417 }
1418 i2c_w1(gspca_dev, 0x1e, value);
1419 i2c_w1(gspca_dev, 0x3a, tslb);
1420 break;
1421 case SENSOR_MT9V111:
1422 case SENSOR_MT9V011:
1423 i2c_r2(gspca_dev, 0x20, &value2);
1424 value2 &= ~0xc0a0;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001425 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001426 value2 |= 0x8080;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001427 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001428 value2 |= 0x4020;
1429 i2c_w2(gspca_dev, 0x20, value2);
1430 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001431 case SENSOR_MT9M112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001432 case SENSOR_MT9M111:
1433 case SENSOR_MT9V112:
1434 i2c_r2(gspca_dev, 0x20, &value2);
1435 value2 &= ~0x0003;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001436 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001437 value2 |= 0x0002;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001438 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001439 value2 |= 0x0001;
1440 i2c_w2(gspca_dev, 0x20, value2);
1441 break;
1442 case SENSOR_HV7131R:
1443 i2c_r1(gspca_dev, 0x01, &value);
1444 value &= ~0x03;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001445 if (vflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001446 value |= 0x01;
Brian Johnson7ddaac72010-03-16 13:58:27 -03001447 if (hflip)
Brian Johnson26e744b2009-07-19 05:52:58 -03001448 value |= 0x02;
1449 i2c_w1(gspca_dev, 0x01, value);
1450 break;
1451 }
Brian Johnson26e744b2009-07-19 05:52:58 -03001452}
1453
Hans Verkuil63069da2012-05-06 09:28:29 -03001454static void set_exposure(struct gspca_dev *gspca_dev, s32 expo)
Brian Johnson26e744b2009-07-19 05:52:58 -03001455{
1456 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001457 u8 exp[8] = {sd->i2c_intf, sd->i2c_addr,
Jean-François Moine4fb81372012-03-24 09:28:39 -03001458 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans Verkuil63069da2012-05-06 09:28:29 -03001459 int expo2;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001460
Jean-François Moine4fb81372012-03-24 09:28:39 -03001461 if (gspca_dev->streaming)
1462 exp[7] = 0x1e;
1463
Brian Johnson26e744b2009-07-19 05:52:58 -03001464 switch (sd->sensor) {
1465 case SENSOR_OV7660:
1466 case SENSOR_OV7670:
Brian Johnson26e744b2009-07-19 05:52:58 -03001467 case SENSOR_OV9655:
1468 case SENSOR_OV9650:
Jean-François Moinea1ac5dc2012-03-24 09:33:42 -03001469 if (expo > 547)
1470 expo2 = 547;
1471 else
1472 expo2 = expo;
1473 exp[0] |= (2 << 4);
1474 exp[2] = 0x10; /* AECH */
1475 exp[3] = expo2 >> 2;
1476 exp[7] = 0x10;
1477 i2c_w(gspca_dev, exp);
1478 exp[2] = 0x04; /* COM1 */
1479 exp[3] = expo2 & 0x0003;
1480 exp[7] = 0x10;
1481 i2c_w(gspca_dev, exp);
1482 expo -= expo2;
1483 exp[7] = 0x1e;
Brian Johnson26e744b2009-07-19 05:52:58 -03001484 exp[0] |= (3 << 4);
Jean-François Moinea1ac5dc2012-03-24 09:33:42 -03001485 exp[2] = 0x2d; /* ADVFL & ADVFH */
Jean-François Moinec5224d82012-03-19 04:30:07 -03001486 exp[3] = expo;
1487 exp[4] = expo >> 8;
Brian Johnson26e744b2009-07-19 05:52:58 -03001488 break;
1489 case SENSOR_MT9M001:
Brian Johnson26e744b2009-07-19 05:52:58 -03001490 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001491 case SENSOR_MT9V011:
1492 exp[0] |= (3 << 4);
1493 exp[2] = 0x09;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001494 exp[3] = expo >> 8;
1495 exp[4] = expo;
Brian Johnson26e744b2009-07-19 05:52:58 -03001496 break;
1497 case SENSOR_HV7131R:
1498 exp[0] |= (4 << 4);
1499 exp[2] = 0x25;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001500 exp[3] = expo >> 5;
1501 exp[4] = expo << 3;
German Galkine10f7312010-03-07 06:19:02 -03001502 exp[5] = 0;
Brian Johnson26e744b2009-07-19 05:52:58 -03001503 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001504 default:
Jean-François Moinec5224d82012-03-19 04:30:07 -03001505 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001506 }
1507 i2c_w(gspca_dev, exp);
Brian Johnson26e744b2009-07-19 05:52:58 -03001508}
1509
Hans Verkuil63069da2012-05-06 09:28:29 -03001510static void set_gain(struct gspca_dev *gspca_dev, s32 g)
Brian Johnson26e744b2009-07-19 05:52:58 -03001511{
1512 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001513 u8 gain[8] = {sd->i2c_intf, sd->i2c_addr,
Jean-François Moine4fb81372012-03-24 09:28:39 -03001514 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Jean-François Moinec5224d82012-03-19 04:30:07 -03001515
Jean-François Moine4fb81372012-03-24 09:28:39 -03001516 if (gspca_dev->streaming)
1517 gain[7] = 0x15; /* or 1d ? */
1518
Brian Johnson26e744b2009-07-19 05:52:58 -03001519 switch (sd->sensor) {
1520 case SENSOR_OV7660:
1521 case SENSOR_OV7670:
1522 case SENSOR_SOI968:
1523 case SENSOR_OV9655:
1524 case SENSOR_OV9650:
1525 gain[0] |= (2 << 4);
Jean-François Moinec5224d82012-03-19 04:30:07 -03001526 gain[3] = ov_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001527 break;
1528 case SENSOR_MT9V011:
Brian Johnson26e744b2009-07-19 05:52:58 -03001529 gain[0] |= (3 << 4);
1530 gain[2] = 0x35;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001531 gain[3] = micron1_gain[g] >> 8;
1532 gain[4] = micron1_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001533 break;
1534 case SENSOR_MT9V112:
Brian Johnson26e744b2009-07-19 05:52:58 -03001535 gain[0] |= (3 << 4);
1536 gain[2] = 0x2f;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001537 gain[3] = micron1_gain[g] >> 8;
1538 gain[4] = micron1_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001539 break;
1540 case SENSOR_MT9M001:
1541 gain[0] |= (3 << 4);
1542 gain[2] = 0x2f;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001543 gain[3] = micron2_gain[g] >> 8;
1544 gain[4] = micron2_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001545 break;
1546 case SENSOR_HV7131R:
1547 gain[0] |= (2 << 4);
1548 gain[2] = 0x30;
Jean-François Moinec5224d82012-03-19 04:30:07 -03001549 gain[3] = hv7131r_gain[g];
Brian Johnson26e744b2009-07-19 05:52:58 -03001550 break;
Brian Johnsone1430472009-09-02 12:39:41 -03001551 default:
Jean-François Moinec5224d82012-03-19 04:30:07 -03001552 return;
Brian Johnson26e744b2009-07-19 05:52:58 -03001553 }
1554 i2c_w(gspca_dev, gain);
Brian Johnson26e744b2009-07-19 05:52:58 -03001555}
1556
Hans Verkuil63069da2012-05-06 09:28:29 -03001557static void set_quality(struct gspca_dev *gspca_dev, s32 val)
Jean-François Moine4c632e42012-03-19 04:35:34 -03001558{
1559 struct sd *sd = (struct sd *) gspca_dev;
1560
Hans Verkuil63069da2012-05-06 09:28:29 -03001561 jpeg_set_qual(sd->jpeg_hdr, val);
Jean-François Moine4c632e42012-03-19 04:35:34 -03001562 reg_w1(gspca_dev, 0x1061, 0x01); /* stop transfer */
1563 reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */
1564 reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
1565 reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
1566 reg_w1(gspca_dev, 0x1061, 0x03); /* restart transfer */
1567 reg_w1(gspca_dev, 0x10e0, sd->fmt);
1568 sd->fmt ^= 0x0c; /* invert QTAB use + write */
1569 reg_w1(gspca_dev, 0x10e0, sd->fmt);
1570}
1571
Brian Johnson26e744b2009-07-19 05:52:58 -03001572#ifdef CONFIG_VIDEO_ADV_DEBUG
1573static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
1574 struct v4l2_dbg_register *reg)
1575{
1576 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03001577
Brian Johnson26e744b2009-07-19 05:52:58 -03001578 switch (reg->match.type) {
1579 case V4L2_CHIP_MATCH_HOST:
1580 if (reg->match.addr != 0)
1581 return -EINVAL;
1582 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1583 return -EINVAL;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001584 reg_r(gspca_dev, reg->reg, 1);
Brian Johnson26e744b2009-07-19 05:52:58 -03001585 reg->val = gspca_dev->usb_buf[0];
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001586 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001587 case V4L2_CHIP_MATCH_I2C_ADDR:
1588 if (reg->match.addr != sd->i2c_addr)
1589 return -EINVAL;
1590 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001591 sd->sensor <= SENSOR_MT9M112) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001592 i2c_r2(gspca_dev, reg->reg, (u16 *) &reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001593 } else {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001594 i2c_r1(gspca_dev, reg->reg, (u8 *) &reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001595 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001596 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001597 }
1598 return -EINVAL;
1599}
1600
1601static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
1602 struct v4l2_dbg_register *reg)
1603{
1604 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03001605
Brian Johnson26e744b2009-07-19 05:52:58 -03001606 switch (reg->match.type) {
1607 case V4L2_CHIP_MATCH_HOST:
1608 if (reg->match.addr != 0)
1609 return -EINVAL;
1610 if (reg->reg < 0x1000 || reg->reg > 0x11ff)
1611 return -EINVAL;
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001612 reg_w1(gspca_dev, reg->reg, reg->val);
1613 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001614 case V4L2_CHIP_MATCH_I2C_ADDR:
1615 if (reg->match.addr != sd->i2c_addr)
1616 return -EINVAL;
1617 if (sd->sensor >= SENSOR_MT9V011 &&
Brian Johnsone99ac542010-03-16 13:58:28 -03001618 sd->sensor <= SENSOR_MT9M112) {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001619 i2c_w2(gspca_dev, reg->reg, reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001620 } else {
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001621 i2c_w1(gspca_dev, reg->reg, reg->val);
Brian Johnson26e744b2009-07-19 05:52:58 -03001622 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001623 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001624 }
1625 return -EINVAL;
1626}
1627#endif
1628
1629static int sd_chip_ident(struct gspca_dev *gspca_dev,
1630 struct v4l2_dbg_chip_ident *chip)
1631{
1632 struct sd *sd = (struct sd *) gspca_dev;
1633
1634 switch (chip->match.type) {
1635 case V4L2_CHIP_MATCH_HOST:
1636 if (chip->match.addr != 0)
1637 return -EINVAL;
1638 chip->revision = 0;
1639 chip->ident = V4L2_IDENT_SN9C20X;
1640 return 0;
1641 case V4L2_CHIP_MATCH_I2C_ADDR:
1642 if (chip->match.addr != sd->i2c_addr)
1643 return -EINVAL;
1644 chip->revision = 0;
1645 chip->ident = i2c_ident[sd->sensor];
1646 return 0;
1647 }
1648 return -EINVAL;
1649}
1650
1651static int sd_config(struct gspca_dev *gspca_dev,
1652 const struct usb_device_id *id)
1653{
1654 struct sd *sd = (struct sd *) gspca_dev;
1655 struct cam *cam;
1656
1657 cam = &gspca_dev->cam;
Hans de Goedeeb3fb7c2012-01-01 16:35:01 -03001658 cam->needs_full_bandwidth = 1;
Brian Johnson26e744b2009-07-19 05:52:58 -03001659
Jean-François Moineff38d582012-03-19 04:55:16 -03001660 sd->sensor = id->driver_info >> 8;
1661 sd->i2c_addr = id->driver_info;
1662 sd->flags = id->driver_info >> 16;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001663 sd->i2c_intf = 0x80; /* i2c 100 Kb/s */
Brian Johnson26e744b2009-07-19 05:52:58 -03001664
1665 switch (sd->sensor) {
Brian Johnsone99ac542010-03-16 13:58:28 -03001666 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03001667 case SENSOR_MT9M111:
Brian Johnson26e744b2009-07-19 05:52:58 -03001668 case SENSOR_OV9650:
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001669 case SENSOR_SOI968:
Brian Johnson26e744b2009-07-19 05:52:58 -03001670 cam->cam_mode = sxga_mode;
1671 cam->nmodes = ARRAY_SIZE(sxga_mode);
1672 break;
Mauro Carvalho Chehabd162e7a2010-12-07 19:39:33 -03001673 case SENSOR_MT9M001:
1674 cam->cam_mode = mono_mode;
1675 cam->nmodes = ARRAY_SIZE(mono_mode);
1676 break;
Jean-François Moinec4407fe2012-03-24 09:23:56 -03001677 case SENSOR_HV7131R:
1678 sd->i2c_intf = 0x81; /* i2c 400 Kb/s */
1679 /* fall thru */
Brian Johnson26e744b2009-07-19 05:52:58 -03001680 default:
1681 cam->cam_mode = vga_mode;
1682 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moinede2d1542009-12-19 07:03:43 -03001683 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001684 }
1685
1686 sd->old_step = 0;
1687 sd->older_step = 0;
1688 sd->exposure_step = 16;
1689
Jean-François Moine92dcffc2012-03-19 04:47:24 -03001690 INIT_WORK(&sd->work, qual_upd);
Brian Johnson26e744b2009-07-19 05:52:58 -03001691
Brian Johnson26e744b2009-07-19 05:52:58 -03001692 return 0;
1693}
1694
Hans Verkuil63069da2012-05-06 09:28:29 -03001695static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
1696{
1697 struct sd *sd = container_of(ctrl->handler, struct sd, ctrl_handler);
1698 struct gspca_dev *gspca_dev = &sd->gspca_dev;
1699
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:
1708 set_cmatrix(&sd->gspca_dev, sd->brightness->val,
1709 sd->contrast->val, sd->saturation->val, sd->hue->val);
1710 break;
1711 case V4L2_CID_GAMMA:
1712 set_gamma(&sd->gspca_dev, ctrl->val);
1713 break;
1714 /* blue/red balance cluster */
1715 case V4L2_CID_BLUE_BALANCE:
1716 set_redblue(&sd->gspca_dev, sd->blue->val, sd->red->val);
1717 break;
1718 /* h/vflip cluster */
1719 case V4L2_CID_HFLIP:
1720 set_hvflip(&sd->gspca_dev, sd->hflip->val, sd->vflip->val);
1721 break;
1722 /* standalone exposure control */
1723 case V4L2_CID_EXPOSURE:
1724 set_exposure(&sd->gspca_dev, ctrl->val);
1725 break;
1726 /* standalone gain control */
1727 case V4L2_CID_GAIN:
1728 set_gain(&sd->gspca_dev, ctrl->val);
1729 break;
1730 /* autogain + exposure or gain control cluster */
1731 case V4L2_CID_AUTOGAIN:
1732 if (sd->sensor == SENSOR_SOI968)
1733 set_gain(&sd->gspca_dev, sd->gain->val);
1734 else
1735 set_exposure(&sd->gspca_dev, sd->exposure->val);
1736 break;
1737 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
1738 set_quality(&sd->gspca_dev, ctrl->val);
1739 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;
1751 struct v4l2_ctrl_handler *hdl = &sd->ctrl_handler;
1752
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);
1764 v4l2_ctrl_cluster(4, &sd->brightness);
1765
1766 sd->gamma = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1767 V4L2_CID_GAMMA, 0, 255, 1, 0x10);
1768
1769 sd->blue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1770 V4L2_CID_BLUE_BALANCE, 0, 127, 1, 0x28);
1771 sd->red = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1772 V4L2_CID_RED_BALANCE, 0, 127, 1, 0x28);
1773 v4l2_ctrl_cluster(2, &sd->blue);
1774
1775 if (sd->sensor != SENSOR_OV9655 && sd->sensor != SENSOR_SOI968 &&
1776 sd->sensor != SENSOR_OV7670 && sd->sensor != SENSOR_MT9M001 &&
1777 sd->sensor != SENSOR_MT9VPRB) {
1778 sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1779 V4L2_CID_HFLIP, 0, 1, 1, 0);
1780 sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1781 V4L2_CID_VFLIP, 0, 1, 1, 0);
1782 v4l2_ctrl_cluster(2, &sd->hflip);
1783 }
1784
1785 if (sd->sensor != SENSOR_SOI968 && sd->sensor != SENSOR_MT9VPRB &&
1786 sd->sensor != SENSOR_MT9M112 && sd->sensor != SENSOR_MT9M111 &&
1787 sd->sensor != SENSOR_MT9V111)
1788 sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1789 V4L2_CID_EXPOSURE, 0, 0x1780, 1, 0x33);
1790
1791 if (sd->sensor != SENSOR_MT9VPRB && sd->sensor != SENSOR_MT9M112 &&
1792 sd->sensor != SENSOR_MT9M111 && sd->sensor != SENSOR_MT9V111) {
1793 sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1794 V4L2_CID_GAIN, 0, 28, 1, 0);
1795 sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1796 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
1797 if (sd->sensor == SENSOR_SOI968)
1798 /* this sensor doesn't have the exposure control and
1799 autogain is clustered with gain instead. This works
1800 because sd->exposure == NULL. */
1801 v4l2_ctrl_auto_cluster(3, &sd->autogain, 0, false);
1802 else
1803 /* Otherwise autogain is clustered with exposure. */
1804 v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
1805 }
1806
1807 sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1808 V4L2_CID_JPEG_COMPRESSION_QUALITY, 50, 90, 1, 80);
1809 if (hdl->error) {
1810 pr_err("Could not initialize controls\n");
1811 return hdl->error;
1812 }
1813 return 0;
1814}
1815
Brian Johnson26e744b2009-07-19 05:52:58 -03001816static int sd_init(struct gspca_dev *gspca_dev)
1817{
1818 struct sd *sd = (struct sd *) gspca_dev;
1819 int i;
1820 u8 value;
1821 u8 i2c_init[9] =
1822 {0x80, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03};
1823
1824 for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
1825 value = bridge_init[i][1];
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001826 reg_w(gspca_dev, bridge_init[i][0], &value, 1);
1827 if (gspca_dev->usb_err < 0) {
Joe Perches91f58422011-08-21 19:56:55 -03001828 pr_err("Device initialization failed\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001829 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001830 }
1831 }
1832
Brian Johnson0c045eb2010-03-16 13:58:27 -03001833 if (sd->flags & LED_REVERSE)
1834 reg_w1(gspca_dev, 0x1006, 0x00);
1835 else
1836 reg_w1(gspca_dev, 0x1006, 0x20);
1837
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001838 reg_w(gspca_dev, 0x10c0, i2c_init, 9);
1839 if (gspca_dev->usb_err < 0) {
Joe Perches91f58422011-08-21 19:56:55 -03001840 pr_err("Device initialization failed\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001841 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001842 }
1843
1844 switch (sd->sensor) {
1845 case SENSOR_OV9650:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001846 ov9650_init_sensor(gspca_dev);
1847 if (gspca_dev->usb_err < 0)
1848 break;
Joe Perches91f58422011-08-21 19:56:55 -03001849 pr_info("OV9650 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001850 break;
1851 case SENSOR_OV9655:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001852 ov9655_init_sensor(gspca_dev);
1853 if (gspca_dev->usb_err < 0)
1854 break;
Joe Perches91f58422011-08-21 19:56:55 -03001855 pr_info("OV9655 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001856 break;
1857 case SENSOR_SOI968:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001858 soi968_init_sensor(gspca_dev);
1859 if (gspca_dev->usb_err < 0)
1860 break;
Joe Perches91f58422011-08-21 19:56:55 -03001861 pr_info("SOI968 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001862 break;
1863 case SENSOR_OV7660:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001864 ov7660_init_sensor(gspca_dev);
1865 if (gspca_dev->usb_err < 0)
1866 break;
Joe Perches91f58422011-08-21 19:56:55 -03001867 pr_info("OV7660 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001868 break;
1869 case SENSOR_OV7670:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001870 ov7670_init_sensor(gspca_dev);
1871 if (gspca_dev->usb_err < 0)
1872 break;
Joe Perches91f58422011-08-21 19:56:55 -03001873 pr_info("OV7670 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001874 break;
1875 case SENSOR_MT9VPRB:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001876 mt9v_init_sensor(gspca_dev);
1877 if (gspca_dev->usb_err < 0)
1878 break;
Jean-François Moineff38d582012-03-19 04:55:16 -03001879 pr_info("MT9VPRB sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001880 break;
1881 case SENSOR_MT9M111:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001882 mt9m111_init_sensor(gspca_dev);
1883 if (gspca_dev->usb_err < 0)
1884 break;
Joe Perches91f58422011-08-21 19:56:55 -03001885 pr_info("MT9M111 sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001886 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001887 case SENSOR_MT9M112:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001888 mt9m112_init_sensor(gspca_dev);
1889 if (gspca_dev->usb_err < 0)
1890 break;
Joe Perches91f58422011-08-21 19:56:55 -03001891 pr_info("MT9M112 sensor detected\n");
Brian Johnsone99ac542010-03-16 13:58:28 -03001892 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001893 case SENSOR_MT9M001:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001894 mt9m001_init_sensor(gspca_dev);
1895 if (gspca_dev->usb_err < 0)
1896 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001897 break;
1898 case SENSOR_HV7131R:
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001899 hv7131r_init_sensor(gspca_dev);
1900 if (gspca_dev->usb_err < 0)
1901 break;
Joe Perches91f58422011-08-21 19:56:55 -03001902 pr_info("HV7131R sensor detected\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03001903 break;
1904 default:
Jean-François Moineff38d582012-03-19 04:55:16 -03001905 pr_err("Unsupported sensor\n");
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001906 gspca_dev->usb_err = -ENODEV;
Brian Johnson26e744b2009-07-19 05:52:58 -03001907 }
Jean-François Moinefe86ec72012-03-19 04:32:15 -03001908 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03001909}
1910
1911static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
1912{
1913 struct sd *sd = (struct sd *) gspca_dev;
1914 u8 value;
Jean-François Moineff38d582012-03-19 04:55:16 -03001915
Brian Johnson26e744b2009-07-19 05:52:58 -03001916 switch (sd->sensor) {
Brian Johnsone8b7acc2009-09-02 13:14:41 -03001917 case SENSOR_SOI968:
1918 if (mode & MODE_SXGA) {
1919 i2c_w1(gspca_dev, 0x17, 0x1d);
1920 i2c_w1(gspca_dev, 0x18, 0xbd);
1921 i2c_w1(gspca_dev, 0x19, 0x01);
1922 i2c_w1(gspca_dev, 0x1a, 0x81);
1923 i2c_w1(gspca_dev, 0x12, 0x00);
1924 sd->hstart = 140;
1925 sd->vstart = 19;
1926 } else {
1927 i2c_w1(gspca_dev, 0x17, 0x13);
1928 i2c_w1(gspca_dev, 0x18, 0x63);
1929 i2c_w1(gspca_dev, 0x19, 0x01);
1930 i2c_w1(gspca_dev, 0x1a, 0x79);
1931 i2c_w1(gspca_dev, 0x12, 0x40);
1932 sd->hstart = 60;
1933 sd->vstart = 11;
1934 }
1935 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001936 case SENSOR_OV9650:
1937 if (mode & MODE_SXGA) {
1938 i2c_w1(gspca_dev, 0x17, 0x1b);
1939 i2c_w1(gspca_dev, 0x18, 0xbc);
1940 i2c_w1(gspca_dev, 0x19, 0x01);
1941 i2c_w1(gspca_dev, 0x1a, 0x82);
1942 i2c_r1(gspca_dev, 0x12, &value);
1943 i2c_w1(gspca_dev, 0x12, value & 0x07);
1944 } else {
1945 i2c_w1(gspca_dev, 0x17, 0x24);
1946 i2c_w1(gspca_dev, 0x18, 0xc5);
1947 i2c_w1(gspca_dev, 0x19, 0x00);
1948 i2c_w1(gspca_dev, 0x1a, 0x3c);
1949 i2c_r1(gspca_dev, 0x12, &value);
1950 i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
1951 }
1952 break;
Brian Johnsone99ac542010-03-16 13:58:28 -03001953 case SENSOR_MT9M112:
Brian Johnson4d708a52009-09-03 19:10:15 -03001954 case SENSOR_MT9M111:
1955 if (mode & MODE_SXGA) {
1956 i2c_w2(gspca_dev, 0xf0, 0x0002);
1957 i2c_w2(gspca_dev, 0xc8, 0x970b);
1958 i2c_w2(gspca_dev, 0xf0, 0x0000);
1959 } else {
1960 i2c_w2(gspca_dev, 0xf0, 0x0002);
1961 i2c_w2(gspca_dev, 0xc8, 0x8000);
1962 i2c_w2(gspca_dev, 0xf0, 0x0000);
1963 }
1964 break;
Brian Johnson26e744b2009-07-19 05:52:58 -03001965 }
1966}
1967
Hans de Goeded80dd5d2012-01-01 16:03:37 -03001968static int sd_isoc_init(struct gspca_dev *gspca_dev)
1969{
1970 struct usb_interface *intf;
1971 u32 flags = gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv;
1972
1973 /*
1974 * When using the SN9C20X_I420 fmt the sn9c20x needs more bandwidth
1975 * than our regular bandwidth calculations reserve, so we force the
1976 * use of a specific altsetting when using the SN9C20X_I420 fmt.
1977 */
1978 if (!(flags & (MODE_RAW | MODE_JPEG))) {
1979 intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
1980
1981 if (intf->num_altsetting != 9) {
1982 pr_warn("sn9c20x camera with unknown number of alt "
1983 "settings (%d), please report!\n",
1984 intf->num_altsetting);
1985 gspca_dev->alt = intf->num_altsetting;
1986 return 0;
1987 }
1988
1989 switch (gspca_dev->width) {
1990 case 160: /* 160x120 */
1991 gspca_dev->alt = 2;
1992 break;
1993 case 320: /* 320x240 */
1994 gspca_dev->alt = 6;
1995 break;
1996 default: /* >= 640x480 */
1997 gspca_dev->alt = 9;
Jean-François Moineff38d582012-03-19 04:55:16 -03001998 break;
Hans de Goeded80dd5d2012-01-01 16:03:37 -03001999 }
2000 }
2001
2002 return 0;
2003}
2004
Brian Johnson26e744b2009-07-19 05:52:58 -03002005#define HW_WIN(mode, hstart, vstart) \
Jean-Francois Moine83955552009-12-12 06:58:01 -03002006((const u8 []){hstart, 0, vstart, 0, \
Brian Johnson26e744b2009-07-19 05:52:58 -03002007(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
2008(mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)})
2009
2010#define CLR_WIN(width, height) \
2011((const u8 [])\
2012{0, width >> 2, 0, height >> 1,\
2013((width >> 10) & 0x01) | ((height >> 8) & 0x6)})
2014
2015static int sd_start(struct gspca_dev *gspca_dev)
2016{
2017 struct sd *sd = (struct sd *) gspca_dev;
2018 int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
2019 int width = gspca_dev->width;
2020 int height = gspca_dev->height;
2021 u8 fmt, scale = 0;
2022
Brian Johnson26e744b2009-07-19 05:52:58 -03002023 jpeg_define(sd->jpeg_hdr, height, width,
2024 0x21);
Hans Verkuil63069da2012-05-06 09:28:29 -03002025 jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual));
Brian Johnson26e744b2009-07-19 05:52:58 -03002026
2027 if (mode & MODE_RAW)
2028 fmt = 0x2d;
2029 else if (mode & MODE_JPEG)
Jean-François Moine4c632e42012-03-19 04:35:34 -03002030 fmt = 0x24;
Brian Johnson26e744b2009-07-19 05:52:58 -03002031 else
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002032 fmt = 0x2f; /* YUV 420 */
Jean-François Moine4c632e42012-03-19 04:35:34 -03002033 sd->fmt = fmt;
Brian Johnson26e744b2009-07-19 05:52:58 -03002034
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002035 switch (mode & SCALE_MASK) {
2036 case SCALE_1280x1024:
Brian Johnson26e744b2009-07-19 05:52:58 -03002037 scale = 0xc0;
Joe Perches91f58422011-08-21 19:56:55 -03002038 pr_info("Set 1280x1024\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002039 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002040 case SCALE_640x480:
Brian Johnson26e744b2009-07-19 05:52:58 -03002041 scale = 0x80;
Joe Perches91f58422011-08-21 19:56:55 -03002042 pr_info("Set 640x480\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002043 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002044 case SCALE_320x240:
Brian Johnson26e744b2009-07-19 05:52:58 -03002045 scale = 0x90;
Joe Perches91f58422011-08-21 19:56:55 -03002046 pr_info("Set 320x240\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002047 break;
Mauro Carvalho Chehab86701c12010-12-07 14:47:10 -03002048 case SCALE_160x120:
Brian Johnson26e744b2009-07-19 05:52:58 -03002049 scale = 0xa0;
Joe Perches91f58422011-08-21 19:56:55 -03002050 pr_info("Set 160x120\n");
Brian Johnson26e744b2009-07-19 05:52:58 -03002051 break;
2052 }
2053
2054 configure_sensor_output(gspca_dev, mode);
Jean-François Moine9a731a32010-06-04 05:26:42 -03002055 reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
2056 reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
Brian Johnson26e744b2009-07-19 05:52:58 -03002057 reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
2058 reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
2059 reg_w1(gspca_dev, 0x1189, scale);
2060 reg_w1(gspca_dev, 0x10e0, fmt);
2061
Hans Verkuil63069da2012-05-06 09:28:29 -03002062 set_cmatrix(gspca_dev, v4l2_ctrl_g_ctrl(sd->brightness),
2063 v4l2_ctrl_g_ctrl(sd->contrast),
2064 v4l2_ctrl_g_ctrl(sd->saturation),
2065 v4l2_ctrl_g_ctrl(sd->hue));
2066 set_gamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma));
2067 set_redblue(gspca_dev, v4l2_ctrl_g_ctrl(sd->blue),
2068 v4l2_ctrl_g_ctrl(sd->red));
2069 set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
2070 set_exposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure));
2071 set_hvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip),
2072 v4l2_ctrl_g_ctrl(sd->vflip));
Brian Johnson26e744b2009-07-19 05:52:58 -03002073
Brian Johnson0c045eb2010-03-16 13:58:27 -03002074 reg_w1(gspca_dev, 0x1007, 0x20);
Jean-François Moineccbaba42012-03-19 04:51:30 -03002075 reg_w1(gspca_dev, 0x1061, 0x03);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002076
2077 /* if JPEG, prepare the compression quality update */
2078 if (mode & MODE_JPEG) {
2079 sd->pktsz = sd->npkt = 0;
2080 sd->nchg = 0;
2081 sd->work_thread =
2082 create_singlethread_workqueue(KBUILD_MODNAME);
2083 }
2084
Jean-François Moinefe86ec72012-03-19 04:32:15 -03002085 return gspca_dev->usb_err;
Brian Johnson26e744b2009-07-19 05:52:58 -03002086}
2087
2088static void sd_stopN(struct gspca_dev *gspca_dev)
2089{
Brian Johnson0c045eb2010-03-16 13:58:27 -03002090 reg_w1(gspca_dev, 0x1007, 0x00);
Jean-François Moineccbaba42012-03-19 04:51:30 -03002091 reg_w1(gspca_dev, 0x1061, 0x01);
Brian Johnson26e744b2009-07-19 05:52:58 -03002092}
2093
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002094/* called on streamoff with alt==0 and on disconnect */
2095/* the usb_lock is held at entry - restore on exit */
2096static void sd_stop0(struct gspca_dev *gspca_dev)
2097{
2098 struct sd *sd = (struct sd *) gspca_dev;
2099
2100 if (sd->work_thread != NULL) {
2101 mutex_unlock(&gspca_dev->usb_lock);
2102 destroy_workqueue(sd->work_thread);
2103 mutex_lock(&gspca_dev->usb_lock);
2104 sd->work_thread = NULL;
2105 }
2106}
2107
Brian Johnsone1430472009-09-02 12:39:41 -03002108static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
Brian Johnson26e744b2009-07-19 05:52:58 -03002109{
2110 struct sd *sd = (struct sd *) gspca_dev;
Hans Verkuil63069da2012-05-06 09:28:29 -03002111 s32 cur_exp = v4l2_ctrl_g_ctrl(sd->exposure);
2112 s32 max = sd->exposure->maximum - sd->exposure_step;
2113 s32 min = sd->exposure->minimum + sd->exposure_step;
Brian Johnsone1430472009-09-02 12:39:41 -03002114 s16 new_exp;
Brian Johnson26e744b2009-07-19 05:52:58 -03002115
2116 /*
2117 * some hardcoded values are present
2118 * like those for maximal/minimal exposure
2119 * and exposure steps
2120 */
2121 if (avg_lum < MIN_AVG_LUM) {
Hans Verkuil63069da2012-05-06 09:28:29 -03002122 if (cur_exp > max)
Brian Johnson26e744b2009-07-19 05:52:58 -03002123 return;
2124
Hans Verkuil63069da2012-05-06 09:28:29 -03002125 new_exp = cur_exp + sd->exposure_step;
2126 if (new_exp > max)
2127 new_exp = max;
2128 if (new_exp < min)
2129 new_exp = min;
2130 v4l2_ctrl_s_ctrl(sd->exposure, new_exp);
Brian Johnson26e744b2009-07-19 05:52:58 -03002131
2132 sd->older_step = sd->old_step;
2133 sd->old_step = 1;
2134
2135 if (sd->old_step ^ sd->older_step)
2136 sd->exposure_step /= 2;
2137 else
2138 sd->exposure_step += 2;
2139 }
2140 if (avg_lum > MAX_AVG_LUM) {
Hans Verkuil63069da2012-05-06 09:28:29 -03002141 if (cur_exp < min)
Brian Johnson26e744b2009-07-19 05:52:58 -03002142 return;
Hans Verkuil63069da2012-05-06 09:28:29 -03002143 new_exp = cur_exp - sd->exposure_step;
2144 if (new_exp > max)
2145 new_exp = max;
2146 if (new_exp < min)
2147 new_exp = min;
2148 v4l2_ctrl_s_ctrl(sd->exposure, new_exp);
Brian Johnson26e744b2009-07-19 05:52:58 -03002149 sd->older_step = sd->old_step;
2150 sd->old_step = 0;
2151
2152 if (sd->old_step ^ sd->older_step)
2153 sd->exposure_step /= 2;
2154 else
2155 sd->exposure_step += 2;
2156 }
2157}
2158
Brian Johnsone1430472009-09-02 12:39:41 -03002159static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
2160{
2161 struct sd *sd = (struct sd *) gspca_dev;
Hans Verkuil63069da2012-05-06 09:28:29 -03002162 s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain);
Brian Johnsone1430472009-09-02 12:39:41 -03002163
Hans Verkuil63069da2012-05-06 09:28:29 -03002164 if (avg_lum < MIN_AVG_LUM && cur_gain < sd->gain->maximum)
2165 v4l2_ctrl_s_ctrl(sd->gain, cur_gain + 1);
2166 if (avg_lum > MAX_AVG_LUM && cur_gain > sd->gain->minimum)
2167 v4l2_ctrl_s_ctrl(sd->gain, cur_gain - 1);
Brian Johnsone1430472009-09-02 12:39:41 -03002168}
2169
2170static void sd_dqcallback(struct gspca_dev *gspca_dev)
2171{
2172 struct sd *sd = (struct sd *) gspca_dev;
2173 int avg_lum;
2174
Hans Verkuil63069da2012-05-06 09:28:29 -03002175 if (!v4l2_ctrl_g_ctrl(sd->autogain))
Brian Johnsone1430472009-09-02 12:39:41 -03002176 return;
2177
2178 avg_lum = atomic_read(&sd->avg_lum);
2179 if (sd->sensor == SENSOR_SOI968)
2180 do_autogain(gspca_dev, avg_lum);
2181 else
2182 do_autoexposure(gspca_dev, avg_lum);
2183}
2184
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002185/* JPEG quality update */
2186/* This function is executed from a work queue. */
2187static void qual_upd(struct work_struct *work)
2188{
2189 struct sd *sd = container_of(work, struct sd, work);
2190 struct gspca_dev *gspca_dev = &sd->gspca_dev;
Hans Verkuil63069da2012-05-06 09:28:29 -03002191 s32 qual = v4l2_ctrl_g_ctrl(sd->jpegqual);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002192
2193 mutex_lock(&gspca_dev->usb_lock);
Hans Verkuil63069da2012-05-06 09:28:29 -03002194 PDEBUG(D_STREAM, "qual_upd %d%%", qual);
2195 set_quality(gspca_dev, qual);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002196 mutex_unlock(&gspca_dev->usb_lock);
2197}
2198
Jean-François Moine28566432010-10-01 07:33:26 -03002199#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002200static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
2201 u8 *data, /* interrupt packet */
2202 int len) /* interrupt packet length */
2203{
2204 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03002205
Brian Johnson33ddc162010-04-18 21:42:40 -03002206 if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
Jean-François Moineff38d582012-03-19 04:55:16 -03002207 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
2208 input_sync(gspca_dev->input_dev);
2209 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
2210 input_sync(gspca_dev->input_dev);
2211 return 0;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002212 }
Jean-François Moineff38d582012-03-19 04:55:16 -03002213 return -EINVAL;
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002214}
2215#endif
2216
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002217/* check the JPEG compression */
2218static void transfer_check(struct gspca_dev *gspca_dev,
2219 u8 *data)
2220{
2221 struct sd *sd = (struct sd *) gspca_dev;
2222 int new_qual, r;
2223
2224 new_qual = 0;
2225
2226 /* if USB error, discard the frame and decrease the quality */
2227 if (data[6] & 0x08) { /* USB FIFO full */
2228 gspca_dev->last_packet_type = DISCARD_PACKET;
2229 new_qual = -5;
2230 } else {
2231
2232 /* else, compute the filling rate and a new JPEG quality */
2233 r = (sd->pktsz * 100) /
2234 (sd->npkt *
2235 gspca_dev->urb[0]->iso_frame_desc[0].length);
2236 if (r >= 85)
2237 new_qual = -3;
2238 else if (r < 75)
2239 new_qual = 2;
2240 }
2241 if (new_qual != 0) {
2242 sd->nchg += new_qual;
2243 if (sd->nchg < -6 || sd->nchg >= 12) {
Hans Verkuil63069da2012-05-06 09:28:29 -03002244 /* Note: we are in interrupt context, so we can't
2245 use v4l2_ctrl_g/s_ctrl here. Access the value
2246 directly instead. */
2247 s32 curqual = sd->jpegqual->cur.val;
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002248 sd->nchg = 0;
Hans Verkuil63069da2012-05-06 09:28:29 -03002249 new_qual += curqual;
2250 if (new_qual < sd->jpegqual->minimum)
2251 new_qual = sd->jpegqual->minimum;
2252 else if (new_qual > sd->jpegqual->maximum)
2253 new_qual = sd->jpegqual->maximum;
2254 if (new_qual != curqual) {
2255 sd->jpegqual->cur.val = new_qual;
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002256 queue_work(sd->work_thread, &sd->work);
2257 }
2258 }
2259 } else {
2260 sd->nchg = 0;
2261 }
2262 sd->pktsz = sd->npkt = 0;
2263}
2264
Brian Johnson26e744b2009-07-19 05:52:58 -03002265static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Brian Johnson26e744b2009-07-19 05:52:58 -03002266 u8 *data, /* isoc packet */
2267 int len) /* iso packet length */
2268{
2269 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineff38d582012-03-19 04:55:16 -03002270 int avg_lum, is_jpeg;
Jean-François Moinedae1de62012-03-24 09:20:25 -03002271 static const u8 frame_header[] =
Brian Johnson26e744b2009-07-19 05:52:58 -03002272 {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
Jean-François Moineff38d582012-03-19 04:55:16 -03002273
2274 is_jpeg = (sd->fmt & 0x03) == 0;
Jean-François Moine1f42df02012-03-19 04:22:44 -03002275 if (len >= 64 && memcmp(data, frame_header, 6) == 0) {
Brian Johnson26e744b2009-07-19 05:52:58 -03002276 avg_lum = ((data[35] >> 2) & 3) |
2277 (data[20] << 2) |
2278 (data[19] << 10);
2279 avg_lum += ((data[35] >> 4) & 3) |
2280 (data[22] << 2) |
2281 (data[21] << 10);
2282 avg_lum += ((data[35] >> 6) & 3) |
2283 (data[24] << 2) |
2284 (data[23] << 10);
2285 avg_lum += (data[36] & 3) |
2286 (data[26] << 2) |
2287 (data[25] << 10);
2288 avg_lum += ((data[36] >> 2) & 3) |
2289 (data[28] << 2) |
2290 (data[27] << 10);
2291 avg_lum += ((data[36] >> 4) & 3) |
2292 (data[30] << 2) |
2293 (data[29] << 10);
2294 avg_lum += ((data[36] >> 6) & 3) |
2295 (data[32] << 2) |
2296 (data[31] << 10);
2297 avg_lum += ((data[44] >> 4) & 3) |
2298 (data[34] << 2) |
2299 (data[33] << 10);
2300 avg_lum >>= 9;
2301 atomic_set(&sd->avg_lum, avg_lum);
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002302
Jean-François Moineff38d582012-03-19 04:55:16 -03002303 if (is_jpeg)
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002304 transfer_check(gspca_dev, data);
2305
Jean-François Moine04d174e2010-09-13 05:22:37 -03002306 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Jean-François Moine1f42df02012-03-19 04:22:44 -03002307 len -= 64;
2308 if (len == 0)
2309 return;
2310 data += 64;
Brian Johnson26e744b2009-07-19 05:52:58 -03002311 }
2312 if (gspca_dev->last_packet_type == LAST_PACKET) {
Jean-François Moineff38d582012-03-19 04:55:16 -03002313 if (is_jpeg) {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002314 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002315 sd->jpeg_hdr, JPEG_HDR_SZ);
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002316 gspca_frame_add(gspca_dev, INTER_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002317 data, len);
2318 } else {
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002319 gspca_frame_add(gspca_dev, FIRST_PACKET,
Brian Johnson26e744b2009-07-19 05:52:58 -03002320 data, len);
2321 }
2322 } else {
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002323 /* if JPEG, count the packets and their size */
Jean-François Moineff38d582012-03-19 04:55:16 -03002324 if (is_jpeg) {
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002325 sd->npkt++;
2326 sd->pktsz += len;
2327 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -03002328 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Brian Johnson26e744b2009-07-19 05:52:58 -03002329 }
2330}
2331
2332/* sub-driver description */
2333static const struct sd_desc sd_desc = {
Jean-François Moineff38d582012-03-19 04:55:16 -03002334 .name = KBUILD_MODNAME,
Brian Johnson26e744b2009-07-19 05:52:58 -03002335 .config = sd_config,
2336 .init = sd_init,
Hans Verkuil63069da2012-05-06 09:28:29 -03002337 .init_controls = sd_init_controls,
Hans de Goeded80dd5d2012-01-01 16:03:37 -03002338 .isoc_init = sd_isoc_init,
Brian Johnson26e744b2009-07-19 05:52:58 -03002339 .start = sd_start,
2340 .stopN = sd_stopN,
Jean-François Moine92dcffc2012-03-19 04:47:24 -03002341 .stop0 = sd_stop0,
Brian Johnson26e744b2009-07-19 05:52:58 -03002342 .pkt_scan = sd_pkt_scan,
Jean-François Moine28566432010-10-01 07:33:26 -03002343#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002344 .int_pkt_scan = sd_int_pkt_scan,
2345#endif
Brian Johnsone1430472009-09-02 12:39:41 -03002346 .dq_callback = sd_dqcallback,
Brian Johnson26e744b2009-07-19 05:52:58 -03002347#ifdef CONFIG_VIDEO_ADV_DEBUG
2348 .set_register = sd_dbg_s_register,
2349 .get_register = sd_dbg_g_register,
2350#endif
2351 .get_chip_ident = sd_chip_ident,
2352};
2353
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002354#define SN9C20X(sensor, i2c_addr, flags) \
Brian Johnson0c045eb2010-03-16 13:58:27 -03002355 .driver_info = ((flags & 0xff) << 16) \
Brian Johnson26e744b2009-07-19 05:52:58 -03002356 | (SENSOR_ ## sensor << 8) \
2357 | (i2c_addr)
2358
Jean-François Moine95c967c2011-01-13 05:20:29 -03002359static const struct usb_device_id device_table[] = {
Brian Johnson26e744b2009-07-19 05:52:58 -03002360 {USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
2361 {USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
2362 {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002363 {USB_DEVICE(0x0c45, 0x624c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002364 {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30, LED_REVERSE)},
2365 {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30,
2366 (FLIP_DETECT | HAS_NO_BUTTON))},
Brian Johnson26e744b2009-07-19 05:52:58 -03002367 {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
2368 {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
2369 {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},
2370 {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)},
Hans de Goede779b51f2011-02-16 08:17:36 -03002371 {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, FLIP_DETECT)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002372 {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)},
2373 {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)},
2374 {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)},
2375 {USB_DEVICE(0x0c45, 0x6282), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002376 {USB_DEVICE(0x0c45, 0x6288), SN9C20X(OV9655, 0x30, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002377 {USB_DEVICE(0x0c45, 0x628c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002378 {USB_DEVICE(0x0c45, 0x628e), SN9C20X(SOI968, 0x30, 0)},
2379 {USB_DEVICE(0x0c45, 0x628f), SN9C20X(OV9650, 0x30, 0)},
2380 {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)},
2381 {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)},
Frank Schaefer114cfbd2011-09-23 05:05:37 -03002382 {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, LED_REVERSE)},
Hans de Goedeb39e0cb2011-02-16 08:33:16 -03002383 {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, LED_REVERSE)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002384 {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)},
2385 {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)},
2386 {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)},
2387 {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnsone99ac542010-03-16 13:58:28 -03002388 {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)},
2389 {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002390 {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)},
2391 {USB_DEVICE(0xa168, 0x0611), SN9C20X(HV7131R, 0x11, 0)},
2392 {USB_DEVICE(0xa168, 0x0613), SN9C20X(HV7131R, 0x11, 0)},
2393 {USB_DEVICE(0xa168, 0x0618), SN9C20X(HV7131R, 0x11, 0)},
Brian Johnson33ddc162010-04-18 21:42:40 -03002394 {USB_DEVICE(0xa168, 0x0614), SN9C20X(MT9M111, 0x5d, 0)},
Brian Johnson26e744b2009-07-19 05:52:58 -03002395 {USB_DEVICE(0xa168, 0x0615), SN9C20X(MT9M111, 0x5d, 0)},
2396 {USB_DEVICE(0xa168, 0x0617), SN9C20X(MT9M111, 0x5d, 0)},
2397 {}
2398};
2399MODULE_DEVICE_TABLE(usb, device_table);
2400
2401/* -- device connect -- */
2402static int sd_probe(struct usb_interface *intf,
2403 const struct usb_device_id *id)
2404{
2405 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
2406 THIS_MODULE);
2407}
2408
Brian Johnson26e744b2009-07-19 05:52:58 -03002409static struct usb_driver sd_driver = {
Jean-François Moineff38d582012-03-19 04:55:16 -03002410 .name = KBUILD_MODNAME,
Brian Johnson26e744b2009-07-19 05:52:58 -03002411 .id_table = device_table,
2412 .probe = sd_probe,
Mauro Carvalho Chehaba39db272010-05-18 00:49:44 -03002413 .disconnect = gspca_disconnect,
Brian Johnson26e744b2009-07-19 05:52:58 -03002414#ifdef CONFIG_PM
2415 .suspend = gspca_suspend,
2416 .resume = gspca_resume,
2417 .reset_resume = gspca_resume,
2418#endif
2419};
2420
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -08002421module_usb_driver(sd_driver);