blob: 7303df0dc16bea361419accbe64a0438fba364c7 [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
Hans de Goedead5ef80d2008-07-14 10:11:42 -030042 unsigned char gain;
43 unsigned char 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
Hans de Goedead5ef80d2008-07-14 10:11:42 -030076#define AUTOGAIN_DEADZONE 1000
Hans de Goededcef3232008-07-10 10:40:53 -030077#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 Goedead5ef80d2008-07-14 10:11:42 -0300110 .maximum = 255,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300111 .step = 1,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300112#define GAIN_DEF 127
113#define GAIN_KNEE 200
Hans de Goededcef3232008-07-10 10:40:53 -0300114 .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",
Hans de Goedef4d52022008-07-15 09:36:42 -0300124#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
125#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
Hans de Goededcef3232008-07-10 10:40:53 -0300126 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300127 .maximum = 255,
Hans de Goededcef3232008-07-10 10:40:53 -0300128 .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 */
Hans de Goede3647fea2008-07-15 05:36:30 -0300247 0x28, 0x1e, /* H & V sizes r15 .. r16 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300248 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};
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300281static const __u8 ov7630_sensor_init_3[][5][8] = {
282 { {0xa0, 0x21, 0x10, 0x36, 0xbd, 0x06, 0xf6, 0x16}, /* exposure */
283 {0xa0, 0x21, 0x76, 0x03, 0xbd, 0x06, 0xf6, 0x16},
284 {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x16},
285 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
286 {0xb0, 0x21, 0x2a, 0xa0, 0x1c, 0x06, 0xf6, 0x1d},
287 },
288 { {0xa0, 0x21, 0x10, 0x83, 0xbd, 0x06, 0xf6, 0x16}, /* exposure */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300289 {0xa0, 0x21, 0x76, 0x00, 0xbd, 0x06, 0xf6, 0x16},
290 {0xa0, 0x21, 0x11, 0x00, 0xbd, 0x06, 0xf6, 0x16},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300291 {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
292/* {0xb0, 0x21, 0x2a, 0xc0, 0x3c, 0x06, 0xf6, 0x1d},
293 * a0 1c,a0 1f,c0 3c frame rate ?line interval from ov6630 */
294/* {0xb0, 0x21, 0x2a, 0xa0, 0x1f, 0x06, 0xf6, 0x1d}, * from win */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300295 {0xb0, 0x21, 0x2a, 0x80, 0x60, 0x06, 0xf6, 0x1d},
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300296 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300297};
298
299static const __u8 initPas106[] = {
300 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
301 0x00, 0x00,
302 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
303 0x16, 0x12, 0x28, COMP1, MCK_INIT1,
304 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
305};
306/* compression 0x86 mckinit1 0x2b */
307static const __u8 pas106_data[][2] = {
308 {0x02, 0x04}, /* Pixel Clock Divider 6 */
309 {0x03, 0x13}, /* Frame Time MSB */
310/* {0x03, 0x12}, * Frame Time MSB */
311 {0x04, 0x06}, /* Frame Time LSB */
312/* {0x04, 0x05}, * Frame Time LSB */
313 {0x05, 0x65}, /* Shutter Time Line Offset */
314/* {0x05, 0x6d}, * Shutter Time Line Offset */
315/* {0x06, 0xb1}, * Shutter Time Pixel Offset */
316 {0x06, 0xcd}, /* Shutter Time Pixel Offset */
317 {0x07, 0xc1}, /* Black Level Subtract Sign */
318/* {0x07, 0x00}, * Black Level Subtract Sign */
319 {0x08, 0x06}, /* Black Level Subtract Level */
320 {0x08, 0x06}, /* Black Level Subtract Level */
321/* {0x08, 0x01}, * Black Level Subtract Level */
322 {0x09, 0x05}, /* Color Gain B Pixel 5 a */
323 {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */
324 {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */
325 {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */
326 {0x0d, 0x00}, /* Color GainH Pixel */
327 {0x0e, 0x0e}, /* Global Gain */
328 {0x0f, 0x00}, /* Contrast */
329 {0x10, 0x06}, /* H&V synchro polarity */
330 {0x11, 0x06}, /* ?default */
331 {0x12, 0x06}, /* DAC scale */
332 {0x14, 0x02}, /* ?default */
333 {0x13, 0x01}, /* Validate Settings */
334};
335static const __u8 initPas202[] = {
336 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
337 0x00, 0x00,
338 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
339 0x28, 0x1e, 0x28, 0x89, 0x30,
340 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
341};
342static const __u8 pas202_sensor_init[][8] = {
343 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
344 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
345 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
346 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
347 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
348 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
349 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
350 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
351 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
352 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
353 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
354 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
355
356 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
357 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
358 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
359 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
360 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
361 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
362 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
363 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
364};
365
366static const __u8 initTas5110[] = {
367 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
368 0x00, 0x00,
369 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
370 0x16, 0x12, 0x60, 0x86, 0x2b,
371 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
372};
373static const __u8 tas5110_sensor_init[][8] = {
374 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
375 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
376 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
377};
378
379static const __u8 initTas5130[] = {
380 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
381 0x00, 0x00,
382 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
383 0x28, 0x1e, 0x60, COMP, MCK_INIT,
384 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
385};
386static const __u8 tas5130_sensor_init[][8] = {
387/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
388 * shutter 0x47 short exposure? */
389 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
390 /* shutter 0x01 long exposure */
391 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
392};
393
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300394/* get one byte in gspca_dev->usb_buf */
395static void reg_r(struct gspca_dev *gspca_dev,
396 __u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300397{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300398 usb_control_msg(gspca_dev->dev,
399 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300400 0, /* request */
401 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
402 value,
403 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300404 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300405 500);
406}
407
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300408static void reg_w(struct gspca_dev *gspca_dev,
409 __u16 value,
410 const __u8 *buffer,
411 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300412{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300413#ifdef CONFIG_VIDEO_ADV_DEBUG
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300414 if (len > sizeof gspca_dev->usb_buf) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300415 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
416 return;
417 }
418#endif
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300419 memcpy(gspca_dev->usb_buf, buffer, len);
420 usb_control_msg(gspca_dev->dev,
421 usb_sndctrlpipe(gspca_dev->dev, 0),
422 0x08, /* request */
423 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
424 value,
425 0, /* index */
426 gspca_dev->usb_buf, len,
427 500);
428}
429
430static void reg_w_big(struct gspca_dev *gspca_dev,
431 __u16 value,
432 const __u8 *buffer,
433 int len)
434{
435 __u8 *tmpbuf;
436
437 tmpbuf = kmalloc(len, GFP_KERNEL);
Hans de Goede0d2a7222008-07-03 08:15:22 -0300438 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300439 usb_control_msg(gspca_dev->dev,
440 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300441 0x08, /* request */
442 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
443 value,
444 0, /* index */
Hans de Goede0d2a7222008-07-03 08:15:22 -0300445 tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300446 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300447 kfree(tmpbuf);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300448}
449
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300450static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300451{
452 int retry = 60;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300453
454 /* is i2c ready */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300455 reg_w(gspca_dev, 0x08, buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300456 while (retry--) {
457 msleep(10);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300458 reg_r(gspca_dev, 0x08);
459 if (gspca_dev->usb_buf[0] == 4)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300460 return 0;
461 }
462 return -1;
463}
464
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300465static void i2c_w_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300466 const __u8 buffer[][8], int len)
467{
468 for (;;) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300469 reg_w(gspca_dev, 0x08, *buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300470 len -= 8;
471 if (len <= 0)
472 break;
473 buffer++;
474 }
475}
476
477static void setbrightness(struct gspca_dev *gspca_dev)
478{
479 struct sd *sd = (struct sd *) gspca_dev;
480 __u8 value;
481
482 switch (sd->sensor) {
483 case SENSOR_OV6650: {
484 __u8 i2cOV6650[] =
485 {0xa0, 0x60, 0x06, 0x11, 0x99, 0x04, 0x94, 0x15};
486
487 i2cOV6650[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300488 if (i2c_w(gspca_dev, i2cOV6650) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300489 goto err;
490 break;
491 }
492 case SENSOR_OV7630: {
493 __u8 i2cOV[] =
494 {0xa0, 0x21, 0x06, 0x36, 0xbd, 0x06, 0xf6, 0x16};
495
496 /* change reg 0x06 */
497 i2cOV[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300498 if (i2c_w(gspca_dev, i2cOV) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300499 goto err;
500 break;
501 }
502 case SENSOR_PAS106: {
503 __u8 i2c1[] =
504 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
505
506 i2c1[3] = sd->brightness >> 3;
507 i2c1[2] = 0x0e;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300508 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300509 goto err;
510 i2c1[3] = 0x01;
511 i2c1[2] = 0x13;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300512 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300513 goto err;
514 break;
515 }
516 case SENSOR_PAS202: {
517 /* __u8 i2cpexpo1[] =
518 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
519 __u8 i2cpexpo[] =
520 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
521 __u8 i2cp202[] =
522 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
523 static __u8 i2cpdoit[] =
524 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
525
526 /* change reg 0x10 */
527 i2cpexpo[4] = 0xff - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300528/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300529 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300530/* if(i2c_w(gspca_dev,i2cpdoit) < 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, i2cpexpo) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300533 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300534 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300535 goto err;
536 i2cp202[3] = sd->brightness >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300537 if (i2c_w(gspca_dev, i2cp202) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300538 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300539 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300540 goto err;
541 break;
542 }
Hans de Goededcef3232008-07-10 10:40:53 -0300543 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300544 __u8 i2c[] =
545 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
546
547 value = 0xff - sd->brightness;
548 i2c[4] = value;
549 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300550 if (i2c_w(gspca_dev, i2c) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300551 goto err;
552 break;
553 }
Hans de Goededcef3232008-07-10 10:40:53 -0300554 case SENSOR_TAS5110:
555 /* FIXME figure out howto control brightness on TAS5110 */
556 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300557 }
558 return;
559err:
560 PDEBUG(D_ERR, "i2c error brightness");
561}
Hans de Goededcef3232008-07-10 10:40:53 -0300562
563static void setsensorgain(struct gspca_dev *gspca_dev)
564{
565 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300566
567 switch (sd->sensor) {
568
569 case SENSOR_TAS5110: {
570 __u8 i2c[] =
571 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
572
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300573 i2c[4] = 255 - sd->gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300574 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300575 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300576 break;
577 }
Hans de Goededcef3232008-07-10 10:40:53 -0300578 case SENSOR_OV6650: {
579 __u8 i2c[] = {0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300580
581 i2c[3] = sd->gain >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300582 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300583 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300584 break;
585 }
Hans de Goededcef3232008-07-10 10:40:53 -0300586 }
587 return;
588err:
589 PDEBUG(D_ERR, "i2c error gain");
590}
591
592static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300593{
594 struct sd *sd = (struct sd *) gspca_dev;
595 __u8 gain;
596 __u8 rgb_value;
597
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300598 gain = sd->gain >> 4;
Hans de Goededcef3232008-07-10 10:40:53 -0300599
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300600 /* red and blue gain */
601 rgb_value = gain << 4 | gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300602 reg_w(gspca_dev, 0x10, &rgb_value, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300603 /* green gain */
604 rgb_value = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300605 reg_w(gspca_dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300606
607 if (sd->sensor_has_gain)
608 setsensorgain(gspca_dev);
609}
610
611static void setexposure(struct gspca_dev *gspca_dev)
612{
613 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300614
615 switch (sd->sensor) {
616 case SENSOR_TAS5110: {
617 __u8 reg;
618
619 /* register 19's high nibble contains the sn9c10x clock divider
620 The high nibble configures the no fps according to the
621 formula: 60 / high_nibble. With a maximum of 30 fps */
Hans de Goedef4d52022008-07-15 09:36:42 -0300622 reg = 120 * sd->exposure / 1000;
623 if (reg < 2)
624 reg = 2;
625 else if (reg > 15)
Hans de Goededcef3232008-07-10 10:40:53 -0300626 reg = 15;
627 reg = (reg << 4) | 0x0b;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300628 reg_w(gspca_dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300629 break;
630 }
Hans de Goededcef3232008-07-10 10:40:53 -0300631 case SENSOR_OV6650: {
Hans de Goedef4d52022008-07-15 09:36:42 -0300632 /* The ov6650 has 2 registers which both influence exposure,
633 first there is register 11, whose low nibble sets the no fps
634 according to: fps = 30 / (low_nibble + 1)
635
636 The fps configures the maximum exposure setting, but it is
637 possible to use less exposure then what the fps maximum
638 allows by setting register 10. register 10 configures the
639 actual exposure as quotient of the full exposure, with 0
640 being no exposure at all (not very usefull) and reg10_max
641 being max exposure possible at that framerate.
642
643 The code maps our 0 - 510 ms exposure ctrl to these 2
644 registers, trying to keep fps as high as possible.
645 */
646 __u8 i2c[] = {0xb0, 0x60, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
647 int reg10, reg11;
648 /* No clear idea why, but setting reg10 above this value
649 results in no change */
650 const int reg10_max = 0x4d;
651
652 reg11 = (60 * sd->exposure + 999) / 1000;
653 if (reg11 < 1)
654 reg11 = 1;
655 else if (reg11 > 16)
656 reg11 = 16;
657
658 /* frame exposure time in ms = 1000 * reg11 / 30 ->
659 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
660 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
661 if (reg10 < 1) /* 0 is a valid value, but is very _black_ */
662 reg10 = 1;
663 else if (reg10 > reg10_max)
664 reg10 = reg10_max;
665
666 /* Write reg 10 and reg11 low nibble */
667 i2c[3] = reg10;
668 i2c[4] |= reg11 - 1;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300669 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300670 PDEBUG(D_ERR, "i2c error exposure");
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300671 break;
672 }
Hans de Goededcef3232008-07-10 10:40:53 -0300673 }
674}
675
676
677static void do_autogain(struct gspca_dev *gspca_dev)
678{
679 struct sd *sd = (struct sd *) gspca_dev;
680 int avg_lum = atomic_read(&sd->avg_lum);
681
682 if (avg_lum == -1)
683 return;
684
685 if (sd->autogain_ignore_frames > 0)
686 sd->autogain_ignore_frames--;
687 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
688 sd->brightness * DESIRED_AVG_LUM / 127,
689 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE))
690 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300691}
692
693/* this function is called at probe time */
694static int sd_config(struct gspca_dev *gspca_dev,
695 const struct usb_device_id *id)
696{
697 struct sd *sd = (struct sd *) gspca_dev;
698 struct cam *cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300699 __u16 product;
700 int sif = 0;
701
Hans de Goededcef3232008-07-10 10:40:53 -0300702 /* nctrls depends upon the sensor, so we use a per cam copy */
703 memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
704 gspca_dev->sd_desc = &sd->sd_desc;
705
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300706 sd->fr_h_sz = 12; /* default size of the frame header */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300707 sd->sd_desc.nctrls = 2; /* default nb of ctrls */
Hans de Goededcef3232008-07-10 10:40:53 -0300708
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300709 product = id->idProduct;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300710/* switch (id->idVendor) { */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300711/* case 0x0c45: * Sonix */
712 switch (product) {
713 case 0x6001: /* SN9C102 */
714 case 0x6005: /* SN9C101 */
715 case 0x6007: /* SN9C101 */
716 sd->sensor = SENSOR_TAS5110;
Hans de Goededcef3232008-07-10 10:40:53 -0300717 sd->sensor_has_gain = 1;
718 sd->sd_desc.nctrls = 4;
719 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300720 sif = 1;
721 break;
722 case 0x6009: /* SN9C101 */
723 case 0x600d: /* SN9C101 */
724 case 0x6029: /* SN9C101 */
725 sd->sensor = SENSOR_PAS106;
726 sif = 1;
727 break;
728 case 0x6011: /* SN9C101 - SN9C101G */
729 sd->sensor = SENSOR_OV6650;
Hans de Goededcef3232008-07-10 10:40:53 -0300730 sd->sensor_has_gain = 1;
731 sd->sd_desc.nctrls = 4;
732 sd->sd_desc.dq_callback = do_autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300733 sif = 1;
734 break;
735 case 0x6019: /* SN9C101 */
736 case 0x602c: /* SN9C102 */
737 case 0x602e: /* SN9C102 */
738 sd->sensor = SENSOR_OV7630;
739 break;
740 case 0x60b0: /* SN9C103 */
741 sd->sensor = SENSOR_OV7630_3;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300742 sd->fr_h_sz = 18; /* size of frame header */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300743 break;
744 case 0x6024: /* SN9C102 */
745 case 0x6025: /* SN9C102 */
746 sd->sensor = SENSOR_TAS5130CXX;
747 break;
748 case 0x6028: /* SN9C102 */
749 sd->sensor = SENSOR_PAS202;
750 break;
751 case 0x602d: /* SN9C102 */
752 sd->sensor = SENSOR_HV7131R;
753 break;
754 case 0x60af: /* SN9C103 */
755 sd->sensor = SENSOR_PAS202;
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -0300756 sd->fr_h_sz = 18; /* size of frame header (?) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300757 break;
758 }
759/* break; */
760/* } */
761
762 cam = &gspca_dev->cam;
763 cam->dev_name = (char *) id->driver_info;
764 cam->epaddr = 0x01;
765 if (!sif) {
766 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300767 cam->nmodes = ARRAY_SIZE(vga_mode);
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300768 if (sd->sensor == SENSOR_OV7630_3) {
769 /* We only have 320x240 & 640x480 */
770 cam->cam_mode++;
771 cam->nmodes--;
772 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300773 } else {
774 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300775 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300776 }
Hans de Goededcef3232008-07-10 10:40:53 -0300777 sd->brightness = BRIGHTNESS_DEF;
778 sd->gain = GAIN_DEF;
779 sd->exposure = EXPOSURE_DEF;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300780 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300781 if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300782 reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300783 return 0;
784}
785
786/* this function is called at open time */
787static int sd_open(struct gspca_dev *gspca_dev)
788{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300789 reg_r(gspca_dev, 0x00);
790 if (gspca_dev->usb_buf[0] != 0x10)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300791 return -ENODEV;
792 return 0;
793}
794
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300795static void pas106_i2cinit(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300796{
797 int i;
798 const __u8 *data;
799 __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 };
800
801 i = ARRAY_SIZE(pas106_data);
802 data = pas106_data[0];
803 while (--i >= 0) {
804 memcpy(&i2c1[2], data, 2);
805 /* copy 2 bytes from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300806 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300807 PDEBUG(D_ERR, "i2c error pas106");
808 data += 2;
809 }
810}
811
812/* -- start the camera -- */
813static void sd_start(struct gspca_dev *gspca_dev)
814{
815 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300816 int mode, l;
817 const __u8 *sn9c10x;
818 __u8 reg01, reg17;
819 __u8 reg17_19[3];
820
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300821 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300822 switch (sd->sensor) {
823 case SENSOR_HV7131R:
824 sn9c10x = initHv7131;
825 reg17_19[0] = 0x60;
826 reg17_19[1] = (mode << 4) | 0x8a;
827 reg17_19[2] = 0x20;
828 break;
829 case SENSOR_OV6650:
830 sn9c10x = initOv6650;
831 reg17_19[0] = 0x68;
832 reg17_19[1] = (mode << 4) | 0x8b;
833 reg17_19[2] = 0x20;
834 break;
835 case SENSOR_OV7630:
836 sn9c10x = initOv7630;
837 reg17_19[0] = 0x68;
838 reg17_19[1] = (mode << 4) | COMP2;
839 reg17_19[2] = MCK_INIT1;
840 break;
841 case SENSOR_OV7630_3:
842 sn9c10x = initOv7630_3;
843 reg17_19[0] = 0x68;
844 reg17_19[1] = (mode << 4) | COMP2;
845 reg17_19[2] = MCK_INIT1;
846 break;
847 case SENSOR_PAS106:
848 sn9c10x = initPas106;
849 reg17_19[0] = 0x24; /* 0x28 */
850 reg17_19[1] = (mode << 4) | COMP1;
851 reg17_19[2] = MCK_INIT1;
852 break;
853 case SENSOR_PAS202:
854 sn9c10x = initPas202;
855 reg17_19[0] = mode ? 0x24 : 0x20;
856 reg17_19[1] = (mode << 4) | 0x89;
857 reg17_19[2] = 0x20;
858 break;
859 case SENSOR_TAS5110:
860 sn9c10x = initTas5110;
861 reg17_19[0] = 0x60;
862 reg17_19[1] = (mode << 4) | 0x86;
863 reg17_19[2] = 0x2b; /* 0xf3; */
864 break;
865 default:
866/* case SENSOR_TAS5130CXX: */
867 sn9c10x = initTas5130;
868 reg17_19[0] = 0x60;
869 reg17_19[1] = (mode << 4) | COMP;
870 reg17_19[2] = mode ? 0x23 : 0x43;
871 break;
872 }
873 switch (sd->sensor) {
874 case SENSOR_OV7630:
875 reg01 = 0x06;
876 reg17 = 0x29;
877 l = 0x10;
878 break;
879 case SENSOR_OV7630_3:
880 reg01 = 0x44;
881 reg17 = 0x68;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300882 l = sizeof initOv7630_3;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300883 break;
884 default:
885 reg01 = sn9c10x[0];
886 reg17 = sn9c10x[0x17 - 1];
887 l = 0x1f;
888 break;
889 }
890
891 /* reg 0x01 bit 2 video transfert on */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300892 reg_w(gspca_dev, 0x01, &reg01, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300893 /* reg 0x17 SensorClk enable inv Clk 0x60 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300894 reg_w(gspca_dev, 0x17, &reg17, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300895/*fixme: for ov7630 102
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300896 reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300897 /* Set the registers from the template */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300898 reg_w_big(gspca_dev, 0x01, sn9c10x, l);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300899 switch (sd->sensor) {
900 case SENSOR_HV7131R:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300901 i2c_w_vector(gspca_dev, hv7131_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300902 sizeof hv7131_sensor_init);
903 break;
904 case SENSOR_OV6650:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300905 i2c_w_vector(gspca_dev, ov6650_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300906 sizeof ov6650_sensor_init);
907 break;
908 case SENSOR_OV7630:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300909 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300910 sizeof ov7630_sensor_init_com);
911 msleep(200);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300912 i2c_w_vector(gspca_dev, ov7630_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300913 sizeof ov7630_sensor_init);
914 break;
915 case SENSOR_OV7630_3:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300916 i2c_w_vector(gspca_dev, ov7630_sensor_init_com,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300917 sizeof ov7630_sensor_init_com);
918 msleep(200);
Andoni Zubimendi4b972d22008-07-14 09:50:26 -0300919 i2c_w_vector(gspca_dev, ov7630_sensor_init_3[mode],
920 sizeof ov7630_sensor_init_3[mode]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300921 break;
922 case SENSOR_PAS106:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300923 pas106_i2cinit(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300924 break;
925 case SENSOR_PAS202:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300926 i2c_w_vector(gspca_dev, pas202_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300927 sizeof pas202_sensor_init);
928 break;
929 case SENSOR_TAS5110:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300930 i2c_w_vector(gspca_dev, tas5110_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300931 sizeof tas5110_sensor_init);
932 break;
933 default:
934/* case SENSOR_TAS5130CXX: */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300935 i2c_w_vector(gspca_dev, tas5130_sensor_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300936 sizeof tas5130_sensor_init);
937 break;
938 }
Hans de Goede3647fea2008-07-15 05:36:30 -0300939 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
940 reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300941 /* compression register */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300942 reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300943 if (sd->sensor != SENSOR_OV7630_3) {
944 /* H_start */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300945 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300946 /* V_START */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300947 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300948 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300949 /* reset 0x17 SensorClk enable inv Clk 0x60 */
950 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300951 reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300952 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300953 if (sd->sensor != SENSOR_OV7630_3)
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300954 reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300955 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300956 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300957 /* Enable video transfert */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300958 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300959 /* Compression */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300960 reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300961 msleep(20);
962
Hans de Goededcef3232008-07-10 10:40:53 -0300963 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300964 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -0300965 setexposure(gspca_dev);
966
967 sd->autogain_ignore_frames = 0;
968 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300969}
970
971static void sd_stopN(struct gspca_dev *gspca_dev)
972{
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300973 __u8 ByteSend;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300974
975 ByteSend = 0x09; /* 0X00 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300976 reg_w(gspca_dev, 0x01, &ByteSend, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300977}
978
979static void sd_stop0(struct gspca_dev *gspca_dev)
980{
981}
982
983static void sd_close(struct gspca_dev *gspca_dev)
984{
985}
986
987static void sd_pkt_scan(struct gspca_dev *gspca_dev,
988 struct gspca_frame *frame, /* target */
989 unsigned char *data, /* isoc packet */
990 int len) /* iso packet length */
991{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300992 int i;
Hans de Goededcef3232008-07-10 10:40:53 -0300993 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300994
995 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300996 for (i = 0; i < len - 6; i++) {
997 if (data[0 + i] == 0xff
998 && data[1 + i] == 0xff
999 && data[2 + i] == 0x00
1000 && data[3 + i] == 0xc4
1001 && data[4 + i] == 0xc4
1002 && data[5 + i] == 0x96) { /* start of frame */
1003 frame = gspca_frame_add(gspca_dev, LAST_PACKET,
1004 frame, data, 0);
Hans de Goededcef3232008-07-10 10:40:53 -03001005 if (i < (len - 10)) {
1006 atomic_set(&sd->avg_lum, data[i + 8] +
1007 (data[i + 9] << 8));
1008 } else {
1009 atomic_set(&sd->avg_lum, -1);
1010#ifdef CONFIG_VIDEO_ADV_DEBUG
1011 PDEBUG(D_STREAM, "packet too short to "
1012 "get avg brightness");
1013#endif
1014 }
Andoni Zubimendi553b9fa2008-07-06 07:27:19 -03001015 data += i + sd->fr_h_sz;
1016 len -= i + sd->fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001017 gspca_frame_add(gspca_dev, FIRST_PACKET,
1018 frame, data, len);
1019 return;
1020 }
1021 }
1022 }
1023 gspca_frame_add(gspca_dev, INTER_PACKET,
1024 frame, data, len);
1025}
1026
1027static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1028{
1029 struct sd *sd = (struct sd *) gspca_dev;
1030
1031 sd->brightness = val;
1032 if (gspca_dev->streaming)
1033 setbrightness(gspca_dev);
1034 return 0;
1035}
1036
1037static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1038{
1039 struct sd *sd = (struct sd *) gspca_dev;
1040
1041 *val = sd->brightness;
1042 return 0;
1043}
1044
Hans de Goededcef3232008-07-10 10:40:53 -03001045static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001046{
1047 struct sd *sd = (struct sd *) gspca_dev;
1048
Hans de Goededcef3232008-07-10 10:40:53 -03001049 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001050 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -03001051 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001052 return 0;
1053}
1054
Hans de Goededcef3232008-07-10 10:40:53 -03001055static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001056{
1057 struct sd *sd = (struct sd *) gspca_dev;
1058
Hans de Goededcef3232008-07-10 10:40:53 -03001059 *val = sd->gain;
1060 return 0;
1061}
1062
1063static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1064{
1065 struct sd *sd = (struct sd *) gspca_dev;
1066
1067 sd->exposure = val;
1068 if (gspca_dev->streaming)
1069 setexposure(gspca_dev);
1070 return 0;
1071}
1072
1073static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1074{
1075 struct sd *sd = (struct sd *) gspca_dev;
1076
1077 *val = sd->exposure;
1078 return 0;
1079}
1080
1081static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1082{
1083 struct sd *sd = (struct sd *) gspca_dev;
1084
1085 sd->autogain = val;
1086 /* when switching to autogain set defaults to make sure
1087 we are on a valid point of the autogain gain /
1088 exposure knee graph, and give this change time to
1089 take effect before doing autogain. */
1090 if (sd->autogain) {
1091 sd->exposure = EXPOSURE_DEF;
1092 sd->gain = GAIN_DEF;
1093 if (gspca_dev->streaming) {
1094 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1095 setexposure(gspca_dev);
1096 setgain(gspca_dev);
1097 }
1098 }
1099
1100 return 0;
1101}
1102
1103static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1104{
1105 struct sd *sd = (struct sd *) gspca_dev;
1106
1107 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001108 return 0;
1109}
1110
1111/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001112static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001113 .name = MODULE_NAME,
1114 .ctrls = sd_ctrls,
1115 .nctrls = ARRAY_SIZE(sd_ctrls),
1116 .config = sd_config,
1117 .open = sd_open,
1118 .start = sd_start,
1119 .stopN = sd_stopN,
1120 .stop0 = sd_stop0,
1121 .close = sd_close,
1122 .pkt_scan = sd_pkt_scan,
1123};
1124
1125/* -- module initialisation -- */
1126#define DVNM(name) .driver_info = (kernel_ulong_t) name
1127static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001128#ifndef CONFIG_USB_SN9C102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001129 {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")},
1130 {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")},
1131 {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")},
1132 {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")},
1133 {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")},
Jean-Francois Moine956e42d2008-07-01 10:03:42 -03001134 {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001135 {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")},
1136 {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")},
1137 {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")},
1138 {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")},
1139 {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")},
1140 {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")},
1141 {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")},
1142 {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")},
1143 {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")},
1144 {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001145#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001146 {}
1147};
1148MODULE_DEVICE_TABLE(usb, device_table);
1149
1150/* -- device connect -- */
1151static int sd_probe(struct usb_interface *intf,
1152 const struct usb_device_id *id)
1153{
1154 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1155 THIS_MODULE);
1156}
1157
1158static struct usb_driver sd_driver = {
1159 .name = MODULE_NAME,
1160 .id_table = device_table,
1161 .probe = sd_probe,
1162 .disconnect = gspca_disconnect,
1163};
1164
1165/* -- module insert / remove -- */
1166static int __init sd_mod_init(void)
1167{
1168 if (usb_register(&sd_driver) < 0)
1169 return -1;
1170 PDEBUG(D_PROBE, "v%s registered", version);
1171 return 0;
1172}
1173static void __exit sd_mod_exit(void)
1174{
1175 usb_deregister(&sd_driver);
1176 PDEBUG(D_PROBE, "deregistered");
1177}
1178
1179module_init(sd_mod_init);
1180module_exit(sd_mod_exit);