Change auto-focus related behavior

OV5645 supports three different modes for its AF functionality.

 0. Released AF. No AF functionality is active.
 1. One-shot focus. Camera analyzes images and locks the lens
    at current focus.
 2. Continous mode: Camera continously analyzes image and
    makes stepwise focal adjustments.

This change sets the default mode for a video stream to continous
mode, and allows for user setting of all modes via the ov5645_af
sysfs node by writing 0, 1 or 2 to the node respectively.

Change-Id: Ia9e3f3088d04c16de8e908e799420ed021480a4f
diff --git a/drivers/media/platform/mxc/capture/ov5645_mipi_v2.c b/drivers/media/platform/mxc/capture/ov5645_mipi_v2.c
index 0953c80..8a1b2ae 100644
--- a/drivers/media/platform/mxc/capture/ov5645_mipi_v2.c
+++ b/drivers/media/platform/mxc/capture/ov5645_mipi_v2.c
@@ -79,6 +79,12 @@
 	SCALING,
 };
 
+enum ov5645_af_mode {
+	ov5645_af_release = 0,
+	ov5645_af_lock = 1,
+	ov5645_af_cont = 2,
+};
+
 struct reg_value {
 	u16 u16RegAddr;
 	u8 u8Val;
@@ -3494,27 +3500,36 @@
 	return u8RdVal;
 }
 
-static void ov5645_enable_af(bool enable)
+static void ov5645_release_af(void)
+{
+	ov5645_write_reg(0x3022, 0x08);
+}
+
+static void ov5645_enable_cont_af(void)
+{
+	ov5645_release_af();
+	ov5645_write_reg(0x3022, 0x12);
+	ov5645_write_reg(0x3022, 0x04);
+}
+
+static void ov5645_lock_af(void)
 {
 	u8 temp;
 	int cnt = 40;
 	/* At full 5M resolution it typically takes 1600ms for AF to stabilize.
 	 * Setting the retry count to 20 gives us enough margin to always succeed */
-	if (enable) {
-		ov5645_write_reg(0x3022, 0x12);
-		ov5645_write_reg(0x3022, 0x03);
-		do {
-			ov5645_read_reg(0x3029, &temp);
-			msleep(50);
-			pr_debug("AF reg 0x3029: 0x%02x\n", temp);
-			// If the status reg 0x3029 reads 0x10 we have stabilized
-		} while (temp != 0x10 && cnt-- > 0);
+	ov5645_release_af();
+	ov5645_write_reg(0x3022, 0x12);
+	ov5645_write_reg(0x3022, 0x03);
+	do {
+		ov5645_read_reg(0x3029, &temp);
+		msleep(50);
+		pr_debug("AF reg 0x3029: 0x%02x\n", temp);
+		// If the status reg 0x3029 reads 0x10 we have stabilized
+	} while (temp != 0x10 && cnt-- > 0);
 
-		if (temp != 0x10)
-			pr_warning("%s: Failed to enable AF\n", __func__);
-	} else {
-		ov5645_write_reg(0x3022, 0x08);
-	}
+	if (temp != 0x10)
+		pr_warning("%s: Failed to enable AF\n", __func__);
 }
 
 static int prev_sysclk, prev_HTS;
@@ -3523,18 +3538,12 @@
 static void OV5645_stream_on(void)
 {
 	ov5645_write_reg(0x4202, 0x00);
-#ifndef OV5645_REG_TUNING_NOT_DONE
-/* Trying to focus here is rarely successful. It's better to remove it for now
- * and set the focus from user space via the sysfs node ov5645_af to shorten
- * the pipeline startup time
- */
-	ov5645_enable_af(true);
-#endif
+	ov5645_enable_cont_af();
 }
 
 static void OV5645_stream_off(void)
 {
-	ov5645_enable_af(false);
+	ov5645_release_af();
 	ov5645_write_reg(0x4202, 0x0f);
 	ov5645_write_reg(0x3008, 0x42);
 }
@@ -4564,10 +4573,26 @@
 	return cnt;
 }
 
-static int ov5645_trigger_af(const char *buffer, struct kernel_param *kp)
+static int ov5645_set_af_mode(const char *buffer, struct kernel_param *kp)
 {
-  ov5645_enable_af(true);
-  return 0;
+	int cnt, val;
+	cnt = sscanf(buffer, "%d", &val);
+
+	switch (val) {
+	case ov5645_af_release:
+		ov5645_release_af();
+		break;
+	case ov5645_af_lock:
+		ov5645_lock_af();
+		break;
+	case ov5645_af_cont:
+		ov5645_enable_cont_af();
+		break;
+	default:
+		pr_warning("%s: Incorrect value written to sysfs node\n", __func__);
+	}
+
+	return 0;
 }
 
 static int ov5645_read_af(char *buffer, struct kernel_param *kp)
@@ -4576,18 +4601,14 @@
 	u8 val;
 	retval = ov5645_read_reg(0x3029, &val);
 
-	if (retval < 0 || val != 0x10)
-		val = 0;
-	else
-	  val = 1;
-	cnt = sprintf(buffer, "%d", (unsigned int)val);
+	cnt = sprintf(buffer, "%d", (unsigned int)val & 0xff);
 	return cnt;
 }
 
 module_param_call(ov5645_set_regs, ov5645_set_regs, NULL, NULL, 0644);
 module_param_call(ov5645_print_reg, ov5645_set_print_reg, ov5645_get_print_reg,
 		NULL, 0644);
-module_param_call(ov5645_af, ov5645_trigger_af, ov5645_read_af, NULL, 0644);
+module_param_call(ov5645_af, ov5645_set_af_mode, ov5645_read_af, NULL, 0644);
 
 /*!
  * ov5645 I2C probe function