V4L/DVB (13872): gspca - sonixj: Add sensor adcm1700 and webcam 0c45:614a.

Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index d389619..7b60343 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -304,6 +304,7 @@
 sonixj		0c45:613c	Sonix Pccam168
 sonixj		0c45:6143	Sonix Pccam168
 sonixj		0c45:6148	Digitus DA-70811/ZSMC USB PC Camera ZS211/Microdia
+sonixj		0c45:614a	Frontech E-Ccam (JIL-2225)
 sn9c20x		0c45:6240	PC Camera (SN9C201 + MT9M001)
 sn9c20x		0c45:6242	PC Camera (SN9C201 + MT9M111)
 sn9c20x		0c45:6248	PC Camera (SN9C201 + OV9655)
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 0bd36a0..1f21c6a 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -64,16 +64,17 @@
 #define BRIDGE_SN9C110 2
 #define BRIDGE_SN9C120 3
 	u8 sensor;			/* Type of image sensor chip */
-#define SENSOR_HV7131R 0
-#define SENSOR_MI0360 1
-#define SENSOR_MO4000 2
-#define SENSOR_MT9V111 3
-#define SENSOR_OM6802 4
-#define SENSOR_OV7630 5
-#define SENSOR_OV7648 6
-#define SENSOR_OV7660 7
-#define SENSOR_PO1030 8
-#define SENSOR_SP80708 9
+#define SENSOR_ADCM1700 0
+#define SENSOR_HV7131R 1
+#define SENSOR_MI0360 2
+#define SENSOR_MO4000 3
+#define SENSOR_MT9V111 4
+#define SENSOR_OM6802 5
+#define SENSOR_OV7630 6
+#define SENSOR_OV7648 7
+#define SENSOR_OV7660 8
+#define SENSOR_PO1030 9
+#define SENSOR_SP80708 10
 	u8 i2c_addr;
 
 	u8 *jpeg_hdr;
