xref: /OK3568_Linux_fs/kernel/drivers/media/usb/gspca/tv8532.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Quickcam cameras initialization data
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun #define MODULE_NAME "tv8532"
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include "gspca.h"
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
12*4882a593Smuzhiyun MODULE_DESCRIPTION("TV8532 USB Camera Driver");
13*4882a593Smuzhiyun MODULE_LICENSE("GPL");
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun /* specific webcam descriptor */
16*4882a593Smuzhiyun struct sd {
17*4882a593Smuzhiyun 	struct gspca_dev gspca_dev;	/* !! must be the first item */
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun 	__u8 packet;
20*4882a593Smuzhiyun };
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun static const struct v4l2_pix_format sif_mode[] = {
23*4882a593Smuzhiyun 	{176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
24*4882a593Smuzhiyun 		.bytesperline = 176,
25*4882a593Smuzhiyun 		.sizeimage = 176 * 144,
26*4882a593Smuzhiyun 		.colorspace = V4L2_COLORSPACE_SRGB,
27*4882a593Smuzhiyun 		.priv = 1},
28*4882a593Smuzhiyun 	{352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
29*4882a593Smuzhiyun 		.bytesperline = 352,
30*4882a593Smuzhiyun 		.sizeimage = 352 * 288,
31*4882a593Smuzhiyun 		.colorspace = V4L2_COLORSPACE_SRGB,
32*4882a593Smuzhiyun 		.priv = 0},
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun /* TV-8532A (ICM532A) registers (LE) */
36*4882a593Smuzhiyun #define R00_PART_CONTROL 0x00
37*4882a593Smuzhiyun #define		LATENT_CHANGE	0x80
38*4882a593Smuzhiyun #define		EXPO_CHANGE	0x04
39*4882a593Smuzhiyun #define R01_TIMING_CONTROL_LOW 0x01
40*4882a593Smuzhiyun #define		CMD_EEprom_Open 0x30
41*4882a593Smuzhiyun #define		CMD_EEprom_Close 0x29
42*4882a593Smuzhiyun #define R03_TABLE_ADDR 0x03
43*4882a593Smuzhiyun #define R04_WTRAM_DATA_L 0x04
44*4882a593Smuzhiyun #define R05_WTRAM_DATA_M 0x05
45*4882a593Smuzhiyun #define R06_WTRAM_DATA_H 0x06
46*4882a593Smuzhiyun #define R07_TABLE_LEN	0x07
47*4882a593Smuzhiyun #define R08_RAM_WRITE_ACTION 0x08
48*4882a593Smuzhiyun #define R0C_AD_WIDTHL	0x0c
49*4882a593Smuzhiyun #define R0D_AD_WIDTHH	0x0d
50*4882a593Smuzhiyun #define R0E_AD_HEIGHTL	0x0e
51*4882a593Smuzhiyun #define R0F_AD_HEIGHTH	0x0f
52*4882a593Smuzhiyun #define R10_AD_COL_BEGINL 0x10
53*4882a593Smuzhiyun #define R11_AD_COL_BEGINH 0x11
54*4882a593Smuzhiyun #define		MIRROR		0x04	/* [10] */
55*4882a593Smuzhiyun #define R14_AD_ROW_BEGINL 0x14
56*4882a593Smuzhiyun #define R15_AD_ROWBEGINH  0x15
57*4882a593Smuzhiyun #define R1C_AD_EXPOSE_TIMEL 0x1c
58*4882a593Smuzhiyun #define R20_GAIN_G1L	0x20
59*4882a593Smuzhiyun #define R21_GAIN_G1H	0x21
60*4882a593Smuzhiyun #define R22_GAIN_RL	0x22
61*4882a593Smuzhiyun #define R23_GAIN_RH	0x23
62*4882a593Smuzhiyun #define R24_GAIN_BL	0x24
63*4882a593Smuzhiyun #define R25_GAIN_BH	0x25
64*4882a593Smuzhiyun #define R26_GAIN_G2L	0x26
65*4882a593Smuzhiyun #define R27_GAIN_G2H	0x27
66*4882a593Smuzhiyun #define R28_QUANT	0x28
67*4882a593Smuzhiyun #define R29_LINE	0x29
68*4882a593Smuzhiyun #define R2C_POLARITY	0x2c
69*4882a593Smuzhiyun #define R2D_POINT	0x2d
70*4882a593Smuzhiyun #define R2E_POINTH	0x2e
71*4882a593Smuzhiyun #define R2F_POINTB	0x2f
72*4882a593Smuzhiyun #define R30_POINTBH	0x30
73*4882a593Smuzhiyun #define R31_UPD		0x31
74*4882a593Smuzhiyun #define R2A_HIGH_BUDGET 0x2a
75*4882a593Smuzhiyun #define R2B_LOW_BUDGET	0x2b
76*4882a593Smuzhiyun #define R34_VID		0x34
77*4882a593Smuzhiyun #define R35_VIDH	0x35
78*4882a593Smuzhiyun #define R36_PID		0x36
79*4882a593Smuzhiyun #define R37_PIDH	0x37
80*4882a593Smuzhiyun #define R39_Test1	0x39		/* GPIO */
81*4882a593Smuzhiyun #define R3B_Test3	0x3b		/* GPIO */
82*4882a593Smuzhiyun #define R83_AD_IDH	0x83
83*4882a593Smuzhiyun #define R91_AD_SLOPEREG 0x91
84*4882a593Smuzhiyun #define R94_AD_BITCONTROL 0x94
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun static const u8 eeprom_data[][3] = {
87*4882a593Smuzhiyun /*	dataH dataM dataL */
88*4882a593Smuzhiyun 	{0x01, 0x00, 0x01},
89*4882a593Smuzhiyun 	{0x01, 0x80, 0x11},
90*4882a593Smuzhiyun 	{0x05, 0x00, 0x14},
91*4882a593Smuzhiyun 	{0x05, 0x00, 0x1c},
92*4882a593Smuzhiyun 	{0x0d, 0x00, 0x1e},
93*4882a593Smuzhiyun 	{0x05, 0x00, 0x1f},
94*4882a593Smuzhiyun 	{0x05, 0x05, 0x19},
95*4882a593Smuzhiyun 	{0x05, 0x01, 0x1b},
96*4882a593Smuzhiyun 	{0x05, 0x09, 0x1e},
97*4882a593Smuzhiyun 	{0x0d, 0x89, 0x2e},
98*4882a593Smuzhiyun 	{0x05, 0x89, 0x2f},
99*4882a593Smuzhiyun 	{0x05, 0x0d, 0xd9},
100*4882a593Smuzhiyun 	{0x05, 0x09, 0xf1},
101*4882a593Smuzhiyun };
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun /* write 1 byte */
reg_w1(struct gspca_dev * gspca_dev,__u16 index,__u8 value)105*4882a593Smuzhiyun static void reg_w1(struct gspca_dev *gspca_dev,
106*4882a593Smuzhiyun 		  __u16 index, __u8 value)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	gspca_dev->usb_buf[0] = value;
109*4882a593Smuzhiyun 	usb_control_msg(gspca_dev->dev,
110*4882a593Smuzhiyun 			usb_sndctrlpipe(gspca_dev->dev, 0),
111*4882a593Smuzhiyun 			0x02,
112*4882a593Smuzhiyun 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
113*4882a593Smuzhiyun 			0,	/* value */
114*4882a593Smuzhiyun 			index, gspca_dev->usb_buf, 1, 500);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun /* write 2 bytes */
reg_w2(struct gspca_dev * gspca_dev,u16 index,u16 value)118*4882a593Smuzhiyun static void reg_w2(struct gspca_dev *gspca_dev,
119*4882a593Smuzhiyun 		  u16 index, u16 value)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	gspca_dev->usb_buf[0] = value;
122*4882a593Smuzhiyun 	gspca_dev->usb_buf[1] = value >> 8;
123*4882a593Smuzhiyun 	usb_control_msg(gspca_dev->dev,
124*4882a593Smuzhiyun 			usb_sndctrlpipe(gspca_dev->dev, 0),
125*4882a593Smuzhiyun 			0x02,
126*4882a593Smuzhiyun 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
127*4882a593Smuzhiyun 			0,	/* value */
128*4882a593Smuzhiyun 			index, gspca_dev->usb_buf, 2, 500);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
tv_8532WriteEEprom(struct gspca_dev * gspca_dev)131*4882a593Smuzhiyun static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	int i;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Open);
136*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(eeprom_data); i++) {
137*4882a593Smuzhiyun 		reg_w1(gspca_dev, R03_TABLE_ADDR, i);
138*4882a593Smuzhiyun 		reg_w1(gspca_dev, R04_WTRAM_DATA_L, eeprom_data[i][2]);
139*4882a593Smuzhiyun 		reg_w1(gspca_dev, R05_WTRAM_DATA_M, eeprom_data[i][1]);
140*4882a593Smuzhiyun 		reg_w1(gspca_dev, R06_WTRAM_DATA_H, eeprom_data[i][0]);
141*4882a593Smuzhiyun 		reg_w1(gspca_dev, R08_RAM_WRITE_ACTION, 0);
142*4882a593Smuzhiyun 	}
143*4882a593Smuzhiyun 	reg_w1(gspca_dev, R07_TABLE_LEN, i);
144*4882a593Smuzhiyun 	reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun /* this function is called at probe time */
sd_config(struct gspca_dev * gspca_dev,const struct usb_device_id * id)148*4882a593Smuzhiyun static int sd_config(struct gspca_dev *gspca_dev,
149*4882a593Smuzhiyun 		     const struct usb_device_id *id)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	struct cam *cam;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	cam = &gspca_dev->cam;
154*4882a593Smuzhiyun 	cam->cam_mode = sif_mode;
155*4882a593Smuzhiyun 	cam->nmodes = ARRAY_SIZE(sif_mode);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	return 0;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
tv_8532_setReg(struct gspca_dev * gspca_dev)160*4882a593Smuzhiyun static void tv_8532_setReg(struct gspca_dev *gspca_dev)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun 	reg_w1(gspca_dev, R3B_Test3, 0x0a);	/* Test0Sel = 10 */
163*4882a593Smuzhiyun 	/******************************************************/
164*4882a593Smuzhiyun 	reg_w1(gspca_dev, R0E_AD_HEIGHTL, 0x90);
165*4882a593Smuzhiyun 	reg_w1(gspca_dev, R0F_AD_HEIGHTH, 0x01);
166*4882a593Smuzhiyun 	reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, 0x018f);
167*4882a593Smuzhiyun 	reg_w1(gspca_dev, R10_AD_COL_BEGINL, 0x44);
168*4882a593Smuzhiyun 						/* begin active line */
169*4882a593Smuzhiyun 	reg_w1(gspca_dev, R11_AD_COL_BEGINH, 0x00);
170*4882a593Smuzhiyun 						/* mirror and digital gain */
171*4882a593Smuzhiyun 	reg_w1(gspca_dev, R14_AD_ROW_BEGINL, 0x0a);
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x02);
174*4882a593Smuzhiyun 	reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00);
175*4882a593Smuzhiyun 	reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
176*4882a593Smuzhiyun 						/* = 0x84 */
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun /* this function is called at probe and resume time */
sd_init(struct gspca_dev * gspca_dev)180*4882a593Smuzhiyun static int sd_init(struct gspca_dev *gspca_dev)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	tv_8532WriteEEprom(gspca_dev);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	return 0;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun 
setexposure(struct gspca_dev * gspca_dev,s32 val)187*4882a593Smuzhiyun static void setexposure(struct gspca_dev *gspca_dev, s32 val)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun 	reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, val);
190*4882a593Smuzhiyun 	reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
191*4882a593Smuzhiyun 						/* 0x84 */
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
setgain(struct gspca_dev * gspca_dev,s32 val)194*4882a593Smuzhiyun static void setgain(struct gspca_dev *gspca_dev, s32 val)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun 	reg_w2(gspca_dev, R20_GAIN_G1L, val);
197*4882a593Smuzhiyun 	reg_w2(gspca_dev, R22_GAIN_RL, val);
198*4882a593Smuzhiyun 	reg_w2(gspca_dev, R24_GAIN_BL, val);
199*4882a593Smuzhiyun 	reg_w2(gspca_dev, R26_GAIN_G2L, val);
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun /* -- start the camera -- */
sd_start(struct gspca_dev * gspca_dev)203*4882a593Smuzhiyun static int sd_start(struct gspca_dev *gspca_dev)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun 	struct sd *sd = (struct sd *) gspca_dev;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8);		/* 0x20; 0x0c */
208*4882a593Smuzhiyun 	reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	/************************************************/
211*4882a593Smuzhiyun 	reg_w1(gspca_dev, R28_QUANT, 0x90);
212*4882a593Smuzhiyun 					/* 0x72 compressed mode 0x28 */
213*4882a593Smuzhiyun 	if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
214*4882a593Smuzhiyun 		/* 176x144 */
215*4882a593Smuzhiyun 		reg_w1(gspca_dev, R29_LINE, 0x41);
216*4882a593Smuzhiyun 					/* CIF - 2 lines/packet */
217*4882a593Smuzhiyun 	} else {
218*4882a593Smuzhiyun 		/* 352x288 */
219*4882a593Smuzhiyun 		reg_w1(gspca_dev, R29_LINE, 0x81);
220*4882a593Smuzhiyun 					/* CIF - 2 lines/packet */
221*4882a593Smuzhiyun 	}
222*4882a593Smuzhiyun 	/************************************************/
223*4882a593Smuzhiyun 	reg_w1(gspca_dev, R2C_POLARITY, 0x10);		/* slow clock */
224*4882a593Smuzhiyun 	reg_w1(gspca_dev, R2D_POINT, 0x14);
225*4882a593Smuzhiyun 	reg_w1(gspca_dev, R2E_POINTH, 0x01);
226*4882a593Smuzhiyun 	reg_w1(gspca_dev, R2F_POINTB, 0x12);
227*4882a593Smuzhiyun 	reg_w1(gspca_dev, R30_POINTBH, 0x01);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	tv_8532_setReg(gspca_dev);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	/************************************************/
232*4882a593Smuzhiyun 	reg_w1(gspca_dev, R31_UPD, 0x01);	/* update registers */
233*4882a593Smuzhiyun 	msleep(200);
234*4882a593Smuzhiyun 	reg_w1(gspca_dev, R31_UPD, 0x00);	/* end update */
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	gspca_dev->empty_packet = 0;		/* check the empty packets */
237*4882a593Smuzhiyun 	sd->packet = 0;				/* ignore the first packets */
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	return 0;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun 
sd_stopN(struct gspca_dev * gspca_dev)242*4882a593Smuzhiyun static void sd_stopN(struct gspca_dev *gspca_dev)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun 	reg_w1(gspca_dev, R3B_Test3, 0x0b);	/* Test0Sel = 11 = GPIO */
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
sd_pkt_scan(struct gspca_dev * gspca_dev,u8 * data,int len)247*4882a593Smuzhiyun static void sd_pkt_scan(struct gspca_dev *gspca_dev,
248*4882a593Smuzhiyun 			u8 *data,			/* isoc packet */
249*4882a593Smuzhiyun 			int len)			/* iso packet length */
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun 	struct sd *sd = (struct sd *) gspca_dev;
252*4882a593Smuzhiyun 	int packet_type0, packet_type1;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	packet_type0 = packet_type1 = INTER_PACKET;
255*4882a593Smuzhiyun 	if (gspca_dev->empty_packet) {
256*4882a593Smuzhiyun 		gspca_dev->empty_packet = 0;
257*4882a593Smuzhiyun 		sd->packet = gspca_dev->pixfmt.height / 2;
258*4882a593Smuzhiyun 		packet_type0 = FIRST_PACKET;
259*4882a593Smuzhiyun 	} else if (sd->packet == 0)
260*4882a593Smuzhiyun 		return;			/* 2 more lines in 352x288 ! */
261*4882a593Smuzhiyun 	sd->packet--;
262*4882a593Smuzhiyun 	if (sd->packet == 0)
263*4882a593Smuzhiyun 		packet_type1 = LAST_PACKET;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	/* each packet contains:
266*4882a593Smuzhiyun 	 * - header 2 bytes
267*4882a593Smuzhiyun 	 * - RGRG line
268*4882a593Smuzhiyun 	 * - 4 bytes
269*4882a593Smuzhiyun 	 * - GBGB line
270*4882a593Smuzhiyun 	 * - 4 bytes
271*4882a593Smuzhiyun 	 */
272*4882a593Smuzhiyun 	gspca_frame_add(gspca_dev, packet_type0,
273*4882a593Smuzhiyun 			data + 2, gspca_dev->pixfmt.width);
274*4882a593Smuzhiyun 	gspca_frame_add(gspca_dev, packet_type1,
275*4882a593Smuzhiyun 			data + gspca_dev->pixfmt.width + 5,
276*4882a593Smuzhiyun 			gspca_dev->pixfmt.width);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
sd_s_ctrl(struct v4l2_ctrl * ctrl)279*4882a593Smuzhiyun static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun 	struct gspca_dev *gspca_dev =
282*4882a593Smuzhiyun 		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	gspca_dev->usb_err = 0;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	if (!gspca_dev->streaming)
287*4882a593Smuzhiyun 		return 0;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	switch (ctrl->id) {
290*4882a593Smuzhiyun 	case V4L2_CID_EXPOSURE:
291*4882a593Smuzhiyun 		setexposure(gspca_dev, ctrl->val);
292*4882a593Smuzhiyun 		break;
293*4882a593Smuzhiyun 	case V4L2_CID_GAIN:
294*4882a593Smuzhiyun 		setgain(gspca_dev, ctrl->val);
295*4882a593Smuzhiyun 		break;
296*4882a593Smuzhiyun 	}
297*4882a593Smuzhiyun 	return gspca_dev->usb_err;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun static const struct v4l2_ctrl_ops sd_ctrl_ops = {
301*4882a593Smuzhiyun 	.s_ctrl = sd_s_ctrl,
302*4882a593Smuzhiyun };
303*4882a593Smuzhiyun 
sd_init_controls(struct gspca_dev * gspca_dev)304*4882a593Smuzhiyun static int sd_init_controls(struct gspca_dev *gspca_dev)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun 	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	gspca_dev->vdev.ctrl_handler = hdl;
309*4882a593Smuzhiyun 	v4l2_ctrl_handler_init(hdl, 2);
310*4882a593Smuzhiyun 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
311*4882a593Smuzhiyun 			V4L2_CID_EXPOSURE, 0, 0x18f, 1, 0x18f);
312*4882a593Smuzhiyun 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
313*4882a593Smuzhiyun 			V4L2_CID_GAIN, 0, 0x7ff, 1, 0x100);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	if (hdl->error) {
316*4882a593Smuzhiyun 		pr_err("Could not initialize controls\n");
317*4882a593Smuzhiyun 		return hdl->error;
318*4882a593Smuzhiyun 	}
319*4882a593Smuzhiyun 	return 0;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun /* sub-driver description */
323*4882a593Smuzhiyun static const struct sd_desc sd_desc = {
324*4882a593Smuzhiyun 	.name = MODULE_NAME,
325*4882a593Smuzhiyun 	.config = sd_config,
326*4882a593Smuzhiyun 	.init = sd_init,
327*4882a593Smuzhiyun 	.init_controls = sd_init_controls,
328*4882a593Smuzhiyun 	.start = sd_start,
329*4882a593Smuzhiyun 	.stopN = sd_stopN,
330*4882a593Smuzhiyun 	.pkt_scan = sd_pkt_scan,
331*4882a593Smuzhiyun };
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun /* -- module initialisation -- */
334*4882a593Smuzhiyun static const struct usb_device_id device_table[] = {
335*4882a593Smuzhiyun 	{USB_DEVICE(0x046d, 0x0920)},
336*4882a593Smuzhiyun 	{USB_DEVICE(0x046d, 0x0921)},
337*4882a593Smuzhiyun 	{USB_DEVICE(0x0545, 0x808b)},
338*4882a593Smuzhiyun 	{USB_DEVICE(0x0545, 0x8333)},
339*4882a593Smuzhiyun 	{USB_DEVICE(0x0923, 0x010f)},
340*4882a593Smuzhiyun 	{}
341*4882a593Smuzhiyun };
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, device_table);
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun /* -- device connect -- */
sd_probe(struct usb_interface * intf,const struct usb_device_id * id)346*4882a593Smuzhiyun static int sd_probe(struct usb_interface *intf,
347*4882a593Smuzhiyun 		    const struct usb_device_id *id)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun 	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
350*4882a593Smuzhiyun 			       THIS_MODULE);
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun static struct usb_driver sd_driver = {
354*4882a593Smuzhiyun 	.name = MODULE_NAME,
355*4882a593Smuzhiyun 	.id_table = device_table,
356*4882a593Smuzhiyun 	.probe = sd_probe,
357*4882a593Smuzhiyun 	.disconnect = gspca_disconnect,
358*4882a593Smuzhiyun #ifdef CONFIG_PM
359*4882a593Smuzhiyun 	.suspend = gspca_suspend,
360*4882a593Smuzhiyun 	.resume = gspca_resume,
361*4882a593Smuzhiyun 	.reset_resume = gspca_resume,
362*4882a593Smuzhiyun #endif
363*4882a593Smuzhiyun };
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun module_usb_driver(sd_driver);
366