blob: 6346ddc679672a8e5cef225fff17e8c1f917bbcf [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * Sunplus spca561 subdriver
3 *
4 * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr
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 "spca561"
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/SPCA561 USB Camera Driver");
29MODULE_LICENSE("GPL");
30
31/* specific webcam descriptor */
32struct sd {
33 struct gspca_dev gspca_dev; /* !! must be the first item */
34
Jean-Francois Moine7879d452008-09-03 16:47:32 -030035 __u16 exposure; /* rev12a only */
Hans de Goede0fc23d22008-09-04 16:22:57 -030036#define EXPOSURE_MIN 1
Hans de Goeded0848eb2009-05-25 15:20:16 -030037#define EXPOSURE_DEF 700 /* == 10 fps */
38#define EXPOSURE_MAX (2047 + 325) /* see setexposure */
Jean-Francois Moine7879d452008-09-03 16:47:32 -030039
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -030040 __u8 contrast; /* rev72a only */
41#define CONTRAST_MIN 0x00
42#define CONTRAST_DEF 0x20
43#define CONTRAST_MAX 0x3f
44
Jean-Francois Moine7879d452008-09-03 16:47:32 -030045 __u8 brightness; /* rev72a only */
46#define BRIGHTNESS_MIN 0
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -030047#define BRIGHTNESS_DEF 0x20
48#define BRIGHTNESS_MAX 0x3f
Jean-Francois Moine7879d452008-09-03 16:47:32 -030049
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -030050 __u8 white;
Hans de Goede9035f2e2009-05-25 15:26:59 -030051#define HUE_MIN 1
52#define HUE_DEF 0x40
53#define HUE_MAX 0x7f
Jean-Francois Moine7879d452008-09-03 16:47:32 -030054
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030055 __u8 autogain;
Jean-Francois Moine7879d452008-09-03 16:47:32 -030056#define AUTOGAIN_MIN 0
57#define AUTOGAIN_DEF 1
58#define AUTOGAIN_MAX 1
59
60 __u8 gain; /* rev12a only */
Hans de Goeded0848eb2009-05-25 15:20:16 -030061#define GAIN_MIN 0
62#define GAIN_DEF 63
63#define GAIN_MAX 255
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030064
Jean-Francois Moined698dc62008-09-03 16:47:51 -030065#define EXPO12A_DEF 3
66 __u8 expo12a; /* expo/gain? for rev 12a */
67
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030068 __u8 chip_revision;
Jean-Francois Moine7879d452008-09-03 16:47:32 -030069#define Rev012A 0
70#define Rev072A 1
71
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030072 signed char ag_cnt;
73#define AG_CNT_START 13
74};
75
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030076static const struct v4l2_pix_format sif_012a_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030077 {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
78 .bytesperline = 160,
79 .sizeimage = 160 * 120,
80 .colorspace = V4L2_COLORSPACE_SRGB,
81 .priv = 3},
82 {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
83 .bytesperline = 176,
84 .sizeimage = 176 * 144,
85 .colorspace = V4L2_COLORSPACE_SRGB,
86 .priv = 2},
87 {320, 240, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
88 .bytesperline = 320,
89 .sizeimage = 320 * 240 * 4 / 8,
90 .colorspace = V4L2_COLORSPACE_SRGB,
91 .priv = 1},
92 {352, 288, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
93 .bytesperline = 352,
94 .sizeimage = 352 * 288 * 4 / 8,
95 .colorspace = V4L2_COLORSPACE_SRGB,
96 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030097};
98
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030099static const struct v4l2_pix_format sif_072a_mode[] = {
Jean-Francois Moineb77c0042008-09-04 16:22:56 -0300100 {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
101 .bytesperline = 160,
102 .sizeimage = 160 * 120,
103 .colorspace = V4L2_COLORSPACE_SRGB,
104 .priv = 3},
105 {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
106 .bytesperline = 176,
107 .sizeimage = 176 * 144,
108 .colorspace = V4L2_COLORSPACE_SRGB,
109 .priv = 2},
110 {320, 240, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
111 .bytesperline = 320,
112 .sizeimage = 320 * 240,
113 .colorspace = V4L2_COLORSPACE_SRGB,
114 .priv = 1},
115 {352, 288, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
116 .bytesperline = 352,
117 .sizeimage = 352 * 288,
118 .colorspace = V4L2_COLORSPACE_SRGB,
119 .priv = 0},
120};
121
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300122/*
123 * Initialization data
124 * I'm not very sure how to split initialization from open data
125 * chunks. For now, we'll consider everything as initialization
126 */
127/* Frame packet header offsets for the spca561 */
128#define SPCA561_OFFSET_SNAP 1
129#define SPCA561_OFFSET_TYPE 2
130#define SPCA561_OFFSET_COMPRESS 3
131#define SPCA561_OFFSET_FRAMSEQ 4
132#define SPCA561_OFFSET_GPIO 5
133#define SPCA561_OFFSET_USBBUFF 6
134#define SPCA561_OFFSET_WIN2GRAVE 7
135#define SPCA561_OFFSET_WIN2RAVE 8
136#define SPCA561_OFFSET_WIN2BAVE 9
137#define SPCA561_OFFSET_WIN2GBAVE 10
138#define SPCA561_OFFSET_WIN1GRAVE 11
139#define SPCA561_OFFSET_WIN1RAVE 12
140#define SPCA561_OFFSET_WIN1BAVE 13
141#define SPCA561_OFFSET_WIN1GBAVE 14
142#define SPCA561_OFFSET_FREQ 15
143#define SPCA561_OFFSET_VSYNC 16
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300144#define SPCA561_INDEX_I2C_BASE 0x8800
145#define SPCA561_SNAPBIT 0x20
146#define SPCA561_SNAPCTRL 0x40
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300147
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300148static const u16 rev72a_reset[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300149 {0x0000, 0x8114}, /* Software GPIO output data */
150 {0x0001, 0x8114}, /* Software GPIO output data */
151 {0x0000, 0x8112}, /* Some kind of reset */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300152 {}
153};
154static const __u16 rev72a_init_data1[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300155 {0x0003, 0x8701}, /* PCLK clock delay adjustment */
156 {0x0001, 0x8703}, /* HSYNC from cmos inverted */
157 {0x0011, 0x8118}, /* Enable and conf sensor */
158 {0x0001, 0x8118}, /* Conf sensor */
159 {0x0092, 0x8804}, /* I know nothing about these */
160 {0x0010, 0x8802}, /* 0x88xx registers, so I won't */
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300161 {}
162};
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300163static const u16 rev72a_init_sensor1[][2] = {
164 {0x0001, 0x000d},
165 {0x0002, 0x0018},
166 {0x0004, 0x0165},
167 {0x0005, 0x0021},
168 {0x0007, 0x00aa},
169 {0x0020, 0x1504},
170 {0x0039, 0x0002},
171 {0x0035, 0x0010},
172 {0x0009, 0x1049},
173 {0x0028, 0x000b},
174 {0x003b, 0x000f},
175 {0x003c, 0x0000},
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300176 {}
177};
178static const __u16 rev72a_init_data2[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300179 {0x0018, 0x8601}, /* Pixel/line selection for color separation */
180 {0x0000, 0x8602}, /* Optical black level for user setting */
181 {0x0060, 0x8604}, /* Optical black horizontal offset */
182 {0x0002, 0x8605}, /* Optical black vertical offset */
183 {0x0000, 0x8603}, /* Non-automatic optical black level */
184 {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
185 {0x0000, 0x865f}, /* Vertical valid pixels window (x2) */
186 {0x00b0, 0x865d}, /* Horizontal valid pixels window (x2) */
187 {0x0090, 0x865e}, /* Vertical valid lines window (x2) */
188 {0x00e0, 0x8406}, /* Memory buffer threshold */
189 {0x0000, 0x8660}, /* Compensation memory stuff */
190 {0x0002, 0x8201}, /* Output address for r/w serial EEPROM */
191 {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */
192 {0x0001, 0x8200}, /* OprMode to be executed by hardware */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300193/* from ms-win */
194 {0x0000, 0x8611}, /* R offset for white balance */
195 {0x00fd, 0x8612}, /* Gr offset for white balance */
196 {0x0003, 0x8613}, /* B offset for white balance */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300197 {0x0000, 0x8614}, /* Gb offset for white balance */
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300198/* from ms-win */
199 {0x0035, 0x8651}, /* R gain for white balance */
200 {0x0040, 0x8652}, /* Gr gain for white balance */
201 {0x005f, 0x8653}, /* B gain for white balance */
202 {0x0040, 0x8654}, /* Gb gain for white balance */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300203 {0x0002, 0x8502}, /* Maximum average bit rate stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300204 {0x0011, 0x8802},
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300205
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300206 {0x0087, 0x8700}, /* Set master clock (96Mhz????) */
207 {0x0081, 0x8702}, /* Master clock output enable */
208
209 {0x0000, 0x8500}, /* Set image type (352x288 no compression) */
210 /* Originally was 0x0010 (352x288 compression) */
211
212 {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
213 {0x0003, 0x865c}, /* Vertical offset for valid lines */
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300214 {}
215};
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300216static const u16 rev72a_init_sensor2[][2] = {
217 {0x0003, 0x0121},
218 {0x0004, 0x0165},
219 {0x0005, 0x002f}, /* blanking control column */
220 {0x0006, 0x0000}, /* blanking mode row*/
221 {0x000a, 0x0002},
222 {0x0009, 0x1061}, /* setexposure times && pixel clock
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300223 * 0001 0 | 000 0110 0001 */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300224 {0x0035, 0x0014},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300225 {}
226};
227
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300228/******************** QC Express etch2 stuff ********************/
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300229static const __u16 Pb100_1map8300[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300230 /* reg, value */
231 {0x8320, 0x3304},
232
233 {0x8303, 0x0125}, /* image area */
234 {0x8304, 0x0169},
235 {0x8328, 0x000b},
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300236 {0x833c, 0x0001}, /*fixme: win:07*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300237
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300238 {0x832f, 0x1904}, /*fixme: was 0419*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300239 {0x8307, 0x00aa},
240 {0x8301, 0x0003},
241 {0x8302, 0x000e},
242 {}
243};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300244static const __u16 Pb100_2map8300[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300245 /* reg, value */
246 {0x8339, 0x0000},
247 {0x8307, 0x00aa},
248 {}
249};
250
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300251static const __u16 spca561_161rev12A_data1[][2] = {
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300252 {0x29, 0x8118}, /* Control register (various enable bits) */
253 {0x08, 0x8114}, /* GPIO: Led off */
254 {0x0e, 0x8112}, /* 0x0e stream off 0x3e stream on */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300255 {0x00, 0x8102}, /* white balance - new */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300256 {0x92, 0x8804},
257 {0x04, 0x8802}, /* windows uses 08 */
258 {}
259};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300260static const __u16 spca561_161rev12A_data2[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300261 {0x21, 0x8118},
262 {0x10, 0x8500},
263 {0x07, 0x8601},
264 {0x07, 0x8602},
265 {0x04, 0x8501},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300266
267 {0x07, 0x8201}, /* windows uses 02 */
268 {0x08, 0x8200},
269 {0x01, 0x8200},
270
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300271 {0x90, 0x8604},
272 {0x00, 0x8605},
273 {0xb0, 0x8603},
274
275 /* sensor gains */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300276 {0x07, 0x8601}, /* white balance - new */
277 {0x07, 0x8602}, /* white balance - new */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300278 {0x00, 0x8610}, /* *red */
279 {0x00, 0x8611}, /* 3f *green */
280 {0x00, 0x8612}, /* green *blue */
281 {0x00, 0x8613}, /* blue *green */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300282 {0x43, 0x8614}, /* green *red - white balance - was 0x35 */
283 {0x40, 0x8615}, /* 40 *green - white balance - was 0x35 */
284 {0x71, 0x8616}, /* 7a *blue - white balance - was 0x35 */
285 {0x40, 0x8617}, /* 40 *green - white balance - was 0x35 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300286
287 {0x0c, 0x8620}, /* 0c */
288 {0xc8, 0x8631}, /* c8 */
289 {0xc8, 0x8634}, /* c8 */
290 {0x23, 0x8635}, /* 23 */
291 {0x1f, 0x8636}, /* 1f */
292 {0xdd, 0x8637}, /* dd */
293 {0xe1, 0x8638}, /* e1 */
294 {0x1d, 0x8639}, /* 1d */
295 {0x21, 0x863a}, /* 21 */
296 {0xe3, 0x863b}, /* e3 */
297 {0xdf, 0x863c}, /* df */
298 {0xf0, 0x8505},
299 {0x32, 0x850a},
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300300/* {0x99, 0x8700}, * - white balance - new (removed) */
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300301 /* HDG we used to do this in stop0, making the init state and the state
302 after a start / stop different, so do this here instead. */
303 {0x29, 0x8118},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300304 {}
305};
306
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300307static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300308{
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300309 int ret;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300310
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300311 ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
312 0, /* request */
313 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
314 value, index, NULL, 0, 500);
315 PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
316 if (ret < 0)
317 PDEBUG(D_ERR, "reg write: error %d", ret);
318}
319
320static void write_vector(struct gspca_dev *gspca_dev,
321 const __u16 data[][2])
322{
323 struct usb_device *dev = gspca_dev->dev;
324 int i;
325
326 i = 0;
327 while (data[i][1] != 0) {
328 reg_w_val(dev, data[i][1], data[i][0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300329 i++;
330 }
331}
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300332
333/* read 'len' bytes to gspca_dev->usb_buf */
334static void reg_r(struct gspca_dev *gspca_dev,
335 __u16 index, __u16 length)
336{
337 usb_control_msg(gspca_dev->dev,
338 usb_rcvctrlpipe(gspca_dev->dev, 0),
339 0, /* request */
340 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
341 0, /* value */
342 index, gspca_dev->usb_buf, length, 500);
343}
344
345/* write 'len' bytes from gspca_dev->usb_buf */
346static void reg_w_buf(struct gspca_dev *gspca_dev,
347 __u16 index, __u16 len)
348{
349 usb_control_msg(gspca_dev->dev,
350 usb_sndctrlpipe(gspca_dev->dev, 0),
351 0, /* request */
352 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
353 0, /* value */
354 index, gspca_dev->usb_buf, len, 500);
355}
356
357static void i2c_write(struct gspca_dev *gspca_dev, __u16 value, __u16 reg)
358{
359 int retry = 60;
360
361 reg_w_val(gspca_dev->dev, 0x8801, reg);
362 reg_w_val(gspca_dev->dev, 0x8805, value);
363 reg_w_val(gspca_dev->dev, 0x8800, value >> 8);
364 do {
365 reg_r(gspca_dev, 0x8803, 1);
366 if (!gspca_dev->usb_buf[0])
367 return;
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300368 msleep(10);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300369 } while (--retry);
370}
371
372static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
373{
374 int retry = 60;
375 __u8 value;
376
377 reg_w_val(gspca_dev->dev, 0x8804, 0x92);
378 reg_w_val(gspca_dev->dev, 0x8801, reg);
379 reg_w_val(gspca_dev->dev, 0x8802, mode | 0x01);
380 do {
381 reg_r(gspca_dev, 0x8803, 1);
382 if (!gspca_dev->usb_buf[0]) {
383 reg_r(gspca_dev, 0x8800, 1);
384 value = gspca_dev->usb_buf[0];
385 reg_r(gspca_dev, 0x8805, 1);
386 return ((int) value << 8) | gspca_dev->usb_buf[0];
387 }
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300388 msleep(10);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300389 } while (--retry);
390 return -1;
391}
392
393static void sensor_mapwrite(struct gspca_dev *gspca_dev,
394 const __u16 (*sensormap)[2])
395{
396 while ((*sensormap)[0]) {
397 gspca_dev->usb_buf[0] = (*sensormap)[1];
398 gspca_dev->usb_buf[1] = (*sensormap)[1] >> 8;
399 reg_w_buf(gspca_dev, (*sensormap)[0], 2);
400 sensormap++;
401 }
402}
403
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300404static void write_sensor_72a(struct gspca_dev *gspca_dev,
405 const __u16 (*sensor)[2])
406{
407 while ((*sensor)[0]) {
408 i2c_write(gspca_dev, (*sensor)[1], (*sensor)[0]);
409 sensor++;
410 }
411}
412
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300413static void init_161rev12A(struct gspca_dev *gspca_dev)
414{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300415 write_vector(gspca_dev, spca561_161rev12A_data1);
416 sensor_mapwrite(gspca_dev, Pb100_1map8300);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300417/*fixme: should be in sd_start*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300418 write_vector(gspca_dev, spca561_161rev12A_data2);
419 sensor_mapwrite(gspca_dev, Pb100_2map8300);
420}
421
422/* this function is called at probe time */
423static int sd_config(struct gspca_dev *gspca_dev,
424 const struct usb_device_id *id)
425{
426 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300427 struct cam *cam;
428 __u16 vendor, product;
429 __u8 data1, data2;
430
431 /* Read frm global register the USB product and vendor IDs, just to
432 * prove that we can communicate with the device. This works, which
433 * confirms at we are communicating properly and that the device
434 * is a 561. */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300435 reg_r(gspca_dev, 0x8104, 1);
436 data1 = gspca_dev->usb_buf[0];
437 reg_r(gspca_dev, 0x8105, 1);
438 data2 = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300439 vendor = (data2 << 8) | data1;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300440 reg_r(gspca_dev, 0x8106, 1);
441 data1 = gspca_dev->usb_buf[0];
442 reg_r(gspca_dev, 0x8107, 1);
443 data2 = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300444 product = (data2 << 8) | data1;
445 if (vendor != id->idVendor || product != id->idProduct) {
446 PDEBUG(D_PROBE, "Bad vendor / product from device");
447 return -EINVAL;
448 }
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300449
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300450 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300451 gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300452
453 sd->chip_revision = id->driver_info;
Jean-Francois Moineb77c0042008-09-04 16:22:56 -0300454 if (sd->chip_revision == Rev012A) {
455 cam->cam_mode = sif_012a_mode;
456 cam->nmodes = ARRAY_SIZE(sif_012a_mode);
457 } else {
458 cam->cam_mode = sif_072a_mode;
459 cam->nmodes = ARRAY_SIZE(sif_072a_mode);
460 }
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300461 sd->brightness = BRIGHTNESS_DEF;
462 sd->contrast = CONTRAST_DEF;
Hans de Goede9035f2e2009-05-25 15:26:59 -0300463 sd->white = HUE_DEF;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300464 sd->exposure = EXPOSURE_DEF;
465 sd->autogain = AUTOGAIN_DEF;
466 sd->gain = GAIN_DEF;
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300467 sd->expo12a = EXPO12A_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300468 return 0;
469}
470
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300471/* this function is called at probe and resume time */
472static int sd_init_12a(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300473{
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300474 PDEBUG(D_STREAM, "Chip revision: 012a");
475 init_161rev12A(gspca_dev);
476 return 0;
477}
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300478static int sd_init_72a(struct gspca_dev *gspca_dev)
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300479{
480 PDEBUG(D_STREAM, "Chip revision: 072a");
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300481 write_vector(gspca_dev, rev72a_reset);
482 msleep(200);
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300483 write_vector(gspca_dev, rev72a_init_data1);
484 write_sensor_72a(gspca_dev, rev72a_init_sensor1);
485 write_vector(gspca_dev, rev72a_init_data2);
486 write_sensor_72a(gspca_dev, rev72a_init_sensor2);
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300487 reg_w_val(gspca_dev->dev, 0x8112, 0x30);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300488 return 0;
489}
490
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300491/* rev 72a only */
492static void setbrightness(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300493{
494 struct sd *sd = (struct sd *) gspca_dev;
495 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300496 __u8 value;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300497
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300498 value = sd->brightness;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300499
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300500 /* offsets for white balance */
501 reg_w_val(dev, 0x8611, value); /* R */
502 reg_w_val(dev, 0x8612, value); /* Gr */
503 reg_w_val(dev, 0x8613, value); /* B */
504 reg_w_val(dev, 0x8614, value); /* Gb */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300505}
506
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300507static void setwhite(struct gspca_dev *gspca_dev)
508{
509 struct sd *sd = (struct sd *) gspca_dev;
510 __u16 white;
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300511 __u8 blue, red;
512 __u16 reg;
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300513
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300514 /* try to emulate MS-win as possible */
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300515 white = sd->white;
516 red = 0x20 + white * 3 / 8;
517 blue = 0x90 - white * 5 / 8;
518 if (sd->chip_revision == Rev012A) {
519 reg = 0x8614;
520 } else {
521 reg = 0x8651;
522 red += sd->contrast - 0x20;
523 blue += sd->contrast - 0x20;
524 }
525 reg_w_val(gspca_dev->dev, reg, red);
526 reg_w_val(gspca_dev->dev, reg + 2, blue);
527}
528
529static void setcontrast(struct gspca_dev *gspca_dev)
530{
531 struct sd *sd = (struct sd *) gspca_dev;
532 struct usb_device *dev = gspca_dev->dev;
533 __u8 value;
534
535 if (sd->chip_revision != Rev072A)
536 return;
537 value = sd->contrast + 0x20;
538
539 /* gains for white balance */
540 setwhite(gspca_dev);
541/* reg_w_val(dev, 0x8651, value); * R - done by setwhite */
542 reg_w_val(dev, 0x8652, value); /* Gr */
543/* reg_w_val(dev, 0x8653, value); * B - done by setwhite */
544 reg_w_val(dev, 0x8654, value); /* Gb */
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300545}
546
547/* rev 12a only */
548static void setexposure(struct gspca_dev *gspca_dev)
549{
550 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goeded0848eb2009-05-25 15:20:16 -0300551 int i, expo = 0;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300552
Hans de Goede0fc23d22008-09-04 16:22:57 -0300553 /* Register 0x8309 controls exposure for the spca561,
554 the basic exposure setting goes from 1-2047, where 1 is completely
555 dark and 2047 is very bright. It not only influences exposure but
556 also the framerate (to allow for longer exposure) from 1 - 300 it
557 only raises the exposure time then from 300 - 600 it halves the
558 framerate to be able to further raise the exposure time and for every
559 300 more it halves the framerate again. This allows for a maximum
560 exposure time of circa 0.2 - 0.25 seconds (30 / (2000/3000) fps).
561 Sometimes this is not enough, the 1-2047 uses bits 0-10, bits 11-12
562 configure a divider for the base framerate which us used at the
563 exposure setting of 1-300. These bits configure the base framerate
564 according to the following formula: fps = 60 / (value + 2) */
Hans de Goeded0848eb2009-05-25 15:20:16 -0300565
566 /* We choose to use the high bits setting the fixed framerate divisor
567 asap, as setting high basic exposure setting without the fixed
568 divider in combination with high gains makes the cam stop */
569 int table[] = { 0, 450, 550, 625, EXPOSURE_MAX };
570
571 for (i = 0; i < ARRAY_SIZE(table) - 1; i++) {
572 if (sd->exposure <= table[i + 1]) {
573 expo = sd->exposure - table[i];
574 if (i)
575 expo += 300;
576 expo |= i << 11;
577 break;
578 }
Hans de Goede0fc23d22008-09-04 16:22:57 -0300579 }
Hans de Goeded0848eb2009-05-25 15:20:16 -0300580
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300581 gspca_dev->usb_buf[0] = expo;
582 gspca_dev->usb_buf[1] = expo >> 8;
583 reg_w_buf(gspca_dev, 0x8309, 2);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300584}
585
586/* rev 12a only */
587static void setgain(struct gspca_dev *gspca_dev)
588{
589 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300590
Hans de Goeded0848eb2009-05-25 15:20:16 -0300591 /* gain reg low 6 bits 0-63 gain, bit 6 and 7, both double the
592 sensitivity when set, so 31 + one of them set == 63, and 15
593 with both of them set == 63 */
594 if (sd->gain < 64)
595 gspca_dev->usb_buf[0] = sd->gain;
596 else if (sd->gain < 128)
597 gspca_dev->usb_buf[0] = (sd->gain / 2) | 0x40;
598 else
599 gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xC0;
600
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300601 gspca_dev->usb_buf[1] = 0;
602 reg_w_buf(gspca_dev, 0x8335, 2);
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300603}
604
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300605static void setautogain(struct gspca_dev *gspca_dev)
606{
607 struct sd *sd = (struct sd *) gspca_dev;
608
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300609 if (sd->autogain)
610 sd->ag_cnt = AG_CNT_START;
611 else
612 sd->ag_cnt = -1;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300613}
614
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300615static int sd_start_12a(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300616{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300617 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300618 int mode;
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300619 static const __u8 Reg8391[8] =
620 {0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300621
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300622 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300623 if (mode <= 1) {
624 /* Use compression on 320x240 and above */
625 reg_w_val(dev, 0x8500, 0x10 | mode);
626 } else {
627 /* I couldn't get the compression to work below 320x240
628 * Fortunately at these resolutions the bandwidth
629 * is sufficient to push raw frames at ~20fps */
630 reg_w_val(dev, 0x8500, mode);
631 } /* -- qq@kuku.eu.org */
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300632
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300633 gspca_dev->usb_buf[0] = 0xaa;
634 gspca_dev->usb_buf[1] = 0x00;
635 reg_w_buf(gspca_dev, 0x8307, 2);
636 /* clock - lower 0x8X values lead to fps > 30 */
637 reg_w_val(gspca_dev->dev, 0x8700, 0x8a);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300638 /* 0x8f 0x85 0x27 clock */
639 reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
640 reg_w_val(gspca_dev->dev, 0x850b, 0x03);
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300641 memcpy(gspca_dev->usb_buf, Reg8391, 8);
642 reg_w_buf(gspca_dev, 0x8391, 8);
643 reg_w_buf(gspca_dev, 0x8390, 8);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300644 setwhite(gspca_dev);
Hans de Goeded0848eb2009-05-25 15:20:16 -0300645 setgain(gspca_dev);
Hans de Goede0fc23d22008-09-04 16:22:57 -0300646 setexposure(gspca_dev);
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300647
648 /* Led ON (bit 3 -> 0 */
649 reg_w_val(gspca_dev->dev, 0x8114, 0x00);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300650 return 0;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300651}
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300652static int sd_start_72a(struct gspca_dev *gspca_dev)
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300653{
654 struct usb_device *dev = gspca_dev->dev;
655 int Clck;
656 int mode;
657
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300658 write_vector(gspca_dev, rev72a_reset);
659 msleep(200);
660 write_vector(gspca_dev, rev72a_init_data1);
661 write_sensor_72a(gspca_dev, rev72a_init_sensor1);
662
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300663 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
664 switch (mode) {
665 default:
Jean-Francois Moinea48196a2009-01-18 14:24:52 -0300666 case 0:
667 Clck = 0x27; /* ms-win 0x87 */
668 break;
669 case 1:
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300670 Clck = 0x25;
671 break;
672 case 2:
673 Clck = 0x22;
674 break;
675 case 3:
676 Clck = 0x21;
677 break;
678 }
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300679 reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */
Jean-Francois Moinea48196a2009-01-18 14:24:52 -0300680 reg_w_val(dev, 0x8702, 0x81);
681 reg_w_val(dev, 0x8500, mode); /* mode */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300682 write_sensor_72a(gspca_dev, rev72a_init_sensor2);
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300683 setcontrast(gspca_dev);
684/* setbrightness(gspca_dev); * fixme: bad values */
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300685 setautogain(gspca_dev);
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300686 reg_w_val(dev, 0x8112, 0x10 | 0x20);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300687 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300688}
689
690static void sd_stopN(struct gspca_dev *gspca_dev)
691{
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300692 struct sd *sd = (struct sd *) gspca_dev;
693
694 if (sd->chip_revision == Rev012A) {
695 reg_w_val(gspca_dev->dev, 0x8112, 0x0e);
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300696 /* Led Off (bit 3 -> 1 */
697 reg_w_val(gspca_dev->dev, 0x8114, 0x08);
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300698 } else {
699 reg_w_val(gspca_dev->dev, 0x8112, 0x20);
700/* reg_w_val(gspca_dev->dev, 0x8102, 0x00); ?? */
701 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300702}
703
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300704static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300705{
706 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300707 int expotimes;
708 int pixelclk;
709 int gainG;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300710 __u8 R, Gr, Gb, B;
711 int y;
712 __u8 luma_mean = 110;
713 __u8 luma_delta = 20;
714 __u8 spring = 4;
715
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300716 if (sd->ag_cnt < 0)
717 return;
718 if (--sd->ag_cnt >= 0)
719 return;
720 sd->ag_cnt = AG_CNT_START;
721
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300722 switch (sd->chip_revision) {
723 case Rev072A:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300724 reg_r(gspca_dev, 0x8621, 1);
725 Gr = gspca_dev->usb_buf[0];
726 reg_r(gspca_dev, 0x8622, 1);
727 R = gspca_dev->usb_buf[0];
728 reg_r(gspca_dev, 0x8623, 1);
729 B = gspca_dev->usb_buf[0];
730 reg_r(gspca_dev, 0x8624, 1);
731 Gb = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300732 y = (77 * R + 75 * (Gr + Gb) + 29 * B) >> 8;
733 /* u= (128*B-(43*(Gr+Gb+R))) >> 8; */
734 /* v= (128*R-(53*(Gr+Gb))-21*B) >> 8; */
735 /* PDEBUG(D_CONF,"reading Y %d U %d V %d ",y,u,v); */
736
737 if (y < luma_mean - luma_delta ||
738 y > luma_mean + luma_delta) {
739 expotimes = i2c_read(gspca_dev, 0x09, 0x10);
740 pixelclk = 0x0800;
741 expotimes = expotimes & 0x07ff;
742 /* PDEBUG(D_PACK,
743 "Exposition Times 0x%03X Clock 0x%04X ",
744 expotimes,pixelclk); */
745 gainG = i2c_read(gspca_dev, 0x35, 0x10);
746 /* PDEBUG(D_PACK,
747 "reading Gain register %d", gainG); */
748
749 expotimes += (luma_mean - y) >> spring;
750 gainG += (luma_mean - y) / 50;
751 /* PDEBUG(D_PACK,
752 "compute expotimes %d gain %d",
753 expotimes,gainG); */
754
755 if (gainG > 0x3f)
756 gainG = 0x3f;
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300757 else if (gainG < 3)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300758 gainG = 3;
759 i2c_write(gspca_dev, gainG, 0x35);
760
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300761 if (expotimes > 0x0256)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300762 expotimes = 0x0256;
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300763 else if (expotimes < 3)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300764 expotimes = 3;
765 i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
766 }
767 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300768 }
769}
770
771static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300772 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300773 int len) /* iso packet length */
774{
Hans de Goede0fc23d22008-09-04 16:22:57 -0300775 struct sd *sd = (struct sd *) gspca_dev;
776
Jean-Francois Moine576ed7b2009-01-16 08:57:28 -0300777 len--;
778 switch (*data++) { /* sequence number */
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300779 case 0: /* start of frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300780 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300781 if (data[1] & 0x10) {
782 /* compressed bayer */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300783 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300784 } else {
Hans de Goede54ab92c2008-07-03 11:20:58 -0300785 /* raw bayer (with a header, which we skip) */
Hans de Goede0fc23d22008-09-04 16:22:57 -0300786 if (sd->chip_revision == Rev012A) {
787 data += 20;
788 len -= 20;
789 } else {
790 data += 16;
791 len -= 16;
792 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300793 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300794 }
795 return;
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300796 case 0xff: /* drop (empty mpackets) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300797 return;
798 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300799 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300800}
801
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300802/* rev 72a only */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300803static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
804{
805 struct sd *sd = (struct sd *) gspca_dev;
806
807 sd->brightness = val;
808 if (gspca_dev->streaming)
809 setbrightness(gspca_dev);
810 return 0;
811}
812
813static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
814{
815 struct sd *sd = (struct sd *) gspca_dev;
816
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300817 *val = sd->brightness;
818 return 0;
819}
820
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300821/* rev 72a only */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300822static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
823{
824 struct sd *sd = (struct sd *) gspca_dev;
825
826 sd->contrast = val;
827 if (gspca_dev->streaming)
828 setcontrast(gspca_dev);
829 return 0;
830}
831
832static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
833{
834 struct sd *sd = (struct sd *) gspca_dev;
835
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300836 *val = sd->contrast;
837 return 0;
838}
839
840static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
841{
842 struct sd *sd = (struct sd *) gspca_dev;
843
844 sd->autogain = val;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300845 if (gspca_dev->streaming)
846 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300847 return 0;
848}
849
850static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
851{
852 struct sd *sd = (struct sd *) gspca_dev;
853
854 *val = sd->autogain;
855 return 0;
856}
857
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300858static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val)
859{
860 struct sd *sd = (struct sd *) gspca_dev;
861
862 sd->white = val;
863 if (gspca_dev->streaming)
864 setwhite(gspca_dev);
865 return 0;
866}
867
868static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val)
869{
870 struct sd *sd = (struct sd *) gspca_dev;
871
872 *val = sd->white;
873 return 0;
874}
875
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300876/* rev12a only */
877static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
878{
879 struct sd *sd = (struct sd *) gspca_dev;
880
881 sd->exposure = val;
882 if (gspca_dev->streaming)
883 setexposure(gspca_dev);
884 return 0;
885}
886
887static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
888{
889 struct sd *sd = (struct sd *) gspca_dev;
890
891 *val = sd->exposure;
892 return 0;
893}
894
895/* rev12a only */
896static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
897{
898 struct sd *sd = (struct sd *) gspca_dev;
899
900 sd->gain = val;
901 if (gspca_dev->streaming)
902 setgain(gspca_dev);
903 return 0;
904}
905
906static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
907{
908 struct sd *sd = (struct sd *) gspca_dev;
909
910 *val = sd->gain;
911 return 0;
912}
913
914/* control tables */
Marton Nemeth7e64dc42009-12-30 09:12:41 -0300915static const struct ctrl sd_ctrls_12a[] = {
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300916 {
917 {
Hans de Goede9035f2e2009-05-25 15:26:59 -0300918 .id = V4L2_CID_HUE,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300919 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goede9035f2e2009-05-25 15:26:59 -0300920 .name = "Hue",
921 .minimum = HUE_MIN,
922 .maximum = HUE_MAX,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300923 .step = 1,
Hans de Goede9035f2e2009-05-25 15:26:59 -0300924 .default_value = HUE_DEF,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300925 },
926 .set = sd_setwhite,
927 .get = sd_getwhite,
928 },
929 {
930 {
931 .id = V4L2_CID_EXPOSURE,
932 .type = V4L2_CTRL_TYPE_INTEGER,
933 .name = "Exposure",
934 .minimum = EXPOSURE_MIN,
935 .maximum = EXPOSURE_MAX,
936 .step = 1,
937 .default_value = EXPOSURE_DEF,
938 },
939 .set = sd_setexposure,
940 .get = sd_getexposure,
941 },
942 {
943 {
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300944 .id = V4L2_CID_GAIN,
945 .type = V4L2_CTRL_TYPE_INTEGER,
946 .name = "Gain",
947 .minimum = GAIN_MIN,
948 .maximum = GAIN_MAX,
949 .step = 1,
950 .default_value = GAIN_DEF,
951 },
952 .set = sd_setgain,
953 .get = sd_getgain,
954 },
955};
956
Marton Nemeth7e64dc42009-12-30 09:12:41 -0300957static const struct ctrl sd_ctrls_72a[] = {
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300958 {
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300959 {
Hans de Goede9035f2e2009-05-25 15:26:59 -0300960 .id = V4L2_CID_HUE,
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300961 .type = V4L2_CTRL_TYPE_INTEGER,
Hans de Goede9035f2e2009-05-25 15:26:59 -0300962 .name = "Hue",
963 .minimum = HUE_MIN,
964 .maximum = HUE_MAX,
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300965 .step = 1,
Hans de Goede9035f2e2009-05-25 15:26:59 -0300966 .default_value = HUE_DEF,
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300967 },
968 .set = sd_setwhite,
969 .get = sd_getwhite,
970 },
971 {
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300972 {
973 .id = V4L2_CID_BRIGHTNESS,
974 .type = V4L2_CTRL_TYPE_INTEGER,
975 .name = "Brightness",
976 .minimum = BRIGHTNESS_MIN,
977 .maximum = BRIGHTNESS_MAX,
978 .step = 1,
979 .default_value = BRIGHTNESS_DEF,
980 },
981 .set = sd_setbrightness,
982 .get = sd_getbrightness,
983 },
984 {
985 {
986 .id = V4L2_CID_CONTRAST,
987 .type = V4L2_CTRL_TYPE_INTEGER,
988 .name = "Contrast",
989 .minimum = CONTRAST_MIN,
990 .maximum = CONTRAST_MAX,
991 .step = 1,
992 .default_value = CONTRAST_DEF,
993 },
994 .set = sd_setcontrast,
995 .get = sd_getcontrast,
996 },
997 {
998 {
999 .id = V4L2_CID_AUTOGAIN,
1000 .type = V4L2_CTRL_TYPE_BOOLEAN,
1001 .name = "Auto Gain",
1002 .minimum = AUTOGAIN_MIN,
1003 .maximum = AUTOGAIN_MAX,
1004 .step = 1,
1005 .default_value = AUTOGAIN_DEF,
1006 },
1007 .set = sd_setautogain,
1008 .get = sd_getautogain,
1009 },
1010};
1011
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001012/* sub-driver description */
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001013static const struct sd_desc sd_desc_12a = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001014 .name = MODULE_NAME,
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001015 .ctrls = sd_ctrls_12a,
1016 .nctrls = ARRAY_SIZE(sd_ctrls_12a),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001017 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001018 .init = sd_init_12a,
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001019 .start = sd_start_12a,
1020 .stopN = sd_stopN,
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001021 .pkt_scan = sd_pkt_scan,
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001022};
1023static const struct sd_desc sd_desc_72a = {
1024 .name = MODULE_NAME,
1025 .ctrls = sd_ctrls_72a,
1026 .nctrls = ARRAY_SIZE(sd_ctrls_72a),
1027 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -03001028 .init = sd_init_72a,
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001029 .start = sd_start_72a,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001030 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001031 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -03001032 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001033};
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001034static const struct sd_desc *sd_desc[2] = {
1035 &sd_desc_12a,
1036 &sd_desc_72a
1037};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001038
1039/* -- module initialisation -- */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -03001040static const __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine87581aa2008-07-26 14:30:01 -03001041 {USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A},
1042 {USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A},
1043 {USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A},
John Ellsonf8f73d02010-03-17 10:22:58 -03001044 {USB_DEVICE(0x0461, 0x0815), .driver_info = Rev072A},
Jean-Francois Moine87581aa2008-07-26 14:30:01 -03001045 {USB_DEVICE(0x046d, 0x0928), .driver_info = Rev012A},
1046 {USB_DEVICE(0x046d, 0x0929), .driver_info = Rev012A},
1047 {USB_DEVICE(0x046d, 0x092a), .driver_info = Rev012A},
1048 {USB_DEVICE(0x046d, 0x092b), .driver_info = Rev012A},
1049 {USB_DEVICE(0x046d, 0x092c), .driver_info = Rev012A},
1050 {USB_DEVICE(0x046d, 0x092d), .driver_info = Rev012A},
1051 {USB_DEVICE(0x046d, 0x092e), .driver_info = Rev012A},
1052 {USB_DEVICE(0x046d, 0x092f), .driver_info = Rev012A},
1053 {USB_DEVICE(0x04fc, 0x0561), .driver_info = Rev072A},
1054 {USB_DEVICE(0x060b, 0xa001), .driver_info = Rev072A},
1055 {USB_DEVICE(0x10fd, 0x7e50), .driver_info = Rev072A},
1056 {USB_DEVICE(0xabcd, 0xcdee), .driver_info = Rev072A},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001057 {}
1058};
1059
1060MODULE_DEVICE_TABLE(usb, device_table);
1061
1062/* -- device connect -- */
1063static int sd_probe(struct usb_interface *intf,
1064 const struct usb_device_id *id)
1065{
Jean-Francois Moine7879d452008-09-03 16:47:32 -03001066 return gspca_dev_probe(intf, id,
1067 sd_desc[id->driver_info],
1068 sizeof(struct sd),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001069 THIS_MODULE);
1070}
1071
1072static struct usb_driver sd_driver = {
1073 .name = MODULE_NAME,
1074 .id_table = device_table,
1075 .probe = sd_probe,
1076 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -03001077#ifdef CONFIG_PM
1078 .suspend = gspca_suspend,
1079 .resume = gspca_resume,
1080#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001081};
1082
1083/* -- module insert / remove -- */
1084static int __init sd_mod_init(void)
1085{
Alexey Klimovf69e9522009-01-01 13:02:07 -03001086 int ret;
1087 ret = usb_register(&sd_driver);
1088 if (ret < 0)
Alexey Klimove6b14842009-01-01 13:04:58 -03001089 return ret;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -03001090 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001091 return 0;
1092}
1093static void __exit sd_mod_exit(void)
1094{
1095 usb_deregister(&sd_driver);
1096 PDEBUG(D_PROBE, "deregistered");
1097}
1098
1099module_init(sd_mod_init);
1100module_exit(sd_mod_exit);