V4L/DVB (8373): gspca: Hue, saturation and contrast controls added for sn9c10x ovxxxx.

(does not work with ov6650)

Signed-off-by: Hans de Goede <j.w.r.degoede@hhs.nl>
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index d34d582..5b3490a 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -45,6 +45,9 @@
 	unsigned char autogain;
 	unsigned char autogain_ignore_frames;
 	unsigned char freq;		/* light freq filter setting */
+	unsigned char saturation;
+	unsigned char hue;
+	unsigned char contrast;
 
 	unsigned char fr_h_sz;		/* size of frame header */
 	char sensor;			/* Type of image sensor chip */
@@ -89,6 +92,12 @@
 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
 	{
@@ -165,6 +174,48 @@
 		.set = sd_setfreq,
 		.get = sd_getfreq,
 	},
+	{
+		{
+			.id      = V4L2_CID_SATURATION,
+			.type    = V4L2_CTRL_TYPE_INTEGER,
+			.name    = "Saturation",
+			.minimum = 0,
+			.maximum = 255,
+			.step    = 1,
+#define SATURATION_DEF 127
+			.default_value = SATURATION_DEF,
+		},
+		.set = sd_setsaturation,
+		.get = sd_getsaturation,
+	},
+	{
+		{
+			.id      = V4L2_CID_HUE,
+			.type    = V4L2_CTRL_TYPE_INTEGER,
+			.name    = "Hue",
+			.minimum = 0,
+			.maximum = 255,
+			.step    = 1,
+#define HUE_DEF 127
+			.default_value = HUE_DEF,
+		},
+		.set = sd_sethue,
+		.get = sd_gethue,
+	},
+	{
+		{
+			.id      = V4L2_CID_CONTRAST,
+			.type    = V4L2_CTRL_TYPE_INTEGER,
+			.name    = "Contrast",
+			.minimum = 0,
+			.maximum = 255,
+			.step    = 1,
+#define CONTRAST_DEF 127
+			.default_value = CONTRAST_DEF,
+		},
+		.set = sd_setcontrast,
+		.get = sd_getcontrast,
+	},
 };
 
 static struct v4l2_pix_format vga_mode[] = {
@@ -735,6 +786,68 @@
 	}
 }
 
+static void setsaturation(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (sd->sensor) {
+/*	case SENSOR_OV6650: */
+	case SENSOR_OV7630_3:
+	case SENSOR_OV7630: {
+		__u8 i2c[] = {0xa0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10};
+		i2c[1] = sd->sensor_addr;
+		i2c[3] = sd->saturation & 0xf0;
+		if (i2c_w(gspca_dev, i2c) < 0)
+			PDEBUG(D_ERR, "i2c error setsaturation");
+		else
+			PDEBUG(D_CONF, "saturation set to: %d",
+				(int)sd->saturation);
+		break;
+	    }
+	}
+}
+
+static void sethue(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (sd->sensor) {
+/*	case SENSOR_OV6650: */
+	case SENSOR_OV7630_3:
+	case SENSOR_OV7630: {
+		__u8 i2c[] = {0xa0, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10};
+		i2c[1] = sd->sensor_addr;
+		i2c[3] = 0x20 | (sd->hue >> 3);
+		if (i2c_w(gspca_dev, i2c) < 0)
+			PDEBUG(D_ERR, "i2c error setsaturation");
+		else
+			PDEBUG(D_CONF, "hue set to: %d", (int)sd->hue);
+		break;
+	    }
+	}
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (sd->sensor) {
+/*	case SENSOR_OV6650: */
+	case SENSOR_OV7630_3:
+	case SENSOR_OV7630: {
+		__u8 i2c[] = {0xa0, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10};
+		i2c[1] = sd->sensor_addr;
+		i2c[3] = 0x20 | (sd->contrast >> 3);
+		if (i2c_w(gspca_dev, i2c) < 0)
+			PDEBUG(D_ERR, "i2c error setcontrast");
+		else
+			PDEBUG(D_CONF, "contrast set to: %d",
+				(int)sd->contrast);
+		break;
+	    }
+	}
+}
+
 
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
@@ -771,7 +884,6 @@
 	sd->fr_h_sz = 12;		/* default size of the frame header */
 	sd->sd_desc.nctrls = 2;		/* default nb of ctrls */
 	sd->autogain = AUTOGAIN_DEF;    /* default is autogain active */
-	sd->freq = FREQ_DEF;
 
 	product = id->idProduct;
 /*	switch (id->idVendor) { */
@@ -811,7 +923,7 @@
 			sd->sensor_addr = 0x21;
 			sd->fr_h_sz = 18;	/* size of frame header */
 			sd->sensor_has_gain = 1;
-			sd->sd_desc.nctrls = 5;
+			sd->sd_desc.nctrls = 8;
 			sd->sd_desc.dq_callback = do_autogain;
 			sd->autogain = 0;
 			break;
@@ -851,6 +963,10 @@
 	sd->brightness = BRIGHTNESS_DEF;
 	sd->gain = GAIN_DEF;
 	sd->exposure = EXPOSURE_DEF;
+	sd->freq = FREQ_DEF;
+	sd->contrast = CONTRAST_DEF;
+	sd->saturation = SATURATION_DEF;
+	sd->hue = HUE_DEF;
 	if (sd->sensor == SENSOR_OV7630_3)	/* jfm: from win trace */
 		reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630);
 	return 0;
@@ -1033,6 +1149,9 @@
 	setbrightness(gspca_dev);
 	setexposure(gspca_dev);
 	setfreq(gspca_dev);
+	setsaturation(gspca_dev);
+	sethue(gspca_dev);
+	setcontrast(gspca_dev);
 
 	sd->autogain_ignore_frames = 0;
 	atomic_set(&sd->avg_lum, -1);
@@ -1208,6 +1327,60 @@
 	return 0;
 }
 
+static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->saturation = val;
+	if (gspca_dev->streaming)
+		setsaturation(gspca_dev);
+	return 0;
+}
+
+static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->saturation;
+	return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->hue = val;
+	if (gspca_dev->streaming)
+		sethue(gspca_dev);
+	return 0;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->hue;
+	return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->contrast = val;
+	if (gspca_dev->streaming)
+		setcontrast(gspca_dev);
+	return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->contrast;
+	return 0;
+}
+
 static int sd_querymenu(struct gspca_dev *gspca_dev,
 			struct v4l2_querymenu *menu)
 {