xref: /OK3568_Linux_fs/kernel/drivers/media/usb/gspca/etoms.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Etoms Et61x151 GPL Linux driver by Michel Xhaard (09/09/2004)
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * V4L2 by Jean-Francois 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 "etoms"
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include "gspca.h"
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
15*4882a593Smuzhiyun MODULE_DESCRIPTION("Etoms 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 	unsigned char autogain;
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun 	char sensor;
25*4882a593Smuzhiyun #define SENSOR_PAS106 0
26*4882a593Smuzhiyun #define SENSOR_TAS5130CXX 1
27*4882a593Smuzhiyun 	signed char ag_cnt;
28*4882a593Smuzhiyun #define AG_CNT_START 13
29*4882a593Smuzhiyun };
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun static const struct v4l2_pix_format vga_mode[] = {
32*4882a593Smuzhiyun 	{320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
33*4882a593Smuzhiyun 		.bytesperline = 320,
34*4882a593Smuzhiyun 		.sizeimage = 320 * 240,
35*4882a593Smuzhiyun 		.colorspace = V4L2_COLORSPACE_SRGB,
36*4882a593Smuzhiyun 		.priv = 1},
37*4882a593Smuzhiyun /*	{640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
38*4882a593Smuzhiyun 		.bytesperline = 640,
39*4882a593Smuzhiyun 		.sizeimage = 640 * 480,
40*4882a593Smuzhiyun 		.colorspace = V4L2_COLORSPACE_SRGB,
41*4882a593Smuzhiyun 		.priv = 0}, */
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun static const struct v4l2_pix_format sif_mode[] = {
45*4882a593Smuzhiyun 	{176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
46*4882a593Smuzhiyun 		.bytesperline = 176,
47*4882a593Smuzhiyun 		.sizeimage = 176 * 144,
48*4882a593Smuzhiyun 		.colorspace = V4L2_COLORSPACE_SRGB,
49*4882a593Smuzhiyun 		.priv = 1},
50*4882a593Smuzhiyun 	{352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
51*4882a593Smuzhiyun 		.bytesperline = 352,
52*4882a593Smuzhiyun 		.sizeimage = 352 * 288,
53*4882a593Smuzhiyun 		.colorspace = V4L2_COLORSPACE_SRGB,
54*4882a593Smuzhiyun 		.priv = 0},
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun #define ETOMS_ALT_SIZE_1000   12
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define ET_GPIO_DIR_CTRL 0x04	/* Control IO bit[0..5] (0 in  1 out) */
60*4882a593Smuzhiyun #define ET_GPIO_OUT 0x05	/* Only IO data */
61*4882a593Smuzhiyun #define ET_GPIO_IN 0x06		/* Read Only IO data */
62*4882a593Smuzhiyun #define ET_RESET_ALL 0x03
63*4882a593Smuzhiyun #define ET_ClCK 0x01
64*4882a593Smuzhiyun #define ET_CTRL 0x02		/* enable i2c OutClck Powerdown mode */
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define ET_COMP 0x12		/* Compression register */
67*4882a593Smuzhiyun #define ET_MAXQt 0x13
68*4882a593Smuzhiyun #define ET_MINQt 0x14
69*4882a593Smuzhiyun #define ET_COMP_VAL0 0x02
70*4882a593Smuzhiyun #define ET_COMP_VAL1 0x03
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun #define ET_REG1d 0x1d
73*4882a593Smuzhiyun #define ET_REG1e 0x1e
74*4882a593Smuzhiyun #define ET_REG1f 0x1f
75*4882a593Smuzhiyun #define ET_REG20 0x20
76*4882a593Smuzhiyun #define ET_REG21 0x21
77*4882a593Smuzhiyun #define ET_REG22 0x22
78*4882a593Smuzhiyun #define ET_REG23 0x23
79*4882a593Smuzhiyun #define ET_REG24 0x24
80*4882a593Smuzhiyun #define ET_REG25 0x25
81*4882a593Smuzhiyun /* base registers for luma calculation */
82*4882a593Smuzhiyun #define ET_LUMA_CENTER 0x39
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun #define ET_G_RED 0x4d
85*4882a593Smuzhiyun #define ET_G_GREEN1 0x4e
86*4882a593Smuzhiyun #define ET_G_BLUE 0x4f
87*4882a593Smuzhiyun #define ET_G_GREEN2 0x50
88*4882a593Smuzhiyun #define ET_G_GR_H 0x51
89*4882a593Smuzhiyun #define ET_G_GB_H 0x52
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun #define ET_O_RED 0x34
92*4882a593Smuzhiyun #define ET_O_GREEN1 0x35
93*4882a593Smuzhiyun #define ET_O_BLUE 0x36
94*4882a593Smuzhiyun #define ET_O_GREEN2 0x37
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun #define ET_SYNCHRO 0x68
97*4882a593Smuzhiyun #define ET_STARTX 0x69
98*4882a593Smuzhiyun #define ET_STARTY 0x6a
99*4882a593Smuzhiyun #define ET_WIDTH_LOW 0x6b
100*4882a593Smuzhiyun #define ET_HEIGTH_LOW 0x6c
101*4882a593Smuzhiyun #define ET_W_H_HEIGTH 0x6d
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun #define ET_REG6e 0x6e		/* OBW */
104*4882a593Smuzhiyun #define ET_REG6f 0x6f		/* OBW */
105*4882a593Smuzhiyun #define ET_REG70 0x70		/* OBW_AWB */
106*4882a593Smuzhiyun #define ET_REG71 0x71		/* OBW_AWB */
107*4882a593Smuzhiyun #define ET_REG72 0x72		/* OBW_AWB */
108*4882a593Smuzhiyun #define ET_REG73 0x73		/* Clkdelay ns */
109*4882a593Smuzhiyun #define ET_REG74 0x74		/* test pattern */
110*4882a593Smuzhiyun #define ET_REG75 0x75		/* test pattern */
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun #define ET_I2C_CLK 0x8c
113*4882a593Smuzhiyun #define ET_PXL_CLK 0x60
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun #define ET_I2C_BASE 0x89
116*4882a593Smuzhiyun #define ET_I2C_COUNT 0x8a
117*4882a593Smuzhiyun #define ET_I2C_PREFETCH 0x8b
118*4882a593Smuzhiyun #define ET_I2C_REG 0x88
119*4882a593Smuzhiyun #define ET_I2C_DATA7 0x87
120*4882a593Smuzhiyun #define ET_I2C_DATA6 0x86
121*4882a593Smuzhiyun #define ET_I2C_DATA5 0x85
122*4882a593Smuzhiyun #define ET_I2C_DATA4 0x84
123*4882a593Smuzhiyun #define ET_I2C_DATA3 0x83
124*4882a593Smuzhiyun #define ET_I2C_DATA2 0x82
125*4882a593Smuzhiyun #define ET_I2C_DATA1 0x81
126*4882a593Smuzhiyun #define ET_I2C_DATA0 0x80
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun #define PAS106_REG2 0x02	/* pxlClk = systemClk/(reg2) */
129*4882a593Smuzhiyun #define PAS106_REG3 0x03	/* line/frame H [11..4] */
130*4882a593Smuzhiyun #define PAS106_REG4 0x04	/* line/frame L [3..0] */
131*4882a593Smuzhiyun #define PAS106_REG5 0x05	/* exposure time line offset(default 5) */
132*4882a593Smuzhiyun #define PAS106_REG6 0x06	/* exposure time pixel offset(default 6) */
133*4882a593Smuzhiyun #define PAS106_REG7 0x07	/* signbit Dac (default 0) */
134*4882a593Smuzhiyun #define PAS106_REG9 0x09
135*4882a593Smuzhiyun #define PAS106_REG0e 0x0e	/* global gain [4..0](default 0x0e) */
136*4882a593Smuzhiyun #define PAS106_REG13 0x13	/* end i2c write */
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun static const __u8 GainRGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun static const __u8 I2c2[] = { 0x08, 0x08, 0x08, 0x08, 0x0d };
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun static const __u8 I2c3[] = { 0x12, 0x05 };
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun static const __u8 I2c4[] = { 0x41, 0x08 };
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun /* read 'len' bytes to gspca_dev->usb_buf */
reg_r(struct gspca_dev * gspca_dev,__u16 index,__u16 len)147*4882a593Smuzhiyun static void reg_r(struct gspca_dev *gspca_dev,
148*4882a593Smuzhiyun 		  __u16 index,
149*4882a593Smuzhiyun 		  __u16 len)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	struct usb_device *dev = gspca_dev->dev;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	if (len > USB_BUF_SZ) {
154*4882a593Smuzhiyun 		gspca_err(gspca_dev, "reg_r: buffer overflow\n");
155*4882a593Smuzhiyun 		return;
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	usb_control_msg(dev,
159*4882a593Smuzhiyun 			usb_rcvctrlpipe(dev, 0),
160*4882a593Smuzhiyun 			0,
161*4882a593Smuzhiyun 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
162*4882a593Smuzhiyun 			0,
163*4882a593Smuzhiyun 			index, gspca_dev->usb_buf, len, 500);
164*4882a593Smuzhiyun 	gspca_dbg(gspca_dev, D_USBI, "reg read [%02x] -> %02x ..\n",
165*4882a593Smuzhiyun 		  index, gspca_dev->usb_buf[0]);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun 
reg_w_val(struct gspca_dev * gspca_dev,__u16 index,__u8 val)168*4882a593Smuzhiyun static void reg_w_val(struct gspca_dev *gspca_dev,
169*4882a593Smuzhiyun 			__u16 index,
170*4882a593Smuzhiyun 			__u8 val)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	struct usb_device *dev = gspca_dev->dev;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	gspca_dev->usb_buf[0] = val;
175*4882a593Smuzhiyun 	usb_control_msg(dev,
176*4882a593Smuzhiyun 			usb_sndctrlpipe(dev, 0),
177*4882a593Smuzhiyun 			0,
178*4882a593Smuzhiyun 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
179*4882a593Smuzhiyun 			0,
180*4882a593Smuzhiyun 			index, gspca_dev->usb_buf, 1, 500);
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun 
reg_w(struct gspca_dev * gspca_dev,__u16 index,const __u8 * buffer,__u16 len)183*4882a593Smuzhiyun static void reg_w(struct gspca_dev *gspca_dev,
184*4882a593Smuzhiyun 		  __u16 index,
185*4882a593Smuzhiyun 		  const __u8 *buffer,
186*4882a593Smuzhiyun 		  __u16 len)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	struct usb_device *dev = gspca_dev->dev;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	if (len > USB_BUF_SZ) {
191*4882a593Smuzhiyun 		pr_err("reg_w: buffer overflow\n");
192*4882a593Smuzhiyun 		return;
193*4882a593Smuzhiyun 	}
194*4882a593Smuzhiyun 	gspca_dbg(gspca_dev, D_USBO, "reg write [%02x] = %02x..\n",
195*4882a593Smuzhiyun 		  index, *buffer);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	memcpy(gspca_dev->usb_buf, buffer, len);
198*4882a593Smuzhiyun 	usb_control_msg(dev,
199*4882a593Smuzhiyun 			usb_sndctrlpipe(dev, 0),
200*4882a593Smuzhiyun 			0,
201*4882a593Smuzhiyun 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
202*4882a593Smuzhiyun 			0, index, gspca_dev->usb_buf, len, 500);
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
i2c_w(struct gspca_dev * gspca_dev,__u8 reg,const __u8 * buffer,int len,__u8 mode)205*4882a593Smuzhiyun static int i2c_w(struct gspca_dev *gspca_dev,
206*4882a593Smuzhiyun 		 __u8 reg,
207*4882a593Smuzhiyun 		 const __u8 *buffer,
208*4882a593Smuzhiyun 		 int len, __u8 mode)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	/* buffer should be [D0..D7] */
211*4882a593Smuzhiyun 	__u8 ptchcount;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	/* set the base address */
214*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_I2C_BASE, 0x40);
215*4882a593Smuzhiyun 					 /* sensor base for the pas106 */
216*4882a593Smuzhiyun 	/* set count and prefetch */
217*4882a593Smuzhiyun 	ptchcount = ((len & 0x07) << 4) | (mode & 0x03);
218*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_I2C_COUNT, ptchcount);
219*4882a593Smuzhiyun 	/* set the register base */
220*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_I2C_REG, reg);
221*4882a593Smuzhiyun 	while (--len >= 0)
222*4882a593Smuzhiyun 		reg_w_val(gspca_dev, ET_I2C_DATA0 + len, buffer[len]);
223*4882a593Smuzhiyun 	return 0;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
i2c_r(struct gspca_dev * gspca_dev,__u8 reg)226*4882a593Smuzhiyun static int i2c_r(struct gspca_dev *gspca_dev,
227*4882a593Smuzhiyun 			__u8 reg)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun 	/* set the base address */
230*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_I2C_BASE, 0x40);
231*4882a593Smuzhiyun 					/* sensor base for the pas106 */
232*4882a593Smuzhiyun 	/* set count and prefetch (cnd: 4 bits - mode: 4 bits) */
233*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_I2C_COUNT, 0x11);
234*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_I2C_REG, reg);	/* set the register base */
235*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_I2C_PREFETCH, 0x02);	/* prefetch */
236*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_I2C_PREFETCH, 0x00);
237*4882a593Smuzhiyun 	reg_r(gspca_dev, ET_I2C_DATA0, 1);	/* read one byte */
238*4882a593Smuzhiyun 	return 0;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun 
Et_WaitStatus(struct gspca_dev * gspca_dev)241*4882a593Smuzhiyun static int Et_WaitStatus(struct gspca_dev *gspca_dev)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun 	int retry = 10;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	while (retry--) {
246*4882a593Smuzhiyun 		reg_r(gspca_dev, ET_ClCK, 1);
247*4882a593Smuzhiyun 		if (gspca_dev->usb_buf[0] != 0)
248*4882a593Smuzhiyun 			return 1;
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun 	return 0;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun 
et_video(struct gspca_dev * gspca_dev,int on)253*4882a593Smuzhiyun static int et_video(struct gspca_dev *gspca_dev,
254*4882a593Smuzhiyun 		    int on)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun 	int ret;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_GPIO_OUT,
259*4882a593Smuzhiyun 		  on ? 0x10		/* startvideo - set Bit5 */
260*4882a593Smuzhiyun 		     : 0);		/* stopvideo */
261*4882a593Smuzhiyun 	ret = Et_WaitStatus(gspca_dev);
262*4882a593Smuzhiyun 	if (ret != 0)
263*4882a593Smuzhiyun 		gspca_err(gspca_dev, "timeout video on/off\n");
264*4882a593Smuzhiyun 	return ret;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun 
Et_init2(struct gspca_dev * gspca_dev)267*4882a593Smuzhiyun static void Et_init2(struct gspca_dev *gspca_dev)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	__u8 value;
270*4882a593Smuzhiyun 	static const __u8 FormLine[] = { 0x84, 0x03, 0x14, 0xf4, 0x01, 0x05 };
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	gspca_dbg(gspca_dev, D_STREAM, "Open Init2 ET\n");
273*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_GPIO_DIR_CTRL, 0x2f);
274*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_GPIO_OUT, 0x10);
275*4882a593Smuzhiyun 	reg_r(gspca_dev, ET_GPIO_IN, 1);
276*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_ClCK, 0x14); /* 0x14 // 0x16 enabled pattern */
277*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_CTRL, 0x1b);
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	/*  compression et subsampling */
280*4882a593Smuzhiyun 	if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv)
281*4882a593Smuzhiyun 		value = ET_COMP_VAL1;	/* 320 */
282*4882a593Smuzhiyun 	else
283*4882a593Smuzhiyun 		value = ET_COMP_VAL0;	/* 640 */
284*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_COMP, value);
285*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_MAXQt, 0x1f);
286*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_MINQt, 0x04);
287*4882a593Smuzhiyun 	/* undocumented registers */
288*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG1d, 0xff);
289*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG1e, 0xff);
290*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG1f, 0xff);
291*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG20, 0x35);
292*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG21, 0x01);
293*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG22, 0x00);
294*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG23, 0xff);
295*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG24, 0xff);
296*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG25, 0x0f);
297*4882a593Smuzhiyun 	/* colors setting */
298*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x30, 0x11);		/* 0x30 */
299*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x31, 0x40);
300*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x32, 0x00);
301*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_O_RED, 0x00);		/* 0x34 */
302*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_O_GREEN1, 0x00);
303*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_O_BLUE, 0x00);
304*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_O_GREEN2, 0x00);
305*4882a593Smuzhiyun 	/*************/
306*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_G_RED, 0x80);		/* 0x4d */
307*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_G_GREEN1, 0x80);
308*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_G_BLUE, 0x80);
309*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_G_GREEN2, 0x80);
310*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_G_GR_H, 0x00);
311*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_G_GB_H, 0x00);		/* 0x52 */
312*4882a593Smuzhiyun 	/* Window control registers */
313*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x61, 0x80);		/* use cmc_out */
314*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x62, 0x02);
315*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x63, 0x03);
316*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x64, 0x14);
317*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x65, 0x0e);
318*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x66, 0x02);
319*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x67, 0x02);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	/**************************************/
322*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_SYNCHRO, 0x8f);		/* 0x68 */
323*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_STARTX, 0x69);		/* 0x6a //0x69 */
324*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_STARTY, 0x0d);		/* 0x0d //0x0c */
325*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_WIDTH_LOW, 0x80);
326*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_HEIGTH_LOW, 0xe0);
327*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_W_H_HEIGTH, 0x60);	/* 6d */
328*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG6e, 0x86);
329*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG6f, 0x01);
330*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG70, 0x26);
331*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG71, 0x7a);
332*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG72, 0x01);
333*4882a593Smuzhiyun 	/* Clock Pattern registers ***************** */
334*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG73, 0x00);
335*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG74, 0x18);		/* 0x28 */
336*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG75, 0x0f);		/* 0x01 */
337*4882a593Smuzhiyun 	/**********************************************/
338*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x8a, 0x20);
339*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x8d, 0x0f);
340*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x8e, 0x08);
341*4882a593Smuzhiyun 	/**************************************/
342*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x03, 0x08);
343*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_PXL_CLK, 0x03);
344*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x81, 0xff);
345*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x80, 0x00);
346*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x81, 0xff);
347*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x80, 0x20);
348*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x03, 0x01);
349*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x03, 0x00);
350*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x03, 0x08);
351*4882a593Smuzhiyun 	/********************************************/
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun /*	reg_r(gspca_dev, ET_I2C_BASE, 1);
354*4882a593Smuzhiyun 					 always 0x40 as the pas106 ??? */
355*4882a593Smuzhiyun 	/* set the sensor */
356*4882a593Smuzhiyun 	if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv)
357*4882a593Smuzhiyun 		value = 0x04;		/* 320 */
358*4882a593Smuzhiyun 	else				/* 640 */
359*4882a593Smuzhiyun 		value = 0x1e;	/* 0x17	 * setting PixelClock
360*4882a593Smuzhiyun 					 * 0x03 mean 24/(3+1) = 6 Mhz
361*4882a593Smuzhiyun 					 * 0x05 -> 24/(5+1) = 4 Mhz
362*4882a593Smuzhiyun 					 * 0x0b -> 24/(11+1) = 2 Mhz
363*4882a593Smuzhiyun 					 * 0x17 -> 24/(23+1) = 1 Mhz
364*4882a593Smuzhiyun 					 */
365*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_PXL_CLK, value);
366*4882a593Smuzhiyun 	/* now set by fifo the FormatLine setting */
367*4882a593Smuzhiyun 	reg_w(gspca_dev, 0x62, FormLine, 6);
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	/* set exposure times [ 0..0x78] 0->longvalue 0x78->shortvalue */
370*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x81, 0x47);	/* 0x47; */
371*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x80, 0x40);	/* 0x40; */
372*4882a593Smuzhiyun 	/* Pedro change */
373*4882a593Smuzhiyun 	/* Brightness change Brith+ decrease value */
374*4882a593Smuzhiyun 	/* Brigth- increase value */
375*4882a593Smuzhiyun 	/* original value = 0x70; */
376*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x81, 0x30);	/* 0x20; - set brightness */
377*4882a593Smuzhiyun 	reg_w_val(gspca_dev, 0x80, 0x20);	/* 0x20; */
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun 
setbrightness(struct gspca_dev * gspca_dev,s32 val)380*4882a593Smuzhiyun static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun 	int i;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	for (i = 0; i < 4; i++)
385*4882a593Smuzhiyun 		reg_w_val(gspca_dev, ET_O_RED + i, val);
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun 
setcontrast(struct gspca_dev * gspca_dev,s32 val)388*4882a593Smuzhiyun static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun 	__u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	memset(RGBG, val, sizeof(RGBG) - 2);
393*4882a593Smuzhiyun 	reg_w(gspca_dev, ET_G_RED, RGBG, 6);
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun 
setcolors(struct gspca_dev * gspca_dev,s32 val)396*4882a593Smuzhiyun static void setcolors(struct gspca_dev *gspca_dev, s32 val)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun 	struct sd *sd = (struct sd *) gspca_dev;
399*4882a593Smuzhiyun 	__u8 I2cc[] = { 0x05, 0x02, 0x02, 0x05, 0x0d };
400*4882a593Smuzhiyun 	__u8 i2cflags = 0x01;
401*4882a593Smuzhiyun 	/* __u8 green = 0; */
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	I2cc[3] = val;	/* red */
404*4882a593Smuzhiyun 	I2cc[0] = 15 - val;	/* blue */
405*4882a593Smuzhiyun 	/* green = 15 - ((((7*I2cc[0]) >> 2 ) + I2cc[3]) >> 1); */
406*4882a593Smuzhiyun 	/* I2cc[1] = I2cc[2] = green; */
407*4882a593Smuzhiyun 	if (sd->sensor == SENSOR_PAS106) {
408*4882a593Smuzhiyun 		i2c_w(gspca_dev, PAS106_REG13, &i2cflags, 1, 3);
409*4882a593Smuzhiyun 		i2c_w(gspca_dev, PAS106_REG9, I2cc, sizeof I2cc, 1);
410*4882a593Smuzhiyun 	}
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun 
getcolors(struct gspca_dev * gspca_dev)413*4882a593Smuzhiyun static s32 getcolors(struct gspca_dev *gspca_dev)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun 	struct sd *sd = (struct sd *) gspca_dev;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	if (sd->sensor == SENSOR_PAS106) {
418*4882a593Smuzhiyun /*		i2c_r(gspca_dev, PAS106_REG9);		 * blue */
419*4882a593Smuzhiyun 		i2c_r(gspca_dev, PAS106_REG9 + 3);	/* red */
420*4882a593Smuzhiyun 		return gspca_dev->usb_buf[0] & 0x0f;
421*4882a593Smuzhiyun 	}
422*4882a593Smuzhiyun 	return 0;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
setautogain(struct gspca_dev * gspca_dev)425*4882a593Smuzhiyun static void setautogain(struct gspca_dev *gspca_dev)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun 	struct sd *sd = (struct sd *) gspca_dev;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	if (sd->autogain)
430*4882a593Smuzhiyun 		sd->ag_cnt = AG_CNT_START;
431*4882a593Smuzhiyun 	else
432*4882a593Smuzhiyun 		sd->ag_cnt = -1;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun 
Et_init1(struct gspca_dev * gspca_dev)435*4882a593Smuzhiyun static void Et_init1(struct gspca_dev *gspca_dev)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun 	__u8 value;
438*4882a593Smuzhiyun /*	__u8 I2c0 [] = {0x0a, 0x12, 0x05, 0x22, 0xac, 0x00, 0x01, 0x00}; */
439*4882a593Smuzhiyun 	__u8 I2c0[] = { 0x0a, 0x12, 0x05, 0x6d, 0xcd, 0x00, 0x01, 0x00 };
440*4882a593Smuzhiyun 						/* try 1/120 0x6d 0xcd 0x40 */
441*4882a593Smuzhiyun /*	__u8 I2c0 [] = {0x0a, 0x12, 0x05, 0xfe, 0xfe, 0xc0, 0x01, 0x00};
442*4882a593Smuzhiyun 						 * 1/60000 hmm ?? */
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	gspca_dbg(gspca_dev, D_STREAM, "Open Init1 ET\n\n");
445*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_GPIO_DIR_CTRL, 7);
446*4882a593Smuzhiyun 	reg_r(gspca_dev, ET_GPIO_IN, 1);
447*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_RESET_ALL, 1);
448*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_RESET_ALL, 0);
449*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_ClCK, 0x10);
450*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_CTRL, 0x19);
451*4882a593Smuzhiyun 	/*   compression et subsampling */
452*4882a593Smuzhiyun 	if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv)
453*4882a593Smuzhiyun 		value = ET_COMP_VAL1;
454*4882a593Smuzhiyun 	else
455*4882a593Smuzhiyun 		value = ET_COMP_VAL0;
456*4882a593Smuzhiyun 	gspca_dbg(gspca_dev, D_STREAM, "Open mode %d Compression %d\n",
457*4882a593Smuzhiyun 		  gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv,
458*4882a593Smuzhiyun 		  value);
459*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_COMP, value);
460*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_MAXQt, 0x1d);
461*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_MINQt, 0x02);
462*4882a593Smuzhiyun 	/* undocumented registers */
463*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG1d, 0xff);
464*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG1e, 0xff);
465*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG1f, 0xff);
466*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG20, 0x35);
467*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG21, 0x01);
468*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG22, 0x00);
469*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG23, 0xf7);
470*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG24, 0xff);
471*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG25, 0x07);
472*4882a593Smuzhiyun 	/* colors setting */
473*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_G_RED, 0x80);
474*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_G_GREEN1, 0x80);
475*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_G_BLUE, 0x80);
476*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_G_GREEN2, 0x80);
477*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_G_GR_H, 0x00);
478*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_G_GB_H, 0x00);
479*4882a593Smuzhiyun 	/* Window control registers */
480*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_SYNCHRO, 0xf0);
481*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_STARTX, 0x56);		/* 0x56 */
482*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_STARTY, 0x05);		/* 0x04 */
483*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_WIDTH_LOW, 0x60);
484*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_HEIGTH_LOW, 0x20);
485*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_W_H_HEIGTH, 0x50);
486*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG6e, 0x86);
487*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG6f, 0x01);
488*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG70, 0x86);
489*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG71, 0x14);
490*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG72, 0x00);
491*4882a593Smuzhiyun 	/* Clock Pattern registers */
492*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG73, 0x00);
493*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG74, 0x00);
494*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_REG75, 0x0a);
495*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_I2C_CLK, 0x04);
496*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_PXL_CLK, 0x01);
497*4882a593Smuzhiyun 	/* set the sensor */
498*4882a593Smuzhiyun 	if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
499*4882a593Smuzhiyun 		I2c0[0] = 0x06;
500*4882a593Smuzhiyun 		i2c_w(gspca_dev, PAS106_REG2, I2c0, sizeof I2c0, 1);
501*4882a593Smuzhiyun 		i2c_w(gspca_dev, PAS106_REG9, I2c2, sizeof I2c2, 1);
502*4882a593Smuzhiyun 		value = 0x06;
503*4882a593Smuzhiyun 		i2c_w(gspca_dev, PAS106_REG2, &value, 1, 1);
504*4882a593Smuzhiyun 		i2c_w(gspca_dev, PAS106_REG3, I2c3, sizeof I2c3, 1);
505*4882a593Smuzhiyun 		/* value = 0x1f; */
506*4882a593Smuzhiyun 		value = 0x04;
507*4882a593Smuzhiyun 		i2c_w(gspca_dev, PAS106_REG0e, &value, 1, 1);
508*4882a593Smuzhiyun 	} else {
509*4882a593Smuzhiyun 		I2c0[0] = 0x0a;
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 		i2c_w(gspca_dev, PAS106_REG2, I2c0, sizeof I2c0, 1);
512*4882a593Smuzhiyun 		i2c_w(gspca_dev, PAS106_REG9, I2c2, sizeof I2c2, 1);
513*4882a593Smuzhiyun 		value = 0x0a;
514*4882a593Smuzhiyun 		i2c_w(gspca_dev, PAS106_REG2, &value, 1, 1);
515*4882a593Smuzhiyun 		i2c_w(gspca_dev, PAS106_REG3, I2c3, sizeof I2c3, 1);
516*4882a593Smuzhiyun 		value = 0x04;
517*4882a593Smuzhiyun 		/* value = 0x10; */
518*4882a593Smuzhiyun 		i2c_w(gspca_dev, PAS106_REG0e, &value, 1, 1);
519*4882a593Smuzhiyun 		/* bit 2 enable bit 1:2 select 0 1 2 3
520*4882a593Smuzhiyun 		   value = 0x07;                                * curve 0 *
521*4882a593Smuzhiyun 		   i2c_w(gspca_dev, PAS106_REG0f, &value, 1, 1);
522*4882a593Smuzhiyun 		 */
523*4882a593Smuzhiyun 	}
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun /*	value = 0x01; */
526*4882a593Smuzhiyun /*	value = 0x22; */
527*4882a593Smuzhiyun /*	i2c_w(gspca_dev, PAS106_REG5, &value, 1, 1); */
528*4882a593Smuzhiyun 	/* magnetude and sign bit for DAC */
529*4882a593Smuzhiyun 	i2c_w(gspca_dev, PAS106_REG7, I2c4, sizeof I2c4, 1);
530*4882a593Smuzhiyun 	/* now set by fifo the whole colors setting */
531*4882a593Smuzhiyun 	reg_w(gspca_dev, ET_G_RED, GainRGBG, 6);
532*4882a593Smuzhiyun 	setcolors(gspca_dev, getcolors(gspca_dev));
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun /* this function is called at probe time */
sd_config(struct gspca_dev * gspca_dev,const struct usb_device_id * id)536*4882a593Smuzhiyun static int sd_config(struct gspca_dev *gspca_dev,
537*4882a593Smuzhiyun 		     const struct usb_device_id *id)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun 	struct sd *sd = (struct sd *) gspca_dev;
540*4882a593Smuzhiyun 	struct cam *cam;
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	cam = &gspca_dev->cam;
543*4882a593Smuzhiyun 	sd->sensor = id->driver_info;
544*4882a593Smuzhiyun 	if (sd->sensor == SENSOR_PAS106) {
545*4882a593Smuzhiyun 		cam->cam_mode = sif_mode;
546*4882a593Smuzhiyun 		cam->nmodes = ARRAY_SIZE(sif_mode);
547*4882a593Smuzhiyun 	} else {
548*4882a593Smuzhiyun 		cam->cam_mode = vga_mode;
549*4882a593Smuzhiyun 		cam->nmodes = ARRAY_SIZE(vga_mode);
550*4882a593Smuzhiyun 	}
551*4882a593Smuzhiyun 	sd->ag_cnt = -1;
552*4882a593Smuzhiyun 	return 0;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun /* this function is called at probe and resume time */
sd_init(struct gspca_dev * gspca_dev)556*4882a593Smuzhiyun static int sd_init(struct gspca_dev *gspca_dev)
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun 	struct sd *sd = (struct sd *) gspca_dev;
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	if (sd->sensor == SENSOR_PAS106)
561*4882a593Smuzhiyun 		Et_init1(gspca_dev);
562*4882a593Smuzhiyun 	else
563*4882a593Smuzhiyun 		Et_init2(gspca_dev);
564*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_RESET_ALL, 0x08);
565*4882a593Smuzhiyun 	et_video(gspca_dev, 0);		/* video off */
566*4882a593Smuzhiyun 	return 0;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun /* -- start the camera -- */
sd_start(struct gspca_dev * gspca_dev)570*4882a593Smuzhiyun static int sd_start(struct gspca_dev *gspca_dev)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun 	struct sd *sd = (struct sd *) gspca_dev;
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	if (sd->sensor == SENSOR_PAS106)
575*4882a593Smuzhiyun 		Et_init1(gspca_dev);
576*4882a593Smuzhiyun 	else
577*4882a593Smuzhiyun 		Et_init2(gspca_dev);
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	setautogain(gspca_dev);
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	reg_w_val(gspca_dev, ET_RESET_ALL, 0x08);
582*4882a593Smuzhiyun 	et_video(gspca_dev, 1);		/* video on */
583*4882a593Smuzhiyun 	return 0;
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun 
sd_stopN(struct gspca_dev * gspca_dev)586*4882a593Smuzhiyun static void sd_stopN(struct gspca_dev *gspca_dev)
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun 	et_video(gspca_dev, 0);		/* video off */
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun 
Et_getgainG(struct gspca_dev * gspca_dev)591*4882a593Smuzhiyun static __u8 Et_getgainG(struct gspca_dev *gspca_dev)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun 	struct sd *sd = (struct sd *) gspca_dev;
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	if (sd->sensor == SENSOR_PAS106) {
596*4882a593Smuzhiyun 		i2c_r(gspca_dev, PAS106_REG0e);
597*4882a593Smuzhiyun 		gspca_dbg(gspca_dev, D_CONF, "Etoms gain G %d\n",
598*4882a593Smuzhiyun 			  gspca_dev->usb_buf[0]);
599*4882a593Smuzhiyun 		return gspca_dev->usb_buf[0];
600*4882a593Smuzhiyun 	}
601*4882a593Smuzhiyun 	return 0x1f;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
Et_setgainG(struct gspca_dev * gspca_dev,__u8 gain)604*4882a593Smuzhiyun static void Et_setgainG(struct gspca_dev *gspca_dev, __u8 gain)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun 	struct sd *sd = (struct sd *) gspca_dev;
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	if (sd->sensor == SENSOR_PAS106) {
609*4882a593Smuzhiyun 		__u8 i2cflags = 0x01;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 		i2c_w(gspca_dev, PAS106_REG13, &i2cflags, 1, 3);
612*4882a593Smuzhiyun 		i2c_w(gspca_dev, PAS106_REG0e, &gain, 1, 1);
613*4882a593Smuzhiyun 	}
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun #define BLIMIT(bright) \
617*4882a593Smuzhiyun 	(u8)((bright > 0x1f) ? 0x1f : ((bright < 4) ? 3 : bright))
618*4882a593Smuzhiyun #define LIMIT(color) \
619*4882a593Smuzhiyun 	(u8)((color > 0xff) ? 0xff : ((color < 0) ? 0 : color))
620*4882a593Smuzhiyun 
do_autogain(struct gspca_dev * gspca_dev)621*4882a593Smuzhiyun static void do_autogain(struct gspca_dev *gspca_dev)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun 	struct sd *sd = (struct sd *) gspca_dev;
624*4882a593Smuzhiyun 	__u8 luma;
625*4882a593Smuzhiyun 	__u8 luma_mean = 128;
626*4882a593Smuzhiyun 	__u8 luma_delta = 20;
627*4882a593Smuzhiyun 	__u8 spring = 4;
628*4882a593Smuzhiyun 	int Gbright;
629*4882a593Smuzhiyun 	__u8 r, g, b;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	if (sd->ag_cnt < 0)
632*4882a593Smuzhiyun 		return;
633*4882a593Smuzhiyun 	if (--sd->ag_cnt >= 0)
634*4882a593Smuzhiyun 		return;
635*4882a593Smuzhiyun 	sd->ag_cnt = AG_CNT_START;
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	Gbright = Et_getgainG(gspca_dev);
638*4882a593Smuzhiyun 	reg_r(gspca_dev, ET_LUMA_CENTER, 4);
639*4882a593Smuzhiyun 	g = (gspca_dev->usb_buf[0] + gspca_dev->usb_buf[3]) >> 1;
640*4882a593Smuzhiyun 	r = gspca_dev->usb_buf[1];
641*4882a593Smuzhiyun 	b = gspca_dev->usb_buf[2];
642*4882a593Smuzhiyun 	r = ((r << 8) - (r << 4) - (r << 3)) >> 10;
643*4882a593Smuzhiyun 	b = ((b << 7) >> 10);
644*4882a593Smuzhiyun 	g = ((g << 9) + (g << 7) + (g << 5)) >> 10;
645*4882a593Smuzhiyun 	luma = LIMIT(r + g + b);
646*4882a593Smuzhiyun 	gspca_dbg(gspca_dev, D_FRAM, "Etoms luma G %d\n", luma);
647*4882a593Smuzhiyun 	if (luma < luma_mean - luma_delta || luma > luma_mean + luma_delta) {
648*4882a593Smuzhiyun 		Gbright += (luma_mean - luma) >> spring;
649*4882a593Smuzhiyun 		Gbright = BLIMIT(Gbright);
650*4882a593Smuzhiyun 		gspca_dbg(gspca_dev, D_FRAM, "Etoms Gbright %d\n", Gbright);
651*4882a593Smuzhiyun 		Et_setgainG(gspca_dev, (__u8) Gbright);
652*4882a593Smuzhiyun 	}
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun #undef BLIMIT
656*4882a593Smuzhiyun #undef LIMIT
657*4882a593Smuzhiyun 
sd_pkt_scan(struct gspca_dev * gspca_dev,u8 * data,int len)658*4882a593Smuzhiyun static void sd_pkt_scan(struct gspca_dev *gspca_dev,
659*4882a593Smuzhiyun 			u8 *data,			/* isoc packet */
660*4882a593Smuzhiyun 			int len)			/* iso packet length */
661*4882a593Smuzhiyun {
662*4882a593Smuzhiyun 	int seqframe;
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	seqframe = data[0] & 0x3f;
665*4882a593Smuzhiyun 	len = (int) (((data[0] & 0xc0) << 2) | data[1]);
666*4882a593Smuzhiyun 	if (seqframe == 0x3f) {
667*4882a593Smuzhiyun 		gspca_dbg(gspca_dev, D_FRAM,
668*4882a593Smuzhiyun 			  "header packet found datalength %d !!\n", len);
669*4882a593Smuzhiyun 		gspca_dbg(gspca_dev, D_FRAM, "G %d R %d G %d B %d",
670*4882a593Smuzhiyun 			  data[2], data[3], data[4], data[5]);
671*4882a593Smuzhiyun 		data += 30;
672*4882a593Smuzhiyun 		/* don't change datalength as the chips provided it */
673*4882a593Smuzhiyun 		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
674*4882a593Smuzhiyun 		gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
675*4882a593Smuzhiyun 		return;
676*4882a593Smuzhiyun 	}
677*4882a593Smuzhiyun 	if (len) {
678*4882a593Smuzhiyun 		data += 8;
679*4882a593Smuzhiyun 		gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
680*4882a593Smuzhiyun 	} else {			/* Drop Packet */
681*4882a593Smuzhiyun 		gspca_dev->last_packet_type = DISCARD_PACKET;
682*4882a593Smuzhiyun 	}
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun 
sd_s_ctrl(struct v4l2_ctrl * ctrl)685*4882a593Smuzhiyun static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
686*4882a593Smuzhiyun {
687*4882a593Smuzhiyun 	struct gspca_dev *gspca_dev =
688*4882a593Smuzhiyun 		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
689*4882a593Smuzhiyun 	struct sd *sd = (struct sd *)gspca_dev;
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	gspca_dev->usb_err = 0;
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	if (!gspca_dev->streaming)
694*4882a593Smuzhiyun 		return 0;
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	switch (ctrl->id) {
697*4882a593Smuzhiyun 	case V4L2_CID_BRIGHTNESS:
698*4882a593Smuzhiyun 		setbrightness(gspca_dev, ctrl->val);
699*4882a593Smuzhiyun 		break;
700*4882a593Smuzhiyun 	case V4L2_CID_CONTRAST:
701*4882a593Smuzhiyun 		setcontrast(gspca_dev, ctrl->val);
702*4882a593Smuzhiyun 		break;
703*4882a593Smuzhiyun 	case V4L2_CID_SATURATION:
704*4882a593Smuzhiyun 		setcolors(gspca_dev, ctrl->val);
705*4882a593Smuzhiyun 		break;
706*4882a593Smuzhiyun 	case V4L2_CID_AUTOGAIN:
707*4882a593Smuzhiyun 		sd->autogain = ctrl->val;
708*4882a593Smuzhiyun 		setautogain(gspca_dev);
709*4882a593Smuzhiyun 		break;
710*4882a593Smuzhiyun 	}
711*4882a593Smuzhiyun 	return gspca_dev->usb_err;
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun static const struct v4l2_ctrl_ops sd_ctrl_ops = {
715*4882a593Smuzhiyun 	.s_ctrl = sd_s_ctrl,
716*4882a593Smuzhiyun };
717*4882a593Smuzhiyun 
sd_init_controls(struct gspca_dev * gspca_dev)718*4882a593Smuzhiyun static int sd_init_controls(struct gspca_dev *gspca_dev)
719*4882a593Smuzhiyun {
720*4882a593Smuzhiyun 	struct sd *sd = (struct sd *)gspca_dev;
721*4882a593Smuzhiyun 	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	gspca_dev->vdev.ctrl_handler = hdl;
724*4882a593Smuzhiyun 	v4l2_ctrl_handler_init(hdl, 4);
725*4882a593Smuzhiyun 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
726*4882a593Smuzhiyun 			V4L2_CID_BRIGHTNESS, 1, 127, 1, 63);
727*4882a593Smuzhiyun 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
728*4882a593Smuzhiyun 			V4L2_CID_CONTRAST, 0, 255, 1, 127);
729*4882a593Smuzhiyun 	if (sd->sensor == SENSOR_PAS106)
730*4882a593Smuzhiyun 		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
731*4882a593Smuzhiyun 			V4L2_CID_SATURATION, 0, 15, 1, 7);
732*4882a593Smuzhiyun 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
733*4882a593Smuzhiyun 			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
734*4882a593Smuzhiyun 	if (hdl->error) {
735*4882a593Smuzhiyun 		pr_err("Could not initialize controls\n");
736*4882a593Smuzhiyun 		return hdl->error;
737*4882a593Smuzhiyun 	}
738*4882a593Smuzhiyun 	return 0;
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun /* sub-driver description */
742*4882a593Smuzhiyun static const struct sd_desc sd_desc = {
743*4882a593Smuzhiyun 	.name = MODULE_NAME,
744*4882a593Smuzhiyun 	.config = sd_config,
745*4882a593Smuzhiyun 	.init = sd_init,
746*4882a593Smuzhiyun 	.init_controls = sd_init_controls,
747*4882a593Smuzhiyun 	.start = sd_start,
748*4882a593Smuzhiyun 	.stopN = sd_stopN,
749*4882a593Smuzhiyun 	.pkt_scan = sd_pkt_scan,
750*4882a593Smuzhiyun 	.dq_callback = do_autogain,
751*4882a593Smuzhiyun };
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun /* -- module initialisation -- */
754*4882a593Smuzhiyun static const struct usb_device_id device_table[] = {
755*4882a593Smuzhiyun 	{USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106},
756*4882a593Smuzhiyun 	{USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX},
757*4882a593Smuzhiyun 	{}
758*4882a593Smuzhiyun };
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, device_table);
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun /* -- device connect -- */
sd_probe(struct usb_interface * intf,const struct usb_device_id * id)763*4882a593Smuzhiyun static int sd_probe(struct usb_interface *intf,
764*4882a593Smuzhiyun 		    const struct usb_device_id *id)
765*4882a593Smuzhiyun {
766*4882a593Smuzhiyun 	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
767*4882a593Smuzhiyun 			       THIS_MODULE);
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun static struct usb_driver sd_driver = {
771*4882a593Smuzhiyun 	.name = MODULE_NAME,
772*4882a593Smuzhiyun 	.id_table = device_table,
773*4882a593Smuzhiyun 	.probe = sd_probe,
774*4882a593Smuzhiyun 	.disconnect = gspca_disconnect,
775*4882a593Smuzhiyun #ifdef CONFIG_PM
776*4882a593Smuzhiyun 	.suspend = gspca_suspend,
777*4882a593Smuzhiyun 	.resume = gspca_resume,
778*4882a593Smuzhiyun 	.reset_resume = gspca_resume,
779*4882a593Smuzhiyun #endif
780*4882a593Smuzhiyun };
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun module_usb_driver(sd_driver);
783