diff mbox series

[v5,10/27] media: ov5640: Split DVP and CSI-2 timings

Message ID 20220224094313.233347-11-jacopo@jmondi.org
State Superseded
Headers show
Series media: ov5640: Rework the clock tree programming for MIPI | expand

Commit Message

Jacopo Mondi Feb. 24, 2022, 9:42 a.m. UTC
Separate the timings for the DVP mode from the timings for the CSI-2
mode in the ov5640 modes definition.

The CSI-2 timings will deviate from the DVP ones as the clock tree is
calculated differently.

In CSI-2 mode change the analog crop rectangles as the OV5640 pixel
array is composed as:
- vertically: 16 dummy columns, 2592 valid ones and 16 dummy columns for
  a total of 2624 columns
- horizontally: 8 optical black lines, 6 dummy ones, 1944 valid and 6
  dummies for a total of 1964 lines

Adjust the analog crop rectangle in CSI-2 mode to:
- Skip the first 16 dummy columns
- Skip the first 14 black/dummy lines
- Pass the whole valid pixel array size to the ISP for all modes except
  1024x768, 720p and 1080p which are obtained by cropping the valid pixel
  array.

Tested in RGB565, UYVY and RGB888 modes in CSI-2 mode.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 drivers/media/i2c/ov5640.c | 609 ++++++++++++++++++++++++++-----------
 1 file changed, 434 insertions(+), 175 deletions(-)
diff mbox series

Patch

diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 9e8fcdf4d072..d781fe9a66ca 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -29,6 +29,13 @@ 
 #define OV5640_XCLK_MIN  6000000
 #define OV5640_XCLK_MAX 54000000
 
+#define OV5640_NATIVE_WIDTH		2624
+#define OV5640_NATIVE_HEIGHT		1964
+#define OV5640_PIXEL_ARRAY_TOP		14
+#define OV5640_PIXEL_ARRAY_LEFT		16
+#define OV5640_PIXEL_ARRAY_WIDTH	2592
+#define OV5640_PIXEL_ARRAY_HEIGHT	1944
+
 #define OV5640_DEFAULT_SLAVE_ID 0x3c
 
 #define OV5640_LINK_RATE_MAX		490000000U
@@ -281,24 +288,34 @@  struct reg_value {
 	u32 delay_ms;
 };
 
