OV5645 driver patch from Alejandro Sierra <alejandro.sierra@nxp.com>

Change-Id: I565525ffe9418ab387616d5ef68351a6d4fa3e35
diff --git a/drivers/media/platform/mxc/capture/ov5645_mipi_v2.c b/drivers/media/platform/mxc/capture/ov5645_mipi_v2.c
index 3e379b4..e3f77ef 100644
--- a/drivers/media/platform/mxc/capture/ov5645_mipi_v2.c
+++ b/drivers/media/platform/mxc/capture/ov5645_mipi_v2.c
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2011-2016 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2017 NXP
  */
 
 /*
@@ -38,6 +37,7 @@
 
 #define OV5645_XCLK_MIN 6000000
 #define OV5645_XCLK_MAX 24000000
+#define OV5645_XCLK_20MHZ 20000000
 
 #define OV5645_CHIP_ID_HIGH_BYTE	0x300A
 #define OV5645_CHIP_ID_LOW_BYTE		0x300B
@@ -49,8 +49,7 @@ enum ov5645_mode {
 	ov5645_mode_720P_1280_720 = 2,
 	ov5645_mode_1080P_1920_1080 = 3,
 	ov5645_mode_QSXGA_2592_1944 = 4,
-	ov5645_mode_QCIF_176_144 = 5,
-	ov5645_mode_MAX = 6,
+	ov5645_mode_MAX = 5,
 	ov5645_mode_INIT = 0xff, /*only for sensor init*/
 };
 
@@ -118,12 +117,26 @@ struct ov5645 {
 
 	void (*io_init)(void);
 };
+
+struct ov5645_res {
+	int width;
+	int height;
+};
+
 /*!
  * Maintains the information on the current state of the sesor.
  */
 static struct ov5645 ov5645_data;
 static int pwn_gpio, rst_gpio;
 
