blob: 403d71cd65d93f32e82982cfdff5f89208c3de1c [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
Joe Perches133a9fe2011-08-21 19:56:57 -030023#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030025#define MODULE_NAME "spca561"
26
Hans de Goede436c2c52010-02-28 09:41:04 -030027#include <linux/input.h>
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030028#include "gspca.h"
29
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030030MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
31MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver");
32MODULE_LICENSE("GPL");
33
Hans Verkuil3fa24bf2012-05-16 08:20:44 -030034#define EXPOSURE_MAX (2047 + 325)
35
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030036/* specific webcam descriptor */
37struct sd {
38 struct gspca_dev gspca_dev; /* !! must be the first item */
39
Hans Verkuil3fa24bf2012-05-16 08:20:44 -030040 struct { /* hue/contrast control cluster */
41 struct v4l2_ctrl *contrast;
42 struct v4l2_ctrl *hue;
43 };
44 struct v4l2_ctrl *autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030045
Jean-Francois Moined698dc62008-09-03 16:47:51 -030046#define EXPO12A_DEF 3
47 __u8 expo12a; /* expo/gain? for rev 12a */
48
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030049 __u8 chip_revision;
Jean-Francois Moine7879d452008-09-03 16:47:32 -030050#define Rev012A 0
51#define Rev072A 1
52
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030053 signed char ag_cnt;
54#define AG_CNT_START 13
55};
56
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030057static const struct v4l2_pix_format sif_012a_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030058 {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
59 .bytesperline = 160,
60 .sizeimage = 160 * 120,
61 .colorspace = V4L2_COLORSPACE_SRGB,
62 .priv = 3},
63 {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
64 .bytesperline = 176,
65 .sizeimage = 176 * 144,
66 .colorspace = V4L2_COLORSPACE_SRGB,
67 .priv = 2},
68 {320, 240, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
69 .bytesperline = 320,
70 .sizeimage = 320 * 240 * 4 / 8,
71 .colorspace = V4L2_COLORSPACE_SRGB,
72 .priv = 1},
73 {352, 288, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
74 .bytesperline = 352,
75 .sizeimage = 352 * 288 * 4 / 8,
76 .colorspace = V4L2_COLORSPACE_SRGB,
77 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030078};
79
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030080static const struct v4l2_pix_format sif_072a_mode[] = {
Jean-Francois Moineb77c0042008-09-04 16:22:56 -030081 {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
82 .bytesperline = 160,
83 .sizeimage = 160 * 120,
84 .colorspace = V4L2_COLORSPACE_SRGB,
85 .priv = 3},
86 {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
87 .bytesperline = 176,
88 .sizeimage = 176 * 144,
89 .colorspace = V4L2_COLORSPACE_SRGB,
90 .priv = 2},
91 {320, 240, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
92 .bytesperline = 320,
93 .sizeimage = 320 * 240,
94 .colorspace = V4L2_COLORSPACE_SRGB,
95 .priv = 1},
96 {352, 288, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
97 .bytesperline = 352,
98 .sizeimage = 352 * 288,
99 .colorspace = V4L2_COLORSPACE_SRGB,
100 .priv = 0},
101};
102
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300103/*
104 * Initialization data
105 * I'm not very sure how to split initialization from open data
106 * chunks. For now, we'll consider everything as initialization
107 */
108/* Frame packet header offsets for the spca561 */
109#define SPCA561_OFFSET_SNAP 1
110#define SPCA561_OFFSET_TYPE 2
111#define SPCA561_OFFSET_COMPRESS 3
112#define SPCA561_OFFSET_FRAMSEQ 4
113#define SPCA561_OFFSET_GPIO 5
114#define SPCA561_OFFSET_USBBUFF 6
115#define SPCA561_OFFSET_WIN2GRAVE 7
116#define SPCA561_OFFSET_WIN2RAVE 8
117#define SPCA561_OFFSET_WIN2BAVE 9
118#define SPCA561_OFFSET_WIN2GBAVE 10
119#define SPCA561_OFFSET_WIN1GRAVE 11
120#define SPCA561_OFFSET_WIN1RAVE 12
121#define SPCA561_OFFSET_WIN1BAVE 13
122#define SPCA561_OFFSET_WIN1GBAVE 14
123#define SPCA561_OFFSET_FREQ 15
124#define SPCA561_OFFSET_VSYNC 16
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300125#define SPCA561_INDEX_I2C_BASE 0x8800
126#define SPCA561_SNAPBIT 0x20
127#define SPCA561_SNAPCTRL 0x40
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300128
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300129static const u16 rev72a_reset[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300130 {0x0000, 0x8114}, /* Software GPIO output data */
131 {0x0001, 0x8114}, /* Software GPIO output data */
132 {0x0000, 0x8112}, /* Some kind of reset */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300133 {}
134};
135static const __u16 rev72a_init_data1[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300136 {0x0003, 0x8701}, /* PCLK clock delay adjustment */
137 {0x0001, 0x8703}, /* HSYNC from cmos inverted */
138 {0x0011, 0x8118}, /* Enable and conf sensor */
139 {0x0001, 0x8118}, /* Conf sensor */
140 {0x0092, 0x8804}, /* I know nothing about these */
141 {0x0010, 0x8802}, /* 0x88xx registers, so I won't */
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300142 {}
143};
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300144static const u16 rev72a_init_sensor1[][2] = {
145 {0x0001, 0x000d},
146 {0x0002, 0x0018},
147 {0x0004, 0x0165},
148 {0x0005, 0x0021},
149 {0x0007, 0x00aa},
150 {0x0020, 0x1504},
151 {0x0039, 0x0002},
152 {0x0035, 0x0010},
153 {0x0009, 0x1049},
154 {0x0028, 0x000b},
155 {0x003b, 0x000f},
156 {0x003c, 0x0000},
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300157 {}
158};
159static const __u16 rev72a_init_data2[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300160 {0x0018, 0x8601}, /* Pixel/line selection for color separation */
161 {0x0000, 0x8602}, /* Optical black level for user setting */
162 {0x0060, 0x8604}, /* Optical black horizontal offset */
163 {0x0002, 0x8605}, /* Optical black vertical offset */
164 {0x0000, 0x8603}, /* Non-automatic optical black level */
165 {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
166 {0x0000, 0x865f}, /* Vertical valid pixels window (x2) */
167 {0x00b0, 0x865d}, /* Horizontal valid pixels window (x2) */
168 {0x0090, 0x865e}, /* Vertical valid lines window (x2) */
169 {0x00e0, 0x8406}, /* Memory buffer threshold */
170 {0x0000, 0x8660}, /* Compensation memory stuff */
171 {0x0002, 0x8201}, /* Output address for r/w serial EEPROM */
172 {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */
173 {0x0001, 0x8200}, /* OprMode to be executed by hardware */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300174/* from ms-win */
175 {0x0000, 0x8611}, /* R offset for white balance */
176 {0x00fd, 0x8612}, /* Gr offset for white balance */
177 {0x0003, 0x8613}, /* B offset for white balance */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300178 {0x0000, 0x8614}, /* Gb offset for white balance */
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300179/* from ms-win */
180 {0x0035, 0x8651}, /* R gain for white balance */
181 {0x0040, 0x8652}, /* Gr gain for white balance */
182 {0x005f, 0x8653}, /* B gain for white balance */
183 {0x0040, 0x8654}, /* Gb gain for white balance */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300184 {0x0002, 0x8502}, /* Maximum average bit rate stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300185 {0x0011, 0x8802},
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300186
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300187 {0x0087, 0x8700}, /* Set master clock (96Mhz????) */
188 {0x0081, 0x8702}, /* Master clock output enable */
189
190 {0x0000, 0x8500}, /* Set image type (352x288 no compression) */
191 /* Originally was 0x0010 (352x288 compression) */
192
193 {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
194 {0x0003, 0x865c}, /* Vertical offset for valid lines */
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300195 {}
196};
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300197static const u16 rev72a_init_sensor2[][2] = {
198 {0x0003, 0x0121},
199 {0x0004, 0x0165},
200 {0x0005, 0x002f}, /* blanking control column */
201 {0x0006, 0x0000}, /* blanking mode row*/
202 {0x000a, 0x0002},
203 {0x0009, 0x1061}, /* setexposure times && pixel clock
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300204 * 0001 0 | 000 0110 0001 */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300205 {0x0035, 0x0014},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300206 {}
207};
208
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300209/******************** QC Express etch2 stuff ********************/
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300210static const __u16 Pb100_1map8300[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300211 /* reg, value */
212 {0x8320, 0x3304},
213
214 {0x8303, 0x0125}, /* image area */
215 {0x8304, 0x0169},
216 {0x8328, 0x000b},
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300217 {0x833c, 0x0001}, /*fixme: win:07*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300218
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300219 {0x832f, 0x1904}, /*fixme: was 0419*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300220 {0x8307, 0x00aa},
221 {0x8301, 0x0003},
222 {0x8302, 0x000e},
223 {}
224};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300225static const __u16 Pb100_2map8300[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300226 /* reg, value */
227 {0x8339, 0x0000},
228 {0x8307, 0x00aa},
229 {}
230};
231
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300232static const __u16 spca561_161rev12A_data1[][2] = {
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300233 {0x29, 0x8118}, /* Control register (various enable bits) */
234 {0x08, 0x8114}, /* GPIO: Led off */
235 {0x0e, 0x8112}, /* 0x0e stream off 0x3e stream on */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300236 {0x00, 0x8102}, /* white balance - new */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300237 {0x92, 0x8804},
238 {0x04, 0x8802}, /* windows uses 08 */
239 {}
240};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300241static const __u16 spca561_161rev12A_data2[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300242 {0x21, 0x8118},
243 {0x10, 0x8500},
244 {0x07, 0x8601},
245 {0x07, 0x8602},
246 {0x04, 0x8501},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300247
248 {0x07, 0x8201}, /* windows uses 02 */
249 {0x08, 0x8200},
250 {0x01, 0x8200},
251
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300252 {0x90, 0x8604},
253 {0x00, 0x8605},
254 {0xb0, 0x8603},
255
256 /* sensor gains */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300257 {0x07, 0x8601}, /* white balance - new */
258 {0x07, 0x8602}, /* white balance - new */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300259 {0x00, 0x8610}, /* *red */
260 {0x00, 0x8611}, /* 3f *green */
261 {0x00, 0x8612}, /* green *blue */
262 {0x00, 0x8613}, /* blue *green */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300263 {0x43, 0x8614}, /* green *red - white balance - was 0x35 */
264 {0x40, 0x8615}, /* 40 *green - white balance - was 0x35 */
265 {0x71, 0x8616}, /* 7a *blue - white balance - was 0x35 */
266 {0x40, 0x8617}, /* 40 *green - white balance - was 0x35 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300267
268 {0x0c, 0x8620}, /* 0c */
269 {0xc8, 0x8631}, /* c8 */
270 {0xc8, 0x8634}, /* c8 */
271 {0x23, 0x8635}, /* 23 */
272 {0x1f, 0x8636}, /* 1f */
273 {0xdd, 0x8637}, /* dd */
274 {0xe1, 0x8638}, /* e1 */
275 {0x1d, 0x8639}, /* 1d */
276 {0x21, 0x863a}, /* 21 */
277 {0xe3, 0x863b}, /* e3 */
278 {0xdf, 0x863c}, /* df */
279 {0xf0, 0x8505},
280 {0x32, 0x850a},
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300281/* {0x99, 0x8700}, * - white balance - new (removed) */
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300282 /* HDG we used to do this in stop0, making the init state and the state
283 after a start / stop different, so do this here instead. */
284 {0x29, 0x8118},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300285 {}
286};
287
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300288static void reg_w_val(struct gspca_dev *gspca_dev, __u16 index, __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300289{
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300290 int ret;
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300291 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300292
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300293 ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
294 0, /* request */
295 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
296 value, index, NULL, 0, 500);
297 PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
298 if (ret < 0)
Joe Perches133a9fe2011-08-21 19:56:57 -0300299 pr_err("reg write: error %d\n", ret);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300300}
301
302static void write_vector(struct gspca_dev *gspca_dev,
303 const __u16 data[][2])
304{
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300305 int i;
306
307 i = 0;
308 while (data[i][1] != 0) {
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300309 reg_w_val(gspca_dev, data[i][1], data[i][0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300310 i++;
311 }
312}
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300313
314/* read 'len' bytes to gspca_dev->usb_buf */
315static void reg_r(struct gspca_dev *gspca_dev,
316 __u16 index, __u16 length)
317{
318 usb_control_msg(gspca_dev->dev,
319 usb_rcvctrlpipe(gspca_dev->dev, 0),
320 0, /* request */
321 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
322 0, /* value */
323 index, gspca_dev->usb_buf, length, 500);
324}
325
326/* write 'len' bytes from gspca_dev->usb_buf */
327static void reg_w_buf(struct gspca_dev *gspca_dev,
328 __u16 index, __u16 len)
329{
330 usb_control_msg(gspca_dev->dev,
331 usb_sndctrlpipe(gspca_dev->dev, 0),
332 0, /* request */
333 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
334 0, /* value */
335 index, gspca_dev->usb_buf, len, 500);
336}
337
338static void i2c_write(struct gspca_dev *gspca_dev, __u16 value, __u16 reg)
339{
340 int retry = 60;
341
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300342 reg_w_val(gspca_dev, 0x8801, reg);
343 reg_w_val(gspca_dev, 0x8805, value);
344 reg_w_val(gspca_dev, 0x8800, value >> 8);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300345 do {
346 reg_r(gspca_dev, 0x8803, 1);
347 if (!gspca_dev->usb_buf[0])
348 return;
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300349 msleep(10);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300350 } while (--retry);
351}
352
353static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
354{
355 int retry = 60;
356 __u8 value;
357
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300358 reg_w_val(gspca_dev, 0x8804, 0x92);
359 reg_w_val(gspca_dev, 0x8801, reg);
360 reg_w_val(gspca_dev, 0x8802, mode | 0x01);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300361 do {
362 reg_r(gspca_dev, 0x8803, 1);
363 if (!gspca_dev->usb_buf[0]) {
364 reg_r(gspca_dev, 0x8800, 1);
365 value = gspca_dev->usb_buf[0];
366 reg_r(gspca_dev, 0x8805, 1);
367 return ((int) value << 8) | gspca_dev->usb_buf[0];
368 }
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300369 msleep(10);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300370 } while (--retry);
371 return -1;
372}
373
374static void sensor_mapwrite(struct gspca_dev *gspca_dev,
375 const __u16 (*sensormap)[2])
376{
377 while ((*sensormap)[0]) {
378 gspca_dev->usb_buf[0] = (*sensormap)[1];
379 gspca_dev->usb_buf[1] = (*sensormap)[1] >> 8;
380 reg_w_buf(gspca_dev, (*sensormap)[0], 2);
381 sensormap++;
382 }
383}
384
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300385static void write_sensor_72a(struct gspca_dev *gspca_dev,
386 const __u16 (*sensor)[2])
387{
388 while ((*sensor)[0]) {
389 i2c_write(gspca_dev, (*sensor)[1], (*sensor)[0]);
390 sensor++;
391 }
392}
393
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300394static void init_161rev12A(struct gspca_dev *gspca_dev)
395{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300396 write_vector(gspca_dev, spca561_161rev12A_data1);
397 sensor_mapwrite(gspca_dev, Pb100_1map8300);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300398/*fixme: should be in sd_start*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300399 write_vector(gspca_dev, spca561_161rev12A_data2);
400 sensor_mapwrite(gspca_dev, Pb100_2map8300);
401}
402
403/* this function is called at probe time */
404static int sd_config(struct gspca_dev *gspca_dev,
405 const struct usb_device_id *id)
406{
407 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300408 struct cam *cam;
409 __u16 vendor, product;
410 __u8 data1, data2;
411
412 /* Read frm global register the USB product and vendor IDs, just to
413 * prove that we can communicate with the device. This works, which
414 * confirms at we are communicating properly and that the device
415 * is a 561. */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300416 reg_r(gspca_dev, 0x8104, 1);
417 data1 = gspca_dev->usb_buf[0];
418 reg_r(gspca_dev, 0x8105, 1);
419 data2 = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300420 vendor = (data2 << 8) | data1;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300421 reg_r(gspca_dev, 0x8106, 1);
422 data1 = gspca_dev->usb_buf[0];
423 reg_r(gspca_dev, 0x8107, 1);
424 data2 = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300425 product = (data2 << 8) | data1;
426 if (vendor != id->idVendor || product != id->idProduct) {
427 PDEBUG(D_PROBE, "Bad vendor / product from device");
428 return -EINVAL;
429 }
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300430
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300431 cam = &gspca_dev->cam;
Hans de Goedeeb3fb7c2012-01-01 16:35:01 -0300432 cam->needs_full_bandwidth = 1;
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300433
434 sd->chip_revision = id->driver_info;
Jean-Francois Moineb77c0042008-09-04 16:22:56 -0300435 if (sd->chip_revision == Rev012A) {
436 cam->cam_mode = sif_012a_mode;
437 cam->nmodes = ARRAY_SIZE(sif_012a_mode);
438 } else {
439 cam->cam_mode = sif_072a_mode;
440 cam->nmodes = ARRAY_SIZE(sif_072a_mode);
441 }
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300442 sd->expo12a = EXPO12A_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300443 return 0;
444}
445
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300446/* this function is called at probe and resume time */
447static int sd_init_12a(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300448{
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300449 PDEBUG(D_STREAM, "Chip revision: 012a");
450 init_161rev12A(gspca_dev);
451 return 0;
452}
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300453static int sd_init_72a(struct gspca_dev *gspca_dev)
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300454{
455 PDEBUG(D_STREAM, "Chip revision: 072a");
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300456 write_vector(gspca_dev, rev72a_reset);
457 msleep(200);
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300458 write_vector(gspca_dev, rev72a_init_data1);
459 write_sensor_72a(gspca_dev, rev72a_init_sensor1);
460 write_vector(gspca_dev, rev72a_init_data2);
461 write_sensor_72a(gspca_dev, rev72a_init_sensor2);
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300462 reg_w_val(gspca_dev, 0x8112, 0x30);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300463 return 0;
464}
465
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300466static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
467{
Hans de Goedea8931d52012-07-02 15:29:56 -0300468 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea8931d52012-07-02 15:29:56 -0300469 __u16 reg;
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300470
Hans de Goedea8931d52012-07-02 15:29:56 -0300471 if (sd->chip_revision == Rev012A)
472 reg = 0x8610;
473 else
474 reg = 0x8611;
475
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300476 reg_w_val(gspca_dev, reg + 0, val); /* R */
477 reg_w_val(gspca_dev, reg + 1, val); /* Gr */
478 reg_w_val(gspca_dev, reg + 2, val); /* B */
479 reg_w_val(gspca_dev, reg + 3, val); /* Gb */
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300480}
481
482static void setwhite(struct gspca_dev *gspca_dev, s32 white, s32 contrast)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300483{
484 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300485 __u8 blue, red;
486 __u16 reg;
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300487
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300488 /* try to emulate MS-win as possible */
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300489 red = 0x20 + white * 3 / 8;
490 blue = 0x90 - white * 5 / 8;
491 if (sd->chip_revision == Rev012A) {
492 reg = 0x8614;
493 } else {
494 reg = 0x8651;
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300495 red += contrast - 0x20;
496 blue += contrast - 0x20;
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300497 reg_w_val(gspca_dev, 0x8652, contrast + 0x20); /* Gr */
498 reg_w_val(gspca_dev, 0x8654, contrast + 0x20); /* Gb */
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300499 }
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300500 reg_w_val(gspca_dev, reg, red);
501 reg_w_val(gspca_dev, reg + 2, blue);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300502}
503
504/* rev 12a only */
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300505static void setexposure(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300506{
Hans de Goeded0848eb2009-05-25 15:20:16 -0300507 int i, expo = 0;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300508
Hans de Goede0fc23d22008-09-04 16:22:57 -0300509 /* Register 0x8309 controls exposure for the spca561,
510 the basic exposure setting goes from 1-2047, where 1 is completely
511 dark and 2047 is very bright. It not only influences exposure but
512 also the framerate (to allow for longer exposure) from 1 - 300 it
513 only raises the exposure time then from 300 - 600 it halves the
514 framerate to be able to further raise the exposure time and for every
515 300 more it halves the framerate again. This allows for a maximum
516 exposure time of circa 0.2 - 0.25 seconds (30 / (2000/3000) fps).
517 Sometimes this is not enough, the 1-2047 uses bits 0-10, bits 11-12
518 configure a divider for the base framerate which us used at the
519 exposure setting of 1-300. These bits configure the base framerate
520 according to the following formula: fps = 60 / (value + 2) */
Hans de Goeded0848eb2009-05-25 15:20:16 -0300521
522 /* We choose to use the high bits setting the fixed framerate divisor
523 asap, as setting high basic exposure setting without the fixed
524 divider in combination with high gains makes the cam stop */
525 int table[] = { 0, 450, 550, 625, EXPOSURE_MAX };
526
527 for (i = 0; i < ARRAY_SIZE(table) - 1; i++) {
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300528 if (val <= table[i + 1]) {
529 expo = val - table[i];
Hans de Goeded0848eb2009-05-25 15:20:16 -0300530 if (i)
531 expo += 300;
532 expo |= i << 11;
533 break;
534 }
Hans de Goede0fc23d22008-09-04 16:22:57 -0300535 }
Hans de Goeded0848eb2009-05-25 15:20:16 -0300536
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300537 gspca_dev->usb_buf[0] = expo;
538 gspca_dev->usb_buf[1] = expo >> 8;
539 reg_w_buf(gspca_dev, 0x8309, 2);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300540}
541
542/* rev 12a only */
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300543static void setgain(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300544{
Hans de Goeded0848eb2009-05-25 15:20:16 -0300545 /* gain reg low 6 bits 0-63 gain, bit 6 and 7, both double the
546 sensitivity when set, so 31 + one of them set == 63, and 15
547 with both of them set == 63 */
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300548 if (val < 64)
549 gspca_dev->usb_buf[0] = val;
550 else if (val < 128)
551 gspca_dev->usb_buf[0] = (val / 2) | 0x40;
Hans de Goeded0848eb2009-05-25 15:20:16 -0300552 else
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300553 gspca_dev->usb_buf[0] = (val / 4) | 0xc0;
Hans de Goeded0848eb2009-05-25 15:20:16 -0300554
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300555 gspca_dev->usb_buf[1] = 0;
556 reg_w_buf(gspca_dev, 0x8335, 2);
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300557}
558
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300559static void setautogain(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300560{
561 struct sd *sd = (struct sd *) gspca_dev;
562
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300563 if (val)
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300564 sd->ag_cnt = AG_CNT_START;
565 else
566 sd->ag_cnt = -1;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300567}
568
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300569static int sd_start_12a(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300570{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300571 int mode;
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300572 static const __u8 Reg8391[8] =
573 {0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300574
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300575 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300576 if (mode <= 1) {
577 /* Use compression on 320x240 and above */
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300578 reg_w_val(gspca_dev, 0x8500, 0x10 | mode);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300579 } else {
580 /* I couldn't get the compression to work below 320x240
581 * Fortunately at these resolutions the bandwidth
582 * is sufficient to push raw frames at ~20fps */
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300583 reg_w_val(gspca_dev, 0x8500, mode);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300584 } /* -- qq@kuku.eu.org */
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300585
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300586 gspca_dev->usb_buf[0] = 0xaa;
587 gspca_dev->usb_buf[1] = 0x00;
588 reg_w_buf(gspca_dev, 0x8307, 2);
589 /* clock - lower 0x8X values lead to fps > 30 */
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300590 reg_w_val(gspca_dev, 0x8700, 0x8a);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300591 /* 0x8f 0x85 0x27 clock */
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300592 reg_w_val(gspca_dev, 0x8112, 0x1e | 0x20);
593 reg_w_val(gspca_dev, 0x850b, 0x03);
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300594 memcpy(gspca_dev->usb_buf, Reg8391, 8);
595 reg_w_buf(gspca_dev, 0x8391, 8);
596 reg_w_buf(gspca_dev, 0x8390, 8);
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300597
598 /* Led ON (bit 3 -> 0 */
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300599 reg_w_val(gspca_dev, 0x8114, 0x00);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300600 return 0;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300601}
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300602static int sd_start_72a(struct gspca_dev *gspca_dev)
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300603{
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300604 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300605 int Clck;
606 int mode;
607
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300608 write_vector(gspca_dev, rev72a_reset);
609 msleep(200);
610 write_vector(gspca_dev, rev72a_init_data1);
611 write_sensor_72a(gspca_dev, rev72a_init_sensor1);
612
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300613 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
614 switch (mode) {
615 default:
Jean-Francois Moinea48196a2009-01-18 14:24:52 -0300616 case 0:
617 Clck = 0x27; /* ms-win 0x87 */
618 break;
619 case 1:
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300620 Clck = 0x25;
621 break;
622 case 2:
623 Clck = 0x22;
624 break;
625 case 3:
626 Clck = 0x21;
627 break;
628 }
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300629 reg_w_val(gspca_dev, 0x8700, Clck); /* 0x27 clock */
630 reg_w_val(gspca_dev, 0x8702, 0x81);
631 reg_w_val(gspca_dev, 0x8500, mode); /* mode */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300632 write_sensor_72a(gspca_dev, rev72a_init_sensor2);
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300633 setwhite(gspca_dev, v4l2_ctrl_g_ctrl(sd->hue),
634 v4l2_ctrl_g_ctrl(sd->contrast));
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300635/* setbrightness(gspca_dev); * fixme: bad values */
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300636 setautogain(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain));
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300637 reg_w_val(gspca_dev, 0x8112, 0x10 | 0x20);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300638 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300639}
640
641static void sd_stopN(struct gspca_dev *gspca_dev)
642{
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300643 struct sd *sd = (struct sd *) gspca_dev;
644
645 if (sd->chip_revision == Rev012A) {
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300646 reg_w_val(gspca_dev, 0x8112, 0x0e);
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300647 /* Led Off (bit 3 -> 1 */
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300648 reg_w_val(gspca_dev, 0x8114, 0x08);
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300649 } else {
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300650 reg_w_val(gspca_dev, 0x8112, 0x20);
651/* reg_w_val(gspca_dev, 0x8102, 0x00); ?? */
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300652 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300653}
654
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300655static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300656{
657 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300658 int expotimes;
659 int pixelclk;
660 int gainG;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300661 __u8 R, Gr, Gb, B;
662 int y;
663 __u8 luma_mean = 110;
664 __u8 luma_delta = 20;
665 __u8 spring = 4;
666
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300667 if (sd->ag_cnt < 0)
668 return;
669 if (--sd->ag_cnt >= 0)
670 return;
671 sd->ag_cnt = AG_CNT_START;
672
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300673 switch (sd->chip_revision) {
674 case Rev072A:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300675 reg_r(gspca_dev, 0x8621, 1);
676 Gr = gspca_dev->usb_buf[0];
677 reg_r(gspca_dev, 0x8622, 1);
678 R = gspca_dev->usb_buf[0];
679 reg_r(gspca_dev, 0x8623, 1);
680 B = gspca_dev->usb_buf[0];
681 reg_r(gspca_dev, 0x8624, 1);
682 Gb = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300683 y = (77 * R + 75 * (Gr + Gb) + 29 * B) >> 8;
684 /* u= (128*B-(43*(Gr+Gb+R))) >> 8; */
685 /* v= (128*R-(53*(Gr+Gb))-21*B) >> 8; */
686 /* PDEBUG(D_CONF,"reading Y %d U %d V %d ",y,u,v); */
687
688 if (y < luma_mean - luma_delta ||
689 y > luma_mean + luma_delta) {
690 expotimes = i2c_read(gspca_dev, 0x09, 0x10);
691 pixelclk = 0x0800;
692 expotimes = expotimes & 0x07ff;
693 /* PDEBUG(D_PACK,
694 "Exposition Times 0x%03X Clock 0x%04X ",
695 expotimes,pixelclk); */
696 gainG = i2c_read(gspca_dev, 0x35, 0x10);
697 /* PDEBUG(D_PACK,
698 "reading Gain register %d", gainG); */
699
700 expotimes += (luma_mean - y) >> spring;
701 gainG += (luma_mean - y) / 50;
702 /* PDEBUG(D_PACK,
703 "compute expotimes %d gain %d",
704 expotimes,gainG); */
705
706 if (gainG > 0x3f)
707 gainG = 0x3f;
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300708 else if (gainG < 3)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300709 gainG = 3;
710 i2c_write(gspca_dev, gainG, 0x35);
711
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300712 if (expotimes > 0x0256)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300713 expotimes = 0x0256;
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300714 else if (expotimes < 3)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300715 expotimes = 3;
716 i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
717 }
718 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300719 }
720}
721
722static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300723 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300724 int len) /* iso packet length */
725{
Hans de Goede0fc23d22008-09-04 16:22:57 -0300726 struct sd *sd = (struct sd *) gspca_dev;
727
Jean-Francois Moine576ed7b2009-01-16 08:57:28 -0300728 len--;
729 switch (*data++) { /* sequence number */
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300730 case 0: /* start of frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300731 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Hans de Goede436c2c52010-02-28 09:41:04 -0300732
733 /* This should never happen */
734 if (len < 2) {
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300735 PERR("Short SOF packet, ignoring");
Hans de Goede436c2c52010-02-28 09:41:04 -0300736 gspca_dev->last_packet_type = DISCARD_PACKET;
737 return;
738 }
739
Peter Senna Tschudin60d21562013-01-24 19:29:09 -0300740#if IS_ENABLED(CONFIG_INPUT)
Hans de Goede436c2c52010-02-28 09:41:04 -0300741 if (data[0] & 0x20) {
742 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
743 input_sync(gspca_dev->input_dev);
744 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
745 input_sync(gspca_dev->input_dev);
746 }
747#endif
748
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300749 if (data[1] & 0x10) {
750 /* compressed bayer */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300751 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300752 } else {
Hans de Goede54ab92c2008-07-03 11:20:58 -0300753 /* raw bayer (with a header, which we skip) */
Hans de Goede0fc23d22008-09-04 16:22:57 -0300754 if (sd->chip_revision == Rev012A) {
755 data += 20;
756 len -= 20;
757 } else {
758 data += 16;
759 len -= 16;
760 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300761 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300762 }
763 return;
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300764 case 0xff: /* drop (empty mpackets) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300765 return;
766 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300767 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300768}
769
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300770static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300771{
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300772 struct gspca_dev *gspca_dev =
773 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
774 struct sd *sd = (struct sd *)gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300775
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300776 gspca_dev->usb_err = 0;
777
778 if (!gspca_dev->streaming)
779 return 0;
780
781 switch (ctrl->id) {
782 case V4L2_CID_BRIGHTNESS:
783 setbrightness(gspca_dev, ctrl->val);
784 break;
785 case V4L2_CID_CONTRAST:
786 /* hue/contrast control cluster for 72a */
787 setwhite(gspca_dev, sd->hue->val, ctrl->val);
788 break;
789 case V4L2_CID_HUE:
790 /* just plain hue control for 12a */
791 setwhite(gspca_dev, ctrl->val, 0);
792 break;
793 case V4L2_CID_EXPOSURE:
794 setexposure(gspca_dev, ctrl->val);
795 break;
796 case V4L2_CID_GAIN:
797 setgain(gspca_dev, ctrl->val);
798 break;
799 case V4L2_CID_AUTOGAIN:
800 setautogain(gspca_dev, ctrl->val);
801 break;
802 }
803 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300804}
805
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300806static const struct v4l2_ctrl_ops sd_ctrl_ops = {
807 .s_ctrl = sd_s_ctrl,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300808};
809
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300810static int sd_init_controls_12a(struct gspca_dev *gspca_dev)
811{
812 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
813
814 gspca_dev->vdev.ctrl_handler = hdl;
815 v4l2_ctrl_handler_init(hdl, 3);
816 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
817 V4L2_CID_HUE, 1, 0x7f, 1, 0x40);
818 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
Hans de Goedea8931d52012-07-02 15:29:56 -0300819 V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
820 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300821 V4L2_CID_EXPOSURE, 1, EXPOSURE_MAX, 1, 700);
822 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
823 V4L2_CID_GAIN, 0, 255, 1, 63);
824
825 if (hdl->error) {
826 pr_err("Could not initialize controls\n");
827 return hdl->error;
828 }
829 return 0;
830}
831
832static int sd_init_controls_72a(struct gspca_dev *gspca_dev)
833{
834 struct sd *sd = (struct sd *)gspca_dev;
835 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
836
837 gspca_dev->vdev.ctrl_handler = hdl;
838 v4l2_ctrl_handler_init(hdl, 4);
839 sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
840 V4L2_CID_CONTRAST, 0, 0x3f, 1, 0x20);
841 sd->hue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
842 V4L2_CID_HUE, 1, 0x7f, 1, 0x40);
843 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
844 V4L2_CID_BRIGHTNESS, 0, 0x3f, 1, 0x20);
845 sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
846 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
847
848 if (hdl->error) {
849 pr_err("Could not initialize controls\n");
850 return hdl->error;
851 }
852 v4l2_ctrl_cluster(2, &sd->contrast);
853 return 0;
854}
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300855
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300856/* sub-driver description */
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300857static const struct sd_desc sd_desc_12a = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300858 .name = MODULE_NAME,
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300859 .init_controls = sd_init_controls_12a,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300860 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300861 .init = sd_init_12a,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300862 .start = sd_start_12a,
863 .stopN = sd_stopN,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300864 .pkt_scan = sd_pkt_scan,
Peter Senna Tschudin60d21562013-01-24 19:29:09 -0300865#if IS_ENABLED(CONFIG_INPUT)
Hans de Goede436c2c52010-02-28 09:41:04 -0300866 .other_input = 1,
867#endif
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300868};
869static const struct sd_desc sd_desc_72a = {
870 .name = MODULE_NAME,
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300871 .init_controls = sd_init_controls_72a,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300872 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300873 .init = sd_init_72a,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300874 .start = sd_start_72a,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300875 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300876 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300877 .dq_callback = do_autogain,
Peter Senna Tschudin60d21562013-01-24 19:29:09 -0300878#if IS_ENABLED(CONFIG_INPUT)
Hans de Goede436c2c52010-02-28 09:41:04 -0300879 .other_input = 1,
880#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300881};
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300882static const struct sd_desc *sd_desc[2] = {
883 &sd_desc_12a,
884 &sd_desc_72a
885};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300886
887/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300888static const struct usb_device_id device_table[] = {
Jean-Francois Moine87581aa2008-07-26 14:30:01 -0300889 {USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A},
890 {USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A},
891 {USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A},
John Ellsonf8f73d02010-03-17 10:22:58 -0300892 {USB_DEVICE(0x0461, 0x0815), .driver_info = Rev072A},
Jean-Francois Moine87581aa2008-07-26 14:30:01 -0300893 {USB_DEVICE(0x046d, 0x0928), .driver_info = Rev012A},
894 {USB_DEVICE(0x046d, 0x0929), .driver_info = Rev012A},
895 {USB_DEVICE(0x046d, 0x092a), .driver_info = Rev012A},
896 {USB_DEVICE(0x046d, 0x092b), .driver_info = Rev012A},
897 {USB_DEVICE(0x046d, 0x092c), .driver_info = Rev012A},
898 {USB_DEVICE(0x046d, 0x092d), .driver_info = Rev012A},
899 {USB_DEVICE(0x046d, 0x092e), .driver_info = Rev012A},
900 {USB_DEVICE(0x046d, 0x092f), .driver_info = Rev012A},
901 {USB_DEVICE(0x04fc, 0x0561), .driver_info = Rev072A},
902 {USB_DEVICE(0x060b, 0xa001), .driver_info = Rev072A},
903 {USB_DEVICE(0x10fd, 0x7e50), .driver_info = Rev072A},
904 {USB_DEVICE(0xabcd, 0xcdee), .driver_info = Rev072A},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300905 {}
906};
907
908MODULE_DEVICE_TABLE(usb, device_table);
909
910/* -- device connect -- */
911static int sd_probe(struct usb_interface *intf,
912 const struct usb_device_id *id)
913{
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300914 return gspca_dev_probe(intf, id,
915 sd_desc[id->driver_info],
916 sizeof(struct sd),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300917 THIS_MODULE);
918}
919
920static struct usb_driver sd_driver = {
921 .name = MODULE_NAME,
922 .id_table = device_table,
923 .probe = sd_probe,
924 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300925#ifdef CONFIG_PM
926 .suspend = gspca_suspend,
927 .resume = gspca_resume,
Hans de Goede8bb58962012-06-30 06:44:47 -0300928 .reset_resume = gspca_resume,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300929#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300930};
931
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -0800932module_usb_driver(sd_driver);