1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Sunplus spca561 subdriver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2004 Michel Xhaard mxhaard@magic.fr
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #define MODULE_NAME "spca561"
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include <linux/input.h>
15*4882a593Smuzhiyun #include "gspca.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
18*4882a593Smuzhiyun MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver");
19*4882a593Smuzhiyun MODULE_LICENSE("GPL");
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define EXPOSURE_MAX (2047 + 325)
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun /* specific webcam descriptor */
24*4882a593Smuzhiyun struct sd {
25*4882a593Smuzhiyun struct gspca_dev gspca_dev; /* !! must be the first item */
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun struct { /* hue/contrast control cluster */
28*4882a593Smuzhiyun struct v4l2_ctrl *contrast;
29*4882a593Smuzhiyun struct v4l2_ctrl *hue;
30*4882a593Smuzhiyun };
31*4882a593Smuzhiyun struct v4l2_ctrl *autogain;
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define EXPO12A_DEF 3
34*4882a593Smuzhiyun __u8 expo12a; /* expo/gain? for rev 12a */
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun __u8 chip_revision;
37*4882a593Smuzhiyun #define Rev012A 0
38*4882a593Smuzhiyun #define Rev072A 1
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun signed char ag_cnt;
41*4882a593Smuzhiyun #define AG_CNT_START 13
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun static const struct v4l2_pix_format sif_012a_mode[] = {
45*4882a593Smuzhiyun {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
46*4882a593Smuzhiyun .bytesperline = 160,
47*4882a593Smuzhiyun .sizeimage = 160 * 120,
48*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
49*4882a593Smuzhiyun .priv = 3},
50*4882a593Smuzhiyun {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
51*4882a593Smuzhiyun .bytesperline = 176,
52*4882a593Smuzhiyun .sizeimage = 176 * 144,
53*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
54*4882a593Smuzhiyun .priv = 2},
55*4882a593Smuzhiyun {320, 240, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
56*4882a593Smuzhiyun .bytesperline = 320,
57*4882a593Smuzhiyun .sizeimage = 320 * 240 * 4 / 8,
58*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
59*4882a593Smuzhiyun .priv = 1},
60*4882a593Smuzhiyun {352, 288, V4L2_PIX_FMT_SPCA561, V4L2_FIELD_NONE,
61*4882a593Smuzhiyun .bytesperline = 352,
62*4882a593Smuzhiyun .sizeimage = 352 * 288 * 4 / 8,
63*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
64*4882a593Smuzhiyun .priv = 0},
65*4882a593Smuzhiyun };
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun static const struct v4l2_pix_format sif_072a_mode[] = {
68*4882a593Smuzhiyun {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
69*4882a593Smuzhiyun .bytesperline = 160,
70*4882a593Smuzhiyun .sizeimage = 160 * 120,
71*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
72*4882a593Smuzhiyun .priv = 3},
73*4882a593Smuzhiyun {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
74*4882a593Smuzhiyun .bytesperline = 176,
75*4882a593Smuzhiyun .sizeimage = 176 * 144,
76*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
77*4882a593Smuzhiyun .priv = 2},
78*4882a593Smuzhiyun {320, 240, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
79*4882a593Smuzhiyun .bytesperline = 320,
80*4882a593Smuzhiyun .sizeimage = 320 * 240,
81*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
82*4882a593Smuzhiyun .priv = 1},
83*4882a593Smuzhiyun {352, 288, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
84*4882a593Smuzhiyun .bytesperline = 352,
85*4882a593Smuzhiyun .sizeimage = 352 * 288,
86*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
87*4882a593Smuzhiyun .priv = 0},
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /*
91*4882a593Smuzhiyun * Initialization data
92*4882a593Smuzhiyun * I'm not very sure how to split initialization from open data
93*4882a593Smuzhiyun * chunks. For now, we'll consider everything as initialization
94*4882a593Smuzhiyun */
95*4882a593Smuzhiyun /* Frame packet header offsets for the spca561 */
96*4882a593Smuzhiyun #define SPCA561_OFFSET_SNAP 1
97*4882a593Smuzhiyun #define SPCA561_OFFSET_TYPE 2
98*4882a593Smuzhiyun #define SPCA561_OFFSET_COMPRESS 3
99*4882a593Smuzhiyun #define SPCA561_OFFSET_FRAMSEQ 4
100*4882a593Smuzhiyun #define SPCA561_OFFSET_GPIO 5
101*4882a593Smuzhiyun #define SPCA561_OFFSET_USBBUFF 6
102*4882a593Smuzhiyun #define SPCA561_OFFSET_WIN2GRAVE 7
103*4882a593Smuzhiyun #define SPCA561_OFFSET_WIN2RAVE 8
104*4882a593Smuzhiyun #define SPCA561_OFFSET_WIN2BAVE 9
105*4882a593Smuzhiyun #define SPCA561_OFFSET_WIN2GBAVE 10
106*4882a593Smuzhiyun #define SPCA561_OFFSET_WIN1GRAVE 11
107*4882a593Smuzhiyun #define SPCA561_OFFSET_WIN1RAVE 12
108*4882a593Smuzhiyun #define SPCA561_OFFSET_WIN1BAVE 13
109*4882a593Smuzhiyun #define SPCA561_OFFSET_WIN1GBAVE 14
110*4882a593Smuzhiyun #define SPCA561_OFFSET_FREQ 15
111*4882a593Smuzhiyun #define SPCA561_OFFSET_VSYNC 16
112*4882a593Smuzhiyun #define SPCA561_INDEX_I2C_BASE 0x8800
113*4882a593Smuzhiyun #define SPCA561_SNAPBIT 0x20
114*4882a593Smuzhiyun #define SPCA561_SNAPCTRL 0x40
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun static const u16 rev72a_reset[][2] = {
117*4882a593Smuzhiyun {0x0000, 0x8114}, /* Software GPIO output data */
118*4882a593Smuzhiyun {0x0001, 0x8114}, /* Software GPIO output data */
119*4882a593Smuzhiyun {0x0000, 0x8112}, /* Some kind of reset */
120*4882a593Smuzhiyun {}
121*4882a593Smuzhiyun };
122*4882a593Smuzhiyun static const __u16 rev72a_init_data1[][2] = {
123*4882a593Smuzhiyun {0x0003, 0x8701}, /* PCLK clock delay adjustment */
124*4882a593Smuzhiyun {0x0001, 0x8703}, /* HSYNC from cmos inverted */
125*4882a593Smuzhiyun {0x0011, 0x8118}, /* Enable and conf sensor */
126*4882a593Smuzhiyun {0x0001, 0x8118}, /* Conf sensor */
127*4882a593Smuzhiyun {0x0092, 0x8804}, /* I know nothing about these */
128*4882a593Smuzhiyun {0x0010, 0x8802}, /* 0x88xx registers, so I won't */
129*4882a593Smuzhiyun {}
130*4882a593Smuzhiyun };
131*4882a593Smuzhiyun static const u16 rev72a_init_sensor1[][2] = {
132*4882a593Smuzhiyun {0x0001, 0x000d},
133*4882a593Smuzhiyun {0x0002, 0x0018},
134*4882a593Smuzhiyun {0x0004, 0x0165},
135*4882a593Smuzhiyun {0x0005, 0x0021},
136*4882a593Smuzhiyun {0x0007, 0x00aa},
137*4882a593Smuzhiyun {0x0020, 0x1504},
138*4882a593Smuzhiyun {0x0039, 0x0002},
139*4882a593Smuzhiyun {0x0035, 0x0010},
140*4882a593Smuzhiyun {0x0009, 0x1049},
141*4882a593Smuzhiyun {0x0028, 0x000b},
142*4882a593Smuzhiyun {0x003b, 0x000f},
143*4882a593Smuzhiyun {0x003c, 0x0000},
144*4882a593Smuzhiyun {}
145*4882a593Smuzhiyun };
146*4882a593Smuzhiyun static const __u16 rev72a_init_data2[][2] = {
147*4882a593Smuzhiyun {0x0018, 0x8601}, /* Pixel/line selection for color separation */
148*4882a593Smuzhiyun {0x0000, 0x8602}, /* Optical black level for user setting */
149*4882a593Smuzhiyun {0x0060, 0x8604}, /* Optical black horizontal offset */
150*4882a593Smuzhiyun {0x0002, 0x8605}, /* Optical black vertical offset */
151*4882a593Smuzhiyun {0x0000, 0x8603}, /* Non-automatic optical black level */
152*4882a593Smuzhiyun {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
153*4882a593Smuzhiyun {0x0000, 0x865f}, /* Vertical valid pixels window (x2) */
154*4882a593Smuzhiyun {0x00b0, 0x865d}, /* Horizontal valid pixels window (x2) */
155*4882a593Smuzhiyun {0x0090, 0x865e}, /* Vertical valid lines window (x2) */
156*4882a593Smuzhiyun {0x00e0, 0x8406}, /* Memory buffer threshold */
157*4882a593Smuzhiyun {0x0000, 0x8660}, /* Compensation memory stuff */
158*4882a593Smuzhiyun {0x0002, 0x8201}, /* Output address for r/w serial EEPROM */
159*4882a593Smuzhiyun {0x0008, 0x8200}, /* Clear valid bit for serial EEPROM */
160*4882a593Smuzhiyun {0x0001, 0x8200}, /* OprMode to be executed by hardware */
161*4882a593Smuzhiyun /* from ms-win */
162*4882a593Smuzhiyun {0x0000, 0x8611}, /* R offset for white balance */
163*4882a593Smuzhiyun {0x00fd, 0x8612}, /* Gr offset for white balance */
164*4882a593Smuzhiyun {0x0003, 0x8613}, /* B offset for white balance */
165*4882a593Smuzhiyun {0x0000, 0x8614}, /* Gb offset for white balance */
166*4882a593Smuzhiyun /* from ms-win */
167*4882a593Smuzhiyun {0x0035, 0x8651}, /* R gain for white balance */
168*4882a593Smuzhiyun {0x0040, 0x8652}, /* Gr gain for white balance */
169*4882a593Smuzhiyun {0x005f, 0x8653}, /* B gain for white balance */
170*4882a593Smuzhiyun {0x0040, 0x8654}, /* Gb gain for white balance */
171*4882a593Smuzhiyun {0x0002, 0x8502}, /* Maximum average bit rate stuff */
172*4882a593Smuzhiyun {0x0011, 0x8802},
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun {0x0087, 0x8700}, /* Set master clock (96Mhz????) */
175*4882a593Smuzhiyun {0x0081, 0x8702}, /* Master clock output enable */
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun {0x0000, 0x8500}, /* Set image type (352x288 no compression) */
178*4882a593Smuzhiyun /* Originally was 0x0010 (352x288 compression) */
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun {0x0002, 0x865b}, /* Horizontal offset for valid pixels */
181*4882a593Smuzhiyun {0x0003, 0x865c}, /* Vertical offset for valid lines */
182*4882a593Smuzhiyun {}
183*4882a593Smuzhiyun };
184*4882a593Smuzhiyun static const u16 rev72a_init_sensor2[][2] = {
185*4882a593Smuzhiyun {0x0003, 0x0121},
186*4882a593Smuzhiyun {0x0004, 0x0165},
187*4882a593Smuzhiyun {0x0005, 0x002f}, /* blanking control column */
188*4882a593Smuzhiyun {0x0006, 0x0000}, /* blanking mode row*/
189*4882a593Smuzhiyun {0x000a, 0x0002},
190*4882a593Smuzhiyun {0x0009, 0x1061}, /* setexposure times && pixel clock
191*4882a593Smuzhiyun * 0001 0 | 000 0110 0001 */
192*4882a593Smuzhiyun {0x0035, 0x0014},
193*4882a593Smuzhiyun {}
194*4882a593Smuzhiyun };
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun /******************** QC Express etch2 stuff ********************/
197*4882a593Smuzhiyun static const __u16 Pb100_1map8300[][2] = {
198*4882a593Smuzhiyun /* reg, value */
199*4882a593Smuzhiyun {0x8320, 0x3304},
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun {0x8303, 0x0125}, /* image area */
202*4882a593Smuzhiyun {0x8304, 0x0169},
203*4882a593Smuzhiyun {0x8328, 0x000b},
204*4882a593Smuzhiyun {0x833c, 0x0001}, /*fixme: win:07*/
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun {0x832f, 0x1904}, /*fixme: was 0419*/
207*4882a593Smuzhiyun {0x8307, 0x00aa},
208*4882a593Smuzhiyun {0x8301, 0x0003},
209*4882a593Smuzhiyun {0x8302, 0x000e},
210*4882a593Smuzhiyun {}
211*4882a593Smuzhiyun };
212*4882a593Smuzhiyun static const __u16 Pb100_2map8300[][2] = {
213*4882a593Smuzhiyun /* reg, value */
214*4882a593Smuzhiyun {0x8339, 0x0000},
215*4882a593Smuzhiyun {0x8307, 0x00aa},
216*4882a593Smuzhiyun {}
217*4882a593Smuzhiyun };
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun static const __u16 spca561_161rev12A_data1[][2] = {
220*4882a593Smuzhiyun {0x29, 0x8118}, /* Control register (various enable bits) */
221*4882a593Smuzhiyun {0x08, 0x8114}, /* GPIO: Led off */
222*4882a593Smuzhiyun {0x0e, 0x8112}, /* 0x0e stream off 0x3e stream on */
223*4882a593Smuzhiyun {0x00, 0x8102}, /* white balance - new */
224*4882a593Smuzhiyun {0x92, 0x8804},
225*4882a593Smuzhiyun {0x04, 0x8802}, /* windows uses 08 */
226*4882a593Smuzhiyun {}
227*4882a593Smuzhiyun };
228*4882a593Smuzhiyun static const __u16 spca561_161rev12A_data2[][2] = {
229*4882a593Smuzhiyun {0x21, 0x8118},
230*4882a593Smuzhiyun {0x10, 0x8500},
231*4882a593Smuzhiyun {0x07, 0x8601},
232*4882a593Smuzhiyun {0x07, 0x8602},
233*4882a593Smuzhiyun {0x04, 0x8501},
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun {0x07, 0x8201}, /* windows uses 02 */
236*4882a593Smuzhiyun {0x08, 0x8200},
237*4882a593Smuzhiyun {0x01, 0x8200},
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun {0x90, 0x8604},
240*4882a593Smuzhiyun {0x00, 0x8605},
241*4882a593Smuzhiyun {0xb0, 0x8603},
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun /* sensor gains */
244*4882a593Smuzhiyun {0x07, 0x8601}, /* white balance - new */
245*4882a593Smuzhiyun {0x07, 0x8602}, /* white balance - new */
246*4882a593Smuzhiyun {0x00, 0x8610}, /* *red */
247*4882a593Smuzhiyun {0x00, 0x8611}, /* 3f *green */
248*4882a593Smuzhiyun {0x00, 0x8612}, /* green *blue */
249*4882a593Smuzhiyun {0x00, 0x8613}, /* blue *green */
250*4882a593Smuzhiyun {0x43, 0x8614}, /* green *red - white balance - was 0x35 */
251*4882a593Smuzhiyun {0x40, 0x8615}, /* 40 *green - white balance - was 0x35 */
252*4882a593Smuzhiyun {0x71, 0x8616}, /* 7a *blue - white balance - was 0x35 */
253*4882a593Smuzhiyun {0x40, 0x8617}, /* 40 *green - white balance - was 0x35 */
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun {0x0c, 0x8620}, /* 0c */
256*4882a593Smuzhiyun {0xc8, 0x8631}, /* c8 */
257*4882a593Smuzhiyun {0xc8, 0x8634}, /* c8 */
258*4882a593Smuzhiyun {0x23, 0x8635}, /* 23 */
259*4882a593Smuzhiyun {0x1f, 0x8636}, /* 1f */
260*4882a593Smuzhiyun {0xdd, 0x8637}, /* dd */
261*4882a593Smuzhiyun {0xe1, 0x8638}, /* e1 */
262*4882a593Smuzhiyun {0x1d, 0x8639}, /* 1d */
263*4882a593Smuzhiyun {0x21, 0x863a}, /* 21 */
264*4882a593Smuzhiyun {0xe3, 0x863b}, /* e3 */
265*4882a593Smuzhiyun {0xdf, 0x863c}, /* df */
266*4882a593Smuzhiyun {0xf0, 0x8505},
267*4882a593Smuzhiyun {0x32, 0x850a},
268*4882a593Smuzhiyun /* {0x99, 0x8700}, * - white balance - new (removed) */
269*4882a593Smuzhiyun /* HDG we used to do this in stop0, making the init state and the state
270*4882a593Smuzhiyun after a start / stop different, so do this here instead. */
271*4882a593Smuzhiyun {0x29, 0x8118},
272*4882a593Smuzhiyun {}
273*4882a593Smuzhiyun };
274*4882a593Smuzhiyun
reg_w_val(struct gspca_dev * gspca_dev,__u16 index,__u8 value)275*4882a593Smuzhiyun static void reg_w_val(struct gspca_dev *gspca_dev, __u16 index, __u8 value)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun int ret;
278*4882a593Smuzhiyun struct usb_device *dev = gspca_dev->dev;
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
281*4882a593Smuzhiyun 0, /* request */
282*4882a593Smuzhiyun USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
283*4882a593Smuzhiyun value, index, NULL, 0, 500);
284*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_USBO, "reg write: 0x%02x:0x%02x\n",
285*4882a593Smuzhiyun index, value);
286*4882a593Smuzhiyun if (ret < 0)
287*4882a593Smuzhiyun pr_err("reg write: error %d\n", ret);
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
write_vector(struct gspca_dev * gspca_dev,const __u16 data[][2])290*4882a593Smuzhiyun static void write_vector(struct gspca_dev *gspca_dev,
291*4882a593Smuzhiyun const __u16 data[][2])
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun int i;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun i = 0;
296*4882a593Smuzhiyun while (data[i][1] != 0) {
297*4882a593Smuzhiyun reg_w_val(gspca_dev, data[i][1], data[i][0]);
298*4882a593Smuzhiyun i++;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /* read 'len' bytes to gspca_dev->usb_buf */
reg_r(struct gspca_dev * gspca_dev,__u16 index,__u16 length)303*4882a593Smuzhiyun static void reg_r(struct gspca_dev *gspca_dev,
304*4882a593Smuzhiyun __u16 index, __u16 length)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun usb_control_msg(gspca_dev->dev,
307*4882a593Smuzhiyun usb_rcvctrlpipe(gspca_dev->dev, 0),
308*4882a593Smuzhiyun 0, /* request */
309*4882a593Smuzhiyun USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
310*4882a593Smuzhiyun 0, /* value */
311*4882a593Smuzhiyun index, gspca_dev->usb_buf, length, 500);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun /* write 'len' bytes from gspca_dev->usb_buf */
reg_w_buf(struct gspca_dev * gspca_dev,__u16 index,__u16 len)315*4882a593Smuzhiyun static void reg_w_buf(struct gspca_dev *gspca_dev,
316*4882a593Smuzhiyun __u16 index, __u16 len)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun usb_control_msg(gspca_dev->dev,
319*4882a593Smuzhiyun usb_sndctrlpipe(gspca_dev->dev, 0),
320*4882a593Smuzhiyun 0, /* request */
321*4882a593Smuzhiyun USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
322*4882a593Smuzhiyun 0, /* value */
323*4882a593Smuzhiyun index, gspca_dev->usb_buf, len, 500);
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
i2c_write(struct gspca_dev * gspca_dev,__u16 value,__u16 reg)326*4882a593Smuzhiyun static void i2c_write(struct gspca_dev *gspca_dev, __u16 value, __u16 reg)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun int retry = 60;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8801, reg);
331*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8805, value);
332*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8800, value >> 8);
333*4882a593Smuzhiyun do {
334*4882a593Smuzhiyun reg_r(gspca_dev, 0x8803, 1);
335*4882a593Smuzhiyun if (!gspca_dev->usb_buf[0])
336*4882a593Smuzhiyun return;
337*4882a593Smuzhiyun msleep(10);
338*4882a593Smuzhiyun } while (--retry);
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun
i2c_read(struct gspca_dev * gspca_dev,__u16 reg,__u8 mode)341*4882a593Smuzhiyun static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun int retry = 60;
344*4882a593Smuzhiyun __u8 value;
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8804, 0x92);
347*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8801, reg);
348*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8802, mode | 0x01);
349*4882a593Smuzhiyun do {
350*4882a593Smuzhiyun reg_r(gspca_dev, 0x8803, 1);
351*4882a593Smuzhiyun if (!gspca_dev->usb_buf[0]) {
352*4882a593Smuzhiyun reg_r(gspca_dev, 0x8800, 1);
353*4882a593Smuzhiyun value = gspca_dev->usb_buf[0];
354*4882a593Smuzhiyun reg_r(gspca_dev, 0x8805, 1);
355*4882a593Smuzhiyun return ((int) value << 8) | gspca_dev->usb_buf[0];
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun msleep(10);
358*4882a593Smuzhiyun } while (--retry);
359*4882a593Smuzhiyun return -1;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
sensor_mapwrite(struct gspca_dev * gspca_dev,const __u16 (* sensormap)[2])362*4882a593Smuzhiyun static void sensor_mapwrite(struct gspca_dev *gspca_dev,
363*4882a593Smuzhiyun const __u16 (*sensormap)[2])
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun while ((*sensormap)[0]) {
366*4882a593Smuzhiyun gspca_dev->usb_buf[0] = (*sensormap)[1];
367*4882a593Smuzhiyun gspca_dev->usb_buf[1] = (*sensormap)[1] >> 8;
368*4882a593Smuzhiyun reg_w_buf(gspca_dev, (*sensormap)[0], 2);
369*4882a593Smuzhiyun sensormap++;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun
write_sensor_72a(struct gspca_dev * gspca_dev,const __u16 (* sensor)[2])373*4882a593Smuzhiyun static void write_sensor_72a(struct gspca_dev *gspca_dev,
374*4882a593Smuzhiyun const __u16 (*sensor)[2])
375*4882a593Smuzhiyun {
376*4882a593Smuzhiyun while ((*sensor)[0]) {
377*4882a593Smuzhiyun i2c_write(gspca_dev, (*sensor)[1], (*sensor)[0]);
378*4882a593Smuzhiyun sensor++;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
init_161rev12A(struct gspca_dev * gspca_dev)382*4882a593Smuzhiyun static void init_161rev12A(struct gspca_dev *gspca_dev)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun write_vector(gspca_dev, spca561_161rev12A_data1);
385*4882a593Smuzhiyun sensor_mapwrite(gspca_dev, Pb100_1map8300);
386*4882a593Smuzhiyun /*fixme: should be in sd_start*/
387*4882a593Smuzhiyun write_vector(gspca_dev, spca561_161rev12A_data2);
388*4882a593Smuzhiyun sensor_mapwrite(gspca_dev, Pb100_2map8300);
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun /* this function is called at probe time */
sd_config(struct gspca_dev * gspca_dev,const struct usb_device_id * id)392*4882a593Smuzhiyun static int sd_config(struct gspca_dev *gspca_dev,
393*4882a593Smuzhiyun const struct usb_device_id *id)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
396*4882a593Smuzhiyun struct cam *cam;
397*4882a593Smuzhiyun __u16 vendor, product;
398*4882a593Smuzhiyun __u8 data1, data2;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun /* Read frm global register the USB product and vendor IDs, just to
401*4882a593Smuzhiyun * prove that we can communicate with the device. This works, which
402*4882a593Smuzhiyun * confirms at we are communicating properly and that the device
403*4882a593Smuzhiyun * is a 561. */
404*4882a593Smuzhiyun reg_r(gspca_dev, 0x8104, 1);
405*4882a593Smuzhiyun data1 = gspca_dev->usb_buf[0];
406*4882a593Smuzhiyun reg_r(gspca_dev, 0x8105, 1);
407*4882a593Smuzhiyun data2 = gspca_dev->usb_buf[0];
408*4882a593Smuzhiyun vendor = (data2 << 8) | data1;
409*4882a593Smuzhiyun reg_r(gspca_dev, 0x8106, 1);
410*4882a593Smuzhiyun data1 = gspca_dev->usb_buf[0];
411*4882a593Smuzhiyun reg_r(gspca_dev, 0x8107, 1);
412*4882a593Smuzhiyun data2 = gspca_dev->usb_buf[0];
413*4882a593Smuzhiyun product = (data2 << 8) | data1;
414*4882a593Smuzhiyun if (vendor != id->idVendor || product != id->idProduct) {
415*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_PROBE, "Bad vendor / product from device\n");
416*4882a593Smuzhiyun return -EINVAL;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun cam = &gspca_dev->cam;
420*4882a593Smuzhiyun cam->needs_full_bandwidth = 1;
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun sd->chip_revision = id->driver_info;
423*4882a593Smuzhiyun if (sd->chip_revision == Rev012A) {
424*4882a593Smuzhiyun cam->cam_mode = sif_012a_mode;
425*4882a593Smuzhiyun cam->nmodes = ARRAY_SIZE(sif_012a_mode);
426*4882a593Smuzhiyun } else {
427*4882a593Smuzhiyun cam->cam_mode = sif_072a_mode;
428*4882a593Smuzhiyun cam->nmodes = ARRAY_SIZE(sif_072a_mode);
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun sd->expo12a = EXPO12A_DEF;
431*4882a593Smuzhiyun return 0;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun /* this function is called at probe and resume time */
sd_init_12a(struct gspca_dev * gspca_dev)435*4882a593Smuzhiyun static int sd_init_12a(struct gspca_dev *gspca_dev)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_STREAM, "Chip revision: 012a\n");
438*4882a593Smuzhiyun init_161rev12A(gspca_dev);
439*4882a593Smuzhiyun return 0;
440*4882a593Smuzhiyun }
sd_init_72a(struct gspca_dev * gspca_dev)441*4882a593Smuzhiyun static int sd_init_72a(struct gspca_dev *gspca_dev)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_STREAM, "Chip revision: 072a\n");
444*4882a593Smuzhiyun write_vector(gspca_dev, rev72a_reset);
445*4882a593Smuzhiyun msleep(200);
446*4882a593Smuzhiyun write_vector(gspca_dev, rev72a_init_data1);
447*4882a593Smuzhiyun write_sensor_72a(gspca_dev, rev72a_init_sensor1);
448*4882a593Smuzhiyun write_vector(gspca_dev, rev72a_init_data2);
449*4882a593Smuzhiyun write_sensor_72a(gspca_dev, rev72a_init_sensor2);
450*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8112, 0x30);
451*4882a593Smuzhiyun return 0;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun
setbrightness(struct gspca_dev * gspca_dev,s32 val)454*4882a593Smuzhiyun static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
457*4882a593Smuzhiyun __u16 reg;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun if (sd->chip_revision == Rev012A)
460*4882a593Smuzhiyun reg = 0x8610;
461*4882a593Smuzhiyun else
462*4882a593Smuzhiyun reg = 0x8611;
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun reg_w_val(gspca_dev, reg + 0, val); /* R */
465*4882a593Smuzhiyun reg_w_val(gspca_dev, reg + 1, val); /* Gr */
466*4882a593Smuzhiyun reg_w_val(gspca_dev, reg + 2, val); /* B */
467*4882a593Smuzhiyun reg_w_val(gspca_dev, reg + 3, val); /* Gb */
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun
setwhite(struct gspca_dev * gspca_dev,s32 white,s32 contrast)470*4882a593Smuzhiyun static void setwhite(struct gspca_dev *gspca_dev, s32 white, s32 contrast)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
473*4882a593Smuzhiyun __u8 blue, red;
474*4882a593Smuzhiyun __u16 reg;
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun /* try to emulate MS-win as possible */
477*4882a593Smuzhiyun red = 0x20 + white * 3 / 8;
478*4882a593Smuzhiyun blue = 0x90 - white * 5 / 8;
479*4882a593Smuzhiyun if (sd->chip_revision == Rev012A) {
480*4882a593Smuzhiyun reg = 0x8614;
481*4882a593Smuzhiyun } else {
482*4882a593Smuzhiyun reg = 0x8651;
483*4882a593Smuzhiyun red += contrast - 0x20;
484*4882a593Smuzhiyun blue += contrast - 0x20;
485*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8652, contrast + 0x20); /* Gr */
486*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8654, contrast + 0x20); /* Gb */
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun reg_w_val(gspca_dev, reg, red);
489*4882a593Smuzhiyun reg_w_val(gspca_dev, reg + 2, blue);
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun /* rev 12a only */
setexposure(struct gspca_dev * gspca_dev,s32 val)493*4882a593Smuzhiyun static void setexposure(struct gspca_dev *gspca_dev, s32 val)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun int i, expo = 0;
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun /* Register 0x8309 controls exposure for the spca561,
498*4882a593Smuzhiyun the basic exposure setting goes from 1-2047, where 1 is completely
499*4882a593Smuzhiyun dark and 2047 is very bright. It not only influences exposure but
500*4882a593Smuzhiyun also the framerate (to allow for longer exposure) from 1 - 300 it
501*4882a593Smuzhiyun only raises the exposure time then from 300 - 600 it halves the
502*4882a593Smuzhiyun framerate to be able to further raise the exposure time and for every
503*4882a593Smuzhiyun 300 more it halves the framerate again. This allows for a maximum
504*4882a593Smuzhiyun exposure time of circa 0.2 - 0.25 seconds (30 / (2000/3000) fps).
505*4882a593Smuzhiyun Sometimes this is not enough, the 1-2047 uses bits 0-10, bits 11-12
506*4882a593Smuzhiyun configure a divider for the base framerate which us used at the
507*4882a593Smuzhiyun exposure setting of 1-300. These bits configure the base framerate
508*4882a593Smuzhiyun according to the following formula: fps = 60 / (value + 2) */
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun /* We choose to use the high bits setting the fixed framerate divisor
511*4882a593Smuzhiyun asap, as setting high basic exposure setting without the fixed
512*4882a593Smuzhiyun divider in combination with high gains makes the cam stop */
513*4882a593Smuzhiyun int table[] = { 0, 450, 550, 625, EXPOSURE_MAX };
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(table) - 1; i++) {
516*4882a593Smuzhiyun if (val <= table[i + 1]) {
517*4882a593Smuzhiyun expo = val - table[i];
518*4882a593Smuzhiyun if (i)
519*4882a593Smuzhiyun expo += 300;
520*4882a593Smuzhiyun expo |= i << 11;
521*4882a593Smuzhiyun break;
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun gspca_dev->usb_buf[0] = expo;
526*4882a593Smuzhiyun gspca_dev->usb_buf[1] = expo >> 8;
527*4882a593Smuzhiyun reg_w_buf(gspca_dev, 0x8309, 2);
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /* rev 12a only */
setgain(struct gspca_dev * gspca_dev,s32 val)531*4882a593Smuzhiyun static void setgain(struct gspca_dev *gspca_dev, s32 val)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun /* gain reg low 6 bits 0-63 gain, bit 6 and 7, both double the
534*4882a593Smuzhiyun sensitivity when set, so 31 + one of them set == 63, and 15
535*4882a593Smuzhiyun with both of them set == 63 */
536*4882a593Smuzhiyun if (val < 64)
537*4882a593Smuzhiyun gspca_dev->usb_buf[0] = val;
538*4882a593Smuzhiyun else if (val < 128)
539*4882a593Smuzhiyun gspca_dev->usb_buf[0] = (val / 2) | 0x40;
540*4882a593Smuzhiyun else
541*4882a593Smuzhiyun gspca_dev->usb_buf[0] = (val / 4) | 0xc0;
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun gspca_dev->usb_buf[1] = 0;
544*4882a593Smuzhiyun reg_w_buf(gspca_dev, 0x8335, 2);
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
setautogain(struct gspca_dev * gspca_dev,s32 val)547*4882a593Smuzhiyun static void setautogain(struct gspca_dev *gspca_dev, s32 val)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun if (val)
552*4882a593Smuzhiyun sd->ag_cnt = AG_CNT_START;
553*4882a593Smuzhiyun else
554*4882a593Smuzhiyun sd->ag_cnt = -1;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun
sd_start_12a(struct gspca_dev * gspca_dev)557*4882a593Smuzhiyun static int sd_start_12a(struct gspca_dev *gspca_dev)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun int mode;
560*4882a593Smuzhiyun static const __u8 Reg8391[8] =
561*4882a593Smuzhiyun {0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00};
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
564*4882a593Smuzhiyun if (mode <= 1) {
565*4882a593Smuzhiyun /* Use compression on 320x240 and above */
566*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8500, 0x10 | mode);
567*4882a593Smuzhiyun } else {
568*4882a593Smuzhiyun /* I couldn't get the compression to work below 320x240
569*4882a593Smuzhiyun * Fortunately at these resolutions the bandwidth
570*4882a593Smuzhiyun * is sufficient to push raw frames at ~20fps */
571*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8500, mode);
572*4882a593Smuzhiyun } /* -- qq@kuku.eu.org */
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun gspca_dev->usb_buf[0] = 0xaa;
575*4882a593Smuzhiyun gspca_dev->usb_buf[1] = 0x00;
576*4882a593Smuzhiyun reg_w_buf(gspca_dev, 0x8307, 2);
577*4882a593Smuzhiyun /* clock - lower 0x8X values lead to fps > 30 */
578*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8700, 0x8a);
579*4882a593Smuzhiyun /* 0x8f 0x85 0x27 clock */
580*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8112, 0x1e | 0x20);
581*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x850b, 0x03);
582*4882a593Smuzhiyun memcpy(gspca_dev->usb_buf, Reg8391, 8);
583*4882a593Smuzhiyun reg_w_buf(gspca_dev, 0x8391, 8);
584*4882a593Smuzhiyun reg_w_buf(gspca_dev, 0x8390, 8);
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun /* Led ON (bit 3 -> 0 */
587*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8114, 0x00);
588*4882a593Smuzhiyun return 0;
589*4882a593Smuzhiyun }
sd_start_72a(struct gspca_dev * gspca_dev)590*4882a593Smuzhiyun static int sd_start_72a(struct gspca_dev *gspca_dev)
591*4882a593Smuzhiyun {
592*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
593*4882a593Smuzhiyun int Clck;
594*4882a593Smuzhiyun int mode;
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun write_vector(gspca_dev, rev72a_reset);
597*4882a593Smuzhiyun msleep(200);
598*4882a593Smuzhiyun write_vector(gspca_dev, rev72a_init_data1);
599*4882a593Smuzhiyun write_sensor_72a(gspca_dev, rev72a_init_sensor1);
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
602*4882a593Smuzhiyun switch (mode) {
603*4882a593Smuzhiyun default:
604*4882a593Smuzhiyun case 0:
605*4882a593Smuzhiyun Clck = 0x27; /* ms-win 0x87 */
606*4882a593Smuzhiyun break;
607*4882a593Smuzhiyun case 1:
608*4882a593Smuzhiyun Clck = 0x25;
609*4882a593Smuzhiyun break;
610*4882a593Smuzhiyun case 2:
611*4882a593Smuzhiyun Clck = 0x22;
612*4882a593Smuzhiyun break;
613*4882a593Smuzhiyun case 3:
614*4882a593Smuzhiyun Clck = 0x21;
615*4882a593Smuzhiyun break;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8700, Clck); /* 0x27 clock */
618*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8702, 0x81);
619*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8500, mode); /* mode */
620*4882a593Smuzhiyun write_sensor_72a(gspca_dev, rev72a_init_sensor2);
621*4882a593Smuzhiyun setwhite(gspca_dev, v4l2_ctrl_g_ctrl(sd->hue),
622*4882a593Smuzhiyun v4l2_ctrl_g_ctrl(sd->contrast));
623*4882a593Smuzhiyun /* setbrightness(gspca_dev); * fixme: bad values */
624*4882a593Smuzhiyun setautogain(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain));
625*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8112, 0x10 | 0x20);
626*4882a593Smuzhiyun return 0;
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun
sd_stopN(struct gspca_dev * gspca_dev)629*4882a593Smuzhiyun static void sd_stopN(struct gspca_dev *gspca_dev)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun if (sd->chip_revision == Rev012A) {
634*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8112, 0x0e);
635*4882a593Smuzhiyun /* Led Off (bit 3 -> 1 */
636*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8114, 0x08);
637*4882a593Smuzhiyun } else {
638*4882a593Smuzhiyun reg_w_val(gspca_dev, 0x8112, 0x20);
639*4882a593Smuzhiyun /* reg_w_val(gspca_dev, 0x8102, 0x00); ?? */
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun
do_autogain(struct gspca_dev * gspca_dev)643*4882a593Smuzhiyun static void do_autogain(struct gspca_dev *gspca_dev)
644*4882a593Smuzhiyun {
645*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
646*4882a593Smuzhiyun int expotimes;
647*4882a593Smuzhiyun int pixelclk;
648*4882a593Smuzhiyun int gainG;
649*4882a593Smuzhiyun __u8 R, Gr, Gb, B;
650*4882a593Smuzhiyun int y;
651*4882a593Smuzhiyun __u8 luma_mean = 110;
652*4882a593Smuzhiyun __u8 luma_delta = 20;
653*4882a593Smuzhiyun __u8 spring = 4;
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun if (sd->ag_cnt < 0)
656*4882a593Smuzhiyun return;
657*4882a593Smuzhiyun if (--sd->ag_cnt >= 0)
658*4882a593Smuzhiyun return;
659*4882a593Smuzhiyun sd->ag_cnt = AG_CNT_START;
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun switch (sd->chip_revision) {
662*4882a593Smuzhiyun case Rev072A:
663*4882a593Smuzhiyun reg_r(gspca_dev, 0x8621, 1);
664*4882a593Smuzhiyun Gr = gspca_dev->usb_buf[0];
665*4882a593Smuzhiyun reg_r(gspca_dev, 0x8622, 1);
666*4882a593Smuzhiyun R = gspca_dev->usb_buf[0];
667*4882a593Smuzhiyun reg_r(gspca_dev, 0x8623, 1);
668*4882a593Smuzhiyun B = gspca_dev->usb_buf[0];
669*4882a593Smuzhiyun reg_r(gspca_dev, 0x8624, 1);
670*4882a593Smuzhiyun Gb = gspca_dev->usb_buf[0];
671*4882a593Smuzhiyun y = (77 * R + 75 * (Gr + Gb) + 29 * B) >> 8;
672*4882a593Smuzhiyun /* u= (128*B-(43*(Gr+Gb+R))) >> 8; */
673*4882a593Smuzhiyun /* v= (128*R-(53*(Gr+Gb))-21*B) >> 8; */
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun if (y < luma_mean - luma_delta ||
676*4882a593Smuzhiyun y > luma_mean + luma_delta) {
677*4882a593Smuzhiyun expotimes = i2c_read(gspca_dev, 0x09, 0x10);
678*4882a593Smuzhiyun pixelclk = 0x0800;
679*4882a593Smuzhiyun expotimes = expotimes & 0x07ff;
680*4882a593Smuzhiyun gainG = i2c_read(gspca_dev, 0x35, 0x10);
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun expotimes += (luma_mean - y) >> spring;
683*4882a593Smuzhiyun gainG += (luma_mean - y) / 50;
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun if (gainG > 0x3f)
686*4882a593Smuzhiyun gainG = 0x3f;
687*4882a593Smuzhiyun else if (gainG < 3)
688*4882a593Smuzhiyun gainG = 3;
689*4882a593Smuzhiyun i2c_write(gspca_dev, gainG, 0x35);
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun if (expotimes > 0x0256)
692*4882a593Smuzhiyun expotimes = 0x0256;
693*4882a593Smuzhiyun else if (expotimes < 3)
694*4882a593Smuzhiyun expotimes = 3;
695*4882a593Smuzhiyun i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun break;
698*4882a593Smuzhiyun }
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun
sd_pkt_scan(struct gspca_dev * gspca_dev,u8 * data,int len)701*4882a593Smuzhiyun static void sd_pkt_scan(struct gspca_dev *gspca_dev,
702*4882a593Smuzhiyun u8 *data, /* isoc packet */
703*4882a593Smuzhiyun int len) /* iso packet length */
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun len--;
708*4882a593Smuzhiyun switch (*data++) { /* sequence number */
709*4882a593Smuzhiyun case 0: /* start of frame */
710*4882a593Smuzhiyun gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun /* This should never happen */
713*4882a593Smuzhiyun if (len < 2) {
714*4882a593Smuzhiyun gspca_err(gspca_dev, "Short SOF packet, ignoring\n\n\n\n\n");
715*4882a593Smuzhiyun gspca_dev->last_packet_type = DISCARD_PACKET;
716*4882a593Smuzhiyun return;
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_INPUT)
720*4882a593Smuzhiyun if (data[0] & 0x20) {
721*4882a593Smuzhiyun input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
722*4882a593Smuzhiyun input_sync(gspca_dev->input_dev);
723*4882a593Smuzhiyun input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
724*4882a593Smuzhiyun input_sync(gspca_dev->input_dev);
725*4882a593Smuzhiyun }
726*4882a593Smuzhiyun #endif
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun if (data[1] & 0x10) {
729*4882a593Smuzhiyun /* compressed bayer */
730*4882a593Smuzhiyun gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
731*4882a593Smuzhiyun } else {
732*4882a593Smuzhiyun /* raw bayer (with a header, which we skip) */
733*4882a593Smuzhiyun if (sd->chip_revision == Rev012A) {
734*4882a593Smuzhiyun data += 20;
735*4882a593Smuzhiyun len -= 20;
736*4882a593Smuzhiyun } else {
737*4882a593Smuzhiyun data += 16;
738*4882a593Smuzhiyun len -= 16;
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun return;
743*4882a593Smuzhiyun case 0xff: /* drop (empty mpackets) */
744*4882a593Smuzhiyun return;
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun
sd_s_ctrl(struct v4l2_ctrl * ctrl)749*4882a593Smuzhiyun static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
750*4882a593Smuzhiyun {
751*4882a593Smuzhiyun struct gspca_dev *gspca_dev =
752*4882a593Smuzhiyun container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
753*4882a593Smuzhiyun struct sd *sd = (struct sd *)gspca_dev;
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun gspca_dev->usb_err = 0;
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun if (!gspca_dev->streaming)
758*4882a593Smuzhiyun return 0;
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun switch (ctrl->id) {
761*4882a593Smuzhiyun case V4L2_CID_BRIGHTNESS:
762*4882a593Smuzhiyun setbrightness(gspca_dev, ctrl->val);
763*4882a593Smuzhiyun break;
764*4882a593Smuzhiyun case V4L2_CID_CONTRAST:
765*4882a593Smuzhiyun /* hue/contrast control cluster for 72a */
766*4882a593Smuzhiyun setwhite(gspca_dev, sd->hue->val, ctrl->val);
767*4882a593Smuzhiyun break;
768*4882a593Smuzhiyun case V4L2_CID_HUE:
769*4882a593Smuzhiyun /* just plain hue control for 12a */
770*4882a593Smuzhiyun setwhite(gspca_dev, ctrl->val, 0);
771*4882a593Smuzhiyun break;
772*4882a593Smuzhiyun case V4L2_CID_EXPOSURE:
773*4882a593Smuzhiyun setexposure(gspca_dev, ctrl->val);
774*4882a593Smuzhiyun break;
775*4882a593Smuzhiyun case V4L2_CID_GAIN:
776*4882a593Smuzhiyun setgain(gspca_dev, ctrl->val);
777*4882a593Smuzhiyun break;
778*4882a593Smuzhiyun case V4L2_CID_AUTOGAIN:
779*4882a593Smuzhiyun setautogain(gspca_dev, ctrl->val);
780*4882a593Smuzhiyun break;
781*4882a593Smuzhiyun }
782*4882a593Smuzhiyun return gspca_dev->usb_err;
783*4882a593Smuzhiyun }
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun static const struct v4l2_ctrl_ops sd_ctrl_ops = {
786*4882a593Smuzhiyun .s_ctrl = sd_s_ctrl,
787*4882a593Smuzhiyun };
788*4882a593Smuzhiyun
sd_init_controls_12a(struct gspca_dev * gspca_dev)789*4882a593Smuzhiyun static int sd_init_controls_12a(struct gspca_dev *gspca_dev)
790*4882a593Smuzhiyun {
791*4882a593Smuzhiyun struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
792*4882a593Smuzhiyun
793*4882a593Smuzhiyun gspca_dev->vdev.ctrl_handler = hdl;
794*4882a593Smuzhiyun v4l2_ctrl_handler_init(hdl, 3);
795*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
796*4882a593Smuzhiyun V4L2_CID_HUE, 1, 0x7f, 1, 0x40);
797*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
798*4882a593Smuzhiyun V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
799*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
800*4882a593Smuzhiyun V4L2_CID_EXPOSURE, 1, EXPOSURE_MAX, 1, 700);
801*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
802*4882a593Smuzhiyun V4L2_CID_GAIN, 0, 255, 1, 63);
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun if (hdl->error) {
805*4882a593Smuzhiyun pr_err("Could not initialize controls\n");
806*4882a593Smuzhiyun return hdl->error;
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun return 0;
809*4882a593Smuzhiyun }
810*4882a593Smuzhiyun
sd_init_controls_72a(struct gspca_dev * gspca_dev)811*4882a593Smuzhiyun static int sd_init_controls_72a(struct gspca_dev *gspca_dev)
812*4882a593Smuzhiyun {
813*4882a593Smuzhiyun struct sd *sd = (struct sd *)gspca_dev;
814*4882a593Smuzhiyun struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
815*4882a593Smuzhiyun
816*4882a593Smuzhiyun gspca_dev->vdev.ctrl_handler = hdl;
817*4882a593Smuzhiyun v4l2_ctrl_handler_init(hdl, 4);
818*4882a593Smuzhiyun sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
819*4882a593Smuzhiyun V4L2_CID_CONTRAST, 0, 0x3f, 1, 0x20);
820*4882a593Smuzhiyun sd->hue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
821*4882a593Smuzhiyun V4L2_CID_HUE, 1, 0x7f, 1, 0x40);
822*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
823*4882a593Smuzhiyun V4L2_CID_BRIGHTNESS, 0, 0x3f, 1, 0x20);
824*4882a593Smuzhiyun sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
825*4882a593Smuzhiyun V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun if (hdl->error) {
828*4882a593Smuzhiyun pr_err("Could not initialize controls\n");
829*4882a593Smuzhiyun return hdl->error;
830*4882a593Smuzhiyun }
831*4882a593Smuzhiyun v4l2_ctrl_cluster(2, &sd->contrast);
832*4882a593Smuzhiyun return 0;
833*4882a593Smuzhiyun }
834*4882a593Smuzhiyun
835*4882a593Smuzhiyun /* sub-driver description */
836*4882a593Smuzhiyun static const struct sd_desc sd_desc_12a = {
837*4882a593Smuzhiyun .name = MODULE_NAME,
838*4882a593Smuzhiyun .init_controls = sd_init_controls_12a,
839*4882a593Smuzhiyun .config = sd_config,
840*4882a593Smuzhiyun .init = sd_init_12a,
841*4882a593Smuzhiyun .start = sd_start_12a,
842*4882a593Smuzhiyun .stopN = sd_stopN,
843*4882a593Smuzhiyun .pkt_scan = sd_pkt_scan,
844*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_INPUT)
845*4882a593Smuzhiyun .other_input = 1,
846*4882a593Smuzhiyun #endif
847*4882a593Smuzhiyun };
848*4882a593Smuzhiyun static const struct sd_desc sd_desc_72a = {
849*4882a593Smuzhiyun .name = MODULE_NAME,
850*4882a593Smuzhiyun .init_controls = sd_init_controls_72a,
851*4882a593Smuzhiyun .config = sd_config,
852*4882a593Smuzhiyun .init = sd_init_72a,
853*4882a593Smuzhiyun .start = sd_start_72a,
854*4882a593Smuzhiyun .stopN = sd_stopN,
855*4882a593Smuzhiyun .pkt_scan = sd_pkt_scan,
856*4882a593Smuzhiyun .dq_callback = do_autogain,
857*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_INPUT)
858*4882a593Smuzhiyun .other_input = 1,
859*4882a593Smuzhiyun #endif
860*4882a593Smuzhiyun };
861*4882a593Smuzhiyun static const struct sd_desc *sd_desc[2] = {
862*4882a593Smuzhiyun &sd_desc_12a,
863*4882a593Smuzhiyun &sd_desc_72a
864*4882a593Smuzhiyun };
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun /* -- module initialisation -- */
867*4882a593Smuzhiyun static const struct usb_device_id device_table[] = {
868*4882a593Smuzhiyun {USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A},
869*4882a593Smuzhiyun {USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A},
870*4882a593Smuzhiyun {USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A},
871*4882a593Smuzhiyun {USB_DEVICE(0x0461, 0x0815), .driver_info = Rev072A},
872*4882a593Smuzhiyun {USB_DEVICE(0x046d, 0x0928), .driver_info = Rev012A},
873*4882a593Smuzhiyun {USB_DEVICE(0x046d, 0x0929), .driver_info = Rev012A},
874*4882a593Smuzhiyun {USB_DEVICE(0x046d, 0x092a), .driver_info = Rev012A},
875*4882a593Smuzhiyun {USB_DEVICE(0x046d, 0x092b), .driver_info = Rev012A},
876*4882a593Smuzhiyun {USB_DEVICE(0x046d, 0x092c), .driver_info = Rev012A},
877*4882a593Smuzhiyun {USB_DEVICE(0x046d, 0x092d), .driver_info = Rev012A},
878*4882a593Smuzhiyun {USB_DEVICE(0x046d, 0x092e), .driver_info = Rev012A},
879*4882a593Smuzhiyun {USB_DEVICE(0x046d, 0x092f), .driver_info = Rev012A},
880*4882a593Smuzhiyun {USB_DEVICE(0x04fc, 0x0561), .driver_info = Rev072A},
881*4882a593Smuzhiyun {USB_DEVICE(0x060b, 0xa001), .driver_info = Rev072A},
882*4882a593Smuzhiyun {USB_DEVICE(0x10fd, 0x7e50), .driver_info = Rev072A},
883*4882a593Smuzhiyun {USB_DEVICE(0xabcd, 0xcdee), .driver_info = Rev072A},
884*4882a593Smuzhiyun {}
885*4882a593Smuzhiyun };
886*4882a593Smuzhiyun
887*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, device_table);
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun /* -- device connect -- */
sd_probe(struct usb_interface * intf,const struct usb_device_id * id)890*4882a593Smuzhiyun static int sd_probe(struct usb_interface *intf,
891*4882a593Smuzhiyun const struct usb_device_id *id)
892*4882a593Smuzhiyun {
893*4882a593Smuzhiyun return gspca_dev_probe(intf, id,
894*4882a593Smuzhiyun sd_desc[id->driver_info],
895*4882a593Smuzhiyun sizeof(struct sd),
896*4882a593Smuzhiyun THIS_MODULE);
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun static struct usb_driver sd_driver = {
900*4882a593Smuzhiyun .name = MODULE_NAME,
901*4882a593Smuzhiyun .id_table = device_table,
902*4882a593Smuzhiyun .probe = sd_probe,
903*4882a593Smuzhiyun .disconnect = gspca_disconnect,
904*4882a593Smuzhiyun #ifdef CONFIG_PM
905*4882a593Smuzhiyun .suspend = gspca_suspend,
906*4882a593Smuzhiyun .resume = gspca_resume,
907*4882a593Smuzhiyun .reset_resume = gspca_resume,
908*4882a593Smuzhiyun #endif
909*4882a593Smuzhiyun };
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun module_usb_driver(sd_driver);
912