-struct ov5640_mode_info {
-	enum ov5640_mode_id id;
-	enum ov5640_downsize_mode dn_mode;
-	enum ov5640_pixel_rate_id pixel_rate;
+struct ov5640_timings {
 	/* Analog crop rectangle. */
 	struct v4l2_rect analog_crop;
 	/* Visibile crop: from analog crop top-left corner. */
 	struct v4l2_rect crop;
-	/* Total pixels per line: crop.width + fixed hblank. */
+	/* Total pixels per line: width + fixed hblank. */
 	u32 htot;
-	/* Default vertical blanking: frame height = crop.height + vblank. */
+	/* Default vertical blanking: frame height = height + vblank. */
 	u32 vblank_def;
-	const struct reg_value *reg_data;
-	u32 reg_data_size;
 	/* DVP only; ignored in MIPI mode. */
 	u32 max_fps;
 };
 
+struct ov5640_mode_info {
+	enum ov5640_mode_id id;
+	enum ov5640_downsize_mode dn_mode;
+	enum ov5640_pixel_rate_id pixel_rate;
+
+	unsigned int width;
+	unsigned int height;
+
+	struct ov5640_timings dvp_timings;
+	struct ov5640_timings csi2_timings;
+
+	const struct reg_value *reg_data;
+	u32 reg_data_size;
+};
+
 struct ov5640_ctrls {
 	struct v4l2_ctrl_handler handler;
 	struct v4l2_ctrl *pixel_rate;
@@ -628,247 +645,479 @@  static const struct ov5640_mode_info ov5640_mode_init_data = {
 		.id		= 0,
 		.dn_mode	= SUBSAMPLING,
 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
-		.analog_crop = {
-			.left	= 0,
-			.top	= 4,
-			.width	= 2624,
-			.height	= 1944,
+		.width	= 640,
+		.height	= 480,
+		.dvp_timings = {
+			.analog_crop = {
+				.left	= 0,
+				.top	= 4,
+				.width	= 2624,
+				.height	= 1944,
+			},
+			.crop = {
+				.left	= 16,
+				.top	= 6,
+				.width	= 640,
+				.height	= 480,
+			},
+			.htot		= 1896,
+			.vblank_def	= 504,
+			.max_fps	= OV5640_30_FPS
 		},
-		.crop = {
-			.left	= 16,
-			.top	= 6,
-			.width	= 640,
-			.height	= 480,
+		.csi2_timings = {
+			.analog_crop = {
+				.left	= OV5640_PIXEL_ARRAY_LEFT,
+				.top	= OV5640_PIXEL_ARRAY_TOP,
+				.width	= OV5640_PIXEL_ARRAY_WIDTH,
+				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
+			},
+			.crop = {
+				.left	= 2,
+				.top	= 4,
+				.width	= 640,
+				.height	= 480,
+			},
+			.htot		= 1896,
+			.vblank_def	= 504,
 		},
-		.htot		= 1896,
-		.vblank_def	= 504,
 		.reg_data	= ov5640_init_setting_30fps_VGA,
 		.reg_data_size	= ARRAY_SIZE(ov5640_init_setting_30fps_VGA),
-		.max_fps	= OV5640_30_FPS
 };
 
-static const struct ov5640_mode_info
-ov5640_mode_data[OV5640_NUM_MODES] = {
+static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = {
 	{
 		/* 160x120 */
 		.id		= OV5640_MODE_QQVGA_160_120,
 		.dn_mode	= SUBSAMPLING,
 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
-		.analog_crop = {
-			.left	= 0,
-			.top	= 4,
-			.width	= 2624,
-			.height	= 1944,
+		.width		= 160,
+		.height		= 120,
+		.dvp_timings = {
+			.analog_crop = {
+				.left	= 0,
+				.top	= 4,
+				.width	= 2624,
+				.height	= 1944,
+			},
+			.crop = {
+				.left	= 16,
+				.top	= 6,
+				.width	= 160,
+				.height	= 120,
+			},
+			.htot		= 1896,
+			.vblank_def	= 864,
+			.max_fps	= OV5640_30_FPS
 		},
-		.crop = {
-			.left	= 16,
-			.top	= 6,
-			.width	= 160,
-			.height	= 120,
+		.csi2_timings = {
+			/* Feed the full valid pixel array to the ISP. */
+			.analog_crop = {
+				.left	= OV5640_PIXEL_ARRAY_LEFT,
+				.top	= OV5640_PIXEL_ARRAY_TOP,
+				.width	= OV5640_PIXEL_ARRAY_WIDTH,
+				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
+			},
+			/* Maintain a minimum processing margin. */
+			.crop = {
+				.left	= 2,
+				.top	= 4,
+				.width	= 160,
+				.height	= 120,
+			},
+			.htot		= 1896,
+			.vblank_def	= 864,
 		},
-		.htot		= 1896,
-		.vblank_def	= 864,
 		.reg_data	= ov5640_setting_QQVGA_160_120,
 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QQVGA_160_120),
-		.max_fps	= OV5640_30_FPS
 	}, {
 		/* 176x144 */
 		.id		= OV5640_MODE_QCIF_176_144,
 		.dn_mode	= SUBSAMPLING,
 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
-		.analog_crop = {
-			.left	= 0,
-			.top	= 4,
-			.width	= 2624,
-			.height	= 1944,
+		.width		= 176,
+		.height		= 144,
+		.dvp_timings = {
+			.analog_crop = {
+				.left	= 0,
+				.top	= 4,
+				.width	= 2624,
+				.height	= 1944,
+			},
+			.crop = {
+				.left	= 16,
+				.top	= 6,
+				.width	= 176,
+				.height	= 144,
+			},
+			.htot		= 1896,
+			.vblank_def	= 840,
+			.max_fps	= OV5640_30_FPS
 		},
-		.crop = {
-			.left	= 16,
-			.top	= 6,
-			.width	= 176,
-			.height	= 144,
+		.csi2_timings = {
+			/* Feed the full valid pixel array to the ISP. */
+			.analog_crop = {
+				.left	= OV5640_PIXEL_ARRAY_LEFT,
+				.top	= OV5640_PIXEL_ARRAY_TOP,
+				.width	= OV5640_PIXEL_ARRAY_WIDTH,
+				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
+			},
+			/* Maintain a minimum processing margin. */
+			.crop = {
+				.left	= 2,
+				.top	= 4,
+				.width	= 176,
+				.height	= 144,
+			},
+			.htot		= 1896,
+			.vblank_def	= 840,
 		},
-		.htot		= 1896,
-		.vblank_def	= 840,
 		.reg_data	= ov5640_setting_QCIF_176_144,
 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QCIF_176_144),
-		.max_fps	= OV5640_30_FPS
 	}, {
 		/* 320x240 */
 		.id		= OV5640_MODE_QVGA_320_240,
 		.dn_mode	= SUBSAMPLING,
+		.width		= 320,
+		.height		= 240,
 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
-		.analog_crop = {
-			.left	= 0,
-			.top	= 4,
-			.width	= 2624,
-			.height	= 1944,
+		.dvp_timings = {
+			.analog_crop = {
+				.left	= 0,
+				.top	= 4,
+				.width	= 2624,
+				.height	= 1944,
+			},
+			.crop = {
+				.left	= 16,
+				.top	= 6,
+				.width	= 320,
+				.height	= 240,
+			},
+			.htot		= 1896,
+			.vblank_def	= 744,
+			.max_fps	= OV5640_30_FPS
 		},
-		.crop = {
-			.left	= 16,
-			.top	= 6,
-			.width	= 320,
-			.height	= 240,
+		.csi2_timings = {
+			/* Feed the full valid pixel array to the ISP. */
+			.analog_crop = {
+				.left	= OV5640_PIXEL_ARRAY_LEFT,
+				.top	= OV5640_PIXEL_ARRAY_TOP,
+				.width	= OV5640_PIXEL_ARRAY_WIDTH,
+				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
+			},
+			/* Maintain a minimum processing margin. */
+			.crop = {
+				.left	= 2,
+				.top	= 4,
+				.width	= 320,
+				.height	= 240,
+			},
+			.htot		= 1896,
+			.vblank_def	= 744,
 		},
-		.htot		= 1896,
-		.vblank_def	= 744,
 		.reg_data	= ov5640_setting_QVGA_320_240,
 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QVGA_320_240),
-		.max_fps	= OV5640_30_FPS
 	}, {
 		/* 640x480 */
 		.id		= OV5640_MODE_VGA_640_480,
 		.dn_mode	= SUBSAMPLING,
 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
-		.analog_crop = {
-			.left	= 0,
-			.top	= 4,
-			.width	= 2624,
-			.height	= 1944,
+		.width		= 640,
+		.height		= 480,
+		.dvp_timings = {
+			.analog_crop = {
+				.left	= 0,
+				.top	= 4,
+				.width	= 2624,
+				.height	= 1944,
+			},
+			.crop = {
+				.left	= 16,
+				.top	= 6,
+				.width	= 640,
+				.height	= 480,
+			},
+			.htot		= 1896,
+			.vblank_def	= 600,
+			.max_fps	= OV5640_60_FPS
 		},
-		.crop = {
-			.left	= 16,
-			.top	= 6,
-			.width	= 640,
-			.height	= 480,
+		.csi2_timings = {
+			/* Feed the full valid pixel array to the ISP. */
+			.analog_crop = {
+				.left	= OV5640_PIXEL_ARRAY_LEFT,
+				.top	= OV5640_PIXEL_ARRAY_TOP,
+				.width	= OV5640_PIXEL_ARRAY_WIDTH,
+				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
+			},
+			/* Maintain a minimum processing margin. */
+			.crop = {
+				.left	= 2,
+				.top	= 4,
+				.width	= 640,
+				.height	= 480,
+			},
+			.htot		= 1896,
+			.vblank_def	= 600,
 		},
-		.htot		= 1896,
-		.vblank_def	= 600,
 		.reg_data	= ov5640_setting_VGA_640_480,
 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_VGA_640_480),
-		.max_fps	= OV5640_60_FPS
 	}, {
 		/* 720x480 */
 		.id		= OV5640_MODE_NTSC_720_480,
 		.dn_mode	= SUBSAMPLING,
+		.width		= 720,
+		.height		= 480,
 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
-		.analog_crop = {
-			.left	= 0,
-			.top	= 4,
-			.width	= 2624,
-			.height	= 1944,
+		.dvp_timings = {
+			.analog_crop = {
+				.left	= 0,
+				.top	= 4,
+				.width	= 2624,
+				.height	= 1944,
+			},
+			.crop = {
+				.left	= 56,
+				.top	= 60,
+				.width	= 720,
+				.height	= 480,
+			},
+			.htot		= 1896,
+			.vblank_def	= 504,
+			.max_fps	= OV5640_30_FPS
 		},
-		.crop = {
-			.left	= 56,
-			.top	= 60,
-			.width	= 720,
-			.height	= 480,
+		.csi2_timings = {
+			/* Feed the full valid pixel array to the ISP. */
+			.analog_crop = {
+				.left	= OV5640_PIXEL_ARRAY_LEFT,
+				.top	= OV5640_PIXEL_ARRAY_TOP,
+				.width	= OV5640_PIXEL_ARRAY_WIDTH,
+				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
+			},
+			.crop = {
+				.left	= 56,
+				.top	= 60,
+				.width	= 720,
+				.height	= 480,
+			},
+			.htot		= 1896,
+			.vblank_def	= 504,
 		},
-		.htot		= 1896,
-		.vblank_def	= 504,
 		.reg_data	= ov5640_setting_NTSC_720_480,
 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_NTSC_720_480),
-		.max_fps	= OV5640_30_FPS
 	}, {
 		/* 720x576 */
 		.id		= OV5640_MODE_PAL_720_576,
 		.dn_mode	= SUBSAMPLING,
+		.width		= 720,
+		.height		= 576,
 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
-		.analog_crop = {
-			.left	= 0,
-			.top	= 4,
-			.width	= 2624,
-			.height	= 1944,
+		.dvp_timings = {
+			.analog_crop = {
+				.left	= 0,
+				.top	= 4,
+				.width	= 2624,
+				.height	= 1944,
+			},
+			.crop = {
+				.left	= 56,
+				.top	= 6,
+				.width	= 720,
+				.height	= 576,
+			},
+			.htot		= 1896,
+			.vblank_def	= 408,
+			.max_fps	= OV5640_30_FPS
 		},
-		.crop = {
-			.left	= 56,
-			.top	= 6,
-			.width	= 720,
-			.height	= 576,
+		.csi2_timings = {
+			/* Feed the full valid pixel array to the ISP. */
+			.analog_crop = {
+				.left	= OV5640_PIXEL_ARRAY_LEFT,
+				.top	= OV5640_PIXEL_ARRAY_TOP,
+				.width	= OV5640_PIXEL_ARRAY_WIDTH,
+				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
+			},
+			.crop = {
+				.left	= 56,
+				.top	= 6,
+				.width	= 720,
+				.height	= 576,
+			},
+			.htot		= 1896,
+			.vblank_def	= 408,
 		},
-		.htot		= 1896,
-		.vblank_def	= 408,
 		.reg_data	= ov5640_setting_PAL_720_576,
 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_PAL_720_576),
-		.max_fps	= OV5640_30_FPS
 	}, {
 		/* 1024x768 */
 		.id		= OV5640_MODE_XGA_1024_768,
 		.dn_mode	= SUBSAMPLING,
 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
-		.analog_crop = {
-			.left	= 0,
-			.top	= 4,
-			.width	= 2624,
-			.height	= 1944,
+		.width		= 1024,
+		.height		= 768,
+		.dvp_timings = {
+			.analog_crop = {
+				.left	= 0,
+				.top	= 4,
+				.width	= 2624,
+				.height	= 1944,
+			},
+			.crop = {
+				.left	= 16,
+				.top	= 6,
+				.width	= 1024,
+				.height	= 768,
+			},
+			.htot		= 1896,
+			.vblank_def	= 312,
+			.max_fps	= OV5640_30_FPS
 		},
-		.crop = {
-			.left	= 16,
-			.top	= 6,
-			.width	= 1024,
-			.height	= 768,
+		.csi2_timings = {
+			.analog_crop = {
+				.left	= 0,
+				.top	= 4,
+				.width	= OV5640_NATIVE_WIDTH,
+				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
+			},
+			.crop = {
+				.left	= 16,
+				.top	= 6,
+				.width	= 1024,
+				.height	= 768,
+			},
+			.htot		= 1896,
+			.vblank_def	= 312,
 		},
-		.htot		= 1896,
-		.vblank_def	= 312,
 		.reg_data	= ov5640_setting_XGA_1024_768,
 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_XGA_1024_768),
-		.max_fps	= OV5640_30_FPS
 	}, {
 		/* 1280x720 */
 		.id		= OV5640_MODE_720P_1280_720,
 		.dn_mode	= SUBSAMPLING,
 		.pixel_rate	= OV5640_PIXEL_RATE_124M,
-		.analog_crop = {
-			.left	= 0,
-			.top	= 250,
-			.width	= 2624,
-			.height	= 1456,
+		.width		= 1280,
+		.height		= 720,
+		.dvp_timings = {
+			.analog_crop = {
+				.left	= 0,
+				.top	= 250,
+				.width	= 2624,
+				.height	= 1456,
+			},
+			.crop = {
+				.left	= 16,
+				.top	= 4,
+				.width	= 1280,
+				.height	= 720,
+			},
+			.htot		= 1892,
+			.vblank_def	= 20,
+			.max_fps	= OV5640_30_FPS
 		},
-		.crop = {
-			.left	= 16,
-			.top	= 4,
-			.width	= 1280,
-			.height	= 720,
+		.csi2_timings = {
+			.analog_crop = {
+				.left	= 0,
+				.top	= 250,
+				.width	= 2624,
+				.height	= 1456,
+			},
+			.crop = {
+				.left	= 16,
+				.top	= 4,
+				.width	= 1280,
+				.height	= 720,
+			},
+			.htot		= 1892,
+			.vblank_def	= 20,
 		},
-		.htot		= 1892,
-		.vblank_def	= 20,
 		.reg_data	= ov5640_setting_720P_1280_720,
 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_720P_1280_720),
-		.max_fps	= OV5640_30_FPS
 	}, {
 		/* 1920x1080 */
 		.id		= OV5640_MODE_1080P_1920_1080,
 		.dn_mode	= SCALING,
 		.pixel_rate	= OV5640_PIXEL_RATE_148M,
-		.analog_crop = {
-			.left	= 336,
-			.top	= 434,
-			.width	= 1952,
-			.height	= 1088,
+		.width		= 1920,
+		.height		= 1080,
+		.dvp_timings = {
+			.analog_crop = {
+				.left	= 336,
+				.top	= 434,
+				.width	= 1952,
+				.height	= 1088,
+			},
+			.crop = {
+				.left	= 16,
+				.top	= 4,
+				.width	= 1920,
+				.height	= 1080,
+			},
+			.htot		= 2500,
+			.vblank_def	= 40,
+			.max_fps	= OV5640_30_FPS
 		},
-		.crop = {
-			.left	= 16,
-			.top	= 4,
-			.width	= 1920,
-			.height	= 1080,
+		.csi2_timings = {
+			/* Crop the full valid pixel array in the center. */
+			.analog_crop = {
+				.left	= 336,
+				.top	= 434,
+				.width	= 1952,
+				.height	= 1088,
+			},
+			/* Maintain a larger processing margins. */
+			.crop = {
+				.left	= 16,
+				.top	= 4,
+				.width	= 1920,
+				.height	= 1080,
+			},
+			.htot		= 2500,
+			.vblank_def	= 40,
 		},
-		.htot		= 2500,
-		.vblank_def	= 40,
 		.reg_data	= ov5640_setting_1080P_1920_1080,
 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
-		.max_fps	= OV5640_30_FPS
 	}, {
 		/* 2592x1944 */
 		.id		= OV5640_MODE_QSXGA_2592_1944,
 		.dn_mode	= SCALING,
 		.pixel_rate	= OV5640_PIXEL_RATE_168M,
-		.analog_crop = {
-			.left	= 0,
-			.top	= 0,
-			.width	= 2624,
-			.height	= 1952,
+		.width		= OV5640_PIXEL_ARRAY_WIDTH,
+		.height		= OV5640_PIXEL_ARRAY_HEIGHT,
+		.dvp_timings = {
+			.analog_crop = {
+				.left	= 0,
+				.top	= 0,
+				.width	= 2624,
+				.height	= 1952,
+			},
+			.crop = {
+				.left	= 16,
+				.top	= 4,
+				.width	= 2592,
+				.height	= 1944,
+			},
+			.htot		= 2844,
+			.vblank_def	= 24,
+			.max_fps	= OV5640_15_FPS
 		},
-		.crop = {
-			.left	= 16,
-			.top	= 4,
-			.width	= 2592,
-			.height	= 1944,
+		.csi2_timings = {
+			/* Give more processing margin to full resolution. */
+			.analog_crop = {
+				.left	= 0,
+				.top	= 0,
+				.width	= OV5640_NATIVE_WIDTH,
+				.height	= 1952,
+			},
+			.crop = {
+				.left	= 16,
+				.top	= 4,
+				.width	= 2592,
+				.height	= 1944,
+			},
+			.htot		= 2844,
+			.vblank_def	= 24,
 		},
-		.htot		= 2844,
-		.vblank_def	= 24,
 		.reg_data	= ov5640_setting_QSXGA_2592_1944,
 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
-		.max_fps	= OV5640_15_FPS
 	},
 };
 
@@ -1271,9 +1520,10 @@  static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
 static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
 {
 	const struct ov5640_mode_info *mode = sensor->current_mode;
+	const struct ov5640_timings *timings = &mode->dvp_timings;
 	u32 rate;
 
-	rate = mode->htot * (mode->crop.height + mode->vblank_def);
+	rate = timings->htot * (timings->crop.height + timings->vblank_def);
 	rate *= ov5640_framerates[sensor->current_fr];
 
 	return rate;
@@ -1357,21 +1607,20 @@  static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
 	if (ret < 0)
 		return ret;
 
-	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE,
-				 mode->crop.width);
+	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width);
 	if (ret < 0)
 		return ret;
 
-	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE,
-				  mode->crop.height);
+	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height);
 }
 
 /* download ov5640 settings to sensor through i2c */
 static int ov5640_set_timings(struct ov5640_dev *sensor,
 			      const struct ov5640_mode_info *mode)
 {
-	const struct v4l2_rect *analog_crop = &mode->analog_crop;
-	const struct v4l2_rect *crop = &mode->crop;
+	const struct ov5640_timings *timings;
+	const struct v4l2_rect *analog_crop;
+	const struct v4l2_rect *crop;
 	int ret;
 
 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
@@ -1380,6 +1629,14 @@  static int ov5640_set_timings(struct ov5640_dev *sensor,
 			return ret;
 	}
 
+	if (ov5640_is_csi2(sensor))
+		timings = &mode->csi2_timings;
+	else
+		timings = &mode->dvp_timings;
+
+	analog_crop = &timings->analog_crop;
+	crop = &timings->crop;
+
 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS,
 				 analog_crop->left);
 	if (ret < 0)
@@ -1408,20 +1665,20 @@  static int ov5640_set_timings(struct ov5640_dev *sensor,
 	if (ret < 0)
 		return ret;
 
-	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, crop->width);
+	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width);
 	if (ret < 0)
 		return ret;
 
-	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, crop->height);
+	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height);
 	if (ret < 0)
 		return ret;
 
-	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot);
+	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot);
 	if (ret < 0)
 		return ret;
 
 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
-				 crop->height + mode->vblank_def);
+				 mode->height + timings->vblank_def);
 	if (ret < 0)
 		return ret;
 
@@ -1849,19 +2106,21 @@  static const struct ov5640_mode_info *
 ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
 		 int width, int height, bool nearest)
 {
+	const struct ov5640_timings *timings;
 	const struct ov5640_mode_info *mode;
 
 	mode = v4l2_find_nearest_size(ov5640_mode_data,
 				      ARRAY_SIZE(ov5640_mode_data),
-				      crop.width, crop.height, width, height);
+				      width, height, width, height);
 
 	if (!mode ||
 	    (!nearest &&
-	     (mode->crop.width != width || mode->crop.height != height)))
+	     (mode->width != width || mode->height != height)))
 		return NULL;
 
 	/* Check to see if the current mode exceeds the max frame rate */
-	if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps])
+	timings = &mode->dvp_timings;
+	if (ov5640_framerates[fr] > ov5640_framerates[timings->max_fps])
 		return NULL;
 
 	return mode;
@@ -2541,8 +2800,8 @@  static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
 	mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true);
 	if (!mode)
 		return -EINVAL;
