From 7856cf922a5a58402bf226018689de94927b88a5 Mon Sep 17 00:00:00 2001
From: Brian Johnson <brijohn@gmail.com>
Date: Sat, 2 May 2009 23:05:06 -0400
Subject: [PATCH] Add support for SXGA

Signed-off-by: Brian Johnson <brijohn@gmail.com>
---
 omnivision.c     |   19 +++++++++++++++++++
 omnivision.h     |    1 +
 sn9c20x-bridge.c |   21 ++++++++++++++++++++-
 sn9c20x-dev.c    |    8 ++++++++
 sn9c20x.h        |    3 ++-
 5 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/omnivision.c b/omnivision.c
index 2454f68..c625e66 100644
--- a/omnivision.c
+++ b/omnivision.c
@@ -527,6 +527,25 @@ int ov7670_auto_flip(struct usb_sn9c20x *dev, __u8 vflip)
 	return ret;
 }
 
+void ov965x_set_sxga_mode(struct usb_sn9c20x *dev, bool sxga)
+{
+	__u8 value;
+	__u8 sxga_hstart[4] = {0x1b, 0xbc, 0x01, 0x82};
+	__u8 vga_hstart[4] = {0x24, 0xC5, 0x00, 0x3C};
+
+	if (sxga) {
+		sn9c20x_write_i2c_data(dev, 4, 0x17, sxga_hstart);
+		sn9c20x_read_i2c_data(dev, 1, 0x12, &value);
+		value = value & 0x7;
+		sn9c20x_write_i2c_data(dev, 1, 0x12, &value);
+	} else {
+		sn9c20x_write_i2c_data(dev, 4, 0x17, vga_hstart);
+		sn9c20x_read_i2c_data(dev, 1, 0x12, &value);
+		value = (value & 0x7) | 0x40;
+		sn9c20x_write_i2c_data(dev, 1, 0x12, &value);
+	}
+}
+
 /**
  * @brief Set hflip and vflip in ov965x sensors
  *
diff --git a/omnivision.h b/omnivision.h
index 42bcf5f..fe2c60b 100644
--- a/omnivision.h
+++ b/omnivision.h
@@ -545,6 +545,7 @@ int soi968_set_gain(struct usb_sn9c20x *dev);
 int soi968_set_autoexposure(struct usb_sn9c20x *dev);
 int soi968_set_autowhitebalance(struct usb_sn9c20x *dev);
 
+void ov965x_set_sxga_mode(struct usb_sn9c20x *dev, bool sxga);
 int ov965x_set_hvflip(struct usb_sn9c20x *);
 int ov965x_flip_detect(struct usb_sn9c20x *dev);
 int ov9650_set_gain(struct usb_sn9c20x *dev);
diff --git a/sn9c20x-bridge.c b/sn9c20x-bridge.c
index c961489..9b25afe 100644
--- a/sn9c20x-bridge.c
+++ b/sn9c20x-bridge.c
@@ -1051,6 +1051,14 @@ int sn9c20x_get_closest_resolution(struct usb_sn9c20x *dev,
 	if (*height < sn9c20x_modes[0].height)
 		*height = sn9c20x_modes[0].height;
 
+	if (dev->camera.set_sxga_mode == NULL) {
+		if (*width > 640)
+			*width = 640;
+
+		if (*height > 480)
+			*height = 480;
+	}
+
 	for (i = SN9C20X_N_MODES - 1; i >= 0; i--) {
 		if (*width >= sn9c20x_modes[i].width
 		    && *height >= sn9c20x_modes[i].height)
@@ -1059,7 +1067,6 @@ int sn9c20x_get_closest_resolution(struct usb_sn9c20x *dev,
 
 	*width = sn9c20x_modes[i].width;
 	*height = sn9c20x_modes[i].height;
-
 	return i;
 }
 
@@ -1107,6 +1114,18 @@ int sn9c20x_set_resolution(struct usb_sn9c20x *dev,
 	window[4] = mode->window[2] >> 4;
 	window[5] = mode->window[3] >> 3;
 
+	if (dev->camera.set_sxga_mode) {
+		if (mode->window[2] > 640 && mode->window[3] > 480) {
+			dev->camera.set_sxga_mode(dev, true);
+			scale |= 0xc0;
+			UDIA_DEBUG("Set Sensor to SXGA\n");
+		} else {
+			dev->camera.set_sxga_mode(dev, false);
+			scale |= 0x80;
+			UDIA_DEBUG("Set Sensor to VGA\n");
+		}
+	}
+
 	usb_sn9c20x_control_write(dev, 0x10fb, clrwindow, 5);
 	usb_sn9c20x_control_write(dev, 0x1180, window, 6);
 	usb_sn9c20x_control_write(dev, SN9C20X_SCALE, &scale, 1);
diff --git a/sn9c20x-dev.c b/sn9c20x-dev.c
index 3e5700e..889c033 100644
--- a/sn9c20x-dev.c
+++ b/sn9c20x-dev.c
@@ -76,6 +76,12 @@ struct sn9c20x_video_mode sn9c20x_modes[SN9C20X_N_MODES] = {
 		.scale = SN9C20X_NO_SCALE,
 		.window = {0, 0, 640, 480}
 	},
+	{
+		.width = 1280,
+		.height = 1024,
+		.scale = SN9C20X_NO_SCALE,
+		.window = {0, 0, 1280, 1024}
+	},
 };
 
 struct sn9c20x_video_format sn9c20x_fmts[SN9C20X_N_FMTS] = {
@@ -144,6 +150,7 @@ int sn9c20x_initialize_sensor(struct usb_sn9c20x *dev)
 		sn9c20x_write_i2c_array(dev, ov9650_init, 0);
 		dev->camera.hstart = 1;
 		dev->camera.vstart = 7;
+		dev->camera.set_sxga_mode = ov965x_set_sxga_mode;
 		dev->camera.set_hvflip = ov965x_set_hvflip;
 		dev->camera.set_exposure = ov_set_exposure;
 		dev->camera.set_auto_gain = ov_set_autogain;
@@ -153,6 +160,7 @@ int sn9c20x_initialize_sensor(struct usb_sn9c20x *dev)
 		break;
 	case OV9655_SENSOR:
 		sn9c20x_write_i2c_array(dev, ov9655_init, 0);
+		dev->camera.set_sxga_mode = ov965x_set_sxga_mode;
 		dev->camera.set_exposure = ov_set_exposure;
 		dev->camera.set_auto_gain = ov_set_autogain;
 		dev->camera.hstart = 0;
diff --git a/sn9c20x.h b/sn9c20x.h
index 1af8ac0..5d51953 100644
--- a/sn9c20x.h
+++ b/sn9c20x.h
@@ -297,7 +297,7 @@ struct sn9c20x_i2c_regs {
 };
 
 #define SN9C20X_N_FMTS	3
-#define SN9C20X_N_MODES	6
+#define SN9C20X_N_MODES	7
 
 extern struct sn9c20x_video_format sn9c20x_fmts[SN9C20X_N_FMTS];
 extern struct sn9c20x_video_mode sn9c20x_modes[SN9C20X_N_MODES];
@@ -321,6 +321,7 @@ struct sn9c20x_camera {
 
 	int (*flip_detect) (struct usb_sn9c20x *dev);
 	int (*set_hvflip) (struct usb_sn9c20x *dev);
+	void (*set_sxga_mode) (struct usb_sn9c20x *dev, bool sxga);
 /* image quality functions */
 	int (*set_exposure) (struct usb_sn9c20x *dev);
 	int (*set_gain) (struct usb_sn9c20x *dev);
-- 
1.5.6.3

