From e27188ee6bed7fae205dfeee0d22fc9fc83a3cb2 Mon Sep 17 00:00:00 2001
From: Jean-Francois Moine <moinejf@free.fr>
Date: Mon, 27 Jul 2009 06:00:03 -0300
Subject: [PATCH] V4L/DVB (12354): gspca - vc032x: H and V flip controls added
 for mi13x0_soc sensors

Also, H/V flip default values adjusted according to the webcam IDs.

Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
---
 drivers/media/video/gspca/vc032x.c | 91 +++++++++++++++++-------------
 1 file changed, 52 insertions(+), 39 deletions(-)

diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index 1a50f8025bd1..d8e8bdc73fa4 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -52,7 +52,10 @@ struct sd {
 #define SENSOR_OV7670 6
 #define SENSOR_PO1200 7
 #define SENSOR_PO3130NC 8
-	u8 ninput;		/* != 0 when 2 sensors - SamsungQ1 */
+	u8 flags;
+#define FL_SAMSUNG 0x01		/* SamsungQ1 (2 sensors) */
+#define FL_HFLIP 0x02		/* mirrored by default */
+#define FL_VFLIP 0x04		/* vertical flipped by default */
 };
 
 /* V4L2 controls supported by the driver */
@@ -66,7 +69,7 @@ static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
-/* next 2 controls work with ov7660 and ov7670 only */
+/* next 2 controls work with some sensors only */
 #define HFLIP_IDX 0
 	{
 	    {
@@ -453,7 +456,7 @@ static const __u8 mi1310_socinitVGA_JPG[][4] = {
 	{0x5b, 0x00, 0x01, 0xbb},
 	{0x2f, 0xde, 0x20, 0xbb},
 	{0xf0, 0x00, 0x00, 0xbb},
-	{0x20, 0x03, 0x02, 0xbb},
+	{0x20, 0x03, 0x02, 0xbb},	/* h/v flip */
 	{0xf0, 0x00, 0x01, 0xbb},
 	{0x05, 0x00, 0x07, 0xbb},
 	{0x34, 0x00, 0x00, 0xbb},
@@ -590,7 +593,8 @@ static const __u8 mi1310_socinitQVGA_JPG[][4] = {
 	{0xbc, 0x01, 0x01, 0xcc},	{0xf0, 0x00, 0x02, 0xbb},
 	{0xc8, 0x9f, 0x0b, 0xbb},	{0x5b, 0x00, 0x01, 0xbb},
 	{0x2f, 0xde, 0x20, 0xbb},	{0xf0, 0x00, 0x00, 0xbb},
-	{0x20, 0x03, 0x02, 0xbb},	{0xf0, 0x00, 0x01, 0xbb},
+	{0x20, 0x03, 0x02, 0xbb},	/* h/v flip */
+	{0xf0, 0x00, 0x01, 0xbb},
 	{0x05, 0x00, 0x07, 0xbb},	{0x34, 0x00, 0x00, 0xbb},
 	{0x35, 0xff, 0x00, 0xbb},	{0xdc, 0x07, 0x02, 0xbb},
 	{0xdd, 0x3c, 0x18, 0xbb},	{0xde, 0x92, 0x6d, 0xbb},
@@ -677,7 +681,7 @@ static const u8 mi1310_soc_InitSXGA_JPG[][4] = {
 	{0xc8, 0x9f, 0x0b, 0xbb},
 	{0x5b, 0x00, 0x01, 0xbb},
 	{0xf0, 0x00, 0x00, 0xbb},
-	{0x20, 0x03, 0x03, 0xbb},
+	{0x20, 0x03, 0x02, 0xbb},	/* h/v flip */
 	{0xf0, 0x00, 0x01, 0xbb},
 	{0x05, 0x00, 0x07, 0xbb},
 	{0x34, 0x00, 0x00, 0xbb},
@@ -1034,7 +1038,7 @@ static const u8 mi1320_soc_InitVGA[][4] = {
 	{0x07, 0x00, 0xe0, 0xbb},
 	{0x08, 0x00, 0x0b, 0xbb},
 	{0x21, 0x00, 0x0c, 0xbb},
-	{0x20, 0x01, 0x03, 0xbb},
+	{0x20, 0x01, 0x03, 0xbb},	/* h/v flip */
 	{0xbf, 0xc0, 0x26, 0xcc},
 	{0xbf, 0xc1, 0x02, 0xcc},
 	{0xbf, 0xcc, 0x04, 0xcc},
@@ -1044,7 +1048,7 @@ static const u8 mi1320_soc_InitVGA[][4] = {
 	{0x06, 0x00, 0x11, 0xbb},
 	{0x07, 0x01, 0x42, 0xbb},
 	{0x08, 0x00, 0x11, 0xbb},
-	{0x20, 0x01, 0x03, 0xbb},
+	{0x20, 0x01, 0x03, 0xbb},	/* h/v flip */
 	{0x21, 0x80, 0x00, 0xbb},
 	{0x22, 0x0d, 0x0f, 0xbb},
 	{0x24, 0x80, 0x00, 0xbb},
@@ -1137,7 +1141,7 @@ static const u8 mi1320_soc_InitQVGA[][4] = {
 	{0x07, 0x00, 0xe0, 0xbb},
 	{0x08, 0x00, 0x0b, 0xbb},
 	{0x21, 0x00, 0x0c, 0xbb},
-	{0x20, 0x01, 0x03, 0xbb},
+	{0x20, 0x01, 0x03, 0xbb},	/* h/v flip */
 	{0xbf, 0xc0, 0x26, 0xcc},
 	{0xbf, 0xc1, 0x02, 0xcc},
 	{0xbf, 0xcc, 0x04, 0xcc},
@@ -1157,7 +1161,7 @@ static const u8 mi1320_soc_InitQVGA[][4] = {
 	{0x06, 0x00, 0x11, 0xbb},
 	{0x07, 0x01, 0x42, 0xbb},
 	{0x08, 0x00, 0x11, 0xbb},
-	{0x20, 0x01, 0x03, 0xbb},
+	{0x20, 0x01, 0x03, 0xbb},	/* h/v flip */
 	{0x21, 0x80, 0x00, 0xbb},
 	{0x22, 0x0d, 0x0f, 0xbb},
 	{0x24, 0x80, 0x00, 0xbb},
@@ -1247,7 +1251,7 @@ static const u8 mi1320_soc_InitSXGA[][4] = {
 	{0x00, 0x00, 0x20, 0xdd},
 	{0xf0, 0x00, 0x00, 0xbb},
 	{0x00, 0x00, 0x30, 0xdd},
-	{0x20, 0x01, 0x03, 0xbb},
+	{0x20, 0x01, 0x03, 0xbb},	/* h/v flip */
 	{0x00, 0x00, 0x20, 0xdd},
 	{0xbf, 0xc0, 0x26, 0xcc},
 	{0xbf, 0xc1, 0x02, 0xcc},
@@ -1258,7 +1262,7 @@ static const u8 mi1320_soc_InitSXGA[][4] = {
 	{0x06, 0x00, 0x11, 0xbb},
 	{0x07, 0x01, 0x42, 0xbb},
 	{0x08, 0x00, 0x11, 0xbb},
-	{0x20, 0x01, 0x03, 0xbb},
+	{0x20, 0x01, 0x03, 0xbb},	/* h/v flip */
 	{0x21, 0x80, 0x00, 0xbb},
 	{0x22, 0x0d, 0x0f, 0xbb},
 	{0x24, 0x80, 0x00, 0xbb},
@@ -1316,7 +1320,7 @@ static const u8 mi1320_soc_InitSXGA[][4] = {
 	{0x06, 0x00, 0x11, 0xbb},
 	{0x07, 0x00, 0x85, 0xbb},
 	{0x08, 0x00, 0x27, 0xbb},
-	{0x20, 0x01, 0x03, 0xbb},
+	{0x20, 0x01, 0x03, 0xbb},	/* h/v flip */
 	{0x21, 0x80, 0x00, 0xbb},
 	{0x22, 0x0d, 0x0f, 0xbb},
 	{0x24, 0x80, 0x00, 0xbb},
@@ -2435,7 +2439,7 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
 	const struct sensor_info *ptsensor_info;
 
 /*fixme: should also check the other sensor (back mi1320_soc, front mc501cb)*/
-	if (sd->ninput != 0) {
+	if (sd->flags & FL_SAMSUNG) {
 		reg_w(dev, 0xa0, 0x01, 0xb301);
 		reg_w(dev, 0x89, 0xf0ff, 0xffff); /* select the back sensor */
 	}
@@ -2560,7 +2564,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
 	cam = &gspca_dev->cam;
 	sd->bridge = id->driver_info >> 8;
-	sd->ninput = id->driver_info & 0xff;
+	sd->flags = id->driver_info & 0xff;
 	sensor = vc032x_probe_sensor(gspca_dev);
 	switch (sensor) {
 	case -1:
@@ -2613,8 +2617,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
 		case SENSOR_MI1320_SOC:
 			cam->cam_mode = bi_mode;
 			cam->nmodes = ARRAY_SIZE(bi_mode);
-			cam->input_flags = V4L2_IN_ST_VFLIP |
-					   V4L2_IN_ST_HFLIP;
 			break;
 		default:
 			cam->cam_mode = vc0323_mode;
@@ -2626,14 +2628,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
 	sd->hflip = HFLIP_DEF;
 	sd->vflip = VFLIP_DEF;
-	if (sd->sensor == SENSOR_OV7670) {
-		sd->hflip = 1;
-		sd->vflip = 1;
-	}
+	if (sd->sensor == SENSOR_OV7670)
+		sd->flags |= FL_HFLIP | FL_VFLIP;
 	sd->lightfreq = FREQ_DEF;
 	if (sd->sensor != SENSOR_OV7670)
 		gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
 	switch (sd->sensor) {
+	case SENSOR_MI1310_SOC:
+	case SENSOR_MI1320_SOC:
 	case SENSOR_OV7660:
 	case SENSOR_OV7670:
 	case SENSOR_PO1200:
@@ -2662,33 +2664,44 @@ static int sd_init(struct gspca_dev *gspca_dev)
 	return 0;
 }
 
-/* for OV7660 and OV7670 only */
+/* some sensors only */
 static void sethvflip(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	__u8 data;
+	u8 data[2], hflip, vflip;
 
+	hflip = sd->hflip;
+	if (sd->flags & FL_HFLIP)
+		hflip != hflip;
+	vflip = sd->vflip;
+	if (sd->flags & FL_VFLIP)
+		vflip != vflip;
 	switch (sd->sensor) {
-	case SENSOR_OV7660:
-		data = 1;
+	case SENSOR_MI1310_SOC:
+	case SENSOR_MI1320_SOC:
+		data[0] = data[1] = 0;		/* select page 0 */
+		i2c_write(gspca_dev, 0xf0, data, 2);
+		data[0] = sd->sensor == SENSOR_MI1310_SOC ? 0x03 : 0x01;
+		data[1] = 0x02 * hflip
+			| 0x01 * vflip;
+		i2c_write(gspca_dev, 0x20, data, 2);
 		break;
+	case SENSOR_OV7660:
 	case SENSOR_OV7670:
-		data = 7;
+		data[0] = sd->sensor == SENSOR_OV7660 ? 0x01 : 0x07;
+		data[0] |= OV7660_MVFP_MIRROR * hflip
+			| OV7660_MVFP_VFLIP * vflip;
+		i2c_write(gspca_dev, OV7660_REG_MVFP, data, 1);
 		break;
 	case SENSOR_PO1200:
-		data = 0;
-		i2c_write(gspca_dev, 0x03, &data, 1);
-		data = 0x80 * sd->hflip
-			| 0x40 * sd->vflip
+		data[0] = 0;
+		i2c_write(gspca_dev, 0x03, data, 1);
+		data[0] = 0x80 * hflip
+			| 0x40 * vflip
 			| 0x06;
-		i2c_write(gspca_dev, 0x1e, &data, 1);
-		return;
-	default:
-		return;
+		i2c_write(gspca_dev, 0x1e, data, 1);
+		break;
 	}
-	data |= OV7660_MVFP_MIRROR * sd->hflip
-		| OV7660_MVFP_VFLIP * sd->vflip;
-	i2c_write(gspca_dev, OV7660_REG_MVFP, &data, 1);
 }
 
 static void setlightfreq(struct gspca_dev *gspca_dev)
@@ -2730,7 +2743,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 	};
 
 /*fixme: back sensor only*/
-	if (sd->ninput != 0) {
+	if (sd->flags & FL_SAMSUNG) {
 		reg_w(gspca_dev->dev, 0x89, 0xf0ff, 0xffff);
 		reg_w(gspca_dev->dev, 0xa9, 0x8348, 0x000e);
 		reg_w(gspca_dev->dev, 0xa9, 0x0000, 0x001a);
@@ -3024,7 +3037,7 @@ static const struct sd_desc sd_desc = {
 	.driver_info = (BRIDGE_ ## bridge << 8) \
 		| (flags)
 static const __devinitdata struct usb_device_id device_table[] = {
-	{USB_DEVICE(0x041e, 0x405b), BF(VC0323, 0)},
+	{USB_DEVICE(0x041e, 0x405b), BF(VC0323, FL_VFLIP)},
 	{USB_DEVICE(0x046d, 0x0892), BF(VC0321, 0)},
 	{USB_DEVICE(0x046d, 0x0896), BF(VC0321, 0)},
 	{USB_DEVICE(0x046d, 0x0897), BF(VC0321, 0)},
@@ -3033,7 +3046,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
 	{USB_DEVICE(0x0ac8, 0x0328), BF(VC0321, 0)},
 	{USB_DEVICE(0x0ac8, 0xc001), BF(VC0321, 0)},
 	{USB_DEVICE(0x0ac8, 0xc002), BF(VC0321, 0)},
-	{USB_DEVICE(0x0ac8, 0xc301), BF(VC0323, 1)},
+	{USB_DEVICE(0x0ac8, 0xc301), BF(VC0323, FL_SAMSUNG)},
 	{USB_DEVICE(0x15b8, 0x6001), BF(VC0323, 0)},
 	{USB_DEVICE(0x15b8, 0x6002), BF(VC0323, 0)},
 	{USB_DEVICE(0x17ef, 0x4802), BF(VC0323, 0)},