blob: 5033810f56fc62a18fde2636587070a297258675 [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 Goedec437d652008-09-03 17:12:22 -030077#define F_RAW 0x04 /* sensor tested ok with raw bayer mode */
78
79/* priv field of struct v4l2_pix_format flags (do not use low nibble!) */
80#define MODE_RAW 0x10 /* raw bayer mode */
Hans de Goedef45f06b2008-09-03 17:12:21 -030081
82/* ctrl_dis helper macros */
83#define NO_EXPO ((1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX))
84#define NO_FREQ (1 << FREQ_IDX)
85#define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX)
Jean-Francois Moine5da162e2008-07-26 14:17:23 -030086
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030087#define COMP2 0x8f
88#define COMP 0xc7 /* 0x87 //0x07 */
89#define COMP1 0xc9 /* 0x89 //0x09 */
90
91#define MCK_INIT 0x63
92#define MCK_INIT1 0x20 /*fixme: Bayer - 0x50 for JPEG ??*/
93
94#define SYS_CLK 0x04
95
Hans de Goedef45f06b2008-09-03 17:12:21 -030096#define SENS(bridge_1, bridge_3, sensor, sensor_1, \
97 sensor_3, _flags, _ctrl_dis, _sensor_addr) \
98{ \
99 .bridge_init = { bridge_1, bridge_3 }, \
100 .bridge_init_size = { sizeof(bridge_1), sizeof(bridge_3) }, \
101 .sensor_init = sensor, \
102 .sensor_init_size = sizeof(sensor), \
103 .sensor_bridge_init = { sensor_1, sensor_3,}, \
104 .sensor_bridge_init_size = { sizeof(sensor_1), sizeof(sensor_3)}, \
105 .flags = _flags, .ctrl_dis = _ctrl_dis, .sensor_addr = _sensor_addr \
106}
107
Hans de Goededcef3232008-07-10 10:40:53 -0300108/* We calculate the autogain at the end of the transfer of a frame, at this
109 moment a frame with the old settings is being transmitted, and a frame is
110 being captured with the old settings. So if we adjust the autogain we must
111 ignore atleast the 2 next frames for the new settings to come into effect
112 before doing any other adjustments */
113#define AUTOGAIN_IGNORE_FRAMES 3
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300114#define AUTOGAIN_DEADZONE 1000
Hans de Goededcef3232008-07-10 10:40:53 -0300115#define DESIRED_AVG_LUM 7000
116
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300117/* V4L2 controls supported by the driver */
118static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
119static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goededcef3232008-07-10 10:40:53 -0300120static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
121static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
122static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
123static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
124static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
125static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede66f35822008-07-16 10:16:28 -0300126static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
127static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300128
129static struct ctrl sd_ctrls[] = {
Hans de Goedee2ad2a52008-09-03 17:12:15 -0300130#define BRIGHTNESS_IDX 0
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300131 {
132 {
133 .id = V4L2_CID_BRIGHTNESS,
134 .type = V4L2_CTRL_TYPE_INTEGER,
135 .name = "Brightness",
136 .minimum = 0,
137 .maximum = 255,
138 .step = 1,
Hans de Goededcef3232008-07-10 10:40:53 -0300139#define BRIGHTNESS_DEF 127
140 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300141 },
142 .set = sd_setbrightness,
143 .get = sd_getbrightness,
144 },
Hans de Goedee2ad2a52008-09-03 17:12:15 -0300145#define GAIN_IDX 1
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300146 {
147 {
Hans de Goededcef3232008-07-10 10:40:53 -0300148 .id = V4L2_CID_GAIN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300149 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goededcef3232008-07-10 10:40:53 -0300150 .name = "Gain",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300151 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300152 .maximum = 255,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300153 .step = 1,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300154#define GAIN_DEF 127
155#define GAIN_KNEE 200
Hans de Goededcef3232008-07-10 10:40:53 -0300156 .default_value = GAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300157 },
Hans de Goededcef3232008-07-10 10:40:53 -0300158 .set = sd_setgain,
159 .get = sd_getgain,
160 },
Hans de Goedee2ad2a52008-09-03 17:12:15 -0300161#define EXPOSURE_IDX 2
Hans de Goededcef3232008-07-10 10:40:53 -0300162 {
163 {
164 .id = V4L2_CID_EXPOSURE,
165 .type = V4L2_CTRL_TYPE_INTEGER,
166 .name = "Exposure",
Hans de Goedef4d52022008-07-15 09:36:42 -0300167#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
168#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
Hans de Goededcef3232008-07-10 10:40:53 -0300169 .minimum = 0,
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300170 .maximum = 255,
Hans de Goededcef3232008-07-10 10:40:53 -0300171 .step = 1,
172 .default_value = EXPOSURE_DEF,
173 .flags = 0,
174 },
175 .set = sd_setexposure,
176 .get = sd_getexposure,
177 },
Hans de Goedee2ad2a52008-09-03 17:12:15 -0300178#define AUTOGAIN_IDX 3
Hans de Goededcef3232008-07-10 10:40:53 -0300179 {
180 {
181 .id = V4L2_CID_AUTOGAIN,
182 .type = V4L2_CTRL_TYPE_BOOLEAN,
183 .name = "Automatic Gain (and Exposure)",
184 .minimum = 0,
185 .maximum = 1,
186 .step = 1,
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300187#define AUTOGAIN_DEF 1
188 .default_value = AUTOGAIN_DEF,
Hans de Goededcef3232008-07-10 10:40:53 -0300189 .flags = 0,
190 },
191 .set = sd_setautogain,
192 .get = sd_getautogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300193 },
Hans de Goedee2ad2a52008-09-03 17:12:15 -0300194#define FREQ_IDX 4
Hans de Goede66f35822008-07-16 10:16:28 -0300195 {
196 {
197 .id = V4L2_CID_POWER_LINE_FREQUENCY,
198 .type = V4L2_CTRL_TYPE_MENU,
199 .name = "Light frequency filter",
200 .minimum = 0,
201 .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
202 .step = 1,
203#define FREQ_DEF 1
204 .default_value = FREQ_DEF,
205 },
206 .set = sd_setfreq,
207 .get = sd_getfreq,
208 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300209};
210
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300211static struct v4l2_pix_format vga_mode[] = {
Hans de Goedec437d652008-09-03 17:12:22 -0300212 {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
213 .bytesperline = 160,
214 .sizeimage = 160 * 120,
215 .colorspace = V4L2_COLORSPACE_SRGB,
216 .priv = 2 | MODE_RAW},
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300217 {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
218 .bytesperline = 160,
Hans de Goede5c51518d2008-09-03 17:12:22 -0300219 .sizeimage = 160 * 120 * 5 / 4,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300220 .colorspace = V4L2_COLORSPACE_SRGB,
221 .priv = 2},
222 {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
223 .bytesperline = 320,
Hans de Goede5c51518d2008-09-03 17:12:22 -0300224 .sizeimage = 320 * 240 * 5 / 4,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300225 .colorspace = V4L2_COLORSPACE_SRGB,
226 .priv = 1},
227 {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
228 .bytesperline = 640,
Hans de Goede5c51518d2008-09-03 17:12:22 -0300229 .sizeimage = 640 * 480 * 5 / 4,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300230 .colorspace = V4L2_COLORSPACE_SRGB,
231 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300232};
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300233static struct v4l2_pix_format sif_mode[] = {
Hans de Goedec437d652008-09-03 17:12:22 -0300234 {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
235 .bytesperline = 176,
236 .sizeimage = 176 * 144,
237 .colorspace = V4L2_COLORSPACE_SRGB,
238 .priv = 1 | MODE_RAW},
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300239 {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
240 .bytesperline = 176,
Hans de Goede5c51518d2008-09-03 17:12:22 -0300241 .sizeimage = 176 * 144 * 5 / 4,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300242 .colorspace = V4L2_COLORSPACE_SRGB,
243 .priv = 1},
244 {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE,
245 .bytesperline = 352,
Hans de Goede5c51518d2008-09-03 17:12:22 -0300246 .sizeimage = 352 * 288 * 5 / 4,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300247 .colorspace = V4L2_COLORSPACE_SRGB,
248 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300249};
250
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300251static const __u8 initHv7131[] = {
252 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
253 0x00, 0x00,
Hans de Goedec437d652008-09-03 17:12:22 -0300254 0x00, 0x00, 0x00, 0x02, 0x01, 0x00,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300255 0x28, 0x1e, 0x60, 0x8a, 0x20,
256 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
257};
258static const __u8 hv7131_sensor_init[][8] = {
259 {0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
260 {0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
261 {0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
262 {0xc0, 0x11, 0x25, 0x03, 0x0e, 0x28, 0x00, 0x16},
263 {0xa0, 0x11, 0x30, 0x10, 0x0e, 0x28, 0x00, 0x15},
264};
265static const __u8 initOv6650[] = {
266 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
267 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Hans de Goedec437d652008-09-03 17:12:22 -0300268 0x00, 0x01, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300269 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00
270};
271static const __u8 ov6650_sensor_init[][8] =
272{
273 /* Bright, contrast, etc are set througth SCBB interface.
274 * AVCAP on win2 do not send any data on this controls. */
275 /* Anyway, some registers appears to alter bright and constrat */
Hans de Goededcef3232008-07-10 10:40:53 -0300276
277 /* Reset sensor */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300278 {0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300279 /* Set clock register 0x11 low nibble is clock divider */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300280 {0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
Hans de Goededcef3232008-07-10 10:40:53 -0300281 /* Next some unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300282 {0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
283/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
284 * THIS SET GREEN SCREEN
285 * (pixels could be innverted in decode kind of "brg",
286 * but blue wont be there. Avoid this data ... */
287 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
288 {0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
289 {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
Hans de Goede722103e2008-07-17 10:24:47 -0300290 /* Enable rgb brightness control */
291 {0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
292 /* HDG: Note windows uses the line below, which sets both register 0x60
293 and 0x61 I believe these registers of the ov6650 are identical as
294 those of the ov7630, because if this is true the windows settings
295 add a bit additional red gain and a lot additional blue gain, which
296 matches my findings that the windows settings make blue much too
297 blue and red a little too red.
298 {0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10}, */
Hans de Goededcef3232008-07-10 10:40:53 -0300299 /* Some more unknown stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300300 {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
301 {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300302};
Hans de Goededcef3232008-07-10 10:40:53 -0300303
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300304static const __u8 initOv7630[] = {
305 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
306 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
Hans de Goedec437d652008-09-03 17:12:22 -0300307 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300308 0x28, 0x1e, /* H & V sizes r15 .. r16 */
Hans de Goedef45f06b2008-09-03 17:12:21 -0300309 0x68, COMP2, MCK_INIT1, /* r17 .. r19 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300310 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
311};
312static const __u8 initOv7630_3[] = {
313 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
314 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300315 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
Hans de Goede3647fea2008-07-15 05:36:30 -0300316 0x28, 0x1e, /* H & V sizes r15 .. r16 */
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300317 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
318 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
319 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
320 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300321};
Hans de Goede6af492e2008-07-22 07:09:33 -0300322static const __u8 ov7630_sensor_init[][8] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300323 {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
324 {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
325/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
Andoni Zubimendi794af522008-07-16 08:33:14 -0300326 {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300327 {0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
328 {0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
329 {0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
330 {0xd0, 0x21, 0x26, 0xa0, 0x9a, 0xa0, 0x30, 0x10},
331 {0xb0, 0x21, 0x2a, 0x80, 0x00, 0xa0, 0x30, 0x10},
332 {0xb0, 0x21, 0x2f, 0x3d, 0x24, 0xa0, 0x30, 0x10},
333 {0xa0, 0x21, 0x32, 0x86, 0x24, 0xa0, 0x30, 0x10},
Andoni Zubimendi794af522008-07-16 08:33:14 -0300334 {0xb0, 0x21, 0x60, 0xa9, 0x4a, 0xa0, 0x30, 0x10},
335/* {0xb0, 0x21, 0x60, 0xa9, 0x42, 0xa0, 0x30, 0x10}, * jfm */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300336 {0xa0, 0x21, 0x65, 0x00, 0x42, 0xa0, 0x30, 0x10},
337 {0xa0, 0x21, 0x69, 0x38, 0x42, 0xa0, 0x30, 0x10},
338 {0xc0, 0x21, 0x6f, 0x88, 0x0b, 0x00, 0x30, 0x10},
339 {0xc0, 0x21, 0x74, 0x21, 0x8e, 0x00, 0x30, 0x10},
340 {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10},
341 {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
342};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300343
Hans de Goedef45f06b2008-09-03 17:12:21 -0300344static const __u8 ov7630_sensor_init_3[][8] = {
345 {0xa0, 0x21, 0x13, 0x80, 0x00, 0x00, 0x00, 0x10},
346};
347
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300348static const __u8 initPas106[] = {
349 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
350 0x00, 0x00,
Hans de Goedec437d652008-09-03 17:12:22 -0300351 0x00, 0x00, 0x00, 0x04, 0x01, 0x00,
Hans de Goedef45f06b2008-09-03 17:12:21 -0300352 0x16, 0x12, 0x24, COMP1, MCK_INIT1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300353 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
354};
355/* compression 0x86 mckinit1 0x2b */
Hans de Goedef45f06b2008-09-03 17:12:21 -0300356static const __u8 pas106_sensor_init[][8] = {
357 /* Pixel Clock Divider 6 */
358 { 0xa1, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14 },
359 /* Frame Time MSB (also seen as 0x12) */
360 { 0xa1, 0x40, 0x03, 0x13, 0x00, 0x00, 0x00, 0x14 },
361 /* Frame Time LSB (also seen as 0x05) */
362 { 0xa1, 0x40, 0x04, 0x06, 0x00, 0x00, 0x00, 0x14 },
363 /* Shutter Time Line Offset (also seen as 0x6d) */
364 { 0xa1, 0x40, 0x05, 0x65, 0x00, 0x00, 0x00, 0x14 },
365 /* Shutter Time Pixel Offset (also seen as 0xb1) */
366 { 0xa1, 0x40, 0x06, 0xcd, 0x00, 0x00, 0x00, 0x14 },
367 /* Black Level Subtract Sign (also seen 0x00) */
368 { 0xa1, 0x40, 0x07, 0xc1, 0x00, 0x00, 0x00, 0x14 },
369 /* Black Level Subtract Level (also seen 0x01) */
370 { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 },
371 { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 },
372 /* Color Gain B Pixel 5 a */
373 { 0xa1, 0x40, 0x09, 0x05, 0x00, 0x00, 0x00, 0x14 },
374 /* Color Gain G1 Pixel 1 5 */
375 { 0xa1, 0x40, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x14 },
376 /* Color Gain G2 Pixel 1 0 5 */
377 { 0xa1, 0x40, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x14 },
378 /* Color Gain R Pixel 3 1 */
379 { 0xa1, 0x40, 0x0c, 0x05, 0x00, 0x00, 0x00, 0x14 },
380 /* Color GainH Pixel */
381 { 0xa1, 0x40, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x14 },
382 /* Global Gain */
383 { 0xa1, 0x40, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x14 },
384 /* Contrast */
385 { 0xa1, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14 },
386 /* H&V synchro polarity */
387 { 0xa1, 0x40, 0x10, 0x06, 0x00, 0x00, 0x00, 0x14 },
388 /* ?default */
389 { 0xa1, 0x40, 0x11, 0x06, 0x00, 0x00, 0x00, 0x14 },
390 /* DAC scale */
391 { 0xa1, 0x40, 0x12, 0x06, 0x00, 0x00, 0x00, 0x14 },
392 /* ?default */
393 { 0xa1, 0x40, 0x14, 0x02, 0x00, 0x00, 0x00, 0x14 },
394 /* Validate Settings */
395 { 0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300396};
Hans de Goedef45f06b2008-09-03 17:12:21 -0300397
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300398static const __u8 initPas202[] = {
399 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
400 0x00, 0x00,
Hans de Goedec437d652008-09-03 17:12:22 -0300401 0x00, 0x00, 0x00, 0x06, 0x03, 0x0a,
Hans de Goedef45f06b2008-09-03 17:12:21 -0300402 0x28, 0x1e, 0x28, 0x89, 0x20,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300403 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
404};
405static const __u8 pas202_sensor_init[][8] = {
406 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10},
407 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
408 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
409 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10},
410 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
411 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
412 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
413 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
414 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
415 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
416 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
417 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
418
419 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
420 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
421 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
422 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
423 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
424 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
425 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
426 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
427};
428
429static const __u8 initTas5110[] = {
430 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
431 0x00, 0x00,
Hans de Goedec437d652008-09-03 17:12:22 -0300432 0x00, 0x01, 0x00, 0x45, 0x09, 0x0a,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300433 0x16, 0x12, 0x60, 0x86, 0x2b,
434 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
435};
436static const __u8 tas5110_sensor_init[][8] = {
437 {0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
438 {0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
439 {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
440};
441
442static const __u8 initTas5130[] = {
443 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00,
444 0x00, 0x00,
Hans de Goedec437d652008-09-03 17:12:22 -0300445 0x00, 0x01, 0x00, 0x68, 0x0c, 0x0a,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300446 0x28, 0x1e, 0x60, COMP, MCK_INIT,
447 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
448};
449static const __u8 tas5130_sensor_init[][8] = {
450/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
451 * shutter 0x47 short exposure? */
452 {0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
453 /* shutter 0x01 long exposure */
454 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10},
455};
456
Hans de Goedef45f06b2008-09-03 17:12:21 -0300457struct sensor_data sensor_data[] = {
458SENS(initHv7131, NULL, hv7131_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, 0),
Hans de Goedec437d652008-09-03 17:12:22 -0300459SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF|F_RAW, 0,
460 0x60),
Hans de Goedef45f06b2008-09-03 17:12:21 -0300461SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
462 F_GAIN, 0, 0x21),
463SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_SIF, NO_EXPO|NO_FREQ,
464 0),
Hans de Goedec437d652008-09-03 17:12:22 -0300465SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, F_RAW,
Hans de Goedef45f06b2008-09-03 17:12:21 -0300466 NO_EXPO|NO_FREQ, 0),
Hans de Goedec437d652008-09-03 17:12:22 -0300467SENS(initTas5110, NULL, tas5110_sensor_init, NULL, NULL, F_GAIN|F_SIF|F_RAW,
Hans de Goedef45f06b2008-09-03 17:12:21 -0300468 NO_BRIGHTNESS|NO_FREQ, 0),
469SENS(initTas5130, NULL, tas5130_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ,
470 0),
471};
472
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300473/* get one byte in gspca_dev->usb_buf */
474static void reg_r(struct gspca_dev *gspca_dev,
475 __u16 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300476{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300477 usb_control_msg(gspca_dev->dev,
478 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300479 0, /* request */
480 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
481 value,
482 0, /* index */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300483 gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300484 500);
485}
486
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300487static void reg_w(struct gspca_dev *gspca_dev,
488 __u16 value,
489 const __u8 *buffer,
490 int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300491{
Jean-Francois Moine335b3f82008-07-30 04:53:02 -0300492#ifdef GSPCA_DEBUG
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300493 if (len > USB_BUF_SZ) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300494 PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
495 return;
496 }
497#endif
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300498 memcpy(gspca_dev->usb_buf, buffer, len);
499 usb_control_msg(gspca_dev->dev,
500 usb_sndctrlpipe(gspca_dev->dev, 0),
501 0x08, /* request */
502 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
503 value,
504 0, /* index */
505 gspca_dev->usb_buf, len,
506 500);
507}
508
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300509static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300510{
511 int retry = 60;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300512
513 /* is i2c ready */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300514 reg_w(gspca_dev, 0x08, buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300515 while (retry--) {
516 msleep(10);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300517 reg_r(gspca_dev, 0x08);
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300518 if (gspca_dev->usb_buf[0] & 0x04) {
519 if (gspca_dev->usb_buf[0] & 0x08)
520 return -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300521 return 0;
Andoni Zubimendib7474cf92008-07-16 08:40:30 -0300522 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300523 }
524 return -1;
525}
526
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300527static void i2c_w_vector(struct gspca_dev *gspca_dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300528 const __u8 buffer[][8], int len)
529{
530 for (;;) {
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300531 reg_w(gspca_dev, 0x08, *buffer, 8);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300532 len -= 8;
533 if (len <= 0)
534 break;
535 buffer++;
536 }
537}
538
539static void setbrightness(struct gspca_dev *gspca_dev)
540{
541 struct sd *sd = (struct sd *) gspca_dev;
542 __u8 value;
543
544 switch (sd->sensor) {
Hans de Goedea975a522008-07-16 15:29:11 -0300545 case SENSOR_OV6650:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300546 case SENSOR_OV7630: {
547 __u8 i2cOV[] =
Hans de Goedea975a522008-07-16 15:29:11 -0300548 {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300549
550 /* change reg 0x06 */
Hans de Goedef45f06b2008-09-03 17:12:21 -0300551 i2cOV[1] = sensor_data[sd->sensor].sensor_addr;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300552 i2cOV[3] = sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300553 if (i2c_w(gspca_dev, i2cOV) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300554 goto err;
555 break;
556 }
557 case SENSOR_PAS106: {
558 __u8 i2c1[] =
559 {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
560
561 i2c1[3] = sd->brightness >> 3;
562 i2c1[2] = 0x0e;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300563 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300564 goto err;
565 i2c1[3] = 0x01;
566 i2c1[2] = 0x13;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300567 if (i2c_w(gspca_dev, i2c1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300568 goto err;
569 break;
570 }
571 case SENSOR_PAS202: {
572 /* __u8 i2cpexpo1[] =
573 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */
574 __u8 i2cpexpo[] =
575 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16};
576 __u8 i2cp202[] =
577 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15};
578 static __u8 i2cpdoit[] =
579 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16};
580
581 /* change reg 0x10 */
582 i2cpexpo[4] = 0xff - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300583/* if(i2c_w(gspca_dev,i2cpexpo1) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300584 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300585/* if(i2c_w(gspca_dev,i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300586 goto err; */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300587 if (i2c_w(gspca_dev, i2cpexpo) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300588 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300589 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300590 goto err;
591 i2cp202[3] = sd->brightness >> 3;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300592 if (i2c_w(gspca_dev, i2cp202) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300593 goto err;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300594 if (i2c_w(gspca_dev, i2cpdoit) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300595 goto err;
596 break;
597 }
Hans de Goededcef3232008-07-10 10:40:53 -0300598 case SENSOR_TAS5130CXX: {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300599 __u8 i2c[] =
600 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
601
602 value = 0xff - sd->brightness;
603 i2c[4] = value;
604 PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300605 if (i2c_w(gspca_dev, i2c) < 0)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300606 goto err;
607 break;
608 }
609 }
610 return;
611err:
612 PDEBUG(D_ERR, "i2c error brightness");
613}
Hans de Goededcef3232008-07-10 10:40:53 -0300614
615static void setsensorgain(struct gspca_dev *gspca_dev)
616{
617 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea975a522008-07-16 15:29:11 -0300618 unsigned char gain = sd->gain;
Hans de Goededcef3232008-07-10 10:40:53 -0300619
620 switch (sd->sensor) {
621
622 case SENSOR_TAS5110: {
623 __u8 i2c[] =
624 {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
625
Hans de Goedea975a522008-07-16 15:29:11 -0300626 i2c[4] = 255 - gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300627 if (i2c_w(gspca_dev, i2c) < 0)
Hans de Goededcef3232008-07-10 10:40:53 -0300628 goto err;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300629 break;
630 }
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300631
Hans de Goedea975a522008-07-16 15:29:11 -0300632 case SENSOR_OV6650:
633 gain >>= 1;
634 /* fall thru */
Hans de Goede6af492e2008-07-22 07:09:33 -0300635 case SENSOR_OV7630: {
Hans de Goedea975a522008-07-16 15:29:11 -0300636 __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
Andoni Zubimendi794af522008-07-16 08:33:14 -0300637
Hans de Goedef45f06b2008-09-03 17:12:21 -0300638 i2c[1] = sensor_data[sd->sensor].sensor_addr;
Hans de Goedea975a522008-07-16 15:29:11 -0300639 i2c[3] = gain >> 2;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300640 if (i2c_w(gspca_dev, i2c) < 0)
641 goto err;
642 break;
643 }
Hans de Goededcef3232008-07-10 10:40:53 -0300644 }
645 return;
646err:
647 PDEBUG(D_ERR, "i2c error gain");
648}
649
650static void setgain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300651{
652 struct sd *sd = (struct sd *) gspca_dev;
653 __u8 gain;
654 __u8 rgb_value;
655
Hans de Goedead5ef80d2008-07-14 10:11:42 -0300656 gain = sd->gain >> 4;
Hans de Goededcef3232008-07-10 10:40:53 -0300657
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300658 /* red and blue gain */
659 rgb_value = gain << 4 | gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300660 reg_w(gspca_dev, 0x10, &rgb_value, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300661 /* green gain */
662 rgb_value = gain;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300663 reg_w(gspca_dev, 0x11, &rgb_value, 1);
Hans de Goededcef3232008-07-10 10:40:53 -0300664
Hans de Goedef45f06b2008-09-03 17:12:21 -0300665 if (sensor_data[sd->sensor].flags & F_GAIN)
Hans de Goededcef3232008-07-10 10:40:53 -0300666 setsensorgain(gspca_dev);
667}
668
669static void setexposure(struct gspca_dev *gspca_dev)
670{
671 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goededcef3232008-07-10 10:40:53 -0300672
673 switch (sd->sensor) {
674 case SENSOR_TAS5110: {
675 __u8 reg;
676
677 /* register 19's high nibble contains the sn9c10x clock divider
678 The high nibble configures the no fps according to the
679 formula: 60 / high_nibble. With a maximum of 30 fps */
Hans de Goedef4d52022008-07-15 09:36:42 -0300680 reg = 120 * sd->exposure / 1000;
681 if (reg < 2)
682 reg = 2;
683 else if (reg > 15)
Hans de Goededcef3232008-07-10 10:40:53 -0300684 reg = 15;
685 reg = (reg << 4) | 0x0b;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300686 reg_w(gspca_dev, 0x19, &reg, 1);
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300687 break;
688 }
Hans de Goedea975a522008-07-16 15:29:11 -0300689 case SENSOR_OV6650:
Hans de Goede6af492e2008-07-22 07:09:33 -0300690 case SENSOR_OV7630: {
Hans de Goedea975a522008-07-16 15:29:11 -0300691 /* The ov6650 / ov7630 have 2 registers which both influence
692 exposure, register 11, whose low nibble sets the nr off fps
Hans de Goedef4d52022008-07-15 09:36:42 -0300693 according to: fps = 30 / (low_nibble + 1)
694
695 The fps configures the maximum exposure setting, but it is
696 possible to use less exposure then what the fps maximum
697 allows by setting register 10. register 10 configures the
698 actual exposure as quotient of the full exposure, with 0
699 being no exposure at all (not very usefull) and reg10_max
700 being max exposure possible at that framerate.
701
702 The code maps our 0 - 510 ms exposure ctrl to these 2
703 registers, trying to keep fps as high as possible.
704 */
Hans de Goede6af492e2008-07-22 07:09:33 -0300705 __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10};
706 int reg10, reg11, reg10_max;
707
Hans de Goede66f35822008-07-16 10:16:28 -0300708 /* ov6645 datasheet says reg10_max is 9a, but that uses
709 tline * 2 * reg10 as formula for calculating texpo, the
710 ov6650 probably uses the same formula as the 7730 which uses
711 tline * 4 * reg10, which explains why the reg10max we've
712 found experimentally for the ov6650 is exactly half that of
Hans de Goedea975a522008-07-16 15:29:11 -0300713 the ov6645. The ov7630 datasheet says the max is 0x41. */
Hans de Goede6af492e2008-07-22 07:09:33 -0300714 if (sd->sensor == SENSOR_OV6650) {
715 reg10_max = 0x4d;
716 i2c[4] = 0xc0; /* OV6650 needs non default vsync pol */
717 } else
718 reg10_max = 0x41;
Hans de Goedef4d52022008-07-15 09:36:42 -0300719
720 reg11 = (60 * sd->exposure + 999) / 1000;
721 if (reg11 < 1)
722 reg11 = 1;
723 else if (reg11 > 16)
724 reg11 = 16;
725
Hans de Goedee2ad2a52008-09-03 17:12:15 -0300726 /* In 640x480, if the reg11 has less than 3, the image is
727 unstable (not enough bandwidth). */
728 if (gspca_dev->width == 640 && reg11 < 3)
729 reg11 = 3;
730
Hans de Goedef4d52022008-07-15 09:36:42 -0300731 /* frame exposure time in ms = 1000 * reg11 / 30 ->
732 reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
733 reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
Hans de Goedea975a522008-07-16 15:29:11 -0300734
735 /* Don't allow this to get below 10 when using autogain, the
736 steps become very large (relatively) when below 10 causing
737 the image to oscilate from much too dark, to much too bright
738 and back again. */
739 if (sd->autogain && reg10 < 10)
740 reg10 = 10;
Hans de Goedef4d52022008-07-15 09:36:42 -0300741 else if (reg10 > reg10_max)
742 reg10 = reg10_max;
743
744 /* Write reg 10 and reg11 low nibble */
Hans de Goedef45f06b2008-09-03 17:12:21 -0300745 i2c[1] = sensor_data[sd->sensor].sensor_addr;
Andoni Zubimendi794af522008-07-16 08:33:14 -0300746 i2c[3] = reg10;
747 i2c[4] |= reg11 - 1;
Hans de Goede6af492e2008-07-22 07:09:33 -0300748
749 /* If register 11 didn't change, don't change it */
750 if (sd->reg11 == reg11 )
751 i2c[0] = 0xa0;
752
753 if (i2c_w(gspca_dev, i2c) == 0)
754 sd->reg11 = reg11;
755 else
Andoni Zubimendi794af522008-07-16 08:33:14 -0300756 PDEBUG(D_ERR, "i2c error exposure");
757 break;
758 }
Hans de Goededcef3232008-07-10 10:40:53 -0300759 }
760}
761
Hans de Goede66f35822008-07-16 10:16:28 -0300762static void setfreq(struct gspca_dev *gspca_dev)
763{
764 struct sd *sd = (struct sd *) gspca_dev;
765
766 switch (sd->sensor) {
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300767 case SENSOR_OV6650:
Hans de Goede6af492e2008-07-22 07:09:33 -0300768 case SENSOR_OV7630: {
Hans de Goede66f35822008-07-16 10:16:28 -0300769 /* Framerate adjust register for artificial light 50 hz flicker
Hans de Goede6af492e2008-07-22 07:09:33 -0300770 compensation, for the ov6650 this is identical to ov6630
771 0x2b register, see ov6630 datasheet.
772 0x4f / 0x8a -> (30 fps -> 25 fps), 0x00 -> no adjustment */
Andoni Zubimendid87616f2008-07-17 05:35:52 -0300773 __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10};
Hans de Goede66f35822008-07-16 10:16:28 -0300774 switch (sd->freq) {
775 default:
776/* case 0: * no filter*/
777/* case 2: * 60 hz */
778 i2c[3] = 0;
779 break;
780 case 1: /* 50 hz */
Hans de Goede722103e2008-07-17 10:24:47 -0300781 i2c[3] = (sd->sensor == SENSOR_OV6650)
782 ? 0x4f : 0x8a;
Hans de Goede66f35822008-07-16 10:16:28 -0300783 break;
784 }
Hans de Goedef45f06b2008-09-03 17:12:21 -0300785 i2c[1] = sensor_data[sd->sensor].sensor_addr;
Hans de Goede66f35822008-07-16 10:16:28 -0300786 if (i2c_w(gspca_dev, i2c) < 0)
787 PDEBUG(D_ERR, "i2c error setfreq");
788 break;
789 }
790 }
791}
792
Hans de Goededcef3232008-07-10 10:40:53 -0300793static void do_autogain(struct gspca_dev *gspca_dev)
794{
795 struct sd *sd = (struct sd *) gspca_dev;
796 int avg_lum = atomic_read(&sd->avg_lum);
797
798 if (avg_lum == -1)
799 return;
800
801 if (sd->autogain_ignore_frames > 0)
802 sd->autogain_ignore_frames--;
803 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
804 sd->brightness * DESIRED_AVG_LUM / 127,
Hans de Goedea975a522008-07-16 15:29:11 -0300805 AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
806 PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
807 (int)sd->gain, (int)sd->exposure);
Hans de Goededcef3232008-07-10 10:40:53 -0300808 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
Hans de Goedea975a522008-07-16 15:29:11 -0300809 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300810}
811
812/* this function is called at probe time */
813static int sd_config(struct gspca_dev *gspca_dev,
814 const struct usb_device_id *id)
815{
816 struct sd *sd = (struct sd *) gspca_dev;
817 struct cam *cam;
Hans de Goede65f33392008-09-03 17:12:15 -0300818
819 reg_r(gspca_dev, 0x00);
820 if (gspca_dev->usb_buf[0] != 0x10)
821 return -ENODEV;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300822
Jean-Francois Moine5da162e2008-07-26 14:17:23 -0300823 /* copy the webcam info from the device id */
Hans de Goedef45f06b2008-09-03 17:12:21 -0300824 sd->sensor = id->driver_info >> 8;
825 sd->bridge = id->driver_info & 0xff;
826 gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300827
828 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300829 cam->epaddr = 0x01;
Hans de Goedef45f06b2008-09-03 17:12:21 -0300830 if (!(sensor_data[sd->sensor].flags & F_SIF)) {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300831 cam->cam_mode = vga_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300832 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300833 } else {
834 cam->cam_mode = sif_mode;
Andoni Zubimendi51fc8e32008-07-10 11:12:24 -0300835 cam->nmodes = ARRAY_SIZE(sif_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300836 }
Hans de Goedec437d652008-09-03 17:12:22 -0300837 if (!(sensor_data[sd->sensor].flags & F_RAW)) {
838 cam->cam_mode++;
839 cam->nmodes--;
840 }
Hans de Goededcef3232008-07-10 10:40:53 -0300841 sd->brightness = BRIGHTNESS_DEF;
842 sd->gain = GAIN_DEF;
843 sd->exposure = EXPOSURE_DEF;
Hans de Goedee2ad2a52008-09-03 17:12:15 -0300844 if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
845 sd->autogain = 0; /* Disable do_autogain callback */
846 else
847 sd->autogain = AUTOGAIN_DEF;
Hans de Goede12ff9122008-07-17 10:30:56 -0300848 sd->freq = FREQ_DEF;
Hans de Goede6af492e2008-07-22 07:09:33 -0300849
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300850 return 0;
851}
852
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300853/* this function is called at probe and resume time */
854static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300855{
Hans de Goede271315a2008-09-03 17:12:19 -0300856 const __u8 stop = 0x09; /* Disable stream turn of LED */
857
858 reg_w(gspca_dev, 0x01, &stop, 1);
859
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300860 return 0;
861}
862
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300863/* -- start the camera -- */
864static void sd_start(struct gspca_dev *gspca_dev)
865{
866 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedef45f06b2008-09-03 17:12:21 -0300867 int mode, l;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300868 const __u8 *sn9c10x;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300869 __u8 reg17_19[3];
870
Hans de Goedef45f06b2008-09-03 17:12:21 -0300871 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 0x07;
872 sn9c10x = sensor_data[sd->sensor].bridge_init[sd->bridge];
873 l = sensor_data[sd->sensor].bridge_init_size[sd->bridge];
874 reg17_19[0] = sn9c10x[0x17 - 1];
875 reg17_19[1] = sn9c10x[0x18 - 1] | (mode << 4);
876 reg17_19[2] = sn9c10x[0x19 - 1];
877 /* Special cases where reg 17 and or 19 value depends on mode */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300878 switch (sd->sensor) {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300879 case SENSOR_PAS202:
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300880 reg17_19[0] = mode ? 0x24 : 0x20;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300881 break;
Hans de Goedef45f06b2008-09-03 17:12:21 -0300882 case SENSOR_TAS5130CXX:
883 /* probably not mode specific at all most likely the upper
884 nibble of 0x19 is exposure (clock divider) just as with
885 the tas5110, we need someone to test this. */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300886 reg17_19[2] = mode ? 0x23 : 0x43;
887 break;
888 }
Hans de Goedec437d652008-09-03 17:12:22 -0300889 /* Disable compression when the raw bayer format has been selected */
890 if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & MODE_RAW)
891 reg17_19[1] &= ~0x80;
Hans de Goede6af492e2008-07-22 07:09:33 -0300892
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300893 /* reg 0x01 bit 2 video transfert on */
Hans de Goedefff42052008-07-23 07:04:39 -0300894 reg_w(gspca_dev, 0x01, &sn9c10x[0x01 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300895 /* reg 0x17 SensorClk enable inv Clk 0x60 */
Hans de Goedefff42052008-07-23 07:04:39 -0300896 reg_w(gspca_dev, 0x17, &sn9c10x[0x17 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300897 /* Set the registers from the template */
Jean-Francois Moine8295d992008-09-03 17:12:19 -0300898 reg_w(gspca_dev, 0x01, sn9c10x, l);
Hans de Goedef45f06b2008-09-03 17:12:21 -0300899
900 /* Init the sensor */
901 i2c_w_vector(gspca_dev, sensor_data[sd->sensor].sensor_init,
902 sensor_data[sd->sensor].sensor_init_size);
903 if (sensor_data[sd->sensor].sensor_bridge_init[sd->bridge])
904 i2c_w_vector(gspca_dev,
905 sensor_data[sd->sensor].sensor_bridge_init[sd->bridge],
906 sensor_data[sd->sensor].sensor_bridge_init_size[
907 sd->bridge]);
908
Hans de Goede3647fea2008-07-15 05:36:30 -0300909 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
910 reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300911 /* compression register */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300912 reg_w(gspca_dev, 0x18, &reg17_19[1], 1);
Andoni Zubimendi794af522008-07-16 08:33:14 -0300913 /* H_start */
914 reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1);
915 /* V_START */
916 reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300917 /* reset 0x17 SensorClk enable inv Clk 0x60 */
918 /*fixme: ov7630 [17]=68 8f (+20 if 102)*/
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300919 reg_w(gspca_dev, 0x17, &reg17_19[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300920 /*MCKSIZE ->3 */ /*fixme: not ov7630*/
Andoni Zubimendi794af522008-07-16 08:33:14 -0300921 reg_w(gspca_dev, 0x19, &reg17_19[2], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300922 /* AE_STRX AE_STRY AE_ENDX AE_ENDY */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300923 reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300924 /* Enable video transfert */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300925 reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300926 /* Compression */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300927 reg_w(gspca_dev, 0x18, &reg17_19[1], 2);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300928 msleep(20);
929
Hans de Goede6af492e2008-07-22 07:09:33 -0300930 sd->reg11 = -1;
931
Hans de Goededcef3232008-07-10 10:40:53 -0300932 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300933 setbrightness(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -0300934 setexposure(gspca_dev);
Hans de Goede66f35822008-07-16 10:16:28 -0300935 setfreq(gspca_dev);
Hans de Goededcef3232008-07-10 10:40:53 -0300936
Hans de Goede6af492e2008-07-22 07:09:33 -0300937 sd->frames_to_drop = 0;
Hans de Goededcef3232008-07-10 10:40:53 -0300938 sd->autogain_ignore_frames = 0;
939 atomic_set(&sd->avg_lum, -1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300940}
941
942static void sd_stopN(struct gspca_dev *gspca_dev)
943{
Hans de Goedef45f06b2008-09-03 17:12:21 -0300944 sd_init(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300945}
946
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300947static void sd_pkt_scan(struct gspca_dev *gspca_dev,
948 struct gspca_frame *frame, /* target */
949 unsigned char *data, /* isoc packet */
950 int len) /* iso packet length */
951{
Hans de Goede0d2a7222008-07-03 08:15:22 -0300952 int i;
Hans de Goededcef3232008-07-10 10:40:53 -0300953 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedec437d652008-09-03 17:12:22 -0300954 struct cam *cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300955
Hans de Goedec36260ee2008-07-16 09:56:07 -0300956 /* frames start with:
957 * ff ff 00 c4 c4 96 synchro
958 * 00 (unknown)
959 * xx (frame sequence / size / compression)
960 * (xx) (idem - extra byte for sn9c103)
961 * ll mm brightness sum inside auto exposure
962 * ll mm brightness sum outside auto exposure
963 * (xx xx xx xx xx) audio values for snc103
964 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300965 if (len > 6 && len < 24) {
Hans de Goede0d2a7222008-07-03 08:15:22 -0300966 for (i = 0; i < len - 6; i++) {
967 if (data[0 + i] == 0xff
968 && data[1 + i] == 0xff
969 && data[2 + i] == 0x00
970 && data[3 + i] == 0xc4
971 && data[4 + i] == 0xc4
972 && data[5 + i] == 0x96) { /* start of frame */
Hans de Goede6af492e2008-07-22 07:09:33 -0300973 int lum = -1;
974 int pkt_type = LAST_PACKET;
Hans de Goedef45f06b2008-09-03 17:12:21 -0300975 int fr_h_sz = (sd->bridge == BRIDGE_103) ?
976 18 : 12;
Hans de Goede6af492e2008-07-22 07:09:33 -0300977
Hans de Goedef45f06b2008-09-03 17:12:21 -0300978 if (len - i < fr_h_sz) {
Hans de Goedec36260ee2008-07-16 09:56:07 -0300979 PDEBUG(D_STREAM, "packet too short to"
980 " get avg brightness");
Hans de Goedef45f06b2008-09-03 17:12:21 -0300981 } else if (sd->bridge == BRIDGE_103) {
Hans de Goede6af492e2008-07-22 07:09:33 -0300982 lum = data[i + 9] +
983 (data[i + 10] << 8);
Hans de Goedef45f06b2008-09-03 17:12:21 -0300984 } else {
985 lum = data[i + 8] + (data[i + 9] << 8);
Hans de Goededcef3232008-07-10 10:40:53 -0300986 }
Hans de Goede6af492e2008-07-22 07:09:33 -0300987 if (lum == 0) {
988 lum = -1;
989 sd->frames_to_drop = 2;
990 }
991 atomic_set(&sd->avg_lum, lum);
992
993 if (sd->frames_to_drop) {
994 sd->frames_to_drop--;
995 pkt_type = DISCARD_PACKET;
996 }
997
998 frame = gspca_frame_add(gspca_dev, pkt_type,
999 frame, data, 0);
Hans de Goedef45f06b2008-09-03 17:12:21 -03001000 data += i + fr_h_sz;
1001 len -= i + fr_h_sz;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001002 gspca_frame_add(gspca_dev, FIRST_PACKET,
1003 frame, data, len);
1004 return;
1005 }
1006 }
1007 }
Hans de Goedec437d652008-09-03 17:12:22 -03001008
1009 if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) {
1010 /* In raw mode we sometimes get some garbage after the frame
1011 ignore this */
1012 int used = frame->data_end - frame->data;
1013 int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage;
1014
1015 if (used + len > size)
1016 len = size - used;
1017 }
1018
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001019 gspca_frame_add(gspca_dev, INTER_PACKET,
1020 frame, data, len);
1021}
1022
1023static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1024{
1025 struct sd *sd = (struct sd *) gspca_dev;
1026
1027 sd->brightness = val;
1028 if (gspca_dev->streaming)
1029 setbrightness(gspca_dev);
1030 return 0;
1031}
1032
1033static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1034{
1035 struct sd *sd = (struct sd *) gspca_dev;
1036
1037 *val = sd->brightness;
1038 return 0;
1039}
1040
Hans de Goededcef3232008-07-10 10:40:53 -03001041static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001042{
1043 struct sd *sd = (struct sd *) gspca_dev;
1044
Hans de Goededcef3232008-07-10 10:40:53 -03001045 sd->gain = val;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001046 if (gspca_dev->streaming)
Hans de Goededcef3232008-07-10 10:40:53 -03001047 setgain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001048 return 0;
1049}
1050
Hans de Goededcef3232008-07-10 10:40:53 -03001051static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001052{
1053 struct sd *sd = (struct sd *) gspca_dev;
1054
Hans de Goededcef3232008-07-10 10:40:53 -03001055 *val = sd->gain;
1056 return 0;
1057}
1058
1059static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
1060{
1061 struct sd *sd = (struct sd *) gspca_dev;
1062
1063 sd->exposure = val;
1064 if (gspca_dev->streaming)
1065 setexposure(gspca_dev);
1066 return 0;
1067}
1068
1069static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
1070{
1071 struct sd *sd = (struct sd *) gspca_dev;
1072
1073 *val = sd->exposure;
1074 return 0;
1075}
1076
1077static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1078{
1079 struct sd *sd = (struct sd *) gspca_dev;
1080
1081 sd->autogain = val;
1082 /* when switching to autogain set defaults to make sure
1083 we are on a valid point of the autogain gain /
1084 exposure knee graph, and give this change time to
1085 take effect before doing autogain. */
1086 if (sd->autogain) {
1087 sd->exposure = EXPOSURE_DEF;
1088 sd->gain = GAIN_DEF;
1089 if (gspca_dev->streaming) {
1090 sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
1091 setexposure(gspca_dev);
1092 setgain(gspca_dev);
1093 }
1094 }
1095
1096 return 0;
1097}
1098
1099static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1100{
1101 struct sd *sd = (struct sd *) gspca_dev;
1102
1103 *val = sd->autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001104 return 0;
1105}
1106
Hans de Goede66f35822008-07-16 10:16:28 -03001107static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
1108{
1109 struct sd *sd = (struct sd *) gspca_dev;
1110
1111 sd->freq = val;
1112 if (gspca_dev->streaming)
1113 setfreq(gspca_dev);
1114 return 0;
1115}
1116
1117static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
1118{
1119 struct sd *sd = (struct sd *) gspca_dev;
1120
1121 *val = sd->freq;
1122 return 0;
1123}
1124
1125static int sd_querymenu(struct gspca_dev *gspca_dev,
1126 struct v4l2_querymenu *menu)
1127{
1128 switch (menu->id) {
1129 case V4L2_CID_POWER_LINE_FREQUENCY:
1130 switch (menu->index) {
1131 case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
1132 strcpy((char *) menu->name, "NoFliker");
1133 return 0;
1134 case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
1135 strcpy((char *) menu->name, "50 Hz");
1136 return 0;
1137 case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
1138 strcpy((char *) menu->name, "60 Hz");
1139 return 0;
1140 }
1141 break;
1142 }
1143 return -EINVAL;
1144}
1145
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001146/* sub-driver description */
Hans de Goededcef3232008-07-10 10:40:53 -03001147static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001148 .name = MODULE_NAME,
1149 .ctrls = sd_ctrls,
1150 .nctrls = ARRAY_SIZE(sd_ctrls),
1151 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001152 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001153 .start = sd_start,
1154 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001155 .pkt_scan = sd_pkt_scan,
Hans de Goede66f35822008-07-16 10:16:28 -03001156 .querymenu = sd_querymenu,
Hans de Goedee2ad2a52008-09-03 17:12:15 -03001157 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001158};
1159
1160/* -- module initialisation -- */
Hans de Goedef45f06b2008-09-03 17:12:21 -03001161#define SB(sensor, bridge) \
1162 .driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge
1163
Hans de Goedee2ad2a52008-09-03 17:12:15 -03001164
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001165static __devinitdata struct usb_device_id device_table[] = {
Hans de Goede222a07f2008-09-03 17:12:20 -03001166#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
Hans de Goedef45f06b2008-09-03 17:12:21 -03001167 {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110, 102)},
1168 {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110, 101)},
1169 {USB_DEVICE(0x0c45, 0x6007), SB(TAS5110, 101)},
1170 {USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)},
1171 {USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)},
Hans de Goede5de39b22008-07-17 10:34:28 -03001172#endif
Hans de Goedef45f06b2008-09-03 17:12:21 -03001173 {USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)},
Hans de Goede222a07f2008-09-03 17:12:20 -03001174#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
Hans de Goedef45f06b2008-09-03 17:12:21 -03001175 {USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)},
1176 {USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)},
1177 {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)},
1178 {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)},
1179 {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)},
1180 {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)},
Hans de Goede222a07f2008-09-03 17:12:20 -03001181#endif
Hans de Goedef45f06b2008-09-03 17:12:21 -03001182 {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)},
Hans de Goede222a07f2008-09-03 17:12:20 -03001183#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
Hans de Goedef45f06b2008-09-03 17:12:21 -03001184 {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)},
1185 {USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)},
1186 {USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)},
1187 {USB_DEVICE(0x0c45, 0x60b0), SB(OV7630, 103)},
Jean-Francois Moinec41492c2008-07-07 08:31:16 -03001188#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001189 {}
1190};
1191MODULE_DEVICE_TABLE(usb, device_table);
1192
1193/* -- device connect -- */
1194static int sd_probe(struct usb_interface *intf,
1195 const struct usb_device_id *id)
1196{
1197 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1198 THIS_MODULE);
1199}
1200
1201static struct usb_driver sd_driver = {
1202 .name = MODULE_NAME,
1203 .id_table = device_table,
1204 .probe = sd_probe,
1205 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001206#ifdef CONFIG_PM
1207 .suspend = gspca_suspend,
1208 .resume = gspca_resume,
1209#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001210};
1211
1212/* -- module insert / remove -- */
1213static int __init sd_mod_init(void)
1214{
1215 if (usb_register(&sd_driver) < 0)
1216 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001217 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001218 return 0;
1219}
1220static void __exit sd_mod_exit(void)
1221{
1222 usb_deregister(&sd_driver);
1223 PDEBUG(D_PROBE, "deregistered");
1224}
1225
1226module_init(sd_mod_init);
1227module_exit(sd_mod_exit);