xref: /openbmc/linux/drivers/media/i2c/ov5640.c (revision afe25fbc)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
219a81c14SSteve Longerbeam /*
319a81c14SSteve Longerbeam  * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
419a81c14SSteve Longerbeam  * Copyright (C) 2014-2017 Mentor Graphics Inc.
519a81c14SSteve Longerbeam  */
619a81c14SSteve Longerbeam 
719a81c14SSteve Longerbeam #include <linux/clk.h>
819a81c14SSteve Longerbeam #include <linux/clk-provider.h>
919a81c14SSteve Longerbeam #include <linux/clkdev.h>
1019a81c14SSteve Longerbeam #include <linux/ctype.h>
1119a81c14SSteve Longerbeam #include <linux/delay.h>
1219a81c14SSteve Longerbeam #include <linux/device.h>
1341d8d7f5SHugues Fruchet #include <linux/gpio/consumer.h>
1419a81c14SSteve Longerbeam #include <linux/i2c.h>
1519a81c14SSteve Longerbeam #include <linux/init.h>
1619a81c14SSteve Longerbeam #include <linux/module.h>
1719a81c14SSteve Longerbeam #include <linux/of_device.h>
1885644a9bSPaul Elder #include <linux/pm_runtime.h>
1941d8d7f5SHugues Fruchet #include <linux/regulator/consumer.h>
2019a81c14SSteve Longerbeam #include <linux/slab.h>
2119a81c14SSteve Longerbeam #include <linux/types.h>
2219a81c14SSteve Longerbeam #include <media/v4l2-async.h>
2319a81c14SSteve Longerbeam #include <media/v4l2-ctrls.h>
2419a81c14SSteve Longerbeam #include <media/v4l2-device.h>
252d18fbc5SAkinobu Mita #include <media/v4l2-event.h>
2619a81c14SSteve Longerbeam #include <media/v4l2-fwnode.h>
2719a81c14SSteve Longerbeam #include <media/v4l2-subdev.h>
2819a81c14SSteve Longerbeam 
2919a81c14SSteve Longerbeam /* min/typical/max system clock (xclk) frequencies */
3019a81c14SSteve Longerbeam #define OV5640_XCLK_MIN  6000000
3141cb1c73SPhilipp Puschmann #define OV5640_XCLK_MAX 54000000
3219a81c14SSteve Longerbeam 
335113d5b3SJacopo Mondi #define OV5640_NATIVE_WIDTH		2624
345113d5b3SJacopo Mondi #define OV5640_NATIVE_HEIGHT		1964
355113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_TOP		14
365113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_LEFT		16
375113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_WIDTH	2592
385113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_HEIGHT	1944
395113d5b3SJacopo Mondi 
40bce93b82SJacopo Mondi /* FIXME: not documented. */
41bce93b82SJacopo Mondi #define OV5640_MIN_VBLANK	24
42bce93b82SJacopo Mondi #define OV5640_MAX_VTS		3375
43bce93b82SJacopo Mondi 
4419a81c14SSteve Longerbeam #define OV5640_DEFAULT_SLAVE_ID 0x3c
4519a81c14SSteve Longerbeam 
463c28588fSJacopo Mondi #define OV5640_LINK_RATE_MAX		490000000U
473c28588fSJacopo Mondi 
48d47c4126SHugues Fruchet #define OV5640_REG_SYS_RESET02		0x3002
49d47c4126SHugues Fruchet #define OV5640_REG_SYS_CLOCK_ENABLE02	0x3006
50f22996dbSHugues Fruchet #define OV5640_REG_SYS_CTRL0		0x3008
513b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWDN	0x42
523b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWUP	0x02
53decea0a9SJai Luthra #define OV5640_REG_SYS_CTRL0_SW_RST	0x82
5419a81c14SSteve Longerbeam #define OV5640_REG_CHIP_ID		0x300a
55f22996dbSHugues Fruchet #define OV5640_REG_IO_MIPI_CTRL00	0x300e
56f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE01	0x3017
57f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE02	0x3018
5819a81c14SSteve Longerbeam #define OV5640_REG_PAD_OUTPUT00		0x3019
59f22996dbSHugues Fruchet #define OV5640_REG_SYSTEM_CONTROL1	0x302e
6019a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL0		0x3034
6119a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL1		0x3035
6219a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL2		0x3036
6319a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL3		0x3037
6419a81c14SSteve Longerbeam #define OV5640_REG_SLAVE_ID		0x3100
65f22996dbSHugues Fruchet #define OV5640_REG_SCCB_SYS_CTRL1	0x3103
6619a81c14SSteve Longerbeam #define OV5640_REG_SYS_ROOT_DIVIDER	0x3108
6719a81c14SSteve Longerbeam #define OV5640_REG_AWB_R_GAIN		0x3400
6819a81c14SSteve Longerbeam #define OV5640_REG_AWB_G_GAIN		0x3402
6919a81c14SSteve Longerbeam #define OV5640_REG_AWB_B_GAIN		0x3404
7019a81c14SSteve Longerbeam #define OV5640_REG_AWB_MANUAL_CTRL	0x3406
7119a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_HI	0x3500
7219a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_MED	0x3501
7319a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_LO	0x3502
7419a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_MANUAL	0x3503
7519a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_REAL_GAIN	0x350a
7619a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_VTS		0x350c
773145efcdSJacopo Mondi #define OV5640_REG_TIMING_HS		0x3800
783145efcdSJacopo Mondi #define OV5640_REG_TIMING_VS		0x3802
793145efcdSJacopo Mondi #define OV5640_REG_TIMING_HW		0x3804
803145efcdSJacopo Mondi #define OV5640_REG_TIMING_VH		0x3806
8186633417SMaxime Ripard #define OV5640_REG_TIMING_DVPHO		0x3808
8286633417SMaxime Ripard #define OV5640_REG_TIMING_DVPVO		0x380a
8319a81c14SSteve Longerbeam #define OV5640_REG_TIMING_HTS		0x380c
8419a81c14SSteve Longerbeam #define OV5640_REG_TIMING_VTS		0x380e
853145efcdSJacopo Mondi #define OV5640_REG_TIMING_HOFFS		0x3810
863145efcdSJacopo Mondi #define OV5640_REG_TIMING_VOFFS		0x3812
87ce85705aSHugues Fruchet #define OV5640_REG_TIMING_TC_REG20	0x3820
8819a81c14SSteve Longerbeam #define OV5640_REG_TIMING_TC_REG21	0x3821
8919a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL00		0x3a00
9019a81c14SSteve Longerbeam #define OV5640_REG_AEC_B50_STEP		0x3a08
9119a81c14SSteve Longerbeam #define OV5640_REG_AEC_B60_STEP		0x3a0a
9219a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0D		0x3a0d
9319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0E		0x3a0e
9419a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0F		0x3a0f
9519a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL10		0x3a10
9619a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL11		0x3a11
9719a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1B		0x3a1b
9819a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1E		0x3a1e
9919a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1F		0x3a1f
10019a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL00	0x3c00
10119a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL01	0x3c01
10219a81c14SSteve Longerbeam #define OV5640_REG_SIGMADELTA_CTRL0C	0x3c0c
10319a81c14SSteve Longerbeam #define OV5640_REG_FRAME_CTRL01		0x4202
104e3ee691dSHugues Fruchet #define OV5640_REG_FORMAT_CONTROL00	0x4300
1057cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_HSIZE		0x4602
1067cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_VSIZE		0x4604
1072b5c18f9SChen-Yu Tsai #define OV5640_REG_JPG_MODE_SELECT	0x4713
1084039b037SLad Prabhakar #define OV5640_REG_CCIR656_CTRL00	0x4730
109f22996dbSHugues Fruchet #define OV5640_REG_POLARITY_CTRL00	0x4740
11019a81c14SSteve Longerbeam #define OV5640_REG_MIPI_CTRL00		0x4800
11119a81c14SSteve Longerbeam #define OV5640_REG_DEBUG_MODE		0x4814
1126c957ed7SJacopo Mondi #define OV5640_REG_PCLK_PERIOD		0x4837
113e3ee691dSHugues Fruchet #define OV5640_REG_ISP_FORMAT_MUX_CTRL	0x501f
11419a81c14SSteve Longerbeam #define OV5640_REG_PRE_ISP_TEST_SET1	0x503d
11519a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL0		0x5580
11619a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL1		0x5581
11719a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL3		0x5583
11819a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL4		0x5584
11919a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL5		0x5585
12019a81c14SSteve Longerbeam #define OV5640_REG_AVG_READOUT		0x56a1
12119a81c14SSteve Longerbeam 
12219a81c14SSteve Longerbeam enum ov5640_mode_id {
12332ea5e05SHugues Fruchet 	OV5640_MODE_QQVGA_160_120 = 0,
12432ea5e05SHugues Fruchet 	OV5640_MODE_QCIF_176_144,
12519a81c14SSteve Longerbeam 	OV5640_MODE_QVGA_320_240,
12619a81c14SSteve Longerbeam 	OV5640_MODE_VGA_640_480,
12719a81c14SSteve Longerbeam 	OV5640_MODE_NTSC_720_480,
12819a81c14SSteve Longerbeam 	OV5640_MODE_PAL_720_576,
12919a81c14SSteve Longerbeam 	OV5640_MODE_XGA_1024_768,
13019a81c14SSteve Longerbeam 	OV5640_MODE_720P_1280_720,
13119a81c14SSteve Longerbeam 	OV5640_MODE_1080P_1920_1080,
13219a81c14SSteve Longerbeam 	OV5640_MODE_QSXGA_2592_1944,
13319a81c14SSteve Longerbeam 	OV5640_NUM_MODES,
13419a81c14SSteve Longerbeam };
13519a81c14SSteve Longerbeam 
13619a81c14SSteve Longerbeam enum ov5640_frame_rate {
13719a81c14SSteve Longerbeam 	OV5640_15_FPS = 0,
13819a81c14SSteve Longerbeam 	OV5640_30_FPS,
139e823fb16SMaxime Ripard 	OV5640_60_FPS,
14019a81c14SSteve Longerbeam 	OV5640_NUM_FRAMERATES,
14119a81c14SSteve Longerbeam };
14219a81c14SSteve Longerbeam 
14322845bf2SJacopo Mondi enum ov5640_pixel_rate_id {
14422845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_168M,
14522845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_148M,
14622845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_124M,
14722845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_96M,
14822845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_48M,
14922845bf2SJacopo Mondi 	OV5640_NUM_PIXEL_RATES,
15022845bf2SJacopo Mondi };
15122845bf2SJacopo Mondi 
15222845bf2SJacopo Mondi /*
15322845bf2SJacopo Mondi  * The chip manual suggests 24/48/96/192 MHz pixel clocks.
15422845bf2SJacopo Mondi  *
15522845bf2SJacopo Mondi  * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for
15622845bf2SJacopo Mondi  * full resolution mode @15 FPS.
15722845bf2SJacopo Mondi  */
15822845bf2SJacopo Mondi static const u32 ov5640_pixel_rates[] = {
15922845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_168M] = 168000000,
16022845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_148M] = 148000000,
16122845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_124M] = 124000000,
16222845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_96M] = 96000000,
16322845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_48M] = 48000000,
16422845bf2SJacopo Mondi };
16522845bf2SJacopo Mondi 
1667a3b8d4bSJacopo Mondi /*
1677a3b8d4bSJacopo Mondi  * MIPI CSI-2 link frequencies.
1687a3b8d4bSJacopo Mondi  *
1697a3b8d4bSJacopo Mondi  * Derived from the above defined pixel rate for bpp = (8, 16, 24) and
1707a3b8d4bSJacopo Mondi  * data_lanes = (1, 2)
1717a3b8d4bSJacopo Mondi  *
1727a3b8d4bSJacopo Mondi  * link_freq = (pixel_rate * bpp) / (2 * data_lanes)
1737a3b8d4bSJacopo Mondi  */
1747a3b8d4bSJacopo Mondi static const s64 ov5640_csi2_link_freqs[] = {
1757a3b8d4bSJacopo Mondi 	992000000, 888000000, 768000000, 744000000, 672000000, 672000000,
1767a3b8d4bSJacopo Mondi 	592000000, 592000000, 576000000, 576000000, 496000000, 496000000,
1777a3b8d4bSJacopo Mondi 	384000000, 384000000, 384000000, 336000000, 296000000, 288000000,
1787a3b8d4bSJacopo Mondi 	248000000, 192000000, 192000000, 192000000, 96000000,
1797a3b8d4bSJacopo Mondi };
1807a3b8d4bSJacopo Mondi 
1817a3b8d4bSJacopo Mondi /* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */
1827a3b8d4bSJacopo Mondi #define OV5640_DEFAULT_LINK_FREQ	13
1837a3b8d4bSJacopo Mondi 
184b7ed3abdSLoic Poulain enum ov5640_format_mux {
185b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_YUV422 = 0,
186b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RGB,
187b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_DITHER,
188b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_DPC,
189b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_SNR_RAW,
190b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_CIP,
191b7ed3abdSLoic Poulain };
192b7ed3abdSLoic Poulain 
193a89f14bbSJacopo Mondi struct ov5640_pixfmt {
194e3ee691dSHugues Fruchet 	u32 code;
195e3ee691dSHugues Fruchet 	u32 colorspace;
1962d7671f6SJacopo Mondi 	u8 bpp;
197935fbc94SJacopo Mondi 	u8 ctrl00;
198935fbc94SJacopo Mondi 	enum ov5640_format_mux mux;
199a89f14bbSJacopo Mondi };
200a89f14bbSJacopo Mondi 
201a89f14bbSJacopo Mondi static const struct ov5640_pixfmt ov5640_dvp_formats[] = {
2022d7671f6SJacopo Mondi 	{
203935fbc94SJacopo Mondi 		/* YUV422, YUYV */
2042d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_JPEG_1X8,
2052d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_JPEG,
2062d7671f6SJacopo Mondi 		.bpp		= 16,
207935fbc94SJacopo Mondi 		.ctrl00		= 0x30,
208935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
2092d7671f6SJacopo Mondi 	}, {
210935fbc94SJacopo Mondi 		/* YUV422, UYVY */
2112d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_UYVY8_2X8,
2122d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
2132d7671f6SJacopo Mondi 		.bpp		= 16,
214935fbc94SJacopo Mondi 		.ctrl00		= 0x3f,
215935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
2162d7671f6SJacopo Mondi 	}, {
217935fbc94SJacopo Mondi 		/* YUV422, YUYV */
2182d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_YUYV8_2X8,
2192d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
2202d7671f6SJacopo Mondi 		.bpp		= 16,
221935fbc94SJacopo Mondi 		.ctrl00		= 0x30,
222935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
2232d7671f6SJacopo Mondi 	}, {
224935fbc94SJacopo Mondi 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2252d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_RGB565_2X8_LE,
2262d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
2272d7671f6SJacopo Mondi 		.bpp		= 16,
228935fbc94SJacopo Mondi 		.ctrl00		= 0x6f,
229935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RGB,
2302d7671f6SJacopo Mondi 	}, {
231935fbc94SJacopo Mondi 		/* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
2322d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_RGB565_2X8_BE,
2332d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
2342d7671f6SJacopo Mondi 		.bpp		= 16,
235935fbc94SJacopo Mondi 		.ctrl00		= 0x61,
236935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RGB,
2372d7671f6SJacopo Mondi 	}, {
238935fbc94SJacopo Mondi 		/* Raw, BGBG... / GRGR... */
239a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_SBGGR8_1X8,
240a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
241a89f14bbSJacopo Mondi 		.bpp		= 8,
242935fbc94SJacopo Mondi 		.ctrl00		= 0x00,
243935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
244a89f14bbSJacopo Mondi 	}, {
245935fbc94SJacopo Mondi 		/* Raw bayer, GBGB... / RGRG... */
246a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_SGBRG8_1X8,
247a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
248935fbc94SJacopo Mondi 		.bpp		= 8,
249935fbc94SJacopo Mondi 		.ctrl00		= 0x01,
250935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
251a89f14bbSJacopo Mondi 	}, {
252935fbc94SJacopo Mondi 		/* Raw bayer, GRGR... / BGBG... */
253a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_SGRBG8_1X8,
254a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
255a89f14bbSJacopo Mondi 		.bpp		= 8,
256935fbc94SJacopo Mondi 		.ctrl00		= 0x02,
257935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
258a89f14bbSJacopo Mondi 	}, {
259935fbc94SJacopo Mondi 		/* Raw bayer, RGRG... / GBGB... */
260a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_SRGGB8_1X8,
261a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
262a89f14bbSJacopo Mondi 		.bpp		= 8,
263935fbc94SJacopo Mondi 		.ctrl00		= 0x03,
264935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
265a89f14bbSJacopo Mondi 	},
266a89f14bbSJacopo Mondi 	{ /* sentinel */ }
267a89f14bbSJacopo Mondi };
268a89f14bbSJacopo Mondi 
269a89f14bbSJacopo Mondi static const struct ov5640_pixfmt ov5640_csi2_formats[] = {
270a89f14bbSJacopo Mondi 	{
271935fbc94SJacopo Mondi 		/* YUV422, YUYV */
272a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_JPEG_1X8,
273a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_JPEG,
274a89f14bbSJacopo Mondi 		.bpp		= 16,
275935fbc94SJacopo Mondi 		.ctrl00		= 0x30,
276935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
277a89f14bbSJacopo Mondi 	}, {
278935fbc94SJacopo Mondi 		/* YUV422, UYVY */
279a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_UYVY8_1X16,
280a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
281a89f14bbSJacopo Mondi 		.bpp		= 16,
282935fbc94SJacopo Mondi 		.ctrl00		= 0x3f,
283935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
284a89f14bbSJacopo Mondi 	}, {
285935fbc94SJacopo Mondi 		/* YUV422, YUYV */
286a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_YUYV8_1X16,
287a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
288a89f14bbSJacopo Mondi 		.bpp		= 16,
289935fbc94SJacopo Mondi 		.ctrl00		= 0x30,
290935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
291a89f14bbSJacopo Mondi 	}, {
292935fbc94SJacopo Mondi 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2930a43fcd7SJacopo Mondi 		.code		= MEDIA_BUS_FMT_RGB565_1X16,
2940a43fcd7SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
2950a43fcd7SJacopo Mondi 		.bpp		= 16,
296935fbc94SJacopo Mondi 		.ctrl00		= 0x6f,
297935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RGB,
2980a43fcd7SJacopo Mondi 	}, {
299935fbc94SJacopo Mondi 		/* BGR888: RGB */
3006ac98b41SJacopo Mondi 		.code		= MEDIA_BUS_FMT_BGR888_1X24,
3016ac98b41SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
3026ac98b41SJacopo Mondi 		.bpp		= 24,
303935fbc94SJacopo Mondi 		.ctrl00		= 0x23,
304935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RGB,
3056ac98b41SJacopo Mondi 	}, {
306935fbc94SJacopo Mondi 		/* Raw, BGBG... / GRGR... */
3072d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_SBGGR8_1X8,
3082d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
3092d7671f6SJacopo Mondi 		.bpp		= 8,
310935fbc94SJacopo Mondi 		.ctrl00		= 0x00,
311935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
3122d7671f6SJacopo Mondi 	}, {
313935fbc94SJacopo Mondi 		/* Raw bayer, GBGB... / RGRG... */
3142d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_SGBRG8_1X8,
3152d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
316935fbc94SJacopo Mondi 		.bpp		= 8,
317935fbc94SJacopo Mondi 		.ctrl00		= 0x01,
318935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
3192d7671f6SJacopo Mondi 	}, {
320935fbc94SJacopo Mondi 		/* Raw bayer, GRGR... / BGBG... */
3212d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_SGRBG8_1X8,
3222d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
3232d7671f6SJacopo Mondi 		.bpp		= 8,
324935fbc94SJacopo Mondi 		.ctrl00		= 0x02,
325935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
3262d7671f6SJacopo Mondi 	}, {
327935fbc94SJacopo Mondi 		/* Raw bayer, RGRG... / GBGB... */
3282d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_SRGGB8_1X8,
3292d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
3302d7671f6SJacopo Mondi 		.bpp		= 8,
331935fbc94SJacopo Mondi 		.ctrl00		= 0x03,
332935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
3332d7671f6SJacopo Mondi 	},
334a89f14bbSJacopo Mondi 	{ /* sentinel */ }
335e3ee691dSHugues Fruchet };
336e3ee691dSHugues Fruchet 
33719a81c14SSteve Longerbeam /*
33819a81c14SSteve Longerbeam  * FIXME: remove this when a subdev API becomes available
33919a81c14SSteve Longerbeam  * to set the MIPI CSI-2 virtual channel.
34019a81c14SSteve Longerbeam  */
34119a81c14SSteve Longerbeam static unsigned int virtual_channel;
3428670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444);
34319a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel,
34419a81c14SSteve Longerbeam 		 "MIPI CSI-2 virtual channel (0..3), default 0");
34519a81c14SSteve Longerbeam 
34619a81c14SSteve Longerbeam static const int ov5640_framerates[] = {
34719a81c14SSteve Longerbeam 	[OV5640_15_FPS] = 15,
34819a81c14SSteve Longerbeam 	[OV5640_30_FPS] = 30,
349e823fb16SMaxime Ripard 	[OV5640_60_FPS] = 60,
35019a81c14SSteve Longerbeam };
35119a81c14SSteve Longerbeam 
35219a81c14SSteve Longerbeam /* regulator supplies */
35319a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = {
35441d8d7f5SHugues Fruchet 	"DOVDD", /* Digital I/O (1.8V) supply */
35519a81c14SSteve Longerbeam 	"AVDD",  /* Analog (2.8V) supply */
35624c8ac89SFabio Estevam 	"DVDD",  /* Digital Core (1.5V) supply */
35719a81c14SSteve Longerbeam };
35819a81c14SSteve Longerbeam 
35919a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name)
36019a81c14SSteve Longerbeam 
36119a81c14SSteve Longerbeam /*
36219a81c14SSteve Longerbeam  * Image size under 1280 * 960 are SUBSAMPLING
36319a81c14SSteve Longerbeam  * Image size upper 1280 * 960 are SCALING
36419a81c14SSteve Longerbeam  */
36519a81c14SSteve Longerbeam enum ov5640_downsize_mode {
36619a81c14SSteve Longerbeam 	SUBSAMPLING,
36719a81c14SSteve Longerbeam 	SCALING,
36819a81c14SSteve Longerbeam };
36919a81c14SSteve Longerbeam 
37019a81c14SSteve Longerbeam struct reg_value {
37119a81c14SSteve Longerbeam 	u16 reg_addr;
37219a81c14SSteve Longerbeam 	u8 val;
37319a81c14SSteve Longerbeam 	u8 mask;
37419a81c14SSteve Longerbeam 	u32 delay_ms;
37519a81c14SSteve Longerbeam };
37619a81c14SSteve Longerbeam 
3775113d5b3SJacopo Mondi struct ov5640_timings {
3783145efcdSJacopo Mondi 	/* Analog crop rectangle. */
3793145efcdSJacopo Mondi 	struct v4l2_rect analog_crop;
3803145efcdSJacopo Mondi 	/* Visibile crop: from analog crop top-left corner. */
3813145efcdSJacopo Mondi 	struct v4l2_rect crop;
3825113d5b3SJacopo Mondi 	/* Total pixels per line: width + fixed hblank. */
383476dec01SMaxime Ripard 	u32 htot;
3845113d5b3SJacopo Mondi 	/* Default vertical blanking: frame height = height + vblank. */
3853145efcdSJacopo Mondi 	u32 vblank_def;
3865113d5b3SJacopo Mondi };
3875113d5b3SJacopo Mondi 
3885113d5b3SJacopo Mondi struct ov5640_mode_info {
3895113d5b3SJacopo Mondi 	enum ov5640_mode_id id;
3905113d5b3SJacopo Mondi 	enum ov5640_downsize_mode dn_mode;
3915113d5b3SJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate;
3925113d5b3SJacopo Mondi 
3935113d5b3SJacopo Mondi 	unsigned int width;
3945113d5b3SJacopo Mondi 	unsigned int height;
3955113d5b3SJacopo Mondi 
3965113d5b3SJacopo Mondi 	struct ov5640_timings dvp_timings;
3975113d5b3SJacopo Mondi 	struct ov5640_timings csi2_timings;
3985113d5b3SJacopo Mondi 
39919a81c14SSteve Longerbeam 	const struct reg_value *reg_data;
40019a81c14SSteve Longerbeam 	u32 reg_data_size;
4015113d5b3SJacopo Mondi 
4025113d5b3SJacopo Mondi 	/* Used by s_frame_interval only. */
4035554c80eSAdam Ford 	u32 max_fps;
40419f2e3e6SHugues Fruchet 	u32 def_fps;
40519a81c14SSteve Longerbeam };
40619a81c14SSteve Longerbeam 
40719a81c14SSteve Longerbeam struct ov5640_ctrls {
40819a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler handler;
409cc196e48SBenoit Parrot 	struct v4l2_ctrl *pixel_rate;
4107a3b8d4bSJacopo Mondi 	struct v4l2_ctrl *link_freq;
41132979f67SJacopo Mondi 	struct v4l2_ctrl *hblank;
412bce93b82SJacopo Mondi 	struct v4l2_ctrl *vblank;
41319a81c14SSteve Longerbeam 	struct {
41419a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_exp;
41519a81c14SSteve Longerbeam 		struct v4l2_ctrl *exposure;
41619a81c14SSteve Longerbeam 	};
41719a81c14SSteve Longerbeam 	struct {
41819a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_wb;
41919a81c14SSteve Longerbeam 		struct v4l2_ctrl *blue_balance;
42019a81c14SSteve Longerbeam 		struct v4l2_ctrl *red_balance;
42119a81c14SSteve Longerbeam 	};
42219a81c14SSteve Longerbeam 	struct {
42319a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_gain;
42419a81c14SSteve Longerbeam 		struct v4l2_ctrl *gain;
42519a81c14SSteve Longerbeam 	};
42619a81c14SSteve Longerbeam 	struct v4l2_ctrl *brightness;
4271068fecaSMylène Josserand 	struct v4l2_ctrl *light_freq;
42819a81c14SSteve Longerbeam 	struct v4l2_ctrl *saturation;
42919a81c14SSteve Longerbeam 	struct v4l2_ctrl *contrast;
43019a81c14SSteve Longerbeam 	struct v4l2_ctrl *hue;
43119a81c14SSteve Longerbeam 	struct v4l2_ctrl *test_pattern;
432ce85705aSHugues Fruchet 	struct v4l2_ctrl *hflip;
433ce85705aSHugues Fruchet 	struct v4l2_ctrl *vflip;
43419a81c14SSteve Longerbeam };
43519a81c14SSteve Longerbeam 
43619a81c14SSteve Longerbeam struct ov5640_dev {
43719a81c14SSteve Longerbeam 	struct i2c_client *i2c_client;
43819a81c14SSteve Longerbeam 	struct v4l2_subdev sd;
43919a81c14SSteve Longerbeam 	struct media_pad pad;
44019a81c14SSteve Longerbeam 	struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
44119a81c14SSteve Longerbeam 	struct clk *xclk; /* system clock to OV5640 */
44219a81c14SSteve Longerbeam 	u32 xclk_freq;
44319a81c14SSteve Longerbeam 
44419a81c14SSteve Longerbeam 	struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];
44519a81c14SSteve Longerbeam 	struct gpio_desc *reset_gpio;
44619a81c14SSteve Longerbeam 	struct gpio_desc *pwdn_gpio;
447c3f3ba3eSHugues Fruchet 	bool   upside_down;
44819a81c14SSteve Longerbeam 
44919a81c14SSteve Longerbeam 	/* lock to protect all members below */
45019a81c14SSteve Longerbeam 	struct mutex lock;
45119a81c14SSteve Longerbeam 
45219a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt fmt;
453fb98e29fSHugues Fruchet 	bool pending_fmt_change;
45419a81c14SSteve Longerbeam 
45519a81c14SSteve Longerbeam 	const struct ov5640_mode_info *current_mode;
456985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *last_mode;
45719a81c14SSteve Longerbeam 	enum ov5640_frame_rate current_fr;
45819a81c14SSteve Longerbeam 	struct v4l2_fract frame_interval;
4593c28588fSJacopo Mondi 	s64 current_link_freq;
46019a81c14SSteve Longerbeam 
46119a81c14SSteve Longerbeam 	struct ov5640_ctrls ctrls;
46219a81c14SSteve Longerbeam 
46319a81c14SSteve Longerbeam 	u32 prev_sysclk, prev_hts;
46419a81c14SSteve Longerbeam 	u32 ae_low, ae_high, ae_target;
46519a81c14SSteve Longerbeam 
46619a81c14SSteve Longerbeam 	bool pending_mode_change;
46719a81c14SSteve Longerbeam 	bool streaming;
46819a81c14SSteve Longerbeam };
46919a81c14SSteve Longerbeam 
47019a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
47119a81c14SSteve Longerbeam {
47219a81c14SSteve Longerbeam 	return container_of(sd, struct ov5640_dev, sd);
47319a81c14SSteve Longerbeam }
47419a81c14SSteve Longerbeam 
47519a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
47619a81c14SSteve Longerbeam {
47719a81c14SSteve Longerbeam 	return &container_of(ctrl->handler, struct ov5640_dev,
47819a81c14SSteve Longerbeam 			     ctrls.handler)->sd;
47919a81c14SSteve Longerbeam }
48019a81c14SSteve Longerbeam 
4818e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor)
4828e823f5cSJacopo Mondi {
4838e823f5cSJacopo Mondi 	return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY;
4848e823f5cSJacopo Mondi }
4858e823f5cSJacopo Mondi 
486a89f14bbSJacopo Mondi static inline const struct ov5640_pixfmt *
487a89f14bbSJacopo Mondi ov5640_formats(struct ov5640_dev *sensor)
488a89f14bbSJacopo Mondi {
489a89f14bbSJacopo Mondi 	return ov5640_is_csi2(sensor) ? ov5640_csi2_formats
490a89f14bbSJacopo Mondi 				      : ov5640_dvp_formats;
491a89f14bbSJacopo Mondi }
492a89f14bbSJacopo Mondi 
493a89f14bbSJacopo Mondi static const struct ov5640_pixfmt *
494a89f14bbSJacopo Mondi ov5640_code_to_pixfmt(struct ov5640_dev *sensor, u32 code)
495a89f14bbSJacopo Mondi {
496a89f14bbSJacopo Mondi 	const struct ov5640_pixfmt *formats = ov5640_formats(sensor);
497a89f14bbSJacopo Mondi 	unsigned int i;
498a89f14bbSJacopo Mondi 
499a89f14bbSJacopo Mondi 	for (i = 0; formats[i].code; ++i) {
500a89f14bbSJacopo Mondi 		if (formats[i].code == code)
501a89f14bbSJacopo Mondi 			return &formats[i];
502a89f14bbSJacopo Mondi 	}
503a89f14bbSJacopo Mondi 
504a89f14bbSJacopo Mondi 	return &formats[0];
505a89f14bbSJacopo Mondi }
506a89f14bbSJacopo Mondi 
507a89f14bbSJacopo Mondi static u32 ov5640_code_to_bpp(struct ov5640_dev *sensor, u32 code)
508a89f14bbSJacopo Mondi {
509a89f14bbSJacopo Mondi 	const struct ov5640_pixfmt *format = ov5640_code_to_pixfmt(sensor,
510a89f14bbSJacopo Mondi 								   code);
511a89f14bbSJacopo Mondi 
512a89f14bbSJacopo Mondi 	return format->bpp;
513a89f14bbSJacopo Mondi }
514a89f14bbSJacopo Mondi 
51519a81c14SSteve Longerbeam /*
51619a81c14SSteve Longerbeam  * FIXME: all of these register tables are likely filled with
51719a81c14SSteve Longerbeam  * entries that set the register to their power-on default values,
51819a81c14SSteve Longerbeam  * and which are otherwise not touched by this driver. Those entries
51919a81c14SSteve Longerbeam  * should be identified and removed to speed register load time
52019a81c14SSteve Longerbeam  * over i2c.
52119a81c14SSteve Longerbeam  */
522fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */
52390b0f355SJacopo Mondi 
52468453b02SGuoniu.zhou static const struct v4l2_mbus_framefmt ov5640_csi2_default_fmt = {
52568453b02SGuoniu.zhou 	.code = MEDIA_BUS_FMT_UYVY8_1X16,
52668453b02SGuoniu.zhou 	.width = 640,
52768453b02SGuoniu.zhou 	.height = 480,
52868453b02SGuoniu.zhou 	.colorspace = V4L2_COLORSPACE_SRGB,
52968453b02SGuoniu.zhou 	.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB),
53068453b02SGuoniu.zhou 	.quantization = V4L2_QUANTIZATION_FULL_RANGE,
53168453b02SGuoniu.zhou 	.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB),
53268453b02SGuoniu.zhou 	.field = V4L2_FIELD_NONE,
53368453b02SGuoniu.zhou };
53468453b02SGuoniu.zhou 
53568453b02SGuoniu.zhou static const struct v4l2_mbus_framefmt ov5640_dvp_default_fmt = {
53690b0f355SJacopo Mondi 	.code = MEDIA_BUS_FMT_UYVY8_2X8,
53790b0f355SJacopo Mondi 	.width = 640,
53890b0f355SJacopo Mondi 	.height = 480,
53990b0f355SJacopo Mondi 	.colorspace = V4L2_COLORSPACE_SRGB,
54090b0f355SJacopo Mondi 	.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB),
54190b0f355SJacopo Mondi 	.quantization = V4L2_QUANTIZATION_FULL_RANGE,
54290b0f355SJacopo Mondi 	.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB),
54390b0f355SJacopo Mondi 	.field = V4L2_FIELD_NONE,
54490b0f355SJacopo Mondi };
54590b0f355SJacopo Mondi 
546e4359019SJacopo Mondi static const struct reg_value ov5640_init_setting[] = {
547decea0a9SJai Luthra 	{0x3103, 0x11, 0, 0},
548576f5d4bSLad Prabhakar 	{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
54919a81c14SSteve Longerbeam 	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
55019a81c14SSteve Longerbeam 	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
55119a81c14SSteve Longerbeam 	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
55219a81c14SSteve Longerbeam 	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
55319a81c14SSteve Longerbeam 	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
55419a81c14SSteve Longerbeam 	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
55519a81c14SSteve Longerbeam 	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
55619a81c14SSteve Longerbeam 	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
55719a81c14SSteve Longerbeam 	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
55819a81c14SSteve Longerbeam 	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
55919a81c14SSteve Longerbeam 	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
56019a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
56119a81c14SSteve Longerbeam 	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
5623145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
56319a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
56419a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
56519a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
56619a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
56719a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
56819a81c14SSteve Longerbeam 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
56919a81c14SSteve Longerbeam 	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
570aa4bb8b8SJacopo Mondi 	{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
5712b5c18f9SChen-Yu Tsai 	{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
57219a81c14SSteve Longerbeam 	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
573aa4bb8b8SJacopo Mondi 	{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
57419a81c14SSteve Longerbeam 	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
57519a81c14SSteve Longerbeam 	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
57619a81c14SSteve Longerbeam 	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
57719a81c14SSteve Longerbeam 	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
57819a81c14SSteve Longerbeam 	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
57919a81c14SSteve Longerbeam 	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
58019a81c14SSteve Longerbeam 	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
58119a81c14SSteve Longerbeam 	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
58219a81c14SSteve Longerbeam 	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
58319a81c14SSteve Longerbeam 	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
58419a81c14SSteve Longerbeam 	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
58519a81c14SSteve Longerbeam 	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
58619a81c14SSteve Longerbeam 	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
58719a81c14SSteve Longerbeam 	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
58819a81c14SSteve Longerbeam 	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
58919a81c14SSteve Longerbeam 	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
59019a81c14SSteve Longerbeam 	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
59119a81c14SSteve Longerbeam 	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
59219a81c14SSteve Longerbeam 	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
59319a81c14SSteve Longerbeam 	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
59419a81c14SSteve Longerbeam 	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
59519a81c14SSteve Longerbeam 	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
59619a81c14SSteve Longerbeam 	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
59719a81c14SSteve Longerbeam 	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
59819a81c14SSteve Longerbeam 	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
59919a81c14SSteve Longerbeam 	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
60019a81c14SSteve Longerbeam 	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
60119a81c14SSteve Longerbeam 	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
60219a81c14SSteve Longerbeam 	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
60319a81c14SSteve Longerbeam 	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
60419a81c14SSteve Longerbeam 	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
60519a81c14SSteve Longerbeam 	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
60619a81c14SSteve Longerbeam 	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
60719a81c14SSteve Longerbeam 	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
60819a81c14SSteve Longerbeam 	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
60919a81c14SSteve Longerbeam 	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
61019a81c14SSteve Longerbeam 	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
61119a81c14SSteve Longerbeam 	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
61219a81c14SSteve Longerbeam 	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
61319a81c14SSteve Longerbeam 	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
61419a81c14SSteve Longerbeam 	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
61519a81c14SSteve Longerbeam 	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
61619a81c14SSteve Longerbeam 	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
61719a81c14SSteve Longerbeam 	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
61819a81c14SSteve Longerbeam 	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
61919a81c14SSteve Longerbeam 	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
62019a81c14SSteve Longerbeam 	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
62119a81c14SSteve Longerbeam 	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
62219a81c14SSteve Longerbeam 	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
62319a81c14SSteve Longerbeam 	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
62419a81c14SSteve Longerbeam };
62519a81c14SSteve Longerbeam 
626db15c195SJacopo Mondi static const struct reg_value ov5640_setting_low_res[] = {
627c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
62819a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
629ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
6303145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
63119a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
63219a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
63319a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
63419a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
63519a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6362b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
637e15197bdSJacopo Mondi 	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
63819a81c14SSteve Longerbeam };
63919a81c14SSteve Longerbeam 
640086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = {
641c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0},
64219a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
643ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
6443145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
64519a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
64619a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
64719a81c14SSteve Longerbeam 	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
64819a81c14SSteve Longerbeam 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
64919a81c14SSteve Longerbeam 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
6502b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
65119a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
65219a81c14SSteve Longerbeam 	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
65319a81c14SSteve Longerbeam };
65419a81c14SSteve Longerbeam 
655086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
656c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
65719a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
658ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
6593145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
66019a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
66119a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
66219a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
66319a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
66419a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6652b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
66619a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
667c14d107eSMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
668c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
66919a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
670476dec01SMaxime Ripard 	{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
67119a81c14SSteve Longerbeam 	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
67219a81c14SSteve Longerbeam 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
67319a81c14SSteve Longerbeam 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
6742b5c18f9SChen-Yu Tsai 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
67519a81c14SSteve Longerbeam 	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
67692b9096cSBenoit Parrot 	{0x4005, 0x1a, 0, 0},
67719a81c14SSteve Longerbeam };
67819a81c14SSteve Longerbeam 
679086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
680c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
68119a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
682ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
6833145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
68419a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
68519a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
68619a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
68719a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
68819a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6892b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
69019a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
69119a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
69219a81c14SSteve Longerbeam };
69319a81c14SSteve Longerbeam 
6945113d5b3SJacopo Mondi static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = {
6958409d017SJacopo Mondi 	{
6968409d017SJacopo Mondi 		/* 160x120 */
6973145efcdSJacopo Mondi 		.id		= OV5640_MODE_QQVGA_160_120,
6983145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6993145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7005113d5b3SJacopo Mondi 		.width		= 160,
7015113d5b3SJacopo Mondi 		.height		= 120,
7025113d5b3SJacopo Mondi 		.dvp_timings = {
7033145efcdSJacopo Mondi 			.analog_crop = {
7043145efcdSJacopo Mondi 				.left	= 0,
7053145efcdSJacopo Mondi 				.top	= 4,
7063145efcdSJacopo Mondi 				.width	= 2624,
7073145efcdSJacopo Mondi 				.height	= 1944,
7083145efcdSJacopo Mondi 			},
7093145efcdSJacopo Mondi 			.crop = {
7103145efcdSJacopo Mondi 				.left	= 16,
7113145efcdSJacopo Mondi 				.top	= 6,
7123145efcdSJacopo Mondi 				.width	= 160,
7133145efcdSJacopo Mondi 				.height	= 120,
7143145efcdSJacopo Mondi 			},
7153145efcdSJacopo Mondi 			.htot		= 1896,
7163145efcdSJacopo Mondi 			.vblank_def	= 864,
7175113d5b3SJacopo Mondi 		},
7185113d5b3SJacopo Mondi 		.csi2_timings = {
7195113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7205113d5b3SJacopo Mondi 			.analog_crop = {
7215113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7225113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7235113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7245113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7255113d5b3SJacopo Mondi 			},
7265113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7275113d5b3SJacopo Mondi 			.crop = {
7285113d5b3SJacopo Mondi 				.left	= 2,
7295113d5b3SJacopo Mondi 				.top	= 4,
7305113d5b3SJacopo Mondi 				.width	= 160,
7315113d5b3SJacopo Mondi 				.height	= 120,
7325113d5b3SJacopo Mondi 			},
733961bed9fSJacopo Mondi 			.htot		= 1600,
734961bed9fSJacopo Mondi 			.vblank_def	= 878,
7355113d5b3SJacopo Mondi 		},
736db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
737db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
73819f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
73919f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7408409d017SJacopo Mondi 	}, {
7418409d017SJacopo Mondi 		/* 176x144 */
7423145efcdSJacopo Mondi 		.id		= OV5640_MODE_QCIF_176_144,
7433145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7443145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7455113d5b3SJacopo Mondi 		.width		= 176,
7465113d5b3SJacopo Mondi 		.height		= 144,
7475113d5b3SJacopo Mondi 		.dvp_timings = {
7483145efcdSJacopo Mondi 			.analog_crop = {
7493145efcdSJacopo Mondi 				.left	= 0,
7503145efcdSJacopo Mondi 				.top	= 4,
7513145efcdSJacopo Mondi 				.width	= 2624,
7523145efcdSJacopo Mondi 				.height	= 1944,
7533145efcdSJacopo Mondi 			},
7543145efcdSJacopo Mondi 			.crop = {
7553145efcdSJacopo Mondi 				.left	= 16,
7563145efcdSJacopo Mondi 				.top	= 6,
7573145efcdSJacopo Mondi 				.width	= 176,
7583145efcdSJacopo Mondi 				.height	= 144,
7593145efcdSJacopo Mondi 			},
7603145efcdSJacopo Mondi 			.htot		= 1896,
7613145efcdSJacopo Mondi 			.vblank_def	= 840,
7625113d5b3SJacopo Mondi 		},
7635113d5b3SJacopo Mondi 		.csi2_timings = {
7645113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7655113d5b3SJacopo Mondi 			.analog_crop = {
7665113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7675113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7685113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7695113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7705113d5b3SJacopo Mondi 			},
7715113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7725113d5b3SJacopo Mondi 			.crop = {
7735113d5b3SJacopo Mondi 				.left	= 2,
7745113d5b3SJacopo Mondi 				.top	= 4,
7755113d5b3SJacopo Mondi 				.width	= 176,
7765113d5b3SJacopo Mondi 				.height	= 144,
7775113d5b3SJacopo Mondi 			},
778961bed9fSJacopo Mondi 			.htot		= 1600,
779961bed9fSJacopo Mondi 			.vblank_def	= 854,
7805113d5b3SJacopo Mondi 		},
781db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
782db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
78319f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
78419f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7858409d017SJacopo Mondi 	}, {
7868409d017SJacopo Mondi 		/* 320x240 */
7873145efcdSJacopo Mondi 		.id		= OV5640_MODE_QVGA_320_240,
7883145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7895113d5b3SJacopo Mondi 		.width		= 320,
7905113d5b3SJacopo Mondi 		.height		= 240,
7913145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7925113d5b3SJacopo Mondi 		.dvp_timings = {
7933145efcdSJacopo Mondi 			.analog_crop = {
7943145efcdSJacopo Mondi 				.left	= 0,
7953145efcdSJacopo Mondi 				.top	= 4,
7963145efcdSJacopo Mondi 				.width	= 2624,
7973145efcdSJacopo Mondi 				.height	= 1944,
7983145efcdSJacopo Mondi 			},
7993145efcdSJacopo Mondi 			.crop = {
8003145efcdSJacopo Mondi 				.left	= 16,
8013145efcdSJacopo Mondi 				.top	= 6,
8023145efcdSJacopo Mondi 				.width	= 320,
8033145efcdSJacopo Mondi 				.height	= 240,
8043145efcdSJacopo Mondi 			},
8053145efcdSJacopo Mondi 			.htot		= 1896,
8063145efcdSJacopo Mondi 			.vblank_def	= 744,
8075113d5b3SJacopo Mondi 		},
8085113d5b3SJacopo Mondi 		.csi2_timings = {
8095113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8105113d5b3SJacopo Mondi 			.analog_crop = {
8115113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8125113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8135113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8145113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8155113d5b3SJacopo Mondi 			},
8165113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
8175113d5b3SJacopo Mondi 			.crop = {
8185113d5b3SJacopo Mondi 				.left	= 2,
8195113d5b3SJacopo Mondi 				.top	= 4,
8205113d5b3SJacopo Mondi 				.width	= 320,
8215113d5b3SJacopo Mondi 				.height	= 240,
8225113d5b3SJacopo Mondi 			},
823961bed9fSJacopo Mondi 			.htot		= 1600,
824961bed9fSJacopo Mondi 			.vblank_def	= 760,
8255113d5b3SJacopo Mondi 		},
826db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
827db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
82819f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
82919f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8308409d017SJacopo Mondi 	}, {
8318409d017SJacopo Mondi 		/* 640x480 */
8323145efcdSJacopo Mondi 		.id		= OV5640_MODE_VGA_640_480,
8333145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8343145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
8355113d5b3SJacopo Mondi 		.width		= 640,
8365113d5b3SJacopo Mondi 		.height		= 480,
8375113d5b3SJacopo Mondi 		.dvp_timings = {
8383145efcdSJacopo Mondi 			.analog_crop = {
8393145efcdSJacopo Mondi 				.left	= 0,
8403145efcdSJacopo Mondi 				.top	= 4,
8413145efcdSJacopo Mondi 				.width	= 2624,
8423145efcdSJacopo Mondi 				.height	= 1944,
8433145efcdSJacopo Mondi 			},
8443145efcdSJacopo Mondi 			.crop = {
8453145efcdSJacopo Mondi 				.left	= 16,
8463145efcdSJacopo Mondi 				.top	= 6,
8473145efcdSJacopo Mondi 				.width	= 640,
8483145efcdSJacopo Mondi 				.height	= 480,
8493145efcdSJacopo Mondi 			},
8503145efcdSJacopo Mondi 			.htot		= 1896,
8513145efcdSJacopo Mondi 			.vblank_def	= 600,
8525113d5b3SJacopo Mondi 		},
8535113d5b3SJacopo Mondi 		.csi2_timings = {
8545113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8555113d5b3SJacopo Mondi 			.analog_crop = {
8565113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8575113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8585113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8595113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8605113d5b3SJacopo Mondi 			},
8615113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
8625113d5b3SJacopo Mondi 			.crop = {
8635113d5b3SJacopo Mondi 				.left	= 2,
8645113d5b3SJacopo Mondi 				.top	= 4,
8655113d5b3SJacopo Mondi 				.width	= 640,
8665113d5b3SJacopo Mondi 				.height	= 480,
8675113d5b3SJacopo Mondi 			},
868961bed9fSJacopo Mondi 			.htot		= 1600,
869961bed9fSJacopo Mondi 			.vblank_def	= 520,
8705113d5b3SJacopo Mondi 		},
871db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
872db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
87319f2e3e6SHugues Fruchet 		.max_fps	= OV5640_60_FPS,
87419f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8758409d017SJacopo Mondi 	}, {
8768409d017SJacopo Mondi 		/* 720x480 */
8773145efcdSJacopo Mondi 		.id		= OV5640_MODE_NTSC_720_480,
8783145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8795113d5b3SJacopo Mondi 		.width		= 720,
8805113d5b3SJacopo Mondi 		.height		= 480,
8813145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8825113d5b3SJacopo Mondi 		.dvp_timings = {
8833145efcdSJacopo Mondi 			.analog_crop = {
8843145efcdSJacopo Mondi 				.left	= 0,
8853145efcdSJacopo Mondi 				.top	= 4,
8863145efcdSJacopo Mondi 				.width	= 2624,
8873145efcdSJacopo Mondi 				.height	= 1944,
8883145efcdSJacopo Mondi 			},
8893145efcdSJacopo Mondi 			.crop = {
890e74ef55bSJacopo Mondi 				.left	= 56,
8913145efcdSJacopo Mondi 				.top	= 60,
8923145efcdSJacopo Mondi 				.width	= 720,
8933145efcdSJacopo Mondi 				.height	= 480,
8943145efcdSJacopo Mondi 			},
8953145efcdSJacopo Mondi 			.htot		= 1896,
8963145efcdSJacopo Mondi 			.vblank_def	= 504,
8975113d5b3SJacopo Mondi 		},
8985113d5b3SJacopo Mondi 		.csi2_timings = {
8995113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
9005113d5b3SJacopo Mondi 			.analog_crop = {
9015113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
9025113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
9035113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
9045113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
9055113d5b3SJacopo Mondi 			},
9065113d5b3SJacopo Mondi 			.crop = {
9075113d5b3SJacopo Mondi 				.left	= 56,
9085113d5b3SJacopo Mondi 				.top	= 60,
9095113d5b3SJacopo Mondi 				.width	= 720,
9105113d5b3SJacopo Mondi 				.height	= 480,
9115113d5b3SJacopo Mondi 			},
9125113d5b3SJacopo Mondi 			.htot		= 1896,
913961bed9fSJacopo Mondi 			.vblank_def	= 1206,
9145113d5b3SJacopo Mondi 		},
915db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
916db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
91719f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
91819f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9198409d017SJacopo Mondi 	}, {
9208409d017SJacopo Mondi 		/* 720x576 */
9213145efcdSJacopo Mondi 		.id		= OV5640_MODE_PAL_720_576,
9223145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
9235113d5b3SJacopo Mondi 		.width		= 720,
9245113d5b3SJacopo Mondi 		.height		= 576,
9253145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
9265113d5b3SJacopo Mondi 		.dvp_timings = {
9273145efcdSJacopo Mondi 			.analog_crop = {
9283145efcdSJacopo Mondi 				.left	= 0,
9293145efcdSJacopo Mondi 				.top	= 4,
9303145efcdSJacopo Mondi 				.width	= 2624,
9313145efcdSJacopo Mondi 				.height	= 1944,
9323145efcdSJacopo Mondi 			},
9333145efcdSJacopo Mondi 			.crop = {
9343145efcdSJacopo Mondi 				.left	= 56,
9353145efcdSJacopo Mondi 				.top	= 6,
9363145efcdSJacopo Mondi 				.width	= 720,
9373145efcdSJacopo Mondi 				.height	= 576,
9383145efcdSJacopo Mondi 			},
9393145efcdSJacopo Mondi 			.htot		= 1896,
9403145efcdSJacopo Mondi 			.vblank_def	= 408,
9415113d5b3SJacopo Mondi 		},
9425113d5b3SJacopo Mondi 		.csi2_timings = {
9435113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
9445113d5b3SJacopo Mondi 			.analog_crop = {
9455113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
9465113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
9475113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
9485113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
9495113d5b3SJacopo Mondi 			},
9505113d5b3SJacopo Mondi 			.crop = {
9515113d5b3SJacopo Mondi 				.left	= 56,
9525113d5b3SJacopo Mondi 				.top	= 6,
9535113d5b3SJacopo Mondi 				.width	= 720,
9545113d5b3SJacopo Mondi 				.height	= 576,
9555113d5b3SJacopo Mondi 			},
9565113d5b3SJacopo Mondi 			.htot		= 1896,
957961bed9fSJacopo Mondi 			.vblank_def	= 1110,
9585113d5b3SJacopo Mondi 		},
959db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
960db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
96119f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
96219f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9638409d017SJacopo Mondi 	}, {
9648409d017SJacopo Mondi 		/* 1024x768 */
9653145efcdSJacopo Mondi 		.id		= OV5640_MODE_XGA_1024_768,
9663145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
9673145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
9685113d5b3SJacopo Mondi 		.width		= 1024,
9695113d5b3SJacopo Mondi 		.height		= 768,
9705113d5b3SJacopo Mondi 		.dvp_timings = {
9713145efcdSJacopo Mondi 			.analog_crop = {
9723145efcdSJacopo Mondi 				.left	= 0,
9733145efcdSJacopo Mondi 				.top	= 4,
9743145efcdSJacopo Mondi 				.width	= 2624,
9753145efcdSJacopo Mondi 				.height	= 1944,
9763145efcdSJacopo Mondi 			},
9773145efcdSJacopo Mondi 			.crop = {
9783145efcdSJacopo Mondi 				.left	= 16,
9793145efcdSJacopo Mondi 				.top	= 6,
9803145efcdSJacopo Mondi 				.width	= 1024,
9813145efcdSJacopo Mondi 				.height	= 768,
9823145efcdSJacopo Mondi 			},
9833145efcdSJacopo Mondi 			.htot		= 1896,
9843145efcdSJacopo Mondi 			.vblank_def	= 312,
9855113d5b3SJacopo Mondi 		},
9865113d5b3SJacopo Mondi 		.csi2_timings = {
9875113d5b3SJacopo Mondi 			.analog_crop = {
9885113d5b3SJacopo Mondi 				.left	= 0,
9895113d5b3SJacopo Mondi 				.top	= 4,
9905113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
9915113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
9925113d5b3SJacopo Mondi 			},
9935113d5b3SJacopo Mondi 			.crop = {
9945113d5b3SJacopo Mondi 				.left	= 16,
9955113d5b3SJacopo Mondi 				.top	= 6,
9965113d5b3SJacopo Mondi 				.width	= 1024,
9975113d5b3SJacopo Mondi 				.height	= 768,
9985113d5b3SJacopo Mondi 			},
9995113d5b3SJacopo Mondi 			.htot		= 1896,
1000961bed9fSJacopo Mondi 			.vblank_def	= 918,
10015113d5b3SJacopo Mondi 		},
1002db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
1003db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
100419f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
100519f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
10068409d017SJacopo Mondi 	}, {
10078409d017SJacopo Mondi 		/* 1280x720 */
10083145efcdSJacopo Mondi 		.id		= OV5640_MODE_720P_1280_720,
10093145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
10103145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_124M,
10115113d5b3SJacopo Mondi 		.width		= 1280,
10125113d5b3SJacopo Mondi 		.height		= 720,
10135113d5b3SJacopo Mondi 		.dvp_timings = {
10143145efcdSJacopo Mondi 			.analog_crop = {
10153145efcdSJacopo Mondi 				.left	= 0,
10163145efcdSJacopo Mondi 				.top	= 250,
10173145efcdSJacopo Mondi 				.width	= 2624,
10183145efcdSJacopo Mondi 				.height	= 1456,
10193145efcdSJacopo Mondi 			},
10203145efcdSJacopo Mondi 			.crop = {
10213145efcdSJacopo Mondi 				.left	= 16,
10223145efcdSJacopo Mondi 				.top	= 4,
10233145efcdSJacopo Mondi 				.width	= 1280,
10243145efcdSJacopo Mondi 				.height	= 720,
10253145efcdSJacopo Mondi 			},
10263145efcdSJacopo Mondi 			.htot		= 1892,
10273145efcdSJacopo Mondi 			.vblank_def	= 20,
10285113d5b3SJacopo Mondi 		},
10295113d5b3SJacopo Mondi 		.csi2_timings = {
10305113d5b3SJacopo Mondi 			.analog_crop = {
10315113d5b3SJacopo Mondi 				.left	= 0,
10325113d5b3SJacopo Mondi 				.top	= 250,
10335113d5b3SJacopo Mondi 				.width	= 2624,
10345113d5b3SJacopo Mondi 				.height	= 1456,
10355113d5b3SJacopo Mondi 			},
10365113d5b3SJacopo Mondi 			.crop = {
10375113d5b3SJacopo Mondi 				.left	= 16,
10385113d5b3SJacopo Mondi 				.top	= 4,
10395113d5b3SJacopo Mondi 				.width	= 1280,
10405113d5b3SJacopo Mondi 				.height	= 720,
10415113d5b3SJacopo Mondi 			},
1042961bed9fSJacopo Mondi 			.htot		= 1600,
1043961bed9fSJacopo Mondi 			.vblank_def	= 560,
10445113d5b3SJacopo Mondi 		},
10453145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_720P_1280_720,
10463145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_720P_1280_720),
104719f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
104819f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
10498409d017SJacopo Mondi 	}, {
10508409d017SJacopo Mondi 		/* 1920x1080 */
10513145efcdSJacopo Mondi 		.id		= OV5640_MODE_1080P_1920_1080,
10523145efcdSJacopo Mondi 		.dn_mode	= SCALING,
10533145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_148M,
10545113d5b3SJacopo Mondi 		.width		= 1920,
10555113d5b3SJacopo Mondi 		.height		= 1080,
10565113d5b3SJacopo Mondi 		.dvp_timings = {
10573145efcdSJacopo Mondi 			.analog_crop = {
10583145efcdSJacopo Mondi 				.left	= 336,
10593145efcdSJacopo Mondi 				.top	= 434,
10603145efcdSJacopo Mondi 				.width	= 1952,
10613145efcdSJacopo Mondi 				.height	= 1088,
10623145efcdSJacopo Mondi 			},
10633145efcdSJacopo Mondi 			.crop = {
10643145efcdSJacopo Mondi 				.left	= 16,
10653145efcdSJacopo Mondi 				.top	= 4,
10663145efcdSJacopo Mondi 				.width	= 1920,
10673145efcdSJacopo Mondi 				.height	= 1080,
10683145efcdSJacopo Mondi 			},
10693145efcdSJacopo Mondi 			.htot		= 2500,
10703145efcdSJacopo Mondi 			.vblank_def	= 40,
10715113d5b3SJacopo Mondi 		},
10725113d5b3SJacopo Mondi 		.csi2_timings = {
10735113d5b3SJacopo Mondi 			/* Crop the full valid pixel array in the center. */
10745113d5b3SJacopo Mondi 			.analog_crop = {
10755113d5b3SJacopo Mondi 				.left	= 336,
10765113d5b3SJacopo Mondi 				.top	= 434,
10775113d5b3SJacopo Mondi 				.width	= 1952,
10785113d5b3SJacopo Mondi 				.height	= 1088,
10795113d5b3SJacopo Mondi 			},
10805113d5b3SJacopo Mondi 			/* Maintain a larger processing margins. */
10815113d5b3SJacopo Mondi 			.crop = {
10825113d5b3SJacopo Mondi 				.left	= 16,
10835113d5b3SJacopo Mondi 				.top	= 4,
10845113d5b3SJacopo Mondi 				.width	= 1920,
10855113d5b3SJacopo Mondi 				.height	= 1080,
10865113d5b3SJacopo Mondi 			},
1087961bed9fSJacopo Mondi 			.htot		= 2234,
1088961bed9fSJacopo Mondi 			.vblank_def	= 24,
10895113d5b3SJacopo Mondi 		},
10903145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_1080P_1920_1080,
10913145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
109219f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
109319f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
10948409d017SJacopo Mondi 	}, {
10958409d017SJacopo Mondi 		/* 2592x1944 */
10963145efcdSJacopo Mondi 		.id		= OV5640_MODE_QSXGA_2592_1944,
10973145efcdSJacopo Mondi 		.dn_mode	= SCALING,
10983145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_168M,
10995113d5b3SJacopo Mondi 		.width		= OV5640_PIXEL_ARRAY_WIDTH,
11005113d5b3SJacopo Mondi 		.height		= OV5640_PIXEL_ARRAY_HEIGHT,
11015113d5b3SJacopo Mondi 		.dvp_timings = {
11023145efcdSJacopo Mondi 			.analog_crop = {
11033145efcdSJacopo Mondi 				.left	= 0,
11043145efcdSJacopo Mondi 				.top	= 0,
11053145efcdSJacopo Mondi 				.width	= 2624,
11063145efcdSJacopo Mondi 				.height	= 1952,
11073145efcdSJacopo Mondi 			},
11083145efcdSJacopo Mondi 			.crop = {
11093145efcdSJacopo Mondi 				.left	= 16,
11103145efcdSJacopo Mondi 				.top	= 4,
11113145efcdSJacopo Mondi 				.width	= 2592,
11123145efcdSJacopo Mondi 				.height	= 1944,
11133145efcdSJacopo Mondi 			},
11143145efcdSJacopo Mondi 			.htot		= 2844,
11153145efcdSJacopo Mondi 			.vblank_def	= 24,
11165113d5b3SJacopo Mondi 		},
11175113d5b3SJacopo Mondi 		.csi2_timings = {
11185113d5b3SJacopo Mondi 			/* Give more processing margin to full resolution. */
11195113d5b3SJacopo Mondi 			.analog_crop = {
11205113d5b3SJacopo Mondi 				.left	= 0,
11215113d5b3SJacopo Mondi 				.top	= 0,
11225113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
11235113d5b3SJacopo Mondi 				.height	= 1952,
11245113d5b3SJacopo Mondi 			},
11255113d5b3SJacopo Mondi 			.crop = {
11265113d5b3SJacopo Mondi 				.left	= 16,
11275113d5b3SJacopo Mondi 				.top	= 4,
11285113d5b3SJacopo Mondi 				.width	= 2592,
11295113d5b3SJacopo Mondi 				.height	= 1944,
11305113d5b3SJacopo Mondi 			},
11315113d5b3SJacopo Mondi 			.htot		= 2844,
11325113d5b3SJacopo Mondi 			.vblank_def	= 24,
11335113d5b3SJacopo Mondi 		},
11343145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QSXGA_2592_1944,
11353145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
113619f2e3e6SHugues Fruchet 		.max_fps	= OV5640_15_FPS,
113719f2e3e6SHugues Fruchet 		.def_fps	= OV5640_15_FPS
11388409d017SJacopo Mondi 	},
113919a81c14SSteve Longerbeam };
114019a81c14SSteve Longerbeam 
11412de6bb97SJacopo Mondi static const struct ov5640_timings *
11422de6bb97SJacopo Mondi ov5640_timings(const struct ov5640_dev *sensor,
11432de6bb97SJacopo Mondi 	       const struct ov5640_mode_info *mode)
11442de6bb97SJacopo Mondi {
11452de6bb97SJacopo Mondi 	if (ov5640_is_csi2(sensor))
11462de6bb97SJacopo Mondi 		return &mode->csi2_timings;
11472de6bb97SJacopo Mondi 
11482de6bb97SJacopo Mondi 	return &mode->dvp_timings;
11492de6bb97SJacopo Mondi }
11502de6bb97SJacopo Mondi 
115119a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor)
115219a81c14SSteve Longerbeam {
115319a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
115419a81c14SSteve Longerbeam 	struct i2c_msg msg;
115519a81c14SSteve Longerbeam 	u8 buf[3];
115619a81c14SSteve Longerbeam 	int ret;
115719a81c14SSteve Longerbeam 
115819a81c14SSteve Longerbeam 	if (client->addr == OV5640_DEFAULT_SLAVE_ID)
115919a81c14SSteve Longerbeam 		return 0;
116019a81c14SSteve Longerbeam 
116119a81c14SSteve Longerbeam 	buf[0] = OV5640_REG_SLAVE_ID >> 8;
116219a81c14SSteve Longerbeam 	buf[1] = OV5640_REG_SLAVE_ID & 0xff;
116319a81c14SSteve Longerbeam 	buf[2] = client->addr << 1;
116419a81c14SSteve Longerbeam 
116519a81c14SSteve Longerbeam 	msg.addr = OV5640_DEFAULT_SLAVE_ID;
116619a81c14SSteve Longerbeam 	msg.flags = 0;
116719a81c14SSteve Longerbeam 	msg.buf = buf;
116819a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
116919a81c14SSteve Longerbeam 
117019a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
117119a81c14SSteve Longerbeam 	if (ret < 0) {
117219a81c14SSteve Longerbeam 		dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
117319a81c14SSteve Longerbeam 		return ret;
117419a81c14SSteve Longerbeam 	}
117519a81c14SSteve Longerbeam 
117619a81c14SSteve Longerbeam 	return 0;
117719a81c14SSteve Longerbeam }
117819a81c14SSteve Longerbeam 
117919a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
118019a81c14SSteve Longerbeam {
118119a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
118219a81c14SSteve Longerbeam 	struct i2c_msg msg;
118319a81c14SSteve Longerbeam 	u8 buf[3];
118419a81c14SSteve Longerbeam 	int ret;
118519a81c14SSteve Longerbeam 
118619a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
118719a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
118819a81c14SSteve Longerbeam 	buf[2] = val;
118919a81c14SSteve Longerbeam 
119019a81c14SSteve Longerbeam 	msg.addr = client->addr;
119119a81c14SSteve Longerbeam 	msg.flags = client->flags;
119219a81c14SSteve Longerbeam 	msg.buf = buf;
119319a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
119419a81c14SSteve Longerbeam 
119519a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
119619a81c14SSteve Longerbeam 	if (ret < 0) {
11973924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
119819a81c14SSteve Longerbeam 			__func__, reg, val);
119919a81c14SSteve Longerbeam 		return ret;
120019a81c14SSteve Longerbeam 	}
120119a81c14SSteve Longerbeam 
120219a81c14SSteve Longerbeam 	return 0;
120319a81c14SSteve Longerbeam }
120419a81c14SSteve Longerbeam 
120519a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
120619a81c14SSteve Longerbeam {
120719a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
120819a81c14SSteve Longerbeam 	struct i2c_msg msg[2];
120919a81c14SSteve Longerbeam 	u8 buf[2];
121019a81c14SSteve Longerbeam 	int ret;
121119a81c14SSteve Longerbeam 
121219a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
121319a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
121419a81c14SSteve Longerbeam 
121519a81c14SSteve Longerbeam 	msg[0].addr = client->addr;
121619a81c14SSteve Longerbeam 	msg[0].flags = client->flags;
121719a81c14SSteve Longerbeam 	msg[0].buf = buf;
121819a81c14SSteve Longerbeam 	msg[0].len = sizeof(buf);
121919a81c14SSteve Longerbeam 
122019a81c14SSteve Longerbeam 	msg[1].addr = client->addr;
122119a81c14SSteve Longerbeam 	msg[1].flags = client->flags | I2C_M_RD;
122219a81c14SSteve Longerbeam 	msg[1].buf = buf;
122319a81c14SSteve Longerbeam 	msg[1].len = 1;
122419a81c14SSteve Longerbeam 
122519a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, msg, 2);
12263924c623SHugues Fruchet 	if (ret < 0) {
12273924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x\n",
12283924c623SHugues Fruchet 			__func__, reg);
122919a81c14SSteve Longerbeam 		return ret;
12303924c623SHugues Fruchet 	}
123119a81c14SSteve Longerbeam 
123219a81c14SSteve Longerbeam 	*val = buf[0];
123319a81c14SSteve Longerbeam 	return 0;
123419a81c14SSteve Longerbeam }
123519a81c14SSteve Longerbeam 
123619a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
123719a81c14SSteve Longerbeam {
123819a81c14SSteve Longerbeam 	u8 hi, lo;
123919a81c14SSteve Longerbeam 	int ret;
124019a81c14SSteve Longerbeam 
124119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &hi);
124219a81c14SSteve Longerbeam 	if (ret)
124319a81c14SSteve Longerbeam 		return ret;
124419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg + 1, &lo);
124519a81c14SSteve Longerbeam 	if (ret)
124619a81c14SSteve Longerbeam 		return ret;
124719a81c14SSteve Longerbeam 
124819a81c14SSteve Longerbeam 	*val = ((u16)hi << 8) | (u16)lo;
124919a81c14SSteve Longerbeam 	return 0;
125019a81c14SSteve Longerbeam }
125119a81c14SSteve Longerbeam 
125219a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
125319a81c14SSteve Longerbeam {
125419a81c14SSteve Longerbeam 	int ret;
125519a81c14SSteve Longerbeam 
125619a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, reg, val >> 8);
125719a81c14SSteve Longerbeam 	if (ret)
125819a81c14SSteve Longerbeam 		return ret;
125919a81c14SSteve Longerbeam 
126019a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg + 1, val & 0xff);
126119a81c14SSteve Longerbeam }
126219a81c14SSteve Longerbeam 
126319a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
126419a81c14SSteve Longerbeam 			  u8 mask, u8 val)
126519a81c14SSteve Longerbeam {
126619a81c14SSteve Longerbeam 	u8 readval;
126719a81c14SSteve Longerbeam 	int ret;
126819a81c14SSteve Longerbeam 
126919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &readval);
127019a81c14SSteve Longerbeam 	if (ret)
127119a81c14SSteve Longerbeam 		return ret;
127219a81c14SSteve Longerbeam 
127319a81c14SSteve Longerbeam 	readval &= ~mask;
127419a81c14SSteve Longerbeam 	val &= mask;
127519a81c14SSteve Longerbeam 	val |= readval;
127619a81c14SSteve Longerbeam 
127719a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg, val);
127819a81c14SSteve Longerbeam }
127919a81c14SSteve Longerbeam 
1280aa288248SMaxime Ripard /*
1281aa288248SMaxime Ripard  * After trying the various combinations, reading various
1282f8a7647dSMauro Carvalho Chehab  * documentations spread around the net, and from the various
1283aa288248SMaxime Ripard  * feedback, the clock tree is probably as follows:
1284aa288248SMaxime Ripard  *
1285aa288248SMaxime Ripard  *   +--------------+
1286aa288248SMaxime Ripard  *   |  Ext. Clock  |
1287aa288248SMaxime Ripard  *   +-+------------+
1288aa288248SMaxime Ripard  *     |  +----------+
1289aa288248SMaxime Ripard  *     +->|   PLL1   | - reg 0x3036, for the multiplier
1290aa288248SMaxime Ripard  *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
1291aa288248SMaxime Ripard  *          |  +--------------+
1292aa288248SMaxime Ripard  *          +->| System Clock |  - reg 0x3035, bits 4-7
1293aa288248SMaxime Ripard  *             +-+------------+
1294aa288248SMaxime Ripard  *               |  +--------------+
1295aa288248SMaxime Ripard  *               +->| MIPI Divider | - reg 0x3035, bits 0-3
1296aa288248SMaxime Ripard  *               |  +-+------------+
1297aa288248SMaxime Ripard  *               |    +----------------> MIPI SCLK
1298aa288248SMaxime Ripard  *               |    +  +-----+
1299aa288248SMaxime Ripard  *               |    +->| / 2 |-------> MIPI BIT CLK
1300aa288248SMaxime Ripard  *               |       +-----+
1301aa288248SMaxime Ripard  *               |  +--------------+
1302aa288248SMaxime Ripard  *               +->| PLL Root Div | - reg 0x3037, bit 4
1303aa288248SMaxime Ripard  *                  +-+------------+
1304aa288248SMaxime Ripard  *                    |  +---------+
13054c85f628SPaul Kocialkowski  *                    +->| Bit Div | - reg 0x3034, bits 0-3
1306aa288248SMaxime Ripard  *                       +-+-------+
1307aa288248SMaxime Ripard  *                         |  +-------------+
1308aa288248SMaxime Ripard  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
1309aa288248SMaxime Ripard  *                         |  +-+-----------+
1310aa288248SMaxime Ripard  *                         |    +---------------> SCLK
1311aa288248SMaxime Ripard  *                         |  +-------------+
1312aa288248SMaxime Ripard  *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
1313aa288248SMaxime Ripard  *                         |  +-+-----------+
1314aa288248SMaxime Ripard  *                         |    +---------------> SCLK 2X
1315aa288248SMaxime Ripard  *                         |  +-------------+
1316aa288248SMaxime Ripard  *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
1317aa288248SMaxime Ripard  *                            ++------------+
1318aa288248SMaxime Ripard  *                             +  +-----------+
1319aa288248SMaxime Ripard  *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
1320aa288248SMaxime Ripard  *                                +-----+-----+
1321aa288248SMaxime Ripard  *                                       +------------> PCLK
1322aa288248SMaxime Ripard  *
13236c957ed7SJacopo Mondi  * There seems to be also constraints:
1324aa288248SMaxime Ripard  *  - the PLL pre-divider output rate should be in the 4-27MHz range
1325aa288248SMaxime Ripard  *  - the PLL multiplier output rate should be in the 500-1000MHz range
1326aa288248SMaxime Ripard  *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
1327aa288248SMaxime Ripard  */
1328aa288248SMaxime Ripard 
1329aa288248SMaxime Ripard /*
1330aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1331aa288248SMaxime Ripard  * set to 3 in the vendor kernels.
1332aa288248SMaxime Ripard  */
1333aa288248SMaxime Ripard #define OV5640_PLL_PREDIV	3
1334aa288248SMaxime Ripard 
1335aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN	4
1336aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX	252
1337aa288248SMaxime Ripard 
1338aa288248SMaxime Ripard /*
1339aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 16, but the value is
1340aa288248SMaxime Ripard  * always set to either 1 or 2 in the vendor kernels.
1341aa288248SMaxime Ripard  */
1342aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN	1
1343aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX	16
1344aa288248SMaxime Ripard 
1345aa288248SMaxime Ripard /*
1346aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 2, but the value is always
1347aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1348aa288248SMaxime Ripard  */
1349aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV			2
1350aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2		BIT(4)
1351aa288248SMaxime Ripard 
1352aa288248SMaxime Ripard /*
1353aa288248SMaxime Ripard  * We only supports 8-bit formats at the moment
1354aa288248SMaxime Ripard  */
1355aa288248SMaxime Ripard #define OV5640_BIT_DIV				2
1356aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT		0x08
1357aa288248SMaxime Ripard 
1358aa288248SMaxime Ripard /*
1359aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1360aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1361aa288248SMaxime Ripard  */
1362aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV	2
1363aa288248SMaxime Ripard 
1364aa288248SMaxime Ripard /*
1365aa288248SMaxime Ripard  * This is hardcoded so that the consistency is maintained between SCLK and
1366aa288248SMaxime Ripard  * SCLK 2x.
1367aa288248SMaxime Ripard  */
1368aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
1369aa288248SMaxime Ripard 
1370aa288248SMaxime Ripard /*
1371aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1372aa288248SMaxime Ripard  * set to 1 in the vendor kernels.
1373aa288248SMaxime Ripard  */
1374aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV			1
1375aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS	0x00
1376aa288248SMaxime Ripard 
1377aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
1378aa288248SMaxime Ripard 					    u8 pll_prediv, u8 pll_mult,
1379aa288248SMaxime Ripard 					    u8 sysdiv)
1380aa288248SMaxime Ripard {
1381aa288248SMaxime Ripard 	unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
1382aa288248SMaxime Ripard 
1383aa288248SMaxime Ripard 	/* PLL1 output cannot exceed 1GHz. */
1384aa288248SMaxime Ripard 	if (sysclk / 1000000 > 1000)
1385aa288248SMaxime Ripard 		return 0;
1386aa288248SMaxime Ripard 
1387aa288248SMaxime Ripard 	return sysclk / sysdiv;
1388aa288248SMaxime Ripard }
1389aa288248SMaxime Ripard 
1390aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
1391aa288248SMaxime Ripard 					 unsigned long rate,
1392aa288248SMaxime Ripard 					 u8 *pll_prediv, u8 *pll_mult,
1393aa288248SMaxime Ripard 					 u8 *sysdiv)
1394aa288248SMaxime Ripard {
1395aa288248SMaxime Ripard 	unsigned long best = ~0;
1396aa288248SMaxime Ripard 	u8 best_sysdiv = 1, best_mult = 1;
1397aa288248SMaxime Ripard 	u8 _sysdiv, _pll_mult;
1398aa288248SMaxime Ripard 
1399aa288248SMaxime Ripard 	for (_sysdiv = OV5640_SYSDIV_MIN;
1400aa288248SMaxime Ripard 	     _sysdiv <= OV5640_SYSDIV_MAX;
1401aa288248SMaxime Ripard 	     _sysdiv++) {
1402aa288248SMaxime Ripard 		for (_pll_mult = OV5640_PLL_MULT_MIN;
1403aa288248SMaxime Ripard 		     _pll_mult <= OV5640_PLL_MULT_MAX;
1404aa288248SMaxime Ripard 		     _pll_mult++) {
1405aa288248SMaxime Ripard 			unsigned long _rate;
1406aa288248SMaxime Ripard 
1407aa288248SMaxime Ripard 			/*
1408aa288248SMaxime Ripard 			 * The PLL multiplier cannot be odd if above
1409aa288248SMaxime Ripard 			 * 127.
1410aa288248SMaxime Ripard 			 */
1411aa288248SMaxime Ripard 			if (_pll_mult > 127 && (_pll_mult % 2))
1412aa288248SMaxime Ripard 				continue;
1413aa288248SMaxime Ripard 
1414aa288248SMaxime Ripard 			_rate = ov5640_compute_sys_clk(sensor,
1415aa288248SMaxime Ripard 						       OV5640_PLL_PREDIV,
1416aa288248SMaxime Ripard 						       _pll_mult, _sysdiv);
1417aa288248SMaxime Ripard 
1418aa288248SMaxime Ripard 			/*
1419aa288248SMaxime Ripard 			 * We have reached the maximum allowed PLL1 output,
1420aa288248SMaxime Ripard 			 * increase sysdiv.
1421aa288248SMaxime Ripard 			 */
14222e3df204SAdam Ford 			if (!_rate)
1423aa288248SMaxime Ripard 				break;
1424aa288248SMaxime Ripard 
1425aa288248SMaxime Ripard 			/*
1426aa288248SMaxime Ripard 			 * Prefer rates above the expected clock rate than
1427aa288248SMaxime Ripard 			 * below, even if that means being less precise.
1428aa288248SMaxime Ripard 			 */
1429aa288248SMaxime Ripard 			if (_rate < rate)
1430aa288248SMaxime Ripard 				continue;
1431aa288248SMaxime Ripard 
1432aa288248SMaxime Ripard 			if (abs(rate - _rate) < abs(rate - best)) {
1433aa288248SMaxime Ripard 				best = _rate;
1434aa288248SMaxime Ripard 				best_sysdiv = _sysdiv;
1435aa288248SMaxime Ripard 				best_mult = _pll_mult;
1436aa288248SMaxime Ripard 			}
1437aa288248SMaxime Ripard 
1438aa288248SMaxime Ripard 			if (_rate == rate)
1439aa288248SMaxime Ripard 				goto out;
1440aa288248SMaxime Ripard 		}
1441aa288248SMaxime Ripard 	}
1442aa288248SMaxime Ripard 
1443aa288248SMaxime Ripard out:
1444aa288248SMaxime Ripard 	*sysdiv = best_sysdiv;
1445aa288248SMaxime Ripard 	*pll_prediv = OV5640_PLL_PREDIV;
1446aa288248SMaxime Ripard 	*pll_mult = best_mult;
1447aa288248SMaxime Ripard 
1448aa288248SMaxime Ripard 	return best;
1449aa288248SMaxime Ripard }
1450aa288248SMaxime Ripard 
1451aa288248SMaxime Ripard /*
1452aa288248SMaxime Ripard  * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
1453aa288248SMaxime Ripard  *			    for the MIPI CSI-2 output.
1454aa288248SMaxime Ripard  */
14556c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
1456aa288248SMaxime Ripard {
14576c957ed7SJacopo Mondi 	u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
1458aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv;
14596c957ed7SJacopo Mondi 	unsigned long link_freq;
14606c957ed7SJacopo Mondi 	unsigned long sysclk;
14616c957ed7SJacopo Mondi 	u8 pclk_period;
14626c957ed7SJacopo Mondi 	u32 sample_rate;
14636c957ed7SJacopo Mondi 	u32 num_lanes;
1464aa288248SMaxime Ripard 	int ret;
1465aa288248SMaxime Ripard 
14666c957ed7SJacopo Mondi 	/* Use the link freq computed at ov5640_update_pixel_rate() time. */
14676c957ed7SJacopo Mondi 	link_freq = sensor->current_link_freq;
14686c957ed7SJacopo Mondi 
1469aa288248SMaxime Ripard 	/*
14706c957ed7SJacopo Mondi 	 * - mipi_div - Additional divider for the MIPI lane clock.
14716c957ed7SJacopo Mondi 	 *
14726c957ed7SJacopo Mondi 	 * Higher link frequencies would make sysclk > 1GHz.
14736c957ed7SJacopo Mondi 	 * Keep the sysclk low and do not divide in the MIPI domain.
1474aa288248SMaxime Ripard 	 */
14756c957ed7SJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX)
14766c957ed7SJacopo Mondi 		mipi_div = 1;
1477aa288248SMaxime Ripard 	else
14786c957ed7SJacopo Mondi 		mipi_div = 2;
1479aa288248SMaxime Ripard 
14806c957ed7SJacopo Mondi 	sysclk = link_freq * mipi_div;
14816c957ed7SJacopo Mondi 	ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
1482aa288248SMaxime Ripard 
14836c957ed7SJacopo Mondi 	/*
14846c957ed7SJacopo Mondi 	 * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio.
14856c957ed7SJacopo Mondi 	 *
14866c957ed7SJacopo Mondi 	 * - root_div = 2 (fixed)
14876c957ed7SJacopo Mondi 	 * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5
14886c957ed7SJacopo Mondi 	 * - pclk_div = 1 (fixed)
14896c957ed7SJacopo Mondi 	 * - p_div  = (2 lanes ? mipi_div : 2 * mipi_div)
14906c957ed7SJacopo Mondi 	 *
14916c957ed7SJacopo Mondi 	 * This results in the following MIPI_SCLK depending on the number
14926c957ed7SJacopo Mondi 	 * of lanes:
14936c957ed7SJacopo Mondi 	 *
14946c957ed7SJacopo Mondi 	 * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK
14956c957ed7SJacopo Mondi 	 * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK
14966c957ed7SJacopo Mondi 	 */
14976c957ed7SJacopo Mondi 	root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
14986c957ed7SJacopo Mondi 	bit_div =  OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
14996c957ed7SJacopo Mondi 	pclk_div = ilog2(OV5640_PCLK_ROOT_DIV);
1500aa288248SMaxime Ripard 
15016c957ed7SJacopo Mondi 	/*
15026c957ed7SJacopo Mondi 	 * Scaler clock:
15036c957ed7SJacopo Mondi 	 * - YUV: PCLK >= 2 * SCLK
15046c957ed7SJacopo Mondi 	 * - RAW or JPEG: PCLK >= SCLK
15056c957ed7SJacopo Mondi 	 * - sclk2x_div = sclk_div / 2
15066c957ed7SJacopo Mondi 	 */
15076c957ed7SJacopo Mondi 	sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
15086c957ed7SJacopo Mondi 	sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
15096c957ed7SJacopo Mondi 
15106c957ed7SJacopo Mondi 	/*
15116c957ed7SJacopo Mondi 	 * Set the pixel clock period expressed in ns with 1-bit decimal
15126c957ed7SJacopo Mondi 	 * (0x01=0.5ns).
15136c957ed7SJacopo Mondi 	 *
15146c957ed7SJacopo Mondi 	 * The register is very briefly documented. In the OV5645 datasheet it
15156c957ed7SJacopo Mondi 	 * is described as (2 * pclk period), and from testing it seems the
15166c957ed7SJacopo Mondi 	 * actual definition is 2 * 8-bit sample period.
15176c957ed7SJacopo Mondi 	 *
15186c957ed7SJacopo Mondi 	 * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2
15196c957ed7SJacopo Mondi 	 */
15206c957ed7SJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
15216c957ed7SJacopo Mondi 	sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16;
15226c957ed7SJacopo Mondi 	pclk_period = 2000000000UL / sample_rate;
15236c957ed7SJacopo Mondi 
15246c957ed7SJacopo Mondi 	/* Program the clock tree registers. */
15256c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
15266c957ed7SJacopo Mondi 	if (ret)
15276c957ed7SJacopo Mondi 		return ret;
15286c957ed7SJacopo Mondi 
15296c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
15306c957ed7SJacopo Mondi 			     (sysdiv << 4) | mipi_div);
1531aa288248SMaxime Ripard 	if (ret)
1532aa288248SMaxime Ripard 		return ret;
1533aa288248SMaxime Ripard 
1534aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
1535aa288248SMaxime Ripard 	if (ret)
1536aa288248SMaxime Ripard 		return ret;
1537aa288248SMaxime Ripard 
15386c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
15396c957ed7SJacopo Mondi 			     root_div | prediv);
1540aa288248SMaxime Ripard 	if (ret)
1541aa288248SMaxime Ripard 		return ret;
1542aa288248SMaxime Ripard 
15436c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
15446c957ed7SJacopo Mondi 			     (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
15456c957ed7SJacopo Mondi 	if (ret)
15466c957ed7SJacopo Mondi 		return ret;
15476c957ed7SJacopo Mondi 
15486c957ed7SJacopo Mondi 	return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
15496c957ed7SJacopo Mondi }
15506c957ed7SJacopo Mondi 
15516c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
15526c957ed7SJacopo Mondi {
15533145efcdSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
15545113d5b3SJacopo Mondi 	const struct ov5640_timings *timings = &mode->dvp_timings;
15556c957ed7SJacopo Mondi 	u32 rate;
15566c957ed7SJacopo Mondi 
15575113d5b3SJacopo Mondi 	rate = timings->htot * (timings->crop.height + timings->vblank_def);
15586c957ed7SJacopo Mondi 	rate *= ov5640_framerates[sensor->current_fr];
15596c957ed7SJacopo Mondi 
15606c957ed7SJacopo Mondi 	return rate;
1561aa288248SMaxime Ripard }
1562aa288248SMaxime Ripard 
1563aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
1564aa288248SMaxime Ripard 				      unsigned long rate,
1565aa288248SMaxime Ripard 				      u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
1566aa288248SMaxime Ripard 				      u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
1567aa288248SMaxime Ripard {
1568aa288248SMaxime Ripard 	unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
1569aa288248SMaxime Ripard 				OV5640_PCLK_ROOT_DIV;
1570aa288248SMaxime Ripard 
1571aa288248SMaxime Ripard 	_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
1572aa288248SMaxime Ripard 				    sysdiv);
1573aa288248SMaxime Ripard 	*pll_rdiv = OV5640_PLL_ROOT_DIV;
1574aa288248SMaxime Ripard 	*bit_div = OV5640_BIT_DIV;
1575aa288248SMaxime Ripard 	*pclk_div = OV5640_PCLK_ROOT_DIV;
1576aa288248SMaxime Ripard 
1577aa288248SMaxime Ripard 	return _rate / *pll_rdiv / *bit_div / *pclk_div;
1578aa288248SMaxime Ripard }
1579aa288248SMaxime Ripard 
15806c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
1581aa288248SMaxime Ripard {
1582aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
15836c957ed7SJacopo Mondi 	u32 rate;
1584aa288248SMaxime Ripard 	int ret;
1585aa288248SMaxime Ripard 
15866c957ed7SJacopo Mondi 	rate = ov5640_calc_pixel_rate(sensor);
1587a89f14bbSJacopo Mondi 	rate *= ov5640_code_to_bpp(sensor, sensor->fmt.code);
15886c957ed7SJacopo Mondi 	rate /= sensor->ep.bus.parallel.bus_width;
15896c957ed7SJacopo Mondi 
1590aa288248SMaxime Ripard 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
1591aa288248SMaxime Ripard 			 &bit_div, &pclk_div);
1592aa288248SMaxime Ripard 
1593aa288248SMaxime Ripard 	if (bit_div == 2)
1594aa288248SMaxime Ripard 		bit_div = 8;
1595aa288248SMaxime Ripard 
1596aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1597aa288248SMaxime Ripard 			     0x0f, bit_div);
1598aa288248SMaxime Ripard 	if (ret)
1599aa288248SMaxime Ripard 		return ret;
1600aa288248SMaxime Ripard 
1601aa288248SMaxime Ripard 	/*
1602aa288248SMaxime Ripard 	 * We need to set sysdiv according to the clock, and to clear
1603aa288248SMaxime Ripard 	 * the MIPI divider.
1604aa288248SMaxime Ripard 	 */
1605aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1606aa288248SMaxime Ripard 			     0xff, sysdiv << 4);
1607aa288248SMaxime Ripard 	if (ret)
1608aa288248SMaxime Ripard 		return ret;
1609aa288248SMaxime Ripard 
1610aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
1611aa288248SMaxime Ripard 			     0xff, mult);
1612aa288248SMaxime Ripard 	if (ret)
1613aa288248SMaxime Ripard 		return ret;
1614aa288248SMaxime Ripard 
1615aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1616aa288248SMaxime Ripard 			     0x1f, prediv | ((pll_rdiv - 1) << 4));
1617aa288248SMaxime Ripard 	if (ret)
1618aa288248SMaxime Ripard 		return ret;
1619aa288248SMaxime Ripard 
1620aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
1621aa288248SMaxime Ripard 			      (ilog2(pclk_div) << 4));
1622aa288248SMaxime Ripard }
1623aa288248SMaxime Ripard 
16247cb013b1SChen-Yu Tsai /* set JPEG framing sizes */
16257cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
16267cb013b1SChen-Yu Tsai 				   const struct ov5640_mode_info *mode)
16277cb013b1SChen-Yu Tsai {
16287cb013b1SChen-Yu Tsai 	int ret;
16297cb013b1SChen-Yu Tsai 
16302b5c18f9SChen-Yu Tsai 	/*
16312b5c18f9SChen-Yu Tsai 	 * compression mode 3 timing
16322b5c18f9SChen-Yu Tsai 	 *
16332b5c18f9SChen-Yu Tsai 	 * Data is transmitted with programmable width (VFIFO_HSIZE).
16342b5c18f9SChen-Yu Tsai 	 * No padding done. Last line may have less data. Varying
16352b5c18f9SChen-Yu Tsai 	 * number of lines per frame, depending on amount of data.
16362b5c18f9SChen-Yu Tsai 	 */
16372b5c18f9SChen-Yu Tsai 	ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
16382b5c18f9SChen-Yu Tsai 	if (ret < 0)
16392b5c18f9SChen-Yu Tsai 		return ret;
16402b5c18f9SChen-Yu Tsai 
16415113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width);
16427cb013b1SChen-Yu Tsai 	if (ret < 0)
16437cb013b1SChen-Yu Tsai 		return ret;
16447cb013b1SChen-Yu Tsai 
16455113d5b3SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height);
16467cb013b1SChen-Yu Tsai }
16477cb013b1SChen-Yu Tsai 
164819a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */
1649bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor,
1650bad1774eSJacopo Mondi 			      const struct ov5640_mode_info *mode)
1651bad1774eSJacopo Mondi {
16525113d5b3SJacopo Mondi 	const struct ov5640_timings *timings;
16535113d5b3SJacopo Mondi 	const struct v4l2_rect *analog_crop;
16545113d5b3SJacopo Mondi 	const struct v4l2_rect *crop;
1655bad1774eSJacopo Mondi 	int ret;
1656bad1774eSJacopo Mondi 
16577cb013b1SChen-Yu Tsai 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
16587cb013b1SChen-Yu Tsai 		ret = ov5640_set_jpeg_timings(sensor, mode);
16597cb013b1SChen-Yu Tsai 		if (ret < 0)
16607cb013b1SChen-Yu Tsai 			return ret;
16617cb013b1SChen-Yu Tsai 	}
16627cb013b1SChen-Yu Tsai 
16632de6bb97SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
16645113d5b3SJacopo Mondi 	analog_crop = &timings->analog_crop;
16655113d5b3SJacopo Mondi 	crop = &timings->crop;
16665113d5b3SJacopo Mondi 
16673145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS,
16683145efcdSJacopo Mondi 				 analog_crop->left);
1669bad1774eSJacopo Mondi 	if (ret < 0)
1670bad1774eSJacopo Mondi 		return ret;
1671bad1774eSJacopo Mondi 
16723145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS,
16733145efcdSJacopo Mondi 				 analog_crop->top);
16743145efcdSJacopo Mondi 	if (ret < 0)
16753145efcdSJacopo Mondi 		return ret;
16763145efcdSJacopo Mondi 
16773145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW,
16783145efcdSJacopo Mondi 				 analog_crop->left + analog_crop->width - 1);
16793145efcdSJacopo Mondi 	if (ret < 0)
16803145efcdSJacopo Mondi 		return ret;
16813145efcdSJacopo Mondi 
16823145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH,
16833145efcdSJacopo Mondi 				 analog_crop->top + analog_crop->height - 1);
16843145efcdSJacopo Mondi 	if (ret < 0)
16853145efcdSJacopo Mondi 		return ret;
16863145efcdSJacopo Mondi 
16873145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left);
16883145efcdSJacopo Mondi 	if (ret < 0)
16893145efcdSJacopo Mondi 		return ret;
16903145efcdSJacopo Mondi 
16913145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top);
16923145efcdSJacopo Mondi 	if (ret < 0)
16933145efcdSJacopo Mondi 		return ret;
16943145efcdSJacopo Mondi 
16955113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width);
16963145efcdSJacopo Mondi 	if (ret < 0)
16973145efcdSJacopo Mondi 		return ret;
16983145efcdSJacopo Mondi 
16995113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height);
1700bad1774eSJacopo Mondi 	if (ret < 0)
1701bad1774eSJacopo Mondi 		return ret;
1702bad1774eSJacopo Mondi 
17035113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot);
1704bad1774eSJacopo Mondi 	if (ret < 0)
1705bad1774eSJacopo Mondi 		return ret;
1706bad1774eSJacopo Mondi 
17073145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
17085113d5b3SJacopo Mondi 				 mode->height + timings->vblank_def);
17093145efcdSJacopo Mondi 	if (ret < 0)
17103145efcdSJacopo Mondi 		return ret;
17113145efcdSJacopo Mondi 
17123145efcdSJacopo Mondi 	return 0;
1713bad1774eSJacopo Mondi }
1714bad1774eSJacopo Mondi 
1715e4359019SJacopo Mondi static void ov5640_load_regs(struct ov5640_dev *sensor,
1716e4359019SJacopo Mondi 			     const struct reg_value *regs, unsigned int regnum)
171719a81c14SSteve Longerbeam {
171819a81c14SSteve Longerbeam 	unsigned int i;
171919a81c14SSteve Longerbeam 	u32 delay_ms;
172019a81c14SSteve Longerbeam 	u16 reg_addr;
172119a81c14SSteve Longerbeam 	u8 mask, val;
172219a81c14SSteve Longerbeam 	int ret = 0;
172319a81c14SSteve Longerbeam 
1724e4359019SJacopo Mondi 	for (i = 0; i < regnum; ++i, ++regs) {
172519a81c14SSteve Longerbeam 		delay_ms = regs->delay_ms;
172619a81c14SSteve Longerbeam 		reg_addr = regs->reg_addr;
172719a81c14SSteve Longerbeam 		val = regs->val;
172819a81c14SSteve Longerbeam 		mask = regs->mask;
172919a81c14SSteve Longerbeam 
17303b987d70SLad Prabhakar 		/* remain in power down mode for DVP */
17313b987d70SLad Prabhakar 		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
17323b987d70SLad Prabhakar 		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
17338e823f5cSJacopo Mondi 		    !ov5640_is_csi2(sensor))
17343b987d70SLad Prabhakar 			continue;
17353b987d70SLad Prabhakar 
173619a81c14SSteve Longerbeam 		if (mask)
173719a81c14SSteve Longerbeam 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
173819a81c14SSteve Longerbeam 		else
173919a81c14SSteve Longerbeam 			ret = ov5640_write_reg(sensor, reg_addr, val);
174019a81c14SSteve Longerbeam 		if (ret)
174119a81c14SSteve Longerbeam 			break;
174219a81c14SSteve Longerbeam 
174319a81c14SSteve Longerbeam 		if (delay_ms)
174419a81c14SSteve Longerbeam 			usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
174519a81c14SSteve Longerbeam 	}
174619a81c14SSteve Longerbeam }
174719a81c14SSteve Longerbeam 
1748dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
1749dc29a1c1SHugues Fruchet {
1750dc29a1c1SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
1751dc29a1c1SHugues Fruchet 			      BIT(0), on ? 0 : BIT(0));
1752dc29a1c1SHugues Fruchet }
1753dc29a1c1SHugues Fruchet 
175419a81c14SSteve Longerbeam /* read exposure, in number of line periods */
175519a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor)
175619a81c14SSteve Longerbeam {
175719a81c14SSteve Longerbeam 	int exp, ret;
175819a81c14SSteve Longerbeam 	u8 temp;
175919a81c14SSteve Longerbeam 
176019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
176119a81c14SSteve Longerbeam 	if (ret)
176219a81c14SSteve Longerbeam 		return ret;
176319a81c14SSteve Longerbeam 	exp = ((int)temp & 0x0f) << 16;
176419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
176519a81c14SSteve Longerbeam 	if (ret)
176619a81c14SSteve Longerbeam 		return ret;
176719a81c14SSteve Longerbeam 	exp |= ((int)temp << 8);
176819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
176919a81c14SSteve Longerbeam 	if (ret)
177019a81c14SSteve Longerbeam 		return ret;
177119a81c14SSteve Longerbeam 	exp |= (int)temp;
177219a81c14SSteve Longerbeam 
177319a81c14SSteve Longerbeam 	return exp >> 4;
177419a81c14SSteve Longerbeam }
177519a81c14SSteve Longerbeam 
177619a81c14SSteve Longerbeam /* write exposure, given number of line periods */
177719a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
177819a81c14SSteve Longerbeam {
177919a81c14SSteve Longerbeam 	int ret;
178019a81c14SSteve Longerbeam 
178119a81c14SSteve Longerbeam 	exposure <<= 4;
178219a81c14SSteve Longerbeam 
178319a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
178419a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_LO,
178519a81c14SSteve Longerbeam 			       exposure & 0xff);
178619a81c14SSteve Longerbeam 	if (ret)
178719a81c14SSteve Longerbeam 		return ret;
178819a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
178919a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_MED,
179019a81c14SSteve Longerbeam 			       (exposure >> 8) & 0xff);
179119a81c14SSteve Longerbeam 	if (ret)
179219a81c14SSteve Longerbeam 		return ret;
179319a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor,
179419a81c14SSteve Longerbeam 				OV5640_REG_AEC_PK_EXPOSURE_HI,
179519a81c14SSteve Longerbeam 				(exposure >> 16) & 0x0f);
179619a81c14SSteve Longerbeam }
179719a81c14SSteve Longerbeam 
179819a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor)
179919a81c14SSteve Longerbeam {
180019a81c14SSteve Longerbeam 	u16 gain;
180119a81c14SSteve Longerbeam 	int ret;
180219a81c14SSteve Longerbeam 
180319a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
180419a81c14SSteve Longerbeam 	if (ret)
180519a81c14SSteve Longerbeam 		return ret;
180619a81c14SSteve Longerbeam 
180719a81c14SSteve Longerbeam 	return gain & 0x3ff;
180819a81c14SSteve Longerbeam }
180919a81c14SSteve Longerbeam 
18103cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
18113cca8ef5SHugues Fruchet {
18123cca8ef5SHugues Fruchet 	return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
18133cca8ef5SHugues Fruchet 				  (u16)gain & 0x3ff);
18143cca8ef5SHugues Fruchet }
18153cca8ef5SHugues Fruchet 
18163cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
18173cca8ef5SHugues Fruchet {
18183cca8ef5SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
18193cca8ef5SHugues Fruchet 			      BIT(1), on ? 0 : BIT(1));
18203cca8ef5SHugues Fruchet }
18213cca8ef5SHugues Fruchet 
1822f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
1823f22996dbSHugues Fruchet {
18243b987d70SLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
18253b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWUP :
18263b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWDN);
1827f22996dbSHugues Fruchet }
1828f22996dbSHugues Fruchet 
1829f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
183019a81c14SSteve Longerbeam {
183119a81c14SSteve Longerbeam 	int ret;
183219a81c14SSteve Longerbeam 
1833aa4bb8b8SJacopo Mondi 	/*
1834aa4bb8b8SJacopo Mondi 	 * Enable/disable the MIPI interface
1835aa4bb8b8SJacopo Mondi 	 *
1836aa4bb8b8SJacopo Mondi 	 * 0x300e = on ? 0x45 : 0x40
1837aa4bb8b8SJacopo Mondi 	 *
1838aa4bb8b8SJacopo Mondi 	 * FIXME: the sensor manual (version 2.03) reports
1839aa4bb8b8SJacopo Mondi 	 * [7:5] = 000  : 1 data lane mode
1840aa4bb8b8SJacopo Mondi 	 * [7:5] = 001  : 2 data lanes mode
1841aa4bb8b8SJacopo Mondi 	 * But this settings do not work, while the following ones
1842aa4bb8b8SJacopo Mondi 	 * have been validated for 2 data lanes mode.
1843aa4bb8b8SJacopo Mondi 	 *
1844aa4bb8b8SJacopo Mondi 	 * [7:5] = 010	: 2 data lanes mode
1845aa4bb8b8SJacopo Mondi 	 * [4] = 0	: Power up MIPI HS Tx
1846aa4bb8b8SJacopo Mondi 	 * [3] = 0	: Power up MIPI LS Rx
1847aa4bb8b8SJacopo Mondi 	 * [2] = 1/0	: MIPI interface enable/disable
1848aa4bb8b8SJacopo Mondi 	 * [1:0] = 01/00: FIXME: 'debug'
1849aa4bb8b8SJacopo Mondi 	 */
1850aa4bb8b8SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
1851aa4bb8b8SJacopo Mondi 			       on ? 0x45 : 0x40);
185219a81c14SSteve Longerbeam 	if (ret)
185319a81c14SSteve Longerbeam 		return ret;
185419a81c14SSteve Longerbeam 
185519a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
185619a81c14SSteve Longerbeam 				on ? 0x00 : 0x0f);
185719a81c14SSteve Longerbeam }
185819a81c14SSteve Longerbeam 
185919a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor)
186019a81c14SSteve Longerbeam {
186119a81c14SSteve Longerbeam 	 /* calculate sysclk */
186219a81c14SSteve Longerbeam 	u32 xvclk = sensor->xclk_freq / 10000;
186319a81c14SSteve Longerbeam 	u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
186419a81c14SSteve Longerbeam 	u32 sclk_rdiv_map[] = {1, 2, 4, 8};
186519a81c14SSteve Longerbeam 	u32 bit_div2x = 1, sclk_rdiv, sysclk;
186619a81c14SSteve Longerbeam 	u8 temp1, temp2;
186719a81c14SSteve Longerbeam 	int ret;
186819a81c14SSteve Longerbeam 
186919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
187019a81c14SSteve Longerbeam 	if (ret)
187119a81c14SSteve Longerbeam 		return ret;
187219a81c14SSteve Longerbeam 	temp2 = temp1 & 0x0f;
187319a81c14SSteve Longerbeam 	if (temp2 == 8 || temp2 == 10)
187419a81c14SSteve Longerbeam 		bit_div2x = temp2 / 2;
187519a81c14SSteve Longerbeam 
187619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
187719a81c14SSteve Longerbeam 	if (ret)
187819a81c14SSteve Longerbeam 		return ret;
187919a81c14SSteve Longerbeam 	sysdiv = temp1 >> 4;
188019a81c14SSteve Longerbeam 	if (sysdiv == 0)
188119a81c14SSteve Longerbeam 		sysdiv = 16;
188219a81c14SSteve Longerbeam 
188319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
188419a81c14SSteve Longerbeam 	if (ret)
188519a81c14SSteve Longerbeam 		return ret;
188619a81c14SSteve Longerbeam 	multiplier = temp1;
188719a81c14SSteve Longerbeam 
188819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
188919a81c14SSteve Longerbeam 	if (ret)
189019a81c14SSteve Longerbeam 		return ret;
189119a81c14SSteve Longerbeam 	prediv = temp1 & 0x0f;
189219a81c14SSteve Longerbeam 	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
189319a81c14SSteve Longerbeam 
189419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
189519a81c14SSteve Longerbeam 	if (ret)
189619a81c14SSteve Longerbeam 		return ret;
189719a81c14SSteve Longerbeam 	temp2 = temp1 & 0x03;
189819a81c14SSteve Longerbeam 	sclk_rdiv = sclk_rdiv_map[temp2];
189919a81c14SSteve Longerbeam 
190019a81c14SSteve Longerbeam 	if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
190119a81c14SSteve Longerbeam 		return -EINVAL;
190219a81c14SSteve Longerbeam 
190319a81c14SSteve Longerbeam 	VCO = xvclk * multiplier / prediv;
190419a81c14SSteve Longerbeam 
190519a81c14SSteve Longerbeam 	sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
190619a81c14SSteve Longerbeam 
190719a81c14SSteve Longerbeam 	return sysclk;
190819a81c14SSteve Longerbeam }
190919a81c14SSteve Longerbeam 
191019a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor)
191119a81c14SSteve Longerbeam {
191219a81c14SSteve Longerbeam 	 /* read HTS from register settings */
191319a81c14SSteve Longerbeam 	u8 mode;
191419a81c14SSteve Longerbeam 	int ret;
191519a81c14SSteve Longerbeam 
191619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
191719a81c14SSteve Longerbeam 	if (ret)
191819a81c14SSteve Longerbeam 		return ret;
191919a81c14SSteve Longerbeam 	mode &= 0xfb;
192019a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
192119a81c14SSteve Longerbeam }
192219a81c14SSteve Longerbeam 
192319a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor)
192419a81c14SSteve Longerbeam {
192519a81c14SSteve Longerbeam 	/* read HTS from register settings */
192619a81c14SSteve Longerbeam 	u16 hts;
192719a81c14SSteve Longerbeam 	int ret;
192819a81c14SSteve Longerbeam 
192919a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
193019a81c14SSteve Longerbeam 	if (ret)
193119a81c14SSteve Longerbeam 		return ret;
193219a81c14SSteve Longerbeam 	return hts;
193319a81c14SSteve Longerbeam }
193419a81c14SSteve Longerbeam 
193519a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor)
193619a81c14SSteve Longerbeam {
193719a81c14SSteve Longerbeam 	u16 vts;
193819a81c14SSteve Longerbeam 	int ret;
193919a81c14SSteve Longerbeam 
194019a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
194119a81c14SSteve Longerbeam 	if (ret)
194219a81c14SSteve Longerbeam 		return ret;
194319a81c14SSteve Longerbeam 	return vts;
194419a81c14SSteve Longerbeam }
194519a81c14SSteve Longerbeam 
194619a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
194719a81c14SSteve Longerbeam {
194819a81c14SSteve Longerbeam 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
194919a81c14SSteve Longerbeam }
195019a81c14SSteve Longerbeam 
195119a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor)
195219a81c14SSteve Longerbeam {
195319a81c14SSteve Longerbeam 	/* get banding filter value */
195419a81c14SSteve Longerbeam 	int ret, light_freq = 0;
195519a81c14SSteve Longerbeam 	u8 temp, temp1;
195619a81c14SSteve Longerbeam 
195719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
195819a81c14SSteve Longerbeam 	if (ret)
195919a81c14SSteve Longerbeam 		return ret;
196019a81c14SSteve Longerbeam 
196119a81c14SSteve Longerbeam 	if (temp & 0x80) {
196219a81c14SSteve Longerbeam 		/* manual */
196319a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
196419a81c14SSteve Longerbeam 				      &temp1);
196519a81c14SSteve Longerbeam 		if (ret)
196619a81c14SSteve Longerbeam 			return ret;
196719a81c14SSteve Longerbeam 		if (temp1 & 0x04) {
196819a81c14SSteve Longerbeam 			/* 50Hz */
196919a81c14SSteve Longerbeam 			light_freq = 50;
197019a81c14SSteve Longerbeam 		} else {
197119a81c14SSteve Longerbeam 			/* 60Hz */
197219a81c14SSteve Longerbeam 			light_freq = 60;
197319a81c14SSteve Longerbeam 		}
197419a81c14SSteve Longerbeam 	} else {
197519a81c14SSteve Longerbeam 		/* auto */
197619a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
197719a81c14SSteve Longerbeam 				      &temp1);
197819a81c14SSteve Longerbeam 		if (ret)
197919a81c14SSteve Longerbeam 			return ret;
198019a81c14SSteve Longerbeam 
198119a81c14SSteve Longerbeam 		if (temp1 & 0x01) {
198219a81c14SSteve Longerbeam 			/* 50Hz */
198319a81c14SSteve Longerbeam 			light_freq = 50;
198419a81c14SSteve Longerbeam 		} else {
198519a81c14SSteve Longerbeam 			/* 60Hz */
198619a81c14SSteve Longerbeam 		}
198719a81c14SSteve Longerbeam 	}
198819a81c14SSteve Longerbeam 
198919a81c14SSteve Longerbeam 	return light_freq;
199019a81c14SSteve Longerbeam }
199119a81c14SSteve Longerbeam 
199219a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
199319a81c14SSteve Longerbeam {
199419a81c14SSteve Longerbeam 	u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
199519a81c14SSteve Longerbeam 	int ret;
199619a81c14SSteve Longerbeam 
199719a81c14SSteve Longerbeam 	/* read preview PCLK */
199819a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
199919a81c14SSteve Longerbeam 	if (ret < 0)
200019a81c14SSteve Longerbeam 		return ret;
200119a81c14SSteve Longerbeam 	if (ret == 0)
200219a81c14SSteve Longerbeam 		return -EINVAL;
200319a81c14SSteve Longerbeam 	sensor->prev_sysclk = ret;
200419a81c14SSteve Longerbeam 	/* read preview HTS */
200519a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
200619a81c14SSteve Longerbeam 	if (ret < 0)
200719a81c14SSteve Longerbeam 		return ret;
200819a81c14SSteve Longerbeam 	if (ret == 0)
200919a81c14SSteve Longerbeam 		return -EINVAL;
201019a81c14SSteve Longerbeam 	sensor->prev_hts = ret;
201119a81c14SSteve Longerbeam 
201219a81c14SSteve Longerbeam 	/* read preview VTS */
201319a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
201419a81c14SSteve Longerbeam 	if (ret < 0)
201519a81c14SSteve Longerbeam 		return ret;
201619a81c14SSteve Longerbeam 	prev_vts = ret;
201719a81c14SSteve Longerbeam 
201819a81c14SSteve Longerbeam 	/* calculate banding filter */
201919a81c14SSteve Longerbeam 	/* 60Hz */
202019a81c14SSteve Longerbeam 	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
202119a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
202219a81c14SSteve Longerbeam 	if (ret)
202319a81c14SSteve Longerbeam 		return ret;
202419a81c14SSteve Longerbeam 	if (!band_step60)
202519a81c14SSteve Longerbeam 		return -EINVAL;
202619a81c14SSteve Longerbeam 	max_band60 = (int)((prev_vts - 4) / band_step60);
202719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
202819a81c14SSteve Longerbeam 	if (ret)
202919a81c14SSteve Longerbeam 		return ret;
203019a81c14SSteve Longerbeam 
203119a81c14SSteve Longerbeam 	/* 50Hz */
203219a81c14SSteve Longerbeam 	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
203319a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
203419a81c14SSteve Longerbeam 	if (ret)
203519a81c14SSteve Longerbeam 		return ret;
203619a81c14SSteve Longerbeam 	if (!band_step50)
203719a81c14SSteve Longerbeam 		return -EINVAL;
203819a81c14SSteve Longerbeam 	max_band50 = (int)((prev_vts - 4) / band_step50);
203919a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
204019a81c14SSteve Longerbeam }
204119a81c14SSteve Longerbeam 
204219a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
204319a81c14SSteve Longerbeam {
204419a81c14SSteve Longerbeam 	/* stable in high */
204519a81c14SSteve Longerbeam 	u32 fast_high, fast_low;
204619a81c14SSteve Longerbeam 	int ret;
204719a81c14SSteve Longerbeam 
204819a81c14SSteve Longerbeam 	sensor->ae_low = target * 23 / 25;	/* 0.92 */
204919a81c14SSteve Longerbeam 	sensor->ae_high = target * 27 / 25;	/* 1.08 */
205019a81c14SSteve Longerbeam 
205119a81c14SSteve Longerbeam 	fast_high = sensor->ae_high << 1;
205219a81c14SSteve Longerbeam 	if (fast_high > 255)
205319a81c14SSteve Longerbeam 		fast_high = 255;
205419a81c14SSteve Longerbeam 
205519a81c14SSteve Longerbeam 	fast_low = sensor->ae_low >> 1;
205619a81c14SSteve Longerbeam 
205719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
205819a81c14SSteve Longerbeam 	if (ret)
205919a81c14SSteve Longerbeam 		return ret;
206019a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
206119a81c14SSteve Longerbeam 	if (ret)
206219a81c14SSteve Longerbeam 		return ret;
206319a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
206419a81c14SSteve Longerbeam 	if (ret)
206519a81c14SSteve Longerbeam 		return ret;
206619a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
206719a81c14SSteve Longerbeam 	if (ret)
206819a81c14SSteve Longerbeam 		return ret;
206919a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
207019a81c14SSteve Longerbeam 	if (ret)
207119a81c14SSteve Longerbeam 		return ret;
207219a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
207319a81c14SSteve Longerbeam }
207419a81c14SSteve Longerbeam 
2075c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor)
207619a81c14SSteve Longerbeam {
207719a81c14SSteve Longerbeam 	u8 temp;
207819a81c14SSteve Longerbeam 	int ret;
207919a81c14SSteve Longerbeam 
208019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
208119a81c14SSteve Longerbeam 	if (ret)
208219a81c14SSteve Longerbeam 		return ret;
2083c2c3f42dSHugues Fruchet 
2084c2c3f42dSHugues Fruchet 	return temp & BIT(0);
208519a81c14SSteve Longerbeam }
208619a81c14SSteve Longerbeam 
2087ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
2088ce85705aSHugues Fruchet {
2089ce85705aSHugues Fruchet 	int ret;
2090ce85705aSHugues Fruchet 
2091ce85705aSHugues Fruchet 	/*
2092ce85705aSHugues Fruchet 	 * TIMING TC REG21:
2093ce85705aSHugues Fruchet 	 * - [0]:	Horizontal binning enable
2094ce85705aSHugues Fruchet 	 */
2095ce85705aSHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2096ce85705aSHugues Fruchet 			     BIT(0), enable ? BIT(0) : 0);
2097ce85705aSHugues Fruchet 	if (ret)
2098ce85705aSHugues Fruchet 		return ret;
2099ce85705aSHugues Fruchet 	/*
2100ce85705aSHugues Fruchet 	 * TIMING TC REG20:
2101ce85705aSHugues Fruchet 	 * - [0]:	Undocumented, but hardcoded init sequences
2102ce85705aSHugues Fruchet 	 *		are always setting REG21/REG20 bit 0 to same value...
2103ce85705aSHugues Fruchet 	 */
2104ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
2105ce85705aSHugues Fruchet 			      BIT(0), enable ? BIT(0) : 0);
2106ce85705aSHugues Fruchet }
2107ce85705aSHugues Fruchet 
210819a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
210919a81c14SSteve Longerbeam {
21108670d70aSHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
211119a81c14SSteve Longerbeam 	u8 temp, channel = virtual_channel;
211219a81c14SSteve Longerbeam 	int ret;
211319a81c14SSteve Longerbeam 
21148670d70aSHugues Fruchet 	if (channel > 3) {
21158670d70aSHugues Fruchet 		dev_err(&client->dev,
21168670d70aSHugues Fruchet 			"%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
21178670d70aSHugues Fruchet 			__func__, channel);
211819a81c14SSteve Longerbeam 		return -EINVAL;
21198670d70aSHugues Fruchet 	}
212019a81c14SSteve Longerbeam 
212119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
212219a81c14SSteve Longerbeam 	if (ret)
212319a81c14SSteve Longerbeam 		return ret;
212419a81c14SSteve Longerbeam 	temp &= ~(3 << 6);
212519a81c14SSteve Longerbeam 	temp |= (channel << 6);
212619a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
212719a81c14SSteve Longerbeam }
212819a81c14SSteve Longerbeam 
212919a81c14SSteve Longerbeam static const struct ov5640_mode_info *
2130b6ae5022SJacopo Mondi ov5640_find_mode(struct ov5640_dev *sensor, int width, int height, bool nearest)
213119a81c14SSteve Longerbeam {
21323c4a7372SHugues Fruchet 	const struct ov5640_mode_info *mode;
213319a81c14SSteve Longerbeam 
2134086c25f8SMaxime Ripard 	mode = v4l2_find_nearest_size(ov5640_mode_data,
2135086c25f8SMaxime Ripard 				      ARRAY_SIZE(ov5640_mode_data),
21365113d5b3SJacopo Mondi 				      width, height, width, height);
213719a81c14SSteve Longerbeam 
21383c4a7372SHugues Fruchet 	if (!mode ||
21393145efcdSJacopo Mondi 	    (!nearest &&
21405113d5b3SJacopo Mondi 	     (mode->width != width || mode->height != height)))
21413c4a7372SHugues Fruchet 		return NULL;
214219a81c14SSteve Longerbeam 
214319a81c14SSteve Longerbeam 	return mode;
214419a81c14SSteve Longerbeam }
214519a81c14SSteve Longerbeam 
214619a81c14SSteve Longerbeam /*
214719a81c14SSteve Longerbeam  * sensor changes between scaling and subsampling, go through
214819a81c14SSteve Longerbeam  * exposure calculation
214919a81c14SSteve Longerbeam  */
215041d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
215141d8d7f5SHugues Fruchet 					 const struct ov5640_mode_info *mode)
215219a81c14SSteve Longerbeam {
215319a81c14SSteve Longerbeam 	u32 prev_shutter, prev_gain16;
215419a81c14SSteve Longerbeam 	u32 cap_shutter, cap_gain16;
215519a81c14SSteve Longerbeam 	u32 cap_sysclk, cap_hts, cap_vts;
215619a81c14SSteve Longerbeam 	u32 light_freq, cap_bandfilt, cap_maxband;
215719a81c14SSteve Longerbeam 	u32 cap_gain16_shutter;
215819a81c14SSteve Longerbeam 	u8 average;
215919a81c14SSteve Longerbeam 	int ret;
216019a81c14SSteve Longerbeam 
216141d8d7f5SHugues Fruchet 	if (!mode->reg_data)
216219a81c14SSteve Longerbeam 		return -EINVAL;
216319a81c14SSteve Longerbeam 
216419a81c14SSteve Longerbeam 	/* read preview shutter */
216519a81c14SSteve Longerbeam 	ret = ov5640_get_exposure(sensor);
216619a81c14SSteve Longerbeam 	if (ret < 0)
216719a81c14SSteve Longerbeam 		return ret;
216819a81c14SSteve Longerbeam 	prev_shutter = ret;
2169c2c3f42dSHugues Fruchet 	ret = ov5640_get_binning(sensor);
217019a81c14SSteve Longerbeam 	if (ret < 0)
217119a81c14SSteve Longerbeam 		return ret;
217219a81c14SSteve Longerbeam 	if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
217319a81c14SSteve Longerbeam 	    mode->id != OV5640_MODE_1080P_1920_1080)
217419a81c14SSteve Longerbeam 		prev_shutter *= 2;
217519a81c14SSteve Longerbeam 
217619a81c14SSteve Longerbeam 	/* read preview gain */
217719a81c14SSteve Longerbeam 	ret = ov5640_get_gain(sensor);
217819a81c14SSteve Longerbeam 	if (ret < 0)
217919a81c14SSteve Longerbeam 		return ret;
218019a81c14SSteve Longerbeam 	prev_gain16 = ret;
218119a81c14SSteve Longerbeam 
218219a81c14SSteve Longerbeam 	/* get average */
218319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
218419a81c14SSteve Longerbeam 	if (ret)
218519a81c14SSteve Longerbeam 		return ret;
218619a81c14SSteve Longerbeam 
218719a81c14SSteve Longerbeam 	/* turn off night mode for capture */
218819a81c14SSteve Longerbeam 	ret = ov5640_set_night_mode(sensor);
218919a81c14SSteve Longerbeam 	if (ret < 0)
219019a81c14SSteve Longerbeam 		return ret;
219119a81c14SSteve Longerbeam 
219219a81c14SSteve Longerbeam 	/* Write capture setting */
2193e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2194e4359019SJacopo Mondi 	ret = ov5640_set_timings(sensor, mode);
219519a81c14SSteve Longerbeam 	if (ret < 0)
219619a81c14SSteve Longerbeam 		return ret;
219719a81c14SSteve Longerbeam 
219819a81c14SSteve Longerbeam 	/* read capture VTS */
219919a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
220019a81c14SSteve Longerbeam 	if (ret < 0)
220119a81c14SSteve Longerbeam 		return ret;
220219a81c14SSteve Longerbeam 	cap_vts = ret;
220319a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
220419a81c14SSteve Longerbeam 	if (ret < 0)
220519a81c14SSteve Longerbeam 		return ret;
220619a81c14SSteve Longerbeam 	if (ret == 0)
220719a81c14SSteve Longerbeam 		return -EINVAL;
220819a81c14SSteve Longerbeam 	cap_hts = ret;
220919a81c14SSteve Longerbeam 
221019a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
221119a81c14SSteve Longerbeam 	if (ret < 0)
221219a81c14SSteve Longerbeam 		return ret;
221319a81c14SSteve Longerbeam 	if (ret == 0)
221419a81c14SSteve Longerbeam 		return -EINVAL;
221519a81c14SSteve Longerbeam 	cap_sysclk = ret;
221619a81c14SSteve Longerbeam 
221719a81c14SSteve Longerbeam 	/* calculate capture banding filter */
221819a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
221919a81c14SSteve Longerbeam 	if (ret < 0)
222019a81c14SSteve Longerbeam 		return ret;
222119a81c14SSteve Longerbeam 	light_freq = ret;
222219a81c14SSteve Longerbeam 
222319a81c14SSteve Longerbeam 	if (light_freq == 60) {
222419a81c14SSteve Longerbeam 		/* 60Hz */
222519a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
222619a81c14SSteve Longerbeam 	} else {
222719a81c14SSteve Longerbeam 		/* 50Hz */
222819a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts;
222919a81c14SSteve Longerbeam 	}
223019a81c14SSteve Longerbeam 
223119a81c14SSteve Longerbeam 	if (!sensor->prev_sysclk) {
223219a81c14SSteve Longerbeam 		ret = ov5640_get_sysclk(sensor);
223319a81c14SSteve Longerbeam 		if (ret < 0)
223419a81c14SSteve Longerbeam 			return ret;
223519a81c14SSteve Longerbeam 		if (ret == 0)
223619a81c14SSteve Longerbeam 			return -EINVAL;
223719a81c14SSteve Longerbeam 		sensor->prev_sysclk = ret;
223819a81c14SSteve Longerbeam 	}
223919a81c14SSteve Longerbeam 
224019a81c14SSteve Longerbeam 	if (!cap_bandfilt)
224119a81c14SSteve Longerbeam 		return -EINVAL;
224219a81c14SSteve Longerbeam 
224319a81c14SSteve Longerbeam 	cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
224419a81c14SSteve Longerbeam 
224519a81c14SSteve Longerbeam 	/* calculate capture shutter/gain16 */
224619a81c14SSteve Longerbeam 	if (average > sensor->ae_low && average < sensor->ae_high) {
224719a81c14SSteve Longerbeam 		/* in stable range */
224819a81c14SSteve Longerbeam 		cap_gain16_shutter =
224919a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
225019a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
225119a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts *
225219a81c14SSteve Longerbeam 			sensor->ae_target / average;
225319a81c14SSteve Longerbeam 	} else {
225419a81c14SSteve Longerbeam 		cap_gain16_shutter =
225519a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
225619a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
225719a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts;
225819a81c14SSteve Longerbeam 	}
225919a81c14SSteve Longerbeam 
226019a81c14SSteve Longerbeam 	/* gain to shutter */
226119a81c14SSteve Longerbeam 	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
226219a81c14SSteve Longerbeam 		/* shutter < 1/100 */
226319a81c14SSteve Longerbeam 		cap_shutter = cap_gain16_shutter / 16;
226419a81c14SSteve Longerbeam 		if (cap_shutter < 1)
226519a81c14SSteve Longerbeam 			cap_shutter = 1;
226619a81c14SSteve Longerbeam 
226719a81c14SSteve Longerbeam 		cap_gain16 = cap_gain16_shutter / cap_shutter;
226819a81c14SSteve Longerbeam 		if (cap_gain16 < 16)
226919a81c14SSteve Longerbeam 			cap_gain16 = 16;
227019a81c14SSteve Longerbeam 	} else {
227119a81c14SSteve Longerbeam 		if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
227219a81c14SSteve Longerbeam 			/* exposure reach max */
227319a81c14SSteve Longerbeam 			cap_shutter = cap_bandfilt * cap_maxband;
227419a81c14SSteve Longerbeam 			if (!cap_shutter)
227519a81c14SSteve Longerbeam 				return -EINVAL;
227619a81c14SSteve Longerbeam 
227719a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
227819a81c14SSteve Longerbeam 		} else {
227919a81c14SSteve Longerbeam 			/* 1/100 < (cap_shutter = n/100) =< max */
228019a81c14SSteve Longerbeam 			cap_shutter =
228119a81c14SSteve Longerbeam 				((int)(cap_gain16_shutter / 16 / cap_bandfilt))
228219a81c14SSteve Longerbeam 				* cap_bandfilt;
228319a81c14SSteve Longerbeam 			if (!cap_shutter)
228419a81c14SSteve Longerbeam 				return -EINVAL;
228519a81c14SSteve Longerbeam 
228619a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
228719a81c14SSteve Longerbeam 		}
228819a81c14SSteve Longerbeam 	}
228919a81c14SSteve Longerbeam 
229019a81c14SSteve Longerbeam 	/* set capture gain */
22913cca8ef5SHugues Fruchet 	ret = ov5640_set_gain(sensor, cap_gain16);
229219a81c14SSteve Longerbeam 	if (ret)
229319a81c14SSteve Longerbeam 		return ret;
229419a81c14SSteve Longerbeam 
229519a81c14SSteve Longerbeam 	/* write capture shutter */
229619a81c14SSteve Longerbeam 	if (cap_shutter > (cap_vts - 4)) {
229719a81c14SSteve Longerbeam 		cap_vts = cap_shutter + 4;
229819a81c14SSteve Longerbeam 		ret = ov5640_set_vts(sensor, cap_vts);
229919a81c14SSteve Longerbeam 		if (ret < 0)
230019a81c14SSteve Longerbeam 			return ret;
230119a81c14SSteve Longerbeam 	}
230219a81c14SSteve Longerbeam 
230319a81c14SSteve Longerbeam 	/* set exposure */
23043cca8ef5SHugues Fruchet 	return ov5640_set_exposure(sensor, cap_shutter);
230519a81c14SSteve Longerbeam }
230619a81c14SSteve Longerbeam 
230719a81c14SSteve Longerbeam /*
230819a81c14SSteve Longerbeam  * if sensor changes inside scaling or subsampling
230919a81c14SSteve Longerbeam  * change mode directly
231019a81c14SSteve Longerbeam  */
231119a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
23123cca8ef5SHugues Fruchet 				  const struct ov5640_mode_info *mode)
231319a81c14SSteve Longerbeam {
231441d8d7f5SHugues Fruchet 	if (!mode->reg_data)
231519a81c14SSteve Longerbeam 		return -EINVAL;
231619a81c14SSteve Longerbeam 
231719a81c14SSteve Longerbeam 	/* Write capture setting */
2318e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2319e4359019SJacopo Mondi 	return ov5640_set_timings(sensor, mode);
232019a81c14SSteve Longerbeam }
232119a81c14SSteve Longerbeam 
2322985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor)
232319a81c14SSteve Longerbeam {
232419a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode = sensor->current_mode;
2325985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *orig_mode = sensor->last_mode;
232619a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
23273cca8ef5SHugues Fruchet 	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
2328dc29a1c1SHugues Fruchet 	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
232919a81c14SSteve Longerbeam 	int ret;
233019a81c14SSteve Longerbeam 
233119a81c14SSteve Longerbeam 	dn_mode = mode->dn_mode;
233219a81c14SSteve Longerbeam 	orig_dn_mode = orig_mode->dn_mode;
233319a81c14SSteve Longerbeam 
233419a81c14SSteve Longerbeam 	/* auto gain and exposure must be turned off when changing modes */
23353cca8ef5SHugues Fruchet 	if (auto_gain) {
23363cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, false);
233719a81c14SSteve Longerbeam 		if (ret)
233819a81c14SSteve Longerbeam 			return ret;
23393cca8ef5SHugues Fruchet 	}
2340bf4a4b51SMaxime Ripard 
23413cca8ef5SHugues Fruchet 	if (auto_exp) {
2342dc29a1c1SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, false);
234319a81c14SSteve Longerbeam 		if (ret)
23443cca8ef5SHugues Fruchet 			goto restore_auto_gain;
23453cca8ef5SHugues Fruchet 	}
234619a81c14SSteve Longerbeam 
23476c957ed7SJacopo Mondi 	if (ov5640_is_csi2(sensor))
23486c957ed7SJacopo Mondi 		ret = ov5640_set_mipi_pclk(sensor);
23496c957ed7SJacopo Mondi 	else
23506c957ed7SJacopo Mondi 		ret = ov5640_set_dvp_pclk(sensor);
2351aa288248SMaxime Ripard 	if (ret < 0)
2352aa288248SMaxime Ripard 		return 0;
2353aa288248SMaxime Ripard 
235419a81c14SSteve Longerbeam 	if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
235519a81c14SSteve Longerbeam 	    (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
235619a81c14SSteve Longerbeam 		/*
235719a81c14SSteve Longerbeam 		 * change between subsampling and scaling
23583cca8ef5SHugues Fruchet 		 * go through exposure calculation
235919a81c14SSteve Longerbeam 		 */
236019a81c14SSteve Longerbeam 		ret = ov5640_set_mode_exposure_calc(sensor, mode);
236119a81c14SSteve Longerbeam 	} else {
236219a81c14SSteve Longerbeam 		/*
236319a81c14SSteve Longerbeam 		 * change inside subsampling or scaling
236419a81c14SSteve Longerbeam 		 * download firmware directly
236519a81c14SSteve Longerbeam 		 */
23663cca8ef5SHugues Fruchet 		ret = ov5640_set_mode_direct(sensor, mode);
236719a81c14SSteve Longerbeam 	}
236819a81c14SSteve Longerbeam 	if (ret < 0)
23693cca8ef5SHugues Fruchet 		goto restore_auto_exp_gain;
23703cca8ef5SHugues Fruchet 
23713cca8ef5SHugues Fruchet 	/* restore auto gain and exposure */
23723cca8ef5SHugues Fruchet 	if (auto_gain)
23733cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
23743cca8ef5SHugues Fruchet 	if (auto_exp)
23753cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
237619a81c14SSteve Longerbeam 
2377ce85705aSHugues Fruchet 	ret = ov5640_set_binning(sensor, dn_mode != SCALING);
2378ce85705aSHugues Fruchet 	if (ret < 0)
2379ce85705aSHugues Fruchet 		return ret;
238019a81c14SSteve Longerbeam 	ret = ov5640_set_ae_target(sensor, sensor->ae_target);
238119a81c14SSteve Longerbeam 	if (ret < 0)
238219a81c14SSteve Longerbeam 		return ret;
238319a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
238419a81c14SSteve Longerbeam 	if (ret < 0)
238519a81c14SSteve Longerbeam 		return ret;
238619a81c14SSteve Longerbeam 	ret = ov5640_set_bandingfilter(sensor);
238719a81c14SSteve Longerbeam 	if (ret < 0)
238819a81c14SSteve Longerbeam 		return ret;
238919a81c14SSteve Longerbeam 	ret = ov5640_set_virtual_channel(sensor);
239019a81c14SSteve Longerbeam 	if (ret < 0)
239119a81c14SSteve Longerbeam 		return ret;
239219a81c14SSteve Longerbeam 
239319a81c14SSteve Longerbeam 	sensor->pending_mode_change = false;
2394985cdcb0SHugues Fruchet 	sensor->last_mode = mode;
239519a81c14SSteve Longerbeam 
239619a81c14SSteve Longerbeam 	return 0;
23973cca8ef5SHugues Fruchet 
23983cca8ef5SHugues Fruchet restore_auto_exp_gain:
23993cca8ef5SHugues Fruchet 	if (auto_exp)
24003cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
24013cca8ef5SHugues Fruchet restore_auto_gain:
24023cca8ef5SHugues Fruchet 	if (auto_gain)
24033cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
24043cca8ef5SHugues Fruchet 
24053cca8ef5SHugues Fruchet 	return ret;
240619a81c14SSteve Longerbeam }
240719a81c14SSteve Longerbeam 
240819ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor,
240919ad26f9SAkinobu Mita 			       struct v4l2_mbus_framefmt *format);
241019ad26f9SAkinobu Mita 
241119a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */
241219a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor)
241319a81c14SSteve Longerbeam {
241419a81c14SSteve Longerbeam 	int ret;
241519a81c14SSteve Longerbeam 
241619a81c14SSteve Longerbeam 	/* first load the initial register values */
2417e4359019SJacopo Mondi 	ov5640_load_regs(sensor, ov5640_init_setting,
2418e4359019SJacopo Mondi 			 ARRAY_SIZE(ov5640_init_setting));
241919a81c14SSteve Longerbeam 
24208f57c2f8SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
24217851fe7aSMaxime Ripard 			     (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
24227851fe7aSMaxime Ripard 			     ilog2(OV5640_SCLK_ROOT_DIV));
24238f57c2f8SMaxime Ripard 	if (ret)
24248f57c2f8SMaxime Ripard 		return ret;
24258f57c2f8SMaxime Ripard 
242619a81c14SSteve Longerbeam 	/* now restore the last capture mode */
2427985cdcb0SHugues Fruchet 	ret = ov5640_set_mode(sensor);
242819ad26f9SAkinobu Mita 	if (ret < 0)
242919ad26f9SAkinobu Mita 		return ret;
243019ad26f9SAkinobu Mita 
243119ad26f9SAkinobu Mita 	return ov5640_set_framefmt(sensor, &sensor->fmt);
243219a81c14SSteve Longerbeam }
243319a81c14SSteve Longerbeam 
243419a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable)
243519a81c14SSteve Longerbeam {
24361fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
243719a81c14SSteve Longerbeam }
243819a81c14SSteve Longerbeam 
2439d7ff6913SJai Luthra /*
2440d7ff6913SJai Luthra  * From section 2.7 power up sequence:
2441d7ff6913SJai Luthra  * t0 + t1 + t2 >= 5ms	Delay from DOVDD stable to PWDN pull down
2442d7ff6913SJai Luthra  * t3 >= 1ms		Delay from PWDN pull down to RESETB pull up
2443d7ff6913SJai Luthra  * t4 >= 20ms		Delay from RESETB pull up to SCCB (i2c) stable
2444d7ff6913SJai Luthra  *
2445d7ff6913SJai Luthra  * Some modules don't expose RESETB/PWDN pins directly, instead providing a
2446d7ff6913SJai Luthra  * "PWUP" GPIO which is wired through appropriate delays and inverters to the
2447d7ff6913SJai Luthra  * pins.
2448d7ff6913SJai Luthra  *
2449d7ff6913SJai Luthra  * In such cases, this gpio should be mapped to pwdn_gpio in the driver, and we
2450d7ff6913SJai Luthra  * should still toggle the pwdn_gpio below with the appropriate delays, while
2451d7ff6913SJai Luthra  * the calls to reset_gpio will be ignored.
2452d7ff6913SJai Luthra  */
2453d7ff6913SJai Luthra static void ov5640_powerup_sequence(struct ov5640_dev *sensor)
245419a81c14SSteve Longerbeam {
2455decea0a9SJai Luthra 	if (sensor->pwdn_gpio) {
24561fddc5daSHugues Fruchet 		gpiod_set_value_cansleep(sensor->reset_gpio, 0);
245719a81c14SSteve Longerbeam 
245819a81c14SSteve Longerbeam 		/* camera power cycle */
245919a81c14SSteve Longerbeam 		ov5640_power(sensor, false);
246019a81c14SSteve Longerbeam 		usleep_range(5000, 10000);
246119a81c14SSteve Longerbeam 		ov5640_power(sensor, true);
246219a81c14SSteve Longerbeam 		usleep_range(5000, 10000);
246319a81c14SSteve Longerbeam 
24641fddc5daSHugues Fruchet 		gpiod_set_value_cansleep(sensor->reset_gpio, 1);
246519a81c14SSteve Longerbeam 		usleep_range(1000, 2000);
246619a81c14SSteve Longerbeam 
24671fddc5daSHugues Fruchet 		gpiod_set_value_cansleep(sensor->reset_gpio, 0);
2468decea0a9SJai Luthra 	} else {
2469decea0a9SJai Luthra 		/* software reset */
2470decea0a9SJai Luthra 		ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0,
2471decea0a9SJai Luthra 				 OV5640_REG_SYS_CTRL0_SW_RST);
2472decea0a9SJai Luthra 	}
24731d4c41f3SLoic Poulain 	usleep_range(20000, 25000);
2474decea0a9SJai Luthra 
2475decea0a9SJai Luthra 	/*
2476decea0a9SJai Luthra 	 * software standby: allows registers programming;
2477decea0a9SJai Luthra 	 * exit at restore_mode() for CSI, s_stream(1) for DVP
2478decea0a9SJai Luthra 	 */
2479decea0a9SJai Luthra 	ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0,
2480decea0a9SJai Luthra 			 OV5640_REG_SYS_CTRL0_SW_PWDN);
248119a81c14SSteve Longerbeam }
248219a81c14SSteve Longerbeam 
24830f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor)
248419a81c14SSteve Longerbeam {
24850f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
24860f7acb52SHugues Fruchet 	int ret;
248719a81c14SSteve Longerbeam 
24880f7acb52SHugues Fruchet 	ret = clk_prepare_enable(sensor->xclk);
24890f7acb52SHugues Fruchet 	if (ret) {
24900f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable clock\n",
24910f7acb52SHugues Fruchet 			__func__);
24920f7acb52SHugues Fruchet 		return ret;
24930f7acb52SHugues Fruchet 	}
249419a81c14SSteve Longerbeam 
249519a81c14SSteve Longerbeam 	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
249619a81c14SSteve Longerbeam 				    sensor->supplies);
24970f7acb52SHugues Fruchet 	if (ret) {
24980f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable regulators\n",
24990f7acb52SHugues Fruchet 			__func__);
250019a81c14SSteve Longerbeam 		goto xclk_off;
25010f7acb52SHugues Fruchet 	}
250219a81c14SSteve Longerbeam 
2503d7ff6913SJai Luthra 	ov5640_powerup_sequence(sensor);
250419a81c14SSteve Longerbeam 
250519a81c14SSteve Longerbeam 	ret = ov5640_init_slave_id(sensor);
250619a81c14SSteve Longerbeam 	if (ret)
250719a81c14SSteve Longerbeam 		goto power_off;
250819a81c14SSteve Longerbeam 
25090f7acb52SHugues Fruchet 	return 0;
25100f7acb52SHugues Fruchet 
25110f7acb52SHugues Fruchet power_off:
25120f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
25130f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
25140f7acb52SHugues Fruchet xclk_off:
25150f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
25160f7acb52SHugues Fruchet 	return ret;
25170f7acb52SHugues Fruchet }
25180f7acb52SHugues Fruchet 
25190f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor)
25200f7acb52SHugues Fruchet {
25210f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
25220f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
25230f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
25240f7acb52SHugues Fruchet }
25250f7acb52SHugues Fruchet 
2526b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
2527b1751ae6SLad Prabhakar {
2528b1751ae6SLad Prabhakar 	int ret;
2529b1751ae6SLad Prabhakar 
2530b1751ae6SLad Prabhakar 	if (!on) {
2531b1751ae6SLad Prabhakar 		/* Reset MIPI bus settings to their default values. */
2532b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2533b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
2534b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
2535b1751ae6SLad Prabhakar 		return 0;
2536b1751ae6SLad Prabhakar 	}
2537b1751ae6SLad Prabhakar 
2538b1751ae6SLad Prabhakar 	/*
2539b1751ae6SLad Prabhakar 	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
2540b1751ae6SLad Prabhakar 	 *
2541b1751ae6SLad Prabhakar 	 * 0x300e = 0x40
2542b1751ae6SLad Prabhakar 	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
2543b1751ae6SLad Prabhakar 	 *		  "ov5640_set_stream_mipi()")
2544b1751ae6SLad Prabhakar 	 * [4] = 0	: Power up MIPI HS Tx
2545b1751ae6SLad Prabhakar 	 * [3] = 0	: Power up MIPI LS Rx
2546b1751ae6SLad Prabhakar 	 * [2] = 0	: MIPI interface disabled
2547b1751ae6SLad Prabhakar 	 */
2548b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
2549b1751ae6SLad Prabhakar 	if (ret)
2550b1751ae6SLad Prabhakar 		return ret;
2551b1751ae6SLad Prabhakar 
2552b1751ae6SLad Prabhakar 	/*
2553b1751ae6SLad Prabhakar 	 * Gate clock and set LP11 in 'no packets mode' (idle)
2554b1751ae6SLad Prabhakar 	 *
2555b1751ae6SLad Prabhakar 	 * 0x4800 = 0x24
2556b1751ae6SLad Prabhakar 	 * [5] = 1	: Gate clock when 'no packets'
2557b1751ae6SLad Prabhakar 	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
2558b1751ae6SLad Prabhakar 	 */
2559b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
2560b1751ae6SLad Prabhakar 	if (ret)
2561b1751ae6SLad Prabhakar 		return ret;
2562b1751ae6SLad Prabhakar 
2563b1751ae6SLad Prabhakar 	/*
2564b1751ae6SLad Prabhakar 	 * Set data lanes and clock in LP11 when 'sleeping'
2565b1751ae6SLad Prabhakar 	 *
2566b1751ae6SLad Prabhakar 	 * 0x3019 = 0x70
2567b1751ae6SLad Prabhakar 	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
2568b1751ae6SLad Prabhakar 	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
2569b1751ae6SLad Prabhakar 	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
2570b1751ae6SLad Prabhakar 	 */
2571b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
2572b1751ae6SLad Prabhakar 	if (ret)
2573b1751ae6SLad Prabhakar 		return ret;
2574b1751ae6SLad Prabhakar 
2575b1751ae6SLad Prabhakar 	/* Give lanes some time to coax into LP11 state. */
2576b1751ae6SLad Prabhakar 	usleep_range(500, 1000);
2577b1751ae6SLad Prabhakar 
2578b1751ae6SLad Prabhakar 	return 0;
2579b1751ae6SLad Prabhakar }
2580b1751ae6SLad Prabhakar 
2581576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
2582576f5d4bSLad Prabhakar {
2583311a6408SLad Prabhakar 	unsigned int flags = sensor->ep.bus.parallel.flags;
258468579b32SHugues Fruchet 	bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
258568579b32SHugues Fruchet 	u8 polarities = 0;
2586576f5d4bSLad Prabhakar 	int ret;
2587576f5d4bSLad Prabhakar 
2588576f5d4bSLad Prabhakar 	if (!on) {
2589576f5d4bSLad Prabhakar 		/* Reset settings to their default values. */
259068579b32SHugues Fruchet 		ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
2591311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2592311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
2593576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
2594576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
2595576f5d4bSLad Prabhakar 		return 0;
2596576f5d4bSLad Prabhakar 	}
2597576f5d4bSLad Prabhakar 
2598576f5d4bSLad Prabhakar 	/*
2599311a6408SLad Prabhakar 	 * Note about parallel port configuration.
2600311a6408SLad Prabhakar 	 *
2601311a6408SLad Prabhakar 	 * When configured in parallel mode, the OV5640 will
2602311a6408SLad Prabhakar 	 * output 10 bits data on DVP data lines [9:0].
2603311a6408SLad Prabhakar 	 * If only 8 bits data are wanted, the 8 bits data lines
2604311a6408SLad Prabhakar 	 * of the camera interface must be physically connected
2605311a6408SLad Prabhakar 	 * on the DVP data lines [9:2].
2606311a6408SLad Prabhakar 	 *
2607311a6408SLad Prabhakar 	 * Control lines polarity can be configured through
2608311a6408SLad Prabhakar 	 * devicetree endpoint control lines properties.
2609311a6408SLad Prabhakar 	 * If no endpoint control lines properties are set,
2610311a6408SLad Prabhakar 	 * polarity will be as below:
2611311a6408SLad Prabhakar 	 * - VSYNC:	active high
2612311a6408SLad Prabhakar 	 * - HREF:	active low
2613311a6408SLad Prabhakar 	 * - PCLK:	active low
261468579b32SHugues Fruchet 	 *
261568579b32SHugues Fruchet 	 * VSYNC & HREF are not configured if BT656 bus mode is selected
2616311a6408SLad Prabhakar 	 */
261768579b32SHugues Fruchet 
261868579b32SHugues Fruchet 	/*
261968579b32SHugues Fruchet 	 * BT656 embedded synchronization configuration
262068579b32SHugues Fruchet 	 *
262168579b32SHugues Fruchet 	 * CCIR656 CTRL00
262268579b32SHugues Fruchet 	 * - [7]:	SYNC code selection (0: auto generate sync code,
262368579b32SHugues Fruchet 	 *		1: sync code from regs 0x4732-0x4735)
262468579b32SHugues Fruchet 	 * - [6]:	f value in CCIR656 SYNC code when fixed f value
262568579b32SHugues Fruchet 	 * - [5]:	Fixed f value
262668579b32SHugues Fruchet 	 * - [4:3]:	Blank toggle data options (00: data=1'h040/1'h200,
262768579b32SHugues Fruchet 	 *		01: data from regs 0x4736-0x4738, 10: always keep 0)
262868579b32SHugues Fruchet 	 * - [1]:	Clip data disable
262968579b32SHugues Fruchet 	 * - [0]:	CCIR656 mode enable
263068579b32SHugues Fruchet 	 *
263168579b32SHugues Fruchet 	 * Default CCIR656 SAV/EAV mode with default codes
263268579b32SHugues Fruchet 	 * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
263368579b32SHugues Fruchet 	 * - CCIR656 mode enable
263468579b32SHugues Fruchet 	 * - auto generation of sync codes
263568579b32SHugues Fruchet 	 * - blank toggle data 1'h040/1'h200
263668579b32SHugues Fruchet 	 * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
263768579b32SHugues Fruchet 	 */
263868579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
263968579b32SHugues Fruchet 			       bt656 ? 0x01 : 0x00);
264068579b32SHugues Fruchet 	if (ret)
264168579b32SHugues Fruchet 		return ret;
264268579b32SHugues Fruchet 
2643311a6408SLad Prabhakar 	/*
2644311a6408SLad Prabhakar 	 * configure parallel port control lines polarity
2645311a6408SLad Prabhakar 	 *
2646311a6408SLad Prabhakar 	 * POLARITY CTRL0
2647311a6408SLad Prabhakar 	 * - [5]:	PCLK polarity (0: active low, 1: active high)
2648311a6408SLad Prabhakar 	 * - [1]:	HREF polarity (0: active low, 1: active high)
2649311a6408SLad Prabhakar 	 * - [0]:	VSYNC polarity (mismatch here between
2650311a6408SLad Prabhakar 	 *		datasheet and hardware, 0 is active high
2651311a6408SLad Prabhakar 	 *		and 1 is active low...)
2652311a6408SLad Prabhakar 	 */
265368579b32SHugues Fruchet 	if (!bt656) {
2654311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
265568579b32SHugues Fruchet 			polarities |= BIT(1);
2656311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
265768579b32SHugues Fruchet 			polarities |= BIT(0);
265868579b32SHugues Fruchet 	}
265968579b32SHugues Fruchet 	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
266068579b32SHugues Fruchet 		polarities |= BIT(5);
2661311a6408SLad Prabhakar 
266268579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
2663311a6408SLad Prabhakar 	if (ret)
2664311a6408SLad Prabhakar 		return ret;
2665311a6408SLad Prabhakar 
2666311a6408SLad Prabhakar 	/*
266768579b32SHugues Fruchet 	 * powerdown MIPI TX/RX PHY & enable DVP
2668311a6408SLad Prabhakar 	 *
2669311a6408SLad Prabhakar 	 * MIPI CONTROL 00
267068579b32SHugues Fruchet 	 * [4] = 1	: Power down MIPI HS Tx
267168579b32SHugues Fruchet 	 * [3] = 1	: Power down MIPI LS Rx
267268579b32SHugues Fruchet 	 * [2] = 0	: DVP enable (MIPI disable)
2673311a6408SLad Prabhakar 	 */
2674311a6408SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
2675311a6408SLad Prabhakar 	if (ret)
2676311a6408SLad Prabhakar 		return ret;
2677311a6408SLad Prabhakar 
2678311a6408SLad Prabhakar 	/*
2679576f5d4bSLad Prabhakar 	 * enable VSYNC/HREF/PCLK DVP control lines
2680576f5d4bSLad Prabhakar 	 * & D[9:6] DVP data lines
2681576f5d4bSLad Prabhakar 	 *
2682576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 01
2683576f5d4bSLad Prabhakar 	 * - 6:		VSYNC output enable
2684576f5d4bSLad Prabhakar 	 * - 5:		HREF output enable
2685576f5d4bSLad Prabhakar 	 * - 4:		PCLK output enable
2686576f5d4bSLad Prabhakar 	 * - [3:0]:	D[9:6] output enable
2687576f5d4bSLad Prabhakar 	 */
26884039b037SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
268968579b32SHugues Fruchet 			       bt656 ? 0x1f : 0x7f);
2690576f5d4bSLad Prabhakar 	if (ret)
2691576f5d4bSLad Prabhakar 		return ret;
2692576f5d4bSLad Prabhakar 
2693576f5d4bSLad Prabhakar 	/*
2694576f5d4bSLad Prabhakar 	 * enable D[5:0] DVP data lines
2695576f5d4bSLad Prabhakar 	 *
2696576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 02
2697576f5d4bSLad Prabhakar 	 * - [7:2]:	D[5:0] output enable
2698576f5d4bSLad Prabhakar 	 */
2699576f5d4bSLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
2700576f5d4bSLad Prabhakar }
2701576f5d4bSLad Prabhakar 
27020f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
27030f7acb52SHugues Fruchet {
27040f7acb52SHugues Fruchet 	int ret = 0;
27050f7acb52SHugues Fruchet 
27060f7acb52SHugues Fruchet 	if (on) {
27070f7acb52SHugues Fruchet 		ret = ov5640_set_power_on(sensor);
27080f7acb52SHugues Fruchet 		if (ret)
27090f7acb52SHugues Fruchet 			return ret;
27100f7acb52SHugues Fruchet 
271119a81c14SSteve Longerbeam 		ret = ov5640_restore_mode(sensor);
271219a81c14SSteve Longerbeam 		if (ret)
271319a81c14SSteve Longerbeam 			goto power_off;
2714b1751ae6SLad Prabhakar 	}
271519a81c14SSteve Longerbeam 
2716576f5d4bSLad Prabhakar 	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
2717b1751ae6SLad Prabhakar 		ret = ov5640_set_power_mipi(sensor, on);
2718576f5d4bSLad Prabhakar 	else
2719576f5d4bSLad Prabhakar 		ret = ov5640_set_power_dvp(sensor, on);
2720b1751ae6SLad Prabhakar 	if (ret)
2721b1751ae6SLad Prabhakar 		goto power_off;
2722aa4bb8b8SJacopo Mondi 
2723b1751ae6SLad Prabhakar 	if (!on)
2724aa4bb8b8SJacopo Mondi 		ov5640_set_power_off(sensor);
272519a81c14SSteve Longerbeam 
272619a81c14SSteve Longerbeam 	return 0;
272719a81c14SSteve Longerbeam 
272819a81c14SSteve Longerbeam power_off:
27290f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
273019a81c14SSteve Longerbeam 	return ret;
273119a81c14SSteve Longerbeam }
273219a81c14SSteve Longerbeam 
273385644a9bSPaul Elder static int ov5640_sensor_suspend(struct device *dev)
273419a81c14SSteve Longerbeam {
273585644a9bSPaul Elder 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
273685644a9bSPaul Elder 	struct ov5640_dev *ov5640 = to_ov5640_dev(sd);
273719a81c14SSteve Longerbeam 
273885644a9bSPaul Elder 	return ov5640_set_power(ov5640, false);
273919a81c14SSteve Longerbeam }
274019a81c14SSteve Longerbeam 
274185644a9bSPaul Elder static int ov5640_sensor_resume(struct device *dev)
274285644a9bSPaul Elder {
274385644a9bSPaul Elder 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
274485644a9bSPaul Elder 	struct ov5640_dev *ov5640 = to_ov5640_dev(sd);
274519a81c14SSteve Longerbeam 
274685644a9bSPaul Elder 	return ov5640_set_power(ov5640, true);
274719a81c14SSteve Longerbeam }
274819a81c14SSteve Longerbeam 
274985644a9bSPaul Elder /* --------------- Subdev Operations --------------- */
275019a81c14SSteve Longerbeam 
275119a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
275219a81c14SSteve Longerbeam 				     struct v4l2_fract *fi,
2753f33b56d3SGuoniu.zhou 				     const struct ov5640_mode_info *mode_info)
275419a81c14SSteve Longerbeam {
2755f33b56d3SGuoniu.zhou 	const struct ov5640_mode_info *mode = mode_info;
27566530a5ebSJagan Teki 	enum ov5640_frame_rate rate = OV5640_15_FPS;
2757f6cc192fSMaxime Ripard 	int minfps, maxfps, best_fps, fps;
2758f6cc192fSMaxime Ripard 	int i;
275919a81c14SSteve Longerbeam 
276019a81c14SSteve Longerbeam 	minfps = ov5640_framerates[OV5640_15_FPS];
2761f33b56d3SGuoniu.zhou 	maxfps = ov5640_framerates[mode->max_fps];
276219a81c14SSteve Longerbeam 
276319a81c14SSteve Longerbeam 	if (fi->numerator == 0) {
276419a81c14SSteve Longerbeam 		fi->denominator = maxfps;
276519a81c14SSteve Longerbeam 		fi->numerator = 1;
2766f33b56d3SGuoniu.zhou 		rate = mode->max_fps;
2767e823fb16SMaxime Ripard 		goto find_mode;
276819a81c14SSteve Longerbeam 	}
276919a81c14SSteve Longerbeam 
2770f6cc192fSMaxime Ripard 	fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
2771f6cc192fSMaxime Ripard 			minfps, maxfps);
2772f6cc192fSMaxime Ripard 
2773f6cc192fSMaxime Ripard 	best_fps = minfps;
2774f6cc192fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
2775f6cc192fSMaxime Ripard 		int curr_fps = ov5640_framerates[i];
2776f6cc192fSMaxime Ripard 
2777f6cc192fSMaxime Ripard 		if (abs(curr_fps - fps) < abs(best_fps - fps)) {
2778f6cc192fSMaxime Ripard 			best_fps = curr_fps;
2779f6cc192fSMaxime Ripard 			rate = i;
2780f6cc192fSMaxime Ripard 		}
2781f6cc192fSMaxime Ripard 	}
278219a81c14SSteve Longerbeam 
278319a81c14SSteve Longerbeam 	fi->numerator = 1;
2784f6cc192fSMaxime Ripard 	fi->denominator = best_fps;
278519a81c14SSteve Longerbeam 
2786e823fb16SMaxime Ripard find_mode:
2787f33b56d3SGuoniu.zhou 	mode = ov5640_find_mode(sensor, mode->width, mode->height, false);
27885a3ad937SMaxime Ripard 	return mode ? rate : -EINVAL;
278919a81c14SSteve Longerbeam }
279019a81c14SSteve Longerbeam 
279119a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd,
27920d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
279319a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
279419a81c14SSteve Longerbeam {
279519a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
279619a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt *fmt;
279719a81c14SSteve Longerbeam 
279819a81c14SSteve Longerbeam 	if (format->pad != 0)
279919a81c14SSteve Longerbeam 		return -EINVAL;
280019a81c14SSteve Longerbeam 
280119a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
280219a81c14SSteve Longerbeam 
280319a81c14SSteve Longerbeam 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
28040d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
280519a81c14SSteve Longerbeam 						 format->pad);
280619a81c14SSteve Longerbeam 	else
280719a81c14SSteve Longerbeam 		fmt = &sensor->fmt;
280819a81c14SSteve Longerbeam 
280919a81c14SSteve Longerbeam 	format->format = *fmt;
281019a81c14SSteve Longerbeam 
281119a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
281219a81c14SSteve Longerbeam 
281319a81c14SSteve Longerbeam 	return 0;
281419a81c14SSteve Longerbeam }
281519a81c14SSteve Longerbeam 
281619a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
281719a81c14SSteve Longerbeam 				   struct v4l2_mbus_framefmt *fmt,
281819a81c14SSteve Longerbeam 				   enum ov5640_frame_rate fr,
281919a81c14SSteve Longerbeam 				   const struct ov5640_mode_info **new_mode)
282019a81c14SSteve Longerbeam {
282119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
282219a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
2823a89f14bbSJacopo Mondi 	const struct ov5640_pixfmt *pixfmt;
2824a89f14bbSJacopo Mondi 	unsigned int bpp;
282519a81c14SSteve Longerbeam 
2826b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, fmt->width, fmt->height, true);
282719a81c14SSteve Longerbeam 	if (!mode)
282819a81c14SSteve Longerbeam 		return -EINVAL;
2829dd81b8ffSJacopo Mondi 
2830a89f14bbSJacopo Mondi 	pixfmt = ov5640_code_to_pixfmt(sensor, fmt->code);
2831a89f14bbSJacopo Mondi 	bpp = pixfmt->bpp;
2832a89f14bbSJacopo Mondi 
2833dd81b8ffSJacopo Mondi 	/*
2834dd81b8ffSJacopo Mondi 	 * Adjust mode according to bpp:
2835dd81b8ffSJacopo Mondi 	 * - 8bpp modes work for resolution >= 1280x720
2836dd81b8ffSJacopo Mondi 	 * - 24bpp modes work resolution < 1280x720
2837dd81b8ffSJacopo Mondi 	 */
2838dd81b8ffSJacopo Mondi 	if (bpp == 8 && mode->width < 1280)
2839dd81b8ffSJacopo Mondi 		mode = &ov5640_mode_data[OV5640_MODE_720P_1280_720];
2840dd81b8ffSJacopo Mondi 	else if (bpp == 24 && mode->width > 1024)
2841dd81b8ffSJacopo Mondi 		mode = &ov5640_mode_data[OV5640_MODE_XGA_1024_768];
2842dd81b8ffSJacopo Mondi 
28435113d5b3SJacopo Mondi 	fmt->width = mode->width;
28445113d5b3SJacopo Mondi 	fmt->height = mode->height;
284519a81c14SSteve Longerbeam 
284619a81c14SSteve Longerbeam 	if (new_mode)
284719a81c14SSteve Longerbeam 		*new_mode = mode;
2848e3ee691dSHugues Fruchet 
2849a89f14bbSJacopo Mondi 	fmt->code = pixfmt->code;
2850a89f14bbSJacopo Mondi 	fmt->colorspace = pixfmt->colorspace;
2851e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
2852e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2853e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
2854e3ee691dSHugues Fruchet 
285519a81c14SSteve Longerbeam 	return 0;
285619a81c14SSteve Longerbeam }
285719a81c14SSteve Longerbeam 
28583c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
28593c28588fSJacopo Mondi {
28603c28588fSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
28613c28588fSJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
28623c28588fSJacopo Mondi 	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
286332979f67SJacopo Mondi 	const struct ov5640_timings *timings;
2864bce93b82SJacopo Mondi 	s32 exposure_val, exposure_max;
286532979f67SJacopo Mondi 	unsigned int hblank;
28663c28588fSJacopo Mondi 	unsigned int i = 0;
28673c28588fSJacopo Mondi 	u32 pixel_rate;
28683c28588fSJacopo Mondi 	s64 link_freq;
28693c28588fSJacopo Mondi 	u32 num_lanes;
287019f2e3e6SHugues Fruchet 	u32 vblank;
28713c28588fSJacopo Mondi 	u32 bpp;
28723c28588fSJacopo Mondi 
28733c28588fSJacopo Mondi 	/*
28743c28588fSJacopo Mondi 	 * Update the pixel rate control value.
28753c28588fSJacopo Mondi 	 *
28763c28588fSJacopo Mondi 	 * For DVP mode, maintain the pixel rate calculation using fixed FPS.
28773c28588fSJacopo Mondi 	 */
28783c28588fSJacopo Mondi 	if (!ov5640_is_csi2(sensor)) {
28793c28588fSJacopo Mondi 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
28803c28588fSJacopo Mondi 					 ov5640_calc_pixel_rate(sensor));
28813c28588fSJacopo Mondi 
28823c28588fSJacopo Mondi 		return 0;
28833c28588fSJacopo Mondi 	}
28843c28588fSJacopo Mondi 
28853c28588fSJacopo Mondi 	/*
28863c28588fSJacopo Mondi 	 * The MIPI CSI-2 link frequency should comply with the CSI-2
28873c28588fSJacopo Mondi 	 * specification and be lower than 1GHz.
28883c28588fSJacopo Mondi 	 *
28893c28588fSJacopo Mondi 	 * Start from the suggested pixel_rate for the current mode and
28903c28588fSJacopo Mondi 	 * progressively slow it down if it exceeds 1GHz.
28913c28588fSJacopo Mondi 	 */
28923c28588fSJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
2893a89f14bbSJacopo Mondi 	bpp = ov5640_code_to_bpp(sensor, fmt->code);
28943c28588fSJacopo Mondi 	do {
28953c28588fSJacopo Mondi 		pixel_rate = ov5640_pixel_rates[pixel_rate_id];
28963c28588fSJacopo Mondi 		link_freq = pixel_rate * bpp / (2 * num_lanes);
28973c28588fSJacopo Mondi 	} while (link_freq >= 1000000000U &&
28983c28588fSJacopo Mondi 		 ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
28993c28588fSJacopo Mondi 
29003c28588fSJacopo Mondi 	sensor->current_link_freq = link_freq;
29013c28588fSJacopo Mondi 
29023c28588fSJacopo Mondi 	/*
29033c28588fSJacopo Mondi 	 * Higher link rates require the clock tree to be programmed with
29043c28588fSJacopo Mondi 	 * 'mipi_div' = 1; this has the effect of halving the actual output
29053c28588fSJacopo Mondi 	 * pixel rate in the MIPI domain.
29063c28588fSJacopo Mondi 	 *
29073c28588fSJacopo Mondi 	 * Adjust the pixel rate and link frequency control value to report it
29083c28588fSJacopo Mondi 	 * correctly to userspace.
29093c28588fSJacopo Mondi 	 */
29103c28588fSJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX) {
29113c28588fSJacopo Mondi 		pixel_rate /= 2;
29123c28588fSJacopo Mondi 		link_freq /= 2;
29133c28588fSJacopo Mondi 	}
29143c28588fSJacopo Mondi 
29153c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
29163c28588fSJacopo Mondi 		if (ov5640_csi2_link_freqs[i] == link_freq)
29173c28588fSJacopo Mondi 			break;
29183c28588fSJacopo Mondi 	}
29193c28588fSJacopo Mondi 	WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
29203c28588fSJacopo Mondi 
29213c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
29223c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
29233c28588fSJacopo Mondi 
292432979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
292532979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
292632979f67SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.hblank,
292732979f67SJacopo Mondi 				 hblank, hblank, 1, hblank);
292832979f67SJacopo Mondi 
292919f2e3e6SHugues Fruchet 	vblank = timings->vblank_def;
2930bce93b82SJacopo Mondi 
293119f2e3e6SHugues Fruchet 	if (sensor->current_fr != mode->def_fps) {
293219f2e3e6SHugues Fruchet 		/*
293319f2e3e6SHugues Fruchet 		 * Compute the vertical blanking according to the framerate
293419f2e3e6SHugues Fruchet 		 * configured with s_frame_interval.
293519f2e3e6SHugues Fruchet 		 */
293619f2e3e6SHugues Fruchet 		int fie_num = sensor->frame_interval.numerator;
293719f2e3e6SHugues Fruchet 		int fie_denom = sensor->frame_interval.denominator;
293819f2e3e6SHugues Fruchet 
293919f2e3e6SHugues Fruchet 		vblank = ((fie_num * pixel_rate / fie_denom) / timings->htot) -
294019f2e3e6SHugues Fruchet 			mode->height;
294119f2e3e6SHugues Fruchet 	}
294219f2e3e6SHugues Fruchet 
294319f2e3e6SHugues Fruchet 	__v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK,
294419f2e3e6SHugues Fruchet 				 OV5640_MAX_VTS - mode->height, 1, vblank);
294519f2e3e6SHugues Fruchet 	__v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, vblank);
294619f2e3e6SHugues Fruchet 
294719f2e3e6SHugues Fruchet 	exposure_max = timings->crop.height + vblank - 4;
2948bce93b82SJacopo Mondi 	exposure_val = clamp_t(s32, sensor->ctrls.exposure->val,
2949bce93b82SJacopo Mondi 			       sensor->ctrls.exposure->minimum,
2950bce93b82SJacopo Mondi 			       exposure_max);
295119f2e3e6SHugues Fruchet 
2952bce93b82SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
2953bce93b82SJacopo Mondi 				 sensor->ctrls.exposure->minimum,
2954bce93b82SJacopo Mondi 				 exposure_max, 1, exposure_val);
2955bce93b82SJacopo Mondi 
29563c28588fSJacopo Mondi 	return 0;
29573c28588fSJacopo Mondi }
29583c28588fSJacopo Mondi 
295919a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd,
29600d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
296119a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
296219a81c14SSteve Longerbeam {
296319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
296419a81c14SSteve Longerbeam 	const struct ov5640_mode_info *new_mode;
2965e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
296619a81c14SSteve Longerbeam 	int ret;
296719a81c14SSteve Longerbeam 
296819a81c14SSteve Longerbeam 	if (format->pad != 0)
296919a81c14SSteve Longerbeam 		return -EINVAL;
297019a81c14SSteve Longerbeam 
297119a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
297219a81c14SSteve Longerbeam 
297319a81c14SSteve Longerbeam 	if (sensor->streaming) {
297419a81c14SSteve Longerbeam 		ret = -EBUSY;
297519a81c14SSteve Longerbeam 		goto out;
297619a81c14SSteve Longerbeam 	}
297719a81c14SSteve Longerbeam 
2978e6441fdeSHugues Fruchet 	ret = ov5640_try_fmt_internal(sd, mbus_fmt,
297919a81c14SSteve Longerbeam 				      sensor->current_fr, &new_mode);
298019a81c14SSteve Longerbeam 	if (ret)
298119a81c14SSteve Longerbeam 		goto out;
298219a81c14SSteve Longerbeam 
2983e738f5ddSMirela Rabulea 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2984e738f5ddSMirela Rabulea 		*v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
2985e738f5ddSMirela Rabulea 		goto out;
2986e738f5ddSMirela Rabulea 	}
298719a81c14SSteve Longerbeam 
29886949d864SHugues Fruchet 	if (new_mode != sensor->current_mode) {
298919f2e3e6SHugues Fruchet 		sensor->current_fr = new_mode->def_fps;
299019a81c14SSteve Longerbeam 		sensor->current_mode = new_mode;
299119a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
29926949d864SHugues Fruchet 	}
299307115449SJacopo Mondi 	if (mbus_fmt->code != sensor->fmt.code)
2994fb98e29fSHugues Fruchet 		sensor->pending_fmt_change = true;
299507115449SJacopo Mondi 
2996e738f5ddSMirela Rabulea 	/* update format even if code is unchanged, resolution might change */
2997e738f5ddSMirela Rabulea 	sensor->fmt = *mbus_fmt;
2998e738f5ddSMirela Rabulea 
29993c28588fSJacopo Mondi 	ov5640_update_pixel_rate(sensor);
30003c28588fSJacopo Mondi 
300119a81c14SSteve Longerbeam out:
300219a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
300319a81c14SSteve Longerbeam 	return ret;
300419a81c14SSteve Longerbeam }
300519a81c14SSteve Longerbeam 
300666ed85ebSJacopo Mondi static int ov5640_get_selection(struct v4l2_subdev *sd,
300766ed85ebSJacopo Mondi 				struct v4l2_subdev_state *sd_state,
300866ed85ebSJacopo Mondi 				struct v4l2_subdev_selection *sel)
300966ed85ebSJacopo Mondi {
301066ed85ebSJacopo Mondi 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
301166ed85ebSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
301266ed85ebSJacopo Mondi 	const struct ov5640_timings *timings;
301366ed85ebSJacopo Mondi 
301466ed85ebSJacopo Mondi 	switch (sel->target) {
301566ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP: {
301666ed85ebSJacopo Mondi 		mutex_lock(&sensor->lock);
301766ed85ebSJacopo Mondi 		timings = ov5640_timings(sensor, mode);
301866ed85ebSJacopo Mondi 		sel->r = timings->analog_crop;
301966ed85ebSJacopo Mondi 		mutex_unlock(&sensor->lock);
302066ed85ebSJacopo Mondi 
302166ed85ebSJacopo Mondi 		return 0;
302266ed85ebSJacopo Mondi 	}
302366ed85ebSJacopo Mondi 
302466ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_NATIVE_SIZE:
302566ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP_BOUNDS:
302666ed85ebSJacopo Mondi 		sel->r.top = 0;
302766ed85ebSJacopo Mondi 		sel->r.left = 0;
302866ed85ebSJacopo Mondi 		sel->r.width = OV5640_NATIVE_WIDTH;
302966ed85ebSJacopo Mondi 		sel->r.height = OV5640_NATIVE_HEIGHT;
303066ed85ebSJacopo Mondi 
303166ed85ebSJacopo Mondi 		return 0;
303266ed85ebSJacopo Mondi 
303366ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP_DEFAULT:
303466ed85ebSJacopo Mondi 		sel->r.top = OV5640_PIXEL_ARRAY_TOP;
303566ed85ebSJacopo Mondi 		sel->r.left = OV5640_PIXEL_ARRAY_LEFT;
303666ed85ebSJacopo Mondi 		sel->r.width = OV5640_PIXEL_ARRAY_WIDTH;
303766ed85ebSJacopo Mondi 		sel->r.height = OV5640_PIXEL_ARRAY_HEIGHT;
303866ed85ebSJacopo Mondi 
303966ed85ebSJacopo Mondi 		return 0;
304066ed85ebSJacopo Mondi 	}
304166ed85ebSJacopo Mondi 
304266ed85ebSJacopo Mondi 	return -EINVAL;
304366ed85ebSJacopo Mondi }
304466ed85ebSJacopo Mondi 
3045e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor,
3046e3ee691dSHugues Fruchet 			       struct v4l2_mbus_framefmt *format)
3047e3ee691dSHugues Fruchet {
3048935fbc94SJacopo Mondi 	bool is_jpeg = format->code == MEDIA_BUS_FMT_JPEG_1X8;
3049935fbc94SJacopo Mondi 	const struct ov5640_pixfmt *pixfmt;
3050e3ee691dSHugues Fruchet 	int ret = 0;
3051e3ee691dSHugues Fruchet 
3052935fbc94SJacopo Mondi 	pixfmt = ov5640_code_to_pixfmt(sensor, format->code);
3053e3ee691dSHugues Fruchet 
3054e3ee691dSHugues Fruchet 	/* FORMAT CONTROL00: YUV and RGB formatting */
3055935fbc94SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00,
3056935fbc94SJacopo Mondi 			       pixfmt->ctrl00);
3057e3ee691dSHugues Fruchet 	if (ret)
3058e3ee691dSHugues Fruchet 		return ret;
3059e3ee691dSHugues Fruchet 
3060e3ee691dSHugues Fruchet 	/* FORMAT MUX CONTROL: ISP YUV or RGB */
3061935fbc94SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL,
3062935fbc94SJacopo Mondi 			       pixfmt->mux);
3063d47c4126SHugues Fruchet 	if (ret)
3064d47c4126SHugues Fruchet 		return ret;
3065d47c4126SHugues Fruchet 
3066d47c4126SHugues Fruchet 	/*
3067d47c4126SHugues Fruchet 	 * TIMING TC REG21:
3068d47c4126SHugues Fruchet 	 * - [5]:	JPEG enable
3069d47c4126SHugues Fruchet 	 */
3070d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3071d47c4126SHugues Fruchet 			     BIT(5), is_jpeg ? BIT(5) : 0);
3072d47c4126SHugues Fruchet 	if (ret)
3073d47c4126SHugues Fruchet 		return ret;
3074d47c4126SHugues Fruchet 
3075d47c4126SHugues Fruchet 	/*
3076d47c4126SHugues Fruchet 	 * SYSTEM RESET02:
3077d47c4126SHugues Fruchet 	 * - [4]:	Reset JFIFO
3078d47c4126SHugues Fruchet 	 * - [3]:	Reset SFIFO
3079d47c4126SHugues Fruchet 	 * - [2]:	Reset JPEG
3080d47c4126SHugues Fruchet 	 */
3081d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
3082d47c4126SHugues Fruchet 			     BIT(4) | BIT(3) | BIT(2),
3083d47c4126SHugues Fruchet 			     is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
3084d47c4126SHugues Fruchet 	if (ret)
3085d47c4126SHugues Fruchet 		return ret;
3086d47c4126SHugues Fruchet 
3087d47c4126SHugues Fruchet 	/*
3088d47c4126SHugues Fruchet 	 * CLOCK ENABLE02:
3089d47c4126SHugues Fruchet 	 * - [5]:	Enable JPEG 2x clock
3090d47c4126SHugues Fruchet 	 * - [3]:	Enable JPEG clock
3091d47c4126SHugues Fruchet 	 */
3092d47c4126SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
3093d47c4126SHugues Fruchet 			      BIT(5) | BIT(3),
3094d47c4126SHugues Fruchet 			      is_jpeg ? (BIT(5) | BIT(3)) : 0);
3095e3ee691dSHugues Fruchet }
309619a81c14SSteve Longerbeam 
309719a81c14SSteve Longerbeam /*
309819a81c14SSteve Longerbeam  * Sensor Controls.
309919a81c14SSteve Longerbeam  */
310019a81c14SSteve Longerbeam 
310119a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
310219a81c14SSteve Longerbeam {
310319a81c14SSteve Longerbeam 	int ret;
310419a81c14SSteve Longerbeam 
310519a81c14SSteve Longerbeam 	if (value) {
310619a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
310719a81c14SSteve Longerbeam 				     BIT(0), BIT(0));
310819a81c14SSteve Longerbeam 		if (ret)
310919a81c14SSteve Longerbeam 			return ret;
311019a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
311119a81c14SSteve Longerbeam 	} else {
311219a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
311319a81c14SSteve Longerbeam 	}
311419a81c14SSteve Longerbeam 
311519a81c14SSteve Longerbeam 	return ret;
311619a81c14SSteve Longerbeam }
311719a81c14SSteve Longerbeam 
311819a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
311919a81c14SSteve Longerbeam {
312019a81c14SSteve Longerbeam 	int ret;
312119a81c14SSteve Longerbeam 
312219a81c14SSteve Longerbeam 	if (value) {
312319a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
312419a81c14SSteve Longerbeam 				     BIT(2), BIT(2));
312519a81c14SSteve Longerbeam 		if (ret)
312619a81c14SSteve Longerbeam 			return ret;
312719a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
312819a81c14SSteve Longerbeam 				       value & 0xff);
312919a81c14SSteve Longerbeam 	} else {
313019a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
313119a81c14SSteve Longerbeam 	}
313219a81c14SSteve Longerbeam 
313319a81c14SSteve Longerbeam 	return ret;
313419a81c14SSteve Longerbeam }
313519a81c14SSteve Longerbeam 
313619a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value)
313719a81c14SSteve Longerbeam {
313819a81c14SSteve Longerbeam 	int ret;
313919a81c14SSteve Longerbeam 
314019a81c14SSteve Longerbeam 	if (value) {
314119a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
314219a81c14SSteve Longerbeam 				     BIT(1), BIT(1));
314319a81c14SSteve Longerbeam 		if (ret)
314419a81c14SSteve Longerbeam 			return ret;
314519a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
314619a81c14SSteve Longerbeam 				       value & 0xff);
314719a81c14SSteve Longerbeam 		if (ret)
314819a81c14SSteve Longerbeam 			return ret;
314919a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
315019a81c14SSteve Longerbeam 				       value & 0xff);
315119a81c14SSteve Longerbeam 	} else {
315219a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
315319a81c14SSteve Longerbeam 	}
315419a81c14SSteve Longerbeam 
315519a81c14SSteve Longerbeam 	return ret;
315619a81c14SSteve Longerbeam }
315719a81c14SSteve Longerbeam 
315819a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
315919a81c14SSteve Longerbeam {
316019a81c14SSteve Longerbeam 	int ret;
316119a81c14SSteve Longerbeam 
316219a81c14SSteve Longerbeam 	ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
316319a81c14SSteve Longerbeam 			     BIT(0), awb ? 0 : 1);
316419a81c14SSteve Longerbeam 	if (ret)
316519a81c14SSteve Longerbeam 		return ret;
316619a81c14SSteve Longerbeam 
316719a81c14SSteve Longerbeam 	if (!awb) {
316819a81c14SSteve Longerbeam 		u16 red = (u16)sensor->ctrls.red_balance->val;
316919a81c14SSteve Longerbeam 		u16 blue = (u16)sensor->ctrls.blue_balance->val;
317019a81c14SSteve Longerbeam 
317119a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
317219a81c14SSteve Longerbeam 		if (ret)
317319a81c14SSteve Longerbeam 			return ret;
317419a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
317519a81c14SSteve Longerbeam 	}
317619a81c14SSteve Longerbeam 
317719a81c14SSteve Longerbeam 	return ret;
317819a81c14SSteve Longerbeam }
317919a81c14SSteve Longerbeam 
31803cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
31813cca8ef5SHugues Fruchet 				    enum v4l2_exposure_auto_type auto_exposure)
318219a81c14SSteve Longerbeam {
318319a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
31843cca8ef5SHugues Fruchet 	bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
318519a81c14SSteve Longerbeam 	int ret = 0;
318619a81c14SSteve Longerbeam 
318719a81c14SSteve Longerbeam 	if (ctrls->auto_exp->is_new) {
31883cca8ef5SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, auto_exp);
318919a81c14SSteve Longerbeam 		if (ret)
319019a81c14SSteve Longerbeam 			return ret;
319119a81c14SSteve Longerbeam 	}
319219a81c14SSteve Longerbeam 
31933cca8ef5SHugues Fruchet 	if (!auto_exp && ctrls->exposure->is_new) {
319419a81c14SSteve Longerbeam 		u16 max_exp;
319519a81c14SSteve Longerbeam 
319619a81c14SSteve Longerbeam 		ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
319719a81c14SSteve Longerbeam 					&max_exp);
319819a81c14SSteve Longerbeam 		if (ret)
319919a81c14SSteve Longerbeam 			return ret;
320019a81c14SSteve Longerbeam 		ret = ov5640_get_vts(sensor);
320119a81c14SSteve Longerbeam 		if (ret < 0)
320219a81c14SSteve Longerbeam 			return ret;
320319a81c14SSteve Longerbeam 		max_exp += ret;
32046146fde3SHugues Fruchet 		ret = 0;
320519a81c14SSteve Longerbeam 
320619a81c14SSteve Longerbeam 		if (ctrls->exposure->val < max_exp)
320719a81c14SSteve Longerbeam 			ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
320819a81c14SSteve Longerbeam 	}
320919a81c14SSteve Longerbeam 
321019a81c14SSteve Longerbeam 	return ret;
321119a81c14SSteve Longerbeam }
321219a81c14SSteve Longerbeam 
32133cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
321419a81c14SSteve Longerbeam {
321519a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
321619a81c14SSteve Longerbeam 	int ret = 0;
321719a81c14SSteve Longerbeam 
321819a81c14SSteve Longerbeam 	if (ctrls->auto_gain->is_new) {
32193cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, auto_gain);
322019a81c14SSteve Longerbeam 		if (ret)
322119a81c14SSteve Longerbeam 			return ret;
322219a81c14SSteve Longerbeam 	}
322319a81c14SSteve Longerbeam 
32243cca8ef5SHugues Fruchet 	if (!auto_gain && ctrls->gain->is_new)
32253cca8ef5SHugues Fruchet 		ret = ov5640_set_gain(sensor, ctrls->gain->val);
322619a81c14SSteve Longerbeam 
322719a81c14SSteve Longerbeam 	return ret;
322819a81c14SSteve Longerbeam }
322919a81c14SSteve Longerbeam 
32309f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = {
32319f6d7bacSChen-Yu Tsai 	"Disabled",
32329f6d7bacSChen-Yu Tsai 	"Color bars",
3233bddc5cdfSChen-Yu Tsai 	"Color bars w/ rolling bar",
3234bddc5cdfSChen-Yu Tsai 	"Color squares",
3235bddc5cdfSChen-Yu Tsai 	"Color squares w/ rolling bar",
32369f6d7bacSChen-Yu Tsai };
32379f6d7bacSChen-Yu Tsai 
3238a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE		BIT(7)
3239a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING		BIT(6)	/* rolling horizontal bar */
3240a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT		BIT(5)
3241a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW		BIT(4)	/* black & white squares */
3242a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD	(0 << 2)
3243a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1	(1 << 2)
3244a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE	(2 << 2)
3245a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2	(3 << 2)
3246a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR			(0 << 0)
3247a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM		(1 << 0)
3248a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE		(2 << 0)
3249a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK		(3 << 0)
3250a0c29afbSChen-Yu Tsai 
3251a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = {
3252a0c29afbSChen-Yu Tsai 	0,
32532aff1fc3SChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
3254a0c29afbSChen-Yu Tsai 		OV5640_TEST_BAR,
3255bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
3256bddc5cdfSChen-Yu Tsai 		OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
3257bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
3258bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
3259a0c29afbSChen-Yu Tsai };
3260a0c29afbSChen-Yu Tsai 
326119a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
326219a81c14SSteve Longerbeam {
3263a0c29afbSChen-Yu Tsai 	return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
3264a0c29afbSChen-Yu Tsai 				test_pattern_val[value]);
326519a81c14SSteve Longerbeam }
326619a81c14SSteve Longerbeam 
32671068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
32681068fecaSMylène Josserand {
32691068fecaSMylène Josserand 	int ret;
32701068fecaSMylène Josserand 
32711068fecaSMylène Josserand 	ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
32721068fecaSMylène Josserand 			     (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
32731068fecaSMylène Josserand 			     0 : BIT(7));
32741068fecaSMylène Josserand 	if (ret)
32751068fecaSMylène Josserand 		return ret;
32761068fecaSMylène Josserand 
32771068fecaSMylène Josserand 	return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
32781068fecaSMylène Josserand 			      (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
32791068fecaSMylène Josserand 			      BIT(2) : 0);
32801068fecaSMylène Josserand }
32811068fecaSMylène Josserand 
3282ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
3283ce85705aSHugues Fruchet {
3284ce85705aSHugues Fruchet 	/*
3285c3f3ba3eSHugues Fruchet 	 * If sensor is mounted upside down, mirror logic is inversed.
3286c3f3ba3eSHugues Fruchet 	 *
3287ce85705aSHugues Fruchet 	 * Sensor is a BSI (Back Side Illuminated) one,
3288ce85705aSHugues Fruchet 	 * so image captured is physically mirrored.
3289ce85705aSHugues Fruchet 	 * This is why mirror logic is inversed in
3290ce85705aSHugues Fruchet 	 * order to cancel this mirror effect.
3291ce85705aSHugues Fruchet 	 */
3292ce85705aSHugues Fruchet 
3293ce85705aSHugues Fruchet 	/*
3294ce85705aSHugues Fruchet 	 * TIMING TC REG21:
3295ce85705aSHugues Fruchet 	 * - [2]:	ISP mirror
3296ce85705aSHugues Fruchet 	 * - [1]:	Sensor mirror
3297ce85705aSHugues Fruchet 	 */
3298ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3299ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3300c3f3ba3eSHugues Fruchet 			      (!(value ^ sensor->upside_down)) ?
3301c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3302ce85705aSHugues Fruchet }
3303ce85705aSHugues Fruchet 
3304ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
3305ce85705aSHugues Fruchet {
3306c3f3ba3eSHugues Fruchet 	/* If sensor is mounted upside down, flip logic is inversed */
3307c3f3ba3eSHugues Fruchet 
3308ce85705aSHugues Fruchet 	/*
3309ce85705aSHugues Fruchet 	 * TIMING TC REG20:
3310ce85705aSHugues Fruchet 	 * - [2]:	ISP vflip
3311ce85705aSHugues Fruchet 	 * - [1]:	Sensor vflip
3312ce85705aSHugues Fruchet 	 */
3313ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
3314ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3315c3f3ba3eSHugues Fruchet 			      (value ^ sensor->upside_down) ?
3316c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3317ce85705aSHugues Fruchet }
3318ce85705aSHugues Fruchet 
3319bce93b82SJacopo Mondi static int ov5640_set_ctrl_vblank(struct ov5640_dev *sensor, int value)
3320bce93b82SJacopo Mondi {
3321bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3322bce93b82SJacopo Mondi 
3323bce93b82SJacopo Mondi 	/* Update the VTOT timing register value. */
3324bce93b82SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
3325bce93b82SJacopo Mondi 				  mode->height + value);
3326bce93b82SJacopo Mondi }
3327bce93b82SJacopo Mondi 
332819a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
332919a81c14SSteve Longerbeam {
333019a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
333119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
333219a81c14SSteve Longerbeam 	int val;
333319a81c14SSteve Longerbeam 
333419a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
333519a81c14SSteve Longerbeam 
333685644a9bSPaul Elder 	if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
333785644a9bSPaul Elder 		return 0;
333885644a9bSPaul Elder 
333919a81c14SSteve Longerbeam 	switch (ctrl->id) {
334019a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
334119a81c14SSteve Longerbeam 		val = ov5640_get_gain(sensor);
334219a81c14SSteve Longerbeam 		if (val < 0)
334319a81c14SSteve Longerbeam 			return val;
334419a81c14SSteve Longerbeam 		sensor->ctrls.gain->val = val;
334519a81c14SSteve Longerbeam 		break;
334619a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
334719a81c14SSteve Longerbeam 		val = ov5640_get_exposure(sensor);
334819a81c14SSteve Longerbeam 		if (val < 0)
334919a81c14SSteve Longerbeam 			return val;
335019a81c14SSteve Longerbeam 		sensor->ctrls.exposure->val = val;
335119a81c14SSteve Longerbeam 		break;
335219a81c14SSteve Longerbeam 	}
335319a81c14SSteve Longerbeam 
3354e13064a3SAndrey Skvortsov 	pm_runtime_mark_last_busy(&sensor->i2c_client->dev);
335585644a9bSPaul Elder 	pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
335685644a9bSPaul Elder 
335719a81c14SSteve Longerbeam 	return 0;
335819a81c14SSteve Longerbeam }
335919a81c14SSteve Longerbeam 
336019a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
336119a81c14SSteve Longerbeam {
336219a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
336319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3364bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3365bce93b82SJacopo Mondi 	const struct ov5640_timings *timings;
3366bce93b82SJacopo Mondi 	unsigned int exp_max;
336719a81c14SSteve Longerbeam 	int ret;
336819a81c14SSteve Longerbeam 
336919a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
337019a81c14SSteve Longerbeam 
3371bce93b82SJacopo Mondi 	switch (ctrl->id) {
3372bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3373bce93b82SJacopo Mondi 		/* Update the exposure range to the newly programmed vblank. */
3374bce93b82SJacopo Mondi 		timings = ov5640_timings(sensor, mode);
3375bce93b82SJacopo Mondi 		exp_max = mode->height + ctrl->val - 4;
3376bce93b82SJacopo Mondi 		__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
3377bce93b82SJacopo Mondi 					 sensor->ctrls.exposure->minimum,
3378bce93b82SJacopo Mondi 					 exp_max, sensor->ctrls.exposure->step,
3379bce93b82SJacopo Mondi 					 timings->vblank_def);
3380bce93b82SJacopo Mondi 		break;
3381bce93b82SJacopo Mondi 	}
3382bce93b82SJacopo Mondi 
338319a81c14SSteve Longerbeam 	/*
338419a81c14SSteve Longerbeam 	 * If the device is not powered up by the host driver do
338519a81c14SSteve Longerbeam 	 * not apply any controls to H/W at this time. Instead
338685644a9bSPaul Elder 	 * the controls will be restored at start streaming time.
338719a81c14SSteve Longerbeam 	 */
338885644a9bSPaul Elder 	if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
338919a81c14SSteve Longerbeam 		return 0;
339019a81c14SSteve Longerbeam 
339119a81c14SSteve Longerbeam 	switch (ctrl->id) {
339219a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
339319a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
339419a81c14SSteve Longerbeam 		break;
339519a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
339619a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
339719a81c14SSteve Longerbeam 		break;
339819a81c14SSteve Longerbeam 	case V4L2_CID_AUTO_WHITE_BALANCE:
339919a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
340019a81c14SSteve Longerbeam 		break;
340119a81c14SSteve Longerbeam 	case V4L2_CID_HUE:
340219a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
340319a81c14SSteve Longerbeam 		break;
340419a81c14SSteve Longerbeam 	case V4L2_CID_CONTRAST:
340519a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
340619a81c14SSteve Longerbeam 		break;
340719a81c14SSteve Longerbeam 	case V4L2_CID_SATURATION:
340819a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
340919a81c14SSteve Longerbeam 		break;
341019a81c14SSteve Longerbeam 	case V4L2_CID_TEST_PATTERN:
341119a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
341219a81c14SSteve Longerbeam 		break;
34131068fecaSMylène Josserand 	case V4L2_CID_POWER_LINE_FREQUENCY:
34141068fecaSMylène Josserand 		ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
34151068fecaSMylène Josserand 		break;
3416ce85705aSHugues Fruchet 	case V4L2_CID_HFLIP:
3417ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
3418ce85705aSHugues Fruchet 		break;
3419ce85705aSHugues Fruchet 	case V4L2_CID_VFLIP:
3420ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
3421ce85705aSHugues Fruchet 		break;
3422bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3423bce93b82SJacopo Mondi 		ret = ov5640_set_ctrl_vblank(sensor, ctrl->val);
3424bce93b82SJacopo Mondi 		break;
342519a81c14SSteve Longerbeam 	default:
342619a81c14SSteve Longerbeam 		ret = -EINVAL;
342719a81c14SSteve Longerbeam 		break;
342819a81c14SSteve Longerbeam 	}
342919a81c14SSteve Longerbeam 
3430e13064a3SAndrey Skvortsov 	pm_runtime_mark_last_busy(&sensor->i2c_client->dev);
343185644a9bSPaul Elder 	pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
343285644a9bSPaul Elder 
343319a81c14SSteve Longerbeam 	return ret;
343419a81c14SSteve Longerbeam }
343519a81c14SSteve Longerbeam 
343619a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
343719a81c14SSteve Longerbeam 	.g_volatile_ctrl = ov5640_g_volatile_ctrl,
343819a81c14SSteve Longerbeam 	.s_ctrl = ov5640_s_ctrl,
343919a81c14SSteve Longerbeam };
344019a81c14SSteve Longerbeam 
344119a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor)
344219a81c14SSteve Longerbeam {
344322845bf2SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
344419a81c14SSteve Longerbeam 	const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
344519a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
344619a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
34471066fc1cSJacopo Mondi 	struct v4l2_fwnode_device_properties props;
344832979f67SJacopo Mondi 	const struct ov5640_timings *timings;
3449bce93b82SJacopo Mondi 	unsigned int max_vblank;
345032979f67SJacopo Mondi 	unsigned int hblank;
345119a81c14SSteve Longerbeam 	int ret;
345219a81c14SSteve Longerbeam 
345319a81c14SSteve Longerbeam 	v4l2_ctrl_handler_init(hdl, 32);
345419a81c14SSteve Longerbeam 
345519a81c14SSteve Longerbeam 	/* we can use our own mutex for the ctrl lock */
345619a81c14SSteve Longerbeam 	hdl->lock = &sensor->lock;
345719a81c14SSteve Longerbeam 
3458cc196e48SBenoit Parrot 	/* Clock related controls */
3459cc196e48SBenoit Parrot 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
346022845bf2SJacopo Mondi 			      ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
346122845bf2SJacopo Mondi 			      ov5640_pixel_rates[0], 1,
346222845bf2SJacopo Mondi 			      ov5640_pixel_rates[mode->pixel_rate]);
3463cc196e48SBenoit Parrot 
34647a3b8d4bSJacopo Mondi 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
34657a3b8d4bSJacopo Mondi 					V4L2_CID_LINK_FREQ,
34667a3b8d4bSJacopo Mondi 					ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
34677a3b8d4bSJacopo Mondi 					OV5640_DEFAULT_LINK_FREQ,
34687a3b8d4bSJacopo Mondi 					ov5640_csi2_link_freqs);
34697a3b8d4bSJacopo Mondi 
347032979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
347132979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
347232979f67SJacopo Mondi 	ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, hblank,
347332979f67SJacopo Mondi 					  hblank, 1, hblank);
347432979f67SJacopo Mondi 
3475bce93b82SJacopo Mondi 	max_vblank = OV5640_MAX_VTS - mode->height;
3476bce93b82SJacopo Mondi 	ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
3477bce93b82SJacopo Mondi 					  OV5640_MIN_VBLANK, max_vblank,
3478bce93b82SJacopo Mondi 					  1, timings->vblank_def);
3479bce93b82SJacopo Mondi 
348019a81c14SSteve Longerbeam 	/* Auto/manual white balance */
348119a81c14SSteve Longerbeam 	ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
348219a81c14SSteve Longerbeam 					   V4L2_CID_AUTO_WHITE_BALANCE,
348319a81c14SSteve Longerbeam 					   0, 1, 1, 1);
348419a81c14SSteve Longerbeam 	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
348519a81c14SSteve Longerbeam 						0, 4095, 1, 0);
348619a81c14SSteve Longerbeam 	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
348719a81c14SSteve Longerbeam 					       0, 4095, 1, 0);
348819a81c14SSteve Longerbeam 	/* Auto/manual exposure */
348919a81c14SSteve Longerbeam 	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
349019a81c14SSteve Longerbeam 						 V4L2_CID_EXPOSURE_AUTO,
349119a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_MANUAL, 0,
349219a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_AUTO);
349319a81c14SSteve Longerbeam 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
349419a81c14SSteve Longerbeam 					    0, 65535, 1, 0);
349519a81c14SSteve Longerbeam 	/* Auto/manual gain */
349619a81c14SSteve Longerbeam 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
349719a81c14SSteve Longerbeam 					     0, 1, 1, 1);
3498afa48057SPaul Elder 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN,
349919a81c14SSteve Longerbeam 					0, 1023, 1, 0);
350019a81c14SSteve Longerbeam 
350119a81c14SSteve Longerbeam 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
350219a81c14SSteve Longerbeam 					      0, 255, 1, 64);
350319a81c14SSteve Longerbeam 	ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
350419a81c14SSteve Longerbeam 				       0, 359, 1, 0);
350519a81c14SSteve Longerbeam 	ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
350619a81c14SSteve Longerbeam 					    0, 255, 1, 0);
350719a81c14SSteve Longerbeam 	ctrls->test_pattern =
350819a81c14SSteve Longerbeam 		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
350919a81c14SSteve Longerbeam 					     ARRAY_SIZE(test_pattern_menu) - 1,
351019a81c14SSteve Longerbeam 					     0, 0, test_pattern_menu);
3511ce85705aSHugues Fruchet 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
3512ce85705aSHugues Fruchet 					 0, 1, 1, 0);
3513ce85705aSHugues Fruchet 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
3514ce85705aSHugues Fruchet 					 0, 1, 1, 0);
351519a81c14SSteve Longerbeam 
35161068fecaSMylène Josserand 	ctrls->light_freq =
35171068fecaSMylène Josserand 		v4l2_ctrl_new_std_menu(hdl, ops,
35181068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY,
35191068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
35201068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
35211068fecaSMylène Josserand 
352219a81c14SSteve Longerbeam 	if (hdl->error) {
352319a81c14SSteve Longerbeam 		ret = hdl->error;
352419a81c14SSteve Longerbeam 		goto free_ctrls;
352519a81c14SSteve Longerbeam 	}
352619a81c14SSteve Longerbeam 
35271066fc1cSJacopo Mondi 	ret = v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &props);
35281066fc1cSJacopo Mondi 	if (ret)
35291066fc1cSJacopo Mondi 		goto free_ctrls;
35301066fc1cSJacopo Mondi 
35311066fc1cSJacopo Mondi 	if (props.rotation == 180)
35321066fc1cSJacopo Mondi 		sensor->upside_down = true;
35331066fc1cSJacopo Mondi 
35341066fc1cSJacopo Mondi 	ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &props);
35351066fc1cSJacopo Mondi 	if (ret)
35361066fc1cSJacopo Mondi 		goto free_ctrls;
35371066fc1cSJacopo Mondi 
3538cc196e48SBenoit Parrot 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
35397a3b8d4bSJacopo Mondi 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
354032979f67SJacopo Mondi 	ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
354119a81c14SSteve Longerbeam 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
354219a81c14SSteve Longerbeam 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
354319a81c14SSteve Longerbeam 
354419a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
354519a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
354619a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
354719a81c14SSteve Longerbeam 
354819a81c14SSteve Longerbeam 	sensor->sd.ctrl_handler = hdl;
354919a81c14SSteve Longerbeam 	return 0;
355019a81c14SSteve Longerbeam 
355119a81c14SSteve Longerbeam free_ctrls:
355219a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(hdl);
355319a81c14SSteve Longerbeam 	return ret;
355419a81c14SSteve Longerbeam }
355519a81c14SSteve Longerbeam 
355619a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
35570d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
355819a81c14SSteve Longerbeam 				  struct v4l2_subdev_frame_size_enum *fse)
355919a81c14SSteve Longerbeam {
3560a89f14bbSJacopo Mondi 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3561a89f14bbSJacopo Mondi 	u32 bpp = ov5640_code_to_bpp(sensor, fse->code);
35627dcb3a2fSJacopo Mondi 	unsigned int index = fse->index;
35637dcb3a2fSJacopo Mondi 
356419a81c14SSteve Longerbeam 	if (fse->pad != 0)
356519a81c14SSteve Longerbeam 		return -EINVAL;
35667dcb3a2fSJacopo Mondi 	if (!bpp)
356719a81c14SSteve Longerbeam 		return -EINVAL;
356819a81c14SSteve Longerbeam 
35697dcb3a2fSJacopo Mondi 	/* Only low-resolution modes are supported for 24bpp formats. */
35707dcb3a2fSJacopo Mondi 	if (bpp == 24 && index >= OV5640_MODE_720P_1280_720)
35717dcb3a2fSJacopo Mondi 		return -EINVAL;
35727dcb3a2fSJacopo Mondi 
35737dcb3a2fSJacopo Mondi 	/* FIXME: Low resolution modes don't work in 8bpp formats. */
35747dcb3a2fSJacopo Mondi 	if (bpp == 8)
35757dcb3a2fSJacopo Mondi 		index += OV5640_MODE_720P_1280_720;
35767dcb3a2fSJacopo Mondi 
35777dcb3a2fSJacopo Mondi 	if (index >= OV5640_NUM_MODES)
35787dcb3a2fSJacopo Mondi 		return -EINVAL;
35797dcb3a2fSJacopo Mondi 
35807dcb3a2fSJacopo Mondi 	fse->min_width = ov5640_mode_data[index].width;
358141d8d7f5SHugues Fruchet 	fse->max_width = fse->min_width;
35827dcb3a2fSJacopo Mondi 	fse->min_height = ov5640_mode_data[index].height;
358341d8d7f5SHugues Fruchet 	fse->max_height = fse->min_height;
358419a81c14SSteve Longerbeam 
358519a81c14SSteve Longerbeam 	return 0;
358619a81c14SSteve Longerbeam }
358719a81c14SSteve Longerbeam 
358819a81c14SSteve Longerbeam static int ov5640_enum_frame_interval(
358919a81c14SSteve Longerbeam 	struct v4l2_subdev *sd,
35900d346d2aSTomi Valkeinen 	struct v4l2_subdev_state *sd_state,
359119a81c14SSteve Longerbeam 	struct v4l2_subdev_frame_interval_enum *fie)
359219a81c14SSteve Longerbeam {
359319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3594f33b56d3SGuoniu.zhou 	const struct ov5640_mode_info *mode;
359519a81c14SSteve Longerbeam 	struct v4l2_fract tpf;
359619a81c14SSteve Longerbeam 	int ret;
359719a81c14SSteve Longerbeam 
359819a81c14SSteve Longerbeam 	if (fie->pad != 0)
359919a81c14SSteve Longerbeam 		return -EINVAL;
360019a81c14SSteve Longerbeam 	if (fie->index >= OV5640_NUM_FRAMERATES)
360119a81c14SSteve Longerbeam 		return -EINVAL;
360219a81c14SSteve Longerbeam 
3603f33b56d3SGuoniu.zhou 	mode = ov5640_find_mode(sensor, fie->width, fie->height, false);
3604f33b56d3SGuoniu.zhou 	if (!mode)
3605f33b56d3SGuoniu.zhou 		return -EINVAL;
3606f33b56d3SGuoniu.zhou 
360719a81c14SSteve Longerbeam 	tpf.numerator = 1;
360819a81c14SSteve Longerbeam 	tpf.denominator = ov5640_framerates[fie->index];
360919a81c14SSteve Longerbeam 
3610f33b56d3SGuoniu.zhou 	ret = ov5640_try_frame_interval(sensor, &tpf, mode);
361119a81c14SSteve Longerbeam 	if (ret < 0)
361219a81c14SSteve Longerbeam 		return -EINVAL;
361319a81c14SSteve Longerbeam 
361419a81c14SSteve Longerbeam 	fie->interval = tpf;
361519a81c14SSteve Longerbeam 	return 0;
361619a81c14SSteve Longerbeam }
361719a81c14SSteve Longerbeam 
361819a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
361919a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
362019a81c14SSteve Longerbeam {
362119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
362219a81c14SSteve Longerbeam 
362319a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
362419a81c14SSteve Longerbeam 	fi->interval = sensor->frame_interval;
362519a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
362619a81c14SSteve Longerbeam 
362719a81c14SSteve Longerbeam 	return 0;
362819a81c14SSteve Longerbeam }
362919a81c14SSteve Longerbeam 
363019a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
363119a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
363219a81c14SSteve Longerbeam {
363319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
363419a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
363519a81c14SSteve Longerbeam 	int frame_rate, ret = 0;
363619a81c14SSteve Longerbeam 
363719a81c14SSteve Longerbeam 	if (fi->pad != 0)
363819a81c14SSteve Longerbeam 		return -EINVAL;
363919a81c14SSteve Longerbeam 
364019a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
364119a81c14SSteve Longerbeam 
364219a81c14SSteve Longerbeam 	if (sensor->streaming) {
364319a81c14SSteve Longerbeam 		ret = -EBUSY;
364419a81c14SSteve Longerbeam 		goto out;
364519a81c14SSteve Longerbeam 	}
364619a81c14SSteve Longerbeam 
364719a81c14SSteve Longerbeam 	mode = sensor->current_mode;
364819a81c14SSteve Longerbeam 
3649f33b56d3SGuoniu.zhou 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval, mode);
3650e823fb16SMaxime Ripard 	if (frame_rate < 0) {
3651e823fb16SMaxime Ripard 		/* Always return a valid frame interval value */
3652e823fb16SMaxime Ripard 		fi->interval = sensor->frame_interval;
3653e823fb16SMaxime Ripard 		goto out;
3654e823fb16SMaxime Ripard 	}
365519a81c14SSteve Longerbeam 
3656b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, mode->width, mode->height, true);
36573c4a7372SHugues Fruchet 	if (!mode) {
36583c4a7372SHugues Fruchet 		ret = -EINVAL;
36593c4a7372SHugues Fruchet 		goto out;
36603c4a7372SHugues Fruchet 	}
36613c4a7372SHugues Fruchet 
3662b6ae5022SJacopo Mondi 	if (ov5640_framerates[frame_rate] > ov5640_framerates[mode->max_fps]) {
3663b6ae5022SJacopo Mondi 		ret = -EINVAL;
3664b6ae5022SJacopo Mondi 		goto out;
3665b6ae5022SJacopo Mondi 	}
3666b6ae5022SJacopo Mondi 
36670929983eSHugues Fruchet 	if (mode != sensor->current_mode ||
36680929983eSHugues Fruchet 	    frame_rate != sensor->current_fr) {
36690929983eSHugues Fruchet 		sensor->current_fr = frame_rate;
36700929983eSHugues Fruchet 		sensor->frame_interval = fi->interval;
36713c4a7372SHugues Fruchet 		sensor->current_mode = mode;
367219a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
3673cc196e48SBenoit Parrot 
367419f2e3e6SHugues Fruchet 		ov5640_update_pixel_rate(sensor);
36756949d864SHugues Fruchet 	}
367619a81c14SSteve Longerbeam out:
367719a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
367819a81c14SSteve Longerbeam 	return ret;
367919a81c14SSteve Longerbeam }
368019a81c14SSteve Longerbeam 
368119a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
36820d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
368319a81c14SSteve Longerbeam 				 struct v4l2_subdev_mbus_code_enum *code)
368419a81c14SSteve Longerbeam {
3685a89f14bbSJacopo Mondi 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3686a89f14bbSJacopo Mondi 	const struct ov5640_pixfmt *formats;
3687a89f14bbSJacopo Mondi 	unsigned int num_formats;
3688a89f14bbSJacopo Mondi 
3689a89f14bbSJacopo Mondi 	if (ov5640_is_csi2(sensor)) {
3690a89f14bbSJacopo Mondi 		formats = ov5640_csi2_formats;
3691a89f14bbSJacopo Mondi 		num_formats = ARRAY_SIZE(ov5640_csi2_formats) - 1;
3692a89f14bbSJacopo Mondi 	} else {
3693a89f14bbSJacopo Mondi 		formats = ov5640_dvp_formats;
3694a89f14bbSJacopo Mondi 		num_formats = ARRAY_SIZE(ov5640_dvp_formats) - 1;
3695a89f14bbSJacopo Mondi 	}
3696a89f14bbSJacopo Mondi 
3697a89f14bbSJacopo Mondi 	if (code->index >= num_formats)
369819a81c14SSteve Longerbeam 		return -EINVAL;
369919a81c14SSteve Longerbeam 
3700a89f14bbSJacopo Mondi 	code->code = formats[code->index].code;
3701a89f14bbSJacopo Mondi 
370219a81c14SSteve Longerbeam 	return 0;
370319a81c14SSteve Longerbeam }
370419a81c14SSteve Longerbeam 
370519a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
370619a81c14SSteve Longerbeam {
370719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
370819a81c14SSteve Longerbeam 	int ret = 0;
370919a81c14SSteve Longerbeam 
371085644a9bSPaul Elder 	if (enable) {
371185644a9bSPaul Elder 		ret = pm_runtime_resume_and_get(&sensor->i2c_client->dev);
371285644a9bSPaul Elder 		if (ret < 0)
371385644a9bSPaul Elder 			return ret;
371485644a9bSPaul Elder 
371585644a9bSPaul Elder 		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
371685644a9bSPaul Elder 		if (ret) {
371785644a9bSPaul Elder 			pm_runtime_put(&sensor->i2c_client->dev);
371885644a9bSPaul Elder 			return ret;
371985644a9bSPaul Elder 		}
372085644a9bSPaul Elder 	}
372185644a9bSPaul Elder 
372219a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
372319a81c14SSteve Longerbeam 
372419a81c14SSteve Longerbeam 	if (sensor->streaming == !enable) {
372519a81c14SSteve Longerbeam 		if (enable && sensor->pending_mode_change) {
3726985cdcb0SHugues Fruchet 			ret = ov5640_set_mode(sensor);
372719a81c14SSteve Longerbeam 			if (ret)
372819a81c14SSteve Longerbeam 				goto out;
3729fb98e29fSHugues Fruchet 		}
3730e3ee691dSHugues Fruchet 
3731fb98e29fSHugues Fruchet 		if (enable && sensor->pending_fmt_change) {
3732e3ee691dSHugues Fruchet 			ret = ov5640_set_framefmt(sensor, &sensor->fmt);
3733e3ee691dSHugues Fruchet 			if (ret)
3734e3ee691dSHugues Fruchet 				goto out;
3735fb98e29fSHugues Fruchet 			sensor->pending_fmt_change = false;
373619a81c14SSteve Longerbeam 		}
373719a81c14SSteve Longerbeam 
37388e823f5cSJacopo Mondi 		if (ov5640_is_csi2(sensor))
3739f22996dbSHugues Fruchet 			ret = ov5640_set_stream_mipi(sensor, enable);
3740f22996dbSHugues Fruchet 		else
3741f22996dbSHugues Fruchet 			ret = ov5640_set_stream_dvp(sensor, enable);
3742f22996dbSHugues Fruchet 
374319a81c14SSteve Longerbeam 		if (!ret)
374419a81c14SSteve Longerbeam 			sensor->streaming = enable;
374519a81c14SSteve Longerbeam 	}
374685644a9bSPaul Elder 
374719a81c14SSteve Longerbeam out:
374819a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
374985644a9bSPaul Elder 
3750e13064a3SAndrey Skvortsov 	if (!enable || ret) {
3751e13064a3SAndrey Skvortsov 		pm_runtime_mark_last_busy(&sensor->i2c_client->dev);
375285644a9bSPaul Elder 		pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
3753e13064a3SAndrey Skvortsov 	}
375485644a9bSPaul Elder 
375519a81c14SSteve Longerbeam 	return ret;
375619a81c14SSteve Longerbeam }
375719a81c14SSteve Longerbeam 
375890b0f355SJacopo Mondi static int ov5640_init_cfg(struct v4l2_subdev *sd,
375990b0f355SJacopo Mondi 			   struct v4l2_subdev_state *state)
376090b0f355SJacopo Mondi {
376168453b02SGuoniu.zhou 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
376290b0f355SJacopo Mondi 	struct v4l2_mbus_framefmt *fmt =
376390b0f355SJacopo Mondi 				v4l2_subdev_get_try_format(sd, state, 0);
376466ed85ebSJacopo Mondi 	struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0);
376590b0f355SJacopo Mondi 
376668453b02SGuoniu.zhou 	*fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt :
376768453b02SGuoniu.zhou 					ov5640_dvp_default_fmt;
376890b0f355SJacopo Mondi 
376966ed85ebSJacopo Mondi 	crop->left = OV5640_PIXEL_ARRAY_LEFT;
377066ed85ebSJacopo Mondi 	crop->top = OV5640_PIXEL_ARRAY_TOP;
377166ed85ebSJacopo Mondi 	crop->width = OV5640_PIXEL_ARRAY_WIDTH;
377266ed85ebSJacopo Mondi 	crop->height = OV5640_PIXEL_ARRAY_HEIGHT;
377366ed85ebSJacopo Mondi 
377490b0f355SJacopo Mondi 	return 0;
377590b0f355SJacopo Mondi }
377690b0f355SJacopo Mondi 
377719a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = {
37782d18fbc5SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
37792d18fbc5SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
37802d18fbc5SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
378119a81c14SSteve Longerbeam };
378219a81c14SSteve Longerbeam 
378319a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = {
378419a81c14SSteve Longerbeam 	.g_frame_interval = ov5640_g_frame_interval,
378519a81c14SSteve Longerbeam 	.s_frame_interval = ov5640_s_frame_interval,
378619a81c14SSteve Longerbeam 	.s_stream = ov5640_s_stream,
378719a81c14SSteve Longerbeam };
378819a81c14SSteve Longerbeam 
378919a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
379090b0f355SJacopo Mondi 	.init_cfg = ov5640_init_cfg,
379119a81c14SSteve Longerbeam 	.enum_mbus_code = ov5640_enum_mbus_code,
379219a81c14SSteve Longerbeam 	.get_fmt = ov5640_get_fmt,
379319a81c14SSteve Longerbeam 	.set_fmt = ov5640_set_fmt,
379466ed85ebSJacopo Mondi 	.get_selection = ov5640_get_selection,
379519a81c14SSteve Longerbeam 	.enum_frame_size = ov5640_enum_frame_size,
379619a81c14SSteve Longerbeam 	.enum_frame_interval = ov5640_enum_frame_interval,
379719a81c14SSteve Longerbeam };
379819a81c14SSteve Longerbeam 
379919a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = {
380019a81c14SSteve Longerbeam 	.core = &ov5640_core_ops,
380119a81c14SSteve Longerbeam 	.video = &ov5640_video_ops,
380219a81c14SSteve Longerbeam 	.pad = &ov5640_pad_ops,
380319a81c14SSteve Longerbeam };
380419a81c14SSteve Longerbeam 
380519a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor)
380619a81c14SSteve Longerbeam {
380719a81c14SSteve Longerbeam 	int i;
380819a81c14SSteve Longerbeam 
380919a81c14SSteve Longerbeam 	for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
381019a81c14SSteve Longerbeam 		sensor->supplies[i].supply = ov5640_supply_name[i];
381119a81c14SSteve Longerbeam 
381219a81c14SSteve Longerbeam 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
381319a81c14SSteve Longerbeam 				       OV5640_NUM_SUPPLIES,
381419a81c14SSteve Longerbeam 				       sensor->supplies);
381519a81c14SSteve Longerbeam }
381619a81c14SSteve Longerbeam 
38170f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor)
38180f7acb52SHugues Fruchet {
38190f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
38200f7acb52SHugues Fruchet 	int ret = 0;
38210f7acb52SHugues Fruchet 	u16 chip_id;
38220f7acb52SHugues Fruchet 
38230f7acb52SHugues Fruchet 	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
38240f7acb52SHugues Fruchet 	if (ret) {
38250f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to read chip identifier\n",
38260f7acb52SHugues Fruchet 			__func__);
382785644a9bSPaul Elder 		return ret;
38280f7acb52SHugues Fruchet 	}
38290f7acb52SHugues Fruchet 
38300f7acb52SHugues Fruchet 	if (chip_id != 0x5640) {
38310f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
38320f7acb52SHugues Fruchet 			__func__, chip_id);
383385644a9bSPaul Elder 		return -ENXIO;
38340f7acb52SHugues Fruchet 	}
38350f7acb52SHugues Fruchet 
383685644a9bSPaul Elder 	return 0;
38370f7acb52SHugues Fruchet }
38380f7acb52SHugues Fruchet 
3839e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client)
384019a81c14SSteve Longerbeam {
384119a81c14SSteve Longerbeam 	struct device *dev = &client->dev;
384219a81c14SSteve Longerbeam 	struct fwnode_handle *endpoint;
384319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor;
384419a81c14SSteve Longerbeam 	int ret;
384519a81c14SSteve Longerbeam 
384619a81c14SSteve Longerbeam 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
384719a81c14SSteve Longerbeam 	if (!sensor)
384819a81c14SSteve Longerbeam 		return -ENOMEM;
384919a81c14SSteve Longerbeam 
385019a81c14SSteve Longerbeam 	sensor->i2c_client = client;
3851fb98e29fSHugues Fruchet 
3852fb98e29fSHugues Fruchet 	/*
3853fb98e29fSHugues Fruchet 	 * default init sequence initialize sensor to
3854*afe25fbcSGuoniu.zhou 	 * YUV422 UYVY VGA(30FPS in parallel mode, 60 in MIPI CSI-2 mode)
3855fb98e29fSHugues Fruchet 	 */
385619a81c14SSteve Longerbeam 	sensor->frame_interval.numerator = 1;
385719a81c14SSteve Longerbeam 	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
385819a81c14SSteve Longerbeam 	sensor->current_fr = OV5640_30_FPS;
385919a81c14SSteve Longerbeam 	sensor->current_mode =
3860086c25f8SMaxime Ripard 		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
3861985cdcb0SHugues Fruchet 	sensor->last_mode = sensor->current_mode;
3862d7b41196SGuoniu.zhou 	sensor->current_link_freq =
3863d7b41196SGuoniu.zhou 		ov5640_csi2_link_freqs[OV5640_DEFAULT_LINK_FREQ];
386419a81c14SSteve Longerbeam 
386519a81c14SSteve Longerbeam 	sensor->ae_target = 52;
386619a81c14SSteve Longerbeam 
3867ce96bcf5SSakari Ailus 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
3868ce96bcf5SSakari Ailus 						  NULL);
386919a81c14SSteve Longerbeam 	if (!endpoint) {
387019a81c14SSteve Longerbeam 		dev_err(dev, "endpoint node not found\n");
387119a81c14SSteve Longerbeam 		return -EINVAL;
387219a81c14SSteve Longerbeam 	}
387319a81c14SSteve Longerbeam 
387419a81c14SSteve Longerbeam 	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
387519a81c14SSteve Longerbeam 	fwnode_handle_put(endpoint);
387619a81c14SSteve Longerbeam 	if (ret) {
387719a81c14SSteve Longerbeam 		dev_err(dev, "Could not parse endpoint\n");
387819a81c14SSteve Longerbeam 		return ret;
387919a81c14SSteve Longerbeam 	}
388019a81c14SSteve Longerbeam 
38812c61e48dSLad Prabhakar 	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
38822c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
38832c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_BT656) {
38842c61e48dSLad Prabhakar 		dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
38852c61e48dSLad Prabhakar 		return -EINVAL;
38862c61e48dSLad Prabhakar 	}
38872c61e48dSLad Prabhakar 
388868453b02SGuoniu.zhou 	sensor->fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt :
388968453b02SGuoniu.zhou 					       ov5640_dvp_default_fmt;
389068453b02SGuoniu.zhou 
389119a81c14SSteve Longerbeam 	/* get system clock (xclk) */
389219a81c14SSteve Longerbeam 	sensor->xclk = devm_clk_get(dev, "xclk");
389319a81c14SSteve Longerbeam 	if (IS_ERR(sensor->xclk)) {
389419a81c14SSteve Longerbeam 		dev_err(dev, "failed to get xclk\n");
389519a81c14SSteve Longerbeam 		return PTR_ERR(sensor->xclk);
389619a81c14SSteve Longerbeam 	}
389719a81c14SSteve Longerbeam 
389819a81c14SSteve Longerbeam 	sensor->xclk_freq = clk_get_rate(sensor->xclk);
389919a81c14SSteve Longerbeam 	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
390019a81c14SSteve Longerbeam 	    sensor->xclk_freq > OV5640_XCLK_MAX) {
390119a81c14SSteve Longerbeam 		dev_err(dev, "xclk frequency out of range: %d Hz\n",
390219a81c14SSteve Longerbeam 			sensor->xclk_freq);
390319a81c14SSteve Longerbeam 		return -EINVAL;
390419a81c14SSteve Longerbeam 	}
390519a81c14SSteve Longerbeam 
390619a81c14SSteve Longerbeam 	/* request optional power down pin */
390719a81c14SSteve Longerbeam 	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
390819a81c14SSteve Longerbeam 						    GPIOD_OUT_HIGH);
39098791a102SFabio Estevam 	if (IS_ERR(sensor->pwdn_gpio))
39108791a102SFabio Estevam 		return PTR_ERR(sensor->pwdn_gpio);
39118791a102SFabio Estevam 
391219a81c14SSteve Longerbeam 	/* request optional reset pin */
391319a81c14SSteve Longerbeam 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
391419a81c14SSteve Longerbeam 						     GPIOD_OUT_HIGH);
39158791a102SFabio Estevam 	if (IS_ERR(sensor->reset_gpio))
39168791a102SFabio Estevam 		return PTR_ERR(sensor->reset_gpio);
391719a81c14SSteve Longerbeam 
391819a81c14SSteve Longerbeam 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
391919a81c14SSteve Longerbeam 
39202d18fbc5SAkinobu Mita 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
39212d18fbc5SAkinobu Mita 			    V4L2_SUBDEV_FL_HAS_EVENTS;
392219a81c14SSteve Longerbeam 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
392319a81c14SSteve Longerbeam 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
392419a81c14SSteve Longerbeam 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
392519a81c14SSteve Longerbeam 	if (ret)
392619a81c14SSteve Longerbeam 		return ret;
392719a81c14SSteve Longerbeam 
392819a81c14SSteve Longerbeam 	ret = ov5640_get_regulators(sensor);
392919a81c14SSteve Longerbeam 	if (ret)
393085644a9bSPaul Elder 		goto entity_cleanup;
393119a81c14SSteve Longerbeam 
393219a81c14SSteve Longerbeam 	mutex_init(&sensor->lock);
393319a81c14SSteve Longerbeam 
393419a81c14SSteve Longerbeam 	ret = ov5640_init_controls(sensor);
393519a81c14SSteve Longerbeam 	if (ret)
393619a81c14SSteve Longerbeam 		goto entity_cleanup;
393719a81c14SSteve Longerbeam 
393885644a9bSPaul Elder 	ret = ov5640_sensor_resume(dev);
393985644a9bSPaul Elder 	if (ret) {
394085644a9bSPaul Elder 		dev_err(dev, "failed to power on\n");
394185644a9bSPaul Elder 		goto entity_cleanup;
394285644a9bSPaul Elder 	}
394385644a9bSPaul Elder 
394485644a9bSPaul Elder 	pm_runtime_set_active(dev);
394585644a9bSPaul Elder 	pm_runtime_get_noresume(dev);
394685644a9bSPaul Elder 	pm_runtime_enable(dev);
394785644a9bSPaul Elder 
394885644a9bSPaul Elder 	ret = ov5640_check_chip_id(sensor);
394985644a9bSPaul Elder 	if (ret)
395085644a9bSPaul Elder 		goto err_pm_runtime;
395185644a9bSPaul Elder 
395215786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
395319a81c14SSteve Longerbeam 	if (ret)
395485644a9bSPaul Elder 		goto err_pm_runtime;
395585644a9bSPaul Elder 
395685644a9bSPaul Elder 	pm_runtime_set_autosuspend_delay(dev, 1000);
395785644a9bSPaul Elder 	pm_runtime_use_autosuspend(dev);
3958e13064a3SAndrey Skvortsov 	pm_runtime_mark_last_busy(dev);
395985644a9bSPaul Elder 	pm_runtime_put_autosuspend(dev);
396019a81c14SSteve Longerbeam 
396119a81c14SSteve Longerbeam 	return 0;
396219a81c14SSteve Longerbeam 
396385644a9bSPaul Elder err_pm_runtime:
396485644a9bSPaul Elder 	pm_runtime_put_noidle(dev);
396585644a9bSPaul Elder 	pm_runtime_disable(dev);
396619a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
396785644a9bSPaul Elder 	ov5640_sensor_suspend(dev);
396819a81c14SSteve Longerbeam entity_cleanup:
396919a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
3970bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
397119a81c14SSteve Longerbeam 	return ret;
397219a81c14SSteve Longerbeam }
397319a81c14SSteve Longerbeam 
3974ed5c2f5fSUwe Kleine-König static void ov5640_remove(struct i2c_client *client)
397519a81c14SSteve Longerbeam {
397619a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
397719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
397885644a9bSPaul Elder 	struct device *dev = &client->dev;
397985644a9bSPaul Elder 
398085644a9bSPaul Elder 	pm_runtime_disable(dev);
398185644a9bSPaul Elder 	if (!pm_runtime_status_suspended(dev))
398285644a9bSPaul Elder 		ov5640_sensor_suspend(dev);
398385644a9bSPaul Elder 	pm_runtime_set_suspended(dev);
398419a81c14SSteve Longerbeam 
398519a81c14SSteve Longerbeam 	v4l2_async_unregister_subdev(&sensor->sd);
398619a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
398719a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
3988bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
398919a81c14SSteve Longerbeam }
399019a81c14SSteve Longerbeam 
399185644a9bSPaul Elder static const struct dev_pm_ops ov5640_pm_ops = {
399285644a9bSPaul Elder 	SET_RUNTIME_PM_OPS(ov5640_sensor_suspend, ov5640_sensor_resume, NULL)
399385644a9bSPaul Elder };
399485644a9bSPaul Elder 
399519a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = {
399619a81c14SSteve Longerbeam 	{"ov5640", 0},
399719a81c14SSteve Longerbeam 	{},
399819a81c14SSteve Longerbeam };
399919a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id);
400019a81c14SSteve Longerbeam 
400119a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = {
400219a81c14SSteve Longerbeam 	{ .compatible = "ovti,ov5640" },
400319a81c14SSteve Longerbeam 	{ /* sentinel */ }
400419a81c14SSteve Longerbeam };
400519a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
400619a81c14SSteve Longerbeam 
400719a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = {
400819a81c14SSteve Longerbeam 	.driver = {
400919a81c14SSteve Longerbeam 		.name  = "ov5640",
401019a81c14SSteve Longerbeam 		.of_match_table	= ov5640_dt_ids,
401185644a9bSPaul Elder 		.pm = &ov5640_pm_ops,
401219a81c14SSteve Longerbeam 	},
401319a81c14SSteve Longerbeam 	.id_table = ov5640_id,
4014aaeb31c0SUwe Kleine-König 	.probe    = ov5640_probe,
401519a81c14SSteve Longerbeam 	.remove   = ov5640_remove,
401619a81c14SSteve Longerbeam };
401719a81c14SSteve Longerbeam 
401819a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver);
401919a81c14SSteve Longerbeam 
402019a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
402119a81c14SSteve Longerbeam MODULE_LICENSE("GPL");
4022