-	fmt->width = mode->crop.width;
-	fmt->height = mode->crop.height;
+	fmt->width = mode->width;
+	fmt->height = mode->height;
 
 	if (new_mode)
 		*new_mode = mode;
@@ -3175,9 +3434,9 @@  static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
 	if (fse->index >= OV5640_NUM_MODES)
 		return -EINVAL;
 
-	fse->min_width = ov5640_mode_data[fse->index].crop.width;
+	fse->min_width = ov5640_mode_data[fse->index].width;
 	fse->max_width = fse->min_width;
-	fse->min_height = ov5640_mode_data[fse->index].crop.height;
+	fse->min_height = ov5640_mode_data[fse->index].height;
 	fse->max_height = fse->min_height;
 
 	return 0;
@@ -3241,16 +3500,16 @@  static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
 	mode = sensor->current_mode;
 
 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
-					       mode->crop.width,
-					       mode->crop.height);
+					       mode->width,
+					       mode->height);
 	if (frame_rate < 0) {
 		/* Always return a valid frame interval value */
 		fi->interval = sensor->frame_interval;
 		goto out;
 	}
 
-	mode = ov5640_find_mode(sensor, frame_rate, mode->crop.width,
-				mode->crop.height, true);
+	mode = ov5640_find_mode(sensor, frame_rate, mode->width,
+				mode->height, true);
 	if (!mode) {
 		ret = -EINVAL;
 		goto out;