From f7f580e414080a2e6f8b5da36a571a2d871c5027 Mon Sep 17 00:00:00 2001
From: Josua Grawitter <grewater@googlemail.com>
Date: Sat, 31 Jan 2009 22:06:50 +0100
Subject: [PATCH] Update and extend MT9M111 code

	Thanks to wangrui <cnsdqdwangrui@hotmail.com> MT9M111 based
	devices are correctly initialized and dynamic AE, AWB and
	Exposure settings are available.

Signed-off-by: Josua Grawitter <grewater@googlemail.com>
---
 micron.c      |  135 ++++++++++++++++++++++++++++++++++----------------------
 micron.h      |    4 ++
 sn9c20x-dev.c |    3 +
 3 files changed, 89 insertions(+), 53 deletions(-)

diff --git a/micron.c b/micron.c
index 9cb8752..13ef778 100644
--- a/micron.c
+++ b/micron.c
@@ -278,61 +278,90 @@ struct sn9c20x_i2c_regs mt9v011_init[] = {
 };
 
 struct sn9c20x_i2c_regs mt9m111_init[] = {
-	{0xf0, 0x0000},
-	/* Reset sensor */
-	{0x0d, 0x0008},
-	{0x0d, 0x0009},
-	{0x0d, 0x0008},
-	/* Select Page map 0x01
-	 * This means  all new writes now have the address prefix 0x1.
-	 * Example: 0x3a becomes 0x13a. */
-	{0xf0, 0x0001},
-	/** Select output format:
-	 * - output raw bayer (8+2 bit)
-	 * FIXME: There are nearly all YUV and RGB variants possible.
-	 * Maybe we should use them.
-	 */
-	{0x3a, 0x7300},
-	/* measure atoexposure through a mix of both possible windows */
-	{0x06, 0x308c},
-	/* Switch back to Page map 0x00 */
-	{0xf0, 0x0000},
-	/* The following set the resoutiona and window size.
-	 * It's a bit more than SXGA.
-	 * VSTART */
-	{0x01, 0x000e},
-	/* HSTART */
-	{0x02, 0x0014},
-	/* VSIZE */
-	{0x03, 0x03c4},
-	/* HSIZE */
-	{0x04, 0x0514},
-	/* Blanking */
-	{0xc8, 0x0003},
-	{0x0a, 0x0001},
-	{0x06, 0x0029},
-	{0x05, 0x0072},
-	{0x20, 0x0000},
-	{0x20, 0x0000},
-	/* Shutter width */
-	{0x09, 0x0190},
-	/* Protect settings */
-	{0x0d, 0x8008},
-	/* Green 1 gain */
-	{0x2b, 0x0188},
-	/* Blue gain */
-	{0x2c, 0x0188},
-	/* Red gain */
-	{0x2d, 0x0188},
-	/* Green 2 gain */
-	{0x2e, 0x0188},
-	/* Blanking (again?) */
-	{0x0a, 0x0001},
-	{0x06, 0x0029},
-	{0x05, 0x0072},
-	{0xff, 0xffff},
+        {0xf0, 0x0000},
+        /* Reset sensor */
+        {0x0d, 0x0008},{0x0d, 0x0009},{0x0d, 0x0008},
+        /* Select Page map 0x01
+         * This means  all new writes now have the address prefix 0x1.
+         * Example: 0x3a becomes 0x13a. */
+        {0xf0, 0x0001},
+	/* change pixel format of both contexts */
+        {0x3a, 0x7300},{0x9b, 0x7300},
+	/* setup AE, AWB, etc */
+        {0x06, 0x708e},
+        /* Switch back to Page map 0x00 */
+        {0xf0, 0x0000},
+        {0xff, 0xffff},
 };
 
