blob: f389a8d0937d8fe90acebf2858639775e679ac1c [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.
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030017 */
18
Joe Perches133a9fe2011-08-21 19:56:57 -030019#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030021#define MODULE_NAME "spca561"
22
Hans de Goede436c2c52010-02-28 09:41:04 -030023#include <linux/input.h>
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030024#include "gspca.h"
25
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030026MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
27MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver");
28MODULE_LICENSE("GPL");
29
Hans Verkuil3fa24bf2012-05-16 08:20:44 -030030#define EXPOSURE_MAX (2047 + 325)
31
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030032/* specific webcam descriptor */
33struct sd {
34 struct gspca_dev gspca_dev; /* !! must be the first item */
35
Hans Verkuil3fa24bf2012-05-16 08:20:44 -030036 struct { /* hue/contrast control cluster */
37 struct v4l2_ctrl *contrast;
38 struct v4l2_ctrl *hue;
39 };
40 struct v4l2_ctrl *autogain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030041
Jean-Francois Moined698dc62008-09-03 16:47:51 -030042#define EXPO12A_DEF 3
43 __u8 expo12a; /* expo/gain? for rev 12a */
44
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030045 __u8 chip_revision;
Jean-Francois Moine7879d452008-09-03 16:47:32 -030046#define Rev012A 0
47#define Rev072A 1
48
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030049 signed char ag_cnt;
50#define AG_CNT_START 13
51};
52
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030053static const struct v4l2_pix_format sif_012a_mode[] = {
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030054 {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
55 .bytesperline = 160,
56 .sizeimage = 160 * 120,
57 .colorspace = V4L2_COLORSPACE_SRGB,
58 .priv = 3},
59 {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
60 .bytesperline = 176,
61 .sizeimage = 176 * 144,
62 .colorspace = V4L2_COLORSPACE_SRGB,
63 .priv = 2},
64 {320, 240, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
65 .bytesperline = 320,
66 .sizeimage = 320 * 240 * 4 / 8,
67 .colorspace = V4L2_COLORSPACE_SRGB,
68 .priv = 1},
69 {352, 288, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
70 .bytesperline = 352,
71 .sizeimage = 352 * 288 * 4 / 8,
72 .colorspace = V4L2_COLORSPACE_SRGB,
73 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030074};
75
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030076static const struct v4l2_pix_format sif_072a_mode[] = {
Jean-Francois Moineb77c0042008-09-04 16:22:56 -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_SGBRG8, V4L2_FIELD_NONE,
88 .bytesperline = 320,
89 .sizeimage = 320 * 240,
90 .colorspace = V4L2_COLORSPACE_SRGB,
91 .priv = 1},
92 {352, 288, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
93 .bytesperline = 352,
94 .sizeimage = 352 * 288,
95 .colorspace = V4L2_COLORSPACE_SRGB,
96 .priv = 0},
97};
98
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030099/*
100 * Initialization data
101 * I'm not very sure how to split initialization from open data
102 * chunks. For now, we'll consider everything as initialization
103 */
104/* Frame packet header offsets for the spca561 */
105#define SPCA561_OFFSET_SNAP 1
106#define SPCA561_OFFSET_TYPE 2
107#define SPCA561_OFFSET_COMPRESS 3
108#define SPCA561_OFFSET_FRAMSEQ 4
109#define SPCA561_OFFSET_GPIO 5
110#define SPCA561_OFFSET_USBBUFF 6
111#define SPCA561_OFFSET_WIN2GRAVE 7
112#define SPCA561_OFFSET_WIN2RAVE 8
113#define SPCA561_OFFSET_WIN2BAVE 9
114#define SPCA561_OFFSET_WIN2GBAVE 10
115#define SPCA561_OFFSET_WIN1GRAVE 11
116#define SPCA561_OFFSET_WIN1RAVE 12
117#define SPCA561_OFFSET_WIN1BAVE 13
118#define SPCA561_OFFSET_WIN1GBAVE 14
119#define SPCA561_OFFSET_FREQ 15
120#define SPCA561_OFFSET_VSYNC 16
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300121#define SPCA561_INDEX_I2C_BASE 0x8800
122#define SPCA561_SNAPBIT 0x20
123#define SPCA561_SNAPCTRL 0x40
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300124
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300125static const u16 rev72a_reset[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300126 {0x0000, 0x8114}, /* Software GPIO output data */
127 {0x0001, 0x8114}, /* Software GPIO output data */
128 {0x0000, 0x8112}, /* Some kind of reset */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300129 {}
130};
131static const __u16 rev72a_init_data1[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300132 {0x0003, 0x8701}, /* PCLK clock delay adjustment */
133 {0x0001, 0x8703}, /* HSYNC from cmos inverted */
134 {0x0011, 0x8118}, /* Enable and conf sensor */
135 {0x0001, 0x8118}, /* Conf sensor */
136 {0x0092, 0x8804}, /* I know nothing about these */
137 {0x0010, 0x8802}, /* 0x88xx registers, so I won't */
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300138 {}
139};
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300140static const u16 rev72a_init_sensor1[][2] = {
141 {0x0001, 0x000d},
142 {0x0002, 0x0018},
143 {0x0004, 0x0165},
144 {0x0005, 0x0021},
145 {0x0007, 0x00aa},
146 {0x0020, 0x1504},
147 {0x0039, 0x0002},
148 {0x0035, 0x0010},
149 {0x0009, 0x1049},
150 {0x0028, 0x000b},
151 {0x003b, 0x000f},
152 {0x003c, 0x0000},
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300153 {}
154};
155static const __u16 rev72a_init_data2[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300156 {0x0018, 0x8601}, /* Pixel/line selection for color separation */
157 {0x0000, 0x8602}, /* Optical black level for user setting */
158 {0x0060, 0x8604}, /* Optical black horizontal offset */
159 {0x0002, 0x8605}, /* Optical black vertical offset */
160 {0x0000, 0x8603}, /* Non-automatic optical black level */
161 {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
162 {0x0000, 0x865f}, /* Vertical valid pixels window (x2) */
163 {0x00b0, 0x865d}, /* Horizontal valid pixels window (x2) */
164 {0x0090, 0x865e}, /* Vertical valid lines window (x2) */
165 {0x00e0, 0x8406}, /* Memory buffer threshold */
166 {0x0000, 0x8660}, /* Compensation memory stuff */
167 {0x0002, 0x8201}, /* Output address for r/w serial EEPROM */
168 {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */
169 {0x0001, 0x8200}, /* OprMode to be executed by hardware */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300170/* from ms-win */
171 {0x0000, 0x8611}, /* R offset for white balance */
172 {0x00fd, 0x8612}, /* Gr offset for white balance */
173 {0x0003, 0x8613}, /* B offset for white balance */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300174 {0x0000, 0x8614}, /* Gb offset for white balance */
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300175/* from ms-win */
176 {0x0035, 0x8651}, /* R gain for white balance */
177 {0x0040, 0x8652}, /* Gr gain for white balance */
178 {0x005f, 0x8653}, /* B gain for white balance */
179 {0x0040, 0x8654}, /* Gb gain for white balance */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300180 {0x0002, 0x8502}, /* Maximum average bit rate stuff */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300181 {0x0011, 0x8802},
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300182
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300183 {0x0087, 0x8700}, /* Set master clock (96Mhz????) */
184 {0x0081, 0x8702}, /* Master clock output enable */
185
186 {0x0000, 0x8500}, /* Set image type (352x288 no compression) */
187 /* Originally was 0x0010 (352x288 compression) */
188
189 {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
190 {0x0003, 0x865c}, /* Vertical offset for valid lines */
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300191 {}
192};
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300193static const u16 rev72a_init_sensor2[][2] = {
194 {0x0003, 0x0121},
195 {0x0004, 0x0165},
196 {0x0005, 0x002f}, /* blanking control column */
197 {0x0006, 0x0000}, /* blanking mode row*/
198 {0x000a, 0x0002},
199 {0x0009, 0x1061}, /* setexposure times && pixel clock
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300200 * 0001 0 | 000 0110 0001 */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300201 {0x0035, 0x0014},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300202 {}
203};
204
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300205/******************** QC Express etch2 stuff ********************/
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300206static const __u16 Pb100_1map8300[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300207 /* reg, value */
208 {0x8320, 0x3304},
209
210 {0x8303, 0x0125}, /* image area */
211 {0x8304, 0x0169},
212 {0x8328, 0x000b},
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300213 {0x833c, 0x0001}, /*fixme: win:07*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300214
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300215 {0x832f, 0x1904}, /*fixme: was 0419*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300216 {0x8307, 0x00aa},
217 {0x8301, 0x0003},
218 {0x8302, 0x000e},
219 {}
220};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300221static const __u16 Pb100_2map8300[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300222 /* reg, value */
223 {0x8339, 0x0000},
224 {0x8307, 0x00aa},
225 {}
226};
227
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300228static const __u16 spca561_161rev12A_data1[][2] = {
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300229 {0x29, 0x8118}, /* Control register (various enable bits) */
230 {0x08, 0x8114}, /* GPIO: Led off */
231 {0x0e, 0x8112}, /* 0x0e stream off 0x3e stream on */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300232 {0x00, 0x8102}, /* white balance - new */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300233 {0x92, 0x8804},
234 {0x04, 0x8802}, /* windows uses 08 */
235 {}
236};
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300237static const __u16 spca561_161rev12A_data2[][2] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300238 {0x21, 0x8118},
239 {0x10, 0x8500},
240 {0x07, 0x8601},
241 {0x07, 0x8602},
242 {0x04, 0x8501},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300243
244 {0x07, 0x8201}, /* windows uses 02 */
245 {0x08, 0x8200},
246 {0x01, 0x8200},
247
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300248 {0x90, 0x8604},
249 {0x00, 0x8605},
250 {0xb0, 0x8603},
251
252 /* sensor gains */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300253 {0x07, 0x8601}, /* white balance - new */
254 {0x07, 0x8602}, /* white balance - new */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300255 {0x00, 0x8610}, /* *red */
256 {0x00, 0x8611}, /* 3f *green */
257 {0x00, 0x8612}, /* green *blue */
258 {0x00, 0x8613}, /* blue *green */
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300259 {0x43, 0x8614}, /* green *red - white balance - was 0x35 */
260 {0x40, 0x8615}, /* 40 *green - white balance - was 0x35 */
261 {0x71, 0x8616}, /* 7a *blue - white balance - was 0x35 */
262 {0x40, 0x8617}, /* 40 *green - white balance - was 0x35 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300263
264 {0x0c, 0x8620}, /* 0c */
265 {0xc8, 0x8631}, /* c8 */
266 {0xc8, 0x8634}, /* c8 */
267 {0x23, 0x8635}, /* 23 */
268 {0x1f, 0x8636}, /* 1f */
269 {0xdd, 0x8637}, /* dd */
270 {0xe1, 0x8638}, /* e1 */
271 {0x1d, 0x8639}, /* 1d */
272 {0x21, 0x863a}, /* 21 */
273 {0xe3, 0x863b}, /* e3 */
274 {0xdf, 0x863c}, /* df */
275 {0xf0, 0x8505},
276 {0x32, 0x850a},
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300277/* {0x99, 0x8700}, * - white balance - new (removed) */
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300278 /* HDG we used to do this in stop0, making the init state and the state
279 after a start / stop different, so do this here instead. */
280 {0x29, 0x8118},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300281 {}
282};
283
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300284static void reg_w_val(struct gspca_dev *gspca_dev, __u16 index, __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300285{
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300286 int ret;
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300287 struct usb_device *dev = gspca_dev->dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300288
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300289 ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
290 0, /* request */
291 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
292 value, index, NULL, 0, 500);
Joe Perches37d5efb2017-09-22 15:20:33 -0400293 gspca_dbg(gspca_dev, D_USBO, "reg write: 0x%02x:0x%02x\n",
294 index, value);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300295 if (ret < 0)
Joe Perches133a9fe2011-08-21 19:56:57 -0300296 pr_err("reg write: error %d\n", ret);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300297}
298
299static void write_vector(struct gspca_dev *gspca_dev,
300 const __u16 data[][2])
301{
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300302 int i;
303
304 i = 0;
305 while (data[i][1] != 0) {
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300306 reg_w_val(gspca_dev, data[i][1], data[i][0]);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300307 i++;
308 }
309}
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300310
311/* read 'len' bytes to gspca_dev->usb_buf */
312static void reg_r(struct gspca_dev *gspca_dev,
313 __u16 index, __u16 length)
314{
315 usb_control_msg(gspca_dev->dev,
316 usb_rcvctrlpipe(gspca_dev->dev, 0),
317 0, /* request */
318 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
319 0, /* value */
320 index, gspca_dev->usb_buf, length, 500);
321}
322
323/* write 'len' bytes from gspca_dev->usb_buf */
324static void reg_w_buf(struct gspca_dev *gspca_dev,
325 __u16 index, __u16 len)
326{
327 usb_control_msg(gspca_dev->dev,
328 usb_sndctrlpipe(gspca_dev->dev, 0),
329 0, /* request */
330 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
331 0, /* value */
332 index, gspca_dev->usb_buf, len, 500);
333}
334
335static void i2c_write(struct gspca_dev *gspca_dev, __u16 value, __u16 reg)
336{
337 int retry = 60;
338
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300339 reg_w_val(gspca_dev, 0x8801, reg);
340 reg_w_val(gspca_dev, 0x8805, value);
341 reg_w_val(gspca_dev, 0x8800, value >> 8);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300342 do {
343 reg_r(gspca_dev, 0x8803, 1);
344 if (!gspca_dev->usb_buf[0])
345 return;
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300346 msleep(10);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300347 } while (--retry);
348}
349
350static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
351{
352 int retry = 60;
353 __u8 value;
354
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300355 reg_w_val(gspca_dev, 0x8804, 0x92);
356 reg_w_val(gspca_dev, 0x8801, reg);
357 reg_w_val(gspca_dev, 0x8802, mode | 0x01);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300358 do {
359 reg_r(gspca_dev, 0x8803, 1);
360 if (!gspca_dev->usb_buf[0]) {
361 reg_r(gspca_dev, 0x8800, 1);
362 value = gspca_dev->usb_buf[0];
363 reg_r(gspca_dev, 0x8805, 1);
364 return ((int) value << 8) | gspca_dev->usb_buf[0];
365 }
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300366 msleep(10);
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300367 } while (--retry);
368 return -1;
369}
370
371static void sensor_mapwrite(struct gspca_dev *gspca_dev,
372 const __u16 (*sensormap)[2])
373{
374 while ((*sensormap)[0]) {
375 gspca_dev->usb_buf[0] = (*sensormap)[1];
376 gspca_dev->usb_buf[1] = (*sensormap)[1] >> 8;
377 reg_w_buf(gspca_dev, (*sensormap)[0], 2);
378 sensormap++;
379 }
380}
381
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300382static void write_sensor_72a(struct gspca_dev *gspca_dev,
383 const __u16 (*sensor)[2])
384{
385 while ((*sensor)[0]) {
386 i2c_write(gspca_dev, (*sensor)[1], (*sensor)[0]);
387 sensor++;
388 }
389}
390
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300391static void init_161rev12A(struct gspca_dev *gspca_dev)
392{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300393 write_vector(gspca_dev, spca561_161rev12A_data1);
394 sensor_mapwrite(gspca_dev, Pb100_1map8300);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300395/*fixme: should be in sd_start*/
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300396 write_vector(gspca_dev, spca561_161rev12A_data2);
397 sensor_mapwrite(gspca_dev, Pb100_2map8300);
398}
399
400/* this function is called at probe time */
401static int sd_config(struct gspca_dev *gspca_dev,
402 const struct usb_device_id *id)
403{
404 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300405 struct cam *cam;
406 __u16 vendor, product;
407 __u8 data1, data2;
408
409 /* Read frm global register the USB product and vendor IDs, just to
410 * prove that we can communicate with the device. This works, which
411 * confirms at we are communicating properly and that the device
412 * is a 561. */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300413 reg_r(gspca_dev, 0x8104, 1);
414 data1 = gspca_dev->usb_buf[0];
415 reg_r(gspca_dev, 0x8105, 1);
416 data2 = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300417 vendor = (data2 << 8) | data1;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300418 reg_r(gspca_dev, 0x8106, 1);
419 data1 = gspca_dev->usb_buf[0];
420 reg_r(gspca_dev, 0x8107, 1);
421 data2 = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300422 product = (data2 << 8) | data1;
423 if (vendor != id->idVendor || product != id->idProduct) {
Joe Perches37d5efb2017-09-22 15:20:33 -0400424 gspca_dbg(gspca_dev, D_PROBE, "Bad vendor / product from device\n");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300425 return -EINVAL;
426 }
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300427
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300428 cam = &gspca_dev->cam;
Hans de Goedeeb3fb7c2012-01-01 16:35:01 -0300429 cam->needs_full_bandwidth = 1;
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300430
431 sd->chip_revision = id->driver_info;
Jean-Francois Moineb77c0042008-09-04 16:22:56 -0300432 if (sd->chip_revision == Rev012A) {
433 cam->cam_mode = sif_012a_mode;
434 cam->nmodes = ARRAY_SIZE(sif_012a_mode);
435 } else {
436 cam->cam_mode = sif_072a_mode;
437 cam->nmodes = ARRAY_SIZE(sif_072a_mode);
438 }
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300439 sd->expo12a = EXPO12A_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300440 return 0;
441}
442
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300443/* this function is called at probe and resume time */
444static int sd_init_12a(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300445{
Joe Perches37d5efb2017-09-22 15:20:33 -0400446 gspca_dbg(gspca_dev, D_STREAM, "Chip revision: 012a\n");
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300447 init_161rev12A(gspca_dev);
448 return 0;
449}
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300450static int sd_init_72a(struct gspca_dev *gspca_dev)
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300451{
Joe Perches37d5efb2017-09-22 15:20:33 -0400452 gspca_dbg(gspca_dev, D_STREAM, "Chip revision: 072a\n");
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300453 write_vector(gspca_dev, rev72a_reset);
454 msleep(200);
Jean-Francois Moinef8a04a62008-12-19 07:21:26 -0300455 write_vector(gspca_dev, rev72a_init_data1);
456 write_sensor_72a(gspca_dev, rev72a_init_sensor1);
457 write_vector(gspca_dev, rev72a_init_data2);
458 write_sensor_72a(gspca_dev, rev72a_init_sensor2);
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300459 reg_w_val(gspca_dev, 0x8112, 0x30);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300460 return 0;
461}
462
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300463static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
464{
Hans de Goedea8931d52012-07-02 15:29:56 -0300465 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea8931d52012-07-02 15:29:56 -0300466 __u16 reg;
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300467
Hans de Goedea8931d52012-07-02 15:29:56 -0300468 if (sd->chip_revision == Rev012A)
469 reg = 0x8610;
470 else
471 reg = 0x8611;
472
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300473 reg_w_val(gspca_dev, reg + 0, val); /* R */
474 reg_w_val(gspca_dev, reg + 1, val); /* Gr */
475 reg_w_val(gspca_dev, reg + 2, val); /* B */
476 reg_w_val(gspca_dev, reg + 3, val); /* Gb */
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300477}
478
479static void setwhite(struct gspca_dev *gspca_dev, s32 white, s32 contrast)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300480{
481 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300482 __u8 blue, red;
483 __u16 reg;
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300484
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300485 /* try to emulate MS-win as possible */
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300486 red = 0x20 + white * 3 / 8;
487 blue = 0x90 - white * 5 / 8;
488 if (sd->chip_revision == Rev012A) {
489 reg = 0x8614;
490 } else {
491 reg = 0x8651;
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300492 red += contrast - 0x20;
493 blue += contrast - 0x20;
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300494 reg_w_val(gspca_dev, 0x8652, contrast + 0x20); /* Gr */
495 reg_w_val(gspca_dev, 0x8654, contrast + 0x20); /* Gb */
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300496 }
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300497 reg_w_val(gspca_dev, reg, red);
498 reg_w_val(gspca_dev, reg + 2, blue);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300499}
500
501/* rev 12a only */
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300502static void setexposure(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300503{
Hans de Goeded0848eb2009-05-25 15:20:16 -0300504 int i, expo = 0;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300505
Hans de Goede0fc23d22008-09-04 16:22:57 -0300506 /* Register 0x8309 controls exposure for the spca561,
507 the basic exposure setting goes from 1-2047, where 1 is completely
508 dark and 2047 is very bright. It not only influences exposure but
509 also the framerate (to allow for longer exposure) from 1 - 300 it
510 only raises the exposure time then from 300 - 600 it halves the
511 framerate to be able to further raise the exposure time and for every
512 300 more it halves the framerate again. This allows for a maximum
513 exposure time of circa 0.2 - 0.25 seconds (30 / (2000/3000) fps).
514 Sometimes this is not enough, the 1-2047 uses bits 0-10, bits 11-12
515 configure a divider for the base framerate which us used at the
516 exposure setting of 1-300. These bits configure the base framerate
517 according to the following formula: fps = 60 / (value + 2) */
Hans de Goeded0848eb2009-05-25 15:20:16 -0300518
519 /* We choose to use the high bits setting the fixed framerate divisor
520 asap, as setting high basic exposure setting without the fixed
521 divider in combination with high gains makes the cam stop */
522 int table[] = { 0, 450, 550, 625, EXPOSURE_MAX };
523
524 for (i = 0; i < ARRAY_SIZE(table) - 1; i++) {
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300525 if (val <= table[i + 1]) {
526 expo = val - table[i];
Hans de Goeded0848eb2009-05-25 15:20:16 -0300527 if (i)
528 expo += 300;
529 expo |= i << 11;
530 break;
531 }
Hans de Goede0fc23d22008-09-04 16:22:57 -0300532 }
Hans de Goeded0848eb2009-05-25 15:20:16 -0300533
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300534 gspca_dev->usb_buf[0] = expo;
535 gspca_dev->usb_buf[1] = expo >> 8;
536 reg_w_buf(gspca_dev, 0x8309, 2);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300537}
538
539/* rev 12a only */
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300540static void setgain(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300541{
Hans de Goeded0848eb2009-05-25 15:20:16 -0300542 /* gain reg low 6 bits 0-63 gain, bit 6 and 7, both double the
543 sensitivity when set, so 31 + one of them set == 63, and 15
544 with both of them set == 63 */
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300545 if (val < 64)
546 gspca_dev->usb_buf[0] = val;
547 else if (val < 128)
548 gspca_dev->usb_buf[0] = (val / 2) | 0x40;
Hans de Goeded0848eb2009-05-25 15:20:16 -0300549 else
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300550 gspca_dev->usb_buf[0] = (val / 4) | 0xc0;
Hans de Goeded0848eb2009-05-25 15:20:16 -0300551
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300552 gspca_dev->usb_buf[1] = 0;
553 reg_w_buf(gspca_dev, 0x8335, 2);
Jean-Francois Moine6c9d3c52008-09-03 16:47:30 -0300554}
555
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300556static void setautogain(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300557{
558 struct sd *sd = (struct sd *) gspca_dev;
559
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300560 if (val)
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300561 sd->ag_cnt = AG_CNT_START;
562 else
563 sd->ag_cnt = -1;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300564}
565
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300566static int sd_start_12a(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300567{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300568 int mode;
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300569 static const __u8 Reg8391[8] =
570 {0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300571
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300572 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300573 if (mode <= 1) {
574 /* Use compression on 320x240 and above */
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300575 reg_w_val(gspca_dev, 0x8500, 0x10 | mode);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300576 } else {
577 /* I couldn't get the compression to work below 320x240
578 * Fortunately at these resolutions the bandwidth
579 * is sufficient to push raw frames at ~20fps */
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300580 reg_w_val(gspca_dev, 0x8500, mode);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300581 } /* -- qq@kuku.eu.org */
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300582
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300583 gspca_dev->usb_buf[0] = 0xaa;
584 gspca_dev->usb_buf[1] = 0x00;
585 reg_w_buf(gspca_dev, 0x8307, 2);
586 /* clock - lower 0x8X values lead to fps > 30 */
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300587 reg_w_val(gspca_dev, 0x8700, 0x8a);
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300588 /* 0x8f 0x85 0x27 clock */
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300589 reg_w_val(gspca_dev, 0x8112, 0x1e | 0x20);
590 reg_w_val(gspca_dev, 0x850b, 0x03);
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300591 memcpy(gspca_dev->usb_buf, Reg8391, 8);
592 reg_w_buf(gspca_dev, 0x8391, 8);
593 reg_w_buf(gspca_dev, 0x8390, 8);
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300594
595 /* Led ON (bit 3 -> 0 */
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300596 reg_w_val(gspca_dev, 0x8114, 0x00);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300597 return 0;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300598}
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300599static int sd_start_72a(struct gspca_dev *gspca_dev)
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300600{
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300601 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300602 int Clck;
603 int mode;
604
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300605 write_vector(gspca_dev, rev72a_reset);
606 msleep(200);
607 write_vector(gspca_dev, rev72a_init_data1);
608 write_sensor_72a(gspca_dev, rev72a_init_sensor1);
609
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300610 mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
611 switch (mode) {
612 default:
Jean-Francois Moinea48196a2009-01-18 14:24:52 -0300613 case 0:
614 Clck = 0x27; /* ms-win 0x87 */
615 break;
616 case 1:
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300617 Clck = 0x25;
618 break;
619 case 2:
620 Clck = 0x22;
621 break;
622 case 3:
623 Clck = 0x21;
624 break;
625 }
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300626 reg_w_val(gspca_dev, 0x8700, Clck); /* 0x27 clock */
627 reg_w_val(gspca_dev, 0x8702, 0x81);
628 reg_w_val(gspca_dev, 0x8500, mode); /* mode */
Jean-Francois Moine0dbc2c12009-01-16 16:24:28 -0300629 write_sensor_72a(gspca_dev, rev72a_init_sensor2);
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300630 setwhite(gspca_dev, v4l2_ctrl_g_ctrl(sd->hue),
631 v4l2_ctrl_g_ctrl(sd->contrast));
Jean-Francois Moine5b7ed282008-12-18 12:38:15 -0300632/* setbrightness(gspca_dev); * fixme: bad values */
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300633 setautogain(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain));
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300634 reg_w_val(gspca_dev, 0x8112, 0x10 | 0x20);
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300635 return 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300636}
637
638static void sd_stopN(struct gspca_dev *gspca_dev)
639{
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300640 struct sd *sd = (struct sd *) gspca_dev;
641
642 if (sd->chip_revision == Rev012A) {
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300643 reg_w_val(gspca_dev, 0x8112, 0x0e);
Hans de Goede6b33e5e2010-02-27 07:18:14 -0300644 /* Led Off (bit 3 -> 1 */
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300645 reg_w_val(gspca_dev, 0x8114, 0x08);
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300646 } else {
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300647 reg_w_val(gspca_dev, 0x8112, 0x20);
648/* reg_w_val(gspca_dev, 0x8102, 0x00); ?? */
Jean-Francois Moined698dc62008-09-03 16:47:51 -0300649 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300650}
651
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300652static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300653{
654 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300655 int expotimes;
656 int pixelclk;
657 int gainG;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300658 __u8 R, Gr, Gb, B;
659 int y;
660 __u8 luma_mean = 110;
661 __u8 luma_delta = 20;
662 __u8 spring = 4;
663
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300664 if (sd->ag_cnt < 0)
665 return;
666 if (--sd->ag_cnt >= 0)
667 return;
668 sd->ag_cnt = AG_CNT_START;
669
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300670 switch (sd->chip_revision) {
671 case Rev072A:
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300672 reg_r(gspca_dev, 0x8621, 1);
673 Gr = gspca_dev->usb_buf[0];
674 reg_r(gspca_dev, 0x8622, 1);
675 R = gspca_dev->usb_buf[0];
676 reg_r(gspca_dev, 0x8623, 1);
677 B = gspca_dev->usb_buf[0];
678 reg_r(gspca_dev, 0x8624, 1);
679 Gb = gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300680 y = (77 * R + 75 * (Gr + Gb) + 29 * B) >> 8;
681 /* u= (128*B-(43*(Gr+Gb+R))) >> 8; */
682 /* v= (128*R-(53*(Gr+Gb))-21*B) >> 8; */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300683
684 if (y < luma_mean - luma_delta ||
685 y > luma_mean + luma_delta) {
686 expotimes = i2c_read(gspca_dev, 0x09, 0x10);
687 pixelclk = 0x0800;
688 expotimes = expotimes & 0x07ff;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300689 gainG = i2c_read(gspca_dev, 0x35, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300690
691 expotimes += (luma_mean - y) >> spring;
692 gainG += (luma_mean - y) / 50;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300693
694 if (gainG > 0x3f)
695 gainG = 0x3f;
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300696 else if (gainG < 3)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300697 gainG = 3;
698 i2c_write(gspca_dev, gainG, 0x35);
699
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300700 if (expotimes > 0x0256)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300701 expotimes = 0x0256;
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300702 else if (expotimes < 3)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300703 expotimes = 3;
704 i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
705 }
706 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300707 }
708}
709
710static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300711 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300712 int len) /* iso packet length */
713{
Hans de Goede0fc23d22008-09-04 16:22:57 -0300714 struct sd *sd = (struct sd *) gspca_dev;
715
Jean-Francois Moine576ed7b2009-01-16 08:57:28 -0300716 len--;
717 switch (*data++) { /* sequence number */
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300718 case 0: /* start of frame */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300719 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Hans de Goede436c2c52010-02-28 09:41:04 -0300720
721 /* This should never happen */
722 if (len < 2) {
Joe Perches37d5efb2017-09-22 15:20:33 -0400723 gspca_err(gspca_dev, "Short SOF packet, ignoring\n\n\n\n\n");
Hans de Goede436c2c52010-02-28 09:41:04 -0300724 gspca_dev->last_packet_type = DISCARD_PACKET;
725 return;
726 }
727
Peter Senna Tschudin60d21562013-01-24 19:29:09 -0300728#if IS_ENABLED(CONFIG_INPUT)
Hans de Goede436c2c52010-02-28 09:41:04 -0300729 if (data[0] & 0x20) {
730 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
731 input_sync(gspca_dev->input_dev);
732 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
733 input_sync(gspca_dev->input_dev);
734 }
735#endif
736
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300737 if (data[1] & 0x10) {
738 /* compressed bayer */
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300739 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300740 } else {
Hans de Goede54ab92c2008-07-03 11:20:58 -0300741 /* raw bayer (with a header, which we skip) */
Hans de Goede0fc23d22008-09-04 16:22:57 -0300742 if (sd->chip_revision == Rev012A) {
743 data += 20;
744 len -= 20;
745 } else {
746 data += 16;
747 len -= 16;
748 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300749 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300750 }
751 return;
Jean-Francois Moine35dc1b42008-12-17 14:34:53 -0300752 case 0xff: /* drop (empty mpackets) */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300753 return;
754 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300755 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300756}
757
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300758static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300759{
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300760 struct gspca_dev *gspca_dev =
761 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
762 struct sd *sd = (struct sd *)gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300763
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300764 gspca_dev->usb_err = 0;
765
766 if (!gspca_dev->streaming)
767 return 0;
768
769 switch (ctrl->id) {
770 case V4L2_CID_BRIGHTNESS:
771 setbrightness(gspca_dev, ctrl->val);
772 break;
773 case V4L2_CID_CONTRAST:
774 /* hue/contrast control cluster for 72a */
775 setwhite(gspca_dev, sd->hue->val, ctrl->val);
776 break;
777 case V4L2_CID_HUE:
778 /* just plain hue control for 12a */
779 setwhite(gspca_dev, ctrl->val, 0);
780 break;
781 case V4L2_CID_EXPOSURE:
782 setexposure(gspca_dev, ctrl->val);
783 break;
784 case V4L2_CID_GAIN:
785 setgain(gspca_dev, ctrl->val);
786 break;
787 case V4L2_CID_AUTOGAIN:
788 setautogain(gspca_dev, ctrl->val);
789 break;
790 }
791 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300792}
793
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300794static const struct v4l2_ctrl_ops sd_ctrl_ops = {
795 .s_ctrl = sd_s_ctrl,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300796};
797
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300798static int sd_init_controls_12a(struct gspca_dev *gspca_dev)
799{
800 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
801
802 gspca_dev->vdev.ctrl_handler = hdl;
803 v4l2_ctrl_handler_init(hdl, 3);
804 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
805 V4L2_CID_HUE, 1, 0x7f, 1, 0x40);
806 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
Hans de Goedea8931d52012-07-02 15:29:56 -0300807 V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
808 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300809 V4L2_CID_EXPOSURE, 1, EXPOSURE_MAX, 1, 700);
810 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
811 V4L2_CID_GAIN, 0, 255, 1, 63);
812
813 if (hdl->error) {
814 pr_err("Could not initialize controls\n");
815 return hdl->error;
816 }
817 return 0;
818}
819
820static int sd_init_controls_72a(struct gspca_dev *gspca_dev)
821{
822 struct sd *sd = (struct sd *)gspca_dev;
823 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
824
825 gspca_dev->vdev.ctrl_handler = hdl;
826 v4l2_ctrl_handler_init(hdl, 4);
827 sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
828 V4L2_CID_CONTRAST, 0, 0x3f, 1, 0x20);
829 sd->hue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
830 V4L2_CID_HUE, 1, 0x7f, 1, 0x40);
831 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
832 V4L2_CID_BRIGHTNESS, 0, 0x3f, 1, 0x20);
833 sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
834 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
835
836 if (hdl->error) {
837 pr_err("Could not initialize controls\n");
838 return hdl->error;
839 }
840 v4l2_ctrl_cluster(2, &sd->contrast);
841 return 0;
842}
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300843
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300844/* sub-driver description */
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300845static const struct sd_desc sd_desc_12a = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300846 .name = MODULE_NAME,
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300847 .init_controls = sd_init_controls_12a,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300848 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300849 .init = sd_init_12a,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300850 .start = sd_start_12a,
851 .stopN = sd_stopN,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300852 .pkt_scan = sd_pkt_scan,
Peter Senna Tschudin60d21562013-01-24 19:29:09 -0300853#if IS_ENABLED(CONFIG_INPUT)
Hans de Goede436c2c52010-02-28 09:41:04 -0300854 .other_input = 1,
855#endif
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300856};
857static const struct sd_desc sd_desc_72a = {
858 .name = MODULE_NAME,
Hans Verkuil3fa24bf2012-05-16 08:20:44 -0300859 .init_controls = sd_init_controls_72a,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300860 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300861 .init = sd_init_72a,
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300862 .start = sd_start_72a,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300863 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300864 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300865 .dq_callback = do_autogain,
Peter Senna Tschudin60d21562013-01-24 19:29:09 -0300866#if IS_ENABLED(CONFIG_INPUT)
Hans de Goede436c2c52010-02-28 09:41:04 -0300867 .other_input = 1,
868#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300869};
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300870static const struct sd_desc *sd_desc[2] = {
871 &sd_desc_12a,
872 &sd_desc_72a
873};
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300874
875/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300876static const struct usb_device_id device_table[] = {
Jean-Francois Moine87581aa2008-07-26 14:30:01 -0300877 {USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A},
878 {USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A},
879 {USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A},
John Ellsonf8f73d02010-03-17 10:22:58 -0300880 {USB_DEVICE(0x0461, 0x0815), .driver_info = Rev072A},
Jean-Francois Moine87581aa2008-07-26 14:30:01 -0300881 {USB_DEVICE(0x046d, 0x0928), .driver_info = Rev012A},
882 {USB_DEVICE(0x046d, 0x0929), .driver_info = Rev012A},
883 {USB_DEVICE(0x046d, 0x092a), .driver_info = Rev012A},
884 {USB_DEVICE(0x046d, 0x092b), .driver_info = Rev012A},
885 {USB_DEVICE(0x046d, 0x092c), .driver_info = Rev012A},
886 {USB_DEVICE(0x046d, 0x092d), .driver_info = Rev012A},
887 {USB_DEVICE(0x046d, 0x092e), .driver_info = Rev012A},
888 {USB_DEVICE(0x046d, 0x092f), .driver_info = Rev012A},
889 {USB_DEVICE(0x04fc, 0x0561), .driver_info = Rev072A},
890 {USB_DEVICE(0x060b, 0xa001), .driver_info = Rev072A},
891 {USB_DEVICE(0x10fd, 0x7e50), .driver_info = Rev072A},
892 {USB_DEVICE(0xabcd, 0xcdee), .driver_info = Rev072A},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300893 {}
894};
895
896MODULE_DEVICE_TABLE(usb, device_table);
897
898/* -- device connect -- */
899static int sd_probe(struct usb_interface *intf,
900 const struct usb_device_id *id)
901{
Jean-Francois Moine7879d452008-09-03 16:47:32 -0300902 return gspca_dev_probe(intf, id,
903 sd_desc[id->driver_info],
904 sizeof(struct sd),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300905 THIS_MODULE);
906}
907
908static struct usb_driver sd_driver = {
909 .name = MODULE_NAME,
910 .id_table = device_table,
911 .probe = sd_probe,
912 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300913#ifdef CONFIG_PM
914 .suspend = gspca_suspend,
915 .resume = gspca_resume,
Hans de Goede8bb58962012-06-30 06:44:47 -0300916 .reset_resume = gspca_resume,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300917#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300918};
919
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -0800920module_usb_driver(sd_driver);