blob: ce8b28f504d395e466a7ce03e0706c1350809789 [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * sonix sn9c102 (bayer) library
3 * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr
4 * Add Pas106 Stefano Mozzi (C) 2004
5 *
6 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
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
23#define MODULE_NAME "sonixb"
24
25#include "gspca.h"
26
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -030027#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
28static const char version[] = "2.1.7";
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030029
30MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
31MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
32MODULE_LICENSE("GPL");
33
34/* specific webcam descriptor */
35struct sd {
36 struct gspca_dev gspca_dev; /* !! must be the first item */
37
Hans de Goededcef3232008-07-10 10:40:53 -030038 struct sd_desc sd_desc; /* our nctrls differ dependend upon the
39 sensor, so we use a per cam copy */
40 atomic_t avg_lum;
41
42 unsigned short gain;
43 unsigned short exposure;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030044 unsigned char brightness;
Hans de Goededcef3232008-07-10 10:40:53 -030045 unsigned char autogain;
46 unsigned char autogain_ignore_frames;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030047
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -030048 unsigned char fr_h_sz; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030049 char sensor; /* Type of image sensor chip */
Hans de Goededcef3232008-07-10 10:40:53 -030050 char sensor_has_gain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030051#define SENSOR_HV7131R 0
52#define SENSOR_OV6650 1
53#define SENSOR_OV7630 2
54#define SENSOR_OV7630_3 3
55#define SENSOR_PAS106 4
56#define SENSOR_PAS202 5
57#define SENSOR_TAS5110 6
58#define SENSOR_TAS5130CXX 7
59};
60
61#define COMP2 0x8f
62#define COMP 0xc7 /* 0x87 //0x07 */
63#define COMP1 0xc9 /* 0x89 //0x09 */
64
65#define MCK_INIT 0x63
66#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
67
68#define SYS_CLK 0x04
69
Hans de Goededcef3232008-07-10 10:40:53 -030070/* We calculate the autogain at the end of the transfer of a frame, at this
71 moment a frame with the old settings is being transmitted, and a frame is
72 being captured with the old settings. So if we adjust the autogain we must
73 ignore atleast the 2 next frames for the new settings to come into effect
74 before doing any other adjustments */
75#define AUTOGAIN_IGNORE_FRAMES 3
76#define AUTOGAIN_DEADZONE 500
77#define DESIRED_AVG_LUM 7000
78
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030079/* V4L2 controls supported by the driver */
80static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
81static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goededcef3232008-07-10 10:40:53 -030082static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
83static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
84static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
85static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
86static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
87static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030088
89static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030090 {
91 {
92 .id = V4L2_CID_BRIGHTNESS,
93 .type = V4L2_CTRL_TYPE_INTEGER,
94 .name = "Brightness",
95 .minimum = 0,
96 .maximum = 255,
97 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -030098#define BRIGHTNESS_DEF 127
99 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300100 },
101 .set = sd_setbrightness,
102 .get = sd_getbrightness,
103 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300104 {
105 {
Hans de Goededcef3232008-07-10 10:40:53 -0300106 .id = V4L2_CID_GAIN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300107 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goededcef3232008-07-10 10:40:53 -0300108 .name = "Gain",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300109 .minimum = 0,
Hans de Goededcef3232008-07-10 10:40:53 -0300110 .maximum = 511,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300111 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -0300112#define GAIN_DEF 255
113#define GAIN_KNEE 400
114 .default_value = GAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300115 },
Hans de Goededcef3232008-07-10 10:40:53 -0300116 .set = sd_setgain,
117 .get = sd_getgain,
118 },
Hans de Goededcef3232008-07-10 10:40:53 -0300119 {
120 {
121 .id = V4L2_CID_EXPOSURE,
122 .type = V4L2_CTRL_TYPE_INTEGER,
123 .name = "Exposure",
124#define EXPOSURE_DEF 0
125#define EXPOSURE_KNEE 353 /* 10 fps */
126 .minimum = 0,
127 .maximum = 511,
128 .step = 1,
129 .default_value = EXPOSURE_DEF,
130 .flags = 0,
131 },
132 .set = sd_setexposure,
133 .get = sd_getexposure,
134 },
Hans de Goededcef3232008-07-10 10:40:53 -0300135 {
136 {
137 .id = V4L2_CID_AUTOGAIN,
138 .type = V4L2_CTRL_TYPE_BOOLEAN,
139 .name = "Automatic Gain (and Exposure)",
140 .minimum = 0,
141 .maximum = 1,
142 .step = 1,
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300143#define AUTOGAIN_DEF 1
144 .default_value = AUTOGAIN_DEF,
Hans de Goededcef3232008-07-10 10:40:53 -0300145 .flags = 0,
146 },
147 .set = sd_setautogain,
148 .get = sd_getautogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300149 },
150};
151
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300152static struct v4l2_pix_format vga_mode[] = {
153 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
154 .bytesperline = 160,
155 .sizeimage = 160 * 120,
156 .colorspace = V4L2_COLORSPACE_SRGB,
157 .priv = 2},
158 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
159 .bytesperline = 320,
160 .sizeimage = 320 * 240,
161 .colorspace = V4L2_COLORSPACE_SRGB,
162 .priv = 1},
163 {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
164 .bytesperline = 640,
165 .sizeimage = 640 * 480,
166 .colorspace = V4L2_COLORSPACE_SRGB,
167 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300168};
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300169static struct v4l2_pix_format sif_mode[] = {
170 {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
171 .bytesperline = 176,
172 .sizeimage = 176 * 144,
173 .colorspace = V4L2_COLORSPACE_SRGB,
174 .priv = 1},
175 {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
176 .bytesperline = 352,
177 .sizeimage = 352 * 288,
178 .colorspace = V4L2_COLORSPACE_SRGB,
179 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300180};
181
182static const __u8 probe_ov7630[] = {0x08, 0x44};
183
184static const __u8 initHv7131[] = {
185 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
186 0x00, 0x00,
187 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
188 0x28, 0x1e, 0x60, 0x8a, 0x20,
189 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
190};
191static const __u8 hv7131_sensor_init[][8] = {
192 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
193 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
194 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
195 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
196 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
197};
198static const __u8 initOv6650[] = {
199 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
200 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b,
202 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
203};
204static const __u8 ov6650_sensor_init[][8] =
205{
206 /* Bright, contrast, etc are set througth SCBB interface.
207 * AVCAP on win2 do not send any data on this controls. */
208 /* Anyway, some registers appears to alter bright and constrat */
Hans de Goededcef3232008-07-10 10:40:53 -0300209
210 /* Reset sensor */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300211 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300212 /* Set clock register 0x11 low nibble is clock divider */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300213 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300214 /* Next some unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300215 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
216/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
217 * THIS SET GREEN SCREEN
218 * (pixels could be innverted in decode kind of "brg",
219 * but blue wont be there. Avoid this data ... */
220 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
221 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
222 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300223 /* Disable autobright ? */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300224 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300225 /* Some more unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300226 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
227 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300228 {0xa0, 0x60, 0x10, 0x57, 0x99, 0x04, 0x94, 0x16},
Hans de Goededcef3232008-07-10 10:40:53 -0300229 /* Framerate adjust register for artificial light 50 hz flicker
230 compensation, identical to ov6630 0x2b register, see 6630 datasheet.
231 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */
232 {0xa0, 0x60, 0x2b, 0x4f, 0x99, 0x04, 0x94, 0x15},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300233};
Hans de Goededcef3232008-07-10 10:40:53 -0300234
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300235static const __u8 initOv7630[] = {
236 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
237 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
238 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
239 0x28, 0x1e, /* H & V sizes r15 .. r16 */
240 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
241 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
242};
243static const __u8 initOv7630_3[] = {
244 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
245 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300246 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
247 0x16, 0x12, /* H & V sizes r15 .. r16 */
248 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
249 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
250 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
251 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300252};
253static const __u8 ov7630_sensor_init_com[][8] = {
254 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
255 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
256/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
257 {0xd0, 0x21, 0x12, 0x78, 0x00, 0x80, 0x34, 0x10}, /* jfm */
258 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
259 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
260 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
261 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
262 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
263 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
264 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
265/* {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10}, jfm */
266 {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, /* jfm */
267 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
268 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
269 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
270 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
271 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
272 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
273};
274static const __u8 ov7630_sensor_init[][8] = {
275 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */
276 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */
277 {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16},
278 {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16},
279 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
280};
281static const __u8 ov7630_sensor_init_3[][8] = {
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300282 {0xa0, 0x21, 0x10, 0x83, 0xbd, 0x06, 0xf6, 0x16}, /* exposure */
283 {0xa0, 0x21, 0x76, 0x00, 0xbd, 0x06, 0xf6, 0x16},
284 {0xa0, 0x21, 0x11, 0x00, 0xbd, 0x06, 0xf6, 0x16},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300285 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
286/* {0xb0, 0x21, 0x2a, 0xc0, 0x3c, 0x06, 0xf6, 0x1d},
287 * a0 1c,a0 1f,c0 3c frame rate ?line interval from ov6630 */
288/* {0xb0, 0x21, 0x2a, 0xa0, 0x1f, 0x06, 0xf6, 0x1d}, * from win */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300289 {0xb0, 0x21, 0x2a, 0x80, 0x60, 0x06, 0xf6, 0x1d},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300290};
291
292static const __u8 initPas106[] = {
293 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
294 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
296 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
297 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
298};
299/* compression 0x86 mckinit1 0x2b */
300static const __u8 pas106_data[][2] = {
301 {0x02, 0x04}, /* Pixel Clock Divider 6 */
302 {0x03, 0x13}, /* Frame Time MSB */
303/* {0x03, 0x12}, * Frame Time MSB */
304 {0x04, 0x06}, /* Frame Time LSB */
305/* {0x04, 0x05}, * Frame Time LSB */
306 {0x05, 0x65}, /* Shutter Time Line Offset */
307/* {0x05, 0x6d}, * Shutter Time Line Offset */
308/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
309 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
310 {0x07, 0xc1}, /* Black Level Subtract Sign */
311/* {0x07, 0x00}, * Black Level Subtract Sign */
312 {0x08, 0x06}, /* Black Level Subtract Level */
313 {0x08, 0x06}, /* Black Level Subtract Level */
314/* {0x08, 0x01}, * Black Level Subtract Level */
315 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
316 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
317 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
318 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
319 {0x0d, 0x00}, /* Color GainH Pixel */
320 {0x0e, 0x0e}, /* Global Gain */
321 {0x0f, 0x00}, /* Contrast */
322 {0x10, 0x06}, /* H&V synchro polarity */
323 {0x11, 0x06}, /* ?default */
324 {0x12, 0x06}, /* DAC scale */
325 {0x14, 0x02}, /* ?default */
326 {0x13, 0x01}, /* Validate Settings */
327};
328static const __u8 initPas202[] = {
329 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
330 0x00, 0x00,
331 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
332 0x28, 0x1e, 0x28, 0x89, 0x30,
333 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
334};
335static const __u8 pas202_sensor_init[][8] = {
336 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
337 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
338 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
339 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
340 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
341 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
342 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
343 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
344 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
345 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
346 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
347 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
348
349 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
350 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
351 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
352 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
353 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
354 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
355 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
356 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
357};
358
359static const __u8 initTas5110[] = {
360 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
361 0x00, 0x00,
362 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
363 0x16, 0x12, 0x60, 0x86, 0x2b,
364 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
365};
366static const __u8 tas5110_sensor_init[][8] = {
367 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
368 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
369 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
370};
371
372static const __u8 initTas5130[] = {
373 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
374 0x00, 0x00,
375 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
376 0x28, 0x1e, 0x60, COMP, MCK_INIT,
377 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
378};
379static const __u8 tas5130_sensor_init[][8] = {
380/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
381 * shutter 0x47 short exposure? */
382 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
383 /* shutter 0x01 long exposure */
384 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
385};
386
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300387/* get one byte in gspca_dev->usb_buf */
388static void reg_r(struct gspca_dev *gspca_dev,
389 __u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300390{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300391 usb_control_msg(gspca_dev->dev,
392 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300393 0, /* request */
394 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
395 value,
396 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300397 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300398 500);
399}
400
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300401static void reg_w(struct gspca_dev *gspca_dev,
402 __u16 value,
403 const __u8 *buffer,
404 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300405{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300406#ifdef CONFIG_VIDEO_ADV_DEBUG
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300407 if (len > sizeof gspca_dev->usb_buf) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300408 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
409 return;
410 }
411#endif
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300412 memcpy(gspca_dev->usb_buf, buffer, len);
413 usb_control_msg(gspca_dev->dev,
414 usb_sndctrlpipe(gspca_dev->dev, 0),
415 0x08, /* request */
416 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
417 value,
418 0, /* index */
419 gspca_dev->usb_buf, len,
420 500);
421}
422
423static void reg_w_big(struct gspca_dev *gspca_dev,
424 __u16 value,
425 const __u8 *buffer,
426 int len)
427{
428 __u8 *tmpbuf;
429
430 tmpbuf = kmalloc(len, GFP_KERNEL);
Hans de Goede0d2a7222008-07-03 08:15:22 -0300431 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300432 usb_control_msg(gspca_dev->dev,
433 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300434 0x08, /* request */
435 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
436 value,
437 0, /* index */
Hans de Goede0d2a7222008-07-03 08:15:22 -0300438 tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300439 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300440 kfree(tmpbuf);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300441}
442
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300443static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300444{
445 int retry = 60;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300446
447 /* is i2c ready */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300448 reg_w(gspca_dev, 0x08, buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300449 while (retry--) {
450 msleep(10);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300451 reg_r(gspca_dev, 0x08);
452 if (gspca_dev->usb_buf[0] == 4)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300453 return 0;
454 }
455 return -1;
456}
457
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300458static void i2c_w_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300459 const __u8 buffer[][8], int len)
460{
461 for (;;) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300462 reg_w(gspca_dev, 0x08, *buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300463 len -= 8;
464 if (len <= 0)
465 break;
466 buffer++;
467 }
468}
469
470static void setbrightness(struct gspca_dev *gspca_dev)
471{
472 struct sd *sd = (struct sd *) gspca_dev;
473 __u8 value;
474
475 switch (sd->sensor) {
476 case SENSOR_OV6650: {
477 __u8 i2cOV6650[] =
478 {0xa0, 0x60, 0x06, 0x11, 0x99, 0x04, 0x94, 0x15};
479
480 i2cOV6650[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300481 if (i2c_w(gspca_dev, i2cOV6650) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300482 goto err;
483 break;
484 }
485 case SENSOR_OV7630: {
486 __u8 i2cOV[] =
487 {0xa0, 0x21, 0x06, 0x36, 0xbd, 0x06, 0xf6, 0x16};
488
489 /* change reg 0x06 */
490 i2cOV[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300491 if (i2c_w(gspca_dev, i2cOV) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300492 goto err;
493 break;
494 }
495 case SENSOR_PAS106: {
496 __u8 i2c1[] =
497 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
498
499 i2c1[3] = sd->brightness >> 3;
500 i2c1[2] = 0x0e;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300501 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300502 goto err;
503 i2c1[3] = 0x01;
504 i2c1[2] = 0x13;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300505 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300506 goto err;
507 break;
508 }
509 case SENSOR_PAS202: {
510 /* __u8 i2cpexpo1[] =
511 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
512 __u8 i2cpexpo[] =
513 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
514 __u8 i2cp202[] =
515 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
516 static __u8 i2cpdoit[] =
517 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
518
519 /* change reg 0x10 */
520 i2cpexpo[4] = 0xff - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300521/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300522 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300523/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300524 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300525 if (i2c_w(gspca_dev, i2cpexpo) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300526 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300527 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300528 goto err;
529 i2cp202[3] = sd->brightness >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300530 if (i2c_w(gspca_dev, i2cp202) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300531 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300532 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300533 goto err;
534 break;
535 }
Hans de Goededcef3232008-07-10 10:40:53 -0300536 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300537 __u8 i2c[] =
538 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
539
540 value = 0xff - sd->brightness;
541 i2c[4] = value;
542 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300543 if (i2c_w(gspca_dev, i2c) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300544 goto err;
545 break;
546 }
Hans de Goededcef3232008-07-10 10:40:53 -0300547 case SENSOR_TAS5110:
548 /* FIXME figure out howto control brightness on TAS5110 */
549 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300550 }
551 return;
552err:
553 PDEBUG(D_ERR, "i2c error brightness");
554}
Hans de Goededcef3232008-07-10 10:40:53 -0300555
556static void setsensorgain(struct gspca_dev *gspca_dev)
557{
558 struct sd *sd = (struct sd *) gspca_dev;
559 unsigned short gain;
560
561 gain = (sd->gain + 1) >> 1;
562 if (gain > 255)
563 gain = 255;
564
565 switch (sd->sensor) {
566
567 case SENSOR_TAS5110: {
568 __u8 i2c[] =
569 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
570
571 i2c[4] = 255 - gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300572 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300573 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300574 break;
575 }
Hans de Goededcef3232008-07-10 10:40:53 -0300576 case SENSOR_OV6650: {
577 __u8 i2c[] = {0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
578 i2c[3] = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300579 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300580 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300581 break;
582 }
Hans de Goededcef3232008-07-10 10:40:53 -0300583 }
584 return;
585err:
586 PDEBUG(D_ERR, "i2c error gain");
587}
588
589static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300590{
591 struct sd *sd = (struct sd *) gspca_dev;
592 __u8 gain;
593 __u8 rgb_value;
594
Hans de Goededcef3232008-07-10 10:40:53 -0300595 gain = sd->gain >> 5;
596
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300597 /* red and blue gain */
598 rgb_value = gain << 4 | gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300599 reg_w(gspca_dev, 0x10, &rgb_value, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300600 /* green gain */
601 rgb_value = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300602 reg_w(gspca_dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300603
604 if (sd->sensor_has_gain)
605 setsensorgain(gspca_dev);
606}
607
608static void setexposure(struct gspca_dev *gspca_dev)
609{
610 struct sd *sd = (struct sd *) gspca_dev;
611 /* translate 0 - 255 to a number of fps in a 30 - 1 scale */
612 int fps = 30 - sd->exposure * 29 / 511;
613
614 switch (sd->sensor) {
615 case SENSOR_TAS5110: {
616 __u8 reg;
617
618 /* register 19's high nibble contains the sn9c10x clock divider
619 The high nibble configures the no fps according to the
620 formula: 60 / high_nibble. With a maximum of 30 fps */
621 reg = 60 / fps;
622 if (reg > 15)
623 reg = 15;
624 reg = (reg << 4) | 0x0b;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300625 reg_w(gspca_dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300626 break;
627 }
Hans de Goededcef3232008-07-10 10:40:53 -0300628 case SENSOR_OV6650: {
629 __u8 i2c[] = {0xa0, 0x60, 0x11, 0xc0, 0x00, 0x00, 0x00, 0x10};
630 i2c[3] = 30 / fps - 1;
631 if (i2c[3] > 15)
632 i2c[3] = 15;
633 i2c[3] |= 0xc0;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300634 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300635 PDEBUG(D_ERR, "i2c error exposure");
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300636 break;
637 }
Hans de Goededcef3232008-07-10 10:40:53 -0300638 }
639}
640
641
642static void do_autogain(struct gspca_dev *gspca_dev)
643{
644 struct sd *sd = (struct sd *) gspca_dev;
645 int avg_lum = atomic_read(&sd->avg_lum);
646
647 if (avg_lum == -1)
648 return;
649
650 if (sd->autogain_ignore_frames > 0)
651 sd->autogain_ignore_frames--;
652 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
653 sd->brightness * DESIRED_AVG_LUM / 127,
654 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE))
655 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300656}
657
658/* this function is called at probe time */
659static int sd_config(struct gspca_dev *gspca_dev,
660 const struct usb_device_id *id)
661{
662 struct sd *sd = (struct sd *) gspca_dev;
663 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300664 __u16 product;
665 int sif = 0;
666
Hans de Goededcef3232008-07-10 10:40:53 -0300667 /* nctrls depends upon the sensor, so we use a per cam copy */
668 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
669 gspca_dev->sd_desc = &sd->sd_desc;
670
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300671 sd->fr_h_sz = 12; /* default size of the frame header */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300672 sd->sd_desc.nctrls = 2; /* default nb of ctrls */
Hans de Goededcef3232008-07-10 10:40:53 -0300673
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300674 product = id->idProduct;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300675/* switch (id->idVendor) { */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300676/* case 0x0c45: * Sonix */
677 switch (product) {
678 case 0x6001: /* SN9C102 */
679 case 0x6005: /* SN9C101 */
680 case 0x6007: /* SN9C101 */
681 sd->sensor = SENSOR_TAS5110;
Hans de Goededcef3232008-07-10 10:40:53 -0300682 sd->sensor_has_gain = 1;
683 sd->sd_desc.nctrls = 4;
684 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300685 sif = 1;
686 break;
687 case 0x6009: /* SN9C101 */
688 case 0x600d: /* SN9C101 */
689 case 0x6029: /* SN9C101 */
690 sd->sensor = SENSOR_PAS106;
691 sif = 1;
692 break;
693 case 0x6011: /* SN9C101 - SN9C101G */
694 sd->sensor = SENSOR_OV6650;
Hans de Goededcef3232008-07-10 10:40:53 -0300695 sd->sensor_has_gain = 1;
696 sd->sd_desc.nctrls = 4;
697 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300698 sif = 1;
699 break;
700 case 0x6019: /* SN9C101 */
701 case 0x602c: /* SN9C102 */
702 case 0x602e: /* SN9C102 */
703 sd->sensor = SENSOR_OV7630;
704 break;
705 case 0x60b0: /* SN9C103 */
706 sd->sensor = SENSOR_OV7630_3;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300707 sd->fr_h_sz = 18; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300708 break;
709 case 0x6024: /* SN9C102 */
710 case 0x6025: /* SN9C102 */
711 sd->sensor = SENSOR_TAS5130CXX;
712 break;
713 case 0x6028: /* SN9C102 */
714 sd->sensor = SENSOR_PAS202;
715 break;
716 case 0x602d: /* SN9C102 */
717 sd->sensor = SENSOR_HV7131R;
718 break;
719 case 0x60af: /* SN9C103 */
720 sd->sensor = SENSOR_PAS202;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300721 sd->fr_h_sz = 18; /* size of frame header (?) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300722 break;
723 }
724/* break; */
725/* } */
726
727 cam = &gspca_dev->cam;
728 cam->dev_name = (char *) id->driver_info;
729 cam->epaddr = 0x01;
730 if (!sif) {
731 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300732 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300733 } else {
734 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300735 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300736 }
Hans de Goededcef3232008-07-10 10:40:53 -0300737 sd->brightness = BRIGHTNESS_DEF;
738 sd->gain = GAIN_DEF;
739 sd->exposure = EXPOSURE_DEF;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300740 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300741 if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300742 reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300743 return 0;
744}
745
746/* this function is called at open time */
747static int sd_open(struct gspca_dev *gspca_dev)
748{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300749 reg_r(gspca_dev, 0x00);
750 if (gspca_dev->usb_buf[0] != 0x10)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300751 return -ENODEV;
752 return 0;
753}
754
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300755static void pas106_i2cinit(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300756{
757 int i;
758 const __u8 *data;
759 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
760
761 i = ARRAY_SIZE(pas106_data);
762 data = pas106_data[0];
763 while (--i >= 0) {
764 memcpy(&i2c1[2], data, 2);
765 /* copy 2 bytes from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300766 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300767 PDEBUG(D_ERR, "i2c error pas106");
768 data += 2;
769 }
770}
771
772/* -- start the camera -- */
773static void sd_start(struct gspca_dev *gspca_dev)
774{
775 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300776 int mode, l;
777 const __u8 *sn9c10x;
778 __u8 reg01, reg17;
779 __u8 reg17_19[3];
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300780 static const __u8 reg15[2] = { 0x28, 0x1e };
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300781
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300782 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300783 switch (sd->sensor) {
784 case SENSOR_HV7131R:
785 sn9c10x = initHv7131;
786 reg17_19[0] = 0x60;
787 reg17_19[1] = (mode << 4) | 0x8a;
788 reg17_19[2] = 0x20;
789 break;
790 case SENSOR_OV6650:
791 sn9c10x = initOv6650;
792 reg17_19[0] = 0x68;
793 reg17_19[1] = (mode << 4) | 0x8b;
794 reg17_19[2] = 0x20;
795 break;
796 case SENSOR_OV7630:
797 sn9c10x = initOv7630;
798 reg17_19[0] = 0x68;
799 reg17_19[1] = (mode << 4) | COMP2;
800 reg17_19[2] = MCK_INIT1;
801 break;
802 case SENSOR_OV7630_3:
803 sn9c10x = initOv7630_3;
804 reg17_19[0] = 0x68;
805 reg17_19[1] = (mode << 4) | COMP2;
806 reg17_19[2] = MCK_INIT1;
807 break;
808 case SENSOR_PAS106:
809 sn9c10x = initPas106;
810 reg17_19[0] = 0x24; /* 0x28 */
811 reg17_19[1] = (mode << 4) | COMP1;
812 reg17_19[2] = MCK_INIT1;
813 break;
814 case SENSOR_PAS202:
815 sn9c10x = initPas202;
816 reg17_19[0] = mode ? 0x24 : 0x20;
817 reg17_19[1] = (mode << 4) | 0x89;
818 reg17_19[2] = 0x20;
819 break;
820 case SENSOR_TAS5110:
821 sn9c10x = initTas5110;
822 reg17_19[0] = 0x60;
823 reg17_19[1] = (mode << 4) | 0x86;
824 reg17_19[2] = 0x2b; /* 0xf3; */
825 break;
826 default:
827/* case SENSOR_TAS5130CXX: */
828 sn9c10x = initTas5130;
829 reg17_19[0] = 0x60;
830 reg17_19[1] = (mode << 4) | COMP;
831 reg17_19[2] = mode ? 0x23 : 0x43;
832 break;
833 }
834 switch (sd->sensor) {
835 case SENSOR_OV7630:
836 reg01 = 0x06;
837 reg17 = 0x29;
838 l = 0x10;
839 break;
840 case SENSOR_OV7630_3:
841 reg01 = 0x44;
842 reg17 = 0x68;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300843 l = sizeof initOv7630_3;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300844 break;
845 default:
846 reg01 = sn9c10x[0];
847 reg17 = sn9c10x[0x17 - 1];
848 l = 0x1f;
849 break;
850 }
851
852 /* reg 0x01 bit 2 video transfert on */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300853 reg_w(gspca_dev, 0x01, &reg01, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300854 /* reg 0x17 SensorClk enable inv Clk 0x60 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300855 reg_w(gspca_dev, 0x17, &reg17, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300856/*fixme: for ov7630 102
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300857 reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300858 /* Set the registers from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300859 reg_w_big(gspca_dev, 0x01, sn9c10x, l);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300860 switch (sd->sensor) {
861 case SENSOR_HV7131R:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300862 i2c_w_vector(gspca_dev, hv7131_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300863 sizeof hv7131_sensor_init);
864 break;
865 case SENSOR_OV6650:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300866 i2c_w_vector(gspca_dev, ov6650_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300867 sizeof ov6650_sensor_init);
868 break;
869 case SENSOR_OV7630:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300870 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300871 sizeof ov7630_sensor_init_com);
872 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300873 i2c_w_vector(gspca_dev, ov7630_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300874 sizeof ov7630_sensor_init);
875 break;
876 case SENSOR_OV7630_3:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300877 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300878 sizeof ov7630_sensor_init_com);
879 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300880 i2c_w_vector(gspca_dev, ov7630_sensor_init_3,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300881 sizeof ov7630_sensor_init_3);
882 break;
883 case SENSOR_PAS106:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300884 pas106_i2cinit(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300885 break;
886 case SENSOR_PAS202:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300887 i2c_w_vector(gspca_dev, pas202_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300888 sizeof pas202_sensor_init);
889 break;
890 case SENSOR_TAS5110:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300891 i2c_w_vector(gspca_dev, tas5110_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300892 sizeof tas5110_sensor_init);
893 break;
894 default:
895/* case SENSOR_TAS5130CXX: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300896 i2c_w_vector(gspca_dev, tas5130_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300897 sizeof tas5130_sensor_init);
898 break;
899 }
900 /* H_size V_size 0x28, 0x1e maybe 640x480 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300901 reg_w(gspca_dev, 0x15, reg15, 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300902 /* compression register */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300903 reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300904 if (sd->sensor != SENSOR_OV7630_3) {
905 /* H_start */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300906 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300907 /* V_START */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300908 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300909 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300910 /* reset 0x17 SensorClk enable inv Clk 0x60 */
911 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300912 reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300913 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300914 if (sd->sensor != SENSOR_OV7630_3)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300915 reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300916 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300917 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300918 /* Enable video transfert */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300919 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300920 /* Compression */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300921 reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300922 msleep(20);
923
Hans de Goededcef3232008-07-10 10:40:53 -0300924 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300925 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -0300926 setexposure(gspca_dev);
927
928 sd->autogain_ignore_frames = 0;
929 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300930}
931
932static void sd_stopN(struct gspca_dev *gspca_dev)
933{
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300934 __u8 ByteSend;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300935
936 ByteSend = 0x09; /* 0X00 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300937 reg_w(gspca_dev, 0x01, &ByteSend, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300938}
939
940static void sd_stop0(struct gspca_dev *gspca_dev)
941{
942}
943
944static void sd_close(struct gspca_dev *gspca_dev)
945{
946}
947
948static void sd_pkt_scan(struct gspca_dev *gspca_dev,
949 struct gspca_frame *frame, /* target */
950 unsigned char *data, /* isoc packet */
951 int len) /* iso packet length */
952{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300953 int i;
Hans de Goededcef3232008-07-10 10:40:53 -0300954 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300955
956 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300957 for (i = 0; i < len - 6; i++) {
958 if (data[0 + i] == 0xff
959 && data[1 + i] == 0xff
960 && data[2 + i] == 0x00
961 && data[3 + i] == 0xc4
962 && data[4 + i] == 0xc4
963 && data[5 + i] == 0x96) { /* start of frame */
964 frame = gspca_frame_add(gspca_dev, LAST_PACKET,
965 frame, data, 0);
Hans de Goededcef3232008-07-10 10:40:53 -0300966 if (i < (len - 10)) {
967 atomic_set(&sd->avg_lum, data[i + 8] +
968 (data[i + 9] << 8));
969 } else {
970 atomic_set(&sd->avg_lum, -1);
971#ifdef CONFIG_VIDEO_ADV_DEBUG
972 PDEBUG(D_STREAM, "packet too short to "
973 "get avg brightness");
974#endif
975 }
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300976 data += i + sd->fr_h_sz;
977 len -= i + sd->fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300978 gspca_frame_add(gspca_dev, FIRST_PACKET,
979 frame, data, len);
980 return;
981 }
982 }
983 }
984 gspca_frame_add(gspca_dev, INTER_PACKET,
985 frame, data, len);
986}
987
988static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
989{
990 struct sd *sd = (struct sd *) gspca_dev;
991
992 sd->brightness = val;
993 if (gspca_dev->streaming)
994 setbrightness(gspca_dev);
995 return 0;
996}
997
998static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
999{
1000 struct sd *sd = (struct sd *) gspca_dev;
1001
1002 *val = sd->brightness;
1003 return 0;
1004}
1005
Hans de Goededcef3232008-07-10 10:40:53 -03001006static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001007{
1008 struct sd *sd = (struct sd *) gspca_dev;
1009
Hans de Goededcef3232008-07-10 10:40:53 -03001010 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001011 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -03001012 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001013 return 0;
1014}
1015
Hans de Goededcef3232008-07-10 10:40:53 -03001016static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001017{
1018 struct sd *sd = (struct sd *) gspca_dev;
1019
Hans de Goededcef3232008-07-10 10:40:53 -03001020 *val = sd->gain;
1021 return 0;
1022}
1023
1024static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1025{
1026 struct sd *sd = (struct sd *) gspca_dev;
1027
1028 sd->exposure = val;
1029 if (gspca_dev->streaming)
1030 setexposure(gspca_dev);
1031 return 0;
1032}
1033
1034static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1035{
1036 struct sd *sd = (struct sd *) gspca_dev;
1037
1038 *val = sd->exposure;
1039 return 0;
1040}
1041
1042static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1043{
1044 struct sd *sd = (struct sd *) gspca_dev;
1045
1046 sd->autogain = val;
1047 /* when switching to autogain set defaults to make sure
1048 we are on a valid point of the autogain gain /
1049 exposure knee graph, and give this change time to
1050 take effect before doing autogain. */
1051 if (sd->autogain) {
1052 sd->exposure = EXPOSURE_DEF;
1053 sd->gain = GAIN_DEF;
1054 if (gspca_dev->streaming) {
1055 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1056 setexposure(gspca_dev);
1057 setgain(gspca_dev);
1058 }
1059 }
1060
1061 return 0;
1062}
1063
1064static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1065{
1066 struct sd *sd = (struct sd *) gspca_dev;
1067
1068 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001069 return 0;
1070}
1071
1072/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001073static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001074 .name = MODULE_NAME,
1075 .ctrls = sd_ctrls,
1076 .nctrls = ARRAY_SIZE(sd_ctrls),
1077 .config = sd_config,
1078 .open = sd_open,
1079 .start = sd_start,
1080 .stopN = sd_stopN,
1081 .stop0 = sd_stop0,
1082 .close = sd_close,
1083 .pkt_scan = sd_pkt_scan,
1084};
1085
1086/* -- module initialisation -- */
1087#define DVNM(name) .driver_info = (kernel_ulong_t) name
1088static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001089#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001090 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1091 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1092 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1093 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1094 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
Jean-Francois Moine956e42d2008-07-01 10:03:42 -03001095 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001096 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1097 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1098 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1099 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1100 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1101 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1102 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1103 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1104 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1105 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001106#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001107 {}
1108};
1109MODULE_DEVICE_TABLE(usb, device_table);
1110
1111/* -- device connect -- */
1112static int sd_probe(struct usb_interface *intf,
1113 const struct usb_device_id *id)
1114{
1115 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1116 THIS_MODULE);
1117}
1118
1119static struct usb_driver sd_driver = {
1120 .name = MODULE_NAME,
1121 .id_table = device_table,
1122 .probe = sd_probe,
1123 .disconnect = gspca_disconnect,
1124};
1125
1126/* -- module insert / remove -- */
1127static int __init sd_mod_init(void)
1128{
1129 if (usb_register(&sd_driver) < 0)
1130 return -1;
1131 PDEBUG(D_PROBE, "v%s registered", version);
1132 return 0;
1133}
1134static void __exit sd_mod_exit(void)
1135{
1136 usb_deregister(&sd_driver);
1137 PDEBUG(D_PROBE, "deregistered");
1138}
1139
1140module_init(sd_mod_init);
1141module_exit(sd_mod_exit);