xref: /OK3568_Linux_fs/kernel/drivers/media/usb/gspca/spca561.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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