V4L/DVB (9125): gspca: Big rewrite of t613 driver

- separate functions for bridge and sensor exchanges
- delays added after some exchanges
- other sensor type

Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index 7e435a3..b561f7c 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -28,8 +28,6 @@
 
 #include "gspca.h"
 
-#define MAX_GAMMA 0x10		/* 0 to 15 */
-
 #define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
 
 MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
@@ -49,6 +47,10 @@
 	unsigned char whitebalance;
 	unsigned char mirror;
 	unsigned char effect;
+
+	__u8 sensor;
+#define SENSOR_TAS5130A 0
+#define SENSOR_OTHER 1
 };
 
 /* V4L2 controls supported by the driver */
@@ -83,9 +85,9 @@
 	  .type = V4L2_CTRL_TYPE_INTEGER,
 	  .name = "Brightness",
 	  .minimum = 0,
-	  .maximum = 0x0f,
+	  .maximum = 14,
 	  .step = 1,
-	  .default_value = 0x09,
+	  .default_value = 8,
 	  },
 	 .set = sd_setbrightness,
 	 .get = sd_getbrightness,
@@ -118,16 +120,17 @@
 	 .set = sd_setcolors,
 	 .get = sd_getcolors,
 	 },
-#define SD_GAMMA 3
+#define GAMMA_MAX 16
+#define GAMMA_DEF 10
 	{
 	 {
 	  .id = V4L2_CID_GAMMA,	/* (gamma on win) */
 	  .type = V4L2_CTRL_TYPE_INTEGER,
-	  .name = "Gamma (Untested)",
+	  .name = "Gamma",
 	  .minimum = 0,
-	  .maximum = MAX_GAMMA,
+	  .maximum = GAMMA_MAX - 1,
 	  .step = 1,
-	  .default_value = 0x09,
+	  .default_value = GAMMA_DEF,
 	  },
 	 .set = sd_setgamma,
 	 .get = sd_getgamma,
@@ -197,7 +200,7 @@
 	  .type = V4L2_CTRL_TYPE_INTEGER,
 	  .name = "Sharpness",
 	  .minimum = 0,
-	  .maximum = MAX_GAMMA,	/* 0 to 16 */
+	  .maximum = 15,
 	  .step = 1,
 	  .default_value = 0x06,
 	  },
@@ -258,7 +261,6 @@
 		.priv = 0},
 };
 
-#define T16_OFFSET_DATA 631
 #define MAX_EFFECTS 7
 /* easily done by soft, this table could be removed,
  * i keep it here just in case */
@@ -272,87 +274,87 @@
 	{0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40},	/* Negative */
 };
 
