xref: /OK3568_Linux_fs/kernel/drivers/media/usb/gspca/spca505.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * SPCA505 chip based cameras initialization data
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * V4L2 by Jean-Francis Moine <http://moinejf.free.fr>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #define MODULE_NAME "spca505"
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include "gspca.h"
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
15*4882a593Smuzhiyun MODULE_DESCRIPTION("GSPCA/SPCA505 USB Camera Driver");
16*4882a593Smuzhiyun MODULE_LICENSE("GPL");
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun /* specific webcam descriptor */
19*4882a593Smuzhiyun struct sd {
20*4882a593Smuzhiyun 	struct gspca_dev gspca_dev;		/* !! must be the first item */
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun 	u8 subtype;
23*4882a593Smuzhiyun #define IntelPCCameraPro 0
24*4882a593Smuzhiyun #define Nxultra 1
25*4882a593Smuzhiyun };
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun static const struct v4l2_pix_format vga_mode[] = {
28*4882a593Smuzhiyun 	{160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
29*4882a593Smuzhiyun 		.bytesperline = 160,
30*4882a593Smuzhiyun 		.sizeimage = 160 * 120 * 3 / 2,
31*4882a593Smuzhiyun 		.colorspace = V4L2_COLORSPACE_SRGB,
32*4882a593Smuzhiyun 		.priv = 4},
33*4882a593Smuzhiyun 	{176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
34*4882a593Smuzhiyun 		.bytesperline = 176,
35*4882a593Smuzhiyun 		.sizeimage = 176 * 144 * 3 / 2,
36*4882a593Smuzhiyun 		.colorspace = V4L2_COLORSPACE_SRGB,
37*4882a593Smuzhiyun 		.priv = 3},
38*4882a593Smuzhiyun 	{320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
39*4882a593Smuzhiyun 		.bytesperline = 320,
40*4882a593Smuzhiyun 		.sizeimage = 320 * 240 * 3 / 2,
41*4882a593Smuzhiyun 		.colorspace = V4L2_COLORSPACE_SRGB,
42*4882a593Smuzhiyun 		.priv = 2},
43*4882a593Smuzhiyun 	{352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
44*4882a593Smuzhiyun 		.bytesperline = 352,
45*4882a593Smuzhiyun 		.sizeimage = 352 * 288 * 3 / 2,
46*4882a593Smuzhiyun 		.colorspace = V4L2_COLORSPACE_SRGB,
47*4882a593Smuzhiyun 		.priv = 1},
48*4882a593Smuzhiyun 	{640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
49*4882a593Smuzhiyun 		.bytesperline = 640,
50*4882a593Smuzhiyun 		.sizeimage = 640 * 480 * 3 / 2,
51*4882a593Smuzhiyun 		.colorspace = V4L2_COLORSPACE_SRGB,
52*4882a593Smuzhiyun 		.priv = 0},
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define SPCA50X_OFFSET_DATA 10
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun #define SPCA50X_REG_USB 0x02	/* spca505 501 */
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define SPCA50X_USB_CTRL 0x00	/* spca505 */
60*4882a593Smuzhiyun #define SPCA50X_CUSB_ENABLE 0x01 /* spca505 */
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun #define SPCA50X_REG_GLOBAL 0x03	/* spca505 */
63*4882a593Smuzhiyun #define SPCA50X_GMISC0_IDSEL 0x01 /* Global control device ID select spca505 */
64*4882a593Smuzhiyun #define SPCA50X_GLOBAL_MISC0 0x00 /* Global control miscellaneous 0 spca505 */
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define SPCA50X_GLOBAL_MISC1 0x01 /* 505 */
67*4882a593Smuzhiyun #define SPCA50X_GLOBAL_MISC3 0x03 /* 505 */
68*4882a593Smuzhiyun #define SPCA50X_GMISC3_SAA7113RST 0x20	/* Not sure about this one spca505 */
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun /* Image format and compression control */
71*4882a593Smuzhiyun #define SPCA50X_REG_COMPRESS 0x04
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun /*
74*4882a593Smuzhiyun  * Data to initialize a SPCA505. Common to the CCD and external modes
75*4882a593Smuzhiyun  */
76*4882a593Smuzhiyun static const u8 spca505_init_data[][3] = {
77*4882a593Smuzhiyun 	/* bmRequest,value,index */
78*4882a593Smuzhiyun 	{SPCA50X_REG_GLOBAL, SPCA50X_GMISC3_SAA7113RST, SPCA50X_GLOBAL_MISC3},
79*4882a593Smuzhiyun 	/* Sensor reset */
80*4882a593Smuzhiyun 	{SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC3},
81*4882a593Smuzhiyun 	{SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC1},
82*4882a593Smuzhiyun 	/* Block USB reset */
83*4882a593Smuzhiyun 	{SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL, SPCA50X_GLOBAL_MISC0},
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	{0x05, 0x01, 0x10},
86*4882a593Smuzhiyun 					/* Maybe power down some stuff */
87*4882a593Smuzhiyun 	{0x05, 0x0f, 0x11},
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	/* Setup internal CCD  ? */
90*4882a593Smuzhiyun 	{0x06, 0x10, 0x08},
91*4882a593Smuzhiyun 	{0x06, 0x00, 0x09},
92*4882a593Smuzhiyun 	{0x06, 0x00, 0x0a},
93*4882a593Smuzhiyun 	{0x06, 0x00, 0x0b},
94*4882a593Smuzhiyun 	{0x06, 0x10, 0x0c},
95*4882a593Smuzhiyun 	{0x06, 0x00, 0x0d},
96*4882a593Smuzhiyun 	{0x06, 0x00, 0x0e},
97*4882a593Smuzhiyun 	{0x06, 0x00, 0x0f},
98*4882a593Smuzhiyun 	{0x06, 0x10, 0x10},
99*4882a593Smuzhiyun 	{0x06, 0x02, 0x11},
100*4882a593Smuzhiyun 	{0x06, 0x00, 0x12},
101*4882a593Smuzhiyun 	{0x06, 0x04, 0x13},
102*4882a593Smuzhiyun 	{0x06, 0x02, 0x14},
103*4882a593Smuzhiyun 	{0x06, 0x8a, 0x51},
104*4882a593Smuzhiyun 	{0x06, 0x40, 0x52},
105*4882a593Smuzhiyun 	{0x06, 0xb6, 0x53},
106*4882a593Smuzhiyun 	{0x06, 0x3d, 0x54},
107*4882a593Smuzhiyun 	{}
108*4882a593Smuzhiyun };
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun /*
111*4882a593Smuzhiyun  * Data to initialize the camera using the internal CCD
112*4882a593Smuzhiyun  */
113*4882a593Smuzhiyun static const u8 spca505_open_data_ccd[][3] = {
114*4882a593Smuzhiyun 	/* bmRequest,value,index */
115*4882a593Smuzhiyun 	/* Internal CCD data set */
116*4882a593Smuzhiyun 	{0x03, 0x04, 0x01},
117*4882a593Smuzhiyun 	/* This could be a reset */
118*4882a593Smuzhiyun 	{0x03, 0x00, 0x01},
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	/* Setup compression and image registers. 0x6 and 0x7 seem to be
121*4882a593Smuzhiyun 	   related to H&V hold, and are resolution mode specific */
122*4882a593Smuzhiyun 		{0x04, 0x10, 0x01},
123*4882a593Smuzhiyun 		/* DIFF(0x50), was (0x10) */
124*4882a593Smuzhiyun 	{0x04, 0x00, 0x04},
125*4882a593Smuzhiyun 	{0x04, 0x00, 0x05},
126*4882a593Smuzhiyun 	{0x04, 0x20, 0x06},
127*4882a593Smuzhiyun 	{0x04, 0x20, 0x07},
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	{0x08, 0x0a, 0x00},
130*4882a593Smuzhiyun 	/* DIFF (0x4a), was (0xa) */
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	{0x05, 0x00, 0x10},
133*4882a593Smuzhiyun 	{0x05, 0x00, 0x11},
134*4882a593Smuzhiyun 	{0x05, 0x00, 0x00},
135*4882a593Smuzhiyun 	/* DIFF not written */
136*4882a593Smuzhiyun 	{0x05, 0x00, 0x01},
137*4882a593Smuzhiyun 	/* DIFF not written */
138*4882a593Smuzhiyun 	{0x05, 0x00, 0x02},
139*4882a593Smuzhiyun 	/* DIFF not written */
140*4882a593Smuzhiyun 	{0x05, 0x00, 0x03},
141*4882a593Smuzhiyun 	/* DIFF not written */
142*4882a593Smuzhiyun 	{0x05, 0x00, 0x04},
143*4882a593Smuzhiyun 	/* DIFF not written */
144*4882a593Smuzhiyun 		{0x05, 0x80, 0x05},
145*4882a593Smuzhiyun 		/* DIFF not written */
146*4882a593Smuzhiyun 		{0x05, 0xe0, 0x06},
147*4882a593Smuzhiyun 		/* DIFF not written */
148*4882a593Smuzhiyun 		{0x05, 0x20, 0x07},
149*4882a593Smuzhiyun 		/* DIFF not written */
150*4882a593Smuzhiyun 		{0x05, 0xa0, 0x08},
151*4882a593Smuzhiyun 		/* DIFF not written */
152*4882a593Smuzhiyun 		{0x05, 0x0, 0x12},
153*4882a593Smuzhiyun 		/* DIFF not written */
154*4882a593Smuzhiyun 	{0x05, 0x02, 0x0f},
155*4882a593Smuzhiyun 	/* DIFF not written */
156*4882a593Smuzhiyun 		{0x05, 0x10, 0x46},
157*4882a593Smuzhiyun 		/* DIFF not written */
158*4882a593Smuzhiyun 		{0x05, 0x8, 0x4a},
159*4882a593Smuzhiyun 		/* DIFF not written */
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	{0x03, 0x08, 0x03},
162*4882a593Smuzhiyun 	/* DIFF (0x3,0x28,0x3) */
163*4882a593Smuzhiyun 	{0x03, 0x08, 0x01},
164*4882a593Smuzhiyun 	{0x03, 0x0c, 0x03},
165*4882a593Smuzhiyun 	/* DIFF not written */
166*4882a593Smuzhiyun 		{0x03, 0x21, 0x00},
167*4882a593Smuzhiyun 		/* DIFF (0x39) */
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun /* Extra block copied from init to hopefully ensure CCD is in a sane state */
170*4882a593Smuzhiyun 	{0x06, 0x10, 0x08},
171*4882a593Smuzhiyun 	{0x06, 0x00, 0x09},
172*4882a593Smuzhiyun 	{0x06, 0x00, 0x0a},
173*4882a593Smuzhiyun 	{0x06, 0x00, 0x0b},
174*4882a593Smuzhiyun 	{0x06, 0x10, 0x0c},
175*4882a593Smuzhiyun 	{0x06, 0x00, 0x0d},
176*4882a593Smuzhiyun 	{0x06, 0x00, 0x0e},
177*4882a593Smuzhiyun 	{0x06, 0x00, 0x0f},
178*4882a593Smuzhiyun 	{0x06, 0x10, 0x10},
179*4882a593Smuzhiyun 	{0x06, 0x02, 0x11},
180*4882a593Smuzhiyun 	{0x06, 0x00, 0x12},
181*4882a593Smuzhiyun 	{0x06, 0x04, 0x13},
182*4882a593Smuzhiyun 	{0x06, 0x02, 0x14},
183*4882a593Smuzhiyun 	{0x06, 0x8a, 0x51},
184*4882a593Smuzhiyun 	{0x06, 0x40, 0x52},
185*4882a593Smuzhiyun 	{0x06, 0xb6, 0x53},
186*4882a593Smuzhiyun 	{0x06, 0x3d, 0x54},
187*4882a593Smuzhiyun 	/* End of extra block */
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 		{0x06, 0x3f, 0x1},
190*4882a593Smuzhiyun 		/* Block skipped */
191*4882a593Smuzhiyun 	{0x06, 0x10, 0x02},
192*4882a593Smuzhiyun 	{0x06, 0x64, 0x07},
193*4882a593Smuzhiyun 	{0x06, 0x10, 0x08},
194*4882a593Smuzhiyun 	{0x06, 0x00, 0x09},
195*4882a593Smuzhiyun 	{0x06, 0x00, 0x0a},
196*4882a593Smuzhiyun 	{0x06, 0x00, 0x0b},
197*4882a593Smuzhiyun 	{0x06, 0x10, 0x0c},
198*4882a593Smuzhiyun 	{0x06, 0x00, 0x0d},
199*4882a593Smuzhiyun 	{0x06, 0x00, 0x0e},
200*4882a593Smuzhiyun 	{0x06, 0x00, 0x0f},
201*4882a593Smuzhiyun 	{0x06, 0x10, 0x10},
202*4882a593Smuzhiyun 	{0x06, 0x02, 0x11},
203*4882a593Smuzhiyun 	{0x06, 0x00, 0x12},
204*4882a593Smuzhiyun 	{0x06, 0x04, 0x13},
205*4882a593Smuzhiyun 	{0x06, 0x02, 0x14},
206*4882a593Smuzhiyun 	{0x06, 0x8a, 0x51},
207*4882a593Smuzhiyun 	{0x06, 0x40, 0x52},
208*4882a593Smuzhiyun 	{0x06, 0xb6, 0x53},
209*4882a593Smuzhiyun 	{0x06, 0x3d, 0x54},
210*4882a593Smuzhiyun 	{0x06, 0x60, 0x57},
211*4882a593Smuzhiyun 	{0x06, 0x20, 0x58},
212*4882a593Smuzhiyun 	{0x06, 0x15, 0x59},
213*4882a593Smuzhiyun 	{0x06, 0x05, 0x5a},
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	{0x05, 0x01, 0xc0},
216*4882a593Smuzhiyun 	{0x05, 0x10, 0xcb},
217*4882a593Smuzhiyun 		{0x05, 0x80, 0xc1},
218*4882a593Smuzhiyun 		/* */
219*4882a593Smuzhiyun 		{0x05, 0x0, 0xc2},
220*4882a593Smuzhiyun 		/* 4 was 0 */
221*4882a593Smuzhiyun 	{0x05, 0x00, 0xca},
222*4882a593Smuzhiyun 		{0x05, 0x80, 0xc1},
223*4882a593Smuzhiyun 		/*  */
224*4882a593Smuzhiyun 	{0x05, 0x04, 0xc2},
225*4882a593Smuzhiyun 	{0x05, 0x00, 0xca},
226*4882a593Smuzhiyun 		{0x05, 0x0, 0xc1},
227*4882a593Smuzhiyun 		/*  */
228*4882a593Smuzhiyun 	{0x05, 0x00, 0xc2},
229*4882a593Smuzhiyun 	{0x05, 0x00, 0xca},
230*4882a593Smuzhiyun 		{0x05, 0x40, 0xc1},
231*4882a593Smuzhiyun 		/* */
232*4882a593Smuzhiyun 	{0x05, 0x17, 0xc2},
233*4882a593Smuzhiyun 	{0x05, 0x00, 0xca},
234*4882a593Smuzhiyun 		{0x05, 0x80, 0xc1},
235*4882a593Smuzhiyun 		/* */
236*4882a593Smuzhiyun 	{0x05, 0x06, 0xc2},
237*4882a593Smuzhiyun 	{0x05, 0x00, 0xca},
238*4882a593Smuzhiyun 		{0x05, 0x80, 0xc1},
239*4882a593Smuzhiyun 		/* */
240*4882a593Smuzhiyun 	{0x05, 0x04, 0xc2},
241*4882a593Smuzhiyun 	{0x05, 0x00, 0xca},
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	{0x03, 0x4c, 0x3},
244*4882a593Smuzhiyun 	{0x03, 0x18, 0x1},
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	{0x06, 0x70, 0x51},
247*4882a593Smuzhiyun 	{0x06, 0xbe, 0x53},
248*4882a593Smuzhiyun 	{0x06, 0x71, 0x57},
249*4882a593Smuzhiyun 	{0x06, 0x20, 0x58},
250*4882a593Smuzhiyun 	{0x06, 0x05, 0x59},
251*4882a593Smuzhiyun 	{0x06, 0x15, 0x5a},
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	{0x04, 0x00, 0x08},
254*4882a593Smuzhiyun 	/* Compress = OFF (0x1 to turn on) */
255*4882a593Smuzhiyun 	{0x04, 0x12, 0x09},
256*4882a593Smuzhiyun 	{0x04, 0x21, 0x0a},
257*4882a593Smuzhiyun 	{0x04, 0x10, 0x0b},
258*4882a593Smuzhiyun 	{0x04, 0x21, 0x0c},
259*4882a593Smuzhiyun 	{0x04, 0x05, 0x00},
260*4882a593Smuzhiyun 	/* was 5 (Image Type ? ) */
261*4882a593Smuzhiyun 	{0x04, 0x00, 0x01},
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	{0x06, 0x3f, 0x01},
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	{0x04, 0x00, 0x04},
266*4882a593Smuzhiyun 	{0x04, 0x00, 0x05},
267*4882a593Smuzhiyun 	{0x04, 0x40, 0x06},
268*4882a593Smuzhiyun 	{0x04, 0x40, 0x07},
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	{0x06, 0x1c, 0x17},
271*4882a593Smuzhiyun 	{0x06, 0xe2, 0x19},
272*4882a593Smuzhiyun 	{0x06, 0x1c, 0x1b},
273*4882a593Smuzhiyun 	{0x06, 0xe2, 0x1d},
274*4882a593Smuzhiyun 	{0x06, 0xaa, 0x1f},
275*4882a593Smuzhiyun 	{0x06, 0x70, 0x20},
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	{0x05, 0x01, 0x10},
278*4882a593Smuzhiyun 	{0x05, 0x00, 0x11},
279*4882a593Smuzhiyun 	{0x05, 0x01, 0x00},
280*4882a593Smuzhiyun 	{0x05, 0x05, 0x01},
281*4882a593Smuzhiyun 		{0x05, 0x00, 0xc1},
282*4882a593Smuzhiyun 		/* */
283*4882a593Smuzhiyun 	{0x05, 0x00, 0xc2},
284*4882a593Smuzhiyun 	{0x05, 0x00, 0xca},
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	{0x06, 0x70, 0x51},
287*4882a593Smuzhiyun 	{0x06, 0xbe, 0x53},
288*4882a593Smuzhiyun 	{}
289*4882a593Smuzhiyun };
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun /*
292*4882a593Smuzhiyun  * Made by Tomasz Zablocki (skalamandra@poczta.onet.pl)
293*4882a593Smuzhiyun  * SPCA505b chip based cameras initialization data
294*4882a593Smuzhiyun  */
295*4882a593Smuzhiyun /* jfm */
296*4882a593Smuzhiyun #define initial_brightness 0x7f	/* 0x0(white)-0xff(black) */
297*4882a593Smuzhiyun /* #define initial_brightness 0x0	//0x0(white)-0xff(black) */
298*4882a593Smuzhiyun /*
299*4882a593Smuzhiyun  * Data to initialize a SPCA505. Common to the CCD and external modes
300*4882a593Smuzhiyun  */
301*4882a593Smuzhiyun static const u8 spca505b_init_data[][3] = {
302*4882a593Smuzhiyun /* start */
303*4882a593Smuzhiyun 	{0x02, 0x00, 0x00},		/* init */
304*4882a593Smuzhiyun 	{0x02, 0x00, 0x01},
305*4882a593Smuzhiyun 	{0x02, 0x00, 0x02},
306*4882a593Smuzhiyun 	{0x02, 0x00, 0x03},
307*4882a593Smuzhiyun 	{0x02, 0x00, 0x04},
308*4882a593Smuzhiyun 	{0x02, 0x00, 0x05},
309*4882a593Smuzhiyun 	{0x02, 0x00, 0x06},
310*4882a593Smuzhiyun 	{0x02, 0x00, 0x07},
311*4882a593Smuzhiyun 	{0x02, 0x00, 0x08},
312*4882a593Smuzhiyun 	{0x02, 0x00, 0x09},
313*4882a593Smuzhiyun 	{0x03, 0x00, 0x00},
314*4882a593Smuzhiyun 	{0x03, 0x00, 0x01},
315*4882a593Smuzhiyun 	{0x03, 0x00, 0x02},
316*4882a593Smuzhiyun 	{0x03, 0x00, 0x03},
317*4882a593Smuzhiyun 	{0x03, 0x00, 0x04},
318*4882a593Smuzhiyun 	{0x03, 0x00, 0x05},
319*4882a593Smuzhiyun 	{0x03, 0x00, 0x06},
320*4882a593Smuzhiyun 	{0x04, 0x00, 0x00},
321*4882a593Smuzhiyun 	{0x04, 0x00, 0x02},
322*4882a593Smuzhiyun 	{0x04, 0x00, 0x04},
323*4882a593Smuzhiyun 	{0x04, 0x00, 0x05},
324*4882a593Smuzhiyun 	{0x04, 0x00, 0x06},
325*4882a593Smuzhiyun 	{0x04, 0x00, 0x07},
326*4882a593Smuzhiyun 	{0x04, 0x00, 0x08},
327*4882a593Smuzhiyun 	{0x04, 0x00, 0x09},
328*4882a593Smuzhiyun 	{0x04, 0x00, 0x0a},
329*4882a593Smuzhiyun 	{0x04, 0x00, 0x0b},
330*4882a593Smuzhiyun 	{0x04, 0x00, 0x0c},
331*4882a593Smuzhiyun 	{0x07, 0x00, 0x00},
332*4882a593Smuzhiyun 	{0x07, 0x00, 0x03},
333*4882a593Smuzhiyun 	{0x08, 0x00, 0x00},
334*4882a593Smuzhiyun 	{0x08, 0x00, 0x01},
335*4882a593Smuzhiyun 	{0x08, 0x00, 0x02},
336*4882a593Smuzhiyun 	{0x06, 0x18, 0x08},
337*4882a593Smuzhiyun 	{0x06, 0xfc, 0x09},
338*4882a593Smuzhiyun 	{0x06, 0xfc, 0x0a},
339*4882a593Smuzhiyun 	{0x06, 0xfc, 0x0b},
340*4882a593Smuzhiyun 	{0x06, 0x18, 0x0c},
341*4882a593Smuzhiyun 	{0x06, 0xfc, 0x0d},
342*4882a593Smuzhiyun 	{0x06, 0xfc, 0x0e},
343*4882a593Smuzhiyun 	{0x06, 0xfc, 0x0f},
344*4882a593Smuzhiyun 	{0x06, 0x18, 0x10},
345*4882a593Smuzhiyun 	{0x06, 0xfe, 0x12},
346*4882a593Smuzhiyun 	{0x06, 0x00, 0x11},
347*4882a593Smuzhiyun 	{0x06, 0x00, 0x14},
348*4882a593Smuzhiyun 	{0x06, 0x00, 0x13},
349*4882a593Smuzhiyun 	{0x06, 0x28, 0x51},
350*4882a593Smuzhiyun 	{0x06, 0xff, 0x53},
351*4882a593Smuzhiyun 	{0x02, 0x00, 0x08},
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	{0x03, 0x00, 0x03},
354*4882a593Smuzhiyun 	{0x03, 0x10, 0x03},
355*4882a593Smuzhiyun 	{}
356*4882a593Smuzhiyun };
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun /*
359*4882a593Smuzhiyun  * Data to initialize the camera using the internal CCD
360*4882a593Smuzhiyun  */
361*4882a593Smuzhiyun static const u8 spca505b_open_data_ccd[][3] = {
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun /* {0x02,0x00,0x00}, */
364*4882a593Smuzhiyun 	{0x03, 0x04, 0x01},		/* rst */
365*4882a593Smuzhiyun 	{0x03, 0x00, 0x01},
366*4882a593Smuzhiyun 	{0x03, 0x00, 0x00},
367*4882a593Smuzhiyun 	{0x03, 0x21, 0x00},
368*4882a593Smuzhiyun 	{0x03, 0x00, 0x04},
369*4882a593Smuzhiyun 	{0x03, 0x00, 0x03},
370*4882a593Smuzhiyun 	{0x03, 0x18, 0x03},
371*4882a593Smuzhiyun 	{0x03, 0x08, 0x01},
372*4882a593Smuzhiyun 	{0x03, 0x1c, 0x03},
373*4882a593Smuzhiyun 	{0x03, 0x5c, 0x03},
374*4882a593Smuzhiyun 	{0x03, 0x5c, 0x03},
375*4882a593Smuzhiyun 	{0x03, 0x18, 0x01},
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun /* same as 505 */
378*4882a593Smuzhiyun 	{0x04, 0x10, 0x01},
379*4882a593Smuzhiyun 	{0x04, 0x00, 0x04},
380*4882a593Smuzhiyun 	{0x04, 0x00, 0x05},
381*4882a593Smuzhiyun 	{0x04, 0x20, 0x06},
382*4882a593Smuzhiyun 	{0x04, 0x20, 0x07},
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	{0x08, 0x0a, 0x00},
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	{0x05, 0x00, 0x10},
387*4882a593Smuzhiyun 	{0x05, 0x00, 0x11},
388*4882a593Smuzhiyun 	{0x05, 0x00, 0x12},
389*4882a593Smuzhiyun 	{0x05, 0x6f, 0x00},
390*4882a593Smuzhiyun 	{0x05, initial_brightness >> 6, 0x00},
391*4882a593Smuzhiyun 	{0x05, (initial_brightness << 2) & 0xff, 0x01},
392*4882a593Smuzhiyun 	{0x05, 0x00, 0x02},
393*4882a593Smuzhiyun 	{0x05, 0x01, 0x03},
394*4882a593Smuzhiyun 	{0x05, 0x00, 0x04},
395*4882a593Smuzhiyun 	{0x05, 0x03, 0x05},
396*4882a593Smuzhiyun 	{0x05, 0xe0, 0x06},
397*4882a593Smuzhiyun 	{0x05, 0x20, 0x07},
398*4882a593Smuzhiyun 	{0x05, 0xa0, 0x08},
399*4882a593Smuzhiyun 	{0x05, 0x00, 0x12},
400*4882a593Smuzhiyun 	{0x05, 0x02, 0x0f},
401*4882a593Smuzhiyun 	{0x05, 0x80, 0x14},		/* max exposure off (0=on) */
402*4882a593Smuzhiyun 	{0x05, 0x01, 0xb0},
403*4882a593Smuzhiyun 	{0x05, 0x01, 0xbf},
404*4882a593Smuzhiyun 	{0x03, 0x02, 0x06},
405*4882a593Smuzhiyun 	{0x05, 0x10, 0x46},
406*4882a593Smuzhiyun 	{0x05, 0x08, 0x4a},
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	{0x06, 0x00, 0x01},
409*4882a593Smuzhiyun 	{0x06, 0x10, 0x02},
410*4882a593Smuzhiyun 	{0x06, 0x64, 0x07},
411*4882a593Smuzhiyun 	{0x06, 0x18, 0x08},
412*4882a593Smuzhiyun 	{0x06, 0xfc, 0x09},
413*4882a593Smuzhiyun 	{0x06, 0xfc, 0x0a},
414*4882a593Smuzhiyun 	{0x06, 0xfc, 0x0b},
415*4882a593Smuzhiyun 	{0x04, 0x00, 0x01},
416*4882a593Smuzhiyun 	{0x06, 0x18, 0x0c},
417*4882a593Smuzhiyun 	{0x06, 0xfc, 0x0d},
418*4882a593Smuzhiyun 	{0x06, 0xfc, 0x0e},
419*4882a593Smuzhiyun 	{0x06, 0xfc, 0x0f},
420*4882a593Smuzhiyun 	{0x06, 0x11, 0x10},		/* contrast */
421*4882a593Smuzhiyun 	{0x06, 0x00, 0x11},
422*4882a593Smuzhiyun 	{0x06, 0xfe, 0x12},
423*4882a593Smuzhiyun 	{0x06, 0x00, 0x13},
424*4882a593Smuzhiyun 	{0x06, 0x00, 0x14},
425*4882a593Smuzhiyun 	{0x06, 0x9d, 0x51},
426*4882a593Smuzhiyun 	{0x06, 0x40, 0x52},
427*4882a593Smuzhiyun 	{0x06, 0x7c, 0x53},
428*4882a593Smuzhiyun 	{0x06, 0x40, 0x54},
429*4882a593Smuzhiyun 	{0x06, 0x02, 0x57},
430*4882a593Smuzhiyun 	{0x06, 0x03, 0x58},
431*4882a593Smuzhiyun 	{0x06, 0x15, 0x59},
432*4882a593Smuzhiyun 	{0x06, 0x05, 0x5a},
433*4882a593Smuzhiyun 	{0x06, 0x03, 0x56},
434*4882a593Smuzhiyun 	{0x06, 0x02, 0x3f},
435*4882a593Smuzhiyun 	{0x06, 0x00, 0x40},
436*4882a593Smuzhiyun 	{0x06, 0x39, 0x41},
437*4882a593Smuzhiyun 	{0x06, 0x69, 0x42},
438*4882a593Smuzhiyun 	{0x06, 0x87, 0x43},
439*4882a593Smuzhiyun 	{0x06, 0x9e, 0x44},
440*4882a593Smuzhiyun 	{0x06, 0xb1, 0x45},
441*4882a593Smuzhiyun 	{0x06, 0xbf, 0x46},
442*4882a593Smuzhiyun 	{0x06, 0xcc, 0x47},
443*4882a593Smuzhiyun 	{0x06, 0xd5, 0x48},
444*4882a593Smuzhiyun 	{0x06, 0xdd, 0x49},
445*4882a593Smuzhiyun 	{0x06, 0xe3, 0x4a},
446*4882a593Smuzhiyun 	{0x06, 0xe8, 0x4b},
447*4882a593Smuzhiyun 	{0x06, 0xed, 0x4c},
448*4882a593Smuzhiyun 	{0x06, 0xf2, 0x4d},
449*4882a593Smuzhiyun 	{0x06, 0xf7, 0x4e},
450*4882a593Smuzhiyun 	{0x06, 0xfc, 0x4f},
451*4882a593Smuzhiyun 	{0x06, 0xff, 0x50},
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	{0x05, 0x01, 0xc0},
454*4882a593Smuzhiyun 	{0x05, 0x10, 0xcb},
455*4882a593Smuzhiyun 	{0x05, 0x40, 0xc1},
456*4882a593Smuzhiyun 	{0x05, 0x04, 0xc2},
457*4882a593Smuzhiyun 	{0x05, 0x00, 0xca},
458*4882a593Smuzhiyun 	{0x05, 0x40, 0xc1},
459*4882a593Smuzhiyun 	{0x05, 0x09, 0xc2},
460*4882a593Smuzhiyun 	{0x05, 0x00, 0xca},
461*4882a593Smuzhiyun 	{0x05, 0xc0, 0xc1},
462*4882a593Smuzhiyun 	{0x05, 0x09, 0xc2},
463*4882a593Smuzhiyun 	{0x05, 0x00, 0xca},
464*4882a593Smuzhiyun 	{0x05, 0x40, 0xc1},
465*4882a593Smuzhiyun 	{0x05, 0x59, 0xc2},
466*4882a593Smuzhiyun 	{0x05, 0x00, 0xca},
467*4882a593Smuzhiyun 	{0x04, 0x00, 0x01},
468*4882a593Smuzhiyun 	{0x05, 0x80, 0xc1},
469*4882a593Smuzhiyun 	{0x05, 0xec, 0xc2},
470*4882a593Smuzhiyun 	{0x05, 0x0, 0xca},
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	{0x06, 0x02, 0x57},
473*4882a593Smuzhiyun 	{0x06, 0x01, 0x58},
474*4882a593Smuzhiyun 	{0x06, 0x15, 0x59},
475*4882a593Smuzhiyun 	{0x06, 0x0a, 0x5a},
476*4882a593Smuzhiyun 	{0x06, 0x01, 0x57},
477*4882a593Smuzhiyun 	{0x06, 0x8a, 0x03},
478*4882a593Smuzhiyun 	{0x06, 0x0a, 0x6c},
479*4882a593Smuzhiyun 	{0x06, 0x30, 0x01},
480*4882a593Smuzhiyun 	{0x06, 0x20, 0x02},
481*4882a593Smuzhiyun 	{0x06, 0x00, 0x03},
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	{0x05, 0x8c, 0x25},
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	{0x06, 0x4d, 0x51},		/* maybe saturation (4d) */
486*4882a593Smuzhiyun 	{0x06, 0x84, 0x53},		/* making green (84) */
487*4882a593Smuzhiyun 	{0x06, 0x00, 0x57},		/* sharpness (1) */
488*4882a593Smuzhiyun 	{0x06, 0x18, 0x08},
489*4882a593Smuzhiyun 	{0x06, 0xfc, 0x09},
490*4882a593Smuzhiyun 	{0x06, 0xfc, 0x0a},
491*4882a593Smuzhiyun 	{0x06, 0xfc, 0x0b},
492*4882a593Smuzhiyun 	{0x06, 0x18, 0x0c},		/* maybe hue (18) */
493*4882a593Smuzhiyun 	{0x06, 0xfc, 0x0d},
494*4882a593Smuzhiyun 	{0x06, 0xfc, 0x0e},
495*4882a593Smuzhiyun 	{0x06, 0xfc, 0x0f},
496*4882a593Smuzhiyun 	{0x06, 0x18, 0x10},		/* maybe contrast (18) */
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	{0x05, 0x01, 0x02},
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	{0x04, 0x00, 0x08},		/* compression */
501*4882a593Smuzhiyun 	{0x04, 0x12, 0x09},
502*4882a593Smuzhiyun 	{0x04, 0x21, 0x0a},
503*4882a593Smuzhiyun 	{0x04, 0x10, 0x0b},
504*4882a593Smuzhiyun 	{0x04, 0x21, 0x0c},
505*4882a593Smuzhiyun 	{0x04, 0x1d, 0x00},		/* imagetype (1d) */
506*4882a593Smuzhiyun 	{0x04, 0x41, 0x01},		/* hardware snapcontrol */
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 	{0x04, 0x00, 0x04},
509*4882a593Smuzhiyun 	{0x04, 0x00, 0x05},
510*4882a593Smuzhiyun 	{0x04, 0x10, 0x06},
511*4882a593Smuzhiyun 	{0x04, 0x10, 0x07},
512*4882a593Smuzhiyun 	{0x04, 0x40, 0x06},
513*4882a593Smuzhiyun 	{0x04, 0x40, 0x07},
514*4882a593Smuzhiyun 	{0x04, 0x00, 0x04},
515*4882a593Smuzhiyun 	{0x04, 0x00, 0x05},
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	{0x06, 0x1c, 0x17},
518*4882a593Smuzhiyun 	{0x06, 0xe2, 0x19},
519*4882a593Smuzhiyun 	{0x06, 0x1c, 0x1b},
520*4882a593Smuzhiyun 	{0x06, 0xe2, 0x1d},
521*4882a593Smuzhiyun 	{0x06, 0x5f, 0x1f},
522*4882a593Smuzhiyun 	{0x06, 0x32, 0x20},
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	{0x05, initial_brightness >> 6, 0x00},
525*4882a593Smuzhiyun 	{0x05, (initial_brightness << 2) & 0xff, 0x01},
526*4882a593Smuzhiyun 	{0x05, 0x06, 0xc1},
527*4882a593Smuzhiyun 	{0x05, 0x58, 0xc2},
528*4882a593Smuzhiyun 	{0x05, 0x00, 0xca},
529*4882a593Smuzhiyun 	{0x05, 0x00, 0x11},
530*4882a593Smuzhiyun 	{}
531*4882a593Smuzhiyun };
532*4882a593Smuzhiyun 
reg_write(struct gspca_dev * gspca_dev,u16 req,u16 index,u16 value)533*4882a593Smuzhiyun static int reg_write(struct gspca_dev *gspca_dev,
534*4882a593Smuzhiyun 		     u16 req, u16 index, u16 value)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun 	int ret;
537*4882a593Smuzhiyun 	struct usb_device *dev = gspca_dev->dev;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	ret = usb_control_msg(dev,
540*4882a593Smuzhiyun 			usb_sndctrlpipe(dev, 0),
541*4882a593Smuzhiyun 			req,
542*4882a593Smuzhiyun 			USB_TYPE_VENDOR | USB_RECIP_DEVICE,
543*4882a593Smuzhiyun 			value, index, NULL, 0, 500);
544*4882a593Smuzhiyun 	gspca_dbg(gspca_dev, D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d\n",
545*4882a593Smuzhiyun 		  req, index, value, ret);
546*4882a593Smuzhiyun 	if (ret < 0)
547*4882a593Smuzhiyun 		pr_err("reg write: error %d\n", ret);
548*4882a593Smuzhiyun 	return ret;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun /* returns: negative is error, pos or zero is data */
reg_read(struct gspca_dev * gspca_dev,u16 req,u16 index)552*4882a593Smuzhiyun static int reg_read(struct gspca_dev *gspca_dev,
553*4882a593Smuzhiyun 			u16 req,	/* bRequest */
554*4882a593Smuzhiyun 			u16 index)	/* wIndex */
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun 	int ret;
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	ret = usb_control_msg(gspca_dev->dev,
559*4882a593Smuzhiyun 			usb_rcvctrlpipe(gspca_dev->dev, 0),
560*4882a593Smuzhiyun 			req,
561*4882a593Smuzhiyun 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
562*4882a593Smuzhiyun 			0,			/* value */
563*4882a593Smuzhiyun 			index,
564*4882a593Smuzhiyun 			gspca_dev->usb_buf, 2,
565*4882a593Smuzhiyun 			500);			/* timeout */
566*4882a593Smuzhiyun 	if (ret < 0)
567*4882a593Smuzhiyun 		return ret;
568*4882a593Smuzhiyun 	return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun 
write_vector(struct gspca_dev * gspca_dev,const u8 data[][3])571*4882a593Smuzhiyun static int write_vector(struct gspca_dev *gspca_dev,
572*4882a593Smuzhiyun 			const u8 data[][3])
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun 	int ret, i = 0;
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	while (data[i][0] != 0) {
577*4882a593Smuzhiyun 		ret = reg_write(gspca_dev, data[i][0], data[i][2],
578*4882a593Smuzhiyun 								data[i][1]);
579*4882a593Smuzhiyun 		if (ret < 0)
580*4882a593Smuzhiyun 			return ret;
581*4882a593Smuzhiyun 		i++;
582*4882a593Smuzhiyun 	}
583*4882a593Smuzhiyun 	return 0;
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun /* this function is called at probe time */
sd_config(struct gspca_dev * gspca_dev,const struct usb_device_id * id)587*4882a593Smuzhiyun static int sd_config(struct gspca_dev *gspca_dev,
588*4882a593Smuzhiyun 			const struct usb_device_id *id)
589*4882a593Smuzhiyun {
590*4882a593Smuzhiyun 	struct sd *sd = (struct sd *) gspca_dev;
591*4882a593Smuzhiyun 	struct cam *cam;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	cam = &gspca_dev->cam;
594*4882a593Smuzhiyun 	cam->cam_mode = vga_mode;
595*4882a593Smuzhiyun 	sd->subtype = id->driver_info;
596*4882a593Smuzhiyun 	if (sd->subtype != IntelPCCameraPro)
597*4882a593Smuzhiyun 		cam->nmodes = ARRAY_SIZE(vga_mode);
598*4882a593Smuzhiyun 	else			/* no 640x480 for IntelPCCameraPro */
599*4882a593Smuzhiyun 		cam->nmodes = ARRAY_SIZE(vga_mode) - 1;
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	return 0;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun /* this function is called at probe and resume time */
sd_init(struct gspca_dev * gspca_dev)605*4882a593Smuzhiyun static int sd_init(struct gspca_dev *gspca_dev)
606*4882a593Smuzhiyun {
607*4882a593Smuzhiyun 	struct sd *sd = (struct sd *) gspca_dev;
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	if (write_vector(gspca_dev,
610*4882a593Smuzhiyun 			 sd->subtype == Nxultra
611*4882a593Smuzhiyun 				? spca505b_init_data
612*4882a593Smuzhiyun 				: spca505_init_data))
613*4882a593Smuzhiyun 		return -EIO;
614*4882a593Smuzhiyun 	return 0;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun 
setbrightness(struct gspca_dev * gspca_dev,s32 brightness)617*4882a593Smuzhiyun static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun 	reg_write(gspca_dev, 0x05, 0x00, (255 - brightness) >> 6);
620*4882a593Smuzhiyun 	reg_write(gspca_dev, 0x05, 0x01, (255 - brightness) << 2);
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun 
sd_start(struct gspca_dev * gspca_dev)623*4882a593Smuzhiyun static int sd_start(struct gspca_dev *gspca_dev)
624*4882a593Smuzhiyun {
625*4882a593Smuzhiyun 	struct sd *sd = (struct sd *) gspca_dev;
626*4882a593Smuzhiyun 	int ret, mode;
627*4882a593Smuzhiyun 	static u8 mode_tb[][3] = {
628*4882a593Smuzhiyun 	/*	  r00   r06   r07	*/
629*4882a593Smuzhiyun 		{0x00, 0x10, 0x10},	/* 640x480 */
630*4882a593Smuzhiyun 		{0x01, 0x1a, 0x1a},	/* 352x288 */
631*4882a593Smuzhiyun 		{0x02, 0x1c, 0x1d},	/* 320x240 */
632*4882a593Smuzhiyun 		{0x04, 0x34, 0x34},	/* 176x144 */
633*4882a593Smuzhiyun 		{0x05, 0x40, 0x40}	/* 160x120 */
634*4882a593Smuzhiyun 	};
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	if (sd->subtype == Nxultra)
637*4882a593Smuzhiyun 		write_vector(gspca_dev, spca505b_open_data_ccd);
638*4882a593Smuzhiyun 	else
639*4882a593Smuzhiyun 		write_vector(gspca_dev, spca505_open_data_ccd);
640*4882a593Smuzhiyun 	ret = reg_read(gspca_dev, 0x06, 0x16);
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	if (ret < 0) {
643*4882a593Smuzhiyun 		gspca_err(gspca_dev, "register read failed err: %d\n", ret);
644*4882a593Smuzhiyun 		return ret;
645*4882a593Smuzhiyun 	}
646*4882a593Smuzhiyun 	if (ret != 0x0101) {
647*4882a593Smuzhiyun 		pr_err("After vector read returns 0x%04x should be 0x0101\n",
648*4882a593Smuzhiyun 		       ret);
649*4882a593Smuzhiyun 	}
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	ret = reg_write(gspca_dev, 0x06, 0x16, 0x0a);
652*4882a593Smuzhiyun 	if (ret < 0)
653*4882a593Smuzhiyun 		return ret;
654*4882a593Smuzhiyun 	reg_write(gspca_dev, 0x05, 0xc2, 0x12);
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	/* necessary because without it we can see stream
657*4882a593Smuzhiyun 	 * only once after loading module */
658*4882a593Smuzhiyun 	/* stopping usb registers Tomasz change */
659*4882a593Smuzhiyun 	reg_write(gspca_dev, 0x02, 0x00, 0x00);
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
662*4882a593Smuzhiyun 	reg_write(gspca_dev, SPCA50X_REG_COMPRESS, 0x00, mode_tb[mode][0]);
663*4882a593Smuzhiyun 	reg_write(gspca_dev, SPCA50X_REG_COMPRESS, 0x06, mode_tb[mode][1]);
664*4882a593Smuzhiyun 	reg_write(gspca_dev, SPCA50X_REG_COMPRESS, 0x07, mode_tb[mode][2]);
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	return reg_write(gspca_dev, SPCA50X_REG_USB,
667*4882a593Smuzhiyun 			 SPCA50X_USB_CTRL,
668*4882a593Smuzhiyun 			 SPCA50X_CUSB_ENABLE);
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun 
sd_stopN(struct gspca_dev * gspca_dev)671*4882a593Smuzhiyun static void sd_stopN(struct gspca_dev *gspca_dev)
672*4882a593Smuzhiyun {
673*4882a593Smuzhiyun 	/* Disable ISO packet machine */
674*4882a593Smuzhiyun 	reg_write(gspca_dev, 0x02, 0x00, 0x00);
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun /* called on streamoff with alt 0 and on disconnect */
sd_stop0(struct gspca_dev * gspca_dev)678*4882a593Smuzhiyun static void sd_stop0(struct gspca_dev *gspca_dev)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun 	if (!gspca_dev->present)
681*4882a593Smuzhiyun 		return;
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	/* This maybe reset or power control */
684*4882a593Smuzhiyun 	reg_write(gspca_dev, 0x03, 0x03, 0x20);
685*4882a593Smuzhiyun 	reg_write(gspca_dev, 0x03, 0x01, 0x00);
686*4882a593Smuzhiyun 	reg_write(gspca_dev, 0x03, 0x00, 0x01);
687*4882a593Smuzhiyun 	reg_write(gspca_dev, 0x05, 0x10, 0x01);
688*4882a593Smuzhiyun 	reg_write(gspca_dev, 0x05, 0x11, 0x0f);
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun 
sd_pkt_scan(struct gspca_dev * gspca_dev,u8 * data,int len)691*4882a593Smuzhiyun static void sd_pkt_scan(struct gspca_dev *gspca_dev,
692*4882a593Smuzhiyun 			u8 *data,			/* isoc packet */
693*4882a593Smuzhiyun 			int len)			/* iso packet length */
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun 	switch (data[0]) {
696*4882a593Smuzhiyun 	case 0:				/* start of frame */
697*4882a593Smuzhiyun 		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
698*4882a593Smuzhiyun 		data += SPCA50X_OFFSET_DATA;
699*4882a593Smuzhiyun 		len -= SPCA50X_OFFSET_DATA;
700*4882a593Smuzhiyun 		gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
701*4882a593Smuzhiyun 		break;
702*4882a593Smuzhiyun 	case 0xff:			/* drop */
703*4882a593Smuzhiyun 		break;
704*4882a593Smuzhiyun 	default:
705*4882a593Smuzhiyun 		data += 1;
706*4882a593Smuzhiyun 		len -= 1;
707*4882a593Smuzhiyun 		gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
708*4882a593Smuzhiyun 		break;
709*4882a593Smuzhiyun 	}
710*4882a593Smuzhiyun }
711*4882a593Smuzhiyun 
sd_s_ctrl(struct v4l2_ctrl * ctrl)712*4882a593Smuzhiyun static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
713*4882a593Smuzhiyun {
714*4882a593Smuzhiyun 	struct gspca_dev *gspca_dev =
715*4882a593Smuzhiyun 		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	gspca_dev->usb_err = 0;
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	if (!gspca_dev->streaming)
720*4882a593Smuzhiyun 		return 0;
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 	switch (ctrl->id) {
723*4882a593Smuzhiyun 	case V4L2_CID_BRIGHTNESS:
724*4882a593Smuzhiyun 		setbrightness(gspca_dev, ctrl->val);
725*4882a593Smuzhiyun 		break;
726*4882a593Smuzhiyun 	}
727*4882a593Smuzhiyun 	return gspca_dev->usb_err;
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun static const struct v4l2_ctrl_ops sd_ctrl_ops = {
731*4882a593Smuzhiyun 	.s_ctrl = sd_s_ctrl,
732*4882a593Smuzhiyun };
733*4882a593Smuzhiyun 
sd_init_controls(struct gspca_dev * gspca_dev)734*4882a593Smuzhiyun static int sd_init_controls(struct gspca_dev *gspca_dev)
735*4882a593Smuzhiyun {
736*4882a593Smuzhiyun 	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 	gspca_dev->vdev.ctrl_handler = hdl;
739*4882a593Smuzhiyun 	v4l2_ctrl_handler_init(hdl, 5);
740*4882a593Smuzhiyun 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
741*4882a593Smuzhiyun 			V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	if (hdl->error) {
744*4882a593Smuzhiyun 		pr_err("Could not initialize controls\n");
745*4882a593Smuzhiyun 		return hdl->error;
746*4882a593Smuzhiyun 	}
747*4882a593Smuzhiyun 	return 0;
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun /* sub-driver description */
751*4882a593Smuzhiyun static const struct sd_desc sd_desc = {
752*4882a593Smuzhiyun 	.name = MODULE_NAME,
753*4882a593Smuzhiyun 	.config = sd_config,
754*4882a593Smuzhiyun 	.init_controls = sd_init_controls,
755*4882a593Smuzhiyun 	.init = sd_init,
756*4882a593Smuzhiyun 	.start = sd_start,
757*4882a593Smuzhiyun 	.stopN = sd_stopN,
758*4882a593Smuzhiyun 	.stop0 = sd_stop0,
759*4882a593Smuzhiyun 	.pkt_scan = sd_pkt_scan,
760*4882a593Smuzhiyun };
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun /* -- module initialisation -- */
763*4882a593Smuzhiyun static const struct usb_device_id device_table[] = {
764*4882a593Smuzhiyun 	{USB_DEVICE(0x041e, 0x401d), .driver_info = Nxultra},
765*4882a593Smuzhiyun 	{USB_DEVICE(0x0733, 0x0430), .driver_info = IntelPCCameraPro},
766*4882a593Smuzhiyun /*fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */
767*4882a593Smuzhiyun 	{}
768*4882a593Smuzhiyun };
769*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, device_table);
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun /* -- device connect -- */
sd_probe(struct usb_interface * intf,const struct usb_device_id * id)772*4882a593Smuzhiyun static int sd_probe(struct usb_interface *intf,
773*4882a593Smuzhiyun 			const struct usb_device_id *id)
774*4882a593Smuzhiyun {
775*4882a593Smuzhiyun 	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
776*4882a593Smuzhiyun 				THIS_MODULE);
777*4882a593Smuzhiyun }
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun static struct usb_driver sd_driver = {
780*4882a593Smuzhiyun 	.name = MODULE_NAME,
781*4882a593Smuzhiyun 	.id_table = device_table,
782*4882a593Smuzhiyun 	.probe = sd_probe,
783*4882a593Smuzhiyun 	.disconnect = gspca_disconnect,
784*4882a593Smuzhiyun #ifdef CONFIG_PM
785*4882a593Smuzhiyun 	.suspend = gspca_suspend,
786*4882a593Smuzhiyun 	.resume = gspca_resume,
787*4882a593Smuzhiyun 	.reset_resume = gspca_resume,
788*4882a593Smuzhiyun #endif
789*4882a593Smuzhiyun };
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun module_usb_driver(sd_driver);
792