xref: /linux/drivers/media/usb/gspca/spca505.c (revision fd9871f70c3ae52b3ea199069ad6879645402952)
1*fd9871f7SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20c0d06caSMauro Carvalho Chehab /*
30c0d06caSMauro Carvalho Chehab  * SPCA505 chip based cameras initialization data
40c0d06caSMauro Carvalho Chehab  *
50c0d06caSMauro Carvalho Chehab  * V4L2 by Jean-Francis Moine <http://moinejf.free.fr>
60c0d06caSMauro Carvalho Chehab  */
70c0d06caSMauro Carvalho Chehab 
80c0d06caSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
90c0d06caSMauro Carvalho Chehab 
100c0d06caSMauro Carvalho Chehab #define MODULE_NAME "spca505"
110c0d06caSMauro Carvalho Chehab 
120c0d06caSMauro Carvalho Chehab #include "gspca.h"
130c0d06caSMauro Carvalho Chehab 
140c0d06caSMauro Carvalho Chehab MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
150c0d06caSMauro Carvalho Chehab MODULE_DESCRIPTION("GSPCA/SPCA505 USB Camera Driver");
160c0d06caSMauro Carvalho Chehab MODULE_LICENSE("GPL");
170c0d06caSMauro Carvalho Chehab 
180c0d06caSMauro Carvalho Chehab /* specific webcam descriptor */
190c0d06caSMauro Carvalho Chehab struct sd {
200c0d06caSMauro Carvalho Chehab 	struct gspca_dev gspca_dev;		/* !! must be the first item */
210c0d06caSMauro Carvalho Chehab 
220c0d06caSMauro Carvalho Chehab 	u8 subtype;
230c0d06caSMauro Carvalho Chehab #define IntelPCCameraPro 0
240c0d06caSMauro Carvalho Chehab #define Nxultra 1
250c0d06caSMauro Carvalho Chehab };
260c0d06caSMauro Carvalho Chehab 
270c0d06caSMauro Carvalho Chehab static const struct v4l2_pix_format vga_mode[] = {
280c0d06caSMauro Carvalho Chehab 	{160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
290c0d06caSMauro Carvalho Chehab 		.bytesperline = 160,
300c0d06caSMauro Carvalho Chehab 		.sizeimage = 160 * 120 * 3 / 2,
310c0d06caSMauro Carvalho Chehab 		.colorspace = V4L2_COLORSPACE_SRGB,
320c0d06caSMauro Carvalho Chehab 		.priv = 4},
330c0d06caSMauro Carvalho Chehab 	{176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
340c0d06caSMauro Carvalho Chehab 		.bytesperline = 176,
350c0d06caSMauro Carvalho Chehab 		.sizeimage = 176 * 144 * 3 / 2,
360c0d06caSMauro Carvalho Chehab 		.colorspace = V4L2_COLORSPACE_SRGB,
370c0d06caSMauro Carvalho Chehab 		.priv = 3},
380c0d06caSMauro Carvalho Chehab 	{320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
390c0d06caSMauro Carvalho Chehab 		.bytesperline = 320,
400c0d06caSMauro Carvalho Chehab 		.sizeimage = 320 * 240 * 3 / 2,
410c0d06caSMauro Carvalho Chehab 		.colorspace = V4L2_COLORSPACE_SRGB,
420c0d06caSMauro Carvalho Chehab 		.priv = 2},
430c0d06caSMauro Carvalho Chehab 	{352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
440c0d06caSMauro Carvalho Chehab 		.bytesperline = 352,
450c0d06caSMauro Carvalho Chehab 		.sizeimage = 352 * 288 * 3 / 2,
460c0d06caSMauro Carvalho Chehab 		.colorspace = V4L2_COLORSPACE_SRGB,
470c0d06caSMauro Carvalho Chehab 		.priv = 1},
480c0d06caSMauro Carvalho Chehab 	{640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
490c0d06caSMauro Carvalho Chehab 		.bytesperline = 640,
500c0d06caSMauro Carvalho Chehab 		.sizeimage = 640 * 480 * 3 / 2,
510c0d06caSMauro Carvalho Chehab 		.colorspace = V4L2_COLORSPACE_SRGB,
520c0d06caSMauro Carvalho Chehab 		.priv = 0},
530c0d06caSMauro Carvalho Chehab };
540c0d06caSMauro Carvalho Chehab 
550c0d06caSMauro Carvalho Chehab #define SPCA50X_OFFSET_DATA 10
560c0d06caSMauro Carvalho Chehab 
570c0d06caSMauro Carvalho Chehab #define SPCA50X_REG_USB 0x02	/* spca505 501 */
580c0d06caSMauro Carvalho Chehab 
590c0d06caSMauro Carvalho Chehab #define SPCA50X_USB_CTRL 0x00	/* spca505 */
600c0d06caSMauro Carvalho Chehab #define SPCA50X_CUSB_ENABLE 0x01 /* spca505 */
610c0d06caSMauro Carvalho Chehab 
620c0d06caSMauro Carvalho Chehab #define SPCA50X_REG_GLOBAL 0x03	/* spca505 */
630c0d06caSMauro Carvalho Chehab #define SPCA50X_GMISC0_IDSEL 0x01 /* Global control device ID select spca505 */
640c0d06caSMauro Carvalho Chehab #define SPCA50X_GLOBAL_MISC0 0x00 /* Global control miscellaneous 0 spca505 */
650c0d06caSMauro Carvalho Chehab 
660c0d06caSMauro Carvalho Chehab #define SPCA50X_GLOBAL_MISC1 0x01 /* 505 */
670c0d06caSMauro Carvalho Chehab #define SPCA50X_GLOBAL_MISC3 0x03 /* 505 */
680c0d06caSMauro Carvalho Chehab #define SPCA50X_GMISC3_SAA7113RST 0x20	/* Not sure about this one spca505 */
690c0d06caSMauro Carvalho Chehab 
700c0d06caSMauro Carvalho Chehab /* Image format and compression control */
710c0d06caSMauro Carvalho Chehab #define SPCA50X_REG_COMPRESS 0x04
720c0d06caSMauro Carvalho Chehab 
730c0d06caSMauro Carvalho Chehab /*
740c0d06caSMauro Carvalho Chehab  * Data to initialize a SPCA505. Common to the CCD and external modes
750c0d06caSMauro Carvalho Chehab  */
760c0d06caSMauro Carvalho Chehab static const u8 spca505_init_data[][3] = {
770c0d06caSMauro Carvalho Chehab 	/* bmRequest,value,index */
780c0d06caSMauro Carvalho Chehab 	{SPCA50X_REG_GLOBAL, SPCA50X_GMISC3_SAA7113RST, SPCA50X_GLOBAL_MISC3},
790c0d06caSMauro Carvalho Chehab 	/* Sensor reset */
800c0d06caSMauro Carvalho Chehab 	{SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC3},
810c0d06caSMauro Carvalho Chehab 	{SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC1},
820c0d06caSMauro Carvalho Chehab 	/* Block USB reset */
830c0d06caSMauro Carvalho Chehab 	{SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL, SPCA50X_GLOBAL_MISC0},
840c0d06caSMauro Carvalho Chehab 
850c0d06caSMauro Carvalho Chehab 	{0x05, 0x01, 0x10},
860c0d06caSMauro Carvalho Chehab 					/* Maybe power down some stuff */
870c0d06caSMauro Carvalho Chehab 	{0x05, 0x0f, 0x11},
880c0d06caSMauro Carvalho Chehab 
890c0d06caSMauro Carvalho Chehab 	/* Setup internal CCD  ? */
900c0d06caSMauro Carvalho Chehab 	{0x06, 0x10, 0x08},
910c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x09},
920c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x0a},
930c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x0b},
940c0d06caSMauro Carvalho Chehab 	{0x06, 0x10, 0x0c},
950c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x0d},
960c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x0e},
970c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x0f},
980c0d06caSMauro Carvalho Chehab 	{0x06, 0x10, 0x10},
990c0d06caSMauro Carvalho Chehab 	{0x06, 0x02, 0x11},
1000c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x12},
1010c0d06caSMauro Carvalho Chehab 	{0x06, 0x04, 0x13},
1020c0d06caSMauro Carvalho Chehab 	{0x06, 0x02, 0x14},
1030c0d06caSMauro Carvalho Chehab 	{0x06, 0x8a, 0x51},
1040c0d06caSMauro Carvalho Chehab 	{0x06, 0x40, 0x52},
1050c0d06caSMauro Carvalho Chehab 	{0x06, 0xb6, 0x53},
1060c0d06caSMauro Carvalho Chehab 	{0x06, 0x3d, 0x54},
1070c0d06caSMauro Carvalho Chehab 	{}
1080c0d06caSMauro Carvalho Chehab };
1090c0d06caSMauro Carvalho Chehab 
1100c0d06caSMauro Carvalho Chehab /*
1110c0d06caSMauro Carvalho Chehab  * Data to initialize the camera using the internal CCD
1120c0d06caSMauro Carvalho Chehab  */
1130c0d06caSMauro Carvalho Chehab static const u8 spca505_open_data_ccd[][3] = {
1140c0d06caSMauro Carvalho Chehab 	/* bmRequest,value,index */
1150c0d06caSMauro Carvalho Chehab 	/* Internal CCD data set */
1160c0d06caSMauro Carvalho Chehab 	{0x03, 0x04, 0x01},
1170c0d06caSMauro Carvalho Chehab 	/* This could be a reset */
1180c0d06caSMauro Carvalho Chehab 	{0x03, 0x00, 0x01},
1190c0d06caSMauro Carvalho Chehab 
1200c0d06caSMauro Carvalho Chehab 	/* Setup compression and image registers. 0x6 and 0x7 seem to be
1210c0d06caSMauro Carvalho Chehab 	   related to H&V hold, and are resolution mode specific */
1220c0d06caSMauro Carvalho Chehab 		{0x04, 0x10, 0x01},
1230c0d06caSMauro Carvalho Chehab 		/* DIFF(0x50), was (0x10) */
1240c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x04},
1250c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x05},
1260c0d06caSMauro Carvalho Chehab 	{0x04, 0x20, 0x06},
1270c0d06caSMauro Carvalho Chehab 	{0x04, 0x20, 0x07},
1280c0d06caSMauro Carvalho Chehab 
1290c0d06caSMauro Carvalho Chehab 	{0x08, 0x0a, 0x00},
1300c0d06caSMauro Carvalho Chehab 	/* DIFF (0x4a), was (0xa) */
1310c0d06caSMauro Carvalho Chehab 
1320c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0x10},
1330c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0x11},
1340c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0x00},
1350c0d06caSMauro Carvalho Chehab 	/* DIFF not written */
1360c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0x01},
1370c0d06caSMauro Carvalho Chehab 	/* DIFF not written */
1380c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0x02},
1390c0d06caSMauro Carvalho Chehab 	/* DIFF not written */
1400c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0x03},
1410c0d06caSMauro Carvalho Chehab 	/* DIFF not written */
1420c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0x04},
1430c0d06caSMauro Carvalho Chehab 	/* DIFF not written */
1440c0d06caSMauro Carvalho Chehab 		{0x05, 0x80, 0x05},
1450c0d06caSMauro Carvalho Chehab 		/* DIFF not written */
1460c0d06caSMauro Carvalho Chehab 		{0x05, 0xe0, 0x06},
1470c0d06caSMauro Carvalho Chehab 		/* DIFF not written */
1480c0d06caSMauro Carvalho Chehab 		{0x05, 0x20, 0x07},
1490c0d06caSMauro Carvalho Chehab 		/* DIFF not written */
1500c0d06caSMauro Carvalho Chehab 		{0x05, 0xa0, 0x08},
1510c0d06caSMauro Carvalho Chehab 		/* DIFF not written */
1520c0d06caSMauro Carvalho Chehab 		{0x05, 0x0, 0x12},
1530c0d06caSMauro Carvalho Chehab 		/* DIFF not written */
1540c0d06caSMauro Carvalho Chehab 	{0x05, 0x02, 0x0f},
1550c0d06caSMauro Carvalho Chehab 	/* DIFF not written */
1560c0d06caSMauro Carvalho Chehab 		{0x05, 0x10, 0x46},
1570c0d06caSMauro Carvalho Chehab 		/* DIFF not written */
1580c0d06caSMauro Carvalho Chehab 		{0x05, 0x8, 0x4a},
1590c0d06caSMauro Carvalho Chehab 		/* DIFF not written */
1600c0d06caSMauro Carvalho Chehab 
1610c0d06caSMauro Carvalho Chehab 	{0x03, 0x08, 0x03},
1620c0d06caSMauro Carvalho Chehab 	/* DIFF (0x3,0x28,0x3) */
1630c0d06caSMauro Carvalho Chehab 	{0x03, 0x08, 0x01},
1640c0d06caSMauro Carvalho Chehab 	{0x03, 0x0c, 0x03},
1650c0d06caSMauro Carvalho Chehab 	/* DIFF not written */
1660c0d06caSMauro Carvalho Chehab 		{0x03, 0x21, 0x00},
1670c0d06caSMauro Carvalho Chehab 		/* DIFF (0x39) */
1680c0d06caSMauro Carvalho Chehab 
1690c0d06caSMauro Carvalho Chehab /* Extra block copied from init to hopefully ensure CCD is in a sane state */
1700c0d06caSMauro Carvalho Chehab 	{0x06, 0x10, 0x08},
1710c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x09},
1720c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x0a},
1730c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x0b},
1740c0d06caSMauro Carvalho Chehab 	{0x06, 0x10, 0x0c},
1750c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x0d},
1760c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x0e},
1770c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x0f},
1780c0d06caSMauro Carvalho Chehab 	{0x06, 0x10, 0x10},
1790c0d06caSMauro Carvalho Chehab 	{0x06, 0x02, 0x11},
1800c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x12},
1810c0d06caSMauro Carvalho Chehab 	{0x06, 0x04, 0x13},
1820c0d06caSMauro Carvalho Chehab 	{0x06, 0x02, 0x14},
1830c0d06caSMauro Carvalho Chehab 	{0x06, 0x8a, 0x51},
1840c0d06caSMauro Carvalho Chehab 	{0x06, 0x40, 0x52},
1850c0d06caSMauro Carvalho Chehab 	{0x06, 0xb6, 0x53},
1860c0d06caSMauro Carvalho Chehab 	{0x06, 0x3d, 0x54},
1870c0d06caSMauro Carvalho Chehab 	/* End of extra block */
1880c0d06caSMauro Carvalho Chehab 
1890c0d06caSMauro Carvalho Chehab 		{0x06, 0x3f, 0x1},
1900c0d06caSMauro Carvalho Chehab 		/* Block skipped */
1910c0d06caSMauro Carvalho Chehab 	{0x06, 0x10, 0x02},
1920c0d06caSMauro Carvalho Chehab 	{0x06, 0x64, 0x07},
1930c0d06caSMauro Carvalho Chehab 	{0x06, 0x10, 0x08},
1940c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x09},
1950c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x0a},
1960c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x0b},
1970c0d06caSMauro Carvalho Chehab 	{0x06, 0x10, 0x0c},
1980c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x0d},
1990c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x0e},
2000c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x0f},
2010c0d06caSMauro Carvalho Chehab 	{0x06, 0x10, 0x10},
2020c0d06caSMauro Carvalho Chehab 	{0x06, 0x02, 0x11},
2030c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x12},
2040c0d06caSMauro Carvalho Chehab 	{0x06, 0x04, 0x13},
2050c0d06caSMauro Carvalho Chehab 	{0x06, 0x02, 0x14},
2060c0d06caSMauro Carvalho Chehab 	{0x06, 0x8a, 0x51},
2070c0d06caSMauro Carvalho Chehab 	{0x06, 0x40, 0x52},
2080c0d06caSMauro Carvalho Chehab 	{0x06, 0xb6, 0x53},
2090c0d06caSMauro Carvalho Chehab 	{0x06, 0x3d, 0x54},
2100c0d06caSMauro Carvalho Chehab 	{0x06, 0x60, 0x57},
2110c0d06caSMauro Carvalho Chehab 	{0x06, 0x20, 0x58},
2120c0d06caSMauro Carvalho Chehab 	{0x06, 0x15, 0x59},
2130c0d06caSMauro Carvalho Chehab 	{0x06, 0x05, 0x5a},
2140c0d06caSMauro Carvalho Chehab 
2150c0d06caSMauro Carvalho Chehab 	{0x05, 0x01, 0xc0},
2160c0d06caSMauro Carvalho Chehab 	{0x05, 0x10, 0xcb},
2170c0d06caSMauro Carvalho Chehab 		{0x05, 0x80, 0xc1},
2180c0d06caSMauro Carvalho Chehab 		/* */
2190c0d06caSMauro Carvalho Chehab 		{0x05, 0x0, 0xc2},
2200c0d06caSMauro Carvalho Chehab 		/* 4 was 0 */
2210c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0xca},
2220c0d06caSMauro Carvalho Chehab 		{0x05, 0x80, 0xc1},
2230c0d06caSMauro Carvalho Chehab 		/*  */
2240c0d06caSMauro Carvalho Chehab 	{0x05, 0x04, 0xc2},
2250c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0xca},
2260c0d06caSMauro Carvalho Chehab 		{0x05, 0x0, 0xc1},
2270c0d06caSMauro Carvalho Chehab 		/*  */
2280c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0xc2},
2290c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0xca},
2300c0d06caSMauro Carvalho Chehab 		{0x05, 0x40, 0xc1},
2310c0d06caSMauro Carvalho Chehab 		/* */
2320c0d06caSMauro Carvalho Chehab 	{0x05, 0x17, 0xc2},
2330c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0xca},
2340c0d06caSMauro Carvalho Chehab 		{0x05, 0x80, 0xc1},
2350c0d06caSMauro Carvalho Chehab 		/* */
2360c0d06caSMauro Carvalho Chehab 	{0x05, 0x06, 0xc2},
2370c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0xca},
2380c0d06caSMauro Carvalho Chehab 		{0x05, 0x80, 0xc1},
2390c0d06caSMauro Carvalho Chehab 		/* */
2400c0d06caSMauro Carvalho Chehab 	{0x05, 0x04, 0xc2},
2410c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0xca},
2420c0d06caSMauro Carvalho Chehab 
2430c0d06caSMauro Carvalho Chehab 	{0x03, 0x4c, 0x3},
2440c0d06caSMauro Carvalho Chehab 	{0x03, 0x18, 0x1},
2450c0d06caSMauro Carvalho Chehab 
2460c0d06caSMauro Carvalho Chehab 	{0x06, 0x70, 0x51},
2470c0d06caSMauro Carvalho Chehab 	{0x06, 0xbe, 0x53},
2480c0d06caSMauro Carvalho Chehab 	{0x06, 0x71, 0x57},
2490c0d06caSMauro Carvalho Chehab 	{0x06, 0x20, 0x58},
2500c0d06caSMauro Carvalho Chehab 	{0x06, 0x05, 0x59},
2510c0d06caSMauro Carvalho Chehab 	{0x06, 0x15, 0x5a},
2520c0d06caSMauro Carvalho Chehab 
2530c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x08},
2540c0d06caSMauro Carvalho Chehab 	/* Compress = OFF (0x1 to turn on) */
2550c0d06caSMauro Carvalho Chehab 	{0x04, 0x12, 0x09},
2560c0d06caSMauro Carvalho Chehab 	{0x04, 0x21, 0x0a},
2570c0d06caSMauro Carvalho Chehab 	{0x04, 0x10, 0x0b},
2580c0d06caSMauro Carvalho Chehab 	{0x04, 0x21, 0x0c},
2590c0d06caSMauro Carvalho Chehab 	{0x04, 0x05, 0x00},
2600c0d06caSMauro Carvalho Chehab 	/* was 5 (Image Type ? ) */
2610c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x01},
2620c0d06caSMauro Carvalho Chehab 
2630c0d06caSMauro Carvalho Chehab 	{0x06, 0x3f, 0x01},
2640c0d06caSMauro Carvalho Chehab 
2650c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x04},
2660c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x05},
2670c0d06caSMauro Carvalho Chehab 	{0x04, 0x40, 0x06},
2680c0d06caSMauro Carvalho Chehab 	{0x04, 0x40, 0x07},
2690c0d06caSMauro Carvalho Chehab 
2700c0d06caSMauro Carvalho Chehab 	{0x06, 0x1c, 0x17},
2710c0d06caSMauro Carvalho Chehab 	{0x06, 0xe2, 0x19},
2720c0d06caSMauro Carvalho Chehab 	{0x06, 0x1c, 0x1b},
2730c0d06caSMauro Carvalho Chehab 	{0x06, 0xe2, 0x1d},
2740c0d06caSMauro Carvalho Chehab 	{0x06, 0xaa, 0x1f},
2750c0d06caSMauro Carvalho Chehab 	{0x06, 0x70, 0x20},
2760c0d06caSMauro Carvalho Chehab 
2770c0d06caSMauro Carvalho Chehab 	{0x05, 0x01, 0x10},
2780c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0x11},
2790c0d06caSMauro Carvalho Chehab 	{0x05, 0x01, 0x00},
2800c0d06caSMauro Carvalho Chehab 	{0x05, 0x05, 0x01},
2810c0d06caSMauro Carvalho Chehab 		{0x05, 0x00, 0xc1},
2820c0d06caSMauro Carvalho Chehab 		/* */
2830c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0xc2},
2840c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0xca},
2850c0d06caSMauro Carvalho Chehab 
2860c0d06caSMauro Carvalho Chehab 	{0x06, 0x70, 0x51},
2870c0d06caSMauro Carvalho Chehab 	{0x06, 0xbe, 0x53},
2880c0d06caSMauro Carvalho Chehab 	{}
2890c0d06caSMauro Carvalho Chehab };
2900c0d06caSMauro Carvalho Chehab 
2910c0d06caSMauro Carvalho Chehab /*
2920c0d06caSMauro Carvalho Chehab  * Made by Tomasz Zablocki (skalamandra@poczta.onet.pl)
2930c0d06caSMauro Carvalho Chehab  * SPCA505b chip based cameras initialization data
2940c0d06caSMauro Carvalho Chehab  */
2950c0d06caSMauro Carvalho Chehab /* jfm */
2960c0d06caSMauro Carvalho Chehab #define initial_brightness 0x7f	/* 0x0(white)-0xff(black) */
2970c0d06caSMauro Carvalho Chehab /* #define initial_brightness 0x0	//0x0(white)-0xff(black) */
2980c0d06caSMauro Carvalho Chehab /*
2990c0d06caSMauro Carvalho Chehab  * Data to initialize a SPCA505. Common to the CCD and external modes
3000c0d06caSMauro Carvalho Chehab  */
3010c0d06caSMauro Carvalho Chehab static const u8 spca505b_init_data[][3] = {
3020c0d06caSMauro Carvalho Chehab /* start */
3030c0d06caSMauro Carvalho Chehab 	{0x02, 0x00, 0x00},		/* init */
3040c0d06caSMauro Carvalho Chehab 	{0x02, 0x00, 0x01},
3050c0d06caSMauro Carvalho Chehab 	{0x02, 0x00, 0x02},
3060c0d06caSMauro Carvalho Chehab 	{0x02, 0x00, 0x03},
3070c0d06caSMauro Carvalho Chehab 	{0x02, 0x00, 0x04},
3080c0d06caSMauro Carvalho Chehab 	{0x02, 0x00, 0x05},
3090c0d06caSMauro Carvalho Chehab 	{0x02, 0x00, 0x06},
3100c0d06caSMauro Carvalho Chehab 	{0x02, 0x00, 0x07},
3110c0d06caSMauro Carvalho Chehab 	{0x02, 0x00, 0x08},
3120c0d06caSMauro Carvalho Chehab 	{0x02, 0x00, 0x09},
3130c0d06caSMauro Carvalho Chehab 	{0x03, 0x00, 0x00},
3140c0d06caSMauro Carvalho Chehab 	{0x03, 0x00, 0x01},
3150c0d06caSMauro Carvalho Chehab 	{0x03, 0x00, 0x02},
3160c0d06caSMauro Carvalho Chehab 	{0x03, 0x00, 0x03},
3170c0d06caSMauro Carvalho Chehab 	{0x03, 0x00, 0x04},
3180c0d06caSMauro Carvalho Chehab 	{0x03, 0x00, 0x05},
3190c0d06caSMauro Carvalho Chehab 	{0x03, 0x00, 0x06},
3200c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x00},
3210c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x02},
3220c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x04},
3230c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x05},
3240c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x06},
3250c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x07},
3260c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x08},
3270c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x09},
3280c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x0a},
3290c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x0b},
3300c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x0c},
3310c0d06caSMauro Carvalho Chehab 	{0x07, 0x00, 0x00},
3320c0d06caSMauro Carvalho Chehab 	{0x07, 0x00, 0x03},
3330c0d06caSMauro Carvalho Chehab 	{0x08, 0x00, 0x00},
3340c0d06caSMauro Carvalho Chehab 	{0x08, 0x00, 0x01},
3350c0d06caSMauro Carvalho Chehab 	{0x08, 0x00, 0x02},
3360c0d06caSMauro Carvalho Chehab 	{0x06, 0x18, 0x08},
3370c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x09},
3380c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x0a},
3390c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x0b},
3400c0d06caSMauro Carvalho Chehab 	{0x06, 0x18, 0x0c},
3410c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x0d},
3420c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x0e},
3430c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x0f},
3440c0d06caSMauro Carvalho Chehab 	{0x06, 0x18, 0x10},
3450c0d06caSMauro Carvalho Chehab 	{0x06, 0xfe, 0x12},
3460c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x11},
3470c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x14},
3480c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x13},
3490c0d06caSMauro Carvalho Chehab 	{0x06, 0x28, 0x51},
3500c0d06caSMauro Carvalho Chehab 	{0x06, 0xff, 0x53},
3510c0d06caSMauro Carvalho Chehab 	{0x02, 0x00, 0x08},
3520c0d06caSMauro Carvalho Chehab 
3530c0d06caSMauro Carvalho Chehab 	{0x03, 0x00, 0x03},
3540c0d06caSMauro Carvalho Chehab 	{0x03, 0x10, 0x03},
3550c0d06caSMauro Carvalho Chehab 	{}
3560c0d06caSMauro Carvalho Chehab };
3570c0d06caSMauro Carvalho Chehab 
3580c0d06caSMauro Carvalho Chehab /*
3590c0d06caSMauro Carvalho Chehab  * Data to initialize the camera using the internal CCD
3600c0d06caSMauro Carvalho Chehab  */
3610c0d06caSMauro Carvalho Chehab static const u8 spca505b_open_data_ccd[][3] = {
3620c0d06caSMauro Carvalho Chehab 
3630c0d06caSMauro Carvalho Chehab /* {0x02,0x00,0x00}, */
3640c0d06caSMauro Carvalho Chehab 	{0x03, 0x04, 0x01},		/* rst */
3650c0d06caSMauro Carvalho Chehab 	{0x03, 0x00, 0x01},
3660c0d06caSMauro Carvalho Chehab 	{0x03, 0x00, 0x00},
3670c0d06caSMauro Carvalho Chehab 	{0x03, 0x21, 0x00},
3680c0d06caSMauro Carvalho Chehab 	{0x03, 0x00, 0x04},
3690c0d06caSMauro Carvalho Chehab 	{0x03, 0x00, 0x03},
3700c0d06caSMauro Carvalho Chehab 	{0x03, 0x18, 0x03},
3710c0d06caSMauro Carvalho Chehab 	{0x03, 0x08, 0x01},
3720c0d06caSMauro Carvalho Chehab 	{0x03, 0x1c, 0x03},
3730c0d06caSMauro Carvalho Chehab 	{0x03, 0x5c, 0x03},
3740c0d06caSMauro Carvalho Chehab 	{0x03, 0x5c, 0x03},
3750c0d06caSMauro Carvalho Chehab 	{0x03, 0x18, 0x01},
3760c0d06caSMauro Carvalho Chehab 
3770c0d06caSMauro Carvalho Chehab /* same as 505 */
3780c0d06caSMauro Carvalho Chehab 	{0x04, 0x10, 0x01},
3790c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x04},
3800c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x05},
3810c0d06caSMauro Carvalho Chehab 	{0x04, 0x20, 0x06},
3820c0d06caSMauro Carvalho Chehab 	{0x04, 0x20, 0x07},
3830c0d06caSMauro Carvalho Chehab 
3840c0d06caSMauro Carvalho Chehab 	{0x08, 0x0a, 0x00},
3850c0d06caSMauro Carvalho Chehab 
3860c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0x10},
3870c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0x11},
3880c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0x12},
3890c0d06caSMauro Carvalho Chehab 	{0x05, 0x6f, 0x00},
3900c0d06caSMauro Carvalho Chehab 	{0x05, initial_brightness >> 6, 0x00},
3910c0d06caSMauro Carvalho Chehab 	{0x05, (initial_brightness << 2) & 0xff, 0x01},
3920c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0x02},
3930c0d06caSMauro Carvalho Chehab 	{0x05, 0x01, 0x03},
3940c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0x04},
3950c0d06caSMauro Carvalho Chehab 	{0x05, 0x03, 0x05},
3960c0d06caSMauro Carvalho Chehab 	{0x05, 0xe0, 0x06},
3970c0d06caSMauro Carvalho Chehab 	{0x05, 0x20, 0x07},
3980c0d06caSMauro Carvalho Chehab 	{0x05, 0xa0, 0x08},
3990c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0x12},
4000c0d06caSMauro Carvalho Chehab 	{0x05, 0x02, 0x0f},
4010c0d06caSMauro Carvalho Chehab 	{0x05, 0x80, 0x14},		/* max exposure off (0=on) */
4020c0d06caSMauro Carvalho Chehab 	{0x05, 0x01, 0xb0},
4030c0d06caSMauro Carvalho Chehab 	{0x05, 0x01, 0xbf},
4040c0d06caSMauro Carvalho Chehab 	{0x03, 0x02, 0x06},
4050c0d06caSMauro Carvalho Chehab 	{0x05, 0x10, 0x46},
4060c0d06caSMauro Carvalho Chehab 	{0x05, 0x08, 0x4a},
4070c0d06caSMauro Carvalho Chehab 
4080c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x01},
4090c0d06caSMauro Carvalho Chehab 	{0x06, 0x10, 0x02},
4100c0d06caSMauro Carvalho Chehab 	{0x06, 0x64, 0x07},
4110c0d06caSMauro Carvalho Chehab 	{0x06, 0x18, 0x08},
4120c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x09},
4130c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x0a},
4140c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x0b},
4150c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x01},
4160c0d06caSMauro Carvalho Chehab 	{0x06, 0x18, 0x0c},
4170c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x0d},
4180c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x0e},
4190c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x0f},
4200c0d06caSMauro Carvalho Chehab 	{0x06, 0x11, 0x10},		/* contrast */
4210c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x11},
4220c0d06caSMauro Carvalho Chehab 	{0x06, 0xfe, 0x12},
4230c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x13},
4240c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x14},
4250c0d06caSMauro Carvalho Chehab 	{0x06, 0x9d, 0x51},
4260c0d06caSMauro Carvalho Chehab 	{0x06, 0x40, 0x52},
4270c0d06caSMauro Carvalho Chehab 	{0x06, 0x7c, 0x53},
4280c0d06caSMauro Carvalho Chehab 	{0x06, 0x40, 0x54},
4290c0d06caSMauro Carvalho Chehab 	{0x06, 0x02, 0x57},
4300c0d06caSMauro Carvalho Chehab 	{0x06, 0x03, 0x58},
4310c0d06caSMauro Carvalho Chehab 	{0x06, 0x15, 0x59},
4320c0d06caSMauro Carvalho Chehab 	{0x06, 0x05, 0x5a},
4330c0d06caSMauro Carvalho Chehab 	{0x06, 0x03, 0x56},
4340c0d06caSMauro Carvalho Chehab 	{0x06, 0x02, 0x3f},
4350c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x40},
4360c0d06caSMauro Carvalho Chehab 	{0x06, 0x39, 0x41},
4370c0d06caSMauro Carvalho Chehab 	{0x06, 0x69, 0x42},
4380c0d06caSMauro Carvalho Chehab 	{0x06, 0x87, 0x43},
4390c0d06caSMauro Carvalho Chehab 	{0x06, 0x9e, 0x44},
4400c0d06caSMauro Carvalho Chehab 	{0x06, 0xb1, 0x45},
4410c0d06caSMauro Carvalho Chehab 	{0x06, 0xbf, 0x46},
4420c0d06caSMauro Carvalho Chehab 	{0x06, 0xcc, 0x47},
4430c0d06caSMauro Carvalho Chehab 	{0x06, 0xd5, 0x48},
4440c0d06caSMauro Carvalho Chehab 	{0x06, 0xdd, 0x49},
4450c0d06caSMauro Carvalho Chehab 	{0x06, 0xe3, 0x4a},
4460c0d06caSMauro Carvalho Chehab 	{0x06, 0xe8, 0x4b},
4470c0d06caSMauro Carvalho Chehab 	{0x06, 0xed, 0x4c},
4480c0d06caSMauro Carvalho Chehab 	{0x06, 0xf2, 0x4d},
4490c0d06caSMauro Carvalho Chehab 	{0x06, 0xf7, 0x4e},
4500c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x4f},
4510c0d06caSMauro Carvalho Chehab 	{0x06, 0xff, 0x50},
4520c0d06caSMauro Carvalho Chehab 
4530c0d06caSMauro Carvalho Chehab 	{0x05, 0x01, 0xc0},
4540c0d06caSMauro Carvalho Chehab 	{0x05, 0x10, 0xcb},
4550c0d06caSMauro Carvalho Chehab 	{0x05, 0x40, 0xc1},
4560c0d06caSMauro Carvalho Chehab 	{0x05, 0x04, 0xc2},
4570c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0xca},
4580c0d06caSMauro Carvalho Chehab 	{0x05, 0x40, 0xc1},
4590c0d06caSMauro Carvalho Chehab 	{0x05, 0x09, 0xc2},
4600c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0xca},
4610c0d06caSMauro Carvalho Chehab 	{0x05, 0xc0, 0xc1},
4620c0d06caSMauro Carvalho Chehab 	{0x05, 0x09, 0xc2},
4630c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0xca},
4640c0d06caSMauro Carvalho Chehab 	{0x05, 0x40, 0xc1},
4650c0d06caSMauro Carvalho Chehab 	{0x05, 0x59, 0xc2},
4660c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0xca},
4670c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x01},
4680c0d06caSMauro Carvalho Chehab 	{0x05, 0x80, 0xc1},
4690c0d06caSMauro Carvalho Chehab 	{0x05, 0xec, 0xc2},
4700c0d06caSMauro Carvalho Chehab 	{0x05, 0x0, 0xca},
4710c0d06caSMauro Carvalho Chehab 
4720c0d06caSMauro Carvalho Chehab 	{0x06, 0x02, 0x57},
4730c0d06caSMauro Carvalho Chehab 	{0x06, 0x01, 0x58},
4740c0d06caSMauro Carvalho Chehab 	{0x06, 0x15, 0x59},
4750c0d06caSMauro Carvalho Chehab 	{0x06, 0x0a, 0x5a},
4760c0d06caSMauro Carvalho Chehab 	{0x06, 0x01, 0x57},
4770c0d06caSMauro Carvalho Chehab 	{0x06, 0x8a, 0x03},
4780c0d06caSMauro Carvalho Chehab 	{0x06, 0x0a, 0x6c},
4790c0d06caSMauro Carvalho Chehab 	{0x06, 0x30, 0x01},
4800c0d06caSMauro Carvalho Chehab 	{0x06, 0x20, 0x02},
4810c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x03},
4820c0d06caSMauro Carvalho Chehab 
4830c0d06caSMauro Carvalho Chehab 	{0x05, 0x8c, 0x25},
4840c0d06caSMauro Carvalho Chehab 
4850c0d06caSMauro Carvalho Chehab 	{0x06, 0x4d, 0x51},		/* maybe saturation (4d) */
4860c0d06caSMauro Carvalho Chehab 	{0x06, 0x84, 0x53},		/* making green (84) */
4870c0d06caSMauro Carvalho Chehab 	{0x06, 0x00, 0x57},		/* sharpness (1) */
4880c0d06caSMauro Carvalho Chehab 	{0x06, 0x18, 0x08},
4890c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x09},
4900c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x0a},
4910c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x0b},
4920c0d06caSMauro Carvalho Chehab 	{0x06, 0x18, 0x0c},		/* maybe hue (18) */
4930c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x0d},
4940c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x0e},
4950c0d06caSMauro Carvalho Chehab 	{0x06, 0xfc, 0x0f},
4960c0d06caSMauro Carvalho Chehab 	{0x06, 0x18, 0x10},		/* maybe contrast (18) */
4970c0d06caSMauro Carvalho Chehab 
4980c0d06caSMauro Carvalho Chehab 	{0x05, 0x01, 0x02},
4990c0d06caSMauro Carvalho Chehab 
5000c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x08},		/* compression */
5010c0d06caSMauro Carvalho Chehab 	{0x04, 0x12, 0x09},
5020c0d06caSMauro Carvalho Chehab 	{0x04, 0x21, 0x0a},
5030c0d06caSMauro Carvalho Chehab 	{0x04, 0x10, 0x0b},
5040c0d06caSMauro Carvalho Chehab 	{0x04, 0x21, 0x0c},
5050c0d06caSMauro Carvalho Chehab 	{0x04, 0x1d, 0x00},		/* imagetype (1d) */
5060c0d06caSMauro Carvalho Chehab 	{0x04, 0x41, 0x01},		/* hardware snapcontrol */
5070c0d06caSMauro Carvalho Chehab 
5080c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x04},
5090c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x05},
5100c0d06caSMauro Carvalho Chehab 	{0x04, 0x10, 0x06},
5110c0d06caSMauro Carvalho Chehab 	{0x04, 0x10, 0x07},
5120c0d06caSMauro Carvalho Chehab 	{0x04, 0x40, 0x06},
5130c0d06caSMauro Carvalho Chehab 	{0x04, 0x40, 0x07},
5140c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x04},
5150c0d06caSMauro Carvalho Chehab 	{0x04, 0x00, 0x05},
5160c0d06caSMauro Carvalho Chehab 
5170c0d06caSMauro Carvalho Chehab 	{0x06, 0x1c, 0x17},
5180c0d06caSMauro Carvalho Chehab 	{0x06, 0xe2, 0x19},
5190c0d06caSMauro Carvalho Chehab 	{0x06, 0x1c, 0x1b},
5200c0d06caSMauro Carvalho Chehab 	{0x06, 0xe2, 0x1d},
5210c0d06caSMauro Carvalho Chehab 	{0x06, 0x5f, 0x1f},
5220c0d06caSMauro Carvalho Chehab 	{0x06, 0x32, 0x20},
5230c0d06caSMauro Carvalho Chehab 
5240c0d06caSMauro Carvalho Chehab 	{0x05, initial_brightness >> 6, 0x00},
5250c0d06caSMauro Carvalho Chehab 	{0x05, (initial_brightness << 2) & 0xff, 0x01},
5260c0d06caSMauro Carvalho Chehab 	{0x05, 0x06, 0xc1},
5270c0d06caSMauro Carvalho Chehab 	{0x05, 0x58, 0xc2},
5280c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0xca},
5290c0d06caSMauro Carvalho Chehab 	{0x05, 0x00, 0x11},
5300c0d06caSMauro Carvalho Chehab 	{}
5310c0d06caSMauro Carvalho Chehab };
5320c0d06caSMauro Carvalho Chehab 
533c93396e1STheodore Kilgore static int reg_write(struct gspca_dev *gspca_dev,
5340c0d06caSMauro Carvalho Chehab 		     u16 req, u16 index, u16 value)
5350c0d06caSMauro Carvalho Chehab {
5360c0d06caSMauro Carvalho Chehab 	int ret;
537c93396e1STheodore Kilgore 	struct usb_device *dev = gspca_dev->dev;
5380c0d06caSMauro Carvalho Chehab 
5390c0d06caSMauro Carvalho Chehab 	ret = usb_control_msg(dev,
5400c0d06caSMauro Carvalho Chehab 			usb_sndctrlpipe(dev, 0),
5410c0d06caSMauro Carvalho Chehab 			req,
5420c0d06caSMauro Carvalho Chehab 			USB_TYPE_VENDOR | USB_RECIP_DEVICE,
5430c0d06caSMauro Carvalho Chehab 			value, index, NULL, 0, 500);
54437d5efb0SJoe Perches 	gspca_dbg(gspca_dev, D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d\n",
5450c0d06caSMauro Carvalho Chehab 		  req, index, value, ret);
5460c0d06caSMauro Carvalho Chehab 	if (ret < 0)
5470c0d06caSMauro Carvalho Chehab 		pr_err("reg write: error %d\n", ret);
5480c0d06caSMauro Carvalho Chehab 	return ret;
5490c0d06caSMauro Carvalho Chehab }
5500c0d06caSMauro Carvalho Chehab 
5510c0d06caSMauro Carvalho Chehab /* returns: negative is error, pos or zero is data */
5520c0d06caSMauro Carvalho Chehab static int reg_read(struct gspca_dev *gspca_dev,
5530c0d06caSMauro Carvalho Chehab 			u16 req,	/* bRequest */
5540c0d06caSMauro Carvalho Chehab 			u16 index)	/* wIndex */
5550c0d06caSMauro Carvalho Chehab {
5560c0d06caSMauro Carvalho Chehab 	int ret;
5570c0d06caSMauro Carvalho Chehab 
5580c0d06caSMauro Carvalho Chehab 	ret = usb_control_msg(gspca_dev->dev,
5590c0d06caSMauro Carvalho Chehab 			usb_rcvctrlpipe(gspca_dev->dev, 0),
5600c0d06caSMauro Carvalho Chehab 			req,
5610c0d06caSMauro Carvalho Chehab 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
5620c0d06caSMauro Carvalho Chehab 			0,			/* value */
5630c0d06caSMauro Carvalho Chehab 			index,
5640c0d06caSMauro Carvalho Chehab 			gspca_dev->usb_buf, 2,
5650c0d06caSMauro Carvalho Chehab 			500);			/* timeout */
5660c0d06caSMauro Carvalho Chehab 	if (ret < 0)
5670c0d06caSMauro Carvalho Chehab 		return ret;
5680c0d06caSMauro Carvalho Chehab 	return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
5690c0d06caSMauro Carvalho Chehab }
5700c0d06caSMauro Carvalho Chehab 
5710c0d06caSMauro Carvalho Chehab static int write_vector(struct gspca_dev *gspca_dev,
5720c0d06caSMauro Carvalho Chehab 			const u8 data[][3])
5730c0d06caSMauro Carvalho Chehab {
5740c0d06caSMauro Carvalho Chehab 	int ret, i = 0;
5750c0d06caSMauro Carvalho Chehab 
5760c0d06caSMauro Carvalho Chehab 	while (data[i][0] != 0) {
577c93396e1STheodore Kilgore 		ret = reg_write(gspca_dev, data[i][0], data[i][2],
578c93396e1STheodore Kilgore 								data[i][1]);
5790c0d06caSMauro Carvalho Chehab 		if (ret < 0)
5800c0d06caSMauro Carvalho Chehab 			return ret;
5810c0d06caSMauro Carvalho Chehab 		i++;
5820c0d06caSMauro Carvalho Chehab 	}
5830c0d06caSMauro Carvalho Chehab 	return 0;
5840c0d06caSMauro Carvalho Chehab }
5850c0d06caSMauro Carvalho Chehab 
5860c0d06caSMauro Carvalho Chehab /* this function is called at probe time */
5870c0d06caSMauro Carvalho Chehab static int sd_config(struct gspca_dev *gspca_dev,
5880c0d06caSMauro Carvalho Chehab 			const struct usb_device_id *id)
5890c0d06caSMauro Carvalho Chehab {
5900c0d06caSMauro Carvalho Chehab 	struct sd *sd = (struct sd *) gspca_dev;
5910c0d06caSMauro Carvalho Chehab 	struct cam *cam;
5920c0d06caSMauro Carvalho Chehab 
5930c0d06caSMauro Carvalho Chehab 	cam = &gspca_dev->cam;
5940c0d06caSMauro Carvalho Chehab 	cam->cam_mode = vga_mode;
5950c0d06caSMauro Carvalho Chehab 	sd->subtype = id->driver_info;
5960c0d06caSMauro Carvalho Chehab 	if (sd->subtype != IntelPCCameraPro)
5970c0d06caSMauro Carvalho Chehab 		cam->nmodes = ARRAY_SIZE(vga_mode);
5980c0d06caSMauro Carvalho Chehab 	else			/* no 640x480 for IntelPCCameraPro */
5990c0d06caSMauro Carvalho Chehab 		cam->nmodes = ARRAY_SIZE(vga_mode) - 1;
6000c0d06caSMauro Carvalho Chehab 
6010c0d06caSMauro Carvalho Chehab 	return 0;
6020c0d06caSMauro Carvalho Chehab }
6030c0d06caSMauro Carvalho Chehab 
6040c0d06caSMauro Carvalho Chehab /* this function is called at probe and resume time */
6050c0d06caSMauro Carvalho Chehab static int sd_init(struct gspca_dev *gspca_dev)
6060c0d06caSMauro Carvalho Chehab {
6070c0d06caSMauro Carvalho Chehab 	struct sd *sd = (struct sd *) gspca_dev;
6080c0d06caSMauro Carvalho Chehab 
6090c0d06caSMauro Carvalho Chehab 	if (write_vector(gspca_dev,
6100c0d06caSMauro Carvalho Chehab 			 sd->subtype == Nxultra
6110c0d06caSMauro Carvalho Chehab 				? spca505b_init_data
6120c0d06caSMauro Carvalho Chehab 				: spca505_init_data))
6130c0d06caSMauro Carvalho Chehab 		return -EIO;
6140c0d06caSMauro Carvalho Chehab 	return 0;
6150c0d06caSMauro Carvalho Chehab }
6160c0d06caSMauro Carvalho Chehab 
6170c0d06caSMauro Carvalho Chehab static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness)
6180c0d06caSMauro Carvalho Chehab {
619c93396e1STheodore Kilgore 	reg_write(gspca_dev, 0x05, 0x00, (255 - brightness) >> 6);
620c93396e1STheodore Kilgore 	reg_write(gspca_dev, 0x05, 0x01, (255 - brightness) << 2);
6210c0d06caSMauro Carvalho Chehab }
6220c0d06caSMauro Carvalho Chehab 
6230c0d06caSMauro Carvalho Chehab static int sd_start(struct gspca_dev *gspca_dev)
6240c0d06caSMauro Carvalho Chehab {
6250c0d06caSMauro Carvalho Chehab 	struct sd *sd = (struct sd *) gspca_dev;
6260c0d06caSMauro Carvalho Chehab 	int ret, mode;
6270c0d06caSMauro Carvalho Chehab 	static u8 mode_tb[][3] = {
6280c0d06caSMauro Carvalho Chehab 	/*	  r00   r06   r07	*/
6290c0d06caSMauro Carvalho Chehab 		{0x00, 0x10, 0x10},	/* 640x480 */
6300c0d06caSMauro Carvalho Chehab 		{0x01, 0x1a, 0x1a},	/* 352x288 */
6310c0d06caSMauro Carvalho Chehab 		{0x02, 0x1c, 0x1d},	/* 320x240 */
6320c0d06caSMauro Carvalho Chehab 		{0x04, 0x34, 0x34},	/* 176x144 */
6330c0d06caSMauro Carvalho Chehab 		{0x05, 0x40, 0x40}	/* 160x120 */
6340c0d06caSMauro Carvalho Chehab 	};
6350c0d06caSMauro Carvalho Chehab 
6360c0d06caSMauro Carvalho Chehab 	if (sd->subtype == Nxultra)
6370c0d06caSMauro Carvalho Chehab 		write_vector(gspca_dev, spca505b_open_data_ccd);
6380c0d06caSMauro Carvalho Chehab 	else
6390c0d06caSMauro Carvalho Chehab 		write_vector(gspca_dev, spca505_open_data_ccd);
6400c0d06caSMauro Carvalho Chehab 	ret = reg_read(gspca_dev, 0x06, 0x16);
6410c0d06caSMauro Carvalho Chehab 
6420c0d06caSMauro Carvalho Chehab 	if (ret < 0) {
64352173c5fSJoe Perches 		gspca_err(gspca_dev, "register read failed err: %d\n", ret);
6440c0d06caSMauro Carvalho Chehab 		return ret;
6450c0d06caSMauro Carvalho Chehab 	}
6460c0d06caSMauro Carvalho Chehab 	if (ret != 0x0101) {
6470c0d06caSMauro Carvalho Chehab 		pr_err("After vector read returns 0x%04x should be 0x0101\n",
6480c0d06caSMauro Carvalho Chehab 		       ret);
6490c0d06caSMauro Carvalho Chehab 	}
6500c0d06caSMauro Carvalho Chehab 
651c93396e1STheodore Kilgore 	ret = reg_write(gspca_dev, 0x06, 0x16, 0x0a);
6520c0d06caSMauro Carvalho Chehab 	if (ret < 0)
6530c0d06caSMauro Carvalho Chehab 		return ret;
654c93396e1STheodore Kilgore 	reg_write(gspca_dev, 0x05, 0xc2, 0x12);
6550c0d06caSMauro Carvalho Chehab 
6560c0d06caSMauro Carvalho Chehab 	/* necessary because without it we can see stream
6570c0d06caSMauro Carvalho Chehab 	 * only once after loading module */
6580c0d06caSMauro Carvalho Chehab 	/* stopping usb registers Tomasz change */
659c93396e1STheodore Kilgore 	reg_write(gspca_dev, 0x02, 0x00, 0x00);
6600c0d06caSMauro Carvalho Chehab 
6610c0d06caSMauro Carvalho Chehab 	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
662c93396e1STheodore Kilgore 	reg_write(gspca_dev, SPCA50X_REG_COMPRESS, 0x00, mode_tb[mode][0]);
663c93396e1STheodore Kilgore 	reg_write(gspca_dev, SPCA50X_REG_COMPRESS, 0x06, mode_tb[mode][1]);
664c93396e1STheodore Kilgore 	reg_write(gspca_dev, SPCA50X_REG_COMPRESS, 0x07, mode_tb[mode][2]);
6650c0d06caSMauro Carvalho Chehab 
666c93396e1STheodore Kilgore 	return reg_write(gspca_dev, SPCA50X_REG_USB,
6670c0d06caSMauro Carvalho Chehab 			 SPCA50X_USB_CTRL,
6680c0d06caSMauro Carvalho Chehab 			 SPCA50X_CUSB_ENABLE);
6690c0d06caSMauro Carvalho Chehab }
6700c0d06caSMauro Carvalho Chehab 
6710c0d06caSMauro Carvalho Chehab static void sd_stopN(struct gspca_dev *gspca_dev)
6720c0d06caSMauro Carvalho Chehab {
6730c0d06caSMauro Carvalho Chehab 	/* Disable ISO packet machine */
674c93396e1STheodore Kilgore 	reg_write(gspca_dev, 0x02, 0x00, 0x00);
6750c0d06caSMauro Carvalho Chehab }
6760c0d06caSMauro Carvalho Chehab 
6770c0d06caSMauro Carvalho Chehab /* called on streamoff with alt 0 and on disconnect */
6780c0d06caSMauro Carvalho Chehab static void sd_stop0(struct gspca_dev *gspca_dev)
6790c0d06caSMauro Carvalho Chehab {
6800c0d06caSMauro Carvalho Chehab 	if (!gspca_dev->present)
6810c0d06caSMauro Carvalho Chehab 		return;
6820c0d06caSMauro Carvalho Chehab 
6830c0d06caSMauro Carvalho Chehab 	/* This maybe reset or power control */
684c93396e1STheodore Kilgore 	reg_write(gspca_dev, 0x03, 0x03, 0x20);
685c93396e1STheodore Kilgore 	reg_write(gspca_dev, 0x03, 0x01, 0x00);
686c93396e1STheodore Kilgore 	reg_write(gspca_dev, 0x03, 0x00, 0x01);
687c93396e1STheodore Kilgore 	reg_write(gspca_dev, 0x05, 0x10, 0x01);
688c93396e1STheodore Kilgore 	reg_write(gspca_dev, 0x05, 0x11, 0x0f);
6890c0d06caSMauro Carvalho Chehab }
6900c0d06caSMauro Carvalho Chehab 
6910c0d06caSMauro Carvalho Chehab static void sd_pkt_scan(struct gspca_dev *gspca_dev,
6920c0d06caSMauro Carvalho Chehab 			u8 *data,			/* isoc packet */
6930c0d06caSMauro Carvalho Chehab 			int len)			/* iso packet length */
6940c0d06caSMauro Carvalho Chehab {
6950c0d06caSMauro Carvalho Chehab 	switch (data[0]) {
6960c0d06caSMauro Carvalho Chehab 	case 0:				/* start of frame */
6970c0d06caSMauro Carvalho Chehab 		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
6980c0d06caSMauro Carvalho Chehab 		data += SPCA50X_OFFSET_DATA;
6990c0d06caSMauro Carvalho Chehab 		len -= SPCA50X_OFFSET_DATA;
7000c0d06caSMauro Carvalho Chehab 		gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
7010c0d06caSMauro Carvalho Chehab 		break;
7020c0d06caSMauro Carvalho Chehab 	case 0xff:			/* drop */
7030c0d06caSMauro Carvalho Chehab 		break;
7040c0d06caSMauro Carvalho Chehab 	default:
7050c0d06caSMauro Carvalho Chehab 		data += 1;
7060c0d06caSMauro Carvalho Chehab 		len -= 1;
7070c0d06caSMauro Carvalho Chehab 		gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
7080c0d06caSMauro Carvalho Chehab 		break;
7090c0d06caSMauro Carvalho Chehab 	}
7100c0d06caSMauro Carvalho Chehab }
7110c0d06caSMauro Carvalho Chehab 
7120c0d06caSMauro Carvalho Chehab static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
7130c0d06caSMauro Carvalho Chehab {
7140c0d06caSMauro Carvalho Chehab 	struct gspca_dev *gspca_dev =
7150c0d06caSMauro Carvalho Chehab 		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
7160c0d06caSMauro Carvalho Chehab 
7170c0d06caSMauro Carvalho Chehab 	gspca_dev->usb_err = 0;
7180c0d06caSMauro Carvalho Chehab 
7190c0d06caSMauro Carvalho Chehab 	if (!gspca_dev->streaming)
7200c0d06caSMauro Carvalho Chehab 		return 0;
7210c0d06caSMauro Carvalho Chehab 
7220c0d06caSMauro Carvalho Chehab 	switch (ctrl->id) {
7230c0d06caSMauro Carvalho Chehab 	case V4L2_CID_BRIGHTNESS:
7240c0d06caSMauro Carvalho Chehab 		setbrightness(gspca_dev, ctrl->val);
7250c0d06caSMauro Carvalho Chehab 		break;
7260c0d06caSMauro Carvalho Chehab 	}
7270c0d06caSMauro Carvalho Chehab 	return gspca_dev->usb_err;
7280c0d06caSMauro Carvalho Chehab }
7290c0d06caSMauro Carvalho Chehab 
7300c0d06caSMauro Carvalho Chehab static const struct v4l2_ctrl_ops sd_ctrl_ops = {
7310c0d06caSMauro Carvalho Chehab 	.s_ctrl = sd_s_ctrl,
7320c0d06caSMauro Carvalho Chehab };
7330c0d06caSMauro Carvalho Chehab 
7340c0d06caSMauro Carvalho Chehab static int sd_init_controls(struct gspca_dev *gspca_dev)
7350c0d06caSMauro Carvalho Chehab {
7360c0d06caSMauro Carvalho Chehab 	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
7370c0d06caSMauro Carvalho Chehab 
7380c0d06caSMauro Carvalho Chehab 	gspca_dev->vdev.ctrl_handler = hdl;
7390c0d06caSMauro Carvalho Chehab 	v4l2_ctrl_handler_init(hdl, 5);
7400c0d06caSMauro Carvalho Chehab 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
7410c0d06caSMauro Carvalho Chehab 			V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
7420c0d06caSMauro Carvalho Chehab 
7430c0d06caSMauro Carvalho Chehab 	if (hdl->error) {
7440c0d06caSMauro Carvalho Chehab 		pr_err("Could not initialize controls\n");
7450c0d06caSMauro Carvalho Chehab 		return hdl->error;
7460c0d06caSMauro Carvalho Chehab 	}
7470c0d06caSMauro Carvalho Chehab 	return 0;
7480c0d06caSMauro Carvalho Chehab }
7490c0d06caSMauro Carvalho Chehab 
7500c0d06caSMauro Carvalho Chehab /* sub-driver description */
7510c0d06caSMauro Carvalho Chehab static const struct sd_desc sd_desc = {
7520c0d06caSMauro Carvalho Chehab 	.name = MODULE_NAME,
7530c0d06caSMauro Carvalho Chehab 	.config = sd_config,
7540c0d06caSMauro Carvalho Chehab 	.init_controls = sd_init_controls,
7550c0d06caSMauro Carvalho Chehab 	.init = sd_init,
7560c0d06caSMauro Carvalho Chehab 	.start = sd_start,
7570c0d06caSMauro Carvalho Chehab 	.stopN = sd_stopN,
7580c0d06caSMauro Carvalho Chehab 	.stop0 = sd_stop0,
7590c0d06caSMauro Carvalho Chehab 	.pkt_scan = sd_pkt_scan,
7600c0d06caSMauro Carvalho Chehab };
7610c0d06caSMauro Carvalho Chehab 
7620c0d06caSMauro Carvalho Chehab /* -- module initialisation -- */
7630c0d06caSMauro Carvalho Chehab static const struct usb_device_id device_table[] = {
7640c0d06caSMauro Carvalho Chehab 	{USB_DEVICE(0x041e, 0x401d), .driver_info = Nxultra},
7650c0d06caSMauro Carvalho Chehab 	{USB_DEVICE(0x0733, 0x0430), .driver_info = IntelPCCameraPro},
7660c0d06caSMauro Carvalho Chehab /*fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */
7670c0d06caSMauro Carvalho Chehab 	{}
7680c0d06caSMauro Carvalho Chehab };
7690c0d06caSMauro Carvalho Chehab MODULE_DEVICE_TABLE(usb, device_table);
7700c0d06caSMauro Carvalho Chehab 
7710c0d06caSMauro Carvalho Chehab /* -- device connect -- */
7720c0d06caSMauro Carvalho Chehab static int sd_probe(struct usb_interface *intf,
7730c0d06caSMauro Carvalho Chehab 			const struct usb_device_id *id)
7740c0d06caSMauro Carvalho Chehab {
7750c0d06caSMauro Carvalho Chehab 	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
7760c0d06caSMauro Carvalho Chehab 				THIS_MODULE);
7770c0d06caSMauro Carvalho Chehab }
7780c0d06caSMauro Carvalho Chehab 
7790c0d06caSMauro Carvalho Chehab static struct usb_driver sd_driver = {
7800c0d06caSMauro Carvalho Chehab 	.name = MODULE_NAME,
7810c0d06caSMauro Carvalho Chehab 	.id_table = device_table,
7820c0d06caSMauro Carvalho Chehab 	.probe = sd_probe,
7830c0d06caSMauro Carvalho Chehab 	.disconnect = gspca_disconnect,
7840c0d06caSMauro Carvalho Chehab #ifdef CONFIG_PM
7850c0d06caSMauro Carvalho Chehab 	.suspend = gspca_suspend,
7860c0d06caSMauro Carvalho Chehab 	.resume = gspca_resume,
7870c0d06caSMauro Carvalho Chehab 	.reset_resume = gspca_resume,
7880c0d06caSMauro Carvalho Chehab #endif
7890c0d06caSMauro Carvalho Chehab };
7900c0d06caSMauro Carvalho Chehab 
7910c0d06caSMauro Carvalho Chehab module_usb_driver(sd_driver);
792