@@ -261,28 +262,37 @@
 
 /* table of the disabled controls */
 static __u32 ctrl_dis[] = {
+	(1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX) |
+	(1 << AUTOGAIN_IDX) | (1 << BRIGHTNESS_IDX), /* SENSOR_ADCM1700 0 */
 	(1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
-						/* SENSOR_HV7131R 0 */
+						/* SENSOR_HV7131R 1 */
 	(1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
-						/* SENSOR_MI0360 1 */
+						/* SENSOR_MI0360 2 */
 	(1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
-						/* SENSOR_MO4000 2 */
+						/* SENSOR_MO4000 3 */
 	(1 << VFLIP_IDX) | (1 << FREQ_IDX),
-						/* SENSOR_MT9V111 3 */
+						/* SENSOR_MT9V111 4 */
 	(1 << INFRARED_IDX) | (1 << VFLIP_IDX) | (1 << FREQ_IDX),
-						/* SENSOR_OM6802 4 */
+						/* SENSOR_OM6802 5 */
 	(1 << INFRARED_IDX),
-						/* SENSOR_OV7630 5 */
+						/* SENSOR_OV7630 6 */
 	(1 << INFRARED_IDX),
-						/* SENSOR_OV7648 6 */
+						/* SENSOR_OV7648 7 */
 	(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
-						/* SENSOR_OV7660 7 */
+						/* SENSOR_OV7660 8 */
 	(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX) |
-			      (1 << FREQ_IDX),	/* SENSOR_PO1030 8 */
+			      (1 << FREQ_IDX),	/* SENSOR_PO1030 9 */
 	(1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX) |
-			      (1 << FREQ_IDX),	/* SENSOR_SP80708 9 */
+			      (1 << FREQ_IDX),	/* SENSOR_SP80708 10 */
 };
 
+static const struct v4l2_pix_format cif_mode[] = {
+	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 352,
+		.sizeimage = 352 * 288 * 4 / 8 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
 static const struct v4l2_pix_format vga_mode[] = {
 	{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 		.bytesperline = 160,
@@ -302,6 +312,17 @@
 		.priv = 0},
 };
 
+static const u8 sn_adcm1700[0x1c] = {
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
+	0x00,	0x42,	0x60,	0x00,	0x1a,	0x20,	0x20,	0x20,
+/*	reg8	reg9	rega	regb	regc	regd	rege	regf */
+	0x80,	0x51,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+/*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
+	0x03,	0x00,	0x05,	0x01,	0x05,	0x16,	0x12,	0x42,
+/*	reg18	reg19	reg1a	reg1b */
+	0x06,	0x00,	0x00,	0x00
+};
+
 /*Data from sn9c102p+hv7131r */
 static const u8 sn_hv7131[0x1c] = {
 /*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
@@ -415,6 +436,7 @@
 
 /* sequence specific to the sensors - !! index = SENSOR_xxx */
 static const u8 *sn_tb[] = {
+	sn_adcm1700,
 	sn_hv7131,
 	sn_mi0360,
 	sn_mo4000,
@@ -432,6 +454,11 @@
 	0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
 	0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
 };
+/* gamma for sensor ADCM1700 */
+static const u8 gamma_spec_0[17] = {
+	0x0f, 0x39, 0x5a, 0x74, 0x86, 0x95, 0xa6, 0xb4,
+	0xbd, 0xc4, 0xcc, 0xd4, 0xd5, 0xde, 0xe4, 0xed, 0xf5
+};
 /* gamma for sensors HV7131R and MT9V111 */
 static const u8 gamma_spec_1[17] = {
 	0x08, 0x3a, 0x52, 0x65, 0x75, 0x83, 0x91, 0x9d,
@@ -450,6 +477,38 @@
 	0x3e, 0x00, 0xcd, 0x0f, 0xf7, 0x0f,	/* VR VG VB */
 	0x00, 0x00, 0x00			/* YUV offsets */
 };
+static const u8 adcm1700_sensor_init[][8] = {
+	{0xa0, 0x51, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xb0, 0x51, 0x04, 0x08, 0x00, 0x00, 0x00, 0x10},
+	{0xdd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+	{0xb0, 0x51, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xdd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+	{0xb0, 0x51, 0x0c, 0xe0, 0x2e, 0x00, 0x00, 0x10},
+	{0xb0, 0x51, 0x10, 0x02, 0x02, 0x00, 0x00, 0x10},
+	{0xb0, 0x51, 0x14, 0x0e, 0x0e, 0x00, 0x00, 0x10},
+	{0xb0, 0x51, 0x1c, 0x00, 0x80, 0x00, 0x00, 0x10},
+	{0xb0, 0x51, 0x20, 0x01, 0x00, 0x00, 0x00, 0x10},
+	{0xdd, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+	{0xb0, 0x51, 0x04, 0x04, 0x00, 0x00, 0x00, 0x10},
+	{0xdd, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+	{0xb0, 0x51, 0x04, 0x01, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x51, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x10},
+	{0xb0, 0x51, 0x14, 0x01, 0x00, 0x00, 0x00, 0x10},
+	{0xb0, 0x51, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{}
+};
+static const u8 adcm1700_sensor_param1[][8] = {
+	{0xb0, 0x51, 0x26, 0xf9, 0x01, 0x00, 0x00, 0x10},
+	{0xd0, 0x51, 0x1e, 0x8e, 0x8e, 0x8e, 0x8e, 0x10},
+
+	{0xa0, 0x51, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x10},
+	{0xb0, 0x51, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10},
+	{0xa0, 0x51, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x10},
+	{0xb0, 0x51, 0x32, 0x00, 0x72, 0x00, 0x00, 0x10},
+	{0xd0, 0x51, 0x1e, 0x8e, 0x91, 0x91, 0x8e, 0x10},
+
+	{}
+};
 static const u8 hv7131r_sensor_init[][8] = {
 	{0xc1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10},
 	{0xb1, 0x11, 0x34, 0x17, 0x7f, 0x00, 0x00, 0x10},
@@ -986,17 +1045,18 @@
 	{}
 };
 
-static const u8 (*sensor_init[10])[8] = {
-	hv7131r_sensor_init,	/* HV7131R 0 */
-	mi0360_sensor_init,	/* MI0360 1 */
-	mo4000_sensor_init,	/* MO4000 2 */
-	mt9v111_sensor_init,	/* MT9V111 3 */
-	om6802_sensor_init,	/* OM6802 4 */
-	ov7630_sensor_init,	/* OV7630 5 */
-	ov7648_sensor_init,	/* OV7648 6 */
-	ov7660_sensor_init,	/* OV7660 7 */
-	po1030_sensor_init,	/* PO1030 8 */
-	sp80708_sensor_init,	/* SP80708 9 */
+static const u8 (*sensor_init[11])[8] = {
+	adcm1700_sensor_init,	/* ADCM1700 0 */
+	hv7131r_sensor_init,	/* HV7131R 1 */
+	mi0360_sensor_init,	/* MI0360 2 */
+	mo4000_sensor_init,	/* MO4000 3 */
+	mt9v111_sensor_init,	/* MT9V111 4 */
+	om6802_sensor_init,	/* OM6802 5 */
+	ov7630_sensor_init,	/* OV7630 6 */
+	ov7648_sensor_init,	/* OV7648 7 */
+	ov7660_sensor_init,	/* OV7660 8 */
+	po1030_sensor_init,	/* PO1030 9 */
+	sp80708_sensor_init,	/* SP80708 10 */
 };
 
 /* read <len> bytes to gspca_dev->usb_buf */
@@ -1064,6 +1124,7 @@
 
 	PDEBUG(D_USBO, "i2c_w2 [%02x] = %02x", reg, val);
 	switch (sd->sensor) {
+	case SENSOR_ADCM1700:
 	case SENSOR_OM6802:		/* i2c command = a0 (100 kHz) */
 		gspca_dev->usb_buf[0] = 0x80 | (2 << 4);
 		break;
@@ -1110,6 +1171,7 @@
 	u8 mode[8];
 
 	switch (sd->sensor) {
+	case SENSOR_ADCM1700:
 	case SENSOR_OM6802:		/* i2c command = 90 (100 kHz) */
 		mode[0] = 0x80 | 0x10;
 		break;
@@ -1284,6 +1346,12 @@
 	reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
 
 	switch (sd->sensor) {
+	case SENSOR_ADCM1700:
+		reg_w1(gspca_dev, 0x01, 0x42);
+		reg_w1(gspca_dev, 0x17, 0x62);
+		reg_w1(gspca_dev, 0x01, 0x42);
+		reg_w1(gspca_dev, 0x01, 0x42);
+		break;
 	case SENSOR_MT9V111:
 		reg_w1(gspca_dev, 0x01, 0x61);
 		reg_w1(gspca_dev, 0x17, 0x61);
@@ -1358,8 +1426,13 @@
 	struct cam *cam;
 
 	cam = &gspca_dev->cam;
-	cam->cam_mode = vga_mode;
-	cam->nmodes = ARRAY_SIZE(vga_mode);
+	if (sd->sensor == SENSOR_ADCM1700) {
+		cam->cam_mode = cif_mode;
+		cam->nmodes = ARRAY_SIZE(cif_mode);
+	} else {
+		cam->cam_mode = vga_mode;
+		cam->nmodes = ARRAY_SIZE(vga_mode);
+	}
 	cam->npkt = 24;			/* 24 packets per ISOC message */
 
 	sd->bridge = id->driver_info >> 16;
@@ -1543,6 +1616,8 @@
 
 	k2 = ((int) sd->brightness - 0x8000) >> 10;
 	switch (sd->sensor) {
+	case SENSOR_ADCM1700:
+		return;
 	case SENSOR_HV7131R:
 		expo = sd->brightness << 4;
 		if (expo > 0x002dc6c0)
@@ -1625,6 +1700,9 @@
 	};
 
 	switch (sd->sensor) {
+	case SENSOR_ADCM1700:
+		gamma_base = gamma_spec_0;
+		break;
 	case SENSOR_HV7131R:
 	case SENSOR_MT9V111:
 		gamma_base = gamma_spec_1;
@@ -1804,6 +1882,8 @@
 	int mode;
 	static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
 	static const u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
+	static const u8 CA_adcm1700[] =
+				{ 0x14, 0xec, 0x0a, 0xf6 };
 	static const u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd };	/* MI0360 */
 	static const u8 CE_ov76xx[] =
 				{ 0x32, 0xdd, 0x32, 0xdd };
@@ -1824,6 +1904,9 @@
 	i2c_w_seq(gspca_dev, sensor_init[sd->sensor]);
 
 	switch (sd->sensor) {
+	case SENSOR_ADCM1700:
+		reg2 = 0x60;
+		break;
 	case SENSOR_OM6802:
 		reg2 = 0x71;
 		break;
@@ -1842,17 +1925,28 @@
 	reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]);
 	reg_w1(gspca_dev, 0x13, sn9c1xx[0x13]);
 	reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
-	reg_w1(gspca_dev, 0xd2, 0x6a);		/* DC29 */
-	reg_w1(gspca_dev, 0xd3, 0x50);
+	if (sd->sensor == SENSOR_ADCM1700) {
+		reg_w1(gspca_dev, 0xd2, 0x3a);		/* DC29 */
+		reg_w1(gspca_dev, 0xd3, 0x30);
+	} else {
+		reg_w1(gspca_dev, 0xd2, 0x6a);		/* DC29 */
+		reg_w1(gspca_dev, 0xd3, 0x50);
+	}
 	reg_w1(gspca_dev, 0xc6, 0x00);
 	reg_w1(gspca_dev, 0xc7, 0x00);
-	reg_w1(gspca_dev, 0xc8, 0x50);
-	reg_w1(gspca_dev, 0xc9, 0x3c);
+	if (sd->sensor == SENSOR_ADCM1700) {
+		reg_w1(gspca_dev, 0xc8, 0x2c);
+		reg_w1(gspca_dev, 0xc9, 0x24);
+	} else {
+		reg_w1(gspca_dev, 0xc8, 0x50);
+		reg_w1(gspca_dev, 0xc9, 0x3c);
+	}
 	reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
 	switch (sd->sensor) {
 	case SENSOR_MT9V111:
 		reg17 = 0xe0;
 		break;
+	case SENSOR_ADCM1700:
 	case SENSOR_OV7630:
 		reg17 = 0xe2;
 		break;
@@ -1881,6 +1975,10 @@
 	for (i = 0; i < 8; i++)
 		reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
 	switch (sd->sensor) {
+	case SENSOR_ADCM1700:
+		reg_w1(gspca_dev, 0x9a, 0x05);
+		reg_w1(gspca_dev, 0x99, 0x60);
+		break;
 	case SENSOR_MT9V111:
 		reg_w1(gspca_dev, 0x9a, 0x07);
 		reg_w1(gspca_dev, 0x99, 0x59);
@@ -1917,6 +2015,11 @@
 		reg1 = 0x06;	/* 640x480: clk 24Mhz, video trf enable */
 	reg17 = 0x61;		/* 0x:20: enable sensor clock */
 	switch (sd->sensor) {
+	case SENSOR_ADCM1700:
+		init = adcm1700_sensor_param1;
+		reg1 = 0x46;
+		reg17 = 0xe2;
+		break;
 	case SENSOR_MO4000:
 		if (mode) {
 /*			reg1 = 0x46;	 * 320 clk 48Mhz 60fp/s */
@@ -1986,8 +2089,12 @@
 	}
 
 	reg_w(gspca_dev, 0xc0, C0, 6);
-	reg_w(gspca_dev, 0xca, CA, 4);
+	if (sd->sensor == SENSOR_ADCM1700)
+		reg_w(gspca_dev, 0xca, CA_adcm1700, 4);
+	else
+		reg_w(gspca_dev, 0xca, CA, 4);
 	switch (sd->sensor) {
+	case SENSOR_ADCM1700:
 	case SENSOR_OV7630:
 	case SENSOR_OV7648:
 	case SENSOR_OV7660:
@@ -2472,6 +2579,7 @@
 /*	{USB_DEVICE(0x0c45, 0x6142), BS(SN9C120, PO2030N)},	 *sn9c120b*/
 	{USB_DEVICE(0x0c45, 0x6143), BS(SN9C120, SP80708)},	/*sn9c120b*/
 	{USB_DEVICE(0x0c45, 0x6148), BS(SN9C120, OM6802)},	/*sn9c120b*/
+	{USB_DEVICE(0x0c45, 0x614a), BS(SN9C120, ADCM1700)},	/*sn9c120b*/
 	{}
 };
 MODULE_DEVICE_TABLE(usb, device_table);