-static const __u8 gamma_table[MAX_GAMMA][34] = {
-	{0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85,
+static const __u8 gamma_table[GAMMA_MAX][34] = {
+	{0x90, 0x00, 0x91, 0x3e, 0x92, 0x69, 0x93, 0x85,	/* 0 */
 	 0x94, 0x95, 0x95, 0xa1, 0x96, 0xae, 0x97, 0xb9,
 	 0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdb,
 	 0x9c, 0xe3, 0x9d, 0xea, 0x9e, 0xf1, 0x9f, 0xf8,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x33, 0x92, 0x5A, 0x93, 0x75,
-	 0x94, 0x85, 0x95, 0x93, 0x96, 0xA1, 0x97, 0xAD,
-	 0x98, 0xB7, 0x99, 0xC2, 0x9A, 0xCB, 0x9B, 0xD4,
-	 0x9C, 0xDE, 0x9D, 0xE7, 0x9E, 0xF0, 0x9F, 0xF7,
+	{0x90, 0x00, 0x91, 0x33, 0x92, 0x5a, 0x93, 0x75,	/* 1 */
+	 0x94, 0x85, 0x95, 0x93, 0x96, 0xa1, 0x97, 0xad,
+	 0x98, 0xb7, 0x99, 0xc2, 0x9a, 0xcb, 0x9b, 0xd4,
+	 0x9c, 0xde, 0x9D, 0xe7, 0x9e, 0xf0, 0x9f, 0xf7,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x2F, 0x92, 0x51, 0x93, 0x6B,
-	 0x94, 0x7C, 0x95, 0x8A, 0x96, 0x99, 0x97, 0xA6,
-	 0x98, 0xB1, 0x99, 0xBC, 0x9A, 0xC6, 0x9B, 0xD0,
-	 0x9C, 0xDB, 0x9D, 0xE4, 0x9E, 0xED, 0x9F, 0xF6,
+	{0x90, 0x00, 0x91, 0x2f, 0x92, 0x51, 0x93, 0x6b,	/* 2 */
+	 0x94, 0x7c, 0x95, 0x8a, 0x96, 0x99, 0x97, 0xa6,
+	 0x98, 0xb1, 0x99, 0xbc, 0x9a, 0xc6, 0x9b, 0xd0,
+	 0x9c, 0xdb, 0x9d, 0xe4, 0x9e, 0xed, 0x9f, 0xf6,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60,
-	 0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9E,
-	 0x98, 0xAA, 0x99, 0xB5, 0x9A, 0xBF, 0x9B, 0xCB,
-	 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+	{0x90, 0x00, 0x91, 0x29, 0x92, 0x48, 0x93, 0x60,	/* 3 */
+	 0x94, 0x72, 0x95, 0x81, 0x96, 0x90, 0x97, 0x9e,
+	 0x98, 0xaa, 0x99, 0xb5, 0x9a, 0xbf, 0x9b, 0xcb,
+	 0x9c, 0xd6, 0x9d, 0xe1, 0x9e, 0xeb, 0x9f, 0xf5,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x23, 0x92, 0x3F, 0x93, 0x55,
+	{0x90, 0x00, 0x91, 0x23, 0x92, 0x3f, 0x93, 0x55,	/* 4 */
 	 0x94, 0x68, 0x95, 0x77, 0x96, 0x86, 0x97, 0x95,
-	 0x98, 0xA2, 0x99, 0xAD, 0x9A, 0xB9, 0x9B, 0xC6,
-	 0x9C, 0xD2, 0x9D, 0xDE, 0x9E, 0xE9, 0x9F, 0xF4,
+	 0x98, 0xa2, 0x99, 0xad, 0x9a, 0xb9, 0x9b, 0xc6,
+	 0x9c, 0xd2, 0x9d, 0xde, 0x9e, 0xe9, 0x9f, 0xf4,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x1B, 0x92, 0x33, 0x93, 0x48,
+	{0x90, 0x00, 0x91, 0x1b, 0x92, 0x33, 0x93, 0x48,	/* 5 */
 	 0x94, 0x59, 0x95, 0x69, 0x96, 0x79, 0x97, 0x87,
-	 0x98, 0x96, 0x99, 0xA3, 0x9A, 0xB1, 0x9B, 0xBE,
-	 0x9C, 0xCC, 0x9D, 0xDA, 0x9E, 0xE7, 0x9F, 0xF3,
+	 0x98, 0x96, 0x99, 0xa3, 0x9a, 0xb1, 0x9b, 0xbe,
+	 0x9c, 0xcc, 0x9d, 0xda, 0x9e, 0xe7, 0x9f, 0xf3,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20,
+	{0x90, 0x00, 0x91, 0x02, 0x92, 0x10, 0x93, 0x20,	/* 6 */
 	 0x94, 0x32, 0x95, 0x40, 0x96, 0x57, 0x97, 0x67,
 	 0x98, 0x77, 0x99, 0x88, 0x9a, 0x99, 0x9b, 0xaa,
 	 0x9c, 0xbb, 0x9d, 0xcc, 0x9e, 0xdd, 0x9f, 0xee,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26,
-	 0x94, 0x38, 0x95, 0x4A, 0x96, 0x60, 0x97, 0x70,
-	 0x98, 0x80, 0x99, 0x90, 0x9A, 0xA0, 0x9B, 0xB0,
-	 0x9C, 0xC0, 0x9D, 0xD0, 0x9E, 0xE0, 0x9F, 0xF0,
+	{0x90, 0x00, 0x91, 0x02, 0x92, 0x14, 0x93, 0x26,	/* 7 */
+	 0x94, 0x38, 0x95, 0x4a, 0x96, 0x60, 0x97, 0x70,
+	 0x98, 0x80, 0x99, 0x90, 0x9a, 0xa0, 0x9b, 0xb0,
+	 0x9c, 0xc0, 0x9D, 0xd0, 0x9e, 0xe0, 0x9f, 0xf0,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35,
-	 0x94, 0x47, 0x95, 0x5A, 0x96, 0x69, 0x97, 0x79,
-	 0x98, 0x88, 0x99, 0x97, 0x9A, 0xA7, 0x9B, 0xB6,
-	 0x9C, 0xC4, 0x9D, 0xD3, 0x9E, 0xE0, 0x9F, 0xF0,
+	{0x90, 0x00, 0x91, 0x10, 0x92, 0x22, 0x93, 0x35,	/* 8 */
+	 0x94, 0x47, 0x95, 0x5a, 0x96, 0x69, 0x97, 0x79,
+	 0x98, 0x88, 0x99, 0x97, 0x9a, 0xa7, 0x9b, 0xb6,
+	 0x9c, 0xc4, 0x9d, 0xd3, 0x9e, 0xe0, 0x9f, 0xf0,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40,
+	{0x90, 0x00, 0x91, 0x10, 0x92, 0x26, 0x93, 0x40,	/* 9 */
 	 0x94, 0x54, 0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
 	 0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd,
 	 0x9c, 0xca, 0x9d, 0xd6, 0x9e, 0xe0, 0x9f, 0xf0,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x18, 0x92, 0x2B, 0x93, 0x44,
-	 0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8E,
-	 0x98, 0x9C, 0x99, 0xAA, 0x9A, 0xB7, 0x9B, 0xC4,
-	 0x9C, 0xD0, 0x9D, 0xD8, 0x9E, 0xE2, 0x9F, 0xF0,
+	{0x90, 0x00, 0x91, 0x18, 0x92, 0x2b, 0x93, 0x44,	/* 10 */
+	 0x94, 0x60, 0x95, 0x70, 0x96, 0x80, 0x97, 0x8e,
+	 0x98, 0x9c, 0x99, 0xaa, 0x9a, 0xb7, 0x9b, 0xc4,
+	 0x9c, 0xd0, 0x9d, 0xd8, 0x9e, 0xe2, 0x9f, 0xf0,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x1A, 0x92, 0x34, 0x93, 0x52,
-	 0x94, 0x66, 0x95, 0x7E, 0x96, 0x8D, 0x97, 0x9B,
-	 0x98, 0xA8, 0x99, 0xB4, 0x9A, 0xC0, 0x9B, 0xCB,
-	 0x9C, 0xD6, 0x9D, 0xE1, 0x9E, 0xEB, 0x9F, 0xF5,
+	{0x90, 0x00, 0x91, 0x1a, 0x92, 0x34, 0x93, 0x52,	/* 11 */
+	 0x94, 0x66, 0x95, 0x7e, 0x96, 0x8D, 0x97, 0x9B,
+	 0x98, 0xa8, 0x99, 0xb4, 0x9a, 0xc0, 0x9b, 0xcb,
+	 0x9c, 0xd6, 0x9d, 0xe1, 0x9e, 0xeb, 0x9f, 0xf5,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x3F, 0x92, 0x5A, 0x93, 0x6E,
-	 0x94, 0x7F, 0x95, 0x8E, 0x96, 0x9C, 0x97, 0xA8,
-	 0x98, 0xB4, 0x99, 0xBF, 0x9A, 0xC9, 0x9B, 0xD3,
-	 0x9C, 0xDC, 0x9D, 0xE5, 0x9E, 0xEE, 0x9F, 0xF6,
-	 0xA0, 0xFF},
-	{0x90, 0x00, 0x91, 0x54, 0x92, 0x6F, 0x93, 0x83,
-	 0x94, 0x93, 0x95, 0xA0, 0x96, 0xAD, 0x97, 0xB7,
-	 0x98, 0xC2, 0x99, 0xCB, 0x9A, 0xD4, 0x9B, 0xDC,
-	 0x9C, 0xE4, 0x9D, 0xEB, 0x9E, 0xF2, 0x9F, 0xF9,
+	{0x90, 0x00, 0x91, 0x3f, 0x92, 0x5a, 0x93, 0x6e,	/* 12 */
+	 0x94, 0x7f, 0x95, 0x8e, 0x96, 0x9c, 0x97, 0xa8,
+	 0x98, 0xb4, 0x99, 0xbf, 0x9a, 0xc9, 0x9b, 0xd3,
+	 0x9c, 0xdc, 0x9d, 0xe5, 0x9e, 0xee, 0x9f, 0xf6,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x6E, 0x92, 0x88, 0x93, 0x9A,
-	 0x94, 0xA8, 0x95, 0xB3, 0x96, 0xBD, 0x97, 0xC6,
-	 0x98, 0xCF, 0x99, 0xD6, 0x9A, 0xDD, 0x9B, 0xE3,
-	 0x9C, 0xE9, 0x9D, 0xEF, 0x9E, 0xF4, 0x9F, 0xFA,
+	{0x90, 0x00, 0x91, 0x54, 0x92, 0x6f, 0x93, 0x83,	/* 13 */
+	 0x94, 0x93, 0x95, 0xa0, 0x96, 0xad, 0x97, 0xb7,
+	 0x98, 0xc2, 0x99, 0xcb, 0x9a, 0xd4, 0x9b, 0xdc,
+	 0x9c, 0xe4, 0x9d, 0xeb, 0x9e, 0xf2, 0x9f, 0xf9,
 	 0xa0, 0xff},
-	{0x90, 0x00, 0x91, 0x93, 0x92, 0xA8, 0x93, 0xB7,
-	 0x94, 0xC1, 0x95, 0xCA, 0x96, 0xD2, 0x97, 0xD8,
-	 0x98, 0xDE, 0x99, 0xE3, 0x9A, 0xE8, 0x9B, 0xED,
-	 0x9C, 0xF1, 0x9D, 0xF5, 0x9E, 0xF8, 0x9F, 0xFC,
-	 0xA0, 0xFF}
+	{0x90, 0x00, 0x91, 0x6e, 0x92, 0x88, 0x93, 0x9a,	/* 14 */
+	 0x94, 0xa8, 0x95, 0xb3, 0x96, 0xbd, 0x97, 0xc6,
+	 0x98, 0xcf, 0x99, 0xd6, 0x9a, 0xdd, 0x9b, 0xe3,
+	 0x9c, 0xe9, 0x9d, 0xef, 0x9e, 0xf4, 0x9f, 0xfa,
+	 0xa0, 0xff},
+	{0x90, 0x00, 0x91, 0x93, 0x92, 0xa8, 0x93, 0xb7,	/* 15 */
+	 0x94, 0xc1, 0x95, 0xca, 0x96, 0xd2, 0x97, 0xd8,
+	 0x98, 0xde, 0x99, 0xe3, 0x9a, 0xe8, 0x9b, 0xed,
+	 0x9c, 0xf1, 0x9d, 0xf5, 0x9e, 0xf8, 0x9f, 0xfc,
+	 0xa0, 0xff}
 };
 
 static const __u8 tas5130a_sensor_init[][8] = {
@@ -364,7 +366,7 @@
 };
 
 /* read 1 byte */
-static int reg_r_1(struct gspca_dev *gspca_dev,
+static int reg_r(struct gspca_dev *gspca_dev,
 		   __u16 index)
 {
 	usb_control_msg(gspca_dev->dev,
@@ -378,26 +380,26 @@
 }
 
 static void reg_w(struct gspca_dev *gspca_dev,
-			__u16 value,
-			__u16 index,
-			const __u8 *buffer, __u16 len)
+		  __u16 index)
 {
-	if (buffer == NULL) {
-		usb_control_msg(gspca_dev->dev,
-				usb_sndctrlpipe(gspca_dev->dev, 0),
-				0,
-			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-				value, index,
-				NULL, 0, 500);
-		return;
-	}
+	usb_control_msg(gspca_dev->dev,
+			usb_sndctrlpipe(gspca_dev->dev, 0),
+			0,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			0, index,
+			NULL, 0, 500);
+}
+
+static void i2c_w(struct gspca_dev *gspca_dev,
+		  const __u8 *buffer, __u16 len)
+{
 	if (len <= USB_BUF_SZ) {
 		memcpy(gspca_dev->usb_buf, buffer, len);
 		usb_control_msg(gspca_dev->dev,
 				usb_sndctrlpipe(gspca_dev->dev, 0),
 				0,
 			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-				value, index,
+				0x01, 0,
 				gspca_dev->usb_buf, len, 500);
 	} else {
 		__u8 *tmpbuf;
@@ -408,12 +410,56 @@
 				usb_sndctrlpipe(gspca_dev->dev, 0),
 				0,
 			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
-				value, index,
+				0x01, 0,
 				tmpbuf, len, 500);
 		kfree(tmpbuf);
 	}
 }
 
+static void other_sensor_init(struct gspca_dev *gspca_dev)
+{
+	int i;
+	const __u8 *p;
+	__u8 byte;
+	__u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
+	static const __u8 sensor_init[] = {
+		0xdf, 0x6d,
+		0xdd, 0x18,
+		0x5a, 0xe0,
+		0x5c, 0x07,
+		0x5d, 0xb0,
+		0x5e, 0x1e,
+		0x60, 0x71,
+		0xef, 0x00,
+		0xe9, 0x00,
+		0xea, 0x00,
+		0x90, 0x24,
+		0x91, 0xb2,
+		0x82, 0x32,
+		0xfd, 0x00,
+		0xfd, 0x01,
+		0xfd, 0x41,
+		0x00			/* table end */
+	};
+
+	p = sensor_init;
+	while (*p != 0) {
+		val[1] = *p++;
+		val[3] = *p++;
+		if (*p == 0)
+			reg_w(gspca_dev, 0x3c80);
+		i2c_w(gspca_dev, val, sizeof val);
+		i = 4;
+		while (--i >= 0) {
+			msleep(15);
+			byte = reg_r(gspca_dev, 0x60);
+			if (!(byte & 0x01))
+				break;
+		}
+	}
+			reg_w(gspca_dev, 0x3c80);
+}
+
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
 		     const struct usb_device_id *id)
@@ -430,7 +476,7 @@
 	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
 	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
 	sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
-	sd->gamma = sd_ctrls[SD_GAMMA].qctrl.default_value;
+	sd->gamma = GAMMA_DEF;
 	sd->mirror = sd_ctrls[SD_MIRROR].qctrl.default_value;
 	sd->freq = sd_ctrls[SD_LIGHTFREQ].qctrl.default_value;
 	sd->whitebalance = sd_ctrls[SD_WHITE_BALANCE].qctrl.default_value;
@@ -439,27 +485,37 @@
 	return 0;
 }
 
-static int init_default_parameters(struct gspca_dev *gspca_dev)
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	PDEBUG(D_CONF, "Gamma: %d", sd->gamma);
+	i2c_w(gspca_dev, gamma_table[sd->gamma], sizeof gamma_table[0]);
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
 	/* some of this registers are not really neded, because
 	 * they are overriden by setbrigthness, setcontrast, etc,
 	 * but wont hurt anyway, and can help someone with similar webcam
 	 * to see the initial parameters.*/
-	int i = 0;
-	__u8 test_byte;
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+	__u8 byte, test_byte;
 
 	static const __u8 read_indexs[] =
 		{ 0x06, 0x07, 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
 		  0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00, 0x00 };
-	static const __u8 n1[6] =
+	static const __u8 n1[] =
 			{0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
-	static const __u8 n2[2] =
+	static const __u8 n2[] =
 			{0x08, 0x00};
-	static const __u8 nset[6] =
-		{ 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 };
-	static const __u8 n3[6] =
+	static const __u8 nset[] =
+			{ 0x61, 0x68, 0x62, 0xff, 0x60, 0x07 };
+	static const __u8 n3[] =
 			{0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
-	static const __u8 n4[0x46] =
+	static const __u8 n4[] =
 		{0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
 		 0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
 		 0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
@@ -469,33 +525,26 @@
 		 0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
 		 0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
 		 0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
-	static const __u8 nset4[18] = {
+	static const __u8 nset4[] = {
 		0xe0, 0x60, 0xe1, 0xa8, 0xe2, 0xe0, 0xe3, 0x60, 0xe4, 0xa8,
 		0xe5, 0xe0, 0xe6, 0x60, 0xe7, 0xa8,
 		0xe8, 0xe0
 	};
 	/* ojo puede ser 0xe6 en vez de 0xe9 */
-	static const __u8 nset2[20] = {
+	static const __u8 nset2[] = {
 		0xd0, 0xbb, 0xd1, 0x28, 0xd2, 0x10, 0xd3, 0x10, 0xd4, 0xbb,
 		0xd5, 0x28, 0xd6, 0x1e, 0xd7, 0x27,
 		0xd8, 0xc8, 0xd9, 0xfc
 	};
-	static const __u8 missing[8] =
+	static const __u8 missing[] =
 		{ 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x80, 0x38 };
-	static const __u8 nset3[18] = {
+	static const __u8 nset3[] = {
 		0xc7, 0x60, 0xc8, 0xa8, 0xc9, 0xe0, 0xca, 0x60, 0xcb, 0xa8,
 		0xcc, 0xe0, 0xcd, 0x60, 0xce, 0xa8,
 		0xcf, 0xe0
 	};
-	static const __u8 nset5[4] =
-		{ 0x8f, 0x24, 0xc3, 0x00 };	/* bright */
-	static const __u8 nset6[34] = {
-		0x90, 0x00, 0x91, 0x1c, 0x92, 0x30, 0x93, 0x43, 0x94, 0x54,
-		0x95, 0x65, 0x96, 0x75, 0x97, 0x84,
-		0x98, 0x93, 0x99, 0xa1, 0x9a, 0xb0, 0x9b, 0xbd, 0x9c, 0xca,
-		0x9d, 0xd8, 0x9e, 0xe5, 0x9f, 0xf2,
-		0xa0, 0xff
-	};			/* Gamma */
+	static const __u8 nset5[] =
+			{ 0x8f, 0x24, 0xc3, 0x00 };	/* bright */
 	static const __u8 nset7[4] =
 			{ 0x66, 0xca, 0xa8, 0xf8 };	/* 50/60 Hz */
 	static const __u8 nset9[4] =
@@ -505,95 +554,111 @@
 	static const __u8 nset10[6] =
 			{ 0x0c, 0x03, 0xab, 0x10, 0x81, 0x20 };
 
-	reg_w(gspca_dev, 0x01, 0x0000, n1, 0x06);
-	reg_w(gspca_dev, 0x01, 0x0000, nset, 0x06);
-	reg_r_1(gspca_dev, 0x0063);
-	reg_w(gspca_dev, 0x01, 0x0000, n2, 0x02);
+	byte = reg_r(gspca_dev, 0x06);
+	test_byte = reg_r(gspca_dev, 0x07);
+	if (byte == 0x08 && test_byte == 0x07) {
+		PDEBUG(D_CONF, "other sensor");
+		sd->sensor = SENSOR_OTHER;
+	} else {
+		PDEBUG(D_CONF, "sensor %02x %02x", byte, test_byte);
+		sd->sensor = SENSOR_TAS5130A;
+	}
 
+	i2c_w(gspca_dev, n1, sizeof n1);
+	test_byte = 0;
+	i = 5;
+	while (--i >= 0) {
+		i2c_w(gspca_dev, nset, sizeof nset);
+		msleep(5);
+		test_byte = reg_r(gspca_dev, 0x0063);
+		msleep(100);
+		if (test_byte == 0x17)
+			break;		/* OK */
+	}
+	if (i < 0) {
+		err("Bad sensor reset %02x", test_byte);
+/*		return -EIO; */
+/*fixme: test - continue */
+	}
+	i2c_w(gspca_dev, n2, sizeof n2);
+
+	i = 0;
 	while (read_indexs[i] != 0x00) {
-		test_byte = reg_r_1(gspca_dev, read_indexs[i]);
-		PDEBUG(D_CONF, "Reg 0x%02x => 0x%02x", read_indexs[i],
+		test_byte = reg_r(gspca_dev, read_indexs[i]);
+		PDEBUG(D_STREAM, "Reg 0x%02x = 0x%02x", read_indexs[i],
 		       test_byte);
 		i++;
 	}
 
-	reg_w(gspca_dev, 0x01, 0x0000, n3, 0x06);
-	reg_w(gspca_dev, 0x01, 0x0000, n4, 0x46);
-	reg_r_1(gspca_dev, 0x0080);
-	reg_w(gspca_dev, 0x00, 0x2c80, NULL, 0);
-	reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14);
-	reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12);
-	reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12);
-	reg_w(gspca_dev, 0x00, 0x3880, NULL, 0);
-	reg_w(gspca_dev, 0x00, 0x3880, NULL, 0);
-	reg_w(gspca_dev, 0x00, 0x338e, NULL, 0);
-	reg_w(gspca_dev, 0x01, 0x0000, nset5, 0x04);
-	reg_w(gspca_dev, 0x00, 0x00a9, NULL, 0);
-	reg_w(gspca_dev, 0x01, 0x0000, nset6, 0x22);
-	reg_w(gspca_dev, 0x00, 0x86bb, NULL, 0);
-	reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0);
+	i2c_w(gspca_dev, n3, sizeof n3);
+	i2c_w(gspca_dev, n4, sizeof n4);
+	reg_r(gspca_dev, 0x0080);
+	reg_w(gspca_dev, 0x2c80);
+	i2c_w(gspca_dev, nset2, sizeof nset2);
+	i2c_w(gspca_dev, nset3, sizeof nset3);
+	i2c_w(gspca_dev, nset4, sizeof nset4);
+	reg_w(gspca_dev, 0x3880);
+	reg_w(gspca_dev, 0x3880);
+	reg_w(gspca_dev, 0x338e);
+	i2c_w(gspca_dev, nset5, sizeof nset5);
+	reg_w(gspca_dev, 0x00a9);
+	setgamma(gspca_dev);
+	reg_w(gspca_dev, 0x86bb);
+	reg_w(gspca_dev, 0x4aa6);
 
-	reg_w(gspca_dev, 0x01, 0x0000, missing, 0x08);
+	i2c_w(gspca_dev, missing, sizeof missing);
 
-	reg_w(gspca_dev, 0x00, 0x2087, NULL, 0);
-	reg_w(gspca_dev, 0x00, 0x2088, NULL, 0);
-	reg_w(gspca_dev, 0x00, 0x2089, NULL, 0);
+	reg_w(gspca_dev, 0x2087);
+	reg_w(gspca_dev, 0x2088);
+	reg_w(gspca_dev, 0x2089);
 
-	reg_w(gspca_dev, 0x01, 0x0000, nset7, 0x04);
-	reg_w(gspca_dev, 0x01, 0x0000, nset10, 0x06);
-	reg_w(gspca_dev, 0x01, 0x0000, nset8, 0x06);
-	reg_w(gspca_dev, 0x01, 0x0000, nset9, 0x04);
+	i2c_w(gspca_dev, nset7, sizeof nset7);
+	i2c_w(gspca_dev, nset10, sizeof nset10);
+	i2c_w(gspca_dev, nset8, sizeof nset8);
+	i2c_w(gspca_dev, nset9, sizeof nset9);
 
-	reg_w(gspca_dev, 0x00, 0x2880, NULL, 0);
-	reg_w(gspca_dev, 0x01, 0x0000, nset2, 0x14);
-	reg_w(gspca_dev, 0x01, 0x0000, nset3, 0x12);
-	reg_w(gspca_dev, 0x01, 0x0000, nset4, 0x12);
+	reg_w(gspca_dev, 0x2880);
+	i2c_w(gspca_dev, nset2, sizeof nset2);
+	i2c_w(gspca_dev, nset3, sizeof nset3);
+	i2c_w(gspca_dev, nset4, sizeof nset4);
 
 	return 0;
 }
 
-/* this function is called at probe and resume time */
-static int sd_init(struct gspca_dev *gspca_dev)
-{
-	init_default_parameters(gspca_dev);
-	return 0;
-}
-
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	unsigned int brightness;
-	__u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x80 };
-	brightness = sd->brightness;
+	__u8 set6[4] = { 0x8f, 0x26, 0xc3, 0x00 };
 
+	brightness = sd->brightness;
 	if (brightness < 7) {
-		set6[3] = 0x70 - (brightness * 0xa);
+		set6[3] = 0x70 - brightness * 0x10;
 	} else {
 		set6[1] = 0x24;
-		set6[3] = 0x00 + ((brightness - 7) * 0xa);
+		set6[3] = 0x00 + ((brightness - 7) * 0x10);
 	}
 
-	reg_w(gspca_dev, 0x01, 0x0000, set6, 4);
+	i2c_w(gspca_dev, set6, sizeof set6);
 }
 
 static void setflip(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-
 	__u8 flipcmd[8] =
-	    { 0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09 };
+		{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
 
-	if (sd->mirror == 1)
+	if (sd->mirror)
 		flipcmd[3] = 0x01;
 
-	reg_w(gspca_dev, 0x01, 0x0000, flipcmd, 8);
+	i2c_w(gspca_dev, flipcmd, sizeof flipcmd);
 }
 
 static void seteffect(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	reg_w(gspca_dev, 0x01, 0x0000, effects_table[sd->effect], 0x06);
+	i2c_w(gspca_dev, effects_table[sd->effect], sizeof effects_table[0]);
 	if (sd->effect == 1 || sd->effect == 5) {
 		PDEBUG(D_CONF,
 		       "This effect have been disabled for webcam \"safety\"");
@@ -601,9 +666,9 @@
 	}
 
 	if (sd->effect == 1 || sd->effect == 4)
-		reg_w(gspca_dev, 0x00, 0x4aa6, NULL, 0);
+		reg_w(gspca_dev, 0x4aa6);
 	else
-		reg_w(gspca_dev, 0x00, 0xfaa6, NULL, 0);
+		reg_w(gspca_dev, 0xfaa6);
 }
 
 static void setwhitebalance(struct gspca_dev *gspca_dev)
@@ -616,7 +681,7 @@
 	if (sd->whitebalance == 1)
 		white_balance[7] = 0x3c;
 
-	reg_w(gspca_dev, 0x01, 0x0000, white_balance, 8);
+	i2c_w(gspca_dev, white_balance, sizeof white_balance);
 }
 
 static void setlightfreq(struct gspca_dev *gspca_dev)
@@ -627,21 +692,21 @@
 	if (sd->freq == 2)	/* 60hz */
 		freq[1] = 0x00;
 
-	reg_w(gspca_dev, 0x1, 0x0000, freq, 0x4);
+	i2c_w(gspca_dev, freq, sizeof freq);
 }
 
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	unsigned int contrast = sd->contrast;
-	__u16 reg_to_write = 0x00;
+	__u16 reg_to_write;
 
 	if (contrast < 7)
 		reg_to_write = 0x8ea9 - (0x200 * contrast);
 	else
 		reg_to_write = (0x00a9 + ((contrast - 7) * 0x200));
 
-	reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
+	reg_w(gspca_dev, reg_to_write);
 }
 
 static void setcolors(struct gspca_dev *gspca_dev)
@@ -650,11 +715,7 @@
 	__u16 reg_to_write;
 
 	reg_to_write = 0xc0bb + sd->colors * 0x100;
-	reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
-}
-
-static void setgamma(struct gspca_dev *gspca_dev)
-{
+	reg_w(gspca_dev, reg_to_write);
 }
 
 static void setsharpness(struct gspca_dev *gspca_dev)
@@ -664,7 +725,99 @@
 
 	reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness;
 
-	reg_w(gspca_dev, 0x00, reg_to_write, NULL, 0);
+	reg_w(gspca_dev, reg_to_write);
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i, mode;
+	static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 };
+	__u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
+	static const __u8 t3[] =
+		{ 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
+		  0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
+	static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 };
+
+	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
+	switch (mode) {
+	case 1:		/* 352x288 */
+		t2[1] = 0x40;
+		break;
+	case 2:		/* 320x240 */
+		t2[1] = 0x10;
+		break;
+	case 3:		/* 176x144 */
+		t2[1] = 0x50;
+		break;
+	case 4:		/* 160x120 */
+		t2[1] = 0x20;
+		break;
+	default:	/* 640x480 (0x00) */
+		break;
+	}
+
+	if (sd->sensor == SENSOR_TAS5130A) {
+		i = 0;
+		while (tas5130a_sensor_init[i][0] != 0) {
+			i2c_w(gspca_dev, tas5130a_sensor_init[i],
+					 sizeof tas5130a_sensor_init[0]);
+			i++;
+		}
+		reg_w(gspca_dev, 0x3c80);
+		/* just in case and to keep sync with logs (for mine) */
+		i2c_w(gspca_dev, tas5130a_sensor_init[3],
+				 sizeof tas5130a_sensor_init[0]);
+		reg_w(gspca_dev, 0x3c80);
+	} else {
+		other_sensor_init(gspca_dev);
+	}
+	/* just in case and to keep sync with logs  (for mine) */
+	i2c_w(gspca_dev, t1, sizeof t1);
+	i2c_w(gspca_dev, t2, sizeof t2);
+	reg_r(gspca_dev, 0x0012);
+	i2c_w(gspca_dev, t3, sizeof t3);
+	reg_w(gspca_dev, 0x0013);
+	i2c_w(gspca_dev, t4, sizeof t4);
+	/* restart on each start, just in case, sometimes regs goes wrong
+	 * when using controls from app */
+	setbrightness(gspca_dev);
+	setcontrast(gspca_dev);
+	setcolors(gspca_dev);
+	return 0;
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame,	/* target */
+			__u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	static __u8 ffd9[] = { 0xff, 0xd9 };
+
+	if (data[0] == 0x5a) {
+		/* Control Packet, after this came the header again,
+		 * but extra bytes came in the packet before this,
+		 * sometimes an EOF arrives, sometimes not... */
+		return;
+	}
+	data += 2;
+	len -= 2;
+	if (data[0] == 0xff && data[1] == 0xd8) {
+		/* extra bytes....., could be processed too but would be
+		 * a waste of time, right now leave the application and
+		 * libjpeg do it for ourserlves.. */
+		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+					ffd9, 2);
+		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
+		return;
+	}
+
+	if (data[len - 2] == 0xff && data[len - 1] == 0xd9) {
+		/* Just in case, i have seen packets with the marker,
+		 * other's do not include it... */
+		len -= 2;
+	}
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
@@ -788,6 +941,7 @@
 static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+
 	*val = sd->gamma;
 	return 0;
 }
@@ -835,9 +989,9 @@
 
 	sd->autogain = val;
 	if (val != 0)
-		reg_w(gspca_dev, 0x00, 0xf48e, NULL, 0);
+		reg_w(gspca_dev, 0xf48e);
 	else
-		reg_w(gspca_dev, 0x00, 0xb48e, NULL, 0);
+		reg_w(gspca_dev, 0xb48e);
 	return 0;
 }
 
@@ -849,100 +1003,6 @@
 	return 0;
 }
 
-static int sd_start(struct gspca_dev *gspca_dev)
-{
-	int mode;
-
-	static const __u8 t1[] = { 0x66, 0x00, 0xa8, 0xe8 };
-	__u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
-	static const __u8 t3[] =
-		{ 0xb3, 0x07, 0xb4, 0x00, 0xb5, 0x88, 0xb6, 0x02, 0xb7, 0x06,
-		  0xb8, 0x00, 0xb9, 0xe7, 0xba, 0x01 };
-	static const __u8 t4[] = { 0x0b, 0x04, 0x0a, 0x40 };
-
-	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
-	switch (mode) {
-	case 1:		/* 352x288 */
-		t2[1] = 0x40;
-		break;
-	case 2:		/* 320x240 */
-		t2[1] = 0x10;
-		break;
-	case 3:		/* 176x144 */
-		t2[1] = 0x50;
-		break;
-	case 4:		/* 160x120 */
-		t2[1] = 0x20;
-		break;
-	default:	/* 640x480 (0x00) */
-		break;
-	}
-
-	reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[0], 0x8);
-	reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[1], 0x8);
-	reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[2], 0x8);
-	reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
-	reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0);
-		/* just in case and to keep sync with logs  (for mine) */
-	reg_w(gspca_dev, 0x01, 0x0000, tas5130a_sensor_init[3], 0x8);
-	reg_w(gspca_dev, 0x00, 0x3c80, NULL, 0);
-		/* just in case and to keep sync with logs  (for mine) */
-	reg_w(gspca_dev, 0x01, 0x0000, t1, 4);
-	reg_w(gspca_dev, 0x01, 0x0000, t2, 6);
-	reg_r_1(gspca_dev, 0x0012);
-	reg_w(gspca_dev, 0x01, 0x0000, t3, 0x10);
-	reg_w(gspca_dev, 0x00, 0x0013, NULL, 0);
-	reg_w(gspca_dev, 0x01, 0x0000, t4, 0x4);
-	/* restart on each start, just in case, sometimes regs goes wrong
-	 * when using controls from app */
-	setbrightness(gspca_dev);
-	setcontrast(gspca_dev);
-	setcolors(gspca_dev);
-	return 0;
-}
-
-static void sd_pkt_scan(struct gspca_dev *gspca_dev,
-			struct gspca_frame *frame,	/* target */
-			__u8 *data,			/* isoc packet */
-			int len)			/* iso packet length */
-{
-	int sof = 0;
-	static __u8 ffd9[] = { 0xff, 0xd9 };
-
-	if (data[0] == 0x5a) {
-		/* Control Packet, after this came the header again,
-		 * but extra bytes came in the packet before this,
-		 * sometimes an EOF arrives, sometimes not... */
-		return;
-	}
-
-	if (data[len - 2] == 0xff && data[len - 1] == 0xd9) {
-		/* Just in case, i have seen packets with the marker,
-		 * other's do not include it... */
-		data += 2;
-		len -= 4;
-	} else if (data[2] == 0xff && data[3] == 0xd8) {
-		sof = 1;
-		data += 2;
-		len -= 2;
-	} else {
-		data += 2;
-		len -= 2;
-	}
-
-	if (sof) {
-		/* extra bytes....., could be processed too but would be
-		 * a waste of time, right now leave the application and
-		 * libjpeg do it for ourserlves.. */
-		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-					ffd9, 2);
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
-		return;
-	}
-
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
-}
-
 static int sd_querymenu(struct gspca_dev *gspca_dev,
 			struct v4l2_querymenu *menu)
 {