V4L/DVB (8819): gspca: Initialize the ov519 at open time and source cleanup.

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/ov519.c b/drivers/media/video/gspca/ov519.c
index c132f8d..4062aed 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -63,11 +63,10 @@
 #define SEN_OV6630 2
 #define SEN_OV7610 3
 #define SEN_OV7620 4
-#define SEN_OV7630 5
-#define SEN_OV7640 6
-#define SEN_OV7670 7
-#define SEN_OV76BE 8
-#define SEN_OV8610 9
+#define SEN_OV7640 5
+#define SEN_OV7670 6
+#define SEN_OV76BE 7
+#define SEN_OV8610 8
 
 };
 
@@ -293,6 +292,541 @@
 #define OV7670_REG_HAECC7      0xaa    /* Hist AEC/AGC control 7 */
 #define OV7670_REG_BD60MAX     0xab    /* 60hz banding step limit */
 
+struct ov_regvals {
+	__u8 reg;
+	__u8 val;
+};
+struct ov_i2c_regvals {
+	__u8 reg;
+	__u8 val;
+};
+
+static const struct ov_i2c_regvals norm_6x20[] = {
+	{ 0x12, 0x80 }, /* reset */
+	{ 0x11, 0x01 },
+	{ 0x03, 0x60 },
+	{ 0x05, 0x7f }, /* For when autoadjust is off */
+	{ 0x07, 0xa8 },
+	/* The ratio of 0x0c and 0x0d  controls the white point */
+	{ 0x0c, 0x24 },
+	{ 0x0d, 0x24 },
+	{ 0x0f, 0x15 }, /* COMS */
+	{ 0x10, 0x75 }, /* AEC Exposure time */
+	{ 0x12, 0x24 }, /* Enable AGC */
+	{ 0x14, 0x04 },
+	/* 0x16: 0x06 helps frame stability with moving objects */
+	{ 0x16, 0x06 },
+/*	{ 0x20, 0x30 },  * Aperture correction enable */
+	{ 0x26, 0xb2 }, /* BLC enable */
+	/* 0x28: 0x05 Selects RGB format if RGB on */
+	{ 0x28, 0x05 },
+	{ 0x2a, 0x04 }, /* Disable framerate adjust */
+/*	{ 0x2b, 0xac },  * Framerate; Set 2a[7] first */
+	{ 0x2d, 0x99 },
+	{ 0x33, 0xa0 }, /* Color Processing Parameter */
+	{ 0x34, 0xd2 }, /* Max A/D range */
+	{ 0x38, 0x8b },
+	{ 0x39, 0x40 },
+
+	{ 0x3c, 0x39 }, /* Enable AEC mode changing */
+	{ 0x3c, 0x3c }, /* Change AEC mode */
+	{ 0x3c, 0x24 }, /* Disable AEC mode changing */
+
+	{ 0x3d, 0x80 },
+	/* These next two registers (0x4a, 0x4b) are undocumented.
+	 * They control the color balance */
+	{ 0x4a, 0x80 },
+	{ 0x4b, 0x80 },
+	{ 0x4d, 0xd2 }, /* This reduces noise a bit */
+	{ 0x4e, 0xc1 },
+	{ 0x4f, 0x04 },
+/* Do 50-53 have any effect? */
+/* Toggle 0x12[2] off and on here? */
+};
+
+static const struct ov_i2c_regvals norm_6x30[] = {
+	{ 0x12, 0x80 }, /* Reset */
+	{ 0x00, 0x1f }, /* Gain */
+	{ 0x01, 0x99 }, /* Blue gain */
+	{ 0x02, 0x7c }, /* Red gain */
+	{ 0x03, 0xc0 }, /* Saturation */
+	{ 0x05, 0x0a }, /* Contrast */
+	{ 0x06, 0x95 }, /* Brightness */
+	{ 0x07, 0x2d }, /* Sharpness */
+	{ 0x0c, 0x20 },
+	{ 0x0d, 0x20 },
+	{ 0x0e, 0x20 },
+	{ 0x0f, 0x05 },
+	{ 0x10, 0x9a },
+	{ 0x11, 0x00 }, /* Pixel clock = fastest */
+	{ 0x12, 0x24 }, /* Enable AGC and AWB */
+	{ 0x13, 0x21 },
+	{ 0x14, 0x80 },
+	{ 0x15, 0x01 },
+	{ 0x16, 0x03 },
+	{ 0x17, 0x38 },
+	{ 0x18, 0xea },
+	{ 0x19, 0x04 },
+	{ 0x1a, 0x93 },
+	{ 0x1b, 0x00 },
+	{ 0x1e, 0xc4 },
+	{ 0x1f, 0x04 },
+	{ 0x20, 0x20 },
+	{ 0x21, 0x10 },
+	{ 0x22, 0x88 },
+	{ 0x23, 0xc0 }, /* Crystal circuit power level */
+	{ 0x25, 0x9a }, /* Increase AEC black ratio */
+	{ 0x26, 0xb2 }, /* BLC enable */
+	{ 0x27, 0xa2 },
+	{ 0x28, 0x00 },
+	{ 0x29, 0x00 },
+	{ 0x2a, 0x84 }, /* 60 Hz power */
+	{ 0x2b, 0xa8 }, /* 60 Hz power */
+	{ 0x2c, 0xa0 },
+	{ 0x2d, 0x95 }, /* Enable auto-brightness */
+	{ 0x2e, 0x88 },
+	{ 0x33, 0x26 },
+	{ 0x34, 0x03 },
+	{ 0x36, 0x8f },
+	{ 0x37, 0x80 },
+	{ 0x38, 0x83 },
+	{ 0x39, 0x80 },
+	{ 0x3a, 0x0f },
+	{ 0x3b, 0x3c },
+	{ 0x3c, 0x1a },
+	{ 0x3d, 0x80 },
+	{ 0x3e, 0x80 },
+	{ 0x3f, 0x0e },
+	{ 0x40, 0x00 }, /* White bal */
+	{ 0x41, 0x00 }, /* White bal */
+	{ 0x42, 0x80 },
+	{ 0x43, 0x3f }, /* White bal */
+	{ 0x44, 0x80 },
+	{ 0x45, 0x20 },
+	{ 0x46, 0x20 },
+	{ 0x47, 0x80 },
+	{ 0x48, 0x7f },
+	{ 0x49, 0x00 },
+	{ 0x4a, 0x00 },
+	{ 0x4b, 0x80 },
+	{ 0x4c, 0xd0 },
+	{ 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
+	{ 0x4e, 0x40 },
+	{ 0x4f, 0x07 }, /* UV avg., col. killer: max */
+	{ 0x50, 0xff },
+	{ 0x54, 0x23 }, /* Max AGC gain: 18dB */
+	{ 0x55, 0xff },
+	{ 0x56, 0x12 },
+	{ 0x57, 0x81 },
+	{ 0x58, 0x75 },
+	{ 0x59, 0x01 }, /* AGC dark current comp.: +1 */
+	{ 0x5a, 0x2c },
+	{ 0x5b, 0x0f }, /* AWB chrominance levels */
+	{ 0x5c, 0x10 },
+	{ 0x3d, 0x80 },
+	{ 0x27, 0xa6 },
+	{ 0x12, 0x20 }, /* Toggle AWB */
+	{ 0x12, 0x24 },
+};
+
+/* Lawrence Glaister <lg@jfm.bc.ca> reports:
+ *
+ * Register 0x0f in the 7610 has the following effects:
+ *
+ * 0x85 (AEC method 1): Best overall, good contrast range
+ * 0x45 (AEC method 2): Very overexposed
+ * 0xa5 (spec sheet default): Ok, but the black level is
+ *	shifted resulting in loss of contrast
+ * 0x05 (old driver setting): very overexposed, too much
+ *	contrast
+ */
+static const struct ov_i2c_regvals norm_7610[] = {
+	{ 0x10, 0xff },
+	{ 0x16, 0x06 },
+	{ 0x28, 0x24 },
+	{ 0x2b, 0xac },
+	{ 0x12, 0x00 },
+	{ 0x38, 0x81 },
+	{ 0x28, 0x24 },	/* 0c */
+	{ 0x0f, 0x85 },	/* lg's setting */
+	{ 0x15, 0x01 },
+	{ 0x20, 0x1c },
+	{ 0x23, 0x2a },
+	{ 0x24, 0x10 },
+	{ 0x25, 0x8a },
+	{ 0x26, 0xa2 },
+	{ 0x27, 0xc2 },
+	{ 0x2a, 0x04 },
+	{ 0x2c, 0xfe },
+	{ 0x2d, 0x93 },
+	{ 0x30, 0x71 },
+	{ 0x31, 0x60 },
+	{ 0x32, 0x26 },
+	{ 0x33, 0x20 },
+	{ 0x34, 0x48 },
+	{ 0x12, 0x24 },
+	{ 0x11, 0x01 },
+	{ 0x0c, 0x24 },
+	{ 0x0d, 0x24 },
+};
+
+static const struct ov_i2c_regvals norm_7620[] = {
+	{ 0x00, 0x00 },		/* gain */
+	{ 0x01, 0x80 },		/* blue gain */
+	{ 0x02, 0x80 },		/* red gain */
+	{ 0x03, 0xc0 },		/* OV7670_REG_VREF */
+	{ 0x06, 0x60 },
+	{ 0x07, 0x00 },
+	{ 0x0c, 0x24 },
+	{ 0x0c, 0x24 },
+	{ 0x0d, 0x24 },
+	{ 0x11, 0x01 },
+	{ 0x12, 0x24 },
+	{ 0x13, 0x01 },
+	{ 0x14, 0x84 },
+	{ 0x15, 0x01 },
+	{ 0x16, 0x03 },
+	{ 0x17, 0x2f },
+	{ 0x18, 0xcf },
+	{ 0x19, 0x06 },
+	{ 0x1a, 0xf5 },
+	{ 0x1b, 0x00 },
+	{ 0x20, 0x18 },
+	{ 0x21, 0x80 },
+	{ 0x22, 0x80 },
+	{ 0x23, 0x00 },
+	{ 0x26, 0xa2 },
+	{ 0x27, 0xea },
+	{ 0x28, 0x20 },
+	{ 0x29, 0x00 },
+	{ 0x2a, 0x10 },
+	{ 0x2b, 0x00 },
+	{ 0x2c, 0x88 },
+	{ 0x2d, 0x91 },
+	{ 0x2e, 0x80 },
+	{ 0x2f, 0x44 },
+	{ 0x60, 0x27 },
+	{ 0x61, 0x02 },
+	{ 0x62, 0x5f },
+	{ 0x63, 0xd5 },
+	{ 0x64, 0x57 },
+	{ 0x65, 0x83 },
+	{ 0x66, 0x55 },
+	{ 0x67, 0x92 },
+	{ 0x68, 0xcf },
+	{ 0x69, 0x76 },
+	{ 0x6a, 0x22 },
+	{ 0x6b, 0x00 },
+	{ 0x6c, 0x02 },
+	{ 0x6d, 0x44 },
+	{ 0x6e, 0x80 },
+	{ 0x6f, 0x1d },
+	{ 0x70, 0x8b },
+	{ 0x71, 0x00 },
+	{ 0x72, 0x14 },
+	{ 0x73, 0x54 },
+	{ 0x74, 0x00 },
+	{ 0x75, 0x8e },
+	{ 0x76, 0x00 },
+	{ 0x77, 0xff },
+	{ 0x78, 0x80 },
+	{ 0x79, 0x80 },
+	{ 0x7a, 0x80 },
+	{ 0x7b, 0xe2 },
+	{ 0x7c, 0x00 },
+};
+
+/* 7640 and 7648. The defaults should be OK for most registers. */
+static const struct ov_i2c_regvals norm_7640[] = {
+	{ 0x12, 0x80 },
+	{ 0x12, 0x14 },
+};
+
+/* 7670. Defaults taken from OmniVision provided data,
+*  as provided by Jonathan Corbet of OLPC		*/
+static const struct ov_i2c_regvals norm_7670[] = {
+	{ OV7670_REG_COM7, OV7670_COM7_RESET },
+	{ OV7670_REG_TSLB, 0x04 },		/* OV */
+	{ OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
+	{ OV7670_REG_CLKRC, 0x01 },
+/*
+ * Set the hardware window.  These values from OV don't entirely
+ * make sense - hstop is less than hstart.  But they work...
+ */
+	{ OV7670_REG_HSTART, 0x13 },
+	{ OV7670_REG_HSTOP, 0x01 },
+	{ OV7670_REG_HREF, 0xb6 },
+	{ OV7670_REG_VSTART, 0x02 },
+	{ OV7670_REG_VSTOP, 0x7a },
+	{ OV7670_REG_VREF, 0x0a },
+
+	{ OV7670_REG_COM3, 0 },
+	{ OV7670_REG_COM14, 0 },
+/* Mystery scaling numbers */
+	{ 0x70, 0x3a },
+	{ 0x71, 0x35 },
+	{ 0x72, 0x11 },
+	{ 0x73, 0xf0 },
+	{ 0xa2, 0x02 },
+/*	{ OV7670_REG_COM10, 0x0 }, */
+
+/* Gamma curve values */
+	{ 0x7a, 0x20 },
+	{ 0x7b, 0x10 },
+	{ 0x7c, 0x1e },
+	{ 0x7d, 0x35 },
+	{ 0x7e, 0x5a },
+	{ 0x7f, 0x69 },
+	{ 0x80, 0x76 },
+	{ 0x81, 0x80 },
+	{ 0x82, 0x88 },
+	{ 0x83, 0x8f },
+	{ 0x84, 0x96 },
+	{ 0x85, 0xa3 },
+	{ 0x86, 0xaf },
+	{ 0x87, 0xc4 },
+	{ 0x88, 0xd7 },
+	{ 0x89, 0xe8 },
+
+/* AGC and AEC parameters.  Note we start by disabling those features,
+   then turn them only after tweaking the values. */
+	{ OV7670_REG_COM8, OV7670_COM8_FASTAEC
+			 | OV7670_COM8_AECSTEP
+			 | OV7670_COM8_BFILT },
+	{ OV7670_REG_GAIN, 0 },
+	{ OV7670_REG_AECH, 0 },
+	{ OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
+	{ OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
+	{ OV7670_REG_BD50MAX, 0x05 },
+	{ OV7670_REG_BD60MAX, 0x07 },
+	{ OV7670_REG_AEW, 0x95 },
+	{ OV7670_REG_AEB, 0x33 },
+	{ OV7670_REG_VPT, 0xe3 },
+	{ OV7670_REG_HAECC1, 0x78 },
+	{ OV7670_REG_HAECC2, 0x68 },
+	{ 0xa1, 0x03 }, /* magic */
+	{ OV7670_REG_HAECC3, 0xd8 },
+	{ OV7670_REG_HAECC4, 0xd8 },
+	{ OV7670_REG_HAECC5, 0xf0 },
+	{ OV7670_REG_HAECC6, 0x90 },
+	{ OV7670_REG_HAECC7, 0x94 },
+	{ OV7670_REG_COM8, OV7670_COM8_FASTAEC
+			| OV7670_COM8_AECSTEP
+			| OV7670_COM8_BFILT
+			| OV7670_COM8_AGC
+			| OV7670_COM8_AEC },
+
+/* Almost all of these are magic "reserved" values.  */
+	{ OV7670_REG_COM5, 0x61 },
+	{ OV7670_REG_COM6, 0x4b },
+	{ 0x16, 0x02 },
+	{ OV7670_REG_MVFP, 0x07 },
+	{ 0x21, 0x02 },
+	{ 0x22, 0x91 },
+	{ 0x29, 0x07 },
+	{ 0x33, 0x0b },
+	{ 0x35, 0x0b },
+	{ 0x37, 0x1d },
+	{ 0x38, 0x71 },
+	{ 0x39, 0x2a },
+	{ OV7670_REG_COM12, 0x78 },
+	{ 0x4d, 0x40 },
+	{ 0x4e, 0x20 },
+	{ OV7670_REG_GFIX, 0 },
+	{ 0x6b, 0x4a },
+	{ 0x74, 0x10 },
+	{ 0x8d, 0x4f },
+	{ 0x8e, 0 },
+	{ 0x8f, 0 },
+	{ 0x90, 0 },
+	{ 0x91, 0 },
+	{ 0x96, 0 },
+	{ 0x9a, 0 },
+	{ 0xb0, 0x84 },
+	{ 0xb1, 0x0c },
+	{ 0xb2, 0x0e },
+	{ 0xb3, 0x82 },
+	{ 0xb8, 0x0a },
+
+/* More reserved magic, some of which tweaks white balance */
+	{ 0x43, 0x0a },
+	{ 0x44, 0xf0 },
+	{ 0x45, 0x34 },
+	{ 0x46, 0x58 },
+	{ 0x47, 0x28 },
+	{ 0x48, 0x3a },
+	{ 0x59, 0x88 },
+	{ 0x5a, 0x88 },
+	{ 0x5b, 0x44 },
+	{ 0x5c, 0x67 },
+	{ 0x5d, 0x49 },
+	{ 0x5e, 0x0e },
+	{ 0x6c, 0x0a },
+	{ 0x6d, 0x55 },
+	{ 0x6e, 0x11 },
+	{ 0x6f, 0x9f },
+					/* "9e for advance AWB" */
+	{ 0x6a, 0x40 },
+	{ OV7670_REG_BLUE, 0x40 },
+	{ OV7670_REG_RED, 0x60 },
+	{ OV7670_REG_COM8, OV7670_COM8_FASTAEC
+			| OV7670_COM8_AECSTEP
+			| OV7670_COM8_BFILT
+			| OV7670_COM8_AGC
+			| OV7670_COM8_AEC
+			| OV7670_COM8_AWB },
+
+/* Matrix coefficients */
+	{ 0x4f, 0x80 },
+	{ 0x50, 0x80 },
+	{ 0x51, 0 },
+	{ 0x52, 0x22 },
+	{ 0x53, 0x5e },
+	{ 0x54, 0x80 },
+	{ 0x58, 0x9e },
+
+	{ OV7670_REG_COM16, OV7670_COM16_AWBGAIN },
+	{ OV7670_REG_EDGE, 0 },
+	{ 0x75, 0x05 },
+	{ 0x76, 0xe1 },
+	{ 0x4c, 0 },
+	{ 0x77, 0x01 },
+	{ OV7670_REG_COM13, OV7670_COM13_GAMMA
+			  | OV7670_COM13_UVSAT
+			  | 2},		/* was 3 */
+	{ 0x4b, 0x09 },
+	{ 0xc9, 0x60 },
+	{ OV7670_REG_COM16, 0x38 },
+	{ 0x56, 0x40 },
+
+	{ 0x34, 0x11 },
+	{ OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
+	{ 0xa4, 0x88 },
+	{ 0x96, 0 },
+	{ 0x97, 0x30 },
+	{ 0x98, 0x20 },
+	{ 0x99, 0x30 },
+	{ 0x9a, 0x84 },
+	{ 0x9b, 0x29 },
+	{ 0x9c, 0x03 },
+	{ 0x9d, 0x4c },
+	{ 0x9e, 0x3f },
+	{ 0x78, 0x04 },
+
+/* Extra-weird stuff.  Some sort of multiplexor register */
+	{ 0x79, 0x01 },
+	{ 0xc8, 0xf0 },
+	{ 0x79, 0x0f },
+	{ 0xc8, 0x00 },
+	{ 0x79, 0x10 },
+	{ 0xc8, 0x7e },
+	{ 0x79, 0x0a },
+	{ 0xc8, 0x80 },
+	{ 0x79, 0x0b },
+	{ 0xc8, 0x01 },
+	{ 0x79, 0x0c },
+	{ 0xc8, 0x0f },
+	{ 0x79, 0x0d },
+	{ 0xc8, 0x20 },
+	{ 0x79, 0x09 },
+	{ 0xc8, 0x80 },
+	{ 0x79, 0x02 },
+	{ 0xc8, 0xc0 },
+	{ 0x79, 0x03 },
+	{ 0xc8, 0x40 },
+	{ 0x79, 0x05 },
+	{ 0xc8, 0x30 },
+	{ 0x79, 0x26 },
+};
+
+static const struct ov_i2c_regvals norm_8610[] = {
+	{ 0x12, 0x80 },
+	{ 0x00, 0x00 },
+	{ 0x01, 0x80 },
+	{ 0x02, 0x80 },
+	{ 0x03, 0xc0 },
+	{ 0x04, 0x30 },
+	{ 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */
+	{ 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */
+	{ 0x0a, 0x86 },
+	{ 0x0b, 0xb0 },
+	{ 0x0c, 0x20 },
+	{ 0x0d, 0x20 },
+	{ 0x11, 0x01 },
+	{ 0x12, 0x25 },
+	{ 0x13, 0x01 },
+	{ 0x14, 0x04 },
+	{ 0x15, 0x01 }, /* Lin and Win think different about UV order */
+	{ 0x16, 0x03 },
+	{ 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */
+	{ 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */
+	{ 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */
+	{ 0x1a, 0xf5 },
+	{ 0x1b, 0x00 },
+	{ 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */
+	{ 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */
+	{ 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */
+	{ 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */
+	{ 0x26, 0xa2 },
+	{ 0x27, 0xea },
+	{ 0x28, 0x00 },
+	{ 0x29, 0x00 },
+	{ 0x2a, 0x80 },
+	{ 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */
+	{ 0x2c, 0xac },
+	{ 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */
+	{ 0x2e, 0x80 },
+	{ 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */
+	{ 0x4c, 0x00 },
+	{ 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */
+	{ 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */
+	{ 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */
+	{ 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */
+	{ 0x63, 0xff },
+	{ 0x64, 0x53 }, /* new windrv 090403 says 0x57,
+			 * maybe thats wrong */
+	{ 0x65, 0x00 },
+	{ 0x66, 0x55 },
+	{ 0x67, 0xb0 },
+	{ 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */
+	{ 0x69, 0x02 },
+	{ 0x6a, 0x22 },
+	{ 0x6b, 0x00 },
+	{ 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but
+			 * deleting bit7 colors the first images red */
+	{ 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */
+	{ 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */
+	{ 0x6f, 0x01 },
+	{ 0x70, 0x8b },
+	{ 0x71, 0x00 },
+	{ 0x72, 0x14 },
+	{ 0x73, 0x54 },
+	{ 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */
+	{ 0x75, 0x0e },
+	{ 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */
+	{ 0x77, 0xff },
+	{ 0x78, 0x80 },
+	{ 0x79, 0x80 },
+	{ 0x7a, 0x80 },
+	{ 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */
+	{ 0x7c, 0x00 },
+	{ 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */
+	{ 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */
+	{ 0x7f, 0xfb },
+	{ 0x80, 0x28 },
+	{ 0x81, 0x00 },
+	{ 0x82, 0x23 },
+	{ 0x83, 0x0b },
+	{ 0x84, 0x00 },
+	{ 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */
+	{ 0x86, 0xc9 },
+	{ 0x87, 0x00 },
+	{ 0x88, 0x00 },
+	{ 0x89, 0x01 },
+	{ 0x12, 0x20 },
+	{ 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */
+};
+
 static unsigned char ov7670_abs_to_sm(unsigned char v)
 {
 	if (v > 127)
@@ -537,18 +1071,10 @@
 	rc = reg_w(sd, R51x_I2C_W_SID, slave);
 	if (rc < 0)
 		return rc;
+	sd->primary_i2c_slave = slave;
 	return reg_w(sd, R51x_I2C_R_SID, slave + 1);
 }
 
-struct ov_regvals {
-	__u8 reg;
-	__u8 val;
-};
-struct ov_i2c_regvals {
-	__u8 reg;
-	__u8 val;
-};
-
 static int write_regvals(struct sd *sd,
 			 const struct ov_regvals *regvals,
 			 int n)
@@ -591,101 +1117,9 @@
 static int ov8xx0_configure(struct sd *sd)
 {
 	int rc;
-	static const struct ov_i2c_regvals norm_8610[] = {
-		{ 0x12, 0x80 },
-		{ 0x00, 0x00 },
-		{ 0x01, 0x80 },
-		{ 0x02, 0x80 },
-		{ 0x03, 0xc0 },
-		{ 0x04, 0x30 },
-		{ 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */
-		{ 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */
-		{ 0x0a, 0x86 },
-		{ 0x0b, 0xb0 },
-		{ 0x0c, 0x20 },
-		{ 0x0d, 0x20 },
-		{ 0x11, 0x01 },
-		{ 0x12, 0x25 },
-		{ 0x13, 0x01 },
-		{ 0x14, 0x04 },
-		{ 0x15, 0x01 }, /* Lin and Win think different about UV order */
-		{ 0x16, 0x03 },
-		{ 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */
-		{ 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */
-		{ 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */
-		{ 0x1a, 0xf5 },
-		{ 0x1b, 0x00 },
-		{ 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */
-		{ 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */
-		{ 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */
-		{ 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */
-		{ 0x26, 0xa2 },
-		{ 0x27, 0xea },
-		{ 0x28, 0x00 },
-		{ 0x29, 0x00 },
-		{ 0x2a, 0x80 },
-		{ 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */
-		{ 0x2c, 0xac },
-		{ 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */
-		{ 0x2e, 0x80 },
-		{ 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */
-		{ 0x4c, 0x00 },
-		{ 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */
-		{ 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */
-		{ 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */
-		{ 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */
-		{ 0x63, 0xff },
-		{ 0x64, 0x53 }, /* new windrv 090403 says 0x57,
-				 * maybe thats wrong */
-		{ 0x65, 0x00 },
-		{ 0x66, 0x55 },
-		{ 0x67, 0xb0 },
-		{ 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */
-		{ 0x69, 0x02 },
-		{ 0x6a, 0x22 },
-		{ 0x6b, 0x00 },
-		{ 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but
-				   deleting bit7 colors the first images red */
-		{ 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */
-		{ 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */
-		{ 0x6f, 0x01 },
-		{ 0x70, 0x8b },
-		{ 0x71, 0x00 },
-		{ 0x72, 0x14 },
-		{ 0x73, 0x54 },
-		{ 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */
-		{ 0x75, 0x0e },
-		{ 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */
-		{ 0x77, 0xff },
-		{ 0x78, 0x80 },
-		{ 0x79, 0x80 },
-		{ 0x7a, 0x80 },
-		{ 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */
-		{ 0x7c, 0x00 },
-		{ 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */
-		{ 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */
-		{ 0x7f, 0xfb },
-		{ 0x80, 0x28 },
-		{ 0x81, 0x00 },
-		{ 0x82, 0x23 },
-		{ 0x83, 0x0b },
-		{ 0x84, 0x00 },
-		{ 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */
-		{ 0x86, 0xc9 },
-		{ 0x87, 0x00 },
-		{ 0x88, 0x00 },
-		{ 0x89, 0x01 },
-		{ 0x12, 0x20 },
-		{ 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */
-	};
 
 	PDEBUG(D_PROBE, "starting ov8xx0 configuration");
 
-	if (init_ov_sensor(sd) < 0)
-		PDEBUG(D_ERR|D_PROBE, "Failed to read sensor ID");
-	else
-		PDEBUG(D_PROBE, "OV86x0 initialized");
-
 	/* Detect sensor (sub)type */
 	rc = i2c_r(sd, OV7610_REG_COM_I);
 	if (rc < 0) {
@@ -698,9 +1132,6 @@
 		PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
 		return -1;
 	}
-	PDEBUG(D_PROBE, "Writing 8610 registers");
-	if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)))
-		return -1;
 
 	/* Set sensor-specific vars */
 /*	sd->sif = 0;		already done */
@@ -714,252 +1145,6 @@
 {
 	int rc, high, low;
 
-	/* Lawrence Glaister <lg@jfm.bc.ca> reports:
-	 *
-	 * Register 0x0f in the 7610 has the following effects:
-	 *
-	 * 0x85 (AEC method 1): Best overall, good contrast range
-	 * 0x45 (AEC method 2): Very overexposed
-	 * 0xa5 (spec sheet default): Ok, but the black level is
-	 *	shifted resulting in loss of contrast
-	 * 0x05 (old driver setting): very overexposed, too much
-	 *	contrast
-	 */
-	static const struct ov_i2c_regvals norm_7610[] = {
-		{ 0x10, 0xff },
-		{ 0x16, 0x06 },
-		{ 0x28, 0x24 },
-		{ 0x2b, 0xac },
-		{ 0x12, 0x00 },
-		{ 0x38, 0x81 },
-		{ 0x28, 0x24 },	/* 0c */
-		{ 0x0f, 0x85 },	/* lg's setting */
-		{ 0x15, 0x01 },
-		{ 0x20, 0x1c },
-		{ 0x23, 0x2a },
-		{ 0x24, 0x10 },
-		{ 0x25, 0x8a },
-		{ 0x26, 0xa2 },
-		{ 0x27, 0xc2 },
-		{ 0x2a, 0x04 },
-		{ 0x2c, 0xfe },
-		{ 0x2d, 0x93 },
-		{ 0x30, 0x71 },
-		{ 0x31, 0x60 },
-		{ 0x32, 0x26 },
-		{ 0x33, 0x20 },
-		{ 0x34, 0x48 },
-		{ 0x12, 0x24 },
-		{ 0x11, 0x01 },
-		{ 0x0c, 0x24 },
-		{ 0x0d, 0x24 },
-	};
-
-	static const struct ov_i2c_regvals norm_7620[] = {
-		{ 0x00, 0x00 },		/* gain */
-		{ 0x01, 0x80 },		/* blue gain */
-		{ 0x02, 0x80 },		/* red gain */
-		{ 0x03, 0xc0 },		/* OV7670_REG_VREF */
-		{ 0x06, 0x60 },
-		{ 0x07, 0x00 },
-		{ 0x0c, 0x24 },
-		{ 0x0c, 0x24 },
-		{ 0x0d, 0x24 },
-		{ 0x11, 0x01 },
-		{ 0x12, 0x24 },
-		{ 0x13, 0x01 },
-		{ 0x14, 0x84 },
-		{ 0x15, 0x01 },
-		{ 0x16, 0x03 },
-		{ 0x17, 0x2f },
-		{ 0x18, 0xcf },
-		{ 0x19, 0x06 },
-		{ 0x1a, 0xf5 },
-		{ 0x1b, 0x00 },
-		{ 0x20, 0x18 },
-		{ 0x21, 0x80 },
-		{ 0x22, 0x80 },
-		{ 0x23, 0x00 },
-		{ 0x26, 0xa2 },
-		{ 0x27, 0xea },
-		{ 0x28, 0x20 },
-		{ 0x29, 0x00 },
-		{ 0x2a, 0x10 },
-		{ 0x2b, 0x00 },
-		{ 0x2c, 0x88 },
-		{ 0x2d, 0x91 },
-		{ 0x2e, 0x80 },
-		{ 0x2f, 0x44 },
-		{ 0x60, 0x27 },
-		{ 0x61, 0x02 },
-		{ 0x62, 0x5f },
-		{ 0x63, 0xd5 },
-		{ 0x64, 0x57 },
-		{ 0x65, 0x83 },
-		{ 0x66, 0x55 },
-		{ 0x67, 0x92 },
-		{ 0x68, 0xcf },
-		{ 0x69, 0x76 },
-		{ 0x6a, 0x22 },
-		{ 0x6b, 0x00 },
-		{ 0x6c, 0x02 },
-		{ 0x6d, 0x44 },
-		{ 0x6e, 0x80 },
-		{ 0x6f, 0x1d },
-		{ 0x70, 0x8b },
-		{ 0x71, 0x00 },
-		{ 0x72, 0x14 },
-		{ 0x73, 0x54 },
-		{ 0x74, 0x00 },
-		{ 0x75, 0x8e },
-		{ 0x76, 0x00 },
-		{ 0x77, 0xff },
-		{ 0x78, 0x80 },
-		{ 0x79, 0x80 },
-		{ 0x7a, 0x80 },
-		{ 0x7b, 0xe2 },
-		{ 0x7c, 0x00 },
-	};
-
-	/* 7640 and 7648. The defaults should be OK for most registers. */
-	static const struct ov_i2c_regvals norm_7640[] = {
-		{ 0x12, 0x80 },
-		{ 0x12, 0x14 },
-	};
-
-	/* 7670. Defaults taken from OmniVision provided data,
-	*  as provided by Jonathan Corbet of OLPC		*/
-	static const struct ov_i2c_regvals norm_7670[] = {
-		{ OV7670_REG_COM7, OV7670_COM7_RESET },
-		{ OV7670_REG_TSLB, 0x04 },		/* OV */
-		{ OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
-		{ OV7670_REG_CLKRC, 0x01 },
-	/*
-	 * Set the hardware window.  These values from OV don't entirely
-	 * make sense - hstop is less than hstart.  But they work...
-	 */
-		{ OV7670_REG_HSTART, 0x13 },	{ OV7670_REG_HSTOP, 0x01 },
-		{ OV7670_REG_HREF, 0xb6 },	{ OV7670_REG_VSTART, 0x02 },
-		{ OV7670_REG_VSTOP, 0x7a },	{ OV7670_REG_VREF, 0x0a },
-
-		{ OV7670_REG_COM3, 0 },	{ OV7670_REG_COM14, 0 },
-	/* Mystery scaling numbers */
-		{ 0x70, 0x3a },		{ 0x71, 0x35 },
-		{ 0x72, 0x11 },		{ 0x73, 0xf0 },
-		{ 0xa2, 0x02 },
-/*		{ OV7670_REG_COM10, 0x0 }, */
-
-	/* Gamma curve values */
-		{ 0x7a, 0x20 },
-		{ 0x7b, 0x10 },
-		{ 0x7c, 0x1e },
-		{ 0x7d, 0x35 },
-		{ 0x7e, 0x5a },		{ 0x7f, 0x69 },
-		{ 0x80, 0x76 },		{ 0x81, 0x80 },
-		{ 0x82, 0x88 },		{ 0x83, 0x8f },
-		{ 0x84, 0x96 },		{ 0x85, 0xa3 },
-		{ 0x86, 0xaf },		{ 0x87, 0xc4 },
-		{ 0x88, 0xd7 },		{ 0x89, 0xe8 },
-
-	/* AGC and AEC parameters.  Note we start by disabling those features,
-	   then turn them only after tweaking the values. */
-		{ OV7670_REG_COM8, OV7670_COM8_FASTAEC
-				 | OV7670_COM8_AECSTEP
-				 | OV7670_COM8_BFILT },
-		{ OV7670_REG_GAIN, 0 },	{ OV7670_REG_AECH, 0 },
-		{ OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
-		{ OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
-		{ OV7670_REG_BD50MAX, 0x05 },	{ OV7670_REG_BD60MAX, 0x07 },
-		{ OV7670_REG_AEW, 0x95 },	{ OV7670_REG_AEB, 0x33 },
-		{ OV7670_REG_VPT, 0xe3 },	{ OV7670_REG_HAECC1, 0x78 },
-		{ OV7670_REG_HAECC2, 0x68 },
-		{ 0xa1, 0x03 }, /* magic */
-		{ OV7670_REG_HAECC3, 0xd8 },	{ OV7670_REG_HAECC4, 0xd8 },
-		{ OV7670_REG_HAECC5, 0xf0 },	{ OV7670_REG_HAECC6, 0x90 },
-		{ OV7670_REG_HAECC7, 0x94 },
-		{ OV7670_REG_COM8, OV7670_COM8_FASTAEC
-				| OV7670_COM8_AECSTEP
-				| OV7670_COM8_BFILT
-				| OV7670_COM8_AGC
-				| OV7670_COM8_AEC },
-
-	/* Almost all of these are magic "reserved" values.  */
-		{ OV7670_REG_COM5, 0x61 },	{ OV7670_REG_COM6, 0x4b },
-		{ 0x16, 0x02 },
-		{ OV7670_REG_MVFP, 0x07 },
-		{ 0x21, 0x02 },		{ 0x22, 0x91 },
-		{ 0x29, 0x07 },		{ 0x33, 0x0b },
-		{ 0x35, 0x0b },		{ 0x37, 0x1d },
-		{ 0x38, 0x71 },		{ 0x39, 0x2a },
-		{ OV7670_REG_COM12, 0x78 },	{ 0x4d, 0x40 },
-		{ 0x4e, 0x20 },		{ OV7670_REG_GFIX, 0 },
-		{ 0x6b, 0x4a },		{ 0x74, 0x10 },
-		{ 0x8d, 0x4f },		{ 0x8e, 0 },
-		{ 0x8f, 0 },		{ 0x90, 0 },
-		{ 0x91, 0 },		{ 0x96, 0 },
-		{ 0x9a, 0 },		{ 0xb0, 0x84 },
-		{ 0xb1, 0x0c },		{ 0xb2, 0x0e },
-		{ 0xb3, 0x82 },		{ 0xb8, 0x0a },
-
-	/* More reserved magic, some of which tweaks white balance */
-		{ 0x43, 0x0a },		{ 0x44, 0xf0 },
-		{ 0x45, 0x34 },		{ 0x46, 0x58 },
-		{ 0x47, 0x28 },		{ 0x48, 0x3a },
-		{ 0x59, 0x88 },		{ 0x5a, 0x88 },
-		{ 0x5b, 0x44 },		{ 0x5c, 0x67 },
-		{ 0x5d, 0x49 },		{ 0x5e, 0x0e },
-		{ 0x6c, 0x0a },		{ 0x6d, 0x55 },
-		{ 0x6e, 0x11 },		{ 0x6f, 0x9f },
-						/* "9e for advance AWB" */
-		{ 0x6a, 0x40 },		{ OV7670_REG_BLUE, 0x40 },
-		{ OV7670_REG_RED, 0x60 },
-		{ OV7670_REG_COM8, OV7670_COM8_FASTAEC
-				| OV7670_COM8_AECSTEP
-				| OV7670_COM8_BFILT
-				| OV7670_COM8_AGC
-				| OV7670_COM8_AEC
-				| OV7670_COM8_AWB },
-
-	/* Matrix coefficients */
-		{ 0x4f, 0x80 },		{ 0x50, 0x80 },
-		{ 0x51, 0 },		{ 0x52, 0x22 },
-		{ 0x53, 0x5e },		{ 0x54, 0x80 },
-		{ 0x58, 0x9e },
-
-		{ OV7670_REG_COM16, OV7670_COM16_AWBGAIN },
-		{ OV7670_REG_EDGE, 0 },
-		{ 0x75, 0x05 },		{ 0x76, 0xe1 },
-		{ 0x4c, 0 },		{ 0x77, 0x01 },
-		{ OV7670_REG_COM13, OV7670_COM13_GAMMA
-				  | OV7670_COM13_UVSAT
-				  | 2},		/* was 3 */
-		{ 0x4b, 0x09 },
-		{ 0xc9, 0x60 },		{ OV7670_REG_COM16, 0x38 },
-		{ 0x56, 0x40 },
-
-		{ 0x34, 0x11 },
-		{ OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
-		{ 0xa4, 0x88 },		{ 0x96, 0 },
-		{ 0x97, 0x30 },		{ 0x98, 0x20 },
-		{ 0x99, 0x30 },		{ 0x9a, 0x84 },
-		{ 0x9b, 0x29 },		{ 0x9c, 0x03 },
-		{ 0x9d, 0x4c },		{ 0x9e, 0x3f },
-		{ 0x78, 0x04 },
-
-	/* Extra-weird stuff.  Some sort of multiplexor register */
-		{ 0x79, 0x01 },		{ 0xc8, 0xf0 },
-		{ 0x79, 0x0f },		{ 0xc8, 0x00 },
-		{ 0x79, 0x10 },		{ 0xc8, 0x7e },
-		{ 0x79, 0x0a },		{ 0xc8, 0x80 },
-		{ 0x79, 0x0b },		{ 0xc8, 0x01 },
-		{ 0x79, 0x0c },		{ 0xc8, 0x0f },
-		{ 0x79, 0x0d },		{ 0xc8, 0x20 },
-		{ 0x79, 0x09 },		{ 0xc8, 0x80 },
-		{ 0x79, 0x02 },		{ 0xc8, 0xc0 },
-		{ 0x79, 0x03 },		{ 0xc8, 0x40 },
-		{ 0x79, 0x05 },		{ 0xc8, 0x30 },
-		{ 0x79, 0x26 },
-	};
 
 	PDEBUG(D_PROBE, "starting OV7xx0 configuration");
 
@@ -1011,8 +1196,9 @@
 			switch (low) {
 			case 0x30:
 				PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635");
-				sd->sensor = SEN_OV7630;
-				break;
+				PDEBUG(D_ERR,
+				      "7630 is not supported by this driver");
+				return -1;
 			case 0x40:
 				PDEBUG(D_PROBE, "Sensor is an OV7645");
 				sd->sensor = SEN_OV7640; /* FIXME */
@@ -1038,32 +1224,6 @@
 		return -1;
 	}
 
-	switch (sd->sensor) {
-	case SEN_OV7620:
-		PDEBUG(D_PROBE, "Writing 7620 registers");
-		if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
-			return -1;
-		break;
-	case SEN_OV7630:
-		PDEBUG(D_ERR, "7630 is not supported by this driver version");
-		return -1;
-	case SEN_OV7640:
-		PDEBUG(D_PROBE, "Writing 7640 registers");
-		if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)))
-			return -1;
-		break;
-	case SEN_OV7670:
-		PDEBUG(D_PROBE, "Writing 7670 registers");
-		if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)))
-			return -1;
-		break;
-	default:
-		PDEBUG(D_PROBE, "Writing 7610 registers");
-		if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)))
-			return -1;
-		break;
-	}
-
 	/* Set sensor-specific vars */
 /*	sd->sif = 0;		already done */
 	return 0;
@@ -1073,141 +1233,7 @@
 static int ov6xx0_configure(struct sd *sd)
 {
 	int rc;
-	static const struct ov_i2c_regvals norm_6x20[] = {
-		{ 0x12, 0x80 }, /* reset */
-		{ 0x11, 0x01 },
-		{ 0x03, 0x60 },
-		{ 0x05, 0x7f }, /* For when autoadjust is off */
-		{ 0x07, 0xa8 },
-		/* The ratio of 0x0c and 0x0d  controls the white point */
-		{ 0x0c, 0x24 },
-		{ 0x0d, 0x24 },
-		{ 0x0f, 0x15 }, /* COMS */
-		{ 0x10, 0x75 }, /* AEC Exposure time */
-		{ 0x12, 0x24 }, /* Enable AGC */
-		{ 0x14, 0x04 },
-		/* 0x16: 0x06 helps frame stability with moving objects */
-		{ 0x16, 0x06 },
-/*		{ 0x20, 0x30 },  * Aperture correction enable */
-		{ 0x26, 0xb2 }, /* BLC enable */
-		/* 0x28: 0x05 Selects RGB format if RGB on */
-		{ 0x28, 0x05 },
-		{ 0x2a, 0x04 }, /* Disable framerate adjust */
-/*		{ 0x2b, 0xac },  * Framerate; Set 2a[7] first */
-		{ 0x2d, 0x99 },
-		{ 0x33, 0xa0 }, /* Color Processing Parameter */
-		{ 0x34, 0xd2 }, /* Max A/D range */
-		{ 0x38, 0x8b },
-		{ 0x39, 0x40 },
-
-		{ 0x3c, 0x39 }, /* Enable AEC mode changing */
-		{ 0x3c, 0x3c }, /* Change AEC mode */
-		{ 0x3c, 0x24 }, /* Disable AEC mode changing */
-
-		{ 0x3d, 0x80 },
-		/* These next two registers (0x4a, 0x4b) are undocumented.
-		 * They control the color balance */
-		{ 0x4a, 0x80 },
-		{ 0x4b, 0x80 },
-		{ 0x4d, 0xd2 }, /* This reduces noise a bit */
-		{ 0x4e, 0xc1 },
-		{ 0x4f, 0x04 },
-/* Do 50-53 have any effect? */
-/* Toggle 0x12[2] off and on here? */
-	};
-
-	static const struct ov_i2c_regvals norm_6x30[] = {
-		{ 0x12, 0x80 }, /* Reset */
-		{ 0x00, 0x1f }, /* Gain */
-		{ 0x01, 0x99 }, /* Blue gain */
-		{ 0x02, 0x7c }, /* Red gain */
-		{ 0x03, 0xc0 }, /* Saturation */
-		{ 0x05, 0x0a }, /* Contrast */
-		{ 0x06, 0x95 }, /* Brightness */
-		{ 0x07, 0x2d }, /* Sharpness */
-		{ 0x0c, 0x20 },
-		{ 0x0d, 0x20 },
-		{ 0x0e, 0x20 },
-		{ 0x0f, 0x05 },
-		{ 0x10, 0x9a },
-		{ 0x11, 0x00 }, /* Pixel clock = fastest */
-		{ 0x12, 0x24 }, /* Enable AGC and AWB */
-		{ 0x13, 0x21 },
-		{ 0x14, 0x80 },
-		{ 0x15, 0x01 },
-		{ 0x16, 0x03 },
-		{ 0x17, 0x38 },
-		{ 0x18, 0xea },
-		{ 0x19, 0x04 },
-		{ 0x1a, 0x93 },
-		{ 0x1b, 0x00 },
-		{ 0x1e, 0xc4 },
-		{ 0x1f, 0x04 },
-		{ 0x20, 0x20 },
-		{ 0x21, 0x10 },
-		{ 0x22, 0x88 },
-		{ 0x23, 0xc0 }, /* Crystal circuit power level */
-		{ 0x25, 0x9a }, /* Increase AEC black ratio */
-		{ 0x26, 0xb2 }, /* BLC enable */
-		{ 0x27, 0xa2 },
-		{ 0x28, 0x00 },
-		{ 0x29, 0x00 },
-		{ 0x2a, 0x84 }, /* 60 Hz power */
-		{ 0x2b, 0xa8 }, /* 60 Hz power */
-		{ 0x2c, 0xa0 },
-		{ 0x2d, 0x95 }, /* Enable auto-brightness */
-		{ 0x2e, 0x88 },
-		{ 0x33, 0x26 },
-		{ 0x34, 0x03 },
-		{ 0x36, 0x8f },
-		{ 0x37, 0x80 },
-		{ 0x38, 0x83 },
-		{ 0x39, 0x80 },
-		{ 0x3a, 0x0f },
-		{ 0x3b, 0x3c },
-		{ 0x3c, 0x1a },
-		{ 0x3d, 0x80 },
-		{ 0x3e, 0x80 },
-		{ 0x3f, 0x0e },
-		{ 0x40, 0x00 }, /* White bal */
-		{ 0x41, 0x00 }, /* White bal */
-		{ 0x42, 0x80 },
-		{ 0x43, 0x3f }, /* White bal */
-		{ 0x44, 0x80 },
-		{ 0x45, 0x20 },
-		{ 0x46, 0x20 },
-		{ 0x47, 0x80 },
-		{ 0x48, 0x7f },
-		{ 0x49, 0x00 },
-		{ 0x4a, 0x00 },
-		{ 0x4b, 0x80 },
-		{ 0x4c, 0xd0 },
-		{ 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
-		{ 0x4e, 0x40 },
-		{ 0x4f, 0x07 }, /* UV avg., col. killer: max */
-		{ 0x50, 0xff },
-		{ 0x54, 0x23 }, /* Max AGC gain: 18dB */
-		{ 0x55, 0xff },
-		{ 0x56, 0x12 },
-		{ 0x57, 0x81 },
-		{ 0x58, 0x75 },
-		{ 0x59, 0x01 }, /* AGC dark current comp.: +1 */
-		{ 0x5a, 0x2c },
-		{ 0x5b, 0x0f }, /* AWB chrominance levels */
-		{ 0x5c, 0x10 },
-		{ 0x3d, 0x80 },
-		{ 0x27, 0xa6 },
-		{ 0x12, 0x20 }, /* Toggle AWB */
-		{ 0x12, 0x24 },
-	};
-
-	PDEBUG(D_PROBE, "starting sensor configuration");
-
-	if (init_ov_sensor(sd) < 0) {
-		PDEBUG(D_ERR, "Failed to read sensor ID.");
-		return -1;
-	}
-	PDEBUG(D_PROBE, "OV6xx0 sensor detected");
+	PDEBUG(D_PROBE, "starting OV6xx0 configuration");
 
 	/* Detect sensor (sub)type */
 	rc = i2c_r(sd, OV7610_REG_COM_I);
@@ -1251,15 +1277,6 @@
 	/* Set sensor-specific vars */
 	sd->sif = 1;
 
-	if (sd->sensor == SEN_OV6620) {
-		PDEBUG(D_PROBE, "Writing 6x20 registers");
-		if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)))
-			return -1;
-	} else {
-		PDEBUG(D_PROBE, "Writing 6x30 registers");
-		if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))
-			return -1;
-	}
 	return 0;
 }
 
@@ -1298,22 +1315,31 @@
 	ov51x_led_control(sd, 0);	/* turn LED off */
 
 	/* Test for 76xx */
-	sd->primary_i2c_slave = OV7xx0_SID;
 	if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0)
 		goto error;
 
 	/* The OV519 must be more aggressive about sensor detection since
 	 * I2C write will never fail if the sensor is not present. We have
 	 * to try to initialize the sensor to detect its presence */
-	if (init_ov_sensor(sd) < 0) {
+	if (init_ov_sensor(sd) >= 0) {
+		if (ov7xx0_configure(sd) < 0) {
+			PDEBUG(D_ERR, "Failed to configure OV7xx0");
+			goto error;
+		}
+	} else {
+
 		/* Test for 6xx0 */
-		sd->primary_i2c_slave = OV6xx0_SID;
 		if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0)
 			goto error;
 
-		if (init_ov_sensor(sd) < 0) {
+		if (init_ov_sensor(sd) >= 0) {
+			if (ov6xx0_configure(sd) < 0) {
+				PDEBUG(D_ERR, "Failed to configure OV6xx0");
+				goto error;
+			}
+		} else {
+
 			/* Test for 8xx0 */
-			sd->primary_i2c_slave = OV8xx0_SID;
 			if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0)
 				goto error;
 
@@ -1321,24 +1347,13 @@
 				PDEBUG(D_ERR,
 					"Can't determine sensor slave IDs");
 				goto error;
-			} else {
-				if (ov8xx0_configure(sd) < 0) {
-					PDEBUG(D_ERR,
-					   "Failed to configure OV8xx0 sensor");
-					goto error;
-				}
 			}
-		} else {
-			if (ov6xx0_configure(sd) < 0) {
-				PDEBUG(D_ERR, "Failed to configure OV6xx0");
+			if (ov8xx0_configure(sd) < 0) {
+				PDEBUG(D_ERR,
+				   "Failed to configure OV8xx0 sensor");
 				goto error;
 			}
 		}
-	} else {
-		if (ov7xx0_configure(sd) < 0) {
-			PDEBUG(D_ERR, "Failed to configure OV7xx0");
-			goto error;
-		}
 	}
 
 	cam = &gspca_dev->cam;
@@ -1364,6 +1379,41 @@
 /* this function is called at open time */
 static int sd_open(struct gspca_dev *gspca_dev)
 {
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	/* initialize the sensor */
+	switch (sd->sensor) {
+	case SEN_OV6620:
+		if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)))
+			return -EIO;
+		break;
+	case SEN_OV6630:
+		if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))
+			return -EIO;
+		break;
+	default:
+/*	case SEN_OV7610: */
+/*	case SEN_OV76BE: */
+		if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)))
+			return -EIO;
+		break;
+	case SEN_OV7620:
+		if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
+			return -EIO;
+		break;
+	case SEN_OV7640:
+		if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)))
+			return -EIO;
+		break;
+	case SEN_OV7670:
+		if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)))
+			return -EIO;
+		break;
+	case SEN_OV8610:
+		if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)))
+			return -EIO;
+		break;
+	}
 	return 0;
 }