blob: 8eaeaa3a96d7b5207b4d24f7f38d72662db8bcad [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
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030027MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
28MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
29MODULE_LICENSE("GPL");
30
31/* specific webcam descriptor */
32struct sd {
33 struct gspca_dev gspca_dev; /* !! must be the first item */
Hans de Goededcef3232008-07-10 10:40:53 -030034 atomic_t avg_lum;
35
Hans de Goedead5ef80d2008-07-14 10:11:42 -030036 unsigned char gain;
37 unsigned char exposure;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030038 unsigned char brightness;
Hans de Goededcef3232008-07-10 10:40:53 -030039 unsigned char autogain;
40 unsigned char autogain_ignore_frames;
Hans de Goede6af492e2008-07-22 07:09:33 -030041 unsigned char frames_to_drop;
Hans de Goede66f35822008-07-16 10:16:28 -030042 unsigned char freq; /* light freq filter setting */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030043
Hans de Goedef45f06b2008-09-03 17:12:21 -030044 __u8 bridge; /* Type of bridge */
45#define BRIDGE_101 0
46#define BRIDGE_102 0 /* We make no difference between 101 and 102 */
47#define BRIDGE_103 1
48
49 __u8 sensor; /* Type of image sensor chip */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030050#define SENSOR_HV7131R 0
51#define SENSOR_OV6650 1
52#define SENSOR_OV7630 2
Hans de Goede6af492e2008-07-22 07:09:33 -030053#define SENSOR_PAS106 3
54#define SENSOR_PAS202 4
55#define SENSOR_TAS5110 5
56#define SENSOR_TAS5130CXX 6
Hans de Goede6af492e2008-07-22 07:09:33 -030057 __u8 reg11;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030058};
59
Hans de Goedef45f06b2008-09-03 17:12:21 -030060typedef const __u8 sensor_init_t[8];
61
62struct sensor_data {
63 const __u8 *bridge_init[2];
64 int bridge_init_size[2];
65 sensor_init_t *sensor_init;
66 int sensor_init_size;
67 sensor_init_t *sensor_bridge_init[2];
68 int sensor_bridge_init_size[2];
69 int flags;
70 unsigned ctrl_dis;
71 __u8 sensor_addr;
72};
73
74/* sensor_data flags */
Jean-Francois Moine5da162e2008-07-26 14:17:23 -030075#define F_GAIN 0x01 /* has gain */
Hans de Goedee2ad2a52008-09-03 17:12:15 -030076#define F_SIF 0x02 /* sif or vga */
Hans de Goedef45f06b2008-09-03 17:12:21 -030077
78/* ctrl_dis helper macros */
79#define NO_EXPO ((1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX))
80#define NO_FREQ (1 << FREQ_IDX)
81#define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX)
Jean-Francois Moine5da162e2008-07-26 14:17:23 -030082
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030083#define COMP2 0x8f
84#define COMP 0xc7 /* 0x87 //0x07 */
85#define COMP1 0xc9 /* 0x89 //0x09 */
86
87#define MCK_INIT 0x63
88#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
89
90#define SYS_CLK 0x04
91
Hans de Goedef45f06b2008-09-03 17:12:21 -030092#define SENS(bridge_1, bridge_3, sensor, sensor_1, \
93 sensor_3, _flags, _ctrl_dis, _sensor_addr) \
94{ \
95 .bridge_init = { bridge_1, bridge_3 }, \
96 .bridge_init_size = { sizeof(bridge_1), sizeof(bridge_3) }, \
97 .sensor_init = sensor, \
98 .sensor_init_size = sizeof(sensor), \
99 .sensor_bridge_init = { sensor_1, sensor_3,}, \
100 .sensor_bridge_init_size = { sizeof(sensor_1), sizeof(sensor_3)}, \
101 .flags = _flags, .ctrl_dis = _ctrl_dis, .sensor_addr = _sensor_addr \
102}
103
Hans de Goededcef3232008-07-10 10:40:53 -0300104/* We calculate the autogain at the end of the transfer of a frame, at this
105 moment a frame with the old settings is being transmitted, and a frame is
106 being captured with the old settings. So if we adjust the autogain we must
107 ignore atleast the 2 next frames for the new settings to come into effect
108 before doing any other adjustments */
109#define AUTOGAIN_IGNORE_FRAMES 3
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300110#define AUTOGAIN_DEADZONE 1000
Hans de Goededcef3232008-07-10 10:40:53 -0300111#define DESIRED_AVG_LUM 7000
112
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300113/* V4L2 controls supported by the driver */
114static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
115static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goededcef3232008-07-10 10:40:53 -0300116static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
117static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
118static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
119static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
120static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
121static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede66f35822008-07-16 10:16:28 -0300122static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
123static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300124
125static struct ctrl sd_ctrls[] = {
Hans de Goedee2ad2a52008-09-03 17:12:15 -0300126#define BRIGHTNESS_IDX 0
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300127 {
128 {
129 .id = V4L2_CID_BRIGHTNESS,
130 .type = V4L2_CTRL_TYPE_INTEGER,
131 .name = "Brightness",
132 .minimum = 0,
133 .maximum = 255,
134 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -0300135#define BRIGHTNESS_DEF 127
136 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300137 },
138 .set = sd_setbrightness,
139 .get = sd_getbrightness,
140 },
Hans de Goedee2ad2a52008-09-03 17:12:15 -0300141#define GAIN_IDX 1
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300142 {
143 {
Hans de Goededcef3232008-07-10 10:40:53 -0300144 .id = V4L2_CID_GAIN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300145 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goededcef3232008-07-10 10:40:53 -0300146 .name = "Gain",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300147 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300148 .maximum = 255,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300149 .step = 1,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300150#define GAIN_DEF 127
151#define GAIN_KNEE 200
Hans de Goededcef3232008-07-10 10:40:53 -0300152 .default_value = GAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300153 },
Hans de Goededcef3232008-07-10 10:40:53 -0300154 .set = sd_setgain,
155 .get = sd_getgain,
156 },
Hans de Goedee2ad2a52008-09-03 17:12:15 -0300157#define EXPOSURE_IDX 2
Hans de Goededcef3232008-07-10 10:40:53 -0300158 {
159 {
160 .id = V4L2_CID_EXPOSURE,
161 .type = V4L2_CTRL_TYPE_INTEGER,
162 .name = "Exposure",
Hans de Goedef4d52022008-07-15 09:36:42 -0300163#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
164#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
Hans de Goededcef3232008-07-10 10:40:53 -0300165 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300166 .maximum = 255,
Hans de Goededcef3232008-07-10 10:40:53 -0300167 .step = 1,
168 .default_value = EXPOSURE_DEF,
169 .flags = 0,
170 },
171 .set = sd_setexposure,
172 .get = sd_getexposure,
173 },
Hans de Goedee2ad2a52008-09-03 17:12:15 -0300174#define AUTOGAIN_IDX 3
Hans de Goededcef3232008-07-10 10:40:53 -0300175 {
176 {
177 .id = V4L2_CID_AUTOGAIN,
178 .type = V4L2_CTRL_TYPE_BOOLEAN,
179 .name = "Automatic Gain (and Exposure)",
180 .minimum = 0,
181 .maximum = 1,
182 .step = 1,
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300183#define AUTOGAIN_DEF 1
184 .default_value = AUTOGAIN_DEF,
Hans de Goededcef3232008-07-10 10:40:53 -0300185 .flags = 0,
186 },
187 .set = sd_setautogain,
188 .get = sd_getautogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300189 },
Hans de Goedee2ad2a52008-09-03 17:12:15 -0300190#define FREQ_IDX 4
Hans de Goede66f35822008-07-16 10:16:28 -0300191 {
192 {
193 .id = V4L2_CID_POWER_LINE_FREQUENCY,
194 .type = V4L2_CTRL_TYPE_MENU,
195 .name = "Light frequency filter",
196 .minimum = 0,
197 .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
198 .step = 1,
199#define FREQ_DEF 1
200 .default_value = FREQ_DEF,
201 },
202 .set = sd_setfreq,
203 .get = sd_getfreq,
204 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300205};
206
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300207static struct v4l2_pix_format vga_mode[] = {
208 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
209 .bytesperline = 160,
210 .sizeimage = 160 * 120,
211 .colorspace = V4L2_COLORSPACE_SRGB,
212 .priv = 2},
213 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
214 .bytesperline = 320,
215 .sizeimage = 320 * 240,
216 .colorspace = V4L2_COLORSPACE_SRGB,
217 .priv = 1},
218 {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
219 .bytesperline = 640,
220 .sizeimage = 640 * 480,
221 .colorspace = V4L2_COLORSPACE_SRGB,
222 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300223};
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300224static struct v4l2_pix_format sif_mode[] = {
225 {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
226 .bytesperline = 176,
227 .sizeimage = 176 * 144,
228 .colorspace = V4L2_COLORSPACE_SRGB,
229 .priv = 1},
230 {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
231 .bytesperline = 352,
232 .sizeimage = 352 * 288,
233 .colorspace = V4L2_COLORSPACE_SRGB,
234 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300235};
236
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300237static const __u8 initHv7131[] = {
238 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
239 0x00, 0x00,
240 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */
241 0x28, 0x1e, 0x60, 0x8a, 0x20,
242 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
243};
244static const __u8 hv7131_sensor_init[][8] = {
245 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
246 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
247 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
248 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
249 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
250};
251static const __u8 initOv6650[] = {
252 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
253 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Hans de Goedef45f06b2008-09-03 17:12:21 -0300254 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300255 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
256};
257static const __u8 ov6650_sensor_init[][8] =
258{
259 /* Bright, contrast, etc are set througth SCBB interface.
260 * AVCAP on win2 do not send any data on this controls. */
261 /* Anyway, some registers appears to alter bright and constrat */
Hans de Goededcef3232008-07-10 10:40:53 -0300262
263 /* Reset sensor */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300264 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300265 /* Set clock register 0x11 low nibble is clock divider */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300266 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300267 /* Next some unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300268 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
269/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
270 * THIS SET GREEN SCREEN
271 * (pixels could be innverted in decode kind of "brg",
272 * but blue wont be there. Avoid this data ... */
273 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
274 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
275 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
Hans de Goede722103e2008-07-17 10:24:47 -0300276 /* Enable rgb brightness control */
277 {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
278 /* HDG: Note windows uses the line below, which sets both register 0x60
279 and 0x61 I believe these registers of the ov6650 are identical as
280 those of the ov7630, because if this is true the windows settings
281 add a bit additional red gain and a lot additional blue gain, which
282 matches my findings that the windows settings make blue much too
283 blue and red a little too red.
284 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */
Hans de Goededcef3232008-07-10 10:40:53 -0300285 /* Some more unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300286 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
287 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300288};
Hans de Goededcef3232008-07-10 10:40:53 -0300289
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300290static const __u8 initOv7630[] = {
291 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
292 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
293 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
294 0x28, 0x1e, /* H & V sizes r15 .. r16 */
Hans de Goedef45f06b2008-09-03 17:12:21 -0300295 0x68, COMP2, MCK_INIT1, /* r17 .. r19 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300296 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
297};
298static const __u8 initOv7630_3[] = {
299 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
300 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300301 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
Hans de Goede3647fea2008-07-15 05:36:30 -0300302 0x28, 0x1e, /* H & V sizes r15 .. r16 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300303 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
304 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
305 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
306 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300307};
Hans de Goede6af492e2008-07-22 07:09:33 -0300308static const __u8 ov7630_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300309 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
310 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
311/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300312 {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300313 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
314 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
315 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
316 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
317 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
318 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
319 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
Andoni Zubimendi794af522008-07-16 08:33:14 -0300320 {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
321/* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300322 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
323 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
324 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
325 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
326 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
327 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
328};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300329
Hans de Goedef45f06b2008-09-03 17:12:21 -0300330static const __u8 ov7630_sensor_init_3[][8] = {
331 {0xa0, 0x21, 0x13, 0x80, 0x00, 0x00, 0x00, 0x10},
332};
333
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300334static const __u8 initPas106[] = {
335 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
336 0x00, 0x00,
337 0x00, 0x00, 0x00, 0x05, 0x01, 0x00,
Hans de Goedef45f06b2008-09-03 17:12:21 -0300338 0x16, 0x12, 0x24, COMP1, MCK_INIT1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300339 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
340};
341/* compression 0x86 mckinit1 0x2b */
Hans de Goedef45f06b2008-09-03 17:12:21 -0300342static const __u8 pas106_sensor_init[][8] = {
343 /* Pixel Clock Divider 6 */
344 { 0xa1, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14 },
345 /* Frame Time MSB (also seen as 0x12) */
346 { 0xa1, 0x40, 0x03, 0x13, 0x00, 0x00, 0x00, 0x14 },
347 /* Frame Time LSB (also seen as 0x05) */
348 { 0xa1, 0x40, 0x04, 0x06, 0x00, 0x00, 0x00, 0x14 },
349 /* Shutter Time Line Offset (also seen as 0x6d) */
350 { 0xa1, 0x40, 0x05, 0x65, 0x00, 0x00, 0x00, 0x14 },
351 /* Shutter Time Pixel Offset (also seen as 0xb1) */
352 { 0xa1, 0x40, 0x06, 0xcd, 0x00, 0x00, 0x00, 0x14 },
353 /* Black Level Subtract Sign (also seen 0x00) */
354 { 0xa1, 0x40, 0x07, 0xc1, 0x00, 0x00, 0x00, 0x14 },
355 /* Black Level Subtract Level (also seen 0x01) */
356 { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 },
357 { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 },
358 /* Color Gain B Pixel 5 a */
359 { 0xa1, 0x40, 0x09, 0x05, 0x00, 0x00, 0x00, 0x14 },
360 /* Color Gain G1 Pixel 1 5 */
361 { 0xa1, 0x40, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x14 },
362 /* Color Gain G2 Pixel 1 0 5 */
363 { 0xa1, 0x40, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x14 },
364 /* Color Gain R Pixel 3 1 */
365 { 0xa1, 0x40, 0x0c, 0x05, 0x00, 0x00, 0x00, 0x14 },
366 /* Color GainH Pixel */
367 { 0xa1, 0x40, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x14 },
368 /* Global Gain */
369 { 0xa1, 0x40, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x14 },
370 /* Contrast */
371 { 0xa1, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14 },
372 /* H&V synchro polarity */
373 { 0xa1, 0x40, 0x10, 0x06, 0x00, 0x00, 0x00, 0x14 },
374 /* ?default */
375 { 0xa1, 0x40, 0x11, 0x06, 0x00, 0x00, 0x00, 0x14 },
376 /* DAC scale */
377 { 0xa1, 0x40, 0x12, 0x06, 0x00, 0x00, 0x00, 0x14 },
378 /* ?default */
379 { 0xa1, 0x40, 0x14, 0x02, 0x00, 0x00, 0x00, 0x14 },
380 /* Validate Settings */
381 { 0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300382};
Hans de Goedef45f06b2008-09-03 17:12:21 -0300383
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300384static const __u8 initPas202[] = {
385 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
386 0x00, 0x00,
387 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */
Hans de Goedef45f06b2008-09-03 17:12:21 -0300388 0x28, 0x1e, 0x28, 0x89, 0x20,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300389 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
390};
391static const __u8 pas202_sensor_init[][8] = {
392 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
393 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
394 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
395 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
396 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
397 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
398 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
399 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
400 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
401 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
402 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
403 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
404
405 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
406 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
407 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
408 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
409 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
410 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
411 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
412 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
413};
414
415static const __u8 initTas5110[] = {
416 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
417 0x00, 0x00,
418 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */
419 0x16, 0x12, 0x60, 0x86, 0x2b,
420 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
421};
422static const __u8 tas5110_sensor_init[][8] = {
423 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
424 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
425 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
426};
427
428static const __u8 initTas5130[] = {
429 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
430 0x00, 0x00,
431 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a,
432 0x28, 0x1e, 0x60, COMP, MCK_INIT,
433 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
434};
435static const __u8 tas5130_sensor_init[][8] = {
436/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
437 * shutter 0x47 short exposure? */
438 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
439 /* shutter 0x01 long exposure */
440 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
441};
442
Hans de Goedef45f06b2008-09-03 17:12:21 -0300443struct sensor_data sensor_data[] = {
444SENS(initHv7131, NULL, hv7131_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, 0),
445SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60),
446SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
447 F_GAIN, 0, 0x21),
448SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_SIF, NO_EXPO|NO_FREQ,
449 0),
450SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, 0,
451 NO_EXPO|NO_FREQ, 0),
452SENS(initTas5110, NULL, tas5110_sensor_init, NULL, NULL, F_GAIN|F_SIF,
453 NO_BRIGHTNESS|NO_FREQ, 0),
454SENS(initTas5130, NULL, tas5130_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ,
455 0),
456};
457
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300458/* get one byte in gspca_dev->usb_buf */
459static void reg_r(struct gspca_dev *gspca_dev,
460 __u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300461{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300462 usb_control_msg(gspca_dev->dev,
463 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300464 0, /* request */
465 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
466 value,
467 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300468 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300469 500);
470}
471
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300472static void reg_w(struct gspca_dev *gspca_dev,
473 __u16 value,
474 const __u8 *buffer,
475 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300476{
Jean-Francois Moine335b3f82008-07-30 04:53:02 -0300477#ifdef GSPCA_DEBUG
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300478 if (len > USB_BUF_SZ) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300479 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
480 return;
481 }
482#endif
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300483 memcpy(gspca_dev->usb_buf, buffer, len);
484 usb_control_msg(gspca_dev->dev,
485 usb_sndctrlpipe(gspca_dev->dev, 0),
486 0x08, /* request */
487 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
488 value,
489 0, /* index */
490 gspca_dev->usb_buf, len,
491 500);
492}
493
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300494static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300495{
496 int retry = 60;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300497
498 /* is i2c ready */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300499 reg_w(gspca_dev, 0x08, buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300500 while (retry--) {
501 msleep(10);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300502 reg_r(gspca_dev, 0x08);
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300503 if (gspca_dev->usb_buf[0] & 0x04) {
504 if (gspca_dev->usb_buf[0] & 0x08)
505 return -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300506 return 0;
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300507 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300508 }
509 return -1;
510}
511
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300512static void i2c_w_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300513 const __u8 buffer[][8], int len)
514{
515 for (;;) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300516 reg_w(gspca_dev, 0x08, *buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300517 len -= 8;
518 if (len <= 0)
519 break;
520 buffer++;
521 }
522}
523
524static void setbrightness(struct gspca_dev *gspca_dev)
525{
526 struct sd *sd = (struct sd *) gspca_dev;
527 __u8 value;
528
529 switch (sd->sensor) {
Hans de Goedea975a522008-07-16 15:29:11 -0300530 case SENSOR_OV6650:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300531 case SENSOR_OV7630: {
532 __u8 i2cOV[] =
Hans de Goedea975a522008-07-16 15:29:11 -0300533 {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300534
535 /* change reg 0x06 */
Hans de Goedef45f06b2008-09-03 17:12:21 -0300536 i2cOV[1] = sensor_data[sd->sensor].sensor_addr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300537 i2cOV[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300538 if (i2c_w(gspca_dev, i2cOV) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300539 goto err;
540 break;
541 }
542 case SENSOR_PAS106: {
543 __u8 i2c1[] =
544 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
545
546 i2c1[3] = sd->brightness >> 3;
547 i2c1[2] = 0x0e;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300548 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300549 goto err;
550 i2c1[3] = 0x01;
551 i2c1[2] = 0x13;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300552 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300553 goto err;
554 break;
555 }
556 case SENSOR_PAS202: {
557 /* __u8 i2cpexpo1[] =
558 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
559 __u8 i2cpexpo[] =
560 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
561 __u8 i2cp202[] =
562 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
563 static __u8 i2cpdoit[] =
564 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
565
566 /* change reg 0x10 */
567 i2cpexpo[4] = 0xff - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300568/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300569 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300570/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300571 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300572 if (i2c_w(gspca_dev, i2cpexpo) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300573 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300574 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300575 goto err;
576 i2cp202[3] = sd->brightness >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300577 if (i2c_w(gspca_dev, i2cp202) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300578 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300579 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300580 goto err;
581 break;
582 }
Hans de Goededcef3232008-07-10 10:40:53 -0300583 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300584 __u8 i2c[] =
585 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
586
587 value = 0xff - sd->brightness;
588 i2c[4] = value;
589 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300590 if (i2c_w(gspca_dev, i2c) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300591 goto err;
592 break;
593 }
594 }
595 return;
596err:
597 PDEBUG(D_ERR, "i2c error brightness");
598}
Hans de Goededcef3232008-07-10 10:40:53 -0300599
600static void setsensorgain(struct gspca_dev *gspca_dev)
601{
602 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea975a522008-07-16 15:29:11 -0300603 unsigned char gain = sd->gain;
Hans de Goededcef3232008-07-10 10:40:53 -0300604
605 switch (sd->sensor) {
606
607 case SENSOR_TAS5110: {
608 __u8 i2c[] =
609 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
610
Hans de Goedea975a522008-07-16 15:29:11 -0300611 i2c[4] = 255 - gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300612 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300613 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300614 break;
615 }
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300616
Hans de Goedea975a522008-07-16 15:29:11 -0300617 case SENSOR_OV6650:
618 gain >>= 1;
619 /* fall thru */
Hans de Goede6af492e2008-07-22 07:09:33 -0300620 case SENSOR_OV7630: {
Hans de Goedea975a522008-07-16 15:29:11 -0300621 __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Andoni Zubimendi794af522008-07-16 08:33:14 -0300622
Hans de Goedef45f06b2008-09-03 17:12:21 -0300623 i2c[1] = sensor_data[sd->sensor].sensor_addr;
Hans de Goedea975a522008-07-16 15:29:11 -0300624 i2c[3] = gain >> 2;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300625 if (i2c_w(gspca_dev, i2c) < 0)
626 goto err;
627 break;
628 }
Hans de Goededcef3232008-07-10 10:40:53 -0300629 }
630 return;
631err:
632 PDEBUG(D_ERR, "i2c error gain");
633}
634
635static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300636{
637 struct sd *sd = (struct sd *) gspca_dev;
638 __u8 gain;
639 __u8 rgb_value;
640
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300641 gain = sd->gain >> 4;
Hans de Goededcef3232008-07-10 10:40:53 -0300642
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300643 /* red and blue gain */
644 rgb_value = gain << 4 | gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300645 reg_w(gspca_dev, 0x10, &rgb_value, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300646 /* green gain */
647 rgb_value = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300648 reg_w(gspca_dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300649
Hans de Goedef45f06b2008-09-03 17:12:21 -0300650 if (sensor_data[sd->sensor].flags & F_GAIN)
Hans de Goededcef3232008-07-10 10:40:53 -0300651 setsensorgain(gspca_dev);
652}
653
654static void setexposure(struct gspca_dev *gspca_dev)
655{
656 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300657
658 switch (sd->sensor) {
659 case SENSOR_TAS5110: {
660 __u8 reg;
661
662 /* register 19's high nibble contains the sn9c10x clock divider
663 The high nibble configures the no fps according to the
664 formula: 60 / high_nibble. With a maximum of 30 fps */
Hans de Goedef4d52022008-07-15 09:36:42 -0300665 reg = 120 * sd->exposure / 1000;
666 if (reg < 2)
667 reg = 2;
668 else if (reg > 15)
Hans de Goededcef3232008-07-10 10:40:53 -0300669 reg = 15;
670 reg = (reg << 4) | 0x0b;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300671 reg_w(gspca_dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300672 break;
673 }
Hans de Goedea975a522008-07-16 15:29:11 -0300674 case SENSOR_OV6650:
Hans de Goede6af492e2008-07-22 07:09:33 -0300675 case SENSOR_OV7630: {
Hans de Goedea975a522008-07-16 15:29:11 -0300676 /* The ov6650 / ov7630 have 2 registers which both influence
677 exposure, register 11, whose low nibble sets the nr off fps
Hans de Goedef4d52022008-07-15 09:36:42 -0300678 according to: fps = 30 / (low_nibble + 1)
679
680 The fps configures the maximum exposure setting, but it is
681 possible to use less exposure then what the fps maximum
682 allows by setting register 10. register 10 configures the
683 actual exposure as quotient of the full exposure, with 0
684 being no exposure at all (not very usefull) and reg10_max
685 being max exposure possible at that framerate.
686
687 The code maps our 0 - 510 ms exposure ctrl to these 2
688 registers, trying to keep fps as high as possible.
689 */
Hans de Goede6af492e2008-07-22 07:09:33 -0300690 __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10};
691 int reg10, reg11, reg10_max;
692
Hans de Goede66f35822008-07-16 10:16:28 -0300693 /* ov6645 datasheet says reg10_max is 9a, but that uses
694 tline * 2 * reg10 as formula for calculating texpo, the
695 ov6650 probably uses the same formula as the 7730 which uses
696 tline * 4 * reg10, which explains why the reg10max we've
697 found experimentally for the ov6650 is exactly half that of
Hans de Goedea975a522008-07-16 15:29:11 -0300698 the ov6645. The ov7630 datasheet says the max is 0x41. */
Hans de Goede6af492e2008-07-22 07:09:33 -0300699 if (sd->sensor == SENSOR_OV6650) {
700 reg10_max = 0x4d;
701 i2c[4] = 0xc0; /* OV6650 needs non default vsync pol */
702 } else
703 reg10_max = 0x41;
Hans de Goedef4d52022008-07-15 09:36:42 -0300704
705 reg11 = (60 * sd->exposure + 999) / 1000;
706 if (reg11 < 1)
707 reg11 = 1;
708 else if (reg11 > 16)
709 reg11 = 16;
710
Hans de Goedee2ad2a52008-09-03 17:12:15 -0300711 /* In 640x480, if the reg11 has less than 3, the image is
712 unstable (not enough bandwidth). */
713 if (gspca_dev->width == 640 && reg11 < 3)
714 reg11 = 3;
715
Hans de Goedef4d52022008-07-15 09:36:42 -0300716 /* frame exposure time in ms = 1000 * reg11 / 30 ->
717 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
718 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
Hans de Goedea975a522008-07-16 15:29:11 -0300719
720 /* Don't allow this to get below 10 when using autogain, the
721 steps become very large (relatively) when below 10 causing
722 the image to oscilate from much too dark, to much too bright
723 and back again. */
724 if (sd->autogain && reg10 < 10)
725 reg10 = 10;
Hans de Goedef4d52022008-07-15 09:36:42 -0300726 else if (reg10 > reg10_max)
727 reg10 = reg10_max;
728
729 /* Write reg 10 and reg11 low nibble */
Hans de Goedef45f06b2008-09-03 17:12:21 -0300730 i2c[1] = sensor_data[sd->sensor].sensor_addr;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300731 i2c[3] = reg10;
732 i2c[4] |= reg11 - 1;
Hans de Goede6af492e2008-07-22 07:09:33 -0300733
734 /* If register 11 didn't change, don't change it */
735 if (sd->reg11 == reg11 )
736 i2c[0] = 0xa0;
737
738 if (i2c_w(gspca_dev, i2c) == 0)
739 sd->reg11 = reg11;
740 else
Andoni Zubimendi794af522008-07-16 08:33:14 -0300741 PDEBUG(D_ERR, "i2c error exposure");
742 break;
743 }
Hans de Goededcef3232008-07-10 10:40:53 -0300744 }
745}
746
Hans de Goede66f35822008-07-16 10:16:28 -0300747static void setfreq(struct gspca_dev *gspca_dev)
748{
749 struct sd *sd = (struct sd *) gspca_dev;
750
751 switch (sd->sensor) {
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300752 case SENSOR_OV6650:
Hans de Goede6af492e2008-07-22 07:09:33 -0300753 case SENSOR_OV7630: {
Hans de Goede66f35822008-07-16 10:16:28 -0300754 /* Framerate adjust register for artificial light 50 hz flicker
Hans de Goede6af492e2008-07-22 07:09:33 -0300755 compensation, for the ov6650 this is identical to ov6630
756 0x2b register, see ov6630 datasheet.
757 0x4f / 0x8a -> (30 fps -> 25 fps), 0x00 -> no adjustment */
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300758 __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans de Goede66f35822008-07-16 10:16:28 -0300759 switch (sd->freq) {
760 default:
761/* case 0: * no filter*/
762/* case 2: * 60 hz */
763 i2c[3] = 0;
764 break;
765 case 1: /* 50 hz */
Hans de Goede722103e2008-07-17 10:24:47 -0300766 i2c[3] = (sd->sensor == SENSOR_OV6650)
767 ? 0x4f : 0x8a;
Hans de Goede66f35822008-07-16 10:16:28 -0300768 break;
769 }
Hans de Goedef45f06b2008-09-03 17:12:21 -0300770 i2c[1] = sensor_data[sd->sensor].sensor_addr;
Hans de Goede66f35822008-07-16 10:16:28 -0300771 if (i2c_w(gspca_dev, i2c) < 0)
772 PDEBUG(D_ERR, "i2c error setfreq");
773 break;
774 }
775 }
776}
777
Hans de Goededcef3232008-07-10 10:40:53 -0300778static void do_autogain(struct gspca_dev *gspca_dev)
779{
780 struct sd *sd = (struct sd *) gspca_dev;
781 int avg_lum = atomic_read(&sd->avg_lum);
782
783 if (avg_lum == -1)
784 return;
785
786 if (sd->autogain_ignore_frames > 0)
787 sd->autogain_ignore_frames--;
788 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
789 sd->brightness * DESIRED_AVG_LUM / 127,
Hans de Goedea975a522008-07-16 15:29:11 -0300790 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
791 PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
792 (int)sd->gain, (int)sd->exposure);
Hans de Goededcef3232008-07-10 10:40:53 -0300793 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Hans de Goedea975a522008-07-16 15:29:11 -0300794 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300795}
796
797/* this function is called at probe time */
798static int sd_config(struct gspca_dev *gspca_dev,
799 const struct usb_device_id *id)
800{
801 struct sd *sd = (struct sd *) gspca_dev;
802 struct cam *cam;
Hans de Goede65f33392008-09-03 17:12:15 -0300803
804 reg_r(gspca_dev, 0x00);
805 if (gspca_dev->usb_buf[0] != 0x10)
806 return -ENODEV;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300807
Jean-Francois Moine5da162e2008-07-26 14:17:23 -0300808 /* copy the webcam info from the device id */
Hans de Goedef45f06b2008-09-03 17:12:21 -0300809 sd->sensor = id->driver_info >> 8;
810 sd->bridge = id->driver_info & 0xff;
811 gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300812
813 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300814 cam->epaddr = 0x01;
Hans de Goedef45f06b2008-09-03 17:12:21 -0300815 if (!(sensor_data[sd->sensor].flags & F_SIF)) {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300816 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300817 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300818 } else {
819 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300820 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300821 }
Hans de Goededcef3232008-07-10 10:40:53 -0300822 sd->brightness = BRIGHTNESS_DEF;
823 sd->gain = GAIN_DEF;
824 sd->exposure = EXPOSURE_DEF;
Hans de Goedee2ad2a52008-09-03 17:12:15 -0300825 if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
826 sd->autogain = 0; /* Disable do_autogain callback */
827 else
828 sd->autogain = AUTOGAIN_DEF;
Hans de Goede12ff9122008-07-17 10:30:56 -0300829 sd->freq = FREQ_DEF;
Hans de Goede6af492e2008-07-22 07:09:33 -0300830
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300831 return 0;
832}
833
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300834/* this function is called at probe and resume time */
835static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300836{
Hans de Goede271315a2008-09-03 17:12:19 -0300837 const __u8 stop = 0x09; /* Disable stream turn of LED */
838
839 reg_w(gspca_dev, 0x01, &stop, 1);
840
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300841 return 0;
842}
843
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300844/* -- start the camera -- */
845static void sd_start(struct gspca_dev *gspca_dev)
846{
847 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedef45f06b2008-09-03 17:12:21 -0300848 int mode, l;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300849 const __u8 *sn9c10x;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300850 __u8 reg17_19[3];
851
Hans de Goedef45f06b2008-09-03 17:12:21 -0300852 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 0x07;
853 sn9c10x = sensor_data[sd->sensor].bridge_init[sd->bridge];
854 l = sensor_data[sd->sensor].bridge_init_size[sd->bridge];
855 reg17_19[0] = sn9c10x[0x17 - 1];
856 reg17_19[1] = sn9c10x[0x18 - 1] | (mode << 4);
857 reg17_19[2] = sn9c10x[0x19 - 1];
858 /* Special cases where reg 17 and or 19 value depends on mode */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300859 switch (sd->sensor) {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300860 case SENSOR_PAS202:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300861 reg17_19[0] = mode ? 0x24 : 0x20;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300862 break;
Hans de Goedef45f06b2008-09-03 17:12:21 -0300863 case SENSOR_TAS5130CXX:
864 /* probably not mode specific at all most likely the upper
865 nibble of 0x19 is exposure (clock divider) just as with
866 the tas5110, we need someone to test this. */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300867 reg17_19[2] = mode ? 0x23 : 0x43;
868 break;
869 }
Hans de Goede6af492e2008-07-22 07:09:33 -0300870
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300871 /* reg 0x01 bit 2 video transfert on */
Hans de Goedefff42052008-07-23 07:04:39 -0300872 reg_w(gspca_dev, 0x01, &sn9c10x[0x01 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300873 /* reg 0x17 SensorClk enable inv Clk 0x60 */
Hans de Goedefff42052008-07-23 07:04:39 -0300874 reg_w(gspca_dev, 0x17, &sn9c10x[0x17 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300875 /* Set the registers from the template */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300876 reg_w(gspca_dev, 0x01, sn9c10x, l);
Hans de Goedef45f06b2008-09-03 17:12:21 -0300877
878 /* Init the sensor */
879 i2c_w_vector(gspca_dev, sensor_data[sd->sensor].sensor_init,
880 sensor_data[sd->sensor].sensor_init_size);
881 if (sensor_data[sd->sensor].sensor_bridge_init[sd->bridge])
882 i2c_w_vector(gspca_dev,
883 sensor_data[sd->sensor].sensor_bridge_init[sd->bridge],
884 sensor_data[sd->sensor].sensor_bridge_init_size[
885 sd->bridge]);
886
Hans de Goede3647fea2008-07-15 05:36:30 -0300887 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
888 reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300889 /* compression register */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300890 reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi794af522008-07-16 08:33:14 -0300891 /* H_start */
892 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
893 /* V_START */
894 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300895 /* reset 0x17 SensorClk enable inv Clk 0x60 */
896 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300897 reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300898 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi794af522008-07-16 08:33:14 -0300899 reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300900 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300901 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300902 /* Enable video transfert */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300903 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300904 /* Compression */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300905 reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300906 msleep(20);
907
Hans de Goede6af492e2008-07-22 07:09:33 -0300908 sd->reg11 = -1;
909
Hans de Goededcef3232008-07-10 10:40:53 -0300910 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300911 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -0300912 setexposure(gspca_dev);
Hans de Goede66f35822008-07-16 10:16:28 -0300913 setfreq(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -0300914
Hans de Goede6af492e2008-07-22 07:09:33 -0300915 sd->frames_to_drop = 0;
Hans de Goededcef3232008-07-10 10:40:53 -0300916 sd->autogain_ignore_frames = 0;
917 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300918}
919
920static void sd_stopN(struct gspca_dev *gspca_dev)
921{
Hans de Goedef45f06b2008-09-03 17:12:21 -0300922 sd_init(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300923}
924
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300925static void sd_pkt_scan(struct gspca_dev *gspca_dev,
926 struct gspca_frame *frame, /* target */
927 unsigned char *data, /* isoc packet */
928 int len) /* iso packet length */
929{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300930 int i;
Hans de Goededcef3232008-07-10 10:40:53 -0300931 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300932
Hans de Goedec36260ee2008-07-16 09:56:07 -0300933 /* frames start with:
934 * ff ff 00 c4 c4 96 synchro
935 * 00 (unknown)
936 * xx (frame sequence / size / compression)
937 * (xx) (idem - extra byte for sn9c103)
938 * ll mm brightness sum inside auto exposure
939 * ll mm brightness sum outside auto exposure
940 * (xx xx xx xx xx) audio values for snc103
941 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300942 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300943 for (i = 0; i < len - 6; i++) {
944 if (data[0 + i] == 0xff
945 && data[1 + i] == 0xff
946 && data[2 + i] == 0x00
947 && data[3 + i] == 0xc4
948 && data[4 + i] == 0xc4
949 && data[5 + i] == 0x96) { /* start of frame */
Hans de Goede6af492e2008-07-22 07:09:33 -0300950 int lum = -1;
951 int pkt_type = LAST_PACKET;
Hans de Goedef45f06b2008-09-03 17:12:21 -0300952 int fr_h_sz = (sd->bridge == BRIDGE_103) ?
953 18 : 12;
Hans de Goede6af492e2008-07-22 07:09:33 -0300954
Hans de Goedef45f06b2008-09-03 17:12:21 -0300955 if (len - i < fr_h_sz) {
Hans de Goedec36260ee2008-07-16 09:56:07 -0300956 PDEBUG(D_STREAM, "packet too short to"
957 " get avg brightness");
Hans de Goedef45f06b2008-09-03 17:12:21 -0300958 } else if (sd->bridge == BRIDGE_103) {
Hans de Goede6af492e2008-07-22 07:09:33 -0300959 lum = data[i + 9] +
960 (data[i + 10] << 8);
Hans de Goedef45f06b2008-09-03 17:12:21 -0300961 } else {
962 lum = data[i + 8] + (data[i + 9] << 8);
Hans de Goededcef3232008-07-10 10:40:53 -0300963 }
Hans de Goede6af492e2008-07-22 07:09:33 -0300964 if (lum == 0) {
965 lum = -1;
966 sd->frames_to_drop = 2;
967 }
968 atomic_set(&sd->avg_lum, lum);
969
970 if (sd->frames_to_drop) {
971 sd->frames_to_drop--;
972 pkt_type = DISCARD_PACKET;
973 }
974
975 frame = gspca_frame_add(gspca_dev, pkt_type,
976 frame, data, 0);
Hans de Goedef45f06b2008-09-03 17:12:21 -0300977 data += i + fr_h_sz;
978 len -= i + fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300979 gspca_frame_add(gspca_dev, FIRST_PACKET,
980 frame, data, len);
981 return;
982 }
983 }
984 }
985 gspca_frame_add(gspca_dev, INTER_PACKET,
986 frame, data, len);
987}
988
989static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
990{
991 struct sd *sd = (struct sd *) gspca_dev;
992
993 sd->brightness = val;
994 if (gspca_dev->streaming)
995 setbrightness(gspca_dev);
996 return 0;
997}
998
999static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1000{
1001 struct sd *sd = (struct sd *) gspca_dev;
1002
1003 *val = sd->brightness;
1004 return 0;
1005}
1006
Hans de Goededcef3232008-07-10 10:40:53 -03001007static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001008{
1009 struct sd *sd = (struct sd *) gspca_dev;
1010
Hans de Goededcef3232008-07-10 10:40:53 -03001011 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001012 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -03001013 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001014 return 0;
1015}
1016
Hans de Goededcef3232008-07-10 10:40:53 -03001017static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001018{
1019 struct sd *sd = (struct sd *) gspca_dev;
1020
Hans de Goededcef3232008-07-10 10:40:53 -03001021 *val = sd->gain;
1022 return 0;
1023}
1024
1025static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1026{
1027 struct sd *sd = (struct sd *) gspca_dev;
1028
1029 sd->exposure = val;
1030 if (gspca_dev->streaming)
1031 setexposure(gspca_dev);
1032 return 0;
1033}
1034
1035static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1036{
1037 struct sd *sd = (struct sd *) gspca_dev;
1038
1039 *val = sd->exposure;
1040 return 0;
1041}
1042
1043static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1044{
1045 struct sd *sd = (struct sd *) gspca_dev;
1046
1047 sd->autogain = val;
1048 /* when switching to autogain set defaults to make sure
1049 we are on a valid point of the autogain gain /
1050 exposure knee graph, and give this change time to
1051 take effect before doing autogain. */
1052 if (sd->autogain) {
1053 sd->exposure = EXPOSURE_DEF;
1054 sd->gain = GAIN_DEF;
1055 if (gspca_dev->streaming) {
1056 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1057 setexposure(gspca_dev);
1058 setgain(gspca_dev);
1059 }
1060 }
1061
1062 return 0;
1063}
1064
1065static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1066{
1067 struct sd *sd = (struct sd *) gspca_dev;
1068
1069 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001070 return 0;
1071}
1072
Hans de Goede66f35822008-07-16 10:16:28 -03001073static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1074{
1075 struct sd *sd = (struct sd *) gspca_dev;
1076
1077 sd->freq = val;
1078 if (gspca_dev->streaming)
1079 setfreq(gspca_dev);
1080 return 0;
1081}
1082
1083static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1084{
1085 struct sd *sd = (struct sd *) gspca_dev;
1086
1087 *val = sd->freq;
1088 return 0;
1089}
1090
1091static int sd_querymenu(struct gspca_dev *gspca_dev,
1092 struct v4l2_querymenu *menu)
1093{
1094 switch (menu->id) {
1095 case V4L2_CID_POWER_LINE_FREQUENCY:
1096 switch (menu->index) {
1097 case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
1098 strcpy((char *) menu->name, "NoFliker");
1099 return 0;
1100 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1101 strcpy((char *) menu->name, "50 Hz");
1102 return 0;
1103 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1104 strcpy((char *) menu->name, "60 Hz");
1105 return 0;
1106 }
1107 break;
1108 }
1109 return -EINVAL;
1110}
1111
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001112/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001113static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001114 .name = MODULE_NAME,
1115 .ctrls = sd_ctrls,
1116 .nctrls = ARRAY_SIZE(sd_ctrls),
1117 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001118 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001119 .start = sd_start,
1120 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001121 .pkt_scan = sd_pkt_scan,
Hans de Goede66f35822008-07-16 10:16:28 -03001122 .querymenu = sd_querymenu,
Hans de Goedee2ad2a52008-09-03 17:12:15 -03001123 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001124};
1125
1126/* -- module initialisation -- */
Hans de Goedef45f06b2008-09-03 17:12:21 -03001127#define SB(sensor, bridge) \
1128 .driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge
1129
Hans de Goedee2ad2a52008-09-03 17:12:15 -03001130
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001131static __devinitdata struct usb_device_id device_table[] = {
Hans de Goede222a07f2008-09-03 17:12:20 -03001132#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
Hans de Goedef45f06b2008-09-03 17:12:21 -03001133 {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110, 102)},
1134 {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110, 101)},
1135 {USB_DEVICE(0x0c45, 0x6007), SB(TAS5110, 101)},
1136 {USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)},
1137 {USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)},
Hans de Goede5de39b22008-07-17 10:34:28 -03001138#endif
Hans de Goedef45f06b2008-09-03 17:12:21 -03001139 {USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)},
Hans de Goede222a07f2008-09-03 17:12:20 -03001140#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
Hans de Goedef45f06b2008-09-03 17:12:21 -03001141 {USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)},
1142 {USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)},
1143 {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)},
1144 {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)},
1145 {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)},
1146 {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)},
Hans de Goede222a07f2008-09-03 17:12:20 -03001147#endif
Hans de Goedef45f06b2008-09-03 17:12:21 -03001148 {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)},
Hans de Goede222a07f2008-09-03 17:12:20 -03001149#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
Hans de Goedef45f06b2008-09-03 17:12:21 -03001150 {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)},
1151 {USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)},
1152 {USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)},
1153 {USB_DEVICE(0x0c45, 0x60b0), SB(OV7630, 103)},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001154#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001155 {}
1156};
1157MODULE_DEVICE_TABLE(usb, device_table);
1158
1159/* -- device connect -- */
1160static int sd_probe(struct usb_interface *intf,
1161 const struct usb_device_id *id)
1162{
1163 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1164 THIS_MODULE);
1165}
1166
1167static struct usb_driver sd_driver = {
1168 .name = MODULE_NAME,
1169 .id_table = device_table,
1170 .probe = sd_probe,
1171 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001172#ifdef CONFIG_PM
1173 .suspend = gspca_suspend,
1174 .resume = gspca_resume,
1175#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001176};
1177
1178/* -- module insert / remove -- */
1179static int __init sd_mod_init(void)
1180{
1181 if (usb_register(&sd_driver) < 0)
1182 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001183 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001184 return 0;
1185}
1186static void __exit sd_mod_exit(void)
1187{
1188 usb_deregister(&sd_driver);
1189 PDEBUG(D_PROBE, "deregistered");
1190}
1191
1192module_init(sd_mod_init);
1193module_exit(sd_mod_exit);