+int mt9m111_set_exposure(struct usb_sn9c20x *dev)
+{
+	int ret;
+	__u16 exposure, page;
+
+	exposure = dev->vsettings.exposure << 8;
+
+	ret = 0;
+	page = 0;
+	ret |= sn9c20x_write_i2c_data16(dev, 1, 0xF0, &page);
+	ret |= sn9c20x_write_i2c_data16(dev, 1, 0x09, &exposure);
+
+	return ret;
+}
+
+int mt9m111_set_autoexposure(struct usb_sn9c20x *dev)
+{
+	int ret;
+	__u16 data, page;
+
+	ret = 0;
+	page = 1;
+	ret |= sn9c20x_write_i2c_data16(dev, 1, 0xF0, &page);
+	ret |= sn9c20x_read_i2c_data16(dev, 1, 0x06, &data);
+
+
+	if (dev->vsettings.auto_exposure == 1) {
+		data |= 0x7000;
+	} else if (dev->vsettings.auto_exposure == 0) {
+		data &= ~0x7000;
+	} else
+		return -EINVAL;
+
+	ret |= sn9c20x_write_i2c_data16(dev, 1, 0x06, &data);
+	page = 0;
+	ret |= sn9c20x_write_i2c_data16(dev, 1, 0xF0, &page);
+
+	if (ret < 0) {
+		UDIA_ERROR("Error: setting of auto exposure failed: "
+			"error while writing to IFP-register 0x06\n");
+		return ret;
+	}
+	return 0;
+}
+
+int mt9m111_set_autowhitebalance(struct usb_sn9c20x *dev)
+{
+	int ret;
+	__u16 data, page;
+
+	ret = 0;
+	page = 1;
+	ret |= sn9c20x_write_i2c_data16(dev, 1, 0xF0, &page);
+	ret |= sn9c20x_read_i2c_data16(dev, 1, 0x06, &data);
+
+	if (dev->vsettings.auto_whitebalance == 1) {
+		data |= 0x0002;
+	} else if (dev->vsettings.auto_whitebalance == 0) {
+		data &= ~0x0002;
+	}
+
+	ret |= sn9c20x_write_i2c_data16(dev, 1, 0x06, &data);
+	page = 0;
+	ret |= sn9c20x_write_i2c_data16(dev, 1, 0xF0, &page);
+
+	return ret;
+}
+
 int mt9v111_select_address_space(struct usb_sn9c20x *dev, __u8 address_space)
 {
 	__u8 buf[2];
diff --git a/micron.h b/micron.h
index c95654b..9b1e27d 100644
--- a/micron.h
+++ b/micron.h
@@ -98,6 +98,10 @@ int mt9v111_set_hvflip(struct usb_sn9c20x *dev);
 int mt9v111_set_autoexposure(struct usb_sn9c20x *dev);
 int mt9v111_set_autowhitebalance(struct usb_sn9c20x *dev);
 
+int mt9m111_set_exposure(struct usb_sn9c20x *dev);
+int mt9m111_set_autoexposure(struct usb_sn9c20x *dev);
+int mt9m111_set_autowhitebalance(struct usb_sn9c20x *dev);
+
 int mt9v011_set_exposure(struct usb_sn9c20x *dev);
 int mt9v011_set_hvflip(struct usb_sn9c20x *dev);
 
diff --git a/sn9c20x-dev.c b/sn9c20x-dev.c
index 16dc305..6ca9dca 100644
--- a/sn9c20x-dev.c
+++ b/sn9c20x-dev.c
@@ -193,6 +193,9 @@ int sn9c20x_initialize_sensor(struct usb_sn9c20x *dev)
 		break;
 	case MT9M111_SENSOR:
 		sn9c20x_write_i2c_array(dev, mt9m111_init, 1);
+		dev->camera.set_exposure = mt9m111_set_exposure;
+		dev->camera.set_auto_exposure = mt9m111_set_autoexposure;
+		dev->camera.set_auto_whitebalance = mt9m111_set_autowhitebalance;
 		dev->camera.hstart = 6;
 		dev->camera.vstart = 2;
 		UDIA_INFO("Detected MT9M111 Sensor.\n");
-- 
1.6.0.6