+struct ov5645_res ov5645_valid_res[] = {
+	[0] = {640, 480},
+	[1] = {720, 480},
+	[2] = {1280, 720},
+	[3] = {1920, 1080},
+	[4] = {2592, 1944},
+};
+
 static struct reg_value ov5645_init_setting_30fps_VGA[] = {
 
 	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
@@ -344,28 +357,6 @@ static struct reg_value ov5645_setting_15fps_QSXGA_2592_1944[] = {
 	{0x4202, 0x00, 0, 0},	/* stream on the sensor */
 };
 
-static struct reg_value ov5645_setting_30fps_QCIF_176_144[] = {
-	{0x3008, 0x42, 0, 0},
-	{0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
-	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
-	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
-	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
-	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
-	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
-	{0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0},
-	{0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
-	{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
-	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
-	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
-	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
-	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
-	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
-	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
-	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
-	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
-	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-};
-
 static struct ov5645_mode_info ov5645_mode_info_data[2][ov5645_mode_MAX + 1] = {
 	{
 		{ov5645_mode_VGA_640_480, -1, 0, 0, NULL, 0},
@@ -375,7 +366,6 @@ static struct ov5645_mode_info ov5645_mode_info_data[2][ov5645_mode_MAX + 1] = {
 		{ov5645_mode_QSXGA_2592_1944, SCALING, 2592, 1944,
 		ov5645_setting_15fps_QSXGA_2592_1944,
 		ARRAY_SIZE(ov5645_setting_15fps_QSXGA_2592_1944)},
-		{ov5645_mode_QCIF_176_144, -1, 0, 0, NULL, 0},
 	},
 	{
 		{ov5645_mode_VGA_640_480, SUBSAMPLING, 640,  480,
@@ -391,9 +381,6 @@ static struct ov5645_mode_info ov5645_mode_info_data[2][ov5645_mode_MAX + 1] = {
 		ov5645_setting_30fps_1080P_1920_1080,
 		ARRAY_SIZE(ov5645_setting_30fps_1080P_1920_1080)},
 		{ov5645_mode_QSXGA_2592_1944, -1, 0, 0, NULL, 0},
-		{ov5645_mode_QCIF_176_144, SUBSAMPLING, 176, 144,
-		 ov5645_setting_30fps_QCIF_176_144,
-		 ARRAY_SIZE(ov5645_setting_30fps_QCIF_176_144)},
 	},
 };
 
@@ -410,7 +397,7 @@ static s32 ov5645_read_reg(u16 reg, u8 *val);
 static s32 ov5645_write_reg(u16 reg, u8 val);
 
 static const struct i2c_device_id ov5645_id[] = {
-	{"ov5645_mipisubdev", 0},
+	{"ov5645_mipi", 0},
 	{},
 };
 
@@ -419,7 +406,7 @@ MODULE_DEVICE_TABLE(i2c, ov5645_id);
 static struct i2c_driver ov5645_i2c_driver = {
 	.driver = {
 		  .owner = THIS_MODULE,
-		  .name  = "ov5645_mipisubdev",
+		  .name  = "ov5645_mipi",
 		  },
 	.probe  = ov5645_probe,
 	.remove = ov5645_remove,
@@ -430,6 +417,19 @@ static const struct ov5645_datafmt ov5645_colour_fmts[] = {
 	{MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
 };
 
+static int get_capturemode(int width, int height)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ov5645_valid_res); i++) {
+		if ((ov5645_valid_res[i].width == width) &&
+		     (ov5645_valid_res[i].height == height))
+			return i;
+	}
+
+	return -1;
+}
+
 static struct ov5645 *to_ov5645(const struct i2c_client *client)
 {
 	return container_of(i2c_get_clientdata(client), struct ov5645, subdev);
@@ -481,7 +481,6 @@ static void ov5645_reset(void)
 
 	gpio_set_value(rst_gpio, 1);
 	msleep(5);
-
 }
 
 static int ov5645_regulator_enable(struct device *dev)
@@ -1331,6 +1330,7 @@ static int ov5645_set_fmt(struct v4l2_subdev *sd,
 	const struct ov5645_datafmt *fmt = ov5645_find_datafmt(mf->code);
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	struct ov5645 *sensor = to_ov5645(client);
+	int capturemode;
 
 	if (!fmt) {
 		mf->code	= ov5645_colour_fmts[0].code;
@@ -1344,7 +1344,16 @@ static int ov5645_set_fmt(struct v4l2_subdev *sd,
 
 	sensor->fmt = fmt;
 
-	return 0;
+	capturemode = get_capturemode(mf->width, mf->height);
+	if (capturemode >= 0) {
+		ov5645_data.streamcap.capturemode = capturemode;
+		ov5645_data.pix.width = mf->width;
+		ov5645_data.pix.height = mf->height;
+		return 0;
+	}
+
+	dev_err(&client->dev, "%s set fail\n", __func__);
+	return -EINVAL;
 }
 
 
@@ -1364,6 +1373,9 @@ static int ov5645_get_fmt(struct v4l2_subdev *sd,
 	mf->colorspace	= fmt->colorspace;
 	mf->field	= V4L2_FIELD_NONE;
 
+	mf->width	= ov5645_data.pix.width;
+	mf->height	= ov5645_data.pix.height;
+
 	return 0;
 }
 
@@ -1523,6 +1535,19 @@ static struct v4l2_subdev_ops ov5645_subdev_ops = {
 	.pad	= &ov5645_subdev_pad_ops,
 };
 
+static void ov5645_adjust_setting_20mhz(void)
+{
+	struct reg_value *regsetting;
+	int i, array_size;
+
+	/* adjust for INIT mode */
+	regsetting = ov5645_init_setting_30fps_VGA;
+	array_size = ARRAY_SIZE(ov5645_init_setting_30fps_VGA);
+
+	for (i = 0; i < array_size; i++, regsetting++)
+		if (regsetting->u16RegAddr == 0x3037)
+			regsetting->u8Val = 0x17;
+}
 
 /*!
  * ov5645 I2C probe function
@@ -1587,6 +1612,9 @@ static int ov5645_probe(struct i2c_client *client,
 		return retval;
 	}
 
+	if (ov5645_data.mclk == OV5645_XCLK_20MHZ)
+		ov5645_adjust_setting_20mhz();
+
 	retval = of_property_read_u32(dev->of_node, "mclk_source",
 					(u32 *) &(ov5645_data.mclk_source));
 	if (retval) {